diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml index 5c094c400fc85605bb8f14cfcae34eba6375cfdb..6d616b4b5b4ac1451057bcd929a94934f84ba5c8 100644 --- a/.github/workflows/continuous-integration-workflow.yml +++ b/.github/workflows/continuous-integration-workflow.yml @@ -6,15 +6,11 @@ jobs: name: Build runs-on: macOS-latest env: - DEVELOPER_DIR: /Applications/Xcode_12.app/Contents/Developer + GIT_SSL_NO_VERIFY: true + DEVELOPER_DIR: /Applications/Xcode.app/Contents/Developer steps: - uses: actions/checkout@v1 - name: Clean - run: xcodebuild -scheme McBopomofo -configuration Release clean - - name: Clean - run: xcodebuild -scheme McBopomofoInstaller -configuration Release clean - - name: Build - run: xcodebuild -scheme McBopomofo -configuration Release build + run: make clean - name: Build - run: xcodebuild -scheme McBopomofoInstaller -configuration Release build - + run: git pull --all && git submodule sync; make update; make diff --git a/.gitignore b/.gitignore index 3160b584c79800adcf60d744d1fb88df9b08b203..d68d256a981c9016d23976d1684d03974800159e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,14 @@ -build -*.pbxuser +*.dmg *.mode1v3 +*.pbxuser *.tm_build_errors -*.dmg +.build .DS_Store -project.xcworkspace -xcuserdata -Credits.rtf -# the executable we used to count the occurance of a string in a file -# that can be built by make -C Source/Data/bin/C_Version -# C_count.occ.exe .idea +.swiftpm +.vscode +build +Credits.rtf +project.xcworkspace +Source/Data/* +xcuserdata \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..df4cdd17292d0cac08146de7da920ff7e4da649c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Source/Data"] + path = Source/Data + url = https://gitee.com/vchewing/libvchewing-data diff --git a/Installer/AppDelegate.swift b/Installer/AppDelegate.swift new file mode 100644 index 0000000000000000000000000000000000000000..2be51151cab12cb7458cba97cd64f6ef1ee964e1 --- /dev/null +++ b/Installer/AppDelegate.swift @@ -0,0 +1,269 @@ +/* + * AppDelegate.swift + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +import Cocoa + +private let kTargetBin = "vChewing" +private let kTargetType = "app" +private let kTargetBundle = "vChewing.app" +private let kDestinationPartial = "~/Library/Input Methods/" +private let kTargetPartialPath = "~/Library/Input Methods/vChewing.app" +private let kTargetFullBinPartialPath = "~/Library/Input Methods/vChewing.app/Contents/MacOS/vChewing" + +private let kTranslocationRemovalTickInterval: TimeInterval = 0.5 +private let kTranslocationRemovalDeadline: TimeInterval = 60.0 + +@NSApplicationMain +@objc (AppDelegate) +class AppDelegate: NSWindowController, NSApplicationDelegate { + @IBOutlet weak private var installButton: NSButton! + @IBOutlet weak private var cancelButton: NSButton! + @IBOutlet weak private var progressSheet: NSWindow! + @IBOutlet weak private var progressIndicator: NSProgressIndicator! + @IBOutlet weak private var appVersionLabel: NSTextField! + @IBOutlet weak private var appCopyrightLabel: NSTextField! + @IBOutlet private var appEULAContent: NSTextView! + + private var archiveUtil: ArchiveUtil? + private var installingVersion = "" + private var upgrading = false + private var translocationRemovalStartTime: Date? + private var currentVersionNumber: Int = 0 + + func runAlertPanel(title: String, message: String, buttonTitle: String) { + let alert = NSAlert() + alert.alertStyle = .informational + alert.messageText = title + alert.informativeText = message + alert.addButton(withTitle: buttonTitle) + alert.runModal() + } + + func applicationDidFinishLaunching(_ notification: Notification) { + guard let installingVersion = Bundle.main.infoDictionary?[kCFBundleVersionKey as String] as? String, + let versionString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else { + return + } + self.installingVersion = installingVersion + self.archiveUtil = ArchiveUtil(appName: kTargetBin, targetAppBundleName: kTargetBundle) + _ = archiveUtil?.validateIfNotarizedArchiveExists() + + cancelButton.nextKeyView = installButton + installButton.nextKeyView = cancelButton + if let cell = installButton.cell as? NSButtonCell { + window?.defaultButtonCell = cell + } + + if let copyrightLabel = Bundle.main.localizedInfoDictionary?["NSHumanReadableCopyright"] as? String { + appCopyrightLabel.stringValue = copyrightLabel + } + if let eulaContent = Bundle.main.localizedInfoDictionary?["CFEULAContent"] as? String { + appEULAContent.string = eulaContent + } + appVersionLabel.stringValue = String(format: "%@ Build %@", versionString, installingVersion) + + window?.title = String(format: NSLocalizedString("%@ (for version %@, r%@)", comment: ""), window?.title ?? "", versionString, installingVersion) + window?.standardWindowButton(.closeButton)?.isHidden = true + window?.standardWindowButton(.miniaturizeButton)?.isHidden = true + window?.standardWindowButton(.zoomButton)?.isHidden = true + + if FileManager.default.fileExists(atPath: (kTargetPartialPath as NSString).expandingTildeInPath) { + let currentBundle = Bundle(path: (kTargetPartialPath as NSString).expandingTildeInPath) + let shortVersion = currentBundle?.infoDictionary?["CFBundleShortVersionString"] as? String + let currentVersion = currentBundle?.infoDictionary?[kCFBundleVersionKey as String] as? String + currentVersionNumber = (currentVersion as NSString?)?.integerValue ?? 0 + if shortVersion != nil, let currentVersion = currentVersion, currentVersion.compare(installingVersion, options: .numeric) == .orderedAscending { + upgrading = true + } + } + + if upgrading { + installButton.title = NSLocalizedString("Upgrade", comment: "") + } + + window?.center() + window?.orderFront(self) + NSApp.activate(ignoringOtherApps: true) + } + + @IBAction func agreeAndInstallAction(_ sender: AnyObject) { + cancelButton.isEnabled = false + installButton.isEnabled = false + removeThenInstallInputMethod() + } + + @objc func timerTick(_ timer: Timer) { + let elapsed = Date().timeIntervalSince(translocationRemovalStartTime ?? Date()) + if elapsed >= kTranslocationRemovalDeadline { + timer.invalidate() + window?.endSheet(progressSheet, returnCode: .cancel) + } else if appBundleChronoshiftedToARandomizedPath(kTargetPartialPath) == false { + progressIndicator.doubleValue = 1.0 + timer.invalidate() + window?.endSheet(progressSheet, returnCode: .continue) + } + } + + func removeThenInstallInputMethod() { + if FileManager.default.fileExists(atPath: (kTargetPartialPath as NSString).expandingTildeInPath) == false { + self.installInputMethod(previousExists: false, previousVersionNotFullyDeactivatedWarning: false) + return + } + + let shouldWaitForTranslocationRemoval = appBundleChronoshiftedToARandomizedPath(kTargetPartialPath) && (window?.responds(to: #selector(NSWindow.beginSheet(_:completionHandler:))) ?? false) + + // 將既存輸入法扔到垃圾桶內 + do { + let sourceDir = (kDestinationPartial as NSString).expandingTildeInPath + let fileManager = FileManager.default + let fileURLString = String(format: "%@/%@", sourceDir, kTargetBundle) + let fileURL = URL(fileURLWithPath: fileURLString) + + // 檢查檔案是否存在 + if fileManager.fileExists(atPath: fileURLString) { + // 塞入垃圾桶 + try fileManager.trashItem(at: fileURL, resultingItemURL: nil) + } else { + NSLog("File does not exist") + } + + } + catch let error as NSError { + NSLog("An error took place: \(error)") + } + + let killTask = Process() + killTask.launchPath = "/usr/bin/killall" + killTask.arguments = ["-9", kTargetBin] + killTask.launch() + killTask.waitUntilExit() + + if shouldWaitForTranslocationRemoval { + progressIndicator.startAnimation(self) + window?.beginSheet(progressSheet) { returnCode in + DispatchQueue.main.async { + if returnCode == .continue { + self.installInputMethod(previousExists: true, previousVersionNotFullyDeactivatedWarning: false) + } else { + self.installInputMethod(previousExists: true, previousVersionNotFullyDeactivatedWarning: true) + } + } + } + + translocationRemovalStartTime = Date() + Timer.scheduledTimer(timeInterval: kTranslocationRemovalTickInterval, target: self, selector: #selector(timerTick(_:)), userInfo: nil, repeats: true) + } else { + self.installInputMethod(previousExists: false, previousVersionNotFullyDeactivatedWarning: false) + } + } + + func installInputMethod(previousExists: Bool, previousVersionNotFullyDeactivatedWarning warning: Bool) { + guard let targetBundle = archiveUtil?.unzipNotarizedArchive() ?? Bundle.main.path(forResource: kTargetBin, ofType: kTargetType) else { + return + } + let cpTask = Process() + cpTask.launchPath = "/bin/cp" + cpTask.arguments = ["-R", targetBundle, (kDestinationPartial as NSString).expandingTildeInPath] + cpTask.launch() + cpTask.waitUntilExit() + + if cpTask.terminationStatus != 0 { + runAlertPanel(title: NSLocalizedString("Install Failed", comment: ""), + message: NSLocalizedString("Cannot copy the file to the destination.", comment: ""), + buttonTitle: NSLocalizedString("Cancel", comment: "")) + endAppWithDelay() + } + + guard let imeBundle = Bundle(path: (kTargetPartialPath as NSString).expandingTildeInPath), + let imeIdentifier = imeBundle.bundleIdentifier + else { + endAppWithDelay() + return + } + + let imeBundleURL = imeBundle.bundleURL + var inputSource = InputSourceHelper.inputSource(for: imeIdentifier) + + if inputSource == nil { + NSLog("Registering input source \(imeIdentifier) at \(imeBundleURL.absoluteString)."); + let status = InputSourceHelper.registerTnputSource(at: imeBundleURL) + if !status { + let message = String(format: NSLocalizedString("Cannot find input source %@ after registration.", comment: ""), imeIdentifier) + runAlertPanel(title: NSLocalizedString("Fatal Error", comment: ""), message: message, buttonTitle: NSLocalizedString("Abort", comment: "")) + endAppWithDelay() + return + } + + inputSource = InputSourceHelper.inputSource(for: imeIdentifier) + if inputSource == nil { + let message = String(format: NSLocalizedString("Cannot find input source %@ after registration.", comment: ""), imeIdentifier) + runAlertPanel(title: NSLocalizedString("Fatal Error", comment: ""), message: message, buttonTitle: NSLocalizedString("Abort", comment: "")) + } + } + + var isMacOS12OrAbove = false + if #available(macOS 12.0, *) { + NSLog("macOS 12 or later detected."); + isMacOS12OrAbove = true + } else { + NSLog("Installer runs with the pre-macOS 12 flow."); + } + + // If the IME is not enabled, enable it. Also, unconditionally enable it on macOS 12.0+, + // as the kTISPropertyInputSourceIsEnabled can still be true even if the IME is *not* + // enabled in the user's current set of IMEs (which means the IME does not show up in + // the user's input menu). + + var mainInputSourceEnabled = InputSourceHelper.inputSourceEnabled(for: inputSource!) + if !mainInputSourceEnabled || isMacOS12OrAbove { + mainInputSourceEnabled = InputSourceHelper.enable(inputSource: inputSource!) + if (mainInputSourceEnabled) { + NSLog("Input method enabled: \(imeIdentifier)"); + } else { + NSLog("Failed to enable input method: \(imeIdentifier)"); + } + } + + // Alert Panel + let ntfPostInstall = NSAlert() + if warning { + ntfPostInstall.messageText = NSLocalizedString("Attention", comment: "") + ntfPostInstall.informativeText = NSLocalizedString("vChewing is upgraded, but please log out or reboot for the new version to be fully functional.", comment: "") + ntfPostInstall.addButton(withTitle: NSLocalizedString("OK", comment: "")) + } else { + if !mainInputSourceEnabled && !isMacOS12OrAbove { + ntfPostInstall.messageText = NSLocalizedString("Warning", comment: "") + ntfPostInstall.informativeText = NSLocalizedString("Input method may not be fully enabled. Please enable it through System Preferences > Keyboard > Input Sources.", comment: "") + ntfPostInstall.addButton(withTitle: NSLocalizedString("Continue", comment: "")) + } else { + ntfPostInstall.messageText = NSLocalizedString("Installation Successful", comment: "") + ntfPostInstall.informativeText = NSLocalizedString("vChewing is ready to use.", comment: "") + ntfPostInstall.addButton(withTitle: NSLocalizedString("OK", comment: "")) + } + } + ntfPostInstall.beginSheetModal(for: window!) { response in + self.endAppWithDelay() + } + } + + func endAppWithDelay() { + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { + NSApp.terminate(self) + } + } + + @IBAction func cancelAction(_ sender: AnyObject) { + NSApp.terminate(self) + } + + func windowWillClose(_ Notification: Notification) { + NSApp.terminate(self) + } + + +} diff --git a/Installer/ArchiveUtil.swift b/Installer/ArchiveUtil.swift new file mode 100644 index 0000000000000000000000000000000000000000..ac20d46d213648de4a188bf97c99ef0d7039a4f3 --- /dev/null +++ b/Installer/ArchiveUtil.swift @@ -0,0 +1,106 @@ +/* + * ArchiveUtil.swift + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +import Cocoa + +struct ArchiveUtil { + var appName: String + var targetAppBundleName: String + + init(appName: String, targetAppBundleName: String) { + self.appName = appName + self.targetAppBundleName = targetAppBundleName + } + + // Returns YES if (1) a zip file under + // Resources/NotarizedArchives/$_appName-$bundleVersion.zip exists, and (2) if + // Resources/$_invalidAppBundleName does not exist. + func validateIfNotarizedArchiveExists() -> Bool { + guard let resourePath = Bundle.main.resourcePath, + let notarizedArchivesPath = notarizedArchivesPath, + let notarizedArchive = notarizedArchive, + let notarizedArchivesContent: [String] = try? FileManager.default.subpathsOfDirectory(atPath: notarizedArchivesPath) + else { + return false + } + + let devModeAppBundlePath = (resourePath as NSString).appendingPathComponent(targetAppBundleName) + let count = notarizedArchivesContent.count + let notarizedArchiveExists = FileManager.default.fileExists(atPath: notarizedArchive) + let devModeAppBundleExists = FileManager.default.fileExists(atPath: devModeAppBundlePath) + + if count > 0 { + if count != 1 || !notarizedArchiveExists || devModeAppBundleExists { + let alert = NSAlert() + alert.alertStyle = .informational + alert.messageText = "Internal Error" + alert.informativeText = "devMode installer, expected archive name: \(notarizedArchive), " + + "archive exists: \(notarizedArchiveExists), devMode app bundle exists: \(devModeAppBundleExists)" + alert.addButton(withTitle: "Terminate") + alert.runModal() + NSApp.terminate(nil) + } else { + return true + } + } + + if !devModeAppBundleExists { + let alert = NSAlert() + alert.alertStyle = .informational + alert.messageText = "Internal Error" + alert.informativeText = "Dev target bundle does not exist: \(devModeAppBundlePath)" + alert.addButton(withTitle: "Terminate") + alert.runModal() + NSApp.terminate(nil) + } + + return false + } + + func unzipNotarizedArchive() -> String? { + if !self.validateIfNotarizedArchiveExists() { + return nil + } + guard let notarizedArchive = notarizedArchive, + let resourcePath = Bundle.main.resourcePath else { + return nil + } + let tempFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent(UUID().uuidString) + let arguments: [String] = [notarizedArchive, "-d", tempFilePath] + let unzipTask = Process() + unzipTask.launchPath = "/usr/bin/unzip" + unzipTask.currentDirectoryPath = resourcePath + unzipTask.arguments = arguments + unzipTask.launch() + unzipTask.waitUntilExit() + + assert(unzipTask.terminationStatus == 0, "Must successfully unzipped") + guard let result = (tempFilePath as NSString).appendingPathExtension(targetAppBundleName) else { + return nil + } + assert(FileManager.default.fileExists(atPath: result), "App bundle must be unzipped at \(resourcePath).") + return result + } + + private var notarizedArchivesPath: String? { + let resourePath = Bundle.main.resourcePath + let notarizedArchivesPath = resourePath?.appending("NotarizedArchives") + return notarizedArchivesPath + } + + private var notarizedArchive: String? { + guard let notarizedArchivesPath = notarizedArchivesPath, + let bundleVersion = Bundle.main.infoDictionary?[kCFBundleVersionKey as String] as? String else { + return nil + } + let notarizedArchiveBasename = "\(appName)-r\(bundleVersion).zip" + let notarizedArchive = notarizedArchivesPath.appending(notarizedArchiveBasename) + return notarizedArchive + } + +} diff --git a/Installer/Chronosphere.h b/Installer/Chronosphere.h new file mode 100644 index 0000000000000000000000000000000000000000..0936de449812b11265266042b1eec96b31d5322f --- /dev/null +++ b/Installer/Chronosphere.h @@ -0,0 +1,17 @@ +/* + * Chronosphere.h + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +@import Cocoa; + +NS_ASSUME_NONNULL_BEGIN + +// Determines if an app is translocated by Gatekeeper to a randomized path +// See https://weblog.rogueamoeba.com/2016/06/29/sierra-and-gatekeeper-path-randomization/ +BOOL appBundleChronoshiftedToARandomizedPath(NSString *bundle); + +NS_ASSUME_NONNULL_END diff --git a/Installer/Chronosphere.m b/Installer/Chronosphere.m new file mode 100644 index 0000000000000000000000000000000000000000..cdf3f34df24fc24a9f1c95f4eed457438559d279 --- /dev/null +++ b/Installer/Chronosphere.m @@ -0,0 +1,38 @@ +/* + * Chronosphere.m + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +#import "Chronosphere.h" +#import + +BOOL appBundleChronoshiftedToARandomizedPath(NSString *bundle) +{ + const char *bundleAbsPath = [[bundle stringByExpandingTildeInPath] UTF8String]; + int entryCount = getfsstat(NULL, 0, 0); + int entrySize = sizeof(struct statfs); + struct statfs *bufs = (struct statfs *)calloc(entryCount, entrySize); + entryCount = getfsstat(bufs, entryCount * entrySize, MNT_NOWAIT); + for (int i = 0; i < entryCount; i++) { + if (!strcmp(bundleAbsPath, bufs[i].f_mntfromname)) { + free(bufs); + + // getfsstat() may return us a cached result, and so we need to get the stat of the mounted fs. + // If statfs() returns an error, the mounted fs is already gone. + struct statfs stat; + int checkResult = statfs(bundleAbsPath, &stat); + if (checkResult != 0) { + // Meaning the app's bundle is not mounted, that is it's not translocated. + // It also means that the app is not loaded. + return NO; + } + + return YES; + } + } + free(bufs); + return NO; +} diff --git a/Source/Installer/Installer-Info.plist b/Installer/Installer-Info.plist similarity index 79% rename from Source/Installer/Installer-Info.plist rename to Installer/Installer-Info.plist index 9088d5a861b6335f17c1acab931064656d769b83..4f418f3e90544ac594c7105d71d614568381eccf 100644 --- a/Source/Installer/Installer-Info.plist +++ b/Installer/Installer-Info.plist @@ -15,11 +15,13 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.1 + $(MARKETING_VERSION) CFBundleSignature MBIN CFBundleVersion - 879 + $(CURRENT_PROJECT_VERSION) + CFEULAContent + License texts used in the customized about window. LSApplicationCategoryType public.app-category.utilities LSHasLocalizedDisplayName @@ -27,7 +29,7 @@ LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright - Copyright © 2011-2012 Mengjuei Hsieh et al. + © 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project. NSMainNibFile MainMenu NSPrincipalClass diff --git a/Source/Installer/Installer-Prefix.pch b/Installer/Installer-Prefix.pch similarity index 100% rename from Source/Installer/Installer-Prefix.pch rename to Installer/Installer-Prefix.pch diff --git a/Source/Installer/NotarizedArchives/README.md b/Installer/NotarizedArchives/README.md similarity index 100% rename from Source/Installer/NotarizedArchives/README.md rename to Installer/NotarizedArchives/README.md diff --git a/Source/Installer/Base.lproj/MainMenu.xib b/Installer/Resources/Base.lproj/MainMenu.xib similarity index 30% rename from Source/Installer/Base.lproj/MainMenu.xib rename to Installer/Resources/Base.lproj/MainMenu.xib index 000f018d1b5ec76708624fbc1de78324969cd121..965dfaf3dd68a24a69c5f7f9866a4b8b0b5f2342 100644 --- a/Source/Installer/Base.lproj/MainMenu.xib +++ b/Installer/Resources/Base.lproj/MainMenu.xib @@ -1,8 +1,8 @@ - + - + @@ -15,10 +15,10 @@ - - + + - + @@ -33,7 +33,7 @@ - + @@ -52,7 +52,7 @@ - + @@ -60,78 +60,156 @@ - - - - - - - - - - - - - - - - - - - - + + - - - - - + + + + + + - + - - - - - - + + + + + + - - - + + + - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + - + - - + - + + + @@ -200,8 +303,20 @@ Gw + + + + + + + + - + + + + + diff --git a/Installer/Resources/en.lproj/InfoPlist.strings b/Installer/Resources/en.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..da19a1c27dcda84073ebdab4254cce6314905f4b --- /dev/null +++ b/Installer/Resources/en.lproj/InfoPlist.strings @@ -0,0 +1,5 @@ +/* Localized versions of Info.plist keys */ + +CFBundleName = "vChewing Installer"; +NSHumanReadableCopyright = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project."; +CFEULAContent = "Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"; diff --git a/Source/Installer/en.lproj/Localizable.strings b/Installer/Resources/en.lproj/Localizable.strings similarity index 57% rename from Source/Installer/en.lproj/Localizable.strings rename to Installer/Resources/en.lproj/Localizable.strings index b3f28f520bc66165f6bfbb0f7e4cef8271c8e5bf..fc23967c0c75433d192a0d2c52b7b027752fae54 100644 --- a/Source/Installer/en.lproj/Localizable.strings +++ b/Installer/Resources/en.lproj/Localizable.strings @@ -1,39 +1,18 @@ -/* No comment provided by engineer. */ -"%@ (for version %@)" = "%1$@ (for version %2$@)"; - -/* No comment provided by engineer. */ -"Agree and Upgrade" = "Agree and Upgrade"; - -/* No comment provided by engineer. */ +"Upgrade" = "Accept & Upgrade"; "Cancel" = "Cancel"; - -/* No comment provided by engineer. */ "Cannot activate the input method." = "Cannot activate the input method."; - -/* No comment provided by engineer. */ "Cannot copy the file to the destination." = "Cannot copy the file to the destination."; - -/* No comment provided by engineer. */ "Install Failed" = "Install Failed"; - -/* No comment provided by engineer. */ "Installation Successful" = "Installation Successful"; - -/* No comment provided by engineer. */ "OK" = "OK"; - -/* No comment provided by engineer. */ -"McBopomofo is ready to use." = "McBopomofo is ready to use."; - +"vChewing is ready to use." = "vChewing is ready to use."; "Stopping the old version. This may take up to one minute…" = "Stopping the old version. This may take up to one minute…"; "Attention" = "Attention"; -"McBopomofo is upgraded, but please log out or reboot for the new version to be fully functional." = "McBopomofo is upgraded, but please log out or reboot for the new version to be fully functional."; - +"vChewing is upgraded, but please log out or reboot for the new version to be fully functional." = "vChewing is upgraded, but please log out or reboot for the new version to be fully functional."; "Fatal Error" = "Fatal Error"; "Abort" = "Abort"; "Cannot register input source %@ at %@." = "Cannot register input source %@ at %@."; "Cannot find input source %@ after registration." = "Cannot find input source %@ after registration."; - "Warning" = "Warning"; "Input method may not be fully enabled. Please enable it through System Preferences > Keyboard > Input Sources." = "Input method may not be fully enabled. Please enable it through System Preferences > Keyboard > Input Sources."; "Continue" = "Continue"; diff --git a/Installer/Resources/en.lproj/MainMenu.strings b/Installer/Resources/en.lproj/MainMenu.strings new file mode 100644 index 0000000000000000000000000000000000000000..4a3f46d6c2316efdfb88423c6920b9bd31a5c433 --- /dev/null +++ b/Installer/Resources/en.lproj/MainMenu.strings @@ -0,0 +1,72 @@ + +/* Class = "NSMenu"; title = "AMainMenu"; ObjectID = "29"; */ +"29.title" = "AMainMenu"; + +/* Class = "NSMenuItem"; title = "vChewing Installer"; ObjectID = "56"; */ +"56.title" = "vChewing Installer"; + +/* Class = "NSMenu"; title = "vChewing Installer"; ObjectID = "57"; */ +"57.title" = "vChewing Installer"; + +/* Class = "NSMenuItem"; title = "About vChewing Installer"; ObjectID = "58"; */ +"58.title" = "About vChewing Installer"; + +/* Class = "NSMenuItem"; title = "File"; ObjectID = "83"; */ +"83.title" = "File"; + +/* Class = "NSMenu"; title = "Services"; ObjectID = "130"; */ +"130.title" = "Services"; + +/* Class = "NSMenuItem"; title = "Services"; ObjectID = "131"; */ +"131.title" = "Services"; + +/* Class = "NSMenuItem"; title = "Hide vChewing Installer"; ObjectID = "134"; */ +"134.title" = "Hide vChewing Installer"; + +/* Class = "NSMenuItem"; title = "Quit vChewing Installer"; ObjectID = "136"; */ +"136.title" = "Quit vChewing Installer"; + +/* Class = "NSMenuItem"; title = "Hide Others"; ObjectID = "145"; */ +"145.title" = "Hide Others"; + +/* Class = "NSMenuItem"; title = "Show All"; ObjectID = "150"; */ +"150.title" = "Show All"; + +/* Class = "NSWindow"; title = "vChewing Installer"; ObjectID = "371"; */ +"371.title" = "vChewing Installer"; + +/* Class = "NSButtonCell"; title = "I Accept"; ObjectID = "576"; */ +"576.title" = "I Accept"; + +/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "593"; */ +"593.title" = "Cancel"; + +/* Class = "NSTextFieldCell"; title = "3-Clause BSD License:"; ObjectID = "AVS-ih-FXM"; */ +"AVS-ih-FXM.title" = "3-Clause BSD License:"; + +/* Class = "NSTextFieldCell"; title = "vChewing for macOS"; ObjectID = "GNc-8S-1VG"; */ +"GNc-8S-1VG.title" = "vChewing for macOS"; + +/* Class = "NSTextFieldCell"; title = "version_placeholder"; ObjectID = "JRP-At-H9q"; */ +// "JRP-At-H9q.title" = "version_placeholder"; + +/* Class = "NSTextFieldCell"; title = "DISCLAIMER: The vChewing project, having no relationship of cooperation or affiliation with the OpenVanilla project, is not responsible for the phrase database shipped in the original McBopomofo project. Certain geopolitical and ideological contents, which are potentially harmful to the global spread of this software, have been removed from vChewing official phrase database."; ObjectID = "Q9M-ni-kUM"; */ +"Q9M-ni-kUM.title" = "DISCLAIMER: The vChewing project, having no relationship of cooperation or affiliation with the OpenVanilla project, is not responsible for the phrase database shipped in the original McBopomofo project. Certain geopolitical and ideological contents, which are potentially harmful to the global spread of this software, have been removed from vChewing official phrase database."; + +/* Class = "NSTextFieldCell"; title = "Derived from OpenVanilla McBopopmofo Project."; ObjectID = "QYf-Nf-hoi"; */ +"QYf-Nf-hoi.title" = "Derived from OpenVanilla McBopopmofo Project."; + +/* Class = "NSTextFieldCell"; title = "McBopomofo Engine by Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, et al.\nvChewing macOS Development Reinforced by Hiraku Wang.\nvChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "VW8-s5-Wpn"; */ +"VW8-s5-Wpn.title" = "McBopomofo Engine by Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, et al.\nvChewing macOS Development Reinforced by Hiraku Wang.\nvChewing Phrase Database Maintained by Shiki Suen."; + +/* Class = "NSTextFieldCell"; title = "Placeholder for showing copyright information."; ObjectID = "eo3-TK-0rB"; */ +// "eo3-TK-0rB.title" = "Placeholder for showing copyright information."; + +/* Class = "NSWindow"; title = "Window"; ObjectID = "gHl-Hx-eQn"; */ +"gHl-Hx-eQn.title" = "Window"; + +/* Class = "NSTextFieldCell"; title = "By installing the software, click the \"I Accept\" to the terms above:"; ObjectID = "mf8-6e-z7X"; */ +"mf8-6e-z7X.title" = "By installing the software, you must accept the terms above."; + +/* Class = "NSTextFieldCell"; title = "Stopping the old version. This may take up to one minute…"; ObjectID = "nTo-dx-qfZ"; */ +"nTo-dx-qfZ.title" = "Stopping the old version. This may take up to one minute…"; diff --git a/Installer/vChewingInstaller-Bridging-Header.h b/Installer/vChewingInstaller-Bridging-Header.h new file mode 100644 index 0000000000000000000000000000000000000000..7d400c5600460005ca45db3e48da884bc1205c40 --- /dev/null +++ b/Installer/vChewingInstaller-Bridging-Header.h @@ -0,0 +1,13 @@ +/* + * vChewingInstaller-Bridging-Header.h + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import "Chronosphere.h" diff --git a/LICENSE-CHS.txt b/LICENSE-CHS.txt new file mode 100644 index 0000000000000000000000000000000000000000..967e25b89a373cb9b2ba84362f8222705d2bde26 --- /dev/null +++ b/LICENSE-CHS.txt @@ -0,0 +1,14 @@ +vChewing macOS: 3-Clause BSD License 伯克利软件三款型授权合约 + +© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project. +小麦注音引擎研发:Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, 等。 +威注音 macOS 程式研发协力:Hiraku Wang。 +威注音词库维护:孙志贵 (Shiki Suen)。 + +该授权条款,在使用者符合以下诸条件之情形下,授予使用者使用及再散播本软件套件装原始码及二进位可执行形式之权利,无论此包装是否经改作皆然: + +1)对于本软件原始码之再散播,必须保留上述之著作权宣告、此诸条件表列,以及下述之免责声明。 +2)对于本套件二进位可执行形式之再散播,必须连带以档案以及/或者其他附于散播包装中之媒介方式,重制上述之著作权宣告、此诸条件表列,以及下述之免责声明。 +3)未获事前取得书面授权,不得使用威注音或本软件贡献者之名称,来为本软件之衍生物做任何表示支援、认可或推广、促销之行为。 + +免责声明:本软件由威注音及本软件之贡献者以现状(「as is」)提供,本软件套件装不负任何明示或默示之担保责任,包括但不限于就适售性以及特定目之之适用性为默示性担保。威注音及本软件之贡献者,无论任何条件、无论成因或任何责任主义、无论此责任为因合约关系、无过失责任主义或因非违约之侵权(包括过失或其他原因等)而起,对于任何因使用本软件套件装所产生之任何直接性、间接性、偶发性、特殊性、惩罚性或任何结果之损害(包括但不限于替代商品或劳务之购用、使用损失、资料损失、利益损失、业务中断等等),不负任何责任,即在该种使用已获事前告知可能会造成此类损害之情形下亦然。 diff --git a/LICENSE-CHT.txt b/LICENSE-CHT.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f605f19b05eef534c03e896dec7729814b9dff0 --- /dev/null +++ b/LICENSE-CHT.txt @@ -0,0 +1,14 @@ +vChewing macOS: 3-Clause BSD License 柏克萊軟體三款型授權合約 + +© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project. +小麥注音引擎研發:Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, 等。 +威注音 macOS 程式研發協力:Hiraku Wang。 +威注音詞庫維護:孫志貴 (Shiki Suen)。 + +該授權條款,在使用者符合以下諸條件之情形下,授予使用者使用及再散播本軟體套件裝原始碼及二進位可執行形式之權利,無論此包裝是否經改作皆然: + +1)對於本軟體原始碼之再散播,必須保留上述之著作權宣告、此諸條件表列,以及下述之免責聲明。 +2)對於本套件二進位可執行形式之再散播,必須連帶以檔案以及/或者其他附於散播包裝中之媒介方式,重製上述之著作權宣告、此諸條件表列,以及下述之免責聲明。 +3)未獲事前取得書面授權,不得使用威注音或本軟體貢獻者之名稱,來為本軟體之衍生物做任何表示支援、認可或推廣、促銷之行為。 + +免責聲明:本軟體由威注音及本軟體之貢獻者以現狀(「as is」)提供,本軟體套件裝不負任何明示或默示之擔保責任,包括但不限於就適售性以及特定目之之適用性為默示性擔保。威注音及本軟體之貢獻者,無論任何條件、無論成因或任何責任主義、無論此責任為因合約關係、無過失責任主義或因非違約之侵權(包括過失或其他原因等)而起,對於任何因使用本軟體套件裝所產生之任何直接性、間接性、偶發性、特殊性、懲罰性或任何結果之損害(包括但不限於替代商品或勞務之購用、使用損失、資料損失、利益損失、業務中斷等等),不負任何責任,即在該種使用已獲事前告知可能會造成此類損害之情形下亦然。 diff --git a/LICENSE-JPN.txt b/LICENSE-JPN.txt new file mode 100644 index 0000000000000000000000000000000000000000..db9eadc1561dbddf44df2f686359a953f6dc18c2 --- /dev/null +++ b/LICENSE-JPN.txt @@ -0,0 +1,14 @@ +vChewing macOS: 3-Clause BSD License 3条項BSDライセンス + +© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project. +小麦注音入力エンジン開発:Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, など。 +威注音 macOS 版の開発協力:Hiraku Wang。 +威注音語彙データの維持:孫志貴 (Shiki Suen)。 + +ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の条件を満たす場合に限り、再頒布および使用が許可されます。 + +① ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および下記免責条項を含めること。 +② バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の著作権表示、本条件一覧、および下記免責条項を含めること。 +③ 書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝または販売促進に、「威注音」の名前または諸貢献者の名前を使用してはならない。 + +本ソフトウェアは、著作権者および諸貢献者によって「現状のまま」提供されており、明示黙示を問わず、商業的な使用可能性、および特定の目的に対する適合性に関する暗黙の保証も含め、またそれに限定されない、いかなる保証もありません。著作権者も諸貢献者も、事由のいかんを問わず、 損害発生の原因いかんを問わず、かつ責任の根拠が契約であるか厳格責任であるか(過失その他の)不法行為であるかを問わず、仮にそのような損害が発生する可能性を知らされていたとしても、本ソフトウェアの使用によって発生した(代替品または代用サービスの調達、使用の喪失、データの喪失、利益の喪失、業務の中断も含め、またそれに限定されない)直接損害、間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害について、一切責任を負わないものとします。 diff --git a/LICENSE.txt b/LICENSE.txt index 44849223f8f1b487cad729853523a22f03c5730a..e7fd4b4d49423d9421f1ee1788d3f07a9bc3003e 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,21 +1,16 @@ -MIT License +vChewing macOS: 3-Clause BSD License -Copyright (c) 2011-2021 Mengjuei Hsieh et al. +© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project. +McBopomofo Engine by Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, et al. +vChewing macOS Development Reinforced by Hiraku Wang. +
vChewing Phrase Database Maintained by Shiki Suen. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8e82984e72d649bf1db8b3ea702ca17e167838e4 --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ ++.PHONY: all + +all: release +install: install-release +update: + @git restore Source/Data/ + git submodule update --init --recursive --remote --force + +ifdef ARCHS +BUILD_SETTINGS += ARCHS="$(ARCHS)" +BUILD_SETTINGS += ONLY_ACTIVE_ARCH=NO +endif + +release: + xcodebuild -project vChewing.xcodeproj -scheme vChewingInstaller -configuration Release $(BUILD_SETTINGS) build + +debug: + xcodebuild -project vChewing.xcodeproj -scheme vChewingInstaller -configuration Debug $(BUILD_SETTINGS) build + +DSTROOT = /Library/Input Methods +VC_APP_ROOT = $(DSTROOT)/vChewing.app + +.PHONY: permission-check install-debug install-release + +permission-check: + [ -w "$(DSTROOT)" ] && [ -w "$(VC_APP_ROOT)" ] || sudo chown -R ${USER} "$(DSTROOT)" + +install-debug: permission-check + open Build/Products/Debug/vChewingInstaller.app + +install-release: permission-check + open Build/Products/Release/vChewingInstaller.app + +.PHONY: clean + +clean: + xcodebuild -scheme vChewingInstaller -configuration Debug $(BUILD_SETTINGS) clean + xcodebuild -scheme vChewingInstaller -configuration Release $(BUILD_SETTINGS) clean + make clean --file=./Source/Data/Makefile || true diff --git a/Packages/SwiftyOpenCC/LICENSE b/Packages/SwiftyOpenCC/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..b02fa70ab9676d7a72255748d53d0272873a279f --- /dev/null +++ b/Packages/SwiftyOpenCC/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 DengXiang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Packages/SwiftyOpenCC/OpenCC/.gitignore b/Packages/SwiftyOpenCC/OpenCC/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..66d9a8bb8ef11cf9c75325ec75aeee4833cde8ab --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/.gitignore @@ -0,0 +1,17 @@ +*.pyc +*.tgz +.project +.cproject +/.vscode +/.mypy_cache +/build +/other +/doc/html +/dist +/opencc.xcodeproj +/test/dict.ocd +/test/dict.txt +/test/dict.bin +/xcode +/node_modules +/*.egg-info diff --git a/Packages/SwiftyOpenCC/OpenCC/AUTHORS b/Packages/SwiftyOpenCC/OpenCC/AUTHORS new file mode 100644 index 0000000000000000000000000000000000000000..52c080efdb7195a97707876bc4422684130cfc27 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/AUTHORS @@ -0,0 +1,12 @@ +Author: +Carbo Kuo + +Contributors: +Peng Huang +Kefu Chai +LI Daobing +Asias +Peng Wu +Xiaojun Ma +佛振 + diff --git a/Packages/SwiftyOpenCC/OpenCC/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d4b653096b6a9821f17500e5795bb8c88b9663b2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/CMakeLists.txt @@ -0,0 +1,230 @@ +# +# Open Chinese Convert +# +# Copyright 2010-2020 Carbo Kuo +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +######## Project settings +cmake_minimum_required(VERSION 2.8) +set (PACKAGE_NAME opencc) +project (${PACKAGE_NAME} CXX) +include (CTest) + +######## Options +option(BUILD_DOCUMENTATION "Use Doxygen to create the HTML based API documentation" OFF) +option(BUILD_SHARED_LIBS "Build opencc as shared library" ON) +option(ENABLE_GTEST "Build all tests." OFF) +option(ENABLE_BENCHMARK "Build benchmark tests." OFF) +option(ENABLE_DARTS "Build DartsDict (ocd format)." ON) +option(BUILD_PYTHON "Build python library" OFF) +option(USE_SYSTEM_DARTS "Use system version of Darts" OFF) +option(USE_SYSTEM_GOOGLE_BENCHMARK "Use system version of Google Benchmark" OFF) +option(USE_SYSTEM_GTEST "Use system version of GoogleTest" OFF) +option(USE_SYSTEM_MARISA "Use system version of Marisa" OFF) +option(USE_SYSTEM_PYBIND11 "Use system version of pybind11" OFF) +option(USE_SYSTEM_RAPIDJSON "Use system version of RapidJSON" OFF) +option(USE_SYSTEM_TCLAP "Use system version of TCLAP" OFF) + +######## Package information +set (PACKAGE_URL https://github.com/BYVoid/Opencc) +set (PACKAGE_BUGREPORT https://github.com/BYVoid/Opencc/issues) +set (OPENCC_VERSION_MAJOR 1) +set (OPENCC_VERSION_MINOR 1) +set (OPENCC_VERSION_REVISION 2) + +if (CMAKE_BUILD_TYPE MATCHES Debug) + set (version_suffix .Debug) +endif (CMAKE_BUILD_TYPE MATCHES Debug) + +set ( + OPENCC_VERSION + ${OPENCC_VERSION_MAJOR}.${OPENCC_VERSION_MINOR}.${OPENCC_VERSION_REVISION}${version_suffix} +) + +set(CPACK_SOURCE_PACKAGE_FILE_NAME + "${PACKAGE_NAME}-${OPENCC_VERSION_MAJOR}.${OPENCC_VERSION_MINOR}.${OPENCC_VERSION_REVISION}" +) +set(CPACK_SOURCE_IGNORE_FILES + "/build/;/test/dict.ocd;/test/dict.txt;/test/dict.bin;/other/;/opencc.xcodeproj/;/.git/;.gitignore;~$;.pyc;${CPACK_SOURCE_IGNORE_FILES}" +) +include(CPack) + +######## Windows + +#if (WIN32) +# set(CMAKE_SHARED_LIBRARY_PREFIX ${CMAKE_INSTALL_PREFIX}) +# set(CMAKE_STATIC_LIBRARY_PREFIX ${CMAKE_INSTALL_PREFIX}) +#endif (WIN32) + +######## Mac OS X + +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(CMAKE_MACOSX_RPATH 1) +endif() + +######## Directory + +set (DIR_PREFIX ${CMAKE_INSTALL_PREFIX}) +set (DIR_INCLUDE ${DIR_PREFIX}/include/) +set (DIR_SHARE ${DIR_PREFIX}/share/) +set (DIR_ETC ${DIR_PREFIX}/etc/) +set (DIR_LIBRARY ${DIR_PREFIX}/lib${LIB_SUFFIX}/) + +if (DEFINED SHARE_INSTALL_PREFIX) + set (DIR_SHARE ${SHARE_INSTALL_PREFIX}) +endif (DEFINED SHARE_INSTALL_PREFIX) + +if (DEFINED INCLUDE_INSTALL_DIR) + set (DIR_INCLUDE ${INCLUDE_INSTALL_DIR}) +endif (DEFINED INCLUDE_INSTALL_DIR) + +if (DEFINED SYSCONF_INSTALL_DIR) + set (DIR_ETC ${SYSCONF_INSTALL_DIR}) +endif (DEFINED SYSCONF_INSTALL_DIR) + +if (DEFINED LIB_INSTALL_DIR) + set (DIR_LIBRARY ${LIB_INSTALL_DIR}) +endif (DEFINED LIB_INSTALL_DIR) + +set (DIR_SHARE_OPENCC ${DIR_SHARE}/opencc/) +set (DIR_SHARE_LOCALE ${DIR_SHARE}/locale/) + +######## Configuration + +configure_file( + opencc.pc.in + opencc.pc + @ONLY +) + +install( + FILES + ${CMAKE_BINARY_DIR}/opencc.pc + DESTINATION + ${DIR_LIBRARY}/pkgconfig +) + +######## Compiler flags + +add_definitions( + -DPKGDATADIR="${DIR_SHARE_OPENCC}" + -DLOCALEDIR="${DIR_SHARE_LOCALE}" + -DVERSION="${OPENCC_VERSION}" + -DPACKAGE_NAME="${PACKAGE_NAME}" +) + +if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + add_definitions( + -std=c++14 + -Wall + ) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") + if (CMAKE_BUILD_TYPE MATCHES Debug) + add_definitions(-O0 -g3) + endif () +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + add_definitions( + -std=c++14 + -Wall + ) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") + if (CMAKE_BUILD_TYPE MATCHES Debug) + add_definitions(-O0 -g3) + endif () +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + add_definitions( + /W4 + /D "_CRT_SECURE_NO_WARNINGS" + ) +endif() + +if (NOT BUILD_SHARED_LIBS) + add_definitions( + -DOpencc_BUILT_AS_STATIC + ) +endif (NOT BUILD_SHARED_LIBS) + +if (ENABLE_GTEST) + add_definitions( + -DPROJECT_BINARY_DIR="${PROJECT_BINARY_DIR}" + -DCMAKE_SOURCE_DIR="${CMAKE_SOURCE_DIR}" + ) +endif() + +if (ENABLE_BENCHMARK) + add_definitions( + -DPROJECT_BINARY_DIR="${PROJECT_BINARY_DIR}" + -DCMAKE_SOURCE_DIR="${CMAKE_SOURCE_DIR}" + ) +endif() + +if (ENABLE_DARTS) + add_definitions( + -DENABLE_DARTS + ) +endif() + + +######## Dependencies + +if(NOT USE_SYSTEM_MARISA) + message(STATUS "Use bundled marisa library.") + add_subdirectory(deps/marisa-0.2.6) +else() + find_library(LIBMARISA NAMES marisa) + if (LIBMARISA) + message(STATUS "libmarisa found: ${LIBMARISA}") + else() + message(FATAL_ERROR "libmarisa not found.") + endif() +endif() + +######## Subdirectories + +add_subdirectory(src) +add_subdirectory(doc) +add_subdirectory(data) +add_subdirectory(test) + +######## Testing + +if (ENABLE_GTEST) + if(NOT USE_SYSTEM_GTEST) + add_subdirectory(deps/gtest-1.11.0) + endif() + enable_testing() +endif() + +if (ENABLE_BENCHMARK) + set(BENCHMARK_ENABLE_TESTING OFF) + if(NOT USE_SYSTEM_GOOGLE_BENCHMARK) + add_subdirectory(deps/google-benchmark) + endif() + enable_testing() +endif() + +######## Python + +if (BUILD_PYTHON) + if(USE_SYSTEM_PYBIND11) + include(pybind11Config) + include(pybind11Common) + include(pybind11Tools) + else() + add_subdirectory(deps/pybind11-2.5.0) + endif() + pybind11_add_module(opencc_clib src/py_opencc.cpp) + target_link_libraries(opencc_clib PRIVATE libopencc) +endif() diff --git a/Packages/SwiftyOpenCC/OpenCC/LICENSE b/Packages/SwiftyOpenCC/OpenCC/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..9f7a310eb2b143dfc4b73551ea60ca17eb2b981f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/LICENSE @@ -0,0 +1,56 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and + + 2. You must cause any modified files to carry prominent notices stating that You changed the files; and + + 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + diff --git a/Packages/SwiftyOpenCC/OpenCC/Makefile b/Packages/SwiftyOpenCC/OpenCC/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ff8bc89b9afb264c3f18609b3f968a657415976c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/Makefile @@ -0,0 +1,103 @@ +# +# Open Chinese Convert +# +# Copyright 2010-2020 Carbo Kuo +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +PREFIX = /usr + +.PHONY: build clean node test xcode-build + +build: + mkdir -p build/rel + (cd build/rel; cmake \ + -DBUILD_DOCUMENTATION:BOOL=ON \ + -DENABLE_GTEST:BOOL=OFF \ + -DENABLE_BENCHMARK:BOOL=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ + ../..) + make -C build/rel VERBOSE=${VERBOSE} PREFIX=${PREFIX} + +package: build + make -C build/rel package_source VERBOSE=${VERBOSE} + make -C build/rel package_source VERBOSE=${VERBOSE} PREFIX=${PREFIX} + +test: + mkdir -p build/dbg/root + (cd build/dbg; cmake \ + -DBUILD_DOCUMENTATION:BOOL=OFF \ + -DENABLE_GTEST:BOOL=ON \ + -DENABLE_BENCHMARK:BOOL=OFF \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_INSTALL_PREFIX=`pwd`/root \ + ../..) + make -C build/dbg VERBOSE=${VERBOSE} + (cd build/dbg; ctest --verbose) + make -C build/dbg install VERBOSE=${VERBOSE} + +benchmark: + mkdir -p build/perf + (cd build/perf; cmake \ + -DBUILD_DOCUMENTATION:BOOL=OFF \ + -DENABLE_GTEST:BOOL=OFF \ + -DENABLE_BENCHMARK:BOOL=ON \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_INSTALL_PREFIX=`pwd`/root \ + ../..) + make -C build/perf VERBOSE=${VERBOSE} PREFIX=${PREFIX} + (cd build/perf; ctest --verbose) + +node: + node-gyp configure + node-gyp build + +node-test: node + npm test + +xcode-build: + mkdir -p xcode + (cd xcode; cmake \ + -G "Xcode" \ + -DBUILD_DOCUMENTATION:BOOL=OFF \ + -DENABLE_GTEST:BOOL=ON \ + -DENABLE_BENCHMARK:BOOL=ON \ + ..; \ + xcodebuild build) + +python-build: + python setup.py build_ext + +python-install: python-build + python setup.py install + +python-dist: python-build + python setup.py bdist_wheel + +python-test: python-build + cd python; pytest . + +test-all: test node-test python-test + +format: + find "src" "node" "test" -iname "*.hpp" -o -iname "*.cpp" -o -iname "*.cc" \ + -o -iname "*.c" -o -iname "*.h" \ + | xargs clang-format -i + +clean: + rm -rf build xcode python/opencc/clib *.egg-info + +install: build + make -C build/rel install VERBOSE=${VERBOSE} PREFIX=${PREFIX} diff --git a/Packages/SwiftyOpenCC/OpenCC/NEWS.md b/Packages/SwiftyOpenCC/OpenCC/NEWS.md new file mode 100644 index 0000000000000000000000000000000000000000..94f06a126a8e447c1aa7dbdf3ed686b9ead0a558 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/NEWS.md @@ -0,0 +1,233 @@ +# Change History of OpenCC + +## Version 1.1.2 + +2021年3月2日 + +* 新增香港繁體轉換。 +* 根據《通用漢字規範表》修正大量簡體異體字轉換。調整臺灣標準,避免過度轉換。 +* 修正編譯兼容性問題,包括並行編譯。 +* 修正1.1.0以來引入的性能嚴重下降問題。 + +## Version 1.1.1 + +2020年5月22日 + +* 正式提供[Python](https://pypi.org/project/OpenCC/)接口和TypeScript類型標註。 +* 更新動態鏈接庫`SOVERSION`到`1.1`,由於C++內部接口發生變更。 +* 進一步改進與Windows MSVC的兼容性。 +* 簡化頭文件結構,加快編譯速度。刪除不必要的`using`。 +* 修復部分香港標準字。 + +## Version 1.1.0 + +2020年5月10日 + +* 新辭典格式`ocd2`,基於Marisa Trie 0.2.5。辭典大小大幅減少。`STPhrases.ocd`從4.3MB減少到`STPhrases.ocd2`的924KB。 +* 升級依賴的rapidjson版本到1.1.0,tclap到1.2.2,gtest到1.11.0。 +* 更改「涌/湧」的默認轉換,修正多個詞組轉換。 +* 提供Windows的預編譯版本下載(AppVeyor)。 +* 增加基準測試結果。 + +## Version 1.0.6 + +2020年4月13日 + +* 正式支持日本語新字體轉換。 +* 升級Node.js依賴,改進兼容性。 +* 修復多處多平臺編譯和兼容性問題。 +* 修正大量轉換錯誤。 + +## Version 1.0.5 + +2017年2月6日 + +* 修正Windows下CMake和Visual Studio的問題。 +* 修正FNV Hash的32位編譯警告。 +* 增加若干臺灣常用詞彙轉換和異體字轉換。 +* 增加和修正若干轉換問題。 +* 加快Node模塊編譯速度。 +* 增加Node模塊的詞典轉換接口和Promise接口。 + +## Version 1.0.4 + +2016年4月1日 + +* 使編譯時的腳本兼容Python 3。 +* 修正Visual C++ 2015的編譯問題。 +* 增補臺灣、香港地區用字用詞轉換。 +* 更新nan以修正Node.js擴展編譯兼容性問題。 + +## Version 1.0.3 + +2015年7月22日 + +* 添加化學元素臺灣用字轉換。 +* 增補100餘組缺失的簡繁轉換字對。 +* 增補香港標準字。 +* 使用nan解決Node.js擴展編譯兼容性問題。 +* 命令行轉換工具支持就地轉換。 +* 測試框架遷移到GTest。 +* 修正Visual C++的編譯問題。 +* 實現無詞典詞彙抽取和分詞算法。 +* 優化轉換性能。 + +## Version 1.0.2 + +2014年11月8日 + +* 修正C語言接口的編譯錯誤問題 +* 修正默認簡繁轉換文件名錯誤問題 +* `DictEntry`增加`Values()`方法 + +## Version 1.0.1 + +2014年10月18日 + +* 使用C++11完全重寫OpenCC +* 修復大量轉換錯誤 +* 增加香港繁體轉換 + +## Version 0.4.3 + +2013年5月17日 + +* 增加接口`opencc_convert_utf8_free` +* 修正Node.js插件內存泄漏問題 +* 修正Windows下獲取當前目錄的問題 + +## Version 0.4.2 + +2013年4月14日 + +* 修正「阪」、「薰」繁簡轉換 +* 增加四對缺失的簡繁轉換 +* 增加API文檔,由Doxygen生成 +* 重構大量代碼 + +## Version 0.4.1 + +2013年3月21日 + +* 修正Node.js 0.10兼容性問題。 +* 從Unihan數據庫增加若干缺失的簡繁轉換單字。 + +## Version 0.4.0 + +2013年3月2日 + +* 修正「雕」「谥」「峯」轉換,新增數百條臺灣科技詞彙。 +* 修正命令行-h錯誤。 +* 修正長行讀取錯誤。 +* 修正錯誤類型拼寫錯誤。 +* 修正UTF-8編碼轉換錯誤。 +* 自動跳過UTF-8的BOM。 +* 修正配置和數據文件相對路徑問題。 +* 增加了gyp編譯系統。 +* 增加了Node.js接口。 + +## Version 0.3.0 + +2011年12月2日 + +* 增加中國大陸、臺灣地區異體字和習慣用詞轉換功能。 +* 修正詞典轉換鏈爲奇數時的緩衝區複製Bug。 +* 修正Big Endian平臺上的UTF-8轉換錯誤。 +* 修正「齣」「薑」詞組的問題。 +* 修正「钁」「卷」「干」「薰」「糉」「蝨」「麺」。 +* 增加「綑」到「捆」的繁簡轉換。 +* 增加「跡」「蹟」對立。 +* 增加「夫」「伕」對立。 +* 增加「毀」「譭」「燬」對立。 +* 增加「背」「揹」對立。 + +## Version 0.2.0 + +2010年12月23日 + +* 取消libopencc對iconv的依賴。 +* 增加UTF8編碼格式錯誤時提示信息。 +* 重構Python封裝。 +* 修正讀取一行長度超過緩衝區時的UTF8截斷錯誤。 +* 使用CMake代替Autotools構建編譯框架。 +* 修正包括「拿不準」在內諸多簡繁轉換問題。 + +## Version 0.1.2 + +2010年9月16日 + +* 增加「僅分詞」和「顯示多重候選字詞」的轉換接口。 +* 改進辭典文件的結構。 +* 修正轉換緩衝區永遠不足的Bug。 +* 修正多辭典轉換時略過某個辭典的Bug。 +* 修正輸入爲空時轉換的Bug。 +* 改進opencc命令行工具參數提示和幫助。 + +## Version 0.1.1 + +2010年8月10日 + +* 增加簡繁混雜到簡體或繁體的轉換。 +* 增加多詞典/詞典組的轉換支持。 +* 修正big endian平臺上的兼容性問題。 +* 修正apple平臺下編譯iconv依賴的問題。 +* 修正辭典中詞條長度長度不相等時轉換錯誤的Bug。 +* 重構辭典代碼抽象。 +* 增加編譯時的測試。 +* 分離辭典爲字典和詞典。 + +## Version 0.1.0 + +2010年7月28日 + +* 修正文件名緩衝區不足的Bug。 +* libopencc版本更新至1.0.0。 +* 分離臺灣特有的繁簡轉換「著」「么」。 +* 修改「众」「教」「查」「污」對應默認異體。 +* 加入「齧啮」「灩滟」繁簡轉換。 +* 增加「岳嶽」一簡對多繁轉換。 +* 隱藏不必要的類型,更新接口註釋。 + +## Version 0.0.5 + +2010年7月21日 + +* 修正`wchar_t`兼容性問題,使用`ucs4`。 +* 增加Windows移植分支。 +* 修正一個文件名緩衝區分配的問題。 +* 增加「囉」「溼」「廕」「彷」「徵」繁簡轉換。 + +## Version 0.0.4 + +2010年7月16日 + +* 增加「卹」「牴」「皁」「羶」「薹」等轉換。 +* 精簡辭典中大量不必要的數詞(含「千」「萬」)。 +* 修正最短路徑分詞時優先後向匹配的實現問題。 +* 修正辭典加載兼容性問題,當無法mmap時直接申請內存。 +* 修正C++接口在64位平臺下編譯的問題。 + +## Version 0.0.3 + +2010年6月22日 + +* 加入繁體到簡體的轉換。 +* 增加提示信息的中文翻譯,使用`GNU Gettext`。 +* 增加辭典配置文件支持。 +* 修正一些兼容性Bug。 + +## Version 0.0.2 + +2010年6月19日 + +* 分離詞庫。 +* 增加平面文件詞庫讀取的支持。 +* 增加平面文件詞庫到`Datrie`詞庫的轉換工具`opencc_dict`。 +* 提供UTF8文本直接轉換的接口。 + +## Version 0.0.1 + +2010年6月11日 + +* OpenCC初始版本釋出。 +* 支持簡繁轉換。 diff --git a/Packages/SwiftyOpenCC/OpenCC/README.md b/Packages/SwiftyOpenCC/OpenCC/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4eca31bde4f66758cd41a7a814a5c4e858568944 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/README.md @@ -0,0 +1,277 @@ +# Open Chinese Convert 開放中文轉換 + +[![Travis](https://img.shields.io/travis/BYVoid/OpenCC.svg)](https://travis-ci.org/BYVoid/OpenCC) +[![AppVeyor](https://img.shields.io/appveyor/ci/Carbo/OpenCC.svg)](https://ci.appveyor.com/project/Carbo/OpenCC) +[![Python package](https://github.com/BYVoid/OpenCC/workflows/Python%20package/badge.svg?branch=master)](https://github.com/BYVoid/OpenCC/actions?query=workflow%3A%22Python+package%22) + +## Introduction 介紹 + +![OpenCC](https://opencc.byvoid.com/img/opencc.png) + +Open Chinese Convert (OpenCC, 開放中文轉換) is an opensource project for conversions between Traditional Chinese, Simplified Chinese and Japanese Kanji (Shinjitai). It supports character-level and phrase-level conversion, character variant conversion and regional idioms among Mainland China, Taiwan and Hong Kong. This is not translation tool between Mandarin and Cantonese, etc. + +中文簡繁轉換開源項目,支持詞彙級別的轉換、異體字轉換和地區習慣用詞轉換(中國大陸、臺灣、香港、日本新字體)。不提供普通話與粵語的轉換。 + +Discussion (Telegram): https://t.me/open_chinese_convert + +### Features 特點 + +* 嚴格區分「一簡對多繁」和「一簡對多異」。 +* 完全兼容異體字,可以實現動態替換。 +* 嚴格審校一簡對多繁詞條,原則爲「能分則不合」。 +* 支持中國大陸、臺灣、香港異體字和地區習慣用詞轉換,如「裏」「裡」、「鼠標」「滑鼠」。 +* 詞庫和函數庫完全分離,可以自由修改、導入、擴展。 + +## Installation 安裝 + +See [Download](https://github.com/BYVoid/OpenCC/wiki/Download). + +## Usage 使用 + +### Online demo 線上轉換展示 + +Warning: **This is NOT an API.** You will be banned if you make calls programmatically. + +https://opencc.byvoid.com/ + +### Node.js + +[npm](https://www.npmjs.com/opencc) `npm install opencc` + +#### JavaScript +```js +const OpenCC = require('opencc'); +const converter = new OpenCC('s2t.json'); +converter.convertPromise("汉字").then(converted => { + console.log(converted); // 漢字 +}); +``` + +#### TypeScript +```ts +import { OpenCC } from 'opencc'; +async function main() { + const converter: OpenCC = new OpenCC('s2t.json'); + const result: string = await converter.convertPromise('汉字'); + console.log(result); +} +``` + +See [demo.js](https://github.com/BYVoid/OpenCC/blob/master/node/demo.js) and [ts-demo.ts](https://github.com/BYVoid/OpenCC/blob/master/node/ts-demo.ts). + +### Python + +[PyPI](https://pypi.org/project/OpenCC/) `pip install opencc` (Windows, Linux, Mac) + +```python +import opencc +converter = opencc.OpenCC('s2t.json') +converter.convert('汉字') # 漢字 +``` + +### C++ + +```c++ +#include "opencc.h" + +int main() { + const SimpleConverter converter("s2t.json"); + converter.Convert("汉字"); // 漢字 + return 0; +} +``` + +### C + +```c +#include "opencc.h" + +int main() { + opencc_t opencc = opencc_open("s2t.json"); + const char* input = "汉字"; + char* converted = opencc_convert_utf8(opencc, input, strlen(input)); // 漢字 + opencc_convert_utf8_free(converted); + opencc_close(opencc); + return 0; +} + +``` + +Document 文檔: https://byvoid.github.io/OpenCC/ + +### Command Line + +* `opencc --help` +* `opencc_dict --help` +* `opencc_phrase_extract --help` + +### Others (Unofficial) + +* Swift (iOS): [SwiftyOpenCC](https://github.com/XQS6LB3A/SwiftyOpenCC) +* Java: [opencc4j](https://github.com/houbb/opencc4j) +* Android: [android-opencc](https://github.com/qichuan/android-opencc) +* PHP: [opencc4php](https://github.com/nauxliu/opencc4php) +* Pure JavaScript: [opencc-js](https://github.com/nk2028/opencc-js) +* WebAssembly: [wasm-opencc](https://github.com/oyyd/wasm-opencc) + +### Configurations 配置文件 + +#### 預設配置文件 + +* `s2t.json` Simplified Chinese to Traditional Chinese 簡體到繁體 +* `t2s.json` Traditional Chinese to Simplified Chinese 繁體到簡體 +* `s2tw.json` Simplified Chinese to Traditional Chinese (Taiwan Standard) 簡體到臺灣正體 +* `tw2s.json` Traditional Chinese (Taiwan Standard) to Simplified Chinese 臺灣正體到簡體 +* `s2hk.json` Simplified Chinese to Traditional Chinese (Hong Kong variant) 簡體到香港繁體 +* `hk2s.json` Traditional Chinese (Hong Kong variant) to Simplified Chinese 香港繁體到簡體 +* `s2twp.json` Simplified Chinese to Traditional Chinese (Taiwan Standard) with Taiwanese idiom 簡體到繁體(臺灣正體標準)並轉換爲臺灣常用詞彙 +* `tw2sp.json` Traditional Chinese (Taiwan Standard) to Simplified Chinese with Mainland Chinese idiom 繁體(臺灣正體標準)到簡體並轉換爲中國大陸常用詞彙 +* `t2tw.json` Traditional Chinese (OpenCC Standard) to Taiwan Standard 繁體(OpenCC 標準)到臺灣正體 +* `hk2t.json` Traditional Chinese (Hong Kong variant) to Traditional Chinese 香港繁體到繁體(OpenCC 標準) +* `t2hk.json` Traditional Chinese (OpenCC Standard) to Hong Kong variant 繁體(OpenCC 標準)到香港繁體 +* `t2jp.json` Traditional Chinese Characters (Kyūjitai) to New Japanese Kanji (Shinjitai) 繁體(OpenCC 標準,舊字體)到日文新字體 +* `jp2t.json` New Japanese Kanji (Shinjitai) to Traditional Chinese Characters (Kyūjitai) 日文新字體到繁體(OpenCC 標準,舊字體) +* `tw2t.json` Traditional Chinese (Taiwan standard) to Traditional Chinese 臺灣正體到繁體(OpenCC 標準) + +## Build 編譯 + +### Build with CMake + +#### Linux & Mac OS X + +g++ 4.6+ or clang 3.2+ is required. + +```bash +make +``` + +#### Windows Visual Studio: + +```bash +build.cmd +``` + +### Test 測試 + +#### Linux & Mac OS X + +``` +make test +``` + +#### Windows Visual Studio: + +```bash +test.cmd +``` + +### Benchmark 基準測試 + +``` +make benchmark +``` + +Example results (from Github CI): + +``` +1: ------------------------------------------------------------------ +1: Benchmark Time CPU Iterations +1: ------------------------------------------------------------------ +1: BM_Initialization/hk2s 1.56 ms 1.56 ms 442 +1: BM_Initialization/hk2t 0.144 ms 0.144 ms 4878 +1: BM_Initialization/jp2t 0.260 ms 0.260 ms 2604 +1: BM_Initialization/s2hk 23.8 ms 23.8 ms 29 +1: BM_Initialization/s2t 25.6 ms 25.6 ms 28 +1: BM_Initialization/s2tw 24.0 ms 23.9 ms 30 +1: BM_Initialization/s2twp 24.6 ms 24.6 ms 28 +1: BM_Initialization/t2hk 0.052 ms 0.052 ms 12897 +1: BM_Initialization/t2jp 0.141 ms 0.141 ms 5012 +1: BM_Initialization/t2s 1.30 ms 1.30 ms 540 +1: BM_Initialization/tw2s 1.39 ms 1.39 ms 529 +1: BM_Initialization/tw2sp 1.69 ms 1.69 ms 426 +1: BM_Initialization/tw2t 0.089 ms 0.089 ms 7707 +1: BM_Convert2M 582 ms 582 ms 1 +1: BM_Convert/100 1.07 ms 1.07 ms 636 +1: BM_Convert/1000 11.0 ms 11.0 ms 67 +1: BM_Convert/10000 113 ms 113 ms 6 +1: BM_Convert/100000 1176 ms 1176 ms 1 +``` + +## Projects using OpenCC 使用 OpenCC 的項目 + +* [ibus-pinyin](https://github.com/ibus/ibus-pinyin) +* [fcitx](https://github.com/fcitx/fcitx) +* [rimeime](https://rime.im/) +* [libgooglepinyin](http://code.google.com/p/libgooglepinyin/) +* [ibus-libpinyin](https://github.com/libpinyin/ibus-libpinyin) +* [alfred-chinese-converter](https://github.com/amowu/alfred-chinese-converter) +* [GoldenDict](https://github.com/goldendict/goldendict) + +## License 許可協議 + +Apache License 2.0 + +## Third Party Library 第三方庫 + +* [darts-clone](https://github.com/s-yata/darts-clone) BSD License +* [marisa-trie](https://github.com/s-yata/marisa-trie) BSD License +* [tclap](http://tclap.sourceforge.net/) MIT License +* [rapidjson](https://github.com/Tencent/rapidjson) MIT License +* [Google Test](https://github.com/google/googletest) BSD License + +All these libraries are statically linked by default. + +## Change History 版本歷史 + +* [NEWS](https://github.com/BYVoid/OpenCC/blob/master/NEWS.md) + +### Links 相關鏈接 + +* Introduction 詳細介紹 https://github.com/BYVoid/OpenCC/wiki/%E7%B7%A3%E7%94%B1 +* 現代漢語常用簡繁一對多字義辨析表 http://ytenx.org/byohlyuk/KienxPyan + +## Contributors 貢獻者 + +* [BYVoid](http://www.byvoid.com/) +* [佛振](https://github.com/lotem) +* [Peng Huang](https://github.com/phuang) +* [LI Daobing](https://github.com/lidaobing) +* [Kefu Chai](https://github.com/tchaikov) +* [Kan-Ru Chen](http://kanru.info/) +* [Ma Xiaojun](https://twitter.com/damage3025) +* [Jiang Jiang](http://jjgod.org/) +* [Ruey-Cheng Chen](https://github.com/rueycheng) +* [Paul Meng](http://home.mno2.org/) +* [Lawrence Lau](https://github.com/ktslwy) +* [瑾昀](https://github.com/kunki) +* [內木一郎](https://github.com/SyaoranHinata) +* [Marguerite Su](https://www.marguerite.su/) +* [Brian White](http://mscdex.net) +* [Qijiang Fan](https://fqj.me/) +* [LEOYoon-Tsaw](https://github.com/LEOYoon-Tsaw) +* [Steven Yao](https://github.com/stevenyao) +* [Pellaeon Lin](https://github.com/pellaeon) +* [stony](https://github.com/stony-shixz) +* [steelywing](https://github.com/steelywing) +* [吕旭东](https://github.com/lvxudong) +* [Weng Xuetian](https://github.com/wengxt) +* [Ma Tao](https://github.com/iwater) +* [Heinz Wiesinger](https://github.com/pprkut) +* [J.W](https://github.com/jakwings) +* [Amo Wu](https://github.com/amowu) +* [Mark Tsai](https://github.com/mxgit1090) +* [Zhe Wang](https://github.com/0x1997) +* [sgqy](https://github.com/sgqy) +* [Qichuan (Sean) ZHANG](https://github.com/qichuan) +* [Flandre Scarlet](https://github.com/XadillaX) +* [宋辰文](https://github.com/songchenwen) +* [iwater](https://github.com/iwater) +* [Xpol Wan](https://github.com/xpol) +* [Weihang Lo](https://github.com/weihanglo) +* [Cychih](https://github.com/pi314) +* [kyleskimo](https://github.com/kyleskimo) +* [Ryuan Choi](https://github.com/bunhere) +* [Tony Able](https://github.com/TonyAble) +* [Xiao Liang](https://github.com/yxliang01) + +Please update this list you have contributed OpenCC. diff --git a/Packages/SwiftyOpenCC/OpenCC/binding.gyp b/Packages/SwiftyOpenCC/OpenCC/binding.gyp new file mode 100644 index 0000000000000000000000000000000000000000..ccc7a0fa6409b22fc3312a6ce7a51188b886fcc9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/binding.gyp @@ -0,0 +1,8 @@ +{ + "includes": [ + "node/global.gypi", + "node/configs.gypi", + "node/dicts.gypi", + "node/node_opencc.gypi", + ] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/build.cmd b/Packages/SwiftyOpenCC/OpenCC/build.cmd new file mode 100644 index 0000000000000000000000000000000000000000..d627a48d7bd8732b6998c8dc1d6f9409984cd558 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/build.cmd @@ -0,0 +1,2 @@ +cmake -S. -Bbuild -DCMAKE_INSTALL_PREFIX:PATH=. +cmake --build build --config Release --target install diff --git a/Packages/SwiftyOpenCC/OpenCC/data/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/data/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9b921f508f4450ea910e1b61163fc012969ed03 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/CMakeLists.txt @@ -0,0 +1,186 @@ +find_package(PythonInterp REQUIRED) + +set(OPENCC_DICT_BIN opencc_dict) +set(DICT_MERGE_BIN "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/merge.py") +set(DICT_REVERSE_BIN "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/reverse.py") +set(DICT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/dictionary) +set(DICT_GENERATED_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +set( + DICTS_RAW + STCharacters + STPhrases + TSCharacters + TSPhrases + TWVariants + TWVariantsRevPhrases + HKVariants + HKVariantsRevPhrases + JPVariants + JPShinjitaiCharacters + JPShinjitaiPhrases +) + +set( + DICTS_GENERATED + TWPhrases + TWPhrasesRev + TWVariantsRev + HKVariantsRev + JPVariantsRev +) + +set(DICTS ${DICTS_RAW} ${DICTS_GENERATED}) + +foreach(DICT ${DICTS}) + set(DICT_TARGETS ${DICT_TARGETS} ${DICT}.ocd2) +endforeach(DICT) + +add_custom_target( + Dictionaries + ALL + DEPENDS + ${DICT_TARGETS} +) + +foreach(DICT ${DICTS_RAW}) + set(DICT_${DICT}_INPUT ${DICT_DIR}/${DICT}.txt) +endforeach(DICT) + +foreach(DICT ${DICTS_GENERATED}) + set(DICT_${DICT}_INPUT ${DICT_GENERATED_DIR}/${DICT}.txt) +endforeach(DICT) + +set( + DICT_TWPhrases_GENERATING_INPUT + ${DICT_DIR}/TWPhrasesIT.txt + ${DICT_DIR}/TWPhrasesName.txt + ${DICT_DIR}/TWPhrasesOther.txt +) +set( + DICT_TWPhrases_GENERATING_COMMAND + ${DICT_MERGE_BIN} ${DICT_TWPhrases_GENERATING_INPUT} TWPhrases.txt +) + +set( + DICT_TWVariantsRev_GENERATING_INPUT + ${DICT_DIR}/TWVariants.txt +) +set( + DICT_TWVariantsRev_GENERATING_COMMAND + ${DICT_REVERSE_BIN} ${DICT_TWVariantsRev_GENERATING_INPUT} TWVariantsRev.txt +) + +set( + DICT_TWPhrasesRev_GENERATING_INPUT + ${DICT_GENERATED_DIR}/TWPhrases.txt +) +set( + DICT_TWPhrasesRev_GENERATING_COMMAND + ${DICT_REVERSE_BIN} ${DICT_TWPhrasesRev_GENERATING_INPUT} TWPhrasesRev.txt +) + +set( + DICT_HKVariantsRev_GENERATING_INPUT + ${DICT_DIR}/HKVariants.txt +) +set( + DICT_HKVariantsRev_GENERATING_COMMAND + ${DICT_REVERSE_BIN} ${DICT_HKVariantsRev_GENERATING_INPUT} HKVariantsRev.txt +) + +set( + DICT_JPVariantsRev_GENERATING_INPUT + ${DICT_DIR}/JPVariants.txt +) +set( + DICT_JPVariantsRev_GENERATING_COMMAND + ${DICT_REVERSE_BIN} ${DICT_JPVariantsRev_GENERATING_INPUT} JPVariantsRev.txt +) + +foreach(DICT ${DICTS_GENERATED}) + add_custom_command( + OUTPUT + ${DICT}.txt + COMMENT + "Generating ${DICT}.txt" + COMMAND + ${DICT_${DICT}_GENERATING_COMMAND} + DEPENDS + ${DICT_${DICT}_GENERATING_INPUT} + ) + set_directory_properties( + PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES + "${DICT_GENERATED_DIR}/${DICT}.txt" + ) +endforeach(DICT) + +add_custom_target( + copy_libopencc_to_dir_of_opencc_dict + COMMENT + "Copying libopencc to directory of opencc_dict" + COMMAND + ${CMAKE_COMMAND} -E copy "$" "$" +) +if (WIN32) + set(DICT_WIN32_DEPENDS copy_libopencc_to_dir_of_opencc_dict) +else() + set(DICT_WIN32_DEPENDS) +endif() + +foreach(DICT ${DICTS}) + add_custom_command( + OUTPUT + ${DICT}.ocd2 + COMMENT + "Building ${DICT}.ocd2" + COMMAND + ${OPENCC_DICT_BIN} + --input ${DICT_${DICT}_INPUT} + --output ${DICT}.ocd2 + --from text + --to ocd2 + DEPENDS + ${DICT_WIN32_DEPENDS} + ${OPENCC_DICT_BIN} + ${DICT_${DICT}_INPUT} + ) + + install( + FILES + ${DICT_GENERATED_DIR}/${DICT}.ocd2 + DESTINATION + ${DIR_SHARE_OPENCC} + ) + + set_directory_properties( + PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES + "${DICT_GENERATED_DIR}/${DICT}.ocd2" + ) +endforeach(DICT) + +set(CONFIG_FILES + config/hk2s.json + config/hk2t.json + config/jp2t.json + config/s2hk.json + config/s2t.json + config/s2tw.json + config/s2twp.json + config/t2hk.json + config/t2jp.json + config/t2s.json + config/t2tw.json + config/tw2s.json + config/tw2sp.json + config/tw2t.json +) + +install( + FILES + ${CONFIG_FILES} + DESTINATION + ${DIR_SHARE_OPENCC} +) diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/hk2s.json b/Packages/SwiftyOpenCC/OpenCC/data/config/hk2s.json new file mode 100644 index 0000000000000000000000000000000000000000..cf0e9b975c6562979b91653ce4b0a2d072905a00 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/hk2s.json @@ -0,0 +1,33 @@ +{ + "name": "Traditional Chinese (Hong Kong variant) to Simplified Chinese", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "TSPhrases.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "HKVariantsRevPhrases.ocd2" + }, { + "type": "ocd2", + "file": "HKVariantsRev.ocd2" + }] + } + }, { + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "TSPhrases.ocd2" + }, { + "type": "ocd2", + "file": "TSCharacters.ocd2" + }] + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/hk2t.json b/Packages/SwiftyOpenCC/OpenCC/data/config/hk2t.json new file mode 100644 index 0000000000000000000000000000000000000000..0d47b91745d8728c62793d3563e685e5f4a0f61d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/hk2t.json @@ -0,0 +1,22 @@ +{ + "name": "Traditional Chinese (Hong Kong variant) to Traditional Chinese", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "HKVariantsRevPhrases.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "HKVariantsRevPhrases.ocd2" + }, { + "type": "ocd2", + "file": "HKVariantsRev.ocd2" + }] + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/jp2t.json b/Packages/SwiftyOpenCC/OpenCC/data/config/jp2t.json new file mode 100644 index 0000000000000000000000000000000000000000..025d891975b09a987a18faefa513609d0a134993 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/jp2t.json @@ -0,0 +1,25 @@ +{ + "name": "New Japanese Kanji (Shinjitai) to Traditional Chinese Characters (Kyūjitai)", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "JPShinjitaiPhrases.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "JPShinjitaiPhrases.ocd2" + }, { + "type": "ocd2", + "file": "JPShinjitaiCharacters.ocd2" + }, { + "type": "ocd2", + "file": "JPVariantsRev.ocd2" + }] + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/s2hk.json b/Packages/SwiftyOpenCC/OpenCC/data/config/s2hk.json new file mode 100644 index 0000000000000000000000000000000000000000..fcaa017eeee74dac3ea50f752e36eb2a59e88f63 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/s2hk.json @@ -0,0 +1,27 @@ +{ + "name": "Simplified Chinese to Traditional Chinese (Hong Kong variant)", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "STPhrases.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "STPhrases.ocd2" + }, { + "type": "ocd2", + "file": "STCharacters.ocd2" + }] + } + }, { + "dict": { + "type": "ocd2", + "file": "HKVariants.ocd2" + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/s2t.json b/Packages/SwiftyOpenCC/OpenCC/data/config/s2t.json new file mode 100644 index 0000000000000000000000000000000000000000..87516acbdd37cbe76de2c24eea918611d22f9b4d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/s2t.json @@ -0,0 +1,22 @@ +{ + "name": "Simplified Chinese to Traditional Chinese", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "STPhrases.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "STPhrases.ocd2" + }, { + "type": "ocd2", + "file": "STCharacters.ocd2" + }] + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/s2tw.json b/Packages/SwiftyOpenCC/OpenCC/data/config/s2tw.json new file mode 100644 index 0000000000000000000000000000000000000000..2a3d7656beea964cae33d272badc5ed69e494beb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/s2tw.json @@ -0,0 +1,27 @@ +{ + "name": "Simplified Chinese to Traditional Chinese (Taiwan standard)", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "STPhrases.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "STPhrases.ocd2" + }, { + "type": "ocd2", + "file": "STCharacters.ocd2" + }] + } + }, { + "dict": { + "type": "ocd2", + "file": "TWVariants.ocd2" + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/s2twp.json b/Packages/SwiftyOpenCC/OpenCC/data/config/s2twp.json new file mode 100644 index 0000000000000000000000000000000000000000..2f36e9352c8ff8ded5cb9143edd6177fab3f926a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/s2twp.json @@ -0,0 +1,32 @@ +{ + "name": "Simplified Chinese to Traditional Chinese (Taiwan standard, with phrases)", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "STPhrases.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "STPhrases.ocd2" + }, { + "type": "ocd2", + "file": "STCharacters.ocd2" + }] + } + }, { + "dict": { + "type": "ocd2", + "file": "TWPhrases.ocd2" + } + }, { + "dict": { + "type": "ocd2", + "file": "TWVariants.ocd2" + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/t2hk.json b/Packages/SwiftyOpenCC/OpenCC/data/config/t2hk.json new file mode 100644 index 0000000000000000000000000000000000000000..519d4a3fd7ac66810999b65ed04fc2ccc6daa08b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/t2hk.json @@ -0,0 +1,16 @@ +{ + "name": "Traditional Chinese to Traditional Chinese (Hong Kong variant)", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "HKVariants.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "ocd2", + "file": "HKVariants.ocd2" + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/t2jp.json b/Packages/SwiftyOpenCC/OpenCC/data/config/t2jp.json new file mode 100644 index 0000000000000000000000000000000000000000..7a43217ffcdd920d5fe189275aa35cfbb074dd59 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/t2jp.json @@ -0,0 +1,16 @@ +{ + "name": "Traditional Chinese Characters (Kyūjitai) to New Japanese Kanji (Shinjitai)", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "JPVariants.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "ocd2", + "file": "JPVariants.ocd2" + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/t2s.json b/Packages/SwiftyOpenCC/OpenCC/data/config/t2s.json new file mode 100644 index 0000000000000000000000000000000000000000..06cf5f58e98ee4d55d22bc4ef00d9f2f5dc9fa75 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/t2s.json @@ -0,0 +1,22 @@ +{ + "name": "Traditional Chinese to Simplified Chinese", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "TSPhrases.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "TSPhrases.ocd2" + }, { + "type": "ocd2", + "file": "TSCharacters.ocd2" + }] + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/t2tw.json b/Packages/SwiftyOpenCC/OpenCC/data/config/t2tw.json new file mode 100644 index 0000000000000000000000000000000000000000..0394f600d97ebbe569b30efe4d47267e850eaba8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/t2tw.json @@ -0,0 +1,16 @@ +{ + "name": "Traditional Chinese to Traditional Chinese (Taiwan standard)", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "TWVariants.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "ocd2", + "file": "TWVariants.ocd2" + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/tw2s.json b/Packages/SwiftyOpenCC/OpenCC/data/config/tw2s.json new file mode 100644 index 0000000000000000000000000000000000000000..4f554393ecd914e38aa13926226eb97bce61102b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/tw2s.json @@ -0,0 +1,33 @@ +{ + "name": "Traditional Chinese (Taiwan standard) to Simplified Chinese", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "TSPhrases.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "TWVariantsRevPhrases.ocd2" + }, { + "type": "ocd2", + "file": "TWVariantsRev.ocd2" + }] + } + }, { + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "TSPhrases.ocd2" + }, { + "type": "ocd2", + "file": "TSCharacters.ocd2" + }] + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/tw2sp.json b/Packages/SwiftyOpenCC/OpenCC/data/config/tw2sp.json new file mode 100644 index 0000000000000000000000000000000000000000..64eb9d97796730d3c1f4065704e39159a1932b36 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/tw2sp.json @@ -0,0 +1,36 @@ +{ + "name": "Traditional Chinese (Taiwan standard) to Simplified Chinese (with phrases)", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "TSPhrases.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "TWPhrasesRev.ocd2" + }, { + "type": "ocd2", + "file": "TWVariantsRevPhrases.ocd2" + }, { + "type": "ocd2", + "file": "TWVariantsRev.ocd2" + }] + } + }, { + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "TSPhrases.ocd2" + }, { + "type": "ocd2", + "file": "TSCharacters.ocd2" + }] + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/config/tw2t.json b/Packages/SwiftyOpenCC/OpenCC/data/config/tw2t.json new file mode 100644 index 0000000000000000000000000000000000000000..ad5295b6544abc1a17387db67fab68646650f9af --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/config/tw2t.json @@ -0,0 +1,22 @@ +{ + "name": "Traditional Chinese (Taiwan standard) to Traditional Chinese", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "ocd2", + "file": "TWVariantsRevPhrases.ocd2" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "ocd2", + "file": "TWVariantsRevPhrases.ocd2" + }, { + "type": "ocd2", + "file": "TWVariantsRev.ocd2" + }] + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/HKVariants.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/HKVariants.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0f688135ff60536e84093754bf72310c2ef0308 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/HKVariants.txt @@ -0,0 +1,63 @@ +僞 偽 +兌 兑 +叄 叁 +只 只 衹 +啓 啓 啟 +喫 吃 +囪 囱 +妝 妝 粧 +媼 媪 +嬀 媯 +悅 悦 +慍 愠 +戶 户 +挩 捝 +搵 揾 +擡 抬 +敓 敚 +敘 敍 敘 +柺 枴 +梲 棁 +棱 稜 棱 +榲 榅 +檯 枱 +氳 氲 +涗 涚 +溫 温 +溼 濕 +潙 溈 +潨 潀 +熅 煴 +爲 為 +癡 痴 +皁 皂 +祕 秘 +稅 税 +竈 灶 +糉 粽 糉 糭 +縕 緼 +纔 才 +脣 唇 +脫 脱 +膃 腽 +臥 卧 +臺 台 +菸 煙 +蒕 蒀 +蔥 葱 +蔿 蒍 +蘊 藴 +蛻 蜕 +衆 眾 +衛 衞 +覈 核 +說 説 +踊 踴 +轀 輼 +醞 醖 +鉢 缽 +鉤 鈎 +銳 鋭 +鍼 針 +閱 閲 +鰮 鰛 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/HKVariantsRevPhrases.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/HKVariantsRevPhrases.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f03fd89710e985b4e7c021994d64b327720cef6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/HKVariantsRevPhrases.txt @@ -0,0 +1,156 @@ +一口吃個 一口喫個 +一口吃成 一口喫成 +一家三口 一家三口 +一家五口 一家五口 +一家六口 一家六口 +一家四口 一家四口 +七星巖 七星巖 +世胄 世胄 +介胄 介冑 +傅巖 傅巖 +免胄 免冑 +冠胄 冠冑 +千巖競秀 千巖競秀 +千巖萬壑 千巖萬壑 +千巖萬谷 千巖萬谷 +口吃 口吃 +台山 台山 +台州 台州 +台州地區 台州地區 +台州市 台州市 +吃口 喫口 吃口 +吃口令 吃口令 +吃口飯 喫口飯 +吃吃 喫喫 吃吃 +吃子 喫子 吃子 +名胄 名胄 +國胄 國胄 +圍巖 圍巖 +地胄 地胄 +壓胄子 壓冑子 +士胄 士胄 +大巖桐 大巖桐 +天台女 天台女 +天台宗 天台宗 +天台山 天台山 +天台縣 天台縣 +天潢貴胄 天潢貴胄 +奇巖 奇巖 +寶胄 寶胄 +小巖洞 小巖洞 +岫巖縣 岫巖縣 +峯巖 峯巖 +嵌巖 嵌巖 +巉巖 巉巖 +巖壁 巖壁 +巖居 巖居 +巖居穴處 巖居穴處 +巖居谷飲 巖居谷飲 +巖岸 巖岸 +巖巉 巖巉 +巖巖 巖巖 +巖徼 巖徼 +巖手縣 巖手縣 +巖村 巖村 +巖洞 巖洞 +巖流圈 巖流圈 +巖牆 巖牆 +巖牆之下 巖牆之下 +巖畫 巖畫 +巖穴 巖穴 +巖穴之士 巖穴之士 +巖薔薇 巖薔薇 +巖邑 巖邑 +巖郎 巖郎 +巖阻 巖阻 +巖陛 巖陛 +帝胄 帝胄 +幽巖 幽巖 +幽棲巖谷 幽棲巖谷 +張口 張口 +懸巖 懸巖 +懸巖峭壁 懸巖峭壁 +懸胄 懸冑 +攀巖 攀巖 +支胄 支胄 +教胄 教胄 +景胄 景胄 +望胄 望胄 +末胄 末胄 +村胄 村胄 +枕巖漱流 枕巖漱流 +枝胄 枝胄 +氏胄 氏胄 +洪胄 洪胄 +浙江天台縣 浙江天台縣 +清胄 清胄 +灰巖殘丘 灰巖殘丘 +玄胄 玄胄 +甲胄 甲冑 +甲胄魚類 甲冑魚類 +皇胄 皇胄 +石灰巖洞 石灰巖洞 +神胄 神胄 +簪纓世胄 簪纓世胄 +系胄 系胄 +紅巖 紅巖 +絕巖 絕巖 +緒胄 緒胄 +纂胄 纂胄 +胃口 胃口 +胄嗣 胄嗣 +胄子 胄子 +胄序 胄序 +胄族 胄族 +胄甲 冑甲 +胄監 胄監 +胄科 冑科 +胄緒 胄緒 +胄胤 胄胤 +胄裔 胄裔 +胄裔繁衍 胄裔繁衍 +胄閥 胄閥 +胡雪巖 胡雪巖 +胤胄 胤胄 +苗胄 苗胄 +英胄 英胄 +華胄 華胄 +血胄 血胄 +裔胄 裔胄 +訓胄 訓胄 +試胄 試胄 +豪門貴胄 豪門貴胄 +貝胄 貝冑 +貴胄 貴胄 +賢胄 賢胄 +蹇吃 蹇吃 +躬擐甲胄 躬擐甲冑 +遐胄 遐胄 +遙胄 遙胄 +遙遙華胄 遙遙華胄 +遠胄 遠胄 +遺胄 遺胄 +鄧艾吃 鄧艾吃 +重巖疊嶂 重巖疊嶂 +金胄 金胄 +鎧胄 鎧冑 +鑿巖 鑿巖 +門胄 門胄 +開口 開口 +雲巖區 雲巖區 +非層巖 非層巖 +韓侂胄 韓侂冑 +飮胄 飮冑 +骨巖巖 骨巖巖 +高胄 高胄 +魚胄 魚冑 +鮮胄 鮮胄 +鴻胄 鴻胄 +黃巖區 黃巖區 +黃巖島 黃巖島 +黃炎貴胄 黃炎貴胄 +齒胄 齒胄 +龍巖 龍巖 +龍巖市 龍巖市 +龍巖村 龍巖村 +龍胄 龍胄 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/JPShinjitaiCharacters.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/JPShinjitaiCharacters.txt new file mode 100644 index 0000000000000000000000000000000000000000..4dd885faec9c11a6997196c5bf687c3a721a36c6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/JPShinjitaiCharacters.txt @@ -0,0 +1,6 @@ +両 兩 輛 +弁 辨 辯 瓣 辦 弁 +御 御 禦 +欠 缺 欠 +糸 絲 糸 +芸 藝 芸 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/JPShinjitaiPhrases.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/JPShinjitaiPhrases.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a85c886758878b1d8360e79cd43aebcae613e4a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/JPShinjitaiPhrases.txt @@ -0,0 +1,176 @@ +一獲千金 一攫千金 +丁寧 叮嚀 +丁重 鄭重 +三差路 三叉路 +世論 輿論 +亜鈴 啞鈴 +交差 交叉 +供宴 饗宴 +俊馬 駿馬 +保塁 堡壘 +個条書 箇条書 +偏平 扁平 +停泊 碇泊 +優俊 優駿 +先兵 尖兵 +先鋭 尖鋭 +共役 共軛 +冗舌 饒舌 +凶器 兇器 +削岩 鑿岩 +包丁 庖丁 +包帯 繃帯 +区画 區劃 +厳然 儼然 +友宜 友誼 +反乱 叛乱 +収集 蒐集 +叙情 抒情 +台頭 擡頭 +合弁 合辦 +喜遊曲 嬉遊曲 +嘆願 歎願 +回転 廻転 +回遊 回游 +奉持 捧持 +委縮 萎縮 +展転 輾轉 +希少 稀少 +幻惑 眩惑 +広範 廣汎 +広野 曠野 +廃虚 廢墟 +建坪率 建蔽率 +弁当 辨當 +弁膜 瓣膜 +弁護 辯護 +弁髪 辮髮 +弦歌 絃歌 +恩義 恩誼 +意向 意嚮 +慰謝料 慰藉料 +憶断 臆断 +憶病 臆病 +戦没 戰歿 +扇情 煽情 +手帳 手帖 +技量 伎倆 +抜粋 抜萃 +披歴 披瀝 +抵触 牴触 +抽選 抽籤 +拘引 勾引 +拠出 醵出 +拠金 醵金 +掘削 掘鑿 +控除 扣除 +援護 掩護 +放棄 抛棄 +散水 撒水 +敬謙 敬虔 +敷延 敷衍 +断固 断乎 +族生 簇生 +昇叙 陞敘 +暖房 煖房 +暗唱 暗誦 +暗夜 闇夜 +暴露 曝露 +枯渇 涸渇 +格好 恰好 +格幅 恰幅 +棄損 毀損 +模索 摸索 +橋頭保 橋頭堡 +欠缺 欠缺 +死体 屍體 +殿部 臀部 +母指 拇指 +気迫 気魄 +決別 訣別 +決壊 決潰 +沈殿 沈澱 +油送船 油槽船 +波乱 波瀾 +注釈 註釋 +洗浄 洗滌 洗浄 +活発 活潑 +浸透 滲透 +浸食 浸蝕 +消却 銷卻 +混然 渾然 +湾曲 彎曲 +溶接 熔接 +漁労 漁撈 +漂然 飄然 +激高 激昂 +火炎 火焰 +焦燥 焦躁 +班点 斑点 +留飲 溜飲 +略奪 掠奪 +疎通 疏通 +発酵 醱酵 +白亜 白堊 +相克 相剋 +知恵 智慧 +破棄 破毀 +確固 確乎 +禁固 禁錮 +符丁 符牒 +粉装 扮装 +紫班 紫斑 +終息 終熄 +総合 綜合 +編集 編輯 +義援 義捐 +耕運機 耕耘機 +肝心 肝腎 +肩甲骨 肩胛骨 +背徳 悖德 +脈拍 脈搏 +膨張 膨脹 +芳純 芳醇 +英知 叡智 +蒸留 蒸溜 +薫蒸 燻蒸 +薫製 燻製 +衣装 衣裳 +衰退 衰退 衰頽 +裕然 悠然 +補佐 輔佐 +訓戒 訓誡 +試練 試煉 +詭弁 詭辯 +講和 媾和 +象眼 象嵌 +貫録 貫禄 +買弁 買辦 +賛辞 讚辭 +踏襲 蹈襲 +車両 車輛 +転倒 顛倒 +輪郭 輪廓 +退色 褪色 +途絶 杜絶 +連係 連繫 +連合 聯合 +選考 銓衡 +酢酸 醋酸 +野卑 野鄙 +鉱石 礦石 +間欠 間歇 +関数 函數 +防御 防禦 +険阻 嶮岨 +障壁 牆壁 +障害 障礙 +隠滅 湮滅 +集落 聚落 +雇用 雇傭 +風諭 諷喩 +飛語 蜚語 +香典 香奠 +骨格 骨骼 +高進 亢進 +鳥観 鳥瞰 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/JPVariants.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/JPVariants.txt new file mode 100644 index 0000000000000000000000000000000000000000..adf08ff1390fed27f8e04496d96490eee209f808 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/JPVariants.txt @@ -0,0 +1,367 @@ +乘 乗 +亂 乱 +亙 亘 +亞 亜 +佛 仏 +來 来 +假 仮 +傳 伝 +僞 偽 +價 価 +儉 倹 +兒 児 +內 内 +兩 両 +剎 刹 +剩 剰 +劍 剣 +劑 剤 +勞 労 +勳 勲 +勵 励 +勸 勧 +勻 匀 +區 区 +卷 巻 +卻 却 +參 参 +吳 呉 +咒 呪 +啞 唖 +單 単 +噓 嘘 +嚙 噛 +嚴 厳 +囑 嘱 +圈 圏 +國 国 +圍 囲 +圓 円 +圖 図 +團 団 +增 増 +墮 堕 +壓 圧 +壘 塁 +壞 壊 +壤 壌 +壯 壮 +壹 壱 +壽 寿 +奧 奥 +奬 奨 +妝 粧 +孃 嬢 +學 学 +寢 寝 +實 実 +寫 写 +寬 寛 +寶 宝 +將 将 +專 専 +對 対 +屆 届 +屬 属 +峯 峰 +峽 峡 +嶽 岳 +巖 巌 +巢 巣 +帶 帯 +廁 厠 +廢 廃 +廣 広 +廳 庁 +彈 弾 +彌 弥 +彎 弯 +彥 彦 +徑 径 +從 従 +徵 徴 +德 徳 +恆 恒 +悅 悦 +惠 恵 +惡 悪 +惱 悩 +慘 惨 +應 応 +懷 懐 +戀 恋 +戰 戦 +戲 戯 +戶 戸 +戾 戻 +拂 払 +拔 抜 +拜 拝 +挾 挟 +插 挿 +揭 掲 +搔 掻 +搖 揺 +搜 捜 +摑 掴 +擇 択 +擊 撃 +擔 担 +據 拠 +擴 拡 +攝 摂 +攪 撹 +收 収 +效 効 +敕 勅 +敘 叙 +數 数 +斷 断 +晉 晋 +晚 晩 +晝 昼 +暨 曁 +曆 暦 +曉 暁 +曾 曽 +會 会 +枡 桝 +查 査 +條 条 +棧 桟 +棱 稜 棱 +榆 楡 +榮 栄 +樂 楽 +樓 楼 +樞 枢 +樣 様 +橫 横 +檢 検 +櫻 桜 +權 権 +歐 欧 +歡 歓 +步 歩 +歲 歳 +歷 歴 +歸 帰 +殘 残 +殼 殻 +毆 殴 +每 毎 +氣 気 +污 汚 +沒 没 +涉 渉 +淚 涙 +淨 浄 +淺 浅 +渴 渇 +溌 潑 +溪 渓 +溫 温 +溼 湿 +滯 滞 +滿 満 +潛 潜 +澀 渋 +澤 沢 +濟 済 +濤 涛 +濱 浜 +濾 沪 +瀧 滝 +瀨 瀬 +灣 湾 +焔 焰 +燈 灯 +燒 焼 +營 営 +爐 炉 +爭 争 +爲 為 +牀 床 +犧 犠 +狀 状 +狹 狭 +獨 独 +獵 猟 +獸 獣 +獻 献 +瓣 弁 +產 産 +畫 画 +當 当 +疊 畳 +疎 疏 +痹 痺 +瘦 痩 +癡 痴 +發 発 +皋 皐 +盜 盗 +盡 尽 +碎 砕 +祕 秘 +祿 禄 +禦 御 +禪 禅 +禮 礼 +禱 祷 +稅 税 +稱 称 +稻 稲 +穎 頴 +穗 穂 +穩 穏 +穰 穣 +竃 竈 +竊 窃 +粹 粋 +糉 粽 +絕 絶 +絲 糸 +經 経 +綠 緑 +緖 緒 +緣 縁 +縣 県 +縱 縦 +總 総 +繋 繫 +繡 繍 +繩 縄 +繪 絵 +繼 継 +續 続 +纔 才 +纖 繊 +缺 欠 +罐 缶 +羣 群 +聯 連 +聰 聡 +聲 声 +聽 聴 +肅 粛 +脣 唇 +脫 脱 +腦 脳 +腳 脚 +膽 胆 +臟 臓 +臺 台 +與 与 +舉 挙 +舊 旧 +舍 舎 +荔 茘 +莊 荘 +莖 茎 +菸 煙 +萊 莱 +萬 万 +蔣 蒋 +蔥 葱 +薰 薫 +藏 蔵 +藝 芸 +藥 薬 +蘆 芦 +處 処 +虛 虚 +號 号 +螢 蛍 +蟲 虫 +蠟 蝋 +蠶 蚕 +蠻 蛮 +裝 装 +覺 覚 +覽 覧 +觀 観 +觸 触 +說 説 +謠 謡 +證 証 +譯 訳 +譽 誉 +讀 読 +變 変 +讓 譲 +豐 豊 +豫 予 +貓 猫 +貳 弐 +賣 売 +賴 頼 +贊 賛 +贗 贋 +踐 践 +輕 軽 +輛 輌 +轉 転 +辨 弁 +辭 辞 +辯 弁 +遞 逓 +遥 遙 +遲 遅 +邊 辺 +鄉 郷 +酢 醋 +醉 酔 +醗 醱 +醫 医 +醬 醤 +釀 醸 +釋 釈 +鋪 舗 +錄 録 +錢 銭 +鍊 錬 +鐵 鉄 +鑄 鋳 +鑛 鉱 +閱 閲 +關 関 +陷 陥 +隨 随 +險 険 +隱 隠 +雙 双 +雜 雑 +雞 鶏 +霸 覇 +靈 霊 +靜 静 +顏 顔 +顯 顕 +餘 余 +騷 騒 +驅 駆 +驗 験 +驛 駅 +髓 髄 +體 体 +髮 髪 +鬥 闘 +鱉 鼈 +鷗 鴎 +鹼 鹸 +鹽 塩 +麥 麦 +麪 麺 +麴 麹 +黃 黄 +黑 黒 +默 黙 +點 点 +黨 党 +齊 斉 +齋 斎 +齒 歯 +齡 齢 +龍 竜 +龜 亀 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/STCharacters.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/STCharacters.txt new file mode 100644 index 0000000000000000000000000000000000000000..912d1625c07605e48f235a4aaa5c7d0ae182e332 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/STCharacters.txt @@ -0,0 +1,3891 @@ +㐷 傌 +㐹 㑶 㐹 +㐽 偑 +㑇 㑳 +㑈 倲 +㑔 㑯 +㑩 儸 +㓆 𠗣 +㓥 劏 +㓰 劃 +㔉 劚 +㖊 噚 +㖞 喎 +㘎 㘚 +㚯 㜄 +㛀 媰 +㛟 𡞵 +㛠 𡢃 +㛣 㜏 +㛤 孋 +㛿 𡠹 +㟆 㠏 +㟜 𡾱 +㟥 嵾 +㡎 幓 +㤘 㥮 +㤽 懤 +㥪 慺 +㧏 掆 +㧐 㩳 +㧑 撝 +㧟 擓 +㧰 擽 +㨫 㩜 +㭎 棡 +㭏 椲 +㭣 𣙎 +㭤 樢 +㭴 樫 +㱩 殰 +㱮 殨 +㲿 瀇 +㳔 濧 +㳕 灡 +㳠 澾 +㳡 濄 +㳢 𣾷 +㳽 瀰 +㴋 潚 +㶉 鸂 +㶶 燶 +㶽 煱 +㺍 獱 +㻅 璯 +㻏 𤫩 +㻘 𤪺 +䀥 䁻 +䁖 瞜 +䂵 碽 +䃅 磾 +䅉 稏 +䅟 穇 +䅪 𥢢 +䇲 筴 +䉤 籔 +䌶 䊷 +䌷 紬 +䌸 縳 +䌹 絅 +䌺 䋙 +䌻 䋚 +䌼 綐 +䌽 綵 +䌾 䋻 +䌿 䋹 +䍀 繿 +䍁 繸 +䍠 䍦 +䎬 䎱 +䏝 膞 +䑽 𦪙 +䓓 薵 +䓕 薳 +䓖 藭 +䓨 罃 +䗖 螮 +䘛 𧝞 +䘞 𧜗 +䙊 𧜵 +䙌 䙡 +䙓 襬 +䜣 訢 +䜤 鿁 +䜥 𧩙 +䜧 䜀 +䜩 讌 +䝙 貙 +䞌 𧵳 +䞍 䝼 +䞎 𧶧 +䞐 賰 +䟢 躎 +䢀 𨊰 +䢁 𨊸 +䢂 𨋢 +䥺 釾 +䥽 鏺 +䥾 䥱 +䥿 𨯅 +䦀 𨦫 +䦁 𨧜 +䦂 䥇 +䦃 鐯 +䦅 鐥 +䦆 钁 +䦶 䦛 +䦷 䦟 +䩄 靦 +䭪 𩞯 +䯃 𩣑 +䯄 騧 +䯅 䯀 +䲝 䱽 +䲞 𩶘 +䲟 鮣 +䲠 鰆 +䲡 鰌 +䲢 鰧 +䲣 䱷 +䴓 鳾 +䴔 鵁 +䴕 鴷 +䴖 鶄 +䴗 鶪 +䴘 鷉 +䴙 鸊 +䶮 龑 +万 萬 万 +与 與 +丑 醜 丑 +专 專 +业 業 +丛 叢 +东 東 +丝 絲 +丢 丟 +两 兩 +严 嚴 +丧 喪 +个 個 箇 +丰 豐 丰 +临 臨 +为 爲 +丽 麗 +举 舉 +么 麼 +义 義 +乌 烏 +乐 樂 +乔 喬 +习 習 +乡 鄉 +书 書 +买 買 +乱 亂 +了 了 瞭 +争 爭 +于 於 于 +亏 虧 +云 雲 云 +亘 亙 亘 +亚 亞 +产 產 +亩 畝 +亲 親 +亵 褻 +亸 嚲 +亿 億 +仅 僅 +仆 僕 仆 +仇 仇 讎 +从 從 +仑 侖 崙 +仓 倉 +仪 儀 +们 們 +价 價 价 +仿 仿 彷 +众 衆 +优 優 +伙 夥 伙 +会 會 +伛 傴 +伞 傘 +伟 偉 +传 傳 +伡 俥 +伣 俔 +伤 傷 +伥 倀 +伦 倫 +伧 傖 +伪 僞 +伫 佇 +体 體 +余 餘 余 +佛 佛 彿 +佣 傭 佣 +佥 僉 +侠 俠 +侣 侶 +侥 僥 +侦 偵 +侧 側 +侨 僑 +侩 儈 +侪 儕 +侬 儂 +侭 儘 +俊 俊 儁 +俣 俁 +俦 儔 +俨 儼 +俩 倆 +俪 儷 +俫 倈 +俭 儉 +修 修 脩 +借 借 藉 +债 債 +倾 傾 +偬 傯 +偻 僂 +偾 僨 +偿 償 +傤 儎 +傥 儻 +傧 儐 +储 儲 +傩 儺 +僵 僵 殭 +儿 兒 +克 克 剋 +兑 兌 +兖 兗 +党 黨 党 +兰 蘭 +关 關 +兴 興 +兹 茲 +养 養 +兽 獸 +冁 囅 +内 內 +冈 岡 +册 冊 +写 寫 +军 軍 +农 農 +冬 冬 鼕 +冯 馮 +冲 衝 沖 +决 決 +况 況 +冻 凍 +净 淨 +凄 悽 淒 +准 準 准 +凉 涼 +凌 凌 淩 +减 減 +凑 湊 +凛 凜 +几 幾 几 +凤 鳳 +凫 鳧 +凭 憑 +凯 凱 +凶 兇 凶 +出 出 齣 +击 擊 +凿 鑿 +刍 芻 +划 劃 划 +刘 劉 +则 則 +刚 剛 +创 創 +删 刪 +别 別 彆 +刬 剗 +刭 剄 +刮 刮 颳 +制 制 製 +刹 剎 +刽 劊 +刾 㓨 +刿 劌 +剀 剴 +剂 劑 +剐 剮 +剑 劍 +剥 剝 +剧 劇 +劝 勸 +办 辦 +务 務 +劢 勱 +动 動 +励 勵 +劲 勁 +劳 勞 +势 勢 +勋 勳 勛 +勚 勩 +匀 勻 +匦 匭 +匮 匱 +区 區 +医 醫 +千 千 韆 +升 升 昇 +华 華 +协 協 +单 單 +卖 賣 +卜 卜 蔔 +占 佔 占 +卢 盧 +卤 滷 鹵 +卧 臥 +卫 衛 +却 卻 +卷 卷 捲 +卺 巹 +厂 廠 厂 +厅 廳 +历 歷 曆 +厉 厲 +压 壓 +厌 厭 +厍 厙 +厐 龎 +厕 廁 +厘 釐 厘 +厢 廂 +厣 厴 +厦 廈 +厨 廚 +厩 廄 +厮 廝 +县 縣 +叁 叄 +参 參 蔘 +叆 靉 +叇 靆 +双 雙 +发 發 髮 +变 變 +叙 敘 +叠 疊 +只 只 隻 祇 +台 臺 檯 颱 台 +叶 葉 叶 +号 號 +叹 嘆 歎 +叽 嘰 +吁 籲 吁 +吃 喫 吃 +合 合 閤 +吊 吊 弔 +同 同 衕 +后 後 后 +向 向 嚮 曏 +吓 嚇 +吕 呂 +吗 嗎 +吨 噸 +听 聽 +启 啓 +吴 吳 +呐 吶 +呒 嘸 +呓 囈 +呕 嘔 +呖 嚦 +呗 唄 +员 員 +呙 咼 +呛 嗆 +呜 嗚 +周 周 週 賙 +咏 詠 +咙 嚨 +咛 嚀 +咝 噝 +咤 吒 +咨 諮 咨 +咸 鹹 咸 +咽 咽 嚥 +哄 哄 鬨 +响 響 +哑 啞 +哒 噠 +哓 嘵 +哔 嗶 +哕 噦 +哗 譁 嘩 +哙 噲 +哜 嚌 +哝 噥 +哟 喲 +唇 脣 唇 +唛 嘜 +唝 嗊 +唠 嘮 +唡 啢 +唢 嗩 +唤 喚 +啧 嘖 +啬 嗇 +啭 囀 +啮 齧 嚙 +啯 嘓 +啰 囉 +啴 嘽 +啸 嘯 +喂 喂 餵 +喷 噴 +喽 嘍 +喾 嚳 +嗫 囁 +嗳 噯 +嘘 噓 +嘤 嚶 +嘱 囑 +噜 嚕 +噪 噪 譟 +嚣 囂 +回 回 迴 +团 團 糰 +园 園 +困 困 睏 +囱 囪 +围 圍 +囵 圇 +国 國 +图 圖 +圆 圓 +圣 聖 +圹 壙 +场 場 +坏 壞 +块 塊 +坚 堅 +坛 壇 罈 +坜 壢 +坝 壩 +坞 塢 +坟 墳 +坠 墜 +垄 壟 +垅 壠 +垆 壚 +垒 壘 +垦 墾 +垩 堊 +垫 墊 +垭 埡 +垯 墶 +垱 壋 +垲 塏 +垴 堖 +埘 塒 +埙 壎 塤 +埚 堝 +堑 塹 +堕 墮 +塆 壪 +墙 牆 +壮 壯 +声 聲 +壳 殼 +壶 壺 +壸 壼 +处 處 +备 備 +复 復 複 覆 +够 夠 +夫 夫 伕 +头 頭 +夸 誇 夸 +夹 夾 +夺 奪 +奁 奩 +奂 奐 +奋 奮 +奖 獎 +奥 奧 +奸 奸 姦 +妆 妝 +妇 婦 +妈 媽 +妩 嫵 +妪 嫗 +妫 嬀 +姗 姍 +姜 姜 薑 +姹 奼 +娄 婁 +娅 婭 +娆 嬈 +娇 嬌 +娈 孌 +娘 娘 孃 +娱 娛 +娲 媧 +娴 嫺 嫻 +婳 嫿 +婴 嬰 +婵 嬋 +婶 嬸 +媪 媼 +媭 嬃 +嫒 嬡 +嫔 嬪 +嫱 嬙 +嬷 嬤 +孙 孫 +学 學 +孪 孿 +宁 寧 甯 +它 它 牠 +宝 寶 +实 實 +宠 寵 +审 審 +宪 憲 +宫 宮 +家 家 傢 +宽 寬 +宾 賓 +寝 寢 +对 對 +寻 尋 +导 導 +寿 壽 +将 將 +尔 爾 +尘 塵 +尝 嘗 嚐 +尧 堯 +尴 尷 +尸 屍 尸 +尽 盡 儘 +局 局 侷 +层 層 +屃 屓 +屉 屜 +届 屆 +属 屬 +屡 屢 +屦 屨 +屿 嶼 +岁 歲 +岂 豈 +岖 嶇 +岗 崗 +岘 峴 +岚 嵐 +岛 島 +岩 巖 岩 +岭 嶺 +岳 嶽 岳 +岽 崬 +岿 巋 +峃 嶨 +峄 嶧 +峡 峽 +峣 嶢 +峤 嶠 +峥 崢 +峦 巒 +峰 峯 +崂 嶗 +崃 崍 +崄 嶮 +崭 嶄 +嵘 嶸 +嵚 嶔 +嵝 嶁 +巅 巔 +巨 巨 鉅 +巩 鞏 +巯 巰 +币 幣 +布 布 佈 +帅 帥 +师 師 +帏 幃 +帐 帳 +帘 簾 帘 +帜 幟 +带 帶 +帧 幀 +席 席 蓆 +帮 幫 +帱 幬 +帻 幘 +帼 幗 +幂 冪 +干 幹 乾 干 +并 並 併 +幸 幸 倖 +广 廣 广 +庄 莊 +庆 慶 +床 牀 +庐 廬 +庑 廡 +库 庫 +应 應 +庙 廟 +庞 龐 +废 廢 +庵 庵 菴 +庼 廎 +廪 廩 +开 開 +异 異 +弃 棄 +弑 弒 +张 張 +弥 彌 瀰 +弦 弦 絃 +弪 弳 +弯 彎 +弹 彈 +强 強 +归 歸 +当 當 噹 +录 錄 彔 +彟 彠 +彦 彥 +彨 彲 +彩 彩 綵 +彻 徹 +征 徵 征 +径 徑 +徕 徠 +御 御 禦 +忆 憶 +忏 懺 +志 志 誌 +忧 憂 +念 念 唸 +忾 愾 +怀 懷 +态 態 +怂 慫 +怃 憮 +怄 慪 +怅 悵 +怆 愴 +怜 憐 +总 總 +怼 懟 +怿 懌 +恋 戀 +恒 恆 +恤 恤 卹 +恳 懇 +恶 惡 噁 +恸 慟 +恹 懨 +恺 愷 +恻 惻 +恼 惱 +恽 惲 +悦 悅 +悫 愨 +悬 懸 +悭 慳 +悮 悞 +悯 憫 +惊 驚 +惧 懼 +惨 慘 +惩 懲 +惫 憊 +惬 愜 +惭 慚 +惮 憚 +惯 慣 +愈 愈 癒 +愠 慍 +愤 憤 +愦 憒 +愿 願 愿 +慑 懾 +慭 憖 +懑 懣 +懒 懶 +懔 懍 +戆 戇 +戋 戔 +戏 戲 +戗 戧 +战 戰 +戚 戚 慼 +戬 戩 +戯 戱 +户 戶 +才 才 纔 +扎 扎 紮 +扑 撲 +托 託 托 +扣 扣 釦 +执 執 +扩 擴 +扪 捫 +扫 掃 +扬 揚 +扰 擾 +折 折 摺 +抚 撫 +抛 拋 +抟 摶 +抠 摳 +抡 掄 +抢 搶 +护 護 +报 報 +抵 抵 牴 +担 擔 +拐 拐 柺 +拟 擬 +拢 攏 +拣 揀 +拥 擁 +拦 攔 +拧 擰 +拨 撥 +择 擇 +挂 掛 挂 +挚 摯 +挛 攣 +挜 掗 +挝 撾 +挞 撻 +挟 挾 +挠 撓 +挡 擋 +挢 撟 +挣 掙 +挤 擠 +挥 揮 +挦 撏 +挨 挨 捱 +挽 挽 輓 +捝 挩 +捞 撈 +损 損 +捡 撿 +换 換 +捣 搗 +据 據 据 +掳 擄 +掴 摑 +掷 擲 +掸 撣 +掺 摻 +掼 摜 +揽 攬 +揾 搵 +揿 撳 +搀 攙 +搁 擱 +搂 摟 +搄 揯 +搅 攪 +搜 搜 蒐 +携 攜 +摄 攝 +摅 攄 +摆 擺 襬 +摇 搖 +摈 擯 +摊 攤 +撄 攖 +撑 撐 +撵 攆 +撷 擷 +撸 擼 +撺 攛 +擜 㩵 +擞 擻 +攒 攢 +敌 敵 +敚 敓 +敛 斂 +敩 斆 +数 數 +斋 齋 +斓 斕 +斗 鬥 斗 +斩 斬 +断 斷 +旋 旋 鏇 +无 無 +旧 舊 +时 時 +旷 曠 +旸 暘 +昆 昆 崑 +昙 曇 +昵 暱 +昼 晝 +昽 曨 +显 顯 +晋 晉 +晒 曬 +晓 曉 +晔 曄 +晕 暈 +晖 暉 +暂 暫 +暅 𣈶 +暗 暗 闇 +暧 曖 +曲 曲 麴 +术 術 朮 +朱 朱 硃 +朴 樸 朴 +机 機 +杀 殺 +杂 雜 +权 權 +杆 杆 桿 +杠 槓 杠 +条 條 +来 來 +杨 楊 +杩 榪 +杯 杯 盃 +杰 傑 杰 +松 松 鬆 +板 板 闆 +极 極 极 +构 構 +枞 樅 +枢 樞 +枣 棗 +枥 櫪 +枧 梘 +枨 棖 +枪 槍 +枫 楓 +枭 梟 +柜 櫃 柜 +柠 檸 +柽 檉 +栀 梔 +栅 柵 +标 標 +栈 棧 +栉 櫛 +栊 櫳 +栋 棟 +栌 櫨 +栎 櫟 +栏 欄 +树 樹 +栖 棲 +栗 慄 栗 +样 樣 +核 核 覈 +栾 欒 +桠 椏 +桡 橈 +桢 楨 +档 檔 +桤 榿 +桥 橋 +桦 樺 +桧 檜 +桨 槳 +桩 樁 +桪 樳 +梁 梁 樑 +梦 夢 +梼 檮 +梾 棶 +梿 槤 +检 檢 +棁 梲 +棂 欞 +椁 槨 +椝 槼 +椟 櫝 +椠 槧 +椢 槶 +椤 欏 +椫 樿 +椭 橢 +椮 槮 +楼 樓 +榄 欖 +榅 榲 +榇 櫬 +榈 櫚 +榉 櫸 +榝 樧 +槚 檟 +槛 檻 +槟 檳 +槠 櫧 +横 橫 +樯 檣 +樱 櫻 +橥 櫫 +橱 櫥 +橹 櫓 +橼 櫞 +檩 檁 +欢 歡 +欤 歟 +欧 歐 +欲 欲 慾 +歼 殲 +殁 歿 +殇 殤 +残 殘 +殒 殞 +殓 殮 +殚 殫 +殡 殯 +殴 毆 +毁 毀 燬 譭 +毂 轂 +毕 畢 +毙 斃 +毡 氈 +毵 毿 +毶 𣯶 +氇 氌 +气 氣 +氢 氫 +氩 氬 +氲 氳 +汇 匯 彙 +汉 漢 +汤 湯 +汹 洶 +沈 沈 瀋 +沟 溝 +没 沒 +沣 灃 +沤 漚 +沥 瀝 +沦 淪 +沧 滄 +沨 渢 +沩 潙 +沪 滬 +沾 沾 霑 +泛 泛 氾 汎 +泞 濘 +注 注 註 +泪 淚 +泶 澩 +泷 瀧 +泸 瀘 +泺 濼 +泻 瀉 +泼 潑 +泽 澤 +泾 涇 +洁 潔 +洒 灑 +洼 窪 +浃 浹 +浅 淺 +浆 漿 +浇 澆 +浈 湞 +浉 溮 +浊 濁 +测 測 +浍 澮 +济 濟 +浏 瀏 +浐 滻 +浑 渾 +浒 滸 +浓 濃 +浔 潯 +浕 濜 +涂 塗 涂 +涌 湧 涌 +涚 涗 +涛 濤 +涝 澇 +涞 淶 +涟 漣 +涠 潿 +涡 渦 +涢 溳 +涣 渙 +涤 滌 +润 潤 +涧 澗 +涨 漲 +涩 澀 +淀 澱 淀 +渊 淵 +渌 淥 +渍 漬 +渎 瀆 +渐 漸 +渑 澠 +渔 漁 +渖 瀋 +渗 滲 +温 溫 +游 遊 游 +湾 灣 +湿 溼 +溁 濚 +溃 潰 +溅 濺 +溆 漵 +溇 漊 +滗 潷 +滚 滾 +滞 滯 +滟 灩 灧 +滠 灄 +满 滿 +滢 瀅 +滤 濾 +滥 濫 +滦 灤 +滨 濱 +滩 灘 +滪 澦 +漓 漓 灕 +潆 瀠 +潇 瀟 +潋 瀲 +潍 濰 +潜 潛 +潴 瀦 +澛 瀂 +澜 瀾 +濑 瀨 +濒 瀕 +灏 灝 +灭 滅 +灯 燈 +灵 靈 +灶 竈 +灾 災 +灿 燦 +炀 煬 +炉 爐 +炖 燉 +炜 煒 +炝 熗 +点 點 +炼 煉 鍊 +炽 熾 +烁 爍 +烂 爛 +烃 烴 +烛 燭 +烟 煙 菸 +烦 煩 +烧 燒 +烨 燁 +烩 燴 +烫 燙 +烬 燼 +热 熱 +焕 煥 +焖 燜 +焘 燾 +煴 熅 +熏 燻 熏 +爱 愛 +爷 爺 +牍 牘 +牦 犛 +牵 牽 +牺 犧 +犊 犢 +状 狀 +犷 獷 +犸 獁 +犹 猶 +狈 狽 +狝 獮 +狞 獰 +独 獨 +狭 狹 +狮 獅 +狯 獪 +狰 猙 +狱 獄 +狲 猻 +猃 獫 +猎 獵 +猕 獼 +猡 玀 +猪 豬 +猫 貓 +猬 蝟 +献 獻 +獭 獺 +玑 璣 +玙 璵 +玚 瑒 +玛 瑪 +玩 玩 翫 +玮 瑋 +环 環 +现 現 +玱 瑲 +玺 璽 +珐 琺 +珑 瓏 +珰 璫 +珲 琿 +琎 璡 +琏 璉 +琐 瑣 +琼 瓊 +瑶 瑤 +瑷 璦 +瑸 璸 +璇 璇 璿 +璎 瓔 +瓒 瓚 +瓮 甕 +瓯 甌 +电 電 +画 畫 +畅 暢 +畴 疇 +疖 癤 +疗 療 +疟 瘧 +疠 癘 +疡 瘍 +疬 癧 +疭 瘲 +疮 瘡 +疯 瘋 +疱 皰 +疴 痾 +症 症 癥 +痈 癰 +痉 痙 +痒 癢 +痖 瘂 +痨 癆 +痪 瘓 +痫 癇 +痴 癡 +瘅 癉 +瘆 瘮 +瘗 瘞 +瘘 瘻 +瘪 癟 +瘫 癱 +瘾 癮 +瘿 癭 +癞 癩 +癣 癬 +癫 癲 +皂 皁 皂 +皑 皚 +皱 皺 +皲 皸 +盏 盞 +盐 鹽 +监 監 +盖 蓋 +盗 盜 +盘 盤 +眍 瞘 +眦 眥 +眬 矓 +睁 睜 +睐 睞 +睑 瞼 +瞆 瞶 +瞒 瞞 +瞩 矚 +矩 矩 榘 +矫 矯 +矶 磯 +矾 礬 +矿 礦 +砀 碭 +码 碼 +砖 磚 +砗 硨 +砚 硯 +砜 碸 +砺 礪 +砻 礱 +砾 礫 +础 礎 +硁 硜 +硕 碩 +硖 硤 +硗 磽 +硙 磑 +硚 礄 +确 確 确 +硵 磠 +硷 礆 +碍 礙 +碛 磧 +碜 磣 +碱 鹼 +礼 禮 +祃 禡 +祎 禕 +祢 禰 +祯 禎 +祷 禱 +祸 禍 +禀 稟 +禄 祿 +禅 禪 +离 離 +私 私 俬 +秃 禿 +秆 稈 +秋 秋 鞦 +种 種 种 +秘 祕 +积 積 +称 稱 +秽 穢 +秾 穠 +稆 穭 +税 稅 +稣 穌 +稳 穩 +穑 穡 +穞 穭 +穷 窮 +窃 竊 +窍 竅 +窎 窵 +窑 窯 +窜 竄 +窝 窩 +窥 窺 +窦 竇 +窭 窶 +竖 豎 +竞 競 +笃 篤 +笋 筍 +笔 筆 +笕 筧 +笺 箋 +笼 籠 +笾 籩 +筑 築 筑 +筚 篳 +筛 篩 +筜 簹 +筝 箏 +筹 籌 +筼 篔 +签 籤 簽 +筿 篠 +简 簡 +箓 籙 +箦 簀 +箧 篋 +箨 籜 +箩 籮 +箪 簞 +箫 簫 +篑 簣 +篓 簍 +篮 籃 +篯 籛 +篱 籬 +簖 籪 +籁 籟 +籴 糴 +类 類 +籼 秈 +粜 糶 +粝 糲 +粤 粵 +粪 糞 +粮 糧 +粽 糉 +糁 糝 +糇 餱 +糍 餈 +系 系 係 繫 +紧 緊 +絷 縶 +緼 縕 +縆 緪 +纟 糹 +纠 糾 +纡 紆 +红 紅 +纣 紂 +纤 纖 縴 +纥 紇 +约 約 +级 級 +纨 紈 +纩 纊 +纪 紀 +纫 紉 +纬 緯 +纭 紜 +纮 紘 +纯 純 +纰 紕 +纱 紗 +纲 綱 +纳 納 +纴 紝 +纵 縱 +纶 綸 +纷 紛 +纸 紙 +纹 紋 +纺 紡 +纻 紵 +纼 紖 +纽 紐 +纾 紓 +线 線 +绀 紺 +绁 紲 +绂 紱 +练 練 +组 組 +绅 紳 +细 細 +织 織 +终 終 +绉 縐 +绊 絆 +绋 紼 +绌 絀 +绍 紹 +绎 繹 +经 經 +绐 紿 +绑 綁 +绒 絨 +结 結 +绔 絝 +绕 繞 +绖 絰 +绗 絎 +绘 繪 +给 給 +绚 絢 +绛 絳 +络 絡 +绝 絕 +绞 絞 +统 統 +绠 綆 +绡 綃 +绢 絹 +绣 繡 +绤 綌 +绥 綏 +绦 絛 +继 繼 +绨 綈 +绩 績 +绪 緒 +绫 綾 +绬 緓 +续 續 +绮 綺 +绯 緋 +绰 綽 +绱 鞝 緔 +绲 緄 +绳 繩 +维 維 +绵 綿 +绶 綬 +绷 繃 綳 +绸 綢 +绹 綯 +绺 綹 +绻 綣 +综 綜 +绽 綻 +绾 綰 +绿 綠 +缀 綴 +缁 緇 +缂 緙 +缃 緗 +缄 緘 +缅 緬 +缆 纜 +缇 緹 +缈 緲 +缉 緝 +缊 縕 +缋 繢 +缌 緦 +缍 綞 +缎 緞 +缏 緶 +缐 線 +缑 緱 +缒 縋 +缓 緩 +缔 締 +缕 縷 +编 編 +缗 緡 +缘 緣 +缙 縉 +缚 縛 +缛 縟 +缜 縝 +缝 縫 +缞 縗 +缟 縞 +缠 纏 +缡 縭 +缢 縊 +缣 縑 +缤 繽 +缥 縹 +缦 縵 +缧 縲 +缨 纓 +缩 縮 +缪 繆 +缫 繅 +缬 纈 +缭 繚 +缮 繕 +缯 繒 +缰 繮 +缱 繾 +缲 繰 +缳 繯 +缴 繳 +缵 纘 +罂 罌 +网 網 +罗 羅 +罚 罰 +罢 罷 +罴 羆 +羁 羈 +羟 羥 +羡 羨 +群 羣 +翘 翹 +翙 翽 +翚 翬 +耢 耮 +耧 耬 +耸 聳 +耻 恥 +聂 聶 +聋 聾 +职 職 +聍 聹 +联 聯 +聩 聵 +聪 聰 +肃 肅 +肠 腸 +肤 膚 +肮 骯 +肴 餚 +肾 腎 +肿 腫 +胀 脹 +胁 脅 +胄 胄 冑 +胆 膽 +背 背 揹 +胜 勝 胜 +胡 胡 鬍 衚 +胧 朧 +胨 腖 +胪 臚 +胫 脛 +胶 膠 +脉 脈 +脍 膾 +脏 髒 臟 +脐 臍 +脑 腦 +脓 膿 +脔 臠 +脚 腳 +脱 脫 +脶 腡 +脸 臉 +腊 臘 腊 +腌 醃 腌 +腘 膕 +腭 齶 +腻 膩 +腼 靦 +腽 膃 +腾 騰 +膑 臏 +膻 羶 膻 +臜 臢 +致 致 緻 +舆 輿 +舍 舍 捨 +舣 艤 +舰 艦 +舱 艙 +舻 艫 +艰 艱 +艳 豔 艷 +艺 藝 +节 節 +芈 羋 +芗 薌 +芜 蕪 +芦 蘆 +芸 芸 蕓 +苁 蓯 +苇 葦 +苈 藶 +苋 莧 +苌 萇 +苍 蒼 +苎 苧 +苏 蘇 甦 囌 +苔 苔 薹 +苧 薴 +苹 蘋 苹 +范 範 范 +茎 莖 +茏 蘢 +茑 蔦 +茔 塋 +茕 煢 +茧 繭 +荆 荊 +荐 薦 荐 +荙 薘 +荚 莢 +荛 蕘 +荜 蓽 +荝 萴 +荞 蕎 +荟 薈 +荠 薺 +荡 蕩 盪 +荣 榮 +荤 葷 +荥 滎 +荦 犖 +荧 熒 +荨 蕁 +荩 藎 +荪 蓀 +荫 蔭 廕 +荬 蕒 +荭 葒 +荮 葤 +药 藥 葯 +莅 蒞 +莱 萊 +莲 蓮 +莳 蒔 +莴 萵 +莶 薟 +获 獲 穫 +莸 蕕 +莹 瑩 +莺 鶯 +莼 蓴 +萚 蘀 +萝 蘿 +萤 螢 +营 營 +萦 縈 +萧 蕭 +萨 薩 +葱 蔥 +蒀 蒕 +蒇 蕆 +蒉 蕢 +蒋 蔣 +蒌 蔞 +蒏 醟 +蒙 蒙 矇 濛 懞 +蓝 藍 +蓟 薊 +蓠 蘺 +蓣 蕷 +蓥 鎣 +蓦 驀 +蔂 虆 +蔑 蔑 衊 +蔷 薔 +蔹 蘞 +蔺 藺 +蔼 藹 +蕰 薀 +蕲 蘄 +蕴 蘊 +薮 藪 +藓 蘚 +藴 蘊 +蘖 櫱 +虏 虜 +虑 慮 +虚 虛 +虫 蟲 虫 +虬 虯 +虮 蟣 +虱 蝨 +虽 雖 +虾 蝦 +虿 蠆 +蚀 蝕 +蚁 蟻 +蚂 螞 +蚃 蠁 +蚕 蠶 +蚝 蠔 蚝 +蚬 蜆 +蛊 蠱 +蛎 蠣 +蛏 蟶 +蛮 蠻 +蛰 蟄 +蛱 蛺 +蛲 蟯 +蛳 螄 +蛴 蠐 +蜕 蛻 +蜗 蝸 +蜡 蠟 蜡 +蝇 蠅 +蝈 蟈 +蝉 蟬 +蝎 蠍 蝎 +蝼 螻 +蝾 蠑 +螀 螿 +螨 蟎 +蟏 蠨 +衅 釁 +衔 銜 +补 補 +表 表 錶 +衬 襯 +衮 袞 +袄 襖 +袅 嫋 裊 +袆 褘 +袜 襪 +袭 襲 +袯 襏 +装 裝 +裆 襠 +裈 褌 +裢 褳 +裣 襝 +裤 褲 +裥 襉 襇 +褛 褸 +褴 襤 +襕 襴 +见 見 +观 觀 +觃 覎 +规 規 +觅 覓 +视 視 +觇 覘 +览 覽 +觉 覺 +觊 覬 +觋 覡 +觌 覿 +觍 覥 +觎 覦 +觏 覯 +觐 覲 +觑 覷 +觞 觴 +触 觸 +觯 觶 +訚 誾 +詟 讋 +誉 譽 +誊 謄 +讠 訁 +计 計 +订 訂 +讣 訃 +认 認 +讥 譏 +讦 訐 +讧 訌 +讨 討 +让 讓 +讪 訕 +讫 訖 +讬 託 +训 訓 +议 議 +讯 訊 +记 記 +讱 訒 +讲 講 +讳 諱 +讴 謳 +讵 詎 +讶 訝 +讷 訥 +许 許 +讹 訛 +论 論 +讻 訩 +讼 訟 +讽 諷 +设 設 +访 訪 +诀 訣 +证 證 証 +诂 詁 +诃 訶 +评 評 +诅 詛 +识 識 +诇 詗 +诈 詐 +诉 訴 +诊 診 +诋 詆 +诌 謅 +词 詞 +诎 詘 +诏 詔 +诐 詖 +译 譯 +诒 詒 +诓 誆 +诔 誄 +试 試 +诖 詿 +诗 詩 +诘 詰 +诙 詼 +诚 誠 +诛 誅 +诜 詵 +话 話 +诞 誕 +诟 詬 +诠 詮 +诡 詭 +询 詢 +诣 詣 +诤 諍 +该 該 +详 詳 +诧 詫 +诨 諢 +诩 詡 +诪 譸 +诫 誡 +诬 誣 +语 語 +诮 誚 +误 誤 +诰 誥 +诱 誘 +诲 誨 +诳 誑 +说 說 +诵 誦 +诶 誒 +请 請 +诸 諸 +诹 諏 +诺 諾 +读 讀 +诼 諑 +诽 誹 +课 課 +诿 諉 +谀 諛 +谁 誰 +谂 諗 +调 調 +谄 諂 +谅 諒 +谆 諄 +谇 誶 +谈 談 +谉 讅 +谊 誼 +谋 謀 +谌 諶 +谍 諜 +谎 謊 +谏 諫 +谐 諧 +谑 謔 +谒 謁 +谓 謂 +谔 諤 +谕 諭 +谖 諼 +谗 讒 +谘 諮 +谙 諳 +谚 諺 +谛 諦 +谜 謎 +谝 諞 +谞 諝 +谟 謨 +谠 讜 +谡 謖 +谢 謝 +谣 謠 +谤 謗 +谥 諡 謚 +谦 謙 +谧 謐 +谨 謹 +谩 謾 +谪 謫 +谫 譾 +谬 謬 +谭 譚 +谮 譖 +谯 譙 +谰 讕 +谱 譜 +谲 譎 +谳 讞 +谴 譴 +谵 譫 +谶 讖 +谷 谷 穀 +豮 豶 +贝 貝 +贞 貞 +负 負 +贠 貟 +贡 貢 +财 財 +责 責 +贤 賢 +败 敗 +账 賬 +货 貨 +质 質 +贩 販 +贪 貪 +贫 貧 +贬 貶 +购 購 +贮 貯 +贯 貫 +贰 貳 +贱 賤 +贲 賁 +贳 貰 +贴 貼 +贵 貴 +贶 貺 +贷 貸 +贸 貿 +费 費 +贺 賀 +贻 貽 +贼 賊 +贽 贄 +贾 賈 +贿 賄 +赀 貲 +赁 賃 +赂 賂 +赃 贓 +资 資 +赅 賅 +赆 贐 +赇 賕 +赈 賑 +赉 賚 +赊 賒 +赋 賦 +赌 賭 +赍 齎 +赎 贖 +赏 賞 +赐 賜 +赑 贔 +赒 賙 +赓 賡 +赔 賠 +赕 賧 +赖 賴 +赗 賵 +赘 贅 +赙 賻 +赚 賺 +赛 賽 +赜 賾 +赝 贗 贋 +赞 贊 讚 +赟 贇 +赠 贈 +赡 贍 +赢 贏 +赣 贛 +赪 赬 +赵 趙 +赶 趕 +趋 趨 +趱 趲 +趸 躉 +跃 躍 +跄 蹌 +跖 蹠 跖 +跞 躒 +践 踐 +跶 躂 +跷 蹺 +跸 蹕 +跹 躚 +跻 躋 +踌 躊 +踪 蹤 +踬 躓 +踯 躑 +蹑 躡 +蹒 蹣 +蹰 躕 +蹿 躥 +躏 躪 +躜 躦 +躯 軀 +輼 轀 +车 車 +轧 軋 +轨 軌 +轩 軒 +轪 軑 +轫 軔 +转 轉 +轭 軛 +轮 輪 +软 軟 +轰 轟 +轱 軲 +轲 軻 +轳 轤 +轴 軸 +轵 軹 +轶 軼 +轷 軤 +轸 軫 +轹 轢 +轺 軺 +轻 輕 +轼 軾 +载 載 +轾 輊 +轿 轎 +辀 輈 +辁 輇 +辂 輅 +较 較 +辄 輒 +辅 輔 +辆 輛 +辇 輦 +辈 輩 +辉 輝 +辊 輥 +辋 輞 +辌 輬 +辍 輟 +辎 輜 +辏 輳 +辐 輻 +辑 輯 +辒 轀 +输 輸 +辔 轡 +辕 轅 +辖 轄 +辗 輾 +辘 轆 +辙 轍 +辚 轔 +辞 辭 +辟 闢 辟 +辩 辯 +辫 辮 +边 邊 +辽 遼 +达 達 +迁 遷 +过 過 +迈 邁 +运 運 +还 還 +这 這 +进 進 +远 遠 +违 違 +连 連 +迟 遲 +迩 邇 +迳 逕 +迹 跡 蹟 +适 適 适 +选 選 +逊 遜 +递 遞 +逦 邐 +逻 邏 +遗 遺 +遥 遙 +邓 鄧 +邝 鄺 +邬 鄔 +邮 郵 +邹 鄒 +邺 鄴 +邻 鄰 +郁 鬱 郁 +郏 郟 +郐 鄶 +郑 鄭 +郓 鄆 +郦 酈 +郧 鄖 +郸 鄲 +酂 酇 +酝 醞 +酦 醱 +酱 醬 +酸 酸 痠 +酽 釅 +酾 釃 +酿 釀 +醖 醞 +采 採 采 寀 +释 釋 +里 裏 里 +鉴 鑑 鑒 +銮 鑾 +錾 鏨 +钅 釒 +钆 釓 +钇 釔 +针 針 鍼 +钉 釘 +钊 釗 +钋 釙 +钌 釕 +钍 釷 +钎 釺 +钏 釧 +钐 釤 +钑 鈒 +钒 釩 +钓 釣 +钔 鍆 +钕 釹 +钖 鍚 +钗 釵 +钘 鈃 +钙 鈣 +钚 鈈 +钛 鈦 +钜 鉅 +钝 鈍 +钞 鈔 +钟 鍾 鐘 鈡 +钠 鈉 +钡 鋇 +钢 鋼 +钣 鈑 +钤 鈐 +钥 鑰 鈅 +钦 欽 +钧 鈞 +钨 鎢 +钩 鉤 +钪 鈧 +钫 鈁 鍅 +钬 鈥 +钭 鈄 +钮 鈕 +钯 鈀 +钰 鈺 +钱 錢 +钲 鉦 +钳 鉗 +钴 鈷 +钵 鉢 +钶 鈳 +钷 鉕 +钸 鈽 +钹 鈸 +钺 鉞 +钻 鑽 鉆 +钼 鉬 +钽 鉭 +钾 鉀 +钿 鈿 +铀 鈾 +铁 鐵 +铂 鉑 +铃 鈴 +铄 鑠 +铅 鉛 +铆 鉚 +铇 鉋 +铈 鈰 +铉 鉉 +铊 鉈 +铋 鉍 +铌 鈮 +铍 鈹 +铎 鐸 +铏 鉶 +铐 銬 +铑 銠 +铒 鉺 +铓 鋩 +铔 錏 +铕 銪 +铖 鋮 +铗 鋏 +铘 鋣 +铙 鐃 +铚 銍 +铛 鐺 +铜 銅 +铝 鋁 +铞 銱 +铟 銦 +铠 鎧 +铡 鍘 +铢 銖 +铣 銑 +铤 鋌 +铥 銩 +铦 銛 +铧 鏵 +铨 銓 +铩 鎩 +铪 鉿 +铫 銚 +铬 鉻 +铭 銘 +铮 錚 +铯 銫 +铰 鉸 +铱 銥 +铲 鏟 剷 +铳 銃 +铴 鐋 +铵 銨 +银 銀 +铷 銣 +铸 鑄 +铹 鐒 +铺 鋪 +铻 鋙 +铼 錸 +铽 鋱 +链 鏈 鍊 +铿 鏗 +销 銷 +锁 鎖 +锂 鋰 +锃 鋥 +锄 鋤 +锅 鍋 +锆 鋯 +锇 鋨 +锈 鏽 +锉 銼 +锊 鋝 +锋 鋒 +锌 鋅 +锍 鋶 +锎 鐦 +锏 鐧 +锐 銳 +锑 銻 +锒 鋃 +锓 鋟 +锔 鋦 +锕 錒 +锖 錆 +锗 鍺 +锘 鍩 +错 錯 +锚 錨 +锛 錛 +锜 錡 +锝 鍀 +锞 錁 +锟 錕 +锠 錩 +锡 錫 +锢 錮 +锣 鑼 +锤 錘 +锥 錐 +锦 錦 +锧 鑕 +锨 鍁 +锩 錈 +锪 鍃 +锫 錇 鉳 +锬 錟 +锭 錠 +键 鍵 +锯 鋸 +锰 錳 +锱 錙 +锲 鍥 +锳 鍈 +锴 鍇 +锵 鏘 +锶 鍶 +锷 鍔 +锸 鍤 +锹 鍬 +锺 鍾 +锻 鍛 +锼 鎪 +锽 鍠 +锾 鍰 +锿 鎄 +镀 鍍 +镁 鎂 +镂 鏤 +镃 鎡 +镄 鐨 +镅 鎇 +镆 鏌 +镇 鎮 +镈 鎛 +镉 鎘 +镊 鑷 +镋 钂 鎲 +镌 鐫 +镍 鎳 +镎 鎿 錼 +镏 鎦 +镐 鎬 +镑 鎊 +镒 鎰 +镓 鎵 +镔 鑌 +镕 鎔 +镖 鏢 +镗 鏜 +镘 鏝 +镙 鏍 +镚 鏰 +镛 鏞 +镜 鏡 +镝 鏑 +镞 鏃 +镟 鏇 +镠 鏐 +镡 鐔 +镢 钁 鐝 +镣 鐐 +镤 鏷 +镥 鑥 +镦 鐓 +镧 鑭 +镨 鐠 +镩 鑹 +镪 鏹 +镫 鐙 +镬 鑊 +镭 鐳 +镮 鐶 +镯 鐲 +镰 鐮 鎌 +镱 鐿 +镲 鑔 +镳 鑣 +镴 鑞 +镵 鑱 +镶 鑲 +长 長 +门 門 +闩 閂 +闪 閃 +闫 閆 +闬 閈 +闭 閉 +问 問 +闯 闖 +闰 閏 +闱 闈 +闲 閒 閑 +闳 閎 +间 間 +闵 閔 +闶 閌 +闷 悶 +闸 閘 +闹 鬧 +闺 閨 +闻 聞 +闼 闥 +闽 閩 +闾 閭 +闿 闓 +阀 閥 +阁 閣 +阂 閡 +阃 閫 +阄 鬮 +阅 閱 +阆 閬 +阇 闍 +阈 閾 +阉 閹 +阊 閶 +阋 鬩 +阌 閿 +阍 閽 +阎 閻 +阏 閼 +阐 闡 +阑 闌 +阒 闃 +阓 闠 +阔 闊 +阕 闋 +阖 闔 +阗 闐 +阘 闒 +阙 闕 +阚 闞 +阛 闤 +队 隊 +阳 陽 +阴 陰 +阵 陣 +阶 階 +际 際 +陆 陸 +陇 隴 +陈 陳 +陉 陘 +陕 陝 +陦 隯 +陧 隉 +陨 隕 +险 險 +随 隨 +隐 隱 +隶 隸 +隽 雋 +难 難 +雇 僱 +雏 雛 +雕 雕 鵰 +雠 讎 +雳 靂 +雾 霧 +霁 霽 +霉 黴 +霡 霢 +霭 靄 +靓 靚 +靔 靝 +静 靜 +面 面 麪 +靥 靨 +鞑 韃 +鞒 鞽 +鞯 韉 +鞲 韝 +韦 韋 +韧 韌 +韨 韍 +韩 韓 +韪 韙 +韫 韞 +韬 韜 +韵 韻 +页 頁 +顶 頂 +顷 頃 +顸 頇 +项 項 +顺 順 +须 須 鬚 +顼 頊 +顽 頑 +顾 顧 +顿 頓 +颀 頎 +颁 頒 +颂 頌 +颃 頏 +预 預 +颅 顱 +领 領 +颇 頗 +颈 頸 +颉 頡 +颊 頰 +颋 頲 +颌 頜 +颍 潁 +颎 熲 +颏 頦 +颐 頤 +频 頻 +颒 頮 +颓 頹 +颔 頷 +颕 頴 +颖 穎 +颗 顆 +题 題 +颙 顒 +颚 顎 +颛 顓 +颜 顏 +额 額 +颞 顳 +颟 顢 +颠 顛 +颡 顙 +颢 顥 +颣 纇 +颤 顫 +颥 顬 +颦 顰 +颧 顴 +风 風 +飏 颺 +飐 颭 +飑 颮 +飒 颯 +飓 颶 +飔 颸 +飕 颼 +飖 颻 +飗 飀 +飘 飄 +飙 飆 +飚 飈 +飞 飛 +飨 饗 +餍 饜 +饣 飠 +饤 飣 +饥 飢 饑 +饦 飥 +饧 餳 +饨 飩 +饩 餼 +饪 飪 +饫 飫 +饬 飭 +饭 飯 +饮 飲 +饯 餞 +饰 飾 +饱 飽 +饲 飼 +饳 飿 +饴 飴 +饵 餌 +饶 饒 +饷 餉 +饸 餄 +饹 餎 +饺 餃 +饻 餏 +饼 餅 +饽 餑 +饾 餖 +饿 餓 +馀 餘 +馁 餒 +馂 餕 +馃 餜 +馄 餛 +馅 餡 +馆 館 +馇 餷 +馈 饋 +馉 餶 +馊 餿 +馋 饞 +馌 饁 +馍 饃 +馎 餺 +馏 餾 +馐 饈 +馑 饉 +馒 饅 +馓 饊 +馔 饌 +馕 饢 +马 馬 +驭 馭 +驮 馱 +驯 馴 +驰 馳 +驱 驅 +驲 馹 +驳 駁 +驴 驢 +驵 駔 +驶 駛 +驷 駟 +驸 駙 +驹 駒 +驺 騶 +驻 駐 +驼 駝 +驽 駑 +驾 駕 +驿 驛 +骀 駘 +骁 驍 +骂 罵 +骃 駰 +骄 驕 +骅 驊 +骆 駱 +骇 駭 +骈 駢 +骉 驫 +骊 驪 +骋 騁 +验 驗 +骍 騂 +骎 駸 +骏 駿 +骐 騏 +骑 騎 +骒 騍 +骓 騅 +骔 騌 +骕 驌 +骖 驂 +骗 騙 +骘 騭 +骙 騤 +骚 騷 +骛 騖 +骜 驁 +骝 騮 +骞 騫 +骟 騸 +骠 驃 +骡 騾 +骢 驄 +骣 驏 +骤 驟 +骥 驥 +骦 驦 +骧 驤 +髅 髏 +髋 髖 +髌 髕 +鬓 鬢 +鬶 鬹 +魇 魘 +魉 魎 +鱼 魚 +鱽 魛 +鱾 魢 +鱿 魷 +鲀 魨 +鲁 魯 +鲂 魴 +鲃 䰾 +鲄 魺 +鲅 鮁 +鲆 鮃 +鲇 鮎 +鲈 鱸 +鲉 鮋 +鲊 鮓 +鲋 鮒 +鲌 鮊 +鲍 鮑 +鲎 鱟 +鲏 鮍 +鲐 鮐 +鲑 鮭 +鲒 鮚 +鲓 鮳 +鲔 鮪 +鲕 鮞 +鲖 鮦 +鲗 鰂 +鲘 鮜 +鲙 鱠 +鲚 鱭 +鲛 鮫 +鲜 鮮 +鲝 鮺 +鲞 鯗 +鲟 鱘 +鲠 鯁 +鲡 鱺 +鲢 鰱 +鲣 鰹 +鲤 鯉 +鲥 鰣 +鲦 鰷 +鲧 鯀 +鲨 鯊 +鲩 鯇 +鲪 鮶 +鲫 鯽 +鲬 鯒 +鲭 鯖 +鲮 鯪 +鲯 鯕 +鲰 鯫 +鲱 鯡 +鲲 鯤 +鲳 鯧 +鲴 鯝 +鲵 鯢 +鲶 鯰 +鲷 鯛 +鲸 鯨 +鲹 鰺 +鲺 鯴 +鲻 鯔 +鲼 鱝 +鲽 鰈 +鲾 鰏 +鲿 鱨 +鳀 鯷 +鳁 鰮 +鳂 鰃 +鳃 鰓 +鳄 鱷 +鳅 鰍 +鳆 鰒 +鳇 鰉 +鳈 鰁 +鳉 鱂 +鳊 鯿 +鳋 鰠 +鳌 鰲 +鳍 鰭 +鳎 鰨 +鳏 鰥 +鳐 鰩 +鳑 鰟 +鳒 鰜 +鳓 鰳 +鳔 鰾 +鳕 鱈 +鳖 鱉 +鳗 鰻 +鳘 鰵 +鳙 鱅 +鳚 䲁 +鳛 鰼 +鳜 鱖 +鳝 鱔 +鳞 鱗 +鳟 鱒 +鳠 鱯 +鳡 鱤 +鳢 鱧 +鳣 鱣 +鳤 䲘 +鸟 鳥 +鸠 鳩 +鸡 雞 +鸢 鳶 +鸣 鳴 +鸤 鳲 +鸥 鷗 +鸦 鴉 +鸧 鶬 +鸨 鴇 +鸩 鴆 +鸪 鴣 +鸫 鶇 +鸬 鸕 +鸭 鴨 +鸮 鴞 +鸯 鴦 +鸰 鴒 +鸱 鴟 +鸲 鴝 +鸳 鴛 +鸴 鷽 +鸵 鴕 +鸶 鷥 +鸷 鷙 +鸸 鴯 +鸹 鴰 +鸺 鵂 +鸻 鴴 +鸼 鵃 +鸽 鴿 +鸾 鸞 +鸿 鴻 +鹀 鵐 +鹁 鵓 +鹂 鸝 +鹃 鵑 +鹄 鵠 +鹅 鵝 +鹆 鵒 +鹇 鷳 鷴 +鹈 鵜 +鹉 鵡 +鹊 鵲 +鹋 鶓 +鹌 鵪 +鹍 鵾 +鹎 鵯 +鹏 鵬 +鹐 鵮 +鹑 鶉 +鹒 鶊 +鹓 鵷 +鹔 鷫 +鹕 鶘 +鹖 鶡 +鹗 鶚 +鹘 鶻 +鹙 鶖 +鹚 鷀 +鹛 鶥 +鹜 鶩 +鹝 鷊 +鹞 鷂 +鹟 鶲 +鹠 鶹 +鹡 鶺 +鹢 鷁 +鹣 鶼 +鹤 鶴 +鹥 鷖 +鹦 鸚 +鹧 鷓 +鹨 鷚 +鹩 鷯 +鹪 鷦 +鹫 鷲 +鹬 鷸 +鹭 鷺 +鹮 䴉 +鹯 鸇 +鹰 鷹 +鹱 鸌 +鹲 鸏 +鹳 鸛 +鹴 鸘 +鹾 鹺 +麦 麥 +麸 麩 +麹 麴 +麺 麪 +麽 麼 +黄 黃 +黉 黌 +黡 黶 +黩 黷 +黪 黲 +黾 黽 +鼋 黿 +鼌 鼂 +鼍 鼉 +鼹 鼴 +齐 齊 +齑 齏 +齿 齒 +龀 齔 +龁 齕 +龂 齗 +龃 齟 +龄 齡 +龅 齙 +龆 齠 +龇 齜 +龈 齦 +龉 齬 +龊 齪 +龋 齲 +龌 齷 +龙 龍 +龚 龔 +龛 龕 +龟 龜 +鿎 䃮 +鿏 䥑 +鿒 鿓 +鿔 鎶 +𠀾 𠁞 +𠆲 儣 +𠆿 𠌥 +𠇹 俓 +𠉂 㒓 +𠉗 𠏢 +𠋆 儭 +𠚳 𠠎 +𠛅 剾 +𠛆 𠞆 +𠛾 𪟖 +𠡠 勑 +𠮶 嗰 +𠯟 哯 +𠯠 噅 +𠰱 㘉 +𠰷 嚧 +𠱞 囃 +𠲥 𡅏 +𠴛 𡃕 +𠴢 𡄔 +𠵸 𡄣 +𠵾 㗲 +𡋀 𡓾 +𡋗 𡑭 +𡋤 壗 +𡍣 𡔖 +𡒄 壈 +𡝠 㜷 +𡞋 㜗 +𡞱 㜢 +𡠟 孎 +𡥧 孻 +𡭜 𡮉 +𡭬 𡮣 +𡳃 𡳳 +𡳒 𦘧 +𡶴 嵼 +𡸃 𡽗 +𡺃 嶈 +𡺄 嶘 +𢋈 㢝 +𢗓 㦛 +𢘙 𢤱 +𢘝 𢣚 +𢘞 𢣭 +𢙏 愻 +𢙐 憹 +𢙑 𢠼 +𢙒 憢 +𢙓 懀 +𢛯 㦎 +𢠁 懎 +𢢐 𤢻 +𢧐 戰 +𢫊 𢷮 +𢫞 𢶫 +𢫬 摋 +𢬍 擫 +𢬦 𢹿 +𢭏 擣 +𢽾 斅 +𣃁 斸 +𣆐 曥 +𣈣 𣋋 +𣍨 𦢈 +𣍯 腪 +𣍰 脥 +𣎑 臗 +𣏢 槫 +𣐕 桱 +𣐤 欍 +𣑶 𣠲 +𣒌 楇 +𣓿 橯 +𣔌 樤 +𣗊 樠 +𣗋 欓 +𣗙 㰙 +𣘐 㯤 +𣘓 𣞻 +𣘴 檭 +𣘷 𣝕 +𣚚 欘 +𣞎 𣠩 +𣨼 殢 +𣭤 𣯴 +𣯣 𣯩 +𣱝 氭 +𣲗 湋 +𣲘 潕 +𣳆 㵗 +𣶩 澅 +𣶫 𣿉 +𣶭 𪷓 +𣷷 𤅶 +𣸣 濆 +𣺼 灙 +𣺽 𤁣 +𣽷 瀃 +𤆡 熓 +𤆢 㷍 +𤇃 爄 +𤇄 熌 +𤇭 爖 +𤇹 熚 +𤈶 熉 +𤈷 㷿 +𤊀 𤒎 +𤊰 𤓩 +𤋏 熡 +𤎺 𤓎 +𤎻 𤑳 +𤙯 𤛮 +𤝢 𤢟 +𤞃 獩 +𤞤 玁 +𤠋 㺏 +𤦀 瓕 +𤩽 瓛 +𤳄 𤳸 +𤶊 癐 +𤶧 𤸫 +𤻊 㿗 +𤽯 㿧 +𤾀 皟 +𤿲 麬 +𥁢 䀉 +𥅘 𥌃 +𥅴 䀹 +𥅿 𥊝 +𥆧 瞤 +𥇢 䁪 +𥎝 䂎 +𥐟 礒 +𥐯 𥖅 +𥐰 𥕥 +𥐻 碙 +𥞦 𥞵 +𥧂 𥨐 +𥩟 竚 +𥩺 𥪂 +𥫣 籅 +𥬀 䉙 +𥬞 籋 +𥬠 篘 +𥭉 𥵊 +𥮋 𥸠 +𥮜 䉲 +𥮾 篸 +𥱔 𥵃 +𥹥 𥼽 +𥺅 䊭 +𥺇 𥽖 +𦈈 𥿊 +𦈉 緷 +𦈋 綇 +𦈌 綀 +𦈎 繟 +𦈏 緍 +𦈐 縺 +𦈑 緸 +𦈒 𦂅 +𦈓 䋿 +𦈔 縎 +𦈕 緰 +𦈖 䌈 +𦈗 𦃄 +𦈘 䌋 +𦈙 䌰 +𦈚 縬 +𦈛 繓 +𦈜 䌖 +𦈝 繏 +𦈞 䌟 +𦈟 䌝 +𦈠 䌥 +𦈡 繻 +𦍠 䍽 +𦛨 朥 +𦝼 膢 +𦟗 𦣎 +𦨩 𦪽 +𦰏 蓧 +𦰴 䕳 +𦶟 爇 +𦶻 𦾟 +𦻕 蘟 +𧉐 𧕟 +𧉞 䗿 +𧌥 𧎈 +𧏖 蠙 +𧏗 蠀 +𧑏 蠾 +𧒭 𧔥 +𧜭 䙱 +𧝝 襰 +𧝧 𧟀 +𧮪 詀 +𧳕 𧳟 +𧹑 䞈 +𧹒 買 +𧹓 𧶔 +𧹔 賬 +𧹕 䝻 +𧹖 賟 +𧹗 贃 +𧿈 𨇁 +𨀁 躘 +𨀱 𨄣 +𨁴 𨅍 +𨂺 𨈊 +𨄄 𨈌 +𨅛 䠱 +𨅫 𨇞 +𨅬 躝 +𨉗 軉 +𨐅 軗 +𨐆 𨊻 +𨐇 𨏠 +𨐈 輄 +𨐉 𨎮 +𨐊 𨏥 +𨑹 䢨 +𨟳 𨣞 +𨠨 𨣧 +𨡙 𨢿 +𨡺 𨣈 +𨤰 𨤻 +𨰾 鎷 +𨰿 釳 +𨱀 𨥛 +𨱁 鈠 +𨱂 鈋 +𨱃 鈲 +𨱄 鈯 +𨱅 鉁 +𨱆 龯 +𨱇 銶 +𨱈 鋉 +𨱉 鍄 +𨱊 𨧱 +𨱋 錂 +𨱌 鏆 +𨱍 鎯 +𨱎 鍮 +𨱏 鎝 +𨱐 𨫒 +𨱑 鐄 +𨱒 鏉 +𨱓 鐎 +𨱔 鐏 +𨱕 𨮂 +𨱖 䥩 +𨷿 䦳 +𨸀 𨳕 +𨸁 𨳑 +𨸂 閍 +𨸃 閐 +𨸄 䦘 +𨸅 𨴗 +𨸆 𨵩 +𨸇 𨵸 +𨸉 𨶀 +𨸊 𨶏 +𨸋 𨶲 +𨸌 𨶮 +𨸎 𨷲 +𨸘 𨽏 +𨸟 䧢 +𩏼 䪏 +𩏽 𩏪 +𩏾 𩎢 +𩏿 䪘 +𩐀 䪗 +𩓋 顂 +𩖕 𩓣 +𩖖 顃 +𩖗 䫴 +𩙥 颰 +𩙦 𩗀 +𩙧 䬞 +𩙨 𩘹 +𩙩 𩘀 +𩙪 颷 +𩙫 颾 +𩙬 𩘺 +𩙭 𩘝 +𩙮 䬘 +𩙯 䬝 +𩙰 𩙈 +𩟿 𩚛 +𩠀 𩚥 +𩠁 𩚵 +𩠂 𩛆 +𩠃 𩛩 +𩠅 𩟐 +𩠆 𩜦 +𩠇 䭀 +𩠈 䭃 +𩠉 𩜇 +𩠊 𩜵 +𩠋 𩝔 +𩠌 餸 +𩠎 𩞄 +𩠏 𩞦 +𩠠 𩠴 +𩡖 𩡣 +𩧦 𩡺 +𩧨 駎 +𩧩 𩤊 +𩧪 䮾 +𩧫 駚 +𩧬 𩢡 +𩧭 䭿 +𩧮 𩢾 +𩧯 驋 +𩧰 䮝 +𩧱 𩥉 +𩧲 駧 +𩧳 𩢸 +𩧴 駩 +𩧵 𩢴 +𩧶 𩣏 +𩧸 𩣫 +𩧺 駶 +𩧻 𩣵 +𩧼 𩣺 +𩧿 䮠 +𩨀 騔 +𩨁 䮞 +𩨂 驄 +𩨃 騝 +𩨄 騪 +𩨅 𩤸 +𩨆 𩤙 +𩨇 䮫 +𩨈 騟 +𩨉 𩤲 +𩨊 騚 +𩨋 𩥄 +𩨌 𩥑 +𩨍 𩥇 +𩨎 龭 +𩨏 䮳 +𩨐 𩧆 +𩩈 䯤 +𩬣 𩭙 +𩬤 𩰀 +𩭹 鬖 +𩯒 𩯳 +𩰰 𩰹 +𩲒 𩳤 +𩴌 𩴵 +𩽹 魥 +𩽺 𩵩 +𩽻 𩵹 +𩽼 鯶 +𩽽 𩶱 +𩽾 鮟 +𩽿 𩶰 +𩾁 鯄 +𩾂 䲖 +𩾃 鮸 +𩾄 𩷰 +𩾅 𩸃 +𩾆 𩸦 +𩾇 鯱 +𩾈 䱙 +𩾊 䱬 +𩾋 䱰 +𩾌 鱇 +𩾎 𩽇 +𪉂 䲰 +𪉃 鳼 +𪉄 𩿪 +𪉅 𪀦 +𪉆 鴲 +𪉈 鴜 +𪉉 𪁈 +𪉊 鷨 +𪉋 𪀾 +𪉌 𪁖 +𪉍 鵚 +𪉎 𪂆 +𪉏 𪃏 +𪉐 𪃍 +𪉑 鷔 +𪉒 𪄕 +𪉔 𪄆 +𪉕 𪇳 +𪎈 䴬 +𪎉 麲 +𪎊 麨 +𪎋 䴴 +𪎌 麳 +𪑅 䵳 +𪔭 𪔵 +𪚏 𪘀 +𪚐 𪘯 +𪜎 𠿕 +𪞝 凙 +𪟎 㔋 +𪟝 勣 +𪠀 𧷎 +𪠟 㓄 +𪠡 𠬙 +𪠳 唓 +𪠵 㖮 +𪠸 嚛 +𪠺 𠽃 +𪠽 噹 +𪡀 嘺 +𪡃 嘪 +𪡋 噞 +𪡏 嗹 +𪡛 㗿 +𪡞 嘳 +𪡺 𡃄 +𪢌 㘓 +𪢐 𡃤 +𪢒 𡂡 +𪢕 嚽 +𪢖 𡅯 +𪢠 囒 +𪢮 圞 +𪢸 墲 +𪣆 埬 +𪣒 堚 +𪣻 塿 +𪤄 𡓁 +𪤚 壣 +𪥠 𧹈 +𪥫 孇 +𪥰 嬣 +𪥿 嬻 +𪧀 孾 +𪧘 寠 +𪨊 㞞 +𪨗 屩 +𪨧 崙 +𪨩 𡸗 +𪨶 輋 +𪨷 巗 +𪨹 𡹬 +𪩇 㟺 +𪩎 巊 +𪩘 巘 +𪩛 𡿖 +𪩷 幝 +𪩸 幩 +𪪏 廬 +𪪑 㢗 +𪪞 廧 +𪪴 𢍰 +𪪼 彃 +𪫌 徿 +𪫡 𢤩 +𪫷 㦞 +𪫺 憸 +𪬚 𢣐 +𪬯 𢤿 +𪭝 𢯷 +𪭢 摐 +𪭧 擟 +𪭯 𢶒 +𪭵 掚 +𪭾 撊 +𪮃 㨻 +𪮋 㩋 +𪮖 撧 +𪮳 𢺳 +𪮶 攋 +𪯋 㪎 +𪰶 曊 +𪱥 膹 +𪱷 梖 +𪲎 櫅 +𪲔 欐 +𪲛 檵 +𪲮 櫠 +𪳍 欇 +𪳗 𣜬 +𪴙 欑 +𪵑 毊 +𪵣 霼 +𪵱 濿 +𪶄 溡 +𪶒 𤄷 +𪶮 𣽏 +𪷍 㵾 +𪷽 灒 +𪸕 熂 +𪸩 煇 +𪹀 𤑹 +𪹠 𤓌 +𪹳 爥 +𪹹 𤒻 +𪺣 𤘀 +𪺪 𤜆 +𪺭 犞 +𪺷 獊 +𪺸 𤠮 +𪺻 㺜 +𪺽 猌 +𪻐 瑽 +𪻨 瓄 +𪻲 瑻 +𪻺 璝 +𪼋 㻶 +𪼴 𤬅 +𪽈 畼 +𪽝 𤳷 +𪽪 痮 +𪽭 𤷃 +𪽮 㿖 +𪽴 𤺔 +𪽷 瘱 +𪾔 盨 +𪾢 睍 +𪾣 眝 +𪾦 矑 +𪾸 矉 +𪿊 𥏝 +𪿞 𥖲 +𪿫 礮 +𪿵 𥗇 +𫀌 𥜰 +𫀓 𥜐 +𫀨 䅐 +𫀬 䅳 +𫀮 𥢷 +𫁂 䆉 +𫁟 竱 +𫁡 鴗 +𫁱 𥶽 +𫁲 䉑 +𫁳 𥯤 +𫁷 䉶 +𫁺 𥴼 +𫂃 簢 +𫂆 簂 +𫂈 䉬 +𫂖 𥴨 +𫂿 𥻦 +𫃗 𩏷 +𫄙 糺 +𫄚 䊺 +𫄛 紟 +𫄜 䋃 +𫄝 𥾯 +𫄞 䋔 +𫄟 絁 +𫄠 絙 +𫄡 絧 +𫄢 絥 +𫄣 繷 +𫄤 繨 +𫄥 纚 +𫄦 𦀖 +𫄧 綖 +𫄨 絺 +𫄩 䋦 +𫄪 𦅇 +𫄫 綟 +𫄬 緤 +𫄭 緮 +𫄮 䋼 +𫄯 𦃩 +𫄰 縍 +𫄱 繬 +𫄲 縸 +𫄳 縰 +𫄴 繂 +𫄵 𦅈 +𫄶 繈 +𫄷 繶 +𫄸 纁 +𫄹 纗 +𫅅 䍤 +𫅗 羵 +𫅥 𦒀 +𫅭 䎙 +𫅼 𦔖 +𫆏 聻 +𫆝 𦟼 +𫆫 𦡝 +𫇘 𦧺 +𫇛 艣 +𫇪 𦱌 +𫇭 蔿 +𫇴 蒭 +𫇽 蕽 +𫈉 蕳 +𫈎 葝 +𫈟 蔯 +𫈵 蕝 +𫉁 薆 +𫉄 藷 +𫊪 䗅 +𫊮 蠦 +𫊸 蟜 +𫊹 𧒯 +𫊻 蟳 +𫋇 蟂 +𫋌 蟘 +𫋲 䙔 +𫋷 襗 +𫋹 襓 +𫋻 襘 +𫌀 襀 +𫌇 襵 +𫌋 𧞫 +𫌨 覼 +𫌪 覛 +𫌫 𧡴 +𫌬 𧢄 +𫌭 覹 +𫌯 䚩 +𫍐 𧭹 +𫍙 訑 +𫍚 訞 +𫍛 訜 +𫍜 詓 +𫍝 諫 +𫍞 𧦝 +𫍟 𧦧 +𫍠 䛄 +𫍡 詑 +𫍢 譊 +𫍣 詷 +𫍤 譑 +𫍥 誂 +𫍦 譨 +𫍧 誺 +𫍨 誫 +𫍩 諣 +𫍪 誋 +𫍫 䛳 +𫍬 誷 +𫍭 𧩕 +𫍮 誳 +𫍯 諴 +𫍰 諰 +𫍱 諯 +𫍲 謏 +𫍳 諥 +𫍴 謱 +𫍵 謸 +𫍶 𧩼 +𫍷 謉 +𫍸 謆 +𫍹 謯 +𫍺 𧫝 +𫍻 譆 +𫍼 𧬤 +𫍽 譞 +𫍾 𧭈 +𫍿 譾 +𫎆 豵 +𫎌 貗 +𫎦 贚 +𫎧 䝭 +𫎨 𧸘 +𫎩 賝 +𫎪 䞋 +𫎫 贉 +𫎬 贑 +𫎭 䞓 +𫎱 䟐 +𫎳 䟆 +𫎸 𧽯 +𫎺 䟃 +𫏃 䠆 +𫏆 蹳 +𫏋 蹻 +𫏌 𨂐 +𫏐 蹔 +𫏑 𨇽 +𫏕 𨆪 +𫏞 𨇰 +𫏨 𨇤 +𫐄 軏 +𫐅 軕 +𫐆 轣 +𫐇 軜 +𫐈 軷 +𫐉 軨 +𫐊 軬 +𫐋 𨎌 +𫐌 軿 +𫐍 𨌈 +𫐎 輢 +𫐏 輖 +𫐐 輗 +𫐑 輨 +𫐒 輷 +𫐓 輮 +𫐔 𨍰 +𫐕 轊 +𫐖 轇 +𫐗 轐 +𫐘 轗 +𫐙 轠 +𫐷 遱 +𫑘 鄟 +𫑡 鄳 +𫑷 醶 +𫓥 釟 +𫓦 釨 +𫓧 鈇 +𫓨 鈛 +𫓩 鏦 +𫓪 鈆 +𫓫 𨥟 +𫓬 鉔 +𫓭 鉠 +𫓮 𨪕 +𫓯 銈 +𫓰 銊 +𫓱 鐈 +𫓲 銁 +𫓳 𨰋 +𫓴 鉾 +𫓵 鋠 +𫓶 鋗 +𫓷 𫒡 +𫓸 錽 +𫓹 錤 +𫓺 鐪 +𫓻 錜 +𫓼 𨨛 +𫓽 錝 +𫓾 錥 +𫓿 𨨢 +𫔀 鍊 +𫔁 鐼 +𫔂 鍉 +𫔃 𨰲 +𫔄 鍒 +𫔅 鎍 +𫔆 䥯 +𫔇 鎞 +𫔈 鎙 +𫔉 𨰃 +𫔊 鏥 +𫔋 䥗 +𫔌 鏾 +𫔍 鐇 +𫔎 鐍 +𫔏 𨬖 +𫔐 𨭸 +𫔑 𨭖 +𫔒 𨮳 +𫔓 𨯟 +𫔔 鑴 +𫔕 𨰥 +𫔖 𨲳 +𫔭 開 +𫔮 閒 +𫔯 閗 +𫔰 閞 +𫔲 𨴹 +𫔴 閵 +𫔵 䦯 +𫔶 闑 +𫔽 𨼳 +𫕚 𩀨 +𫕥 霣 +𫕨 𩅙 +𫖃 靧 +𫖅 䪊 +𫖇 鞾 +𫖑 𩎖 +𫖒 韠 +𫖓 𩏂 +𫖔 韛 +𫖕 韝 +𫖖 𩏠 +𫖪 𩑔 +𫖫 䪴 +𫖬 䪾 +𫖭 𩒎 +𫖮 顗 +𫖯 頫 +𫖰 䫂 +𫖱 䫀 +𫖲 䫟 +𫖳 頵 +𫖴 𩔳 +𫖵 𩓥 +𫖶 顅 +𫖷 𩔑 +𫖸 願 +𫖹 顣 +𫖺 䫶 +𫗇 䫻 +𫗈 𩗓 +𫗉 𩗴 +𫗊 䬓 +𫗋 飋 +𫗚 𩟗 +𫗞 飦 +𫗟 䬧 +𫗠 餦 +𫗡 𩚩 +𫗢 飵 +𫗣 飶 +𫗤 𩛌 +𫗥 餫 +𫗦 餔 +𫗧 餗 +𫗨 𩛡 +𫗩 饠 +𫗪 餧 +𫗫 餬 +𫗬 餪 +𫗭 餵 +𫗮 餭 +𫗯 餱 +𫗰 䭔 +𫗱 䭑 +𫗳 𩝽 +𫗴 饘 +𫗵 饟 +𫘛 馯 +𫘜 馼 +𫘝 駃 +𫘞 駞 +𫘟 駊 +𫘠 駤 +𫘡 駫 +𫘣 駻 +𫘤 騃 +𫘥 騉 +𫘦 騊 +𫘧 騄 +𫘨 騠 +𫘩 騜 +𫘪 騵 +𫘫 騴 +𫘬 騱 +𫘭 騻 +𫘮 䮰 +𫘯 驓 +𫘰 驙 +𫘱 驨 +𫘽 鬠 +𫙂 𩯁 +𫚈 鱮 +𫚉 魟 +𫚊 鰑 +𫚋 鱄 +𫚌 魦 +𫚍 魵 +𫚎 𩶁 +𫚏 䱁 +𫚐 䱀 +𫚑 鮅 +𫚒 鮄 +𫚓 鮤 +𫚔 鮰 +𫚕 鰤 +𫚖 鮆 +𫚗 鮯 +𫚘 𩻮 +𫚙 鯆 +𫚚 鮿 +𫚛 鮵 +𫚜 䲅 +𫚝 𩸄 +𫚞 鯬 +𫚟 𩸡 +𫚠 䱧 +𫚡 鯞 +𫚢 鰋 +𫚣 鯾 +𫚤 鰦 +𫚥 鰕 +𫚦 鰫 +𫚧 鰽 +𫚨 𩻗 +𫚩 𩻬 +𫚪 鱊 +𫚫 鱢 +𫚬 𩼶 +𫚭 鱲 +𫛚 鳽 +𫛛 鳷 +𫛜 鴀 +𫛝 鴅 +𫛞 鴃 +𫛟 鸗 +𫛠 𩿤 +𫛡 鴔 +𫛢 鸋 +𫛣 鴥 +𫛤 鴐 +𫛥 鵊 +𫛦 鴮 +𫛧 𪀖 +𫛨 鵧 +𫛩 鴳 +𫛪 鴽 +𫛫 鶰 +𫛬 䳜 +𫛭 鵟 +𫛮 䳤 +𫛯 鶭 +𫛰 䳢 +𫛱 鵫 +𫛲 鵰 +𫛳 鵩 +𫛴 鷤 +𫛵 鶌 +𫛶 鶒 +𫛷 鶦 +𫛸 鶗 +𫛹 𪃧 +𫛺 䳧 +𫛻 𪃒 +𫛼 䳫 +𫛽 鷅 +𫛾 𪆷 +𫜀 鷐 +𫜁 鷩 +𫜂 𪅂 +𫜃 鷣 +𫜄 鷷 +𫜅 䴋 +𫜊 𪉸 +𫜑 麷 +𫜒 䴱 +𫜓 𪌭 +𫜔 䴽 +𫜕 𪍠 +𫜙 䵴 +𫜟 𪓰 +𫜨 䶕 +𫜩 齧 +𫜪 齩 +𫜫 𫜦 +𫜬 齰 +𫜭 齭 +𫜮 齴 +𫜯 𪙏 +𫜰 齾 +𫜲 龓 +𫜳 䶲 +𫝈 㑮 +𫝋 𠐊 +𫝦 㛝 +𫝧 㜐 +𫝨 媈 +𫝩 嬦 +𫝪 𡟫 +𫝫 婡 +𫝬 嬇 +𫝭 孆 +𫝮 孄 +𫝵 嶹 +𫞅 𦠅 +𫞗 潣 +𫞚 澬 +𫞛 㶆 +𫞝 灍 +𫞠 爧 +𫞡 爃 +𫞢 𤛱 +𫞣 㹽 +𫞥 珼 +𫞦 璾 +𫞧 𤩂 +𫞨 璼 +𫞩 璊 +𫞷 𥢶 +𫟃 絍 +𫟄 綋 +𫟅 綡 +𫟆 緟 +𫟇 𦆲 +𫟑 䖅 +𫟕 䕤 +𫟞 訨 +𫟟 詊 +𫟠 譂 +𫟡 誴 +𫟢 䜖 +𫟤 䡐 +𫟥 䡩 +𫟦 䡵 +𫟫 𨞺 +𫟬 𨟊 +𫟲 釚 +𫟳 釲 +𫟴 鈖 +𫟵 鈗 +𫟶 銏 +𫟷 鉝 +𫟸 鉽 +𫟹 鉷 +𫟺 䤤 +𫟻 銂 +𫟼 鐽 +𫟽 𨧰 +𫟾 𨩰 +𫟿 鎈 +𫠀 䥄 +𫠁 鑉 +𫠂 閝 +𫠅 韚 +𫠆 頍 +𫠇 𩖰 +𫠈 䫾 +𫠊 䮄 +𫠋 騼 +𫠌 𩦠 +𫠏 𩵦 +𫠐 魽 +𫠑 䱸 +𫠒 鱆 +𫠖 𩿅 +𫠜 齯 +𫢸 僤 +𫧃 𣍐 +𫧮 𪋿 +𫬐 㘔 +𫮃 墠 +𫰛 娙 +𫶇 嵽 +𫷷 廞 +𫸩 彄 +𬀩 暐 +𬬭 錀 +𬬻 鑪 +𬭊 𨧀 +𬭛 𨨏 +𬭭 鏚 +𬭳 𨭎 +𬭶 𨭆 +𬶋 鮈 +𬶍 鮀 +𬶏 鮠 +𬶟 鯻 +𬸪 鷭 +𬸯 鷿 +𰬸 繐 +𰰨 菕 +𰶎 譅 +𰾄 鋂 +𰾭 鑀 +𱊜 𪈼 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/STPhrases.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/STPhrases.txt new file mode 100644 index 0000000000000000000000000000000000000000..4dc2669191f811857154ed011a64367f9694577b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/STPhrases.txt @@ -0,0 +1,49041 @@ +㓦划 㓦劃 +一丝不挂 一絲不掛 +一了心愿 一了心願 +一了百了 一了百了 +一了百当 一了百當 +一争两丑 一爭兩醜 +一伙 一夥 +一伙人 一夥人 +一伙头 一夥頭 +一偿宿愿 一償宿願 +一元复始 一元復始 +一克 一克 +一党 一黨 +一冲性子 一沖性子 +一准 一準 +一出剧 一齣劇 +一出去 一出去 +一出场 一出場 +一出子 一齣子 +一出戏 一齣戲 +一出来 一出來 +一出生 一出生 +一出祁山 一出祁山 +一分收获 一分收穫 +一分耕耘 一分耕耘 +一分钟 一分鐘 +一划 一劃 +一别 一別 +一别多年 一別多年 +一别头 一彆頭 +一刻千金 一刻千金 +一前一后 一前一後 +一力承当 一力承當 +一卷 一卷 +一厘一毫 一釐一毫 +一厢情愿 一廂情願 +一去不回 一去不回 +一去不复 一去不復 +一去不复返 一去不復返 +一发 一發 +一发之差 一髮之差 +一发之间 一髮之間 +一发千钧 一髮千鈞 +一口钟 一口鐘 +一只 一隻 +一台 一臺 +一台台 一臺臺 +一叶 一葉 +一叶兰 一葉蘭 +一叶扁舟 一葉扁舟 +一叶知秋 一葉知秋 +一号木杆 一號木桿 +一吊 一吊 +一吊钱 一吊錢 +一同 一同 +一向 一向 +一周 一週 +一周天 一周天 +一周年 一週年 +一周遭 一周遭 +一哄 一鬨 +一哄而上 一哄而上 +一哄而散 一鬨而散 +一哄而起 一哄而起 +一哄而集 一哄而集 +一喊出 一喊出 +一回 一回 +一回事 一回事 +一团 一團 +一团和气 一團和氣 +一团团 一團團 +一团漆黑 一團漆黑 +一团火 一團火 +一团糟 一團糟 +一国两制 一國兩制 +一地胡拿 一地胡拿 +一地里 一地裏 +一块面 一塊麪 +一坛 一罈 +一坛坛 一罈罈 +一坛死水 一壇死水 +一塌糊涂 一塌糊塗 +一壶千金 一壺千金 +一夜致富 一夜致富 +一大伙 一大夥 +一天后 一天後 +一天星斗 一天星斗 +一天钟 一天鐘 +一夫一妻 一夫一妻 +一夫当关 一夫當關 +一妻制 一妻制 +一妻多夫 一妻多夫 +一孔出气 一孔出氣 +一字一板 一字一板 +一字千金 一字千金 +一寸秋波 一寸秋波 +一将功成 一將功成 +一展长才 一展長才 +一干 一干 +一干二净 一乾二淨 +一干人 一干人 +一干家中 一干家中 +一干弟兄 一干弟兄 +一干弟子 一干弟子 +一干而尽 一乾而盡 +一干部下 一干部下 +一并 一併 +一开出来 一開出來 +一弦 一弦 +一当 一當 +一心向上 一心向上 +一念 一念 +一念三千 一念三千 +一扎 一紮 +一托头 一托頭 +一托气 一托氣 +一扣 一扣 +一折 一折 +一折一磨 一折一磨 +一折两段 一折兩段 +一折八扣 一折八扣 +一拍即合 一拍即合 +一挂 一掛 +一挂之下 一掛之下 +一掷千金 一擲千金 +一掷百万 一擲百萬 +一搜 一搜 +一摇一摆 一搖一擺 +一摇三摆 一搖三擺 +一播出 一播出 +一斗 一斗 +一斗再斗 一鬥再鬥 +一斗斗 一斗斗 +一方面 一方面 +一无所获 一無所獲 +一日万机 一日萬機 +一日三秋 一日三秋 +一日千里 一日千里 +一日叫娘 一日叫孃 +一早起了 一早起了 +一时糊涂 一時糊塗 +一曲 一曲 +一曲千金 一曲千金 +一曲阳关 一曲陽關 +一本万利 一本萬利 +一杆 一杆 +一杆进洞 一桿進洞 +一杠 一槓 +一杯 一杯 +一杯杯 一杯杯 +一杯羹 一杯羹 +一松 一鬆 +一板 一板 +一板一眼 一板一眼 +一板三眼 一板三眼 +一柜 一櫃 +一树百获 一樹百穫 +一根烟 一根菸 +一死了之 一死了之 +一毫一发 一毫一髮 +一池秋水 一池秋水 +一沐三捉发 一沐三捉髮 +一沐三握发 一沐三握髮 +一波三折 一波三折 +一泻千里 一瀉千里 +一派胡言 一派胡言 +一流人才 一流人才 +一涂 一塗 +一游 一遊 +一溜烟 一溜煙 +一点钟 一點鐘 +一物一制 一物一制 +一物克一物 一物剋一物 +一百多万 一百多萬 +一百廿万 一百廿萬 +一目了然 一目瞭然 +一相情愿 一相情願 +一看出 一看出 +一碗面 一碗麪 +一碧万顷 一碧萬頃 +一禾九穗 一禾九穗 +一种 一種 +一秒钟 一秒鐘 +一穗三秀 一穗三秀 +一笑了之 一笑了之 +一笑千金 一笑千金 +一笔划 一筆劃 +一答一合 一答一合 +一签 一簽 +一箭之仇 一箭之仇 +一箭双雕 一箭雙鵰 +一系 一系 +一系列 一系列 +一统志 一統志 +一网打尽 一網打盡 +一翻出 一翻出 +一胎制 一胎制 +一至于此 一至於此 +一致 一致 +一致字 一致字 +一致性 一致性 +一致百虑 一致百慮 +一般等价 一般等價 +一落千丈 一落千丈 +一表 一表 +一表人才 一表人才 +一表人材 一表人材 +一表人物 一表人物 +一表非俗 一表非俗 +一表非凡 一表非凡 +一见钟情 一見鍾情 +一见面 一見面 +一视同仁 一視同仁 +一览表 一覽表 +一触即发 一觸即發 +一言不发 一言不發 +一言不合 一言不合 +一言千金 一言千金 +一言已定千金不移 一言已定千金不移 +一言既出 一言既出 +一言既出驷马难追 一言既出駟馬難追 +一言难尽 一言難盡 +一讲出 一講出 +一语不发 一語不發 +一说出 一說出 +一诺值千金 一諾值千金 +一诺千金 一諾千金 +一败涂地 一敗塗地 +一赞 一讚 +一走了之 一走了之 +一起干 一起幹 +一蹴可几 一蹴可幾 +一身作事一身当 一身作事一身當 +一轨同风 一軌同風 +一辞莫赞 一辭莫贊 +一递里 一遞裏 +一逞兽欲 一逞獸慾 +一道烟 一道煙 +一醉解千愁 一醉解千愁 +一里 一里 +一里一外 一裏一外 +一针 一針 +一针见血 一針見血 +一锅面 一鍋麪 +一锹掘个井 一鍬掘個井 +一院制 一院制 +一雨成秋 一雨成秋 +一面 一面 +一面之交 一面之交 +一面之缘 一面之緣 +一面之识 一面之識 +一面之词 一面之詞 +一面之辞 一面之辭 +一面之雅 一面之雅 +一面倒 一面倒 +一面儿官司 一面兒官司 +一面如旧 一面如舊 +一面点 一面點 +一飞冲天 一飛沖天 +一食万钱 一食萬錢 +一饭千金 一飯千金 +一饮而尽 一飲而盡 +一马当先 一馬當先 +一麾出守 一麾出守 +一鼓一板 一鼓一板 +一鼻孔出气 一鼻孔出氣 +一龙生九种种种各别 一龍生九種種種各別 +丁一确二 丁一確二 +丁丁冬冬 丁丁冬冬 +丁丁当当 丁丁當當 +丁丑 丁丑 +丁伯升 丁伯升 +丁克 丁克 +丁冬 丁冬 +丁固生松 丁固生松 +丁娘十索 丁娘十索 +丁字梁 丁字梁 +丁当 丁當 +丁柏升 丁柏升 +丁种 丁種 +丁种维生素 丁種維生素 +丁铃当啷 丁鈴噹啷 +丁零当啷 丁零當啷 +丁鸿志 丁鴻志 +七万 七萬 +七万三千 七萬三千 +七万五千 七萬五千 +七万八千 七萬八千 +七万六千 七萬六千 +七万四千 七萬四千 +七个 七個 +七个八个 七個八個 +七了八当 七了八當 +七余 七餘 +七八下里 七八下裏 +七出 七出 +七出祁山 七出祁山 +七分钟 七分鐘 +七划 七劃 +七十七万 七十七萬 +七十七国集团 七十七國集團 +七十五万 七十五萬 +七千 七千 +七千两百 七千兩百 +七发 七發 +七只 七隻 +七台 七臺 +七台河 七臺河 +七台河市 七臺河市 +七叶胆 七葉膽 +七周 七週 +七回 七回 +七团 七團 +七国集团 七國集團 +七坛 七罈 +七天后 七天後 +七娘 七娘 +七娘妈 七孃媽 +七孔生烟 七孔生煙 +七巧板 七巧板 +七弦 七絃 +七彩 七彩 +七彩缤纷 七彩繽紛 +七彩虹 七彩虹 +七情六欲 七情六慾 +七扎 七紮 +七折 七折 +七折八扣 七折八扣 +七政四余 七政四餘 +七星坛 七星壇 +七星岩 七星巖 +七星板 七星板 +七星瓢虫 七星瓢蟲 +七杯 七杯 +七步之才 七步之才 +七步奇才 七步奇才 +七点钟 七點鐘 +七百万 七百萬 +七百多万 七百多萬 +七种 七種 +七秒钟 七秒鐘 +七窍冒烟 七竅冒煙 +七窍生烟 七竅生煙 +七色板 七色板 +七里 七里 +七里河 七里河 +七里河区 七里河區 +七里香 七里香 +万一 萬一 +万一只 萬一只 +万万 萬萬 +万万不可 萬萬不可 +万万千千 萬萬千千 +万万岁 萬萬歲 +万丈 萬丈 +万丈光芒 萬丈光芒 +万丈深渊 萬丈深淵 +万丈竿头 萬丈竿頭 +万丈红尘 萬丈紅塵 +万丈高楼平地起 萬丈高樓平地起 +万不及一 萬不及一 +万不可失 萬不可失 +万不失一 萬不失一 +万不得已 萬不得已 +万世 萬世 +万世一时 萬世一時 +万世师表 萬世師表 +万个 萬個 +万丰 萬豐 +万丹 萬丹 +万丹乡 萬丹鄉 +万乘 萬乘 +万乘之国 萬乘之國 +万乘之尊 萬乘之尊 +万事 萬事 +万事亨通 萬事亨通 +万事俱备只欠东风 萬事俱備只欠東風 +万事具备 萬事具備 +万事大吉 萬事大吉 +万事如意 萬事如意 +万事得 萬事得 +万事皆从急中错 萬事皆從急中錯 +万事皆休 萬事皆休 +万事皆备 萬事皆備 +万事起头难 萬事起頭難 +万事达 萬事達 +万事达卡 萬事達卡 +万事通 萬事通 +万人 萬人 +万人之敌 萬人之敵 +万人之敵 萬人之敵 +万人坑 萬人坑 +万人敌 萬人敵 +万人空巷 萬人空巷 +万人迷 萬人迷 +万仞 萬仞 +万代 萬代 +万代一时 萬代一時 +万代兰 萬代蘭 +万代千秋 萬代千秋 +万份 萬份 +万众 萬衆 +万众一心 萬衆一心 +万众欢腾 萬衆歡騰 +万众瞩目 萬衆矚目 +万位 萬位 +万余 萬餘 +万余只 萬餘隻 +万余里 萬餘里 +万俟 万俟 +万倍 萬倍 +万儿 萬兒 +万儿八千 萬兒八千 +万元 萬元 +万元户 萬元戶 +万全 萬全 +万全之策 萬全之策 +万全之计 萬全之計 +万全县 萬全縣 +万全街 萬全街 +万兽之王 萬獸之王 +万几 萬幾 +万分 萬分 +万分之一 萬分之一 +万分感激 萬分感激 +万分痛苦 萬分痛苦 +万别千差 萬別千差 +万剐千刀 萬剮千刀 +万劫 萬劫 +万劫不复 萬劫不復 +万千 萬千 +万华 萬華 +万华区 萬華區 +万华站 萬華站 +万博宣伟 萬博宣偉 +万博省 萬博省 +万卷 萬卷 +万卷书 萬卷書 +万历 萬曆 +万县 萬縣 +万县地区 萬縣地區 +万县市 萬縣市 +万县港 萬縣港 +万变不离其宗 萬變不離其宗 +万古 萬古 +万古不灭 萬古不滅 +万古千秋 萬古千秋 +万古流芳 萬古流芳 +万古留芳 萬古留芳 +万古长新 萬古長新 +万古长春 萬古長春 +万古长青 萬古長青 +万只 萬隻 +万叶 萬葉 +万名 萬名 +万向节 萬向節 +万国 萬國 +万国公报 萬國公報 +万国公法 萬國公法 +万国宫 萬國宮 +万国旗 萬國旗 +万国码 萬國碼 +万国邮联 萬國郵聯 +万国音标 萬國音標 +万圆 萬圓 +万圣节 萬聖節 +万坛 萬罈 +万境归空 萬境歸空 +万壑 萬壑 +万壑争流 萬壑爭流 +万天后 萬天後 +万夫 萬夫 +万夫不当 萬夫不當 +万夫莫当 萬夫莫當 +万夫莫敌 萬夫莫敵 +万头攒动 萬頭攢動 +万姓 萬姓 +万姓统谱 萬姓統譜 +万字 萬字 +万宁市 萬寧市 +万安 萬安 +万安县 萬安縣 +万宝华 萬寶華 +万宝囊 萬寶囊 +万宝常 萬寶常 +万宝路 萬寶路 +万家 萬家 +万家乐 萬家樂 +万家灯火 萬家燈火 +万家生佛 萬家生佛 +万家香 萬家香 +万寿 萬壽 +万寿千秋 萬壽千秋 +万寿山 萬壽山 +万寿无疆 萬壽無疆 +万寿果 萬壽果 +万寿菊 萬壽菊 +万山 萬山 +万山特区 萬山特區 +万山镇 萬山鎮 +万岁 萬歲 +万岁千秋 萬歲千秋 +万岁爷 萬歲爺 +万峦 萬巒 +万峦乡 萬巒鄉 +万州区 萬州區 +万年 萬年 +万年历 萬年曆 +万年历表 萬年曆錶 +万年县 萬年縣 +万年青 萬年青 +万幸 萬幸 +万念 萬念 +万念俱灰 萬念俱灰 +万急 萬急 +万恩市 萬恩市 +万恶 萬惡 +万恶之源 萬惡之源 +万恶之首 萬惡之首 +万恶淫为首 萬惡淫爲首 +万恶滔天 萬惡滔天 +万户 萬戶 +万户侯 萬戶侯 +万户千门 萬戶千門 +万扎 萬紮 +万把 萬把 +万把块 萬把塊 +万斛泉源 萬斛泉源 +万斤 萬斤 +万斯同 萬斯同 +万方 萬方 +万旗 万旗 +万无 萬無 +万无一失 萬無一失 +万无失一 萬無失一 +万智牌 萬智牌 +万有 萬有 +万有引力 萬有引力 +万有引力定律 萬有引力定律 +万望 萬望 +万机 萬機 +万杞良 萬杞良 +万柏林 萬柏林 +万柏林区 萬柏林區 +万桶 萬桶 +万步 萬步 +万步表 萬步表 +万死 萬死 +万死一生 萬死一生 +万死不辞 萬死不辭 +万段 萬段 +万毒枯 萬毒枯 +万民伞 萬民傘 +万水千山 萬水千山 +万沙浪 萬沙浪 +万泉河 萬泉河 +万法唯识 萬法唯識 +万泰银 萬泰銀 +万洋山 萬洋山 +万源市 萬源市 +万灵丹 萬靈丹 +万灵节 萬靈節 +万灵药 萬靈藥 +万点 萬點 +万点大关 萬點大關 +万物 萬物 +万物之灵 萬物之靈 +万状 萬狀 +万用 萬用 +万用字元 萬用字元 +万用手冊 萬用手冊 +万用电表 萬用電表 +万用表 萬用表 +万盛 萬盛 +万盛区 萬盛區 +万盛溪 萬盛溪 +万目睽睽 萬目睽睽 +万石 萬石 +万福 萬福 +万福玛丽亚 萬福瑪麗亞 +万秀区 萬秀區 +万种 萬種 +万种风情 萬種風情 +万窍 萬竅 +万端 萬端 +万签插架 萬籤插架 +万箭攒心 萬箭攢心 +万箭穿心 萬箭穿心 +万箭穿身 萬箭穿身 +万箱 萬箱 +万籁 萬籟 +万籁俱寂 萬籟俱寂 +万籁无声 萬籟無聲 +万籤插架 萬籤插架 +万米 萬米 +万米长跑 萬米長跑 +万紫千红 萬紫千紅 +万红千紫 萬紅千紫 +万绪千头 萬緒千頭 +万绪千端 萬緒千端 +万维网 萬維網 +万绿丛中 萬綠叢中 +万缕千丝 萬縷千絲 +万缘 萬緣 +万能 萬能 +万能工专 萬能工專 +万能曲尺 萬能曲尺 +万能梗 萬能梗 +万能梗犬 萬能梗犬 +万能胶 萬能膠 +万能选手 萬能選手 +万能钥匙 萬能鑰匙 +万能锅 萬能鍋 +万般 萬般 +万般皆下品 萬般皆下品 +万般皆是命 萬般皆是命 +万艾可 萬艾可 +万花争艳 萬花爭豔 +万花筒 萬花筒 +万苦千辛 萬苦千辛 +万荣乡 萬榮鄉 +万荣县 萬榮縣 +万虑俱清 萬慮俱清 +万言 萬言 +万言书 萬言書 +万语千言 萬語千言 +万象 萬象 +万象包罗 萬象包羅 +万象更新 萬象更新 +万象森罗 萬象森羅 +万贯 萬貫 +万贯家产 萬貫家產 +万贯家私 萬貫家私 +万贯家财 萬貫家財 +万载千秋 萬載千秋 +万载县 萬載縣 +万道 萬道 +万那杜 萬那杜 +万邦 萬邦 +万部 萬部 +万里 萬里 +万里之望 萬里之望 +万里乡 萬里鄉 +万里侯 萬里侯 +万里同风 萬里同風 +万里封侯 萬里封侯 +万里无云 萬里無雲 +万里春愁直 萬裏春愁直 +万里晴空 萬里晴空 +万里江山 萬里江山 +万里迢迢 萬里迢迢 +万里追踪 萬里追蹤 +万里长城 萬里長城 +万里长征 萬里長征 +万里长江 萬里長江 +万里长空 萬里長空 +万里鹏程 萬里鵬程 +万里鹏翼 萬里鵬翼 +万重 萬重 +万重山 萬重山 +万金 萬金 +万金不换 萬金不換 +万金之躯 萬金之軀 +万金油 萬金油 +万钧 萬鈞 +万钧之力 萬鈞之力 +万锺 萬鍾 +万难 萬難 +万顷 萬頃 +万顷琉璃 萬頃琉璃 +万顷碧波 萬頃碧波 +万馀 萬餘 +万马 萬馬 +万马千军 萬馬千軍 +万马奔腾 萬馬奔騰 +万马皆瘖 萬馬皆瘖 +万马齐喑 萬馬齊喑 +万马齐瘖 萬馬齊瘖 +万鸦老 萬鴉老 +万齐融 萬齊融 +丈余 丈餘 +丈八灯台 丈八燈臺 +丈母娘 丈母孃 +三万 三萬 +三个 三個 +三个鼻子管 三個鼻子管 +三丰 三豐 +三仙台 三仙臺 +三代同堂 三代同堂 +三余 三餘 +三元合金 三元合金 +三元里 三元里 +三克 三克 +三党 三黨 +三八制 三八制 +三冬 三冬 +三冬两夏 三冬兩夏 +三准 三準 +三出祁山 三出祁山 +三分钟 三分鐘 +三只 三隻 +三只手 三隻手 +三台 三臺 +三台县 三臺縣 +三台联播 三臺聯播 +三叶期 三葉期 +三叶松 三葉松 +三叶草 三葉草 +三叶虫 三葉蟲 +三叹 三嘆 +三合会 三合會 +三合土 三合土 +三合房 三合房 +三合星 三合星 +三合板 三合板 +三合院 三合院 +三同 三同 +三向 三向 +三周 三週 +三周年 三週年 +三呼万岁 三呼萬歲 +三回两转 三回兩轉 +三回九曲 三回九曲 +三回九转 三回九轉 +三回五次 三回五次 +三回五转 三回五轉 +三国志 三國志 +三坛大戒 三壇大戒 +三复 三複 +三复斯言 三復斯言 +三复白圭 三復白圭 +三大发明 三大發明 +三大差别 三大差別 +三天后 三天後 +三头两面 三頭兩面 +三头马车制 三頭馬車制 +三夹板 三夾板 +三娘教子 三孃教子 +三对三斗牛 三對三鬥牛 +三对六面 三對六面 +三尸 三尸 +三尸神 三尸神 +三年制 三年制 +三弦 三絃 +三征七辟 三徵七辟 +三思台 三思臺 +三思而后 三思而後 +三思而后行 三思而後行 +三恶道 三惡道 +三战两胜 三戰兩勝 +三才 三才 +三才图会 三才圖會 +三扎 三紮 +三折肱 三折肱 +三折肱为良医 三折肱爲良醫 +三振出局 三振出局 +三方面 三方面 +三日不读书面目可憎 三日不讀書面目可憎 +三星集团 三星集團 +三月里的桃花 三月裏的桃花 +三杆 三杆 +三杠 三槓 +三杯 三杯 +三杯和万事 三杯和萬事 +三杯鸡 三杯雞 +三板 三板 +三极 三極 +三极真空 三極真空 +三极管 三極管 +三次曲线 三次曲線 +三段制 三段制 +三江并流 三江並流 +三浴三熏 三浴三熏 +三涂 三塗 +三点钟 三點鐘 +三熏三沐 三熏三沐 +三班制 三班制 +三瓦两舍 三瓦兩舍 +三瓦四舍 三瓦四舍 +三生有幸 三生有幸 +三用表 三用表 +三番四复 三番四復 +三百万 三百萬 +三百个 三百個 +三百千千 三百千千 +三百多万 三百多萬 +三百馀万 三百餘萬 +三秋 三秋 +三秒钟 三秒鐘 +三穗 三穗 +三穗县 三穗縣 +三级三审制 三級三審制 +三结合 三結合 +三统历 三統曆 +三统历史 三統歷史 +三胜制 三勝制 +三脚采茶戏 三腳採茶戲 +三舍 三舍 +三苏 三蘇 +三表 三表 +三角关系 三角關係 +三角套汇 三角套匯 +三角巾包扎法 三角巾包紮法 +三角板 三角板 +三角表 三角表 +三辟 三辟 +三连胜 三連勝 +三部合唱 三部合唱 +三部曲 三部曲 +三里 三里 +三里屯 三里屯 +三里河 三里河 +三针 三針 +三长制 三長制 +三门干部 三門幹部 +三青团 三青團 +三面 三面 +三面亚当 三面亞當 +三面体 三面體 +三面夏娃 三面夏娃 +三面红旗 三面紅旗 +三面网 三面網 +三面角 三面角 +三马同槽 三馬同槽 +三鹿集团 三鹿集團 +上一个 上一個 +上万 上萬 +上上个月 上上個月 +上下五千年 上下五千年 +上下交困 上下交困 +上下同心 上下同心 +上下游 上下游 +上不了 上不了 +上不了台面 上不了檯面 +上不得台盘 上不得檯盤 +上个星期 上個星期 +上个月 上個月 +上中下游 上中下游 +上了 上了 +上了岁数 上了歲數 +上了年纪 上了年紀 +上党 上黨 +上党梆子 上黨梆子 +上冲 上衝 +上冲下洗 上沖下洗 +上千 上千 +上千万 上千萬 +上千人 上千人 +上升 上升 +上升为 上升爲 +上升趋势 上升趨勢 +上半叶 上半葉 +上发条 上發條 +上台 上臺 +上台演唱 上臺演唱 +上台演奏 上臺演奏 +上台演讲 上臺演講 +上叶 上葉 +上合屋 上閤屋 +上合组织 上合組織 +上吊 上吊 +上吊自杀 上吊自殺 +上同调 上同調 +上周 上週 +上回 上回 +上复 上覆 +上夸克 上夸克 +上层建筑 上層建築 +上市柜 上市櫃 +上弦 上弦 +上当 上當 +上彩 上彩 +上搜 上搜 +上杠 上槓 +上柜 上櫃 +上栗县 上栗縣 +上梁 上樑 +上梁不正 上樑不正 +上梁不正下梁歪 上樑不正下樑歪 +上梁山 上梁山 +上梁文 上梁文 +上游 上游 +上游工业 上游工業 +上百万 上百萬 +上确界 上確界 +上签 上籤 +上签写 上簽寫 +上签名 上簽名 +上签字 上簽字 +上签收 上簽收 +上舍 上舍 +上花台 上花臺 +上药 上藥 +上药膏 上藥膏 +上蜡 上蠟 +上表 上表 +上课钟 上課鐘 +上野树里 上野樹里 +上链 上鍊 +上面 上面 +上马杯 上馬杯 +下一个 下一個 +下三面 下三面 +下下个月 下下個月 +下不了 下不了 +下不了台 下不了臺 +下不来台 下不來臺 +下个星期 下個星期 +下个月 下個月 +下了 下了 +下于 下於 +下仑路 下崙路 +下冲 下衝 +下出 下出 +下划线 下劃線 +下厂 下廠 +下发 下發 +下台 下臺 +下台阶 下臺階 +下叶 下葉 +下同 下同 +下向 下向 +下周 下週 +下咽 下嚥 +下回 下回 +下城里 下城裏 +下夸克 下夸克 +下弦 下弦 +下彩 下彩 +下得了 下得了 +下手干 下手幹 +下才 下才 +下摆 下襬 +下有苏杭 下有蘇杭 +下板儿 下板兒 +下梁 下樑 +下水道系统 下水道系統 +下注 下注 +下注解 下註解 +下游 下游 +下游工业 下游工業 +下确界 下確界 +下种 下種 +下笔千言 下筆千言 +下签 下籤 +下签写 下簽寫 +下签名 下簽名 +下签字 下簽字 +下签收 下簽收 +下药 下藥 +下表 下表 +下课后 下課後 +下课钟 下課鐘 +下采 下采 +下里 下里 +下里巴人 下里巴人 +下面 下面 下麪 +下面条 下麪條 +下面请看 下面請看 +下风方向 下風方向 +下马杯 下馬杯 +不一致 不一致 +不一致字 不一致字 +不上台盘 不上檯盤 +不下于 不下於 +不丑 不醜 +不世出 不世出 +不中于款 不中於款 +不丰不杀 不豐不殺 +不为牛后 不爲牛後 +不为米折腰 不爲米折腰 +不乐于 不樂於 +不了 不了 +不了之局 不了之局 +不了了之 不了了之 +不了了当 不了了當 +不了情 不了情 +不了汉 不了漢 +不了解 不瞭解 +不以词害志 不以詞害志 +不以辞害志 不以辭害志 +不体面 不體面 +不作准 不作準 +不侮暗室 不侮暗室 +不修 不修 +不修小节 不修小節 +不修帷薄 不修帷薄 +不修边幅 不修邊幅 +不借 不借 +不值当 不值當 +不假外出 不假外出 +不偏极 不偏極 +不停当 不停當 +不光彩 不光彩 +不克 不克 +不克制 不剋制 +不克自制 不克自制 +不全症 不全症 +不再出版 不再出版 +不准 不準 不准 +不准他 不准他 +不准你 不准你 +不准备 不準備 +不准她 不准她 +不准它 不准它 +不准我 不准我 +不准没 不准沒 +不准确 不準確 +不准翻印 不准翻印 +不准许 不准許 +不准谁 不准誰 +不准问 不准問 +不减当年 不減當年 +不出 不出 +不出去 不出去 +不出所料 不出所料 +不出材 不出材 +不出来 不出來 +不分胜负 不分勝負 +不分胜败 不分勝敗 +不分青红皂白 不分青紅皁白 +不切合实际 不切合實際 +不划算 不划算 +不利于 不利於 +不前不后 不前不後 +不加修饰 不加修飾 +不加区别 不加區別 +不加自制 不加自制 +不劳无获 不勞無獲 +不劳而获 不勞而獲 +不升 不升 +不升反降 不升反降 +不单只是 不單只是 +不卜可知 不卜可知 +不占 不佔 +不占凶吉 不占凶吉 +不占卜 不占卜 +不占吉凶 不占吉凶 +不占算 不占算 +不发心 不發心 +不变价格 不變價格 +不只 不只 +不只是 不只是 +不可以道里计 不可以道里計 +不可同年而语 不可同年而語 +不可同日 不可同日 +不可同日而语 不可同日而語 +不可向迩 不可向邇 +不可当 不可當 +不可战胜 不可戰勝 +不可挽回 不可挽回 +不可救药 不可救藥 +不可胜书 不可勝書 +不可胜原 不可勝原 +不可胜数 不可勝數 +不可胜纪 不可勝紀 +不可胜言 不可勝言 +不可胜计 不可勝計 +不可胜记 不可勝記 +不吃烟火食 不吃煙火食 +不合 不合 +不合体统 不合體統 +不合作 不合作 +不合作运动 不合作運動 +不合式 不合式 +不合时宜 不合時宜 +不合标准 不合標準 +不合格 不合格 +不合法 不合法 +不合理 不合理 +不合算 不合算 +不合群 不合羣 +不合节 不合節 +不合规定 不合規定 +不合适 不合適 +不合逻辑 不合邏輯 +不吊 不弔 +不同 不同 +不同于 不同於 +不同人 不同人 +不同以往 不同以往 +不同凡响 不同凡響 +不同印本 不同印本 +不同处 不同處 +不同意 不同意 +不同日月 不同日月 +不同点 不同點 +不同调 不同調 +不向 不向 +不告而别 不告而別 +不周 不周 +不周到 不周到 +不周山 不周山 +不周延 不周延 +不周风 不周風 +不善于 不善於 +不图打点只图混水 不圖打點只圖混水 +不在了 不在了 +不堪回首 不堪回首 +不复 不復 +不复存在 不復存在 +不外借 不外借 +不多于 不多於 +不多几日 不多幾日 +不大合时 不大合時 +不大精采 不大精采 +不好了 不好了 +不好干涉 不好干涉 +不好干預 不好干預 +不好干预 不好干預 +不嫌母丑 不嫌母醜 +不孕症 不孕症 +不孝有三无后为大 不孝有三無後爲大 +不学亡术 不學亡術 +不学无术 不學無術 +不安于位 不安於位 +不安于室 不安於室 +不完全叶 不完全葉 +不寒而栗 不寒而慄 +不对腔板 不對腔板 +不小于 不小於 +不少于 不少於 +不尽 不盡 +不尽年 不盡年 +不尽心 不盡心 +不尽木 不盡木 +不尽根 不盡根 +不尽然 不盡然 +不尽相同 不盡相同 +不尽道理 不盡道理 +不屑于 不屑於 +不属于 不屬於 +不差毫厘 不差毫釐 +不差毫发 不差毫髮 +不干 不幹 不乾 +不干不净 不乾不淨 +不干不淨吃了没病 不乾不淨吃了沒病 +不干了 不幹了 +不干事 不幹事 +不干他 不干他 +不干休 不干休 +不干你 不干你 +不干净 不乾淨 +不干她 不干她 +不干它 不干它 +不干己事 不干己事 +不干性 不乾性 +不干我 不干我 +不干扰 不干擾 +不干杯 不乾杯 +不干涉 不干涉 +不干涉主义 不干涉主義 +不干渴 不乾渴 +不干犯 不干犯 +不干着急 不乾着急 +不干胶 不乾膠 +不干脆 不乾脆 +不干裂 不乾裂 +不干预 不干預 +不并 不併 +不幸 不幸 +不幸之事 不幸之事 +不幸之幸 不幸之幸 +不幸受害 不幸受害 +不幸的是 不幸的是 +不当 不當 +不当一回事 不當一回事 +不当不对 不當不對 +不当不正 不當不正 +不当事 不當事 +不当人 不當人 +不当人化化 不當人化化 +不当人子 不當人子 +不当党 不當黨 +不当党产 不當黨產 +不当准 不當準 +不当官 不當官 +不当家 不當家 +不当家化化 不當家化化 +不当家花拉 不當家花拉 +不当家花花 不當家花花 +不当家豁拉 不當家豁拉 +不当得利 不當得利 +不当数 不當數 +不当稳便 不當穩便 +不当紧 不當緊 +不当耍处 不當耍處 +不当道 不當道 +不形于色 不形於色 +不彩 不彩 +不徇颜面 不徇顏面 +不得了 不得了 +不得台盘 不得檯盤 +不得志 不得志 +不得闲 不得閒 +不念 不念 +不念旧恶 不念舊惡 +不恶而严 不惡而嚴 +不情不愿 不情不願 +不情愿 不情願 +不惮强御 不憚強禦 +不愿 不願 +不愿意 不願意 +不成才 不成才 +不战而胜 不戰而勝 +不才 不才 +不打不成才 不打不成才 +不托 不託 +不扣 不扣 +不折 不折 +不折不扣 不折不扣 +不挂 不掛 +不挂眼 不掛眼 +不放松 不放鬆 +不敢出声 不敢出聲 +不敢出气 不敢出氣 +不敢后人 不敢後人 +不敢当 不敢當 +不整合 不整合 +不斗 不鬥 +不断电系统 不斷電系統 +不早了 不早了 +不时之须 不時之須 +不明就里 不明就裏 +不明确 不明確 +不是个儿 不是個兒 +不是了处 不是了處 +不是别人 不是別人 +不松下 不鬆下 +不极 不極 +不极不反 不極不反 +不染纤尘 不染纖塵 +不标准 不標準 +不欲 不欲 +不欺暗室 不欺暗室 +不止于此 不止於此 +不正当 不正當 +不正当关系 不正當關係 +不正当竞争 不正當競爭 +不正确 不正確 +不死药 不死藥 +不毒不发 不毒不發 +不气干 不氣干 +不求收获 不求收獲 +不治之症 不治之症 +不注意 不注意 +不测风云 不測風雲 +不涂 不塗 +不消几日 不消幾日 +不甘于 不甘於 +不甘后人 不甘後人 +不甚了了 不甚了了 +不甚合意 不甚合意 +不用干 不用幹 +不用斗了 不用鬥了 +不畏强御 不畏強禦 +不畏彊御 不畏彊禦 +不留情面 不留情面 +不相同 不相同 +不相干 不相干 +不知凡几 不知凡幾 +不知去向 不知去向 +不知所云 不知所云 +不确 不確 +不确定 不確定 +不确定性 不確定性 +不确定性原理 不確定性原理 +不确定感 不確定感 +不确定故意 不確定故意 +不确实 不確實 +不符合 不符合 +不等于 不等於 +不等价交换 不等價交換 +不管闲事 不管閒事 +不系 不繫 +不系舟 不繫舟 +不约而合 不約而合 +不约而同 不約而同 +不织布 不織布 +不结汇进口 不結匯進口 +不绝于耳 不絕於耳 +不老药 不老藥 +不肯干休 不肯干休 +不育症 不育症 +不胜 不勝 +不胜之态 不勝之態 +不胜其扰 不勝其擾 +不胜其烦 不勝其煩 +不胜其苦 不勝其苦 +不胜唏嘘 不勝唏噓 +不胜感喟 不勝感喟 +不胜感激 不勝感激 +不胜春 不勝春 +不胜枚举 不勝枚舉 +不胜衣 不勝衣 +不胜负荷 不勝負荷 +不胜酒力 不勝酒力 +不能出口 不能出口 +不能尽数 不能盡數 +不能胜数 不能勝數 +不能自制 不能自制 +不能赞一辞 不能贊一辭 +不至于 不至於 +不致 不致 +不致于 不致於 +不舍 不捨 +不舍得 不捨得 +不舍昼夜 不捨晝夜 +不舒适 不舒適 +不良于行 不良於行 +不良倾向 不良傾向 +不良才 不良才 +不良适应 不良適應 +不药而愈 不藥而癒 +不药而癒 不藥而癒 +不获 不獲 +不落人后 不落人後 +不虚发 不虛發 +不行了 不行了 +不表 不表 +不见世面 不見世面 +不见了 不見了 +不见识面 不見識面 +不见面 不見面 +不规范 不規範 +不解之仇 不解之仇 +不讨采 不討采 +不让须眉 不讓鬚眉 +不讲情面 不講情面 +不识局面 不識局面 +不识闲 不識閒 +不说价 不說價 +不说出 不說出 +不谈别的 不談別的 +不谋而合 不謀而合 +不谋而同 不謀而同 +不谐当 不諧當 +不谷 不穀 +不负所托 不負所托 +不赞 不讚 +不赞一词 不讚一詞 +不赞一辞 不讚一辭 +不赞同 不贊同 +不赞成 不贊成 +不足为据 不足爲據 +不足之症 不足之症 +不足回旋 不足回旋 +不足挂齿 不足掛齒 +不足采信 不足採信 +不辞而别 不辭而別 +不远万里 不遠萬里 +不远千里 不遠千里 +不连续面 不連續面 +不适 不適 +不适合 不適合 +不适当 不適當 +不适感 不適感 +不适用 不適用 +不逊于 不遜於 +不透明水彩画 不透明水彩畫 +不通吊庆 不通弔慶 +不遗余力 不遺餘力 +不避彊御 不避彊禦 +不采 不採 +不采声 不采聲 +不锈钢 不鏽鋼 +不锈钢板 不鏽鋼板 +不问前因后果 不問前因後果 +不问是非曲直 不問是非曲直 +不降反升 不降反升 +不限于 不限於 +不须 不須 +不顾前后 不顧前後 +不顾后果 不顧後果 +不顾曲直 不顧曲直 +不顾闲野 不顧閒野 +不食人间烟火 不食人間煙火 +不食周粟 不食周粟 +不食干腊 不食乾腊 +不食烟火 不食煙火 +不龟手药 不龜手藥 +不龟药 不龜藥 +与他一斗 與他一鬥 +与众不同 與衆不同 +与克制 與剋制 +与党 與黨 +与君一席话胜读十年书 與君一席話勝讀十年書 +与国同休 與國同休 +与她一斗 與她一鬥 +与子同袍 與子同袍 +与日同辉 與日同輝 +与此同时 與此同時 +与民同乐 與民同樂 +与民同忧 與民同憂 +丑三 丑三 +丑丑 醜醜 +丑丫头 醜丫頭 +丑事 醜事 +丑于 醜於 +丑人 醜人 +丑人多作怪 醜人多作怪 +丑侪 醜儕 +丑八怪 醜八怪 +丑剌剌 醜剌剌 +丑剧 醜劇 +丑化 醜化 +丑史 醜史 +丑名 醜名 +丑咤 醜吒 +丑地 醜地 +丑声 醜聲 +丑声四溢 醜聲四溢 +丑声远播 醜聲遠播 +丑头怪脸 醜頭怪臉 +丑夷 醜夷 +丑女 醜女 +丑女人 醜女人 +丑女效颦 醜女效顰 +丑奴儿 醜奴兒 +丑妇 醜婦 +丑媳 醜媳 +丑媳妇 醜媳婦 +丑媳妇总得要见公婆 醜媳婦總得要見公婆 +丑小鸭 醜小鴨 +丑巴怪 醜巴怪 +丑年 丑年 +丑徒 醜徒 +丑态 醜態 +丑态毕露 醜態畢露 +丑态百出 醜態百出 +丑怪 醜怪 +丑恶 醜惡 +丑日 丑日 +丑旦 丑旦 +丑时 丑時 +丑月 丑月 +丑末 醜末 +丑杂 醜雜 +丑样 醜樣 +丑死 醜死 +丑比 醜比 +丑毙了 醜斃了 +丑沮 醜沮 +丑牛 丑牛 +丑生 醜生 +丑男 醜男 +丑相 醜相 +丑类 醜類 +丑类恶物 醜類惡物 +丑脸 醜臉 +丑虏 醜虜 +丑行 醜行 +丑角 丑角 +丑言 醜言 +丑诋 醜詆 +丑话 醜話 +丑语 醜語 +丑贼生 醜賊生 +丑辞 醜辭 +丑辱 醜辱 +丑逆 醜逆 +丑闻 醜聞 +丑闻案 醜聞案 +丑陋 醜陋 +专业人才 專業人才 +专修 專修 +专修班 專修班 +专修科 專修科 +专修科目 專修科目 +专利药 專利藥 +专利药品 專利藥品 +专制 專制 +专制主义 專制主義 +专制制度 專制制度 +专制君主制 專制君主制 +专制政体 專制政體 +专制政府 專制政府 +专制政治 專制政治 +专制权 專制權 +专制起来 專制起來 +专勤制度 專勤制度 +专向 專向 +专家系统 專家系統 +专家评价 專家評價 +专干 專幹 +专征 專征 +专心一志 專心一志 +专心致志 專心致志 +专才 專才 +专摆 專擺 +专柜 專櫃 +专柜小姐 專櫃小姐 +专欲难成 專欲難成 +专注 專注 +专注力 專注力 +专精于 專精於 +专美于前 專美於前 +专辑里 專輯裏 +专鉴 專鑒 +专门人才 專門人才 +专门术语 專門術語 +且于 且於 +且听下回分解 且聽下回分解 +世上无难事只怕有心人 世上無難事只怕有心人 +世仇 世仇 +世出世 世出世 +世台 世臺 +世台会 世臺會 +世彩堂 世綵堂 +世彩堂帖 世綵堂帖 +世恩录 世恩錄 +世情看冷暖人面逐高低 世情看冷暖人面逐高低 +世所周知 世所周知 +世田谷 世田谷 +世界大同 世界大同 +世界旅游组织 世界旅遊組織 +世界杯 世界盃 +世界杯室 世界盃室 +世界杯赛 世界盃賽 +世界纪录 世界紀錄 +世界范围 世界範圍 +世界里 世界裏 +世系 世系 +世纪钟 世紀鐘 +世纪钟表 世紀鐘錶 +世胄 世胄 +世表 世表 +世阿弥 世阿彌 +世面 世面 +丘克 丘克 +丙种 丙種 +丙种射线 丙種射線 +丙舍 丙舍 +业余 業餘 +业余大学 業餘大學 +业余教育 業餘教育 +业余爱好 業餘愛好 +业余者 業餘者 +业务范围 業務範圍 +业界标准 業界標準 +业种 業種 +业精于勤 業精於勤 +业荒于嬉 業荒於嬉 +业馀电台 業餘電臺 +丛台区 叢臺區 +丛生叶 叢生葉 +东丰 東豐 +东丰县 東豐縣 +东丰阁 東豐閣 +东京柜 東京櫃 +东仓里 東倉里 +东伙 東夥 +东冲西突 東衝西突 +东加里曼丹 東加里曼丹 +东北向 東北向 +东北面 東北面 +东升 東昇 +东南向 東南向 +东南面 東南面 +东厂 東廠 +东台 東臺 +东台市 東臺市 +东台湾 東臺灣 +东向 東向 +东周 東周 +东周时 東周時 +东周时代 東周時代 +东周时期 東周時期 +东周钟 東周鐘 +东奔西向 東奔西向 +东学党 東學黨 +东山之志 東山之志 +东山里 東山里 +东山里站 東山里站 +东岳 東嶽 +东干 東干 +东征 東征 +东征西怨 東征西怨 +东征西讨 東征西討 +东扬西荡 東揚西蕩 +东折西绕 東折西繞 +东挨西撞 東挨西撞 +东挪西借 東挪西借 +东摇西摆 東搖西擺 +东方发白 東方發白 +东方汇理 東方匯理 +东林党 東林黨 +东欧集团 東歐集團 +东海捞针 東海撈針 +东涂西抹 東塗西抹 +东淨里的砖儿 東淨裏的磚兒 +东游 東遊 +东窗事发 東窗事發 +东胜区 東勝區 +东胡 東胡 +东芝医疗系 東芝醫療繫 +东荡西除 東蕩西除 +东蒙 東蒙 +东西向 東西向 +东西周 東西周 +东讨西征 東討西征 +东谷拉瓦 東谷拉瓦 +东邻西舍 東鄰西舍 +东里 東里 +东量西折 東量西折 +东面 東面 +东飘西荡 東飄西蕩 +丝发 絲髮 +丝发之功 絲髮之功 +丝布 絲布 +丝弦 絲絃 +丝恩发怨 絲恩髮怨 +丝托索 絲托索 +丝挂子 絲掛子 +丝杆 絲桿 +丝杠 絲槓 +丝来线去 絲來線去 +丝板 絲板 +丝瓜布 絲瓜布 +丝盘虫 絲盤蟲 +丝线 絲線 +丝织厂 絲織廠 +丝绒布 絲絨布 +丝虫 絲蟲 +丝虫病 絲蟲病 +丢丑 丟醜 +丢了 丟了 +丢体面 丟體面 +丢入爪哇国里 丟入爪哇國裏 +丢出 丟出 +丢出去 丟出去 +丢包术 丟包術 +丢在脑后 丟在腦後 +丢巧针 丟巧針 +丢面子 丟面子 +两万 兩萬 +两个 兩個 +两个中国 兩個中國 +两个或两个以上 兩個或兩個以上 +两个或更多 兩個或更多 +两个肩膀扛张嘴 兩個肩膀扛張嘴 +两人同心 兩人同心 +两余 兩餘 +两克 兩克 +两党 兩黨 +两千 兩千 +两厢情愿 兩廂情願 +两只 兩隻 +两只手 兩隻手 +两只脚赶不上一张嘴 兩隻腳趕不上一張嘴 +两台 兩臺 +两叶 兩葉 +两叶掩目 兩葉掩目 +两合公司 兩合公司 +两周 兩週 +两周年 兩週年 +两回 兩回 +两回事 兩回事 +两国关系 兩國關係 +两天后 兩天後 +两天晒网 兩天曬網 +两头三面 兩頭三面 +两头白面 兩頭白面 +两娘女 兩娘女 +两岸关系 兩岸關係 +两当 兩當 +两当一 兩當一 +两当县 兩當縣 +两性关系 兩性關係 +两情两愿 兩情兩願 +两扎 兩紮 +两撇胡 兩撇鬍 +两方面 兩方面 +两杆 兩杆 +两杠 兩槓 +两杯 兩杯 +两板 兩板 +两极 兩極 +两极分化 兩極分化 +两极化 兩極化 +两极管 兩極管 +两极观点 兩極觀點 +两段制 兩段制 +两点钟 兩點鐘 +两班制 兩班制 +两百万 兩百萬 +两百个 兩百個 +两百多万 兩百多萬 +两相情愿 兩相情願 +两眼发直 兩眼發直 +两种 兩種 +两种人 兩種人 +两秒钟 兩秒鐘 +两腿发软 兩腿發軟 +两虎共斗 兩虎共鬥 +两虎相斗 兩虎相鬥 +两西西里王国 兩西西里王國 +两院制 兩院制 +两面 兩面 +两面三刀 兩面三刀 +两面不是人 兩面不是人 +两面不讨好 兩面不討好 +两面二舌 兩面二舌 +两面作战 兩面作戰 +两面倒 兩面倒 +两面光 兩面光 +两面刀 兩面刀 +两面夹攻 兩面夾攻 +两面性 兩面性 +两面手法 兩面手法 +两面派 兩面派 +两面讨好 兩面討好 +两面转圜 兩面轉圜 +两面锯 兩面鋸 +两面顾全 兩面顧全 +两鼠斗穴 兩鼠鬥穴 +严丝合缝 嚴絲合縫 +严了眼儿 嚴了眼兒 +严于 嚴於 +严于律己 嚴於律己 +严云农 嚴云農 +严冬 嚴冬 +严制 嚴制 +严加防范 嚴加防範 +严复 嚴復 +严恶 嚴惡 +严禁吸烟 嚴禁吸菸 +严禁烟火 嚴禁煙火 +严重后果 嚴重後果 +丧失殆尽 喪失殆盡 +丧尸 喪屍 +丧尽 喪盡 +丧尽天良 喪盡天良 +丧志 喪志 +丧荡游魂 喪蕩游魂 +丧钟 喪鐘 +个个 個個 +个个称羡 個個稱羨 +个中 箇中 +个中三昧 箇中三昧 +个中人 箇中人 +个中原因 箇中原因 +个中奥妙 箇中奧妙 +个中奥秘 箇中奧祕 +个中好手 箇中好手 +个中强手 箇中強手 +个中消息 箇中消息 +个中滋味 箇中滋味 +个中玄机 箇中玄機 +个中理由 箇中理由 +个中讯息 箇中訊息 +个中资讯 箇中資訊 +个中道理 箇中道理 +个中高手 箇中高手 +个事 個事 +个人 個人 +个人主义 個人主義 +个人伤害 個人傷害 +个人储蓄 個人儲蓄 +个人利益 個人利益 +个人化 個人化 +个人单季 個人單季 +个人卫生 個人衛生 +个人外交 個人外交 +个人奖 個人獎 +个人崇拜 個人崇拜 +个人工作室 個人工作室 +个人得失 個人得失 +个人性 個人性 +个人所得 個人所得 +个人所得税 個人所得稅 +个人护理 個人護理 +个人拨接 個人撥接 +个人本位 個人本位 +个人消费 個人消費 +个人用 個人用 +个人用户 個人用戶 +个人电脑 個人電腦 +个人组 個人組 +个人网站 個人網站 +个人资料 個人資料 +个人赛 個人賽 +个人隐私 個人隱私 +个人风 個人風 +个人首页 個人首頁 +个位 個位 +个位数 個位數 +个体 個體 +个体发育 個體發育 +个体户 個體戶 +个体所有 個體所有 +个体经济 個體經濟 +个例 個例 +个儿 個兒 +个别 個別 +个别差异 個別差異 +个别性 個別性 +个别情况 個別情況 +个别指导 個別指導 +个别教学 個別教學 +个别测验 個別測驗 +个别现象 個別現象 +个别生产 個別生產 +个别谈话 個別談話 +个别辅导 個別輔導 +个头 個頭 +个头儿 個頭兒 +个子 個子 +个屁阿 個屁阿 +个展 個展 +个性 個性 +个性化 個性化 +个性难改 個性難改 +个把 個把 +个把月 個把月 +个数 個數 +个旧 箇舊 +个旧县 箇舊縣 +个旧市 箇舊市 +个样 個樣 +个核 個核 +个案 個案 +个案分析 個案分析 +个案研究 個案研究 +个案纪录 個案紀錄 +个股为 個股爲 +个过客 個過客 +个钟 個鐘 +个钟表 個鐘錶 +中上游 中上游 +中下游 中下游 +中书舍人 中書舍人 +中了暑 中了暑 +中了标 中了標 +中了毒 中了毒 +中于 中於 +中云 中雲 +中介社团 中介社團 +中仑 中崙 +中仑站 中崙站 +中价位 中價位 +中低价位 中低價位 +中俄关系 中俄關系 +中千世界 中千世界 +中华台北 中華臺北 +中华电视台 中華電視臺 +中华肝吸虫病 中華肝吸蟲病 +中华苏维埃共和国 中華蘇維埃共和國 +中华革命党 中華革命黨 +中原板荡 中原板蕩 +中原标准时间 中原標準時間 +中台 中臺 中颱 +中台医专 中臺醫專 +中台湾 中臺灣 +中台禅寺 中臺禪寺 +中台科技大学 中臺科技大學 +中叶 中葉 +中国共产党 中國共產黨 +中国制 中國製 +中国制造 中國製造 +中国剩余定理 中國剩餘定理 +中国医药 中國醫藥 +中国历史 中國歷史 +中国同盟会 中國同盟會 +中国国民党 中國國民黨 +中型钟 中型鐘 +中型钟表 中型鐘錶 +中型钟表面 中型鐘表面 +中型钟面 中型鐘面 +中央专制集权 中央專制集權 +中央党 中央黨 +中央党部 中央黨部 +中央台 中央臺 +中央广播电台 中央廣播電臺 +中央标准局 中央標準局 +中央汇金 中央匯金 +中央电视台 中央電視臺 +中央监控系统 中央監控系統 +中央空调系统 中央空調系統 +中央面 中央面 +中子俘获 中子俘獲 +中岳 中嶽 +中度台风 中度颱風 +中彩 中彩 +中心汇率 中心匯率 +中恶 中惡 +中懑之症 中懣之症 +中才 中才 +中控台 中控臺 +中控面板 中控面板 +中搜 中搜 +中文台 中文臺 +中文系 中文系 +中文里 中文裏 +中日关系 中日關係 +中暗箭 中暗箭 +中板 中板 +中极 中極 +中枢系统 中樞系統 +中核 中核 +中止症 中止症 +中比关系 中比關係 +中注模样 中注模樣 +中涂 中塗 +中港台 中港臺 +中游 中游 +中环杯 中環盃 +中盘胜 中盤勝 +中秋 中秋 +中秋佳节 中秋佳節 +中秋帖 中秋帖 +中秋月饼 中秋月餅 +中秋节 中秋節 +中程计划 中程計劃 +中筋面粉 中筋麪粉 +中签 中籤 +中美发表 中美發表 +中胡 中胡 +中草药 中草藥 +中药 中藥 +中药偏方 中藥偏方 +中药学 中藥學 +中药店 中藥店 +中药房 中藥房 +中药材 中藥材 +中药铺 中藥鋪 +中表 中表 +中西合并 中西合併 +中西合璧 中西合璧 +中谷 中谷 +中谷有蓷 中谷有蓷 +中转柜台 中轉櫃檯 +中远集团 中遠集團 +中远香港集团 中遠香港集團 +中间纤维 中間纖維 +中风后 中風後 +丰上锐下 豐上銳下 +丰下 豐下 +丰丘明 豐丘明 +丰业 豐業 +丰乐 豐樂 +丰乐亭 豐樂亭 +丰产 豐產 +丰产田 豐產田 +丰亨豫大 豐亨豫大 +丰仪 丰儀 +丰伟 豐偉 +丰俭由人 豐儉由人 +丰儀 丰儀 +丰功 豐功 +丰功伟业 豐功偉業 +丰功伟绩 豐功偉績 +丰功厚利 豐功厚利 +丰功大业 豐功大業 +丰功懋烈 豐功懋烈 +丰功盛烈 豐功盛烈 +丰华 豐華 +丰南 豐南 +丰南区 豐南區 +丰厚 豐厚 +丰原 豐原 +丰原市 豐原市 +丰县 豐縣 +丰取刻与 豐取刻與 +丰台 豐臺 +丰台区 豐臺區 +丰城 豐城 +丰城剑气 豐城劍氣 +丰城市 豐城市 +丰城贯斗 豐城貫斗 +丰壤 豐壤 +丰奢 豐奢 +丰妍 豐妍 +丰姿 丰姿 +丰姿冶丽 丰姿冶麗 +丰姿绰约 丰姿綽約 +丰宁 豐寧 +丰宁县 豐寧縣 +丰实 豐實 +丰容 丰容 +丰容靓饰 豐容靚飾 +丰富 豐富 +丰富多彩 豐富多彩 +丰富性 豐富性 +丰川悦司 豐川悅司 +丰年 豐年 +丰年玉 豐年玉 +丰年祭 豐年祭 +丰年稔岁 豐年稔歲 +丰年节 豐年節 +丰年虾 豐年蝦 +丰度 丰度 豐度 +丰悴 豐悴 +丰情 丰情 +丰收 豐收 +丰收年 豐收年 +丰本 豐本 +丰杀 豐殺 +丰标 丰標 +丰标不凡 丰標不凡 +丰歉 豐歉 +丰殖 豐殖 +丰水 豐水 +丰水期 豐水期 +丰沛 豐沛 +丰注 豐注 +丰泽 豐澤 +丰泽区 豐澤區 +丰润 豐潤 +丰润区 豐潤區 +丰渔桥 豐漁橋 +丰溪里 豐溪里 +丰满 豐滿 +丰满区 豐滿區 +丰滨 豐濱 +丰滨乡 豐濱鄉 +丰炽 豐熾 +丰熟 豐熟 +丰田 豐田 +丰登 豐登 +丰盈 豐盈 +丰盛 豐盛 +丰硕 豐碩 +丰碑 豐碑 +丰神 丰神 +丰神俊美 丰神俊美 +丰神异彩 豐神異彩 +丰神绰约 丰神綽約 +丰神飘洒 丰神飄灑 +丰稔 豐稔 +丰穰 豐穰 +丰美 豐美 +丰耗 豐耗 +丰肌 豐肌 +丰胸 豐胸 +丰腆 豐腆 +丰腴 豐腴 +丰臣秀吉 豐臣秀吉 +丰若晖 豐若暉 +丰若有肌柔若无骨 丰若有肌柔若無骨 +丰茂 豐茂 +丰茸 丰茸 +丰草 豐草 +丰蔚 豐蔚 +丰衍 豐衍 +丰衣足食 豐衣足食 +丰裕 豐裕 +丰赡 豐贍 +丰足 豐足 +丰都 豐都 +丰都县 豐都縣 +丰采 丰采 +丰镇 豐鎮 +丰镇市 豐鎮市 +丰镐 豐鎬 +丰隆 豐隆 +丰韵 丰韻 +丰韻 丰韻 +丰顺 豐順 +丰顺县 豐順縣 +丰颊 豐頰 +丰饶 豐饒 +丰饶丰足 豐饒豐足 +串亲戚 串親戚 +串出来 串出來 +串同 串同 +串哄 串哄 +串游 串游 +临别 臨別 +临别依依 臨別依依 +临别时 臨別時 +临别赠言 臨別贈言 +临制 臨制 +临危致命 臨危致命 +临去秋波 臨去秋波 +临夏回族自治州 臨夏回族自治州 +临幸 臨幸 +临床特征 臨牀特徵 +临机制变 臨機制變 +临机制胜 臨機制勝 +临江折轴 臨江折軸 +临海水土志 臨海水土誌 +临潼斗宝 臨潼鬥寶 +丸药 丸藥 +丸药盒 丸藥盒 +丹参 丹蔘 +丹台 丹臺 +丹布朗 丹布朗 +丹干 丹干 +丹徒布衣 丹徒布衣 +丹朱 丹朱 +丹药 丹藥 +为中台 爲中颱 +为了 爲了 +为人师表 爲人師表 +为准 爲準 +为念 爲念 +为恶不悛 爲惡不悛 +为所欲为 爲所欲爲 +为模范 爲模範 +为着 爲着 +为规范 爲規範 +为鉴 爲鑑 +主仆 主僕 +主修 主修 +主修科目 主修科目 +主席台 主席臺 +主席团 主席團 +主干 主幹 +主干家庭 主幹家庭 +主干线 主幹線 +主干网络 主幹網絡 +主干网路 主幹網路 +主控台 主控臺 +主播台 主播臺 +主教团 主教團 +主普坛 主普壇 +主机板 主機板 +主板 主板 +主梁 主樑 +主法向量 主法向量 +主画面 主畫面 +主要树种 主要樹種 +主钟差 主鐘差 +主钟曲线 主鐘曲線 +主题曲 主題曲 +主题论坛区 主題論壇區 +丽于 麗於 +丽舍 麗舍 +举不胜举 舉不勝舉 +举了 舉了 +举例发凡 舉例發凡 +举出 舉出 +举出来 舉出來 +举发 舉發 +举尾虫 舉尾蟲 +举手可采 舉手可采 +举手表 舉手表 +举手表决 舉手表決 +举措失当 舉措失當 +举杯 舉杯 舉盃 +举杯畅饮 舉杯暢飲 +举止闲冶 舉止閒冶 +举目千里 舉目千里 +举荐征辟 舉薦征辟 +乃至于 乃至於 +乃里 乃里 +久仰山斗 久仰山斗 +久别 久別 +久别相逢 久別相逢 +久别重逢 久別重逢 +久违颜范 久違顏範 +么娘 麼娘 +义义合合 義義合合 +义仆 義僕 +义占 義佔 +义同生死 義同生死 +义和团 義和團 +义大利杯 義大利杯 +义大利面 義大利麪 +义庄 義莊 +义形于色 義形於色 +义气干霄 義氣干霄 +义薄云天 義薄雲天 +之于 之於 +之余 之餘 +之八九只 之八九只 +之叹 之嘆 +之后 之後 +之征 之徵 +之念 之念 +之托 之託 +之杯 之杯 +之核 之核 +之欲 之慾 +之游 之遊 +之秋 之秋 +之鉴 之鑑 +之钟 之鐘 +乌东察克 烏東察克 +乌东査克 烏東查克 +乌云 烏雲 +乌云密布 烏雲密佈 +乌云蔽日 烏雲蔽日 +乌什塔拉回族乡 烏什塔拉回族鄉 +乌克丽丽 烏克麗麗 +乌克兰 烏克蘭 +乌克兰人 烏克蘭人 +乌克兰籍 烏克蘭籍 +乌克兰队 烏克蘭隊 +乌兰察布 烏蘭察布 +乌兰察布市 烏蘭察布市 +乌兰巴托 烏蘭巴托 +乌兹冲锋枪 烏茲衝鋒槍 +乌兹别克 烏茲別克 +乌兹别克人 烏茲別克人 +乌兹别克共和国 烏茲別克共和國 +乌兹别克斯坦 烏茲別克斯坦 +乌兹别克族 烏茲別克族 +乌冬面 烏冬麪 +乌发 烏髮 +乌合 烏合 +乌合之众 烏合之衆 +乌合之卒 烏合之卒 +乌孜别克 烏孜別克 +乌孜别克族 烏孜別克族 +乌孜别克语 烏孜別克語 +乌干达 烏干達 +乌干达共和国 烏干達共和國 +乌当 烏當 +乌当区 烏當區 +乌托邦 烏托邦 +乌拉特后旗 烏拉特後旗 +乌松 烏松 +乌梁海 烏梁海 +乌梁海盆地 烏梁海盆地 +乌沈沈 烏沈沈 +乌洛托品 烏洛托品 +乌涂 烏塗 +乌涂水 烏塗水 +乌滋别克 烏滋別克 +乌滋别克斯坦 烏滋別克斯坦 +乌烟瘴气 烏煙瘴氣 +乌狗吃食白狗当灾 烏狗吃食白狗當災 +乌苏 烏蘇 +乌苏市 烏蘇市 +乌苏拉 烏蘇拉 +乌苏里斯克 烏蘇里斯克 +乌苏里江 烏蘇里江 +乌药 烏藥 +乌获 烏獲 +乌菲兹美术馆 烏菲茲美術館 +乌里 烏里 +乌里雅苏台 烏里雅蘇臺 +乌鲁克恰提 烏魯克恰提 +乌鲁克恰提县 烏魯克恰提縣 +乌鲁克穆河 烏魯克穆河 +乌龙面 烏龍麪 +乏困 乏困 +乐不可极 樂不可極 +乐于 樂於 +乐于助人 樂於助人 +乐合彩 樂合彩 +乐器钟 樂器鐘 +乐团 樂團 +乐坏了 樂壞了 +乐坛 樂壇 +乐府杂录 樂府雜錄 +乐意于 樂意於 +乐曲 樂曲 +乐极则悲 樂極則悲 +乐极忘形 樂極忘形 +乐极悲来 樂極悲來 +乐极悲生 樂極悲生 +乐极生悲 樂極生悲 +乐游原 樂遊原 +乐理 樂理 +乐祸幸灾 樂禍幸災 +乐透彩 樂透彩 +乐颠了馅 樂顛了餡 +乒乓球台 乒乓球檯 +乔修亚 喬修亞 +乔修亚.吉尔菲艾斯 喬修亞.吉爾菲艾斯 +乔做胡为 喬做胡爲 +乔岳 喬嶽 +乔布斯 喬布斯 +乔德里 喬德里 +乔志 喬志 +乔才 喬才 +乔杰立 喬傑立 +乔松 喬松 +乔松之寿 喬松之壽 +乔治克隆尼 喬治克隆尼 +乔治克鲁尼 喬治克魯尼 +乔治.布希 喬治.布希 +乖别 乖別 +乘了 乘了 +乘云 乘雲 +乘凶完配 乘凶完配 +乘奔御风 乘奔御風 +乘法表 乘法表 +乘胜 乘勝 +乘胜追击 乘勝追擊 +乘胜逐北 乘勝逐北 +乘鹤驾云 乘鶴駕雲 +乙丑 乙丑 +乙种 乙種 +乙种射线 乙種射線 +乙种粒子 乙種粒子 +乙种维生素 乙種維生素 +九世之仇 九世之仇 +九个 九個 +九个人 九個人 +九个月 九個月 +九九乘法表 九九乘法表 +九九表 九九表 +九亿五千万 九億五千萬 +九余 九餘 +九冬 九冬 +九出祁山 九出祁山 +九分钟 九分鐘 +九划 九劃 +九千点 九千點 +九只 九隻 +九台 九臺 +九台市 九臺市 +九合 九合 +九合一匡 九合一匡 +九吊六的 九吊六的 +九回肠 九迴腸 +九天后 九天後 +九宵云 九宵雲 +九宵云外 九宵雲外 +九扎 九紮 +九折 九折 +九折优待 九折優待 +九折臂 九折臂 +九曲 九曲 +九曲桥 九曲橋 +九曲洞 九曲洞 +九杯 九杯 +九点钟 九點鐘 +九炼成钢 九鍊成鋼 +九百万 九百萬 +九百个 九百個 +九秋 九秋 +九秒钟 九秒鐘 +九章算术 九章算術 +九谷 九穀 +九里 九里 +九里余 九里餘 +九里区 九里區 +九针 九針 +九零后 九零後 +九霄云外 九霄雲外 +九面体 九面體 +九香虫 九香蟲 +九龙杯 九龍杯 +九龙表行 九龍表行 +乞力马扎罗山 乞力馬扎羅山 +乞留恶滥 乞留惡濫 +乞留曲律 乞留曲律 +也不尽然 也不盡然 +也克制 也剋制 +也向 也向 +也对于 也對於 +也念 也念 +也斗了胆 也斗了膽 +也舍下 也捨下 +也须 也須 +习于 習於 +习惯于 習慣於 +习玩 習翫 +习非胜是 習非勝是 +乡党 鄉黨 +乡党尚齿 鄉黨尚齒 +乡团 鄉團 +乡土艺术 鄉土藝術 +乡愿 鄉愿 +乡曲 鄉曲 +乡曲之誉 鄉曲之譽 +乡民代表 鄉民代表 +乡民代表会 鄉民代表會 +乡里 鄉里 +乡里小人 鄉里小人 +乡镇代表 鄉鎮代表 +乡镇民代表 鄉鎮民代表 +乡间别墅 鄉間別墅 +乡面 鄉面 +书不尽 書不盡 +书不尽言 書不盡言 +书中自有千钟粟 書中自有千鍾粟 +书写不能症 書寫不能症 +书刊杂志 書刊雜誌 +书卷 書卷 +书卷奖 書卷獎 +书卷气 書卷氣 +书台 書檯 +书后 書後 +书呆子 書呆子 +书坛 書壇 +书录 書錄 +书报杂志 書報雜誌 +书柜 書櫃 +书种 書種 +书签 書籤 +书系 書系 +书虫 書蟲 +书虫子 書蟲子 +书面 書面 +书面上 書面上 +书面报告 書面報告 +书面纸 書面紙 +书面许可 書面許可 +书面语 書面語 +书面资料 書面資料 +乩坛 乩壇 +买一个饶一个 買一個饒一個 +买了 買了 +买价 買價 +买凶 買兇 +买咸鱼放生 買鹹魚放生 +买回 買回 +买回去 買回去 +买回家 買回家 +买回来 買回來 +买大彩 買大彩 +买汇 買匯 +买烟 買菸 +买物历 買物歷 +买臣复水 買臣覆水 +买闲钱 買閒錢 +买面子 買面子 +买风云雷雨 買風雲雷雨 +乱世凶年 亂世凶年 +乱了 亂了 +乱了手脚 亂了手腳 +乱作一团 亂作一團 +乱党 亂黨 +乱冲 亂衝 +乱发 亂髮 +乱哄 亂鬨 +乱哄不过来 亂鬨不過來 +乱哄哄 亂哄哄 +乱成一团 亂成一團 +乱扣 亂扣 +乱搞男女关系 亂搞男女關係 +乱松松 亂鬆鬆 +乱极则平 亂極則平 +乱棒胡敲 亂棒胡敲 +乱涂 亂塗 +乱针绣 亂針繡 +乱集团 亂集團 +乱首垢面 亂首垢面 +乳制品 乳製品 +乳娘 乳孃 +乳液聚合 乳液聚合 +乳糖不耐症 乳糖不耐症 +乳臭未干 乳臭未乾 +乳药求死 乳藥求死 +乾元 乾元 +乾兌 乾兌 +乾卦 乾卦 +乾坤一掷 乾坤一擲 +乾坤再造 乾坤再造 +乾坤大挪移 乾坤大挪移 +乾尽午中 乾盡午中 +乾象历 乾象曆 +乾隆 乾隆 +乾隆年间 乾隆年間 +乾隆皇帝 乾隆皇帝 +了不得 了不得 +了不成 了不成 +了不起 了不起 +了了 了了 +了事 了事 +了事环 了事環 +了债 了債 +了儿 了兒 +了决 了決 +了劣 了劣 +了却 了卻 +了却此生 了卻此生 +了去 了去 +了如 瞭如 +了如指掌 瞭如指掌 +了局 了局 +了帐 了帳 +了当 了當 +了当不得 了當不得 +了得 了得 +了得了 了得了 +了悟 了悟 +了愿 了願 +了手 了手 +了收 了收 +了断 了斷 +了无 了無 +了无挂碍 了無掛礙 +了无新意 了無新意 +了无牵挂 了無牽掛 +了无生机 了無生機 +了无生趣 了無生趣 +了无痕迹 了無痕跡 +了无罣碍 了無罣礙 +了无长进 了無長進 +了望 瞭望 +了望台 瞭望臺 +了望塔 瞭望塔 +了望山 瞭望山 +了望所 瞭望所 +了案 了案 +了此残生 了此殘生 +了毕 了畢 +了清 了清 +了然 瞭然 +了然不惑 瞭然不惑 +了然于心 瞭然於心 +了纳 了納 +了结 了結 +了若指掌 瞭若指掌 +了落 了落 +了解 瞭解 +了解到 瞭解到 +了讫 了訖 +了话 了話 +了语 了語 +了账 了賬 +了身达命 了身達命 +了鸟 了鳥 +争了 爭了 +争先发言 爭先發言 +争先后 爭先後 +争先恐后 爭先恐後 +争出 爭出 +争奇斗妍 爭奇鬥妍 +争奇斗异 爭奇鬥異 +争奇斗艳 爭奇鬥豔 +争妍斗奇 爭妍鬥奇 +争妍斗胜 爭妍鬥勝 +争妍斗艳 爭妍鬥豔 +争强好胜 爭強好勝 +争强斗胜 爭強鬥勝 +争强显胜 爭強顯勝 +争强赌胜 爭強賭勝 +争斗 爭鬥 +争斗不休 爭鬥不休 +争相罗致 爭相羅致 +争红斗紫 爭紅鬥紫 +争胜 爭勝 +争胜要强 爭勝要強 +争闲气 爭閒氣 +争面子 爭面子 +事与愿违 事與願違 +事也干 事也幹 +事出 事出 +事出不意 事出不意 +事出不测 事出不測 +事出有因 事出有因 +事前事后 事前事後 +事发 事發 +事发地点 事發地點 +事发时 事發時 +事可干 事可幹 +事后 事後 +事后聪明 事後聰明 +事后诸葛亮 事後諸葛亮 +事好干 事好幹 +事实胜于雄辩 事實勝於雄辯 +事干 事幹 +事态发展 事態發展 +事情可干 事情可幹 +事情好干 事情好幹 +事情干脆 事情干脆 +事成之后 事成之後 +事有斗巧 事有鬥巧 +事迹 事蹟 +二丁挂 二丁掛 +二仑 二崙 +二仑乡 二崙鄉 +二价 二價 +二余 二餘 +二党制 二黨制 +二六板 二六板 +二冲程引擎 二衝程引擎 +二出祁山 二出祁山 +二分钟 二分鐘 +二划 二劃 +二叠系 二疊系 +二口虫 二口蟲 +二只 二隻 +二台 二臺 +二叶松 二葉松 +二合一 二合一 +二吊六 二吊六 +二周 二週 +二和药 二和藥 +二回 二回 +二回熟 二回熟 +二堂舍子 二堂舍子 +二天后 二天後 +二姑娘顽老雕 二姑娘頑老雕 +二娘 二孃 二娘 +二娘子 二娘子 +二屋里 二屋裏 +二年制 二年制 +二弦 二絃 +二志 二志 +二恶英 二噁英 +二手烟 二手菸 +二拉八当 二拉八當 +二撇胡 二撇鬍 +二斗 二斗 +二杆子 二桿子 +二杯 二杯 +二板 二板 +二极 二極 +二极体 二極體 +二极管 二極管 +二柜 二櫃 +二次曲 二次曲 +二次曲线 二次曲線 +二次曲面 二次曲面 +二段制 二段制 +二流人才 二流人才 +二点钟 二點鐘 +二班制 二班制 +二田制 二田制 +二百万 二百萬 +二百个 二百個 +二百多万 二百多萬 +二种 二種 +二秒钟 二秒鐘 +二缶钟惑 二缶鐘惑 +二老板 二老闆 +二胡 二胡 +二致 二致 +二苏 二蘇 +二虎相斗 二虎相鬥 +二表哥 二表哥 +二表妹 二表妹 +二表姊 二表姊 +二表姊夫 二表姊夫 +二表姐 二表姐 +二表嫂 二表嫂 +二表弟 二表弟 +二进位制 二進位制 +二进制 二進制 +二部制 二部制 +二部合唱 二部合唱 +二部曲 二部曲 +二里 二里 +二里头 二里頭 +二里头文化 二里頭文化 +二重分类表 二重分類表 +二门不出 二門不出 +二面角 二面角 +二项式系数 二項式係數 +于一 於一 +于一役 於一役 +于七 於七 +于三 於三 +于丑 於醜 +于世 於世 +于丹 于丹 +于之 於之 +于乎 於乎 +于乐 於樂 +于九 於九 +于事 於事 +于事无济 於事無濟 +于事无补 於事無補 +于二 於二 +于于 于于 +于五 於五 +于人 於人 +于仁泰 于仁泰 +于今 於今 +于今犹烈 於今猶烈 +于从濂 于從濂 +于他 於他 +于伏 於伏 +于会泳 于會泳 +于伟国 于偉國 +于何 於何 +于余曲折 于餘曲折 +于你 於你 +于佳卉 于佳卉 +于光远 于光遠 +于克勒 于克勒 +于八 於八 +于六 於六 +于冕 于冕 +于军 于軍 +于农 於農 +于凌奎 于凌奎 +于凤桐 于鳳桐 +于凤至 于鳳至 +于前 於前 +于劣 於劣 +于勒 于勒 +于勤 於勤 +于化虎 于化虎 +于十 於十 +于半 於半 +于占元 于占元 +于双戈 于雙戈 +于台烟 于臺煙 +于右任 于右任 +于吉 于吉 +于后 於後 +于呼哀哉 於呼哀哉 +于品海 于品海 +于嗟 于嗟 +于四 於四 +于国 於國 +于国桢 于國楨 +于坚 于堅 +于垂 於垂 +于堅 于堅 +于墙 於牆 +于大宝 于大寶 +于天仁 于天仁 +于夫罗 於夫羅 +于奇库杜克 于奇庫杜克 +于她 於她 +于好 於好 +于始 於始 +于姓 于姓 +于娜 于娜 +于娟 于娟 +于子千 于子千 +于孔兼 于孔兼 +于学忠 于學忠 +于它 於它 +于家 於家 +于家为国 於家爲國 +于家堡 于家堡 +于密 於密 +于寘 于寘 +于小伟 于小偉 +于小彤 于小彤 +于尔岑 于爾岑 +于尔根 于爾根 +于尔里克 于爾里克 +于尽 於盡 +于山 于山 +于山国 于山國 +于左 於左 +于差 於差 +于己 於己 +于市 於市 +于帅 于帥 +于帥 于帥 +于幕 於幕 +于幼军 于幼軍 +于幼华 於幼華 +于广洲 于廣洲 +于康震 于康震 +于式枚 于式枚 +于弱 於弱 +于强 於強 +于归 于歸 +于征 於徵 +于徐 于徐 +于從濂 于從濂 +于德海 于德海 +于心 於心 +于心不安 於心不安 +于心不忍 於心不忍 +于心何忍 於心何忍 +于心无愧 於心無愧 +于志宁 于志寧 +于怀 於懷 +于思 于思 +于慎行 于慎行 +于慧 于慧 +于戏 於戲 +于成龍 于成龍 +于成龙 于成龍 +于我 於我 +于振 于振 +于振武 于振武 +于敏 于敏 +于敏中 于敏中 +于敝 於敝 +于斌 于斌 +于斯 於斯 +于斯塔德 于斯塔德 +于斯納爾斯貝里 于斯納爾斯貝里 +于斯纳尔斯贝里 于斯納爾斯貝里 +于斯达尔 于斯達爾 +于斯達爾 于斯達爾 +于时 於時 +于明涛 于明濤 +于是 於是 +于是之 於是之 +于是乎 於是乎 +于是就 於是就 +于晨楠 于晨楠 +于晴 于晴 +于杰 于傑 +于树洁 于樹潔 +于根伟 于根偉 +于格 于格 +于梨华 於梨華 +于樂 于樂 +于欣源 于欣源 +于正升 于正昇 +于正昌 于正昌 +于此 於此 +于毕 於畢 +于民 於民 +于民润国 於民潤國 +于水 於水 +于永波 于永波 +于汉超 于漢超 +于江震 于江震 +于法 於法 +于法无据 於法無據 +于波 于波 +于泽尔 于澤爾 +于洪区 于洪區 +于浩威 于浩威 +于海洋 于海洋 +于涛 于濤 +于湘兰 于湘蘭 +于潜县 於潛縣 +于濤 于濤 +于火 於火 +于焉 於焉 +于爾里克 于爾里克 +于物 於物 +于特森 于特森 +于玉立 于玉立 +于田 于田 +于田县 于田縣 +于盲 於盲 +于祂 於祂 +于禁 于禁 +于秀敏 于秀敏 +于穆 於穆 +于素秋 于素秋 +于终 於終 +于美 於美 +于美人 於美人 +于色 於色 +于若木 于若木 +于荫霖 于蔭霖 +于菟 於菟 +于蓝 於藍 +于行 於行 +于衡 于衡 +于衷 於衷 +于西翰 于西翰 +于謙 于謙 +于该 於該 +于谦 于謙 +于贈 于贈 +于贝尔 于貝爾 +于赠 于贈 +于越 于越 +于軍 于軍 +于过 於過 +于远伟 于遠偉 +于途 於途 +于道泉 于道泉 +于邑 於邑 +于都 于都 +于都县 于都縣 +于里察 于里察 +于野 於野 +于阗 于闐 +于陆 於陸 +于雾霭之中 於霧靄之中 +于震寰 于震寰 +于震环 于震環 +于靖 于靖 +于韋斯屈萊 于韋斯屈萊 +于韦斯屈莱 于韋斯屈萊 +于风政 于風政 +于飞 于飛 +于飞之乐 于飛之樂 +于馀曲折 于餘曲折 +于默奥 于默奧 +亏不尽 虧不盡 +亏了 虧了 +亏折 虧折 +亏本出售 虧本出售 +云中 雲中 +云中君 雲中君 +云中白鹤 雲中白鶴 +云为 云爲 +云乎 云乎 +云云 云云 +云从龙风从虎 雲從龍風從虎 +云仙杂记 雲仙雜記 +云何 云何 +云儿 雲兒 +云兴霞蔚 雲興霞蔚 +云冈 雲岡 +云冈石佛 雲岡石佛 +云冈石窟 雲岡石窟 +云出无心 雲出無心 +云华 雲華 +云南 雲南 +云南回变 雲南回變 +云南白药 雲南白藥 +云南省 雲南省 +云南起义 雲南起義 +云南黄馨 雲南黃馨 +云县 雲縣 +云台 雲臺 +云台山 雲臺山 +云合雾集 雲合霧集 +云吞 雲吞 +云吞面 雲吞麪 +云和 雲和 +云和县 雲和縣 +云嘉南 雲嘉南 +云团 雲團 +云图 雲圖 +云城区 云城區 +云天 雲天 +云天昊 雲天昊 +云天高谊 雲天高誼 +云头 雲頭 +云头儿 雲頭兒 +云子 雲子 +云孙 雲孫 +云安 雲安 +云安县 雲安縣 +云实 雲實 +云室 雲室 +云小啾 雲小啾 +云尔 云爾 +云层 雲層 +云屏 雲屏 +云屯雨集 雲屯雨集 +云山 雲山 +云山雾罩 雲山霧罩 +云岩区 雲巖區 +云岭 雲嶺 +云帆 雲帆 +云师 雲師 +云帚 雲帚 +云开见日 雲開見日 +云形定规 雲形定規 +云彩 雲彩 +云影 雲影 +云情雨意 雲情雨意 +云房 雲房 +云手 雲手 +云扰 雲擾 +云收雨散 雲收雨散 +云收雾散 雲收霧散 +云散 雲散 +云散风流 雲散風流 +云景 雲景 +云朵 雲朵 +云杉 雲杉 +云板 雲板 +云林 雲林 +云林人 雲林人 +云林县 雲林縣 +云林寺 雲林寺 +云林工专 雲林工專 +云林科技大学 雲林科技大學 +云林讯 雲林訊 +云栈 雲棧 +云根 雲根 +云梢 雲梢 +云梦 雲夢 +云梦县 雲夢縣 +云梦大泽 雲夢大澤 +云梯 雲梯 +云梯车 雲梯車 +云步 雲步 +云母 雲母 +云母片 雲母片 +云母石 雲母石 +云气 雲氣 +云水 雲水 +云水僧 雲水僧 +云水道人 雲水道人 +云汉 雲漢 +云河 雲河 +云泥 雲泥 +云泥之别 雲泥之別 +云泥异路 雲泥異路 +云浮 雲浮 +云浮市 雲浮市 +云海 雲海 +云消雨散 雲消雨散 +云消雾散 雲消霧散 +云涌 雲湧 +云涛 雲濤 +云液 雲液 +云淡风轻 雲淡風輕 +云游 雲遊 +云游四方 雲遊四方 +云溪 云溪 +云溪区 云溪區 +云烟 雲煙 +云烟过眼 雲煙過眼 +云烟过眼录 雲煙過眼錄 +云然 云然 +云爲 云爲 +云片糕 雲片糕 +云版 雲版 +云物 雲物 +云石 雲石 +云科大 雲科大 +云程发轫 雲程發軔 +云窗雾槛 雲窗霧檻 +云章 雲章 +云端 雲端 +云端里看厮杀 雲端裏看廝殺 +云端里老鼠 雲端裏老鼠 +云笈七签 雲笈七籤 +云笈七籤 雲笈七籤 +云篦 雲篦 +云精 雲精 +云系 雲系 +云网 雲網 +云翳 雲翳 +云翻雨复 雲翻雨覆 +云肩 雲肩 +云腿 雲腿 +云芝 雲芝 +云英 雲英 +云英未嫁 雲英未嫁 +云莽莽 雲莽莽 +云蒸霞蔚 雲蒸霞蔚 +云行雨施 雲行雨施 +云表 雲表 +云西市 雲西市 +云谲波诡 雲譎波詭 +云谷 雲谷 +云豆 雲豆 +云豹 雲豹 +云贵 雲貴 +云贵川 雲貴川 +云贵高原 雲貴高原 +云起龙骧 雲起龍驤 +云路 雲路 +云车 雲車 +云车风马 雲車風馬 +云遮月 雲遮月 +云量 雲量 +云锣 雲鑼 +云锦 雲錦 +云门 雲門 +云门舞集 雲門舞集 +云阳 雲陽 +云阳县 雲陽縣 +云阳市 雲陽市 +云阶月地 雲階月地 +云际 雲際 +云雀 雲雀 +云集 雲集 +云雨 雲雨 +云雨之欢 雲雨之歡 +云雨巫山 雲雨巫山 +云雨高唐 雲雨高唐 +云雾 雲霧 +云雾径迹 雲霧徑跡 +云霄 雲霄 +云霄县 雲霄縣 +云霄飞车 雲霄飛車 +云霓 雲霓 +云霓之望 雲霓之望 +云霞 雲霞 +云霭 雲靄 +云顶 雲頂 +云须 雲鬚 +云髻 雲髻 +云鬓 雲鬢 +云鬟 雲鬟 +云麾勋章 雲麾勳章 +云麾将军碑 雲麾將軍碑 +云龙 雲龍 +云龙区 雲龍區 +云龙县 雲龍縣 +云龙风虎 雲龍風虎 +互不干涉 互不干涉 +互不干涉內政 互不干涉內政 +互于 互於 +互别苗头 互別苗頭 +互制 互制 +互动关系 互動關係 +互动台 互動臺 +互助合作 互助合作 +互发 互發 +互向 互向 +互有胜负 互有勝負 +互生叶 互生葉 +互相联系 互相聯繫 +互致问候 互致問候 +互蒙其利 互蒙其利 +互鉴 互鑑 +五七干校 五七幹校 +五七干部学校 五七幹部學校 +五万 五萬 +五万三千 五萬三千 +五万两千 五萬兩千 +五万五千 五萬五千 +五万八千 五萬八千 +五世同堂 五世同堂 +五个 五個 +五代同堂 五代同堂 +五余 五餘 +五倍子虫 五倍子蟲 +五克 五克 +五党 五黨 +五公里 五公里 +五出戏 五齣戲 +五出祁山 五出祁山 +五分钟 五分鐘 +五划 五劃 +五十五万 五十五萬 +五十六万 五十六萬 +五十多万 五十多萬 +五千 五千 +五千多万 五千多萬 +五发 五發 +五只 五隻 +五台 五臺 +五台县 五臺縣 +五台山 五臺山 +五台市 五臺市 +五叶 五葉 +五周 五週 +五周年 五週年 +五天后 五天後 +五岳 五嶽 +五年计划 五年計劃 +五度制调值标记法 五度制調值標記法 +五弦 五絃 +五彩 五彩 +五彩夺目 五彩奪目 +五彩宾纷 五彩賓紛 +五彩缤纷 五彩繽紛 +五扎 五紮 +五折 五折 +五斗 五斗 +五斗折腰 五斗折腰 +五斗柜 五斗櫃 +五斗橱 五斗櫥 +五斗米 五斗米 +五斗米道 五斗米道 +五斗解酲 五斗解酲 +五杯 五杯 +五板 五板 +五棵松 五棵松 +五浊恶世 五濁惡世 +五点钟 五點鐘 +五百万 五百萬 +五百个 五百個 +五百多万 五百多萬 +五百姻缘天注定 五百姻緣天註定 +五种 五種 +五种性 五種性 +五秒钟 五秒鐘 +五笔划 五筆劃 +五育并重 五育並重 +五胡 五胡 +五胡之乱 五胡之亂 +五胡乱华 五胡亂華 +五胡十六国 五胡十六國 +五脏 五臟 +五脏俱全 五臟俱全 +五脏六腑 五臟六腑 +五脏庙 五臟廟 +五脏神 五臟神 +五色祥云 五色祥雲 +五花腌猪肉 五花醃豬肉 +五虫 五蟲 +五行并下 五行並下 +五行生克 五行生剋 +五谷 五穀 +五谷不分 五穀不分 +五谷不升 五穀不升 +五谷丰收 五穀豐收 +五谷丰登 五穀豐登 +五谷丰稔 五穀豐稔 +五谷杂粮 五穀雜糧 +五谷王北街 五谷王北街 +五谷王南街 五谷王南街 +五辟 五辟 +五采 五采 +五里 五里 +五里雾 五里霧 +五里雾中 五里霧中 +五面 五面 +五面体 五面體 +五马分尸 五馬分屍 +井台 井臺 +井干 井榦 +井干摧败 井榦摧敗 +井田制 井田制 +井田制度 井田制度 +井里 井裏 +亘古 亙古 +亚东关系 亞東關係 +亚于 亞於 +亚克力 亞克力 +亚克朗 亞克朗 +亚利叶 亞利葉 +亚力克 亞力克 +亚历 亞歷 +亚历山大 亞歷山大 +亚历桑 亞歷桑 +亚当 亞當 +亚当山德勒 亞當山德勒 +亚当斯 亞當斯 +亚当斯密 亞當斯密 +亚得里亚海 亞得里亞海 +亚德安布洛迪 亞德安布洛迪 +亚松森 亞松森 +亚核 亞核 +亚洲周刊 亞洲週刊 +亚洲杯 亞洲盃 +亚穆苏克罗 亞穆蘇克羅 +亚美利加人种 亞美利加人種 +亚美尼亚历 亞美尼亞曆 +亚词汇单元 亞詞彙單元 +亚里 亞里 +亚里士多德 亞里士多德 +亚里斯多德 亞里斯多德 +亚里斯提 亞里斯提 +亚雷克斯 亞雷克斯 +亚青杯 亞青盃 +亚麻布 亞麻布 +亟欲 亟欲 +亟须 亟須 +亡了 亡了 +亡国灭种 亡國滅種 +交个 交個 +交了 交了 +交于 交於 +交出 交出 +交出去 交出去 +交出来 交出來 +交割价 交割價 +交卷 交卷 +交叉耐药性 交叉耐藥性 +交发 交發 +交口称赞 交口稱讚 +交合 交合 +交哄 交鬨 +交响乐团 交響樂團 +交响曲 交響曲 +交回 交回 +交回去 交回去 +交回来 交回來 +交困 交困 +交差了事 交差了事 +交并 交併 +交恶 交惡 +交战团体 交戰團體 +交托 交託 +交换价值 交換價值 +交换技术 交換技術 +交易价 交易價 +交易台 交易臺 +交杯 交杯 +交杯盏 交杯盞 +交杯酒 交杯酒 +交汇 交匯 +交汇处 交匯處 +交流团 交流團 +交游 交遊 +交游广阔 交遊廣闊 +交白卷 交白卷 +交货价 交貨價 +交通号志 交通號誌 +交通标志 交通標誌 +交通管制 交通管制 +交面 交面 +亦云 亦云 +亦同 亦同 +亦对于 亦對於 +亦庄亦谐 亦莊亦諧 +亦当 亦當 +亦舍下 亦捨下 +亦须 亦須 +产业别 產業別 +产业后备 產業後備 +产业链 產業鏈 +产出 產出 +产制 產製 +产卵洄游 產卵洄游 +产后 產後 +产后检査 產後檢查 +产品组合 產品組合 +产地价格 產地價格 +产婆术 產婆術 +产学合作 產學合作 +产生出 產生出 +产销合一 產銷合一 +产销合同 產銷合同 +亨利克森 亨利克森 +亨塞克 亨塞克 +享尽 享盡 +享御 享御 +京二胡 京二胡 +京胡 京胡 +亭台 亭臺 +亭台楼榭 亭臺樓榭 +亭台楼阁 亭臺樓閣 +亭彩 亭彩 +亭彩店 亭彩店 +亮丑 亮醜 +亮光蜡 亮光蠟 +亮彩 亮彩 +亮钟 亮鐘 +亲历 親歷 +亲历其境 親歷其境 +亲友团 親友團 +亲台 親臺 +亲娘 親孃 +亲子关系 親子關係 +亲子台 親子臺 +亲子鉴定 親子鑑定 +亲密关系 親密關係 +亲属关系 親屬關係 +亲幸 親倖 +亲征 親征 +亲戚 親戚 +亲戚关系 親戚關係 +亲极反疏 親極反疏 +亲民党 親民黨 +亲痛仇快 親痛仇快 +亲笔签名 親筆簽名 +亲系 親系 +亲缘关系 親緣關係 +亲自出马 親自出馬 +亲自干 親自幹 +亲自挂帅 親自掛帥 +亲身经历 親身經歷 +亹亹不卷 亹亹不卷 +人中豪杰 人中豪傑 +人为万物之灵 人爲萬物之靈 +人云 人云 +人云亦云 人云亦云 +人众胜天 人衆勝天 +人体彩绘 人體彩繪 +人克莱门斯 人克萊門斯 +人出现 人出現 +人别哭 人別哭 +人到中年万事休 人到中年萬事休 +人制 人制 +人前人后 人前人後 +人力回天 人力回天 +人千人万 人千人萬 +人参 人蔘 +人参果 人蔘果 +人参精 人蔘精 +人口分布 人口分佈 +人各有志 人各有志 +人同此心 人同此心 +人同此心心同此理 人同此心心同此理 +人后 人後 +人团法 人團法 +人困马乏 人困馬乏 +人如其面 人如其面 +人如风后入江云 人如風後入江雲 +人定胜天 人定勝天 +人寿年丰 人壽年豐 +人尽其才 人盡其才 +人尽可夫 人盡可夫 +人尽皆知 人盡皆知 +人工冬眠 人工冬眠 +人工心脏 人工心臟 +人工阅卷 人工閱卷 +人心不同 人心不同 +人心向背 人心向背 +人心如面 人心如面 +人心所向 人心所向 +人心涣漓 人心渙漓 +人性本恶 人性本惡 +人才 人才 +人才出众 人才出衆 +人才外流 人才外流 +人才库 人才庫 +人才流失 人才流失 +人才济济 人才濟濟 +人才辈出 人才輩出 +人才难得 人才難得 +人无千日 人無千日 +人机介面 人機介面 +人机界面 人機界面 +人权斗士 人權鬥士 +人杰 人傑 +人杰地灵 人傑地靈 +人极 人極 +人欲 人慾 +人欲横流 人慾橫流 +人民代表 人民代表 +人民党 人民黨 +人民团体 人民團體 +人民意志 人民意志 +人流手术 人流手術 +人浮于事 人浮於事 +人浮于食 人浮於食 +人海战术 人海戰術 +人烟 人煙 +人烟凑集 人煙湊集 +人烟浩穰 人煙浩穰 +人烟稀少 人煙稀少 +人烟稠密 人煙稠密 +人烟辐辏 人煙輻輳 +人物志 人物誌 +人生价值 人生價值 +人生舞台 人生舞臺 +人神同愤 人神同憤 +人种 人種 +人种学 人種學 +人种差别 人種差別 +人穷志不穷 人窮志不窮 +人穷志短 人窮志短 +人老精姜老辣 人老精薑老辣 +人胜节 人勝節 +人赃俱获 人贓俱獲 +人造板 人造板 +人造纤维 人造纖維 +人链 人鏈 +人间烟火 人間煙火 +人际关系 人際關係 +人面 人面 +人面上 人面上 +人面兽心 人面獸心 +人面桃花 人面桃花 +人面狮身 人面獅身 +人面逐高低 人面逐高低 +人饥己饥 人飢己飢 +亿万 億萬 +亿万富翁 億萬富翁 +亿万富豪 億萬富豪 +亿万斯年 億萬斯年 +亿个 億個 +亿余 億餘 +亿只 億隻 +亿多只 億多隻 +亿天后 億天後 +什不闲 什不閒 +什么 什麼 +什叶派 什葉派 +什里店 什里店 +什锦炒面 什錦炒麪 +什锦面 什錦麪 +什面 什面 +仁人志士 仁人志士 +仁布 仁布 +仁布县 仁布縣 +仁心仁术 仁心仁術 +仁术 仁術 +仁杰 仁杰 +仁武厂 仁武廠 +仁至义尽 仁至義盡 +仅余 僅餘 +仅作参考 僅作參考 +仅供参考 僅供參考 +仅占 僅佔 +仅只 僅只 +仅次于 僅次於 +仆人 僕人 +仆仆 僕僕 +仆仆风尘 僕僕風塵 +仆从 僕從 +仆使 僕使 +仆倒 仆倒 +仆僮 僕僮 +仆僮成群 僕僮成羣 +仆吏 僕吏 +仆固怀恩 僕固懷恩 +仆地 仆地 +仆夫 僕伕 +仆妇 僕婦 +仆姑 僕姑 +仆婢 僕婢 +仆射 僕射 +仆射姑 僕射姑 +仆少 僕少 +仆役 僕役 +仆憎 僕憎 +仆欧 僕歐 +仆然 仆然 +仆程 僕程 +仆虽罢驽 僕雖罷駑 +仆街 仆街 +仇人 仇人 +仇仇 仇讎 +仇偶 仇偶 +仇口儿 仇口兒 +仇国论 仇國論 +仇外心理 仇外心理 +仇家 仇家 +仇怨 仇怨 +仇恨 仇恨 +仇恨罪 仇恨罪 +仇恨罪行 仇恨罪行 +仇敌 仇敵 +仇杀 仇殺 +仇梓鸣 仇梓鳴 +仇疙瘩 仇疙瘩 +仇英 仇英 +仇视 仇視 +仇隙 仇隙 +仇香 仇香 +今儿个 今兒個 +今冬 今冬 +今后 今後 +今秋 今秋 +介于 介於 +介于两难 介於兩難 +介壳虫 介殼蟲 +介系词 介係詞 +介绍出来 介紹出來 +介胄 介冑 +介虫 介蟲 +介面 介面 +介面卡 介面卡 +介面板 介面板 +仍复 仍復 +从上向下 從上向下 +从下向上 從下向上 +从事于 從事於 +从于 從於 +从今以后 從今以後 +从价税 從價稅 +从外向內 從外向內 +从宽发落 從寬發落 +从属于 從屬於 +从属关系 從屬關係 +从心所欲 從心所欲 +从此以后 從此以後 +从此往后 從此往後 +从轻发落 從輕發落 +从里到外 從裏到外 +从里向外 從裏向外 +仑丰村 崙豐村 +仑背 崙背 +仑背乡 崙背鄉 +仓皇出逃 倉皇出逃 +他了 他了 +他克制 他剋制 +他出 他出 +他出去 他出去 +他出来 他出來 +他志 他志 +他念 他念 +他种 他種 +他钟 他鐘 +仗托 仗托 +付了 付了 +付出 付出 +付出去 付出去 +付出型 付出型 +付合 付合 +付托 付託 +仙台 仙台 +仙后 仙后 +仙后座 仙后座 +仙坛 仙壇 +仙岩 仙岩 +仙才 仙才 +仙术 仙術 +仙游 仙遊 +仙游县 仙遊縣 +仙药 仙藥 +仙迹 仙蹟 +仟克 仟克 +仡栗 仡栗 +代价 代價 +代出 代出 +代工厂 代工廠 +代录 代錄 +代扣 代扣 +代数几何 代數幾何 +代数曲线 代數曲線 +代数曲面 代數曲面 +代理 代理 +代码表 代碼表 +代签 代簽 +代签人 代簽人 +代表 代表 +代表人 代表人 +代表人物 代表人物 +代表会 代表會 +代表作 代表作 +代表团 代表團 +代表处 代表處 +代表大会 代表大會 +代表性 代表性 +代表权 代表權 +代表署 代表署 +代表色 代表色 +代表金 代表金 +代表队 代表隊 +代议制 代議制 +令人发指 令人髮指 +令人注目 令人注目 +令出如山 令出如山 +令出必行 令出必行 +令出惟行 令出惟行 +令岳 令岳 +令狐冲 令狐沖 +以一当十 以一當十 +以一持万 以一持萬 +以一知万 以一知萬 +以一驭万 以一馭萬 +以人为鉴 以人爲鑑 +以价制量 以價制量 +以众克寡 以衆克寡 +以免借口 以免藉口 +以冰致蝇 以冰致蠅 +以利于 以利於 +以功复过 以功覆過 +以升量石 以升量石 +以华制华 以華制華 +以古为鉴 以古爲鑑 +以后 以後 +以售其奸 以售其奸 +以多胜少 以多勝少 +以夷制夷 以夷制夷 +以少克众 以少克衆 +以少胜多 以少勝多 +以弱制强 以弱制強 +以弱胜强 以弱勝強 +以往鉴来 以往鑑來 +以意逆志 以意逆志 +以智取胜 以智取勝 +以暴制暴 以暴制暴 +以柔克刚 以柔克剛 +以柔制刚 以柔制剛 +以泪洗面 以淚洗面 +以点带面 以點帶面 +以自制 以自制 +以至于 以至於 +以致 以致 +以致于 以致於 +以药养医 以藥養醫 +以莛叩钟 以莛叩鐘 +以莛撞钟 以莛撞鐘 +以蜡代薪 以蠟代薪 +以观后效 以觀後效 +以貍致鼠 以貍致鼠 +以防万一 以防萬一 +以静制动 以靜制動 +仪制 儀制 +仪器表 儀器表 +仪征 儀徵 +仪征市 儀徵市 +仪态万千 儀態萬千 +仪态万方 儀態萬方 +仪注 儀注 +仪范 儀範 +仪表 儀表 儀錶 +仪表出众 儀表出衆 +仪表堂堂 儀表堂堂 +仪表板 儀表板 +仪表版 儀表版 +仪表盘 儀表盤 +仰之弥高 仰之彌高 +仰叹 仰嘆 +仰给于人 仰給於人 +仰药 仰藥 +仰面 仰面 +仲冬 仲冬 +仲秋 仲秋 +件钟 件鐘 +价位 價位 +价值 價值 +价值冲突 價值衝突 +价值判断 價值判斷 +价值增殖 價值增殖 +价值尺度 價值尺度 +价值工程 價值工程 +价值形式 價值形式 +价值感 價值感 +价值指标 價值指標 +价值标准 價值標準 +价值观 價值觀 +价值观念 價值觀念 +价值规律 價值規律 +价值论 價值論 +价值连城 價值連城 +价值逻辑 價值邏輯 +价值量 價值量 +价单 價單 +价差 價差 +价廉物美 價廉物美 +价格 價格 +价格冻结 價格凍結 +价格战 價格戰 +价格标 價格標 +价格标签 價格標籤 +价格范围 價格範圍 +价格表 價格表 +价款 價款 +价比 價比 +价电子 價電子 +价目 價目 +价目单 價目單 +价目表 價目表 +价码 價碼 +价钱 價錢 +任一个 任一個 +任于 任於 +任人摆布 任人擺佈 +任务团 任務團 +任教于 任教於 +任期制 任期制 +任由摆布 任由擺佈 +任笔沈诗 任筆沈詩 +任重致远 任重致遠 +仿佛 彷彿 +仿制 仿製 +仿制品 仿製品 +仿制药 仿製藥 +企业团 企業團 +企业系 企業系 +企业集团 企業集團 +企划 企劃 +企划书 企劃書 +企划人 企劃人 +企划厅 企劃廳 +企划处 企劃處 +企划案 企劃案 +企划组 企劃組 +企划部 企劃部 +企管系 企管系 +伊万诺 伊萬諾 +伊于湖底 伊于湖底 +伊于胡底 伊于胡底 +伊吉克 伊吉克 +伊周 伊周 +伊塞克湖 伊塞克湖 +伊布拉欣 伊布拉欣 +伊府面 伊府麪 +伊拉克 伊拉克 +伊拉克人 伊拉克人 +伊拉克籍 伊拉克籍 +伊拉克队 伊拉克隊 +伊斯兰党 伊斯蘭黨 +伊斯兰历 伊斯蘭曆 +伊核 伊核 +伊犁纵谷 伊犁縱谷 +伊莱克斯 伊萊克斯 +伊郁 伊鬱 +伊里奇 伊里奇 +伊里布 伊里布 +伊里格瑞 伊裏格瑞 +伊面 伊麪 +伍员鞭尸 伍員鞭屍 +伍德合金 伍德合金 +伍瑞克 伍瑞克 +伍采克 伍采克 +伏几 伏几 +伏尸 伏屍 +伏尸流血 伏屍流血 +伏尸遍野 伏屍遍野 +伏愿 伏願 +伏胜 伏勝 +伐异党同 伐異黨同 +伐罪吊民 伐罪弔民 +休仑湖 休崙湖 +休克 休克 +休征 休徵 +休戚 休慼 +休戚与共 休慼與共 +休戚相关 休慼相關 +休杰克曼 休傑克曼 +休致 休致 +休闲区 休閒區 +休闲服 休閒服 +休闲活动 休閒活動 +休闲组 休閒組 +休闲裤 休閒褲 +休闲鞋 休閒鞋 +休闲风 休閒風 +休闲馆 休閒館 +众口同声 衆口同聲 +众口熏天 衆口熏天 +众志成城 衆志成城 +众所周知 衆所周知 +众曲不容直 衆曲不容直 +优于 優於 +优先发展 優先發展 +优势种 優勢種 +优哉游哉 優哉遊哉 +优惠价 優惠價 +优惠价格 優惠價格 +优游 優遊 +优游不迫 優遊不迫 +优游自在 優遊自在 +优游自得 優遊自得 +优胜 優勝 +优胜劣败 優勝劣敗 +优胜奖 優勝獎 +优胜者 優勝者 +优胜队 優勝隊 +伙人 夥人 +伙众 夥衆 +伙伴 夥伴 +伙伴国 夥伴國 +伙伴龙 夥伴龍 +伙办 夥辦 +伙友 夥友 +伙同 夥同 +伙够 夥夠 +伙夫 伙伕 +伙头 伙頭 +伙房 伙房 +伙穿 夥穿 +伙计 夥計 +伙食 伙食 +伙食团 伙食團 +伙食费 伙食費 +会上签署 會上簽署 +会上签订 會上簽訂 +会个 會個 +会了 會了 +会于 會於 +会党 會黨 +会出 會出 +会出去 會出去 +会出来 會出來 +会升 會升 +会占 會佔 +会占卜 會占卜 +会发 會發 +会合 會合 +会合周期 會合週期 +会合处 會合處 +会合点 會合點 +会吊 會弔 +会同 會同 +会同县 會同縣 +会后 會後 +会员价 會員價 +会员制 會員制 +会员团 會員團 +会场价 會場價 +会尽 會盡 +会干 會幹 +会干净 會乾淨 +会干扰 會干擾 +会干政 會干政 +会干杯 會乾杯 +会干枯 會乾枯 +会干涉 會干涉 +会干涸 會乾涸 +会干脆 會乾脆 +会干裂 會乾裂 +会干预 會干預 +会当 會當 +会念 會念 +会扣 會扣 +会杯 會杯 +会种 會種 +会签制度 會簽制度 +会计分录 會計分錄 +会计制度 會計制度 +会计报表 會計報表 +会计标准 會計標準 +会计系 會計系 +会议记录 會議記錄 +会逢其适 會逢其適 +会里 會里 +会里县 會里縣 +会长团 會長團 +会面 會面 +会面处 會面處 +会须 會須 +伞面 傘面 +伟克适 偉克適 +伟晶岩 偉晶岩 +传习录 傳習錄 +传于 傳於 +传位于四太子 傳位于四太子 +传出 傳出 +传出去 傳出去 +传出来 傳出來 +传出神经 傳出神經 +传制权 傳制權 +传动系统 傳動系統 +传动链 傳動鏈 +传发 傳發 +传回 傳回 +传回来 傳回來 +传布 傳佈 +传心术 傳心術 +传播出去 傳播出去 +传播学系 傳播學系 +传教团 傳教團 +传杯弄盏 傳杯弄盞 +传杯换盏 傳杯換盞 +传杯送盏 傳杯送盞 +传板 傳板 +传灯录 傳燈錄 +传热系数 傳熱係數 +传真发送 傳真發送 +传种 傳種 +传统中国医药 傳統中國醫藥 +传统医药 傳統醫藥 +传舍 傳舍 +传译出 傳譯出 +传赞 傳贊 +传输技术 傳輸技術 +传输控制 傳輸控制 +传输控制协定 傳輸控制協定 +传达出 傳達出 +传达出来 傳達出來 +传递出去 傳遞出去 +传闻证据 傳聞證據 +传颂千古 傳頌千古 +伤了 傷了 +伤亡枕藉 傷亡枕藉 +伤别 傷別 +伤口发炎 傷口發炎 +伤寒杆菌 傷寒桿菌 +伤寒症 傷寒症 +伤心欲绝 傷心欲絕 +伤心致死 傷心致死 +伤痕累累 傷痕累累 +伤药 傷藥 +伤风克 傷風克 +伦理 倫理 +伦理规范 倫理規範 +伪托 僞託 +伪药 僞藥 +伯余 伯余 +伯克 伯克 +伯克利 伯克利 +伯克制度 伯克制度 +伯克来 伯克來 +伯南克 伯南克 +伯娘 伯孃 +伯尔发斯特 伯爾發斯特 +伯杰 伯傑 +伯纳克 伯納克 +伯罗奔尼撒同盟 伯羅奔尼撒同盟 +伯里克利 伯里克利 +伯雍种玉 伯雍種玉 +估价 估價 +估价单 估價單 +估价行 估價行 +估算出 估算出 +伴同 伴同 +伴娘 伴娘 +伴游 伴遊 +伸出 伸出 +伸出去 伸出去 +伸出援手 伸出援手 +伸出来 伸出來 +伸向 伸向 +伸回 伸回 +伸回去 伸回去 +伸回来 伸回來 +伸展出 伸展出 +伸展出去 伸展出去 +伸志 伸志 +伸手不打笑面人 伸手不打笑面人 +似于 似於 +似松实紧 似鬆實緊 +佃租制度 佃租制度 +但云 但云 +但得一片橘皮吃且莫忘了洞庭湖 但得一片橘皮吃且莫忘了洞庭湖 +但愿 但願 +但愿如此 但願如此 +但曲 但曲 +但求如愿 但求如願 +但须 但須 +位于 位於 +位准 位準 +位极人臣 位極人臣 +低了 低了 +低于 低於 +低价 低價 +低价买进 低價買進 +低价位 低價位 +低价卖出 低價賣出 +低价团 低價團 +低价格 低價格 +低价高报 低價高報 +低卡路里 低卡路里 +低合金钢 低合金鋼 +低回 低迴 +低回不已 低迴不已 +低度发展国家 低度發展國家 +低标准 低標準 +低洼 低窪 +低筋面粉 低筋麪粉 +低荡 低盪 +低谷 低谷 +住个 住個 +住宅凶方 住宅兇方 +住扎 住紮 +佐饔得尝 佐饔得嘗 +体会出 體會出 +体制 體制 +体坛 體壇 +体坛人士 體壇人士 +体察出 體察出 +体干班 體幹班 +体彩 體彩 +体征 體徵 +体念 體念 +体温表 體溫表 +体物写志 體物寫志 +体现出 體現出 +体系 體系 +体系化 體系化 +体育台 體育臺 +体育系 體育系 +体育锻炼 體育鍛煉 +体胀系数 體脹係數 +体范 體範 +体表 體表 +体重表 體重表 +体面 體面 +体面起来 體面起來 +体验出 體驗出 +何以克当 何以克當 +何只 何只 +何小升 何小昇 +何尝 何嘗 +何干 何干 +何当 何當 +何必当初 何必當初 +何志 何志 +何志钦 何志欽 +何杰金氏病 何杰金氏病 +何极 何極 +何济于事 何濟於事 +何秋美 何秋美 +何种 何種 +何胜雄 何勝雄 +何至于 何至於 +何至于此 何至於此 +何豪杰 何豪傑 +何足挂齿 何足掛齒 +何须 何須 +余〇 餘〇 +余一 餘一 +余七 餘七 +余三 餘三 +余三勝 余三勝 +余三胜 余三勝 +余上沅 余上沅 +余下 餘下 +余业 餘業 +余个 餘個 +余九 餘九 +余事 餘事 +余二 餘二 +余五 餘五 +余亩 餘畝 +余人 餘人 +余件 餘件 +余众 餘衆 +余位 餘位 +余余 余余 +余俗 餘俗 +余倍 餘倍 +余僇 餘僇 +余元 餘元 +余光 餘光 +余光中 余光中 +余光生 余光生 +余党 餘黨 +余八 餘八 +余六 餘六 +余兰香 余蘭香 +余兴 餘興 +余刃 餘刃 +余切 餘切 +余利 餘利 +余剩 餘剩 +余割 餘割 +余力 餘力 +余勇 餘勇 +余勇可贾 餘勇可賈 +余十 餘十 +余压 餘壓 +余发扬 余發揚 +余只 餘隻 +余名 餘名 +余吾镇 余吾鎮 +余味 餘味 +余响 餘響 +余响绕梁 餘響繞梁 +余喘 餘喘 +余四 餘四 +余地 餘地 +余墨 餘墨 +余声 餘聲 +余外 餘外 +余天 余天 +余头 餘頭 +余妙 餘妙 +余姓 余姓 +余姚 餘姚 +余姚市 餘姚市 +余威 餘威 +余威德 余威德 +余子 餘子 +余子明 余子明 +余子碌碌 餘子碌碌 +余字 餘字 +余存 餘存 +余孽 餘孽 +余宪宗 余憲宗 +余岁 餘歲 +余干 餘干 +余干县 餘干縣 +余年 餘年 +余庆 餘慶 +余庆县 餘慶縣 +余座 餘座 +余弦 餘弦 +余思 餘思 +余思敏 余思敏 +余悸 餘悸 +余情 餘情 +余情未了 餘情未了 +余户 餘戶 +余政宪 余政憲 +余数 餘數 +余数定理 餘數定理 +余文 余文 +余文彬 余文彬 +余日 餘日 +余明 餘明 +余映 餘映 +余晖 餘暉 +余暇 餘暇 +余月 余月 +余本 餘本 +余杭 餘杭 +余杭区 餘杭區 +余杯 餘杯 +余枝 餘枝 +余桃 餘桃 +余桶 餘桶 +余次 餘次 +余款 餘款 +余歌沧 余歌滄 +余步 餘步 +余殃 餘殃 +余毒 餘毒 +余气 餘氣 +余氯 餘氯 +余江 餘江 +余江县 餘江縣 +余沥 餘瀝 +余波 餘波 +余波荡漾 餘波盪漾 +余泽 餘澤 +余派 餘派 +余温 餘溫 +余火 餘火 +余灿荣 余燦榮 +余炳贤 余炳賢 +余点 餘點 +余烈 餘烈 +余烬 餘燼 +余热 餘熱 +余珍 餘珍 +余珮琳 余珮琳 +余生 餘生 +余男 余男 +余留 餘留 +余留事务 餘留事務 +余留无符号数 餘留無符號數 +余码 餘碼 +余碧芬 余碧芬 +余秀菁 余秀菁 +余秉谚 余秉諺 +余种 餘種 +余窍 餘竅 +余筱萍 余筱萍 +余篇 餘篇 +余粮 餘糧 +余绪 餘緒 +余缺 餘缺 +余罪 餘罪 +余羡 餘羨 +余脉 餘脈 +余膏 餘膏 +余苑绮 余苑綺 +余英时 余英時 +余荫 餘蔭 +余蓄 餘蓄 +余裕 餘裕 +余角 餘角 +余论 餘論 +余貾 餘貾 +余责 餘責 +余贤明 余賢明 +余车 余車 +余载 餘載 +余辉 餘輝 +余辜 餘辜 +余部 餘部 +余酲 餘酲 +余里 餘里 +余量 餘量 +余钱 餘錢 +余闰 餘閏 +余闲 餘閒 +余集 餘集 +余雪兰 余雪蘭 +余雪明 余雪明 +余零 餘零 +余震 餘震 +余霞 餘霞 +余音 餘音 +余音绕梁 餘音繞樑 +余韵 餘韻 +余项 餘項 +余额 餘額 +余风 餘風 +余食 餘食 +余香 餘香 +佚游 佚遊 +佚荡 佚蕩 +佛修根 佛修根 +佛克斯 佛克斯 +佛克纳 佛克納 +佛兰克林 佛蘭克林 +佛前佛后 佛前佛後 +佛历 佛曆 +佛尼亚克 佛尼亞克 +佛布兹 佛布茲 +佛曲 佛曲 +佛瑞克 佛瑞克 +佛瑞斯特怀特克 佛瑞斯特懷特克 +佛科摆 佛科擺 +佛罗棱萨 佛羅棱薩 +佛罗里达 佛羅里達 +佛罗里达州 佛羅里達州 +佛舍利 佛舍利 +佛蒙特 佛蒙特 +佛蒙特州 佛蒙特州 +佛里特 佛里特 +佛里特曼 佛里特曼 +佛钟 佛鐘 +佛雷克 佛雷克 +佛面上刮金 佛面上刮金 +作业平台 作業平臺 +作业系统 作業系統 +作了 作了 +作价 作價 +作倒了行市 作倒了行市 +作准 作準 +作出 作出 +作出来 作出來 +作出让步 作出讓步 +作别 作別 +作品里 作品裏 +作奸犯科 作奸犯科 +作好准备 作好準備 +作幸 作倖 +作庄 作莊 +作废后 作廢後 +作息时间表 作息時間表 +作恶 作惡 +作恶多端 作惡多端 +作曲 作曲 +作曲人 作曲人 +作曲家 作曲家 +作曲者 作曲者 +作育英才 作育英才 +作舍道旁 作舍道旁 +作舍道边 作舍道邊 +佞幸 佞幸 +你克制 你剋制 +你夸我逞 你誇我逞 +你干一杯 你乾一杯 +你干那杯 你乾那杯 +你念 你念 +你才子发昏 你纔子發昏 +你搜 你搜 +你斗了胆 你斗了膽 +你是为了 你是爲了 +你有千条妙计我有一定之规 你有千條妙計我有一定之規 +你系 你係 +佣中佼佼 傭中佼佼 +佣书 傭書 +佣人 傭人 +佣仆 傭僕 +佣作 傭作 +佣保 傭保 +佣兵 傭兵 +佣工 傭工 +佣懒 傭懶 +佣给 傭給 +佣耕 傭耕 +佣金 佣金 +佣金收益 佣金收益 +佣金费用 佣金費用 +佣钱 佣錢 +佣钿 佣鈿 +佥同 僉同 +佩挂 佩掛 +佩斯托瑞斯 佩斯托瑞斯 +佩脱拉克 佩脫拉克 +佳人才子 佳人才子 +佳冬 佳冬 +佳冬乡 佳冬鄉 +佳肴 佳餚 +佳致 佳致 +佳里 佳里 +佳里鎮 佳里鎮 +佳里镇 佳里鎮 +使其斗 使其鬥 +使出 使出 +使出来 使出來 +使团 使團 +使困扰 使困擾 +使困窘 使困窘 +使尽 使盡 +使心作幸 使心作倖 +使用价值 使用價值 +使用借贷 使用借貸 +使用者介面 使用者介面 +使用范围 使用範圍 +使节团 使節團 +使转向 使轉向 +侍仆 侍僕 +侍御 侍御 +侏儒症 侏儒症 +侏罗系 侏羅系 +侔德复载 侔德覆載 +供出 供出 +供制 供製 +供大于求 供大於求 +供应链 供應鏈 +供暖系统 供暖系統 +供水系统 供水系統 +供油系统 供油系統 +供电系统 供電系統 +供给制 供給制 +供给面 供給面 +供过于求 供過於求 +供销合作 供銷合作 +供销合作社 供銷合作社 +依个人 依個人 +依从关系 依從關係 +依依不舍 依依不捨 +依依难舍 依依難捨 +依头缕当 依頭縷當 +依存关系 依存關係 +依托 依託 +依据 依據 +依法炮制 依法炮製 +依然范特西 依然范特西 +依赞 依贊 +依附于 依附於 +侠气干云 俠氣干雲 +侥天之幸 僥天之倖 +侥幸 僥倖 +侥幸取胜 僥倖取勝 +侥幸获胜 僥倖獲勝 +侦听台 偵聽臺 +侦讯笔录 偵訊筆錄 +侧冲 側衝 +侧向 側向 +侧录 側錄 +侧撞防护系统 側撞防護系統 +侧链 側鏈 +侧面 側面 +侧面图 側面圖 +侧面性 側面性 +侨团 僑團 +侨汇 僑匯 +侨选代表 僑選代表 +侮蔑 侮蔑 +侯万户 侯萬戶 +侯彩凤 侯彩鳳 +侯胜茂 侯勝茂 +侵入岩 侵入岩 +侵占 侵佔 +侵占到 侵佔到 +侵占罪 侵佔罪 +侵哄 侵哄 +侵并 侵併 +侵蚀基准 侵蝕基準 +便了 便了 +便于 便於 +便吃干 便吃乾 +便宜不过当家 便宜不過當家 +便当 便當 +便当店 便當店 +便当盒 便當盒 +便益不失当家 便益不失當家 +便签 便籤 +便药 便藥 +便辟 便辟 +便面 便面 +便须 便須 +促发 促發 +促销价 促銷價 +俄克拉何马 俄克拉何馬 +俄克拉何马城 俄克拉何馬城 +俄克拉何马州 俄克拉何馬州 +俄克拉荷马州 俄克拉荷馬州 +俄制 俄製 +俄占 俄佔 +俄国共产党 俄國共產黨 +俄文系 俄文系 +俄罗斯党 俄羅斯黨 +俄语系 俄語系 +俊刮 俊刮 +俊杰 俊傑 +俊游 俊遊 +俊眼修眉 俊眼修眉 +俏丽短发 俏麗短髮 +俗念 俗念 +俘获 俘獲 +俚曲 俚曲 +保不准 保不準 +保丽龙板 保麗龍板 +保修期 保修期 +保养厂 保養廠 +保准 保準 +保发 保發 +保守党 保守黨 +保安团 保安團 +保安责任制 保安責任制 +保护状制 保護狀制 +保护范围 保護範圍 +保持克制 保持克制 +保持联系 保持聯繫 +保暖杯 保暖杯 +保温杯 保溫杯 +保甲制度 保甲制度 +保留价格 保留價格 +保留征收 保留徵收 +保留曲线 保留曲線 +保皇党 保皇黨 +保税工厂 保稅工廠 +保结制度 保結制度 +保证价格 保證價格 +保险杆 保險桿 +保险柜 保險櫃 +保险范围 保險範圍 +保险解开系统 保險解開系統 +保障范围 保障範圍 +信个 信個 +信丰 信豐 +信丰县 信豐縣 +信义计划 信義計劃 +信人调丢了瓢 信人調丟了瓢 +信口开合 信口開合 +信口胡说 信口胡說 +信号台 信號臺 +信号系统 信號系統 +信合社 信合社 +信嘴胡说 信嘴胡說 +信噪 信噪 +信天游 信天游 +信念 信念 +信息技术 信息技術 +信息系统 信息系統 +信托 信託 +信托公司 信託公司 +信托贸易 信托貿易 +信据 信據 +信步闲游 信步閒遊 +信汇 信匯 +信用合作 信用合作 +信笔涂鸦 信筆塗鴉 +信箱里 信箱裏 +信而有征 信而有徵 +信马游缰 信馬游繮 +俪采 儷采 +俭仆 儉僕 +俭朴 儉樸 +俭确之教 儉确之教 +修业 修業 +修业年限 修業年限 +修业期满 修業期滿 +修习 修習 +修书 修書 +修五脏庙 修五臟廟 +修仙 修仙 +修伊特 修伊特 +修修 修修 +修修补补 修修補補 +修养 修養 +修养成 修養成 +修函 修函 +修到 修到 +修剪 修剪 +修史 修史 +修名 脩名 +修和 修和 +修墓 修墓 +修士 修士 +修复 修復 +修女 修女 +修好 修好 +修威特 修威特 +修学 修學 +修定 修定 +修宪 修憲 +修宪案 修憲案 +修容 修容 +修己 修己 +修建 修建 +修得 修得 +修心养性 修心養性 +修成 修成 +修护 修護 +修护站 修護站 +修护队 修護隊 +修持 修持 +修指甲 修指甲 +修撰 修撰 +修改 修改 +修改为 修改爲 +修改后 修改後 +修改成 修改成 +修敬 脩敬 +修整 修整 +修文 修文 +修文偃武 修文偃武 +修文县 修文縣 +修斋 修齋 +修旧利废 修舊利廢 +修明 修明 +修曼德 修曼德 +修杰楷 修杰楷 +修枝 修枝 +修桥补路 修橋補路 +修桥铺路 修橋鋪路 +修樾 脩樾 +修正 修正 +修正为 修正爲 +修正主义 修正主義 +修正期 修正期 +修正案 修正案 +修正档 修正檔 +修正法 修正法 +修正液 修正液 +修武县 修武縣 +修母画荻 修母畫荻 +修水 修水 +修水利 修水利 +修水县 修水縣 +修治 修治 +修润 脩潤 +修濬 修濬 +修炼 修煉 +修炼成仙 修煉成仙 +修版 修版 +修理 修理 +修理匠 修理匠 +修理厂 修理廠 +修理好 修理好 +修理店 修理店 +修理站 修理站 +修理费 修理費 +修理起来 修理起來 +修理部 修理部 +修的 修的 +修盖 修蓋 +修省 修省 +修眉 修眉 +修睦 修睦 +修短 修短 +修竹 修竹 +修筑 修築 +修筑公路 修築公路 +修筑工事 修築工事 +修筑工程 修築工程 +修筑道路 修築道路 +修练 修練 +修缮 修繕 +修缮费 修繕費 +修罗 修羅 +修置产室 修置產室 +修耕 修耕 +修胡刀 修鬍刀 +修脚 修腳 +修脯 脩脯 +修葺 修葺 +修行 修行 +修行人 修行人 +修补 修補 +修补匠 修補匠 +修褉 修褉 +修订 修訂 +修订历史 修訂歷史 +修订本 修訂本 +修订案 修訂案 +修订版 修訂版 +修词学 修詞學 +修课 修課 +修谨以俟 修謹以俟 +修谱 修譜 +修起 修起 +修起来 修起來 +修路 修路 +修蹄 修蹄 +修身 修身 +修身养性 修身養性 +修身齐家 修身齊家 +修车厂 修車廠 +修辞 修辭 +修辞学 修辭學 +修辞格 修辭格 +修边 修邊 +修边幅 修邊幅 +修造 修造 +修造厂 修造廠 +修道 修道 +修道人 修道人 +修道会 修道會 +修道士 修道士 +修道张 修道張 +修道院 修道院 +修配 修配 +修配厂 修配廠 +修金 脩金 +修长 修長 +修阻 修阻 +修面 修面 +修鞋匠 修鞋匠 +修饰 修飾 +修饰句 修飾句 +修饰字 修飾字 +修饰词 修飾詞 +修饰话 修飾話 +修饰语 修飾語 +修饰边幅 修飾邊幅 +修齐 修齊 +修龄 修齡 +俯冲 俯衝 +俯冲点 俯衝點 +俯冲角 俯衝角 +俯曲 俯曲 +俯首就范 俯首就範 +俱发 俱發 +俱收并蓄 俱收並蓄 +俱杯 俱杯 +俱舍师 俱舍師 +俱舍论 俱舍論 +俾资挹注 俾資挹注 +倍日并行 倍日並行 +倒了 倒了 +倒了八辈子楣 倒了八輩子楣 +倒了架 倒了架 +倒了架子 倒了架子 +倒了柴 倒了柴 +倒了核桃车子 倒了核桃車子 +倒价 倒價 +倒八字须 倒八字鬚 +倒出 倒出 +倒出去 倒出去 +倒出来 倒出來 +倒前倒后 倒前倒後 +倒台 倒臺 +倒吊 倒吊 +倒吊蜡烛 倒吊蠟燭 +倒向 倒向 +倒回 倒回 +倒回去 倒回去 +倒回来 倒回來 +倒屣奔出 倒屣奔出 +倒彩 倒彩 +倒念 倒唸 +倒悬挨命 倒懸捱命 +倒扣 倒扣 +倒扣针儿 倒扣針兒 +倒抽了一口气 倒抽了一口氣 +倒持干戈 倒持干戈 +倒挂 倒掛 +倒挂金钩 倒掛金鉤 +倒杯 倒杯 +倒杯水 倒杯水 +倒杯茶 倒杯茶 +倒板 倒板 +倒竖虎须 倒豎虎鬚 +倒绷孩儿 倒繃孩兒 +倒置干戈 倒置干戈 +倒载干戈 倒載干戈 +倒钟摆效应 倒鐘擺效應 +候虫 候蟲 +倚儿不当 倚兒不當 +倚多为胜 倚多爲勝 +倚托 倚托 +倚晴楼七种 倚晴樓七種 +倚闲 倚閑 +倚马千言 倚馬千言 +倛丑 倛醜 +借一步 借一步 +借不到 借不到 +借东风 借東風 +借个 借個 +借个火 借個火 +借主 借主 +借书 借書 +借书单 借書單 +借书证 借書證 +借了 借了 +借交报仇 借交報仇 +借人 借人 +借代 借代 +借令 借令 +借以 藉以 +借位 借位 +借住 借住 +借作 借作 +借使 借使 +借借 藉藉 +借借看 借借看 +借债 借債 +借债人 借債人 +借债度日 借債度日 +借光 借光 +借入方 借入方 +借入款 借入款 +借典 借典 +借出 借出 +借出去 借出去 +借出来 借出來 +借刀杀人 借刀殺人 +借到 借到 +借券 借券 +借剑杀人 借劍殺人 +借力 借力 +借助 藉助 +借助于 藉助於 +借势 借勢 +借卉 藉卉 +借单 借單 +借单儿 借單兒 +借去 借去 +借取 借取 +借口 藉口 +借古喻今 借古喻今 +借古讽今 借古諷今 +借名 借名 +借听于聋 借聽於聾 +借唱 借唱 +借喻 借喻 +借回 借回 +借回去 借回去 +借回来 借回來 +借地 借地 +借坐 借坐 +借契 借契 +借好 借好 +借妻 借妻 +借字 借字 +借字儿 借字兒 +借完 借完 +借客报仇 借客報仇 +借宿 借宿 +借宿一夜 借宿一夜 +借宿一晚 借宿一晚 +借寇兵 藉寇兵 +借寇兵赍盗粮 藉寇兵齎盜糧 +借寇恂 借寇恂 +借对 借對 +借寿 借壽 +借尸还魂 借屍還魂 +借弹 借彈 +借得 借得 +借手 藉手 +借手除敌 借手除敵 +借托 借托 +借抄 借抄 +借抽 借抽 +借招 借招 +借据 借據 +借提 借提 +借支 借支 +借放 借放 +借故 藉故 +借故推辞 藉故推辭 +借方 借方 +借方差额 借方差額 +借有 借有 +借机 藉機 +借条 借條 +借来 借來 +借来借去 借來借去 +借梯子下楼 借梯子下樓 +借槁 藉槁 +借款 借款 +借款人 借款人 +借此 藉此 +借此机会 藉此機會 +借水推船 借水推船 +借水行舟 借水行舟 +借满 借滿 +借火 借火 +借点 借點 +借球 借球 +借甚 藉甚 +借用 借用 +借由 藉由 +借的 借的 +借看 借看 +借看一下 借看一下 +借着 藉着 +借穿 借穿 +借端 藉端 +借端生事 藉端生事 +借箸 借箸 +借箸代筹 藉箸代籌 +借箸代谋 借箸代謀 +借米下得锅讨米下不得锅 借米下得鍋討米下不得鍋 +借约 借約 +借给 借給 +借腹生子 借腹生子 +借花献佛 借花獻佛 +借茶活捉 借茶活捉 +借草枕块 藉草枕塊 +借让 借讓 +借讬 借託 +借记卡 借記卡 +借词 藉詞 借詞 +借读 借讀 +借调 借調 +借贷 借貸 +借贷无门 借貸無門 +借贷资本 借貸資本 +借资 藉資 +借资挹注 借資挹注 +借走 借走 +借过 借過 +借过一下 借過一下 +借道 借道 +借酒三分醉 借酒三分醉 +借酒浇愁 借酒澆愁 +借酒装疯 借酒裝瘋 +借重 借重 +借鉴 借鑑 +借鑑 借鑑 +借钱 借錢 +借镜 借鏡 +借问 借問 +借阅 借閱 +借阅率 借閱率 +借韵 借韻 +借题 借題 +借题发挥 借題發揮 +借风使船 借風使船 +借齿牙 借齒牙 +倡条冶叶 倡條冶葉 +倦游 倦遊 +倦鸟余花 倦鳥餘花 +倪云林 倪雲林 +倪嗣冲 倪嗣沖 +倮虫 倮蟲 +债台高筑 債臺高築 +债权团 債權團 +值回票价 值回票價 +值得一干 值得一幹 +值得干 值得幹 +值得庆幸 值得慶幸 +值得注意 值得注意 +值得注意的是 值得注意的是 +值得称赞 值得稱讚 +值日表 值日表 +倾出 傾出 +倾向 傾向 +倾向于 傾向於 +倾向性 傾向性 +倾复重器 傾覆重器 +倾家尽产 傾家盡產 +倾家荡产 傾家蕩產 +倾尽 傾盡 +倾巢出动 傾巢出動 +倾巢而出 傾巢而出 +倾斜面 傾斜面 +倾杯 傾杯 +倾注 傾注 +倾箱倒柜 傾箱倒櫃 +倾耳注目 傾耳注目 +倾诉衷曲 傾訴衷曲 +偃仆 偃仆 +偃松 偃松 +偃武修文 偃武修文 +偃蹇困穷 偃蹇困窮 +假借 假借 +假借义 假借義 +假借字 假借字 +假借法 假借法 +假力于人 假力於人 +假发 假髮 +假叶 假葉 +假意周旋 假意周旋 +假托 假託 +假期忧郁症候群 假期憂鬱症候羣 +假药 假藥 +假面 假面 +假面具 假面具 +假面剧 假面劇 +偎干 偎乾 +偎干就湿 偎乾就溼 +偏了 偏了 +偏于 偏於 +偏信则暗 偏信則闇 +偏出 偏出 +偏后 偏後 +偏向 偏向 +偏回 偏回 +偏回去 偏回去 +偏回来 偏回來 +偏幸 偏倖 +偏才 偏才 +偏执症 偏執症 +偏暗 偏暗 +偏极光 偏極光 +偏极光镜 偏極光鏡 +偏极化 偏極化 +偏极滤光镜 偏極濾光鏡 +偏极镜 偏極鏡 +偏正式合成词 偏正式合成詞 +偏相关系数 偏相關係數 +偏重于 偏重於 +偕同 偕同 +做一天和尚撞一天钟 做一天和尚撞一天鐘 +做不了 做不了 +做了 做了 +做准备工作 做準備工作 +做出 做出 +做出事来 做出事來 +做出场 做出場 +做出好戏 做齣好戲 +做出来 做出來 +做好做恶 做好做惡 +做尽 做盡 +做庄 做莊 +做张做致 做張做致 +做得了 做得了 +做针线 做針線 +停了 停了 +停云 停雲 +停云慢步 停雲慢步 +停云落月 停雲落月 +停停当当 停停當當 +停制 停製 +停尸 停屍 +停尸房 停屍房 +停尸间 停屍間 +停当 停當 +停征 停徵 +停摆 停擺 +停板 停板 +停板制度 停板制度 +停表 停表 +偢采 偢采 +健康胜于财富 健康勝於財富 +健忘症 健忘症 +偶发 偶發 +偶发事件 偶發事件 +偶发性 偶發性 +偶合 偶合 +偷了 偷了 +偷出 偷出 +偷出去 偷出去 +偷出来 偷出來 +偷发 偷發 +偷合取容 偷合取容 +偷合苟容 偷合苟容 +偷回 偷回 +偷回去 偷回去 +偷回来 偷回來 +偷婆娘 偷婆娘 +偷尝禁果 偷嚐禁果 +偷得浮生半日闲 偷得浮生半日閒 +偷期暗会 偷期暗會 +偷梁换柱 偷樑換柱 +偷种 偷種 +偷鸡不着 偷雞不着 +偷鸡吊狗 偷雞吊狗 +偿回 償回 +偿回去 償回去 +偿回来 償回來 +偿得夙愿 償得夙願 +偿愿 償願 +傅克斯 傅克斯 +傅利叶 傅利葉 +傅匀余 傅勻余 +傅岩 傅巖 +傅彩 傅彩 +傅科摆 傅科擺 +傅立叶 傅立葉 +傅立叶变换 傅立葉變換 +傅粉施朱 傅粉施朱 +傅说版筑 傅說版築 +傅里叶 傅里葉 +傍个影儿 傍個影兒 +傍系 傍系 +傒幸 傒倖 +傢伙 傢伙 +傢伙座儿 傢伙座兒 +傥荡 儻蕩 +储备干部 儲備幹部 +储训人才 儲訓人才 +储训干部 儲訓幹部 +催并 催併 +催眠曲 催眠曲 +催眠术 催眠術 +催眠药 催眠藥 +催谷 催谷 +傲世轻才 傲世輕才 +傲睨万物 傲睨萬物 +傲霜斗雪 傲霜鬥雪 +傻大个 傻大個 +傻大个儿 傻大個兒 +傻里傻气 傻里傻氣 +像杯 像杯 +像赞 像贊 +僦舍 僦舍 +僮仆 僮僕 +僮御 僮御 +僮手指千 僮手指千 +僵事 僵事 +僵仆 僵仆 +僵住 僵住 +僵冷 僵冷 +僵化 僵化 +僵卧 僵臥 +僵固 僵固 +僵固性 僵固性 +僵尸 殭屍 +僵尸网络 殭屍網絡 +僵局 僵局 +僵持 僵持 +僵持不下 僵持不下 +僵掉 僵掉 +僵李代桃 僵李代桃 +僵死 僵死 +僵直 僵直 +僵直性 僵直性 +僵直性脊椎炎 僵直性脊椎炎 +僵硬 僵硬 +僵立 僵立 +僵臥 僵臥 +僵蚕 殭蠶 +儌幸 儌倖 +儒术 儒術 +儒略历 儒略曆 +儒略历史 儒略歷史 +儒略改革历 儒略改革曆 +儒略改革历史 儒略改革歷史 +儿不嫌母丑犬不怨主贫 兒不嫌母醜犬不怨主貧 +儿童台 兒童臺 +儿童团 兒童團 +兀术 兀朮 +允准 允准 +允当 允當 +元凶 元兇 +元后 元后 +元培医事技术学校 元培醫事技術學校 +元恶 元惡 +元恶大奸 元惡大奸 +元恶大憝 元惡大憝 +元曲 元曲 +元曲四大家 元曲四大家 +元秋 元秋 +元素周期表 元素週期表 +兄台 兄臺 +兄弟党 兄弟黨 +充发 充發 +充场面 充場面 +充当 充當 +充斥市面 充斥市面 +充满了 充滿了 +充类至尽 充類至盡 +充能干 充能幹 +充门面 充門面 +充饥 充飢 +充饥止渴 充飢止渴 +充饥画饼 充飢畫餅 +兆个 兆個 +兆丰 兆豐 +兆丰金 兆豐金 +兆丰银 兆豐銀 +兆余 兆餘 +先义后利 先義後利 +先了 先了 +先了一步 先了一步 +先于 先於 +先人后己 先人後己 +先修班 先修班 +先借 先借 +先公后私 先公後私 +先出 先出 +先出去 先出去 +先出来 先出來 +先占 先佔 +先发 先發 +先发制人 先發制人 +先发投手 先發投手 +先发投手群 先發投手羣 +先后 先後 先后 +先后倒置 先後倒置 +先后顺序 先後順序 +先向 先向 +先回 先回 +先回到 先回到 +先回去 先回去 +先回来 先回來 +先声后实 先聲後實 +先天下之忧而忧后天下之乐而乐 先天下之憂而憂后天下之樂而樂 +先天不足后天失调 先天不足後天失調 +先守后攻 先守後攻 +先小人后君子 先小人後君子 +先尝 先嚐 +先干为敬 先乾爲敬 +先忧后乐 先憂後樂 +先念 先念 +先意承志 先意承志 +先攻后守 先攻後守 +先斩后奏 先斬後奏 +先斩后闻 先斬後聞 +先期录音 先期錄音 +先来后上 先來後上 +先来后下 先來後下 +先来后到 先來後到 +先盛后衰 先盛後衰 +先礼后兵 先禮後兵 +先签 先簽 +先缺后空 先缺後空 +先花后果 先花後果 +先苦后甘 先苦後甘 +先行后闻 先行後聞 +先赢后输 先贏後輸 +先进先出 先進先出 +先进后出 先進後出 +先采 先採 +先锋模范作用 先鋒模範作用 +先难后获 先難後獲 +先驱新党 先驅新黨 +光了 光了 +光了了 光了了 +光二极管 光二極管 +光价 光價 +光光荡荡 光光蕩蕩 +光冲量 光衝量 +光出律 光出律 +光出溜 光出溜 +光前绝后 光前絕後 +光前耀后 光前耀後 +光前裕后 光前裕後 +光卤石 光鹵石 +光发送器 光發送器 +光可鉴人 光可鑑人 +光合 光合 +光合作用 光合作用 +光合细菌 光合細菌 +光向 光向 +光周期 光週期 +光圈范围 光圈範圍 +光复 光復 +光复乡 光復鄉 +光复会 光復會 +光复南路 光復南路 +光复国土 光復國土 +光复国小 光復國小 +光复旧京 光復舊京 +光复旧物 光復舊物 +光复节 光復節 +光复路 光復路 +光学字符识别 光學字符識別 +光学录音 光學錄音 +光学系统 光學系統 +光导纤维 光導纖維 +光度表 光度表 +光彩 光彩 +光彩夺目 光彩奪目 +光彩耀眼 光彩耀眼 +光彩起来 光彩起來 +光念 光念 +光效应艺术 光效應藝術 +光敏症 光敏症 +光明云 光明雲 +光明党 光明黨 +光明面 光明面 +光杆 光桿 +光杆儿 光桿兒 +光杆司令 光桿司令 +光杠 光槓 +光板儿 光板兒 +光烟雾 光煙霧 +光焰万丈 光焰萬丈 +光电二极 光電二極 +光电二极体 光電二極體 +光电二极管 光電二極管 +光碟杂志 光碟雜誌 +光碟柜 光碟櫃 +光纤 光纖 +光纤分布式数据介面 光纖分佈式數據介面 +光纤分布数据接口 光纖分佈數據接口 +光纤分散式资料介面 光纖分散式資料介面 +光纤接口 光纖接口 +光纤电缆 光纖電纜 +光纤维 光纖維 +光纤衰减 光纖衰減 +光纤通信 光纖通信 +光纤通信系统 光纖通信系統 +光纤通讯 光纖通訊 +光纤通讯干道网路系统 光纖通訊幹道網路系統 +光纤飞弹 光纖飛彈 +光能合成 光能合成 +光脊梁 光脊樑 +光致致 光緻緻 +光艺术 光藝術 +光芒万丈 光芒萬丈 +光范围 光範圍 +光表 光表 +光辉典范 光輝典範 +光采 光采 +光面 光面 +光面内质网 光面內質網 +光面子 光面子 +克东 克東 +克东县 克東縣 +克丝钳子 克絲鉗子 +克丽丝 克麗絲 +克亚 克亞 +克什 克什 +克什克腾 克什克騰 +克什克腾旗 克什克騰旗 +克什米尔 克什米爾 +克仑特罗 克侖特羅 +克伦克 克倫克 +克伦奇 克倫奇 +克伦威尔 克倫威爾 +克佩罗 克佩羅 +克俭 克儉 +克俭克勤 克儉克勤 +克克 剋剋 +克克尔 克克爾 +克兰诗 克蘭詩 +克兰达尔 克蘭達爾 +克分子 克分子 +克利 克利 +克利斯 克利斯 +克利斯提 克利斯提 +克利福洛 克利福洛 +克制 剋制 +克制不了 剋制不了 +克制不住 剋制不住 +克剥 剋剝 +克劳 克勞 +克劳佛 克勞佛 +克劳修斯 克勞修斯 +克劳可 克勞可 +克劳契 克勞契 +克劳德 克勞德 +克劳斯 克勞斯 +克劳福 克勞福 +克劳福德 克勞福德 +克劳芙特 克勞芙特 +克勒 克勒 +克勒拉省 克勒拉省 +克勒特 克勒特 +克勤 克勤 +克勤克俭 克勤克儉 +克卜勒 克卜勒 +克卜勒定律 克卜勒定律 +克原子 克原子 +克啬 剋嗇 +克基拉岛 克基拉島 +克复 克復 +克夫 剋夫 +克娄巴特拉 克婁巴特拉 +克孜勒苏 克孜勒蘇 +克孜勒苏地区 克孜勒蘇地區 +克孜勒苏柯尔克孜自治州 克孜勒蘇柯爾克孜自治州 +克孜勒苏河 克孜勒蘇河 +克孜尔千佛洞 克孜爾千佛洞 +克孜尔尕哈 克孜爾尕哈 +克孜尔尕哈烽火台 克孜爾尕哈烽火臺 +克宁 克寧 +克定 克定 +克家 克家 +克家子 克家子 +克尔 克爾 +克尔白 克爾白 +克尽 克盡 +克尽厥职 克盡厥職 +克尽夫道 克盡夫道 +克尽妇道 克盡婦道 +克尽己职 克盡己職 +克山 克山 +克山县 克山縣 +克己 克己 +克己主义 克己主義 +克己复礼 克己復禮 +克己奉公 克己奉公 +克强 克強 +克当一面 克當一面 +克当量 克當量 +克意 剋意 +克扣 剋扣 +克拉 克拉 +克拉克 克拉克 +克拉兹 克拉茲 +克拉夫特 克拉夫特 +克拉姆 克拉姆 +克拉本 克拉本 +克拉玛依 克拉瑪依 +克捷 克捷 +克敌 克敵 +克敌制胜 克敵制勝 +克敦孝行 克敦孝行 +克文 克文 +克斯 克斯 +克日 剋日 +克明 克明 +克星 剋星 +克服 克服 +克服不了 克服不了 +克服困难 克服困難 +克朗 克朗 +克朗代克 克朗代克 +克期 剋期 +克来汀症 克來汀症 +克林伊斯威特 克林伊斯威特 +克林德 克林德 +克林斯曼 克林斯曼 +克林霉素 克林黴素 +克林顿 克林頓 +克柔 克柔 +克核 剋核 +克格勃 克格勃 +克死 剋死 +克汀病 克汀病 +克汗 克汗 +克沙奇病毒 克沙奇病毒 +克洛 克洛 +克洛尔 克洛爾 +克洛斯 克洛斯 +克洛格 克洛格 +克流感 克流感 +克瑞强 克瑞強 +克瑞斯波 克瑞斯波 +克瑞格 克瑞格 +克绍箕裘 克紹箕裘 +克绳祖武 克繩祖武 +克罗地亚 克羅地亞 +克罗地亚共和国 克羅地亞共和國 +克罗地亚语 克羅地亞語 +克罗埃 克羅埃 +克罗埃西亚 克羅埃西亞 +克罗德 克羅德 +克罗恩科 克羅恩科 +克罗诺斯 克羅諾斯 +克罗齐 克羅齊 +克耳文 克耳文 +克耶族 克耶族 +克耶邦 克耶邦 +克苦耐劳 克苦耐勞 +克药 克藥 +克莉 克莉 +克莉丝 克莉絲 +克莉丝汀 克莉絲汀 +克莉丝汀娜 克莉絲汀娜 +克莉丝特丝 克莉絲特絲 +克莉兰柯 克莉蘭柯 +克莉奥佩特拉 克莉奧佩特拉 +克莉斯蒂纳 克莉斯蒂納 +克莉芭丝 克莉芭絲 +克莱 克萊 +克莱伦斯宫 克萊倫斯宮 +克莱儿 克萊兒 +克莱因 克萊因 +克莱恩 克萊恩 +克莱斯勒 克萊斯勒 +克莱斯勒汽车公司 克萊斯勒汽車公司 +克莱曼 克萊曼 +克莱柏 克萊柏 +克莱査克 克萊查克 +克莱格 克萊格 +克莱蒙特 克萊蒙特 +克莱门斯 克萊門斯 +克莱顿 克萊頓 +克萨斯州 克薩斯州 +克落 剋落 +克蕾儿 克蕾兒 +克薄 剋薄 +克虏伯 克虜伯 +克西 克西 +克让 克讓 +克谐 克諧 +克赖斯特彻奇 克賴斯特徹奇 +克郎 克郎 +克郡 克郡 +克里 克里 +克里丝蒂娃 克里絲蒂娃 +克里契科 克里契科 +克里奥尔语 克里奧爾語 +克里姆林 克里姆林 +克里姆林宫 克里姆林宮 +克里姆林杯 克里姆林杯 +克里岛 克里島 +克里斯 克里斯 +克里斯伊凡 克里斯伊凡 +克里斯塔基斯 克里斯塔基斯 +克里斯托 克里斯托 +克里斯托弗 克里斯托弗 +克里斯普 克里斯普 +克里斯汀 克里斯汀 +克里斯汀贝尔 克里斯汀貝爾 +克里斯蒂安 克里斯蒂安 +克里斯蒂安松 克里斯蒂安松 +克里普斯 克里普斯 +克里木 克里木 +克里木半岛 克里木半島 +克里木战争 克里木戰爭 +克里梅 克里梅 +克里特 克里特 +克里特克 克里特克 +克里特克里岛 克里特克里島 +克里特岛 克里特島 +克里米亚 克里米亞 +克里米亚半岛 克里米亞半島 +克里米亚战争 克里米亞戰爭 +克里蒙梭 克里蒙梭 +克里门 克里門 +克里门特 克里門特 +克队 克隊 +克隆 克隆 +克隆人 克隆人 +克隆尼 克隆尼 +克隆技术 克隆技術 +克隆斯台 克隆斯臺 +克隆氏病 克隆氏病 +克难 克難 +克难街 克難街 +克难运动 克難運動 +克雅氏症 克雅氏症 +克雷伯氏菌属 克雷伯氏菌屬 +克雷因 克雷因 +克雷姆凯 克雷姆凱 +克雷尼尔 克雷尼爾 +克雷文 克雷文 +克雷斯 克雷斯 +克雷斯吉 克雷斯吉 +克雷格 克雷格 +克雷门斯 克雷門斯 +克雷默 克雷默 +克霉唑 克黴唑 +克顺克卑 克順克卑 +克食 克食 +克鲁 克魯 +克鲁伦河 克魯倫河 +克鲁克斯 克魯克斯 +克鲁兹 克魯茲 +克鲁利 克魯利 +克鲁尼 克魯尼 +克鲁斯 克魯斯 +克鲁斯州 克魯斯州 +克鲁格 克魯格 +克麦洛伏 克麥洛伏 +免不了 免不了 +免于 免於 +免参 免參 +免征 免徵 +免疫系统 免疫系統 +免胄 免冑 +免试升学 免試升學 +免试升高中班 免試升高中班 +兔尽狗烹 兔盡狗烹 +党三役 黨三役 +党中央 黨中央 +党主席 黨主席 +党义 黨義 +党争 黨爭 +党产 黨產 +党人 黨人 +党代会 黨代會 +党代表 黨代表 +党伍 黨伍 +党內 黨內 +党內人士 黨內人士 +党內初选 黨內初選 +党內斗争 黨內鬥爭 +党八股 黨八股 +党公职 黨公職 +党军 黨軍 +党刊 黨刊 +党务 黨務 +党参 黨蔘 +党友 黨友 +党史 黨史 +党同伐异 黨同伐異 +党名 黨名 +党员 黨員 +党员大会 黨員大會 +党员证 黨員證 +党团 黨團 +党团员 黨團員 +党国 黨國 +党国元老 黨國元老 +党外 黨外 +党外人士 黨外人士 +党太尉 党太尉 +党太尉吃匾食 党太尉吃匾食 +党委 黨委 +党委书记 黨委書記 +党委会 黨委會 +党小组 黨小組 +党工 黨工 +党徒 黨徒 +党徽 黨徽 +党怀英 党懷英 +党性 黨性 +党总支 黨總支 +党报 黨報 +党支书 党支書 +党政 黨政 +党政军 黨政軍 +党政机关 黨政機關 +党旗 黨旗 +党校 黨校 +党格 黨格 +党棍 黨棍 +党歌 黨歌 +党法 黨法 +党派 黨派 +党派集会 黨派集會 +党的基本 黨的基本 +党祸 黨禍 +党禁 黨禁 +党章 黨章 +党籍 黨籍 +党籍碑 黨籍碑 +党纪 黨紀 +党纪国法 黨紀國法 +党纲 黨綱 +党组 黨組 +党羽 黨羽 +党职 黨職 +党营 黨營 +党见 黨見 +党言 黨言 +党论 黨論 +党证 黨證 +党课 黨課 +党费 黨費 +党进 党進 +党部 黨部 +党锢 黨錮 +党锢之祸 黨錮之禍 +党阀 黨閥 +党鞭 黨鞭 +党項 党項 +党项 党項 +党项族 党項族 +党风 黨風 +党魁 黨魁 +党龄 黨齡 +兜肚断了带子 兜肚斷了帶子 +入不支出 入不支出 +入不敷出 入不敷出 +入主出奴 入主出奴 +入伍须知 入伍須知 +入伙 入夥 +入党 入黨 +入冬 入冬 +入出境 入出境 +入出境管理局 入出境管理局 +入口匝道号志管制 入口匝道號誌管制 +入团 入團 +入境签证 入境簽證 +入夜后 入夜後 +入室升堂 入室升堂 +入帘 入簾 +入托 入托 +入秋 入秋 +入舍 入舍 +入药 入藥 +內出血 內出血 +內分泌系统 內分泌系統 +內制作 內製作 +內务柜 內務櫃 +內外交困 內外交困 +內外向包办 內外向包辦 +內外姻党 內外姻黨 +內外并重 內外並重 +內婚制 內婚制 +內布拉斯 內布拉斯 +內布拉斯加 內布拉斯加 +內心里 內心裏 +內掌柜的 內掌櫃的 +內服药 內服藥 +內科手术 內科手術 +內脏器官移植 內臟器官移植 +內蒙古 內蒙古 +內蒙古自治区 內蒙古自治區 +內部联系 內部聯繫 +內阁制 內閣制 +全世界无产者联合起来 全世界無產者聯合起來 +全体同仁 全體同仁 +全党 全黨 +全党全军 全黨全軍 +全党同志 全黨同志 +全军复没 全軍覆沒 +全军复灭 全軍覆滅 +全出 全出 +全出去 全出去 +全出来 全出來 +全台 全臺 +全台湾 全臺灣 +全向 全向 +全国不分区代表 全國不分區代表 +全国人民代表大会 全國人民代表大會 +全国人民代表大会常务委员会 全國人民代表大會常務委員會 +全国代表大会 全國代表大會 +全国劳动模范 全國勞動模範 +全国同胞 全國同胞 +全国大会党 全國大會黨 +全国教育资讯服务系统 全國教育資訊服務系統 +全国纪录 全國紀錄 +全国范围 全國範圍 +全场一致 全場一致 +全尸 全屍 +全干 全乾 +全当 全當 +全录 全錄 +全彩 全綵 +全彩干式印表机 全彩乾式印表機 +全所同仁 全所同仁 +全才 全才 +全托 全託 +全挂子 全掛子 +全斗焕 全斗煥 +全无准备 全無準備 +全日制 全日制 +全权代表 全權代表 +全校同学 全校同學 +全然不同 全然不同 +全班同学 全班同學 +全球位置测定系统 全球位置測定系統 +全球卫星导航系统 全球衛星導航系統 +全球发展中心 全球發展中心 +全球定位系统 全球定位系統 +全球定位系统卫星测量 全球定位系統衛星測量 +全球气候升温 全球氣候升溫 +全球环境变迁资讯系统 全球環境變遷資訊系統 +全球范围 全球範圍 +全盘托出 全盤托出 +全神灌注 全神灌注 +全神贯注 全神貫注 +全票价 全票價 +全程参加 全程參加 +全系列 全系列 +全系统 全系統 +全线出击 全線出擊 +全缘叶 全緣葉 +全胜 全勝 +全胜记录 全勝記錄 +全范围 全範圍 +全裂叶 全裂葉 +全谷物 全穀物 +全面 全面 +全面包围 全面包圍 +全面包裹 全面包裹 +全面发展 全面發展 +全面实施 全面實施 +全面性 全面性 +全面战争 全面戰爭 +全面禁止 全面禁止 +全面禁止核试验条约 全面禁止核試驗條約 +全面规划 全面規劃 +全面进行 全面進行 +八万 八萬 +八万一千 八萬一千 +八万四千法门 八萬四千法門 +八万多 八萬多 +八万大藏经 八萬大藏經 +八个 八個 +八仙桌上摆夜壶 八仙桌上擺夜壺 +八位元个人电脑 八位元個人電腦 +八余 八餘 +八克 八克 +八军团 八軍團 +八出祁山 八出祁山 +八十天环游地球 八十天環遊地球 +八十种好 八十種好 +八千里 八千里 +八厂 八廠 +八只 八隻 +八台 八臺 +八周 八週 +八周年 八週年 +八大胡同 八大胡同 +八天后 八天後 +八字方针 八字方針 +八字胡 八字鬍 +八字胡须 八字鬍鬚 +八小时制 八小時制 +八小时工作制 八小時工作制 +八扎 八紮 +八折 八折 +八斗 八斗 +八斗之才 八斗之才 +八斗子 八斗子 +八斗才 八斗才 +八斗陈思 八斗陳思 +八旗制度 八旗制度 +八极 八極 +八极拳 八極拳 +八步周行 八步周行 +八点钟 八點鐘 +八珍咸粥 八珍鹹粥 +八百万 八百萬 +八百多万 八百多萬 +八秒钟 八秒鐘 +八级工资制 八級工資制 +八蜡 八蜡 +八表 八表 +八辟 八辟 +八进制 八進制 +八里 八里 +八里乡 八里鄉 +八面 八面 +八面体 八面體 +八面光 八面光 +八面受敌 八面受敵 +八面圆通 八面圓通 +八面威风 八面威風 +八面玲珑 八面玲瓏 +八面见光 八面見光 +八面锋 八面鋒 +公之于众 公之於衆 +公了 公了 +公仆 公僕 +公仔面 公仔麪 +公价 公價 +公众参与 公衆參與 +公余 公餘 +公使团 公使團 +公克 公克 +公公向孙子磕头 公公向孫子磕頭 +公共休闲环境 公共休閒環境 +公共关系 公共關係 +公共团体 公共團體 +公共支出 公共支出 +公出 公出 +公切面 公切面 +公制 公制 +公制单位 公制單位 +公升 公升 +公历 公曆 +公厘 公釐 +公合 公合 +公同 公同 +公同共有 公同共有 +公听并观 公聽並觀 +公告价格 公告價格 +公告地价 公告地價 +公墓里放鞭炮 公墓裏放鞭炮 +公孙丑 公孫丑 +公孙大娘 公孫大娘 +公定价 公定價 +公定价格 公定價格 +公布 公佈 +公布于众 公佈於衆 +公布出来 公佈出來 +公布栏 公佈欄 +公干 公幹 +公平合理 公平合理 +公广集团 公廣集團 +公开出来 公開出來 +公开场合 公開場合 +公才公望 公才公望 +公报私仇 公報私仇 +公据 公據 +公斗 公斗 +公方代表 公方代表 +公明党 公明黨 +公有制 公有制 +公民表决 公民表決 +公然表示 公然表示 +公用征收 公用徵收 +公用限制 公用限制 +公益彩券 公益彩券 +公私两尽 公私兩盡 +公私合营 公私合營 +公羊春秋 公羊春秋 +公认会计准 公認會計准 +公诸于世 公諸於世 +公诸同好 公諸同好 +公路个人赛 公路個人賽 +公里 公里 +公里数 公里數 +公里时 公里時 +公门之中好修行 公門之中好修行 +公门修行 公門修行 +公门里好修行 公門裏好修行 +六万 六萬 +六个 六個 +六余 六餘 +六冲 六沖 +六出奇计 六出奇計 +六出祁山 六出祁山 +六厂 六廠 +六发 六發 +六只 六隻 +六台 六臺 +六合 六合 +六合区 六合區 +六合彩 六合彩 +六合拳 六合拳 +六合路 六合路 +六周 六週 +六周年 六週年 +六回 六回 +六天后 六天後 +六度万行 六度萬行 +六弦 六絃 +六彩 六彩 +六才子书 六才子書 +六扎 六紮 +六折 六折 +六星彩 六星彩 +六曲 六曲 +六极 六極 +六欲 六慾 +六点钟 六點鐘 +六百万 六百萬 +六百个 六百個 +六百多万 六百多萬 +六祖坛经 六祖壇經 +六种 六種 +六谷 六穀 +六通四辟 六通四辟 +六道轮回 六道輪迴 +六里 六里 +六面 六面 +六面体 六面體 +六须鲇 六鬚鮎 +六须鲶 六鬚鮎 +兰克 蘭克 +兰台 蘭臺 +兰台令史 蘭臺令史 +兰台公子 蘭臺公子 +兰台石室 蘭臺石室 +兰叶描 蘭葉描 +兰叶撇 蘭葉撇 +兰摧玉折 蘭摧玉折 +兰摧蕙折 蘭摧蕙折 +兰棱 蘭棱 +兰秋 蘭秋 +兰艾同烬 蘭艾同燼 +兰艾同焚 蘭艾同焚 +兰花烟 蘭花煙 +兰里老太太 蘭里老太太 +共产主义青年团 共產主義青年團 +共产党 共產黨 +共产党人 共產黨人 +共产党员 共產黨員 +共产党宣言 共產黨宣言 +共产党政府 共產黨政府 +共产党部队 共產黨部隊 +共产制 共產制 +共产集团 共產集團 +共享计划 共享計劃 +共价 共價 +共价键 共價鍵 +共党 共黨 +共出 共出 +共发射极 共發射極 +共同 共同 +共同交际语 共同交際語 +共同代理 共同代理 +共同代表 共同代表 +共同企业 共同企業 +共同体 共同體 +共同保证 共同保證 +共同决议案 共同決議案 +共同利益 共同利益 +共同努力 共同努力 +共同基金 共同基金 +共同市场 共同市場 +共同性 共同性 +共同感觉 共同感覺 +共同正犯 共同正犯 +共同海损 共同海損 +共同点 共同點 +共同社 共同社 +共同科目 共同科目 +共同筛选 共同篩選 +共同管道 共同管道 +共同纲领 共同綱領 +共同经营 共同經營 +共同继承 共同繼承 +共同被告人 共同被告人 +共同诉讼 共同訴訟 +共同语 共同語 +共同财产 共同財產 +共同财产制 共同財產制 +共同趋向 共同趨向 +共同运销 共同運銷 +共同通讯社 共同通訊社 +共同闸道介面 共同閘道介面 +共和党 共和黨 +共和党人 共和黨人 +共和党籍 共和黨籍 +共和制 共和制 +共和历 共和曆 +共和历史 共和歷史 +共基极 共基極 +共审制度 共審制度 +共御外侮 共禦外侮 +共挽鹿车 共挽鹿車 +共摆 共擺 +共游 共遊 +共获 共獲 +共轭不尽根 共軛不盡根 +共轭双曲线 共軛雙曲線 +共轭复数 共軛複數 +共通意志 共通意志 +共铲 共剷 +共青团 共青團 +共餐青年团 共餐青年團 +关不了 關不了 +关个 關個 +关了 關了 +关了钉儿 關了釘兒 +关于 關於 +关云长 關雲長 +关出 關出 +关台 關臺 +关合 關合 +关同 關同 +关回 關回 +关回去 關回去 +关山万里 關山萬里 +关岭布依族苗族自治县 關嶺布依族苗族自治縣 +关岳 關岳 +关弓与我确 關弓與我确 +关征 關征 +关念 關念 +关怀面 關懷面 +关注 關注 +关注度 關注度 +关税同盟 關稅同盟 +关系 關係 +关系人 關係人 +关系代名词 關係代名詞 +关系企业 關係企業 +关系到 關係到 +关系命题 關係命題 +关系奖 關係獎 +关系密切 關係密切 +关系式 關係式 +关系户 關係戶 +关系法 關係法 +关系着 關係着 +关系融洽 關係融洽 +关系词 關係詞 +关系调 關係調 +关系运算 關係運算 +关系部 關係部 +关节面 關節面 +兴云作雨 興雲作雨 +兴云作雾 興雲作霧 +兴云吐雾 興雲吐霧 +兴云布雨 興雲佈雨 +兴云致雨 興雲致雨 +兴会淋漓 興會淋漓 +兴修 興修 +兴冲冲 興沖沖 +兴叹 興嘆 +兴复 興復 +兴复不浅 興復不淺 +兴尽 興盡 +兴尽悲来 興盡悲來 +兴尽意阑 興盡意闌 +兴旺发达 興旺發達 +兴筑 興築 +兴致 興致 +兴致勃勃 興致勃勃 +兴致勃发 興致勃發 +兴致盎然 興致盎然 +兴致索然 興致索然 +兴隆台 興隆臺 +兴隆台区 興隆臺區 +兴高彩烈 興高彩烈 +兴高采烈 興高采烈 +兵出无名 兵出無名 +兵制 兵制 +兵器术 兵器術 +兵团 兵團 +兵尽器竭 兵盡器竭 +兵尽矢穷 兵盡矢窮 +兵工厂 兵工廠 +兵工厂队 兵工廠隊 +兵疲马困 兵疲馬困 +兵种 兵種 +兵籍表 兵籍表 +兵马司倒了墙 兵馬司倒了牆 +其从如云 其從如雲 +其他支出 其他支出 +其余 其餘 +其八九只 其八九只 +其势凶凶 其勢兇兇 +其后 其後 +其核 其核 +其次辟地 其次辟地 +具体计划 具體計劃 +典借 典借 +典制 典制 +典型示范 典型示範 +典当 典當 +典据 典據 +典章制度 典章制度 +典范 典範 +典范性 典範性 +典范长存 典範長存 +兹核 茲核 +养了 養了 +养儿待老积谷防饥 養兒待老積穀防饑 +养儿防老积谷防饥 養兒防老積穀防飢 +养兵千日 養兵千日 +养兵千日用兵一时 養兵千日用兵一時 +养兵千日用在一时 養兵千日用在一時 +养兵千日用在一朝 養兵千日用在一朝 +养军千日 養軍千日 +养军千日用军一时 養軍千日用軍一時 +养军千日用在一时 養軍千日用在一時 +养军千日用在一朝 養軍千日用在一朝 +养出 養出 +养发 養髮 +养娘 養娘 +养婆娘 養婆娘 +养子防老积谷防饥 養子防老積穀防飢 +养家糊口 養家餬口 +养小防老积谷防饥 養小防老積穀防饑 +养志 養志 +养性修真 養性修真 +养老鼠咬布袋 養老鼠咬布袋 +养颜有术 養顏有術 +兼了 兼了 +兼修 兼修 +兼听则明偏信则暗 兼聽則明偏信則暗 +兼容并包 兼容幷包 +兼容并蓄 兼容幷蓄 +兼并 兼併 +兼并与收购 兼併與收購 +兼收并蓄 兼收幷蓄 +兼筹并顾 兼籌幷顧 +兽医系 獸醫系 +兽奸 獸姦 +兽心人面 獸心人面 +兽性大发 獸性大發 +兽欲 獸慾 +兽药 獸藥 +内出血 內出血 +内制 內製 +内参 內參 +内向 內向 +内哄 內鬨 +内在几何 內在幾何 +内在几何学 內在幾何學 +内塔尼亚胡 內塔尼亞胡 +内奸 內奸 +内容管理系统 內容管理系統 +内布拉斯加 內布拉斯加 +内布拉斯加州 內布拉斯加州 +内忧外困 內憂外困 +内扣 內扣 +内斗 內鬥 +内松外紧 內鬆外緊 +内核 內核 +内紧外松 內緊外鬆 +内细胞团 內細胞團 +内脏 內臟 +内蒙 內蒙 +内蒙古 內蒙古 +内蒙古大学 內蒙古大學 +内蒙古自治区 內蒙古自治區 +内部斗争 內部鬥爭 +内面包的 內面包的 +冈田准 岡田准 +冉冉上升 冉冉上升 +冉有仆 冉有僕 +冊叶 冊葉 +再于 再於 +再借 再借 +再借不难 再借不難 +再冲 再衝 +再出 再出 +再出去 再出去 +再出来 再出來 +再出现 再出現 +再制 再製 +再制品 再製品 +再制盐 再製鹽 +再制纸 再製紙 +再发 再發 +再发生 再發生 +再发见 再發見 +再向 再向 +再回 再回 +再回到 再回到 +再回去 再回去 +再回来 再回來 +再干 再幹 +再干一杯 再乾一杯 +再念 再念 +再斗一斗 再鬥一鬥 +再来一个 再來一個 +再生制动 再生制動 +再生纤维 再生纖維 +再种 再種 +再见面 再見面 +再转复 再轉復 +再造手术 再造手術 +再长爹娘 再長爹孃 +冒了 冒了 +冒儿咕冬 冒兒咕冬 +冒出 冒出 +冒出来 冒出來 +冒升 冒升 +冒烟 冒煙 +冒烟突火 冒煙突火 +冒镝当锋 冒鏑當鋒 +冗余 冗餘 +写不出 寫不出 +写个 寫個 +写了 寫了 +写出 寫出 +写出去 寫出去 +写出来 寫出來 +写回 寫回 +写回去 寫回去 +写回来 寫回來 +写字台 寫字檯 +写真合成海报 寫真合成海報 +军事管制 軍事管制 +军制 軍制 +军品出口领导小组 軍品出口領導小組 +军团 軍團 +军团杆菌 軍團桿菌 +军团菌 軍團菌 +军团菌病 軍團菌病 +军官团 軍官團 +军政当局 軍政當局 +军民合作 軍民合作 +军种 軍種 +军舰岩 軍艦岩 +军阀割据 軍閥割據 +军队克制 軍隊剋制 +农业合作 農業合作 +农业合作化 農業合作化 +农业技术 農業技術 +农业生产合作社 農業生產合作社 +农业生产技术 農業生產技術 +农产品平准基金 農產品平準基金 +农作曲 農作曲 +农作物品种 農作物品種 +农化系 農化系 +农历 農曆 +农历年 農曆年 +农历新年 農曆新年 +农地重划 農地重劃 +农复会 農復會 +农奴制 農奴制 +农奴制度 農奴制度 +农家品种 農家品種 +农庄 農莊 +农技团 農技團 +农机系 農機系 +农村合作化 農村合作化 +农村家庭联产承包责任制 農村家庭聯產承包責任制 +农民党 農民黨 +农民历 農民曆 +农民历史 農民歷史 +农民团体 農民團體 +农经系 農經系 +农舍 農舍 +农艺系 農藝系 +农药 農藥 +农药商 農藥商 +冠世之才 冠世之才 +冠军杯 冠軍盃 +冠子虫 冠子蟲 +冠状动脉旁路移植手术 冠狀動脈旁路移植手術 +冠状动脉旁通手术 冠狀動脈旁通手術 +冠状动脉硬化症 冠狀動脈硬化症 +冠盖云集 冠蓋雲集 +冠盖如云 冠蓋如雲 +冠胄 冠冑 +冤仇 冤仇 +冥凌 冥淩 +冥凌浃行 冥淩浹行 +冥子里 冥子裏 +冥蒙 冥濛 +冬不拉 冬不拉 +冬事 冬事 +冬令 冬令 +冬令救济 冬令救濟 +冬令进补 冬令進補 +冬储 冬儲 +冬冬 鼕鼕 +冬冬鼓 鼕鼕鼓 +冬凌 冬凌 +冬初 冬初 +冬夏 冬夏 +冬天 冬天 +冬天里 冬天裏 +冬奥会 冬奧會 +冬字头 冬字頭 +冬季 冬季 +冬季世界 冬季世界 +冬季作物 冬季作物 +冬季档 冬季檔 +冬季节 冬季節 +冬季赛 冬季賽 +冬季运动 冬季運動 +冬学 冬學 +冬宫 冬宮 +冬小麦 冬小麥 +冬山 冬山 +冬山乡 冬山鄉 +冬山河 冬山河 +冬心 冬心 +冬扇夏炉 冬扇夏爐 +冬日 冬日 +冬日可爱 冬日可愛 +冬日里 冬日裏 +冬暖 冬暖 +冬暖夏凉 冬暖夏涼 +冬月 冬月 +冬柴铁 冬柴鐵 +冬温夏凊 冬溫夏凊 +冬游 冬遊 +冬灌 冬灌 +冬烘 冬烘 +冬烘先生 冬烘先生 +冬狩 冬狩 +冬瓜 冬瓜 +冬瓜汤 冬瓜湯 +冬瓜茶 冬瓜茶 +冬眠 冬眠 +冬眠期 冬眠期 +冬笋 冬筍 +冬粉 冬粉 +冬耕 冬耕 +冬至 冬至 +冬至点 冬至點 +冬节 冬節 +冬菇 冬菇 +冬藏 冬藏 +冬虫夏草 冬蟲夏草 +冬衣 冬衣 +冬装 冬裝 +冬赈 冬賑 +冬运 冬運 +冬运会 冬運會 +冬闲 冬閒 +冬防 冬防 +冬雨 冬雨 +冬雪 冬雪 +冬雾 冬霧 +冬青 冬青 +冬青树 冬青樹 +冬风 冬風 +冬麦 冬麥 +冯胜贤 馮勝賢 +冯虚御风 馮虛御風 +冯骥才 馮驥才 +冰上曲棍球 冰上曲棍球 +冰上表演 冰上表演 +冰了 冰了 +冰前刮雪 冰前颳雪 +冰厂 冰廠 +冰壶秋月 冰壺秋月 +冰岩 冰岩 +冰斗 冰斗 +冰杯 冰杯 +冰柜 冰櫃 +冰核 冰核 +冰火不同炉 冰火不同爐 +冰炭不同器 冰炭不同器 +冰炭不同罏 冰炭不同罏 +冰生于水而寒于水 冰生於水而寒於水 +冰碛岩 冰磧岩 +冰雕 冰雕 +冰雪皇后 冰雪皇后 +冰面 冰面 +冲上 衝上 +冲上前 衝上前 +冲上去 衝上去 +冲上来 衝上來 +冲下 衝下 +冲下去 衝下去 +冲下来 衝下來 +冲不上 衝不上 +冲不下 衝不下 +冲不入 衝不入 +冲不出 衝不出 +冲不开 衝不開 +冲不破 衝不破 +冲不过 衝不過 +冲不进 衝不進 +冲了上 衝了上 +冲了下 衝了下 +冲了入 衝了入 +冲了出 衝了出 +冲了来 衝了來 +冲了过 衝了過 +冲了进 衝了進 +冲人 沖人 +冲他 衝他 +冲你 衝你 +冲倒 衝倒 +冲克 沖剋 +冲入 衝入 +冲冠 衝冠 +冲冠发怒 衝冠髮怒 +冲冲 沖沖 +冲冲水 沖沖水 +冲决 沖決 +冲决堤防 沖決堤防 +冲凉 沖涼 +冲出 衝出 +冲出去 衝出去 +冲出来 衝出來 +冲出重围 衝出重圍 +冲击 衝擊 +冲击力 衝擊力 +冲击性 衝擊性 +冲击波 衝擊波 +冲击韧性 衝擊韌性 +冲到 衝到 +冲刷 沖刷 +冲刺 衝刺 +冲刺班 衝刺班 +冲剂 沖劑 +冲力 衝力 +冲动 衝動 +冲动型 衝動型 +冲劲 衝勁 +冲劲十足 衝勁十足 +冲势 衝勢 +冲印 沖印 +冲压 衝壓 +冲压机 衝壓機 +冲厕所 沖廁所 +冲去 衝去 +冲口而出 衝口而出 +冲口而发 衝口而發 +冲向 衝向 +冲向前 衝向前 +冲和 沖和 +冲喜 沖喜 +冲回 衝回 +冲回去 衝回去 +冲在下 衝在下 +冲在前 衝在前 +冲在最前 衝在最前 +冲坏 沖壞 +冲坚陷阵 衝堅陷陣 +冲垮 沖垮 衝垮 +冲堂 衝堂 +冲塌 沖塌 +冲天 沖天 +冲天之怒 沖天之怒 +冲天炉 沖天爐 +冲天炮 沖天炮 +冲头阵 衝頭陣 +冲她 衝她 +冲子 衝子 +冲州撞府 衝州撞府 +冲帐 沖帳 +冲年 沖年 +冲床 衝牀 +冲开 衝開 +冲弱 沖弱 +冲得入 衝得入 +冲得出 衝得出 +冲得过 衝得過 +冲得进 衝得進 +冲心 衝心 +冲怀 沖懷 +冲我 衝我 +冲扩 沖擴 +冲掉 沖掉 +冲撞 衝撞 +冲撞力 衝撞力 +冲散 衝散 +冲断 沖斷 +冲断层 衝斷層 +冲昏 衝昏 +冲昏头脑 衝昏頭腦 +冲昧 沖昧 +冲服 沖服 +冲服剂 沖服劑 +冲末 沖末 +冲杀 衝殺 +冲来 衝來 +冲来冲去 衝來衝去 +冲模 沖模 +冲毁 沖毀 +冲水 沖水 +冲沟 沖溝 +冲泡 沖泡 +冲泡式 沖泡式 +冲波 衝波 +冲波激浪 衝波激浪 +冲波逆折 衝波逆折 +冲泻 沖瀉 +冲洗 沖洗 +冲洗照片 沖洗照片 +冲流 沖流 +冲浪 衝浪 +冲浪客 衝浪客 +冲浪板 衝浪板 +冲浪者 衝浪者 +冲浪赛 衝浪賽 +冲涤 沖滌 +冲淋浴 沖淋浴 +冲淡 沖淡 +冲澡 沖澡 +冲然 衝然 +冲牀工 沖牀工 +冲犯 衝犯 +冲田 沖田 +冲盹 衝盹 +冲盹儿 衝盹兒 +冲着 衝着 +冲破 衝破 +冲积 沖積 +冲积土 沖積土 +冲积堤 沖積堤 +冲积层 沖積層 +冲积岛 沖積島 +冲积平原 沖積平原 +冲积扇 沖積扇 +冲积物 沖積物 +冲程 衝程 +冲税 沖稅 +冲穴 衝穴 +冲空机 沖空機 +冲突 衝突 +冲突区 衝突區 +冲突性 衝突性 +冲突点 衝突點 +冲线 衝線 +冲绳 沖繩 +冲绳县 沖繩縣 +冲绳岛 沖繩島 +冲绳群岛 沖繩羣島 +冲脉 衝脈 +冲自己 衝自己 +冲至 衝至 +冲茶 沖茶 +冲虚 沖虛 +冲虚真人 沖虛真人 +冲虚真经 沖虛真經 +冲蚀 沖蝕 +冲襟 沖襟 +冲要 衝要 +冲走 沖走 +冲起 衝起 +冲起来 衝起來 +冲车 衝車 +冲过 衝過 +冲过去 衝過去 +冲过来 衝過來 +冲进 衝進 +冲进去 衝進去 +冲进来 衝進來 +冲退 衝退 +冲量 衝量 +冲销 沖銷 +冲锋 衝鋒 +冲锋号 衝鋒號 +冲锋枪 衝鋒槍 +冲锋鎗 衝鋒鎗 +冲锋陷阵 衝鋒陷陣 +冲门 衝門 +冲陷 衝陷 +冲霄 沖霄 +冲霄汉外 沖霄漢外 +冲风 衝風 +冲高 衝高 +冲默 沖默 +冲鼻 沖鼻 +冲龄 沖齡 +决了 決了 +决定出 決定出 +决心干 決心幹 +决志 決志 +决斗 決鬥 +决斗者 決鬥者 +决策千里 決策千里 +决策当局 決策當局 +决胜 決勝 +决胜千里 決勝千里 +决胜局 決勝局 +决胜期 決勝期 +决胜点 決勝點 +决胜盘 決勝盤 +决胜节 決勝節 +决胜负 決勝負 +冶叶倡条 冶葉倡條 +冶游 冶遊 +冶炼 冶煉 +冶炼厂 冶煉廠 +冶炼炉 冶煉爐 +冶荡 冶蕩 +冷冻柜 冷凍櫃 +冷地里 冷地里 +冷布 冷布 +冷心冷面 冷心冷面 +冷感症 冷感症 +冷战以后 冷戰以後 +冷板凳 冷板凳 +冷板曲 冷板曲 +冷气团 冷氣團 +冷淡关系 冷淡關係 +冷灰里爆出火来 冷灰裏爆出火來 +冷腌法 冷醃法 +冷藏柜 冷藏櫃 +冷读术 冷讀術 +冷轧钢板 冷軋鋼板 +冷酒儿后犯 冷酒兒後犯 +冷锅里爆豆 冷鍋裏爆豆 +冷面 冷麪 冷面 +冷面冷心 冷面冷心 +冷面相 冷面相 +冻僵 凍僵 +净余 淨餘 +净发 淨髮 +净尽 淨盡 +净心修身 淨心修身 +凄丽 悽麗 +凄冷 淒冷 +凄凄 悽悽 +凄凉 淒涼 +凄切 悽切 +凄历 悽歷 +凄厉 淒厲 +凄咽 悽咽 +凄婉 悽婉 +凄寒 淒寒 +凄怆 悽愴 +凄怨 悽怨 +凄恻 悽惻 +凄惨 悽慘 +凄惶 悽惶 +凄楚 悽楚 +凄沧 淒滄 +凄清 悽清 +凄然 悽然 +凄紧 悽緊 +凄绝 悽絕 +凄美 悽美 +凄艳 悽豔 +凄苦 悽苦 +凄迷 悽迷 +凄酸 悽酸 +凄雨 淒雨 +凄风 悽風 +准三后 准三后 +准不准 準不準 +准不准他 准不准他 +准不准你 准不准你 +准不准备 準不準備 +准不准她 准不准她 +准不准它 准不准它 +准不准我 准不准我 +准不准确 準不準確 +准不准许 准不准許 +准不准谁 准不准誰 +准予 准予 +准以 准以 +准伏 准伏 +准会 準會 +准例 準例 +准保 準保 +准保护 准保護 +准保释 准保釋 +准信 準信 +准假 准假 +准儿 準兒 +准入 准入 +准决斗 准決鬥 +准决赛 準決賽 +准分子 準分子 +准分子雷射仪 準分子雷射儀 +准则 準則 +准噶尔 準噶爾 +准噶尔盆地 準噶爾盆地 +准噶尔翼龙 準噶爾翼龍 +准备 準備 +准备下 準備下 +准备充分 準備充分 +准备准备 準備準備 +准备好 準備好 +准备好了 準備好了 +准备好的 準備好的 +准备活动 準備活動 +准备率 準備率 +准备给 準備給 +准备金 準備金 +准备金率 準備金率 +准头 準頭 +准奏 准奏 +准妈妈 準媽媽 +准定 準定 +准将 准將 +准尉 准尉 +准平原 準平原 +准度 準度 +准式 準式 +准得 準得 +准折 准折 +准拟 準擬 +准拿督 準拿督 +准据 準據 +准新娘 準新娘 +准新郎 準新郎 +准时 準時 +准时出席 準時出席 +准时到 準時到 +准时到达 準時到達 +准星 準星 +准是 準是 +准普尔 准普爾 +准格尔 準格爾 +准格尔盆地 準格爾盆地 +准此 准此 +准決賽 準決賽 +准点 準點 +准点率 準點率 +准用 準用 +准的 準的 +准确 準確 +准确度 準確度 +准确性 準確性 +准确无误 準確無誤 +准确率 準確率 +准稳旋涡结构 準穩旋渦結構 +准算 准算 +准线 準線 +准绳 準繩 +准考证 准考證 +准葛尔盆地 準葛爾盆地 +准许 准許 +准话 準話 +准谱 準譜 +准谱儿 準譜兒 +准货币 準貨幣 +准错不了 準錯不了 +凉了 涼了 +凉了半截 涼了半截 +凉台 涼臺 +凉席 涼蓆 +凉药 涼藥 +凉面 涼麪 +凌云 凌雲 +凌云健笔 凌雲健筆 +凌云县 凌雲縣 +凌云壮志 凌雲壯志 +凌云翰 淩云翰 +凌借 凌藉 +凌十八 淩十八 +凌如焕 淩如焕 +凌姓 淩姓 +凌小姐 淩小姐 +凌志 凌志 +凌志美 淩志美 +凌惠平 淩惠平 +凌昌焕 淩昌焕 +凌氏 淩氏 +凌氏惠平 淩氏惠平 +凌水 淩水 +凌河 淩河 +凌烟阁 凌煙閣 +凌策 淩策 +凌统 淩統 +凌蒙初 淩濛初 +凌退思 淩退思 +凌驰 淩馳 +减个 減個 +减了 減了 +减价 減價 +减价出售 減價出售 +减价时间 減價時間 +减压时间表 減壓時間表 +减压症 減壓症 +减压表 減壓表 +减噪 減噪 +减征 減徵 +减肥药 減肥藥 +凑不出来 湊不出來 +凑出 湊出 +凑合 湊合 +凑合着 湊合着 +凑四合六 湊四合六 +凛栗 凜慄 +凝合 凝合 +凝合力 凝合力 +凝咽 凝咽 +凝灰岩 凝灰岩 +凝炼 凝鍊 +几丁质 幾丁質 +几万 幾萬 +几万个 幾萬個 +几万人 幾萬人 +几万元 幾萬元 +几万块 幾萬塊 +几上 几上 +几下 幾下 +几世 幾世 +几世纪 幾世紀 +几丝 幾絲 +几两 幾兩 +几个 幾個 +几个人 幾個人 +几个月 幾個月 +几为所害 幾爲所害 +几乎 幾乎 +几乎不 幾乎不 +几乎不可能 幾乎不可能 +几乎在 幾乎在 +几乎完全 幾乎完全 +几乎是 幾乎是 +几乎没有 幾乎沒有 +几事 幾事 +几于 幾於 +几人 幾人 +几人份 幾人份 +几亿 幾億 +几付 幾付 +几代 幾代 +几令 幾令 +几件 幾件 +几件事 幾件事 +几任 幾任 +几份 幾份 +几伍 幾伍 +几众 幾衆 +几位 幾位 +几位数 幾位數 +几何 幾何 +几何体 幾何體 +几何光学 幾何光學 +几何原本 幾何原本 +几何图形 幾何圖形 +几何图案 幾何圖案 +几何学 幾何學 +几何拓扑 幾何拓撲 +几何拓扑学 幾何拓撲學 +几何级数 幾何級數 +几何线 幾何線 +几何量 幾何量 +几倍 幾倍 +几儿 幾兒 +几儿个 幾兒個 +几元 幾元 +几克 幾克 +几党 幾黨 +几內亚 幾內亞 +几內亚共和国 幾內亞共和國 +几內亚比索 幾內亞比索 +几內亚比索共和国 幾內亞比索共和國 +几內亚比绍 幾內亞比紹 +几內亚湾 幾內亞灣 +几关 幾關 +几具 幾具 +几内亚 幾內亞 +几内亚比绍 幾內亞比紹 +几内亚湾 幾內亞灣 +几冊 幾冊 +几净窗明 几淨窗明 +几几 几几 +几几乎乎 幾幾乎乎 +几凳 几凳 +几出 幾齣 +几刀 幾刀 +几分 幾分 +几分之几 幾分之幾 +几分收获 幾分收穫 +几分钟 幾分鐘 +几划 幾劃 +几列 幾列 +几副 幾副 +几动 幾動 +几化 幾化 +几匹 幾匹 +几匹马 幾匹馬 +几区 幾區 +几十 幾十 +几十万 幾十萬 +几十个 幾十個 +几十人 幾十人 +几十亿 幾十億 +几十年 幾十年 +几千 幾千 +几千万 幾千萬 +几千个 幾千個 +几千人 幾千人 +几千元 幾千元 +几千块 幾千塊 +几千年 幾千年 +几发 幾發 +几句 幾句 +几句话 幾句話 +几只 幾隻 +几可乱真 幾可亂真 +几台 幾臺 +几号 幾號 +几吋 幾吋 +几名 幾名 +几员 幾員 +几回 幾回 +几回价 幾回價 +几因 幾因 +几团 幾團 +几国 幾國 +几圆 幾圓 +几圈 幾圈 +几场 幾場 +几块 幾塊 +几块钱 幾塊錢 +几垒 幾壘 +几声 幾聲 +几处 幾處 +几多 幾多 +几大 幾大 +几大块 幾大塊 +几大片 幾大片 +几大类 幾大類 +几天 幾天 +几天后 幾天後 +几天来 幾天來 +几头 幾頭 +几子 几子 +几孔 幾孔 +几字 幾字 +几季 幾季 +几客 幾客 +几家 幾家 +几家欢乐 幾家歡樂 +几家欢乐几家愁 幾家歡樂幾家愁 +几寸 幾寸 +几封 幾封 +几封信 幾封信 +几小时 幾小時 +几尾 幾尾 +几局 幾局 +几层 幾層 +几层楼 幾層樓 +几届 幾屆 +几岁 幾歲 +几巷 幾巷 +几师 幾師 +几希 幾希 +几席 几席 +几幅 幾幅 +几年 幾年 +几年几班 幾年幾班 +几年来 幾年來 +几年生 幾年生 +几年级 幾年級 +几床 幾牀 +几度 幾度 +几度春风 幾度春風 +几座 幾座 +几开 幾開 +几弄 幾弄 +几张 幾張 +几弹 幾彈 +几微 幾微 +几成 幾成 +几成新 幾成新 +几截 幾截 +几户 幾戶 +几所 幾所 +几手 幾手 +几打 幾打 +几批 幾批 +几拳 幾拳 +几支 幾支 +几文钱 幾文錢 +几斤 幾斤 +几斤几两 幾斤幾兩 +几旁 几旁 +几旅 幾旅 +几日 幾日 +几日份 幾日份 +几时 幾時 +几星 幾星 +几星期 幾星期 +几晚 幾晚 +几曾 幾曾 +几月 幾月 +几月份 幾月份 +几期 幾期 +几本 幾本 +几本书 幾本書 +几杆 幾桿 +几杖 几杖 +几杯 幾杯 +几板 幾板 +几枚 幾枚 +几枝 幾枝 +几枪 幾槍 +几架 幾架 +几栋 幾棟 +几株 幾株 +几样 幾樣 +几格 幾格 +几案 几案 +几案之才 几案之才 +几档 幾檔 +几桶 幾桶 +几梯次 幾梯次 +几棵 幾棵 +几椅 几椅 +几楼 幾樓 +几榻 几榻 +几次 幾次 +几次三番 幾次三番 +几欲 幾欲 +几步 幾步 +几殆 幾殆 +几段 幾段 +几比几 幾比幾 +几毛 幾毛 +几毛钱 幾毛錢 +几洞 幾洞 +几滴 幾滴 +几滴水 幾滴水 +几炷香 幾炷香 +几点 幾點 +几点了 幾點了 +几点几 幾點幾 +几点钟 幾點鐘 +几版 幾版 +几率 幾率 +几环 幾環 +几班 幾班 +几番 幾番 +几番家 幾番家 +几百 幾百 +几百万 幾百萬 +几百个 幾百個 +几百人 幾百人 +几百亿 幾百億 +几百元 幾百元 +几百块 幾百塊 +几百年 幾百年 +几盏 幾盞 +几盒 幾盒 +几盒装 幾盒裝 +几眼 幾眼 +几碗 幾碗 +几碗饭 幾碗飯 +几社 幾社 +几票 幾票 +几种 幾種 +几科 幾科 +几秒 幾秒 +几秒钟 幾秒鐘 +几稀 幾稀 +几窝 幾窩 +几站 幾站 +几章 幾章 +几竿 幾竿 +几笔 幾筆 +几笼 幾籠 +几筒 幾筒 +几筵 几筵 +几箱 幾箱 +几米 幾米 +几类 幾類 +几粒 幾粒 +几级 幾級 +几线 幾線 +几组 幾組 +几经 幾經 +几缕 幾縷 +几罐 幾罐 +几股 幾股 +几胎 幾胎 +几能 幾能 +几能勾 幾能勾 +几脚 幾腳 +几至 幾至 +几般 幾般 +几节 幾節 +几节课 幾節課 +几街 幾街 +几袋 幾袋 +几角 幾角 +几角形 幾角形 +几许 幾許 +几课 幾課 +几谏 幾諫 +几起 幾起 +几趟 幾趟 +几趟路 幾趟路 +几路 幾路 +几车 幾車 +几转 幾轉 +几辆 幾輛 +几辆车 幾輛車 +几近 幾近 +几近于 幾近於 +几通 幾通 +几道 幾道 +几道菜 幾道菜 +几部 幾部 +几里 幾里 +几针 幾針 +几门 幾門 +几间 幾間 +几集 幾集 +几面上 几面上 +几页 幾頁 +几顶 幾頂 +几项 幾項 +几顿 幾頓 +几颗 幾顆 +几题 幾題 +几首 幾首 +几首歌 幾首歌 +凡事总有一个开头 凡事總有一個開頭 +凡于 凡於 +凡才 凡才 +凡此种种 凡此種種 +凡须 凡須 +凤凰于蜚 鳳凰于蜚 +凤凰于飞 鳳凰于飛 +凤凰台 鳳凰臺 +凤占 鳳占 +凤去台空 鳳去臺空 +凤台 鳳台 +凤台县 鳳臺縣 +凤尾松 鳳尾松 +凤梨干 鳳梨乾 +凤皇于蜚 鳳皇于蜚 +凭借 憑藉 +凭借着 憑藉着 +凭准 憑準 +凭几 憑几 +凭吊 憑弔 +凭媒说合 憑媒說合 +凭折 憑摺 +凭据 憑據 +凭空出现 憑空出現 +凭虚御风 憑虛御風 +凭闲 憑閑 +凯复 凱復 +凯特布兰琪 凱特布蘭琪 +凯迪拉克 凱迪拉克 +凯里 凱里 +凯里市 凱裏市 +凶事 凶事 +凶人 兇人 +凶仪 兇儀 +凶侠 兇俠 +凶信 凶信 +凶兆 凶兆 +凶党 兇黨 +凶具 兇具 +凶凶 兇兇 +凶凶恶恶 兇兇惡惡 +凶凶狠狠 兇兇狠狠 +凶刀 兇刀 +凶器 兇器 +凶地 凶地 +凶多吉少 凶多吉少 +凶嫌 兇嫌 +凶宅 凶宅 +凶岁 凶歲 +凶巴巴 兇巴巴 +凶年 凶年 +凶年饥岁 凶年饑歲 +凶徒 兇徒 +凶得 兇得 +凶得狠 兇得狠 +凶德 凶德 +凶怪 凶怪 +凶恶 兇惡 +凶悍 兇悍 +凶惧 兇懼 +凶手 兇手 +凶日 凶日 +凶暴 兇暴 +凶服 凶服 +凶杀 兇殺 +凶杀案 兇殺案 +凶枪 兇槍 +凶案 兇案 +凶横 兇橫 +凶死 凶死 +凶残 兇殘 +凶殘 兇殘 +凶殴 兇毆 +凶殺 兇殺 +凶气 凶氣 +凶焰 兇焰 +凶煞 凶煞 +凶燄 凶燄 +凶犯 兇犯 +凶狂 兇狂 +凶狠 兇狠 +凶猛 兇猛 +凶疑 兇疑 +凶相 兇相 +凶相毕露 兇相畢露 +凶礼 凶禮 +凶神 凶神 +凶神恶煞 凶神惡煞 +凶神附体 凶神附體 +凶竖 凶豎 +凶终隙末 凶終隙末 +凶耗 凶耗 +凶肆 凶肆 +凶荒 凶荒 +凶虐 兇虐 +凶讯 凶訊 +凶起来 兇起來 +凶身 凶身 +凶逆 凶逆 +凶门 凶門 +凶险 兇險 +凶顽 兇頑 +凸出 凸出 +凸出去 凸出去 +凸出成 凸出成 +凸出来 凸出來 +凸多面体 凸多面體 +凸折线 凸折線 +凸显出 凸顯出 +凸显出来 凸顯出來 +凸板印刷 凸板印刷 +凸面 凸面 +凸面体 凸面體 +凸面部分 凸面部分 +凸面镜 凸面鏡 +凹凸有致 凹凸有致 +凹板 凹板 +凹洞里 凹洞裏 +凹雕 凹雕 +凹面 凹面 +凹面镜 凹面鏡 +出一回神 出一回神 +出上 出上 +出下 出下 +出不起 出不起 +出丑 出醜 +出丑扬疾 出醜揚疾 +出丑狼藉 出醜狼藉 +出世 出世 +出世作 出世作 +出世法 出世法 +出丧 出喪 +出个 出個 +出个价 出個價 +出主意 出主意 +出乎 出乎 +出乎寻常 出乎尋常 +出乎意外 出乎意外 +出乎意料 出乎意料 +出乎预料 出乎預料 +出乖弄丑 出乖弄醜 +出乖露丑 出乖露醜 +出乘 出乘 +出书 出書 +出乱子 出亂子 +出了 出了 +出了事 出了事 +出了月 出了月 +出事 出事 +出事情 出事情 +出于 出於 +出云 出雲 +出亡 出亡 +出产 出產 +出产地 出產地 +出人 出人 +出人命 出人命 +出人头地 出人頭地 +出人意外 出人意外 +出人意料 出人意料 +出人意料之外 出人意料之外 +出人意表 出人意表 +出仕 出仕 +出价 出價 +出任 出任 +出份子 出份子 +出伏 出伏 +出众 出衆 +出伦之才 出倫之才 +出使 出使 +出倒 出倒 +出借 出借 +出借书 出借書 +出儿 齣兒 +出入 出入 +出入口 出入口 +出入境 出入境 +出入将相 出入將相 +出入平安 出入平安 +出入相随 出入相隨 +出入証 出入証 +出入证 出入證 +出入门 出入門 +出公差 出公差 +出关 出關 +出兵 出兵 +出其不备 出其不備 +出其不意 出其不意 +出其不意攻其不备 出其不意攻其不備 +出其东门 出其東門 +出其右 出其右 +出具 出具 +出典 出典 +出军 出軍 +出冷门 出冷門 +出出 出出 +出出气 出出氣 +出出进进 出出進進 +出击 出擊 +出分子 出分子 +出刊 出刊 +出列 出列 +出到 出到 +出力 出力 +出动 出動 +出勤 出勤 +出勤率 出勤率 +出卖 出賣 +出卖灵魂 出賣靈魂 +出厂 出廠 +出厂价 出廠價 +出厂价格 出廠價格 +出去 出去 +出去会 出去會 +出去时 出去時 +出去玩 出去玩 +出双入对 出雙入對 +出发 出發 +出发到 出發到 +出发地 出發地 +出发日 出發日 +出发点 出發點 +出口 出口 +出口产品 出口產品 +出口伤人 出口傷人 +出口值 出口值 +出口入耳 出口入耳 +出口到 出口到 +出口区 出口區 +出口商 出口商 +出口商品 出口商品 +出口国 出口國 +出口处 出口處 +出口导向 出口導向 +出口成章 出口成章 +出口税 出口稅 +出口调查 出口調查 +出口货 出口貨 +出口贸易 出口貿易 +出口量 出口量 +出口额 出口額 +出台 出臺 +出号 出號 +出名 出名 +出品 出品 +出品人 出品人 +出品国 出品國 +出售 出售 +出售一空 出售一空 +出售给 出售給 +出唱片 出唱片 +出喽子 出嘍子 +出团 出團 +出国 出國 +出国前 出國前 +出国时 出國時 +出国者 出國者 +出圈 出圈 +出圈儿 出圈兒 +出土 出土 +出土文物 出土文物 +出土物 出土物 +出在 出在 +出场 出場 +出场费 出場費 +出埃及记 出埃及記 +出城 出城 +出堂 出堂 +出塞 出塞 +出境 出境 +出境检查 出境檢查 +出境签证 出境簽證 +出境証 出境証 +出境证 出境證 +出声 出聲 +出处 出處 +出处不如聚处 出處不如聚處 +出外 出外 +出外人 出外人 +出外景 出外景 +出大差 出大差 +出大恭 出大恭 +出太阳 出太陽 +出头 出頭 +出头之日 出頭之日 +出头天 出頭天 +出头日子 出頭日子 +出头棍 出頭棍 +出头椽儿先朽烂 出頭椽兒先朽爛 +出头露角 出頭露角 +出头露面 出頭露面 +出头鸟 出頭鳥 +出奇 出奇 +出奇不意 出奇不意 +出奇制胜 出奇制勝 +出奔 出奔 +出好 出好 +出妇 出婦 +出妻 出妻 +出姓 出姓 +出娄子 出婁子 +出嫁 出嫁 +出完 出完 +出官 出官 +出定 出定 +出宰 出宰 +出家 出家 +出家人 出家人 +出家人吃八方 出家人吃八方 +出将入相 出將入相 +出小恭 出小恭 +出尔反尔 出爾反爾 +出尖 出尖 +出尖儿 出尖兒 +出尘 出塵 +出尽 出盡 +出局 出局 +出局数 出局數 +出山 出山 +出岔 出岔 +出岔儿 出岔兒 +出岔子 出岔子 +出巡 出巡 +出工 出工 +出差 出差 +出差费 出差費 +出差错 出差錯 +出师 出師 +出师不利 出師不利 +出师表 出師表 +出席 出席 +出席率 出席率 +出席者 出席者 +出席表决比例 出席表決比例 +出席费 出席費 +出幼 出幼 +出店 出店 +出庭 出庭 +出庭作证 出庭作證 +出庭应讯 出庭應訊 +出彩 出彩 +出征 出征 +出征收 出徵收 +出得 出得 +出心 出心 +出恭 出恭 +出息 出息 +出意外 出意外 +出戏 齣戲 +出战 出戰 +出户 出戶 +出手 出手 +出手得卢 出手得盧 +出手见高低 出手見高低 +出把戏 出把戲 +出招 出招 +出拳 出拳 +出挑 出挑 +出掌 出掌 +出操 出操 +出操课 出操課 +出故典 出故典 +出教 出教 +出数儿 出數兒 +出文 出文 +出斩 出斬 +出新 出新 +出景 出景 +出月 出月 +出月子 出月子 +出有 出有 +出有入无 出有入無 +出材 出材 +出条子 出條子 +出来 出來 +出来时 出來時 +出校 出校 +出格 出格 +出梅 出梅 +出楼子 出樓子 +出榜 出榜 +出橐 出橐 +出此下策 出此下策 +出死入生 出死入生 +出殃 出殃 +出殡 出殯 +出殡日 出殯日 +出毛病 出毛病 +出气 出氣 +出气口 出氣口 +出气多进气少 出氣多進氣少 +出气筒 出氣筒 +出水 出水 +出水伙计 出水夥計 +出水口 出水口 +出水管 出水管 +出水芙蓉 出水芙蓉 +出汗 出汗 +出汙泥而不染 出污泥而不染 +出江 出江 +出没 出沒 +出没不定 出沒不定 +出没无常 出沒無常 +出油 出油 +出注 出注 +出洋 出洋 +出洋相 出洋相 +出活 出活 +出浴 出浴 +出海 出海 +出海口 出海口 +出海打鱼 出海打魚 +出海捕鱼 出海捕魚 +出涕 出涕 +出淤泥而不染 出淤泥而不染 +出清 出清 +出港 出港 +出港大厅 出港大廳 +出港证 出港證 +出游 出遊 +出溜 出溜 +出溜儿 出溜兒 +出漏子 出漏子 +出演 出演 +出火 出火 +出火炕 出火炕 +出炉 出爐 +出点 出點 +出点子 出點子 +出热 出熱 +出片 出片 +出版 出版 +出版业 出版業 +出版业务 出版業務 +出版人 出版人 +出版前编目 出版前編目 +出版品 出版品 +出版品奖 出版品獎 +出版商 出版商 +出版地缺 出版地缺 +出版所 出版所 +出版日 出版日 +出版日期 出版日期 +出版期缺 出版期缺 +出版法 出版法 +出版物 出版物 +出版界 出版界 +出版社 出版社 +出版社不详 出版社不詳 +出版社丛集 出版社叢集 +出版社清样 出版社清樣 +出版社目录卡 出版社目錄卡 +出版社装祯 出版社裝禎 +出版者 出版者 +出版自由 出版自由 +出版节 出版節 +出版项 出版項 +出牌 出牌 +出状况 出狀況 +出狱 出獄 +出猎 出獵 +出现 出現 +出现意外 出現意外 +出现数 出現數 +出球 出球 +出生 出生 +出生入死 出生入死 +出生别 出生別 +出生地 出生地 +出生地点 出生地點 +出生年 出生年 +出生日 出生日 +出生日期 出生日期 +出生牙 出生牙 +出生率 出生率 +出生纸 出生紙 +出生缺陷 出生缺陷 +出生证 出生證 +出界 出界 +出疹子 出疹子 +出的 出的 +出监 出監 +出盘 出盤 +出示 出示 +出示证件 出示證件 +出社会 出社會 +出神 出神 +出神入化 出神入化 +出票 出票 +出科 出科 +出租 出租 +出租人 出租人 +出租店 出租店 +出租汽车 出租汽車 +出租率 出租率 +出租给 出租給 +出租车 出租車 +出稿 出稿 +出窍 出竅 +出窝老 出窩老 +出站 出站 +出笏 出笏 +出笼 出籠 +出笼鸟 出籠鳥 +出籍 出籍 +出类拔群 出類拔羣 +出类拔萃 出類拔萃 +出类超群 出類超羣 +出粗 出粗 +出粜 出糶 +出粮 出糧 +出糗 出糗 +出红差 出紅差 +出纳 出納 +出纳台 出納臺 +出纳员 出納員 +出纳处 出納處 +出纳科 出納科 +出纳系统 出納系統 +出纳组 出納組 +出线 出線 +出结 出結 +出给 出給 +出继 出繼 +出缺 出缺 +出群 出羣 +出群拔萃 出羣拔萃 +出老千 出老千 +出脱 出脫 +出自 出自 +出自于 出自於 +出自娘胎 出自孃胎 +出自肺腑 出自肺腑 +出臭子儿 出臭子兒 +出航 出航 +出色 出色 +出花儿 出花兒 +出花样 出花樣 +出芽 出芽 +出芽法 出芽法 +出芽生殖 出芽生殖 +出苗 出苗 +出苗率 出苗率 +出草 出草 +出落 出落 +出虚恭 出虛恭 +出蛰 出蟄 +出血 出血 +出血性 出血性 +出血性登革热 出血性登革熱 +出血热 出血熱 +出血病 出血病 +出血筒子 出血筒子 +出血量 出血量 +出行 出行 +出言 出言 +出言不逊 出言不遜 +出言成章 出言成章 +出言无状 出言無狀 +出言有序 出言有序 +出警入跸 出警入蹕 +出让 出讓 +出记 出記 +出访 出訪 +出诉 出訴 +出诊 出診 +出调 出調 +出谋划策 出謀劃策 +出谋献策 出謀獻策 +出谷迁乔 出谷遷喬 +出豁 出豁 +出货 出貨 +出货单 出貨單 +出货量 出貨量 +出费 出費 +出资 出資 +出资人 出資人 +出赘 出贅 +出赛 出賽 +出走 出走 +出起 出起 +出起来 出起來 +出超 出超 +出超国 出超國 +出超额 出超額 +出路 出路 +出跳 出跳 +出身 出身 +出车 出車 +出车祸 出車禍 +出轨 出軌 +出轨行为 出軌行爲 +出过 出過 +出迎 出迎 +出进口 出進口 +出远门 出遠門 +出逃 出逃 +出道 出道 +出道时 出道時 +出量 出量 +出金 出金 +出钱 出錢 +出钱出力 出錢出力 +出铁 出鐵 +出锋头 出鋒頭 +出错 出錯 +出错信息 出錯信息 +出锤 出錘 +出镜 出鏡 +出镜头 出鏡頭 +出门 出門 +出门在外 出門在外 +出门子 出門子 +出门时 出門時 +出问题 出問題 +出闸 出閘 +出阁 出閣 +出阁之喜 出閣之喜 +出阵 出陣 +出陈布新 出陳佈新 +出院 出院 +出险 出險 +出难题 出難題 +出面 出面 +出鞘 出鞘 +出韵 出韻 +出顶 出頂 +出项 出項 +出题 出題 +出风口 出風口 +出风头 出風頭 +出饭 出飯 +出首 出首 +出马 出馬 +出马上场 出馬上場 +出马上阵 出馬上陣 +出高价 出高價 +出鬼入神 出鬼入神 +出齐 出齊 +击出 擊出 +击发 擊發 +击向 擊向 +击板 擊板 +击沈 擊沈 +击筑 擊築 +击钟 擊鐘 +击钟陈鼎 擊鐘陳鼎 +击钟鼎食 擊鐘鼎食 +函复 函覆 +函谷关 函谷關 +凿出 鑿出 +凿出去 鑿出去 +凿出来 鑿出來 +凿凿有据 鑿鑿有據 +凿壁悬梁 鑿壁懸梁 +凿岩 鑿巖 +凿岩机 鑿岩機 +凿船虫 鑿船蟲 +刀创药 刀創藥 +刀削面 刀削麪 +刀割针扎 刀割針扎 +刀布 刀布 +刀板 刀板 +刀耕火种 刀耕火種 +刀面 刀面 +刁奸 刁姦 +刁恶 刁惡 +刁斗 刁斗 +分一杯羹 分一杯羹 +分不出 分不出 +分个 分個 +分久必合 分久必合 +分久必合合久必分 分久必合合久必分 +分了 分了 +分伙 分夥 +分克 分克 +分党 分黨 +分出 分出 +分出去 分出去 +分出来 分出來 +分分合合 分分合合 +分别 分別 +分别出 分別出 +分别财产制 分別財產制 +分别部居 分別部居 +分半钟 分半鐘 +分占 分佔 +分厂 分廠 +分厘卡 分釐卡 +分厘毫丝 分釐毫絲 +分发 分發 +分发到 分發到 +分发区 分發區 +分发给 分發給 +分合 分合 +分向岛 分向島 +分多钟 分多鐘 +分天之仇 分天之仇 +分子化合物 分子化合物 +分子钟 分子鐘 +分封制 分封制 +分尸 分屍 +分尸案 分屍案 +分工合作 分工合作 +分工整合 分工整合 +分布 分佈 +分布于 分佈於 +分布区 分佈區 +分布图 分佈圖 +分布学习 分佈學習 +分布式 分佈式 +分布式发展模型 分佈式發展模型 +分布式拒绝服务 分佈式拒絕服務 +分布式环境 分佈式環境 +分布式结构 分佈式結構 +分布式网络 分佈式網絡 +分布控制 分佈控制 +分布范围 分佈範圍 +分布连结网络 分佈連結網絡 +分当 分當 +分录 分錄 +分形几何 分形幾何 +分形几何学 分形幾何學 +分形同气 分形同氣 +分得出 分得出 +分我杯羹 分我杯羹 +分摆 分擺 +分散于 分散於 +分散注意 分散注意 +分数挂帅 分數掛帥 +分时系统 分時系統 +分权制衡 分權制衡 +分杯羹 分杯羹 +分析出 分析出 +分析出来 分析出來 +分泌出 分泌出 +分泌系统 分泌系統 +分离出 分離出 +分离出来 分離出來 +分离术 分離術 +分种 分種 +分筋术 分筋術 +分类目录 分類目錄 +分系 分系 +分系统 分系統 +分级制 分級制 +分获 分獲 +分行布白 分行布白 +分裂症 分裂症 +分身乏术 分身乏術 +分身术 分身術 +分辨出 分辨出 +分辨出来 分辨出來 +分辨善恶 分辨善惡 +分进合 分進合 +分进合击 分進合擊 +分针 分針 +分钟 分鐘 +分门别类 分門別類 +切个 切個 +切云 切雲 +切出 切出 +切出去 切出去 +切出来 切出來 +切合 切合 +切合实际 切合實際 +切合需要 切合需要 +切向 切向 +切向力 切向力 +切向速度 切向速度 +切向量 切向量 +切平面 切平面 +切开术 切開術 +切当 切當 +切菜板 切菜板 +切除术 切除術 +切面 切面 +切骨之仇 切骨之仇 +刊了 刊了 +刊出 刊出 +刊出来 刊出來 +刊布 刊佈 +刊板 刊板 +刊误表 刊誤表 +刑于 刑于 +刑余 刑餘 +刑克 刑剋 +刑法志 刑法志 +刑辟 刑辟 +划一 劃一 +划一不二 劃一不二 +划一桨 划一槳 +划上 劃上 +划下 劃下 +划下道来 劃下道來 +划不来 划不來 +划为 劃爲 +划了 劃了 +划了一会 划了一會 +划价 劃價 +划伤 劃傷 +划位 劃位 +划入 劃入 +划具 划具 +划出 劃出 +划分 劃分 +划分为 劃分爲 +划分成 劃分成 +划分法 劃分法 +划划 劃劃 +划到 劃到 +划到岸 划到岸 +划到江心 划到江心 +划动 划動 +划单人艇 划單人艇 +划去 劃去 +划双人 划雙人 +划向 划向 +划圆防守 劃圓防守 +划在 劃在 +划地 劃地 +划地为王 劃地爲王 +划地自限 劃地自限 +划子 划子 +划定 劃定 +划定为 劃定爲 +划座位 劃座位 +划开 劃開 +划归 劃歸 +划得 劃得 +划得来 划得來 +划成 劃成 +划拉 劃拉 +划拨 劃撥 +划拨帐号 劃撥帳號 +划拳 划拳 +划掉 劃掉 +划时代 劃時代 +划来 划來 +划来划去 劃來劃去 +划桨 划槳 +划款 劃款 +划水 划水 +划法 劃法 +划清 劃清 +划清界线 劃清界線 +划清界限 劃清界限 +划然 劃然 +划界 劃界 +划痕 劃痕 +划着 划着 +划着走 划着走 +划破 劃破 +划策 劃策 +划算 划算 +划纹症 劃紋症 +划线 劃線 +划船 划船 +划艇 划艇 +划花 劃花 +划行 划行 +划设 劃設 +划走 划走 +划起 划起 +划起来 划起來 +划足 劃足 +划过 劃過 +划过去 划過去 +划过来 划過來 +划进 划進 +划进去 划進去 +划进来 划進來 +划龙舟 划龍舟 +刓团 刓團 +刖足适屦 刖足適屨 +刖趾适屦 刖趾適屨 +列举出 列舉出 +列了 列了 +列克星顿 列克星頓 +列出 列出 +列出来 列出來 +列别杰夫 列別傑夫 +列印出来 列印出來 +列夫托尔斯泰 列夫托爾斯泰 +列宁威权体系 列寧威權體系 +列布 列布 +列席代表 列席代表 +列当 列當 +列御寇 列禦寇 +列氏寒暑表 列氏寒暑表 +列表 列表 +列表机 列表機 +刘云山 劉雲山 +刘任杰 劉任傑 +刘伟杰 劉偉杰 +刘克庄 劉克莊 +刘克襄 劉克襄 +刘占吉 劉占吉 +刘向 劉向 +刘嘉发 劉嘉發 +刘复 劉復 +刘宗周 劉宗周 +刘峰松 劉峯松 +刘幸义 劉幸義 +刘幸如 劉倖如 +刘志勤 劉志勤 +刘志升 劉志昇 +刘志威 劉志威 +刘念 劉念 +刘松仁 劉松仁 +刘松年 劉松年 +刘松藩 劉松藩 +刘知几 劉知幾 +刘秋凤 劉秋鳳 +刘胡兰 劉胡蘭 +刘表 劉表 +刘鉴 劉鑑 +刘鉴庭 劉鑑庭 +刘长发 劉長發 +刘阮上天台 劉阮上天臺 +刘青云 劉青雲 +则个 則個 +刚出 剛出 +刚出去 剛出去 +刚出来 剛出來 +刚出道 剛出道 +刚回 剛回 +刚回到 剛回到 +刚回去 剛回去 +刚回来 剛回來 +刚干 剛乾 +刚才 剛纔 +刚才一载 剛纔一載 +刚才在 剛纔在 +刚才是 剛纔是 +刚板硬正 剛板硬正 +刚柔并济 剛柔並濟 +创业板 創業板 +创业板上市 創業板上市 +创价学会 創價學會 +创伤后 創傷後 +创伤后压力 創傷後壓力 +创伤后压力紊乱 創傷後壓力紊亂 +创作出 創作出 +创作曲 創作曲 +创出 創出 +创制 創制 創製 +创制权 創制權 +创历年 創歷年 +创巨 創鉅 +创意曲 創意曲 +创意杯 創意盃 +创汇 創匯 +创立出 創立出 +创纪录 創紀錄 +创获 創穫 +创记录 創記錄 +创造出 創造出 +创造出来 創造出來 +创面 創面 +初冬 初冬 +初出茅庐 初出茅廬 +初升 初升 +初发 初發 +初发芙蓉 初發芙蓉 +初唐四杰 初唐四傑 +初回 初回 +初征 初征 +初志 初志 +初愿 初願 +初次见面 初次見面 +初登板 初登板 +初秋 初秋 +初秋图 初秋圖 +初级关系 初級關係 +初级团体 初級團體 +初选制 初選制 +初露才华 初露才華 +判别 判別 +判别式 判別式 +判据 判據 +判断出 判斷出 +判然不合 判然不合 +判若云泥 判若雲泥 +別干净 別乾淨 +刨出来 刨出來 +利于 利於 +利古里亚 利古里亞 +利多于弊 利多於弊 +利多出尽 利多出盡 +利字当头 利字當頭 +利害关系 利害關係 +利害关系人 利害關係人 +利害关系方 利害關係方 +利害冲突 利害衝突 +利弊参半 利弊參半 +利得汇 利得彙 +利息支出 利息支出 +利托 利托 +利析秋毫 利析秋毫 +利欲 利慾 +利欲心 利慾心 +利欲熏心 利慾薰心 +利欲薰心 利慾薰心 +利比里亚 利比里亞 +利用价值 利用價值 +利用系数 利用係數 +利益团体 利益團體 +利益集团 利益集團 +利空出尽 利空出盡 +利纳克斯 利納克斯 +利默里克 利默里克 +别上 別上 +别上去 別上去 +别上来 別上來 +别下 別下 +别下去 別下去 +别下来 別下來 +别业 別業 +别个 別個 +别义 別義 +别乡 別鄉 +别乱 別亂 +别了 別了 +别于 別於 +别人 別人 +别人的 別人的 +别人的孩子死不完 別人的孩子死不完 +别人的肉偎不热 別人的肉偎不熱 +别人肉帖不在腮颊上 別人肉帖不在腮頰上 +别从 別從 +别传 別傳 +别体 別體 +别作一眼 別作一眼 +别使 別使 +别倒 別倒 +别傻 別傻 +别傻了 別傻了 +别像 別像 +别克 別克 +别党 別黨 +别关 別關 +别具 別具 +别具一格 別具一格 +别具匠心 別具匠心 +别具只眼 別具隻眼 +别具慧眼 別具慧眼 +别具炉锤 別具爐錘 +别具肺肠 別具肺腸 +别再 別再 +别出 別出 +别出去 別出去 +别出心裁 別出心裁 +别出新裁 別出新裁 +别出机杼 別出機杼 +别出来 別出來 +别创新格 別創新格 +别别扭扭 彆彆扭扭 +别到 別到 +别刻 別刻 +别办 別辦 +别加 別加 +别动 別動 +别动队 別動隊 +别劲 別勁 +别区 別區 +别去 別去 +别县 別縣 +别又 別又 +别受 別受 +别变 別變 +别口气 彆口氣 +别句 別句 +别只 別隻 +别叫 別叫 +别史 別史 +别号 別號 +别名 別名 +别后 別後 +别后寒温 別後寒溫 +别向 別向 +别吓 別嚇 +别吓人 別嚇人 +别哭 別哭 +别嘴 彆嘴 +别国 別國 +别在 別在 +别墅 別墅 +别墅区 別墅區 +别墨 別墨 +别处 別處 +别太客气 別太客氣 +别套 別套 +别子 別子 +别字 別字 +别守 別守 +别客气 別客氣 +别室 別室 +别宫祭江 別宮祭江 +别害羞 別害羞 +别家 別家 +别寄 別寄 +别对 別對 +别将 別將 +别局 別局 +别岁 別歲 +别巷 別巷 +别师 別師 +别庄 別莊 +别开 別開 +别开生面 別開生面 +别开蹊径 別開蹊徑 +别异 別異 +别弹 別彈 +别强 彆強 +别当 別當 +别得 別得 +别忙 別忙 +别念 別唸 +别急 別急 +别怪 別怪 +别情 別情 +别情依依 別情依依 +别想 別想 +别意 別意 +别成 別成 +别房 別房 +别手 別手 +别扭 彆扭 +别把 別把 +别拍 別拍 +别拔 別拔 +别拗 彆拗 +别拿 別拿 +别挤 別擠 +别排 別排 +别描头 別描頭 +别提 別提 +别提了 別提了 +别搬 別搬 +别支 別支 +别收 別收 +别教 別教 +别数 別數 +别族 別族 +别无 別無 +别无他法 別無他法 +别无他物 別無他物 +别无他用 別無他用 +别无分号 別無分號 +别无选择 別無選擇 +别无长物 別無長物 +别日南鸿才北去 別日南鴻纔北去 +别是 別是 +别替 別替 +别有 別有 +别有天地 別有天地 +别有居心 別有居心 +别有所指 別有所指 +别有洞天 別有洞天 +别有用心 別有用心 +别有用意 別有用意 +别有肺肠 別有肺腸 +别有韵味 別有韻味 +别有风味 別有風味 +别本 別本 +别杀 別殺 +别材 別材 +别束 別束 +别来 別來 +别来无恙 別來無恙 +别枝 別枝 +别架 別架 +别栋 別棟 +别树一帜 別樹一幟 +别树一旗 別樹一旗 +别树一格 別樹一格 +别校 別校 +别样 別樣 +别棵 別棵 +别殿 別殿 +别气 彆氣 +别法 別法 +别派 別派 +别爲 別爲 +别现 別現 +别班 別班 +别理 別理 +别生 別生 +别生枝节 別生枝節 +别生气 別生氣 +别用 別用 +别由 別由 +别白 別白 +别的 別的 +别的人 別的人 +别省 別省 +别看 別看 +别着 彆着 +别离 別離 +别种 別種 +别种的 別種的 +别科 別科 +别称 別稱 +别笑 別笑 +别第 別第 +别答 別答 +别筵 別筵 +别管 別管 +别箱 別箱 +别线 別線 +别组 別組 +别给 別給 +别绪 別緒 +别罐 別罐 +别脚 別腳 +别致 別緻 +别致有趣 別致有趣 +别苗头 別苗頭 +别被 別被 +别裁 別裁 +别裁伪体 別裁僞體 +别解 別解 +别讨 別討 +别让 別讓 +别记 別記 +别讲 別講 +别论 別論 +别识别见 別識別見 +别试 別試 +别话 別話 +别说 別說 +别说出 別說出 +别说到 別說到 +别说起 別說起 +别请 別請 +别课 別課 +别调 別調 +别谈 別談 +别赋 別賦 +别赏 別賞 +别走 別走 +别起 別起 +别起来 別起來 +别趣 別趣 +别跑 別跑 +别踢 別踢 +别转 別轉 +别输 別輸 +别辟 別闢 +别辟蹊径 別闢蹊徑 +别辟门户 別闢門戶 +别过 別過 +别过去 別過去 +别过头 別過頭 +别过来 別過來 +别逃 別逃 +别针 別針 +别队 別隊 +别院 別院 +别除权 別除權 +别集 別集 +别项 別項 +别颏腮 別頦腮 +别颗 別顆 +别题 別題 +别风淮雨 別風淮雨 +别馆 別館 +别首 別首 +别驾 別駕 +别骑 別騎 +别鹤 別鶴 +别鹤孤鸾 別鶴孤鸞 +别鹤操 別鶴操 +别鹤离鸾 別鶴離鸞 +刬恶除奸 剗惡除奸 +刮上 刮上 +刮下 刮下 +刮下去 刮下去 +刮下来 刮下來 +刮书背 刮書背 +刮了 颳了 +刮伤 刮傷 +刮倒 颳倒 +刮冷风 刮冷風 +刮出 刮出 +刮刀 刮刀 +刮刮 刮刮 +刮刮乐 刮刮樂 +刮刮匝匝 刮刮匝匝 +刮刮卡 刮刮卡 +刮刮叫 刮刮叫 +刮刮杂杂 刮刮雜雜 +刮刮而谈 刮刮而談 +刮到 刮到 +刮削 刮削 +刮剌 刮剌 +刮剌剌 刮剌剌 +刮去 颳去 +刮取 刮取 +刮喇 刮喇 +刮在 刮在 +刮地器 刮地器 +刮地皮 刮地皮 +刮垢 刮垢 +刮垢磨光 刮垢磨光 +刮大风 颳大風 +刮头 刮頭 +刮好 刮好 +刮子 刮子 +刮宫术 刮宮術 +刮得 颳得 +刮打 刮打 +刮拉 刮拉 +刮掉 刮掉 +刮搭板儿 刮搭板兒 +刮摩 刮摩 +刮来刮去 刮來刮去 +刮毒 刮毒 +刮涎 刮涎 +刮痕 刮痕 +刮痧 刮痧 +刮的 刮的 +刮皮刀 刮皮刀 +刮目相待 刮目相待 +刮目相看 刮目相看 +刮着 颳着 +刮研 刮研 +刮破 刮破 +刮肠洗胃 刮腸洗胃 +刮胡 刮鬍 +刮胡刀 刮鬍刀 +刮胡子 刮鬍子 +刮脸 刮臉 +刮脸刀 刮臉刀 +刮脸皮 刮臉皮 +刮舌 刮舌 +刮舌子 刮舌子 +刮补 刮補 +刮言 刮言 +刮走 颳走 +刮起 颳起 +刮起来 刮起來 +刮躁 刮躁 +刮过 刮過 +刮过去 刮過去 +刮过来 刮過來 +刮铲 刮鏟 +刮除 刮除 +刮雪 颳雪 +刮须 刮鬚 +刮风 颳風 +刮风下雪倒便宜 刮風下雪倒便宜 +刮风后 颳風後 +刮骨 刮骨 +刮骨去毒 刮骨去毒 +刮骨疗毒 刮骨療毒 +到不了 到不了 +到了 到了 +到岸价 到岸價 +到岸价格 到岸價格 +到此一游 到此一遊 +到达签证 到達簽證 +到那个时候 到那個時候 +到那里 到那裏 +制中 制中 +制为 製爲 +制举 制舉 +制义 制義 +制书 制書 +制于 制於 +制件 製件 +制伏 制伏 +制住 制住 +制作 製作 +制作业 製作業 +制作人 製作人 +制作出 製作出 +制作出来 製作出來 +制作商 製作商 +制作好 製作好 +制作成 製作成 +制作群 製作羣 +制作者 製作者 +制作费 製作費 +制假 製假 +制做 製做 +制军 制軍 +制冰 製冰 +制冰机 製冰機 +制冷 製冷 +制冷剂 製冷劑 +制冷机 製冷機 +制出 製出 +制剂 製劑 +制动 制動 +制动器 制動器 +制动因子 制動因子 +制动火箭 制動火箭 +制动缸 制動缸 +制动踏板 制動踏板 +制勘 制勘 +制压射击 制壓射擊 +制取 製取 +制变 制變 +制台 制臺 +制命 制命 +制品 製品 +制售 製售 +制图 製圖 +制图员 製圖員 +制图学 製圖學 +制图室 製圖室 +制图尺 製圖尺 +制图师 製圖師 +制图板 製圖板 +制图样 製圖樣 +制图桌 製圖桌 +制图者 製圖者 +制图车 製圖車 +制坯 製坯 +制备 製備 +制定 制定 +制定出 制定出 +制定出来 制定出來 +制宪 制憲 +制宪会议 制憲會議 +制宪权 制憲權 +制导 制導 +制币 制幣 +制度 制度 +制度化 制度化 +制度性 制度性 +制度法 制度法 +制度面 制度面 +制式 制式 +制式化 制式化 +制得 製得 +制成 製成 +制成品 製成品 +制播 製播 +制敌机先 制敵機先 +制新宪 制新憲 +制服 制服 +制服呢 制服呢 +制服警察 制服警察 +制材 製材 +制梃 制梃 +制止 制止 +制毒 製毒 +制氧 製氧 +制水阀 制水閥 +制法 製法 +制浆 製漿 +制海 制海 +制海权 制海權 +制爲 製爲 +制片 製片 +制片人 製片人 +制片厂 製片廠 +制片商 製片商 +制片家 製片家 +制版 製版 +制版术 製版術 +制盐 製鹽 +制礼 制禮 +制礼作乐 制禮作樂 +制科 制科 +制程 製程 +制空 制空 +制空权 制空權 +制策 制策 +制签 制籤 +制糖 製糖 +制糖厂 製糖廠 +制约 制約 +制约刺激 制約刺激 +制约反应 制約反應 +制纸 製紙 +制胜 制勝 +制胜之道 制勝之道 +制艺 制藝 +制茶 製茶 +制药 製藥 +制药业 製藥業 +制药企业 製藥企業 +制药厂 製藥廠 +制衡 制衡 +制衡作用 制衡作用 +制衣 製衣 +制衣厂 製衣廠 +制表 製表 +制裁 制裁 +制裁案 制裁案 +制订 制訂 +制诰 制誥 +制造 製造 +制造业 製造業 +制造业者 製造業者 +制造出 製造出 +制造出来 製造出來 +制造厂 製造廠 +制造厂商 製造廠商 +制造品 製造品 +制造商 製造商 +制造器 製造器 +制造场 製造場 +制造成 製造成 +制造术 製造術 +制造者 製造者 +制造费用 製造費用 +制酸剂 制酸劑 +制酸性 製酸性 +制醣 制醣 +制钟 制鐘 +制钱 制錢 +制限 制限 +制限选举 制限選舉 +制陶 製陶 +制陶工人 製陶工人 +制面 制面 +制面具 製面具 +制革 製革 +制革厂 製革廠 +制革工厂 製革工廠 +制鞋 製鞋 +制鞋业 製鞋業 +制鞋匠 製鞋匠 +制鞋工人 製鞋工人 +制音器 制音器 +制高点 制高點 +刷卷 刷卷 +刷新纪录 刷新紀錄 +刺不准 刺不準 +刺出 刺出 +刺出去 刺出去 +刺出来 刺出來 +刺参 刺蔘 +刺头泥里陷 刺頭泥裏陷 +刺干 刺干 +刺探出 刺探出 +刺杀出局 刺殺出局 +刺枪术 刺槍術 +刺激启动不同步 刺激啓動不同步 +刺绣 刺繡 +刺股悬梁 刺股懸梁 +刺胳针 刺胳針 +刺针 刺針 +刺骨悬梁 刺骨懸梁 +刻个 刻個 +刻了 刻了 +刻于 刻於 +刻出 刻出 +刻划 刻劃 +刻划入微 刻劃入微 +刻划出 刻劃出 +刻半钟 刻半鐘 +刻多钟 刻多鐘 +刻录机 刻錄機 +刻板 刻板 +刻板印象 刻板印象 +刻蜡纸 刻蠟紙 +刻足适屦 刻足適屨 +刻钟 刻鐘 +剂量当量 劑量當量 +剃了 剃了 +剃发 剃髮 +剃发为尼 剃髮爲尼 +剃发令 剃髮令 +剃发留辫 剃髮留辮 +剃发铺 剃髮鋪 +剃头发 剃頭髮 +剃胡 剃鬍 +剃须 剃鬚 +剃须刀 剃鬚刀 +剉折 剉折 +削了 削了 +削价 削價 +削发 削髮 +削发为僧 削髮爲僧 +削发为尼 削髮爲尼 +削发披缁 削髮披緇 +削苹果 削蘋果 +削足适履 削足適履 +削趾适屦 削趾適屨 +削面 削麪 +前不巴村后不巴店 前不巴村後不巴店 +前事不忘后事之师 前事不忘後事之師 +前亲晚后 前親晚後 +前人失脚后人把滑 前人失腳後人把滑 +前人撒土迷了后人的眼 前人撒土迷了後人的眼 +前人栽树后人乘凉 前人栽樹後人乘涼 +前人种树 前人種樹 +前仆后继 前仆後繼 +前仆后起 前仆後起 +前仇 前仇 +前仰后合 前仰後合 +前修 前修 +前俯后仰 前俯後仰 +前倨后卑 前倨後卑 +前倨后恭 前倨後恭 +前儿个 前兒個 +前几天 前幾天 +前出后空 前出後空 +前前后后 前前後後 +前功尽废 前功盡廢 +前功尽弃 前功盡棄 +前功尽灭 前功盡滅 +前厂 前廠 +前台 前臺 +前叶 前葉 +前合后仰 前合後仰 +前合后偃 前合後偃 +前后 前後 +前后任 前後任 +前后夹攻 前後夾攻 +前后左右 前後左右 +前后文 前後文 +前后相悖 前後相悖 +前后相随 前後相隨 +前后矛盾 前後矛盾 +前后脚儿 前後腳兒 +前向拥塞通知 前向擁塞通知 +前呼后应 前呼後應 +前呼后拥 前呼後擁 +前回 前回 +前因后果 前因後果 +前奏曲 前奏曲 +前婚后嫁 前婚後嫁 +前家后继 前家後繼 +前志 前志 +前怕狼后怕虎 前怕狼後怕虎 +前思后想 前思後想 +前扑后继 前撲後繼 +前挽后推 前挽後推 +前推后拥 前推後擁 +前新系 前新系 +前无古人后无来者 前無古人後無來者 +前核 前核 +前歌后舞 前歌後舞 +前甲板 前甲板 +前短后长 前短後長 +前程万里 前程萬里 +前缘未了 前緣未了 +前苏联 前蘇聯 +前街后巷 前街後巷 +前言不对后语 前言不對後語 +前言不答后语 前言不答後語 +前词汇加工 前詞彙加工 +前词汇语音加工 前詞彙語音加工 +前词汇阶段 前詞彙階段 +前赴后继 前赴後繼 +前车之复 前車之覆 +前车之覆后车之鉴 前車之覆後車之鑑 +前车之鉴 前車之鑑 +前车可鉴 前車可鑑 +前车复后车戒 前車覆後車戒 +前进党 前進黨 +前途未卜 前途未卜 +前遮后拥 前遮後擁 +前郭尔罗斯蒙古族自治县 前郭爾羅斯蒙古族自治縣 +前长后短 前長後短 +前门不进师姑后门不进和尚 前門不進師姑後門不進和尚 +前门打虎后门打狼 前門打虎後門打狼 +前门拒虎后门进狼 前門拒虎後門進狼 +前面 前面 +剑叶 劍葉 +剑合珠还 劍合珠還 +剑术 劍術 +剑杆 劍桿 +剔了 剔了 +剔出 剔出 +剔团圆 剔團圓 +剔团𪢮 剔團圞 +剔庄货 剔莊貨 +剔齿纤 剔齒纖 +剖别 剖別 +剖宫产手术 剖宮產手術 +剖腹产手术 剖腹產手術 +剖腹手术 剖腹手術 +剖面 剖面 +剖面图 剖面圖 +剥制 剝製 +剥尽 剝盡 +剥挽 剝挽 +剥极必复 剝極必復 +剥离症 剝離症 +剥采比 剝採比 +剥面皮 剝面皮 +剧力万钧 劇力萬鈞 +剧团 劇團 +剧坛 劇壇 +剧曲 劇曲 +剧种 劇種 +剧药 劇藥 +剩个 剩個 +剩了 剩了 +剩余 剩餘 +剩余价值 剩餘價值 +剩余定理 剩餘定理 +剩余放射性 剩餘放射性 +剩余辐射 剩餘輻射 +剩馀价值 剩餘價值 +剩馀价值率 剩餘價值率 +剪个 剪個 +剪了 剪了 +剪其发 剪其髮 +剪出 剪出 +剪发 剪髮 +剪发披缁 剪髮披緇 +剪头发 剪頭髮 +剪彩 剪綵 +剪彩仪式 剪彩儀式 +剪恶除奸 剪惡除奸 +剪牡丹喂牛 剪牡丹喂牛 +剪秋罗 剪秋羅 +剪贴出 剪貼出 +副厂长 副廠長 +副团长 副團長 +副性征 副性徵 +副总干事 副總幹事 +副曲 副曲 +副法向量 副法向量 +割了 割了 +割出 割出 +割回 割回 +割回去 割回去 +割回来 割回來 +割圆术 割圓術 +割据 割據 +割舍 割捨 +割舍不下 割捨不下 +剺面 剺面 +剿获 剿獲 +劈划 劈劃 +劈地价来 劈地價來 +劈尸万段 劈屍萬段 +劈心里 劈心裏 +劈挂拳 劈掛拳 +劈脑后 劈腦後 +劈里 劈里 +劈里啪啦 劈里啪啦 +劈面 劈面 +力不从愿 力不從願 +力不同科 力不同科 +力不胜任 力不勝任 +力不自胜 力不自勝 +力争上游 力爭上游 +力克 力克 +力克制 力剋制 +力回馈 力回饋 +力困筋乏 力困筋乏 +力尽 力盡 +力尽神危 力盡神危 +力尽筋疲 力盡筋疲 +力尽筋舒 力盡筋舒 +力征 力征 +力拼众敌 力拼衆敵 +力挽 力挽 +力挽狂澜 力挽狂瀾 +力敌万人 力敵萬人 +力敌万夫 力敵萬夫 +力系 力系 +力胜 力勝 +力薄才疏 力薄才疏 +力量党 力量黨 +劝出 勸出 +劝出去 勸出去 +劝出来 勸出來 +劝善惩恶 勸善懲惡 +劝善戒恶 勸善戒惡 +劝善黜恶 勸善黜惡 +劝回 勸回 +劝回去 勸回去 +劝回来 勸回來 +办伙 辦伙 +办公台 辦公檯 +办公室里 辦公室裏 +办后事 辦後事 +功同良相 功同良相 +功同赏异 功同賞異 +功大于过 功大於過 +功布 功布 +功流万世 功流萬世 +功率恶化 功率惡化 +功率表 功率表 +功率输出 功率輸出 +功绩制 功績制 +功能团 功能團 +功能团体 功能團體 +功能磁共振成像术 功能磁共振成像術 +功能表 功能表 +功致 功緻 +功课表 功課表 +功过参半 功過參半 +加个 加個 +加了 加了 +加于 加於 +加仑 加侖 +加价 加價 +加出 加出 +加利波里 加利波里 +加勒比海共同体 加勒比海共同體 +加勒比海共同市场 加勒比海共同市場 +加升 加升 +加卷 加捲 +加发 加發 +加回 加回 +加回去 加回去 +加回来 加回來 +加害于 加害於 +加密后的 加密後的 +加尔克汉德省 加爾克漢德省 +加州技术学院 加州技術學院 +加工出口 加工出口 +加工出口区 加工出口區 +加工厂 加工廠 +加巴里雅 加巴里雅 +加布 加布 +加强控制 加強控制 +加强管制 加強管制 +加当 加當 +加拉干达 加拉干達 +加拿大铝业集团 加拿大鋁業集團 +加挂 加掛 +加挂车厢 加掛車廂 +加杯 加杯 +加杯水 加杯水 +加氢精制 加氫精制 +加油团 加油團 +加注 加註 加注 +加涂 加塗 +加签 加簽 +加签证 加簽證 +加荣耀于 加榮耀於 +加药 加藥 +加解密系统 加解密系統 +加达里 加達裏 +加速踏板 加速踏板 +加里 加里 +加里宁 加里寧 +加里宁格勒 加里寧格勒 +加里宁格勒州 加里寧格勒州 +加里曼丹 加里曼丹 +加里波的 加里波的 +加里波第 加里波第 +加里肋亚 加里肋亞 +加里肋亚海 加里肋亞海 +务须 務須 +劣于 劣於 +劣种 劣種 +劣缺搊搜 劣缺搊搜 +劣药 劣藥 +动不了 動不了 +动了 動了 +动力系统 動力系統 +动向 動向 +动向不明 動向不明 +动如参商 動如參商 +动干戈 動干戈 +动念 動念 +动态范围 動態範圍 +动手术 動手術 +动物系 動物系 +动物纤维 動物纖維 +动物育种 動物育種 +动画艺术 動畫藝術 +动荡 動盪 +动荡不安 動盪不安 +动荡不定 動盪不定 +动配合 動配合 +助于 助於 +助恶 助惡 +助理 助理 +助选团 助選團 +努瓦克肖特 努瓦克肖特 +劫余 劫餘 +劫制 劫制 +劫后余生 劫後餘生 +劫后英雄传 劫後英雄傳 +劫后馀烬 劫後餘燼 +劫后馀生 劫後餘生 +劬劳顾复 劬勞顧復 +励志 勵志 +励志书 勵志書 +劲度系数 勁度係數 +劲松 勁松 +劲秋 勁秋 +劲舞团 勁舞團 +劲骨丰肌 勁骨豐肌 +劳军团 勞軍團 +劳力士表 勞力士錶 +劳务出口 勞務出口 +劳动党 勞動黨 +劳动合同 勞動合同 +劳动基准法 勞動基準法 +劳动模范 勞動模範 +劳发 勞發 +劳台重 勞臺重 +劳困 勞困 +劳工党 勞工黨 +劳工团体 勞工團體 +劳工退休准备金 勞工退休準備金 +劳资关系 勞資關係 +劳资合作 勞資合作 +劳逸结合 勞逸結合 +劳里斯 勞里斯 +劳雇关系 勞僱關係 +劾系 劾繫 +势不可当 勢不可當 +势不并立 勢不並立 +势力并行 勢力並行 +势力范围 勢力範圍 +势合形离 勢合形離 +势同水火 勢同水火 +势穷力极 勢窮力極 +勃发 勃發 +勃德修正案 勃德修正案 +勃极烈 勃極烈 +勃郁 勃鬱 +勇于 勇於 +勇于认错 勇於認錯 +勋章 勳章 +勒借 勒借 +勒克 勒克 +勒克司 勒克司 +勒克莱尔 勒克萊爾 +勒里勒得 勒里勒得 +勘合 勘合 +勘误表 勘誤表 +募兵制 募兵制 +勤仆 勤僕 +勤俭朴实 勤儉樸實 +勤俭朴素 勤儉樸素 +勤劳致富 勤勞致富 +勤朴 勤樸 +勺药 勺藥 +勾了 勾了 +勾出 勾出 +勾划 勾劃 +勾勒出 勾勒出 +勾干 勾幹 +勾当 勾當 +勾心斗角 勾心鬥角 +勾画出 勾畫出 +勾魂荡魄 勾魂蕩魄 +勿念 勿念 +勿施于人 勿施於人 +勿药 勿藥 +勿药有喜 勿藥有喜 +勿药而愈 勿藥而愈 +勿里洞岛 勿里洞島 +匀出 勻出 +匀出来 勻出來 +匀面 勻面 +包乘制 包乘制 +包产到户制 包產到戶制 +包价旅游 包價旅遊 +包伙 包伙 +包准 包準 +包利克莱荳斯 包利克萊荳斯 +包占 包占 +包干 包乾 +包干儿 包乾兒 +包干制 包乾制 +包庄 包莊 +包待制 包待制 +包扎 包紮 +包扎法 包紮法 +包承制 包承制 +包揽闲事 包攬閒事 +包班制 包班制 +包皮环切术 包皮環切術 +包种茶 包種茶 +包罗万象 包羅萬象 +包衣种子 包衣種子 +包裹表决 包裹表決 +包谷 包穀 +包谷花 包谷花 +包里斯 包里斯 +包髻团衫 包髻團衫 +匋斋吉金录 匋齋吉金錄 +匏有苦叶 匏有苦葉 +匏系 匏繫 +化了 化了 +化出 化出 +化出化入 化出化入 +化合 化合 +化合价 化合價 +化合反应 化合反應 +化合态 化合態 +化合性 化合性 +化合物 化合物 +化合量 化合量 +化妆台 化妝臺 +化学合成 化學合成 +化学工厂 化學工廠 +化学弹药 化學彈藥 +化学当量 化學當量 +化学战斗部 化學戰鬥部 +化学系 化學系 +化学纤维 化學纖維 +化工厂 化工廠 +化工系 化工系 +化干戈为玉帛 化干戈爲玉帛 +化暗为明 化暗爲明 +化纤 化纖 +化纤厂 化纖廠 +化肥厂 化肥廠 +化隆回族自治县 化隆回族自治縣 +化验台 化驗臺 +北京中医药大学 北京中醫藥大學 +北京周报 北京週報 +北京国家游泳中心 北京國家游泳中心 +北京师范大学 北京師範大學 +北京汽车制造厂有限公司 北京汽車製造廠有限公司 +北京艺术学院 北京藝術學院 +北仑 北侖 +北仑区 北侖區 +北叶门 北葉門 +北向 北向 +北周 北周 +北回 北迴 +北回归线 北迴歸線 +北回线 北迴線 +北回铁路 北迴鐵路 +北岳 北嶽 +北征 北征 +北斗 北斗 +北斗七星 北斗七星 +北斗星 北斗星 +北斗镇 北斗鎮 +北曲 北曲 +北极 北極 +北极光 北極光 +北极冻原 北極凍原 +北极区 北極區 +北极圈 北極圈 +北极地区 北極地區 +北极星 北極星 +北极星飞弹 北極星飛彈 +北极海 北極海 +北极熊 北極熊 +北极犬 北極犬 +北极狐 北極狐 +北极锋 北極鋒 +北极鲸 北極鯨 +北柴胡 北柴胡 +北洋系 北洋系 +北瓦兹里斯坦 北瓦茲里斯坦 +北辕适楚 北轅適楚 +北里 北里 +北面 北面 +北面称臣 北面稱臣 +北马里亚纳 北马里亞納 +匙扣 匙扣 +匡合 匡合 +匡复 匡復 +匡当 匡當 +匡济之才 匡濟之才 +匣里龙吟 匣裏龍吟 +匪党 匪黨 +匪干 匪幹 +匪徒集团 匪徒集團 +匹似闲 匹似閒 +匹头里 匹頭裏 +匹面 匹面 +匹马只轮 匹馬隻輪 +区分出 區分出 +区划 區劃 +区别 區別 +区别性 區別性 +区别词 區別詞 +区域网路技术 區域網路技術 +区域范围 區域範圍 +区段征收 區段徵收 +医卜星相 醫卜星相 +医学系 醫學系 +医宗金鉴 醫宗金鑑 +医托 醫托 +医术 醫術 +医疗团 醫療團 +医药 醫藥 +医药业 醫藥業 +医药分业 醫藥分業 +医药分离 醫藥分離 +医药品 醫藥品 +医药商店 醫藥商店 +医药学 醫藥學 +医药气候学 醫藥氣候學 +医药界 醫藥界 +医药罔效 醫藥罔效 +医药费 醫藥費 +医院里 醫院裏 +匾扎 匾扎 +匿于 匿於 +十万 十萬 +十三经注疏 十三經注疏 +十个 十個 +十个月 十個月 +十九万 十九萬 +十九个 十九個 +十二万 十二萬 +十二万分 十二萬分 +十二个 十二個 +十二指肠虫 十二指腸蟲 +十二木表法 十二木表法 +十二面体 十二面體 +十五万 十五萬 +十五个 十五個 +十五个吊桶打水 十五個吊桶打水 +十余 十餘 +十余只 十餘隻 +十余里 十餘里 +十克 十克 +十克拉 十克拉 +十八万 十八萬 +十八个 十八個 +十八姑娘 十八姑娘 +十公克 十公克 +十公升 十公升 +十公里 十公里 +十六万 十六萬 +十六个 十六個 +十六国春秋 十六國春秋 +十六进制 十六進制 +十冬腊月 十冬臘月 +十几 十幾 +十几万 十幾萬 +十几个 十幾個 +十几个月 十幾個月 +十几二十 十幾二十 +十几人 十幾人 +十几元 十幾元 +十几分 十幾分 +十几号 十幾號 +十几块 十幾塊 +十几天 十幾天 +十几岁 十幾歲 +十几年 十幾年 +十几次 十幾次 +十出戏 十齣戲 +十出祁山 十出祁山 +十分干 十分乾 +十分钟 十分鐘 +十划 十劃 +十加仑 十加侖 +十卷 十卷 +十发 十發 +十只 十隻 +十台 十臺 +十叶 十葉 +十周 十週 +十周年 十週年 +十四万 十四萬 +十四个 十四個 +十回 十回 +十团 十團 +十国春秋 十國春秋 +十多万 十多萬 +十多个 十多個 +十多只 十多隻 +十天半个月 十天半個月 +十天后 十天後 +十天干 十天干 +十字军东征 十字軍東征 +十字军远征 十字軍遠征 +十干 十干 +十年后 十年後 +十恶 十惡 +十恶不赦 十惡不赦 +十扎 十紮 +十方地面 十方地面 +十曲 十曲 +十来个 十來個 +十杯 十杯 +十杯水 十杯水 +十杯酒 十杯酒 +十点钟 十點鐘 +十种 十種 +十秒钟 十秒鐘 +十荡十决 十蕩十決 +十谒朱门九不开 十謁朱門九不開 +十足虫 十足蟲 +十进位制 十進位制 +十进制 十進制 +十进算术 十進算術 +十郎八当 十郎八當 +十里 十里 +十里余 十里餘 +十里洋场 十里洋場 +十里长亭 十里長亭 +十里长亭无客走 十里長亭無客走 +十针 十針 +十面 十面 +十面体 十面體 +十面埋伏 十面埋伏 +十鼠同穴 十鼠同穴 +千万 千萬 +千万买邻 千萬買鄰 +千万分之一 千萬分之一 +千万千万 千萬千萬 +千万富翁 千萬富翁 +千万年 千萬年 +千不幸万不幸 千不幸萬不幸 +千不是万不是 千不是萬不是 +千丝万缕 千絲萬縷 +千个 千個 +千乘 千乘 +千乘万骑 千乘萬騎 +千乞 千乞 +千了百当 千了百當 +千亩 千畝 +千人所指 千人所指 +千亿 千億 +千仇万恨 千仇萬恨 +千仓万箱 千倉萬箱 +千仞 千仞 +千伏 千伏 +千位 千位 +千位元 千位元 +千余 千餘 +千余只 千餘隻 +千余里 千餘里 +千佛塔 千佛塔 +千佛山 千佛山 +千佛洞 千佛洞 +千依万顺 千依萬順 +千依百顺 千依百順 +千兆 千兆 +千克 千克 +千兵万马 千兵萬馬 +千军万马 千軍萬馬 +千军易得一将难求 千軍易得一將難求 +千刀万剁 千刀萬剁 +千刀万剐 千刀萬剮 +千刁万恶 千刁萬惡 +千分 千分 +千分之 千分之 +千分之一 千分之一 +千分之三 千分之三 +千分之二 千分之二 +千分表 千分表 +千千 千千 +千千万万 千千萬萬 +千卡 千卡 +千变万化 千變萬化 +千变万状 千變萬狀 +千变万轸 千變萬軫 +千古 千古 +千古事 千古事 +千古传诵 千古傳誦 +千古恨 千古恨 +千古未闻 千古未聞 +千古流传 千古流傳 +千古独步 千古獨步 +千古绝唱 千古絕唱 +千古罪人 千古罪人 +千古遗恨 千古遺恨 +千只 千隻 +千只足够 千只足夠 +千叮万嘱 千叮萬囑 +千叶 千葉 +千叶县 千葉縣 +千吨 千噸 +千吨级核武器 千噸級核武器 +千周 千周 +千呼万唤 千呼萬喚 +千咒万骂 千咒萬罵 +千唤万唤 千喚萬喚 +千回百折 千迴百折 +千回百转 千迴百轉 +千多只 千多隻 +千天后 千天後 +千夫 千夫 +千夫所指 千夫所指 +千夫长 千夫長 +千头万绪 千頭萬緒 +千头橘奴 千頭橘奴 +千头百绪 千頭百緒 +千奇百怪 千奇百怪 +千妥万妥 千妥萬妥 +千妥万当 千妥萬當 +千姿百态 千姿百態 +千娇百媚 千嬌百媚 +千娇百态 千嬌百態 +千孔百疮 千孔百瘡 +千字文 千字文 +千字节 千字節 +千家 千家 +千家万户 千家萬戶 +千家姓 千家姓 +千家诗 千家詩 +千寻 千尋 +千层糕 千層糕 +千层面 千層麪 +千山万壑 千山萬壑 +千山万水 千山萬水 +千山区 千山區 +千山山脉 千山山脈 +千岁 千歲 +千岁一时 千歲一時 +千岐万辙 千岐萬轍 +千岛列岛 千島列島 +千岛湖 千島湖 +千岛湖事件 千島湖事件 +千岛群岛 千島羣島 +千岛酱 千島醬 +千岩万壑 千巖萬壑 +千岩万谷 千巖萬谷 +千岩竞秀 千巖競秀 +千嶂 千嶂 +千差万别 千差萬別 +千差万差来人不差 千差萬差來人不差 +千帆 千帆 +千年 千年 +千年万载 千年萬載 +千年前 千年前 +千年怪兽 千年怪獸 +千年田地八百主 千年田地八百主 +千年艾 千年艾 +千态万状 千態萬狀 +千思万想 千思萬想 +千总 千總 +千恩万谢 千恩萬謝 +千愁万恨 千愁萬恨 +千愁万绪 千愁萬緒 +千愁万虑 千愁萬慮 +千户 千戶 +千手千眼观音 千手千眼觀音 +千扎 千紮 +千挑万选 千挑萬選 +千挑百选 千挑百選 +千推万阻 千推萬阻 +千支万派 千支萬派 +千斤 千斤 +千斤重担 千斤重擔 +千斤顶 千斤頂 +千方万计 千方萬計 +千方百计 千方百計 +千日 千日 +千日红 千日紅 +千日菊 千日菊 +千日酒 千日酒 +千村万落 千村萬落 +千条万端 千條萬端 +千条万绪 千條萬緒 +千杯 千杯 +千欢万喜 千歡萬喜 +千步 千步 +千湖国 千湖國 +千点 千點 +千牛 千牛 +千牛刀 千牛刀 +千状万态 千狀萬態 +千状万端 千狀萬端 +千瓦 千瓦 +千瓦小时 千瓦小時 +千瓦时 千瓦時 +千生万死 千生萬死 +千疮百孔 千瘡百孔 +千百万 千百萬 +千百年 千百年 +千百成群 千百成羣 +千皓宣 千皓宣 +千真万真 千真萬真 +千真万确 千真萬確 +千石 千石 +千碱基对 千鹼基對 +千禧 千禧 +千禧年 千禧年 +千秋 千秋 +千秋万世 千秋萬世 +千秋万代 千秋萬代 +千秋万古 千秋萬古 +千秋万岁 千秋萬歲 +千秋佳城 千秋佳城 +千秋大业 千秋大業 +千秋庙 千秋廟 +千秋节 千秋節 +千章 千章 +千端万绪 千端萬緒 +千算万算不值天一划 千算萬算不值天一劃 +千篇一律 千篇一律 +千米 千米 +千粒重 千粒重 +千红万紫 千紅萬紫 +千经万卷 千經萬卷 +千绪万端 千緒萬端 +千羊之皮不如一狐之腋 千羊之皮不如一狐之腋 +千般 千般 +千般万样 千般萬樣 +千英宇 千英宇 +千虑一失 千慮一失 +千虑一得 千慮一得 +千言 千言 +千言万语 千言萬語 +千赫 千赫 +千赫兹 千赫茲 +千足港条 千足港條 +千足虫 千足蟲 +千载 千載 +千载一会 千載一會 +千载一合 千載一合 +千载一时 千載一時 +千载一逢 千載一逢 +千载一遇 千載一遇 +千载扬名 千載揚名 +千载独步 千載獨步 +千载难逢 千載難逢 +千辛万苦 千辛萬苦 +千辛百苦 千辛百苦 +千里 千里 +千里一曲 千里一曲 +千里之堤 千里之堤 +千里之外 千里之外 +千里之行 千里之行 +千里命驾 千里命駕 +千里始足下 千里始足下 +千里姻缘一线牵 千里姻緣一線牽 +千里寄鹅毛 千里寄鵝毛 +千里搭长棚 千里搭長棚 +千里犹面 千里猶面 +千里目 千里目 +千里眼 千里眼 +千里移檄 千里移檄 +千里足 千里足 +千里达 千里達 +千里迢迢 千里迢迢 +千里迢遥 千里迢遙 +千里送鹅毛 千里送鵝毛 +千里镜 千里鏡 +千里馈粮 千里饋糧 +千里马 千里馬 +千里驹 千里駒 +千里鹅毛 千里鵝毛 +千金 千金 +千金一刻 千金一刻 +千金一掷 千金一擲 +千金一笑 千金一笑 +千金一诺 千金一諾 +千金之子 千金之子 +千金之家 千金之家 +千金买笑 千金買笑 +千金买骨 千金買骨 +千金小姐 千金小姐 +千金市骨 千金市骨 +千金敝帚 千金敝帚 +千金方 千金方 +千金裘 千金裘 +千金要方 千金要方 +千金记 千金記 +千金躯 千金軀 +千金难买 千金難買 +千钧 千鈞 +千钧一发 千鈞一髮 +千钧重负 千鈞重負 +千锤百炼 千錘百煉 +千锺粟 千鍾粟 +千镒之裘非一狐之白 千鎰之裘非一狐之白 +千门 千門 +千门万户 千門萬戶 +千闻不如一见 千聞不如一見 +千阳 千陽 +千阳县 千陽縣 +千难万险 千難萬險 +千难万难 千難萬難 +千面人 千面人 +千页群岛 千頁羣島 +千顷陂 千頃陂 +千鬼百怪 千鬼百怪 +千鸟 千鳥 +千鸟渊国家公墓 千鳥淵國家公墓 +升上 升上 +升上去 升上去 +升上来 升上來 +升为 升爲 +升了 升了 +升仙 昇仙 +升任 升任 +升任为 升任爲 +升值 升值 +升入 升入 +升出 升出 +升出来 升出來 +升到 升到 +升力 升力 +升势 升勢 +升势受阻 升勢受阻 +升升 升升 +升华 昇華 +升华作用 昇華作用 +升压 升壓 +升号 升號 +升回 升回 +升回去 升回去 +升回来 升回來 +升在 升在 +升坐 升坐 +升堂 升堂 +升堂入室 升堂入室 +升堂拜母 升堂拜母 +升天 昇天 +升好 升好 +升学 升學 +升学主义 升學主義 +升学压力 升學壓力 +升学率 升學率 +升学班 升學班 +升学考试 升學考試 +升官 升官 +升官发财 升官發財 +升官图 升官圖 +升帐 升帳 +升幂 升冪 +升幂级数 升冪級數 +升幅 升幅 +升平 昇平 +升引 升引 +升得 升得 +升息 升息 +升成 升成 +升斗 升斗 +升斗之禄 升斗之祿 +升斗小民 升斗小民 +升旗 升旗 +升旗仪式 升旗儀式 +升旗典礼 升旗典禮 +升来 升來 +升来升去 升來升去 +升格 升格 +升格为 升格爲 +升格成 升格成 +升水 升水 +升汞 昇汞 +升沉 升沉 +升温 升溫 +升火 升火 +升点 升點 +升爲 升爲 +升班 升班 +升班考试 升班考試 +升的 升的 +升破 升破 +升科 升科 +升空 升空 +升等 升等 +升等考试 升等考試 +升级 升級 +升级性 升級性 +升级成 升級成 +升级换代 升級換代 +升级版 升級版 +升结肠 升結腸 +升职 升職 +升腾 升騰 +升至 升至 +升记号 升記號 +升调 升調 +升起 升起 +升起来 升起來 +升迁 升遷 +升迁制度 升遷制度 +升迁管道 升遷管道 +升过 升過 +升速 升速 +升遐 升遐 +升阳 昇陽 +升阶 升階 +升降 升降 +升降机 升降機 +升降梯 升降梯 +升降舵 升降舵 +升降记号 升降記號 +升限 升限 +升高 升高 +升高为 升高爲 +升高自下 升高自下 +午后 午後 +半个 半個 +半个世纪 半個世紀 +半乳糖血症 半乳糖血症 +半于 半於 +半价 半價 +半价优待 半價優待 +半价倍息 半價倍息 +半保留复制 半保留複製 +半分钟 半分鐘 +半制品 半製品 +半只 半隻 +半吊子 半吊子 +半夜里 半夜裏 +半导体厂 半導體廠 +半岛电视台 半島電視臺 +半干 半乾 +半径范围 半徑範圍 +半托 半托 +半排出期 半排出期 +半日制 半日制 +半日制学校 半日制學校 +半杯 半杯 +半板 半板 +半涂而罢 半塗而罷 +半点钟 半點鐘 +半票价 半票價 +半秒钟 半秒鐘 +半老徐娘 半老徐娘 +半路出家 半路出家 +半里 半里 +半面 半面 +半面之交 半面之交 +半面之旧 半面之舊 +华东师范 華東師範 +华东师范大学 華東師範大學 +华严钟 華嚴鐘 +华中师范大学 華中師範大學 +华冈艺术学校 華岡藝術學校 +华南师范大学 華南師範大學 +华发 華髮 +华尔滋舞曲 華爾滋舞曲 +华彩 華彩 +华志 華志 +华星秋月之章 華星秋月之章 +华核 華覈 +华氏寒暑表 華氏寒暑表 +华润万家 華潤萬家 +华特里德 華特里德 +华纳音乐集团 華納音樂集團 +华胄 華胄 +华表 華表 +华表鹤归 華表鶴歸 +华里 華里 +华阳国志 華陽國志 +协力同心 協力同心 +协合 協合 +协同 協同 +协同作战 協同作戰 +协同作用 協同作用 +协同动作 協同動作 +协奏曲 協奏曲 +协议范本 協議範本 +协议规范 協議規範 +协调出 協調出 +卑梁之衅 卑梁之釁 +卓别林 卓別林 +卓尔出群 卓爾出羣 +卓柏卡布拉 卓柏卡布拉 +单一价 單一價 +单一合体字 單一合體字 +单个儿 單個兒 +单于 單于 +单交种 單交種 +单价 單價 +单位价格 單位價格 +单位信托 單位信托 +单位切向量 單位切向量 +单位制 單位制 +单位向量 單位向量 +单位面积 單位面積 +单克隆 單克隆 +单克隆抗体 單克隆抗體 +单单于 單單於 +单只 單隻 +单只是 單只是 +单叶双曲面 單葉雙曲面 +单向 單向 +单向天线 單向天線 +单向电流 單向電流 +单向行驶 單向行駛 +单向通车 單向通車 +单向道 單向道 +单向阀 單向閥 +单周 單週 +单味药 單味藥 +单夫只妇 單夫隻婦 +单婚制 單婚制 +单子叶 單子葉 +单子叶植物 單子葉植物 +单字表 單字表 +单干 單幹 +单干户 單幹戶 +单张汇票 單張匯票 +单弦 單絃 +单循环赛制 單循環賽制 +单打独斗 單打獨鬥 +单挂号 單掛號 +单据 單據 +单摆 單擺 +单方制剂 單方製劑 +单方向 單方向 +单方面 單方面 +单曲 單曲 +单曲榜 單曲榜 +单杠 單槓 +单杯 單杯 +单板 單板 +单板心合板 單板心合板 +单板机 單板機 +单核 單核 +单核细胞增多症 單核細胞增多症 +单模光纤 單模光纖 +单法货制 單法貨制 +单端孢霉烯类毒素中毒症 單端孢黴烯類毒素中毒症 +单系 單系 +单链 單鏈 +单面 單面 +单面山 單面山 +卖不出去 賣不出去 +卖个破绽 賣個破綻 +卖了 賣了 +卖了儿子招女婿 賣了兒子招女婿 +卖价 賣價 +卖俏营奸 賣俏營奸 +卖俏行奸 賣俏行奸 +卖俏迎奸 賣俏迎奸 +卖光了 賣光了 +卖出 賣出 +卖出去 賣出去 +卖卜 賣卜 +卖卜测字 賣卜測字 +卖卦口没量斗 賣卦口沒量斗 +卖呆 賣呆 +卖奸 賣姦 +卖恶 賣惡 +卖拐 賣柺 +卖油娘子水梳头 賣油娘子水梳頭 +卖炭的掉在面缸里 賣炭的掉在麪缸裏 +卖盐的做雕銮匠 賣鹽的做雕鑾匠 +卖红萝卜 賣紅蘿蔔 +卖膏药的 賣膏藥的 +卖良姜 賣良姜 +卖药 賣藥 +卖药人 賣藥人 +卖荳腐点了河滩地 賣荳腐點了河灘地 +卖金须向识金家 賣金須向識金家 +卖面子 賣面子 +南丰 南豐 +南丰县 南豐縣 +南京钟 南京鐘 +南京钟表 南京鐘錶 +南出 南出 +南北向 南北向 +南北极 南北極 +南台 南臺 +南台工专 南臺工專 +南台湾 南臺灣 +南叶门 南葉門 +南向 南向 +南回 南迴 +南回公路 南迴公路 +南回归线 南迴歸線 +南回线 南迴線 +南回铁路 南迴鐵路 +南宫适 南宮适 +南屏晚钟 南屏晚鐘 +南山并寿 南山並壽 +南山有台 南山有臺 +南山杯 南山盃 +南岳 南嶽 +南征 南征 +南征北伐 南征北伐 +南征北战 南征北戰 +南征北讨 南征北討 +南方周末 南方週末 +南无阿弥陀佛 南無阿彌陀佛 +南曲 南曲 +南朝梁 南朝梁 +南极 南極 +南极仙翁 南極仙翁 +南极光 南極光 +南极呈祥 南極呈祥 +南极圈 南極圈 +南极地区 南極地區 +南极大陆 南極大陸 +南极座 南極座 +南极星沉 南極星沉 +南极星辉 南極星輝 +南极洲 南極洲 +南极洲半岛 南極洲半島 +南极老人星 南極老人星 +南极腾辉 南極騰輝 +南枝向火北枝寒 南枝向火北枝寒 +南汇 南匯 +南汇区 南匯區 +南洋模范 南洋模範 +南涌 南涌 +南游 南遊 +南特杰克 南特傑克 +南筑 南筑 +南箕北斗 南箕北斗 +南胡 南胡 +南里 南里 +南针 南針 +南面 南面 +南面为王 南面爲王 +南面百城 南面百城 +南面称伯 南面稱伯 +南面称孤 南面稱孤 +南面称王 南面稱王 +博克达山 博克達山 +博古图录 博古圖錄 +博士后 博士後 +博学多才 博學多才 +博客里 博客裏 +博尔塔拉蒙古自治州 博爾塔拉蒙古自治州 +博彩 博彩 +博彩业 博彩業 +博文反应系列 博文反應系列 +博斗 博鬥 +博汇 博彙 +博物志 博物志 +博莱克 博萊克 +博蒙特 博蒙特 +博采 博採 +博采众长 博採衆長 +博闻彊志 博聞彊志 +博鳌亚洲论坛 博鰲亞洲論壇 +卜人 卜人 +卜儿 卜兒 +卜冠文 卜冠文 +卜卜 卜卜 +卜卜米 卜卜米 +卜卦 卜卦 +卜卦家 卜卦家 +卜吉 卜吉 +卜商 卜商 +卜夜卜昼 卜夜卜晝 +卜威廉 卜威廉 +卜婿 卜婿 +卜学亮 卜學亮 +卜宅 卜宅 +卜居 卜居 +卜年 卜年 +卜度 卜度 +卜式 卜式 +卜征 卜征 +卜日 卜日 +卜易 卜易 +卜昼卜夜 卜晝卜夜 +卜珓 卜珓 +卜睿哲 卜睿哲 +卜祝 卜祝 +卜窀穸 卜窀穸 +卜筑 卜築 +卜筮 卜筮 +卜筮官 卜筮官 +卜算 卜算 +卜老 卜老 +卜者 卜者 +卜舫济 卜舫濟 +卜蜂 卜蜂 +卜课 卜課 +卜辞 卜辭 +卜邻 卜鄰 +卜骨 卜骨 +卞庄 卞莊 +卞庄子 卞莊子 +卞梁 卞梁 +占〇 佔〇 +占一 佔一 +占七 佔七 +占万 佔万 +占三 佔三 +占上 占上 +占上游 佔上游 +占上风 佔上風 +占下 佔下 +占下风 佔下風 +占不占 佔不佔 +占不足 佔不足 +占世界 佔世界 +占东 佔東 +占两 佔兩 +占个 佔個 +占个位 佔個位 +占中 佔中 +占为 佔爲 +占为己有 佔爲己有 +占主 佔主 +占主导地位 占主導地位 +占九 佔九 +占了 佔了 +占了卜 占了卜 +占二 佔二 +占五 佔五 +占亲 占親 +占人 占人 +占人便宜 佔人便宜 +占亿 佔億 +占优 佔優 +占优势 佔優勢 +占位 佔位 +占住 佔住 +占便宜 佔便宜 +占便宜的是呆 佔便宜的是呆 +占俄 佔俄 +占候 占候 +占停车 佔停車 +占先 佔先 +占光 佔光 +占全 佔全 +占八 佔八 +占六 佔六 +占凤 占鳳 +占分 佔分 +占到 佔到 +占加 佔加 +占劣 佔劣 +占北 佔北 +占十 佔十 +占千 佔千 +占半 佔半 +占南 佔南 +占卜 占卜 +占卜师 占卜師 +占卜术 占卜術 +占占 佔佔 +占卦 占卦 +占印 佔印 +占压 佔壓 +占去 佔去 +占取 佔取 +占台 佔臺 +占后 佔後 +占哺乳 佔哺乳 +占嗫 佔囁 +占四 佔四 +占国内 佔國內 +占在 佔在 +占地 佔地 +占地盘 佔地盤 +占场 佔場 +占场儿 佔場兒 +占城 占城 佔城 +占多 佔多 +占多数 佔多數 +占大 佔大 +占头 佔頭 +占头筹 佔頭籌 +占好 佔好 +占射 占射 +占小 佔小 +占少 佔少 +占尽 佔盡 +占尽便宜 佔盡便宜 +占局部 佔局部 +占居 佔居 +占屋 佔屋 +占山 佔山 +占市场 佔市場 +占平均 佔平均 +占床 佔牀 +占座 佔座 +占强 占強 +占得 佔得 +占德 佔德 +占总 佔總 +占房 占房 +占拜 占拜 +占据 佔據 +占掉 佔掉 +占整体 佔整體 +占断 占斷 +占新 佔新 +占星 占星 +占星学 占星學 +占星家 占星家 +占星师 占星師 +占星术 占星術 +占有 佔有 +占有五不验 占有五不驗 +占有权 佔有權 +占有欲 佔有慾 +占有率 佔有率 +占查 佔查 +占梦 占夢 +占次 佔次 +占比 佔比 +占毕 佔畢 +占法 佔法 +占满 佔滿 +占澳 佔澳 +占爲 佔爲 +占率 佔率 +占用 佔用 +占百 佔百 +占着 佔着 +占稳 佔穩 +占筮 占筮 +占线 佔線 +占缺 佔缺 +占网 佔網 +占美 佔美 +占耕 佔耕 +占至多 佔至多 +占至少 佔至少 +占花魁 佔花魁 +占苏 佔蘇 +占英 佔英 +占葡 佔葡 +占西 佔西 +占课 占課 佔課 +占资源 佔資源 +占起 佔起 +占起来 佔起來 +占超过 佔超過 +占身 占身 +占过 佔過 +占过去 佔過去 +占过来 佔過來 +占道 佔道 +占零 佔零 +占領 佔領 +占领 佔領 +占领军 佔領軍 +占领区 佔領區 +占领地 佔領地 +占领者 佔領者 +占风使帆 占風使帆 +占饭 佔飯 +占香 佔香 +占马 佔馬 +占验 占驗 +占高枝儿 佔高枝兒 +占鳌头 佔鰲頭 +卡其布 卡其布 +卡卡布 卡卡布 +卡尔加里 卡爾加里 +卡尔扎伊 卡爾扎伊 +卡尔文克莱因 卡爾文克萊因 +卡布 卡布 +卡布其诺 卡布其諾 +卡布其诺咖啡 卡布其諾咖啡 +卡布列拉 卡布列拉 +卡布奇诺 卡布奇諾 +卡布瑞 卡布瑞 +卡布瑞拉 卡布瑞拉 +卡布雷拉 卡布雷拉 +卡带柜 卡帶櫃 +卡式录音带 卡式錄音帶 +卡式录音机 卡式錄音機 +卡扎菲 卡扎菲 +卡扣 卡扣 +卡拉布里亚 卡拉布里亞 +卡拉曼里斯 卡拉曼里斯 +卡洛里 卡洛里 +卡片柜 卡片櫃 +卡片目录 卡片目錄 +卡特里娜 卡特里娜 +卡纳塔克邦 卡納塔克邦 +卡耶里 卡耶里 +卡芬雅克 卡芬雅克 +卡苏里 卡蘇里 +卡萨布兰加 卡薩布蘭加 +卡萨布兰卡 卡薩布蘭卡 +卡路里 卡路里 +卡迪拉克 卡迪拉克 +卡里 卡里 +卡里扎德 卡里紮德 +卡面 卡面 +卢仁杰 盧仁傑 +卢克索 盧克索 +卢千惠 盧千惠 +卢同 盧同 +卢布 盧布 +卢布尔雅那 盧布爾雅那 +卢布里雅纳 盧布里雅納 +卢棱伽 盧棱伽 +卢比西克 盧比西克 +卢胡 盧胡 +卢贝松 盧貝松 +卢郁佳 盧郁佳 +卤人 鹵人 +卤代烃 鹵代烴 +卤制 滷製 +卤化 鹵化 +卤化物 鹵化物 +卤化银 鹵化銀 +卤味 滷味 +卤地 鹵地 +卤族 鹵族 +卤梅水 滷梅水 +卤水 滷水 +卤汁 滷汁 +卤湖 滷湖 +卤煮 滷煮 +卤牛肉 滷牛肉 +卤簿 鹵簿 +卤素 鹵素 +卤素灯 鹵素燈 +卤肉 滷肉 +卤肉饭 滷肉飯 +卤莽 鹵莽 +卤莽灭裂 鹵莽滅裂 +卤菜 滷菜 +卤虾 滷蝦 +卤虾油 滷蝦油 +卤蛋 滷蛋 +卤钝 鹵鈍 +卤面 滷麪 +卤鸡 滷雞 +卤鸡肉 滷雞肉 +卦千纸 卦千紙 +卧室里 臥室裏 +卧游 臥遊 +卧薪尝胆 臥薪嚐膽 +卫教系 衛教系 +卫星云图 衛星雲圖 +卫星定位系统 衛星定位系統 +卫星导航系统 衛星導航系統 +卫星钟 衛星鐘 +卫生标准 衛生標準 +卫生系 衛生系 +卯上干 卯上幹 +卯后酒 卯後酒 +卯尽全力 卯盡全力 +卯足了劲 卯足了勁 +卯酉参辰 卯酉參辰 +印不出 印不出 +印佣 印傭 +印出 印出 +印出去 印出去 +印出来 印出來 +印制 印製 +印制厂 印製廠 +印制电路 印製電路 +印制电路板 印製電路板 +印刷厂 印刷廠 +印刷术 印刷術 +印刷电路板 印刷電路板 +印发 印發 +印台 印臺 +印台区 印臺區 +印合 印合 +印堂发黑 印堂發黑 +印度人民党 印度人民黨 +印度国大党 印度國大黨 +印度法系 印度法系 +印板儿 印板兒 +印染厂 印染廠 +印核 印核 +印欧语系 印歐語系 +印累绶若 印累綬若 +印花布 印花布 +印表 印表 +印表机 印表機 +印鉴 印鑑 +印鉴鉴定 印鑑鑑定 +危于 危於 +危于累卵 危於累卵 +危亡之秋 危亡之秋 +危害评价 危害評價 +即兴发挥 即興發揮 +即兴曲 即興曲 +即兴表演 即興表演 +即期外汇交易 即期外匯交易 +即期汇票 即期匯票 +即食面 即食麪 +却后 卻後 +却回去 卻回去 +却回来 卻回來 +却才 卻纔 +卵与石斗 卵與石鬥 +卵核 卵核 +卷一卷 捲一捲 +卷上 捲上 +卷不起 捲不起 +卷了 捲了 +卷云 捲雲 +卷住 捲住 +卷儿 卷兒 +卷入 捲入 +卷入漩涡 捲入漩渦 +卷刃 捲刃 +卷到 捲到 +卷动 捲動 +卷动门 捲動門 +卷包 捲包 +卷卷 卷卷 +卷去 捲去 +卷发 捲髮 +卷发器 捲髮器 +卷取 卷取 +卷叶蛾 卷葉蛾 +卷吸作用 捲吸作用 +卷回 捲回 +卷图 捲圖 +卷土 捲土 +卷土重来 捲土重來 +卷地皮 卷地皮 +卷娄 卷婁 +卷子 卷子 +卷子本 卷子本 +卷宗 卷宗 +卷尺 捲尺 +卷尾猴 捲尾猴 +卷层云 卷層雲 +卷層云 捲層雲 +卷帘 捲簾 +卷帘格 捲簾格 +卷帘门 捲簾門 +卷帙 卷帙 +卷帙浩繁 卷帙浩繁 +卷帻 卷幘 +卷开 捲開 +卷心 捲心 +卷心菜 捲心菜 +卷怀 卷懷 +卷成 捲成 +卷扬 捲揚 +卷扬机 捲揚機 +卷拢 捲攏 +卷旋 捲旋 +卷旗息鼓 卷旗息鼓 +卷曲 捲曲 +卷来 捲來 +卷来卷去 捲來捲去 +卷柏 卷柏 +卷染 卷染 +卷棚 捲棚 +卷款 捲款 +卷款潜逃 捲款潛逃 +卷款逃走 捲款逃走 +卷毛 捲毛 +卷浪 捲浪 +卷浪翻波 捲浪翻波 +卷烟 捲菸 +卷烟画片 捲煙畫片 +卷烟盒 捲菸盒 +卷甲 卷甲 +卷甲重来 捲甲重來 +卷积云 卷積雲 +卷笔刀 卷筆刀 +卷筒 捲筒 +卷筒纸 捲筒紙 +卷繖花序 卷繖花序 +卷纬 卷緯 +卷纸 捲紙 +卷线器 捲線器 +卷绕 卷繞 +卷缠 捲纏 +卷缩 捲縮 +卷翘 捲翹 +卷耳 卷耳 +卷腿裤 捲腿褲 +卷舌 捲舌 +卷舌元音 捲舌元音 +卷舌音 捲舌音 +卷舒 卷舒 +卷菸 捲菸 +卷落叶 捲落葉 +卷衣袖 捲衣袖 +卷袖 捲袖 +卷装 卷裝 +卷走 捲走 +卷起 捲起 +卷起來 捲起來 +卷起来 捲起來 +卷轴 卷軸 +卷轴式 卷軸式 +卷轴装 卷軸裝 +卷过 捲過 +卷进 捲進 +卷逃 捲逃 +卷钢 捲鋼 +卷铺盖 捲鋪蓋 +卷阿 卷阿 +卷须 卷鬚 +卷领 卷領 +卷风 捲風 +卷饼 捲餅 +卸了 卸了 +卸尸宴 卸屍宴 +卸扣 卸扣 +卿云 卿雲 +厂主 廠主 +厂卫 廠衛 +厂名 廠名 +厂商 廠商 +厂地 廠地 +厂址 廠址 +厂外 廠外 +厂子 廠子 +厂字旁 廠字旁 +厂家 廠家 +厂容 廠容 +厂房 廠房 +厂方 廠方 +厂棚 廠棚 +厂牌 廠牌 +厂用电 廠用電 +厂矿 廠礦 +厂礼拜 廠禮拜 +厂税 廠稅 +厂衣 廠衣 +厂规 廠規 +厂部 厂部 +厂长 廠長 +厄台 厄臺 +厄尔布鲁士 厄爾布魯士 +厄立特里亚 厄立特里亞 +厅舍 廳舍 +历下 歷下 +历下区 歷下區 +历久 歷久 +历久不衰 歷久不衰 +历久常新 歷久常新 +历久弥坚 歷久彌堅 +历久弥新 歷久彌新 +历书 曆書 +历乱 歷亂 +历代 歷代 +历代先皇 歷代先皇 +历代名画记 歷代名畫記 +历代志上 歷代志上 +历代志下 歷代志下 +历代祖先 歷代祖先 +历任 歷任 +历元 曆元 +历劫 歷劫 +历劫归来 歷劫歸來 +历历 歷歷 +历历可数 歷歷可數 +历历可纪 歷歷可紀 +历历可考 歷歷可考 +历历可见 歷歷可見 +历历可辨 歷歷可辨 +历历在目 歷歷在目 +历历如绘 歷歷如繪 +历历落落 歷歷落落 +历史 歷史 +历史上 歷史上 +历史久远 歷史久遠 +历史事件 歷史事件 +历史人物 歷史人物 +历史剧 歷史劇 +历史博物馆 歷史博物館 +历史名词 歷史名詞 +历史学 歷史學 +历史学家 歷史學家 +历史学者 歷史學者 +历史家 歷史家 +历史小说 歷史小說 +历史年表 歷史年表 +历史性 歷史性 +历史总在重演 歷史總在重演 +历史悠久 歷史悠久 +历史意义 歷史意義 +历史文学 歷史文學 +历史新高 歷史新高 +历史时代 歷史時代 +历史时期 歷史時期 +历史比较语言学 歷史比較語言學 +历史沿革 歷史沿革 +历史潮流 歷史潮流 +历史版本 歷史版本 +历史社会学 歷史社會學 +历史系 歷史系 +历史线图 歷史線圖 +历史背景 歷史背景 +历史观 歷史觀 +历史观点 歷史觀點 +历史语言学 歷史語言學 +历史语词 歷史語詞 +历史课 歷史課 +历史遗产 歷史遺產 +历史遗迹 歷史遺蹟 +历史里 歷史裏 +历史重演 歷史重演 +历命 曆命 +历城 歷城 +历城区 歷城區 +历城县 歷城縣 +历夏经秋 歷夏經秋 +历头 曆頭 +历始 曆始 +历审 歷審 +历室 曆室 +历尽 歷盡 +历尽沧桑 歷盡滄桑 +历尽艰辛 歷盡艱辛 +历尽艰险 歷盡艱險 +历尽艰难 歷盡艱難 +历尾 曆尾 +历届 歷屆 +历山 歷山 +历年 歷年 +历年来 歷年來 +历数 歷數 +历日 歷日 +历日旷久 歷日曠久 +历时 歷時 +历月 歷月 +历有年所 歷有年所 +历朝 歷朝 +历朝历代 歷朝歷代 +历朝通俗演义 歷朝通俗演義 +历本 曆本 +历来 歷來 +历来如此 歷來如此 +历来最低点 歷來最低點 +历次 歷次 +历正 歷正 +历沴 歷沴 +历法 曆法 +历澜 歷瀾 +历物之意 歷物之意 +历狱 曆獄 +历碌 歷碌 +历程 歷程 +历纪 曆紀 +历线 歷線 +历练 歷練 +历练之才 歷練之才 +历练老成 歷練老成 +历经 歷經 +历经沧桑 歷經滄桑 +历经波折 歷經波折 +历落 歷落 +历象 曆象 +历象表 曆象表 +历遍 歷遍 +历险 歷險 +历险归来 歷險歸來 +历险记 歷險記 +历齿 歷齒 +压价 壓價 +压克力 壓克力 +压克力板 壓克力板 +压出 壓出 +压出去 壓出去 +压出来 壓出來 +压制 壓制 壓製 +压制住 壓制住 +压制性 壓制性 +压力团体 壓力團體 +压力症 壓力症 +压力表 壓力錶 +压卷 壓卷 +压回 壓回 +压回去 壓回去 +压回来 壓回來 +压杆 壓桿 +压板 壓板 +压缩饼干 壓縮餅乾 +压胄子 壓冑子 +压舌板 壓舌板 +压面棍 壓麪棍 +厌恶 厭惡 +厌恶感 厭惡感 +厌食症 厭食症 +厓谷 厓谷 +厘出 釐出 +厘升 釐升 +厘定 釐定 +厘改 釐改 +厘整 釐整 +厘正 釐正 +厘清 釐清 +厘米 釐米 +厘订 釐訂 +厘金 厘金 +厘革 釐革 +厚朴 厚朴 +厚板 厚板 +厚纸板 厚紙板 +厝薪于火 厝薪於火 +原于 原於 +原价 原價 +原厂 原廠 +原厂药 原廠藥 +原发 原發 +原发性 原發性 +原发性进行性失语 原發性進行性失語 +原叶体 原葉體 +原始公社制度 原始公社制度 +原始艺术 原始藝術 +原始记录 原始記錄 +原子云 原子雲 +原子价 原子價 +原子发电厂 原子發電廠 +原子团 原子團 +原子爆破弹药 原子爆破彈藥 +原子能发电 原子能發電 +原子能发电站 原子能發電站 +原子钟 原子鐘 +原定价 原定價 +原料价格 原料價格 +原料药 原料藥 +原曲 原曲 +原板 原板 +原核 原核 +原种 原種 +原纤维 原纖維 +原苏联 原蘇聯 +原虫 原蟲 +原野游侠 原野遊俠 +原钟 原鐘 +原须 原須 +厥后 厥後 +厨余 廚餘 +厨娘 廚娘 +厨柜 廚櫃 +厮斗 廝鬥 +厮舍 廝舍 +去不了 去不了 +去了 去了 +去借 去借 +去台人员 去臺人員 +去后 去後 +去向 去向 +去向不明 去向不明 +去干 去幹 +去念 去唸 +去恶从善 去惡從善 +去搜 去搜 +去暗投明 去暗投明 +去杀胜残 去殺勝殘 +去核 去核 +县党部 縣黨部 +县志 縣誌 +县里 縣裏 +参与 參與 +参与人员 參與人員 +参与制 參與制 +参与度 參與度 +参与感 參與感 +参与权 參與權 +参与率 參與率 +参与者 參與者 +参两院 參兩院 +参予 參予 +参事 參事 +参伍 參伍 +参众两院 參衆兩院 +参会 參會 +参佐 參佐 +参假 參假 +参军 參軍 +参前落后 參前落後 +参加 參加 +参加为 參加爲 +参加人 參加人 +参加国 參加國 +参加奖 參加獎 +参加完 參加完 +参加者 參加者 +参劾 參劾 +参半 參半 +参合 參合 +参同契 參同契 +参商 參商 +参团 參團 +参场 參場 +参堂 參堂 +参天 參天 +参头 參頭 +参奏 參奏 +参孙 參孫 +参宿 參宿 +参宿七 參宿七 +参将 參將 +参展 參展 +参展商 參展商 +参展团 參展團 +参差 參差 +参差不齐 參差不齊 +参差错落 參差錯落 +参度 參度 +参悟 參悟 +参战 參戰 +参战国 參戰國 +参拜 參拜 +参拾壹 參拾壹 +参拾陆 參拾陸 +参政 參政 +参政权 參政權 +参数 參數 +参朝 參朝 +参本 參本 +参杂 參雜 +参校 參校 +参汤 蔘湯 +参演 參演 +参灵 參靈 +参照 參照 +参照卡 參照卡 +参照物 參照物 +参照系 參照系 +参看 參看 +参知政事 參知政事 +参破 參破 +参禅 參禪 +参绥 蔘綏 +参综 參綜 +参考 參考 +参考书 參考書 +参考书目 參考書目 +参考价 參考價 +参考价值 參考價值 +参考值 參考值 +参考参考 參考參考 +参考座标 參考座標 +参考性 參考性 +参考手冊 參考手冊 +参考文献 參考文獻 +参考材料 參考材料 +参考法 參考法 +参考消息 參考消息 +参考特藏 參考特藏 +参考系 參考系 +参考资料 參考資料 +参股 參股 +参茸 蔘茸 +参见 參見 +参见互照 參見互照 +参见注 參見注 +参观 參觀 +参观券 參觀券 +参观参观 參觀參觀 +参观团 參觀團 +参观团体 參觀團體 +参观完 參觀完 +参观者 參觀者 +参订 參訂 +参训 參訓 +参议 參議 +参议会 參議會 +参议员 參議員 +参议院 參議院 +参访 參訪 +参访团 參訪團 +参评 參評 +参话头 參話頭 +参请 參請 +参谋 參謀 +参谋总部 參謀總部 +参谋总长 參謀總長 +参谋长 參謀長 +参谒 參謁 +参谭 參譚 +参赛 參賽 +参赛国 參賽國 +参赛权 參賽權 +参赛片 參賽片 +参赛者 參賽者 +参赞 參贊 +参辰 參辰 +参辰卯酉 參辰卯酉 +参辰日月 參辰日月 +参选 參選 +参选人 參選人 +参透 參透 +参道 參道 +参酌 參酌 +参量 參量 +参量空间 參量空間 +参错 參錯 +参阅 參閱 +参院 參院 +参革 參革 +参预 參預 +参验 參驗 +又云 又云 +又咸 又鹹 +又咽 又咽 +又干 又幹 +又干又硬 又乾又硬 +又弱一个 又弱一個 +又当别论 又當別論 +又摇又摆 又搖又擺 +又来了 又來了 +又饥又渴 又飢又渴 +及于 及於 +及早准备 及早準備 +友于 友于 +友党 友黨 +友台 友臺 +友好代表 友好代表 +友好关系 友好關係 +友情价 友情價 +友民党 友民黨 +友谊万岁 友誼萬歲 +双丰 雙豐 +双主修 雙主修 +双凸面 雙凸面 +双台子 雙臺子 +双台子区 雙臺子區 +双叶 雙葉 +双后前兵开局 雙后前兵開局 +双向 雙向 +双向交通 雙向交通 +双向沟通 雙向溝通 +双向讨论区 雙向討論區 +双周 雙週 +双周刊 雙週刊 +双周期性 雙週期性 +双回门 雙回門 +双复磷 雙復磷 +双子叶 雙子葉 +双子叶植物 雙子葉植物 +双手万能 雙手萬能 +双手赞成 雙手贊成 +双扣 雙扣 +双折 雙摺 +双折射 雙折射 +双拐 雙柺 +双挂号 雙掛號 +双捻布 雙捻布 +双方同意 雙方同意 +双方面 雙方面 +双曲 雙曲 +双曲余割 雙曲餘割 +双曲余弦 雙曲餘弦 +双曲抛物面 雙曲拋物面 +双曲拱桥 雙曲拱橋 +双曲正弦 雙曲正弦 +双曲线 雙曲線 +双曲线正弦 雙曲線正弦 +双杠 雙槓 +双杯 雙杯 +双柑斗酒 雙柑斗酒 +双核 雙核 +双江拉祜族佤族布朗族傣族自治县 雙江拉祜族佤族布朗族傣族自治縣 +双湖特别区 雙湖特別區 +双画面电视 雙畫面電視 +双胜类 雙胜類 +双语立体声系统 雙語立體聲系統 +双轨制 雙軌制 +双进双出 雙進雙出 +双重标准 雙重標準 +双链 雙鏈 +双链核酸 雙鏈核酸 +双雕 雙鵰 +双面 雙面 +双面人 雙面人 +双面娇娃 雙面嬌娃 +双面谍 雙面諜 +双龙大裂谷 雙龍大裂谷 +反个 反個 +反乱并 反亂併 +反了 反了 +反于 反於 +反修 反修 +反光板 反光板 +反光面 反光面 +反冲 反衝 +反冲力 反衝力 +反制 反制 +反升 反升 +反卷 反捲 +反反复复 反反覆覆 +反叛党 反叛黨 +反右派斗争 反右派鬥爭 +反向 反向 +反向而行 反向而行 +反回头 反回頭 +反坦克 反坦克 +反坦克炮 反坦克炮 +反复 反覆 反復 +反复不一 反覆不一 +反复不定 反覆不定 +反复不常 反覆不常 +反复制 反複製 +反复思维 反覆思維 +反复思量 反覆思量 +反复性 反覆性 +反复无常 反覆無常 +反对党 反對黨 +反导向 反導向 +反导向飞弹 反導向飛彈 +反导系统 反導系統 +反射面 反射面 +反录病毒 反錄病毒 +反托拉斯 反托拉斯 +反托拉斯法案 反托拉斯法案 +反扣 反扣 反釦 +反掌折枝 反掌折枝 +反攻复国 反攻復國 +反攻复国大业 反攻復國大業 +反攻复国战争 反攻復國戰爭 +反斗 反斗 +反斗城 反斗城 +反方向 反方向 +反时针 反時針 +反时钟 反時鐘 +反时钟方向 反時鐘方向 +反映出 反映出 +反映出来 反映出來 +反曲弓 反曲弓 +反朴 反樸 +反核 反核 +反清复明 反清復明 +反烟 反煙 +反烟运动 反煙運動 +反目成仇 反目成仇 +反经合义 反經合義 +反袁斗争 反袁鬥爭 +反败为胜 反敗爲勝 +反转录 反轉錄 +反转录病毒 反轉錄病毒 +反酷刑折磨公约 反酷刑折磨公約 +反铲 反剷 +反阴复阴 反陰復陰 +反面 反面 +反面人物 反面人物 +反面儿 反面兒 +反面教员 反面教員 +反面教材 反面教材 +反面无情 反面無情 +反面角色 反面角色 +反颜相向 反顏相向 +反馈表 反饋表 +发上 發上 +发上冲冠 髮上衝冠 +发上去 發上去 +发上指冠 髮上指冠 +发上来 發上來 +发下 發下 +发下去 發下去 +发下来 發下來 +发不出 發不出 +发不到 發不到 +发不起 發不起 +发业 發業 +发丝 髮絲 +发丧 發喪 +发个 發個 +发个儿 發個兒 +发为血之本 髮爲血之本 +发乎情 發乎情 +发乎情止乎礼义 發乎情止乎禮義 +发乔 發喬 +发书 發書 +发乱钗横 髮亂釵橫 +发乳 髮乳 +发了 發了 +发予 發予 +发于 發於 +发些 發些 +发交 發交 +发亮 發亮 +发人 發人 +发人深省 發人深省 +发人省思 發人省思 +发付 發付 +发令 發令 +发令枪 發令槍 +发件人 發件人 +发作 發作 +发俊科 發俊科 +发信 發信 +发信号 發信號 +发像管 發像管 +发僵 發僵 +发兆 發兆 +发光 發光 +发光二极体 發光二極體 +发光二极管 發光二極管 +发光体 發光體 +发光可鉴 髮光可鑑 +发光器 發光器 +发光屏 發光屏 +发光度 發光度 +发光强度 發光強度 +发光颜料 發光顏料 +发兵 發兵 +发冢 發冢 +发冷 發冷 +发凡 發凡 +发凡举例 發凡舉例 +发出 發出 +发出去 發出去 +发出指示 發出指示 +发出来 發出來 +发函 發函 +发刊 發刊 +发刊词 發刊詞 +发利市 發利市 +发到 發到 +发功 發功 +发动 發動 +发动力 發動力 +发动期 發動期 +发动机 發動機 +发包 發包 +发包给 發包給 +发匪 髮匪 +发匮 發匱 +发单 發單 +发卖 發賣 +发卡 髮卡 發卡 +发卷 髮捲 +发去 發去 +发发 發發 +发叶 發葉 +发号 發號 +发号令 發號令 +发号出令 發號出令 +发号布令 發號佈令 +发号施令 發號施令 +发向 發向 +发呆 發呆 +发呕 發嘔 +发咒 發咒 +发响 發響 +发哑 發啞 +发哥 發哥 +发售 發售 +发售量 發售量 +发喉急 發喉急 +发喊连天 發喊連天 +发喘 發喘 +发嘎嘎声 發嘎嘎聲 +发嘘声 發噓聲 +发噱 發噱 +发回 發回 +发回去 發回去 +发回来 發回來 +发困 發睏 +发圈 髮圈 +发型 髮型 +发型师 髮型師 +发墨 發墨 +发声 發聲 +发声器 發聲器 +发声器官 發聲器官 +发声法 發聲法 +发复 發覆 +发天阴 發天陰 +发头 發頭 +发头风 發頭風 +发夹 髮夾 +发奉 發奉 +发奋 發奮 +发奋图强 發奮圖強 +发奋有为 發奮有爲 +发奖 發獎 +发套 髮套 +发奸摘隐 發奸摘隱 +发奸擿伏 發奸擿伏 +发好 發好 +发如飞蓬 髮如飛蓬 +发妻 髮妻 +发姐 髮姐 +发威 發威 +发威动怒 發威動怒 +发嫁 發嫁 +发完 發完 +发家 發家 +发富发贵 發富發貴 +发封 發封 +发射 發射 +发射井 發射井 +发射台 發射臺 +发射器 發射器 +发射场 發射場 +发射控制 發射控制 +发射机 發射機 +发射机应答器 發射機應答器 +发射极 發射極 +发射点 發射點 +发射站 發射站 +发尾 髮尾 +发屋 髮屋 +发屋求狸 發屋求狸 +发展 發展 +发展下去 發展下去 +发展不平均 發展不平均 +发展中 發展中 +发展中国 發展中國 +发展中国家 發展中國家 +发展为 發展爲 +发展出 發展出 +发展出来 發展出來 +发展到 發展到 +发展区 發展區 +发展史 發展史 +发展局 發展局 +发展心理 發展心理 +发展性 發展性 +发展成 發展成 +发展核武器 發展核武器 +发展潜力 發展潛力 +发展生产 發展生產 +发展的国家 發展的國家 +发展研究中心 發展研究中心 +发展观 發展觀 +发展起来 發展起來 +发展趋势 發展趨勢 +发展速度 發展速度 +发展部 發展部 +发岁 發歲 +发已霜白 髮已霜白 +发市 發市 +发布 發佈 +发布会 發佈會 +发带 髮帶 +发干 發乾 +发庄 發莊 +发廊 髮廊 +发廪 發廩 +发开 發開 +发式 髮式 +发引 發引 +发引千钧 髮引千鈞 +发往 發往 +发得 發得 +发心 發心 +发忿 發忿 +发怒 發怒 +发怔 發怔 +发急 發急 +发性 發性 +发怨言 發怨言 +发怵 發怵 +发恨 發恨 +发息 發息 +发恼 發惱 +发悲 發悲 +发悸 發悸 +发情 發情 +发情周期 發情週期 +发情期 發情期 +发想 發想 +发愁 發愁 +发意 發意 +发愣 發愣 +发愤 發憤 +发愤努力 發憤努力 +发愤向上 發憤向上 +发愤图强 發憤圖強 +发愤忘食 發憤忘食 +发愿 發願 +发慌 發慌 +发憷 發憷 +发懒 發懶 +发成 發成 +发扬 發揚 +发扬光大 發揚光大 +发扬踔厉 發揚踔厲 +发扬蹈厉 發揚蹈厲 +发抒 發抒 +发抖 發抖 +发报 發報 +发报人 發報人 +发报员 發報員 +发报器 發報器 +发报机 發報機 +发指 髮指 +发指令 發指令 +发指眦裂 髮指眥裂 +发挥 發揮 +发挥不了 發揮不了 +发挥作用 發揮作用 +发挥出 發揮出 +发挥出来 發揮出來 +发挥到 發揮到 +发挥性 發揮性 +发挥所长 發揮所長 +发挽双髻 髮挽雙髻 +发掉 發掉 +发排 發排 +发掘 發掘 +发掘出 發掘出 +发掘出来 發掘出來 +发掘到 發掘到 +发摃 發摃 +发摆子 發擺子 +发擂 發擂 +发擿 發擿 +发擿奸伏 發擿奸伏 +发收 發收 +发改委 發改委 +发放 發放 +发政施仁 發政施仁 +发散 發散 +发文 發文 +发文者 發文者 +发旋 髮旋 +发明 發明 +发明人 發明人 +发明创造 發明創造 +发明到 發明到 +发明奖 發明獎 +发明家 發明家 +发明展 發明展 +发明者 發明者 +发昏 發昏 +发昏章第十一 發昏章第十一 +发春 發春 +发晕 發暈 +发暗 發暗 +发有 發有 +发木 發木 +发村 發村 +发束 髮束 +发条 發條 +发来 發來 +发来发去 發來發去 +发松 發鬆 +发极 發極 +发标 發標 +发样 發樣 +发根 髮根 +发案 發案 +发梢 髮梢 +发梳 髮梳 +发棠 發棠 +发棵 發棵 +发楞 發楞 +发榜 發榜 +发横 發橫 +发横财 發橫財 +发款 發款 +发毛 發毛 +发气 發氣 +发水 發水 +发汗 發汗 +发汗剂 發汗劑 +发汗药 發汗藥 +发油 髮油 +发泄 發泄 +发泄出来 發泄出來 +发泡 發泡 +发泡体 發泡體 +发泡剂 發泡劑 +发泡成形 發泡成形 +发泡胶 發泡膠 +发洋财 發洋財 +发洪 發洪 +发派 發派 +发淡科 發淡科 +发源 發源 +发源地 發源地 +发漂 髮漂 +发潮 發潮 +发火 發火 +发火器 發火器 +发火点 發火點 +发炎 發炎 +发炎性 發炎性 +发炮 發炮 +发点 發點 +发烛 發燭 +发烟 發煙 +发烟剂 發煙劑 +发烦 發煩 +发烧 發燒 +发烧友 發燒友 +发烧客 發燒客 +发烧度 發燒度 +发烧时 發燒時 +发烧片 發燒片 +发烫 發燙 +发热 發熱 +发热时 發熱時 +发热量 發熱量 +发爲 發爲 +发片 發片 +发片日 發片日 +发牌 發牌 +发牒 發牒 +发牙豆 發牙豆 +发牢骚 發牢騷 +发物 發物 +发状 髮狀 +发狂 發狂 +发狠 發狠 +发现 發現 +发现体 發現體 +发现出 發現出 +发现到 發現到 +发现号 發現號 +发现学习 發現學習 +发现数 發現數 +发现物 發現物 +发球 發球 +发球区 發球區 +发球员 發球員 +发球局 發球局 +发球权 發球權 +发球点 發球點 +发生 發生 +发生关系 發生關係 +发生器 發生器 +发生地 發生地 +发生学 發生學 +发生学分类法 發生學分類法 +发生率 發生率 +发甲 發甲 +发电 發電 +发电厂 發電廠 +发电场 發電場 +发电所 發電所 +发电机 發電機 +发电机组 發電機組 +发电板 發電板 +发电站 發電站 +发电量 發電量 +发疯 發瘋 +发疹 發疹 +发疹子 發疹子 +发病 發病 +发病率 發病率 +发痒 發癢 +发痛 發痛 +发痧 發痧 +发痴 發癡 +发癡 發癡 +发癣 髮癬 +发癫 發癲 +发白 發白 +发白时 發白時 +发的 發的 +发皇 發皇 +发皓齿 發皓齒 +发监 發監 +发直 發直 +发眩 發眩 +发矢 發矢 +发短信 發短信 +发短心长 髮短心長 +发石车 發石車 +发砲 發砲 +发硎 發硎 +发硎新试 發硎新試 +发硬 發硬 +发硬时 發硬時 +发神经 發神經 +发神经病 發神經病 +发祥 發祥 +发祥地 發祥地 +发票 發票 +发禁 髮禁 +发福 發福 +发科 發科 +发科打诨 發科打諢 +发积 發積 +发稿 發稿 +发稿时 發稿時 +发窘 發窘 +发端 發端 +发端词 發端詞 +发笑 發笑 +发笔 發筆 +发笺 髮箋 +发策 發策 +发策决科 發策決科 +发签 發籤 +发箍 髮箍 +发箧 發篋 +发箭 發箭 +发簪 髮簪 +发籤 發籤 +发粉 發粉 +发糕 發糕 +发紫 發紫 +发絲 髮絲 +发红 發紅 +发纱 髮紗 +发绀 發紺 +发结 髮結 +发给 發給 +发绿 發綠 +发缨 髮纓 +发网 髮網 +发老狠 發老狠 +发聋振聩 發聾振聵 +发肤 髮膚 +发育 發育 +发育不良 發育不良 +发育成 發育成 +发育期 發育期 +发育条件 發育條件 +发育生物学 發育生物學 +发肿 發腫 +发胀 發脹 +发胀感 發脹感 +发胖 發胖 +发胡 發胡 +发胶 髮膠 +发脚 髮腳 +发脱 發脫 +发脱口齿 發脫口齒 +发脾寒 發脾寒 +发脾气 發脾氣 +发腊 髮臘 +发自 發自 +发自內心 發自內心 +发自肺腑 發自肺腑 +发臭 發臭 +发船 發船 +发色 髮色 +发色勒 髮色勒 +发花 發花 +发芽 發芽 +发芽势 發芽勢 +发芽率 發芽率 +发草 發草 +发草帖 發草帖 +发菜 髮菜 +发落 發落 +发蒙 發矇 +发蒙振落 發蒙振落 +发蓝 發藍 +发蔫 發蔫 +发薪 發薪 +发薪水 發薪水 +发虚 發虛 +发蜡 髮蠟 +发蜡条 髮蠟條 +发行 發行 +发行人 發行人 +发行商 發行商 +发行备忘录 發行備忘錄 +发行日 發行日 +发行权 發行權 +发行红利股 發行紅利股 +发行者 發行者 +发行量 發行量 +发行量加权股价指数 發行量加權股價指數 +发行额 發行額 +发行首日 發行首日 +发表 發表 +发表会 發表會 +发表出来 發表出來 +发表声明 發表聲明 +发表意见 發表意見 +发表欲 發表慾 +发表演讲 發表演講 +发见 發見 +发觉 發覺 +发觉出 發覺出 +发觉到 發覺到 +发解 發解 +发言 發言 +发言中肯 發言中肯 +发言人 發言人 +发言人卡 發言人卡 +发言人室 發言人室 +发言发语 發言發語 +发言台 發言臺 +发言权 發言權 +发言条 發言條 +发言者 發言者 +发言遣辞 發言遣辭 +发誓 發誓 +发讪 發訕 +发议论 發議論 +发话 發話 +发话器 發話器 +发诨子 發諢子 +发语词 發語詞 +发语辞 發語辭 +发课 發課 +发财 發財 +发财票 發財票 +发财致富 發財致富 +发财金 發財金 +发货 發貨 +发货单 發貨單 +发质 髮質 +发贴 發貼 +发起 發起 +发起人 發起人 +发起来 發起來 +发起烧来 發起燒來 +发越 發越 +发足 發足 +发跡 發跡 +发踊冲冠 髮踊沖冠 +发踪指示 發蹤指示 +发蹙 發蹙 +发躁 發躁 +发身 發身 +发车 發車 +发轫 發軔 +发软 發軟 +发轿 發轎 +发辫 髮辮 +发达 發達 +发达为 發達爲 +发达到 發達到 +发达国 發達國 +发达国家 發達國家 +发达地区 發達地區 +发达起来 發達起來 +发过 發過 +发过去 發過去 +发过来 發過來 +发运 發運 +发还 發還 +发进 發進 +发进去 發進去 +发进来 發進來 +发迹 發跡 +发迹变泰 發跡變泰 +发送 發送 +发送功率 發送功率 +发送器 發送器 +发送机 發送機 +发遣 發遣 +发配 發配 +发酒疯 發酒瘋 +发酒风 發酒風 +发酵 發酵 +发酵乳 發酵乳 +发酵乳酸 發酵乳酸 +发酵出来 發酵出來 +发酵粉 發酵粉 +发酵饲料 發酵飼料 +发酸 發酸 +发采扬明 發采揚明 +发野 發野 +发量 髮量 +发针 髮針 +发钗 髮釵 +发长 髮長 +发问 發問 +发问者 發問者 +发间 髮間 +发闷 發悶 +发闹 發鬧 +发阴天 發陰天 +发际 髮際 +发隐擿伏 發隱擿伏 +发难 發難 +发雕 髮雕 +发霉 發黴 +发霜 髮霜 +发露 發露 +发青 發青 +发面 發麪 +发鞍 發鞍 +发音 發音 +发音体 發音體 +发音合作人 發音合作人 +发音器 發音器 +发音器官 發音器官 +发音学 發音學 +发音方法 發音方法 +发音部位 發音部位 +发音障碍 發音障礙 +发頂 髮頂 +发須 髮鬚 +发须俱 髮鬚俱 +发须已 髮鬚已 +发须斑 髮鬚斑 +发须皆 髮鬚皆 +发须都 髮鬚都 +发颤 發顫 +发风 發風 +发风骂坐 發風罵坐 +发飘 發飄 +发飙 發飆 +发飚 發飈 +发饰 髮飾 +发饷 發餉 +发香 髮香 +发马 發馬 +发骚 發騷 +发高烧 發高燒 +发高热 發高熱 +发髻 髮髻 +发鬓 髮鬢 +发麻 發麻 +发黄 發黃 +发黏 發黏 +发黑 發黑 +叔于田 叔于田 +叔梁纥 叔梁紇 +取之不尽 取之不盡 +取之不尽用之不竭 取之不盡用之不竭 +取了 取了 +取信于 取信於 +取信于人 取信於人 +取值范围 取值範圍 +取决于 取決於 +取出 取出 +取出来 取出來 +取向 取向 +取回 取回 +取回去 取回去 +取回来 取回來 +取得一致 取得一致 +取得胜利 取得勝利 +取才 取才 +取材于 取材於 +取法于 取法於 +取胜 取勝 +取舍 取捨 +取舍不定 取捨不定 +取舍之间 取捨之間 +取舍难定 取捨難定 +取药 取藥 +取阳谷 取陽谷 +受不了 受不了 +受了 受了 +受人之托 受人之託 +受制 受制 +受制于 受制於 +受制于人 受制於人 +受命于天 受命於天 +受困 受困 +受夠了 受夠了 +受尽 受盡 +受尽压迫 受盡壓迫 +受尽折磨 受盡折磨 +受得了 受得了 +受托 受託 +受托人 受託人 +受托者 受託者 +受折磨 受折磨 +受理 受理 +受用不尽 受用不盡 +受聘于 受聘於 +受阻于 受阻於 +受限于 受限於 +受难曲 受難曲 +受骗上当 受騙上當 +变不了 變不了 +变不出花样 變不出花樣 +变丑 變醜 +变个 變個 +变了 變了 +变了又变 變了又變 +变价 變價 +变修 變修 +变出 變出 +变出来 變出來 +变动汇率 變動匯率 +变化万端 變化萬端 +变化范围 變化範圍 +变回 變回 +变回去 變回去 +变回来 變回來 +变奏曲 變奏曲 +变尽方法 變盡方法 +变异型克雅氏症 變異型克雅氏症 +变异系数 變異係數 +变形虫 變形蟲 +变征 變徵 +变征之声 變徵之聲 +变征之音 變徵之音 +变性手术 變性手術 +变性气团 變性氣團 +变暗 變暗 +变松 變鬆 +变相加价 變相加價 +变种 變種 +变种人 變種人 +变脏 變髒 +变质岩 變質岩 +变速杆 變速桿 +变造出 變造出 +变髒 變髒 +变魔术 變魔術 +叙事曲 敘事曲 +叙别 敘別 +叙录 敘錄 +叙述出来 敘述出來 +叛党 叛黨 +叠了 疊了 +叠出 疊出 +叠出去 疊出去 +叠出来 疊出來 +叠合 疊合 +叠层岩 疊層岩 +叠彩区 疊彩區 +口仇 口仇 +口出 口出 +口出不逊 口出不遜 +口出恶言 口出惡言 +口出秽言 口出穢言 +口占 口占 +口布 口布 +口干 口乾 +口干舌燥 口乾舌燥 +口彩 口彩 +口念 口唸 +口愿 口願 +口才 口才 +口才好 口才好 +口才辨给 口才辨給 +口技表演者 口技表演者 +口服药 口服藥 +口杯 口杯 +口燥唇干 口燥脣乾 +口腔里 口腔裏 +口腹之欲 口腹之慾 +口血未干 口血未乾 +口语字词识别 口語字詞識別 +口述出来 口述出來 +口述历史 口述歷史 +口里 口裏 +口钟 口鐘 +古书云 古書云 +古云 古云 +古今注 古今注 +古典艺术 古典藝術 +古切里 古切里 +古制 古制 +古巴共产党 古巴共產黨 +古弦 古絃 +古書云 古書云 +古朴 古樸 +古杰拉尔 古傑拉爾 +古杰拉特邦 古傑拉特邦 +古板 古板 +古柯叶 古柯葉 +古柯咸 古柯鹹 +古游 古遊 +古腾堡计划 古騰堡計劃 +古語云 古語云 +古语云 古語云 +古迹 古蹟 +古里古怪 古里古怪 +古钟 古鐘 +古钟表 古鐘錶 +句践复国 句踐復國 +另一回 另一回 +另一回事 另一回事 +另一方面 另一方面 +另一种 另一種 +另一面 另一面 +另于 另於 +另借 另借 +另开生面 另開生面 +另当别论 另當別論 +另方面 另方面 +另谋出路 另謀出路 +另谋发展 另謀發展 +另起烟爨 另起煙爨 +另辟 另闢 +另辟新径 另闢新徑 +另辟蹊径 另闢蹊徑 +叨念 叨唸 +叩出 叩出 +叩头虫 叩頭蟲 +叩钟 叩鐘 +只不过 只不過 +只不过几年前 只不過幾年前 +只不过是 只不過是 +只为了 只爲了 +只买 只買 +只买到 只買到 +只争旦夕 只爭旦夕 +只于 只於 +只产 只產 +只亮 只亮 +只亮出 只亮出 +只亮到 只亮到 +只今 只今 +只从 只從 +只会 只會 +只会到 只會到 +只会在 只會在 +只传 只傳 +只传出 只傳出 +只住 只住 +只余 只餘 +只作 只作 +只借 只借 +只借不还 只借不還 +只借到 只借到 +只做 只做 +只停 只停 +只养 只養 +只再 只再 +只写 只寫 +只写出 只寫出 +只写到 只寫到 +只写在 只寫在 +只冲 只衝 +只准 只准 +只凭 只憑 +只分 只分 +只刊 只刊 +只判 只判 +只剩 只剩 +只剩下 只剩下 +只办 只辦 +只加 只加 +只加到 只加到 +只动 只動 +只包 只包 +只卖 只賣 +只占 只佔 +只占到 只佔到 +只占卜 只占卜 +只占吉 只占吉 +只占神问卜 只占神問卜 +只占算 只占算 +只印 只印 +只去 只去 +只发 只發 +只受 只受 +只受到 只受到 +只变 只變 +只可 只可 +只可以 只可以 +只可在 只可在 +只可意会不可言传 只可意會不可言傳 +只叹 只嘆 +只吃 只吃 +只合 只合 +只含 只含 +只听 只聽 +只听到 只聽到 +只和 只和 +只唱 只唱 +只唱出 只唱出 +只唱到 只唱到 +只喊 只喊 +只喝 只喝 +只喝到 只喝到 +只回 只回 +只回到 只回到 +只回去 只回去 +只回来 只回來 +只因 只因 +只因为 只因爲 +只图 只圖 +只在 只在 +只坐 只坐 +只声不出 隻聲不出 +只多 只多 +只多不少 只多不少 +只够 只夠 +只夠到 只夠到 +只夠在 只夠在 +只套 只套 +只好 只好 +只好去 只好去 +只好在 只好在 +只好来 只好來 +只字 隻字 +只字不提 隻字不提 +只字片纸 隻字片紙 +只字片言 隻字片言 +只字片语 隻字片語 +只学 只學 +只学会 只學會 +只学到 只學到 +只守 只守 +只守不攻 只守不攻 +只守到 只守到 +只定 只定 +只害 只害 +只对 只對 +只封 只封 +只射 只射 +只射到 只射到 +只将 只將 +只尽 只盡 +只尽到 只盡到 +只差 只差 +只带 只帶 +只帮 只幫 +只帮忙 只幫忙 +只应 只應 +只延 只延 +只开 只開 +只开出 只開出 +只开到 只開到 +只开去 只開去 +只开回 只開回 +只开来 只開來 +只当 只當 +只录 只錄 +只录到 只錄到 +只影 隻影 +只影全无 隻影全無 +只待 只待 +只得 只得 +只得到 只得到 +只念 只念 +只怕 只怕 +只怕会 只怕會 +只怕是 只怕是 +只怪 只怪 +只想 只想 +只想出 只想出 +只想到 只想到 +只想去 只想去 +只想来 只想來 +只愿 只願 +只愿意 只願意 +只懂 只懂 +只懂得 只懂得 +只成 只成 +只戴 只戴 +只手 隻手 +只手单拳 隻手單拳 +只手擎天 隻手擎天 +只手空拳 隻手空拳 +只手遮天 隻手遮天 +只打 只打 +只找 只找 +只找出 只找出 +只找到 只找到 +只把 只把 +只报 只報 +只抱 只抱 +只拜 只拜 +只拼 只拼 +只挑 只挑 +只挡 只擋 +只捉 只捉 +只捉到 只捉到 +只排 只排 +只接 只接 +只接到 只接到 +只提 只提 +只插 只插 +只插到 只插到 +只搬 只搬 +只摆 只擺 +只撞 只撞 +只收 只收 +只收到 只收到 +只放 只放 +只教 只教 +只敢 只敢 +只数 只數 +只数到 只數到 +只日 隻日 +只是 只是 +只是为了 只是爲了 +只是会 只是會 +只是在 只是在 +只是有 只是有 +只替 只替 +只有 只有 +只有出的气没有进的气 只有出的氣沒有進的氣 +只有在 只有在 +只来 只來 +只来到 只來到 +只査 只查 +只査出 只查出 +只査到 只查到 +只欠东风 只欠東風 +只此一家别无分店 只此一家別無分店 +只比 只比 +只求 只求 +只求无过 只求無過 +只求自保 只求自保 +只派 只派 +只流 只流 +只流出 只流出 +只流到 只流到 +只涂 只塗 +只消 只消 +只漏 只漏 +只漏出 只漏出 +只漏到 只漏到 +只演 只演 +只点 只點 +只照 只照 +只照到 只照到 +只煮 只煮 +只爲 只爲 +只猜 只猜 +只猜出 只猜出 +只猜到 只猜到 +只玩 只玩 +只甚 只甚 +只用 只用 +只用到 只用到 +只画 只畫 +只留 只留 +只留下 只留下 +只留到 只留到 +只看 只看 +只看出 只看出 +只看到 只看到 +只眼 隻眼 +只眼独具 隻眼獨具 +只睡 只睡 +只睡到 只睡到 +只知其一不知其二 只知其一不知其二 +只知有己不知有人 只知有己不知有人 +只砍 只砍 +只种 只種 +只租 只租 +只租不买 只租不買 +只租不卖 只租不賣 +只称 只稱 +只穿 只穿 +只立 隻立 +只站 只站 +只站到 只站到 +只等 只等 +只答 只答 +只管 只管 +只管出 只管出 +只管到 只管到 +只管去 只管去 +只管在 只管在 +只管来 只管來 +只索 只索 +只红 只紅 +只红到 只紅到 +只约 只約 +只经 只經 +只经过 只經過 +只编 只編 +只缝 只縫 +只罚 只罰 +只考 只考 +只考出 只考出 +只考到 只考到 +只聘 只聘 +只肯 只肯 +只能 只能 +只能在 只能在 +只能有 只能有 +只花 只花 +只补 只補 +只被 只被 +只装 只裝 +只要 只要 +只要会 只要會 +只要在 只要在 +只要是 只要是 +只要有 只要有 +只要能 只要能 +只见 只見 +只见树木 只見樹木 +只言片字 隻言片字 +只言片语 隻言片語 +只订 只訂 +只认钱不认人 只認錢不認人 +只让 只讓 +只让出 只讓出 +只让到 只讓到 +只记 只記 +只记到 只記到 +只记在 只記在 +只记得 只記得 +只讲 只講 +只讲出 只講出 +只讲到 只講到 +只许 只許 +只许州官放火不许百姓点灯 只許州官放火不許百姓點燈 +只许成功 只許成功 +只设 只設 +只设到 只設到 +只设在 只設在 +只说 只說 +只说不做 只說不做 +只说出 只說出 +只说到 只說到 +只说是 只說是 +只读 只讀 +只调 只調 +只费 只費 +只赌 只賭 +只赔 只賠 +只赚 只賺 +只赚到 只賺到 +只赢 只贏 +只赢不输 只贏不輸 +只走 只走 +只走到 只走到 +只赶 只趕 +只赶出 只趕出 +只赶到 只趕到 +只赶去 只趕去 +只赶回 只趕回 +只赶来 只趕來 +只跌 只跌 +只跟 只跟 +只跟到 只跟到 +只跟去 只跟去 +只跟在 只跟在 +只跟来 只跟來 +只跳 只跳 +只踢 只踢 +只踩 只踩 +只踩到 只踩到 +只身 隻身 +只身一人 隻身一人 +只身上已 只身上已 +只身上无 只身上無 +只身上有 只身上有 +只身上没 只身上沒 +只身上的 只身上的 +只身孤影 隻身孤影 +只转 只轉 +只转到 只轉到 +只轮不反 隻輪不反 +只轮不返 隻輪不返 +只轰 只轟 +只载 只載 +只输 只輸 +只输到 只輸到 +只达 只達 +只过 只過 +只过去 只過去 +只过来 只過來 +只进 只進 +只进到 只進到 +只追 只追 +只追到 只追到 +只追回 只追回 +只送 只送 +只送不卖 只送不賣 +只通 只通 +只通到 只通到 +只道 只道 +只配 只配 +只采 只採 +只采到 只採到 +只采声 只採聲 +只重衣衫不重人 只重衣衫不重人 +只量 只量 +只量出 只量出 +只量到 只量到 +只铺 只鋪 +只销 只銷 +只镀 只鍍 +只问 只問 +只闯 只闖 +只闯出 只闖出 +只闯到 只闖到 +只闻 只聞 +只防 只防 +只降 只降 +只降到 只降到 +只限 只限 +只限于 只限於 +只限到 只限到 +只限在 只限在 +只陪 只陪 +只需 只需 +只需要 只需要 +只露 只露 +只露出 只露出 +只露到 只露到 +只靠 只靠 +只须 只須 +只顾 只顧 +只顾到 只顧到 +只顾在 只顧在 +只领 只領 +只领到 只領到 +只飞 只飛 +只鸡斗酒 只雞斗酒 +只鸡絮酒 隻雞絮酒 +叫个 叫個 +叫了 叫了 +叫价 叫價 +叫出 叫出 +叫出去 叫出去 +叫出声 叫出聲 +叫出来 叫出來 +叫回 叫回 +叫回去 叫回去 +叫回来 叫回來 +叫板 叫板 +召回 召回 +召幸 召幸 +叮人战术 叮人戰術 +叮叮当当 叮叮噹噹 +叮叮当当的婆娘 叮叮噹噹的婆娘 +叮当 叮噹 +叮当作响 叮噹作響 +叮当响 叮噹響 +叮当声 叮噹聲 +可了不得 可了不得 +可于 可於 +可仑坡 可侖坡 +可以克制 可以剋制 +可供参考 可供參考 +可免于 可免於 +可别 可別 +可变化合价 可變化合價 +可可托海 可可托海 +可可托海镇 可可托海鎮 +可叹 可嘆 +可向 可向 +可周 可週 +可喜娘 可喜娘 +可回收 可回收 +可好了 可好了 +可少不了 可少不了 +可展曲面 可展曲面 +可干制 可乾製 +可干拭 可乾拭 +可干饮 可乾飲 +可当 可當 +可怜虫 可憐蟲 +可恶 可惡 +可愿 可願 +可愿意 可願意 +可憎娘 可憎娘 +可憎才 可憎才 +可持续发展 可持續發展 +可操作的艺术 可操作的藝術 +可擦写可编程只读存储器 可擦寫可編程只讀存儲器 +可望取胜者 可望取勝者 +可欲 可欲 +可紧可松 可緊可鬆 +可结合性 可結合性 +可转换同位素 可轉換同位素 +可采 可採 +可鉴 可鑑 +台上 臺上 +台下 臺下 +台东 臺東 +台东人 臺東人 +台东区 臺東區 +台东县 臺東縣 +台东县长 臺東縣長 +台东大学 臺東大學 +台东市 臺東市 +台东线 臺東線 +台两 臺兩 +台中 臺中 +台中人 臺中人 +台中区 臺中區 +台中县 臺中縣 +台中县市 臺中縣市 +台中商专 臺中商專 +台中场 臺中場 +台中市 臺中市 +台中市人 臺中市人 +台中市文 臺中市文 +台中师范 臺中師範 +台中师范学院 臺中師範學院 +台中店 臺中店 +台中敎育大学 臺中教育大學 +台中港 臺中港 +台中港路 臺中港路 +台中盆地 臺中盆地 +台中站 臺中站 +台中讯 臺中訊 +台企联 臺企聯 +台企银 臺企銀 +台佟 臺佟 +台候 臺候 +台儿庄 臺兒莊 +台光 臺光 +台军 臺軍 +台凤 臺鳳 +台凳 檯凳 +台函 臺函 +台制 臺製 +台制品 臺製品 +台前 臺前 +台前县 臺前縣 +台前台后 臺前臺後 +台办 臺辦 +台北 臺北 +台北人 臺北人 +台北区 臺北區 +台北县 臺北縣 +台北地院 臺北地院 +台北场 臺北場 +台北城 臺北城 +台北大学 臺北大學 +台北客 臺北客 +台北市 臺北市 +台北市市 臺北市市 +台北市立 臺北市立 +台北市长 臺北市長 +台北市队 臺北市隊 +台北师院 臺北師院 +台北护专 臺北護專 +台北捷运 臺北捷運 +台北桥 臺北橋 +台北港 臺北港 +台北盆地 臺北盆地 +台北站 臺北站 +台北讯 臺北訊 +台北队 臺北隊 +台华轮 臺華輪 +台南 臺南 +台南人 臺南人 +台南区 臺南區 +台南县 臺南縣 +台南县市 臺南縣市 +台南大学 臺南大學 +台南孔庙 臺南孔廟 +台南市 臺南市 +台南府 臺南府 +台南站 臺南站 +台历 檯曆 +台压版 臺壓版 +台台 臺臺 +台号 臺號 +台司 臺司 +台后 臺後 +台启 臺啓 +台命 臺命 +台和 臺和 +台商 臺商 +台商圈 臺商圈 +台啤队 臺啤隊 +台地 臺地 +台场 臺場 +台型 臺型 +台城 臺城 +台基 臺基 +台塑 臺塑 +台墩 臺墩 +台大 臺大 +台大医院 臺大醫院 +台大学生 臺大學生 +台女 臺女 +台妹 臺妹 +台委 臺委 +台媒 臺媒 +台子 臺子 檯子 +台子女 臺子女 +台子孙 臺子孫 +台孙 臺孫 +台孩 臺孩 +台安 臺安 檯安 +台安县 臺安縣 +台客 臺客 +台客呛辣 臺客嗆辣 +台客舞 臺客舞 +台尺 臺尺 +台山 台山 +台山市 台山市 +台峪 臺峪 +台州 台州 +台州地区 台州地區 +台州市 台州市 +台币 臺幣 +台布 檯布 +台布下 檯布下 +台师大 臺師大 +台帘 臺簾 +台席 臺席 +台庆 臺慶 +台座 臺座 +台开 臺開 +台式 臺式 +台式机 臺式機 +台意 臺意 +台意怒 臺意怒 +台成 臺成 +台扇 檯扇 +台拉维夫 臺拉維夫 +台指期 臺指期 +台收 臺收 +台数 臺數 +台文 臺文 +台斤 臺斤 +台新 臺新 +台新金 臺新金 +台新银 臺新銀 +台日 臺日 +台旨 臺旨 +台期指 臺期指 +台本 臺本 +台机 臺機 +台柱 臺柱 +台榭 臺榭 +台槐 臺槐 +台步 臺步 +台水澎运 臺水澎運 +台江 臺江 +台江区 臺江區 +台江县 臺江縣 +台汽 臺汽 +台汽客运 臺汽客運 +台海 臺海 +台海两岸 臺海兩岸 +台港 臺港 +台港澳侨 臺港澳僑 +台湾 臺灣 +台湾世界展望会 臺灣世界展望會 +台湾人 臺灣人 +台湾光复 臺灣光復 +台湾光复节 臺灣光復節 +台湾共和国 臺灣共和國 +台湾关系法 臺灣關係法 +台湾凤蝶 臺灣鳳蝶 +台湾化 臺灣化 +台湾区 臺灣區 +台湾台 臺灣台 +台湾史 臺灣史 +台湾叶鼻蝠 臺灣葉鼻蝠 +台湾味 臺灣味 +台湾团 臺灣團 +台湾国 臺灣國 +台湾国语 臺灣國語 +台湾土狗 臺灣土狗 +台湾地区 臺灣地區 +台湾大学 臺灣大學 +台湾大学附属医学院 臺灣大學附屬醫學院 +台湾女 臺灣女 +台湾学术网路 臺灣學術網路 +台湾岛 臺灣島 +台湾工业技术学院 臺灣工業技術學院 +台湾师范大学 臺灣師範大學 +台湾心 臺灣心 +台湾敎育学院 臺灣教育學院 +台湾散打王 臺灣散打王 +台湾新美术运动 臺灣新美術運動 +台湾日 臺灣日 +台湾日日新报 臺灣日日新報 +台湾杜鹃 臺灣杜鵑 +台湾歌 臺灣歌 +台湾民主自治同盟 臺灣民主自治同盟 +台湾汽车客运公司 臺灣汽車客運公司 +台湾海峡 臺灣海峽 +台湾海洋大学 臺灣海洋大學 +台湾海洋学院 臺灣海洋學院 +台湾版 臺灣版 +台湾犬 臺灣犬 +台湾猕猴桃 臺灣獼猴桃 +台湾玉 臺灣玉 +台湾环颈雉 臺灣環頸雉 +台湾电力 臺灣電力 +台湾电力公司 臺灣電力公司 +台湾电视公司 臺灣電視公司 +台湾疗养院 臺灣療養院 +台湾省 臺灣省 +台湾省政府教育厅 臺灣省政府教育廳 +台湾省政府林业试验所 臺灣省政府林業試驗所 +台湾省政府消防处 臺灣省政府消防處 +台湾省政府警政厅 臺灣省政府警政廳 +台湾省政府财政厅 臺灣省政府財政廳 +台湾省立 臺灣省立 +台湾省议会 臺灣省議會 +台湾社 臺灣社 +台湾神学院 臺灣神學院 +台湾科技大学 臺灣科技大學 +台湾籍 臺灣籍 +台湾米 臺灣米 +台湾粉蝶 臺灣粉蝶 +台湾精品 臺灣精品 +台湾糖业公司 臺灣糖業公司 +台湾红 臺灣紅 +台湾经验 臺灣經驗 +台湾肥料公司 臺灣肥料公司 +台湾航业公司 臺灣航業公司 +台湾艺术专科学校 臺灣藝術專科學校 +台湾茶 臺灣茶 +台湾菜 臺灣菜 +台湾蓝鹊 臺灣藍鵲 +台湾行 臺灣行 +台湾警察专科学校 臺灣警察專科學校 +台湾证券集中保管公司 臺灣證券集中保管公司 +台湾话 臺灣話 +台湾铝业 臺灣鋁業 +台湾铝业公司 臺灣鋁業公司 +台湾银行 臺灣銀行 +台湾队 臺灣隊 +台湾青年 臺灣青年 +台湾馆 臺灣館 +台湾高山族 臺灣高山族 +台澎 臺澎 +台澎金马 臺澎金馬 +台灯 檯燈 +台照 臺照 +台版 臺版 +台独 臺獨 +台独运动 臺獨運動 +台玻 臺玻 +台球 檯球 +台球桌 檯球桌 +台甫 臺甫 +台电 臺電 +台电公司 臺電公司 +台盆 臺盆 +台盏 臺盞 +台盘 檯盤 +台省 臺省 +台矶 臺磯 +台科大 臺科大 +台秤 檯秤 +台积电 臺積電 +台站 臺站 +台端 臺端 +台笔 檯筆 +台籍 臺籍 +台糖 臺糖 +台糖公司 臺糖公司 +台经院 臺經院 +台维斯杯 臺維斯杯 +台网 臺網 +台美 臺美 +台联 臺聯 +台联会 臺聯會 +台联党 臺聯黨 +台股 臺股 +台肥 臺肥 +台胜科 臺勝科 +台胞 臺胞 +台胞证 臺胞證 +台航 臺航 +台艺 臺藝 +台艺大 臺藝大 +台菜 臺菜 +台菜餐厅 臺菜餐廳 +台衔 臺銜 +台装 臺裝 +台装货 臺裝貨 +台西 臺西 +台西乡 臺西鄉 +台视 臺視 +台视公司 臺視公司 +台讳 臺諱 +台词 臺詞 +台语 臺語 +台语歌 臺語歌 +台账 臺賬 +台资 臺資 +台车 臺車 +台车道 臺車道 +台辅 臺輔 +台达 臺達 +台达电 臺達電 +台金 臺金 +台鉴 臺鑒 +台钟 檯鐘 +台钱 臺錢 +台钻 臺鑽 +台铁 臺鐵 +台铁局 臺鐵局 +台铝 臺鋁 +台银 臺銀 +台长 臺長 +台阁 臺閣 +台阁生风 臺閣生風 +台阶 臺階 +台面 檯面 +台面上 檯面上 +台面前 檯面前 +台音 臺音 +台风 颱風 +台风后 颱風後 +台风夜 颱風夜 +台风天 颱風天 +台风季 颱風季 +台风尾 颱風尾 +台风眼 颱風眼 +台风稳健 臺風穩健 +台风草 颱風草 +台风警报 颱風警報 +台风险 颱風險 +台风雨 颱風雨 +台马轮 臺馬輪 +台驾 臺駕 +叱吒风云 叱吒風雲 +叱咤乐坛 叱吒樂壇 +叱咤叱叱咤 叱吒叱叱吒 +叱咤叱咤叱咤咤 叱吒叱吒叱吒吒 +叱咤风云 叱吒風雲 +叱嗟风云 叱嗟風雲 +史克里亚宾 史克里亞賓 +史冬鹏 史冬鵬 +史勒德克 史勒德克 +史坦尼克 史坦尼克 +史坦布律克 史坦布律克 +史坦布瑞纳 史坦布瑞納 +史坦布莱纳 史坦布萊納 +史垂克 史垂克 +史塔克 史塔克 +史塔克豪斯 史塔克豪斯 +史崔克 史崔克 +史托克 史托克 +史托姆 史托姆 +史托威 史托威 +史托瑟 史托瑟 +史托腾柏格 史托騰柏格 +史托苏儿 史托蘇兒 +史査克 史查克 +史査克队 史查克隊 +史派克李 史派克李 +史派克特 史派克特 +史游 史游 +史瑞克 史瑞克 +史瑞波妮克 史瑞波妮克 +史瓦布 史瓦布 +史翠克 史翠克 +史莱克 史萊克 +史达克 史達克 +史迹 史蹟 +右分枝关系从句 右分枝關係從句 +右后 右後 +右后卫 右後衛 +右后方 右後方 +右戚 右戚 +右拐 右拐 +右面 右面 +叶一茜 葉一茜 +叶丁仁 葉丁仁 +叶下珠 葉下珠 +叶丛 葉叢 +叶两传 葉兩傳 +叶亮清 葉亮清 +叶代芝 葉代芝 +叶伟志 葉偉志 +叶佐禹 葉佐禹 +叶俊凯 葉俊凱 +叶俊荣 葉俊榮 +叶儿 葉兒 +叶全真 葉全真 +叶公好龙 葉公好龍 +叶公超 葉公超 +叶兰 葉蘭 +叶利钦 葉利欽 +叶南铭 葉南銘 +叶卡捷琳堡 葉卡捷琳堡 +叶卡捷琳娜 葉卡捷琳娜 +叶卡特琳娜堡 葉卡特琳娜堡 +叶原 葉原 +叶县 葉縣 +叶口蝠科 葉口蝠科 +叶可欣 葉可欣 +叶可蓁 葉可蓁 +叶叶 葉葉 +叶叶琹 葉叶琹 +叶名琛 葉名琛 +叶君璋 葉君璋 +叶咏捷 葉詠捷 +叶国兴 葉國興 +叶圣陶 葉聖陶 +叶块繁殖 葉塊繁殖 +叶城县 葉城縣 +叶堂 葉堂 +叶天士 葉天士 +叶子 葉子 +叶子列 葉子列 +叶子戏 葉子戲 +叶子杰 葉子杰 +叶子格 葉子格 +叶子烟 葉子菸 +叶子纲 葉子綱 +叶宗留 葉宗留 +叶宗贤 葉宗賢 +叶宜津 葉宜津 +叶宪祖 葉憲祖 +叶尔勤 葉爾勤 +叶尔羌 葉爾羌 +叶尔羌河 葉爾羌河 +叶尔辛 葉爾辛 +叶尖 葉尖 +叶尼基河 葉尼基河 +叶尼塞河 葉尼塞河 +叶庆元 葉慶元 +叶序 葉序 +叶形 葉形 +叶彦伯 葉彥伯 +叶彰廷 葉彰廷 +叶德辉 葉德輝 +叶志仙 葉志仙 +叶志远 葉志遠 +叶恭弘 叶恭弘 +叶惠青 葉惠青 +叶慈 葉慈 +叶成忠 葉成忠 +叶拱 葉拱 +叶挺 葉挺 +叶政彦 葉政彥 +叶文贵 葉文貴 +叶斑 葉斑 +叶斑病 葉斑病 +叶斯沛森 葉斯沛森 +叶昌桐 葉昌桐 +叶明顺 葉明順 +叶景栋 葉景棟 +叶杰生 葉傑生 +叶枝 葉枝 +叶柄 葉柄 +叶树 葉樹 +叶树姗 葉樹姍 +叶根吉 葉根吉 +叶正玲 葉正玲 +叶步梁 葉步樑 +叶永烈 葉永烈 +叶永骞 葉永騫 +叶江川 葉江川 +叶泰兴 葉泰興 +叶泽山 葉澤山 +叶清照 葉清照 +叶湘伦 葉湘倫 +叶炳强 葉炳強 +叶片 葉片 +叶片状 葉片狀 +叶状 葉狀 +叶状体 葉狀體 +叶状植物 葉狀植物 +叶王 葉王 +叶甜菜 葉甜菜 +叶盛兰 葉盛蘭 +叶硕堂 葉碩堂 +叶礼庭 葉禮庭 +叶紫华 葉紫華 +叶红素 葉紅素 +叶绍锜 葉紹錡 +叶绿体 葉綠體 +叶绿体基质 葉綠體基質 +叶绿素 葉綠素 +叶缘 葉緣 +叶美君 葉美君 +叶羿君 葉羿君 +叶耳 葉耳 +叶肉 葉肉 +叶肥 葉肥 +叶脉 葉脈 +叶脉序 葉脈序 +叶脤 葉脤 +叶腋 葉腋 +叶舌 葉舌 +叶芽 葉芽 +叶茎 葉莖 +叶菊兰 葉菊蘭 +叶菜类 葉菜類 +叶落归根 葉落歸根 +叶落归秋 葉落歸秋 +叶落知秋 葉落知秋 +叶落粪本 葉落糞本 +叶蕴仪 葉蘊儀 +叶蜂 葉蜂 +叶蜡石 葉蠟石 +叶蝉 葉蟬 +叶语 葉語 +叶赛莺 葉賽鶯 +叶赤铁路 葉赤鐵路 +叶跡 葉跡 +叶轮 葉輪 +叶轮机械 葉輪機械 +叶轴 葉軸 +叶适 葉適 +叶选平 葉選平 +叶酸 葉酸 +叶金川 葉金川 +叶针 葉針 +叶锈病 葉鏽病 +叶长龙 葉長龍 +叶门 葉門 +叶门共和国 葉門共和國 +叶闲花 葉閒花 +叶面 葉面 +叶面对称 葉面對稱 +叶面施肥 葉面施肥 +叶鞘 葉鞘 +叶音 叶音 +叶韵 叶韻 +叶黄素 葉黃素 +叶鼻蝠 葉鼻蝠 +号寒啼饥 號寒啼飢 +号志 號誌 +号志机 號誌機 +号志灯 號誌燈 +号挂子 號掛子 +号板 號板 +号码布 號碼布 +号舍 號舍 +司令台 司令臺 +司天台 司天臺 +司法制度 司法制度 +叹为 嘆爲 +叹为观止 歎爲觀止 +叹之 嘆之 +叹了 嘆了 +叹号 歎號 +叹喟 嘆喟 +叹声 嘆聲 +叹息 嘆息 +叹惋 嘆惋 +叹惜 嘆惜 +叹曰 嘆曰 +叹服 歎服 +叹气 嘆氣 +叹绝 歎絕 +叹羡 歎羨 +叹老 嘆老 +叹词 嘆詞 +叹赏 歎賞 +叹道 嘆道 +吁了 吁了 +吁俞 吁俞 +吁叹 吁嘆 +吁吁 吁吁 +吁咈 吁咈 +吁咈都俞 吁咈都俞 +吁嗟 吁嗟 +吁嘘 吁噓 +吁天 籲天 +吁气 吁氣 +吁求 籲求 +吁请 籲請 +吃一顿挨一顿 吃一頓挨一頓 +吃不了 吃不了 +吃不出 吃不出 +吃不出来 吃不出來 +吃了 吃了 +吃了定心丸 吃了定心丸 +吃了秤砣 吃了秤砣 +吃了蜜蜂儿屎似的 吃了蜜蜂兒屎似的 +吃了饭 吃了飯 +吃亏上当 吃虧上當 +吃亏就是占便宜 吃虧就是佔便宜 +吃人一个蛋恩情无法断 吃人一個蛋恩情無法斷 +吃人虫 吃人蟲 +吃伤了 吃傷了 +吃几碗干饭 吃幾碗乾飯 +吃出 吃出 +吃合家欢 吃合家歡 +吃后悔药 吃後悔藥 +吃回头草 吃回頭草 +吃地面 吃地面 +吃姜 吃薑 +吃完面 吃完麪 +吃尽 吃盡 +吃尽当光 吃盡當光 +吃干了 吃乾了 +吃干醋 吃乾醋 +吃得了 吃得了 +吃得出 吃得出 +吃得出来 吃得出來 +吃挂络儿 吃掛絡兒 +吃敲才 吃敲才 +吃板刀面 吃板刀麪 +吃枪药 吃槍藥 +吃烟 吃煙 +吃药 吃藥 +吃药前 吃藥前 +吃药后 吃藥後 +吃药时 吃藥時 +吃豆干 吃豆乾 +吃辣面 吃辣麪 +吃过面 吃過麪 +吃里扒外 吃裏扒外 +吃里爬外 吃裏爬外 +吃钉板 吃釘板 +吃错药 吃錯藥 +吃闲话 吃閒話 +吃闲饭 吃閒飯 +吃面 吃麪 +吃饭傢伙 吃飯傢伙 +吃饭别忘了种谷人 吃飯別忘了種穀人 +吃饭家伙 吃飯家伙 +吃饱了饭撑的 吃飽了飯撐的 +吃饱没事干 吃飽沒事幹 +各不相同 各不相同 +各个 各個 +各个击破 各個擊破 +各人儿洗面儿各人儿光 各人兒洗面兒各人兒光 +各从其志 各從其志 +各借 各借 +各党 各黨 +各党派 各黨派 +各出 各出 +各别 各別 +各升 各升 +各厂 各廠 +各发 各發 +各吊 各吊 +各向 各向 +各向异性 各向異性 +各回 各回 +各回合 各回合 +各团 各團 +各团体 各團體 +各如其面 各如其面 +各尽 各盡 +各尽其用 各盡其用 +各尽所能 各盡所能 +各干各 各幹各 +各当 各當 +各念 各念 +各打五十板 各打五十板 +各方面 各方面 +各有千秋 各有千秋 +各有胜负 各有勝負 +各版面 各版面 +各种 各種 +各种事 各種事 +各种人 各種人 +各种各样 各種各樣 +各种颜色 各種顏色 +各签 各簽 +各类钟 各類鐘 +各系 各系 +各系所 各系所 +各级党委 各級黨委 +各胜 各勝 +各行其志 各行其志 +各谋出路 各謀出路 +各辟 各闢 +各辟蹊径 各闢蹊徑 +各里 各里 +各院系 各院系 +各须 各須 +合上 合上 +合下 合下 +合不合 合不合 +合不拢嘴 合不攏嘴 +合不来 合不來 +合中 閤中 +合久必分 合久必分 +合义复词 合義複詞 +合乎 合乎 +合乎逻辑 合乎邏輯 +合于 合於 +合于时宜 合于時宜 +合从 合從 +合付 合付 +合众 合衆 +合众为一 合衆爲一 +合众国 合衆國 +合众国际社 合衆國際社 +合众社 合衆社 +合众银行 合衆銀行 +合伙 合夥 +合伙人 合夥人 +合会 合會 +合传 合傳 +合住 合住 +合体 合體 +合体字 合體字 +合作 合作 +合作主义 合作主義 +合作伙伴 合作伙伴 +合作农场 合作農場 +合作化 合作化 +合作协议 合作協議 +合作商店 合作商店 +合作学 合作學 +合作市 合作市 +合作所 合作所 +合作无懈 合作無懈 +合作无间 合作無間 +合作案 合作案 +合作社 合作社 +合作署 合作署 +合作者 合作者 +合作节 合作節 +合作金库 合作金庫 +合借 合借 +合做 合做 +合儿 閤兒 +合八字 合八字 +合养 合養 +合准 合準 +合出 合出 +合击 合擊 +合刃 合刃 +合则两利 合則兩利 +合到 合到 +合券 合券 +合刻 合刻 +合剂 合劑 +合力 合力 +合办 合辦 +合十 合十 +合卺 合巹 +合历 合曆 +合发 合發 +合变 合變 +合口 合口 +合口元音 合口元音 +合口味 合口味 +合口呼 合口呼 +合叶 合葉 +合吃 合吃 +合吃族 合吃族 +合合 合合 +合同 合同 +合同各方 合同各方 +合同文字 合同文字 +合同法 合同法 +合后 合後 +合唱 合唱 +合唱团 合唱團 +合唱曲 合唱曲 +合唱队 合唱隊 +合嘴合舌 合嘴合舌 +合四乙尺工 合四乙尺工 +合围 合圍 +合在 合在 +合在一起 合在一起 +合声 合聲 +合夥人 合夥人 +合头 合頭 +合奏 合奏 +合奏团 合奏團 +合奏曲 合奏曲 +合契若神 合契若神 +合好 合好 +合婚 合婚 +合子 合子 +合子钱 合子錢 +合子饼 合子餅 +合宅 合宅 +合定 合定 +合宜 合宜 +合家 閤家 +合家大小 合家大小 +合家子 閤家子 +合家欢 閤家歡 +合局 合局 +合山市 合山市 +合川区 合川區 +合并 合併 +合并为 合併爲 +合并在 合併在 +合并成 合併成 +合并有 合併有 +合并案 合併案 +合并症 合併症 +合府 閤府 +合府上 閤府上 +合度 合度 +合式 合式 +合弦 合弦 +合弹 合彈 +合当 合當 +合当有事 合當有事 +合彩 合彩 +合影 合影 +合影留念 合影留念 +合得 合得 +合得来 合得來 +合心 合心 +合心合意 合心合意 +合恩角 合恩角 +合情 合情 +合情合理 合情合理 +合情理 合情理 +合意 合意 +合意儿 合意兒 +合成 合成 +合成乐器 合成樂器 +合成乳 合成乳 +合成代谢 合成代謝 +合成体 合成體 +合成作用 合成作用 +合成器 合成器 +合成数 合成數 +合成染料 合成染料 +合成树脂 合成樹脂 +合成橡胶 合成橡膠 +合成氨 合成氨 +合成法 合成法 +合成洗涤 合成洗滌 +合成洗涤剂 合成洗滌劑 +合成清洁剂 合成清潔劑 +合成物 合成物 +合成皮 合成皮 +合成石油 合成石油 +合成类固醇 合成類固醇 +合成纤维 合成纖維 +合成色素 合成色素 +合成词 合成詞 +合成语境 合成語境 +合成语音 合成語音 +合战 合戰 +合手 合手 +合扑 合撲 +合折 合折 +合报 合報 +合抱 合抱 +合拍 合拍 +合拢 合攏 +合指症 合指症 +合掌 合掌 +合掌瓜 合掌瓜 +合数 合數 +合族 合族 +合时 合時 +合时宜 合時宜 +合昏 合昏 +合是 合是 +合朔 合朔 +合本 合本 +合机 合機 +合杀 合殺 +合板 合板 +合板眼 合板眼 +合校 合校 +合格 合格 +合格率 合格率 +合格者 合格者 +合格证 合格證 +合格赛 合格賽 +合欢 合歡 +合欢山 合歡山 +合欢扇 合歡扇 +合欢结 合歡結 +合款 合款 +合气 合氣 +合气道 合氣道 +合水县 合水縣 +合江县 合江縣 +合江省 合江省 +合沓 合沓 +合法 合法 +合法化 合法化 +合法性 合法性 +合法斗争 合法鬥爭 +合注 合注 +合洗 合洗 +合派 合派 +合流 合流 +合流处 合流處 +合浦县 合浦縣 +合浦珠还 合浦珠還 +合浦还珠 合浦還珠 +合溜 合溜 +合演 合演 +合火 合火 +合照 合照 +合照留念 合照留念 +合爲 合爲 +合牵 合牽 +合独 合獨 +合班 合班 +合球 合球 +合理 合理 +合理化 合理化 +合理化作用 合理化作用 +合理合情 合理合情 +合理密植 合理密植 +合理布局 合理佈局 +合理性 合理性 +合理标 合理標 +合理错误 合理錯誤 +合璧 合璧 +合璧连珠 合璧連珠 +合瓣 合瓣 +合瓣花冠 合瓣花冠 +合生 合生 +合用 合用 +合盖 合蓋 +合眼 閤眼 +合眼摸象 合眼摸象 +合着 合着 +合租 合租 +合稀释 合稀釋 +合窆 合窆 +合站 合站 +合符 合符 +合签 合簽 +合算 合算 +合纤 合纖 +合约 合約 +合约书 合約書 +合约人 合約人 +合约价 合約價 +合约法 合約法 +合纵 合縱 +合纵连横 合縱連橫 +合组 合組 +合编 合編 +合缝 合縫 +合群 合羣 +合群性 合羣性 +合而为一 合而爲一 +合股 合股 +合肥 合肥 +合肥人 合肥人 +合肥县 合肥縣 +合肥工业大学 合肥工業大學 +合肥市 合肥市 +合胃口 合胃口 +合色鞋 合色鞋 +合苦 合苦 +合菜戴帽 合菜戴帽 +合营 合營 +合著 合著 +合著者 合著者 +合葬 合葬 +合补 合補 +合计 合計 +合计为 合計爲 +合订本 合訂本 +合议制 合議制 +合议庭 合議庭 +合该 合該 +合该有事 合該有事 +合请 合請 +合读 合讀 +合调 合調 +合谋 合謀 +合谐 合諧 +合谷 合谷 +合谷穴 合谷穴 +合购 合購 +合资 合資 +合资案 合資案 +合起 合起 +合起来 合起來 +合踢 合踢 +合踩 合踩 +合身 合身 +合辙 合轍 +合辙儿 合轍兒 +合辙押韵 合轍押韻 +合适 合適 +合通 合通 +合造 合造 +合逻辑 合邏輯 +合遝 合遝 +合醵 合醵 +合采 合採 +合金 合金 +合金元素 合金元素 +合金钢 合金鋼 +合钓 合釣 +合锯 合鋸 +合镜 合鏡 +合闸 合閘 +合阳县 合陽縣 +合零为整 合零爲整 +合面 合面 +合音 合音 +合领 合領 +合骑 合騎 +合髻 合髻 +合龙 合龍 +合龙门 合龍門 +吉丁当 吉丁當 +吉伯特氏症候群 吉伯特氏症候羣 +吉凶 吉凶 +吉凶庆吊 吉凶慶弔 +吉凶悔吝 吉凶悔吝 +吉凶未卜 吉凶未卜 +吉卜力工作室 吉卜力工作室 +吉卜赛 吉卜賽 +吉卜赛人 吉卜賽人 +吉卜龄 吉卜齡 +吉占 吉占 +吉尔库克 吉爾庫克 +吉尼普里 吉尼普里 +吉布兹 吉布茲 +吉布地 吉布地 +吉布地共和国 吉布地共和國 +吉布提 吉布提 +吉布森 吉布森 +吉普斯夸 吉普斯夸 +吉林师范大学 吉林師範大學 +吉田松阴 吉田松陰 +吉蔑 吉蔑 +吉蔑族 吉蔑族 +吉诺布里 吉諾布里 +吉里 吉里 +吉里巴斯 吉里巴斯 +吉里巴斯共和国 吉里巴斯共和國 +吊上 吊上 +吊上去 吊上去 +吊上来 吊上來 +吊下 吊下 +吊下去 吊下去 +吊下来 吊下來 +吊丧 弔喪 +吊丧问疾 弔喪問疾 +吊个 吊個 +吊书 弔書 +吊了 吊了 +吊伐 吊伐 +吊儿郎当 吊兒郎當 +吊兰 吊蘭 +吊具 吊具 +吊刑 吊刑 +吊到 吊到 +吊卷 吊卷 +吊去 吊去 +吊取 吊取 +吊古 弔古 +吊古寻幽 弔古尋幽 +吊吊 吊吊 +吊名 吊名 +吊唁 弔唁 +吊喉 弔喉 +吊喭 弔喭 +吊嗓 吊嗓 +吊嗓子 吊嗓子 +吊嘴 吊嘴 +吊场 吊場 +吊坠 吊墜 +吊塔 吊塔 +吊头 弔頭 +吊奠 弔奠 +吊好 吊好 +吊子 吊子 +吊子曰儿 吊子曰兒 +吊孝 弔孝 +吊客 弔客 +吊客眉 弔客眉 +吊宴 弔宴 +吊带 吊帶 +吊带衫 吊帶衫 +吊带裤 吊帶褲 +吊床 吊牀 +吊影 弔影 +吊得 吊得 +吊慰 弔慰 +吊扇 吊扇 +吊打 吊打 +吊扣 吊扣 吊釦 +吊拷 弔拷 +吊拷絣把 吊拷絣把 +吊拷绷扒 吊拷繃扒 +吊挂 吊掛 +吊挂在 吊掛在 +吊挂着 吊掛着 +吊撒 弔撒 +吊放声纳 吊放聲納 +吊文 弔文 +吊斗 吊斗 +吊旗 弔旗 +吊杆 吊杆 +吊杠 吊槓 +吊来吊去 吊來吊去 +吊架 吊架 +吊档裤 吊檔褲 +吊桥 吊橋 +吊桶 吊桶 +吊桶落在井里 吊桶落在井裏 +吊楼 吊樓 +吊死 吊死 +吊死问孤 弔死問孤 +吊死问疾 弔死問疾 +吊死鬼 吊死鬼 +吊死鬼搽粉 吊死鬼搽粉 +吊死鬼的裹脚布 吊死鬼的裹腳布 +吊毛 吊毛 +吊民 弔民 +吊民伐罪 弔民伐罪 +吊水 吊水 +吊灯 吊燈 +吊环 吊環 +吊球 吊球 +吊瓶族 吊瓶族 +吊盘 吊盤 +吊着 吊着 +吊祭 弔祭 +吊稍 吊稍 +吊窗 吊窗 +吊篮 吊籃 +吊索 吊索 +吊纸 弔紙 +吊线 吊線 +吊绳 吊繩 +吊者大悦 弔者大悅 +吊胃口 吊胃口 +吊脚 吊腳 +吊脚儿 吊腳兒 +吊脚儿事 弔腳兒事 +吊腰撒跨 弔腰撒跨 +吊膀子 吊膀子 +吊臂 吊臂 +吊衣架 吊衣架 +吊袜 吊襪 +吊袜带 吊襪帶 +吊装 吊裝 +吊裤 吊褲 +吊裤带 吊褲帶 +吊誉沽名 吊譽沽名 +吊词 弔詞 +吊诡 弔詭 +吊诡矜奇 弔詭矜奇 +吊谎 弔謊 +吊贺迎送 弔賀迎送 +吊走 吊走 +吊起 吊起 +吊起来 吊起來 +吊车 吊車 +吊车尾 吊車尾 +吊运 吊運 +吊钟 吊鐘 +吊钢丝 吊鋼絲 +吊钩 吊鉤 +吊铺 吊鋪 +吊销 吊銷 +吊销执照 吊銷執照 +吊门 吊門 +吊问 弔問 +吊颈 吊頸 +吊饰 吊飾 +吊鹤 弔鶴 +同一 同一 +同一个 同一個 +同一个世界同一个梦想 同一個世界同一個夢想 +同一人 同一人 +同一场 同一場 +同一型 同一型 +同一处 同一處 +同一家 同一家 +同一年 同一年 +同一座 同一座 +同一性 同一性 +同一所 同一所 +同一片 同一片 +同一班 同一班 +同一组 同一組 +同上 同上 +同下 同下 +同不同意 同不同意 +同业 同業 +同业公会 同業公會 +同业拆借 同業拆借 +同个 同個 +同中有异 同中有異 +同为 同爲 +同义 同義 +同义反复 同義反復 +同义字 同義字 +同义词 同義詞 +同义语 同義語 +同乐 同樂 +同乐会 同樂會 +同乡 同鄉 +同乡亲故 同鄉親故 +同乡会 同鄉會 +同事 同事 +同事家 同事家 +同于 同於 +同产 同產 +同享 同享 +同人 同人 +同人女 同人女 +同人志 同人誌 +同仁 同仁 +同仁县 同仁縣 +同仁堂 同仁堂 +同仇 同仇 +同仇敌忾 同仇敵愾 +同休共戚 同休共慼 +同伙 同夥 +同传耳麦 同傳耳麥 +同伴 同伴 +同位 同位 +同位素 同位素 +同位素分离 同位素分離 +同位素扫描 同位素掃描 +同位角 同位角 +同位语 同位語 +同住 同住 +同体 同體 +同余 同餘 +同余式 同餘式 +同余类 同餘類 +同侪 同儕 +同侪压力 同儕壓力 +同侪团体 同儕團體 +同侪审查 同儕審查 +同侪扶持 同儕扶持 +同侪检视 同儕檢視 +同侪谘商 同儕諮商 +同修 同修 +同做 同做 +同僚 同僚 +同光 同光 +同党 同黨 +同出 同出 +同出一源 同出一源 +同出一脉 同出一脈 +同出同进 同出同進 +同分 同分 +同分异构体 同分異構體 +同分异构物 同分異構物 +同分数 同分數 +同列 同列 +同到 同到 +同功一体 同功一體 +同动词 同動詞 +同化 同化 +同化作用 同化作用 +同区 同區 +同升 同升 +同卵 同卵 +同卵双生 同卵雙生 +同卵双胞胎 同卵雙胞胎 +同去 同去 +同县 同縣 +同参 同參 +同右 同右 +同号 同號 +同吃 同吃 +同吃同住 同吃同住 +同名 同名 +同名之累 同名之累 +同名同姓 同名同姓 +同名数 同名數 +同向 同向 +同命 同命 +同命鸟 同命鳥 +同命鸳鸯 同命鴛鴦 +同唱 同唱 +同喜 同喜 +同团 同團 +同国 同國 +同在 同在 +同地 同地 +同坐 同坐 +同型 同型 +同型性 同型性 +同型机 同型機 +同型配子 同型配子 +同堂 同堂 +同声 同聲 +同声一哭 同聲一哭 +同声之谊 同聲之誼 +同声传译 同聲傳譯 +同声异俗 同聲異俗 +同声相应 同聲相應 +同声翻译 同聲翻譯 +同天 同天 +同好 同好 +同姓 同姓 +同姓同名 同姓同名 +同字框 同字框 +同学 同學 +同学们 同學們 +同学会 同學會 +同学家 同學家 +同学录 同學錄 +同学路 同學路 +同安 同安 +同安区 同安區 +同安县 同安縣 +同安街 同安街 +同宗 同宗 +同宗同气 同宗同氣 +同定 同定 +同室 同室 +同室操戈 同室操戈 +同宿 同宿 +同寅 同寅 +同对 同對 +同尘 同塵 +同居 同居 +同居人 同居人 +同居各爨 同居各爨 +同屋 同屋 +同属 同屬 +同岁 同歲 +同州梆子 同州梆子 +同工 同工 +同工同酬 同工同酬 +同工异曲 同工異曲 +同工异调 同工異調 +同左 同左 +同席 同席 +同年 同年 +同年代 同年代 +同年同月 同年同月 +同年级 同年級 +同年而语 同年而語 +同庆 同慶 +同床 同牀 +同床异梦 同牀異夢 +同庚 同庚 +同度 同度 +同座 同座 +同异 同異 +同张 同張 +同归 同歸 +同归于尽 同歸於盡 +同归殊途 同歸殊途 +同当 同當 +同形词 同形詞 +同往 同往 +同德 同德 +同德县 同德縣 +同德同心 同德同心 +同心 同心 +同心僇力 同心僇力 +同心协力 同心協力 +同心县 同心縣 +同心合力 同心合力 +同心合意 同心合意 +同心同德 同心同德 +同心圆 同心圓 +同心圆理论 同心圓理論 +同心并力 同心並力 +同心戮力 同心戮力 +同心断金 同心斷金 +同心方胜儿 同心方勝兒 +同心结 同心結 +同心髻 同心髻 +同志 同志 +同志合道 同志合道 +同志天地 同志天地 +同志酒吧 同志酒吧 +同忧相救 同憂相救 +同态 同態 +同性 同性 +同性恋 同性戀 +同性恋恐惧症 同性戀恐懼症 +同性恋者 同性戀者 +同性恋酒吧 同性戀酒吧 +同性爱 同性愛 +同性相斥 同性相斥 +同恩 同恩 +同恶相助 同惡相助 +同恶相救 同惡相救 +同恶相求 同惡相求 +同恶相济 同惡相濟 +同情 同情 +同情心 同情心 +同情者 同情者 +同意 同意 +同意书 同意書 +同意权 同意權 +同意案 同意案 +同意票 同意票 +同感 同感 +同愿 同願 +同房 同房 +同房兄弟 同房兄弟 +同手同脚 同手同腳 +同打 同打 +同指 同指 +同排 同排 +同支 同支 +同改 同改 +同文 同文 +同文同种 同文同種 +同文算指 同文算指 +同文韵统 同文韻統 +同文馆 同文館 +同斜层 同斜層 +同方 同方 +同旁內角 同旁內角 +同族 同族 +同日 同日 +同日生 同日生 +同日而言 同日而言 +同日而语 同日而語 +同时 同時 +同时代 同時代 +同时候 同時候 +同时期 同時期 +同时语言学 同時語言學 +同是 同是 +同是天涯沦落人 同是天涯淪落人 +同月 同月 +同月同日 同月同日 +同有 同有 +同期 同期 +同期录音 同期錄音 +同机 同機 +同村 同村 +同条共贯 同條共貫 +同来 同來 +同来同往 同來同往 +同构 同構 +同枕共眠 同枕共眠 +同林鸟 同林鳥 +同校 同校 +同样 同樣 +同样会 同樣會 +同样在 同樣在 +同样地 同樣地 +同样是 同樣是 +同根 同根 +同案 同案 +同案犯 同案犯 +同桌 同桌 +同梦 同夢 +同梯 同梯 +同榜 同榜 +同榻 同榻 +同欢 同歡 +同欢同赏 同歡同賞 +同款 同款 +同正 同正 +同步 同步 +同步传输 同步傳輸 +同步加速器 同步加速器 +同步卫星 同步衛星 +同步录音 同步錄音 +同步数位阶层 同步數位階層 +同步电动 同步電動 +同步辐射仪 同步輻射儀 +同步辐射加速器 同步輻射加速器 +同步辐射研究中心 同步輻射研究中心 +同步进行 同步進行 +同母 同母 +同母异父 同母異父 +同气 同氣 +同气之光 同氣之光 +同气之情 同氣之情 +同气相求 同氣相求 +同气连枝 同氣連枝 +同江 同江 +同江市 同江市 +同治 同治 +同派 同派 +同流合污 同流合污 +同济 同濟 +同济会 同濟會 +同济医科大学 同濟醫科大學 +同济大学 同濟大學 +同渡 同渡 +同温 同溫 +同温同压 同溫同壓 +同温层 同溫層 +同游 同遊 +同源 同源 +同源词 同源詞 +同点 同點 +同爨 同爨 +同爲 同爲 +同父 同父 +同父异母 同父異母 +同牀各梦 同牀各夢 +同牀异梦 同牀異夢 +同班 同班 +同班同学 同班同學 +同理 同理 +同理可证 同理可證 +同理心 同理心 +同甘共苦 同甘共苦 +同甘同苦 同甘同苦 +同甘苦 同甘苦 +同生 同生 +同生共死 同生共死 +同生死 同生死 +同用 同用 +同甲 同甲 +同病相怜 同病相憐 +同盖 同蓋 +同盟 同盟 +同盟会 同盟會 +同盟会宣言 同盟會宣言 +同盟党 同盟黨 +同盟军 同盟軍 +同盟国 同盟國 +同盟条约 同盟條約 +同盟罢工 同盟罷工 +同盟者 同盟者 +同省 同省 +同知 同知 +同砚 同硯 +同种 同種 +同科 同科 +同穴 同穴 +同窗 同窗 +同窗夜语 同窗夜語 +同窗契友 同窗契友 +同站 同站 +同章 同章 +同符合契 同符合契 +同等 同等 +同等学力 同等學力 +同等学历 同等學歷 +同篇 同篇 +同类 同類 +同类产品 同類產品 +同类意识 同類意識 +同类相吸 同類相吸 +同类相呼 同類相呼 +同类相残 同類相殘 +同类相求 同類相求 +同类相聚 同類相聚 +同类相食 同類相食 +同类色 同類色 +同类项 同類項 +同系 同系 +同素异形 同素異形 +同素异形体 同素異形體 +同素异性 同素異性 +同素异性体 同素異性體 +同约 同約 +同级 同級 +同级评审 同級評審 +同级车 同級車 +同线 同線 +同组 同組 +同缘同相 同緣同相 +同罗杯 同羅杯 +同罪 同罪 +同翅目 同翅目 +同考官 同考官 +同职 同職 +同胞 同胞 +同胞兄妹 同胞兄妹 +同胞兄弟 同胞兄弟 +同胞共乳 同胞共乳 +同胞双生 同胞雙生 +同胞爱 同胞愛 +同致 同致 +同舍生 同舍生 +同舟之谊 同舟之誼 +同舟共济 同舟共濟 +同舟而济 同舟而濟 +同船济水 同船濟水 +同色 同色 +同行 同行 +同行同业 同行同業 +同行相忌 同行相忌 +同行语 同行語 +同衾共枕 同衾共枕 +同衾帱 同衾幬 +同袍 同袍 +同袍同泽 同袍同澤 +同被 同被 +同襟 同襟 +同见同知 同見同知 +同言线 同言線 +同订 同訂 +同论 同論 +同语线 同語線 +同调 同調 +同谋 同謀 +同谋者 同謀者 +同谱 同譜 +同质 同質 +同质性 同質性 +同走 同走 +同起同坐 同起同坐 +同跑 同跑 +同路 同路 +同路人 同路人 +同车 同車 +同轨 同軌 +同轨同文 同軌同文 +同轴 同軸 +同轴圆 同軸圓 +同轴圆弧 同軸圓弧 +同轴电缆 同軸電纜 +同辈 同輩 +同边 同邊 +同达 同達 +同过 同過 +同进 同進 +同进同出 同進同出 +同进士出身 同進士出身 +同道 同道 +同道者 同道者 +同配生殖 同配生殖 +同酬 同酬 +同重 同重 +同量 同量 +同量异位素 同量異位素 +同长 同長 +同门 同門 +同门友 同門友 +同门异户 同門異戶 +同队 同隊 +同音 同音 +同音字 同音字 +同音词 同音詞 +同韵词 同韻詞 +同项 同項 +同题 同題 +同高 同高 +同龄 同齡 +同龄人 同齡人 +同龄林 同齡林 +名不当实 名不當實 +名义价值 名義價值 +名人录 名人錄 +名噪 名噪 +名坛 名壇 +名垂后世 名垂後世 +名垂罔极 名垂罔極 +名复金瓯 名覆金甌 +名山胜境 名山勝境 +名师出高徒 名師出高徒 +名录 名錄 +名录服务 名錄服務 +名曲 名曲 +名望体面 名望體面 +名次表 名次表 +名种 名種 +名称标签 名稱標籤 +名系 名系 +名胄 名胄 +名胜 名勝 +名胜古迹 名勝古蹟 +名臣言行录 名臣言行錄 +名表 名錶 +名言录 名言錄 +名重识暗 名重識暗 +名鉴 名鑑 +名门之后 名門之後 +名闻于世 名聞於世 +后七子 後七子 +后上 後上 +后上去 後上去 +后上来 後上來 +后下 後下 +后下去 後下去 +后下来 後下來 +后不为例 後不爲例 +后世 後世 +后两者 後兩者 +后丰 后豐 +后主 後主 +后事 後事 +后事之师 後事之師 +后于 後於 +后人 後人 +后人乘凉 後人乘涼 +后代 後代 +后代子孙 後代子孫 +后仰 後仰 +后仰前合 後仰前合 +后件 後件 +后任 後任 +后会 後會 +后会可期 後會可期 +后会无期 後會無期 +后会有期 後會有期 +后会难期 後會難期 +后传 後傳 +后作 後作 +后侧 後側 +后信号灯 後信號燈 +后偏 後偏 +后像 後像 +后儿 後兒 +后元音 後元音 +后先辉映 後先輝映 +后冠 后冠 +后冷战 後冷戰 +后冷战时代 後冷戰時代 +后凉 後涼 +后凋 後凋 +后分 後分 +后到 後到 +后制 後製 +后力不继 後力不繼 +后加 後加 +后加成分 後加成分 +后劲 後勁 +后劲溪 後勁溪 +后势 後勢 +后勤 後勤 +后勤人员 後勤人員 +后勤区 後勤區 +后勤学 後勤學 +后勤部 後勤部 +后北街 后北街 +后区 後區 +后医系 後醫系 +后半 後半 +后半世 後半世 +后半叶 後半葉 +后半场 後半場 +后半夜 後半夜 +后半天 後半天 +后半季 後半季 +后半晌 後半晌 +后半期 後半期 +后半段 後半段 +后半部 後半部 +后卫 後衛 +后印 後印 +后印象主义 後印象主義 +后去 後去 +后发先至 後發先至 +后发制人 後發制人 +后发座 后髮座 +后台 後臺 +后台老板 後臺老闆 +后叶 後葉 +后合前仰 後合前仰 +后后 後後 +后向 後向 +后周 後周 +后味 後味 +后命 後命 +后哨 後哨 +后唐 後唐 +后嗣 後嗣 +后园 後園 +后图 後圖 +后土 后土 +后场 後場 +后坐 後坐 +后坐力 後坐力 +后埔 後埔 +后堂 後堂 +后壁 後壁 +后壁乡 後壁鄉 +后壁湖 後壁湖 +后备 後備 +后备军 後備軍 +后备军人 後備軍人 +后备部 後備部 +后天 後天 +后天免疫 後天免疫 +后天免疫缺乏症候群 後天免疫缺乏症候羣 +后天性 後天性 +后夫 後夫 +后头 後頭 +后奏 後奏 +后奏曲 後奏曲 +后妃 后妃 +后妈 後媽 +后妻 後妻 +后娘 後孃 +后婚 後婚 +后婚儿 後婚兒 +后嫁 後嫁 +后学 後學 +后学儿 後學兒 +后安路 后安路 +后实先声 後實先聲 +后宫 後宮 +后尘 後塵 +后尧婆 後堯婆 +后尾 後尾 +后尾儿 後尾兒 +后山 後山 +后巷 後巷 +后巷前街 後巷前街 +后市 後市 +后帝 后帝 +后平路 后平路 +后年 後年 +后广告纪元 後廣告紀元 +后庄 後莊 +后序 後序 +后座 後座 +后座力 後座力 +后座系 後座繫 +后庭 後庭 +后庭花 後庭花 +后弦 後弦 +后影 後影 +后心 後心 +后怕 後怕 +后恭前倨 後恭前倨 +后悔 後悔 +后悔不及 後悔不及 +后悔不来 後悔不來 +后悔不迭 後悔不迭 +后悔何及 後悔何及 +后悔无及 後悔無及 +后悔药儿 後悔藥兒 +后悔莫及 後悔莫及 +后患 後患 +后患无穷 後患無窮 +后感 後感 +后感觉 後感覺 +后房 後房 +后手 後手 +后手不上 後手不上 +后手不接 後手不接 +后手儿 後手兒 +后手钱 後手錢 +后拥前呼 後擁前呼 +后拥前推 後擁前推 +后拥前遮 後擁前遮 +后拥前驱 後擁前驅 +后挡板 後擋板 +后排 後排 +后掠翼 後掠翼 +后掠角 後掠角 +后接 後接 +后掩蔽 後掩蔽 +后援 後援 +后援会 後援會 +后援军 後援軍 +后摆 後襬 +后撤 後撤 +后攻 後攻 +后放 後放 +后效 後效 +后文 後文 +后方 後方 +后方区 後方區 +后无来者 後無來者 +后日 後日 +后昆 後昆 +后晋 後晉 +后晌 後晌 +后晚 後晚 +后景 後景 +后有 後有 +后望镜 後望鏡 +后期 後期 +后期印象派 後期印象派 +后来 後來 +后来之秀 後來之秀 +后来人 後來人 +后来居上 後來居上 +后果 後果 +后果前因 後果前因 +后果堪忧 後果堪憂 +后果堪虞 後果堪虞 +后桅 後桅 +后桥 後橋 +后梁 後梁 +后梁太祖 後梁太祖 +后槽 後槽 +后步 後步 +后段 後段 +后段班 後段班 +后殿 後殿 +后母 後母 +后汉 後漢 +后汉书 後漢書 +后汉纪 後漢紀 +后派 後派 +后浪 後浪 +后浪推前浪 後浪推前浪 +后海湾 后海灣 +后海灣 后海灣 +后港 後港 +后滚翻 後滾翻 +后灯 後燈 +后点 後點 +后照镜 後照鏡 +后燕 後燕 +后爲 後爲 +后父 後父 +后爹 後爹 +后王 后王 +后现代 後現代 +后现代主义 後現代主義 +后现代剧场 後現代劇場 +后生 後生 +后生动物 後生動物 +后生可畏 後生可畏 +后生小子 後生小子 +后生小辈 後生小輩 +后生晚学 後生晚學 +后用 後用 +后由 後由 +后甲板 後甲板 +后皇 后皇 +后盖 後蓋 +后盾 後盾 +后知 後知 +后知后觉 後知後覺 +后福 後福 +后秃 後禿 +后秦 後秦 +后程 後程 +后稷 后稷 +后空翻 後空翻 +后窗 後窗 +后站 後站 +后端 後端 +后竹围 後竹圍 +后篇 後篇 +后级扩大机 後級擴大機 +后继 後繼 +后继乏人 後繼乏人 +后继乏力 後繼乏力 +后继无人 後繼無人 +后继无力 後繼無力 +后继有人 後繼有人 +后续 後續 +后续力 後續力 +后续的解释过程 後續的解釋過程 +后缀 後綴 +后缘 後緣 +后罩房 後罩房 +后置 後置 +后置词 後置詞 +后羿 后羿 +后羿射日 后羿射日 +后翅 後翅 +后翻筋斗 後翻筋斗 +后者 後者 +后肢 後肢 +后背 後背 +后脑 後腦 +后脑勺 後腦勺 +后脑杓 後腦杓 +后脚 後腳 +后脸儿 後臉兒 +后腰 後腰 +后腿 後腿 +后腿肉 後腿肉 +后膛 後膛 +后舱 後艙 +后舱门 後艙門 +后节 後節 +后花园 後花園 +后菜园 後菜園 +后藏 後藏 +后藤 後藤 +后虑 後慮 +后蜀 後蜀 +后行 後行 +后街 后街 +后裔 後裔 +后襟 後襟 +后西游记 後西遊記 +后视镜 後視鏡 +后觉 後覺 +后角 后角 +后言 後言 +后计 後計 +后记 後記 +后设 後設 +后词汇加工 後詞彙加工 +后话 後話 +后读 後讀 +后豐 后豐 +后账 後賬 +后赤壁赋 後赤壁賦 +后走 後走 +后赵 後趙 +后起 後起 +后起之秀 後起之秀 +后起字 後起字 +后足 後足 +后跟 後跟 +后路 後路 +后身 後身 +后车 後車 +后车之戒 後車之戒 +后车之鉴 後車之鑑 +后车站 後車站 +后车轴 後車軸 +后转 後轉 +后轮 後輪 +后辈 後輩 +后辈小子 後輩小子 +后辍 後輟 +后辛 后辛 +后辟 后辟 +后边 後邊 +后边儿 後邊兒 +后过 後過 +后进 後進 +后进先出 後進先出 +后述 後述 +后退 後退 +后退色 後退色 +后送 後送 +后送医院 後送醫院 +后遗 後遺 +后遗症 後遺症 +后部 後部 +后里 后里 +后里乡 后里鄉 +后重 後重 +后金 後金 +后钩儿 後鉤兒 +后镜 後鏡 +后门 後門 +后防 後防 +后院 後院 +后院子 後院子 +后院起火 後院起火 +后集 後集 +后面 後面 +后项 後項 +后顾 後顧 +后顾之忧 後顧之憂 +后顾之患 後顧之患 +后顾之虑 後顧之慮 +后顾之虞 後顧之虞 +后颈 後頸 +后首 後首 +后魏 後魏 +后鼻音 後鼻音 +后龙 後龍 +后龙溪 後龍溪 +后龙镇 後龍鎮 +吐出 吐出 +吐出来 吐出來 +吐司面包 吐司麪包 +吐哺捉发 吐哺捉髮 +吐哺握发 吐哺握髮 +吐穗 吐穗 +吐谷浑 吐谷渾 +吐露出 吐露出 +向上 向上 +向上地 向上地 +向下 向下 +向东 向東 +向东看 向東看 +向东走 向東走 +向人 向人 +向何处 向何處 +向使 向使 +向例 向例 +向光 向光 +向光性 向光性 +向內 向內 +向內走 向內走 +向前 向前 +向前看 向前看 +向前看齐 向前看齊 +向前翻腾 向前翻騰 +向前走 向前走 +向前进 向前進 +向化 向化 +向北 向北 +向北地 向北地 +向北看 向北看 +向北走 向北走 +向午 向午 +向南 向南 +向南看 向南看 +向南走 向南走 +向右 向右 +向右拐 向右拐 +向右看 向右看 +向右看齐 向右看齊 +向右转 向右轉 +向右转走 向右轉走 +向后 向後 +向后冲 向後衝 +向后看 向後看 +向后翻腾 向後翻騰 +向后走 向後走 +向后转 向後轉 +向后转走 向後轉走 +向善 向善 +向地 向地 +向地性 向地性 +向培良 向培良 +向壁虚构 向壁虛構 +向壁虚造 向壁虛造 +向声背实 向聲背實 +向外 向外 +向外冲 向外衝 +向外看 向外看 +向外走 向外走 +向天 向天 +向学 向學 +向宠 向寵 +向导 嚮導 +向导公司 嚮導公司 +向导员 嚮導員 +向导犬 嚮導犬 +向左 向左 +向左拐 向左拐 +向左看 向左看 +向左看齐 向左看齊 +向左转 向左轉 +向左转走 向左轉走 +向巴平措 向巴平措 +向平之愿 向平之願 +向年 向年 +向应 嚮應 +向度 向度 +向当 向當 +向往 嚮往 +向心 向心 +向心力 向心力 +向心店 向心店 +向心花序 向心花序 +向性 向性 +向慕 嚮慕 +向戌 向戌 +向斜 向斜 +向斜层 向斜層 +向日 向日 +向日性 向日性 +向日葵 向日葵 +向时 向時 +向明 嚮明 +向晓 向曉 +向晚 向晚 +向晦 嚮晦 +向暮 向暮 +向来 向來 +向来是 向來是 +向来都是 向來都是 +向流星雨 向流星雨 +向海 向海 +向溼性 向溼性 +向火 向火 +向火乞儿 向火乞兒 +向用 向用 +向电性 向電性 +向盘 向盤 +向着 向着 +向秀 向秀 +向秀丽 向秀麗 +向者 曏者 +向背 向背 +向荣 向榮 +向西 向西 +向西南 向西南 +向触 向觸 +向迩 嚮邇 +向里面冲 向裏面衝 +向量 向量 +向量代数 向量代數 +向量分析 向量分析 +向量图形 向量圖形 +向钱看 向錢看 +向阳 向陽 +向阳信 向陽信 +向阳区 向陽區 +向阳大道 向陽大道 +向隅 向隅 +向隅独泣 向隅獨泣 +向隅而泣 向隅而泣 +向非 向非 +向顺 向順 +向风 向風 +向风针 向風針 +吓不了 嚇不了 +吓了 嚇了 +吓了一跳 嚇了一跳 +吓出 嚇出 +吓出病来 嚇出病來 +吓得发抖 嚇得發抖 +吕后 呂后 +吕太后的筵席 呂太后的筵席 +吕宋烟 呂宋菸 +吕岩 呂岩 +吕布 呂布 +吕布戟 呂布戟 +吕梁 呂梁 +吕梁山 呂梁山 +吕梁市 呂梁市 +吕氏春秋 呂氏春秋 +吕芳烟 呂芳煙 +吕蒙 呂蒙 +吕蒙正 呂蒙正 +吕贝克 呂貝克 +吗啡针 嗎啡針 +君主专制 君主專制 +君主专制制 君主專制制 +君主制 君主制 +君主立宪制 君主立憲制 +君合国 君合國 +君子不念旧恶 君子不念舊惡 +君子于役 君子于役 +君子交绝不出恶声 君子交絕不出惡聲 +君子坦荡荡小人长戚戚 君子坦蕩蕩小人長慼慼 +君子报仇十年不晚 君子報仇十年不晚 +君子言先不言后 君子言先不言後 +吞了 吞了 +吞了下去 吞了下去 +吞云吐雾 吞雲吐霧 +吞刀刮肠 吞刀刮腸 +吞咽 吞嚥 +吞并 吞併 +吞烟 吞煙 +吞米桑布札 吞米桑布札 +吟叹 吟歎 +吟坛 吟壇 +吟游 吟遊 +吟游诗人 吟遊詩人 +吠舍 吠舍 +否极必泰 否極必泰 +否极泰来 否極泰來 +否极生泰 否極生泰 +吧台 吧檯 +吧托女 吧托女 +吨公里 噸公里 +含了 含了 +含商咀征 含商咀徵 +含宫咀征 含宮咀徵 +含油岩 含油岩 +含烟笼雾 含煙籠霧 +含苞欲放 含苞欲放 +含蜡 含蠟 +含齿戴发 含齒戴髮 +听不出 聽不出 +听不出来 聽不出來 +听不得一面之词 聽不得一面之詞 +听了 聽了 +听了风就是雨 聽了風就是雨 +听于 聽於 +听候发落 聽候發落 +听出 聽出 +听出来 聽出來 +听墙面 聽牆面 +听弦 聽絃 +听得出 聽得出 +听得出来 聽得出來 +听腻了 聽膩了 +听见了 聽見了 +听觉范围 聽覺範圍 +听证制度 聽證制度 +听骨链 聽骨鏈 +启动技术 啓動技術 +启发 啓發 +启发式 啓發式 +启发式敎学法 啓發式教學法 +启发性 啓發性 +启发性程式 啓發性程式 +启发法 啓發法 +启示录 啓示錄 +启蒙 啓蒙 +启蒙专制君主 啓蒙專制君主 +启蒙哲学 啓蒙哲學 +启蒙时代 啓蒙時代 +启蒙运动 啓蒙運動 +吴下阿蒙 吳下阿蒙 +吴俊杰 吳俊傑 +吴克群 吳克羣 +吴嘉种 吳嘉種 +吴复连 吳復連 +吴嶽修 吳嶽修 +吴幸桦 吳幸樺 +吴志 吳志 +吴志伟 吳志偉 +吴志扬 吳志揚 +吴志祺 吳志祺 +吴志远 吳志遠 +吴皓升 吳皓昇 +吴育升 吳育昇 +吴荣杰 吳榮杰 +吴蒙惠 吳蒙惠 +吴越同舟 吳越同舟 +吴越春秋 吳越春秋 +吴越曲 吳越曲 +吴采璋 吳采璋 +吴里克 吳里克 +吴隆杰 吳隆傑 +吸了 吸了 +吸出 吸出 +吸出去 吸出去 +吸出来 吸出來 +吸回 吸回 +吸回去 吸回去 +吸回来 吸回來 +吸地板 吸地板 +吸尽 吸盡 +吸干 吸乾 +吸引不了 吸引不了 +吸得干干 吸得乾乾 +吸杯 吸杯 +吸油烟机 吸油煙機 +吸烟 吸菸 +吸烟区 吸菸區 +吸烟客 吸菸客 +吸烟室 吸菸室 +吸烟族 吸菸族 +吸烟率 吸菸率 +吸烟者 吸菸者 +吸管虫 吸管蟲 +吸虫 吸蟲 +吸虫纲 吸蟲綱 +吸血虫 吸血蟲 +吹了 吹了 +吹云 吹雲 +吹出 吹出 +吹出去 吹出去 +吹出来 吹出來 +吹发 吹髮 +吹台 吹臺 +吹叶机 吹葉機 +吹向 吹向 +吹头发 吹頭髮 +吹干 吹乾 +吹气胜兰 吹氣勝蘭 +吹炼 吹煉 +吹绵介壳虫 吹綿介殼蟲 +吹胡 吹鬍 +吹胡子 吹鬍子 +吹胡子瞪眼睛 吹鬍子瞪眼睛 +吹风胡哨 吹風胡哨 +吻别 吻別 +吻别时 吻別時 +吻合 吻合 +吼出 吼出 +吾为之范我驰驱 吾爲之範我馳驅 +吾党 吾黨 +吾当 吾當 +呂后 呂后 +呆串了皮 呆串了皮 +呆了 呆了 +呆了一呆 呆了一呆 +呆呆兽 呆呆獸 +呆呆挣挣 呆呆掙掙 +呆头 呆頭 +呆小症 呆小症 +呆板 呆板 +呆气 呆氣 +呆滞 呆滯 +呆痴 呆癡 +呆着 待著 +呆脑 呆腦 +呆致致 呆緻緻 +呆话 呆話 +呆里呆气 呆裏呆氣 +呆里撒奸 呆裏撒奸 +呈准 呈准 +呈现出 呈現出 +呈现出来 呈現出來 +呈逆价差 呈逆價差 +告别 告別 +告别式 告別式 +告发 告發 +告示板 告示板 +呕出物 嘔出物 +呗赞 唄讚 +员山庄 員山莊 +呛了 嗆了 +呜咽 嗚咽 +周一 週一 +周一岳 周一嶽 +周三 週三 +周三径一 周三徑一 +周上 週上 +周世惠 周世惠 +周东昱 周東昱 +周中 週中 +周丽淇 周麗淇 +周书 周書 +周事 周事 +周二 週二 +周五 週五 +周亚夫 周亞夫 +周人 周人 +周人之急 賙人之急 +周仓 周倉 +周代 周代 +周休 週休 +周休二日 週休二日 +周会 週會 +周伟 周偉 +周传瑛 周傳瑛 +周传英 周傳英 +周传雄 周傳雄 +周作人 周作人 +周佳佑 周佳佑 +周佳琦 周佳琦 +周俊三 周俊三 +周俊勳 周俊勳 +周內 周內 +周全 周全 +周全方便 周全方便 +周公 周公 +周公吐哺 周公吐哺 +周公瑾 周公瑾 +周六 週六 +周六日 週六日 +周典论 周典論 +周刊 週刊 +周到 周到 +周助 周助 +周勃 周勃 +周匝 周匝 +周华健 周華健 +周南 周南 +周卫 周衛 +周历 周曆 +周厉王 周厲王 +周原 周原 +周口 周口 +周口地区 周口地區 +周口市 周口市 +周口店 周口店 +周口店文化 周口店文化 +周召 周召 +周召共和 周召共和 +周台竹 周臺竹 +周告 周告 +周周 週週 +周四 週四 +周回 週迴 +周围 周圍 +周围人 周圍人 +周围性眩晕 周圍性眩暈 +周围环境 周圍環境 +周培蕾 周培蕾 +周堂 周堂 +周士榆 周士榆 +周士渊 周士淵 +周处 周處 +周备 周備 +周大福 周大福 +周天 周天 +周奕成 周奕成 +周妙音 周妙音 +周姓 周姓 +周孟晔 周孟曄 +周宁 周寧 +周宁县 周寧縣 +周守训 周守訓 +周宏哲 周宏哲 +周宏室 周宏室 +周官 周官 +周定纬 周定緯 +周宣王 周宣王 +周室 周室 +周家 周家 +周密 周密 +周小 周小 +周小川 周小川 +周岁 週歲 +周平王 周平王 +周年 週年 +周年庆 週年慶 +周年纪念 週年紀念 +周年视差 週年視差 +周幼婷 周幼婷 +周幽王 周幽王 +周庄 周莊 +周庄王 周莊王 +周庄镇 周莊鎮 +周康王 周康王 +周延 周延 +周弘宪 周弘憲 +周忌 周忌 +周志全 周志全 +周志浩 周志浩 +周志诚 周志誠 +周思源 周思源 +周思齐 周思齊 +周急 周急 +周急继乏 周急繼乏 +周总理 周總理 +周恒毅 周恆毅 +周恤 周恤 +周恩来 周恩來 +周情孔思 周情孔思 +周慧敏 周慧敏 +周成王 周成王 +周承玮 周承瑋 +周折 周折 +周报 週報 +周敏鸿 周敏鴻 +周敦颐 周敦頤 +周数 週數 +周文 周文 +周文王 周文王 +周方 周方 +周旋 周旋 +周旋到底 周旋到底 +周日 週日 +周日版 週日版 +周昉 周昉 +周易 周易 +周星驰 周星馳 +周春秀 周春秀 +周晓涵 周曉涵 +周晬 周晬 +周朝 周朝 +周期 週期 +周期函数 週期函數 +周期彗星 週期彗星 +周期律 週期律 +周期性 週期性 +周期数 週期數 +周期系 週期系 +周期表 週期表 +周期解 週期解 +周末 週末 +周末愉快 週末愉快 +周末效应 週末效應 +周村 周村 +周村区 周村區 +周杰 周杰 +周杰伦 周杰倫 +周柏臣 周柏臣 +周某 周某 +周树人 周樹人 +周梁淑怡 周梁淑怡 +周梦瑶 周夢瑤 +周正 周正 +周武王 周武王 +周武王姬发 周武王姬發 +周武雄 周武雄 +周氏 周氏 +周永康 周永康 +周永明 周永明 +周治平 周治平 +周泓谕 周泓諭 +周波 周波 +周流 周流 +周浃 周浹 +周济 賙濟 +周海媚 周海媚 +周润发 周潤發 +周渝民 周渝民 +周游 周遊 +周游世界 周遊世界 +周游列国 周遊列國 +周游券 周遊券 +周灿德 周燦德 +周率 周率 +周王朝 周王朝 +周瑜 周瑜 +周瑜打黄盖 周瑜打黃蓋 +周璇 周璇 +周盈成 周盈成 +周盈文 周盈文 +周盛渊 周盛淵 +周相 周相 +周知 周知 +周礼 周禮 +周礼良 周禮良 +周秀霞 周秀霞 +周程张朱 周程張朱 +周穆王 周穆王 +周立昌 周立昌 +周立波 周立波 +周章 周章 +周章狼狈 周章狼狽 +周筱涵 周筱涵 +周经凯 周經凱 +周给 周給 +周缘 周緣 +周置 周置 +周美里 周美里 +周美青 周美青 +周考 週考 +周而不比 周而不比 +周而复始 週而復始 +周至 周至 +周至县 周至縣 +周董 周董 +周蓓姬 周蓓姬 +周蕙 周蕙 +周薪 週薪 +周行 周行 +周览 周覽 +周角 周角 +周记 週記 +周详 周詳 +周诰 周誥 +周赐海 周賜海 +周赧王 周赧王 +周走秀 週走秀 +周身 周身 +周转 週轉 +周边 周邊 +周边设备 周邊設備 +周迅 周迅 +周近 周近 +周遍 周遍 +周道 周道 +周遭 周遭 +周遭事物 周遭事物 +周遮 周遮 +周邦彦 周邦彥 +周郎 周郎 +周郎癖 周郎癖 +周郎顾曲 周郎顧曲 +周采诗 周采詩 +周锡玮 周錫瑋 +周锦贵 周錦貴 +周长 周長 +周雅淑 周雅淑 +周韫维 周韞維 +周顗 周顗 +周颂 周頌 +周颙 周顒 +周髀 周髀 +周髀算经 周髀算經 +周龙 周龍 +呱嗒板儿 呱嗒板兒 +味同嚼蜡 味同嚼蠟 +味胜易牙 味勝易牙 +呼之欲出 呼之欲出 +呼出 呼出 +呼出来 呼出來 +呼吁 呼籲 +呼吸困难 呼吸困難 +呼吸系统 呼吸系統 +呼图克图 呼圖克圖 +命世之才 命世之才 +命世才 命世才 +命中注定 命中註定 +命名系统 命名系統 +命理 命理 +命运注定 命運註定 +命题范围 命題範圍 +咀咽 咀嚥 +咀嚼出 咀嚼出 +和丰 和豐 +和了 和了 +和什托洛盖 和什托洛蓋 +和光同尘 和光同塵 +和克制 和剋制 +和合 和合 +和合二仙 和合二仙 +和合僧 和合僧 +和合日 和合日 +和合汤 和合湯 +和同 和同 +和哄 和哄 +和奸 和姦 +和布克赛尔县 和布克賽爾縣 +和布克赛尔蒙古自治县 和布克賽爾蒙古自治縣 +和平工作团 和平工作團 +和平里 和平里 +和弦 和絃 +和杯 和杯 +和核 和核 +和气致祥 和氣致祥 +和盘托出 和盤托出 +和而不同 和而不同 +和胜 和勝 +和谐一致 和諧一致 +和面 和麪 +和风拂面 和風拂面 +咍台 咍臺 +咎征 咎徵 +咏叹 詠歎 +咏赞 詠贊 +咏雪之才 詠雪之才 +咒印术 咒印術 +咒愿 咒愿 +咒术 咒術 +咕咕钟 咕咕鐘 +咖啡杯 咖啡杯 +咖啡色系 咖啡色系 +咙胡 嚨胡 +咣当 咣噹 +咨询 諮詢 +咫尺万里 咫尺萬里 +咫尺千里 咫尺千里 +咬了 咬了 +咬了一口 咬了一口 +咬出 咬出 +咬合 咬合 +咬合不正 咬合不正 +咬合调整 咬合調整 +咬姜呷醋 咬薑呷醋 +咬字不准 咬字不準 +咬屁虫 咬屁蟲 +咬弦 咬弦 +咬折丁子的老婆 咬折丁子的老婆 +咬秋 咬秋 +咬舌自尽 咬舌自盡 +咭叮当 咭叮噹 +咭当当 咭噹噹 +咯当 咯噹 +咳嗽药 咳嗽藥 +咸丝丝 鹹絲絲 +咸丰 咸豐 +咸丰县 咸豐縣 +咸丰草 咸豐草 +咸五登三 咸五登三 +咸亨 咸亨 +咸亨酒店 咸亨酒店 +咸信 咸信 +咸兴 咸興 +咸兴市 咸興市 +咸卤 鹹鹵 +咸味 鹹味 +咸和 咸和 +咸咸 鹹鹹 +咸嘴淡舌 鹹嘴淡舌 +咸土 鹹土 +咸宁 咸寧 +咸宁地区 咸寧地區 +咸宁市 咸寧市 +咸安区 咸安區 +咸宜 咸宜 +咸度 鹹度 +咸得 鹹得 +咸批 鹹批 +咸水 鹹水 +咸水妹 鹹水妹 +咸水湖 鹹水湖 +咸水鱼 鹹水魚 +咸池 咸池 +咸汤 鹹湯 +咸津津 鹹津津 +咸津津儿 鹹津津兒 +咸派 鹹派 +咸海 鹹海 +咸淡 鹹淡 +咸淡适中 鹹淡適中 +咸湖 鹹湖 +咸湿 鹹溼 +咸潟 鹹潟 +咸猪手 鹹豬手 +咸猪肉 鹹豬肉 +咸的 鹹的 +咸盐 鹹鹽 +咸类 鹹類 +咸粥 鹹粥 +咸肉 鹹肉 +咸菜 鹹菜 +咸菜干 鹹菜乾 +咸蛋 鹹蛋 +咸认为 咸認爲 +咸酥鸡 鹹酥雞 +咸镜 咸鏡 +咸镜北道 咸鏡北道 +咸镜南道 咸鏡南道 +咸镜道 咸鏡道 +咸阳 咸陽 +咸阳地区 咸陽地區 +咸阳宫 咸陽宮 +咸阳市 咸陽市 +咸阳桥 咸陽橋 +咸阳火 咸陽火 +咸食 鹹食 +咸鱼 鹹魚 +咸鱼翻身 鹹魚翻身 +咸鸭蛋 鹹鴨蛋 +咽下 嚥下 +咽不了 嚥不了 +咽了 嚥了 +咽住 嚥住 +咽到 嚥到 +咽哽 咽哽 +咽唾 嚥唾 +咽喉 咽喉 +咽峡 咽峽 +咽干 咽乾 +咽气 嚥氣 +咽炎 咽炎 +咽病 咽病 +咽痛 咽痛 +咽着 嚥着 +咽肌 嚥肌 +咽苦吞甘 嚥苦吞甘 +咽进 嚥進 +咽部 咽部 +咽镜 咽鏡 +哀兵必胜 哀兵必勝 +哀凄 哀悽 +哀叹 哀嘆 +哀吊 哀弔 +哀哀欲绝 哀哀欲絕 +哀戚 哀慼 +哀挽 哀輓 +哀莫大于心死 哀莫大於心死 +品尝 品嚐 +品尝会 品嚐會 +品尝到 品嚐到 +品汇 品彙 +品种 品種 +品种改良 品種改良 +品系 品系 +品花宝鉴 品花寶鑑 +品莲台 品蓮臺 +品貌出众 品貌出衆 +品质管制 品質管制 +品鉴 品鑑 +哄乱 哄亂 +哄了 哄了 +哄人 哄人 +哄伙 鬨夥 +哄传 哄傳 +哄传一时 哄傳一時 +哄劝 哄勸 +哄动 鬨動 +哄动一时 哄動一時 +哄吓骗诈 哄嚇騙詐 +哄哄 哄哄 +哄哄翕翕 哄哄翕翕 +哄堂 鬨堂 +哄堂大笑 鬨堂大笑 +哄弄 哄弄 +哄得 哄得 +哄抢 哄搶 +哄抬 哄擡 +哄抬物价 哄擡物價 +哄来哄去 哄來哄去 +哄然 鬨然 +哄然大笑 鬨然大笑 +哄笑 鬨笑 +哄诱 哄誘 +哄赚 哄賺 +哄走 哄走 +哄闹 鬨鬧 +哄骗 哄騙 +哈丰角 哈豐角 +哈克 哈克 +哈克莉洛 哈克莉洛 +哈克贝利芬历险记 哈克貝利芬歷險記 +哈利发 哈利發 +哈利法克斯 哈利法克斯 +哈卡里 哈卡里 +哈发林 哈發林 +哈塞布苏 哈塞布蘇 +哈巴罗夫斯克 哈巴羅夫斯克 +哈巴谷书 哈巴谷書 +哈布斯堡 哈布斯堡 +哈比亚里马纳 哈比亞里馬納 +哈特谢普苏 哈特謝普蘇 +哈玛斯派系 哈瑪斯派系 +哈玛斯集团 哈瑪斯集團 +哈萨克 哈薩克 +哈萨克人 哈薩克人 +哈萨克共和国 哈薩克共和國 +哈萨克文 哈薩克文 +哈萨克斯坦 哈薩克斯坦 +哈萨克族 哈薩克族 +哈萨克语 哈薩克語 +哈里 哈里 +哈里伯顿 哈里伯頓 +哈里发 哈里發 +哈里发塔 哈里發塔 +哈里发帝国 哈里發帝國 +哈里尔 哈里爾 +哈里斯 哈里斯 +哈里斯堡 哈里斯堡 +哈里札德 哈里札德 +哈里森史密特 哈裏森史密特 +哈里路亚 哈里路亞 +哈里逊 哈里遜 +哈里逊福特 哈里遜福特 +哈里里 哈里里 +响了 響了 +响卜 響卜 +响叮当 響叮噹 +响弦 響絃 +响当当 響噹噹 +响彻云汉 響徹雲漢 +响彻云际 響徹雲際 +响彻云霄 響徹雲霄 +响板 響板 +响遏行云 響遏行雲 +响钟 響鐘 +响马党羽 響馬黨羽 +哑子托梦 啞子托夢 +哑板 啞板 +哗众 譁衆 +哗变 譁變 +哗哗 嘩嘩 +哗啦 嘩啦 +哗地 嘩地 +哗然 譁然 +哗的 嘩的 +哗笑 譁笑 +哥伦布 哥倫布 +哥伦布市 哥倫布市 +哥伦布纪 哥倫布紀 +哥林多后书 哥林多後書 +哥萨克 哥薩克 +哥里 哥里 +哪一个 哪一個 +哪一出 哪一齣 +哪个 哪個 +哪个人 哪個人 +哪个月 哪個月 +哪几 哪幾 +哪几个 哪幾個 +哪几天 哪幾天 +哪几次 哪幾次 +哪只 哪隻 +哪台 哪臺 +哪回 哪回 +哪方面 哪方面 +哪种 哪種 +哪种人 哪種人 +哪里 哪裏 +哪里买 哪裏買 +哪里人 哪裏人 +哪里哪里 哪裏哪裏 +哪里摔倒哪里爬 哪裏摔倒哪裏爬 +哭个 哭個 +哭个夠 哭個夠 +哭个痛快 哭個痛快 +哭了 哭了 +哭出 哭出 +哭出来 哭出來 +哭尽 哭盡 +哭成一团 哭成一團 +哭秋风 哭秋風 +哭脏 哭髒 +哲学系 哲學系 +哲学范畴 哲學範疇 +哲布尊丹巴 哲布尊丹巴 +哲理 哲理 +哲里木 哲里木 +哺喂 哺餵 +哼个 哼個 +哼出 哼出 +哽咽 哽咽 +唁吊 唁弔 +唇似抹朱 脣似抹朱 +唇如涂朱 脣如塗朱 +唇干 脣乾 +唇彩 脣彩 +唇彩盘 脣彩盤 +唇燥舌干 脣燥舌乾 +唇若抹朱 脣若抹朱 +唇若涂朱 脣若塗朱 +唇若涂脂 脣若塗脂 +唉叹 唉嘆 +唐三彩 唐三彩 +唐志中 唐志中 +唐才常 唐才常 +唐氏症 唐氏症 +唐氏综合症 唐氏綜合症 +唐王游地府 唐王遊地府 +唐美云 唐美雲 +唐胖子吊在醋缸里 唐胖子吊在醋缸裏 +唤出 喚出 +唤回 喚回 +售价 售價 +售价为 售價爲 +售出 售出 +售台 售臺 +售后 售後 +售后服务 售後服務 +售后部 售後部 +售货台 售貨臺 +售货合约 售貨合約 +唯意志论 唯意志論 +唱个 唱個 +唱了 唱了 +唱出 唱出 +唱出来 唱出來 +唱叹 唱嘆 +唱回 唱回 +唱回去 唱回去 +唱回来 唱回來 +唱对台戏 唱對臺戲 +唱念 唱唸 +唱曲 唱曲 +唱游 唱遊 +唱片目录 唱片目錄 +唱针 唱針 +唸了 唸了 +唾余 唾餘 +唾沫直咽 唾沫直嚥 +唾面 唾面 +唾面自干 唾面自乾 +啃书虫 啃書蟲 +啃出 啃出 +啄针儿 啄針兒 +商业发票 商業發票 +商业计划 商業計劃 +商借 商借 +商务代表 商務代表 +商历 商曆 +商周 商周 +商品价值 商品價值 +商品价格 商品價格 +商品目录 商品目錄 +商品输出 商品輸出 +商团 商團 +商学系 商學系 +商秋 商秋 +商科集团 商科集團 +啜哄 啜哄 +啤酒厂 啤酒廠 +啧啧称赞 嘖嘖稱讚 +啧啧赞叹 嘖嘖讚歎 +啮合 齧合 +啷当 啷噹 +啼饥号寒 啼飢號寒 +喀喇崑仑山 喀喇崑崙山 +喀喇昆仑公路 喀喇崑崙公路 +喀喇昆仑山 喀喇崑崙山 +喀喇昆仑山脉 喀喇崑崙山脈 +喀喇沁左翼蒙古族自治县 喀喇沁左翼蒙古族自治縣 +喀布尔 喀布爾 +喀布尔河 喀布爾河 +喀拉喀托火山 喀拉喀托火山 +喀拉昆仑山 喀拉崑崙山 +喂乳 餵乳 +喂了 餵了 +喂了一声 喂了一聲 +喂你 餵你 +喂偏食 喂偏食 +喂养 餵養 +喂动物 餵動物 +喂哺 餵哺 +喂喂 喂喂 +喂奶 餵奶 +喂奶时 餵奶時 +喂它 餵它 +喂我 餵我 +喂母乳 餵母乳 +喂狗 餵狗 +喂猪 餵豬 +喂眼 喂眼 +喂给 餵給 +喂羊 餵羊 +喂貓 餵貓 +喂过 餵過 +喂食 餵食 +喂饭 餵飯 +喂饱 餵飽 +喂马 餵馬 +喂驴 餵驢 +喂鱼 餵魚 +喂鸡 餵雞 +喂鸭 餵鴨 +喂鹅 餵鵝 +善了 善了 +善于 善於 +善于词令 善於詞令 +善于辞令 善於辭令 +善价 善價 +善后 善後 +善后事宜 善後事宜 +善后借款 善後借款 +善善恶恶 善善惡惡 +善尽 善盡 +善念 善念 +善恶 善惡 +善恶不分 善惡不分 +善意回应 善意回應 +善才 善才 +善才童子 善才童子 +善有善报恶有恶报 善有善報惡有惡報 +善有善报恶有恶报若然不报时晨未到 善有善報惡有惡報若然不報時晨未到 +善罢干休 善罷干休 +善财难舍 善財難捨 +喇叭虫 喇叭蟲 +喉咙里 喉嚨裏 +喉咽 喉咽 +喉头发干 喉頭發乾 +喉干舌燥 喉乾舌燥 +喊了 喊了 +喊价 喊價 +喊出 喊出 +喊出去 喊出去 +喊出来 喊出來 +喊回 喊回 +喊回去 喊回去 +喊回来 喊回來 +喑恶叱咤 喑惡叱吒 +喘出 喘出 +喘吁吁 喘吁吁 +喜不自胜 喜不自勝 +喜冲冲 喜衝衝 +喜出望外 喜出望外 +喜娘 喜娘 +喜形于色 喜形於色 +喜忧参半 喜憂參半 +喜怒不形于色 喜怒不形於色 +喜恶 喜惡 +喜极而泣 喜極而泣 +喜欢表 喜歡錶 +喜欢钟 喜歡鐘 +喜欢钟表 喜歡鐘錶 +喜获 喜獲 +喜虫儿 喜蟲兒 +喝个 喝個 +喝了 喝了 +喝交杯 喝交杯 +喝倒彩 喝倒彩 +喝倒采 喝倒采 +喝出 喝出 +喝参 喝參 +喝尽 喝盡 +喝干 喝乾 +喝彩 喝彩 +喝彩声 喝彩聲 +喝杯 喝杯 +喝采 喝采 +喝风呵烟 喝風呵煙 +喝风疴烟 喝風痾煙 +喟叹 喟嘆 +喧哄 喧鬨 +喧哗 喧譁 +喧噪 喧噪 +喫亏的是乖占便宜的是呆 喫虧的是乖占便宜的是呆 +喷云吐雾 噴雲吐霧 +喷云嗳雾 噴雲噯霧 +喷出 噴出 +喷出去 噴出去 +喷出口 噴出口 +喷出来 噴出來 +喷发 噴發 +喷墨印表机 噴墨印表機 +喷射发动机 噴射發動機 +喷射战斗机 噴射戰鬥機 +喷气发动 噴氣發動 +喷气发动机 噴氣發動機 +喷洒 噴灑 +喷薄欲出 噴薄欲出 +嗅出 嗅出 +嗑药 嗑藥 +嗔拳不打笑面 嗔拳不打笑面 +嗛志 嗛志 +嗜欲 嗜慾 +嗜眠症 嗜眠症 +嗜睡症 嗜睡症 +嗜血杆菌 嗜血桿菌 +嗜酸乳干菌 嗜酸乳干菌 +嗝症 嗝症 +嗟叹 嗟嘆 +嗟吁 嗟吁 +嗣后 嗣後 +嗣适 嗣適 +嘀嗒的表 嘀嗒的錶 +嘀里嘟噜 嘀裏嘟嚕 +嘉义师范 嘉義師範 +嘉义师范学院 嘉義師範學院 +嘉南药专 嘉南藥專 +嘉南药理科技大学 嘉南藥理科技大學 +嘉布瑞尔 嘉布瑞爾 +嘉柏隆里 嘉柏隆里 +嘉肴 嘉餚 +嘉言录 嘉言錄 +嘉谷 嘉穀 +嘉里 嘉裏 +嘘下台 噓下臺 +嘘下台去 噓下臺去 +嘘下台来 噓下臺來 +嘱托 囑託 +嘴松 嘴鬆 +嘴答谷 嘴答谷 +嘴里 嘴裏 +噎饥 噎饑 +噙齿戴发 噙齒戴髮 +噜噜苏苏 嚕嚕囌囌 +噜苏 嚕囌 +器物录 器物錄 +噪动 譟動 +噪声 噪聲 +噪杂 噪雜 +噪点 噪點 +噪诈 譟詐 +噪音 噪音 +噪音控制 噪音控制 +噪音管制 噪音管制 +噪音管制法 噪音管制法 +噪鹛 噪鶥 +噫吁戏 噫吁戲 +噶大克 噶大克 +噶布伦 噶布倫 +噶当派 噶當派 +噶拉多杰仁波切 噶拉多傑仁波切 +嚚暗 嚚闇 +嚷出 嚷出 +嚷出去 嚷出去 +嚷出来 嚷出來 +嚷刮 嚷刮 +嚼不了 嚼不了 +嚼舌自尽 嚼舌自盡 +嚼蜡 嚼蠟 +嚼谷 嚼穀 +囉囉苏苏 囉囉囌囌 +囉苏 囉囌 +囊橐丰盈 囊橐豐盈 +囊温郎当 囊溫郎當 +囓合 囓合 +囚系 囚繫 +囚首丧面 囚首喪面 +囚首垢面 囚首垢面 +四万 四萬 +四万一千 四萬一千 +四万七千 四萬七千 +四万三千 四萬三千 +四万两千 四萬兩千 +四万五千 四萬五千 +四万八千 四萬八千 +四万六千 四萬六千 +四万四千 四萬四千 +四下里 四下裏 +四世同堂 四世同堂 +四两拨千斤 四兩撥千斤 +四个 四個 +四个坚持 四個堅持 +四个现代化 四個現代化 +四代同堂 四代同堂 +四体不勤五谷不分 四體不勤五穀不分 +四余 四餘 +四停八当 四停八當 +四克 四克 +四党 四黨 +四六面体 四六面體 +四凶 四凶 +四出征收 四出徵收 +四出戏 四齣戲 +四出祁山 四出祁山 +四分历 四分曆 +四分历史 四分歷史 +四分钟 四分鐘 +四十一万 四十一萬 +四十五万 四十五萬 +四十四万 四十四萬 +四十多万 四十多萬 +四千 四千 +四千两百 四千兩百 +四千多万 四千多萬 +四只 四隻 +四台 四臺 +四号台 四號臺 +四合 四合 +四合一 四合一 +四合房 四合房 +四合院 四合院 +四向 四向 +四周 四周 四週 +四周围 四周圍 +四周年 四週年 +四大发明 四大發明 +四大须生 四大鬚生 +四天后 四天後 +四川师范大学 四川師範大學 +四川师范学院 四川師範學院 +四年制 四年制 +四年制的大学 四年制的大學 +四库禁毁书丛刋 四庫禁燬書叢刋 +四弘誓愿 四弘誓願 +四才子 四才子 +四扎 四紮 +四方八面 四方八面 +四方台 四方臺 +四方台区 四方臺區 +四星彩 四星彩 +四杯 四杯 +四杰 四傑 +四板 四板 +四极 四極 +四极管 四極管 +四柜 四櫃 +四核 四核 +四洲志 四洲志 +四海升平 四海昇平 +四海皆准 四海皆准 +四点钟 四點鐘 +四百万 四百萬 +四百个 四百個 +四百多万 四百多萬 +四秒钟 四秒鐘 +四级三审制 四級三審制 +四胡 四胡 +四舍五入 四捨五入 +四舍六入 四捨六入 +四表 四表 +四邻八舍 四鄰八舍 +四部合唱 四部合唱 +四部曲 四部曲 +四里 四里 +四面 四面 +四面体 四面體 +四面佛 四面佛 +四面八方 四面八方 +四面受困 四面受困 +四面受敌 四面受敵 +四面楚歌 四面楚歌 +四面玲珑 四面玲瓏 +四面见光 四面見光 +四面钟 四面鐘 +回九 回九 +回乡 回鄉 +回书 回書 +回买 回買 +回了 回了 +回事 回事 +回交 回交 +回京 回京 +回人 回人 +回亿 回億 +回传 回傳 +回佣 回佣 +回信 回信 +回信地址 回信地址 +回候 回候 +回光返照 迴光返照 +回光镜 回光鏡 +回冲 回沖 +回击 回擊 +回函 回函 +回到 回到 +回力棒 回力棒 +回力球 回力球 +回动 回動 +回匝 迴匝 +回升 回升 +回单 回單 +回单儿 回單兒 +回卷 回捲 +回厂 回廠 +回历 回曆 +回去 回去 +回口 回口 +回台 回臺 +回合 回合 +回吐 回吐 +回向 迴向 +回告 回告 +回味 回味 +回味无穷 回味無窮 +回和 回和 +回咬 回咬 +回响 迴響 +回嗔作喜 回嗔作喜 +回嘴 回嘴 +回回 回回 +回回历 回回曆 +回回青 回回青 +回回鼻子 回回鼻子 +回国 回國 +回圈 迴圈 +回塘 回塘 +回填 回填 +回墨印 回墨印 +回声 回聲 +回声定位 回聲定位 +回声探测 迴聲探測 +回复 回覆 回復 +回复青春 回復青春 +回天 迴天 +回天之力 回天之力 +回天乏术 回天乏術 +回头 回頭 +回头一看 回頭一看 +回头书 回頭書 +回头人 回頭人 +回头儿 回頭兒 +回头客 回頭客 +回头掣脑 回頭掣腦 +回头是岸 回頭是岸 +回头草 回頭草 +回头见 回頭見 +回头路 回頭路 +回头车子 回頭車子 +回奉 回奉 +回娘家 回孃家 +回子 回子 +回字 回字 +回定 回定 +回家 回家 +回家乐 回家樂 +回家路 回家路 +回家路上 回家路上 +回家途中 回家途中 +回容 回容 +回山倒海 回山倒海 +回师 回師 +回帖 回帖 +回带 迴帶 +回席 回席 +回应 迴應 +回府 回府 +回廊 迴廊 +回弹 回彈 +回归 迴歸 +回归年 迴歸年 +回归潮 迴歸潮 +回归热 迴歸熱 +回归线 迴歸線 +回形夹 迴形夾 +回得 回得 +回得去 回得去 +回得来 回得來 +回心 迴心 +回心转意 回心轉意 +回忆 回憶 +回忆录 回憶錄 +回忆说 回憶說 +回忆起 回憶起 +回忌 回忌 +回念 回念 +回思 回思 +回想 回想 +回想到 回想到 +回想起 回想起 +回想起来 回想起來 +回惶 回惶 +回戏 回戲 +回手 回手 +回扣 回扣 +回执 回執 +回折格子 回折格子 +回护 迴護 +回报 回報 +回报率 回報率 +回拜 回拜 +回拨 回撥 +回掉 回掉 +回援 回援 +回收 回收 +回收价值 回收價值 +回收商 回收商 +回收场 回收場 +回收物 回收物 +回收率 回收率 +回收站 回收站 +回收量 回收量 +回放 回放 +回敎会议组织 回教會議組織 +回教 回教 +回教世界 回教世界 +回教人 回教人 +回教信徒 回教信徒 +回教党 回教黨 +回教国 回教國 +回教圣战 回教聖戰 +回教帝国 回教帝國 +回教开斋节 回教開齋節 +回教徒 回教徒 +回教忠孝节 回教忠孝節 +回敬 回敬 +回数票 回數票 +回文 迴文 +回文织锦 迴文織錦 +回斡 迴斡 +回旋 迴旋 +回族 回族 +回旨 回旨 +回易 回易 +回映 回映 +回春 回春 +回暖 回暖 +回望 回望 +回朝 回朝 +回本 回本 +回条 回條 +回来 回來 +回档 回檔 +回梦 迴夢 +回棋 回棋 +回椎 回椎 +回民 回民 +回民区 回民區 +回水 回水 +回波 回波 +回流 迴流 +回清倒影 迴清倒影 +回温 回溫 +回港 回港 +回游 迴游 +回溯 回溯 +回溯到 回溯到 +回滩 回灘 +回潮 回潮 +回潮率 回潮率 +回火 回火 +回灯 回燈 +回炉 回爐 +回炉复帐 回爐復帳 +回点 回點 +回煞 回煞 +回片 回片 +回状 回狀 +回环 迴環 +回环转折 迴環轉折 +回班 回班 +回球 回球 +回甘 回甘 +回生 回生 +回生乏术 回生乏術 +回生起死 回生起死 +回用 回用 +回电 回電 +回疆 回疆 +回盘 回盤 +回目 回目 +回盲瓣 迴盲瓣 +回看 回看 +回眸 回眸 +回眸一笑 回眸一笑 +回着 回着 +回示 回示 +回礼 回禮 +回神 回神 +回票面 回票面 +回禀 回稟 +回禄 回祿 +回禄之灾 回祿之災 +回程 回程 +回稳 回穩 +回穴 迴穴 +回空 回空 +回笼 回籠 +回答 回答 +回答出来 回答出來 +回答到 回答到 +回答说 回答說 +回籍 回籍 +回纥 回紇 +回纥兵 回紇兵 +回纥军 回紇軍 +回纳 回納 +回纹针 迴紋針 +回绕 迴繞 +回绝 回絕 +回翔 迴翔 +回老家 回老家 +回肠 迴腸 +回肠九回 回腸九回 +回肠九转 迴腸九轉 +回肠伤气 迴腸傷氣 +回肠寸断 迴腸寸斷 +回肠荡气 迴腸蕩氣 +回背 回背 +回腕 迴腕 +回航 回航 +回航途中 回航途中 +回船转舵 回船轉舵 +回良玉 回良玉 +回荡 迴盪 +回落 回落 +回补 回補 +回西流 回西流 +回见 回見 +回访 回訪 +回诊 回診 +回话 回話 +回诵 迴誦 +回请 回請 +回购 回購 +回购额 回購額 +回赎 回贖 +回赠 回贈 +回起 回起 +回跌 回跌 +回路 迴路 +回身 回身 +回车 回車 +回车键 回車鍵 +回转 迴轉 +回转仪 迴轉儀 +回转半径 回轉半徑 +回转寿司 回轉壽司 +回软 回軟 +回过 回過 +回过来 回過來 +回过神 回過神 +回返 回返 +回还 回還 +回送 回送 +回递性 迴遞性 +回途 回途 +回遑 回遑 +回道 回道 +回避 迴避 +回避学习 迴避學習 +回邪 回邪 +回邮 回郵 +回邮信封 回郵信封 +回部 回部 +回采 回採 +回銮 迴鑾 +回销 回銷 +回锅 回鍋 +回锅油 回鍋油 +回锅肉 回鍋肉 +回锋 回鋒 +回门 回門 +回阑 回闌 +回防 回防 +回阳荡气 迴陽蕩氣 +回雪 迴雪 +回青 回青 +回音 迴音 +回顾 回顧 +回风 迴風 +回飙 迴飆 +回飞棒 回飛棒 +回馈 回饋 +回首 回首 +回马 回馬 +回马枪 回馬槍 +回驳 回駁 +回魂仙梦 迴魂仙夢 +回鱼箸 回魚箸 +回鹘 回鶻 +回鹘文 回鶻文 +回黄倒皂 回黃倒皂 +回黄转绿 回黃轉綠 +因事制宜 因事制宜 +因于 因於 +因地制宜 因地制宜 +因奸成孕 因姦成孕 +因斯布鲁克 因斯布魯克 +因时制宜 因時制宜 +因果关系 因果關係 +因缘巧合 因緣巧合 +团丁 團丁 +团主 團主 +团书 團書 +团伙 團伙 +团体 團體 +团体冠军 團體冠軍 +团体协约 團體協約 +团体奖 團體獎 +团体性 團體性 +团体意识 團體意識 +团体操 團體操 +团体治疗 團體治療 +团体活动 團體活動 +团体票 團體票 +团体组 團體組 +团体行 團體行 +团体行动 團體行動 +团体规范 團體規範 +团体赛 團體賽 +团体辅导 團體輔導 +团保 團保 +团剥 團剝 +团勇 團勇 +团匪 團匪 +团名 團名 +团员 團員 +团团 團團 +团团围住 團團圍住 +团团转 團團轉 +团围 團圍 +团圆 團圓 +团圆夜 團圓夜 +团圆日 團圓日 +团圆节 團圓節 +团圆饭 團圓飯 +团坐 團坐 +团头 團頭 +团头团脸 團頭團臉 +团头聚面 團頭聚面 +团契 團契 +团委 團委 +团子 糰子 +团年 團年 +团康 團康 +团弄 團弄 +团扇 團扇 +团扇妾 團扇妾 +团拜 團拜 +团掿 團掿 +团旗 團旗 +团服 團服 +团栾 團欒 +团案 團案 +团沙群岛 團沙羣島 +团牌 團牌 +团状 團狀 +团瓢 團瓢 +团矿 團礦 +团社 團社 +团空 團空 +团管区 團管區 +团粉 糰粉 +团粒 團粒 +团练 團練 +团结 團結 +团结一心 團結一心 +团结一致 團結一致 +团结就是力量 團結就是力量 +团结工会 團結工會 +团聚 團聚 +团脐 團臍 +团脸 團臉 +团花 團花 +团茶 團茶 +团荷 團荷 +团藻 團藻 +团行 團行 +团购 團購 +团费 團費 +团部 團部 +团长 團長 +团队 團隊 +团队奖 團隊獎 +团队报 團隊報 +团队精神 團隊精神 +团队赛 團隊賽 +团音 團音 +团风 團風 +团风县 團風縣 +团香扇 團香扇 +团鱼 團魚 +团龙 團龍 +团龙儿 團龍兒 +团𪢮 團圞 +园游会 園遊會 +园游券 園遊券 +园里 園裏 +困乏 睏乏 +困了 困了 +困于 困於 +困人 困人 +困住 困住 +困倦 睏倦 +困倦起来 困倦起來 +困兽 困獸 +困兽之斗 困獸之鬥 +困兽犹斗 困獸猶鬥 +困厄 困厄 +困围 困圍 +困在 困在 +困境 困境 +困处 困處 +困处泥涂 困處泥塗 +困学 困學 +困守 困守 +困局 困局 +困心衡虑 困心衡慮 +困惑 困惑 +困惑不解 困惑不解 +困惫 困憊 +困意 睏意 +困扰 困擾 +困斗 困鬥 +困歇 困歇 +困滞 困滯 +困畏 困畏 +困知勉行 困知勉行 +困穷 困窮 +困窘 困窘 +困竭 困竭 +困腾腾 困騰騰 +困苦 困苦 +困觉 睏覺 +困话 困話 +困踬 困躓 +困蹙 困蹙 +困阨 困阨 +困阻 困阻 +困隘 困隘 +困难 困難 +困难在于 困難在於 +困难度 困難度 +困难点 困難點 +困难重重 困難重重 +困顿 困頓 +围了 圍了 +围困 圍困 +围困在 圍困在 +围场满族蒙古族自治县 圍場滿族蒙古族自治縣 +围岩 圍巖 +固于 固於 +固定制 固定制 +固定术 固定術 +固定汇率 固定匯率 +固征 固徵 +国一制 國一制 +国之桢干 國之楨榦 +国乐团 國樂團 +国于 國於 +国仇 國仇 +国会制 國會制 +国共两党 國共兩黨 +国共合作 國共合作 +国别 國別 +国别史 國別史 +国剧团 國劇團 +国务院台湾事务办公室 國務院臺灣事務辦公室 +国务院法制局 國務院法制局 +国历 國曆 +国历年 國曆年 +国发 國發 +国发院 國發院 +国台办 國臺辦 +国台语 國臺語 +国合会 國合會 +国困民艰 國困民艱 +国土规划 國土規劃 +国土资讯系统 國土資訊系統 +国外汇兑 國外匯兌 +国大主席团 國大主席團 +国大代表 國大代表 +国大代表部 國大代表部 +国大党 國大黨 +国家党 國家黨 +国家制度 國家制度 +国家发展和改革委员会 國家發展和改革委員會 +国家发展改革委 國家發展改革委 +国家发展计划委员会 國家發展計劃委員會 +国家外汇管理局 國家外匯管理局 +国家开发银行 國家開發銀行 +国家文物鉴定委员会 國家文物鑑定委員會 +国家旅游度假区 國家旅遊度假區 +国家杯 國家杯 +国家标准 國家標準 +国家标准中文交换码 國家標準中文交換碼 +国家标准化管理委员会 國家標準化管理委員會 +国家标准码 國家標準碼 +国家栋梁 國家棟梁 +国家永续发展论坛 國家永續發展論壇 +国家空气品质标准 國家空氣品質標準 +国家规范 國家規範 +国家计划委员会 國家計劃委員會 +国家食品药品监督管理局 國家食品藥品監督管理局 +国建学术联谊会 國建學術聯誼會 +国建计划 國建計劃 +国戚 國戚 +国戚皇亲 國戚皇親 +国术 國術 +国术团 國術團 +国术社 國術社 +国术馆 國術館 +国梁 國樑 +国民党 國民黨 +国民党军队 國民黨軍隊 +国民党员 國民黨員 +国民党版 國民黨版 +国民党籍 國民黨籍 +国民常用字标准字体表 國民常用字標準字體表 +国民生活须知 國民生活須知 +国民礼仪范例 國民禮儀範例 +国民裁判制 國民裁判制 +国民革命党 國民革命黨 +国泰综合医院 國泰綜合醫院 +国王杯 國王杯 +国社党 國社黨 +国科会同步幅射研究中心 國科會同步幅射研究中心 +国科会晶片设计制作中心 國科會晶片設計製作中心 +国科会精密仪器发展中心 國科會精密儀器發展中心 +国穷民困 國窮民困 +国立历史博物馆 國立歷史博物館 +国立台北科技大学 國立臺北科技大學 +国立台湾博物馆 國立臺灣博物館 +国立台湾图书馆 國立臺灣圖書館 +国立台湾技术大学 國立臺灣技術大學 +国立教育广播电台 國立教育廣播電臺 +国胄 國胄 +国药 國藥 +国语注音符号第一式 國語注音符號第一式 +国语注音符号第二式 國語注音符號第二式 +国贸系 國貿系 +国防体制 國防體制 +国际人权标准 國際人權標準 +国际体操联合会 國際體操聯合會 +国际先驱论坛报 國際先驅論壇報 +国际公制 國際公制 +国际关系 國際關係 +国际关系学院 國際關係學院 +国际准备 國際準備 +国际分工体制 國際分工體制 +国际单位制 國際單位制 +国际台 國際臺 +国际合作 國際合作 +国际合作节 國際合作節 +国际奥林匹克委员会 國際奧林匹克委員會 +国际学术网路 國際學術網路 +国际学舍 國際學舍 +国际开发总会 國際開發總會 +国际柜 國際櫃 +国际标准 國際標準 +国际标准书码 國際標準書碼 +国际标准化组织 國際標準化組織 +国际标准舞 國際標準舞 +国际水准 國際水準 +国际漫游 國際漫遊 +国际漫游拨接服务 國際漫遊撥接服務 +国际电影制片人协会联盟 國際電影製片人協會聯盟 +国际羽毛球联合会 國際羽毛球聯合會 +国际舞台 國際舞臺 +国际航空联合会 國際航空聯合會 +国际讬管制度 國際託管制度 +国际贷借 國際貸借 +国际足球联合会 國際足球聯合會 +图书巡回车 圖書巡迴車 +图书目录 圖書目錄 +图书餐饮复合式餐厅 圖書餐飲複合式餐廳 +图书馆周 圖書館週 +图亚克拜 圖亞克拜 +图像用户介面 圖像用戶介面 +图克 圖克 +图录 圖錄 +图形用户界面 圖形用戶界面 +图形界面 圖形界面 +图文并茂 圖文並茂 +图木舒克 圖木舒克 +图木舒克市 圖木舒克市 +图板 圖板 +图表 圖表 +图表说明 圖表說明 +图财致命 圖財致命 +图资系统 圖資系統 +图里 圖裏 +图里亚夫 圖里亞夫 +图里河 圖里河 +图鉴 圖鑑 +图面 圖面 +囿于 囿於 +囿于一时 囿於一時 +囿于成见 囿於成見 +圆台 圓臺 +圆周 圓周 +圆周率 圓周率 +圆周角 圓周角 +圆周运动 圓周運動 +圆形面包 圓形麪包 +圆板 圓板 +圆板状 圓板狀 +圆柱面 圓柱面 +圆舞曲 圓舞曲 +圆锥台 圓錐臺 +圆锥曲线 圓錐曲線 +圆雕 圓雕 +圆面大耳 圓面大耳 +圆面积 圓面積 +圆面饼 圓麪餅 +圈占 圈佔 +圈子里 圈子裏 +圈扣 圈釦 +圈杯 圈杯 +圈梁 圈樑 +圈里 圈裏 +圈里人 圈裏人 +土中曲蟮 土中曲蟮 +土制 土製 +土制品 土製品 +土参 土參 +土司面包 土司麪包 +土地利用规划 土地利用規劃 +土地征收 土地徵收 +土地重划 土地重劃 +土壤冲蚀 土壤沖蝕 +土布 土布 +土托鱼 土托魚 +土托鱼羹 土托魚羹 +土木工程学系 土木工程學系 +土木系 土木系 +土法炼钢 土法煉鋼 +土洋并举 土洋並舉 +土洋结合 土洋結合 +土种 土種 +土耳其进行曲 土耳其進行曲 +土药 土藥 +土谷祠 土穀祠 +土里 土裏 +土里土气 土裏土氣 +土霉素 土黴素 +圣修伯里 聖修伯里 +圣克里斯多福 聖克里斯多福 +圣克里斯托巴 聖克里斯托巴 +圣克鲁斯 聖克魯斯 +圣克鲁斯岛 聖克魯斯島 +圣哈辛托 聖哈辛托 +圣坛 聖壇 +圣塔蒙尼加 聖塔蒙尼加 +圣帕台风 聖帕颱風 +圣帕强台 聖帕強颱 +圣帕特里克 聖帕特里克 +圣帕袭台 聖帕襲臺 +圣德克旭贝里 聖德克旭貝里 +圣拉蒙 聖拉蒙 +圣杯 聖盃 +圣杰门队 聖傑門隊 +圣母升天节 聖母升天節 +圣潘克勒斯站 聖潘克勒斯站 +圣火台 聖火臺 +圣皮埃尔和密克隆 聖皮埃爾和密克隆 +圣神降临周 聖神降臨週 +圣胡安 聖胡安 +圣药 聖藥 +圣诞叶 聖誕葉 +圣诞百合 聖誕百合 +圣迹 聖蹟 +圣餐台 聖餐檯 +圣餐布 聖餐布 +在一定范围内 在一定範圍內 +在下面 在下面 +在世界范围内 在世界範圍內 +在于 在於 +在克制 在剋制 +在全国范围 在全國範圍 +在全国范围内 在全國範圍內 +在全省范围内 在全省範圍內 +在出 在出 +在台 在臺 +在台协会 在臺協會 +在后 在後 +在坛子胡同 在罈子胡同 +在天愿做比翼鸟在地愿做连理枝 在天願做比翼鳥在地願做連理枝 +在家修 在家修 +在家出家 在家出家 +在家千日好出门一时难 在家千日好出門一時難 +在家靠父母出外靠朋友 在家靠父母出外靠朋友 +在密切注意 在密切注意 +在念 在唸 +在某种程度上 在某種程度上 +在核 在覈 +在桥梁工地上 在橋梁工地上 +在此之后 在此之後 +在此后 在此後 +在泛 在泛 +在眼里 在眼裏 +在种 在種 +在职干部 在職幹部 +在职进修 在職進修 +在范围内 在範圍內 +在规范 在規範 +在野党 在野黨 +圭表 圭表 +地一卷 地一捲 +地下修文 地下修文 +地下修文郎 地下修文郎 +地下害虫 地下害蟲 +地下工厂 地下工廠 +地下开采 地下開採 +地下水面 地下水面 +地下电台 地下電臺 +地下签赌 地下簽賭 +地下通汇 地下通匯 +地丑德齐 地醜德齊 +地价 地價 +地价公告 地價公告 +地价税 地價稅 +地克制 地剋制 +地冲 地衝 +地制法 地制法 +地区党 地區黨 +地区冲突 地區衝突 +地区差价 地區差價 +地占 地佔 +地台 地臺 +地坛 地壇 +地塞米松 地塞米松 +地复天翻 地覆天翻 +地大物丰 地大物豐 +地尽其利 地盡其利 +地干吧 地幹吧 +地平面 地平面 +地当 地當 +地志 地誌 +地念 地念 +地方志 地方誌 +地方戏曲 地方戲曲 +地方色彩 地方色彩 +地无三里平 地無三里平 +地板 地板 +地板操 地板操 +地板运动 地板運動 +地极 地極 +地核 地核 +地灵人杰 地靈人傑 +地热发电厂 地熱發電廠 +地牛发威 地牛發威 +地狱谷 地獄谷 +地球同步轨道 地球同步軌道 +地理 地理 +地理极 地理極 +地理资讯系统 地理資訊系統 +地瓜叶 地瓜葉 +地瓜签 地瓜籤 +地瓜面 地瓜面 +地缘关系 地緣關係 +地缝里 地縫裏 +地老天荒不了情 地老天荒不了情 +地胄 地胄 +地蜡 地蠟 +地表 地表 +地表水 地表水 +地质年代表 地質年代表 +地质年表 地質年表 +地质编录 地質編錄 +地里 地裏 +地里鬼 地裏鬼 +地面 地面 +地面上 地面上 +地面下 地面下 +地面层 地面層 +地面控制 地面控制 +地面核爆炸 地面核爆炸 +地面气压 地面氣壓 +地面水 地面水 +地面温度 地面溫度 +地面灌溉 地面灌溉 +地面站 地面站 +地面部队 地面部隊 +地面零点 地面零點 +场合 場合 +场记板 場記板 +场面 場面 +场面阔绰 場面闊綽 +均一价 均一價 +均权制度 均權制度 +均田制 均田制 +均田制度 均田制度 +坊曲 坊曲 +坍台 坍臺 +坎塔布连 坎塔布連 +坎塔布连山脉 坎塔布連山脈 +坎塔布连海 坎塔布連海 +坏了 壞了 +坏了性命 壞了性命 +坏于 壞於 +坏家伙 壞傢伙 +坏恶 壞惡 +坐了 坐了 +坐冷板凳 坐冷板凳 +坐台 坐檯 +坐台子 坐檯子 +坐台小姐 坐檯小姐 +坐回 坐回 +坐困 坐困 +坐困愁城 坐困愁城 +坐如钟 坐如鐘 +坐山观虎斗 坐山觀虎鬥 +坐庄 坐莊 +坐板疮 坐板瘡 +坐标 座標 +坐标系 座標系 +坐致 坐致 +坐药 坐藥 +坐萝卜 坐蘿蔔 +坐薪尝胆 坐薪嘗膽 +坐蜡 坐蠟 +坐钟 坐鐘 +坐领干薪 坐領乾薪 +坑蒙 坑蒙 +坑里 坑裏 +块肉馀生录 塊肉餘生錄 +坚白同异 堅白同異 +坚臥烟霞 堅臥煙霞 +坚致 堅緻 +坛佳酿 罈佳釀 +坛兆 壇兆 +坛台 壇臺 +坛场 壇場 +坛坛罐罐 罈罈罐罐 +坛坫 壇坫 +坛坫周旋 壇坫周旋 +坛城 壇城 +坛女儿红 罈女兒紅 +坛好酒 罈好酒 +坛子 罈子 +坛宇 壇宇 +坛烧刀子 罈燒刀子 +坛燒刀子 罈燒刀子 +坛白干 罈白干 +坛美酒 罈美酒 +坛老酒 罈老酒 +坛陈年 罈陳年 +坛騞 罈騞 +坛高粱 罈高粱 +坡布莱 坡布萊 +坤极 坤極 +坤范 坤範 +坤表 坤錶 +坦克 坦克 +坦克兵 坦克兵 +坦克型 坦克型 +坦克车 坦克車 +坦坦荡荡 坦坦蕩蕩 +坦尚尼亚联合共和国 坦尚尼亞聯合共和國 +坦涂 坦塗 +坦荡 坦蕩 +坦荡荡 坦蕩蕩 +坨里 坨里 +坯布 坯布 +坱郁 坱鬱 +垂了 垂了 +垂了下去 垂了下去 +垂了下来 垂了下來 +垂于 垂於 +垂于将来 垂於將來 +垂发 垂髮 +垂吊 垂吊 +垂帘 垂簾 +垂帘听政 垂簾聽政 +垂念 垂念 +垂死挣扎 垂死掙扎 +垂注 垂注 +垂涎欲滴 垂涎欲滴 +垂直于 垂直於 +垂直搜索 垂直搜索 +垂直面 垂直面 +垂范 垂範 +垂范百世 垂範百世 +垂裕后昆 垂裕後昆 +垂面 垂面 +垂馨千祀 垂馨千祀 +垃圾回收 垃圾回收 +垃圾虫 垃圾蟲 +垄断价格 壟斷價格 +垄断资产 壟斷資產 +垄断集团 壟斷集團 +型别 型別 +型别转换 型別轉換 +型录 型錄 +型录式广告 型錄式廣告 +型板 型板 +型范 型範 +垢面 垢面 +垣曲 垣曲 +垣曲县 垣曲縣 +垦丁杯 墾丁盃 +垦复 墾複 +垦辟 墾闢 +垫个 墊個 +垫了 墊了 +垫出 墊出 +垫出去 墊出去 +垫出来 墊出來 +垫发 墊發 +垫回 墊回 +垫回去 墊回去 +垫回来 墊回來 +垫板 墊板 +垮了 垮了 +垮台 垮臺 +垮向 垮向 +埃克托 埃克托 +埃克托柏辽兹 埃克托柏遼茲 +埃及历 埃及曆 +埃及历史 埃及歷史 +埃及艳后 埃及豔后 +埃夫伯里 埃夫伯里 +埃布罗 埃布羅 +埃布罗河 埃布羅河 +埃德蒙顿 埃德蒙頓 +埃拉托塞尼斯 埃拉托塞尼斯 +埃格尔松 埃格爾松 +埃荣冲 埃榮衝 +埃里温 埃裏溫 +埋了 埋了 +埋头寻表 埋頭尋錶 +埋头寻钟 埋頭尋鐘 +埋头寻钟表 埋頭尋鐘錶 +埋头苦干 埋頭苦幹 +埋尸 埋屍 +埋布 埋佈 +埋杆竖柱 埋杆豎柱 +埋没人才 埋沒人才 +城市依赖症 城市依賴症 +城市规划 城市規劃 +城里 城裏 +城雕 城雕 +埔里 埔里 +埔里社抚垦局 埔裏社撫墾局 +埔里镇 埔里鎮 +域名抢注 域名搶注 +域名注册 域名註冊 +域多利皇后 域多利皇后 +埤塘里 埤塘里 +培养出 培養出 +培养出来 培養出來 +培尔松 培爾松 +培植出 培植出 +培特曼赫鲁威克 培特曼赫魯威克 +培美曲塞 培美曲塞 +培育出 培育出 +培育出来 培育出來 +培里克利斯 培裏克利斯 +培里克里斯 培里克里斯 +基于 基於 +基克维特 基克維特 +基准 基準 +基准兵 基準兵 +基准日 基準日 +基准法 基準法 +基准点 基準點 +基准线 基準線 +基准面 基準面 +基因修改 基因修改 +基因技术 基因技術 +基因表达 基因表達 +基团 基團 +基地台 基地臺 +基尔库克 基爾庫克 +基岩 基岩 +基布兹 基布茲 +基干 基幹 +基度山恩仇记 基度山恩仇記 +基性岩石 基性岩石 +基本多文种平面 基本多文種平面 +基本词汇 基本詞彙 +基本面 基本面 +基板 基板 +基极 基極 +基民党 基民黨 +基里兰柯 基里蘭柯 +基里巴斯 基里巴斯 +基里巴斯共和国 基裏巴斯共和國 +基面 基面 +堂分姑娘 堂分姑娘 +堂后官 堂後官 +堂屋里挂草荐 堂屋裏掛草薦 +堂布 堂布 +堆了 堆了 +堆案盈几 堆案盈几 +堕云雾中 墮雲霧中 +堕胎药 墮胎藥 +堙淀 堙澱 +堪为表率 堪爲表率 +堪布 堪布 +堪当 堪當 +堪当重任 堪當重任 +堪称典范 堪稱典範 +堪舆术 堪輿術 +塌台 塌臺 +塑炼 塑煉 +塑炼机 塑煉機 +塑胶制 塑膠製 +塑胶布 塑膠布 +塑胶杯 塑膠杯 +塑胶板 塑膠板 +塑造出 塑造出 +塔什干 塔什干 +塔什库尔干乡 塔什庫爾干鄉 +塔什库尔干塔吉克自治县 塔什庫爾干塔吉克自治縣 +塔什库尔干自治县 塔什庫爾干自治縣 +塔克 塔克 +塔克拉玛干 塔克拉瑪干 +塔克拉玛干沙漠 塔克拉瑪干沙漠 +塔克拉马干 塔克拉馬干 +塔克辛 塔克辛 +塔台 塔臺 +塔吉克 塔吉克 +塔吉克人 塔吉克人 +塔吉克共和国 塔吉克共和國 +塔吉克斯坦 塔吉克斯坦 +塔吉克族 塔吉克族 +塔吊 塔吊 +塔娜苏冈 塔娜蘇岡 +塔娜苏甘 塔娜蘇甘 +塔布 塔布 +塔波兰尼克 塔波蘭尼克 +塔罗维克 塔羅維克 +塔里契亚努 塔里契亞努 +塔里木 塔里木 +塔里木河 塔里木河 +塔里木盆地 塔里木盆地 +塔里班 塔里班 +塔钟 塔鐘 +塞上曲 塞上曲 +塞下曲 塞下曲 +塞克 塞克 +塞克森 塞克森 +塞回 塞回 +塞尔提克 塞爾提克 +塞尔提克队 塞爾提克隊 +塞尔维亚克罗地亚语 塞爾維亞克羅地亞語 +塞尔维亚民主党 塞爾維亞民主黨 +塞尔蒂克 塞爾蒂克 +塞尔蒂克队 塞爾蒂克隊 +塞瓦斯托波尔 塞瓦斯托波爾 +塞耳盗钟 塞耳盜鐘 +塞药 塞藥 +塞莉佛维克 塞莉佛維克 +塞车症候群 塞車症候羣 +塞韦里诺 塞韋裏諾 +填个 填個 +填了 填了 +填发 填發 +填字游戏 填字遊戲 +填表 填表 +填表格 填表格 +墓志 墓誌 +墓志铭 墓誌銘 +墓表 墓表 +墙里 牆裏 +墙面 牆面 +墙面而立 牆面而立 +增修 增修 +增辟 增闢 +增量参数 增量參數 +墟里 墟里 +墨卷 墨卷 +墨发 墨髮 +墨斗 墨斗 +墨斗鱼 墨斗魚 +墨沈 墨沈 +墨沈未干 墨瀋未乾 +墨沈沈 墨沈沈 +墨索里尼 墨索里尼 +墨荡子 墨盪子 +墨西哥合众国 墨西哥合衆國 +墨迹未干 墨跡未乾 +墩台 墩臺 +墩布 墩布 +壁志 壁誌 +壁立千仞 壁立千仞 +壁钟 壁鐘 +壑谷 壑谷 +士别三日 士別三日 +士别三日刮目相待 士別三日刮目相待 +士别多日 士別多日 +士胄 士胄 +壮室之秋 壯室之秋 +壮志 壯志 +壮志凌云 壯志凌雲 +壮志凌霄 壯志凌霄 +壮志未酬 壯志未酬 +壮游 壯遊 +壮阳药 壯陽藥 +壮面 壯麪 +声价 聲價 +声价不凡 聲價不凡 +声价十倍 聲價十倍 +声如洪钟 聲如洪鐘 +声彻云霄 聲徹雲霄 +声情并茂 聲情並茂 +声类系统 聲類系統 +壳里 殼裏 +壶口瀑布 壺口瀑布 +壶范 壺範 +壶里 壺裏 +壶里乾坤 壺裏乾坤 +壹个人 壹個人 +壹周刊 壹週刊 +壹败涂地 壹敗塗地 +壹郁 壹鬱 +处于 處於 +处女表演 處女表演 +处方药 處方藥 +处理 處理 +处理厂 處理廠 +处理表 處理表 +备尝 備嘗 +备尝忧患 備嘗憂患 +备尝艰苦 備嘗艱苦 +备尝艰辛 備嘗艱辛 +备尝辛苦 備嘗辛苦 +备御 備禦 +备忘录 備忘錄 +备抵折旧 備抵折舊 +备注 備註 +备注栏 備註欄 +复三 復三 +复上 覆上 +复业 復業 +复习 複習 +复习考 複習考 +复书 復書 +复交 復交 +复亩珍 複畝珍 +复仇 復仇 +复仇者 復仇者 +复仇记 復仇記 +复仇雪耻 復仇雪恥 +复仞年如 複仞年如 +复以百万 複以百萬 +复任 復任 +复会 復會 +复位 復位 +复住 覆住 +复信 覆信 +复健 復健 +复健中心 復健中心 +复健医学 復健醫學 +复健科 復健科 +复健赛 復健賽 +复元 復元 +复元音 複元音 +复共轭 複共軛 +复兴 復興 +复兴中学 復興中學 +复兴乡 復興鄉 +复兴党 復興黨 +复兴剧校 復興劇校 +复兴剧艺学校 復興劇藝學校 +复兴北路 復興北路 +复兴区 復興區 +复兴南路 復興南路 +复兴号 復興號 +复兴基地 復興基地 +复兴岗 復興崗 +复兴岛 復興島 +复兴工商 復興工商 +复兴广播 復興廣播 +复兴广播电台 復興廣播電臺 +复兴时代 復興時代 +复兴社 復興社 +复兴路 復興路 +复兴门 復興門 +复兴馆 復興館 +复兴高中 復興高中 +复冒 覆冒 +复写 複寫 +复写纸 複寫紙 +复军 覆軍 +复军杀将 覆軍殺將 +复冰 復冰 +复决 複決 +复决权 複決權 +复出 復出 +复函 覆函 +复函数 複函數 +复分数 複分數 +复分析 複分析 +复分解 複分解 +复分解反应 複分解反應 +复刊 復刊 +复列 複列 +复利 複利 +复利法 複利法 +复利率 複利率 +复利计算 複利計算 +复制 複製 +复制下来 複製下來 +复制出 複製出 +复制品 複製品 +复刻 復刻 +复华 復華 +复华金 復華金 +复卒 復卒 +复印 複印 +复印品 複印品 +复印机 複印機 +复印纸 複印紙 +复原 復原 +复原期 復原期 +复去翻来 覆去翻來 +复发 復發 +复发性 複發性 +复发率 複發率 +复变函数 複變函數 +复变函数论 複變函數論 +复古 復古 +复古会 復古會 +复古风 復古風 +复句 複句 +复叶 複葉 +复合 複合 +复合企业 複合企業 +复合传动 複合傳動 +复合体 複合體 +复合元音 複合元音 +复合光 複合光 +复合包装 複合包裝 +复合句 複合句 +复合命题 複合命題 +复合国 複合國 +复合型 複合型 +复合增长 複合增長 +复合字 複合字 +复合年 複合年 +复合式 複合式 +复合性 複合性 +复合技 複合技 +复合摄影 複合攝影 +复合机 複合機 +复合材料 複合材料 +复合板 複合板 +复合架 複合架 +复合样式 複合樣式 +复合概念 複合概念 +复合模 複合模 +复合母音 複合母音 +复合民族国家 複合民族國家 +复合物 複合物 +复合管 複合管 +复合肥料 複合肥料 +复合膜 複合膜 +复合药 複合藥 +复合蛋白质 複合蛋白質 +复合装甲 複合裝甲 +复合词 複合詞 +复合词素词 複合詞素詞 +复合量词 複合量詞 +复合金属 複合金屬 +复合韵母 複合韻母 +复名 複名 +复名数 複名數 +复名词 複名詞 +复吸 復吸 +复呈 覆呈 +复员 復員 +复员令 復員令 +复命 覆命 +复品牌 複品牌 +复回 復回 +复国 復國 +复圆 復圓 +复土 復土 +复圣 復聖 +复在 覆在 +复基因 複基因 +复墓 覆墓 +复壁 複壁 +复壮 復壯 +复复 複復 +复始 復始 +复姓 複姓 +复婚 復婚 +复婚制 複婚制 +复子明辟 復子明辟 +复字键 複字鍵 +复学 復學 +复学生 復學生 +复宗 覆宗 +复审 複審 +复对数 複對數 +复工 復工 +复帐 覆帳 +复帱 覆幬 +复平面 複平面 +复庇之恩 覆庇之恩 +复康巴士 復康巴士 +复建 復建 +复建中心 復建中心 +复式 複式 +复式关税 複式關稅 +复式教学 複式教學 +复式路面 複式路面 +复归 復歸 +复役 復役 +复循环发电 複循環發電 +复思 復思 +复意 複意 +复成 覆成 +复拍子 複拍子 +复按 覆按 +复政 復政 +复数 複數 +复数域 複數域 +复数平面 複數平面 +复数形 複數形 +复数形式 複數形式 +复文 覆文 +复新 復新 +复方 複方 +复旦 復旦 +复旦大学 復旦大學 +复旦桥 復旦橋 +复旧 復舊 +复旧如新 復舊如新 +复明 復明 +复本 複本 +复本位制度 複本位制度 +复杂 複雜 +复杂劳动 複雜勞動 +复杂化 複雜化 +复杂度 複雜度 +复杂度理论 複雜度理論 +复杂性 複雜性 +复杂生产 複雜生產 +复杂系统 複雜系統 +复权 復權 +复杯 覆杯 +复果 複果 +复查 複查 +复査 複查 +复校 覆校 +复核 複覈 +复案 復案 +复检 複檢 +复次 複次 +复殖吸虫 複殖吸蟲 +复殖目 複殖目 +复比 複比 +复比例 複比例 +复氧能力 復氧能力 +复水 覆水 +复没 覆沒 +复活 復活 +复活岛 復活島 +复活日 復活日 +复活的军团 復活的軍團 +复活节 復活節 +复活节岛 復活節島 +复活赛 復活賽 +复流 複流 +复测 複測 +复海移山 覆海移山 +复灭 覆滅 +复燃 復燃 +复现 復現 +复瓿 覆瓿 +复生 復生 +复用 複用 +复电 覆電 +复盂 覆盂 +复盂之固 覆盂之固 +复盂之安 覆盂之安 +复盆 覆盆 +复盆之冤 覆盆之冤 +复盆子 覆盆子 +复盆难照 覆盆難照 +复盐 複鹽 +复盖 覆蓋 +复盖住 覆蓋住 +复盖率 覆蓋率 +复盖面 覆蓋面 +复盘 覆盤 +复盘难照 覆盤難照 +复目 複目 +复相关 複相關 +复眼 複眼 +复礼 復禮 +复礼克己 復禮克己 +复种 複種 +复种指数 複種指數 +复称 複稱 +复穴 複穴 +复籍 復籍 +复线 複線 +复综语 複綜語 +复耕 復耕 +复职 復職 +复肥 複肥 +复育 覆育 +复舟 覆舟 +复舟载舟 覆舟載舟 +复色 複色 +复色光 複色光 +复苏 復甦 +复苏期 復甦期 +复苏术 復甦術 +复萌 復萌 +复蔽 覆蔽 +复蕉寻鹿 覆蕉尋鹿 +复被 覆被 +复襦 複襦 +复视 複視 +复训 複訓 +复议 複議 +复评 複評 +复诊 複診 +复词 複詞 +复试 複試 +复诵 複誦 +复读 復讀 +复读生 復讀生 +复课 復課 +复败 覆敗 +复赛 複賽 +复蹈其辙 復蹈其轍 +复蹈前辙 復蹈前轍 +复身 復身 +复车 覆車 +复车之戒 覆車之戒 +复车之轨 覆車之軌 +复车之辙 覆車之轍 +复车之鉴 覆車之鑑 +复车当戒 覆車當戒 +复车继轨 覆車繼軌 +复转 復轉 +复载 覆載 +复辅音 複輔音 +复辙 覆轍 +复辙重蹈 覆轍重蹈 +复辟 復辟 +复辟事件 復辟事件 +复返 復返 +复述 複述 +复逆 覆逆 +复选 複選 +复选题 複選題 +复道 複道 +复酱瓿 覆醬瓿 +复醒 復醒 +复醢 覆醢 +复钱 複錢 +复阁 複閣 +复阅 複閱 +复除 復除 +复雠 復讎 +复雨翻云 覆雨翻雲 +复露 覆露 +复音 複音 覆音 +复音形 複音形 +复音词 複音詞 +复韵 複韻 +复韵母 複韻母 +复频 複頻 +复验 複驗 +复魄 復魄 +复鹿寻蕉 覆鹿尋蕉 +复鹿遗蕉 覆鹿遺蕉 +复鼎 覆鼎 +复𫗧 覆餗 +复𫗧之忧 覆餗之憂 +复𫗧之患 覆餗之患 +复𫗧之衅 覆餗之釁 +夏于乔 夏于喬 +夏于喬 夏于喬 +夏历 夏曆 +夏后氏 夏后氏 +夏商周 夏商周 +夏天里 夏天裏 +夏姆锡克 夏姆錫克 +夏川里美 夏川里美 +夏布 夏布 +夏日里 夏日裏 +夏时制 夏時制 +夏洛克 夏洛克 +夏游 夏遊 +夏炉冬扇 夏爐冬扇 +夏秋 夏秋 +夏种 夏種 +夏虫 夏蟲 +夏虫不可以语冰 夏蟲不可以語冰 +夏虫不可语冰 夏蟲不可語冰 +夏虫朝菌 夏蟲朝菌 +夏里夫 夏里夫 +夏鑪冬扇 夏鑪冬扇 +夕烟 夕煙 +外交代表 外交代表 +外交关系 外交關係 +外交关系理事会 外交關係理事會 +外交团 外交團 +外交系 外交系 +外佣 外傭 +外侧裂周区 外側裂周區 +外借 外借 +外出 外出 +外出服 外出服 +外出血 外出血 +外出装 外出裝 +外出访问 外出訪問 +外制 外製 +外厂 外廠 +外发 外發 +外合里差 外合裏差 +外合里应 外合裏應 +外后日 外後日 +外向 外向 +外向型 外向型 +外国旅游者 外國旅遊者 +外屋里的灶君爷 外屋裏的竈君爺 +外弦 外弦 +外强中干 外強中乾 +外御其侮 外禦其侮 +外戚 外戚 +外才 外才 +外挂 外掛 +外挂式 外掛式 +外文系 外文系 +外明不知里暗 外明不知裏暗 +外来物种 外來物種 +外来种 外來種 +外松内紧 外鬆內緊 +外核 外核 +外欲 外慾 +外汇 外匯 +外汇储备 外匯儲備 +外汇兑换 外匯兌換 +外汇存底 外匯存底 +外汇定期存单 外匯定期存單 +外汇局 外匯局 +外汇市场 外匯市場 +外汇收入 外匯收入 +外汇汇率 外匯匯率 +外汇管制 外匯管制 +外汇银行 外匯銀行 +外涂 外塗 +外烟 外菸 +外用药 外用藥 +外科学系 外科學系 +外科手术 外科手術 +外聘制 外聘制 +外舍 外舍 +外蒙 外蒙 +外蒙古 外蒙古 +外表 外表 +外表上 外表上 +外语系 外語系 +外调制 外調制 +外部链接 外部鏈接 +外面 外面 +外面儿光 外面兒光 +外面情 外面情 +夙仇 夙仇 +夙心往志 夙心往志 +夙愿 夙願 +夙愿以偿 夙願以償 +多不胜数 多不勝數 +多丑 多醜 +多么 多麼 +多义关系 多義關係 +多事之秋 多事之秋 +多事逞才 多事逞才 +多于 多於 +多云 多雲 +多云偶 多雲偶 +多云偶阵雨 多雲偶陣雨 +多云偶雨 多雲偶雨 +多云有雨 多雲有雨 +多人聊天系统 多人聊天系統 +多余 多餘 +多侧面 多側面 +多借 多借 +多党 多黨 +多党制 多黨制 +多党选举 多黨選舉 +多冲 多衝 +多凶少吉 多凶少吉 +多出 多出 +多出来 多出來 +多功能表 多功能表 +多动症 多動症 +多占 多佔 +多原作艺术 多原作藝術 +多发性 多發性 +多发病 多發病 +多只 多隻 +多台 多臺 +多吃多占 多吃多佔 +多向 多向 +多哈回合 多哈回合 +多回 多回 +多天后 多天後 +多妻制 多妻制 +多姿多彩 多姿多彩 +多姿多采 多姿多采 +多媒体杂志 多媒體雜誌 +多媒体简报系统 多媒體簡報系統 +多少只 多少隻 +多层复 多層複 +多层复迭 多層複迭 +多干 多幹 +多平台 多平臺 +多平台环境 多平臺環境 +多幸 多幸 +多式综合语 多式綜合語 +多当 多當 +多彩 多彩 +多彩多姿 多彩多姿 +多情种子 多情種子 +多才 多才 +多才多艺 多才多藝 +多拉尔蒙 多拉爾蒙 +多指症 多指症 +多数党 多數黨 +多方面 多方面 +多极化 多極化 +多核 多核 +多模光纤 多模光纖 +多欲 多欲 +多汗症 多汗症 +多特蒙德 多特蒙德 +多种 多種 +多种多样 多種多樣 +多种经营 多種經營 +多种语言 多種語言 +多种语言支持 多種語言支持 +多管闲事 多管閒事 +多米尼克 多米尼克 +多粒子系统 多粒子系統 +多蒙寄声 多蒙寄聲 +多蒙推毂 多蒙推轂 +多蒙药石 多蒙藥石 +多表 多表 +多轨录音 多軌錄音 +多边合作 多邊合作 +多采 多采 +多采多姿 多采多姿 +多里 多里 +多面 多面 +多面体 多面體 +多面性 多面性 +多面手 多面手 +多面角 多面角 +夜儿个 夜兒個 +夜光云 夜光雲 +夜光杯 夜光杯 +夜光虫 夜光蟲 +夜光表 夜光錶 +夜半钟声 夜半鐘聲 +夜台 夜臺 +夜合 夜合 +夜合花 夜合花 +夜合钱 夜合錢 +夜尿症 夜尿症 +夜度娘 夜度娘 +夜惊症 夜驚症 +夜暗 夜暗 +夜暗风高 夜暗風高 +夜曲 夜曲 +夜游 夜遊 +夜游子 夜遊子 +夜游神 夜遊神 +夜游队 夜遊隊 +夜盲症 夜盲症 +夜色迷蒙 夜色迷濛 +夜谭随录 夜譚隨錄 +夜里 夜裏 +夜雨秋灯录 夜雨秋燈錄 +够了 夠了 +够克制 夠剋制 +够凶 夠兇 +够出 夠出 +够涂 夠塗 +够种 夠種 +够钟情 夠鍾情 +够钟爱 夠鍾愛 +夠面子 夠面子 +大一统志 大一統誌 +大不了 大不了 +大不相同 大不相同 +大不里士 大不里士 +大丑 大丑 +大专同学 大專同學 +大专杯 大專盃 +大业千秋 大業千秋 +大个 大個 +大个儿 大個兒 +大个子 大個子 +大丰 大豐 +大丰市 大豐市 +大丰收 大豐收 +大丰簋 大豐簋 +大义觉迷录 大義覺迷錄 +大乌苏里岛 大烏蘇里島 +大事化小小事化了 大事化小小事化了 +大于 大於 +大人药 大人藥 +大仁药专 大仁藥專 +大价钱 大價錢 +大众捷运系统 大衆捷運系統 +大伙 大夥 +大伙人 大夥人 +大伙儿 大夥兒 +大余 大餘 +大余县 大餘縣 +大便干燥 大便乾燥 +大修 大修 +大修理 大修理 +大修理基金 大修理基金 +大修道院 大修道院 +大修道院长 大修道院長 +大借款 大借款 +大傢伙儿 大傢伙兒 +大元大一统志 大元大一統誌 +大党 大黨 +大兵团 大兵團 +大冲 大沖 +大减价 大減價 +大凶 大凶 +大出 大出 +大出丧 大出喪 +大出其汗 大出其汗 +大出意料之外 大出意料之外 +大出手 大出手 +大出血 大出血 +大出锋头 大出鋒頭 +大出风头 大出風頭 +大利面 大利麪 +大别 大別 +大别山 大別山 +大别山脉 大別山脈 +大制作 大製作 +大力发展 大力發展 +大动干戈 大動干戈 +大千 大千 +大千世界 大千世界 +大华技术学院 大華技術學院 +大协奏曲 大協奏曲 +大单于 大單于 +大卤面 大滷麪 +大卷 大卷 +大厂 大廠 +大厂县 大廠縣 +大厂回族自治县 大廠回族自治縣 +大历 大曆 +大历十才子 大曆十才子 +大历史 大歷史 +大厦栋梁 大廈棟梁 +大发 大發 +大发利市 大發利市 +大发慈悲 大發慈悲 +大发牢骚 大發牢騷 +大发神威 大發神威 +大发脾气 大發脾氣 +大发雷霆 大發雷霆 +大叔于田 大叔于田 +大只 大隻 +大台 大臺 +大台北 大臺北 +大台北区 大臺北區 +大叶合欢 大葉合歡 +大叶大学 大葉大學 +大叶性肺炎 大葉性肺炎 +大叶桉 大葉桉 +大叶野百合 大葉野百合 +大叹 大嘆 +大合唱 大合唱 +大同 大同 +大同世界 大同世界 +大同主义 大同主義 +大同之世 大同之世 +大同乡 大同鄉 +大同书 大同書 +大同区 大同區 +大同县 大同縣 +大同商专 大同商專 +大同国中 大同國中 +大同大学 大同大學 +大同小异 大同小異 +大同市 大同市 +大同教 大同教 +大同煤矿 大同煤礦 +大同盆地 大同盆地 +大同盟 大同盟 +大同社会 大同社會 +大同路 大同路 +大后天 大後天 +大后年 大後年 +大后方 大後方 +大周后 大周后 +大周折 大周折 +大咸 大咸 +大哗 大譁 +大回 大回 +大回朝 大回朝 +大团 大團 +大团圆 大團圓 +大团白脸 大團白臉 +大团结 大團結 +大国家党 大國家黨 +大地回春 大地回春 +大地春回 大地春回 +大场面 大場面 +大型钟 大型鐘 +大型钟表 大型鐘錶 +大型钟表面 大型鐘表面 +大型钟面 大型鐘面 +大天后宫 大天后宮 +大夫松 大夫松 +大头症 大頭症 +大头针 大頭針 +大头面目 大頭面目 +大夸 大誇 +大奸 大奸 +大奸似忠 大奸似忠 +大姑娘 大姑娘 +大姑娘坐花轿 大姑娘坐花轎 +大娘 大娘 +大娘子 大娘子 +大家伙儿 大家夥兒 +大家风范 大家風範 +大尽 大盡 +大山谷州立大学 大山谷州立大學 +大岩桐 大巖桐 +大峡谷 大峽谷 +大布 大布 +大布棚 大布棚 +大干 大幹 +大干一场 大幹一場 +大干一票 大幹一票 +大干特干 大幹特幹 +大幸 大幸 +大廉价 大廉價 +大当 大當 +大志 大志 +大恶 大惡 +大才 大才 +大才小用 大才小用 +大才槃槃 大才槃槃 +大打出手 大打出手 +大打折扣 大打折扣 +大折儿 大摺兒 +大抚台 大撫臺 +大搜 大搜 +大摆 大擺 +大摆褶子 大擺褶子 +大摇大摆 大搖大擺 +大放异彩 大放異彩 +大放异采 大放異采 +大政方针 大政方針 +大敌当前 大敵當前 +大斗 大斗 +大斗小秤 大斗小秤 +大方向 大方向 +大旱云霓 大旱雲霓 +大旱望云霓 大旱望雲霓 +大明历 大明曆 +大明历史 大明歷史 +大明大摆 大明大擺 +大是不同 大是不同 +大曲 大麴 +大曲道 大曲道 +大曲酒 大麴酒 +大有分别 大有分別 +大有斩获 大有斬獲 +大本钟 大本鐘 +大本钟敲 大本鐘敲 +大来历 大來歷 +大杯 大杯 +大板 大板 +大板根 大板根 +大板车 大板車 +大核 大核 +大梁 大梁 大樑 +大楼监控系统 大樓監控系統 +大欖涌 大欖涌 +大欲 大欲 +大武仑 大武崙 +大气团 大氣團 +大气折射 大氣折射 +大气系 大氣系 +大水冲倒龙王庙 大水沖倒龍王廟 +大水冲倒龙王殿 大水沖倒龍王殿 +大水冲溺 大水沖溺 +大汉技术学院 大漢技術學院 +大汗淋漓 大汗淋漓 +大海捞针 大海撈針 +大涌 大涌 +大润发 大潤發 +大涨小回 大漲小回 +大清一统志 大清一統志 +大湄公河次区域合作 大湄公河次區域合作 +大溪豆干 大溪豆幹 +大烟 大煙 +大爱台 大愛臺 +大班制 大班制 +大理岩 大理岩 +大病初愈 大病初癒 +大症 大症 +大白日里借不出个干灯盏来 大白日裏借不出個乾燈盞來 +大目干连 大目乾連 +大目干连冥间救母变文 大目乾連冥間救母變文 +大秋 大秋 +大秋作物 大秋作物 +大秋元 大秋元 +大笨钟 大笨鐘 +大笨钟敲 大笨鐘敲 +大精彩 大精彩 +大系 大系 +大缸里翻油沿路拾芝麻 大缸裏翻油沿路拾芝麻 +大老板 大老闆 +大而无当 大而無當 +大肆搜捕 大肆搜捕 +大肠杆菌 大腸桿菌 +大肠杆菌群 大腸桿菌羣 +大胜 大勝 +大胡子 大鬍子 +大脑出血性中风 大腦出血性中風 +大脚婆娘 大腳婆娘 +大腔当 大腔當 +大致 大致 +大致上 大致上 +大致说来 大致說來 +大舍 大舍 +大花面 大花面 +大苏打 大蘇打 +大英联合王国 大英聯合王國 +大范围 大範圍 +大获 大獲 +大获全胜 大獲全勝 +大虫 大蟲 +大虫不吃伏肉 大蟲不吃伏肉 +大虫口里倒涎 大蟲口裏倒涎 +大虫吃小虫 大蟲吃小蟲 +大虫头上做窠 大蟲頭上做窠 +大蜡 大蜡 +大衍历 大衍曆 +大衍历史 大衍歷史 +大表 大表 +大表哥 大表哥 +大表妹 大表妹 +大表姊 大表姊 +大表弟 大表弟 +大表惊叹 大表驚歎 +大裂谷 大裂谷 +大角度俯冲轰炸 大角度俯衝轟炸 +大言非夸 大言非夸 +大谷 大谷 +大象口里拔生牙 大象口裏拔生牙 +大费周折 大費周折 +大费周章 大費周章 +大赞 大讚 +大辟 大辟 +大迦叶 大迦葉 +大通回族土族自治县 大通回族土族自治縣 +大通师范学堂 大通師範學堂 +大采 大采 +大里 大里 +大里市 大里市 +大里溪 大里溪 +大金发苔 大金髮薹 +大鉴 大鑒 +大钟 大鐘 +大锤 大錘 +大门不出二门不迈 大門不出二門不邁 +大陆冷气团 大陸冷氣團 +大陆同胞 大陸同胞 +大陆团 大陸團 +大陆性气团 大陸性氣團 +大陆板块 大陸板塊 +大陆气团 大陸氣團 +大陆法系 大陸法系 +大陪审团 大陪審團 +大难不死必有后禄 大難不死必有後祿 +大难不死必有后福 大難不死必有後福 +大集合 大集合 +大雨如注 大雨如注 +大面 大面 +大面儿上 大面兒上 +大面皮儿 大面皮兒 +大风后 大風後 +大风鉴 大風鑑 +大食团 大食團 +大马步挂 大馬步掛 +大麦克 大麥克 +大麦克指数 大麥克指數 +大麻烟 大麻煙 +大麻里 大麻里 +大麻里乡 大麻里鄉 +大黑松 大黑松 +天下大势分久必合合久必分 天下大勢分久必合合久必分 +天下安注意相天下危注意将 天下安注意相天下危注意將 +天下无难事只怕有心人 天下無難事只怕有心人 +天下杂志 天下雜誌 +天不从人愿 天不從人願 +天人合一 天人合一 +天人永别 天人永別 +天从人愿 天從人願 +天价 天價 +天作之合 天作之合 +天克地冲 天剋地衝 +天冬氨酸 天冬氨酸 +天冬苯丙二肽酯 天冬苯丙二肽酯 +天冬酰胺 天冬醯胺 +天历 天曆 +天发神谶碑 天發神讖碑 +天台 天台 天臺 +天台县 天台縣 +天台女 天台女 +天台宗 天台宗 +天台山 天台山 +天同 天同 +天后 天后 天後 +天后站 天后站 +天后级 天后級 +天团 天團 +天地万物 天地萬物 +天地为范 天地爲範 +天地之别 天地之別 +天地可表 天地可表 +天地志狼 天地志狼 +天坛 天壇 +天坛座 天壇座 +天壤之别 天壤之別 +天复 天覆 +天复地载 天覆地載 +天妒英才 天妒英才 +天孙娘娘 天孫娘娘 +天差地别 天差地別 +天干 天干 +天干地支 天干地支 +天干物燥 天乾物燥 +天幸 天幸 +天心和合 天心和合 +天心岩 天心岩 +天才 天才 +天才儿童 天才兒童 +天才出自勤奋 天才出自勤奮 +天才型 天才型 +天才教育 天才教育 +天才横溢 天才橫溢 +天才论 天才論 +天文台 天文臺 +天文学钟 天文學鐘 +天文钟 天文鐘 +天无三日晴地无三里平 天無三日晴地無三里平 +天日之表 天日之表 +天昏地暗 天昏地暗 +天暗 天暗 +天有不测风云 天有不測風雲 +天有不测风云人有旦夕祸福 天有不測風雲人有旦夕禍福 +天机云锦 天機雲錦 +天津师范 天津師範 +天津师范大学 天津師範大學 +天渊之别 天淵之別 +天潢贵胄 天潢貴胄 +天然纤维 天然纖維 +天璇 天璇 +天生干 天生幹 +天盟誓表现 天盟誓表現 +天纳克 天納克 +天纵之才 天縱之才 +天缘凑合 天緣湊合 +天缘巧合 天緣巧合 +天缘注定 天緣注定 +天翻地复 天翻地覆 +天花板 天花板 +天表 天表 +天要下雨娘要嫁人 天要下雨孃要嫁人 +天要落雨娘要嫁人 天要落雨孃要嫁人 +天覆地载 天覆地載 +天路历程 天路歷程 +天门冬 天門冬 +天门冬科 天門冬科 +天随人愿 天隨人願 +太乙神针 太乙神針 +太仆 太僕 +太仆寺 太僕寺 +太仆寺卿 太僕寺卿 +太仆寺旗 太僕寺旗 +太公钓鱼愿者上钩 太公釣魚願者上鉤 +太冲 太沖 +太初历 太初曆 +太初历史 太初歷史 +太卜 太卜 +太原师范学院 太原師範學院 +太后 太后 +太咸 太鹹 +太好了 太好了 +太子党 太子黨 +太子舍人 太子舍人 +太干 太乾 +太平御览 太平御覽 +太平洋周边 太平洋周邊 +太平洋联合铁路 太平洋聯合鐵路 +太扯了 太扯了 +太松 太鬆 +太极 太極 +太极剑 太極劍 +太极图 太極圖 +太极图说 太極圖說 +太极拳 太極拳 +太极门 太極門 +太皇太后 太皇太后 +太空天文台 太空天文臺 +太空游 太空遊 +太空艺术 太空藝術 +太谷 太谷 +太谷县 太谷縣 +太谷灯 太谷燈 +太阳升 太陽昇 +太阳历 太陽曆 +太阳微系统公司 太陽微系統公司 +太阳照在桑干河上 太陽照在桑乾河上 +太阳电池板 太陽電池板 +太阳神计划 太陽神計劃 +太阳系 太陽系 +太阳能板 太陽能板 +太阳谷 太陽谷 +太阳黑子周 太陽黑子週 +太阴历 太陰曆 +太麻里 太麻里 +太麻里乡 太麻里鄉 +太麻里溪 太麻里溪 +夫党 夫黨 +夫力 伕力 +夫妇关系 夫婦關係 +夫妇合璧 夫婦合璧 +夫妇好合 夫婦好合 +夫妻关系 夫妻關係 +夫娘 夫娘 +夫子 夫子 伕子 +夫役 伕役 +夭折 夭折 +央浼营干 央浼營幹 +夯土建筑 夯土建築 +夯干 夯幹 +失之毫厘 失之毫釐 +失之毫厘差之千里 失之毫釐差之千里 +失之毫厘差以千里 失之毫釐差以千里 +失之毫厘谬以千里 失之毫厘謬以千里 +失于 失於 +失体面 失體面 +失信于人 失信於人 +失修 失修 +失准 失準 +失出 失出 +失张失志 失張失志 +失当 失當 +失忆症 失憶症 +失志 失志 +失据 失據 +失智症 失智症 +失眠症 失眠症 +失而复得 失而復得 +失语症 失語症 +失读症 失讀症 +失调症 失調症 +失面子 失面子 +失饥伤饱 失飢傷飽 +头一回 頭一回 +头上打一下脚底板响 頭上打一下腳底板響 +头发 頭髮 +头发上指 頭髮上指 +头发了狂 頭發了狂 +头发了疯 頭發了瘋 +头发壳子 頭髮殼子 +头发胡子一把抓 頭髮鬍子一把抓 +头向前 頭向前 +头回 頭回 +头巾吊在水里 頭巾弔在水裏 +头当 頭當 +头彩 頭彩 +头悬梁锥刺股 頭懸梁錐刺股 +头昏眼暗 頭昏眼暗 +头朝里 頭朝裏 +头板 頭板 +头柜 頭櫃 +头破血出 頭破血出 +头脑发胀 頭腦發脹 +头脑简单四肢发达 頭腦簡單四肢發達 +头花发 頭花髮 +头足愿 頭足願 +头里 頭裏 +头面 頭面 +头面人物 頭面人物 +夷坚志 夷堅志 +夸下海口 誇下海口 +夸丽 夸麗 +夸了 誇了 +夸人 夸人 +夸克 夸克 +夸克星 夸克星 +夸功 誇功 +夸口 誇口 +夸嘴 誇嘴 +夸多斗靡 誇多鬥靡 +夸大 誇大 +夸大不实 誇大不實 +夸大之词 誇大之詞 +夸大其词 誇大其詞 +夸大其辞 誇大其辭 +夸大狂 誇大狂 +夸夸 誇誇 +夸夸其谈 誇誇其談 +夸奖 誇獎 +夸姣 夸姣 +夸官 誇官 +夸容 夸容 +夸尔 夸爾 +夸张 誇張 +夸张其辞 誇張其辭 +夸张法 誇張法 +夸强说会 誇強說會 +夸得 誇得 +夸成 誇成 +夸才卖智 誇才賣智 +夸来夸去 誇來誇去 +夸毗 夸毗 +夸海口 誇海口 +夸父 夸父 +夸父逐日 夸父逐日 +夸特 夸特 +夸示 誇示 +夸耀 誇耀 +夸胜道强 誇勝道強 +夸能斗智 誇能鬥智 +夸脱 夸脫 +夸诞 夸誕 +夸诞不经 夸誕不經 +夸诩 誇詡 +夸说 誇說 +夸赞 誇讚 +夸起 誇起 +夸起来 誇起來 +夸辩 誇辯 +夸过 誇過 +夸饰 誇飾 +夹个 夾個 +夹了 夾了 +夹克 夾克 +夹布子 夾布子 +夹当儿 夾當兒 +夹彩塑 夾彩塑 +夹心饼干 夾心餅乾 +夹板 夾板 +夹板气 夾板氣 +夹板船 夾板船 +夹注 夾註 +夹注号 夾注號 +夺回 奪回 +夺回去 奪回去 +夺回来 奪回來 +夺彩 奪彩 +夺志 奪志 +夺斗 奪鬥 +夺杯 奪盃 +夺眶而出 奪眶而出 +夺门而出 奪門而出 +奇丑 奇醜 +奇丑无比 奇醜無比 +奇冤极枉 奇冤極枉 +奇努克 奇努克 +奇台 奇台 +奇台县 奇臺縣 +奇岩 奇巖 +奇异夸克 奇異夸克 +奇彩 奇彩 +奇志 奇志 +奇才 奇才 +奇才异能 奇才異能 +奇术 奇術 +奇杯 奇盃 +奇袭战术 奇襲戰術 +奇迹 奇蹟 +奇里安 奇里安 +奈向 奈向 +奉公克己 奉公剋己 +奉别 奉別 +奉复 奉復 +奉干 奉干 +奉毂后车 奉轂後車 +奉献出 奉獻出 +奉系 奉系 +奉系军阀 奉系軍閥 +奉苹蘩 奉蘋蘩 +奉药 奉藥 +奉蒸尝 奉蒸嘗 +奉表 奉表 +奉辛比克党 奉辛比克黨 +奋勇向前 奮勇向前 +奋勇当先 奮勇當先 +奋发 奮發 +奋发向上 奮發向上 +奋发图强 奮發圖強 +奋发有为 奮發有爲 +奋发自强 奮發自強 +奋发蹈厉 奮發蹈厲 +奋志 奮志 +奋斗 奮鬥 +奋斗不懈 奮鬥不懈 +奋斗到底 奮鬥到底 +奋斗目标 奮鬥目標 +奎尼匹克 奎尼匹克 +奎松市 奎松市 +奏了 奏了 +奏于 奏於 +奏出 奏出 +奏出去 奏出去 +奏出来 奏出來 +奏折 奏摺 +奏曲 奏曲 +奏表 奏表 +奏鸣曲 奏鳴曲 +奏鸣曲式 奏鳴曲式 +契努克 契努克 +契合 契合 +契合度 契合度 +契合金兰 契合金蘭 +契据 契據 +契沙比克湾 契沙比克灣 +奔出 奔出 +奔向 奔向 +奔回 奔回 +奔回来 奔回來 +奖借 獎借 +奖励制度 獎勵制度 +奖杯 獎盃 +奖赞 獎贊 +套个 套個 +套了 套了 +套出 套出 +套出来 套出來 +套曲 套曲 +套板 套板 +套汇 套匯 +套种 套種 +套装旅游 套裝旅遊 +套问出 套問出 +套马杆 套馬杆 +奢念 奢念 +奥万大 奧萬大 +奥克兰 奧克蘭 +奥克拉荷马 奧克拉荷馬 +奥克拉荷马州 奧克拉荷馬州 +奥克拉荷马市 奧克拉荷馬市 +奥克斯纳德 奧克斯納德 +奥克明 奧克明 +奥克苏斯河 奧克蘇斯河 +奥克蒙 奧克蒙 +奥兰多布鲁 奧蘭多布魯 +奥占 奧佔 +奥士力克 奧士力克 +奥妮克西亚 奧妮克西亞 +奥密克戎 奧密克戎 +奥尔布赖特 奧爾布賴特 +奥布里 奧布里 +奥德修斯 奧德修斯 +奥托 奧托 +奥托瓦兹 奧托瓦茲 +奥拜克 奧拜克 +奥杜伐峡谷 奧杜伐峽谷 +奥林匹克 奧林匹克 +奥林匹克世运 奧林匹克世運 +奥林匹克体育场 奧林匹克體育場 +奥林匹克日 奧林匹克日 +奥林匹克精神 奧林匹克精神 +奥林匹克运动会 奧林匹克運動會 +奥林匹克运动会组织委员会 奧林匹克運動會組織委員會 +奥特朗托 奧特朗托 +奥特朗托海峡 奧特朗托海峽 +奥运团 奧運團 +奥迪修斯 奧迪修斯 +奥里斯 奧里斯 +奥里萨 奧里薩 +奥里萨省 奧里薩省 +奥里萨邦 奧里薩邦 +奥里里亚 奧里里亞 +奥陶系 奧陶系 +奧克拉荷马州 奧克拉荷馬州 +女丑 女丑 +女丑剧场 女丑劇場 +女中豪杰 女中豪傑 +女乳症 女乳症 +女人心海底针 女人心海底針 +女仆 女僕 +女仆部 女僕部 +女佣 女傭 +女佣人 女傭人 +女修士 女修士 +女修道 女修道 +女修道张 女修道張 +女修道院 女修道院 +女同 女同 +女同志 女同志 +女同胞 女同胞 +女大当嫁 女大當嫁 +女大须嫁 女大須嫁 +女娘 女娘 +女子参政主义 女子參政主義 +女子参政权 女子參政權 +女宿舍 女宿舍 +女尸 女屍 +女御 女御 +女性厌恶 女性厭惡 +女性第二性征 女性第二性徵 +女性艺术 女性藝術 +女性艺术史 女性藝術史 +女杰 女傑 +女王杯 女王杯 +女生外向 女生外嚮 +女秀才 女秀才 +女系家族 女系家族 +女舍监 女舍監 +女药头 女藥頭 +女貌郎才 女貌郎才 +女长须嫁 女長須嫁 +奴仆 奴僕 +奴儿干 奴兒干 +奴儿干都司 奴兒干都司 +奴才 奴才 +奴隶制 奴隸制 +奴隶制度 奴隸制度 +奶制品 奶製品 +奶卷 奶捲 +奶妈怀里的孩子 奶媽懷裏的孩子 +奶娘 奶孃 +奸人 奸人 +奸人之雄 奸人之雄 +奸伏 姦伏 +奸佞 奸佞 +奸俏 奸俏 +奸党 奸黨 +奸凶 姦凶 +奸刁 奸刁 +奸匪 奸匪 +奸同鬼蜮 奸同鬼蜮 +奸商 奸商 +奸夫 姦夫 +奸夫淫妇 姦夫淫婦 +奸妇 姦婦 +奸宄 奸宄 +奸官污吏 奸官污吏 +奸尸 姦屍 +奸巧 奸巧 +奸徒 奸徒 +奸恶 奸惡 +奸情 姦情 +奸慝 奸慝 +奸杀 姦殺 +奸棍 奸棍 +奸毒 奸毒 +奸污 姦污 +奸淫 姦淫 +奸淫掳掠 姦淫擄掠 +奸滑 奸滑 +奸狡 奸狡 +奸猾 奸猾 +奸盗邪淫 姦盜邪淫 +奸笑 奸笑 +奸细 奸細 +奸胥猾吏 奸胥猾吏 +奸臣 奸臣 +奸言 奸言 +奸计 奸計 +奸诈 奸詐 +奸诈不级 奸詐不級 +奸谋 奸謀 +奸贼 奸賊 +奸通 姦通 +奸邪 奸邪 +奸险 奸險 +奸雄 奸雄 +奸非 姦非 +奸顽 奸頑 +奸骗 奸騙 +奸黠 奸黠 +她克制 她剋制 +她准知 她準知 +好一出 好一齣 +好不了 好不了 +好不容易才 好不容易纔 +好丑 好醜 +好个 好個 +好了 好了 +好了吗 好了嗎 +好了吧 好了吧 +好了歌 好了歌 +好于 好於 +好价 好價 +好体面 好體面 +好傢伙 好傢伙 +好兵帅克 好兵帥克 +好几 好幾 +好几万 好幾萬 +好几个 好幾個 +好几亿 好幾億 +好几十 好幾十 +好几十万 好幾十萬 +好几千 好幾千 +好几千万 好幾千萬 +好几天 好幾天 +好几年 好幾年 +好几百 好幾百 +好几百万 好幾百萬 +好凶 好凶 +好出 好出 +好出风头 好出風頭 +好勇斗狠 好勇鬥狠 +好合 好合 +好向 好向 +好咸 好鹹 +好善嫉恶 好善嫉惡 +好善恶恶 好善惡惡 +好困 好睏 +好困吧 好睏吧 +好困啊 好睏啊 +好多个 好多個 +好好地干 好好地幹 +好好学习天天向上 好好學習天天向上 +好好干 好好幹 +好家伙 好傢伙 +好干 好乾 +好当 好當 +好彩头 好彩頭 +好心倒做了驴肝肺 好心倒做了驢肝肺 +好恶 好惡 +好戏还在后头 好戲還在後頭 +好戏连台 好戲連臺 +好手如云 好手如雲 +好斗 好鬥 +好斗笠 好斗笠 +好斗篷 好斗篷 +好斗胆 好斗膽 +好时是他人恶时是家人 好時是他人惡時是家人 +好暗 好暗 +好极了 好極了 +好死不如恶活 好死不如惡活 +好气万千 好氣萬千 +好汉不怕出身低 好漢不怕出身低 +好汉不论出身低 好漢不論出身低 +好汉做事好汉当 好漢做事好漢當 +好汉只怕病来磨 好漢只怕病來磨 +好生恶杀 好生惡殺 +好立克 好立克 +好签 好籤 +好管闲事 好管閒事 +好胜 好勝 +好胜心 好勝心 +好自矜夸 好自矜誇 +好话当作耳边风 好話當作耳邊風 +好话说尽 好話說盡 +好谀恶直 好諛惡直 +好逸恶劳 好逸惡勞 +好酒贪杯 好酒貪杯 +好采头 好采頭 +好面子 好面子 +如不胜衣 如不勝衣 +如临深谷 如臨深谷 +如临渊谷 如臨淵谷 +如于 如於 +如云 如雲 +如何干 如何幹 +如入云端 如入雲端 +如入宝山空手回 如入寶山空手回 +如出一口 如出一口 +如出一辙 如出一轍 +如同 如同 +如坐云雾 如坐雲霧 +如坐针毡 如坐鍼氈 +如堕五里雾中 如墮五里霧中 +如堕烟雾 如墮煙霧 +如干 如干 +如愿 如願 +如愿以偿 如願以償 +如所周知 如所周知 +如日东升 如日東昇 +如日方升 如日方升 +如有雷同 如有雷同 +如果干 如果幹 +如法泡制 如法泡製 +如法炮制 如法炮製 +如获珍宝 如獲珍寶 +如获至宝 如獲至寶 +如隔三秋 如隔三秋 +如须 如須 +如饥似渴 如飢似渴 +如饥如渴 如飢如渴 +妄念 妄念 +妄想症 妄想症 +妆台 妝臺 +妇人生须 婦人生鬚 +妇女团体 婦女團體 +妇女杂志 婦女雜誌 +妇女联合会 婦女聯合會 +妊娠毒血症 妊娠毒血症 +妖后 妖后 +妖术 妖術 +妖术惑众 妖術惑衆 +妖术邪法 妖術邪法 +妖气冲天 妖氣沖天 +妖精谷 妖精谷 +妖里妖气 妖里妖氣 +妙发灵机 妙發靈機 +妙妙熊历险记 妙妙熊歷險記 +妙手回春 妙手回春 +妙才 妙才 +妙探寻凶 妙探尋兇 +妙曲 妙曲 +妙极 妙極 +妙极了 妙極了 +妙药 妙藥 +妢胡 妢胡 +妥当 妥當 +妥当人 妥當人 +妻党 妻黨 +始于 始於 +始愿 始願 +姌袅 姌嫋 +姑娘 姑娘 +姑娘家 姑娘家 +姑息养奸 姑息養奸 +姑恶 姑惡 +姑苏 姑蘇 +姑表 姑表 +姓岳 姓岳 +姓系 姓系 +委员制 委員制 +委托 委託 +委托书 委託書 +委托人 委託人 +委曲 委曲 +委曲成全 委曲成全 +委曲求全 委曲求全 +委派代表 委派代表 +委罪于人 委罪於人 +姘出去 姘出去 +姚俊杰 姚俊傑 +姚升志 姚昇志 +姚志源 姚志源 +姚采颖 姚采穎 +姜丝 薑絲 +姜丰年 姜豐年 +姜凤君 姜鳳君 +姜切片 薑切片 +姜夔 姜夔 +姜大宇 姜大宇 +姜太公 姜太公 +姜嫄 姜嫄 +姜子牙 姜子牙 +姜家大被 姜家大被 +姜宸英 姜宸英 +姜尚 姜尚 +姜就是老 薑就是老 +姜建铭 姜建銘 +姜愈老愈辣 薑愈老愈辣 +姜文杰 姜文杰 +姜是老 薑是老 +姜是老的辣 薑是老的辣 +姜末 薑末 +姜桂 薑桂 +姜桂老辣 薑桂老辣 +姜母 薑母 +姜母鸭 薑母鴨 +姜汁 薑汁 +姜汤 薑湯 +姜沧源 姜滄源 +姜片 薑片 +姜石年 薑石年 +姜竹祥 姜竹祥 +姜糖 薑糖 +姜维 姜維 +姜维平 姜維平 +姜老辣 薑老辣 +姜至奂 姜至奐 +姜芋 姜芋 +姜茶 薑茶 +姜蓉 薑蓉 +姜越老越辣 薑越老越辣 +姜辣 薑辣 +姜辣素 薑辣素 +姜还是老 薑還是老 +姜还是老的辣 薑還是老的辣 +姜远珍 姜遠珍 +姜郁美 姜郁美 +姜金龙 姜金龍 +姜锡柱 姜錫柱 +姜饼 薑餅 +姜麻园 薑麻園 +姜黄 薑黃 +姜黄素 薑黃素 +姜黄色 薑黃色 +姨娘 姨娘 姨孃 +姨表 姨表 +姬姜 姬姜 +姬松茸 姬松茸 +姱修 姱修 +姻党 姻黨 +姻戚 姻戚 +姿采 姿采 +威克岛 威克島 +威克斯 威克斯 +威克森 威克森 +威克菲尔 威克菲爾 +威克菲尔德 威克菲爾德 +威奇托 威奇托 +威尔生氏症 威爾生氏症 +威布里吉 威布里吉 +威廉亚历山大 威廉亞歷山大 +威比苏诺 威比蘇諾 +威氏注音法 威氏注音法 +威里斯 威里斯 +威风八面 威風八面 +娇娘 嬌娘 +娇嫩欲滴 嬌嫩欲滴 +娇艳欲滴 嬌豔欲滴 +娇袅不胜 嬌嫋不勝 +娘亲 孃親 +娘儿 孃兒 +娘儿们 娘兒們 +娘儿俩 孃兒倆 +娘姨 孃姨 +娘娘 娘娘 +娘娘庙 娘娘廟 +娘娘腔 娘娘腔 +娘婆 娘婆 +娘子 娘子 +娘子关 娘子關 +娘子军 娘子軍 +娘家 孃家 +娘家姓 孃家姓 +娘母子 娘母子 +娘的 孃的 +娘老子 孃老子 +娘胎 孃胎 +娘舅 孃舅 +娩出 娩出 +娱乐台 娛樂臺 +娴于 嫺於 +娴于辞令 嫺於辭令 +娶了 娶了 +娶回 娶回 +娶回家 娶回家 +婆娘 婆娘 +婆娘子 婆娘子 +婚前婚后 婚前婚後 +婚后 婚後 +婚姻制度 婚姻制度 +婢仆 婢僕 +婴儿猝死症候群 嬰兒猝死症候羣 +婴儿猝死综合症 嬰兒猝死綜合症 +婶娘 嬸孃 +媒人口无量斗 媒人口無量斗 +媒人婆迷了路 媒人婆迷了路 +媒体狂并潮 媒體狂併潮 +媒体访问控制 媒體訪問控制 +媒合 媒合 +媚如秋月 媚如秋月 +媮合苟容 媮合苟容 +媵御 媵御 +嫁个 嫁個 +嫁个老公 嫁個老公 +嫁了 嫁了 +嫁于 嫁於 +嫁出 嫁出 +嫁出去 嫁出去 +嫁出来 嫁出來 +嫁祸于 嫁禍於 +嫁祸于人 嫁禍於人 +嫉恶 嫉惡 +嫉恶好善 嫉惡好善 +嫉恶如仇 嫉惡如仇 +嫉恶若仇 嫉惡若仇 +嫌凶 嫌兇 +嫌好道丑 嫌好道醜 +嫌好道恶 嫌好道惡 +嫌恶 嫌惡 +嫔御 嬪御 +嫠忧宗周 嫠憂宗周 +嫡出 嫡出 +嫡系 嫡系 +嫩叶 嫩葉 +嬉游 嬉遊 +嬖幸 嬖倖 +嬴余 嬴餘 +子之丰兮 子之丰兮 +子云 子云 +子叶 子葉 +子姜炒鸡 子薑炒雞 +子孙娘娘 子孫娘娘 +子宫內膜异位症 子宮內膜異位症 +子曰诗云 子曰詩云 +子杰 子傑 +子母钟 子母鐘 +子游 子游 +子癫前症 子癲前症 +子目录 子目錄 +子系统 子系統 +子集合 子集合 +孔明借箭 孔明借箭 +孔章望斗 孔章望斗 +孔虫 孔蟲 +孕出 孕出 +孕穗 孕穗 +孕穗期 孕穗期 +孕育出 孕育出 +孖虫 孖蟲 +字据 字據 +字根合体字 字根合體字 +字根表 字根表 +字母表 字母表 +字汇 字彙 +字汇判断任务 字彙判斷任務 +字码表 字碼表 +字表 字表 +字表输入法 字表輸入法 +字里 字裏 +字里行间 字裏行間 +字面 字面 +字面上 字面上 +字面意义 字面意義 +字面意思 字面意思 +字面解释 字面解釋 +字音表 字音表 +存于 存於 +存亡之秋 存亡之秋 +存亡未卜 存亡未卜 +存十一于千百 存十一於千百 +存录 存錄 +存念 存念 +存托凭证 存託憑證 +存托股 存托股 +存扣 存扣 +存折 存摺 +存款准备率 存款準備率 +存款准备金 存款準備金 +存款准备金率 存款準備金率 +孙协志 孫協志 +孙大千 孫大千 +孙杰 孫杰 +孙胜男 孫勝男 +孝布 孝布 +孝重千斤日减一斤 孝重千斤日減一斤 +孟什维克 孟什維克 +孟冬 孟冬 +孟姜女 孟姜女 +孟小冬 孟小冬 +孟尝君 孟嘗君 +孟德尔松 孟德爾松 +孟村回族自治县 孟村回族自治縣 +孟秋 孟秋 +孟获 孟獲 +孢子叶 孢子葉 +孢子虫 孢子蟲 +季冬 季冬 +季后 季後 +季后赛 季後賽 +季咸 季咸 +季布 季布 +季布一诺 季布一諾 +季札挂剑 季札掛劍 +季瑟雅克 季瑟雅克 +季秋 季秋 +季节洄游 季節洄游 +孤云 孤雲 +孤云野鹤 孤雲野鶴 +孤儿药 孤兒藥 +孤军奋斗 孤軍奮鬥 +孤凄 孤悽 +孤寡不谷 孤寡不穀 +孤形只影 孤形隻影 +孤形吊影 孤形吊影 +孤征 孤征 +孤拐 孤拐 +孤拐面 孤拐面 +孤注 孤注 +孤注一掷 孤注一擲 +孤涂 孤塗 +孤游 孤遊 +孤灯挑尽 孤燈挑盡 +孤身只影 孤身隻影 +孤辰合注 孤辰合注 +学习团 學習團 +学习曲线 學習曲線 +学习范例 學習範例 +学习计划 學習計劃 +学了个不留 學了個不留 +学以致用 學以致用 +学优才赡 學優才贍 +学位制度 學位制度 +学分制 學分制 +学制 學制 +学力鉴定 學力鑑定 +学区制 學區制 +学历 學歷 學曆 +学台 學臺 +学名药 學名藥 +学员制 學員制 +学回 學回 +学回去 學回去 +学回来 學回來 +学士后医学系 學士後醫學系 +学徒制 學徒制 +学术 學術 +学术团体 學術團體 +学术奖 學術獎 +学术性 學術性 +学术报告 學術報告 +学术文化团体 學術文化團體 +学术水平 學術水平 +学术界 學術界 +学术研究 學術研究 +学术科 學術科 +学术组 學術組 +学术网路 學術網路 +学术自由 學術自由 +学校同学 學校同學 +学浅才疏 學淺才疏 +学然后知不足 學然後知不足 +学疏才浅 學疏才淺 +学籍表 學籍表 +学系 學系 +学经历 學經歷 +学舍 學舍 +学里 學裏 +学长制 學長制 +孩儿面 孩兒面 +孬种 孬種 +孱困 孱困 +孵出 孵出 +孵出来 孵出來 +孽党 孽黨 +孽种 孽種 +孽障种子 孽障種子 +宁个 寧個 +宁中则 甯中則 +宁夏回族 寧夏回族 +宁夏回族自治区 寧夏回族自治區 +宁庄子 甯莊子 +宁当玉碎 寧當玉碎 +宁悼子 甯悼子 +宁惠子 甯惠子 +宁愿 寧願 +宁成子 甯成子 +宁戚 甯戚 +宁折不弯 寧折不彎 +宁撞金钟一下不打破鼓三千 寧撞金鐘一下不打破鼓三千 +宁斧成 甯斧成 +宁武子 甯武子 +宁浩 甯浩 +宁猛力 甯猛力 +宁调元 甯調元 +宁越 甯越 +宁静致远 寧靜致遠 +宅舍 宅舍 +宇宙云 宇宙雲 +宇宙志 宇宙誌 +守先待后 守先待後 +守制 守制 +守御 守禦 +守正不回 守正不回 +守舍 守舍 +守节不回 守節不回 +安万特 安萬特 +安了 安了 +安于 安於 +安于一隅 安於一隅 +安于泰山 安於泰山 +安于现状 安於現狀 +安仁鬓秋 安仁鬢秋 +安克拉 安克拉 +安克拉治 安克拉治 +安克雷奇 安克雷奇 +安全系数 安全係數 +安全系统 安全系統 +安全防范 安全防範 +安可曲 安可曲 +安吉里科 安吉里科 +安地卡及巴布达 安地卡及巴布達 +安山岩 安山岩 +安布罗斯 安布羅斯 +安席克 安席克 +安扎 安扎 +安提瓜和巴布达 安提瓜和巴布達 +安杰 安傑 +安格鲁萨克逊 安格魯薩克遜 +安步当车 安步當車 +安沈铁路 安瀋鐵路 +安眠药 安眠藥 +安纳托利亚 安納托利亞 +安胎药 安胎藥 +安胡 安胡 +安营扎寨 安營紮寨 +安萨里 安薩里 +安适 安適 +安适如常 安適如常 +安钦云 安欽雲 +安闲惬意 安閒愜意 +安闲自在 安閒自在 +安闲自得 安閒自得 +安闲舒适 安閒舒適 +安闲随意 安閒隨意 +安魂弥撒 安魂彌撒 +安魂曲 安魂曲 +宋三彩 宋三彩 +宋亨欣叶纯豪 宋亨欣葉純豪 +宋克 宋克 +宋干节 宋干節 +宋板 宋板 +完了 完了 +完全叶 完全葉 +完全愈复 完全癒復 +完全正确 完全正確 +完工后 完工後 +完成后 完成後 +完税价格 完稅價格 +完税货价 完稅貨價 +宏志 宏志 +宏愿 宏願 +宏碁集团 宏碁集團 +宗周 宗周 +宗周钟 宗周鐘 +宗教团 宗教團 +宗教团体 宗教團體 +宗法制度 宗法制度 +官不怕大只怕管 官不怕大只怕管 +官价 官價 +官兵一致 官兵一致 +官准 官准 +官制 官制 +官卷 官卷 +官历 官曆 +官台木 官臺木 +官商合办 官商合辦 +官地为采 官地爲寀 +官复原职 官復原職 +官庄 官莊 +官念 官念 +官报私仇 官報私仇 +官料药 官料藥 +官板儿 官板兒 +官私合营 官私合營 +官能团 官能團 +官能症 官能症 +官舍 官舍 +官面 官面 +官面儿 官面兒 +定义出 定義出 +定义范围 定義範圍 +定了 定了 +定于 定於 +定于一尊 定於一尊 +定价 定價 +定准 定準 +定出 定出 +定出来 定出來 +定制 定製 +定制化 定製化 +定南针 定南針 +定向 定向 +定向培育 定向培育 +定向天线 定向天線 +定向越野 定向越野 +定弦 定弦 +定当 定當 +定时号志 定時號誌 +定时钟 定時鐘 +定点厂 定點廠 +定理 定理 +定碳杯 定碳杯 +定胜败 定勝敗 +定范围 定範圍 +定计划 定計劃 +定都于 定都於 +定风针 定風針 +宛若游龙 宛若游龍 +宛转周折 宛轉周折 +宜丰 宜豐 +宜丰县 宜豐縣 +宜于 宜於 +宜云 宜云 +宝丰 寶豐 +宝丰县 寶豐縣 +宝卷 寶卷 +宝历 寶曆 +宝山庄 寶山莊 +宝山空回 寶山空回 +宝庄 寶莊 +宝志 寶誌 +宝胄 寶胄 +宝贝团 寶貝團 +宝里宝气 寶里寶氣 +宝鉴 寶鑑 +宝钢集团 寶鋼集團 +实业计划 實業計劃 +实价 實價 +实况录影 實況錄影 +实况录音 實況錄音 +实发 實發 +实名制 實名制 +实干 實幹 +实干家 實幹家 +实录 實錄 +实才 實才 +实据 實據 +实时技术 實時技術 +实用价值 實用價值 +实症 實症 +实质面 實質面 +实践是检验真理的唯一标准 實踐是檢驗真理的唯一標準 +实际范围 實際範圍 +宠幸 寵幸 +审囚刷卷 審囚刷卷 +审干 審幹 +审曲面势 審曲面勢 +审核 審覈 +审理 審理 +审级制度 審級制度 +审计范围 審計範圍 +客串演出 客串演出 +客制化 客製化 +客制化服务 客製化服務 +客如云集 客如雲集 +客游 客遊 +客舍 客舍 +宣传周 宣傳週 +宣卷 宣卷 +宣室志 宣室志 +宣布 宣佈 +宣布无效 宣佈無效 +宣布独立 宣佈獨立 +宣布破产 宣佈破產 +宣誓代表 宣誓代表 +宣赞 宣贊 +室內乐团 室內樂團 +室里 室裏 +宦游 宦遊 +宪台 憲臺 +宫里 宮裏 +宫里蓝 宮里藍 +宰制 宰制 +害于 害於 +害人虫 害人蟲 +害发 害發 +害虫 害蟲 +宴游 宴遊 +宵征 宵征 +家丑 家醜 +家丑不可外传 家醜不可外傳 +家丑不可外传流言切莫轻信 家醜不可外傳流言切莫輕信 +家丑不可外扬 家醜不可外揚 +家什 傢什 +家仆 家僕 +家伙 傢伙 +家佣 家傭 +家俱 傢俱 +家具 傢俱 +家具行 傢俱行 +家制 家制 +家和万事兴 家和萬事興 +家山药 家山藥 +家庄 家莊 +家庭制度 家庭制度 +家庭计划 家庭計劃 +家当 家當 +家政系 家政系 +家族同盟 家族同盟 +家无斗储 家無斗儲 +家机布 家機布 +家私 傢俬 +家种 家種 +家系 家系 +家财万贯 家財萬貫 +家赀万贯 家貲萬貫 +家里 家裏 +家里的 家裏的 +家长制 家長制 +家长里短 家長裏短 +家门不幸 家門不幸 +家门有幸 家門有幸 +宸极 宸極 +宸游 宸遊 +容于 容於 +容光焕发 容光煥發 +容克 容克 +容后说明 容後說明 +容容多后福 容容多後福 +容幸 容幸 +容范 容範 +容表 容表 +宽了 寬了 +宽于 寬於 +宽余 寬餘 +宽宽松松 寬寬鬆鬆 +宽打周遭 寬打周遭 +宽松 寬鬆 +宽泛 寬泛 +宾主关系 賓主關係 +宾主尽欢 賓主盡歡 +宾客如云 賓客如雲 +宾语关系从句 賓語關係從句 +宿仇 宿仇 +宿志 宿志 +宿愿 宿願 +宿愿已偿 宿願已償 +宿愿得偿 宿願得償 +宿松 宿松 +宿松县 宿松縣 +宿舍 宿舍 +宿舍区 宿舍區 +宿舍楼 宿舍樓 +宿舍网路 宿舍網路 +宿舍费 宿舍費 +寂历 寂歷 +寄了 寄了 +寄于 寄於 +寄出 寄出 +寄出去 寄出去 +寄发 寄發 +寄回 寄回 +寄托 寄託 +寄托在 寄託在 +寄托着 寄託着 +寄挂号 寄掛號 +寄挂号信 寄掛號信 +寄生昆虫 寄生昆蟲 +寄生虫 寄生蟲 +寄生虫病 寄生蟲病 +寅台 寅臺 +密云 密雲 +密云不雨 密雲不雨 +密云县 密雲縣 +密仑 密侖 +密克罗尼西亚 密克羅尼西亞 +密切关系 密切關係 +密切注意 密切注意 +密切注视 密切注視 +密合 密合 +密密扎扎 密密扎扎 +密布 密佈 +密折 密摺 +密致 密緻 +密苏里 密蘇里 +密苏里州 密蘇里州 +密苏里河 密蘇里河 +寇不可玩 寇不可翫 +寇仇 寇仇 +寇准 寇準 +富于 富於 +富于想像 富於想像 +富余 富餘 +富兰克林 富蘭克林 +富富有余 富富有餘 +富布赖特 富布賴特 +富春秋 富春秋 +富维克 富維克 +富色彩 富色彩 +富贵如浮云 富貴如浮雲 +富贵浮云 富貴浮雲 +富里 富里 +富里乡 富里鄉 +寒于 寒於 +寒假里 寒假裏 +寒冬 寒冬 +寒冬腊月 寒冬臘月 +寒号虫 寒號蟲 +寒暑表 寒暑表 +寒栗 寒慄 +寒武系 寒武系 +寒波荡漾 寒波盪漾 +寒症 寒症 +寒秋 寒秋 +寒舍 寒舍 +寓于 寓於 +寓兵于农 寓兵於農 +寓教于乐 寓教於樂 +寓禁于征 寓禁於征 +寝丘之志 寢丘之志 +察合台 察合臺 +察合台汗国 察合臺汗國 +察布查尔 察布查爾 +察布查尔县 察布查爾縣 +察干 察干 +察核 察覈 +察觉出 察覺出 +寡占 寡佔 +寡合 寡合 +寡欲 寡慾 +寥寥无几 寥寥無幾 +寮采 寮寀 +寸丝不挂 寸絲不掛 +寸发千金 寸髮千金 +对了 對了 +对了槛儿 對了檻兒 +对于 對於 +对偶多面体 對偶多面體 +对冲 對沖 +对冲基金 對沖基金 +对准 對準 +对准目标 對準目標 +对准表 對準錶 +对准钟 對準鐘 +对准钟表 對準鐘錶 +对华发动 對華發動 +对台 對臺 +对台戏 對臺戲 +对合 對合 +对合起来 對合起來 +对外关系 對外關係 +对天发誓 對天發誓 +对妻失语症 對妻失語症 +对对胡 對對胡 +对当 對當 +对折 對摺 +对数表 對數表 +对杯 對杯 +对流云系 對流雲系 +对焦范围 對焦範圍 +对照表 對照表 +对症 對症 +对症下药 對症下藥 +对症发药 對症發藥 +对着干 對着幹 +对立面 對立面 +对等关系 對等關係 +对表 對錶 +对酒当歌 對酒當歌 +对针 對針 +对面 對面 +对面不见人 對面不見人 +寺舍 寺舍 +寺钟 寺鐘 +寻仇 尋仇 +寻出 尋出 +寻回 尋回 +寻幽探胜 尋幽探勝 +寻幽访胜 尋幽訪勝 +寻找出 尋找出 +寻找出来 尋找出來 +寻来范畴 尋來範疇 +寻求出来 尋求出來 +寻获 尋獲 +导出 導出 +导出值 導出值 +导出去 導出去 +导出来 導出來 +导向 導向 +导向型 導向型 +导向思考 導向思考 +导向飞弹 導向飛彈 +导向鱼雷 導向魚雷 +导师制 導師制 +导引之术 導引之術 +导引系统 導引系統 +导弹武器技术控制制度 導彈武器技術控制制度 +导弹系统 導彈系統 +导板 導板 +导气之术 導氣之術 +导流板 導流板 +导游 導遊 +导生制 導生制 +导致 導致 +导致死亡 導致死亡 +导航系统 導航系統 +导风板 導風板 +寿丰 壽豐 +寿丰乡 壽豐鄉 +寿数已尽 壽數已盡 +寿险责任准备金 壽險責任準備金 +寿面 壽麪 +封个 封個 +封了 封了 +封了火 封了火 +封侯万里 封侯萬里 +封台 封臺 +封后 封后 +封妻荫子 封妻廕子 +封官许愿 封官許願 +封建制度 封建制度 +封建割据 封建割據 +封弥 封彌 +封杀出局 封殺出局 +封檐板 封檐板 +封胡羯末 封胡羯末 +封胡遏末 封胡遏末 +封蜡 封蠟 +封里 封裏 +封面 封面 +封面人物 封面人物 +封面女郎 封面女郎 +封面设计 封面設計 +封面里 封面裏 +射不出 射不出 +射了 射了 +射准 射準 +射出 射出 +射出去 射出去 +射出来 射出來 +射向 射向 +射回 射回 +射回去 射回去 +射回来 射回來 +射复 射覆 +射干 射干 +射影几何 射影幾何 +射影几何学 射影幾何學 +射雕 射鵰 +射雕手 射鵰手 +射雕英雄传 射鵰英雄傳 +射频干扰 射頻干擾 +射频识别 射頻識別 +将于 將於 +将假当真 將假當真 +将出 將出 +将出去 將出去 +将出来 將出來 +将功折罪 將功折罪 +将功折过 將功折過 +将占 將佔 +将占卜 將占卜 +将回 將回 +将回到 將回到 +将回去 將回去 +将回来 將回來 +将尽 將盡 +将尽未尽 將盡未盡 +将才 將才 +将无同 將無同 +将相本无种 將相本無種 +将遇良才 將遇良才 +将门之后 將門之後 +小丑 小丑 小醜 +小丑丫鬟 小醜丫鬟 +小丑跳梁 小醜跳樑 +小丑鱼 小丑魚 +小业种 小業種 +小个 小個 +小个子 小個子 +小丰满发电厂 小豐滿發電廠 +小了 小了 +小于 小於 +小云 小云 +小人得志 小人得志 +小仆 小僕 +小价 小价 +小众艺术 小衆藝術 +小伙 小夥 +小伙子 小夥子 +小伙计 小夥計 +小余 小余 +小便斗 小便斗 +小修 小修 +小傢伙 小傢伙 +小儿麻痹症 小兒麻痹症 +小克 小克 +小冬 小冬 +小冲突 小衝突 +小几 小几 +小划子 小划子 +小别 小別 +小千 小千 +小千世界 小千世界 +小升 小升 +小卷 小卷 小捲 +小厂 小廠 +小发 小發 +小发财 小發財 +小只 小隻 +小叮当 小叮噹 +小叶 小葉 +小同乡 小同鄉 +小后生 小後生 +小周天 小周天 +小回 小回 +小场面 小場面 +小型柜橱 小型櫃櫥 +小型钟 小型鐘 +小型钟表 小型鐘錶 +小型钟表面 小型鐘表面 +小型钟面 小型鐘面 +小夜曲 小夜曲 +小天后 小天后 +小姑娘 小姑娘 +小姑娘树 小姑娘樹 +小娘 小娘 +小娘子 小娘子 +小子后生 小子後生 +小尝 小嚐 +小尽 小盡 +小岩洞 小巖洞 +小布 小布 +小庵 小庵 +小廉曲谨 小廉曲謹 +小志 小志 +小念 小念 +小恶魔 小惡魔 +小才大用 小才大用 +小才子 小才子 +小挂儿 小掛兒 +小插曲 小插曲 +小时了了 小時了了 +小曲 小曲 +小朱 小朱 +小杯 小杯 +小杰 小杰 +小松 小松 +小松糕 小鬆糕 +小板 小板 +小柜子 小櫃子 +小栗旬 小栗旬 +小步舞曲 小步舞曲 +小毛虫 小毛蟲 +小池百合子 小池百合子 +小注 小注 +小泽征尔 小澤征爾 +小游 小遊 +小瀑布 小瀑布 +小班制 小班制 +小秀才 小秀才 +小秀才学堂 小秀才學堂 +小秋 小秋 +小秋收 小秋收 +小种 小種 +小穗 小穗 +小筑 小築 +小米面 小米麪 +小系 小系 +小红萝卜 小紅蘿蔔 +小老板 小老闆 +小胜 小勝 +小胜利 小勝利 +小胡子 小鬍子 +小胡桃 小胡桃 +小脏鬼 小髒鬼 +小舍人 小舍人 +小花远志 小花遠志 +小苏 小蘇 +小苏打 小蘇打 +小苏打粉 小蘇打粉 +小苹果 小蘋果 +小范 小范 +小范围 小範圍 +小萝卜头 小蘿蔔頭 +小虫 小蟲 +小虫子 小蟲子 +小行板 小行板 +小表哥 小表哥 +小表妹 小表妹 +小表姊 小表姊 +小表嫂 小表嫂 +小表弟 小表弟 +小里小气 小裏小氣 +小针 小針 +小针美容 小針美容 +小钟 小鐘 +小铲 小鏟 +小铲子 小鏟子 +小集团 小集團 +小面包 小麪包 +小须鲸 小鬚鯨 +小鬼当家 小鬼當家 +少不了 少不了 +少了 少了 +少于 少於 +少冲 少衝 +少出 少出 +少占 少佔 +少吊 少吊 +少年才俊 少年才俊 +少惹闲事 少惹閒事 +少扣 少扣 +少掌柜 少掌櫃 +少数党 少數黨 +少杰 少傑 +少私寡欲 少私寡慾 +少管闲事 少管閒事 +少说几句 少說幾句 +少采 少採 +尔冬升 爾冬升 +尔后 爾後 +尔当 爾當 +尔本周 爾本週 +尖团 尖團 +尖团字 尖團字 +尖团音 尖團音 +尖扎 尖扎 +尖扎县 尖扎縣 +尖管面 尖管麪 +尖裂叶 尖裂葉 +尘卷风 塵捲風 +尘肺症 塵肺症 +尘芥虫 塵芥蟲 +尘表 塵表 +尘襟尽涤 塵襟盡滌 +尘饭涂羹 塵飯塗羹 +尚余 尚餘 +尚志 尚志 +尚志市 尚志市 +尚慕杰 尚慕傑 +尚须 尚須 +尝个 嚐個 +尝了 嚐了 +尝了一口 嚐了一口 +尝了尝 嚐了嚐 +尝了鲜 嚐了鮮 +尝出 嚐出 +尝到 嚐到 +尝尝 嚐嚐 +尝尝鲜 嚐嚐鮮 +尝尽 嚐盡 +尝巧 嘗巧 +尝敌 嘗敵 +尝新 嘗新 +尝来尝去 嚐來嚐去 +尝汤戏 嘗湯戲 +尝点 嚐點 +尝甜头 嘗甜頭 +尝胆 嘗膽 +尝胆臥薪 嘗膽臥薪 +尝膳 嘗膳 +尝草 嘗草 +尝药 嘗藥 +尝试 嘗試 +尝试性 嘗試性 +尝试错误学习 嘗試錯誤學習 +尝起来 嚐起來 +尝遍 嚐遍 +尝酸 嘗酸 +尝鲜 嚐鮮 +尝鼎一脔 嘗鼎一臠 +尤云殢雨 尤雲殢雨 +尤克利斯 尤克利斯 +尤克勒斯 尤克勒斯 +尤克斯 尤克斯 +尤克里斯 尤克里斯 +尤克里里琴 尤克裏裏琴 +尤基里斯 尤基里斯 +尤班克斯 尤班克斯 +尤秋兴 尤秋興 +尤里 尤里 +尤里斯伊文思 尤里斯伊文思 +尤里比底斯 尤里比底斯 +尤里西斯 尤里西斯 +尤须 尤須 +尧布 堯布 +尨眉皓发 尨眉皓髮 +就于 就於 +就克制 就剋制 +就出 就出 +就出去 就出去 +就出来 就出來 +就吃干 就吃乾 +就回 就回 +就回去 就回去 +就回来 就回來 +就干一 就幹一 +就干一杯 就乾一杯 +就干吧 就幹吧 +就干淨 就乾淨 +就当 就當 +就当作 就當作 +就念 就唸 +就扣 就扣 +就拿出 就拿出 +就日瞻云 就日瞻雲 +就是了 就是了 +就晚了 就晚了 +就汤下面 就湯下麪 +就系 就係 +就范 就範 +就读于 就讀於 +尸位 尸位 +尸位素餐 尸位素餐 +尸体 屍體 +尸体剖检 屍體剖檢 +尸体袋 屍體袋 +尸体解剖 屍體解剖 +尸僵 屍僵 +尸利 尸利 +尸变 屍變 +尸块 屍塊 +尸居余气 尸居餘氣 +尸居龙见 尸居龍見 +尸山血海 屍山血海 +尸斑 屍斑 +尸格 屍格 +尸检 屍檢 +尸榇 屍櫬 +尸横遍野 屍橫遍野 +尸灵 屍靈 +尸祝 尸祝 +尸祝代庖 尸祝代庖 +尸禄 尸祿 +尸禄素餐 尸祿素餐 +尸臣 尸臣 +尸蜡 屍蠟 +尸衣 屍衣 +尸解 尸解 +尸谏 尸諫 +尸身 屍身 尸身 +尸陀林 尸陀林 +尸饔 尸饔 +尸首 屍首 +尸骨 屍骨 +尸骨无存 屍骨無存 +尸骨早寒 屍骨早寒 +尸骨未寒 屍骨未寒 +尸骸 屍骸 +尸鸠 尸鳩 +尹秋君 尹秋君 +尹邢避面 尹邢避面 +尺二秀才 尺二秀才 +尺寸千里 尺寸千里 +尺寸斗粟 尺寸斗粟 +尺布斗粟 尺布斗粟 +尺幅千里 尺幅千里 +尺板 尺板 +尺板斗食 尺板斗食 +尼亚加拉瀑布 尼亞加拉瀑布 +尼克 尼克 +尼克劳斯 尼克勞斯 +尼克松 尼克松 +尼克森 尼克森 +尼克洛 尼克洛 +尼克队 尼克隊 +尼加拉瀑布 尼加拉瀑布 +尼勒克 尼勒克 +尼勒克县 尼勒克縣 +尼坛 尼壇 +尼坦雅胡 尼坦雅胡 +尼姑庵 尼姑庵 +尼布楚条约 尼布楚條約 +尼布甲尼撒 尼布甲尼撒 +尼庵 尼庵 +尼采 尼采 +尼龙布 尼龍布 +尽世 盡世 +尽义务 盡義務 +尽了 盡了 +尽些 盡些 +尽享 盡享 +尽人 盡人 +尽人事 盡人事 +尽人情 盡人情 +尽人皆知 盡人皆知 +尽付东流 盡付東流 +尽付阙如 盡付闕如 +尽信 盡信 +尽做 盡做 +尽做坏事 盡做壞事 +尽先 儘先 +尽全力 盡全力 +尽全心 盡全心 +尽兴 盡興 +尽兴而归 盡興而歸 +尽其 盡其 +尽其在我 盡其在我 +尽其所有 盡其所有 +尽其所能 盡其所能 +尽其所长 盡其所長 +尽出 盡出 +尽到 盡到 +尽力 盡力 +尽力去做 盡力去做 +尽力而为 盡力而爲 +尽去 盡去 +尽可 儘可 +尽可能 儘可能 +尽命 盡命 +尽善 盡善 +尽善尽美 盡善盡美 +尽在 盡在 +尽场儿 盡場兒 +尽够 儘夠 +尽失 盡失 +尽头 盡頭 +尽头话 盡頭話 +尽如 盡如 +尽如人意 盡如人意 +尽子 儘子 +尽孝 盡孝 +尽尽 儘儘 +尽展所长 盡展所長 +尽属 盡屬 +尽己 盡己 +尽带 盡帶 +尽席 盡席 +尽年 盡年 +尽底下 儘底下 +尽得 盡得 +尽心 盡心 +尽心图报 盡心圖報 +尽心尽力 盡心盡力 +尽心竭力 盡心竭力 +尽心竭诚 盡心竭誠 +尽忠 盡忠 +尽忠报国 盡忠報國 +尽忠竭力 盡忠竭力 +尽忠职守 盡忠職守 +尽快 儘快 +尽快地 儘快地 +尽态极妍 盡態極妍 +尽性 儘性 +尽情 盡情 +尽情吐露 盡情吐露 +尽情尽理 盡情盡理 +尽情欢乐 盡情歡樂 +尽情欢唱 盡情歡唱 +尽情歌唱 盡情歌唱 +尽情玩乐 盡情玩樂 +尽想 儘想 +尽意 盡意 +尽意随心 儘意隨心 +尽收 盡收 +尽收眼底 盡收眼底 +尽教 儘教 +尽散 盡散 +尽数 盡數 +尽日 盡日 +尽日穷夜 盡日窮夜 +尽早 儘早 +尽是 盡是 +尽有可能 儘有可能 +尽本分 盡本分 +尽欢 盡歡 +尽欢而散 盡歡而散 +尽沾恩露 盡霑恩露 +尽然 盡然 +尽瘁 盡瘁 +尽瘁鞠躬 盡瘁鞠躬 +尽皆 盡皆 +尽盘将军 盡盤將軍 +尽礼 盡禮 +尽端 盡端 +尽管 儘管 +尽管如此 儘管如此 +尽美尽善 盡美盡善 +尽职 盡職 +尽职尽责 盡職盡責 +尽能 盡能 +尽自 儘自 +尽致 盡致 +尽节 盡節 +尽节竭诚 盡節竭誠 +尽若 盡若 +尽落尾 儘落尾 +尽要 盡要 +尽览 盡覽 +尽言 盡言 +尽让 儘讓 +尽诚竭节 盡誠竭節 +尽读 盡讀 +尽责 盡責 +尽责任 盡責任 +尽述 盡述 +尽速 儘速 +尽释前嫌 盡釋前嫌 +尽里 儘裏 +尽量 儘量 +尽铅华 盡鉛華 +尾注 尾註 +尾身幸次 尾身幸次 +尿崩症 尿崩症 +尿布 尿布 +尿布台 尿布臺 +尿布疹 尿布疹 +尿斗 尿斗 +尿杯 尿杯 +尿毒症 尿毒症 +局促 侷促 +局里 局裏 +局限 侷限 +局限于 侷限於 +局面 局面 +层云 層雲 +层出 層出 +层出不穷 層出不窮 +层出叠见 層出疊見 +层压板 層壓板 +层台 層臺 +层积云 層積雲 +层见叠出 層見疊出 +层见迭出 層見迭出 +层面 層面 +居于 居於 +居住于 居住於 +居心险恶 居心險惡 +居里 居里 +居里夫人 居里夫人 +屈一伸万 屈一伸萬 +屈万里 屈萬里 +屈就于 屈就於 +屈志 屈志 +屈才 屈才 +屈折 屈折 +屈折语 屈折語 +屈曲 屈曲 +屈服于 屈服於 +屋子里 屋子裏 +屋梁 屋樑 +屋舍 屋舍 +屋里 屋裏 +屋里人 屋裏人 +屋里的 屋裏的 +屋面 屋面 +屋面板 屋面板 +屋面瓦 屋面瓦 +屏当 屏當 +屏极 屏極 +屏风后 屏風後 +屑于 屑於 +展出 展出 +展卷 展卷 +展台 展臺 +展团 展團 +展布 展布 +展才 展才 +展现出 展現出 +展现出来 展現出來 +展示出 展示出 +展示柜 展示櫃 +展采 展采 +展露出 展露出 +展露出来 展露出來 +属于 屬於 +属于偶 屬於偶 +属意于 屬意於 +属托 屬託 +属毛离里 屬毛離裏 +屠苏 屠蘇 +屠苏酒 屠蘇酒 +屡仆屡起 屢仆屢起 +屡出新招 屢出新招 +屡出狂言 屢出狂言 +屡战屡胜 屢戰屢勝 +屡顾尔仆 屢顧爾僕 +履历 履歷 +履历片 履歷片 +履历表 履歷表 +屯扎 屯紮 +屯田制 屯田制 +屯里 屯裏 +山中无历日 山中無曆日 +山中白云 山中白雲 +山仔后 山仔后 +山前山后 山前山後 +山后 山後 +山向 山向 +山地同胞 山地同胞 +山地管制区 山地管制區 +山地管制游览区 山地管制遊覽區 +山岩 山岩 +山岳 山嶽 +山崩钟应 山崩鐘應 +山庄 山莊 +山斗 山斗 +山有扶苏 山有扶蘇 +山栖谷隐 山棲谷隱 +山栖谷饮 山棲谷飲 +山梁 山樑 +山洞里 山洞裏 +山洪暴发 山洪暴發 +山穷水尽 山窮水盡 +山系 山系 +山缪杰克森 山繆傑克森 +山羊胡 山羊鬍 +山羊胡子 山羊鬍子 +山羊须 山羊鬚 +山胡桃木 山胡桃木 +山苏 山蘇 +山药 山藥 +山药蛋 山藥蛋 +山谷 山谷 +山谷地 山谷地 +山里 山裏 +山里站 山里站 +山里红 山裏紅 +山重水复 山重水複 +山雨欲来 山雨欲來 +山雨欲来风满楼 山雨欲來風滿樓 +岁丰年稔 歲豐年稔 +岁修 歲修 +岁凶 歲凶 +岁出 歲出 +岁寒松柏 歲寒松柏 +岁稔年丰 歲稔年豐 +岁聿云暮 歲聿云暮 +岁计余绌 歲計餘絀 +岂只 豈只 +岐周 岐周 +岑参 岑參 +岔曲 岔曲 +岗台 崗臺 +岚烟波影 嵐煙波影 +岛链 島鏈 +岩仓使节团 岩倉使節團 +岩圈 岩圈 +岩土 岩土 +岩土体 岩土體 +岩基 岩基 +岩墙 巖牆 +岩墙之下 巖牆之下 +岩壁 巖壁 +岩层 岩層 +岩居 巖居 +岩居穴处 巖居穴處 +岩居谷饮 巖居谷飲 +岩屑 岩屑 +岩岩 巖巖 +岩岸 巖岸 +岩巉 巖巉 +岩床 岩牀 +岩徼 巖徼 +岩心 岩心 +岩手县 巖手縣 +岩村 巖村 +岩村明宪 岩村明憲 +岩棉 岩棉 +岩洞 巖洞 +岩流圈 巖流圈 +岩浆 岩漿 +岩浆岩 岩漿岩 +岩浆流 岩漿流 +岩溶 岩溶 +岩濑健 岩瀨健 +岩画 巖畫 +岩盐 岩鹽 +岩石 岩石 +岩石圈 岩石圈 +岩石学 岩石學 +岩石层 岩石層 +岩石循环 岩石循環 +岩礁 岩礁 +岩穴 巖穴 +岩穴之士 巖穴之士 +岩羊 岩羊 +岩脉 岩脈 +岩蔷薇 巖薔薇 +岩邑 巖邑 +岩郎 巖郎 +岩阻 巖阻 +岩陛 巖陛 +岫岩县 岫巖縣 +岭表 嶺表 +岱岳 岱嶽 +岳丈 岳丈 +岳云 岳雲 +岳坟 岳墳 +岳家 岳家 +岳家军 岳家軍 +岳岳 嶽嶽 +岳庙 岳廟 +岳母 岳母 +岳氏 岳氏 +岳父 岳父 +岳珂 岳珂 +岳阳 岳陽 +岳阳县 岳陽縣 +岳阳楼 岳陽樓 +岳阳楼记 岳陽樓記 +岳飞 岳飛 +岳麓 嶽麓 +峇峇娘惹 峇峇孃惹 +峇里岛 峇里島 +峡谷 峽谷 +峰回 峯迴 +峰回路转 峯迴路轉 +峰岩 峯巖 +峰火台 峯火臺 +峻岭 峻嶺 +峻极 峻極 +崑仑 崑崙 +崑仑奴 崑崙奴 +崑仑奴传 崑崙奴傳 +崑仑山 崑崙山 +崑仑山脉 崑崙山脈 +崑曲 崑曲 +崔京周 崔京周 +崔克索 崔克索 +崔敬邕墓志铭 崔敬邕墓誌銘 +崔涂 崔塗 +崖广 崖广 +崖谷 崖谷 +崤谷 崤谷 +崩症 崩症 +嵌岩 嵌巖 +嵚埼历落 嶔埼歷落 +嵫厘 嵫釐 +嶰谷 嶰谷 +嶽云 嶽雲 +巅崖峻谷 巔崖峻谷 +巉岩 巉巖 +巍巍荡荡 巍巍蕩蕩 +川党参 川黨蔘 +川后 川后 +川埼症 川埼症 +川杯 川杯 +川汇区 川匯區 +川谷 川穀 +州同 州同 +州里 州里 +巡回 巡迴 +巡回公演 巡迴公演 +巡回剧团 巡迴劇團 +巡回医疗 巡迴醫療 +巡回图书馆 巡迴圖書館 +巡回大使 巡迴大使 +巡回学校 巡迴學校 +巡回审判 巡迴審判 +巡回展 巡迴展 +巡回检査 巡迴檢查 +巡回法庭 巡回法庭 +巡回演出 巡迴演出 +巡回演唱 巡迴演唱 +巡回祭 巡迴祭 +巡回赛 巡迴賽 +巡回车 巡迴車 +巡幸 巡幸 +巡游 巡遊 +工业体系 工業體系 +工业团体 工業團體 +工业技术 工業技術 +工业民主制 工業民主制 +工于 工於 +工于心计 工於心計 +工人党 工人黨 +工价 工價 +工余 工餘 +工作制 工作制 +工作制度 工作制度 +工作台 工作臺 +工作团 工作團 +工作表 工作表 +工作规范 工作規範 +工作面 工作面 +工党 工黨 +工厂 工廠 +工厂卫生 工廠衛生 +工厂工业 工廠工業 +工厂布置 工廠佈置 +工厂权 工廠權 +工厂法 工廠法 +工厂自动化 工廠自動化 +工商综合区 工商綜合區 +工团 工團 +工团主义 工團主義 +工布江达 工布江達 +工布江达县 工布江達縣 +工欲善其事 工欲善其事 +工矿炸药 工礦炸藥 +工种 工種 +工程学系 工程學系 +工程系 工程系 +工致 工緻 +工艺美术 工藝美術 +左云 左雲 +左云县 左雲縣 +左光斗 左光斗 +左冲 左衝 +左冲右突 左衝右突 +左右前后 左右前後 +左右摇摆 左右搖擺 +左右采之 左右采之 +左右采获 左右採獲 +左后 左後 +左后方 左後方 +左向 左向 +左手不托右手 左手不托右手 +左拐 左拐 +左氏春秋 左氏春秋 +左邻右舍 左鄰右舍 +左邻右里 左鄰右里 +左里克 左里克 +左面 左面 +巧了 巧了 +巧克力 巧克力 +巧克力糖 巧克力糖 +巧克力脆片 巧克力脆片 +巧克力色 巧克力色 +巧克力酱 巧克力醬 +巧克莉 巧克莉 +巧历 巧曆 +巧发奇中 巧發奇中 +巧合 巧合 +巧同造化 巧同造化 +巧干 巧幹 +巧当儿 巧當兒 +巨万 鉅萬 +巨业 鉅業 +巨亏 鉅虧 +巨人症 巨人症 +巨作 鉅作 +巨债 鉅債 +巨公 鉅公 +巨制 鉅製 +巨变 鉅變 +巨商 鉅商 +巨奖 鉅獎 +巨奸 鉅奸 +巨子 鉅子 +巨富 鉅富 +巨款 鉅款 +巨献 鉅獻 +巨祥 鉅祥 +巨细 鉅細 +巨脾症 巨脾症 +巨舰 鉅艦 +巨著 鉅著 +巨贪 鉅貪 +巨野 鉅野 +巨额 鉅額 +巨鹿 鉅鹿 +巨黍 鉅黍 +巫咸 巫咸 +巫山云雨 巫山雲雨 +巫术 巫術 +差之千里 差之千里 +差之毫厘 差之毫釐 +差于 差於 +差以毫厘 差以毫釐 +差价 差價 +差别 差別 +差别待遇 差別待遇 +差别费率 差別費率 +差发 差發 +差多了 差多了 +差恶 差惡 +差若豪厘 差若豪釐 +己丑 己丑 +己出 己出 +己所不欲 己所不欲 +己饥己溺 己飢己溺 +已于 已於 +已作出保 已作出保 +已占 已佔 +已占卜 已占卜 +已占算 已占算 +已对于 已對於 +已扣 已扣 +已极 已極 +已系 已係 +巴人下里 巴人下里 +巴克 巴克 +巴克利 巴克利 +巴克南德 巴克南德 +巴克夏猪 巴克夏豬 +巴克礼 巴克禮 +巴克科思 巴克科思 +巴克莱 巴克萊 +巴克莱银行 巴克萊銀行 +巴克雷 巴克雷 +巴克霍兹 巴克霍茲 +巴别塔 巴別塔 +巴前算后 巴前算後 +巴厘岛 巴厘島 +巴尔克嫩德 巴爾克嫩德 +巴尔干 巴爾幹 +巴尔干半岛 巴爾幹半島 +巴尔干山 巴爾幹山 +巴尔干山脉 巴爾幹山脈 +巴尔扎克 巴爾扎克 +巴尔札克 巴爾札克 +巴尔舍夫斯基 巴爾舍夫斯基 +巴尔贝里尼宫殿 巴爾貝里尼宮殿 +巴尔赞 巴爾贊 +巴尔陶克 巴爾陶克 +巴尖儿好胜 巴尖兒好勝 +巴布 巴布 +巴布亚 巴布亞 +巴布亚新几内亚 巴布亞新幾內亞 +巴布亚省 巴布亞省 +巴布亚纽 巴布亞紐 +巴布亚纽几內亚 巴布亞紐幾內亞 +巴布亚纽几内亚 巴布亞紐幾內亞 +巴布尔 巴布爾 +巴布延群岛 巴布延羣島 +巴布拉族 巴布拉族 +巴布狄伦 巴布狄倫 +巴托丽 巴托麗 +巴托莉 巴托莉 +巴拉克 巴拉克 +巴拉松 巴拉松 +巴控克什米尔 巴控克什米爾 +巴斗 巴斗 +巴斯克 巴斯克 +巴斯克人 巴斯克人 +巴斯克语 巴斯克語 +巴斯德菌症 巴斯德菌症 +巴斯特纳克 巴斯特納克 +巴松管 巴松管 +巴比合金 巴比合金 +巴比布朗 巴比布朗 +巴比特合金 巴比特合金 +巴氏杆菌 巴氏桿菌 +巴洛克 巴洛克 +巴洛克式 巴洛克式 +巴洛克艺术 巴洛克藝術 +巴洛克风格 巴洛克風格 +巴洛马天文台 巴洛馬天文臺 +巴游 巴游 +巴瑞克 巴瑞克 +巴罗克 巴羅克 +巴胡提 巴胡提 +巴舍莱 巴舍萊 +巴贝克 巴貝克 +巴贝西亚原虫病 巴貝西亞原蟲病 +巴里 巴里 +巴里坤 巴里坤 +巴里坤县 巴裏坤縣 +巴里坤哈萨克自治县 巴裏坤哈薩克自治縣 +巴里坤草原 巴裏坤草原 +巴里岛 巴里島 +巴里库廷火山 巴里庫廷火山 +巴里斯 巴里斯 +巴金森氏症 巴金森氏症 +巴音布克草原 巴音布克草原 +巴马干酪 巴馬乾酪 +巷里 巷裏 +巾帼须眉 巾幗鬚眉 +币别 幣別 +币制 幣制 +市不二价 市不二價 +市不豫价 市不豫價 +市价 市價 +市党部 市黨部 +市制 市制 +市占 市佔 +市占率 市佔率 +市地重划 市地重劃 +市场价 市場價 +市场价格 市場價格 +市场准入 市場準入 +市场占有率 市場佔有率 +市无二价 市無二價 +市里 市裏 +市长杯 市長盃 +市面 市面 +市面上 市面上 +布一个 佈一個 +布丁 布丁 +布下 佈下 +布丹 布丹 +布于 佈於 +布什 布什 +布什尔 布什爾 +布什尔省 布什爾省 +布仑特 布侖特 +布会 佈會 +布伞 布傘 +布伦 布倫 +布伦尼 布倫尼 +布伦托海 布倫托海 +布伦森 布倫森 +布伦特 布倫特 +布佳迪 布佳迪 +布依 布依 +布依族 布依族 +布偶 布偶 +布偶戏 布偶戲 +布克 布克 +布克奖 布克獎 +布兰 布蘭 +布兰克 布蘭克 +布兰妮 布蘭妮 +布兰妮斯皮尔斯 布蘭妮斯皮爾斯 +布兰德 布蘭德 +布兰枯秀 布蘭枯秀 +布兰森 布蘭森 +布兰特 布蘭特 +布兰琪 布蘭琪 +布兰登堡 布蘭登堡 +布兰登堡门 布蘭登堡門 +布农 布農 +布农族 布農族 +布冯 布馮 +布划 佈劃 +布列 佈列 +布列兹涅 布列茲涅 +布列兹涅夫 布列茲涅夫 +布列兹涅夫主义 布列茲涅夫主義 +布列塔尼 布列塔尼 +布列开 布列開 +布利吉 布利吉 +布利斯班 布利斯班 +布利斯班市 布利斯班市 +布加勒斯条约 布加勒斯條約 +布加勒斯特 布加勒斯特 +布劳恩 布勞恩 +布势 佈勢 +布勒斯特 布勒斯特 +布包 布包 +布匹 布匹 +布匿战争 布匿戰爭 +布卡拉 布卡拉 +布叶 布葉 +布合 布合 +布吉河 布吉河 +布吉纳法索 布吉納法索 +布告 佈告 +布告栏 佈告欄 +布告牌 佈告牌 +布哈拉 布哈拉 +布哈林 布哈林 +布哈林模式 布哈林模式 +布哨 佈哨 +布喀河 布喀河 +布囊 布囊 +布囊其口 佈囊其口 +布坎南 布坎南 +布基纳法索 布基納法索 +布复 布覆 +布头 布頭 +布奇 布奇 +布娃娃 布娃娃 +布婚 布婚 +布宁 布寧 +布宜若 布宜若 +布宜诺 布宜諾 +布宜诺斯艾利斯 布宜諾斯艾利斯 +布宪 布憲 +布尔 布爾 +布尔乔亚 布爾喬亞 +布尔什维克 布爾什維克 +布尔代数 布爾代數 +布尔兹 布爾茲 +布尔哥尼 布爾哥尼 +布尔津 布爾津 +布尔津县 布爾津縣 +布尔省 布爾省 +布尔诺 布爾諾 +布尼亚病毒 布尼亞病毒 +布局 佈局 +布岗 佈崗 +布巾 布巾 +布布 布布 +布帆 布帆 +布帆无恙 布帆無恙 +布希 布希 +布希号 布希號 +布希威克 布希威克 +布希总统 布希總統 +布希曼 布希曼 +布帘 布簾 +布帛 布帛 +布帛菽粟 布帛菽粟 +布幔 布幔 +布幕 布幕 +布干维尔 布干維爾 +布干维尔岛 布干維爾島 +布庄 布莊 +布店 布店 +布德 佈德 +布德尔 布德爾 +布德施仁 布德施仁 +布德施惠 布德施惠 +布慈 佈慈 +布托 布托 +布扣 佈扣 +布拉 布拉 +布拉克 布拉克 +布拉加队 布拉加隊 +布拉吉 布拉吉 +布拉姆兹 布拉姆茲 +布拉姆斯 布拉姆斯 +布拉席耶利 布拉席耶利 +布拉德 布拉德 +布拉恰诺 布拉恰諾 +布拉曼德 布拉曼德 +布拉柴维尔 布拉柴維爾 +布拉格 布拉格 +布拉格定律 布拉格定律 +布拉格队 布拉格隊 +布拉欣 布拉欣 +布拉索夫 布拉索夫 +布拉萨市 布拉薩市 +布拉谢 布拉謝 +布拉迪斯拉发 布拉迪斯拉發 +布拉马普得拉河 布拉馬普得拉河 +布拖 布拖 +布拖县 布拖縣 +布招儿 布招兒 +布掸子 布撣子 +布摆 佈擺 +布政 佈政 +布政使 布政使 +布政司 布政司 +布教 佈教 +布散 佈散 +布料 布料 +布施 佈施 +布景 佈景 +布朗 布朗 +布朗克士 布朗克士 +布朗克斯 布朗克斯 +布朗士 布朗士 +布朗夏 布朗夏 +布朗大学 布朗大學 +布朗妮 布朗妮 +布朗宁 布朗寧 +布朗德 布朗德 +布朗族 布朗族 +布朗森 布朗森 +布朗特 布朗特 +布朗贝克 布朗貝克 +布朗费德 布朗費德 +布朗运动 布朗運動 +布望 布望 +布条 布條 +布来德史崔 布來德史崔 +布林 布林 +布林代数 布林代數 +布林底希 布林底希 +布林迪西 布林迪西 +布格河 布格河 +布桩 布樁 +布梏 布梏 +布氏杆菌 布氏桿菌 +布氏杆菌病 布氏桿菌病 +布氏菌苗 布氏菌苗 +布氏非鲫 布氏非鯽 +布气 布氣 +布水 布水 +布法罗 布法羅 +布洒器 布灑器 +布洛克 布洛克 +布洛斯顿 布洛斯頓 +布洛沙德 布洛沙德 +布洛湾 布洛灣 +布洛芬 布洛芬 +布满 佈滿 +布濩 布濩 +布热津斯基 布熱津斯基 +布特 布特 +布特哈 布特哈 +布特拉加亚 布特拉加亞 +布班尼斯瓦 布班尼斯瓦 +布琼布拉 布瓊布拉 +布瑞 布瑞 +布瑞尤 布瑞尤 +布瑞斯特 布瑞斯特 +布瑞特 布瑞特 +布瑞顿 布瑞頓 +布用填 布用填 +布疋 布疋 +布疑阵 佈疑陣 +布痕瓦尔德 布痕瓦爾德 +布白 布白 +布立吞族 布立吞族 +布算 布算 +布篷 布篷 +布素 布素 +布累尔 布累爾 +布纶堡 布綸堡 +布纹纸 布紋紙 +布线 佈線 +布维岛 布維島 +布缦 布縵 +布网 佈網 +布罗德赫斯特 布羅德赫斯特 +布罗温斯文学 布羅溫斯文學 +布罗迪 布羅迪 +布置 佈置 +布署 佈署 +布耳 布耳 +布胡会 布胡會 +布臆 布臆 +布色 布色 +布荆 布荊 +布草衣服 布草衣服 +布莱 布萊 +布莱克 布萊克 +布莱克史密斯 布萊克史密斯 +布莱克曼 布萊克曼 +布莱克本 布萊克本 +布莱尔 布萊爾 +布莱尼 布萊尼 +布莱希特 布萊希特 +布莱德 布萊德 +布莱德利 布萊德利 +布莱德彼特 布萊德彼特 +布莱德福 布萊德福 +布莱德雷 布萊德雷 +布莱恩 布萊恩 +布莱恩特 布萊恩特 +布莱恩狄帕玛 布萊恩狄帕瑪 +布莱特 布萊特 +布莱特妮墨菲 布萊特妮墨菲 +布莱雅特蒙古 布萊雅特蒙古 +布莱顿 布萊頓 +布菜 佈菜 +布萨 布薩 +布衣 布衣 +布衣之交 布衣之交 +布衣之怒 布衣之怒 +布衣交 布衣交 +布衣卿相 布衣卿相 +布衣小民 布衣小民 +布衣粝食 布衣糲食 +布衣苇带 布衣葦帶 +布衣蔬食 布衣蔬食 +布衣韦带 布衣韋帶 +布衣黔首 布衣黔首 +布衫 布衫 +布袋 布袋 +布袋和尚 布袋和尚 +布袋安 布袋安 +布袋戏 布袋戲 +布袋戏偶 布袋戲偶 +布袋戏馆 布袋戲館 +布袋港 布袋港 +布袋莲 布袋蓮 +布袋装 布袋裝 +布袋镇 布袋鎮 +布袜青鞋 布襪青鞋 +布被 布被 +布被十年 布被十年 +布裙荆钗 布裙荊釵 +布褐 布褐 +布西县 布西縣 +布让 佈讓 +布设 佈設 +布谷 布穀 +布谷鸟 布穀鳥 +布谷鸟钟 布穀鳥鐘 +布货 布貨 +布边 布邊 +布达 布達 +布达佩斯 布達佩斯 +布达式 布達式 +布达拉宫 布達拉宮 +布达拉寺 布達拉寺 +布达拉山 布達拉山 +布迪亚 布迪亞 +布道 佈道 +布道大会 佈道大會 +布道所 佈道所 +布那喀 布那喀 +布里 布里 +布里亚族 布里亞族 +布里兹涅夫 布里茲涅夫 +布里坦尼 布里坦尼 +布里奇顿 布里奇頓 +布里姬沃特 布里姬沃特 +布里斯 布里斯 +布里斯托 布里斯托 +布里斯托尔海峡 布里斯托爾海峽 +布里斯本 布里斯本 +布里斯本市 布里斯本市 +布里斯本河 布里斯本河 +布里斯班 布里斯班 +布里迪雅 布里迪雅 +布里迪雅通 布里迪雅通 +布防 佈防 +布防迎战 布防迎戰 +布阵 佈陣 +布阵安营 佈陣安營 +布隆伯格 布隆伯格 +布隆克特 布隆克特 +布隆吉尔河 布隆吉爾河 +布隆方丹 布隆方丹 +布隆迪 布隆迪 +布雅湾 布雅灣 +布雪 佈雪 +布雷 佈雷 +布雷克 布雷克 +布雷克磨 布雷克磨 +布雷封锁 佈雷封鎖 +布雷尔 布雷爾 +布雷尔港 布雷爾港 +布雷希特 布雷希特 +布雷恩 布雷恩 +布雷拉 布雷拉 +布雷的 佈雷的 +布雷舰 佈雷艦 +布雷艇 佈雷艇 +布雷蒙 布雷蒙 +布雷迪 布雷迪 +布雷速度 佈雷速度 +布雷队 佈雷隊 +布雷顿 布雷頓 +布雷顿森林 佈雷頓森林 +布雷默 布雷默 +布面 布面 +布面相片 布面相片 +布鞋 布鞋 +布须曼人 布須曼人 +布马雪 布馬雪 +布鲁 布魯 +布鲁乐谷 布魯樂谷 +布鲁克 布魯克 +布鲁克斯 布魯克斯 +布鲁克林 布魯克林 +布鲁克林大桥 布魯克林大橋 +布鲁克纳 布魯克納 +布鲁克雪德丝 布魯克雪德絲 +布鲁勒 布魯勒 +布鲁塞尔 布魯塞爾 +布鲁奈勒斯基 布魯奈勒斯基 +布鲁姆费尔德 布魯姆費爾德 +布鲁尼 布魯尼 +布鲁托 布魯托 +布鲁斯 布魯斯 +布鲁斯史普林斯汀 布魯斯史普林斯汀 +布鲁斯威利 布魯斯威利 +布鲁斯特 布魯斯特 +布鲁日 布魯日 +布鲁氏菌 布魯氏菌 +布鲁氏菌病 布魯氏菌病 +布鲁珊 布魯珊 +布鲁诺 布魯諾 +布鲁金斯 布魯金斯 +布鼓雷门 布鼓雷門 +帅呆了 帥呆了 +帆布 帆布 +帆布包 帆布包 +帆布椅 帆布椅 +帆布牀 帆布牀 +帆布袋 帆布袋 +帆布鞋 帆布鞋 +帆板 帆板 +师云而云 師云而云 +师出无名 師出無名 +师出有名 師出有名 +师团 師團 +师娘 師孃 +师徒合同 師徒合同 +师杯 師杯 +师生杯 師生盃 +师范 師範 +师范大学 師範大學 +师范学校 師範學校 +师范学院 師範學院 +师范教育 師範教育 +师范毕业 師範畢業 +师范生 師範生 +师范类 師範類 +师范附小 師範附小 +师范院校 師範院校 +师表 師表 +希伯来历 希伯來曆 +希伯来历史 希伯來歷史 +希克斯 希克斯 +希区考克 希區考克 +希布伦市 希布倫市 +希拉克 希拉剋 +希拉里 希拉里 +希拉里克林顿 希拉裏克林頓 +希斯仑 希斯崙 +希斯莱杰 希斯萊傑 +希斯雷杰 希斯雷傑 +希格斯机制 希格斯機制 +希腊建筑 希臘建築 +帐面 帳面 +帕丝齐克 帕絲齊克 +帕修斯 帕修斯 +帕克 帕克 +帕台农 帕臺農 +帕台农神庙 帕臺農神廟 +帕特里克 帕特里克 +帕特里夏 帕特里夏 +帕穆克 帕穆克 +帕索里尼 帕索里尼 +帕累托最优 帕累托最優 +帕累托法则 帕累托法則 +帕罗贝克 帕羅貝克 +帕谢克 帕謝克 +帕金森氏症 帕金森氏症 +帕金森症 帕金森症 +帘子 簾子 +帘子布 簾子布 +帘子线 簾子線 +帘官 簾官 +帘布 簾布 +帘帐 簾帳 +帘帷 簾帷 +帘幔 簾幔 +帘幕 簾幕 +帘幕式 簾幕式 +帘幽梦 簾幽夢 +帘栊 簾櫳 +帘波 簾波 +帝制 帝制 +帝制时代 帝制時代 +帝后 帝后 +帝胄 帝胄 +带丑闻 帶醜聞 +带个 帶個 +带个好 帶個好 +带了 帶了 +带凶 帶凶 +带出 帶出 +带出去 帶出去 +带出来 帶出來 +带发修行 帶髮修行 +带同 帶同 +带回 帶回 +带回到 帶回到 +带回去 帶回去 +带回来 帶回來 +带团 帶團 +带团参加 帶團參加 +带征 帶徵 +带征银 帶徵銀 +带扣 帶扣 +带罪征收 帶罪徵收 +带膆貂挂 帶膆貂掛 +席丰履厚 席豐履厚 +席卷 席捲 +席卷一空 席捲一空 +席卷亚洲 席捲亞洲 +席卷天下 席捲天下 +席卷而来 席捲而來 +席卷而逃 席捲而逃 +席哈克 席哈克 +席志成 席誌成 +席棚 蓆棚 +席湘漓 席湘漓 +席胜 席勝 +席面 席面 +帮不了 幫不了 +帮个场子 幫個場子 +帮伙 幫夥 +帮佣 幫傭 +帮冬 幫冬 +帮凶 幫兇 +帮别 幫別 +帮懒钻闲 幫懶鑽閒 +帮闲钻懒 幫閒鑽懶 +帷薄不修 帷薄不修 +常价 常價 +常任代表 常任代表 +常向 常向 +常回 常回 +常回去 常回去 +常回来 常回來 +常态分布 常態分佈 +常用参考书 常用參考書 +常绿阔叶 常綠闊葉 +常绿阔叶林 常綠闊葉林 +常胜 常勝 +常胜军 常勝軍 +常胜家 常勝家 +常胜将军 常勝將軍 +常衡制 常衡制 +常见于 常見於 +常须 常須 +帽帘 帽簾 +幅面 幅面 +幕前幕后 幕前幕後 +幕后 幕後 +幕后人物 幕後人物 +幕后新闻 幕後新聞 +幕后消息 幕後消息 +幕后花絮 幕後花絮 +幕后英雄 幕後英雄 +幕布 幕布 +幡布 幡布 +干一 幹一 +干一坛 乾一罈 +干一坛法 幹一壇法 +干一杯 乾一杯 +干一碗 乾一碗 +干上 幹上 +干下去 幹下去 +干不 幹不 +干不下 幹不下 +干不了 幹不了 +干不干 幹不幹 +干不干净 乾不乾淨 +干不干杯 乾不乾杯 +干不成 幹不成 +干与 干與 +干丝 乾絲 +干两年 幹兩年 +干两杯 乾兩杯 +干个 幹個 +干个够 幹個夠 +干么 幹麼 +干乔 乾喬 +干买卖 幹買賣 +干了 幹了 乾了 +干了什么 幹了什麼 +干了杯 乾了杯 +干了这一杯 乾了這一杯 +干了这一瓶 乾了這一瓶 +干了这杯 乾了這杯 +干了这碗 乾了這碗 +干事 幹事 +干事会 幹事會 +干事长 幹事長 +干云蔽日 乾雲蔽日 +干井 乾井 +干些 幹些 +干些什么 幹些什麼 +干产 乾產 +干亲 乾親 +干人 幹人 +干什 幹什 +干什么 幹什麼 +干他 幹他 干他 +干仗 幹仗 +干任何 幹任何 +干休 干休 +干休所 幹休所 +干伸舌 乾伸舌 +干何事 幹何事 +干你 幹你 干你 +干你娘 幹你孃 +干傻事 幹傻事 +干儿 乾兒 +干儿子 乾兒子 +干冒烟 乾冒煙 +干农活 幹農活 +干冰 乾冰 +干冷 乾冷 +干净 乾淨 +干净俐落 乾淨俐落 +干凉 乾涼 +干几件 幹幾件 +干几宗 幹幾宗 +干几手 乾幾手 +干几杯 乾幾杯 +干几桩 幹幾樁 +干几番 幹幾番 +干几碗 乾幾碗 +干几辈 幹幾輩 +干凯文 干凱文 +干出 幹出 +干刍 乾芻 +干別的 幹別的 +干到 幹到 +干制 乾製 +干刻版 乾刻版 +干剥剥 乾剝剝 +干办 幹辦 +干劲 幹勁 +干劲儿 幹勁兒 +干劲冲天 幹勁沖天 +干劲十足 幹勁十足 +干卦 乾卦 +干卿何事 干卿何事 +干卿底事 干卿底事 +干又热 乾又熱 +干台 乾颱 +干号 乾號 +干吊着下巴 乾吊着下巴 +干吏 幹吏 +干吗 幹嗎 +干呕 乾嘔 +干员 幹員 +干和 乾和 +干咳 乾咳 +干咽 乾嚥 +干咽唾 乾嚥唾 +干哑 乾啞 +干哕 乾噦 +干哥 乾哥 +干哥哥 乾哥哥 +干哭 乾哭 +干唱 乾唱 +干啤 乾啤 +干啥 幹啥 +干啼 乾啼 +干啼湿哭 乾啼溼哭 +干嘛 幹嘛 +干嚎 乾嚎 +干回付 乾回付 +干图 乾圖 +干圆洁净 乾圓潔淨 +干土 乾土 +干地 乾地 +干坏事 幹壞事 +干坐 乾坐 +干坐着 乾坐着 +干坛子 乾罈子 +干坞 乾塢 +干城 干城 +干堂婶 乾堂嬸 +干塘 乾塘 +干大事 幹大事 +干头 幹頭 +干女 乾女 +干女儿 乾女兒 +干女友 幹女友 +干女同事 幹女同事 +干女婿 乾女婿 +干女教师 幹女教師 +干奴才 乾奴才 +干她 幹她 干她 +干好 幹好 +干妈 乾媽 +干妹 乾妹 +干妹妹 乾妹妹 +干姊 乾姊 +干姊姊 乾姊姊 +干姐 乾姐 +干姜 乾薑 +干姬松茸 乾姬松茸 +干娘 乾孃 +干子 乾子 +干季 乾季 +干宅 乾宅 +干完 幹完 +干家 幹家 +干将 干將 +干将莫邪 干將莫邪 +干就干 幹就幹 +干尸 乾屍 +干尽 幹盡 +干尽一坛 乾盡一罈 +干尽一壺 乾盡一壺 +干尽一杯 乾盡一杯 +干尽一碗 乾盡一碗 +干屎橛 乾屎橛 +干巴 乾巴 +干巴巴 乾巴巴 +干巴巴的 乾巴巴的 +干布 乾布 +干干 乾乾 +干干儿的 乾乾兒的 +干干净净 乾乾淨淨 +干干巴巴 乾乾巴巴 +干干干干 幹幹幹幹 +干干淨淨 乾乾淨淨 +干干爽爽 乾乾爽爽 +干干瘦瘦 乾乾瘦瘦 +干干的 乾乾的 +干干脆脆 乾乾脆脆 +干式 乾式 +干弟 乾弟 +干弟弟 乾弟弟 +干强盗 幹強盜 +干当 幹當 +干得 幹得 +干得一杯 乾得一杯 +干得三杯 乾得三杯 +干得两杯 乾得兩杯 +干得了 幹得了 +干得很 乾得很 +干急 乾急 +干性 乾性 +干性油 乾性油 +干性皮肤 乾性皮膚 +干戈 干戈 +干戈扰攘 干戈擾攘 +干成 幹成 +干我 幹我 干我 +干戚 干鏚 +干扁豆角 干扁豆角 +干手净脚 乾手淨腳 +干才 幹才 +干打垒 乾打壘 +干打雷 乾打雷 +干扰 干擾 +干扰到 干擾到 +干扰力 干擾力 +干扰素 干擾素 +干折 乾折 +干拎娘 幹拎娘 +干挠 干撓 +干掉 幹掉 +干掉一杯 乾掉一杯 +干掉一瓶 乾掉一瓶 +干掉一碗 乾掉一碗 +干掉这杯 乾掉這杯 +干掉这碗 乾掉這碗 +干掉那杯 乾掉那杯 +干掉那碗 乾掉那碗 +干探 幹探 +干撂台 乾撂臺 +干撇下 乾撇下 +干擦 乾擦 +干支 干支 +干支剌 乾支剌 +干支支 乾支支 +干支沟 干支溝 +干政 干政 +干数杯 乾數杯 +干料 乾料 +干断 乾斷 +干旦 乾旦 +干旱 乾旱 +干旱地区 乾旱地區 +干时 干時 +干暖 乾暖 +干曜 乾曜 +干材 乾材 +干村沙 乾村沙 +干杯 乾杯 +干果 乾果 +干枝 乾枝 +干枯 乾枯 +干架 幹架 +干柴 乾柴 +干柴烈火 乾柴烈火 +干校 幹校 +干梅 乾梅 +干梅子 乾梅子 +干正事 幹正事 +干此坛 乾此罈 +干此杯 乾此杯 +干死 乾死 +干毛巾 乾毛巾 +干池 乾池 +干沟 乾溝 +干没 乾沒 +干洗 乾洗 +干洗店 乾洗店 +干活 幹活 +干活儿 幹活兒 +干流 幹流 +干济 幹濟 +干涉 干涉 +干涉仪 干涉儀 +干涉现象 干涉現象 +干涩 乾澀 +干涸 乾涸 +干淨 乾淨 +干淨俐落 乾淨俐落 +干渠 乾渠 +干渴 乾渴 +干湿 乾溼 +干湿发 乾溼髮 +干溪 乾溪 +干漆 乾漆 +干灯盏 乾燈盞 +干点 乾點 幹點 +干烧 乾燒 +干热 乾熱 +干焦 乾焦 +干煸 乾煸 +干熬 乾熬 +干熱 乾熱 +干燥 乾燥 +干燥剂 乾燥劑 +干燥器 乾燥器 +干燥机 乾燥機 +干燥箱 乾燥箱 +干父之蛊 幹父之蠱 +干爸 乾爸 +干爸爸 乾爸爸 +干爹 乾爹 +干爽 乾爽 +干片 乾片 +干犯 干犯 +干犯法 幹犯法 +干球温度 乾球溫度 +干甚 幹甚 +干甚么 幹甚麼 +干生受 乾生受 +干生子 乾生子 +干生气 乾生氣 +干田 乾田 +干电 乾電 +干电池 乾電池 +干略 幹略 +干疥 乾疥 +干瘦 乾瘦 +干瘪 乾癟 +干瘪瘪 乾癟癟 +干瘾 乾癮 +干癣 乾癬 +干癣性 乾癬性 +干白 乾白 +干白儿 乾白兒 +干的 乾的 +干的停当 幹的停當 +干眼 乾眼 +干眼病 乾眼病 +干眼症 乾眼症 +干着 幹着 乾着 +干着急 乾着急 +干瞪眼 乾瞪眼 +干硬 乾硬 +干碍 干礙 +干礼 乾禮 +干稿 乾稿 +干站 乾站 +干站着 乾站着 +干笑 乾笑 +干等 乾等 +干管 幹管 +干篾片 乾篾片 +干粉 乾粉 +干粗活 幹粗活 +干粮 乾糧 +干粮袋 乾糧袋 +干糇 乾餱 +干系 干係 +干細胞 幹細胞 +干红 乾紅 +干纲 乾綱 +干纲不振 乾綱不振 +干线 幹線 +干练 幹練 +干细胞 幹細胞 +干结 乾結 +干绷 乾繃 +干绷儿 乾繃兒 +干缺 幹缺 +干群 幹羣 +干群关系 幹羣關係 +干耗 乾耗 +干肉 乾肉 +干肉片 乾肉片 +干股 乾股 +干肥 乾肥 +干脆 乾脆 +干脆利落 乾脆利落 +干花 乾花 +干苔 乾薹 +干茨腊 乾茨臘 +干茶钱 乾茶錢 +干草 乾草 +干草叉 乾草叉 +干草堆 乾草堆 +干草机 乾草機 +干草粉 乾草粉 +干菜 乾菜 +干营生 幹營生 +干落 乾落 +干薪 乾薪 +干虔 乾虔 +干蛊 幹蠱 +干血浆 乾血漿 +干衣 乾衣 +干衣机 乾衣機 +干裂 乾裂 +干警 幹警 +干谒 干謁 +干象 乾象 +干贝 乾貝 +干货 乾貨 +干起 幹起 +干起来 幹起來 +干路 幹路 +干躁 乾躁 +干过 幹過 +干过一杯 乾過一杯 +干过杯 乾過杯 +干过瘾 乾過癮 +干这 幹這 +干这一杯 乾這一杯 +干这一行 幹這一行 +干这杯 乾這杯 +干这种事 幹這種事 +干连 干連 +干透 乾透 +干造 乾造 +干逼 乾逼 +干道 幹道 +干邑 干邑 +干那 幹那 +干那一杯 乾那一杯 +干那杯 乾那杯 +干部 幹部 +干酪 乾酪 +干酵母 乾酵母 +干醋 乾醋 +干重 乾重 +干量 乾量 +干锅 乾鍋 +干闼婆 乾闥婆 +干阿奶 乾阿奶 +干雷 乾雷 +干霍乱 乾霍亂 +干面 乾麪 +干革命 幹革命 +干预 干預 +干颡 乾顙 +干饭 乾飯 +干馆 乾館 +干馏 乾餾 +干馏法 乾餾法 +干鱼 乾魚 +干鲜 乾鮮 +干麻 幹麻 +干麻学 幹麻學 +干麻阿 幹麻阿 +平个 平個 +平个人 平個人 +平了 平了 +平价 平價 +平价住宅 平價住宅 +平价供应中心 平價供應中心 +平价商店 平價商店 +平克佛洛伊德 平克佛洛伊德 +平准 平準 +平准基金 平準基金 +平分秋色 平分秋色 +平台 平臺 +平台式扫描器 平臺式掃描器 +平台数 平臺數 +平台阶段 平臺階段 +平地上起一个霹雳 平地上起一個霹靂 +平地松林 平地松林 +平地楼台 平地樓臺 +平地青云 平地青雲 +平均价 平均價 +平均消费倾向 平均消費傾向 +平均股价 平均股價 +平复 平復 +平复帖 平復帖 +平复起来 平復起來 +平头并进 平頭並進 +平安里 平安裏 +平定准噶尔回部得胜图 平定準噶爾回部得勝圖 +平平当当 平平當當 +平康里 平康里 +平方公里 平方公里 +平方千米 平方千米 +平易谦冲 平易謙沖 +平板 平板 +平板仪 平板儀 +平板玻璃 平板玻璃 +平板车 平板車 +平梁 平梁 +平步青云 平步青雲 +平泉庄 平泉莊 +平胡 平胡 +平行六面 平行六面 +平行六面体 平行六面體 +平行叶脉 平行葉脈 +平行表亲 平行表親 +平衡台 平衡臺 +平表 平表 +平谷 平谷 +平谷区 平谷區 +平谷县 平谷縣 +平足症 平足症 +平针缝 平針縫 +平铲 平鏟 +平雕 平雕 +平面 平面 +平面几何 平面幾何 +平面图 平面圖 +平面图形 平面圖形 +平面媒体 平面媒體 +平面描迹 平面描跡 +平面曲线 平面曲線 +平面段 平面段 +平面波 平面波 +平面测量 平面測量 +平面艺术 平面藝術 +平面角 平面角 +平面镜 平面鏡 +平面雕刻 平面雕刻 +年久失修 年久失修 +年代里 年代裏 +年余 年餘 +年几 年幾 +年历 年曆 +年台 年臺 +年同 年同 +年后 年後 +年团子 年團子 +年复一年 年復一年 +年少得志 年少得志 +年德并高 年德並高 +年表 年表 +年谷 年穀 +年里 年裏 +年金制度 年金制度 +年鉴 年鑑 +年龄特征 年齡特徵 +并一不二 併一不二 +并上 並上 +并不 並不 +并不会 並不會 +并不在 並不在 +并不在乎 並不在乎 +并不并 併不併 +并不是 並不是 +并不能 並不能 +并与 並與 +并且 並且 +并世 並世 +并世无双 並世無雙 +并为 併爲 +并举 並舉 +并于 並於 +并产 併產 +并介之人 並介之人 +并先 並先 +并入 併入 +并兴 並興 +并兼 併兼 +并再 並再 +并出 並出 +并刀 並刀 +并列 並列 +并到 併到 +并力 併力 +并包 幷包 +并卷机 併捲機 +并发 併發 +并发动 並發動 +并发展 並發展 +并发现 並發現 +并发症 併發症 +并发表 並發表 +并叠 併疊 +并口 並口 +并可 並可 +并可以 並可以 +并合 併合 +并同 並同 +并名 併名 +并吞 併吞 +并吞下 併吞下 +并回 並回 +并回去 並回去 +并回来 並回來 +并在 並在 +并坐 並坐 +并垂不朽 並垂不朽 +并处 並處 +并头 並頭 +并头之花 並頭之花 +并头莲 並頭蓮 +并存 並存 +并存不悖 並存不悖 +并存在 並存在 +并寿 並壽 +并将 並將 +并州 幷州 +并州剪 幷州剪 +并州故乡 幷州故鄉 +并当 並當 +并往 並往 +并得 並得 +并成 併成 +并把 並把 +并拢 併攏 +并排 並排 +并排而坐 並排而坐 +并无 並無 +并无不可 並無不可 +并无不当 並無不當 +并无此事 並無此事 +并日 並日 +并日而食 並日而食 +并时 並時 +并是 並是 +并曰入淀 並曰入澱 +并有 並有 +并未 並未 +并条 並條 +并案 併案 +并案处理 併案處理 +并概青云 並概青雲 +并毂 並轂 +并没 並沒 +并没有 並沒有 +并派 並派 +并流 並流 併流 +并激 並激 +并火 併火 +并然 並然 +并爲 並爲 +并用 並用 +并由 並由 +并禽 並禽 +并科 併科 +并称 並稱 +并立 並立 +并纱 併紗 +并线 併線 +并网 併網 +并置 並置 +并翼齐飞 並翼齊飛 +并联 並聯 +并肩 並肩 +并肩作战 並肩作戰 +并肩前进 並肩前進 +并肩子 併肩子 +并肩干 並肩幹 +并肩而行 並肩而行 +并能 並能 +并能夠 並能夠 +并蒂 並蒂 +并蒂莲 並蒂蓮 +并行 並行 +并行不悖 並行不悖 +并行口 並行口 +并行程序 並行程序 +并行计算 並行計算 +并要 並要 +并规范 並規範 +并论 並論 +并请 並請 +并购 併購 +并购买 併購買 +并购案 併購案 +并赃拿败 並贓拿敗 +并赃拿贼 併贓拿賊 +并赃治罪 併贓治罪 +并起 並起 +并跡 並跡 +并躺 並躺 +并躺在 並躺在 +并轨 並軌 +并辏 並輳 +并辔 並轡 +并过 並過 +并过去 並過去 +并过来 並過來 +并进 並進 +并进去 並進去 +并进来 並進來 +并迭 並迭 +并邀 並邀 +并邦 並邦 +并邻 並鄰 +并采 並採 +并重 並重 +并除 併除 +并非 並非 +并非在 並非在 +并非是 並非是 +并马 並馬 +并驰 並馳 +并驱 並驅 +并驾 並駕 +并驾齐驱 並駕齊驅 +并骛 並騖 +并骨 併骨 +幸不辱命 幸不辱命 +幸为先容 幸爲先容 +幸事 幸事 +幸于 幸於 +幸于始者怠于终 幸於始者怠於終 +幸亏 幸虧 +幸亏在 幸虧在 +幸亏是 幸虧是 +幸亏有 幸虧有 +幸会 幸會 +幸位 幸位 +幸倡 幸倡 +幸免 倖免 +幸免于难 倖免於難 +幸发亭 幸發亭 +幸喜 幸喜 +幸好 幸好 +幸好是 幸好是 +幸好有 幸好有 +幸子 幸子 +幸存 倖存 +幸存者 倖存者 +幸幸 倖幸 +幸得 幸得 +幸感歌姬 倖感歌姬 +幸未 幸未 +幸村 幸村 +幸次 幸次 +幸民 幸民 +幸灾乐祸 幸災樂禍 +幸然 幸然 +幸甚 幸甚 +幸生 幸生 +幸福 幸福 +幸福女人小公主 幸福女人小公主 +幸福学 幸福學 +幸福家庭 幸福家庭 +幸福感 幸福感 +幸福戏院 幸福戲院 +幸童 幸童 +幸而 幸而 +幸而是 幸而是 +幸能 幸能 +幸臣 倖臣 +幸获识荆 幸獲識荊 +幸蒙 幸蒙 +幸运 幸運 +幸运之星 幸運之星 +幸运之神 幸運之神 +幸运人 幸運人 +幸运儿 幸運兒 +幸运券 幸運券 +幸运抽奖 幸運抽獎 +幸运星 幸運星 +幸运物 幸運物 +幸运球 幸運球 +幸运胡 幸運鬍 +幸运色 幸運色 +幸运草 幸運草 +幸进 倖進 +幸逢 幸逢 +幺么小丑 幺麼小醜 +幺并矢 幺並矢 +幺麼小丑 幺麼小醜 +幺麽小丑 幺麼小醜 +幻出 幻出 +幻念 幻念 +幻想曲 幻想曲 +幻术 幻術 +幼发拉底 幼發拉底 +幼发拉底河 幼發拉底河 +幼发拉底河谷 幼發拉底河谷 +幼托 幼托 +幼虫 幼蟲 +幽咽 幽咽 +幽岩 幽巖 +幽幽暗暗 幽幽暗暗 +幽明录 幽明錄 +幽暗 幽暗 +幽栖岩谷 幽棲巖谷 +幽谷 幽谷 +幽门狭窄症 幽門狹窄症 +幽闭恐惧症 幽閉恐懼症 +广东住血吸虫 廣東住血吸蟲 +广东炒面 廣東炒麪 +广东药学院 廣東藥學院 +广丰 廣豐 +广丰县 廣豐縣 +广厦万间 廣廈萬間 +广发 廣發 +广告曲 廣告曲 +广告板 廣告板 +广告系 廣告系 +广场恐怖症 廣場恐怖症 +广场恐惧症 廣場恐懼症 +广布 廣佈 +广征 廣徵 +广播台 廣播臺 +广播电台 廣播電臺 +广播系统 廣播系統 +广泛 廣泛 +广舍 廣捨 +广部 广部 +广里 廣裏 +庄上 莊上 +庄严 莊嚴 +庄主 莊主 +庄农 莊農 +庄员 莊員 +庄周 莊周 +庄周梦蝶 莊周夢蝶 +庄园 莊園 +庄园制度 莊園制度 +庄士顿道 莊士頓道 +庄子 莊子 +庄客 莊客 +庄家 莊家 +庄志伟 莊志偉 +庄户 莊戶 +庄房 莊房 +庄敬 莊敬 +庄田 莊田 +庄秋南 莊秋南 +庄稼 莊稼 +庄稼人 莊稼人 +庄稼院 莊稼院 +庄胜雄 莊勝雄 +庄舄越吟 莊舄越吟 +庄语 莊語 +庄里 莊裏 +庄重 莊重 +庄院 莊院 +庄骚 莊騷 +庆丰 慶豐 +庆云 慶雲 +庆云县 慶雲縣 +庆余 慶餘 +庆历 慶曆 +庆历新政 慶曆新政 +庆吊 慶弔 +庆幸 慶幸 +庇荫 庇廕 +庇里牛斯 庇里牛斯 +庇里牛斯山 庇里牛斯山 +床头柜 牀頭櫃 +床席 牀蓆 +床板 牀板 +序升 序升 +序录 序錄 +序曲 序曲 +庐山真面目 廬山真面目 +庐山面目 廬山面目 +庐舍 廬舍 +库仑 庫侖 +库仑定律 庫侖定律 +库仑计 庫侖計 +库克 庫克 +库克山 庫克山 +库克群岛 庫克羣島 +库克船长 庫克船長 +库尔德工人党 庫爾德工人黨 +库尔斯克 庫爾斯克 +库工党 庫工黨 +库布里克 庫布里克 +库木吐拉千佛洞 庫木吐拉千佛洞 +库瑞克 庫瑞克 +库苏古尔湖 庫蘇古爾湖 +库贝克 庫貝克 +库贾氏症 庫賈氏症 +库辛尼克 庫辛尼克 +库里尔台 庫里爾臺 +库里提巴 庫裏提巴 +应付得当 應付得當 +应付票据 應付票據 +应克制 應剋制 +应制 應制 +应占 應占 +应声虫 應聲蟲 +应当 應當 +应当会 應當會 +应当在 應當在 +应当是 應當是 +应当有 應當有 +应当能 應當能 +应征 應徵 +应征信 應徵信 +应征稿 應徵稿 +应征者 應徵者 +应急出口 應急出口 +应收帐款周转率 應收帳款週轉率 +应收票据 應收票據 +应时当令 應時當令 +应有尽有 應有盡有 +应用于 應用於 +应用平台 應用平臺 +应用技术 應用技術 +应用范例 應用範例 +应用范围 應用範圍 +应运而出 應運而出 +应钟 應鐘 +应须 應須 +底价 底價 +底夸克 底夸克 +底板 底板 +底极 底極 +底栖有孔虫 底棲有孔蟲 +底格里斯 底格里斯 +底格里斯河 底格里斯河 +底脚里人 底腳裏人 +底里 底裏 +底面 底面 +店伙 店夥 +店里 店裏 +店面 店面 +店面广告 店面廣告 +庙台 廟臺 +庙里 廟裏 +府兵制 府兵制 +府台 府臺 +府后 府後 +府干 府幹 +府谷 府谷 +府谷县 府谷縣 +庞克 龐克 +庞克头 龐克頭 +庞巴瓦克 龐巴瓦克 +庞德维克 龐德維克 +庞志龙 龐志龍 +庞眉白发 龐眉白髮 +庞眉皓发 龐眉皓髮 +废了 廢了 +废后 廢后 +度假胜地 度假勝地 +度搜 度搜 +度曲 度曲 +度身定制 度身定製 +座钟 座鐘 +庵主 庵主 +庵儿 庵兒 +庵堂 庵堂 +庵婪 菴婪 +庵寺 庵寺 +庵庐 菴廬 +庵庵 菴菴 +庵罗树园 菴羅樹園 +庵舍 菴舍 +庵蔼 菴藹 +庵观 庵觀 +庶几 庶幾 +庶几无愧 庶幾無愧 +庶出 庶出 +康乃狄克 康乃狄克 +康乃狄克州 康乃狄克州 +康回 康回 +康复 康復 +康复医学 康復醫學 +康多莉扎赖斯 康多莉扎賴斯 +康庄 康莊 +康庄大道 康莊大道 +康托尔 康托爾 +康梁 康梁 +康济录 康濟錄 +康百克 康百克 +康纳克立 康納克立 +康采恩 康采恩 +庸才 庸才 +庸暗 庸闇 +廉价 廉價 +廉价品 廉價品 +廉售价 廉售價 +廉纤 廉纖 +廖于诚 廖于誠 +廖俊杰 廖俊傑 +廖千莹 廖千瑩 +廖志坚 廖志堅 +廖本烟 廖本煙 +廖本胜 廖本勝 +廖英杰 廖英傑 +廖金钟 廖金鐘 +廛布 廛布 +廢后 廢后 +廪秋 廩秋 +廪膳秀才 廩膳秀才 +延伸出 延伸出 +延修 延修 +延厘 延釐 +延发 延發 +延后 延後 +延地里 延地裏 +延挨 延挨 +延陵挂剑 延陵掛劍 +廷争面折 廷爭面折 +廷巴克图 廷巴克圖 +廷布 廷布 +建于 建於 +建党 建黨 +建党节 建黨節 +建出 建出 +建制 建制 +建厂 建廠 +建台 建臺 +建教合作 建教合作 +建教合作班 建教合作班 +建极 建極 +建立规范 建立規範 +建筑 建築 +建筑业 建築業 +建筑商 建築商 +建筑学 建築學 +建筑容积管制 建築容積管制 +建筑工业 建築工業 +建筑工人 建築工人 +建筑工地 建築工地 +建筑工程 建築工程 +建筑师 建築師 +建筑执照 建築執照 +建筑机械 建築機械 +建筑材料 建築材料 +建筑法规 建築法規 +建筑物 建築物 +建筑界 建築界 +建筑科 建築科 +建筑系 建築系 +建筑结构 建築結構 +建筑群 建築羣 +建筑艺术 建築藝術 +建筑节 建築節 +建筑设计 建築設計 +建筑起来 建築起來 +建筑面积 建築面積 +建造出 建造出 +建都于 建都於 +廿五万 廿五萬 +开不了 開不了 +开个 開個 +开了 開了 +开云见日 開雲見日 +开价 開價 +开伙 開伙 +开元录 開元錄 +开冬 開冬 +开出 開出 +开出去 開出去 +开出来 開出來 +开刀手术 開刀手術 +开列于后 開列於後 +开创出 開創出 +开化党 開化黨 +开卷 開卷 +开卷有得 開卷有得 +开卷有益 開卷有益 +开卷考 開卷考 +开厂 開廠 +开发 開發 +开发中 開發中 +开发中国 開發中國 +开发中国家 開發中國家 +开发为 開發爲 +开发井 開發井 +开发人员 開發人員 +开发出 開發出 +开发出来 開發出來 +开发区 開發區 +开发周期 開發週期 +开发商 開發商 +开发国家 開發國家 +开发基金 開發基金 +开发局 開發局 +开发成 開發成 +开发案 開發案 +开发法 開發法 +开发环境 開發環境 +开发署 開發署 +开发者 開發者 +开发过程 開發過程 +开发金 開發金 +开发银行 開發銀行 +开台 開臺 +开台圣王 開臺聖王 +开台锣鼓 開臺鑼鼓 +开吊 開弔 +开后门 開後門 +开向 開向 +开哄 開鬨 +开回 開回 +开回去 開回去 +开回来 開回來 +开复 開復 +开天辟地 開天闢地 +开彩 開彩 +开征 開徵 +开支范围 開支範圍 +开放式系统 開放式系統 +开放性医疗制度 開放性醫療制度 +开放系统 開放系統 +开放系统互连 開放系統互連 +开放舞台 開放舞臺 +开新板 開新板 +开明专制 開明專制 +开杆 開杆 +开杠 開槓 +开棺验尸 開棺驗屍 +开疆辟土 開疆闢土 +开盘价 開盤價 +开盘汇率 開盤匯率 +开秋 開秋 +开筑 開築 +开膛手杰克 開膛手傑克 +开药 開藥 +开药方 開藥方 +开蒙 開蒙 +开诚布公 開誠佈公 +开辟 開闢 +开辟出来 開闢出來 +开辟者 開闢者 +开辟记 開闢記 +开采 開採 +开采权 開採權 +开采法 開採法 +开除党籍 開除黨籍 +开面 開面 +开齐合撮 開齊合撮 +异中求同 異中求同 +异于 異於 +异动表 異動表 +异口同声 異口同聲 +异口同辞 異口同辭 +异口同音 異口同音 +异同 異同 +异形叶 異形葉 +异彩 異彩 +异志 異志 +异念 異念 +异才 異才 +异曲同工 異曲同工 +异派同源 異派同源 +异烟碱醯酸 異菸鹼醯酸 +异种 異種 +异苔同岑 異薹同岑 +异路同归 異路同歸 +异途同归 異途同歸 +异采 異采 +弃宗弄赞 棄宗弄贊 +弃尸 棄屍 +弃尸案 棄屍案 +弃弓折箭 棄弓折箭 +弃恶从善 棄惡從善 +弃暗投明 棄暗投明 +弃核 棄核 +弃武修文 棄武修文 +弃瑕录用 棄瑕錄用 +弃舍 棄捨 +弄丑 弄醜 +弄僵 弄僵 +弄出 弄出 +弄出去 弄出去 +弄出来 弄出來 +弄坏了 弄壞了 +弄干 弄乾 +弄拧了 弄擰了 +弄松 弄鬆 +弄盏传杯 弄盞傳杯 +弄粉调朱 弄粉調朱 +弄脏 弄髒 +弄面吃 弄麪吃 +弄鬼吊猴 弄鬼弔猴 +弈秋 弈秋 +弊帚千金 弊帚千金 +弊幸 弊倖 +弊恶 弊惡 +弋获 弋獲 +弓不虚发 弓不虛發 +弓弦 弓弦 +弓影杯蛇 弓影杯蛇 +弓影浮杯 弓影浮杯 +弓折矢尽 弓折矢盡 +弓折箭尽 弓折箭盡 +弓极 弓極 +弓浆虫 弓漿蟲 +弓腰曲背 弓腰曲背 +引人入胜 引人入勝 +引人注意 引人注意 +引人注目 引人注目 +引以为鉴 引以爲鑑 +引伸出 引伸出 +引体向上 引體向上 +引信系统 引信系統 +引出 引出 +引出去 引出去 +引出来 引出來 +引发 引發 +引发出 引發出 +引发物质 引發物質 +引向 引向 +引导出 引導出 +引布 引布 +引拉出 引拉出 +引据 引據 +引斗 引鬥 +引渡回国 引渡回國 +引牵出 引牽出 +引种 引種 +引线穿针 引線穿針 +引经据典 引經據典 +引经据古 引經據古 +引而不发 引而不發 +引致 引致 +引蛇出洞 引蛇出洞 +弗兰克 弗蘭克 +弗洛里斯岛 弗洛裏斯島 +弗罗里达 弗羅裏達 +弗罗里达州 弗羅裏達州 +弗里得里希 弗裏得裏希 +弗里德里希 弗里德里希 +弗里敦 弗里敦 +弗里斯兰 弗里斯蘭 +弗里曼 弗里曼 +弗雷德里克 弗雷德裏克 +弗雷德里克顿 弗雷德裏克頓 +弘历 弘曆 +弘愿 弘願 +张三丰 張三丰 +张世杰 張世傑 +张了 張了 +张云光 張雲光 +张兆志 張兆志 +张克帆 張克帆 +张出 張出 +张勇杰 張勇傑 +张勋 張勳 +张千 張千 +张基郁 張基郁 +张堪折辕 張堪折轅 +张大千 張大千 +张必 張必 +张志 張志 +张志和 張志和 +张志家 張誌家 +张志弘 張志弘 +张志强 張志強 +张志忠 張志忠 +张志新 張志新 +张志贤 張志賢 +张志辉 張志輝 +张志铭 張志銘 +张扬出去 張揚出去 +张扬出来 張揚出來 +张挂 張掛 +张挂在 張掛在 +张挂起 張掛起 +张挂起来 張掛起來 +张文松 張文松 +张斗辉 張斗輝 +张智杰 張智傑 +张木松 張木松 +张杰 張傑 +张栋梁 張棟樑 +张灯挂彩 張燈掛彩 +张灯结彩 張燈結綵 +张玄墓志铭 張玄墓誌銘 +张琴松 張琴松 +张秋 張秋 +张秋明 張秋明 +张罗殆尽 張羅殆盡 +张聪秋 張聰秋 +张致 張致 +张良借箸 張良借箸 +张良慕赤松 張良慕赤松 +张苙云 張苙雲 +张荣发 張榮發 +张金涂 張金塗 +张飞穿针 張飛穿針 +张黑女墓志铭 張黑女墓誌銘 +弥久 彌久 +弥习弥佳 彌習彌佳 +弥事 彌事 +弥勒 彌勒 +弥勒佛 彌勒佛 +弥勒县 彌勒縣 +弥勒菩萨 彌勒菩薩 +弥天 彌天 +弥天亙地 彌天亙地 +弥天大罪 彌天大罪 +弥天大谎 彌天大謊 +弥天案 彌天案 +弥封 彌封 +弥山遍野 瀰山遍野 +弥年 彌年 +弥弥 瀰瀰 +弥撒 彌撒 +弥撒曲 彌撒曲 +弥撒经书 彌撒經書 +弥敬 彌敬 +弥时 彌時 +弥月 彌月 +弥月之喜 彌月之喜 +弥月酒 彌月酒 +弥望 彌望 +弥渡县 彌渡縣 +弥满 彌滿 +弥漫 瀰漫 +弥漫性 瀰漫性 +弥漫着 瀰漫着 +弥猴桃 彌猴桃 +弥生文化 彌生文化 +弥留 彌留 +弥留之际 彌留之際 +弥纶 彌綸 +弥缝 彌縫 +弥罗 彌羅 +弥蒙 彌矇 +弥补 彌補 +弥赛亚 彌賽亞 +弥足珍贵 彌足珍貴 +弥迦书 彌迦書 +弥陀 彌陀 +弥陀乡 彌陀鄉 +弦上 弦上 +弦不虚发 弦不虛發 +弦乐 絃樂 +弦乐团 絃樂團 +弦动 絃動 +弦器 絃器 +弦声 絃聲 +弦子 弦子 +弦弓 弦弓 +弦拨 弦撥 +弦断 絃斷 +弦月 弦月 +弦歌 絃歌 +弦琴 絃琴 +弦索 絃索 +弦线 絃線 +弦轴 絃軸 +弦重 弦重 +弦长 弦長 +弦面板 弦面板 +弦音 絃音 +弯出去 彎出去 +弯出来 彎出來 +弯回 彎回 +弯回去 彎回去 +弯回来 彎回來 +弯弯曲曲 彎彎曲曲 +弯折 彎折 +弯拐 彎拐 +弯曲 彎曲 +弯曲度 彎曲度 +弯曲状 彎曲狀 +弯曲空间 彎曲空間 +弯管面 彎管麪 +弱不胜衣 弱不勝衣 +弱于 弱於 +弱势团体 弱勢團體 +弱智赖于涵 弱智賴于涵 +弱水三千 弱水三千 +弱音踏板 弱音踏板 +弹不出 彈不出 +弹了 彈了 +弹出 彈出 +弹出去 彈出去 +弹出来 彈出來 +弹升 彈升 +弹回 彈回 +弹回去 彈回去 +弹回来 彈回來 +弹奏出 彈奏出 +弹子台 彈子檯 +弹射出 彈射出 +弹尽援绝 彈盡援絕 +弹尽粮绝 彈盡糧絕 +弹布尔 彈布爾 +弹性制造系统 彈性製造系統 +弹性控制 彈性控制 +弹性纤维 彈性纖維 +弹无虚发 彈無虛發 +弹涂鱼 彈塗魚 +弹珠台 彈珠檯 +弹药 彈藥 +弹药兵 彈藥兵 +弹药库 彈藥庫 +弹药箱 彈藥箱 +弹药补给站 彈藥補給站 +弹跳板 彈跳板 +弹针 彈針 +强了 強了 +强于 強於 +强借 強借 +强制 強制 +强制作用 強制作用 +强制保险 強制保險 +强制力 強制力 +强制处分 強制處分 +强制性 強制性 +强制手段 強制手段 +强制执行 強制執行 +强制罪 強制罪 +强制认领 強制認領 +强制辩护 強制辯護 +强制险 強制險 +强力攻占 強力攻佔 +强加于 強加於 +强加于人 強加於人 +强占 強佔 +强占性 強佔性 +强咽 強嚥 +强奸 強姦 +强奸民意 強姦民意 +强奸犯 強姦犯 +强奸罪 強姦罪 +强干 強幹 +强干弱枝 強幹弱枝 +强征 強徵 +强心针 強心針 +强投松 強投松 +强梁 強梁 +强烈台风 強烈颱風 +强烈愿望 強烈願望 +强聒不舍 強聒不捨 +强迫性储物症 強迫性儲物症 +强迫症 強迫症 +强音踏板 強音踏板 +弼针 弼針 +彊干弱枝 彊幹弱枝 +彊御 彊禦 +彊志 彊志 +彊梁 彊梁 +归于 歸於 +归余 歸餘 +归功于 歸功於 +归向 歸向 +归向导引 歸向導引 +归咎于 歸咎於 +归回 歸回 +归因于 歸因於 +归属于 歸屬於 +归并 歸併 +归并到 歸併到 +归并在 歸併在 +归烟 歸煙 +归真反朴 歸真反樸 +归类于 歸類於 +归纳出 歸納出 +归罪于 歸罪於 +归虚谷 歸虛谷 +归诸于 歸諸於 +归里包堆 歸裏包堆 +归随于 歸隨於 +归面 歸面 +归顺于 歸順於 +当一回事 當一回事 +当一声 噹一聲 +当一当 當一當 +当上 當上 +当上去 當上去 +当上来 當上來 +当下 當下 +当下去 當下去 +当下来 當下來 +当不上 當不上 +当不了 當不了 +当不得 當不得 +当不成 當不成 +当不来 當不來 +当不起 當不起 +当不过 當不過 +当且仅当 當且僅當 +当世 當世 +当世之冠 當世之冠 +当世儒宗 當世儒宗 +当世冠 當世冠 +当世才度 當世才度 +当世无双 當世無雙 +当世无敌 當世無敵 +当个 當個 +当中 當中 +当为 當爲 +当之无愧 當之無愧 +当之有愧 當之有愧 +当了 當了 +当事 當事 +当事人 當事人 +当事国 當事國 +当事者 當事者 +当于 當於 +当仁不让 當仁不讓 +当今 當今 +当今无辈 當今無輩 +当代 當代 +当代人 當代人 +当代史 當代史 +当代大师 當代大師 +当代新儒家 當代新儒家 +当令 當令 +当众 當衆 +当众宣布 當衆宣佈 +当众表明 當衆表明 +当众表示 當衆表示 +当作 當作 +当便 當便 +当值 當值 +当做 當做 +当儿 當兒 +当元 當元 +当先 當先 +当关 當關 +当兵 當兵 +当其冲 當其衝 +当准 當準 +当初 當初 +当到 當到 +当前 當前 +当前之计 當前之計 +当前季 當前季 +当务之急 當務之急 +当劳之急 當勞之急 +当午 當午 +当卢 當盧 +当即 當即 +当原 當原 +当厨 當廚 +当口 當口 +当句对 當句對 +当可 當可 +当合 當合 +当周 當週 +当啷 噹啷 +当啷落地 噹啷落地 +当回事 當回事 +当回事儿 當回事兒 +当国 當國 +当地 當地 +当地人 當地人 +当地化 當地化 +当地居民 當地居民 +当地时间 當地時間 +当场 當場 +当场出丑 當場出醜 +当场出彩 當場出彩 +当场只手 當場隻手 +当场听到 當場聽到 +当场抓到 當場抓到 +当场献丑 當場獻醜 +当场看到 當場看到 +当坊土地 當坊土地 +当垆 當壚 +当堂 當堂 +当堵 當堵 +当夕 當夕 +当夜 當夜 +当天 當天 +当天事当天毕 當天事當天畢 +当头 當頭 +当头一棒 當頭一棒 +当头人 當頭人 +当头棒喝 當頭棒喝 +当头炮 當頭炮 +当头阵 當頭陣 +当完兵 當完兵 +当官 當官 +当官追究 當官追究 +当室 當室 +当家 當家 +当家三年狗也嫌 當家三年狗也嫌 +当家人 當家人 +当家人恶水缸 當家人惡水缸 +当家作主 當家作主 +当家和尚 當家和尚 +当家子 當家子 +当家小生 當家小生 +当家才知柴米价 當家纔知柴米價 +当家方知柴米贵 當家方知柴米貴 +当家的 當家的 +当家立事 當家立事 +当家花旦 當家花旦 +当局 當局 +当局称迷傍观必审 當局稱迷傍觀必審 +当局者迷 當局者迷 +当局者迷傍观者清 當局者迷傍觀者清 +当局者迷旁观者清 當局者迷旁觀者清 +当巡 當巡 +当差 當差 +当差的 當差的 +当年 當年 +当应 當應 +当庭 當庭 +当归 當歸 +当归鸭 當歸鴨 +当当 噹噹 +当当丁丁 當當丁丁 +当当当 噹噹噹 +当当船 噹噹船 +当当车 噹噹車 +当役 當役 +当待 當待 +当得 當得 +当得上 當得上 +当得来 當得來 +当得起 當得起 +当心 當心 +当意 當意 +当成 當成 +当手 當手 +当拦 當攔 +当掉 當掉 +当撑 當撐 +当政 當政 +当政者 當政者 +当敌 當敵 +当断不断 當斷不斷 +当断不断反受其乱 當斷不斷反受其亂 +当日 當日 +当日份 當日份 +当时 當時 +当时得令 當時得令 +当时的 當時的 +当时车 當時車 +当是 當是 +当晚 當晚 +当曲河 當曲河 +当月 當月 +当月份 當月份 +当朝 當朝 +当朝宰相 當朝宰相 +当期 當期 +当机 當機 +当机立断 當機立斷 +当权 當權 +当权派 當權派 +当权者 當權者 +当村 當村 +当来 當來 +当来当去 當來當去 +当案 當案 +当槽 當槽 +当此 當此 +当涂 當塗 +当涂县 當塗縣 +当演员 當演員 +当灾 當災 +当炉 當爐 +当然 當然 +当然会 當然會 +当然在 當然在 +当然是 當然是 +当然有 當然有 +当然继承主义 當然繼承主義 +当牢节级 當牢節級 +当班 當班 +当班人员 當班人員 +当用 當用 +当用则用 當用則用 +当番 當番 +当的一响 噹的一響 +当的一声 噹的一聲 +当直 當直 +当直巡逻 當直巡邏 +当直的 當直的 +当真 當真 +当真假 當真假 +当真的 當真的 +当眼 當眼 +当眼处 當眼處 +当票 當票 +当票子 當票子 +当空 當空 +当紧 當緊 +当红 當紅 +当罏 當罏 +当罏红袖 當罏紅袖 +当者披靡 當者披靡 +当耳边风 當耳邊風 +当艄拿舵 當艄拿舵 +当艄顺 當艄順 +当花 當花 +当行 當行 +当行出色 當行出色 +当行家 當行家 +当街 當街 +当衣买酒喝 當衣買酒喝 +当该 當該 +当赌 當賭 +当起 當起 +当起来 當起來 +当路 當路 +当路子 當路子 +当轴 當軸 +当过 當過 +当选 當選 +当选为 當選爲 +当选人 當選人 +当选无效 當選無效 +当选者 當選者 +当道 當道 +当道者 當道者 +当量 當量 +当量剂量 當量劑量 +当量浓度 當量濃度 +当铺 當鋪 +当门对户 當門對戶 +当门户 當門戶 +当门抵户 當門抵戶 +当门牙齿 當門牙齒 +当间 當間 +当阳 當陽 +当阳市 當陽市 +当院 當院 +当雄 當雄 +当雄县 當雄縣 +当面 當面 +当面唾骂 當面唾罵 +当面对质 當面對質 +当面言明 當面言明 +当面银子对面钱 當面銀子對面錢 +当面错过 當面錯過 +当面锣对面鼓 當面鑼對面鼓 +当面鼓对面锣 當面鼓對面鑼 +当风秉烛 當風秉燭 +录上 錄上 +录上去 錄上去 +录上来 錄上來 +录下 錄下 +录下去 錄下去 +录下来 錄下來 +录个 錄個 +录了 錄了 +录事 錄事 +录供 錄供 +录像 錄像 +录像带 錄像帶 +录像机 錄像機 +录像片 錄像片 +录到 錄到 +录制 錄製 +录取 錄取 +录取人数 錄取人數 +录取分数 錄取分數 +录取名单 錄取名單 +录取名额 錄取名額 +录取率 錄取率 +录取通知书 錄取通知書 +录囚 錄囚 +录在 錄在 +录录 彔彔 +录录歌 錄錄歌 +录录音 錄錄音 +录影 錄影 +录影器 錄影器 +录影带 錄影帶 +录影带奖 錄影帶獎 +录影机 錄影機 +录影碟 錄影碟 +录影节目 錄影節目 +录得 錄得 +录成 錄成 +录放影机 錄放影機 +录放音机 錄放音機 +录歌 錄歌 +录灌 錄灌 +录点 錄點 +录用 錄用 +录的 錄的 +录科 錄科 +录起 錄起 +录起来 錄起來 +录载 錄載 +录过 錄過 +录遗 錄遺 +录音 錄音 +录音室 錄音室 +录音师 錄音師 +录音带 錄音帶 +录音机 錄音機 +录音电话 錄音電話 +录音间 錄音間 +录鬼簿 錄鬼簿 +彗核 彗核 +彗氾画涂 彗氾畫塗 +形丑心善 形醜心善 +形于 形於 +形于色 形於色 +形于言色 形於言色 +形于辞色 形於辭色 +形于颜色 形於顏色 +形制 形制 +形单影只 形單影隻 +形只影单 形隻影單 +形同 形同 +形同具文 形同具文 +形同虚设 形同虛設 +形同陌路 形同陌路 +形名参同 形名參同 +形孤影只 形孤影隻 +形容尽致 形容盡致 +形影相吊 形影相弔 +形态发生素 形態發生素 +形疲神困 形疲神困 +形胜 形勝 +形象艺术 形象藝術 +彤云 彤雲 +彩云 彩雲 +彩云国 彩雲國 +彩云易散 彩雲易散 +彩信 彩信 +彩先达 彩先達 +彩光 彩光 +彩光板 彩光板 +彩凤 綵鳳 +彩凤随鸦 彩鳳隨鴉 +彩券 彩券 +彩券局 彩券局 +彩券行 彩券行 +彩印 彩印 +彩卷 彩卷 +彩叶芋 彩葉芋 +彩叶草 彩葉草 +彩号 彩號 +彩喷 彩噴 +彩图 彩圖 +彩塑 彩塑 +彩墨 彩墨 +彩头 彩頭 +彩女 綵女 +彩妆 彩妝 +彩妆保养化 彩妝保養化 +彩妆品 彩妝品 +彩妆师 彩妝師 +彩市 彩市 +彩带 綵帶 +彩带舞 綵帶舞 +彩度 彩度 +彩弹 彩彈 +彩影 彩影 +彩扩 彩擴 +彩排 彩排 +彩旗 彩旗 +彩旦 彩旦 +彩条 彩條 +彩棚 綵棚 +彩楼 綵樓 +彩楼配 綵樓配 +彩民 彩民 +彩池 彩池 +彩灯 彩燈 +彩照 彩照 +彩牌楼 綵牌樓 +彩球 綵球 +彩瓷 彩瓷 +彩电 彩電 +彩电视 彩電視 +彩画 彩畫 +彩砖 彩磚 +彩礼 彩禮 +彩票 彩票 +彩票卡 彩票卡 +彩笔 彩筆 +彩笔生 彩筆生 +彩笔生花 綵筆生花 +彩管生花 彩管生花 +彩纸 彩紙 +彩线 綵線 +彩练 彩練 +彩绘 彩繪 +彩绸 綵綢 +彩缎 綵緞 +彩缯 綵繒 +彩胜 綵勝 +彩船 綵船 +彩色 彩色 +彩色世界 彩色世界 +彩色正片 彩色正片 +彩色照 彩色照 +彩色照片 彩色照片 +彩色片 彩色片 +彩色版 彩色版 +彩色玻璃 彩色玻璃 +彩色电影 彩色電影 +彩色电视 彩色電視 +彩色电视机 彩色電視機 +彩色笔 彩色筆 +彩色米 彩色米 +彩色缤纷 彩色繽紛 +彩虹 彩虹 +彩虹仙子 彩虹仙子 +彩虹冰铺 彩虹冰鋪 +彩虹桥 彩虹橋 +彩蛋 彩蛋 +彩蝶 彩蝶 +彩蝶谷 彩蝶谷 +彩衣 綵衣 +彩衣娱亲 綵衣娛親 +彩调 彩調 +彩车 彩車 +彩轿 彩轎 +彩迷 彩迷 +彩釉 彩釉 +彩金 彩金 +彩钱 彩錢 +彩铃 彩鈴 +彩陶 彩陶 +彩陶文化 彩陶文化 +彩雕 彩雕 +彩霞 彩霞 +彩饰 彩飾 +彩饰版 彩飾版 +彩鸾 綵鸞 +彩鹢 彩鷁 +彪个子 彪個子 +彪炳千古 彪炳千古 +彭于晏 彭于晏 +彭克港 彭克港 +彭咸 彭咸 +彭志光 彭志光 +彭志华 彭志華 +彭绍升 彭紹升 +彭胜竹 彭勝竹 +彭蒙 彭蒙 +彰化师范大学 彰化師範大學 +彰善瘅恶 彰善癉惡 +彰彰可据 彰彰可據 +彰显出 彰顯出 +影像合成 影像合成 +影像处理系统 影像處理系統 +影占 影占 +影只形单 影隻形單 +影后 影后 +影响不了 影響不了 +影坛 影壇 +影坛红星 影壇紅星 +影评人周 影評人週 +役于 役於 +役于外物 役於外物 +役别 役別 +役种 役種 +彻里彻外 徹裏徹外 +彼得后书 彼得後書 +彼得里皿 彼得里皿 +彼此克制 彼此剋制 +往上面 往上面 +往下面 往下面 +往事如烟 往事如煙 +往前面 往前面 +往后 往後 +往后冲 往後衝 +往后方 往後方 +往后面 往後面 +往回 往回 +往复 往復 +往复泵 往復泵 +往复运动 往復運動 +往外冲 往外衝 +往外面 往外面 +往日無仇 往日無讎 +往来于 往來於 +往泥里踩 往泥裏踩 +往还于 往還於 +往里 往裏 +往里面 往裏面 +往里面冲 往裏面衝 +征了 徵了 +征人 徵人 +征令 徵令 +征伐 征伐 +征信 徵信 +征信录 徵信錄 +征信所 徵信所 +征信社 徵信社 +征候 徵候 +征候群 徵候羣 +征兆 徵兆 +征兵 徵兵 +征兵制 徵兵制 +征兵制度 徵兵制度 +征兵法 徵兵法 +征兵站 徵兵站 +征到 徵到 +征剿 征剿 +征募 徵募 +征占 徵佔 +征友 徵友 +征友栏 徵友欄 +征发 徵發 +征召 徵召 +征名责实 徵名責實 +征吏 徵吏 +征启 徵啓 +征咎 徵咎 +征圣 徵聖 +征地 徵地 +征士 徵士 +征夫 征夫 +征婚 徵婚 +征实 徵實 +征尘 征塵 +征帆 征帆 +征庸 徵庸 +征引 徵引 +征彸 征彸 +征得 徵得 +征怪 徵怪 +征意见 徵意見 +征戍 征戍 +征战 征戰 +征才 徵才 +征招 徵招 +征收 徵收 +征收范围 徵收範圍 +征收额 徵收額 +征效 徵效 +征敛 征斂 +征敛无度 征斂無度 +征文 徵文 +征文启事 徵文啓事 +征文比赛 徵文比賽 +征旆 征旆 +征服 征服 +征服兵 征服兵 +征服到地 征服到地 +征服者 征服者 +征求 徵求 +征求启事 徵求啓事 +征状 徵狀 +征用 徵用 +征程 征程 +征税 徵稅 +征税额 徵稅額 +征稿 徵稿 +征稿栏 徵稿欄 +征答 徵答 +征管 徵管 +征粮 徵糧 +征纳 徵納 +征结 徵結 +征缴 徵繳 +征聘 徵聘 +征聘人员 徵聘人員 +征衣 征衣 +征衫 征衫 +征讨 征討 +征训 徵訓 +征询 徵詢 +征调 徵調 +征象 徵象 +征购 徵購 +征费 徵費 +征车 徵車 +征辟 徵辟 +征迹 徵跡 +征选 徵選 +征逐 徵逐 +征途 征途 +征集 徵集 +征集令 徵集令 +征风召雨 徵風召雨 +征马 征馬 +征驾 征駕 +征验 徵驗 +征验出 徵驗出 +径向 徑向 +待了 待了 +待价而沽 待價而沽 +待价藏珠 待價藏珠 +待制 待制 +待发 待發 +待在家里 待在家裏 +待如己出 待如己出 +待核 待覈 +很丑 很醜 +很僵 很僵 +很凶 很兇 +很咸 很鹹 +很干 很乾 +很干了 很乾了 +很暗 很暗 +很松 很鬆 +律历志 律曆志 +律师团 律師團 +徐伟胜 徐偉勝 +徐余伟 徐余偉 +徐克 徐克 +徐千惠 徐千惠 +徐台荪 徐臺蓀 +徐台荪宫仲毅 徐臺蓀宮仲毅 +徐妃半面妆 徐妃半面妝 +徐娘 徐娘 +徐娘半老 徐娘半老 +徐家汇 徐家彙 +徐州师范大学 徐州師範大學 +徐干 徐幹 +徐志摩 徐志摩 +徐汇 徐匯 +徐汇区 徐彙區 +徐清云 徐清雲 +徐赞升 徐讚昇 +徐霞客游记 徐霞客遊記 +徒托空言 徒託空言 +徒步当车 徒步當車 +得了 得了 +得了些颜色就开起染房来 得了些顏色就開起染房來 +得于 得於 +得偿所愿 得償所願 +得克制 得剋制 +得克萨斯州 得克薩斯州 +得克萨斯州沃思堡电 得克薩斯州沃思堡電 +得准不准 得準不準 +得出 得出 +得失参半 得失參半 +得幸 得幸 +得当 得當 +得志 得志 +得意之余 得意之餘 +得放手时须放手 得放手時須放手 +得未尝有 得未嘗有 +得益于 得益於 +得而复失 得而復失 +得胜 得勝 +得胜之兵 得勝之兵 +得胜之师 得勝之師 +得胜口 得勝口 +得胜回朝 得勝回朝 +得胜头回 得勝頭回 +得胜的猫儿欢似虎 得勝的貓兒歡似虎 +得胜课 得勝課 +得道升天 得道昇天 +得采 得采 +得黄金百不如得季布诺 得黃金百不如得季布諾 +得黄金百斤不如得季布一诺 得黃金百斤不如得季布一諾 +徘回 徘迴 +徘徊于 徘徊於 +徜徉于 徜徉於 +御世 御世 +御书 御書 +御书房 御書房 +御人 御人 +御仗 御仗 +御侮 禦侮 +御制 御製 +御前 御前 +御前会议 御前會議 +御医 御醫 +御博表 御博表 +御厨 御廚 +御史 御史 +御史台 御史臺 +御史大夫 御史大夫 +御史雨 御史雨 +御夫 御夫 +御夫座 御夫座 +御夫有术 御夫有術 +御孙 御孫 +御宅族 御宅族 +御宇 御宇 +御守 御守 +御宝 御寶 +御容 御容 +御寇 禦寇 +御寒 禦寒 +御库 御庫 +御庙 御廟 +御府 御府 +御弟 御弟 +御所 御所 +御手 御手 +御手洗 御手洗 +御敌 禦敵 +御旨 御旨 +御札 御札 +御极 御極 +御林军 御林軍 +御案 御案 +御气 御氣 +御沟 御溝 +御沟流叶 御溝流葉 +御沟题叶 御溝題葉 +御河 御河 +御状 御狀 +御用 御用 +御碑亭 御碑亭 +御窑 御窯 +御笔 御筆 +御者 御者 +御膳 御膳 +御膳房 御膳房 +御花园 御花園 +御苑 御苑 +御览 御覽 +御赐 御賜 +御轮 御輪 +御道 御道 +御酒 御酒 +御风 御風 +御馔 御饌 +御驾 御駕 +御驾亲征 御駕親征 +御龙 御龍 +循环制 循環制 +循环反复 循環反覆 +循环往复 循環往復 +循环系统 循環系統 +循环赛制 循環賽制 +微克 微克 +微分几何 微分幾何 +微分几何学 微分幾何學 +微升 微升 +微卷 微卷 +微孔板 微孔板 +微居里 微居里 +微微的发烫 微微的發燙 +微核 微核 +微波倒送系统 微波倒送系統 +微纤 微纖 +微胶囊技术 微膠囊技術 +微雕 微雕 +徯幸 徯倖 +德佛亚克 德佛亞克 +德克萨斯 德克薩斯 +德克萨斯州 德克薩斯州 +德兰克林 德蘭克林 +德勒巴克 德勒巴克 +德占 德佔 +德国学术交流总署 德國學術交流總署 +德国杯 德國杯 +德国统一社会党 德國統一社會黨 +德国马克 德國馬克 +德垂后裔 德垂後裔 +德布勒森 德布勒森 +德布西 德布西 +德干 德干 +德干高原 德干高原 +德弗札克 德弗札克 +德意志 德意志 +德意志关税同盟 德意志關稅同盟 +德意志学术交流中心 德意志學術交流中心 +德意志民主共和国 德意志民主共和國 +德意志联邦共和国 德意志聯邦共和國 +德意志银行 德意志銀行 +德意志革命 德意志革命 +德才 德才 +德才兼备 德才兼備 +德拉克洛瓦 德拉克洛瓦 +德拉克罗瓦 德拉克羅瓦 +德文系 德文系 +德沃夏克 德沃夏克 +德法年鉴 德法年鑑 +德润佣书 德潤傭書 +德瑞克 德瑞克 +德胜头回 德勝頭迴 +德胜门 德勝門 +德薄才疏 德薄才疏 +德语系 德語系 +德谟克利泰斯 德謨克利泰斯 +德谟克拉西 德謨克拉西 +德里 德里 +德里达 德里達 +德高而毁来 德高而譭來 +徼幸 徼倖 +心不甘情不愿 心不甘情不願 +心于 心於 +心余 心餘 +心凉了半截 心涼了半截 +心口合一 心口合一 +心同此理 心同此理 +心向 心向 +心向往之 心嚮往之 +心向祖国 心向祖國 +心回意转 心回意轉 +心头小鹿撞个不住 心頭小鹿撞個不住 +心存侥幸 心存僥倖 +心安神闲 心安神閒 +心宽出少年 心寬出少年 +心弦 心絃 +心志 心志 +心念 心念 +心意回转 心意回轉 +心愿 心願 +心慈面软 心慈面軟 +心折 心折 +心折首肯 心折首肯 +心曲 心曲 +心有余力不足 心有餘力不足 +心有余悸 心有餘悸 +心有余而力不足 心有餘而力不足 +心有戚戚 心有慼慼 +心服情愿 心服情願 +心术 心術 +心术不正 心術不正 +心杯 心杯 +心欲专凿石穿 心欲專鑿石穿 +心活面软 心活面軟 +心游 心遊 +心满愿足 心滿願足 +心物合一 心物合一 +心理 心理 +心理发展 心理發展 +心理学系 心理學系 +心理系 心理系 +心理面 心理面 +心甘情愿 心甘情願 +心相系 心相繫 +心神专注 心神專注 +心系 心繫 +心细似发 心細似髮 +心细如发 心細如髮 +心肺复苏术 心肺復甦術 +心脏 心臟 +心脏地区 心臟地區 +心脏复苏术 心臟復甦術 +心脏学 心臟學 +心脏按摩 心臟按摩 +心脏搭桥手术 心臟搭橋手術 +心脏收缩压 心臟收縮壓 +心脏瓣 心臟瓣 +心脏疾患 心臟疾患 +心脏病 心臟病 +心脏病发 心臟病發 +心脏病史 心臟病史 +心脏痲痹 心臟痲痹 +心脏痲痺 心臟痲痺 +心脏科 心臟科 +心脏移植 心臟移植 +心脏移殖 心臟移殖 +心脏舒张压 心臟舒張壓 +心脏节律器 心臟節律器 +心脏衰竭 心臟衰竭 +心脏计 心臟計 +心脏镜 心臟鏡 +心脏麻痹 心臟麻痹 +心脏麻痺 心臟麻痺 +心花怒发 心花怒發 +心荡 心蕩 +心荡神怡 心蕩神怡 +心荡神摇 心蕩神搖 +心荡神迷 心蕩神迷 +心荡神驰 心蕩神馳 +心药 心藥 +心虔志诚 心虔志誠 +心路历程 心路歷程 +心里 心裏 +心里不安 心裏不安 +心里头 心裏頭 +心里有个谱 心裏有個譜 +心里有数 心裏有數 +心里有谱 心裏有譜 +心里有鬼 心裏有鬼 +心里痒痒 心裏癢癢 +心里美萝卜 心裏美蘿蔔 +心里话 心裏話 +心里面 心裏面 +心长发短 心長髮短 +心闲手敏 心閒手敏 +心高遮了太阳 心高遮了太陽 +必修 必修 +必修科 必修科 +必修课 必修課 +必修课程 必修課程 +必备良药 必備良藥 +必当 必當 +必死之症 必死之症 +必胜 必勝 +必胜客 必勝客 +必须 必須 +忆念 憶念 +忌烟 忌菸 +忍个 忍個 +忍了 忍了 +忍冬 忍冬 +忍冬花 忍冬花 +忍受不了 忍受不了 +忍受得了 忍受得了 +忍术 忍術 +忍饥受渴 忍饑受渴 +忍饥受饿 忍饑受餓 +忍饥挨饿 忍飢挨餓 +忏悔录 懺悔錄 +忒恶 忒惡 +忖前思后 忖前思後 +志不可夺 志不可奪 +志不可满 志不可滿 +志不在此 志不在此 +志业 志業 +志丹 志丹 +志丹县 志丹縣 +志乃 志乃 +志之不忘 誌之不忘 +志书 志書 +志事 志事 +志于 志於 +志仁 志仁 +志伟 志偉 +志保 志保 +志冲斗牛 志沖斗牛 +志分 志分 +志同心合 志同心合 +志同气合 志同氣合 +志同道合 志同道合 +志向 志向 +志哀 誌哀 +志喜 誌喜 +志在 志在 +志在千里 志在千里 +志在四方 志在四方 +志在必得 志在必得 +志坚 志堅 +志坚胆壮 志堅膽壯 +志士 志士 +志士仁人 志士仁人 +志大心高 志大心高 +志大才疏 志大才疏 +志大才短 志大才短 +志学 志學 +志尚 志尚 +志工 志工 +志工团 志工團 +志工队 志工隊 +志广才疏 志廣才疏 +志庆 誌慶 +志度 志度 +志异 誌異 +志强 志強 +志得意满 志得意滿 +志心 志心 +志怪 志怪 +志怪小说 志怪小說 +志悼 誌悼 +志意 志意 +志愿 志願 +志愿书 志願書 +志愿兵 志願兵 +志愿军 志願軍 +志愿卡 志願卡 +志愿役 志願役 +志愿者 志願者 +志成 志成 +志文 志文 +志明 志明 +志村健 志村健 +志杰 志傑 +志气 志氣 +志气凌云 志氣凌雲 +志清 志清 +志满气得 志滿氣得 +志玲 志玲 +志田 志田 +志留系 志留系 +志留纪 志留紀 +志略 志略 +志能之士 志能之士 +志航基地 志航基地 +志节 志節 +志英 志英 +志行 志行 +志诚 志誠 +志诚君子 志誠君子 +志贞 志貞 +志趣 志趣 +志趣相投 志趣相投 +志足意满 志足意滿 +志量 志量 +志骄意满 志驕意滿 +志高气扬 志高氣揚 +忘不了 忘不了 +忘了 忘了 +忘忧谷 忘憂谷 +忘生舍死 忘生捨死 +忙不择价 忙不擇價 +忙了手脚 忙了手腳 +忙于 忙於 +忙作一团 忙作一團 +忙并 忙併 +忙成一团 忙成一團 +忙昏了头 忙昏了頭 +忙进忙出 忙進忙出 +忙里 忙裏 +忙里偷闲 忙裏偷閒 +忙里忙外 忙裏忙外 +忠于 忠於 +忠于国家 忠於國家 +忠于职守 忠於職守 +忠人之托 忠人之托 +忠仆 忠僕 +忧喜参半 憂喜參半 +忧形于色 憂形於色 +忧戚 憂戚 +忧郁 憂鬱 +忧郁剂 憂鬱劑 +忧郁症 憂鬱症 +快乐幸福 快樂幸福 +快了 快了 +快借 快借 +快停了 快停了 +快克 快克 +快克制 快剋制 +快出 快出 +快出去 快出去 +快出来 快出來 +快升 快升 +快去快回 快去快回 +快吃干 快吃乾 +快向 快向 +快回 快回 +快回到 快回到 +快回去 快回去 +快回来 快回來 +快好了 快好了 +快完了 快完了 +快干 快乾 +快干了 快乾了 +快干杯 快乾杯 +快干裂 快乾裂 +快当 快當 +快快当当 快快當當 +快搜 快搜 +快松下 快鬆下 +快板 快板 +快板儿 快板兒 +快死了 快死了 +快没了 快沒了 +快满了 快滿了 +快熟了 快熟了 +快狠准 快狠準 +快舍下 快捨下 +快赢了 快贏了 +快适 快適 +快递杯 快遞杯 +快速发展 快速發展 +快速面 快速麪 +念一 念一 +念上 念上 +念不 念不 +念中 念中 +念之 念之 +念书 唸書 +念了 唸了 +念了一声 唸了一聲 +念他 念他 +念以 念以 +念佛 唸佛 +念作 唸作 +念你 念你 +念儿 念兒 +念冰 念冰 +念出 念出 +念到 唸到 +念力 念力 +念及 念及 +念叨 唸叨 +念可 念可 +念吧 唸吧 +念和 念和 +念咒 唸咒 +念啊 唸啊 +念在 念在 +念头 念頭 +念她 念她 +念好 念好 +念完 唸完 +念对 唸對 +念得 念得 +念心 念心 +念念 念念 +念念有词 唸唸有詞 +念情 念情 +念想 念想 +念慈 念慈 +念成 念成 +念我 念我 +念日 念日 +念旧 念舊 +念是 念是 +念曰 唸曰 +念曲叫曲 念曲叫曲 +念有 念有 +念来 念來 +念此 念此 +念母 念母 +念法 念法 +念点 念點 +念珠 念珠 +念琛 念琛 +念生 念生 +念白 唸白 +念的 唸的 +念着 念着 唸着 +念经 唸經 +念给 念給 +念诗 唸詩 +念诵 唸誦 +念起 念起 +念过 念過 +念这 念這 +念道 念道 +念都 念都 +念错 唸錯 +念青 念青 +念鱼 念魚 +忽前忽后 忽前忽後 +忽明忽暗 忽明忽暗 +忽舍下 忽捨下 +忿发 忿發 +怀了 懷了 +怀宠尸位 懷寵尸位 +怀忧丧志 懷憂喪志 +怀念 懷念 +怀恶不悛 懷惡不悛 +怀才不遇 懷才不遇 +怀才抱德 懷才抱德 +怀表 懷錶 +怀里 懷裏 +怀钟 懷鐘 +怎么 怎麼 +怎么了 怎麼了 +怎么回事 怎麼回事 +怎么干 怎麼幹 +怎么得了 怎麼得了 +怎么着 怎麼着 +怒于 怒於 +怒从心上起恶向胆边生 怒從心上起惡向膽邊生 +怒冲冲 怒衝衝 +怒发冲冠 怒髮衝冠 +怒发冲天 怒髮沖天 +怒容满面 怒容滿面 +怒形于色 怒形於色 +怒恶 怒惡 +怒气冲冲 怒氣衝衝 +怒气冲发 怒氣沖發 +怒气冲天 怒氣沖天 +怒江大峡谷 怒江大峽谷 +怒火万丈 怒火萬丈 +怒火冲天 怒火沖天 +怒目相向 怒目相向 +怒臂当车 怒臂當車 +怙恶不悛 怙惡不悛 +怙恶不改 怙惡不改 +怜才 憐才 +思不出位 思不出位 +思前思后 思前思後 +思前想后 思前想後 +思前算后 思前算後 +思如泉涌 思如泉湧 +思念 思念 +思想体系 思想體系 +思想准备 思想準備 +思致 思致 +思虑周详 思慮周詳 +怠于 怠於 +急于 急於 +急于星火 急於星火 +急于求成 急於求成 +急人之困 急人之困 +急冲 急衝 +急冲而下 急衝而下 +急升 急升 +急并各邦 急並各邦 +急征重敛 急征重斂 +急松松 急鬆鬆 +急水也有回头浪 急水也有回頭浪 +急症 急症 +急进党 急進黨 +急重症 急重症 +急须 急須 +性丑闻 性醜聞 +性价比 性價比 +性伙伴 性夥伴 +性倾向 性傾向 +性冲动 性衝動 +性别 性別 +性别歧视 性別歧視 +性别比 性別比 +性别角色 性別角色 +性发 性發 +性取向 性取向 +性向 性向 +性向测验 性向測驗 +性征 性徵 +性恶 性惡 +性恶说 性惡說 +性指向 性指向 +性格不合 性格不合 +性欲 性慾 +性欲高潮 性慾高潮 +性泼凶顽 性潑凶頑 +性神经症 性神經症 +性荷尔蒙 性荷爾蒙 +性饥渴 性飢渴 +怨仇 怨仇 +怨叹 怨嘆 +怨念 怨念 +怨气冲天 怨氣沖天 +怪了 怪了 +怪杰 怪傑 +怪里怪气 怪里怪氣 +怫郁 怫鬱 +怯症 怯症 +总会杯 總會杯 +总体规划 總體規劃 +总厂 總廠 +总参谋部 總參謀部 +总参谋长 總參謀長 +总发 總髮 +总台 總檯 +总合 總合 +总后勤部 總後勤部 +总回报 總回報 +总干事 總幹事 +总批发 總批發 +总方针 總方針 +总星系 總星系 +总机厂 總機廠 +总杆数 總桿數 +总杆赛 總桿賽 +总汇 總彙 +总理 總理 +总统制 總統制 +总统杯 總統盃 +总裁制 總裁制 +总量管制 總量管制 +总面积 總面積 +恂栗 恂慄 +恃才傲物 恃才傲物 +恃才矜己 恃才矜己 +恃才自专 恃才自專 +恋念 戀念 +恋恋不舍 戀戀不捨 +恋恋难舍 戀戀難捨 +恋曲 戀曲 +恋生恶死 戀生惡死 +恋酒贪杯 戀酒貪杯 +恐变症 恐變症 +恐同症 恐同症 +恐后争先 恐後爭先 +恐怖症 恐怖症 +恐惧症 恐懼症 +恐慌症 恐慌症 +恐旷症 恐曠症 +恐水症 恐水症 +恐法症 恐法症 +恐韩症 恐韓症 +恐高症 恐高症 +恐鸡症 恐雞症 +恒星周期 恆星週期 +恒春野百合 恆春野百合 +恒生指数 恆生指數 +恒生股价指数 恆生股價指數 +恒生银行 恆生銀行 +恒言录 恆言錄 +恕乏价催 恕乏价催 +恙虫 恙蟲 +恙虫病 恙蟲病 +恢台 恢臺 +恢复 恢復 +恢复为 恢復爲 +恢复到 恢復到 +恢复原状 恢復原狀 +恢复名誉 恢復名譽 +恢复室 恢復室 +恢复常态 恢復常態 +恢复期 恢復期 +恢复起来 恢復起來 +恢复过来 恢復過來 +恢恢有余 恢恢有餘 +恣心所欲 恣心所欲 +恣情纵欲 恣情縱欲 +恤典 卹典 +恤荒 卹荒 +恤金 卹金 +恨了 恨了 +恨意尽消 恨意盡消 +恨苦修行 恨苦修行 +恨透了 恨透了 +恩仇 恩仇 +恩仇记 恩仇記 +恩克巴雅尔 恩克巴雅爾 +恩克鲁玛 恩克魯瑪 +恩准 恩准 +恩台 恩臺 +恩同再造 恩同再造 +恩同父母 恩同父母 +恩培多克勒 恩培多克勒 +恩威克 恩威克 +恩威并施 恩威並施 +恩威并济 恩威並濟 +恩威并用 恩威並用 +恩威并行 恩威並行 +恩威并重 恩威並重 +恩将仇报 恩將仇報 +恩将仇报者 恩將仇報者 +恩幸 恩幸 +恩给制 恩給制 +恩艾斯克 恩艾斯克 +恬淡寡欲 恬淡寡欲 +恬淡无欲 恬淡無欲 +恬适 恬適 +恭喜发财 恭喜發財 +息交绝游 息交絕遊 +息谷 息穀 +恰克 恰克 +恰克图 恰克圖 +恰克图条约 恰克圖條約 +恰当 恰當 +恰才 恰纔 +恳愿 懇願 +恳托 懇託 +恶业 惡業 +恶习 惡習 +恶习不改 惡習不改 +恶事 惡事 +恶事传千里 惡事傳千里 +恶人 惡人 +恶人先告状 惡人先告狀 +恶人有恶报 惡人有惡報 +恶人自有恶人磨 惡人自有惡人磨 +恶仗 惡仗 +恶作剧 惡作劇 +恶作剧者 惡作劇者 +恶例 惡例 +恶俗 惡俗 +恶兆 惡兆 +恶党 惡黨 +恶凶凶 惡兇兇 +恶劣 惡劣 +恶劣影响 惡劣影響 +恶劣性 惡劣性 +恶势力 惡勢力 +恶化 惡化 +恶化趋势 惡化趨勢 +恶化顷向 惡化頃向 +恶叉白赖 惡叉白賴 +恶发 惡發 +恶口 惡口 +恶名 惡名 +恶名儿 惡名兒 +恶名昭彰 惡名昭彰 +恶名昭著 惡名昭著 +恶哏哏 惡哏哏 +恶唑啉 噁唑啉 +恶唑啉酮 噁唑啉酮 +恶因 惡因 +恶地 惡地 +恶声 惡聲 +恶女 惡女 +恶女阿楚 惡女阿楚 +恶妇 惡婦 +恶婆 惡婆 +恶嫌 惡嫌 +恶子 惡子 +恶孽 惡孽 +恶客 惡客 +恶寒 惡寒 +恶少 惡少 +恶岁 惡歲 +恶形 惡形 +恶形恶状 惡形惡狀 +恶徒 惡徒 +恶德 惡德 +恶心 噁心 +恶心感 噁心感 +恶念 惡念 +恶怜 惡憐 +恶性 惡性 +恶性不改 惡性不改 +恶性倒闭 惡性倒閉 +恶性循环 惡性循環 +恶性疟原虫 惡性瘧原蟲 +恶性瘤 惡性瘤 +恶性竞争 惡性競爭 +恶性肿瘤 惡性腫瘤 +恶性补习 惡性補習 +恶性贫血 惡性貧血 +恶性通货膨胀 惡性通貨膨脹 +恶恶 惡惡 +恶恶从短 惡惡從短 +恶恶实实 惡惡實實 +恶意 惡意 +恶意中伤 惡意中傷 +恶意代码 惡意代碼 +恶意毁谤 惡意譭謗 +恶感 惡感 +恶战 惡戰 +恶报 惡報 +恶搞 惡搞 +恶搞文化 惡搞文化 +恶支杀 惡支殺 +恶政 惡政 +恶斗 惡鬥 +恶曜 惡曜 +恶月 惡月 +恶有 惡有 +恶有善报 惡有善報 +恶有恶报 惡有惡報 +恶极 惡極 +恶果 惡果 +恶梦 惡夢 +恶梦探侦 惡夢探偵 +恶棍 惡棍 +恶棍歹徒 惡棍歹徒 +恶模恶样 惡模惡樣 +恶毒 惡毒 +恶气 惡氣 +恶水 惡水 +恶汉 惡漢 +恶法 惡法 +恶浊 惡濁 +恶浪 惡浪 +恶湿居下 惡溼居下 +恶灵 惡靈 +恶煞 惡煞 +恶犬 惡犬 +恶狗 惡狗 +恶狠 惡狠 +恶狠狠 惡狠狠 +恶狼 惡狼 +恶疮 惡瘡 +恶疾 惡疾 +恶病质 惡病質 +恶癖 惡癖 +恶直丑正 惡直醜正 +恶相 惡相 +恶眉恶眼 惡眉惡眼 +恶神 惡神 +恶积祸盈 惡積禍盈 +恶稔祸盈 惡稔禍盈 +恶稔罪盈 惡稔罪盈 +恶稔贯盈 惡稔貫盈 +恶紫夺朱 惡紫奪朱 +恶终 惡終 +恶缘恶业 惡緣惡業 +恶耗 惡耗 +恶臭 惡臭 +恶臭味 惡臭味 +恶臭性 惡臭性 +恶臭扑鼻 惡臭撲鼻 +恶行 惡行 +恶衣恶食 惡衣惡食 +恶衣粝食 惡衣糲食 +恶衣菲食 惡衣菲食 +恶衣蔬食 惡衣蔬食 +恶补 惡補 +恶言 惡言 +恶言伤人 惡言傷人 +恶言恶语 惡言惡語 +恶言泼语 惡言潑語 +恶言相向 惡言相向 +恶言詈辞 惡言詈辭 +恶讯 惡訊 +恶识 惡識 +恶诧 惡詫 +恶语 惡語 +恶语中伤 惡語中傷 +恶语伤人 惡語傷人 +恶语相向 惡語相向 +恶质 惡質 +恶质化 惡質化 +恶贯满盈 惡貫滿盈 +恶贯祸盈 惡貫禍盈 +恶贼 惡賊 +恶赖 惡賴 +恶趣 惡趣 +恶躁 惡躁 +恶运 惡運 +恶运当头 惡運當頭 +恶迹 惡跡 +恶逆 惡逆 +恶道 惡道 +恶醉强酒 惡醉強酒 +恶阻 惡阻 +恶限 惡限 +恶障 惡障 +恶露 惡露 +恶霸 惡霸 +恶霸地主 惡霸地主 +恶霸成性 惡霸成性 +恶风 惡風 +恶食 惡食 +恶马恶人骑 惡馬惡人騎 +恶骂 惡罵 +恶鬼 惡鬼 +恶魔 惡魔 +恶魔党 惡魔黨 +恶魔岛 惡魔島 +悍药 悍藥 +悒郁 悒鬱 +悒郁不忿 悒鬱不忿 +悒郁寡欢 悒鬱寡歡 +悔不当初 悔不當初 +悖入悖出 悖入悖出 +悚栗 悚慄 +悟出 悟出 +悟出来 悟出來 +悠哉游哉 悠哉遊哉 +悠悠荡荡 悠悠盪盪 +悠暗 悠闇 +悠活丽致 悠活麗緻 +悠游 悠遊 +悠游卡 悠遊卡 +悠游表 悠遊錶 +悠然自适 悠然自適 +悠荡 悠盪 +悠闲地 悠閒地 +悠闲自在 悠閒自在 +患难之交才是真正的朋友 患難之交纔是真正的朋友 +您克制 您剋制 +悬吊 懸吊 +悬岩 懸巖 +悬岩峭壁 懸巖峭壁 +悬心吊胆 懸心吊膽 +悬念 懸念 +悬挂 懸掛 +悬挂国旗 懸掛國旗 +悬挂在 懸掛在 +悬挂式滑翔 懸掛式滑翔 +悬挂式滑翔机 懸掛式滑翔機 +悬挂物 懸掛物 +悬旌万里 懸旌萬里 +悬梁 懸樑 +悬梁刺股 懸樑刺股 +悬梁自尽 懸樑自盡 +悬河注水 懸河注水 +悬河注火 懸河注火 +悬灯结彩 懸燈結彩 +悬肠挂肚 懸腸掛肚 +悬胄 懸冑 +悬臂梁 懸臂樑 +悬车致仕 懸車致仕 +悬针 懸針 +悬针垂露 懸針垂露 +悬钟 懸鐘 +悭吝苦克 慳吝苦剋 +悲不自胜 悲不自勝 +悲凄 悲悽 +悲叹 悲嘆 +悲咽 悲咽 +悲喜交并 悲喜交並 +悲回风 悲回風 +悲怆交响曲 悲愴交響曲 +悲悲戚戚 悲悲慼慼 +悲愿 悲願 +悲戚 悲慼 +悲欢合散 悲歡合散 +悲欢离合 悲歡離合 +悲歌当哭 悲歌當哭 +悲泗淋漓 悲泗淋漓 +悲犬咸阳 悲犬咸陽 +悲痛欲绝 悲痛欲絕 +悲秋 悲秋 +悲秋伤春 悲秋傷春 +悲筑 悲筑 +悲谷 悲谷 +悲郁 悲鬱 +悸栗 悸慄 +悼念 悼念 +惄如调饥 惄如調饑 +情不愿 情不願 +情不自胜 情不自勝 +情人眼里出西施 情人眼裏出西施 +情人眼里有西施 情人眼裏有西施 +情仇 情仇 +情僧录 情僧錄 +情况证据 情況證據 +情同一家 情同一家 +情同手足 情同手足 +情同骨肉 情同骨肉 +情同鱼水 情同魚水 +情孚意合 情孚意合 +情弦 情弦 +情志 情志 +情急了 情急了 +情感冲动 情感衝動 +情愿 情願 +情投意合 情投意合 +情报系统 情報系統 +情文并茂 情文並茂 +情有所钟 情有所鍾 +情有独钟 情有獨鍾 +情欲 情慾 +情欲戏 情慾戲 +情溢于表 情溢於表 +情种 情種 +情系 情繫 +情至意尽 情至意盡 +情致 情致 +情采 情采 +情面 情面 +情面难却 情面難卻 +惇朴 惇樸 +惊叹 驚歎 +惊恐万分 驚恐萬分 +惊恐万状 驚恐萬狀 +惊才绝艳 驚才絕豔 +惊赞 驚讚 +惊钟 驚鐘 +惊闺叶 驚閨葉 +惊险百出 驚險百出 +惋叹 惋嘆 +惏栗 惏慄 +惑志 惑志 +惑术 惑術 +惕栗 惕慄 +惜别 惜別 +惜别会 惜別會 +惟天可表 惟天可表 +惠塔克 惠塔克 +惠里香 惠里香 +惠鉴 惠鑑 +惦念 惦念 +惦挂 惦掛 +惧于 懼於 +惧高症 懼高症 +惨历 慘歷 +惨戚 慘慼 +惨栗 慘慄 +惨遭不幸 慘遭不幸 +惩前毖后 懲前毖後 +惩忿窒欲 懲忿窒欲 +惩恶劝善 懲惡勸善 +惩恶奖善 懲惡獎善 +惬当 愜當 +惯于 慣於 +惯性系 慣性系 +惯摆 慣擺 +想不出 想不出 +想不出来 想不出來 +想个 想個 +想个办法 想個辦法 +想个方法 想個方法 +想也别想 想也別想 +想了 想了 +想了又想 想了又想 +想借 想借 +想像出 想像出 +想像出来 想像出來 +想克制 想剋制 +想出 想出 +想出去 想出去 +想出来 想出來 +想前顾后 想前顧後 +想回 想回 +想回去 想回去 +想回来 想回來 +想尽 想盡 +想尽办法 想盡辦法 +想尽方法 想盡方法 +想干 想幹 +想干什么 想幹什麼 +想当然 想當然 +想当然耳 想當然耳 +想录 想錄 +想念 想念 +想说出 想說出 +想都别想 想都別想 +惴栗 惴慄 +惹人注意 惹人注意 +惹人注目 惹人注目 +惹出 惹出 +惹出来 惹出來 +惹口面 惹口面 +惺松 惺鬆 +愁云 愁雲 +愁云惨雾 愁雲慘霧 +愁容满面 愁容滿面 +愁布袋 愁布袋 +愁戚戚 愁慼慼 +愆面 愆面 +愈出愈奇 愈出愈奇 +愈发 愈發 +愈合 癒合 +意会出 意會出 +意克制 意剋制 +意出望外 意出望外 +意切言尽 意切言盡 +意切辞尽 意切辭盡 +意前笔后 意前筆後 +意占 意佔 +意合情投 意合情投 +意向 意向 +意向书 意向書 +意大利直面 意大利直麪 +意大利面 意大利麪 +意广才疏 意廣才疏 +意得志满 意得志滿 +意志 意志 +意志力 意志力 +意志消沈 意志消沈 +意志消沉 意志消沉 +意念 意念 +意思表示 意思表示 +意愿 意願 +意欲 意欲 +意气相合 意氣相合 +意气风发 意氣風發 +意满志得 意滿志得 +意犹未尽 意猶未盡 +意表 意表 +意见不合 意見不合 +意见调査表 意見調查表 +意识历程 意識歷程 +意转心回 意轉心回 +意里意思 意裏意思 +意面 意麪 +愚公谷 愚公谷 +愚暗 愚闇 +愚者千虑必有一得 愚者千慮必有一得 +愚蒙 愚蒙 +感于 感於 +感冒药 感冒藥 +感化饼干 感化餅乾 +感发 感發 +感叹 感嘆 +感同身受 感同身受 +感念 感念 +感恩不尽 感恩不盡 +感慨万千 感慨萬千 +感激万分 感激萬分 +感激不尽 感激不盡 +感觉出 感覺出 +感觉出来 感覺出來 +愤发 憤發 +愤而行凶 憤而行兇 +愧不敢当 愧不敢當 +愧于 愧於 +愿不愿 願不願 +愿不愿意 願不願意 +愿力 願力 +愿天下有 願天下有 +愿寘诚念 願寘誠念 +愿干一杯 願乾一杯 +愿干这杯 願乾這杯 +愿干那杯 願乾那杯 +愿心 願心 +愿意 願意 +愿意不愿意 願意不願意 +愿意干 願意幹 +愿景 願景 +愿望 願望 +愿朴 愿樸 +愿者上钩 願者上鉤 +愿而恭 愿而恭 +愿行 願行 +愿谨 願謹 +愿闻其详 願聞其詳 +慈云 慈雲 +慈制 慈制 +慈安太后 慈安太后 +慈悲喜舍 慈悲喜捨 +慈禧太后 慈禧太后 +慌了 慌了 +慌了手脚 慌了手腳 +慌了神儿 慌了神兒 +慌作一团 慌作一團 +慌成一团 慌成一團 +慌里慌张 慌里慌張 +慢了 慢了 +慢咽 慢嚥 +慢工出巧匠 慢工出巧匠 +慢工出细活 慢工出細活 +慢工出细货 慢工出細貨 +慢曲 慢曲 +慢板 慢板 +慢板情歌 慢板情歌 +慢游 慢遊 +慢表 慢表 +慧种 慧種 +慨叹 慨嘆 +慰借 慰藉 +慰情胜无 慰情勝無 +憎恶 憎惡 +懂了 懂了 +懈松 懈鬆 +懒于 懶於 +懒惰虫 懶惰蟲 +懒虫 懶蟲 +懔栗 懍慄 +懰栗 懰慄 +懵药 懵藥 +懵里懵懂 懵裏懵懂 +懿戚 懿戚 +懿范 懿範 +懿范长昭 懿範長昭 +戏剧台 戲劇臺 +戏剧团 戲劇團 +戏剧系 戲劇系 +戏台 戲臺 +戏团 戲團 +戏彩娱亲 戲綵娛親 +戏曲 戲曲 +戏曲馆 戲曲館 +戏法人人会变巧妙各有不同 戲法人人會變巧妙各有不同 +戏谷 戲谷 +戏里 戲裏 +成不了 成不了 +成个儿 成個兒 +成了 成了 +成于 成於 +成于思 成於思 +成交价 成交價 +成仇 成仇 +成兆才 成兆才 +成功的男人后面必有一个奉献的女人 成功的男人後面必有一個奉獻的女人 +成功范例 成功範例 +成千 成千 +成千上万 成千上萬 +成千成万 成千成萬 +成千成百 成千成百 +成千累万 成千累萬 +成千论万 成千論萬 +成合 成合 +成名曲 成名曲 +成名术 成名術 +成周 成周 +成团打块 成團打塊 +成套出售 成套出售 +成岩作用 成岩作用 +成批出售 成批出售 +成本价 成本價 +成核 成核 +成百上千 成百上千 +成群打伙 成羣打夥 +成群结伙 成羣結夥 +成群结党 成羣結黨 +成药 成藥 +成虫 成蟲 +成衣厂 成衣廠 +成都卖卜 成都賣卜 +成骨不全症 成骨不全症 +我们死后将会洪水滔天 我們死後將會洪水滔天 +我克制 我剋制 +我党 我黨 +我只 我只 +我只有 我只有 +我向 我向 +我回 我回 +我回到 我回到 +我回去 我回去 +我回来 我回來 +我干一杯 我乾一杯 +我念 我念 +我愿 我願 +我愿意 我願意 +我扣 我扣 +我搜 我搜 +我系 我係 +我醉欲眠 我醉欲眠 +戒坛 戒壇 +戒涂 戒塗 +戒烟 戒菸 +戒烟法 戒菸法 +或于 或於 +或系之牛 或繫之牛 +或采 或採 +战个 戰個 +战了 戰了 +战云 戰雲 +战云密布 戰雲密佈 +战云浓密 戰雲濃密 +战前战后 戰前戰後 +战后 戰後 +战团 戰團 +战地钟声 戰地鐘聲 +战士授田凭据 戰士授田憑據 +战天斗地 戰天鬥地 +战战栗栗 戰戰慄慄 +战斗 戰鬥 +战斗人员 戰鬥人員 +战斗任务 戰鬥任務 +战斗力 戰鬥力 +战斗区 戰鬥區 +战斗员 戰鬥員 +战斗意志 戰鬥意志 +战斗旅 戰鬥旅 +战斗机 戰鬥機 +战斗编组 戰鬥編組 +战斗群 戰鬥羣 +战斗者 戰鬥者 +战斗舰 戰鬥艦 +战斗英雄 戰鬥英雄 +战斗营 戰鬥營 +战斗行为 戰鬥行爲 +战斗车 戰鬥車 +战斗轰炸 戰鬥轟炸 +战斗队形 戰鬥隊形 +战无不克 戰無不克 +战无不胜 戰無不勝 +战无不胜攻无不克 戰無不勝攻無不克 +战无不胜攻无不取 戰無不勝攻無不取 +战术 戰術 +战术导弹 戰術導彈 +战术核武器 戰術核武器 +战术轰炸 戰術轟炸 +战栗 戰慄 +战略伙伴 戰略伙伴 +战略防御倡议 戰略防禦倡議 +战胜 戰勝 +战胜国 戰勝國 +战表 戰表 +戚串 戚串 +戚党 戚黨 +戚凯罗 戚凱羅 +戚友 戚友 +戚墅堰 戚墅堰 +戚墅堰区 戚墅堰區 +戚夫人 戚夫人 +戚家军 戚家軍 +戚容 戚容 +戚属 戚屬 +戚戚 慼慼 +戚施 戚施 +戚族 戚族 +戚旧 戚舊 +戚然 戚然 +戚继光 戚繼光 +戚谊 戚誼 +戚里 戚里 +戛云 戛雲 +截发 截髮 +截发留宾 截髮留賓 +截板 截板 +截然不同 截然不同 +截获 截獲 +截趾适履 截趾適履 +截趾适屦 截趾適屨 +截面 截面 +截面图 截面圖 +戬谷 戩穀 +戮力同心 戮力同心 +戮尸 戮屍 +戳个儿 戳個兒 +戳脊梁 戳脊樑 +戳脊梁骨 戳脊梁骨 +戴个 戴個 +戴了 戴了 +戴克 戴克 +戴克拉克 戴克拉克 +戴克辛 戴克辛 +戴出 戴出 +戴出去 戴出去 +戴出来 戴出來 +戴发含齿 戴髮含齒 +戴天之仇 戴天之仇 +戴姆勒克莱斯勒 戴姆勒克萊斯勒 +戴希穆克 戴希穆克 +戴瑞克罗 戴瑞克羅 +戴维斯杯 戴維斯盃 +戴胜益 戴勝益 +戴胜通 戴勝通 +戴蒙 戴蒙 +戴蒙德 戴蒙德 +戴表 戴錶 +戴表元 戴表元 +戴诚志 戴誠志 +户口制 戶口制 +户口制度 戶口制度 +户对门当 戶對門當 +戽斗 戽斗 +房中术 房中術 +房价 房價 +房地产共同基金 房地產共同基金 +房地价 房地價 +房室结回路 房室結迴路 +房屋修护 房屋修護 +房屋修护费 房屋修護費 +房屋里 房屋裏 +房舍 房舍 +房里 房裏 +所云 所云 +所云云 所云云 +所余 所餘 +所剩无几 所剩無幾 +所占 所佔 +所发现 所發現 +所向 所向 +所向披靡 所向披靡 +所向无前 所向無前 +所向无敌 所向無敵 +所周知 所周知 +所布之 所佈之 +所布的 所佈的 +所干 所幹 +所幸 所幸 +所念 所念 +所托 所託 +所扣 所扣 +所有制 所有制 +所系 所繫 +所致 所致 +所见略同 所見略同 +所见而云 所見而云 +所讥而云 所譏而云 +所谓而云 所謂而云 +扁担压不出个屁来 扁擔壓不出個屁來 +扁拟谷盗虫 扁擬穀盜蟲 +扁铲 扁鏟 +扁锹形虫 扁鍬形蟲 +扇叶蒲葵 扇葉蒲葵 +扇面 扇面 +扇面对 扇面對 +扇面琴 扇面琴 +手一卷 手一捲 +手一松 手一鬆 +手不松 手不鬆 +手不释卷 手不釋卷 +手写识别 手寫識別 +手冢治虫 手冢治虫 +手到回春 手到回春 +手制 手製 +手制动 手制動 +手卷 手卷 +手同脚 手同腳 +手工台 手工檯 +手彩儿 手彩兒 +手心里 手心裏 +手折 手摺 +手挽手 手挽手 +手掌多汗症 手掌多汗症 +手摇杯 手搖杯 +手擀面 手擀麪 +手术 手術 +手术刀 手術刀 +手术台 手術檯 +手术室 手術室 +手术房 手術房 +手术用 手術用 +手术衣 手術衣 +手术费 手術費 +手松 手鬆 +手板 手板 +手板子 手板子 +手板葫芦 手板葫蘆 +手腕式指北针 手腕式指北針 +手表 手錶 +手表带 手錶帶 +手足口症 手足口症 +手酸 手痠 +手采 手採 +手里 手裏 +手里余 手裏餘 +手铲 手鏟 +手链 手鍊 手鏈 +手面 手面 +手面赚吃 手面賺吃 +才上到 纔上到 +才上去 纔上去 +才上来 纔上來 +才下去 纔下去 +才下来 纔下來 +才不 纔不 +才不会 纔不會 +才不是 纔不是 +才不能 纔不能 +才为世出 才爲世出 +才买 纔買 +才人 才人 +才会 纔會 +才会到 纔會到 +才会在 纔會在 +才会有 纔會有 +才俊 才俊 +才信 纔信 +才储八斗 才儲八斗 +才像 纔像 +才像是 纔像是 +才具 才具 +才兼文武 才兼文武 +才再 纔再 +才出 纔出 +才出去 纔出去 +才出来 纔出來 +才分 才分 +才则 纔則 +才刚 纔剛 +才到 纔到 +才力 才力 +才勇兼优 才勇兼優 +才华 才華 +才华出众 才華出衆 +才华横溢 才華橫溢 +才华洋溢 才華洋溢 +才华盖世 才華蓋世 +才去 纔去 +才可 纔可 +才可以 纔可以 +才可容颜十五余 纔可容顏十五餘 +才名 才名 +才器 才器 +才回 纔回 +才回到 纔回到 +才回去 纔回去 +才回来 纔回來 +才在 纔在 +才士 才士 +才多 纔多 +才多出 纔多出 +才够 纔夠 +才大难用 才大難用 +才女 才女 +才好 纔好 +才如史迁 才如史遷 +才始 纔始 +才媛 才媛 +才子 才子 +才子书 才子書 +才子佳人 才子佳人 +才学 才學 +才学兼优 才學兼優 +才守 才守 +才定 才定 +才对 纔對 +才将 纔將 +才干 才幹 +才干旱 纔乾旱 +才干杯 纔乾杯 +才干淨 纔乾淨 +才干透 纔乾透 +才广妨身 才廣妨身 +才开 纔開 +才开出 纔開出 +才开到 纔開到 +才当曹斗 才當曹斗 +才得两年 纔得兩年 +才得到 纔得到 +才微智浅 才微智淺 +才德 才德 +才德兼备 才德兼備 +才思 才思 +才思敏捷 才思敏捷 +才怪 纔怪 +才悟 才悟 +才情 才情 +才想 纔想 +才打 纔打 +才打出 纔打出 +才打到 纔打到 +才拿 纔拿 +才拿出 纔拿出 +才拿到 纔拿到 +才敢 纔敢 +才料 纔料 +才是 纔是 +才智 才智 +才有 纔有 +才望 才望 +才来 纔來 +才来到 纔來到 +才松下 纔鬆下 +才此 纔此 +才气 才氣 +才气无双 才氣無雙 +才气纵横 才氣縱橫 +才气过人 才氣過人 +才没 纔沒 +才没有 纔沒有 +才没能 纔沒能 +才派 纔派 +才派人 纔派人 +才爲 纔爲 +才用 才用 +才用到 纔用到 +才略 才略 +才略过人 才略過人 +才疏学浅 才疏學淺 +才疏德薄 才疏德薄 +才疏志大 才疏志大 +才疏意广 才疏意廣 +才疏计拙 才疏計拙 +才看 纔看 +才看出 纔看出 +才看到 纔看到 +才短气粗 才短氣粗 +才秀人微 才秀人微 +才等 纔等 +才等到 纔等到 +才算 纔算 +才算是 纔算是 +才给 纔給 +才能 才能 纔能 +才能勇敢追 纔能勇敢追 +才能夠 纔能夠 +才能干济 才能幹濟 +才能有 纔能有 +才色 才色 +才艺 才藝 +才艺卓绝 才藝卓絕 +才艺技能 才藝技能 +才艺班 才藝班 +才艺秀 才藝秀 +才蔽识浅 才蔽識淺 +才藻 才藻 +才行 纔行 才行 +才要 纔要 +才讲 纔講 +才识 才識 +才识过人 才識過人 +才语 才語 +才读 纔讀 +才读到 纔讀到 +才貌 才貌 +才貌出众 才貌出衆 +才貌双全 才貌雙全 +才贯二酉 才貫二酉 +才资 才資 +才起来 纔起來 +才跟 纔跟 +才轻德薄 才輕德薄 +才过去 纔過去 +才过子建 才過子建 +才过屈宋 才過屈宋 +才过来 纔過來 +才非玉润 才非玉潤 +才高八斗 才高八斗 +才高意广 才高意廣 +才高气傲 才高氣傲 +才高行厚 才高行厚 +才高行洁 才高行潔 +扎上 紮上 +扎上去 紮上去 +扎上来 紮上來 +扎下 紮下 +扎下去 紮下去 +扎下来 紮下來 +扎乎 扎乎 +扎了 紮了 +扎伊尔 扎伊爾 +扎住 扎住 +扎兰屯 扎蘭屯 +扎兰屯市 扎蘭屯市 +扎到 扎到 +扎卡维 扎卡維 +扎啤 扎啤 +扎嘴 扎嘴 +扎囊 扎囊 +扎囊县 扎囊縣 +扎囮 紮囮 +扎在 紮在 +扎垫 扎墊 +扎堆 扎堆 +扎好 紮好 +扎好底子 紮好底子 +扎好根 紮好根 +扎实 紮實 +扎实推进 紮實推進 +扎寨 紮寨 +扎尔达里 扎爾達里 +扎带 紮帶 +扎带子 紮帶子 +扎心 扎心 +扎成 紮成 +扎手 扎手 +扎手舞脚 扎手舞腳 +扎扎 扎扎 +扎扎实实 紮紮實實 +扎括 扎括 +扎挣 扎掙 +扎掂 扎掂 +扎撒 扎撒 +扎枪 扎槍 +扎根 紮根 +扎格罗斯 扎格羅斯 +扎格罗斯山脉 扎格羅斯山脈 +扎欧扎翁 紮歐紮翁 +扎煞 扎煞 +扎猛子 扎猛子 +扎眉扎眼 扎眉扎眼 +扎眼 扎眼 +扎空枪 扎空槍 +扎穿 扎穿 +扎窝子 扎窩子 +扎筏子 扎筏子 +扎紧 紮緊 +扎线带 紮線帶 +扎结 紮結 +扎缚 扎縛 +扎罚子 扎罰子 +扎耳朵 扎耳朵 +扎脑门儿 扎腦門兒 +扎脚 紮腳 +扎花 扎花 +扎草 扎草 +扎营 紮營 +扎裹 紮裹 +扎诈 紮詐 +扎赉特 扎賚特 +扎赉特旗 扎賚特旗 +扎起 紮起 +扎起来 紮起來 +扎针 扎針 +扎铁 紮鐵 +扎马剌丁 紮馬剌丁 +扎马鲁丁 紮馬魯丁 +扎鲁特 扎魯特 +扎鲁特旗 扎魯特旗 +扑个满怀 撲個滿懷 +扑个空 撲個空 +扑了 撲了 +扑克 撲克 +扑克牌 撲克牌 +扑克脸 撲克臉 +扑冬 撲鼕 +扑冬冬 撲鼕鼕 +扑出 撲出 +扑出去 撲出去 +扑出来 撲出來 +扑同 撲同 +扑向 撲向 +扑复 撲復 +扑灭蚊虫 撲滅蚊蟲 +扑通通冬 撲通通冬 +扑面 撲面 +扑面而来 撲面而來 +扒出 扒出 +打一个吞 打一個吞 +打个 打個 +打个前失 打個前失 +打个千儿 打個千兒 +打个沉儿 打個沉兒 +打个照会 打個照會 +打个照面 打個照面 +打个花 打個花 +打个问号 打個問號 +打中伙 打中伙 +打了一个闷雷 打了一個悶雷 +打了个千儿 打了個千兒 +打了个盹儿 打了個盹兒 +打了个落花流水 打了個落花流水 +打了偏手 打了偏手 +打了半跪 打了半跪 +打了牙肚里嚥 打了牙肚裏嚥 +打价 打價 +打伙 打夥 +打伙子穿靴 打夥子穿靴 +打冲锋 打衝鋒 +打出 打出 +打出去 打出去 +打出吊入 打出弔入 +打出头棍 打出頭棍 +打出头棒子 打出頭棒子 +打出手 打出手 +打出来 打出來 +打击报复 打擊報復 +打击板 打擊板 +打制 打製 +打制石器 打製石器 +打千 打千 +打卡钟 打卡鐘 +打卤面 打滷麪 +打印台 打印臺 +打印范围 打印範圍 +打参 打參 +打发 打發 +打发掉 打發掉 +打发时间 打發時間 +打合 打合 +打向 打向 +打听出 打聽出 +打和哄 打和哄 +打哄 打鬨 +打回 打回 +打回去 打回去 +打回来 打回來 +打回票 打回票 +打团 打團 +打墙板儿翻上下 打牆板兒翻上下 +打夜胡 打夜胡 +打太极 打太極 +打太极拳 打太極拳 +打完针 打完針 +打家劫舍 打家劫舍 +打对台 打對臺 +打干 打幹 +打干哕 打乾噦 +打干淨毬儿 打乾淨毬兒 +打并 打併 +打开后门说 打開後門說 +打开板壁讲亮话 打開板壁講亮話 +打当 打當 +打心眼里 打心眼裏 +打恶心 打噁心 +打成一团 打成一團 +打扑克 打撲克 +打折 打折 +打折扣 打折扣 +打折网 打折網 +打报台 打報臺 +打抽丰 打抽豐 +打拐 打拐 +打挨 打捱 +打摆子 打擺子 +打擂台 打擂臺 +打斗 打鬥 +打斗片 打鬥片 +打暗号 打暗號 +打来回 打來回 +打板 打板 +打板子 打板子 +打桨杆 打槳桿 +打棍出箱 打棍出箱 +打没头坛 打沒頭壇 +打淨捞干 打淨撈乾 +打游击 打游擊 +打游飞 打游飛 +打照面 打照面 +打狗不看主人面 打狗不看主人面 +打狗也要看主人面 打狗也要看主人面 +打狗看主人面 打狗看主人面 +打破纪录 打破紀錄 +打秋丰 打秋豐 +打秋千 打鞦韆 +打秋风 打秋風 +打筋斗 打筋斗 +打簧表 打簧錶 +打紧板 打緊板 +打绝板 打絕板 +打翻了的牛奶而哭泣 打翻了的牛奶而哭泣 +打老鼠伤了玉瓶 打老鼠傷了玉瓶 +打耳刮子 打耳刮子 +打胜 打勝 +打胜仗 打勝仗 +打胡哨 打胡哨 +打花胡哨 打花胡哨 +打药 打藥 +打蛇不死后患无穷 打蛇不死後患無窮 +打蜡 打蠟 +打蜡机 打蠟機 +打话不同 打話不同 +打诨发科 打諢發科 +打谷 打穀 +打谷场 打穀場 +打谷机 打穀機 +打路庄板 打路莊板 +打造出 打造出 +打道回府 打道回府 +打里打外 打裏打外 +打里照外 打裏照外 +打野胡 打野胡 +打量出 打量出 +打针 打針 +打钟 打鐘 +打靠后 打靠後 +打风后 打風後 +打饥荒 打饑荒 +扔出 扔出 +扔出去 扔出去 +扔出来 扔出來 +扔回 扔回 +扔回去 扔回去 +扔回来 扔回來 +扔在脑后 扔在腦後 +托买 託買 +托了 託了 +托事 託事 +托交 託交 +托人 託人 +托人情 託人情 +托付 託付 +托住 托住 +托儿 托兒 +托儿所 託兒所 +托克 托克 +托克托 托克托 +托克托县 托克托縣 +托克逊 托克遜 +托克逊县 托克遜縣 +托出 托出 +托利党人 托利黨人 +托利米尔 托利米爾 +托勒 托勒 +托勒密 托勒密 +托勒密王 托勒密王 +托勒尔 托勒爾 +托勒玫 托勒玫 +托卖 託賣 +托古讽今 託古諷今 +托叶 托葉 +托名 託名 +托命 託命 +托咎 託咎 +托地 托地 +托塔天王 托塔天王 +托塞洛 托塞洛 +托墨 托墨 +托大 託大 +托夫 托夫 +托子 托子 +托孤 託孤 +托实 托實 +托尔 托爾 +托尔斯泰 托爾斯泰 +托尔金 托爾金 +托幼 托幼 +托庇 託庇 +托拉 托拉 +托拉博拉 托拉博拉 +托拉斯 托拉斯 +托故 託故 +托斯卡 托斯卡 +托斯卡尼 托斯卡尼 +托斯卡尼尼 托斯卡尼尼 +托木尔 托木爾 +托木尔峰 托木爾峯 +托杯 托杯 +托架 托架 +托梦 託夢 +托比亚斯 托比亞斯 +托比麦奎尔 托比麥奎爾 +托洛斯基 托洛斯基 +托洛茨基 托洛茨基 +托派 託派 +托熟 托熟 +托特 托特 +托瑞丝 托瑞絲 +托瑞赛 托瑞賽 +托生 託生 +托疾 託疾 +托病 託病 +托登汉队 托登漢隊 +托盘 托盤 +托盘区 托盤區 +托福 託福 +托福考 托福考 +托福考试 托福考試 +托管 託管 +托管国 託管國 +托米 托米 +托米欧佳 托米歐佳 +托维 托維 +托罗斯山 托羅斯山 +托老中心 托老中心 +托老院 托老院 +托育 托育 +托胆 托膽 +托胎 托胎 +托腮 托腮 +托色 托色 +托荤咸食 托葷鹹食 +托莱多 托萊多 +托蒂 托蒂 +托言 託言 +托词 託詞 +托赖 托賴 +托起 托起 +托起来 托起來 +托足 托足 +托足无门 托足無門 +托身 託身 +托辞 託辭 +托辣斯 托辣斯 +托辣斯法 托辣斯法 +托过 託過 +托运 託運 +托运行李 托運行李 +托里 托里 +托里县 托里縣 +托里拆利 托里拆利 +托鉢 托鉢 +托钵人 托鉢人 +托钵修会 托鉢修會 +托钵僧 托鉢僧 +托附 託附 +托领 托領 +托马 托馬 +托马斯 托馬斯 +托马斯阿奎纳 托馬斯阿奎納 +扛了 扛了 +扛出 扛出 +扛出去 扛出去 +扛出来 扛出來 +扛大梁 扛大樑 +扞御 扞禦 +扣一 扣一 +扣上 扣上 +扣下 扣下 +扣了 扣了 +扣人 扣人 +扣件 扣件 +扣住 扣住 +扣作 扣作 +扣你 扣你 +扣儿 扣兒 +扣光 扣光 +扣克 扣剋 +扣入 扣入 +扣减 扣減 +扣出 扣出 +扣击 扣擊 +扣分 扣分 +扣分标准 扣分標準 +扣划 扣劃 +扣到 扣到 +扣动 扣動 +扣压 扣壓 +扣去 扣去 +扣发 扣發 +扣取 扣取 +扣响 扣響 +扣啊 扣啊 +扣回 扣回 +扣回去 扣回去 +扣回来 扣回來 +扣在 扣在 +扣头 扣頭 +扣女 扣女 +扣好 扣好 +扣子 釦子 +扣完 扣完 +扣将 扣將 +扣带 扣帶 +扣开 扣開 +扣得 扣得 +扣我 扣我 +扣扣 扣扣 +扣抵 扣抵 +扣押 扣押 +扣掉 扣掉 +扣杀 扣殺 +扣板 扣板 +扣板机 扣板機 +扣查 扣查 +扣款 扣款 +扣法 扣法 +扣满 扣滿 +扣点 扣點 +扣牌 扣牌 +扣牢 扣牢 +扣率 扣率 +扣环 釦環 +扣球 扣球 +扣留 扣留 +扣的 扣的 +扣眼 釦眼 +扣着 扣着 +扣税 扣稅 +扣篮 扣籃 +扣紧 扣緊 +扣绊 扣絆 +扣缴 扣繳 +扣罚 扣罰 +扣肉 扣肉 +扣船 扣船 +扣薪 扣薪 +扣表 扣表 +扣费 扣費 +扣起 扣起 +扣车 扣車 +扣过 扣過 +扣进 扣進 +扣针 釦針 +扣钩 扣鉤 +扣钱 扣錢 +扣锁 扣鎖 +扣门 扣門 +扣问 扣問 +扣除 扣除 +扣题 扣題 +执念 執念 +执政党 執政黨 +执政团 執政團 +执板 執板 +执行面 執行面 +扩厂 擴廠 +扩厂计划 擴廠計劃 +扩大范围 擴大範圍 +扩建工厂 擴建工廠 +扩张术 擴張術 +扩散出来 擴散出來 +扩音机系统 擴音機系統 +扪参历井 捫參歷井 +扪隙发罅 捫隙發罅 +扫出 掃出 +扫出去 掃出去 +扫出来 掃出來 +扫地俱尽 掃地俱盡 +扫地出门 掃地出門 +扫干淨 掃乾淨 +扫晴娘 掃晴娘 +扫田刮地 掃田刮地 +扫眉才子 掃眉才子 +扫荡 掃蕩 +扫荡残敌 掃蕩殘敵 +扬升 揚升 +扬名后世 揚名後世 +扬名立万 揚名立萬 +扬善去恶 揚善去惡 +扬善隐恶 揚善隱惡 +扬州清曲 揚州清曲 +扬州画舫录 揚州畫舫錄 +扬己露才 揚己露才 +扬谷 揚穀 +扭出 扭出 +扭出去 扭出去 +扭出来 扭出來 +扭别 扭別 +扭头折颈 扭頭折頸 +扭成一团 扭成一團 +扭摆 扭擺 +扭摆不停 扭擺不停 +扭曲 扭曲 +扭曲作直 扭曲作直 +扭转乾坤 扭轉乾坤 +扮装皇后 扮裝皇后 +扯出 扯出 +扯出去 扯出去 +扯出来 扯出來 +扯后腿 扯後腿 +扯篷拉纤 扯篷拉縴 +扯纤 扯縴 +扯闲白 扯閒白 +扯闲盘儿 扯閒盤兒 +扯闲篇 扯閒篇 +扯面 扯麪 +扰流板 擾流板 +扳回 扳回 +扳回一城 扳回一城 +扶了 扶了 +扶余 扶余 +扶余县 扶余縣 +扶余国 扶餘國 +扶出 扶出 +扶出去 扶出去 +扶出来 扶出來 +扶危救困 扶危救困 +扶危济困 扶危濟困 +扶同 扶同 +扶同硬证 扶同硬證 +扶同诖误 扶同詿誤 +扶善惩恶 扶善懲惡 +扶幼周 扶幼週 +扶手椅里 扶手椅裏 +扶苏 扶蘇 +扶贫济困 扶貧濟困 +批价 批價 +批准 批准 +批准下来 批准下來 +批准书 批准書 +批准的 批准的 +批出 批出 +批出去 批出去 +批出来 批出來 +批发 批發 +批发业 批發業 +批发价 批發價 +批发价格 批發價格 +批发商 批發商 +批发市场 批發市場 +批发店 批發店 +批回 批迴 +批复 批覆 +批尸 批屍 +批斗 批鬥 +批核 批覈 +批汇 批匯 +批注 批註 +批荡 批蕩 +扼制 扼制 +找不准 找不準 +找不出 找不出 +找个 找個 +找了 找了 +找价 找價 +找借口 找藉口 +找出 找出 +找出去 找出去 +找出来 找出來 +找出路 找出路 +找台阶 找臺階 +找台阶下 找臺階下 +找台阶儿 找臺階兒 +找回 找回 +找回去 找回去 +找回来 找回來 +找寻出 找尋出 +找面子 找面子 +承修 承修 +承先启后 承先啓後 +承制 承製 +承前启后 承前啓後 +承受不了 承受不了 +承宣布政使司 承宣布政使司 +承平面 承平面 +承当 承當 +承当不起 承當不起 +承蒙 承蒙 +承蒙关照 承蒙關照 +承蒙指教 承蒙指教 +承销价差 承銷價差 +承销团 承銷團 +技术 技術 +技术专科 技術專科 +技术专科学校 技術專科學校 +技术人员 技術人員 +技术作物 技術作物 +技术分析 技術分析 +技术单位 技術單位 +技术发展 技術發展 +技术合作 技術合作 +技术员 技術員 +技术团 技術團 +技术士 技術士 +技术处 技術處 +技术学院 技術學院 +技术官 技術官 +技术性 技術性 +技术情报 技術情報 +技术所限 技術所限 +技术指导 技術指導 +技术援助 技術援助 +技术故障 技術故障 +技术标准 技術標準 +技术水准 技術水準 +技术水平 技術水平 +技术潜水 技術潛水 +技术犯规 技術犯規 +技术知识 技術知識 +技术装备 技術裝備 +技术规范 技術規範 +技术部 技術部 +技术部门 技術部門 +技术降落 技術降落 +技术面 技術面 +技术革命 技術革命 +技术革新 技術革新 +技艺团 技藝團 +抄发 抄發 +抄台 抄臺 +抄后路 抄後路 +抄录 抄錄 +抄录下来 抄錄下來 +抄录在 抄錄在 +抄录编目 抄錄編目 +抄手游廊 抄手遊廊 +抄扎 抄扎 +抄获 抄獲 +把上了 把上了 +把个 把個 +把了 把了 +把你干 把你幹 +把卷 把卷 +把定了心 把定了心 +把方才 把方纔 +把脸一板 把臉一板 +把饭叫饥 把飯叫饑 +抑制 抑制 +抑制作用 抑制作用 +抑制剂 抑制劑 +抑制器 抑制器 +抑制栽培 抑制栽培 +抑制酶 抑制酶 +抑恶扬善 抑惡揚善 +抑扬升降性 抑揚昇降性 +抑郁 抑鬱 +抑郁不平 抑鬱不平 +抑郁寡欢 抑鬱寡歡 +抑郁症 抑鬱症 +抒发 抒發 +抒情曲 抒情曲 +抒情歌曲 抒情歌曲 +抓不准 抓不準 +抓准 抓準 +抓出 抓出 +抓出去 抓出去 +抓出来 抓出來 +抓周 抓周 +抓回 抓回 +抓回去 抓回去 +抓回来 抓回來 +抓奸 抓姦 +抓彩 抓彩 +抓斗 抓鬥 +抓药 抓藥 +抓获 抓獲 +抔土未干 抔土未乾 +投不准 投不準 +投不出 投不出 +投了 投了 +投井自尽 投井自盡 +投出 投出 +投出去 投出去 +投出来 投出來 +投合 投合 +投向 投向 +投喂 投餵 +投回 投回 +投射出 投射出 +投影几何 投影幾何 +投影几何学 投影幾何學 +投影面 投影面 +投手板 投手板 +投手防御率 投手防禦率 +投托 投托 +投梭折齿 投梭折齒 +投河自尽 投河自盡 +投注 投注 +投注站 投注站 +投潘岳果 投潘岳果 +投环自尽 投環自盡 +投票表决 投票表決 +投药 投藥 +投闲置散 投閒置散 +抖了 抖了 +抖了起来 抖了起來 +抖出 抖出 +抖出去 抖出去 +抖出来 抖出來 +抖搜精神 抖搜精神 +抗了 抗了 +抗噪 抗噪 +抗干扰性 抗干擾性 +抗御 抗禦 +抗志 抗志 +抗忧郁药 抗憂鬱藥 +抗战歌曲 抗戰歌曲 +抗战胜利 抗戰勝利 +抗拒不了 抗拒不了 +抗日救亡团体 抗日救亡團體 +抗病品种 抗病品種 +抗病毒药 抗病毒藥 +抗癌药 抗癌藥 +抗癌药物 抗癌藥物 +抗组胺药 抗組胺藥 +抗药 抗藥 +抗药性 抗藥性 +抗药能力 抗藥能力 +抗菌药 抗菌藥 +抗逆转录 抗逆轉錄 +折上 折上 +折上去 折上去 +折上来 折上來 +折下 折下 +折下去 折下去 +折下来 折下來 +折不断 折不斷 +折中 折中 +折价 折價 +折价出售 折價出售 +折价券 折價券 +折价卷 折價卷 +折伤 折傷 +折倒 折倒 +折光 折光 +折兑 折兌 +折兑率 折兌率 +折兵 折兵 +折冲 折衝 +折冲厌难 折衝厭難 +折冲尊俎 折衝尊俎 +折冲御侮 折衝禦侮 +折冲樽俎 折衝樽俎 +折刀 折刀 +折刀儿 折刀兒 +折券 折券 +折剉 折剉 +折半 折半 +折半出售 折半出售 +折卖 折賣 +折受 折受 +折变 折變 +折叠 摺疊 +折叠为 摺疊爲 +折叠式 摺疊式 +折叠扇 摺疊扇 +折叠椅 摺疊椅 +折叠牀 摺疊牀 +折叠起来 摺疊起來 +折台 折檯 +折合 摺合 +折合椅 摺合椅 +折回 折回 +折回去 折回去 +折回来 折回來 +折壁脚 折壁腳 +折头 折頭 +折奏 摺奏 +折好 摺好 +折子 摺子 +折子戏 摺子戲 +折实 折實 +折对 折對 +折寿 折壽 +折射 折射 +折射光 折射光 +折射出 折射出 +折射式望远镜 折射式望遠鏡 +折射波 折射波 +折射率 折射率 +折射线 折射線 +折射角 折射角 +折尺 摺尺 +折屐 折屐 +折帐 折帳 +折弯 折彎 +折当 折當 +折得 折得 +折成 折成 +折戟沈河 折戟沈河 +折戟沉沙 折戟沉沙 +折扇 摺扇 +折扣 折扣 +折扣价 折扣價 +折扣战 折扣戰 +折扣率 折扣率 +折抵 折抵 +折挫 折挫 +折损 折損 +折损率 折損率 +折断 折斷 +折旧 折舊 +折旧基金 折舊基金 +折旧率 折舊率 +折旧费 折舊費 +折服 折服 +折本 折本 +折杀 折殺 +折枝 折枝 +折柬 折柬 +折柳 折柳 +折柳攀花 折柳攀花 +折桂 折桂 +折桂攀蟾 折桂攀蟾 +折梯 摺梯 +折椅 摺椅 +折狱 折獄 +折现 折現 +折现率 折現率 +折痕 摺痕 +折的 折的 +折碗 折碗 +折磨 折磨 +折福 折福 +折秤 折秤 +折简 折簡 +折算 折算 +折算法 折算法 +折算率 折算率 +折箩 折籮 +折箭 折箭 +折箭为盟 折箭爲盟 +折箭为誓 折箭爲誓 +折篷 摺篷 +折纸 摺紙 +折纸工 摺紙工 +折线 折線 +折缝 折縫 +折罚 折罰 +折翼 折翼 +折耗 折耗 +折肱 折肱 +折腰 折腰 +折腰五斗 折腰五斗 +折腰升斗 折腰升斗 +折腰步 折腰步 +折腾 折騰 +折臂三公 折臂三公 +折色 折色 +折节 折節 +折节下交 折節下交 +折节下士 折節下士 +折节向学 折節向學 +折节待士 折節待士 +折节礼士 折節禮士 +折节读书 折節讀書 +折莫 折莫 +折行 折行 +折衷 折衷 +折衷主义 折衷主義 +折衷家庭 折衷家庭 +折衷方案 折衷方案 +折衷法 折衷法 +折衷鹦鹉 折衷鸚鵡 +折裙 摺裙 +折角 折角 +折让 折讓 +折证 折證 +折账 折賬 +折起 折起 +折起来 折起來 +折足复𫗧 折足覆餗 +折跟头 折跟頭 +折身 折身 +折转 折轉 +折辨 折辨 +折辩 折辯 +折辱 折辱 +折过儿 折過兒 +折返 折返 +折返点 折返點 +折进 折進 +折进去 摺進去 +折进来 摺進來 +折钱 折錢 +折长补短 折長補短 +折页 摺頁 +折鼎复𫗧 折鼎覆餗 +抚台 撫臺 +抚台街 撫臺街 +抚尸 撫屍 +抚尸恸哭 撫尸慟哭 +抚尸痛哭 撫屍痛哭 +抚恤 撫卹 +抚松 撫松 +抚松县 撫松縣 +抚梁易柱 撫梁易柱 +抚面 撫面 +抚面痛哭 撫面痛哭 +抛出 拋出 +抛出去 拋出去 +抛出来 拋出來 +抛向 拋向 +抛在脑后 拋在腦後 +抛头露面 拋頭露面 +抛妻别子 拋妻別子 +抛尸露骨 拋屍露骨 +抛摆 拋擺 +抛物面 拋物面 +抟击掀发 摶擊掀發 +抟柱乘梁 摶柱乘梁 +抟沙嚼蜡 摶沙嚼蠟 +抟砂炼汞 摶砂煉汞 +抟风板 摶風板 +抠出 摳出 +抠出来 摳出來 +抢了 搶了 +抢修 搶修 +抢修工作 搶修工作 +抢占 搶佔 +抢回 搶回 +抢尽 搶盡 +抢尽锋头 搶盡鋒頭 +抢救出来 搶救出來 +抢杠 搶槓 +抢种 搶種 +护厂 護廠 +护发 護髮 +护发乳液 護髮乳液 +护发素 護髮素 +护向 護向 +护壁板 護壁板 +护念 護念 +护板 護板 +护理 護理 +护理系 護理系 +护面 護面 +护面具 護面具 +报仇 報仇 +报仇雪恨 報仇雪恨 +报仇雪耻 報仇雪恥 +报价 報價 +报价单 報價單 +报修 報修 +报值挂号 報值掛號 +报出 報出 +报出去 報出去 +报出来 報出來 +报刊杂志 報刊雜誌 +报台 報臺 +报名表 報名表 +报告出来 報告出來 +报团 報團 +报国尽忠 報國盡忠 +报复 報復 +报复主义 報復主義 +报复关税 報復關稅 +报复性 報復性 +报导出来 報導出來 +报录人 報錄人 +报税表 報稅表 +报穷制裁 報窮制裁 +报章杂志 報章雜誌 +报系 報系 +报表 報表 +报表纸 報表紙 +报表语言 報表語言 +披云 披雲 +披云雾睹青天 披雲霧睹青天 +披卷 披卷 +披发 披髮 +披发入山 披髮入山 +披发垢面 披髮垢面 +披发左衽 披髮左衽 +披发涂面 披髮塗面 +披发缨冠 披髮纓冠 +披发藻目 披髮藻目 +披复 披覆 +披头四乐团 披頭四樂團 +披头四合唱团 披頭四合唱團 +披头散发 披頭散髮 +披挂 披掛 +披挂上阵 披掛上陣 +披挂绰鎗 披掛綽鎗 +披榛采兰 披榛採蘭 +披红挂彩 披紅掛綵 +披肝挂胆 披肝掛膽 +披针形叶 披針形葉 +抬价 擡價 +抬出 擡出 +抬出去 擡出去 +抬出来 擡出來 +抬回 擡回 +抬回去 擡回去 +抬回来 擡回來 +抬杠 擡槓 +抬高身价 擡高身價 +抱出 抱出 +抱出去 抱出去 +抱出来 抱出來 +抱出笼 抱出籠 +抱回 抱回 +抱回家 抱回家 +抱回来 抱回來 +抱大足杆 抱大足桿 +抱布贸丝 抱布貿絲 +抱成一团 抱成一團 +抱抱团 抱抱團 +抱朴 抱朴 +抱朴子 抱朴子 +抱朴而长吟兮 抱朴而長吟兮 +抱素怀朴 抱素懷樸 +抱负水准 抱負水準 +抵了 抵了 +抵借 抵借 +抵制 抵制 +抵向 抵向 +抵当 抵當 +抵御 抵禦 +抵御外侮 抵禦外侮 +抵扣 抵扣 +抵押借款 抵押借款 +抵挡不了 抵擋不了 +抵牾 牴牾 +抵触 牴觸 +抵针 抵針 +抹了 抹了 +抹布 抹布 +抹干 抹乾 +抹面 抹面 +抻面 抻面 +押出 押出 +押回 押回 +押回去 押回去 +押回来 押回來 +押当 押當 +押柜 押櫃 +押汇 押匯 +押注 押注 +押解回 押解回 +抽丰 抽豐 +抽公签 抽公籤 +抽出 抽出 +抽出去 抽出去 +抽出来 抽出來 +抽出空 抽出空 +抽厘 抽釐 +抽后腿 抽後腿 +抽咽 抽咽 +抽回 抽回 +抽尽 抽盡 +抽屉里 抽屜裏 +抽干 抽乾 +抽斗 抽斗 +抽油烟机 抽油煙機 +抽烟 抽菸 +抽烟室 抽菸室 +抽穗 抽穗 +抽穗期 抽穗期 +抽签 抽籤 +抽绎出 抽繹出 +抽蓄发电 抽蓄發電 +抿发 抿髮 +拂弦 拂弦 +拂荡 拂盪 +拂钟无声 拂鐘無聲 +拂面 拂面 +拂面而来 拂面而來 +拂须 拂鬚 +担仔面 擔仔麪 +担干系 擔干係 +担干纪 擔干紀 +担当 擔當 +担当不起 擔當不起 +担当不过 擔當不過 +担当起来 擔當起來 +担担面 擔擔麪 +担水向河头卖 擔水向河頭賣 +担饥受冻 擔飢受凍 +拆伙 拆夥 +拆借 拆借 +拆出 拆出 +拆出去 拆出去 +拆出来 拆出來 +拆台 拆臺 +拆回 拆回 +拆回去 拆回去 +拆回来 拆回來 +拆封后 拆封後 +拆扣 拆扣 +拆白党 拆白黨 +拆迁范围 拆遷範圍 +拈折 拈折 +拈花摘叶 拈花摘葉 +拈针指 拈針指 +拈须 拈鬚 +拉丁语系 拉丁語系 +拉个手 拉個手 +拉了 拉了 +拉了一把 拉了一把 +拉克施尔德钟 拉克施爾德鐘 +拉克替醇 拉克替醇 +拉克莫诺夫 拉克莫諾夫 +拉出 拉出 +拉出去 拉出去 +拉出来 拉出來 +拉制 拉制 +拉升 拉昇 +拉卜楞 拉卜楞 +拉卜楞寺 拉卜楞寺 +拉合子 拉合子 +拉合尔 拉合爾 +拉合尔市 拉合爾市 +拉后腿 拉後腿 +拉向 拉向 +拉回 拉回 +拉回去 拉回去 +拉回来 拉回來 +拉尔维克 拉爾維克 +拉布 拉布 +拉布拉 拉布拉 +拉布拉他 拉布拉他 +拉布拉他河 拉布拉他河 +拉布拉多 拉布拉多 +拉布拉多半岛 拉布拉多半島 +拉布拉多寒流 拉布拉多寒流 +拉布拉多犬 拉布拉多犬 +拉德万斯卡 拉德萬斯卡 +拉托维亚 拉托維亞 +拉文克劳 拉文克勞 +拉杆 拉桿 +拉杆子 拉桿子 +拉法叶 拉法葉 +拉法叶舰 拉法葉艦 +拉涅里 拉涅里 +拉狄克 拉狄克 +拉皮手术 拉皮手術 +拉祖里 拉祖里 +拉纤 拉縴 +拉缆子摆渡 拉纜子擺渡 +拉蒙 拉蒙 +拉贾帕克萨 拉賈帕克薩 +拉达克 拉達克 +拉里 拉里 +拉里加尼 拉里加尼 +拉里拉尼 拉里拉尼 +拉链 拉鍊 +拉链工程 拉鍊工程 +拉面 拉麪 +拉面店 拉麪店 +拌嘴斗舌 拌嘴鬥舌 +拌折 拌折 +拌种 拌種 +拌面 拌麪 +拍出 拍出 +拍出去 拍出去 +拍出好戏 拍齣好戲 +拍出来 拍出來 +拍卖价 拍賣價 +拍发 拍發 +拍台拍凳 拍檯拍凳 +拍摄出 拍攝出 +拍板 拍板 +拏云 拏雲 +拏云攫石 拏雲攫石 +拐上 拐上 +拐下 拐下 +拐了 拐了 +拐人 拐人 +拐住 拐住 +拐入 拐入 +拐出 拐出 +拐出去 拐出去 +拐出来 拐出來 +拐到 拐到 +拐卖 拐賣 +拐去 拐去 +拐回 拐回 +拐回去 拐回去 +拐回来 拐回來 +拐子 柺子 +拐带 拐帶 +拐弯 拐彎 +拐得 拐得 +拐杖 柺杖 +拐来 拐來 +拐枣 拐棗 +拐棍 柺棍 +拐棒 柺棒 +拐点 拐點 +拐着 拐着 +拐臂 拐臂 +拐角 拐角 +拐诱 拐誘 +拐走 拐走 +拐跑 拐跑 +拐过 拐過 +拐进 拐進 +拐骗 拐騙 +拑制 拑制 +拒于 拒於 +拒人于 拒人於 +拒人于千里之外 拒人於千里之外 +拒烟 拒菸 +拓朴 拓樸 +拓朴学 拓樸學 +拔不出 拔不出 +拔不出腿来 拔不出腿來 +拔个 拔個 +拔了 拔了 +拔了一个尖儿 拔了一個尖兒 +拔了萝卜地皮宽 拔了蘿蔔地皮寬 +拔出 拔出 +拔出去 拔出去 +拔出来 拔出來 +拔发 拔髮 +拔回 拔回 +拔回去 拔回去 +拔回来 拔回來 +拔围出夫 拔圍出夫 +拔地参天 拔地參天 +拔宅上升 拔宅上昇 +拔宅飞升 拔宅飛昇 +拔山志 拔山志 +拔山曲 拔山曲 +拔群出类 拔羣出類 +拔群出萃 拔羣出萃 +拔萃出类 拔萃出類 +拔萃出群 拔萃出羣 +拔萝卜 拔蘿蔔 +拔虎须 拔虎鬚 +拔须 拔鬚 +拖了 拖了 +拖出 拖出 +拖出去 拖出去 +拖出来 拖出來 +拖吊 拖吊 +拖吊车 拖吊車 +拖后腿 拖後腿 +拖回 拖回 +拖回去 拖回去 +拖回来 拖回來 +拖地板 拖地板 +拖布 拖布 +拖干淨 拖乾淨 +拖延战术 拖延戰術 +拖斗 拖斗 +拖板 拖板 +拖板车 拖板車 +拖链 拖鏈 +拖鞋柜 拖鞋櫃 +拖麻拽布 拖麻拽布 +拗别 拗彆 +拗别搅炒 拗彆攪炒 +拗曲作直 拗曲作直 +拘于 拘於 +拘出 拘出 +拘板 拘板 +拘泥于 拘泥於 +拘系 拘繫 +拙于 拙於 +拙于言词 拙於言詞 +拙于言辞 拙於言辭 +拙朴 拙樸 +拚命干 拚命幹 +拚斗 拚鬥 +拚生尽死 拚生盡死 +拚舍 拚捨 +招了 招了 +招供出来 招供出來 +招出 招出 +招出来 招出來 +招回 招回 +招回去 招回去 +招回来 招回來 +招复 招復 +招待不周 招待不周 +招术 招術 +招致 招致 +拜冬 拜冬 +拜别 拜別 +拜占庭 拜占庭 +拜占庭帝国 拜占庭帝國 +拜占庭文化 拜占庭文化 +拜台 拜臺 +拜复 拜覆 +拜岳 拜岳 +拜托 拜託 +拜斗 拜斗 +拜科努尔航天发射基地 拜科努爾航天發射基地 +拜表 拜表 +拟于 擬於 +拟于不伦 擬於不倫 +拟出 擬出 +拟制 擬製 +拟卤素 擬鹵素 +拟定出 擬定出 +拟核 擬核 +拟阿拖品药物 擬阿拖品藥物 +拣出 揀出 +拣别 揀別 +拥向 擁向 +拦前断后 攔前斷後 +拦当 攔當 +拦柜 攔櫃 +拧了 擰了 +拧干 擰乾 +拧松 擰鬆 +拧种 擰種 +拨万论千 撥萬論千 +拨万轮千 撥萬輪千 +拨乱之才 撥亂之才 +拨云撩雨 撥雲撩雨 +拨云睹日 撥雲睹日 +拨云见日 撥雲見日 +拨出 撥出 +拨出去 撥出去 +拨出来 撥出來 +拨发 撥發 +拨号系统 撥號系統 +拨回 撥回 +拨回去 撥回去 +拨回来 撥回來 +拨开云雾见青天 撥開雲霧見青天 +拨弦 撥絃 +拨接式数据通信 撥接式數據通信 +拨蜡法 撥蠟法 +拨谷 撥穀 +拨雨撩云 撥雨撩雲 +括发 括髮 +括弧里 括弧裏 +拭干 拭乾 +拮据 拮据 +拱出 拱出 +拱手而别 拱手而別 +拱手让出 拱手讓出 +拱托 拱托 +拱极星 拱極星 +拳击台 拳擊臺 +拳坛 拳壇 +拳曲 拳曲 +拳术 拳術 +拷克机 拷克機 +拼了 拼了 +拼了命 拼了命 +拼凑出 拼湊出 +拼出 拼出 +拼出去 拼出去 +拼出来 拼出來 +拼列出 拼列出 +拼合 拼合 +拼合版画 拼合版畫 +拼回 拼回 +拼回去 拼回去 +拼回来 拼回來 +拼图游戏 拼圖遊戲 +拼字游戏 拼字遊戲 +拼布 拼布 +拼布图形 拼布圖形 +拼斗 拼鬥 +拼板 拼板 +拼板游戏 拼板遊戲 +拼板玩具 拼板玩具 +拼板胶 拼板膠 +拼板舟 拼板舟 +拼缀出 拼綴出 +拼花地板 拼花地板 +拼贴艺术 拼貼藝術 +拽布披麻 拽布披麻 +拽布拖麻 拽布拖麻 +拽扎 拽扎 +拾回 拾回 +拾沈 拾瀋 +拾穗 拾穗 +拾获 拾獲 +拿下表 拿下錶 +拿下钟 拿下鐘 +拿不了 拿不了 +拿不准 拿不準 +拿不出手 拿不出手 +拿个 拿個 +拿云手 拿雲手 +拿云捉月 拿雲捉月 +拿云握雾 拿雲握霧 +拿准 拿準 +拿出 拿出 +拿出去 拿出去 +拿出手 拿出手 +拿出来 拿出來 +拿回 拿回 +拿回去 拿回去 +拿回家 拿回家 +拿回来 拿回來 +拿坡里 拿坡里 +拿坡里号 拿坡里號 +拿板弄势 拿板弄勢 +拿枪杆 拿槍桿 +拿波里 拿波里 +拿着鸡毛当令箭 拿着雞毛當令箭 +拿破仑 拿破崙 +拿破仑法典 拿破崙法典 +拿破仑波拿巴 拿破侖波拿巴 +拿笔杆 拿筆桿 +拿药 拿藥 +拿获 拿獲 +拿贼要赃拿奸要双 拿賊要贓拿姦要雙 +持不同政见 持不同政見 +持不同政见者 持不同政見者 +持胜 持勝 +挂一挂 掛一掛 +挂一漏万 掛一漏萬 +挂一漏百 掛一漏百 +挂上 掛上 +挂上去 掛上去 +挂上来 掛上來 +挂上钩 掛上鉤 +挂下 掛下 +挂下去 掛下去 +挂下来 掛下來 +挂不上 掛不上 +挂不下 掛不下 +挂不住 掛不住 +挂个 掛個 +挂了 掛了 +挂了幌子 掛了幌子 +挂住 掛住 +挂僵 掛僵 +挂入 掛入 +挂冠 掛冠 +挂冠归里 掛冠歸里 +挂冠求去 掛冠求去 +挂冠而去 掛冠而去 +挂出 掛出 +挂出去 掛出去 +挂出来 掛出來 +挂到 掛到 +挂勾 掛勾 +挂千 掛千 +挂单 掛單 +挂印悬牌 掛印懸牌 +挂印而逃 掛印而逃 +挂历 掛曆 +挂号 掛號 +挂号信 掛號信 +挂号处 掛號處 +挂号证 掛號證 +挂号费 掛號費 +挂名 掛名 +挂名夫妻 掛名夫妻 +挂味儿 掛味兒 +挂回 掛回 +挂回去 掛回去 +挂回来 掛回來 +挂图 掛圖 +挂图表 掛圖表 +挂在 掛在 +挂在口上 掛在口上 +挂在嘴上 掛在嘴上 +挂在嘴边 掛在嘴邊 +挂坠盒 掛墜盒 +挂失 掛失 +挂失止付 掛失止付 +挂头牌 掛頭牌 +挂好 掛好 +挂孝 掛孝 +挂帅 掛帥 +挂帅的社会 掛帥的社會 +挂帐 掛帳 +挂帘 掛簾 +挂幌子 掛幌子 +挂彩 掛彩 +挂得 掛得 +挂心 掛心 +挂念 掛念 +挂怀 掛懷 +挂意 掛意 +挂成 掛成 +挂招牌 掛招牌 +挂掉 掛掉 +挂搭 掛搭 +挂斗 掛斗 +挂断 掛斷 +挂有 掛有 +挂来 掛來 +挂来挂去 掛來掛去 +挂杯架 掛杯架 +挂架 掛架 +挂满 掛滿 +挂漏 掛漏 +挂火 掛火 +挂灯 掛燈 +挂灯结彩 掛燈結綵 +挂牌 掛牌 +挂牌汇率 掛牌匯率 +挂球蛋 掛球蛋 +挂的 掛的 +挂碍 掛礙 +挂篮 掛籃 +挂红 掛紅 +挂红灯 掛紅燈 +挂络儿 掛絡兒 +挂羊头 掛羊頭 +挂羊头卖狗肉 掛羊頭賣狗肉 +挂羊头煮狗肉 掛羊頭煮狗肉 +挂肚牵心 掛肚牽心 +挂肚牵肠 掛肚牽腸 +挂肠悬胆 掛腸懸膽 +挂落儿 掛落兒 +挂虑 掛慮 +挂衣 掛衣 +挂衣冠 掛衣冠 +挂衣架 掛衣架 +挂衣钩 掛衣鉤 +挂表 掛錶 +挂角读书 掛角讀書 +挂记 掛記 +挂账 掛賬 +挂货铺 掛貨鋪 +挂起 掛起 +挂起来 掛起來 +挂车 掛車 +挂轴 掛軸 +挂过 掛過 +挂过去 掛過去 +挂过来 掛過來 +挂进 掛進 +挂进去 掛進去 +挂进来 掛進來 +挂钟 掛鐘 +挂钩 掛鉤 +挂钩儿 掛鉤兒 +挂钩子 掛鉤子 +挂锁 掛鎖 +挂镜儿 掛鏡兒 +挂零 掛零 +挂面 掛麪 +挂齿 掛齒 +挂龙雨 掛龍雨 +指不胜屈 指不勝屈 +指了 指了 +指亲托故 指親托故 +指出 指出 +指北针 指北針 +指南针 指南針 +指向 指向 +指向装置 指向裝置 +指回 指回 +指回去 指回去 +指回来 指回來 +指定曲 指定曲 +指征 指徵 +指手划脚 指手劃腳 +指挥台 指揮台 +指日高升 指日高升 +指极星 指極星 +指标体系 指標體系 +指水盟松 指水盟松 +指破迷团 指破迷團 +指示板 指示板 +指纹纪录 指紋紀錄 +指纹鉴定 指紋鑑定 +指认出 指認出 +指证历历 指證歷歷 +指针 指針 +指针式 指針式 +按下不表 按下不表 +按了 按了 +按出 按出 +按出去 按出去 +按出来 按出來 +按回 按回 +按回去 按回去 +按回来 按回來 +按扣 按扣 +按时间先后 按時間先後 +按照字面 按照字面 +按照计划 按照計劃 +按理出牌 按理出牌 +按表操课 按表操課 +按计划 按計劃 +按质定价 按質定價 +按需出版 按需出版 +挌斗 挌鬥 +挑了 挑了 +挑了只 挑了隻 +挑出 挑出 +挑出去 挑出去 +挑出来 挑出來 +挑口板 挑口板 +挑台 挑臺 +挑大梁 挑大樑 +挑尽 挑盡 +挑得篮里便是菜 挑得籃裏便是菜 +挑拣出 挑揀出 +挑斗 挑鬥 +挑正梁 挑正樑 +挑选出 挑選出 +挑选出来 挑選出來 +挖出 挖出 +挖出去 挖出去 +挖出来 挖出來 +挖心搜胆 挖心搜膽 +挖掘出 挖掘出 +挖掘出来 挖掘出來 +挖耳当招 挖耳當招 +挚而有别 摯而有別 +挟制 挾制 +挟朋树党 挾朋樹黨 +挠折 撓折 +挠曲 撓曲 +挠直为曲 撓直爲曲 +挡不了 擋不了 +挡了 擋了 +挡修 擋修 +挡出 擋出 +挡回 擋回 +挡回去 擋回去 +挡回来 擋回來 +挡御 擋禦 +挡板 擋板 +挡泥板 擋泥板 +挡雨板 擋雨板 +挣出 掙出 +挣扎 掙扎 +挣扎表 掙扎表 +挤了 擠了 +挤兑出来 擠兌出來 +挤出 擠出 +挤出去 擠出去 +挤出来 擠出來 +挤占 擠佔 +挤压出 擠壓出 +挤向 擠向 +挤成一团 擠成一團 +挤昏了头 擠昏了頭 +挤身于 擠身於 +挥了 揮了 +挥出 揮出 +挥别 揮別 +挥发 揮發 +挥发性 揮發性 +挥发性存储器 揮發性存儲器 +挥发油 揮發油 +挥发物 揮發物 +挥戈回日 揮戈回日 +挥手告别 揮手告別 +挥手致意 揮手致意 +挥杆 揮杆 +挨三顶五 挨三頂五 +挨三顶四 捱三頂四 +挨上 捱上 +挨上去 挨上去 +挨不上 挨不上 +挨个 挨個 +挨个儿 挨個兒 +挨了 捱了 +挨了揍 捱了揍 +挨了过去 捱了過去 +挨了过来 捱了過來 +挨亲儿 挨親兒 +挨人儿 挨人兒 +挨光 挨光 +挨刀的 挨刀的 +挨到 捱到 +挨呲 挨呲 +挨呲儿 挨呲兒 +挨头子 挨頭子 +挨家 挨家 +挨家挨户 挨家挨戶 +挨山塞海 挨山塞海 +挨延 挨延 +挨得 捱得 +挨得住 捱得住 +挨户 挨戶 +挨打 捱打 +挨打受气 挨打受氣 +挨打受骂 挨打受罵 +挨批 挨批 +挨拿 挨拿 +挨挤 挨擠 +挨挨 挨挨 +挨挨儿 挨挨兒 +挨挨抢抢 挨挨搶搶 +挨挨蹭蹭 挨挨蹭蹭 +挨捕 挨捕 +挨排 挨排 +挨揍 捱揍 +挨整 捱整 +挨斗 挨鬥 +挨日子 捱日子 +挨时间 捱時間 +挨板子 挨板子 +挨棍子 挨棍子 +挨次 挨次 +挨满 捱滿 +挨着 挨着 +挨磨 捱磨 +挨肩 挨肩 +挨肩儿 挨肩兒 +挨肩叠背 挨肩疊背 +挨肩搭背 挨肩搭背 +挨肩擦背 挨肩擦背 +挨肩擦脸 挨肩擦臉 +挨肩擦膀 挨肩擦膀 +挨苦 捱苦 +挨身 挨身 +挨边 挨邊 +挨边儿 挨邊兒 +挨过 捱過 +挨过去 捱過去 +挨过来 捱過來 +挨近 挨近 +挨门 挨門 +挨门挨户 挨門挨戶 +挨门逐户 挨門逐戶 +挨闹 挨鬧 +挨靠 挨靠 +挨风缉缝 挨風緝縫 +挨饥抵饿 捱飢抵餓 +挨饿 捱餓 +挨饿受冻 挨餓受凍 +挨骂 捱罵 +挪借 挪借 +挪出 挪出 +挫折 挫折 +挫折感 挫折感 +振兴医疗复健中心 振興醫療復健中心 +振杰 振杰 +振聋发嘳 振聾發嘳 +振聋发聩 振聾發聵 +振荡 振盪 +振荡器 振盪器 +振荡电流 振盪電流 +振荡电路 振盪電路 +振衣千仞冈 振衣千仞岡 +挹彼注兹 挹彼注茲 +挹彼注此 挹彼注此 +挹注 挹注 +挺了 挺了 +挺出 挺出 +挺出去 挺出去 +挺出来 挺出來 +挺升 挺升 +挺尸 挺屍 +挺起腰板儿 挺起腰板兒 +挺身而出 挺身而出 +挽住 挽住 +挽具 挽具 +挽力 挽力 +挽回 挽回 +挽回不了 挽回不了 +挽夫 輓夫 +挽幛 挽幛 +挽手 挽手 +挽手儿 挽手兒 +挽救 挽救 +挽救不了 挽救不了 +挽救儿童 挽救兒童 +挽曲 輓曲 +挽歌 輓歌 +挽歌郎 輓歌郎 +挽毂 挽轂 +挽留 挽留 +挽眉毛 挽眉毛 +挽联 輓聯 +挽聯 輓聯 +挽脸师 挽臉師 +挽袖 挽袖 +挽詞 輓詞 +挽詩 輓詩 +挽词 輓詞 +挽诗 輓詩 +挽起 挽起 +挽辞 挽辭 +挽面 挽面 +挽额 輓額 +挽髻 挽髻 +挽麦子 挽麥子 +捅了 捅了 +捅出 捅出 +捆了 捆了 +捆扎 捆紮 +捉不准 捉不準 +捉不胜捉 捉不勝捉 +捉发 捉髮 +捉奸 捉姦 +捉奸党 捉奸黨 +捉奸徒 捉奸徒 +捉奸捉双 捉姦捉雙 +捉奸细 捉奸細 +捉奸见双 捉姦見雙 +捉奸见床 捉姦見牀 +捉奸贼 捉奸賊 +捉摸不出 捉摸不出 +捉获 捉獲 +捉贼见赃捉奸见双 捉賊見贓捉姦見雙 +捋虎须 捋虎鬚 +捋采 捋采 +捍御 捍禦 +捏不准 捏不準 +捏了一把冷汗 捏了一把冷汗 +捏了一把汗 捏了一把汗 +捏出 捏出 +捏出水儿来的 捏出水兒來的 +捏制 捏製 +捏合 捏合 +捏造出 捏造出 +捏造出来 捏造出來 +捏面人 捏麪人 +捐出 捐出 +捐出去 捐出去 +捐出来 捐出來 +捐益表 捐益表 +捐赠盈余 捐贈盈餘 +捕影系风 捕影繫風 +捕获 捕獲 +捕虏岩 捕虜岩 +捕虫 捕蟲 +捕虫叶 捕蟲葉 +捕虫堇菜 捕蟲堇菜 +捕虫植物 捕蟲植物 +捕虫灯 捕蟲燈 +捕虫网 捕蟲網 +捕风系影 捕風繫影 +捞出 撈出 +捞干 撈乾 +捞面 撈麪 +损于 損於 +损兵折将 損兵折將 +损军折将 損軍折將 +损将折兵 損將折兵 +损折 損折 +损益表 損益表 +捡了 撿了 +捡回 撿回 +捡回去 撿回去 +捡回来 撿回來 +换个 換個 +换个儿 換個兒 +换了 換了 +换借 換借 +换出 換出 +换出去 換出去 +换出来 換出來 +换厂 換廠 +换发 換髮 +换只 換隻 +换台 換臺 +换吊 換吊 +换向 換向 +换向器 換向器 +换回 換回 +换回去 換回去 +换回来 換回來 +换心手术 換心手術 +换房旅游 換房旅遊 +换扣 換扣 +换挡杆 換擋桿 +换板 換板 +换档杆 換檔桿 +换汇 換匯 +换汤不换药 換湯不換藥 +换签 換籤 +换算无收获面积 換算無收穫面積 +换算表 換算表 +换系 換系 +换肾手术 換腎手術 +换药 換藥 +捣针 搗針 +捣鬼吊白 搗鬼弔白 +捧出 捧出 +捧出去 捧出去 +捧出来 捧出來 +捧回 捧回 +捧杯 捧杯 +据为己有 據爲己有 +据义履方 據義履方 +据了解 據瞭解 +据云 據云 +据以 據以 +据传 據傳 +据传说 據傳說 +据估计 據估計 +据信 據信 +据守 據守 +据守天险 據守天險 +据实 據實 +据实以报 據實以報 +据实相告 據實相告 +据常 據常 +据干而窥井底 據榦而窺井底 +据悉 據悉 +据情办理 據情辦理 +据我看 據我看 +据报 據報 +据报导 據報導 +据报道 據報道 +据有 據有 +据此 據此 +据点 據點 +据牀指麾 據牀指麾 +据理 據理 +据理力争 據理力爭 +据理而争 據理而爭 +据称 據稱 +据统计 據統計 +据说 據說 +据说在 據說在 +据说是 據說是 +据说有 據說有 +据道 據道 +据闻 據聞 +据险固守 據險固守 +据鞍 據鞍 +捵面 捵麪 +捶台拍凳 捶檯拍凳 +捶炼 捶鍊 +捷众药业 捷衆藥業 +捷克 捷克 +捷克人 捷克人 +捷克共和国 捷克共和國 +捷克斯拉夫 捷克斯拉夫 +捷克斯洛伐克 捷克斯洛伐克 +捷克暨斯洛伐克联邦共和国 捷克暨斯洛伐克聯邦共和國 +捷克籍 捷克籍 +捷克语 捷克語 +捷克队 捷克隊 +捷尔任斯克 捷爾任斯克 +捷才 捷才 +捷运系统 捷運系統 +捻合 捻合 +捻针 捻鍼 +捻须 捻鬚 +掀了 掀了 +掀了开来 掀了開來 +掀出 掀出 +掀出去 掀出去 +掀出来 掀出來 +掀帘子 掀簾子 +掂折 掂折 +掂梢折本 掂梢折本 +授权范围 授權範圍 +掉个 掉個 +掉了 掉了 +掉价儿 掉價兒 +掉出 掉出 +掉出来 掉出來 +掉发 掉髮 +掉回头 掉回頭 +掊克 掊克 +掊斗折衡 掊斗折衡 +掌柜 掌櫃 +掌柜的 掌櫃的 +掌状复叶 掌狀複葉 +掏出 掏出 +掏出来 掏出來 +排兵布阵 排兵佈陣 +排出 排出 +排出体 排出體 +排出作用 排出作用 +排出去 排出去 +排出来 排出來 +排列组合 排列組合 +排名表 排名表 +排当 排當 +排扣 排扣 +排放出 排放出 +排放系统 排放系統 +排档杆 排檔桿 +排水系统 排水系統 +排泄系统 排泄系統 +排烟 排煙 +排版系统 排版系統 +排表 排表 +排门挨户 排門挨戶 +排除万难 排除萬難 +排须 排鬚 +排骨面 排骨麪 +掘出 掘出 +掘出来 掘出來 +掘墓鞭尸 掘墓鞭屍 +探个究竟 探個究竟 +探了 探了 +探出 探出 +探出去 探出去 +探出来 探出來 +探听出 探聽出 +探奇访胜 探奇訪勝 +探寻出 探尋出 +探寻胜迹 探尋勝蹟 +探幽访胜 探幽訪勝 +探知欲 探知慾 +探究出 探究出 +探获 探獲 +探询出 探詢出 +探针 探針 +探骊获珠 探驪獲珠 +掣后腿 掣後腿 +掣签 掣籤 +掤扒吊栲 掤扒吊栲 +接出 接出 +接受不了 接受不了 +接口规范 接口規範 +接合 接合 +接合上 接合上 +接合处 接合處 +接合点 接合點 +接合生殖 接合生殖 +接合菌纲 接合菌綱 +接合起来 接合起來 +接合面 接合面 +接回 接回 +接回去 接回去 +接回来 接回來 +接扣 接扣 +接生术 接生術 +接种 接種 +接种率 接種率 +接穗 接穗 +接绍香烟 接紹香煙 +接续香烟 接續香煙 +接获 接獲 +接触面 接觸面 +接近于 接近於 +接面 接面 +控制 控制 +控制不了 控制不了 +控制住 控制住 +控制力 控制力 +控制区 控制區 +控制单元 控制單元 +控制卡 控制卡 +控制台 控制檯 +控制器 控制器 +控制塔 控制塔 +控制好 控制好 +控制室 控制室 +控制性 控制性 +控制权 控制權 +控制杆 控制桿 +控制板 控制板 +控制棒 控制棒 +控制欲 控制慾 +控制码 控制碼 +控制站 控制站 +控制组 控制組 +控制范围 控制範圍 +控制裕如 控制裕如 +控制论 控制論 +控制键 控制鍵 +控卷 控捲 +控御 控御 +推倒了油瓶不扶 推倒了油瓶不扶 +推出 推出 +推出去 推出去 +推出来 推出來 +推升 推升 +推后 推後 +推向 推向 +推回 推回 +推回去 推回去 +推回来 推回來 +推定出来 推定出來 +推干淨儿 推乾淨兒 +推弦 推絃 +推心致腹 推心致腹 +推情准理 推情準理 +推想出 推想出 +推托 推託 +推托之词 推托之詞 +推挽 推輓 +推断出 推斷出 +推杆 推杆 +推杯 推杯 +推派出 推派出 +推演出来 推演出來 +推理 推理 +推算出 推算出 +推算出来 推算出來 +推舟于陆 推舟於陸 +推诚布信 推誠佈信 +推诚布公 推誠佈公 +推辇归里 推輦歸里 +推销术 推銷術 +推陈出新 推陳出新 +推陈布新 推陳佈新 +掩卷 掩卷 +掩口卢胡 掩口盧胡 +掩口胡卢 掩口胡盧 +掩恶扬善 掩惡揚善 +掩恶溢美 掩惡溢美 +掩罪藏恶 掩罪藏惡 +掩耳盗钟 掩耳盜鐘 +掩面 掩面 +掩面大哭 掩面大哭 +掩面失色 掩面失色 +掩面而泣 掩面而泣 +掩面而过 掩面而過 +措置失当 措置失當 +措置得当 措置得當 +措词不当 措詞不當 +措辞不当 措辭不當 +掰了 掰了 +掳获 擄獲 +掷出 擲出 +掷杯 擲杯 +掺合 摻合 +揉合 揉合 +揉成一团 揉成一團 +揉面 揉麪 +揍了 揍了 +描了 描了 +描写出 描寫出 +描写出来 描寫出來 +描出 描出 +描出来 描出來 +描涂 描塗 +描绘出 描繪出 +描绘出来 描繪出來 +提不出 提不出 +提个 提個 +提了 提了 +提价 提價 +提克瑞提 提克瑞提 +提克里特 提克里特 +提出 提出 +提出去 提出去 +提出建议 提出建議 +提出异议 提出異議 +提出抗辩 提出抗辯 +提出来 提出來 +提制 提製 +提升 提升 +提升为 提升爲 +提升到 提升到 +提向 提向 +提回 提回 +提回去 提回去 +提回来 提回來 +提子干 提子乾 +提学御史 提學御史 +提干 提幹 +提心吊胆 提心吊膽 +提拉米苏 提拉米蘇 +提摩太后书 提摩太後書 +提梁 提樑 +提炼 提煉 +提炼出 提煉出 +提甕出汲 提甕出汲 +提纯复壮 提純復壯 +提舍尼 提舍尼 +插于 插於 +插回 插回 +插回去 插回去 +插回来 插回來 +插图卷 插圖卷 +插扣 插扣 +插曲 插曲 +插架万轴 插架萬軸 +插箭游营 插箭遊營 +插足于 插足於 +插针 插針 +握不准 握不準 +握云拿雾 握雲拿霧 +握云携雨 握雲攜雨 +握别 握別 +握发 握髮 +握发吐哺 握髮吐哺 +握发吐餐 握髮吐餐 +握手极欢 握手極歡 +握手道别 握手道別 +握雨携云 握雨攜雲 +握雾拿云 握霧拿雲 +揣合逢迎 揣合逢迎 +揣在怀里 揣在懷裏 +揣奸把猾 揣奸把猾 +揩台抹凳 揩檯抹凳 +揩干 揩乾 +揪出 揪出 +揪出去 揪出去 +揪出来 揪出來 +揪发 揪髮 +揪斗 揪鬥 +揪采 揪採 +揪须 揪鬚 +揭丑 揭醜 +揭出 揭出 +揭发 揭發 +揭发出 揭發出 +揭布 揭布 +揭折 揭折 +揭示板 揭示板 +揭露出 揭露出 +援据 援據 +揽胜 攬勝 +揽胜图 攬勝圖 +揽闲事 攬閒事 +搀伙 攙夥 +搁板 擱板 +搁脚板 擱腳板 +搅合 攪合 +搋在怀里 搋在懷裏 +搋面 搋麪 +搌布 搌布 +搏斗 搏鬥 +搏炼 搏煉 +搏砂炼汞 搏砂煉汞 +搓板 搓板 +搓熟的汤团 搓熟的湯團 +搓粉团朱 搓粉團朱 +搓粉抟朱 搓粉摶朱 +搜下 搜下 +搜书 搜書 +搜了 搜了 +搜人 搜人 +搜出 搜出 +搜刮 搜刮 +搜到 搜到 +搜剿 搜剿 +搜吧 搜吧 +搜听 搜聽 +搜啊 搜啊 +搜图 搜圖 +搜奇 搜奇 +搜奇抉怪 搜奇抉怪 +搜奇访古 搜奇訪古 +搜奇选妙 搜奇選妙 +搜宝 搜寶 +搜客 搜客 +搜寻 搜尋 +搜寻到 搜尋到 +搜寻引擎 搜尋引擎 +搜寻软体 搜尋軟體 +搜山 搜山 +搜店 搜店 +搜房 搜房 +搜扬仄陋 搜揚仄陋 +搜扬侧陋 搜揚側陋 +搜括 蒐括 +搜括一空 搜括一空 +搜捕 搜捕 +搜捕到 搜捕到 +搜掠 搜掠 +搜搜 搜搜 +搜搜客 搜搜客 +搜搜客网 搜搜客網 +搜救 搜救 +搜救犬 搜救犬 +搜星 搜星 +搜查 搜查 +搜査证 搜查證 +搜根剔齿 搜根剔齒 +搜根究底 搜根究底 +搜根问底 搜根問底 +搜检 搜檢 +搜歌 搜歌 +搜求 搜求 +搜游 搜遊 +搜爆 搜爆 +搜狐 搜狐 +搜狐网 搜狐網 +搜狗 搜狗 +搜的 搜的 +搜神 搜神 +搜神记 搜神記 +搜秀 搜秀 +搜章擿句 搜章擿句 +搜索 搜索 +搜索到 搜索到 +搜索前进 搜索前進 +搜索半径 搜索半徑 +搜索引擎 搜索引擎 +搜索枯肠 搜索枯腸 +搜索票 搜索票 +搜索结果 搜索結果 +搜索范围 搜索範圍 +搜索队 搜索隊 +搜缴 搜繳 +搜网 搜網 +搜罗 蒐羅 +搜肠刮肚 搜腸刮肚 +搜获 搜獲 +搜藏 蒐藏 +搜藏家 蒐藏家 +搜虎 搜虎 +搜证 蒐證 +搜豹 搜豹 +搜购 蒐購 +搜走 搜走 +搜身 搜身 +搜遍 搜遍 +搜酷 搜酷 +搜集 蒐集 搜集 +搜集到 蒐集到 +搢绅录 搢紳錄 +搪饥 搪飢 +搬出 搬出 +搬出去 搬出去 +搬出来 搬出來 +搬回 搬回 +搬回去 搬回去 +搬回来 搬回來 +搬斗 搬鬥 +搭个 搭個 +搭伙 搭夥 +搭克露 搭克露 +搭出 搭出 +搭干铺 搭乾鋪 +搭扣 搭扣 +搭机回 搭機回 +搭面 搭面 +搯出来 搯出來 +携云挈雨 攜雲挈雨 +携云握雨 攜雲握雨 +携出 攜出 +携同 攜同 +携带式卫星通信系统 攜帶式衛星通信系統 +携手合作 攜手合作 +携手同心 攜手同心 +携手并肩 攜手並肩 +搽穰卷儿 搽穰捲兒 +搽药 搽藥 +摁扣 摁釦 +摄于 攝於 +摄制 攝製 +摄制厂 攝製廠 +摄制成 攝製成 +摄录影机 攝錄影機 +摄影术 攝影術 +摄影艺术 攝影藝術 +摄氏寒暑表 攝氏寒暑表 +摆上 擺上 +摆上去 擺上去 +摆上来 擺上來 +摆下 擺下 +摆下去 擺下去 +摆下来 擺下來 +摆不下 擺不下 +摆不平 擺不平 +摆不开 擺不開 +摆乌龙 擺烏龍 +摆了一道 擺了一道 +摆事实讲道理 擺事實講道理 +摆云锣儿 擺雲鑼兒 +摆供 擺供 +摆出 擺出 +摆出去 擺出去 +摆出来 擺出來 +摆划 擺劃 +摆列 擺列 +摆列出 擺列出 +摆到 擺到 +摆制 擺制 +摆动 擺動 +摆动波 擺動波 +摆卖 擺賣 +摆回 擺回 +摆回去 擺回去 +摆回来 擺回來 +摆在 擺在 +摆在心上 擺在心上 +摆在眼前 擺在眼前 +摆地摊 擺地攤 +摆夷 擺夷 +摆好 擺好 +摆姿势 擺姿勢 +摆子 擺子 +摆官架子 擺官架子 +摆尾 擺尾 +摆尾摇头 擺尾搖頭 +摆布 擺佈 +摆席 擺席 +摆平 擺平 +摆开 擺開 +摆开阵势 擺開陣勢 +摆弄 擺弄 +摆当 擺當 +摆得 擺得 +摆忙 擺忙 +摆成 擺成 +摆手 擺手 +摆拨 擺撥 +摆拨不下 擺撥不下 +摆振 擺振 +摆搠 擺搠 +摆搭 擺搭 +摆摆 擺擺 +摆摆头 擺擺頭 +摆摆手 擺擺手 +摆摆摇摇 擺擺搖搖 +摆摊 擺攤 +摆摊儿 擺攤兒 +摆摊子 擺攤子 +摆撼 擺撼 +摆擂台 擺擂臺 +摆放 擺放 +摆放在 擺放在 +摆明 擺明 +摆来 擺來 +摆来摆去 擺來擺去 +摆架子 擺架子 +摆样 擺樣 +摆样子 擺樣子 +摆格 擺格 +摆槊 擺槊 +摆款 擺款 +摆法 擺法 +摆浪子 擺浪子 +摆渡 擺渡 +摆渡船 擺渡船 +摆满 擺滿 +摆点 擺點 +摆番 擺番 +摆空架子 擺空架子 +摆站 擺站 +摆线 擺線 +摆置 擺置 +摆脱 擺脫 +摆脱不了 擺脫不了 +摆脱到 擺脫到 +摆脱危机 擺脫危機 +摆花架子 擺花架子 +摆荡 擺盪 +摆荡吊环 擺蕩吊環 +摆荡起来 擺盪起來 +摆落 擺落 +摆行阵 擺行陣 +摆袖却金 擺袖卻金 +摆设 擺設 +摆设儿 擺設兒 +摆请儿 擺請兒 +摆谱 擺譜 +摆谱儿 擺譜兒 +摆起 擺起 +摆起来 擺起來 +摆轮 擺輪 +摆进 擺進 +摆进去 擺進去 +摆进来 擺進來 +摆酒 擺酒 +摆酒席 擺酒席 +摆针 擺針 +摆钟 擺鐘 +摆锤 擺錘 +摆长 擺長 +摆门子 擺門子 +摆门面 擺門面 +摆阔 擺闊 +摆阔气 擺闊氣 +摆阵 擺陣 +摆露 擺露 +摆饭 擺飯 +摆饰 擺飾 +摆齐 擺齊 +摆龙门阵 擺龍門陣 +摇了 搖了 +摇了一下 搖了一下 +摇头摆尾 搖頭擺尾 +摇头摆脑 搖頭擺腦 +摇摆 搖擺 +摇摆不定 搖擺不定 +摇摆乐 搖擺樂 +摇摆舞 搖擺舞 +摇摇摆摆 搖搖擺擺 +摇摇欲坠 搖搖欲墜 +摇摇荡荡 搖搖蕩蕩 +摇杆 搖桿 +摇板 搖板 +摇滚乐团 搖滾樂團 +摇滚团 搖滾團 +摇篮曲 搖籃曲 +摇荡 搖盪 +摇荡不停 搖盪不停 +摇车儿里的爷爷拄拐棍儿的孙子 搖車兒裏的爺爺拄拐棍兒的孫子 +摇针 搖針 +摊了 攤了 +摊了事 攤了事 +摊了人命 攤了人命 +摊出 攤出 +摊出去 攤出去 +摊出来 攤出來 +摊薄后每股盈利 攤薄後每股盈利 +摒出 摒出 +摔了 摔了 +摔了一跤 摔了一跤 +摔出 摔出 +摔断了 摔斷了 +摔断了腿 摔斷了腿 +摔筋斗 摔筋斗 +摔跟斗 摔跟斗 +摘伏发隐 摘伏發隱 +摘借 摘借 +摘出 摘出 +摘出去 摘出去 +摘出来 摘出來 +摘奸发伏 摘奸發伏 +摘录 摘錄 +摘录自 摘錄自 +摘绵术 摘綿術 +摛藻雕章 摛藻雕章 +摧兰折玉 摧蘭折玉 +摧坚获丑 摧堅獲醜 +摧志屈道 摧志屈道 +摧折 摧折 +摧枯折腐 摧枯折腐 +摧眉折腰 摧眉折腰 +摩厉以须 摩厲以須 +摩合罗 摩合羅 +摩托 摩托 +摩托化 摩托化 +摩托罗垃 摩托羅垃 +摩托罗拉 摩托羅拉 +摩托船 摩托船 +摩托车 摩托車 +摩托车的士 摩托車的士 +摩托车组 摩托車組 +摩擦系数 摩擦係數 +摩根费里曼 摩根費里曼 +摩肩如云 摩肩如雲 +摩苏尔 摩蘇爾 +摩苏尔市 摩蘇爾市 +摩诃迦叶 摩訶迦葉 +摩里西斯 摩里西斯 +摭采 摭採 +摸不准 摸不準 +摸了 摸了 +摸出 摸出 +摸出去 摸出去 +摸出来 摸出來 +摸彩 摸彩 +摸彩券 摸彩券 +摸彩品 摸彩品 +摸彩箱 摸彩箱 +摸秋 摸秋 +摸索出 摸索出 +摸钟 摸鐘 +摹扎特 摹紮特 +撂了 撂了 +撇吊 撇弔 +撑了 撐了 +撑出 撐出 +撑场面 撐場面 +撑头获脑 撐頭獲腦 +撑市面 撐市面 +撑杆 撐杆 +撑杆跳 撐杆跳 +撑杆跳高 撐杆跳高 +撑门面 撐門面 +撒克逊 撒克遜 +撒克逊人 撒克遜人 +撒出 撒出 +撒呓症 撒囈症 +撒布 撒佈 +撒极 撒極 +撒种 撒種 +撒马尔干 撒馬爾幹 +撕了 撕了 +撞个满怀 撞個滿懷 +撞出 撞出 +撞出去 撞出去 +撞出来 撞出來 +撞击式印表机 撞擊式印表機 +撞向 撞向 +撞尸 撞屍 +撞府冲州 撞府沖州 +撞木钟 撞木鐘 +撞球台 撞球檯 +撞球杆 撞球桿 +撞警钟 撞警鐘 +撞针 撞針 +撞钟 撞鐘 +撞钟太岁 撞鐘太歲 +撞阵冲军 撞陣衝軍 +撤出 撤出 +撤出去 撤出去 +撤出来 撤出來 +撤后 撤後 +撤回 撤回 +撤回去 撤回去 +撤回来 撤回來 +撤帘 撤簾 +撤并 撤併 +撤柜 撤櫃 +撤销记录 撤銷記錄 +撧折 撧折 +撩云拨雨 撩雲撥雨 +撩斗 撩鬥 +撩虎须 撩虎鬚 +撬了 撬了 +撬出去 撬出去 +撬出来 撬出來 +撬杠 撬槓 +播于 播於 +播出 播出 +播出去 播出去 +播出来 播出來 +播出频道 播出頻道 +播发 播發 +播恶遗臭 播惡遺臭 +播放列表 播放列表 +播放歌曲 播放歌曲 +播种 播種 +播种期 播種期 +播种机 播種機 +播种法 播種法 +播种面积 播種面積 +播荡 播蕩 +播越失据 播越失據 +撮合 撮合 +撮合山 撮合山 +撮科打哄 撮科打哄 +撮药 撮藥 +撰出来 撰出來 +撰录 撰錄 +撵出 攆出 +撵出去 攆出去 +撵出来 攆出來 +撺哄 攛哄 +撺哄鸟乱 攛哄鳥亂 +擀面 擀麪 +擀面杖 擀麪杖 +擂台 擂臺 +擂台赛 擂臺賽 +擂鼓交响曲 擂鼓交響曲 +擅于 擅於 +擅长于 擅長於 +操作台 操作檯 +操作系统 操作系統 +操作规范 操作規範 +操作钟 操作鐘 +操同室之戈 操同室之戈 +操纵台 操縱檯 +操纵杆 操縱桿 +操船术 操船術 +擎拳合掌 擎拳合掌 +擐系 擐繫 +擒奸摘伏 擒奸摘伏 +擒奸擿伏 擒奸擿伏 +擒奸讨暴 擒奸討暴 +擒获 擒獲 +擘划 擘劃 +擢升 擢升 +擢发 擢髮 +擢发抽肠 擢髮抽腸 +擢发难数 擢髮難數 +擦俊药 擦俊藥 +擦出 擦出 +擦出爱 擦出愛 +擦刮 擦刮 +擦布 擦布 +擦干 擦乾 +擦干净 擦乾淨 +擦干淨 擦乾淨 +擦碗布 擦碗布 +擦药 擦藥 +擦面子 擦面子 +擿埴索涂 擿埴索塗 +擿奸发伏 擿奸發伏 +攀云 攀雲 +攀亲引戚 攀親引戚 +攀今吊古 攀今吊古 +攀升 攀升 +攀岩 攀巖 +攀折 攀折 +攀花折柳 攀花折柳 +攀蟾折桂 攀蟾折桂 +攧攧仆仆 攧攧仆仆 +支出 支出 +支出费用 支出費用 +支划 支劃 +支努干 支努干 +支干 支幹 +支当 支當 +支撑不了 支撐不了 +支杆 支桿 +支烟 支菸 +支系 支系 +支系统 支系統 +支胄 支胄 +收了 收了 +收出 收出 +收出去 收出去 +收出来 收出來 +收发 收發 +收发器 收發器 +收发室 收發室 +收发短信 收發短信 +收发站 收發站 +收回 收回 +收回到 收回到 +收回去 收回去 +收回成命 收回成命 +收回来 收回來 +收复 收復 +收复失土 收復失土 +收复失地 收復失地 +收复河山 收復河山 +收尸 收屍 +收录 收錄 +收录两用机 收錄兩用機 +收录在 收錄在 +收录音机 收錄音機 +收拾干淨 收拾乾淨 +收据 收據 +收款台 收款臺 +收汇 收匯 +收盘价 收盤價 +收盘价格 收盤價格 +收盘汇率 收盤匯率 +收秋 收秋 +收获 收穫 +收获节 收穫節 +收获量 收穫量 +收购价 收購價 +收购价格 收購價格 +收针 收針 +收银台 收銀臺 +攸戚相关 攸慼相關 +改不了 改不了 +改个 改個 +改了 改了 +改了又改 改了又改 +改于 改於 +改修 改修 +改制 改制 改製 +改制为 改製爲 +改变不了 改變不了 +改向 改向 +改回 改回 +改头换面 改頭換面 +改当 改當 +改征 改徵 +改念 改唸 +改恶向善 改惡向善 +改扣 改扣 +改签 改簽 +改良品种 改良品種 +改良种 改良種 +攻了 攻了 +攻克 攻克 +攻击范围 攻擊範圍 +攻击面 攻擊面 +攻占 攻佔 +攻向 攻向 +攻守同盟 攻守同盟 +攻无不克 攻無不克 +攻无不克战无不胜 攻無不克戰無不勝 +放一百二十个心 放一百二十個心 +放个 放個 +放之四海皆准 放之四海皆準 +放之四海而皆准 放之四海而皆準 +放了 放了 +放了屁儿却使手掩 放了屁兒卻使手掩 +放党 放黨 +放出 放出 +放出去 放出去 +放出手眼 放出手眼 +放出来 放出來 +放参 放參 +放回 放回 +放回去 放回去 +放在心里 放在心裏 +放在眼里 放在眼裏 +放大系数 放大係數 +放学后 放學後 +放射出 放射出 +放射出来 放射出來 +放射性发光材料 放射性發光材料 +放射性同位素 放射性同位素 +放射性烟羽 放射性煙羽 +放射虫 放射蟲 +放尽 放盡 +放屁虫 放屁蟲 +放暗箭 放暗箭 +放松 放鬆 +放松管制 放松管制 +放流水标准 放流水標準 +放烟 放煙 +放烟幕 放煙幕 +放烟幕弹 放煙幕彈 +放烟火 放煙火 +放荡 放蕩 +放荡不羁 放蕩不羈 +放荡任气 放蕩任氣 +放荡弛纵 放蕩弛縱 +放蒙挣 放懞掙 +放诸四海皆准 放諸四海皆準 +放轻松 放輕鬆 +放马后炮 放馬後炮 +放马后砲 放馬後砲 +政党 政黨 +政党政治 政黨政治 +政出多门 政出多門 +政制 政制 +政团 政團 +政坛 政壇 +政工干校 政工幹校 +政府机关开放系统互连总则 政府機關開放系統互連總則 +政教合一 政教合一 +政治体制 政治體制 +政治局面 政治局面 +政治斗争 政治鬥爭 +政治系 政治系 +政治舞台 政治舞臺 +政治面 政治面 +政策面 政策面 +政见发表 政見發表 +故事里 故事裏 +故于 故於 +故云 故云 +故出 故出 +故地重游 故地重遊 +故当 故當 +故态复萌 故態復萌 +故舍 故舍 +故里 故里 +效价能 效價能 +敌党 敵黨 +敌前敌后 敵前敵後 +敌占区 敵佔區 +敌台 敵臺 +敌后 敵後 +敌后伏击 敵後伏擊 +敌后作战 敵後作戰 +敌后工作 敵後工作 +敌后工作人员 敵後工作人員 +敌后方 敵後方 +敌忾同仇 敵愾同仇 +敌百虫 敵百蟲 +敏于 敏於 +敏于事而慎于言 敏於事而慎於言 +敏于伎 敏於伎 +救人一命胜造七级浮屠 救人一命勝造七級浮屠 +救人须救彻 救人須救徹 +救出 救出 +救出去 救出去 +救出来 救出來 +救回 救回 +救回去 救回去 +救回来 救回來 +救困扶危 救困扶危 +救国团 救國團 +救恩计划 救恩計劃 +救生艇甲板 救生艇甲板 +救药 救藥 +敖力布告 敖力布告 +敖游 敖遊 +敖荡 敖盪 +教个 教個 +教了 教了 +教于 教於 +教准部 教準部 +教出 教出 +教团 教團 +教坛 教壇 +教外别传 教外別傳 +教学示范 教學示範 +教学计划 教學計劃 +教学钟 教學鐘 +教猱升木 教猱升木 +教练团 教練團 +教育出来 教育出來 +教育制度 教育制度 +教育团体 教育團體 +教育方针 教育方針 +教育系 教育系 +教胄 教胄 +教范 教範 +敝帚千金 敝帚千金 +敝舍 敝舍 +敢于 敢於 +敢作敢当 敢作敢當 +敢借 敢借 +敢做敢当 敢做敢當 +敢出 敢出 +敢出去 敢出去 +敢出来 敢出來 +敢向 敢向 +敢干 敢幹 +敢当 敢當 +敢情欲 敢情欲 +敢摆 敢擺 +敢斗了胆 敢斗了膽 +散于 散於 +散伙 散夥 +散兵游勇 散兵遊勇 +散出 散出 +散发 散發 散髮 +散发传单 散發傳單 +散发出 散發出 +散发出来 散發出來 +散尽 散盡 +散布 散佈 +散布开 散佈開 +散布者 散佈者 +散曲 散曲 +散板 散板 +散荡 散蕩 +敦克尔克大撤退 敦克爾克大撤退 +敦朴 敦樸 +敦煌千佛洞 敦煌千佛洞 +敦煌曲子 敦煌曲子 +敬同 敬同 +敬姜犹绩 敬姜猶績 +敬挽 敬輓 +敬烟 敬菸 +敬鉴 敬鑒 +数万 數萬 +数万人 數萬人 +数万元 數萬元 +数不尽 數不盡 +数不胜数 數不勝數 +数与虏确 數與虜确 +数了 數了 +数以万计 數以萬計 +数以万订 數以萬訂 +数以千计 數以千計 +数以百万计 數以百萬計 +数位化录音带 數位化錄音帶 +数位快速篆刻系统 數位快速篆刻系統 +数位控制 數位控制 +数位板 數位板 +数位艺术 數位藝術 +数借 數借 +数值控制 數值控制 +数值范围 數值範圍 +数出 數出 +数十万 數十萬 +数千 數千 +数千万 數千萬 +数千亿 數千億 +数周 數週 +数天后 數天後 +数字时钟 數字時鐘 +数字系数 數字係數 +数字钟 數字鐘 +数字钟表 數字鐘錶 +数学系 數學系 +数据 數據 +数据介面 數據介面 +数据传输 數據傳輸 +数据卡 數據卡 +数据压缩 數據壓縮 +数据处理 數據處理 +数据库 數據庫 +数据总线 數據總線 +数据挖掘 數據挖掘 +数据接口 數據接口 +数据机 數據機 +数据段 數據段 +数据流 數據流 +数据源 數據源 +数据结构 數據結構 +数据网络 數據網絡 +数据调制解调器 數據調制解調器 +数据资料 數據資料 +数据通信 數據通信 +数据通讯 數據通訊 +数据链 數據鏈 +数据链路 數據鏈路 +数据链路层 數據鏈路層 +数据链路连接识别码 數據鏈路連接識別碼 +数术 數術 +数杯 數杯 +数理 數理 +数百万 數百萬 +数米志炊 數米志炊 +数罪并罚 數罪併罰 +数里 數里 +敲丧钟 敲喪鐘 +敲了 敲了 +敲出 敲出 +敲钟 敲鐘 +整个 整個 +整个人 整個人 +整个地球 整個地球 +整个月 整個月 +整个来说 整個來說 +整了 整了 +整人游戏 整人遊戲 +整修 整修 +整修费 整修費 +整党 整黨 +整出剧 整齣劇 +整出戏 整齣戲 +整厂输出 整廠輸出 +整发 整發 +整发用品 整髮用品 +整只 整隻 +整叶 整葉 +整合 整合 +整合出 整合出 +整合到 整合到 +整合商 整合商 +整合型 整合型 +整合式 整合式 +整合性 整合性 +整合成 整合成 +整合法 整合法 +整合管理资讯化 整合管理資訊化 +整合系统 整合系統 +整合行销传播 整合行銷傳播 +整周 整週 +整型手术 整型手術 +整型术 整型術 +整容手术 整容手術 +整容术 整容術 +整庄 整莊 +整形术 整形術 +整数集合 整數集合 +整杯 整杯 +整杯水 整杯水 +整杯茶 整杯茶 +整杯酒 整杯酒 +整柜 整櫃 +整根烟 整根菸 +整理 整理 +整理出 整理出 +整理出来 整理出來 +整装待发 整裝待發 +整面 整面 +整风后 整風後 +整齐划一 整齊劃一 +整齐干淨 整齊乾淨 +敷了 敷了 +敷出 敷出 +敷布 敷布 +敷彩泥塑 敷彩泥塑 +敷涂 敷塗 +敷药 敷藥 +敷衍了事 敷衍了事 +敷面 敷面 +敷面膜 敷面膜 +敹一针 敹一針 +文不尽意 文不盡意 +文丑 文丑 +文书鉴定 文書鑑定 +文了 文了 +文件旅游 文件旅遊 +文件柜 文件櫃 +文修武偃 文修武偃 +文修武备 文修武備 +文创志业 文創志業 +文化体系 文化體系 +文化冲击 文化衝擊 +文化斗争 文化鬥爭 +文化水准 文化水準 +文同 文同 +文君当垆 文君當壚 +文坛 文壇 +文坛人士 文壇人士 +文复会 文復會 +文学系 文學系 +文彩 文彩 +文征明 文徵明 +文心雕龙 文心雕龍 +文思泉涌 文思泉湧 +文情并茂 文情並茂 +文才 文才 +文擅雕龙 文擅雕龍 +文斯范恩 文斯范恩 +文星和合 文星和合 +文曲 文曲 +文曲星 文曲星 +文武全才 文武全才 +文武合一 文武合一 +文汇报 文匯報 +文汇阁 文匯閣 +文炳雕龙 文炳雕龍 +文种 文種 +文章星斗 文章星斗 +文致 文致 +文艺复兴 文藝復興 +文艺演出 文藝演出 +文表 文表 +文身断发 文身斷髮 +文选烂秀才半 文選爛秀才半 +文采 文采 +文采出众 文采出衆 +文采郁郁 文采郁郁 +文采风流 文采風流 +文鉴 文鑑 +文锦复阱 文錦覆阱 +文面 文面 +斋坛 齋壇 +斋栗 齋慄 +斋舍 齋舍 +斐然向风 斐然向風 +斑岩 斑岩 +斗一斗 鬥一鬥 +斗上 鬥上 +斗上一斗 鬥上一鬥 +斗不过 鬥不過 +斗丽 鬥麗 +斗了 鬥了 +斗了一斗 鬥了一鬥 +斗了起来 鬥了起來 +斗争 鬥爭 +斗争大会 鬥爭大會 +斗争形式 鬥爭形式 +斗争性 鬥爭性 +斗争意志 鬥爭意志 +斗争斗合 鬥爭鬥合 +斗争方式 鬥爭方式 +斗他一斗 鬥他一鬥 +斗倒 鬥倒 +斗储 斗儲 +斗六 斗六 +斗六市 斗六市 +斗内力 鬥內力 +斗分子 鬥分子 +斗别气 鬥彆氣 +斗力 鬥力 +斗力不如斗智 鬥力不如鬥智 +斗劲 鬥勁 +斗十余 鬥十餘 +斗升 斗升 +斗升之水 斗升之水 +斗升之禄 斗升之祿 +斗南 斗南 +斗南一人 斗南一人 +斗南镇 斗南鎮 +斗叠 鬥疊 +斗口 鬥口 +斗口齿 鬥口齒 +斗叶儿 鬥葉兒 +斗叶子 鬥葉子 +斗合 鬥合 +斗哄 鬥鬨 +斗嘴 鬥嘴 +斗地主 鬥地主 +斗城 斗城 +斗士 鬥士 +斗大 斗大 +斗大的手卷 斗大的手卷 +斗大的馒头 斗大的饅頭 +斗头 鬥頭 +斗她一斗 鬥她一鬥 +斗子 斗子 +斗室 斗室 +斗室生辉 斗室生輝 +斗富 鬥富 +斗小马 斗小馬 +斗尾港 斗尾港 +斗居 斗居 +斗山 斗山 +斗巧 鬥巧 +斗巧争奇 鬥巧爭奇 +斗帐 斗帳 +斗幌子 鬥幌子 +斗店 斗店 +斗府 斗府 +斗弄 鬥弄 +斗引 鬥引 +斗彩 鬥彩 +斗很 鬥很 +斗心眼 鬥心眼 +斗志 鬥志 +斗志昂扬 鬥志昂揚 +斗志高昂 鬥志高昂 +斗成 鬥成 +斗打 鬥打 +斗批改 鬥批改 +斗技 鬥技 +斗折蛇行 斗折蛇行 +斗拱 斗拱 +斗数 斗數 +斗文 鬥文 +斗斋 斗齋 +斗斗 鬥鬥 斗斗 +斗斗嘴 鬥鬥嘴 +斗斛之禄 斗斛之祿 +斗方 斗方 +斗方名士 斗方名士 +斗智 鬥智 +斗智不斗力 鬥智不鬥力 +斗智斗力 鬥智鬥力 +斗暴 鬥暴 +斗杓 斗杓 +斗杓东指 斗杓東指 +斗杓转势 斗杓轉勢 +斗来斗去 鬥來鬥去 +斗极 斗極 +斗柄 斗柄 +斗栱 斗栱 +斗概 斗概 +斗武 鬥武 +斗殴 鬥毆 +斗气 鬥氣 +斗沟子 斗溝子 +斗法 鬥法 +斗渠 斗渠 +斗灯 斗燈 +斗烟丝 斗菸絲 +斗然 斗然 +斗牌 鬥牌 +斗牙拌齿 鬥牙拌齒 +斗牙斗齿 鬥牙鬥齒 +斗牛 鬥牛 +斗牛㹴 鬥牛㹴 +斗牛之间 斗牛之間 +斗牛场 鬥牛場 +斗牛士 鬥牛士 +斗牛士之歌 鬥牛士之歌 +斗牛梗 鬥牛梗 +斗牛赛 鬥牛賽 +斗牛阵 鬥牛陣 +斗犀台 鬥犀臺 +斗犬 鬥犬 +斗狠 鬥狠 +斗百余 鬥百餘 +斗百草 鬥百草 +斗的 斗的 +斗真 斗真 +斗眼 鬥眼 +斗私批修 鬥私批修 +斗笠 斗笠 +斗筲 斗筲 +斗筲之人 斗筲之人 +斗筲之器 斗筲之器 +斗筲之徒 斗筲之徒 +斗筲之才 斗筲之才 +斗筲之材 斗筲之材 +斗筲之辈 斗筲之輩 +斗筲小器 斗筲小器 +斗筲役 斗筲役 +斗筲穿窬 斗筲穿窬 +斗箕 斗箕 +斗篷 斗篷 +斗粟囊金 斗粟囊金 +斗粟尺布 斗粟尺布 +斗纹 斗紋 +斗绝 斗絕 +斗绝一隅 斗絕一隅 +斗罗大陆 斗羅大陸 +斗而铸兵 鬥而鑄兵 +斗而铸锥 鬥而鑄錐 +斗胆 斗膽 +斗胜 鬥勝 +斗脚 鬥腳 +斗舰 鬥艦 +斗艳 鬥豔 +斗艳争芳 鬥豔爭芳 +斗茶 鬥茶 +斗草 鬥草 +斗蓬装 斗蓬裝 +斗薮 斗藪 +斗蟋蟀 鬥蟋蟀 +斗话 鬥話 +斗起 鬥起 +斗起来 鬥起來 +斗趣 鬥趣 +斗趣儿 鬥趣兒 +斗车 斗車 +斗转参横 斗轉參橫 +斗转星移 斗轉星移 +斗酒 斗酒 +斗酒博凉州 斗酒博涼州 +斗酒只鸡 斗酒隻雞 +斗酒学士 斗酒學士 +斗酒百篇 斗酒百篇 +斗重山齐 斗重山齊 +斗量 斗量 +斗量车载 斗量車載 +斗门 斗門 +斗门区 斗門區 +斗闲气 鬥閒氣 +斗闷 鬥悶 +斗闷子 鬥悶子 +斗阵 鬥陣 +斗雪红 鬥雪紅 +斗顿 斗頓 +斗风 鬥風 +斗食 斗食 +斗饤 鬥飣 +斗香 斗香 +斗魁 斗魁 +斗鱼 鬥魚 +斗鸡 鬥雞 +斗鸡台 鬥雞臺 +斗鸡场 鬥雞場 +斗鸡眼 鬥雞眼 +斗鸡走狗 鬥雞走狗 +斗鸡走马 鬥雞走馬 +斗鸭 鬥鴨 +斗鹌鹑 鬥鵪鶉 +料不准 料不準 +料前不能料后 料前不能料後 +料敌制胜 料敵制勝 +料斗 料斗 +斜了 斜了 +斜对面 斜對面 +斜座标系 斜座標系 +斜曲 斜曲 +斜杠 斜槓 +斜管面 斜管麪 +斜纹布 斜紋布 +斜谷 斜谷 +斜面 斜面 +斤斗 斤斗 +斥卤 斥鹵 +斩尽 斬盡 +斩尽杀绝 斬盡殺絕 +斩获 斬獲 +斫雕为朴 斫雕爲樸 +断不了 斷不了 +断了 斷了 +断仇谷 斷仇谷 +断发 斷髮 +断发文身 斷髮文身 +断后 斷後 +断后路 斷後路 +断头台 斷頭臺 +断弦 斷絃 +断念 斷念 +断根绝种 斷根絕種 +断烟 斷煙 +断种 斷種 +断纸余墨 斷紙余墨 +断钗重合 斷釵重合 +断雨残云 斷雨殘雲 +断面 斷面 +断面图 斷面圖 +斯伯丁杯 斯伯丁盃 +斯克 斯克 +斯克里亚宾 斯克里亞賓 +斯坦贝克 斯坦貝克 +斯干 斯干 +斯当东 斯當東 +斯托 斯托 +斯托肯立石圈 斯托肯立石圈 +斯摩棱斯克 斯摩棱斯克 +斯杯 斯杯 +斯洛伐克 斯洛伐克 +斯洛伐克共和国 斯洛伐克共和國 +斯洛伐克语 斯洛伐克語 +斯瓦希里 斯瓦希里 +斯瓦希里语 斯瓦希里語 +斯瓦特谷地 斯瓦特谷地 +斯科普里 斯科普里 +斯芬克士 斯芬克士 +斯芬克斯 斯芬克斯 +斯诺克 斯諾克 +斯迪里 斯迪里 +斯里 斯里 +斯里兰卡 斯里蘭卡 +斯里兰卡民主社会主义共和国 斯里蘭卡民主社會主義共和國 +斯里兰卡电信 斯里蘭卡電信 +斯里巴加湾港 斯里巴加灣港 +斯里査潘 斯里查潘 +斯雷布雷尼察 斯雷布雷尼察 +斯须 斯須 +新不伦瑞克 新不倫瑞克 +新丰 新豐 +新丰乡 新豐鄉 +新丰县 新豐縣 +新丰酒 新豐酒 +新书看板 新書看板 +新余 新餘 +新余市 新餘市 +新修本草 新修本草 +新党 新黨 +新几內亚 新幾內亞 +新几內亚岛 新幾內亞島 +新几内亚 新幾內亞 +新出 新出 +新出土 新出土 +新出土儿 新出土兒 +新出手儿 新出手兒 +新出来 新出來 +新出炉 新出爐 +新出生 新出生 +新制 新制 +新制度 新制度 +新剧同志会 新劇同志會 +新单曲 新單曲 +新历 新曆 +新历史 新歷史 +新发 新發 +新发明 新發明 +新发村 新發村 +新台 新臺 +新台币 新臺幣 +新叶 新葉 +新喀里多尼亚 新喀里多尼亞 +新城电台 新城電臺 +新娘 新娘 +新娘子 新娘子 +新娘花 新娘花 +新娘车 新娘車 +新娘进了房媒人扔过墙 新娘進了房媒人扔過牆 +新婚不如远别 新婚不如遠別 +新嫁娘 新嫁娘 +新局面 新局面 +新干 新幹 +新干县 新幹縣 +新干线 新幹線 +新庄 新莊 +新庄市 新莊市 +新征 新徵 +新德里 新德里 +新慕道团 新慕道團 +新扎 新紮 +新技术 新技術 +新报台 新報臺 +新斯科舍 新斯科舍 +新曲 新曲 +新板特区 新板特區 +新注音 新注音 +新注音输入法 新注音輸入法 +新潮流系 新潮流系 +新疆回变 新疆回變 +新疆师范大学 新疆師範大學 +新秋 新秋 +新竹师范学院 新竹師範學院 +新系 新系 +新纪录 新紀錄 +新罕布什尔 新罕布什爾 +新罕布什尔州 新罕布什爾州 +新罕布夏 新罕布夏 +新胜利 新勝利 +新艺术 新藝術 +新艺综合体 新藝綜合體 +新芬党 新芬黨 +新药 新藥 +新莺出谷 新鶯出谷 +新规范 新規範 +新闻价值 新聞價值 +新闻出版总署 新聞出版總署 +新闻发布会 新聞發佈會 +新闻发言人 新聞發言人 +新闻台 新聞臺 +新闻周刊 新聞週刊 +新闻杂志 新聞雜誌 +新闻系 新聞系 +新集团 新集團 +新面孔 新面孔 +斲雕为朴 斲雕爲樸 +方便面 方便麪 +方公里 方公里 +方几 方几 +方向 方向 +方向仪 方向儀 +方向性 方向性 +方向感 方向感 +方向灯 方向燈 +方向盘 方向盤 +方向线 方向線 +方向舵 方向舵 +方圆十里 方圓十里 +方岳 方岳 +方彩绫 方彩綾 +方志 方誌 +方志友 方志友 +方志贤 方志賢 +方才 方纔 +方斯蔑如 方斯蔑如 +方方面面 方方面面 +方术 方術 +方济谷派 方濟谷派 +方胜 方勝 +方药 方藥 +方言志 方言志 +方里 方里 +方针 方針 +方面 方面 +方面兼圻 方面兼圻 +方面大耳 方面大耳 +方面官 方面官 +方面官员 方面官員 +於夫罗 於夫羅 +施于 施於 +施仁布德 施仁佈德 +施仁布恩 施仁佈恩 +施仁布泽 施仁佈澤 +施佳升 施佳昇 +施出 施出 +施恩布德 施恩佈德 +施放烟火 施放煙火 +施朱傅粉 施朱傅粉 +施瓦布 施瓦布 +施粥舍饭 施粥捨飯 +施耐庵 施耐庵 +施舍 施捨 +施舍之道 施舍之道 +施药 施藥 +施诺布莉琪 施諾布莉琪 +旁出 旁出 +旁征 旁徵 +旁征博引 旁徵博引 +旁注 旁註 +旁系 旁系 +旁系亲 旁系親 +旁系亲属 旁系親屬 +旁系血亲 旁系血親 +旁观者审当局者迷 旁觀者審當局者迷 +旅历 旅歷 +旅游 旅遊 +旅游业 旅遊業 +旅游书 旅遊書 +旅游事业 旅遊事業 +旅游区 旅遊區 +旅游卡 旅遊卡 +旅游史 旅遊史 +旅游团 旅遊團 +旅游城市 旅遊城市 +旅游客 旅遊客 +旅游局 旅遊局 +旅游局长 旅遊局長 +旅游展 旅遊展 +旅游手冊 旅遊手冊 +旅游景点 旅遊景點 +旅游村 旅遊村 +旅游点 旅遊點 +旅游热点 旅遊熱點 +旅游界 旅遊界 +旅游社 旅遊社 +旅游线 旅遊線 +旅游网 旅遊網 +旅游者 旅遊者 +旅游胜地 旅遊勝地 +旅游集散 旅遊集散 +旅游馆 旅遊館 +旅程表 旅程表 +旅舍 旅舍 +旅行剧团 旅行劇團 +旅行团 旅行團 +旋回 旋迴 +旋干转坤 旋乾轉坤 +旋松 旋鬆 +旋毛虫 旋毛蟲 +旋胡 旋胡 +旋转乾坤 旋轉乾坤 +旋转乾坤之力 旋轉乾坤之力 +旋转台 旋轉臺 +旋转曲面 旋轉曲面 +旋转极 旋轉極 +旋辟 旋辟 +旋里 旋里 +旌别 旌別 +旌善惩恶 旌善懲惡 +旌恤 旌卹 +旌表 旌表 +旍表 旍表 +族党 族黨 +族里 族裏 +旗开得胜 旗開得勝 +旗杆 旗杆 +旗杆上绑鸡毛 旗杆上綁雞毛 +旗鼓相当 旗鼓相當 +旛胜 旛勝 +无一幸免 無一倖免 +无业游民 無業遊民 +无业闲散 無業閒散 +无主尸 無主屍 +无了无休 無了無休 +无云 無雲 +无以复加 無以復加 +无价 無價 +无价之宝 無價之寶 +无价事 無价事 +无价宝 無價寶 +无价珍珠 無價珍珠 +无伴奏合唱 無伴奏合唱 +无余 無餘 +无偏无党 無偏無黨 +无党 無黨 +无党无偏 無黨無偏 +无党无派 無黨無派 +无党派 無黨派 +无党派投票人 無黨派投票人 +无党籍 無黨籍 +无农药 無農藥 +无冤无仇 無冤無仇 +无冬无夏 無冬無夏 +无几 無幾 +无凭无据 無憑無據 +无出 無出 +无出其右 無出其右 +无动于衷 無動於衷 +无助于 無助於 +无千大万 無千大萬 +无千带数 無千帶數 +无千无万 無千無萬 +无厘头 無厘頭 +无取胜希望者 無取勝希望者 +无可救药 無可救藥 +无后 無後 +无后为大 無後爲大 +无回豁 無回豁 +无复孑遗 無復孑遺 +无头愿 無頭願 +无尽 無盡 +无尽无休 無盡無休 +无尽无穷 無盡無窮 +无尽缘起 無盡緣起 +无尽藏 無盡藏 +无尿症 無尿症 +无干 無干 +无序 無序 +无店面 無店面 +无异于 無異於 +无形输出 無形輸出 +无征不信 無徵不信 +无念 無念 +无恶不作 無惡不作 +无愧于 無愧於 +无所不用其极 無所不用其極 +无所牵挂 無所牽掛 +无所适从 無所適從 +无挂无碍 無掛無礙 +无损于 無損於 +无据 無據 +无敌不克 無敵不克 +无期别 無期別 +无机化合物 無機化合物 +无极 無極 +无极县 無極縣 +无核 無核 +无梁 無樑 +无梁斗 無樑斗 +无梁楼盖 無樑樓蓋 +无欲 無慾 +无欲则刚 無欲則剛 +无止尽 無止盡 +无法克制 無法剋制 +无法挽救 無法挽救 +无济于事 無濟於事 +无烟 無煙 +无烟囱工业 無煙囪工業 +无烟火药 無煙火藥 +无烟炭 無煙炭 +无烟焦煤 無煙焦煤 +无烟煤 無煙煤 +无牵无挂 無牽無掛 +无畏于 無畏於 +无畏布施 無畏佈施 +无穷尽 無窮盡 +无穷无尽 無窮無盡 +无精打采 無精打采 +无线电台 無線電臺 +无缘见面 無緣見面 +无药 無藥 +无药可救 無藥可救 +无补于世 無補於世 +无补于事 無補於事 +无补于时 無補於時 +无表情 無表情 +无视于 無視於 +无计向 無計向 +无足挂齿 無足掛齒 +无适无莫 無適無莫 +无针不引线 無針不引線 +无针注射器 無針注射器 +无钩绦虫 無鉤絛蟲 +无限制 無限制 +无面值邮票 無面值郵票 +无面目 無面目 +无须 無須 +既得陇复望蜀 既得隴復望蜀 +既有今日何必当初 既有今日何必當初 +日久弥新 日久彌新 +日出 日出 +日出万言必有一伤 日出萬言必有一傷 +日出三竿 日出三竿 +日出日落 日出日落 +日出而作 日出而作 +日出而作日入而息 日出而作日入而息 +日制 日製 +日升 日升 +日升月恒 日升月恆 +日占 日佔 +日历 日曆 +日历年度 日曆年度 +日历纸 日曆紙 +日历表 日曆表 +日后 日後 +日均价 日均價 +日复一日 日復一日 +日头打西出来 日頭打西出來 +日子里 日子裏 +日干 日干 +日干夜干 日幹夜幹 +日御 日御 +日志 日誌 +日据 日據 +日据时代 日據時代 +日文系 日文系 +日晒 日曬 +日月升恒 日月升恆 +日月参辰 日月參辰 +日月合璧 日月合璧 +日本共产党 日本共產黨 +日本共同社 日本共同社 +日本制 日本製 +日本台 日本臺 +日本团 日本團 +日本国志 日本國誌 +日本社会党 日本社會黨 +日正当中 日正當中 +日比谷公园 日比谷公園 +日游 日遊 +日理万机 日理萬機 +日番谷 日番谷 +日知录 日知錄 +日程表 日程表 +日系 日系 +日行千里 日行千里 +日表 日表 +日试万言 日試萬言 +日语系 日語系 +日趋恶劣 日趨惡劣 +日转千街 日轉千街 +日转千阶 日轉千階 +日进斗金 日進斗金 +日里 日裏 +日锻月炼 日鍛月煉 +日食万钱 日食萬錢 +旧公烟 舊公煙 +旧制 舊制 +旧制度 舊制度 +旧厂 舊廠 +旧历 舊曆 +旧历史 舊歷史 +旧历年 舊曆年 +旧地重游 舊地重遊 +旧庄 舊莊 +旧念复萌 舊念復萌 +旧态复萌 舊態復萌 +旧恨新仇 舊恨新仇 +旧恶 舊惡 +旧游 舊遊 +旧疾复发 舊疾復發 +旧病复发 舊病復發 +旧症 舊症 +旧皇历 舊皇曆 +旧药 舊藥 +旧表 舊錶 +旧钟 舊鐘 +旧钟表 舊鐘錶 +早了 早了 +早于 早於 +早借 早借 +早借早还 早借早還 +早出 早出 +早出晚归 早出晚歸 +早动手早收获 早動手早收穫 +早占勿药 早占勿藥 +早去早回 早去早回 +早参 早參 +早名必折 早名必折 +早日康复 早日康復 +早有计划 早有計劃 +早知今日何必当初 早知今日何必當初 +早知今日悔不当初 早知今日悔不當初 +早秋 早秋 +早自修 早自修 +早起的鸟儿有虫吃 早起的鳥兒有蟲吃 +旭日东升 旭日東昇 +旭日初升 旭日初昇 +旱干 旱乾 +旱烟 旱菸 +旱烟筒 旱菸筒 +旱烟袋 旱菸袋 +时代不同风尚不同 時代不同風尚不同 +时代周刊 時代週刊 +时价 時價 +时刻准备 時刻準備 +时刻表 時刻表 +时后 時後 +时和岁丰 時和歲豐 +时和年丰 時和年豐 +时宪历 時憲曆 +时尚周 時尚週 +时干下 時幹下 +时念 時念 +时报周刊 時報週刊 +时报杂志 時報雜誌 +时症 時症 +时程表 時程表 +时紧时松 時緊時鬆 +时装周 時裝週 +时装表演 時裝表演 +时针 時針 +时钟 時鐘 +时钟座 時鐘座 +时间电价 時間電價 +时间艺术 時間藝術 +时间范围 時間範圍 +时间表 時間表 +时间里 時間裏 +旷世之才 曠世之才 +旷世奇才 曠世奇才 +旷世逸才 曠世逸才 +旷日弥久 曠日彌久 +旷若发蒙 曠若發矇 +旷荡 曠蕩 +旷课记录 曠課記錄 +旸谷 暘谷 +昂纳克 昂納克 +昆仑 崑崙 +昆仑山 崑崙山 +昆仑山脉 崑崙山脈 +昆剧 崑劇 +昆宁佩克 昆寧佩克 +昆山 崑山 +昆布 昆布 +昆曲 崑曲 +昆玉 崑玉 +昆腔 崑腔 +昆苏 崑蘇 +昆虫 昆蟲 +昆虫学 昆蟲學 +昆虫学家 昆蟲學家 +昆虫纲 昆蟲綱 +昆调 崑調 +昆都仑 昆都侖 +昆都仑区 昆都侖區 +昊天不吊 昊天不弔 +昊天罔极 昊天罔極 +昌吉回族自治州 昌吉回族自治州 +明中舍去暗中来 明中捨去暗中來 +明了 明瞭 +明争暗斗 明爭暗鬥 +明于 明於 +明于观人 明於觀人 +明人不做暗事 明人不做暗事 +明人不说暗话 明人不說暗話 +明伙画供 明伙畫供 +明修栈道 明修棧道 +明修栈道暗渡陈仓 明修棧道暗渡陳倉 +明升暗降 明升暗降 +明华园歌剧团 明華園歌劇團 +明发 明發 +明台 明臺 +明后 明後 +明后天 明後天 +明复 明覆 +明夷待访录 明夷待訪錄 +明媚闲雅 明媚閒雅 +明实录 明實錄 +明察暗访 明察暗訪 +明察秋毫 明察秋毫 +明尼苏大学 明尼蘇大學 +明尼苏达 明尼蘇達 +明尼苏达州 明尼蘇達州 +明岗暗哨 明崗暗哨 +明师出高徒 明師出高徒 +明并日月 明並日月 +明弃暗取 明棄暗取 +明当 明當 +明征 明徵 +明志 明志 +明志工专 明志工專 +明志工业 明志工業 +明志工业专科学校 明志工業專科學校 +明扣 明釦 +明据 明據 +明摆 明擺 +明摆着 明擺着 +明斯克 明斯克 +明是一盆火暗是一把刀 明是一盆火暗是一把刀 +明暗 明暗 +明暗不定 明暗不定 +明月当空 明月當空 +明杠 明槓 +明来暗往 明來暗往 +明板 明板 +明枪好躲暗箭难防 明槍好躲暗箭難防 +明枪易趓暗箭难防 明槍易趓暗箭難防 +明枪易躲暗箭难防 明槍易躲暗箭難防 +明枪暗箭 明槍暗箭 +明查暗访 明查暗訪 +明査暗访 明查暗訪 +明欺暗骗 明欺暗騙 +明沟暗渠 明溝暗渠 +明潭抽蓄水力发电工程 明潭抽蓄水力發電工程 +明珠暗投 明珠暗投 +明白了当 明白了當 +明目张胆 明目張膽 +明知就里 明知就裏 +明知山有虎偏向虎山行 明知山有虎偏向虎山行 +明知山有虎故作采樵人 明知山有虎故作採樵人 +明确 明確 +明确性 明確性 +明窗净几 明窗淨几 +明窗彩户 明窗彩戶 +明窗淨几 明窗淨几 +明细表 明細表 +明者视于无形聪者听于无声 明者視於無形聰者聽於無聲 +明范 明範 +明见万里 明見萬里 +明里 明裏 +明鉴 明鑑 +明鉴万里 明鑑萬里 +明鉴秋毫 明鑑秋毫 +明鎗容易躲暗剑最难防 明鎗容易躲暗劍最難防 +明鎗容易躲暗箭最难防 明鎗容易躲暗箭最難防 +明鎗易躲暗箭难逃 明鎗易躲暗箭難逃 +明降暗升 明降暗升 +昏了 昏了 +昏困 昏困 +昏天暗地 昏天暗地 +昏头转向 昏頭轉向 +昏昏暗暗 昏昏暗暗 +昏昏欲睡 昏昏欲睡 +昏暗 昏暗 +昏沈 昏沈 +易于 易於 +易于反掌 易於反掌 +易克制 易剋制 +易卜拉辛 易卜拉辛 +易卜生 易卜生 +易发难收 易發難收 +易学启蒙 易學啓蒙 +易容术 易容術 +易游网 易遊網 +易熔合金 易熔合金 +星云 星雲 +星占学 星占學 +星历 星曆 +星历表 星曆錶 +星回 星迴 +星团 星團 +星巴克 星巴克 +星彩 星彩 +星彩正彩 星彩正彩 +星斗 星斗 +星期几 星期幾 +星期后 星期後 +星术 星術 +星点弹涂 星點彈塗 +星相术 星相術 +星移斗换 星移斗換 +星移斗转 星移斗轉 +星系 星系 +星罗云布 星羅雲佈 +星罗云散 星羅雲散 +星罗棋布 星羅棋佈 +星落云散 星落雲散 +星虫 星蟲 +星表 星表 +星象恶曜 星象惡曜 +星辰表 星辰錶 +星驰电发 星馳電發 +映入眼帘 映入眼簾 +映出 映出 +映照出 映照出 +映照出来 映照出來 +春假里 春假裏 +春兰秋菊 春蘭秋菊 +春华秋实 春華秋實 +春卷 春捲 +春卷皮 春捲皮 +春去秋来 春去秋來 +春台 春臺 +春回大地 春回大地 +春困 春困 +春困秋乏 春困秋乏 +春夏秋冬 春夏秋冬 +春天里 春天裏 +春宵一刻值千金 春宵一刻值千金 +春心荡漾 春心蕩漾 +春日里 春日裏 +春来秋去 春來秋去 +春树暮云 春樹暮雲 +春武里府 春武里府 +春游 春遊 +春生夏长秋收冬藏 春生夏長秋收冬藏 +春生秋杀 春生秋殺 +春祈秋报 春祈秋報 +春秋 春秋 +春秋三传 春秋三傳 +春秋五霸 春秋五霸 +春秋儿 春秋兒 +春秋几何 春秋幾何 +春秋大一统 春秋大一統 +春秋大梦 春秋大夢 +春秋左氏传 春秋左氏傳 +春秋战国 春秋戰國 +春秋战国时代 春秋戰國時代 +春秋日高 春秋日高 +春秋时代 春秋時代 +春秋榜 春秋榜 +春秋笔削 春秋筆削 +春秋笔法 春秋筆法 +春秋繁露 春秋繁露 +春秋配 春秋配 +春秋鼎盛 春秋鼎盛 +春笋怒发 春筍怒發 +春纤 春纖 +春胜 春勝 +春花秋月 春花秋月 +春药 春藥 +春蚓秋蛇 春蚓秋蛇 +春露秋霜 春露秋霜 +春风满面 春風滿面 +春风面 春風面 +春香斗学 春香鬥學 +昧于 昧於 +昧于事理 昧於事理 +昧谷 昧谷 +昨夜里 昨夜裏 +昨天夜里 昨天夜裏 +昭君出塞 昭君出塞 +昭回 昭回 +昭苏 昭蘇 +昭苏县 昭蘇縣 +是个 是個 +是只 是隻 +是念 是念 +是罐子也有两个耳朵 是罐子也有兩個耳朵 +是非只为多开口 是非只爲多開口 +是非善恶 是非善惡 +是非曲直 是非曲直 +是须 是須 +昴宿星团 昴宿星團 +昴星团 昴星團 +昼伏夜出 晝伏夜出 +昼伏夜游 晝伏夜游 +显出 顯出 +显微手术 顯微手術 +显摆 顯擺 +显现出 顯現出 +显现出来 顯現出來 +显着标志 顯着標志 +显示出 顯示出 +显示出来 顯示出來 +显示板 顯示板 +显示表 顯示錶 +显示钟 顯示鐘 +显示钟表 顯示鐘錶 +显著 顯著 +显著标志 顯著標志 +显露出 顯露出 +显露出来 顯露出來 +晃了 晃了 +晃晃荡荡 晃晃蕩蕩 +晃荡 晃盪 +晋升 晉升 +晋升为 晉升爲 +晋阳秋 晉陽秋 +晏几道 晏幾道 +晏子春秋 晏子春秋 +晒伤 曬傷 +晒台 曬臺 +晒图 曬圖 +晒图纸 曬圖紙 +晒干 曬乾 +晒成 曬成 +晒晒 曬曬 +晒烟 曬菸 +晒种 曬種 +晒衣 曬衣 +晒谷 曬穀 +晒谷场 曬穀場 +晒黑 曬黑 +晕台 暈臺 +晕头转向 暈頭轉向 +晕船药 暈船藥 +晕血症 暈血症 +晕车药 暈車藥 +晕针 暈針 +晚于 晚於 +晚参 晚參 +晚娘 晚娘 +晚娘的拳头云里的日头 晚娘的拳頭雲裏的日頭 +晚娘面孔 晚娘面孔 +晚期癌症 晚期癌症 +晚生后学 晚生後學 +晚秋 晚秋 +晚秋作物 晚秋作物 +晚秋时节 晚秋時節 +晚钟 晚鐘 +晚食当肉 晚食當肉 +晞发 晞髮 +晤面 晤面 +晦暗 晦暗 +晦蒙 晦蒙 +晨参暮省 晨參暮省 +晨参暮礼 晨參暮禮 +晨钟 晨鐘 +晨钟暮鼓 晨鐘暮鼓 +普冬冬 普鼕鼕 +普列谢茨克 普列謝茨克 +普列谢茨克卫星发射场 普列謝茨克衛星發射場 +普利艾托 普利艾托 +普勒托利亚 普勒托利亞 +普勒斯威克 普勒斯威克 +普同文化 普同文化 +普天同庆 普天同慶 +普奥同盟 普奧同盟 +普庵咒 普庵咒 +普庵老祖 普庵老祖 +普拉斯尼克 普拉斯尼克 +普拉玛娜苏达 普拉瑪娜蘇達 +普拉齐克 普拉齊克 +普普艺术 普普藝術 +普朗克 普朗克 +普朗克常数 普朗克常數 +普氏立克次体 普氏立克次體 +普罗扎克 普羅扎克 +普莱克斯 普萊克斯 +普里 普里 +普里什蒂纳 普裏什蒂納 +普里切特 普里切特 +普里斯特 普里斯特 +普里斯特莱 普里斯特萊 +普里斯莱 普里斯萊 +普里斯蒂纳 普里斯蒂納 +普里查德 普里查德 +普里霍吉可 普里霍吉可 +普隆克 普隆克 +普雷克斯流程 普雷克斯流程 +景云 景雲 +景从云合 景從雲合 +景从云集 景從雲集 +景星庆云 景星慶雲 +景胄 景胄 +景致 景緻 +景谷 景谷 +景谷县 景谷縣 +晴了 晴了 +晴云秋月 晴雲秋月 +晴时多云 晴時多雲 +晴空万里 晴空萬里 +晴转多云 晴轉多雲 +晴雨表 晴雨表 +晶体三极体 晶體三極體 +晶体三极管 晶體三極管 +晶体二极体 晶體二極體 +晶体二极管 晶體二極管 +晶体振荡 晶體振盪 +晶圆厂 晶圓廠 +晶核 晶核 +晶系 晶系 +晶面 晶面 +智周 智周 +智囊团 智囊團 +智尽能索 智盡能索 +智慧型车辆暨公路系统 智慧型車輛暨公路系統 +智慧板 智慧板 +智术 智術 +智者千虑必有一失 智者千慮必有一失 +晾干 晾乾 +暂于 暫於 +暂借 暫借 +暂别 暫別 +暂升 暫升 +暂并列 暫並列 +暂扣 暫扣 +暂染发慕丝 暫染髮慕絲 +暌合 暌合 +暑修 暑修 +暑修班 暑修班 +暑假里 暑假裏 +暖云兜 暖雲兜 +暖冬 暖冬 +暖厂 暖廠 +暖帘 暖簾 +暖气团 暖氣團 +暖种 暖種 +暖色系 暖色系 +暖荡撩锅 暖盪撩鍋 +暗下去 暗下去 +暗下来 暗下來 +暗中 暗中 +暗中作怪 暗中作怪 +暗中摸索 暗中摸索 +暗中监视 暗中監視 +暗中行事 暗中行事 +暗九 暗九 +暗乱 闇亂 +暗了 暗了 +暗了下来 暗了下來 +暗事 暗事 +暗井 暗井 +暗付 暗付 +暗伤 暗傷 +暗伦 闇倫 +暗光鸟 暗光鳥 +暗公鸟 暗公鳥 +暗冥 闇冥 +暗到 暗到 +暗劣 闇劣 +暗反应 暗反應 +暗叫 暗叫 +暗叫一声 暗叫一聲 +暗号 暗號 +暗号灯 暗號燈 +暗叹 暗歎 +暗吃一惊 暗吃一驚 +暗合 暗合 +暗含 暗含 +暗喜 暗喜 +暗喻 暗喻 +暗器 暗器 +暗地 暗地 +暗地里 暗地裏 +暗场 暗場 +暗堡 暗堡 +暗处 暗處 +暗娼 暗娼 +暗室 暗室 +暗室不欺 暗室不欺 +暗室亏心 暗室虧心 +暗室可欺 暗室可欺 +暗室私心 暗室私心 +暗室逢灯 暗室逢燈 +暗害 暗害 +暗察明访 暗察明訪 +暗射 暗射 +暗射地图 暗射地圖 +暗屋 暗屋 +暗巷 暗巷 +暗底下 暗底下 +暗度陈仓 暗度陳倉 +暗弱 闇弱 +暗影 暗影 +暗得 暗得 +暗忖 暗忖 +暗念 暗念 +暗恋 暗戀 +暗想 暗想 +暗房 暗房 +暗扣 暗釦 +暗指 暗指 +暗探 暗探 +暗操贱业 暗操賤業 +暗斗 暗鬥 +暗无天日 暗無天日 +暗昧 闇昧 +暗暗 暗暗 +暗暗淡淡 暗暗淡淡 +暗杀 暗殺 +暗杀党 暗殺黨 +暗杀案 暗殺案 +暗杠 暗槓 +暗格 暗格 +暗桩 暗樁 +暗楼子 暗樓子 +暗槓 暗槓 +暗沈沈 暗沈沈 +暗沉 暗沉 +暗沟 暗溝 +暗沟里 暗溝裏 +暗河 暗河 +暗泣 暗泣 +暗流 暗流 +暗浅 闇淺 +暗涌 暗湧 +暗淡 暗淡 +暗淡无光 暗淡無光 +暗渠 暗渠 +暗渡陈仓 暗渡陳倉 +暗滩 暗灘 +暗潮 暗潮 +暗潮汹涌 暗潮洶湧 +暗澹 暗澹 +暗火 闇火 +暗灰色 暗灰色 +暗然 闇然 +暗然失色 暗然失色 +暗电流 暗電流 +暗疾 暗疾 +暗的 暗的 +暗盒 暗盒 +暗盘 暗盤 +暗盼 暗盼 +暗码 暗碼 +暗礁 暗礁 +暗示 暗示 +暗移 暗移 +暗笑 暗笑 +暗笑一声 暗笑一聲 +暗算 暗算 +暗管 暗管 +暗箭 暗箭 +暗箭中人 暗箭中人 +暗箭伤人 暗箭傷人 +暗箭明鎗 暗箭明鎗 +暗箭难防 暗箭難防 +暗箱 暗箱 +暗箱操作 暗箱操作 +暗紫色 暗紫色 +暗红 暗紅 +暗红色 暗紅色 +暗线 暗線 +暗线光谱 暗線光譜 +暗练 暗練 +暗结珠胎 暗結珠胎 +暗自 暗自 +暗自流泪 暗自流淚 +暗自神伤 暗自神傷 +暗自窃喜 暗自竊喜 +暗色 暗色 +暗色彩 暗色彩 +暗花儿 暗花兒 +暗莫 闇莫 +暗蓝发 闇藍髮 +暗蔼 暗藹 +暗藏 暗藏 +暗藏春色 暗藏春色 +暗藏玄机 暗藏玄機 +暗藏着 暗藏着 +暗藏鬼胎 暗藏鬼胎 +暗虚 暗虛 +暗行 暗行 +暗袋 暗袋 +暗褐 暗褐 +暗褐色 暗褐色 +暗计 暗計 +暗记 暗記 +暗记儿 暗記兒 +暗记在心 暗記在心 +暗讽 暗諷 +暗访 暗訪 +暗语 暗語 +暗诵 闇誦 +暗跳 闇跳 +暗转 暗轉 +暗边 暗邊 +暗送 暗送 +暗送秋波 暗送秋波 +暗适应 暗適應 +暗通 暗通 +暗通款曲 暗通款曲 +暗道 暗道 +暗部 暗部 +暗里 暗裏 +暗釦 暗釦 +暗锁 暗鎖 +暗门 暗門 +暗门子 暗門子 +暗问 暗問 +暗间儿 暗間兒 +暗顺应 暗順應 +暗香 暗香 +暗香疏影 暗香疏影 +暗骂 暗罵 +暗黑 暗黑 +暗黑王 暗黑王 +暗黝 暗黝 +暮云亲舍 暮雲親舍 +暮云春树 暮雲春樹 +暮烟 暮煙 +暮礼晨参 暮禮晨參 +暮秋 暮秋 +暮雨朝云 暮雨朝雲 +暮鼓晨钟 暮鼓晨鐘 +暴发 暴發 +暴发出来 暴發出來 +暴发户 暴發戶 +暴君焚城录 暴君焚城錄 +暴尸于市 暴屍於市 +暴扣 暴扣 +暴敛横征 暴斂橫徵 +暴晒 暴曬 +暴腌 暴醃 +暴露出 暴露出 +暴露出来 暴露出來 +暴面 暴面 +暴食症 暴食症 +曙后星孤 曙後星孤 +曝光表 曝光表 +曝晒 曝曬 +曝露出 曝露出 +曰云 曰云 +曲从 曲從 +曲体 曲體 +曲别针 曲別針 +曲匝 曲匝 +曲卷 曲捲 +曲台 曲臺 +曲名 曲名 +曲周 曲周 +曲周县 曲周縣 +曲园 曲園 +曲士 曲士 +曲媚取容 曲媚取容 +曲子 曲子 +曲学 曲學 +曲学诐行 曲學詖行 +曲学阿世 曲學阿世 +曲室 曲室 +曲宴 曲宴 +曲射炮 曲射炮 +曲尘 麴塵 +曲尺 曲尺 +曲尺楼梯 曲尺樓梯 +曲尽人情 曲盡人情 +曲尽其妙 曲盡其妙 +曲局 曲局 +曲希瑞 曲希瑞 +曲庇 曲庇 +曲度 曲度 +曲式 曲式 +曲张 曲張 +曲径 曲徑 +曲径通幽 曲徑通幽 +曲律 曲律 +曲心矫肚 曲心矯肚 +曲意 曲意 +曲意俯就 曲意俯就 +曲意奉承 曲意奉承 +曲意逢迎 曲意逢迎 +曲房 曲房 +曲折 曲折 +曲折离奇 曲折離奇 +曲折萦纡 曲折縈紆 +曲拐 曲拐 +曲拗 曲拗 +曲挠 曲撓 +曲曲 曲曲 +曲曲弯弯 曲曲彎彎 +曲曲折折 曲曲折折 +曲本 曲本 +曲松 曲松 +曲松县 曲松縣 +曲柄 曲柄 +曲柄笠 曲柄笠 +曲柄钻 曲柄鑽 +曲栏 曲欄 +曲棍 曲棍 +曲棍球 曲棍球 +曲棍球员 曲棍球員 +曲棍球赛 曲棍球賽 +曲水 曲水 +曲水县 曲水縣 +曲水流觞 曲水流觴 +曲江 曲江 +曲江区 曲江區 +曲江县 曲江縣 +曲江宴 曲江宴 +曲江池 曲江池 +曲池穴 曲池穴 +曲沃 曲沃 +曲沃县 曲沃縣 +曲流 曲流 +曲牌 曲牌 +曲率 曲率 +曲率向量 曲率向量 +曲球 曲球 +曲琼 曲瓊 +曲生 麴生 +曲盖 曲蓋 +曲目 曲目 +曲直 曲直 +曲直分明 曲直分明 +曲礼 曲禮 +曲秀才 麴秀才 +曲突徙薪 曲突徙薪 +曲笔 曲筆 +曲笛 曲笛 +曲线 曲線 +曲线图 曲線圖 +曲线拟合 曲線擬合 +曲线板 曲線板 +曲线美 曲線美 +曲线论 曲線論 +曲线运动 曲線運動 +曲终人散 曲終人散 +曲终奏雅 曲終奏雅 +曲绕 曲繞 +曲肱为枕 曲肱爲枕 +曲肱之乐 曲肱之樂 +曲肱而枕 曲肱而枕 +曲背 曲背 +曲膝礼 曲膝禮 +曲臂 曲臂 +曲致 曲致 +曲艺 曲藝 +曲艾玲 曲艾玲 +曲菌 麴菌 +曲薄 曲薄 +曲蘖 麴櫱 +曲蟮 曲蟮 +曲裾 曲裾 +曲解 曲解 +曲话 曲話 +曲说 曲說 +曲调 曲調 +曲谨 曲謹 +曲谱 曲譜 +曲赦 曲赦 +曲躬躬 曲躬躬 +曲车 麴車 +曲轴 曲軸 +曲辫子 曲辮子 +曲道 曲道 +曲道士 麴道士 +曲道赛 曲道賽 +曲酒 麴酒 +曲里拐弯 曲裏拐彎 +曲钱 麴錢 +曲阜 曲阜 +曲阜县 曲阜縣 +曲阜孔庙 曲阜孔廟 +曲阜市 曲阜市 +曲阳 曲陽 +曲阳县 曲陽縣 +曲阻 曲阻 +曲院 麴院 +曲隐 曲隱 +曲霉 麴黴 +曲霉毒素 麴黴毒素 +曲靖 曲靖 +曲靖地区 曲靖地區 +曲靖市 曲靖市 +曲面 曲面 +曲面论 曲面論 +曲项目 曲項目 +曲颈瓶 曲頸瓶 +曲颈甑 曲頸甑 +曲风 曲風 +曲高和寡 曲高和寡 +曲麻莱 曲麻萊 +曲麻莱县 曲麻萊縣 +曳尾泥涂 曳尾泥塗 +曳尾涂中 曳尾塗中 +更仆难数 更僕難數 +更出 更出 +更加规范 更加規範 +更动表 更動表 +更向 更向 +更复 更復 +更大范围 更大範圍 +更当 更當 +更待干罢 更待干罷 +更愿 更願 +更愿意 更願意 +更甚于 更甚於 +更签 更籤 +更胜一筹 更勝一籌 +更钟 更鐘 +更须 更須 +更鼓敲尽 更鼓敲盡 +曷极 曷極 +曹余章 曹餘章 +曹参 曹參 +曹子里 曹子里 +曹郁芬 曹郁芬 +曼尼托巴省 曼尼托巴省 +曼苏尔 曼蘇爾 +曼苏尔.达杜拉 曼蘇爾.達杜拉 +曼谷 曼谷 +曼谷人 曼谷人 +曼谷包 曼谷包 +曼谷市 曼谷市 +曼谷邮报 曼谷郵報 +曾于 曾於 +曾几何时 曾幾何時 +曾参 曾參 +曾参杀人 曾參殺人 +曾台霖 曾臺霖 +曾孝谷 曾孝谷 +曾志伟 曾志偉 +曾志朗 曾志朗 +曾朴 曾樸 +曾母暗沙 曾母暗沙 +曾砚闲 曾硯閒 +最上面 最上面 +最下面 最下面 +最低价 最低價 +最低谷 最低谷 +最初几天 最初幾天 +最初几年 最初幾年 +最前面 最前面 +最后 最後 +最后一天 最後一天 +最后审判 最後審判 +最后晚餐 最後晚餐 +最后更新 最後更新 +最后期限 最後期限 +最后的审判 最後的審判 +最后的晚餐 最後的晚餐 +最后胜利 最後勝利 +最后通牒 最後通牒 +最后面 最後面 +最大范围 最大範圍 +最小范围 最小範圍 +最近几天 最近幾天 +最近几年 最近幾年 +最适化 最適化 +最适合 最適合 +最里面 最裏面 +最须 最須 +最高当局 最高當局 +會干擾 會干擾 +月中折桂 月中折桂 +月丽于箕 月麗於箕 +月余 月餘 +月光曲 月光曲 +月入数万 月入數萬 +月出 月出 +月历 月曆 +月台 月臺 +月台票 月臺票 +月团 月團 +月地云阶 月地雲階 +月坠花折 月墜花折 +月娘 月娘 +月宫娘娘 月宮娘娘 +月岩 月岩 +月御 月御 +月核 月核 +月桂叶 月桂葉 +月桂树叶 月桂樹葉 +月牙铲 月牙鏟 +月球表面 月球表面 +月相表 月相錶 +月离于毕 月離於畢 +月经规则术 月經規則術 +月色迷蒙 月色迷濛 +月落参横 月落參橫 +月里嫦娥 月裏嫦娥 +月锻季炼 月鍛季煉 +月面 月面 +有一分心尽一分力 有一分心盡一分力 +有个 有個 +有个人 有個人 +有个地洞钻了下去 有個地洞鑽了下去 +有个好歹 有個好歹 +有个屁用 有個屁用 +有个数儿 有個數兒 +有个说儿 有個說兒 +有了 有了 +有了人家 有了人家 +有了存孝不显彦章 有了存孝不顯彥章 +有了胎 有了胎 +有事之无范 有事之無範 +有云 有云 +有仆 有僕 +有仇 有仇 +有仇不报非君子 有仇不報非君子 +有仇必报 有仇必報 +有价 有價 +有价值 有價值 +有价証券 有價証券 +有价证券 有價證券 +有何面目 有何面目 +有余 有餘 +有佛出世 有佛出世 +有准 有準 +有凭有据 有憑有據 +有出入 有出入 +有出好戏 有齣好戲 +有出息 有出息 +有利于 有利於 +有别 有別 +有别于 有別於 +有刮划没是处 有刮劃沒是處 +有力出力 有力出力 +有助于 有助於 +有助于记忆 有助於記憶 +有勾当 有勾當 +有去无回 有去無回 +有发头陀寺 有髮頭陀寺 +有只 有隻 +有同情心 有同情心 +有后 有後 +有周 有周 +有够赞 有夠讚 +有奖征答 有獎徵答 +有女同车 有女同車 +有子万事足 有子萬事足 +有孔虫 有孔蟲 +有宝何必人前夸 有寶何必人前誇 +有害于 有害於 +有尽有让 有儘有讓 +有幸 有幸 +有序 有序 +有当 有當 +有征 有徵 +有征无战 有征無戰 +有志 有志 +有志一同 有志一同 +有志之士 有志之士 +有志于 有志於 +有志气 有志氣 +有志竟成 有志竟成 +有志者事竟成 有志者事竟成 +有志难酬 有志難酬 +有恒街 有恆街 +有意志 有意志 +有意栽花花不发无心插柳柳成阴 有意栽花花不發無心插柳柳成陰 +有感于 有感於 +有感而云 有感而云 +有感而发 有感而發 +有所不同 有所不同 +有才 有才 +有才干 有才幹 +有才无命 有才無命 +有把傢伙 有把傢伙 +有损于 有損於 +有效范围 有效範圍 +有效面积 有效面積 +有晚娘就有晚爷 有晚娘就有晚爺 +有机化合 有機化合 +有机化合物 有機化合物 +有机合成 有機合成 +有板有眼 有板有眼 +有极 有極 +有枝有叶 有枝有葉 +有枝添叶 有枝添葉 +有栖川 有棲川 +有核 有核 +有棱有角 有棱有角 +有求于人 有求於人 +有烟煤 有煙煤 +有益于 有益於 +有福同享 有福同享 +有福同享有祸同当 有福同享有禍同當 +有福同享有难同当 有福同享有難同當 +有秋 有秋 +有种 有種 +有种人 有種人 +有系统 有系統 +有缘千里来相会 有緣千里來相會 +有缘千里来相会无缘对面不相逢 有緣千里來相會無緣對面不相逢 +有联系 有聯繫 +有脸面 有臉面 +有致 有致 +有致癌 有致癌 +有色人种 有色人種 +有节制 有節制 +有苦说不出 有苦說不出 +有药瘾者 有藥癮者 +有被种子植物纲 有被種子植物綱 +有计划 有計劃 +有赖于 有賴於 +有进有出 有進有出 +有采 有采 +有鉴 有鑑 +有鉴于 有鑑於 +有鉴于此 有鑑於此 +有钩绦虫 有鉤絛蟲 +有钱不买半年闲 有錢不買半年閒 +有钱出钱 有錢出錢 +有钱有闲 有錢有閒 +有难同当 有難同當 +有面 有面 +有面儿 有面兒 +朋克 朋克 +朋党 朋黨 +朋党为奸 朋黨爲奸 +朋党之争 朋黨之爭 +朋党比周 朋黨比周 +朋党论 朋黨論 +朋奸 朋奸 +朋比为奸 朋比爲奸 +朋比作仇 朋比作仇 +朋比作奸 朋比作奸 +服了 服了 +服于 服於 +服从于 服從於 +服制 服制 +服务于 服務於 +服务台 服務檯 +服务周到 服務周到 +服务团 服務團 +服务范围 服務範圍 +服务规范 服務規範 +服御 服御 +服毒自尽 服毒自盡 +服用药 服用藥 +服舍 服舍 +服药 服藥 +服药过量 服藥過量 +服装周 服裝週 +服饰周 服飾週 +朔云 朔雲 +朔党 朔黨 +朗朗云天 朗朗雲天 +望乡台 望鄉臺 +望了望 望了望 +望云 望雲 +望云之情 望雲之情 +望出去 望出去 +望后石 望后石 +望向 望向 +望幸 望幸 +望弥撒 望彌撒 +望楼台 望樓臺 +望眼欲穿 望眼欲穿 +望秋先零 望秋先零 +望穿秋水 望穿秋水 +望胄 望胄 +朝东面 朝東面 +朝乾夕惕 朝乾夕惕 +朝云 朝雲 +朝云暮雨 朝雲暮雨 +朝出夕改 朝出夕改 +朝北面 朝北面 +朝升暮合 朝升暮合 +朝南面 朝南面 +朝参暮礼 朝參暮禮 +朝发夕至 朝發夕至 +朝后 朝後 +朝向 朝向 +朝圣团 朝聖團 +朝核 朝核 +朝梁暮晋 朝梁暮晉 +朝梁暮陈 朝梁暮陳 +朝西面 朝西面 +朝野两党 朝野兩黨 +朝钟 朝鐘 +朝钟暮鼓 朝鐘暮鼓 +朝鲜冷面 朝鮮冷麪 +朝鲜劳动党 朝鮮勞動黨 +期货价 期貨價 +朦在鼓里 朦在鼓裏 +朦胧 朦朧 +木偶戏扎 木偶戲紮 +木制 木製 +木制品 木製品 +木厂 木廠 +木叶 木葉 +木垒哈萨克自治县 木壘哈薩克自治縣 +木强则折 木強則折 +木心板 木心板 +木朽不雕 木朽不雕 +木杆 木杆 +木材干馏 木材乾餾 +木杠 木槓 +木板 木板 +木板凳 木板凳 +木板地 木板地 +木板墙 木板牆 +木板大鼓 木板大鼓 +木板牀 木板牀 +木板画 木板畫 +木柜 木櫃 +木梁 木樑 +木芍药 木芍藥 +木薯淀粉 木薯澱粉 +木蜡 木蠟 +木表法 木表法 +木里藏族自治县 木裏藏族自治縣 +木钟 木鐘 +木铲 木鏟 +木雕 木雕 +木雕像 木雕像 +木雕家 木雕家 +木雕师 木雕師 +木雕泥塑 木雕泥塑 +木雕节 木雕節 +未了 未了 +未了公案 未了公案 +未了因 未了因 +未了情 未了情 +未了缘 未了緣 +未几 未幾 +未出 未出 +未出去 未出去 +未出来 未出來 +未出货 未出貨 +未卜 未卜 +未卜先知 未卜先知 +未发货 未發貨 +未可同日而语 未可同日而語 +未嫁新娘 未嫁新娘 +未尝 未嘗 +未尝不可 未嘗不可 +未尽 未盡 +未尽事宜 未盡事宜 +未干 未乾 +未开发国家 未開發國家 +未必尽然 未必盡然 +未扣 未扣 +未折现 未折現 +未易才 未易才 +未知万一 未知萬一 +未确定 未確定 +未竟之志 未竟之志 +未签字者 未簽字者 +未获 未獲 +未获得 未獲得 +未降反升 未降反升 +末了 末了 +末叶 末葉 +末后 末後 +末大必折 末大必折 +末娘 末娘 +末末了 末末了 +末胄 末胄 +末药 末藥 +本价 本價 +本位制 本位制 +本党 本黨 +本厂 本廠 +本古里昂 本古里昂 +本台 本臺 +本台消息 本臺消息 +本同末异 本同末異 +本周 本週 +本周一 本週一 +本周三 本週三 +本周二 本週二 +本周五 本週五 +本周六 本週六 +本周四 本週四 +本回 本回 +本团 本團 +本地管理界面 本地管理界面 +本垒板 本壘板 +本当 本當 +本征 本徵 +本征值 本徵值 +本征向量 本徵向量 +本志 本志 +本愿 本願 +本所同仁 本所同仁 +本报台 本報臺 +本期发生 本期發生 +本期发生额 本期發生額 +本机振荡 本機振盪 +本来面目 本來面目 +本杰明 本傑明 +本杰明富兰克林 本傑明富蘭克林 +本科系 本科系 +本系 本系 本係 +本色当行 本色當行 +本草药学 本草藥學 +本里 本里 +札什伦布寺 札什倫布寺 +札夸威 札夸威 +札板儿 札板兒 +札格拉布 札格拉布 +札格瑞布 札格瑞布 +术业有专攻 術業有專攻 +术前 術前 +术后 術後 +术士 術士 +术德兼修 術德兼修 +术数 術數 +术科 術科 +术艺 術藝 +术语 術語 +术赤 朮赤 +朱一贵 朱一貴 +朱丝栏抄本 朱絲欄抄本 +朱丹 朱丹 +朱丽亚 朱麗亞 +朱丽叶 朱麗葉 +朱书麟 朱書麟 +朱买臣 朱買臣 +朱云折槛 朱雲折檻 +朱云鹏 朱雲鵬 +朱亥 朱亥 +朱仑街 朱崙街 +朱仙镇 朱仙鎮 +朱俊 朱儁 +朱俊彰 朱俊彰 +朱俊晓 朱俊曉 +朱允炆 朱允炆 +朱元璋 朱元璋 +朱元祥 朱元祥 +朱先 朱先 +朱光 朱光 +朱全忠 朱全忠 +朱兴荣 朱興榮 +朱凤芝 朱鳳芝 +朱利亚尼 朱利亞尼 +朱利娅 朱利婭 +朱利安 朱利安 +朱利安尼 朱利安尼 +朱华 朱華 +朱印本 朱印本 +朱卷 硃卷 +朱口皓齿 朱口皓齒 +朱古力 朱古力 +朱古力糖 朱古力糖 +朱古律糖 朱古律糖 +朱咏薇 朱詠薇 +朱哲琴 朱哲琴 +朱唇 朱脣 +朱唇榴齿 朱脣榴齒 +朱唇皓齿 朱脣皓齒 +朱唇粉面 朱脣粉面 +朱培庆 朱培慶 +朱墨 朱墨 +朱墨本 朱墨本 +朱墨烂然 朱墨爛然 +朱士行 朱士行 +朱天文 朱天文 +朱姓 朱姓 +朱婉琪 朱婉琪 +朱子 朱子 +朱子学 朱子學 +朱子家训 朱子家訓 +朱子治家格言 朱子治家格言 +朱子语录 朱子語錄 +朱子语类 朱子語類 +朱孝天 朱孝天 +朱学 朱學 +朱宏瑜 朱宏瑜 +朱宗庆 朱宗慶 +朱实 朱實 +朱家 朱家 +朱家兴 朱家興 +朱家彦 朱家彥 +朱家欣 朱家欣 +朱家鼎 朱家鼎 +朱容基 朱容基 +朱尉铭 朱尉銘 +朱尔典 朱爾典 +朱尔金 朱爾金 +朱尼奥 朱尼奧 +朱巴一 朱巴一 +朱希真 朱希真 +朱干玉戚 朱干玉鏚 +朱广沪 朱廣滬 +朱庆余 朱慶餘 +朱庇特 朱庇特 +朱延平 朱延平 +朱弁 朱弁 +朱弦 朱弦 +朱弦玉磬 朱弦玉磬 +朱德 朱德 +朱执信 朱執信 +朱批 硃批 +朱拉隆功 朱拉隆功 +朱提 朱提 +朱敦儒 朱敦儒 +朱敬一 朱敬一 +朱文 朱文 +朱文庆 朱文慶 +朱明 朱明 +朱智勳 朱智勳 +朱朝亮 朱朝亮 +朱木炎 朱木炎 +朱朱 朱朱 +朱权 朱權 +朱柏庐 朱柏廬 +朱标 朱標 +朱棣 朱棣 +朱槿 朱槿 +朱比特 朱比特 +朱永弘 朱永弘 +朱泽民 朱澤民 +朱洪武 朱洪武 +朱淑真 朱淑真 +朱温 朱溫 +朱漆 朱漆 +朱熹 朱熹 +朱理安历 朱理安曆 +朱理安历史 朱理安歷史 +朱瑞 朱瑞 +朱瑞特兹 朱瑞特茲 +朱瓦碧甍 朱瓦碧甍 +朱甍碧瓦 朱甍碧瓦 +朱由校 朱由校 +朱瞻基 朱瞻基 +朱砂 硃砂 +朱砂痣 硃砂痣 +朱砂符 硃砂符 +朱砂红 硃砂紅 +朱祁钰 朱祁鈺 +朱祁镇 朱祁鎮 +朱祖谋 朱祖謀 +朱穆 朱穆 +朱立伦 朱立倫 +朱笔 硃筆 +朱筠 朱筠 +朱紫 朱紫 +朱紫难别 朱紫難別 +朱红 硃紅 +朱红灯 朱紅燈 +朱红色 硃紅色 +朱经武 朱經武 +朱美 朱美 +朱耷 朱耷 +朱自清 朱自清 +朱舜水 朱舜水 +朱色 硃色 +朱茵 朱茵 +朱莉娅 朱莉婭 +朱蒙 朱蒙 +朱蕉 朱蕉 +朱衣 朱衣 +朱衣吏 朱衣吏 +朱衣点头 朱衣點頭 +朱衣神 朱衣神 +朱记 朱記 +朱诺 朱諾 +朱谕 硃諭 +朱贝尔 朱貝爾 +朱轓皂盖 朱轓皂蓋 +朱轩 朱軒 +朱轮 朱輪 +朱轮华毂 朱輪華轂 +朱迪亚 朱迪亞 +朱邸 朱邸 +朱郁信 朱郁信 +朱铭 朱銘 +朱镕基 朱鎔基 +朱门 朱門 +朱门绣户 朱門繡戶 +朱阁 朱閣 +朱阁青楼 朱閣青樓 +朱阿英 朱阿英 +朱陆异同 朱陸異同 +朱陈 朱陳 +朱陈之好 朱陳之好 +朱雀 朱雀 +朱雀号 朱雀號 +朱雀桥 朱雀橋 +朱顶 朱頂 +朱颜 朱顏 +朱颜粉面 朱顏粉面 +朱颜鹤发 朱顏鶴髮 +朱马亚 朱馬亞 +朱骏声 朱駿聲 +朱高炽 朱高熾 +朱鸟 朱鳥 +朱鹭 朱鷺 +朱鹮 朱䴉 +朱黄 朱黃 +朴世莉 朴世莉 +朴京琳 朴京琳 +朴仔树 朴仔樹 +朴修斯 樸修斯 +朴克牌 樸克牌 +朴凤柱 朴鳳柱 +朴刀 朴刀 +朴厚 樸厚 +朴吉渊 朴吉淵 +朴周永 朴周永 +朴子 朴子 +朴子市 朴子市 +朴子溪 朴子溪 +朴学 樸學 +朴实 樸實 +朴实作风 樸實作風 +朴实无华 樸實無華 +朴宣英 朴宣英 +朴志胤 朴志胤 +朴忠 朴忠 +朴念仁 樸念仁 +朴恩惠 朴恩惠 +朴拙 樸拙 +朴新阳 朴新陽 +朴智星 朴智星 +朴树 朴樹 +朴槿惠 朴槿惠 +朴樕 樸樕 +朴次茅斯 樸次茅斯 +朴正恩 朴正恩 +朴正熙 朴正熙 +朴正祥 朴正祥 +朴永训 朴永訓 +朴泰桓 朴泰桓 +朴父 朴父 +朴璐美 朴璐美 +朴直 樸直 +朴真熙 朴真熙 +朴硝 朴硝 +朴素 樸素 +朴素无华 樸素無華 +朴茂 朴茂 +朴茨茅斯 朴茨茅斯 +朴茨茅斯队 朴茨茅斯隊 +朴讷 樸訥 +朴讷诚笃 樸訥誠篤 +朴诗妍 朴詩妍 +朴质 樸質 +朴质无华 樸質無華 +朴资茅斯 朴資茅斯 +朴资茅斯条约 朴資茅斯條約 +朴赞浩 朴贊浩 +朴鄙 樸鄙 +朴重 樸重 +朴野 樸野 +朴野无文 樸野無文 +朴钝 樸鈍 +朴陋 樸陋 +朴马 樸馬 +朴鲁 樸魯 +朵云 朵雲 +机修厂 機修廠 +机关团体 機關團體 +机关布景 機關佈景 +机关用尽 機關用盡 +机制 機制 機製 +机发 機發 +机台 機臺 +机器压制 機器壓製 +机壳厂 機殼廠 +机板 機板 +机柜 機櫃 +机械学系 機械學系 +机械系 機械系 +机械表 機械錶 +机械钟 機械鐘 +机械钟表 機械鐘錶 +机种 機種 +机绣 機繡 +机缘巧合 機緣巧合 +机辟 機辟 +朽木不雕 朽木不雕 +朽木之才 朽木之才 +朽木虫 朽木蟲 +朽棘不雕 朽棘不雕 +杀人须见血救人须救彻 殺人須見血救人須救徹 +杀价 殺價 +杀出 殺出 +杀出去 殺出去 +杀出来 殺出來 +杀出重围 殺出重圍 +杀千刀 殺千刀 +杀千刀的 殺千刀的 +杀才 殺才 +杀敌致果 殺敵致果 +杀虫 殺蟲 +杀虫剂 殺蟲劑 +杀虫器 殺蟲器 +杀虫药 殺蟲藥 +杀蠹药 殺蠹藥 +杀身出生 殺身出生 +杂交种 雜交種 +杂交育种 雜交育種 +杂合菜 雜合菜 +杂合面儿 雜合麪兒 +杂和面 雜和麪 +杂和面儿 雜和麪兒 +杂婚制 雜婚制 +杂当 雜當 +杂录 雜錄 +杂志 雜誌 +杂志奖 雜誌獎 +杂志社 雜誌社 +杂志纸 雜誌紙 +杂念 雜念 +杂技团 雜技團 +杂技表演 雜技表演 +杂板令 雜板令 +杂症 雜症 +杂种 雜種 +杂种人 雜種人 +杂种优势 雜種優勢 +杂种后代 雜種後代 +杂种狗 雜種狗 +杂谷脑 雜谷腦 +杂谷脑镇 雜谷腦鎮 +杂酱面 雜醬麪 +杂面 雜麪 +权利请愿书 權利請願書 +权制 權制 +权力斗争 權力鬥爭 +权力欲 權力慾 +权变锋出 權變鋒出 +权幸 權幸 +权术 權術 +权欲熏心 權慾薰心 +权能划分 權能劃分 +杆上 杆上 +杆儿 杆兒 桿兒 +杆刀 桿刀 +杆塔 杆塔 +杆子 杆子 桿子 +杆状 桿狀 +杆直 桿直 +杆秤 桿秤 +杆茵 桿茵 +杆菌 桿菌 +杆菌性 桿菌性 +杆菌类 桿菌類 +杆菌素 桿菌素 +杈杆儿 杈桿兒 +李万进 李萬進 +李三娘 李三娘 +李丰永 李豐永 +李云光 李雲光 +李云娜 李雲娜 +李代桃僵 李代桃僵 +李修贤 李修賢 +李克强 李克強 +李克昂 李克昂 +李克齐 李克齊 +李公朴 李公樸 +李准基 李準基 +李千娜 李千娜 +李卜克內西 李卜克內西 +李卜克内西 李卜克內西 +李叔同 李叔同 +李后主 李後主 +李咸阳 李咸陽 +李国修 李國修 +李圣杰 李聖傑 +李复兴 李復興 +李复甸 李復甸 +李大同 李大同 +李安修 李安修 +李家同 李家同 +李布瑞斯库 李布瑞斯庫 +李干龙 李乾龍 +李开复 李開復 +李志勳 李志勳 +李志宏 李志宏 +李志强 李志強 +李念 李念 +李斯特氏杆菌 李斯特氏桿菌 +李杰 李傑 +李洪志 李洪志 +李炳千 李炳千 +李百药 李百藥 +李盟干 李盟乾 +李秋静 李秋靜 +李胜琛 李勝琛 +李连杰 李連杰 +李連杰 李連杰 +李郭同舟 李郭同舟 +李鉴原 李鑑原 +李钟奭 李鐘奭 +李钟郁 李鍾郁 +李链福 李鍊福 +李锺郁 李鍾郁 +杏坛 杏壇 +杏干儿 杏乾兒 +杏核 杏核 +杏雨梨云 杏雨梨雲 +材干 材幹 +材料系 材料系 +材疏志大 材疏志大 +材种 材種 +材积表 材積表 +村子里 村子裏 +村干事 村幹事 +村庄 村莊 +村胄 村胄 +村舍 村舍 +村里 村裏 +村里长 村裏長 +杜丽娘 杜麗娘 +杜克 杜克 +杜寅杰 杜寅傑 +杜尔伯特蒙古族自治县 杜爾伯特蒙古族自治縣 +杜尚别 杜尚別 +杜尼克 杜尼克 +杜布林斯基 杜布林斯基 +杜布罗夫尼克 杜布羅夫尼克 +杜斯特布拉吉 杜斯特布拉吉 +杜杰利 杜傑利 +杜杰尔 杜傑爾 +杜松子酒 杜松子酒 +杜正胜 杜正勝 +杜秋娘 杜秋娘 +杜秋娘歌 杜秋娘歌 +杜绝后患 杜絕後患 +杜老志道 杜老誌道 +杜门不出 杜門不出 +杜雅里克 杜雅里克 +杞宋无征 杞宋無徵 +杞梁 杞梁 +杞梁妻 杞梁妻 +束修 束脩 +束发 束髮 +束发封帛 束髮封帛 +束发金冠 束髮金冠 +束矢难折 束矢難折 +束身修行 束身修行 +束身自修 束身自修 +杠上 槓上 +杠头 槓頭 +杠子 槓子 +杠杆 槓桿 +杠杆收购 槓桿收購 +杠杠 槓槓 +杠牌 槓牌 +杠着 槓着 +杠起 槓起 +杠铃 槓鈴 +杠龟 槓龜 +条几 條几 +条干 條幹 +条据 條據 +条板箱 條板箱 +条纹布 條紋布 +来个 來個 +来了 來了 +来于 來於 +来千去万 來千去萬 +来历 來歷 +来历不明 來歷不明 +来发 來發 +来台 來臺 +来台访问 來臺訪問 +来叶 來葉 +来回 來回 +来回来去 來回來去 +来回来去地 來回來去地 +来回的话 來回的話 +来回票 來回票 +来复 來複 +来复日 來復日 +来复枪 來復槍 +来复线 來復線 +来宾致词 來賓致詞 +来念 來唸 +来来回回 來來回回 +来杯 來杯 +来自于 來自於 +来苏 來蘇 +来苏水 來蘇水 +来苏糖 來蘇糖 +杨万发 楊萬發 +杨万里 楊萬里 +杨云龙 楊雲龍 +杨俊胜 楊俊勝 +杨修 楊修 +杨凌示范区 楊淩示範區 +杨千霈 楊千霈 +杨叶窜儿 楊葉竄兒 +杨士梁 楊士樑 +杨宏志 楊宏志 +杨志卖刀 楊志賣刀 +杨文志 楊文誌 +杨日松 楊日松 +杨朱 楊朱 +杨松 楊松 +杨松弦 楊松弦 +杨氏系数 楊氏係數 +杨秋兴 楊秋興 +杨胜帆 楊勝帆 +杨胜旭 楊勝旭 +杨致远 楊致遠 +杨苏棣 楊甦棣 +杨采妮 楊采妮 +杨雅筑 楊雅筑 +杪秋 杪秋 +杭丁顿舞蹈症 杭丁頓舞蹈症 +杭州师范学院 杭州師範學院 +杭州萝卜绍兴种 杭州蘿蔔紹興種 +杭锦后旗 杭錦後旗 +杯上 杯上 +杯中 杯中 +杯中之物 杯中之物 +杯中物 杯中物 +杯了 杯了 +杯具 杯具 +杯内 杯內 +杯前 杯前 +杯口 杯口 +杯台 杯臺 +杯后 杯後 +杯和 杯和 +杯垫 杯墊 +杯壁 杯壁 +杯套 杯套 +杯子 杯子 +杯布 杯佈 +杯干 杯乾 +杯底 杯底 +杯底不可饲金鱼 杯底不可飼金魚 +杯座 杯座 +杯弓蛇影 杯弓蛇影 +杯换 杯換 +杯是 杯是 +杯杯 杯杯 +杯水 杯水 +杯水之谢 杯水之謝 +杯水粒粟 杯水粒粟 +杯水车薪 杯水車薪 +杯沿 杯沿 +杯状 杯狀 +杯白干 杯白乾 +杯的 杯的 +杯盏 杯盞 +杯盖 杯蓋 +杯盘 杯盤 +杯盘狼藉 杯盤狼藉 +杯盘舞 杯盤舞 +杯碟 杯碟 +杯突 杯突 +杯羹 杯羹 +杯茶 杯茶 +杯葛 杯葛 +杯葛运动 杯葛運動 +杯蛇鬼车 杯蛇鬼車 +杯装 杯裝 +杯觥交错 杯觥交錯 +杯赛 盃賽 +杯身 杯身 +杯酒 杯酒 +杯酒戈矛 杯酒戈矛 +杯酒解怨 杯酒解怨 +杯酒言欢 杯酒言歡 +杯酒释兵权 杯酒釋兵權 +杯里 杯裏 +杯面 杯麪 +杰乐米 傑樂米 +杰伊汉港 傑伊漢港 +杰伦 杰倫 +杰佛兹 傑佛茲 +杰佛利 傑佛利 +杰佛士 傑佛士 +杰佛森 傑佛森 +杰佛瑞 傑佛瑞 +杰佛逊 傑佛遜 +杰作 傑作 +杰克 傑克 +杰克伦敦 傑克倫敦 +杰克尼克逊 傑克尼克遜 +杰克德米 傑克德米 +杰克森 傑克森 +杰克盖伦海 傑克蓋倫海 +杰克葛伦霍 傑克葛倫霍 +杰克逊 傑克遜 +杰出 傑出 +杰利 傑利 +杰卡伯 傑卡伯 +杰哈德巴特勒 傑哈德巴特勒 +杰哈德巴狄厄 傑哈德巴狄厄 +杰士派 傑士派 +杰夫 傑夫 +杰奎琳 傑奎琳 +杰奎琳肯尼迪 傑奎琳肯尼迪 +杰尔 傑爾 +杰尔村 傑爾村 +杰尼斯 傑尼斯 +杰弗逊 傑弗遜 +杰弗里乔叟 傑弗里喬叟 +杰拉 傑拉 +杰拉尔德 傑拉爾德 +杰拉德 傑拉德 +杰斯 傑斯 +杰杰 傑傑 +杰森 傑森 +杰森包恩 傑森包恩 +杰森史塔森 傑森史塔森 +杰特 杰特 +杰瑞 傑瑞 +杰福斯 傑福斯 +杰福瑞 傑福瑞 +杰米 傑米 +杰米森 傑米森 +杰米福克斯 傑米福克斯 +杰西 傑西 +杰西卡 傑西卡 +杰西卡艾尔芭 傑西卡艾爾芭 +杰西詹姆斯 傑西詹姆斯 +杰迪卓 傑迪卓 +杰里森 傑里森 +杰里科 傑里科 +杰里米 傑里米 +東涌 東涌 +杳无人烟 杳無人煙 +松一下 鬆一下 +松一些 鬆一些 +松一口气 鬆一口氣 +松一松 鬆一鬆 +松下 松下 +松下一口 鬆下一口 +松下了 鬆下了 +松下公司 松下公司 +松下来 鬆下來 +松下电器 松下電器 +松下电机 松下電機 +松下电气工业 松下電氣工業 +松不开 鬆不開 +松不松 鬆不鬆 +松不紧 鬆不緊 +松丘 松丘 +松乔 松喬 +松乔之寿 松喬之壽 +松了 鬆了 +松了一口气 鬆了一口氣 +松了松 鬆了鬆 +松井秀 松井秀 +松井秀喜 松井秀喜 +松些 鬆些 +松仁 松仁 +松元音 鬆元音 +松冈 松岡 +松冈利胜 松岡利勝 +松出一 鬆出一 +松出口 鬆出口 +松动 鬆動 +松劲 鬆勁 +松化石 松化石 +松北 松北 +松北区 松北區 +松原 松原 +松原市 松原市 +松口 鬆口 +松口气 鬆口氣 +松口蘑 松口蘑 +松叶 松葉 +松叶牡丹 松葉牡丹 +松叶蕨 松葉蕨 +松喉 鬆喉 +松土 鬆土 +松土机 鬆土機 +松坎 松坎 +松坝 松壩 +松垮 鬆垮 +松大辅 松大輔 +松子 松子 +松宽 鬆寬 +松尾芭蕉 松尾芭蕉 +松山 松山 +松山区 松山區 +松山庄 松山莊 +松山机场 松山機場 +松岭 松嶺 +松岭区 松嶺區 +松巴哇 松巴哇 +松巴哇岛 松巴哇島 +松开 鬆開 +松弛 鬆弛 +松弛下来 鬆弛下來 +松弛到 鬆弛到 +松弛剂 鬆弛劑 +松弛法 鬆弛法 +松得多 鬆得多 +松快 鬆快 +松懈 鬆懈 +松懈下 鬆懈下 +松懈下来 鬆懈下來 +松手 鬆手 +松扣 鬆釦 +松指部 松指部 +松掉 鬆掉 +松放 鬆放 +松散 鬆散 +松散物料 鬆散物料 +松明 松明 +松智路 松智路 +松木 松木 +松本 松本 +松本仞 松本仞 +松本润 松本潤 +松本秀树 松本秀樹 +松材线虫 松材線蟲 +松松 鬆鬆 +松松垮垮 鬆鬆垮垮 +松松散散 鬆鬆散散 +松松脆脆 鬆鬆脆脆 +松松软软 鬆鬆軟軟 +松林 松林 +松果 松果 +松果体 松果體 +松果腺 松果腺 +松枝 松枝 +松柏 松柏 +松柏之坚 松柏之堅 +松柏之寿 松柏之壽 +松柏之茂 松柏之茂 +松柏后凋 松柏後凋 +松柏园 松柏園 +松柏节操 松柏節操 +松柏长青 松柏長青 +松柏长青茶 松柏長青茶 +松柔 鬆柔 +松树 松樹 +松桃 松桃 +松桃县 松桃縣 +松桃苗族自治县 松桃苗族自治縣 +松毛 松毛 +松毛松翼 鬆毛鬆翼 +松毛虫 松毛蟲 +松毬 松毬 +松气 鬆氣 +松江 松江 +松江区 松江區 +松江省 松江省 +松江路 松江路 +松河 松河 +松油 松油 +松油管 鬆油管 +松油门 鬆油門 +松浦 松浦 +松浦亚 松浦亞 +松浮 鬆浮 +松涛 松濤 +松溪 松溪 +松溪县 松溪縣 +松滋 松滋 +松滋市 松滋市 +松漠 松漠 +松潘 松潘 +松潘县 松潘縣 +松烟 松煙 +松烟墨 松煙墨 +松焦油 松焦油 +松煤 松煤 +松狮 鬆獅 +松球 松球 +松球鱼 松球魚 +松瓤 松瓤 +松田 松田 +松田圣子 松田聖子 +松皮癣 松皮癬 +松石 松石 +松科 松科 +松竹 松竹 +松竹梅 松竹梅 +松竹路 松竹路 +松筠之操 松筠之操 +松筠之节 松筠之節 +松篁交翠 松篁交翠 +松类 松類 +松糕 鬆糕 +松紧 鬆緊 +松紧带 鬆緊帶 +松纹 松紋 +松绑 鬆綁 +松缓 鬆緩 +松胶 松膠 +松脂 松脂 +松脂石 松脂石 +松脆 鬆脆 +松脆饼 鬆脆餅 +松脱 鬆脫 +松节油 松節油 +松节油精 松節油精 +松花 松花 +松花江 松花江 +松花江平原 松花江平原 +松花砚 松花硯 +松花纸 松花紙 +松花蛋 松花蛋 +松花饼 松花餅 +松茸 松茸 +松菌 松菌 +松萝 松蘿 +松萝共倚 松蘿共倚 +松蕈 松蕈 +松蕊 松蕊 +松藻虫 松藻蟲 +松蘑 松蘑 +松蛋 鬆蛋 +松蛋包 鬆蛋包 +松解 鬆解 +松赞干布 松贊干布 +松赞干布陵 松贊干布陵 +松起 鬆起 +松起来 鬆起來 +松软 鬆軟 +松软适口 鬆軟適口 +松辽平原 松遼平原 +松通 鬆通 +松针 松針 +松阳 松陽 +松阳县 松陽縣 +松隆子 松隆子 +松雪泰子 松雪泰子 +松露 松露 +松露猪 松露豬 +松青 松青 +松风 松風 +松风水月 松風水月 +松风流 松風流 +松饼 鬆餅 +松香 松香 +松香水 松香水 +松香油 松香油 +松高路 松高路 +松鱼 松魚 +松鸡 松雞 +松鸦 松鴉 +松鹤 松鶴 +松鹤延年 松鶴延年 +松鹤遐龄 松鶴遐齡 +松鼠 松鼠 +松鼠猴 松鼠猴 +板上钉钉 板上釘釘 +板书 板書 +板儿 板兒 +板凳 板凳 +板凳区 板凳區 +板刷 板刷 +板块 板塊 +板块构造 板塊構造 +板块理论 板塊理論 +板壁 板壁 +板子 板子 +板岩 板岩 +板式 板式 +板式塔 板式塔 +板房 板房 +板擦 板擦 +板擦儿 板擦兒 +板斧 板斧 +板本 板本 +板机 板機 +板材 板材 +板条 板條 +板条箱 板條箱 +板板 闆闆 +板板六十四 板板六十四 +板极 板極 +板栗 板栗 +板桥 板橋 +板桥中学 板橋中學 +板桥国中 板橋國中 +板桥国小 板橋國小 +板桥市 板橋市 +板桩 板樁 +板梁桥 板梁橋 +板油 板油 +板滞 板滯 +板烟 板煙 +板牙 板牙 +板状 板狀 +板球 板球 +板画 板畫 +板皮 板皮 +板眼 板眼 +板着脸 板着臉 +板纸 板紙 +板结 板結 +板羽球 板羽球 +板胡 板胡 +板脸 板臉 +板荡 板蕩 +板蓝根 板藍根 +板规 板規 +板起 板起 +板起面孔 板起面孔 +板车 板車 +板金 板金 +板金工 板金工 +板门店 板門店 +板门店停战村 板門店停戰村 +板鸭 板鴨 +板鼓 板鼓 +极不 極不 +极为庞大 極爲龐大 +极乐 極樂 +极乐世界 極樂世界 +极乐舞 極樂舞 +极乐鸟 極樂鳥 +极了 極了 +极低 極低 +极低频辐射 極低頻輻射 +极佳 極佳 +极便当 極便當 +极值 極值 +极光 極光 +极其 極其 +极具 極具 +极冠 極冠 +极切瞻韩 極切瞻韓 +极刑 極刑 +极力 極力 +极力争取 極力爭取 +极化 極化 +极口 極口 +极右 極右 +极右份子 極右份子 +极右派 極右派 +极右翼 極右翼 +极品 極品 +极圈 極圈 +极地 極地 +极地年 極地年 +极地气候 極地氣候 +极地狐 極地狐 +极坐标 極座標 +极坐标系 極座標系 +极处 極處 +极大 極大 +极大值 極大值 +极大期 極大期 +极头麻化 極頭麻化 +极好 極好 +极婺联辉 極婺聯輝 +极富 極富 +极小 極小 +极小值 極小值 +极少 極少 +极少数 極少數 +极尽 極盡 +极左 極左 +极左份子 極左份子 +极左派 極左派 +极带 極帶 +极带地区 極帶地區 +极度 極度 +极微 極微 +极性 極性 +极性键 極性鍵 +极恶 極惡 +极愿 極願 +极早 極早 +极有可能 極有可能 +极权 極權 +极权主义 極權主義 +极权国家 極權國家 +极权政治 極權政治 +极板 極板 +极核 極核 +极深研几 極深研幾 +极点 極點 +极爲 極爲 +极盛 極盛 +极盛时期 極盛時期 +极目 極目 +极目望去 極目望去 +极目远望 極目遠望 +极目远眺 極目遠眺 +极短篇 極短篇 +极移 極移 +极端 極端 +极端主义 極端主義 +极端份子 極端份子 +极端派 極端派 +极细小 極細小 +极至 極至 +极致 極致 +极色 極色 +极表同情 極表同情 +极轴 極軸 +极选 極選 +极量 極量 +极锋 極鋒 +极间电容 極間電容 +极限 極限 +极限体育 極限體育 +极限值 極限值 +极限强度 極限強度 +极高 極高 +极高点 極高點 +构筑 構築 +构筑工事 構築工事 +构筑物 構築物 +析出 析出 +析毫剖厘 析毫剖釐 +枕借 枕藉 +枕岩漱流 枕巖漱流 +枕席 枕蓆 +枕戈尝胆 枕戈嘗膽 +枕状玄武岩 枕狀玄武岩 +林下风致 林下風致 +林下风范 林下風範 +林丰正 林豐正 +林义杰 林義傑 +林云 林雲 +林云阁 林雲閣 +林俊杰 林俊杰 +林克 林克 +林克平大学 林克平大學 +林克海德 林克海德 +林克谟 林克謨 +林克谦 林克謙 +林冲 林沖 +林冲夜奔 林沖夜奔 +林占梅 林占梅 +林口台地 林口臺地 +林合隆 林合隆 +林周 林周 +林周县 林周縣 +林国梁 林國樑 +林宏岳 林宏嶽 +林布兰 林布蘭 +林干闵 林乾閔 +林德布拉德 林德布拉德 +林志嘉 林志嘉 +林志坚 林志堅 +林志声 林志聲 +林志杰 林志傑 +林志炫 林志炫 +林志玲 林志玲 +林志翔 林志翔 +林志辉 林志輝 +林志隆 林志隆 +林志雄 林志雄 +林志颖 林志穎 +林恢复 林恢復 +林承志 林承志 +林振丰 林振豐 +林敬杰 林敬傑 +林智胜 林智勝 +林木参天 林木參天 +林杰梁 林杰樑 +林杰闵 林傑閔 +林松 林松 +林松焕 林松煥 +林正杰 林正杰 +林永发 林永發 +林秀合 林秀合 +林秋 林秋 +林秋桂 林秋桂 +林群志 林羣志 +林致光 林致光 +林芳郁 林芳郁 +林英杰 林英傑 +林荣松 林榮松 +林表 林表 +林谷桦 林谷樺 +林谷芳 林谷芳 +林郁方 林郁方 +林钟 林鐘 +林靖杰 林靖傑 +林颖穗 林穎穗 +林默娘 林默娘 +枚卜 枚卜 +果于 果於 +果子干 果子乾 +果子干儿 果子乾兒 +果子药 果子藥 +果干 果乾 +果杯 果杯 +果松 果松 +果核 果核 +果穗 果穗 +枝不得大于干 枝不得大於榦 +枝叶 枝葉 +枝叶扶疏 枝葉扶疏 +枝叶茂盛 枝葉茂盛 +枝干 枝幹 +枝干断折 枝幹斷折 +枝繁叶茂 枝繁葉茂 +枝胄 枝胄 +枝针 枝針 +枣庄 棗莊 +枣核 棗核 +枪打出头鸟 槍打出頭鳥 +枪托 槍托 +枪术 槍術 +枪杆 槍桿 +枪杆儿 槍桿兒 +枪杆子 槍桿子 +枪枝弹药 槍枝彈藥 +枪械弹药 槍械彈藥 +枫之谷 楓之谷 +枫叶 楓葉 +枯叶 枯葉 +枯叶蝶 枯葉蝶 +枯干 枯乾 +枯草杆菌 枯草桿菌 +架个 架個 +架了 架了 +架出 架出 +架出去 架出去 +架出来 架出來 +架回 架回 +架回去 架回去 +架回来 架回來 +架梁 架樑 +架海金梁 架海金梁 +架钟 架鐘 +枷板 枷板 +柏克 柏克 +柏克曼温度计 柏克曼溫度計 +柏克莱 柏克萊 +柏克郡 柏克郡 +柏克里克千佛洞 柏克里克千佛洞 +柏南克 柏南克 +柏卡里 柏卡里 +柏台 柏臺 +柏台乌府 柏臺烏府 +柏戴克 柏戴克 +柏林剧团 柏林劇團 +柏梁体 柏梁體 +柏梁台 柏梁臺 +柏梁诗 柏梁詩 +柏纳马修兹 柏納馬修茲 +柏罗米修斯 柏羅米修斯 +柏节松操 柏節松操 +柏里斯 柏里斯 +某个 某個 +某个人 某個人 +某只 某隻 +某方面 某方面 +某种 某種 +某种人 某種人 +某舍 某舍 +某面 某面 +染发 染髮 +染发剂 染髮劑 +染布 染布 +染干 染干 +染指于 染指於 +染指于鼎 染指於鼎 +染殿后 染殿後 +染织厂 染織廠 +柔克 柔克 +柔情万千 柔情萬千 +柔情万种 柔情萬種 +柔术 柔術 +柔枝嫩叶 柔枝嫩葉 +柔能克刚 柔能克剛 +柔能制刚 柔能制剛 +柜上 櫃上 +柜买中心 櫃買中心 +柜位 櫃位 +柜台 櫃檯 +柜台委讬 櫃檯委託 +柜员机 櫃員機 +柜坊赌局 櫃坊賭局 +柜子 櫃子 +柜房 櫃房 +柜柳 柜柳 +柜橱 櫃櫥 +柜身子 櫃身子 +柜里 櫃裏 +柜面儿 櫃面兒 +查克拉 查克拉 +查克瑞 查克瑞 +查准率 查準率 +查出 查出 +查干 查干 +查干湖 查干湖 +查扣 查扣 +查核 查覈 +查获 查獲 +柬埔寨人民党 柬埔寨人民黨 +柯克 柯克 +柯克斯 柯克斯 +柯尔克孜 柯爾克孜 +柯尔克孜族 柯爾克孜族 +柯尔克孜语 柯爾克孜語 +柯普里亚诺夫 柯普里亞諾夫 +柯札克 柯札克 +柯里 柯里 +柱梁 柱樑 +柳升耀 柳昇耀 +柳叶 柳葉 +柳叶儿 柳葉兒 +柳叶刀 柳葉刀 +柳叶描 柳葉描 +柳叶眉 柳葉眉 +柳叶鱼 柳葉魚 +柳斌杰 柳斌杰 +柳暗花明 柳暗花明 +柳暗花明又一村 柳暗花明又一村 +柳烟花雾 柳煙花霧 +柳诒征 柳詒徵 +柴埼幸 柴埼幸 +柴油发动机 柴油發動機 +柴胡 柴胡 +査不出 查不出 +査价 查價 +査修 查修 +査克拉 查克拉 +査兑克 查兌克 +査出 查出 +査出来 查出來 +査卷 查卷 +査号台 查號臺 +査回 查回 +査回去 查回去 +査回来 查回來 +査找周期 查找週期 +査报表 查報表 +査无实据 查無實據 +査获 查獲 +査表 查表 +査询台 查詢檯 +査问出 查問出 +栅极 柵極 +标价 標價 +标准 標準 +标准值 標準值 +标准偏差 標準偏差 +标准像 標準像 +标准元音 標準元音 +标准公顷 標準公頃 +标准制 標準制 +标准动作 標準動作 +标准化 標準化 +标准单位 標準單位 +标准号码 標準號碼 +标准型 標準型 +标准大气 標準大氣 +标准字体 標準字體 +标准尺寸 標準尺寸 +标准局 標準局 +标准工资 標準工資 +标准差 標準差 +标准接口 標準接口 +标准时 標準時 +标准时区 標準時區 +标准时间 標準時間 +标准普尔 標準普爾 +标准木 標準木 +标准杆 標準桿 +标准模型 標準模型 +标准气压 標準氣壓 +标准溶液 標準溶液 +标准版 標準版 +标准状况 標準狀況 +标准状态 標準狀態 +标准电阻 標準電阻 +标准组 標準組 +标准组织 標準組織 +标准细分表 標準細分表 +标准舞 標準舞 +标准规 標準規 +标准规格 標準規格 +标准规范 標準規範 +标准语 標準語 +标准镜头 標準鏡頭 +标准间 標準間 +标准音 標準音 +标准题名 標準題名 +标出 標出 +标出去 標出去 +标出来 標出來 +标占 標占 +标同伐异 標同伐異 +标志 標誌 +标志性 標誌性 +标志着 標誌着 +标本同治 標本同治 +标本虫 標本蟲 +标杆 標杆 +标标致致 標標致致 +标注 標註 +标示出 標示出 +标签 標籤 +标致 標緻 +标表 標表 +标记识别 標記識別 +栈板 棧板 +栉发工 櫛髮工 +栋折榱崩 棟折榱崩 +栋梁 棟樑 +栋梁之任 棟樑之任 +栋梁之材 棟樑之材 +栋梁之臣 棟樑之臣 +栏干 欄干 +栏杆 欄杆 +栏板 欄板 +栏柜 欄櫃 +树党 樹黨 +树叶 樹葉 +树干 樹幹 +树干断 樹幹斷 +树德技术学院 樹德技術學院 +树梁 樹樑 +树欲息而风不停 樹欲息而風不停 +树欲静而风不止 樹欲靜而風不止 +树种 樹種 +树虫子 樹蟲子 +树高千丈落叶归根 樹高千丈落葉歸根 +栖于 棲於 +栖栖皇皇 棲棲皇皇 +栗冽 慄冽 +栗凿 栗鑿 +栗喇 栗喇 +栗子 栗子 +栗尾 栗尾 +栗暴 栗暴 +栗栗 慄慄 +栗栗不安 慄慄不安 +栗栗危惧 慄慄危懼 +栗烈 栗烈 +栗然 慄然 +栗爆 栗爆 +栗田雄介 栗田雄介 +栗碌 栗碌 +栗色 栗色 +栗苞 栗苞 +栗薪 栗薪 +栗鼠 栗鼠 +校准 校準 +校园骨干 校園骨幹 +校核 校覈 +校舍 校舍 +样板 樣板 +样板戏 樣板戲 +样范 樣範 +核下 核下 +核二厂 核二廠 +核人 核人 +核仁 核仁 +核以 核以 +核价 覈價 +核体 核體 +核保 覈保 +核僵持 核僵持 +核儿 核兒 +核冬天 核冬天 +核准 覈准 +核准的 覈准的 +核减 覈減 +核出口控制 核出口控制 +核力 核力 +核办 核辦 +核化 核化 +核区 核區 +核发 核發 +核发电 核發電 +核发电厂 核發電廠 +核可 核可 +核合成 核合成 +核和 核和 +核四 核四 +核型 核型 +核复 覈覆 +核子 核子 +核子厂 核子廠 +核孔 核孔 +核字 覈字 +核定 覈定 +核实 覈實 +核审 覈審 +核对 覈對 +核对表 覈對表 +核岛 核島 +核工 核工 +核弹 核彈 +核当量 核當量 +核心 核心 +核战 核戰 +核战斗部 核戰鬥部 +核批 覈批 +核技术 核技術 +核报 覈報 +核拨 覈撥 +核收 覈收 +核数 核數 +核是 核是 +核有 核有 +核果 核果 +核查 覈查 +核查制度 核查制度 +核桃 核桃 +核武 核武 +核火箭发动机 核火箭發動機 +核炫 核炫 +核点 核點 +核燃料后处理 核燃料後處理 +核爆 核爆 +核爆炸烟云 核爆炸煙雲 +核状 核狀 +核球 核球 +核甘 核甘 +核电 核電 +核电厂 核電廠 +核电磁脉冲 核電磁脈衝 +核的 核的 +核磁 核磁 +核示 覈示 +核种 核種 +核突 核突 +核算 覈算 +核粒 核粒 +核糖 核糖 +核糖核酸 核糖核酸 +核素 核素 +核线 核線 +核编 覈編 +核能 核能 +核能发电 核能發電 +核能发电厂 核能發電廠 +核能技术 核能技術 +核能电厂 核能電廠 +核膜 核膜 +核苷 核苷 +核菌 核菌 +核融合 核融合 +核融合发电 核融合發電 +核解 核解 +核计 覈計 +核计划 核計劃 +核试 核試 +核谈 核談 +核质 核質 +核资 覈資 +核载 核載 +核配 核配 +核酪 核酪 +核酶 核酶 +核酸 核酸 +核销 覈銷 +核防御 核防禦 +核验 覈驗 +根壮叶茂 根壯葉茂 +根据 根據 +根据上表 根據上表 +根据地 根據地 +根据规定 根據規定 +根深叶茂 根深葉茂 +根烟 根菸 +根目录 根目錄 +根系 根系 +根茎叶 根莖葉 +根须 根鬚 +格丹斯克 格丹斯克 +格于 格於 +格于成例 格於成例 +格于环境 格於環境 +格但斯克 格但斯克 +格兰杰 格蘭傑 +格列佛游记 格列佛遊記 +格列高利历 格列高利曆 +格别乌 格別烏 +格勒诺布尔 格勒諾布爾 +格子布 格子布 +格子棉布 格子棉布 +格拉哥里字母 格拉哥里字母 +格斗 格鬥 +格斗王 格鬥王 +格斗者 格鬥者 +格斗赛 格鬥賽 +格林威治天文台 格林威治天文臺 +格林威治标准时间 格林威治標準時間 +格林尼治标准时间 格林尼治標準時間 +格物致知 格物致知 +格瑞诺布 格瑞諾布 +格致 格致 +格致中学 格致中學 +格致国中 格致國中 +格致诚正修齐 格致誠正修齊 +格范 格範 +格里 格里 +格里历 格里曆 +格里姆斯塔 格里姆斯塔 +格里高利 格里高利 +格里高利历 格里高利曆 +栽种 栽種 +栽种机 栽種機 +栽种法 栽種法 +栽觔斗 栽觔斗 +栽跟斗 栽跟斗 +桂仔云 桂仔云 +桂圆干 桂圓乾 +桂林团 桂林團 +桂秋 桂秋 +桂系军阀 桂系軍閥 +桃叶歌 桃葉歌 +桃叶渡 桃葉渡 +桃叶珊瑚 桃葉珊瑚 +桃园中坜台地 桃園中壢臺地 +桃核 桃核 +桃核雕 桃核雕 +桃花人面 桃花人面 +桃花面 桃花面 +桃金娘 桃金娘 +桃金娘科 桃金娘科 +桅杆 桅杆 +框出 框出 +框出来 框出來 +案准 案准 +案几 案几 +案卷 案卷 +案发 案發 +案发前 案發前 +案发后 案發後 +案发时 案發時 +案头柜 案頭櫃 +案据 案據 +案板 案板 +桉叶油 桉葉油 +桌几 桌几 +桌别林 桌別林 +桌历 桌曆 +桌布 桌布 +桌椅板凳 桌椅板凳 +桌面 桌面 +桌面上 桌面上 +桌面儿 桌面兒 +桌面儿上 桌面兒上 +桌面系统 桌面系統 +桐叶知秋 桐葉知秋 +桐花烟 桐花煙 +桑叶 桑葉 +桑定党 桑定黨 +桑布森 桑布森 +桑干 桑乾 +桑干河 桑乾河 +桑干盆地 桑乾盆地 +桑托斯 桑托斯 +桑托荣 桑托榮 +桑托里尼岛 桑托里尼島 +桑杰士 桑傑士 +桑蓬之志 桑蓬之志 +桑虫 桑蟲 +桑针 桑針 +桓台 桓臺 +桓台县 桓臺縣 +桓表 桓表 +桢干 楨幹 +档卷 檔卷 +档案传输系统 檔案傳輸系統 +档案搜寻系统 檔案搜尋系統 +档案柜 檔案櫃 +桥台 橋臺 +桥梁 橋樑 +桥梁工事 橋樑工事 +桥梁工程 橋樑工程 +桥面 橋面 +桥面上 橋面上 +桶里 桶裏 +桶里射鱼 桶裏射魚 +梁上 樑上 +梁上君子 樑上君子 +梁世煌 梁世煌 +梁丽 梁麗 +梁书 梁書 +梁仙台 梁仙臺 +梁任公 梁任公 +梁伟聪 梁偉聰 +梁伟铭 梁偉銘 +梁修身 梁修身 +梁元帝 梁元帝 +梁又琳 梁又琳 +梁启超 梁啓超 +梁咏琪 梁詠琪 +梁唐晋汉周书 梁唐晉漢周書 +梁园 梁園 +梁园区 梁園區 +梁园宴雪 梁園宴雪 +梁园虽好不是久恋之家 梁園雖好不是久戀之家 +梁国荣 梁國榮 +梁太祖 梁太祖 +梁姓 梁姓 +梁子 樑子 +梁子湖 梁子湖 +梁子湖区 梁子湖區 +梁孟 梁孟 +梁实秋 梁實秋 +梁家辉 梁家輝 +梁容银 梁容銀 +梁山 梁山 +梁山伯 梁山伯 +梁山伯与祝英台 梁山伯與祝英臺 +梁山伯祝英台 梁山伯祝英臺 +梁山县 梁山縣 +梁山市 梁山市 +梁山泊 梁山泊 +梁州 梁州 +梁平 梁平 +梁平县 梁平縣 +梁建伟 梁建偉 +梁德馨 梁德馨 +梁心颐 梁心頤 +梁惠王 梁惠王 +梁敬帝 梁敬帝 +梁文冲 梁文沖 +梁文音 梁文音 +梁文骐 梁文騏 +梁朝伟 梁朝偉 +梁木 梁木 +梁木其坏 樑木其壞 +梁架 樑架 +梁柱 樑柱 +梁栋 樑棟 +梁案 梁案 +梁楷 梁楷 +梁次震 梁次震 +梁武帝 梁武帝 +梁氏 梁氏 +梁河 梁河 +梁河县 梁河縣 +梁漱溟 梁漱溟 +梁父吟 梁父吟 +梁狱上书 梁獄上書 +梁玉芳 梁玉芳 +梁皇宝忏 梁皇寶懺 +梁皇忏 梁皇懺 +梁祝 梁祝 +梁简文帝 梁簡文帝 +梁红玉 梁紅玉 +梁经伦 梁經倫 +梁羽生 梁羽生 +梁茜雯 梁茜雯 +梁赞 梁贊 +梁辀 梁輈 +梁辰鱼 梁辰魚 +梁锦兴 梁錦興 +梁静茹 梁靜茹 +梁靜茹 梁靜茹 +梁鸿 梁鴻 +梁鸿五噫 梁鴻五噫 +梁龙 樑龍 +梅克 梅克 +梅克尔 梅克爾 +梅尼尔氏症 梅尼爾氏症 +梅布托 梅布托 +梅干 梅乾 +梅干菜 梅乾菜 +梅德韦杰夫 梅德韋傑夫 +梅杰 梅傑 +梅核 梅核 +梅花小娘 梅花小娘 +梅西叶 梅西葉 +梅西叶星表 梅西葉星表 +梅西耶星表 梅西耶星表 +梅里 梅里 +梅里亚 梅里亞 +梅里亚姆韦伯斯特 梅里亞姆韋伯斯特 +梅里斯 梅里斯 +梅里斯区 梅里斯區 +梅里斯达斡尔族区 梅里斯達斡爾族區 +梅里美 梅里美 +梅里雪山 梅里雪山 +梓里 梓里 +梢云 梢雲 +梦云 夢雲 +梦兰叶吉 夢蘭叶吉 +梦卜 夢卜 +梦周公 夢周公 +梦回 夢迴 +梦工厂 夢工廠 +梦工厂动画 夢工廠動畫 +梦往神游 夢往神遊 +梦有五不占 夢有五不占 +梦游 夢遊 +梦游症 夢遊症 +梦粱录 夢粱錄 +梦系 夢繫 +梦行症 夢行症 +梦里 夢裏 +梦里蝴蝶 夢裏蝴蝶 +梨云 梨雲 +梨干 梨乾 +梨干儿 梨乾兒 +梯冲 梯衝 +梯度回波 梯度回波 +梯恩梯当量 梯恩梯當量 +梯板 梯板 +械斗 械鬥 +械系 械繫 +梳了 梳了 +梳发 梳髮 +梳头发 梳頭髮 +梳妆台 梳妝檯 +梳理 梳理 +梵册贝叶 梵冊貝葉 +梵谷 梵谷 +检修 檢修 +检出 檢出 +检复 檢覆 +检字表 檢字表 +检尸 檢屍 +检录 檢錄 +检査出 檢查出 +检査出来 檢查出來 +检核 檢核 +检核表 檢核表 +检测出 檢測出 +检测出来 檢測出來 +检索系统 檢索系統 +检警合一 檢警合一 +检阅台 檢閱臺 +检验出 檢驗出 +检验出来 檢驗出來 +棉制 棉製 +棉卷 棉卷 +棉厂 棉廠 +棉布 棉布 +棉布婚 棉布婚 +棉签 棉籤 +棉纤维 棉纖維 +棉纺厂 棉紡廠 +棉花布 棉花布 +棉花店里歇工 棉花店裏歇工 +棉花火药 棉花火藥 +棉药签 棉藥籤 +棉铃虫 棉鈴蟲 +棋布 棋佈 +棋布星罗 棋佈星羅 +棋杯 棋杯 +棋罗星布 棋羅星佈 +棋逢对手将遇良才 棋逢對手將遇良才 +棒下出孝子 棒下出孝子 +棒坛 棒壇 +棒头出孝子 棒頭出孝子 +棒子面 棒子麪 +棒曲霉素 棒麴黴素 +棒极了 棒極了 +棒状杆菌 棒狀桿菌 +棒针 棒針 +棒针衫 棒針衫 +棕色种 棕色種 +棘针 棘針 +棘针科 棘針科 +棘针门 棘針門 +棫朴 棫樸 +森林学系 森林學系 +森林抚育采伐 森林撫育採伐 +森林游乐区 森林遊樂區 +森林生态系 森林生態系 +森林里 森林裏 +森罗万象 森羅萬象 +棱体 棱體 +棱台 棱臺 +棱层 棱層 +棱等登 棱等登 +棱线 棱線 +棱缝 棱縫 +棱锥 棱錐 +棱锥台 棱錐臺 +棱镜 棱鏡 +棺材出了讨挽歌郎钱 棺材出了討挽歌郎錢 +棺材板 棺材板 +棺材里 棺材裏 +棺材里伸手 棺材裏伸手 +椅里 椅裏 +植党 植黨 +植党营私 植黨營私 +植发 植髮 +植基于 植基於 +植根于 植根於 +植物区系 植物區系 +植物志 植物誌 +植物纤维 植物纖維 +植病系 植病系 +植皮手术 植皮手術 +椭圆面 橢圓面 +椰枣干 椰棗乾 +椰胡 椰胡 +椰雕 椰雕 +椽梁 椽梁 +椿萱并茂 椿萱並茂 +楚庄王 楚莊王 +楚庄绝缨 楚莊絕纓 +楚庄问鼎 楚莊問鼎 +楚汉春秋 楚漢春秋 +楚霸王困垓下 楚霸王困垓下 +楞了楞 楞了楞 +楣运当头 楣運當頭 +楮叶 楮葉 +楼台 樓臺 +楼台亭阁 樓臺亭閣 +楼台会 樓臺會 +楼板 樓板 +楼梯台 樓梯臺 +楼梯平台 樓梯平臺 +楼阁亭台 樓閣亭臺 +楼面 樓面 +概念 概念 +榆叶梅 榆葉梅 +榔板 榔板 +榕坛问业 榕壇問業 +榨干 榨乾 +榨油厂 榨油廠 +榻布 榻布 +槃才 槃才 +槃槃大才 槃槃大才 +槓杆 槓桿 +槓杆原理 槓桿原理 +槭叶止血草 槭葉止血草 +樊于期 樊於期 +樛曲 樛曲 +模制 模製 +模制品 模製品 +模块板 模塊板 +模型板 模型板 +模式种 模式種 +模拟出 模擬出 +模板 模板 +模板工 模板工 +模糊集合理论 模糊集合理論 +模组厂 模組廠 +模网论坛 模網論壇 +模胡 模胡 +模范 模範 +模范丈夫 模範丈夫 +模范人物 模範人物 +模范作用 模範作用 +模范区 模範區 +模范城市 模範城市 +模范大音阶 模範大音階 +模范学生 模範學生 +模范带头 模範帶頭 +模范带头作用 模範帶頭作用 +模范教师 模範教師 +模范村 模範村 +模范棒棒堂 模範棒棒堂 +模范生 模範生 +模范省 模範省 +模范章 模範章 +模范行动 模範行動 +模表 模表 +模里西斯 模里西斯 +模里西斯共和国 模里西斯共和國 +横了心 橫了心 +横冲 橫衝 +横冲直撞 橫衝直撞 +横出 橫出 +横切面 橫切面 +横剖面 橫剖面 +横向 橫向 +横尸 橫屍 +横尸遍野 橫屍遍野 +横征暴敛 橫徵暴斂 +横截面 橫截面 +横打鼻梁儿 橫打鼻梁兒 +横扫千军 橫掃千軍 +横折 橫折 +横摆 橫擺 +横断面 橫斷面 +横杆 橫杆 +横杠 橫槓 +横梁 橫樑 +横眉冷对千夫指 橫眉冷對千夫指 +横秋 橫秋 +横筋斗 橫筋斗 +横舍 橫舍 +横面 橫面 +横须贺 橫須賀 +横须贺市 橫須賀市 +樱花杯 櫻花盃 +樵苏 樵蘇 +樵苏不爨 樵蘇不爨 +樵采 樵採 +橄榄岩 橄欖岩 +橘核 橘核 +橡子面 橡子麪 +橡子面儿 橡子麪兒 +橡斗 橡斗 +橡木叶 橡木葉 +橦布 橦布 +橫亘 橫亙 +橱柜 櫥櫃 +檀板 檀板 +欠当 欠當 +欠据 欠據 +次一个 次一個 +次于 次於 +次分面 次分面 +次后 次後 +次级团体 次級團體 +欢乐谷 歡樂谷 +欢喜欲狂 歡喜欲狂 +欣喜欲狂 欣喜欲狂 +欣戚 欣戚 +欣欣向荣 欣欣向榮 +欣然同意 欣然同意 +欣生恶死 欣生惡死 +欧伯托 歐伯托 +欧佩克 歐佩克 +欧克 歐克 +欧克曼 歐克曼 +欧克莱 歐克萊 +欧几里得 歐幾里得 +欧几里得原理 歐幾里得原理 +欧几里德 歐幾里德 +欧化倾向 歐化傾向 +欧布拉多 歐布拉多 +欧布莱特 歐布萊特 +欧式几何 歐式幾何 +欧式几何学 歐式幾何學 +欧式建筑 歐式建築 +欧战后 歐戰後 +欧拉朱万 歐拉朱萬 +欧普艺术 歐普藝術 +欧氏几何学 歐氏幾何學 +欧洲共同体 歐洲共同體 +欧洲共同市场 歐洲共同市場 +欧洲复兴计画 歐洲復興計畫 +欧洲安全与合作组织 歐洲安全與合作組織 +欧洲安全和合作组织 歐洲安全和合作組織 +欧洲杯 歐洲盃 +欧洲火药库 歐洲火藥庫 +欧洲货币体系 歐洲貨幣體系 +欧游 歐遊 +欧游之行 歐遊之行 +欧游记趣 歐遊記趣 +欧特里尼 歐特里尼 +欧秋雅 歐秋雅 +欧系 歐系 +欧罗巴人种 歐羅巴人種 +欧胡岛 歐胡島 +欧萨苏纳 歐薩蘇納 +欧足联杯 歐足聯杯 +欧里 歐里 +欧里庇得斯 歐里庇得斯 +欧里桑 歐里桑 +欧阳修 歐陽修 +欧雷克 歐雷克 +欲不可从 欲不可從 +欲人不知莫若勿为 欲人不知莫若勿爲 +欲令智昏 慾令智昏 +欲加之罪 欲加之罪 +欲加之罪何患无词 慾加之罪何患無詞 +欲加之罪何患无辞 欲加之罪何患無辭 +欲取固与 欲取固與 +欲取姑与 欲取姑與 +欲取姑予 欲取姑予 +欲哭无泪 欲哭無淚 +欲善其事必先利其器 慾善其事必先利其器 +欲堑 欲塹 +欲壑难填 慾壑難填 +欲壑难饱 欲壑難飽 +欲女 慾女 +欲就还推 欲就還推 +欲待 欲待 +欲得 欲得 +欲念 慾念 +欲振乏力 欲振乏力 +欲擒故纵 欲擒故縱 +欲望 慾望 +欲求 欲求 +欲求不满 慾求不滿 +欲海 慾海 +欲海难填 欲海難填 +欲深谿壑 欲深谿壑 +欲火 慾火 +欲火焚身 慾火焚身 +欲炙之色 欲炙之色 +欲界 欲界 +欲益反损 欲益反損 +欲盖弥彰 欲蓋彌彰 +欲穷千里目 欲窮千里目 +欲绝 欲絕 +欲罢不能 欲罷不能 +欲裂 欲裂 +欲言又止 欲言又止 +欲语还休 欲語還休 +欲说还休 欲說還休 +欲购从速 欲購從速 +欲速不达 欲速不達 +欲速则不达 欲速則不達 +欲速而不达 欲速而不達 +欲障 慾障 +欷吁 欷吁 +欸乃曲 欸乃曲 +欹嵚历落 欹嶔歷落 +欺善怕恶 欺善怕惡 +欺敌战术 欺敵戰術 +欺蒙 欺矇 +款冬 款冬 +款曲 款曲 +歇了 歇了 +歇后 歇後 +歇后语 歇後語 +歇斯底里 歇斯底里 +歇洛克福尔摩斯 歇洛克福爾摩斯 +歇马杯 歇馬杯 +歌仔戏团 歌仔戲團 +歌剧团 歌劇團 +歌台舞榭 歌臺舞榭 +歌后 歌后 +歌坛 歌壇 +歌坛上 歌壇上 +歌坛新秀 歌壇新秀 +歌声绕梁 歌聲繞梁 +歌曲 歌曲 +歌板 歌板 +歌舞升平 歌舞昇平 +歌舞团 歌舞團 +歌钟 歌鐘 +歌风台 歌風臺 +歎吁 歎吁 +歛出来 歛出來 +止不了 止不了 +止于 止於 +止于至善 止於至善 +止咳药 止咳藥 +止恶扬善 止惡揚善 +止泻药 止瀉藥 +止涨回跌 止漲回跌 +止痛药 止痛藥 +止血药 止血藥 +止谤莫如自修 止謗莫如自脩 +止跌回升 止跌回升 +止饥 止飢 +正义党 正義黨 +正义发展党 正義發展黨 +正义斗争 正義鬥爭 +正于 正於 +正修工专 正修工專 +正凶 正凶 +正出 正出 +正则参数 正則參數 +正反两面 正反兩面 +正反合 正反合 +正反面 正反面 +正合 正合 +正合我意 正合我意 +正合适 正合適 +正后 正後 +正后像 正後像 +正后方 正後方 +正向 正向 +正向前看 正向前看 +正处于 正處於 +正多面体 正多面體 +正头娘子 正頭娘子 +正官庄 正官莊 +正宫娘娘 正宮娘娘 +正对面 正對面 +正常范围 正常範圍 +正弦 正弦 +正弦曲线 正弦曲線 +正当 正當 +正当中 正當中 +正当化 正當化 +正当性 正當性 +正当时 正當時 +正当理由 正當理由 +正当行为 正當行爲 +正当防卫 正當防衛 +正当防卫行为 正當防衛行爲 +正念 正念 +正手板 正手板 +正方向 正方向 +正方晶系 正方晶系 +正极 正極 +正枝正叶 正枝正葉 +正梁 正樑 +正正当当 正正當當 +正正确确 正正確確 +正电子发射体层 正電子發射體層 +正电子发射层析 正電子發射層析 +正电子发射断层照相术 正電子發射斷層照相術 +正电子发射计算机断层 正電子發射計算機斷層 +正电极 正電極 +正确 正確 +正确处理 正確處理 +正确处理人民内部矛盾 正確處理人民內部矛盾 +正确度 正確度 +正确性 正確性 +正确路线 正確路線 +正误表 正誤表 +正集团 正集團 +正面 正面 +正面人物 正面人物 +正面图 正面圖 +正面攻击 正面攻擊 +此仆彼起 此仆彼起 +此发彼应 此發彼應 +此后 此後 +此系 此係 +步人后尘 步人後塵 +步兵团 步兵團 +步出 步出 +步后尘 步後塵 +步向 步向 +步斗踏罡 步斗踏罡 +步月登云 步月登雲 +步枪团 步槍團 +步步行凶 步步行兇 +步步高升 步步高昇 +步线行针 步線行針 +步罡踏斗 步罡踏斗 +步行虫 步行蟲 +步调一致 步調一致 +步进制 步進制 +步青云 步青雲 +步飞烟传 步飛煙傳 +武丑 武丑 +武偃文修 武偃文修 +武后 武后 +武器系统 武器系統 +武器级别材料 武器級別材料 +武坛 武壇 +武大郎吃毒药 武大郎吃毒藥 +武当 武當 +武当山 武當山 +武当派 武當派 +武斗 武鬥 +武曲星 武曲星 +武术 武術 +武术指导 武術指導 +武术比赛 武術比賽 +武术竞赛 武術競賽 +武松 武松 +武松打虎 武松打虎 +武梁祠画像 武梁祠畫像 +武胜关 武勝關 +武胜县 武勝縣 +武装冲突 武裝衝突 +武装斗争 武裝鬥爭 +武里省 武里省 +歧出 歧出 +歪向 歪向 +歪才 歪才 +歪摆布 歪擺佈 +歪曲 歪曲 +歪曲事实 歪曲事實 +歹念 歹念 +歹斗 歹鬥 +死不了 死不了 +死不了心 死不了心 +死了 死了 +死于 死於 +死于安乐 死於安樂 +死于非命 死於非命 +死伤枕借 死傷枕藉 +死伤相借 死傷相藉 +死党 死黨 +死别 死別 +死别生离 死別生離 +死后 死後 +死后多年 死後多年 +死命挣扎 死命掙扎 +死定了 死定了 +死尸 死屍 +死当 死當 +死扣 死扣 +死有余辜 死有餘辜 +死有重于泰山轻于鸿毛 死有重於泰山輕於鴻毛 +死板 死板 +死板板 死板板 +死气沈沈 死氣沈沈 +死海古卷 死海古卷 +死海经卷 死海經卷 +死灰复然 死灰復然 +死灰复燃 死灰復燃 +死灰复燎 死灰復燎 +死生未卜 死生未卜 +死症 死症 +死知府不如一个活老鼠 死知府不如一個活老鼠 +死而不僵 死而不僵 +死而后已 死而後已 +死而后止 死而後止 +死而复活 死而復活 +死而复生 死而復生 +死而复苏 死而復甦 +死胡同 死衚衕 +死要面子 死要面子 +死谷 死谷 +死里求生 死裏求生 +死里逃生 死裏逃生 +死难同胞 死難同胞 +死面 死麪 死面 +死马当活马医 死馬當活馬醫 +死马当活马治 死馬當活馬治 +殆尽 殆盡 +殊别 殊別 +殊域周咨录 殊域周咨錄 +殊属不当 殊屬不當 +殊方同致 殊方同致 +殊涂一致 殊塗一致 +殊涂同会 殊塗同會 +殊涂同归 殊塗同歸 +殊涂同致 殊塗同致 +殊胜 殊勝 +殊致 殊致 +殊致同归 殊致同歸 +殊路同归 殊路同歸 +殊途同归 殊途同歸 +残余 殘餘 +残余沾染 殘餘沾染 +残余物 殘餘物 +残党 殘黨 +残冬 殘冬 +残冬腊月 殘冬臘月 +残卷 殘卷 +残干 殘幹 +残废后 殘廢後 +残念 殘念 +残春雾雨余 殘春霧雨餘 +残杯冷炙 殘杯冷炙 +残秋 殘秋 +残肴 殘餚 +殖谷 殖穀 +殚尽 殫盡 +殚思极虑 殫思極慮 +殚精极思 殫精極思 +殚精极虑 殫精極慮 +殡舍 殯舍 +殢云尤雨 殢雲尤雨 +殢雨尤云 殢雨尤雲 +殴斗 毆鬥 +段皇云 段皇雲 +殷同 殷同 +殷墟卜辞 殷墟卜辭 +殷师牛斗 殷師牛鬥 +殷鉴 殷鑑 +殷鉴不远 殷鑑不遠 +殿后 殿後 +殿钟自鸣 殿鐘自鳴 +毁了 毀了 +毁于 毀於 +毁于一旦 毀於一旦 +毁尸灭迹 毀屍滅跡 +毁廉蔑耻 毀廉蔑恥 +毁弃 譭棄 +毁方瓦合 毀方瓦合 +毁炎 燬炎 +毁犀 燬犀 +毁誉 譭譽 +毁誉参半 譭譽參半 +毁诬 譭誣 +毁钟为铎 譭鐘爲鐸 +毋贻后患 毋貽後患 +毋须 毋須 +毋须乎 毋須乎 +母丑 母醜 +母乳喂养 母乳餵養 +母党 母黨 +母后 母后 +母大虫 母大蟲 +母权制 母權制 +母板 母板 +母系 母系 +母系亲属 母系親屬 +母系制度 母系制度 +母系社会 母系社會 +母范 母範 +母钟 母鐘 +母音表 母音表 +每一个人 每一個人 +每一个人都有美中不足的地方 每一個人都有美中不足的地方 +每个 每個 +每个人 每個人 +每个月 每個月 +每于 每於 +每公里 每公里 +每分钟 每分鐘 +每只 每隻 +每周 每週 +每周一次 每週一次 +每回 每回 +每当 每當 +每战必胜 每戰必勝 +每日限价 每日限價 +每杯 每杯 +每每只 每每只 +每种 每種 +每秒钟 每秒鐘 +每端口价格 每端口價格 +每面 每面 +毒僵指 毒殭指 +毒症 毒症 +毒药 毒藥 +毒药苦口 毒藥苦口 +毒药苦口利于病 毒藥苦口利於病 +毒虫 毒蟲 +毒针 毒針 +比上不足比下有余 比上不足比下有餘 +比不了 比不了 +比个 比個 +比个大哥二哥 比個大哥二哥 +比个高下 比個高下 +比个高低 比個高低 +比了 比了 +比什凯克 比什凱克 +比价 比價 +比众不同 比衆不同 +比例代表制 比例代表制 +比出 比出 +比划 比劃 +比合 比合 +比周 比周 +比喻失当 比喻失當 +比干 比干 +比并 比並 +比手划脚 比手劃腳 +比才 比才 +比杆赛 比桿賽 +比约克曼 比約克曼 +比舍 比舍 +比表面 比表面 +比较规范 比較規範 +毕业于 畢業於 +毕于 畢於 +毕其功于一役 畢其功於一役 +毕力同心 畢力同心 +毕升 畢昇 +毕宿星团 畢宿星團 +毕生发展 畢生發展 +毕翠克丝 畢翠克絲 +毗婆尸佛 毗婆尸佛 +毗舍婆佛 毗舍婆佛 +毙而后已 斃而後已 +毚欲 毚欲 +毛了 毛了 +毛了手脚 毛了手腳 +毛出在羊身上 毛出在羊身上 +毛卷 毛卷 +毛厕里砖儿 毛廁裏磚兒 +毛发 毛髮 +毛发之功 毛髮之功 +毛发俱竖 毛髮俱豎 +毛发倒竖 毛髮倒豎 +毛发悚然 毛髮悚然 +毛发森竖 毛髮森豎 +毛发皆竖 毛髮皆豎 +毛发耸然 毛髮聳然 +毛司里砖儿 毛司裏磚兒 +毛囊虫 毛囊蟲 +毛团 毛團 +毛团把戏 毛團把戲 +毛坑没后壁 毛坑沒後壁 +毛姜 毛薑 +毛巾布 毛巾布 +毛布 毛布 +毛板 毛板 +毛栗子 毛栗子 +毛毛虫 毛毛蟲 +毛毯里 毛毯裏 +毛纺厂 毛紡廠 +毛线针 毛線針 +毛织布 毛織布 +毛虫 毛蟲 +毛语录 毛語錄 +毛里塔尼亚 毛里塔尼亞 +毛里拖毡 毛裏拖氈 +毛里求斯 毛里求斯 +毫不相干 毫不相干 +毫仑目 毫侖目 +毫克 毫克 +毫升 毫升 +毫厘 毫釐 +毫厘不差 毫釐不差 +毫厘不爽 毫釐不爽 +毫厘之差 毫釐之差 +毫厘千里 毫釐千里 +毫发 毫髮 +毫发不差 毫髮不差 +毫发不爽 毫髮不爽 +毫发之差 毫髮之差 +毫发无损 毫髮無損 +毫发未伤 毫髮未傷 +毫居里 毫居里 +毫无 毫無 +毫无二致 毫無二致 +毫无价值 毫無價值 +毫无准备 毫無準備 +毫无根据 毫無根據 +毫无节制 毫無節制 +毫针 毫針 +毯里 毯裏 +氏症 氏症 +氏胄 氏胄 +民丰 民豐 +民丰县 民豐縣 +民主党 民主黨 +民主党人 民主黨人 +民主党员 民主黨員 +民主党派 民主黨派 +民主党籍 民主黨籍 +民主制度 民主制度 +民主进步党 民主進步黨 +民主进步党籍 民主進步黨籍 +民主集中制 民主集中制 +民众代表 民衆代表 +民众党 民衆黨 +民众团体 民衆團體 +民俗曲艺 民俗曲藝 +民党 民黨 +民和回族土族自治县 民和回族土族自治縣 +民和年丰 民和年豐 +民团 民團 +民坠涂炭 民墜塗炭 +民心向背 民心向背 +民心所向 民心所向 +民心趋向 民心趨向 +民志 民志 +民怨盈涂 民怨盈塗 +民意代表 民意代表 +民意向背 民意向背 +民政里 民政里 +民族党 民族黨 +民族同化 民族同化 +民族团结 民族團結 +民族复兴运动 民族復興運動 +民族志 民族誌 +民族色彩 民族色彩 +民极 民極 +民生涂炭 民生塗炭 +民生雕敝 民生雕敝 +民用建筑 民用建築 +民用航空器适航证书 民用航空器適航證書 +民社党 民社黨 +民穷财尽 民窮財盡 +民谣歌曲 民謠歌曲 +民进党 民進黨 +民进党员 民進黨員 +民进党团 民進黨團 +民进党版 民進黨版 +民进党籍 民進黨籍 +民间合会 民間合會 +民间团体 民間團體 +民间艺术 民間藝術 +民风淳朴 民風淳樸 +民风纯朴 民風純樸 +气一冲 氣一衝 +气了 氣了 +气充志定 氣充志定 +气充志骄 氣充志驕 +气克斗牛 氣克斗牛 +气冲冲 氣沖沖 +气冲斗牛 氣衝斗牛 +气冲牛斗 氣衝牛斗 +气冲霄汉 氣衝霄漢 +气出 氣出 +气力用尽 氣力用盡 +气动控制 氣動控制 +气势熏灼 氣勢熏灼 +气压表 氣壓表 +气吁吁 氣吁吁 +气吞牛斗 氣吞牛斗 +气味相合 氣味相合 +气喘吁吁 氣喘吁吁 +气团 氣團 +气在心里 氣在心裏 +气定神闲 氣定神閒 +气尽 氣盡 +气帘 氣簾 +气扬采飞 氣揚采飛 +气数已尽 氣數已盡 +气极败坏 氣極敗壞 +气满志得 氣滿志得 +气满志骄 氣滿志驕 +气焰熏天 氣焰熏天 +气燄万丈 氣燄萬丈 +气管切开术 氣管切開術 +气管插管术 氣管插管術 +气若游丝 氣若游絲 +气象万千 氣象萬千 +气象台 氣象臺 +气郁 氣鬱 +气铲 氣鏟 +气骄志满 氣驕志滿 +氘核 氘核 +氢净合成油 氫淨合成油 +氢卤酸 氫鹵酸 +氤郁 氤鬱 +氨基甲酸酯类化合物 氨基甲酸酯類化合物 +氮血症 氮血症 +水一冲 水一衝 +水上摩托车 水上摩托車 +水俣症 水俁症 +水光云影 水光雲影 +水再冲 水再衝 +水准 水準 +水准仪 水準儀 +水准器 水準器 +水准图 水準圖 +水准测量 水準測量 +水利制 水利制 +水力发电 水力發電 +水力发电站 水力發電站 +水厂 水廠 +水又冲 水又衝 +水合 水合 +水合物 水合物 +水团 水團 +水尽山穷 水盡山窮 +水尽鹅飞 水盡鵝飛 +水已冲 水已衝 +水已干 水已乾 +水帘 水簾 +水帘洞 水簾洞 +水干 水乾 +水干尽 水乾盡 +水干掉 水乾掉 +水平面 水平面 +水底写字板 水底寫字板 +水底捞针 水底撈針 +水当当 水噹噹 +水彩 水彩 +水彩画 水彩畫 +水彩画家 水彩畫家 +水彩笔 水彩筆 +水彩颜料 水彩顏料 +水急冲 水急衝 +水成岩 水成岩 +水才干 水纔乾 +水斗 水斗 +水斧虫 水斧蟲 +水晶杯 水晶杯 +水曲 水曲 +水曲柳 水曲柳 +水来汤里去 水來湯裏去 +水杯 水杯 +水柜 水櫃 +水波荡漾 水波盪漾 +水泥厂 水泥廠 +水泥板 水泥板 +水注 水注 +水流內布袋戏台 水流內布袋戲臺 +水浒后传 水滸後傳 +水清可鉴 水清可鑑 +水温表 水溫表 +水烟 水煙 +水烟袋 水菸袋 +水磨腔曲子 水磨腔曲子 +水秋千 水鞦韆 +水穷山尽 水窮山盡 +水管系 水管系 +水管面 水管麪 +水精帘 水精簾 +水系 水系 +水经注 水經注 +水落石出 水落石出 +水蜡树 水蠟樹 +水蜡虫 水蠟蟲 +水表 水錶 +水谷 水谷 +水谷之海 水穀之海 +水谷隼 水谷隼 +水轮发动 水輪發動 +水轮发动机 水輪發動機 +水轮发电 水輪發電 +水逝云卷 水逝雲卷 +水里 水裏 +水里乡 水里鄉 +水里水里来火里火里去 水裏水裏來火裏火裏去 +水里纳瓜 水裏納瓜 +水里鄉 水里鄉 +水鉴 水鑑 +水陆并进 水陸並進 +水面 水面 +水面上 水面上 +水面系数 水面係數 +水面舰 水面艦 +水面舰艇 水面艦艇 +水龙卷 水龍捲 +永不录用 永不錄用 +永丰 永豐 +永丰余 永豐餘 +永丰县 永豐縣 +永丰堂 永豐堂 +永丰舰 永豐艦 +永丰舰事件 永豐艦事件 +永丰金 永豐金 +永修县 永修縣 +永别 永別 +永别酒 永別酒 +永历 永曆 +永发 永發 +永志 永志 +永志不忘 永誌不忘 +永结同心 永結同心 +永续发展 永續發展 +永胜 永勝 +永胜县 永勝縣 +汀曲 汀曲 +求借 求借 +求出 求出 +求助于 求助於 +求助于人 求助於人 +求古录 求古錄 +求同 求同 +求同存异 求同存異 +求才 求才 +求才若渴 求才若渴 +求教于 求教於 +求死愿望 求死願望 +求生意志 求生意志 +求田问舍 求田問舍 +求知欲 求知慾 +求神问卜 求神問卜 +求签 求籤 +求胜 求勝 +求胜心 求勝心 +求过于供 求過於供 +求道于盲 求道於盲 +汇业 匯業 +汇业财经集团 匯業財經集團 +汇业银行 匯業銀行 +汇丰 匯豐 +汇丰银行 匯豐銀行 +汇付 匯付 +汇价 匯價 +汇信 匯信 +汇兑 匯兌 +汇入 匯入 +汇出 匯出 +汇出行 匯出行 +汇刊 彙刊 +汇划 匯劃 +汇到 匯到 +汇合 匯合 +汇回 匯回 +汇寄 匯寄 +汇展 匯展 +汇川区 匯川區 +汇差 匯差 +汇市 匯市 +汇总 彙總 +汇成 匯成 +汇报 彙報 +汇拢 匯攏 +汇改 匯改 +汇整 彙整 +汇映 彙映 +汇款 匯款 +汇款人 匯款人 +汇款单 匯款單 +汇水 匯水 +汇流 匯流 +汇流处 匯流處 +汇流排 匯流排 +汇流点 匯流點 +汇流环 匯流環 +汇演 匯演 +汇点 匯點 +汇爲 匯爲 +汇率 匯率 +汇率制 匯率制 +汇率差额 匯率差額 +汇电 匯電 +汇票 匯票 +汇算 彙算 +汇纂 彙纂 +汇给 匯給 +汇编 彙編 +汇编语言 彙編語言 +汇聚 匯聚 +汇至 匯至 +汇费 匯費 +汇辑 彙輯 +汇进 匯進 +汇通 匯通 +汇金 匯金 +汇钱 匯錢 +汇银 匯銀 +汇集 彙集 +汇集点 匯集點 +汉书艺文志 漢書藝文志 +汉克 漢克 +汉克阿伦 漢克阿倫 +汉台 漢臺 +汉台区 漢臺區 +汉城特别市 漢城特別市 +汉奸 漢奸 +汉奸走狗 漢奸走狗 +汉学系 漢學系 +汉宫秋 漢宮秋 +汉宫秋月 漢宮秋月 +汉弥尔顿 漢彌爾頓 +汉弥登钟 漢彌登鐘 +汉弥登钟表公司 漢彌登鐘錶公司 +汉志 漢志 +汉杰 漢傑 +汉满蒙回藏 漢滿蒙回藏 +汉药方 漢藥方 +汉萨同盟 漢薩同盟 +汉藏语系 漢藏語系 +汗出如浆 汗出如漿 +汗出如雨 汗出如雨 +汗洽股栗 汗洽股慄 +汗流满面 汗流滿面 +汗腾格里 汗騰格里 +汙蔑 污衊 +汞合金 汞合金 +江云渭树 江雲渭樹 +江南四大才子 江南四大才子 +江南机器制造局 江南機器製造局 +江参 江參 +江宏杰 江宏傑 +江干 江干 +江干区 江乾區 +江志雄 江志雄 +江村销夏录 江村銷夏錄 +江海同归 江海同歸 +江淹才尽 江淹才盡 +江湖术士 江湖術士 +江湖术语 江湖術語 +江苏 江蘇 +江苏人 江蘇人 +江苏南钢 江蘇南鋼 +江苏省 江蘇省 +江苏队 江蘇隊 +江表 江表 +江西师范大学 江西師範大學 +江郎才尽 江郎才盡 +江采苹 江采蘋 +江面 江面 +江面上 江面上 +江韦仑 江韋侖 +池里 池裏 +污水处理厂 污水處理廠 +污蔑 污衊 +汤下面 湯下麪 +汤加里罗 湯加里羅 +汤团 湯糰 +汤姆历险记 湯姆歷險記 +汤姆斯杯 湯姆斯杯 +汤姆汉克 湯姆漢克 +汤姆索亚历险记 湯姆索亞歷險記 +汤杯 湯杯 +汤药 湯藥 +汤里来水里去 湯裏來水裏去 +汤面 湯麪 +汪少杰 汪少傑 +汪曲克 汪曲克 +汲于 汲於 +汲汲于 汲汲於 +汴梁 汴梁 +汹涌 洶湧 +汽电共生系统 汽電共生系統 +汽表 汽表 +汽车厂 汽車廠 +汽轮发电 汽輪發電 +汽轮发电机 汽輪發電機 +沃依采克 沃依采克 +沃兹尼克 沃茲尼克 +沃枝叶不如培根本 沃枝葉不如培根本 +沃达丰 沃達豐 +沃野千里 沃野千里 +沈下 沈下 +沈不住气 沈不住氣 +沈世宏 沈世宏 +沈世朋 沈世朋 +沈丘县 沈丘縣 +沈云英 沈雲英 +沈亚之 沈亞之 +沈从文 沈從文 +沈伟豪 沈偉豪 +沈传芷 沈傳芷 +沈住气 沈住氣 +沈佳颖 沈佳穎 +沈佺期 沈佺期 +沈兼士 沈兼士 +沈冤 沈冤 +沈勇 沈勇 +沈北新 沈北新 +沈北新区 沈北新區 +沈厚 沈厚 +沈吉线 瀋吉線 +沈吟 沈吟 +沈周 沈周 +沈哲鲲 沈哲鯤 +沈国放 沈國放 +沈塔尼 沈塔尼 +沈复 沈復 +沈天俞 沈天俞 +沈如峰 沈如峯 +沈家诚 沈家誠 +沈寂 沈寂 +沈富雄 沈富雄 +沈尹默 沈尹默 +沈山线 瀋山線 +沈崇诲 沈崇誨 +沈州 瀋州 +沈庆京 沈慶京 +沈庆光 沈慶光 +沈建宏 沈建宏 +沈得住气 沈得住氣 +沈思 沈思 +沈思往事 沈思往事 +沈惠珍 沈惠珍 +沈括 沈括 +沈振来 沈振來 +沈文台 沈文臺 +沈文成 沈文成 +沈明伦 沈明倫 +沈春华 沈春華 +沈昭铭 沈昭銘 +沈柏苍 沈柏蒼 +沈殿霞 沈殿霞 +沈水 瀋水 +沈没 沈沒 +沈沦 沈淪 +沈河 瀋河 +沈河区 瀋河區 +沈浊 沈濁 +沈浮 沈浮 +沈海 瀋海 +沈海铁路 瀋海鐵路 +沈浸 沈浸 +沈淀 沈澱 +沈淀出来 沈澱出來 +沈淀法 沈澱法 +沈淀物 沈澱物 +沈淑敏 沈淑敏 +沈湎 沈湎 +沈湎酒色 沈湎酒色 +沈溺 沈溺 +沈滞 沈滯 +沈滞性 沈滯性 +沈玉琳 沈玉琳 +沈璀庭 沈璀庭 +沈甸甸 沈甸甸 +沈疔 沈疔 +沈疴 沈痾 +沈痛 沈痛 +沈痼 沈痼 +沈睡 沈睡 +沈睡不醒 沈睡不醒 +沈砂池 沈砂池 +沈积 沈積 +沈积岩 沈積岩 +沈积石 沈積石 +沈筒 沈筒 +沈筱珺 沈筱珺 +沈约 沈約 +沈继昌 沈繼昌 +沈腰 沈腰 +沈腰潘鬓 沈腰潘鬢 +沈船 沈船 +沈落 沈落 +沈葆桢 沈葆楨 +沈葆祯 沈葆禎 +沈诗钧 沈詩鈞 +沈迷 沈迷 +沈迷不醒 沈迷不醒 +沈郁 沈鬱 +沈醉 沈醉 +沈重 沈重 +沈钧启 沈鈞啓 +沈钰杰 沈鈺傑 +沈闷 沈悶 +沈阳 瀋陽 +沈阳市 瀋陽市 +沈阳师范 瀋陽師範 +沈阳师范大学 瀋陽師範大學 +沈降 沈降 +沈陷 沈陷 +沈雁冰 沈雁冰 +沈雨庭 沈雨庭 +沈静 沈靜 +沈静下来 沈靜下來 +沈靳扬 沈靳揚 +沈香 沈香 +沈鱼落雁 沈魚落雁 +沈默 沈默 +沈默不语 沈默不語 +沈默寡言 沈默寡言 +沉浸于 沉浸於 +沉淀 沉澱 +沉淀剂 沉澱劑 +沉淀法 沉澱法 +沉淀物 沉澱物 +沉渐刚克 沉漸剛克 +沉湎于 沉湎於 +沉溺于 沉溺於 +沉潜刚克 沉潛剛克 +沉积岩 沉積岩 +沉迷于 沉迷於 +沉郁 沉鬱 +沉郁顿挫 沉鬱頓挫 +沉醉于 沉醉於 +沉陷于 沉陷於 +沓合 沓合 +沙仑 沙崙 +沙依巴克 沙依巴克 +沙依巴克区 沙依巴克區 +沙克 沙克 +沙克疫苗 沙克疫苗 +沙参 沙蔘 +沙发 沙發 +沙发垫 沙發墊 +沙发椅 沙發椅 +沙发牀 沙發牀 +沙坑杆 沙坑桿 +沙岩 沙岩 +沙弥 沙彌 +沙弥戒 沙彌戒 +沙河涌 沙河涌 +沙洛培克 沙洛培克 +沙漠生态系 沙漠生態系 +沙茶面 沙茶麪 +沙里夫 沙里夫 +沙里淘金 沙裏淘金 +沙雕 沙雕 +沙雕赛 沙雕賽 +沙魚涌 沙魚涌 +沟谷 溝谷 +没个出豁 沒個出豁 +没个好结果 沒個好結果 +没个开交 沒個開交 +没个是处 沒個是處 +没个见识 沒個見識 +没个里儿表儿 沒個裏兒表兒 +没个黑家白日的 沒個黑家白日的 +没乱里 沒亂裏 +没了 沒了 +没了主意 沒了主意 +没了当 沒了當 +没了指望 沒了指望 +没了期 沒了期 +没了法 沒了法 +没了王的蜜蜂 沒了王的蜜蜂 +没了经纬 沒了經緯 +没了结处 沒了結處 +没了落 沒了落 +没事干 沒事幹 +没人烟 沒人煙 +没件好当眼的 沒件好當眼的 +没体面 沒體面 +没借 沒借 +没做摆布 沒做擺佈 +没关系 沒關係 +没准 沒準 +没准儿 沒準兒 +没准头 沒準頭 +没出 沒出 +没出去 沒出去 +没出息 沒出息 +没出来 沒出來 +没出豁 沒出豁 +没出豁处 沒出豁處 +没出长 沒出長 +没升 沒升 +没合杀 沒合殺 +没合煞 沒合煞 +没合眼儿 沒合眼兒 +没后 沒後 +没后跟 沒後跟 +没向 沒向 +没回 沒回 +没回去 沒回去 +没回来 沒回來 +没地里 沒地里 +没地里巡检 沒地裏巡檢 +没处出豁 沒處出豁 +没头当 沒頭當 +没完没了 沒完沒了 +没家亲引不出外鬼来 沒家親引不出外鬼來 +没干 沒幹 +没干头 沒幹頭 +没干没净 沒乾沒淨 +没干没淨 沒乾沒淨 +没干淨 沒幹淨 +没幸 沒幸 +没张没致 沒張沒致 +没当 沒當 +没当家花花 沒當家花花 +没志气 沒志氣 +没志行 沒志行 +没念 沒念 +没意志 沒意志 +没折至 沒摺至 +没担当 沒擔當 +没摆布处 沒擺佈處 +没有人烟 沒有人煙 +没有准儿 沒有準兒 +没有差别 沒有差別 +没有来历 沒有來歷 +没有联系 沒有聯繫 +没有面目 沒有面目 +没来历 沒來歷 +没来回 沒來回 +没松下 沒鬆下 +没极奈何 沒極奈何 +没样范 沒樣範 +没梁桶 沒梁桶 +没梢干 沒梢幹 +没爷娘的祖宗 沒爺孃的祖宗 +没爹没娘 沒爹沒孃 +没种 沒種 +没签 沒簽 +没算当 沒算當 +没精打彩 沒精打彩 +没精打采 沒精打采 +没脊梁 沒脊樑 +没脸面 沒臉面 +没药 沒藥 +没见世面 沒見世面 +没见食面 沒見食面 +没讨个空处 沒討個空處 +没说出 沒說出 +没造化的种子 沒造化的種子 +没采 沒采 +没里没外 沒裏沒外 +没量斗 沒量斗 +没雕当 沒雕當 +没面子 沒面子 +没面皮 沒面皮 +没面目 沒面目 +沤郁 漚鬱 +沥干 瀝乾 +沥血之仇 瀝血之仇 +沦于 淪於 +沮舍 沮舍 +河不出图 河不出圖 +河升镇 河昇鎮 +河岳 河嶽 +河干 河干 +河曲 河曲 +河曲县 河曲縣 +河曲智叟 河曲智叟 +河梁 河梁 +河流汇集 河流匯集 +河涌 河涌 +河涸海干 河涸海乾 +河系 河系 +河落海干 河落海乾 +河谷 河谷 +河里 河裏 +河里孩儿岸上娘 河裏孩兒岸上孃 +河里淹死是会水的 河裏淹死是會水的 +河面 河面 +河面上 河面上 +油价 油價 +油伙儿 油夥兒 +油光满面 油光滿面 +油厂 油廠 +油回磨转 油回磨轉 +油头粉面 油頭粉面 +油尽灯枯 油盡燈枯 +油布 油布 +油当量 油當量 +油彩 油彩 +油斗 油鬥 +油杯 油杯 +油松 油松 +油漆未干 油漆未乾 +油烟 油煙 +油烟机 油煙機 +油电混合车 油電混合車 +油花卜 油花卜 +油茶面儿 油茶麪兒 +油表 油表 +油里滑 油裏滑 +油面 油麪 +油页岩 油頁岩 +治了 治了 +治愈 治癒 +治术 治術 +治疗炎症 治療炎症 +沽名吊誉 沽名吊譽 +沽名干誉 沽名干譽 +沽酒当炉 沽酒當爐 +沾体 霑體 +沾恩 霑恩 +沾染控制 沾染控制 +沾洽 霑洽 +沾衿 霑衿 +沿才授职 沿才授職 +沿门托钵 沿門托鉢 +沿门挨户 沿門挨戶 +泄了 泄了 +泄出 泄出 +泄出去 泄出去 +泄出来 泄出來 +泄欲 泄慾 +泅游 泅遊 +泉台 泉臺 +泉州师范学院 泉州師範學院 +泊松 泊松 +泊松分布 泊松分佈 +泌尿系统 泌尿系統 +泌水乐饥 泌水樂飢 +泐复 泐覆 +泐布 泐布 +法书要录 法書要錄 +法云 法雲 +法云地 法雲地 +法克斯 法克斯 +法兰克 法蘭克 +法兰克林 法蘭克林 +法兰克欧兹 法蘭克歐茲 +法兰克福 法蘭克福 +法兰克福学派 法蘭克福學派 +法兰克福汇报 法蘭克福匯報 +法兰克福证券交易所 法蘭克福證券交易所 +法兰克福车展 法蘭克福車展 +法出多门 法出多門 +法制 法制 +法制办公室 法制辦公室 +法制化 法制化 +法制局 法制局 +法制日报 法制日報 +法占 法佔 +法台 法臺 +法向量 法向量 +法因于敝而成于过 法因於敝而成於過 +法国共产党 法國共產黨 +法国杯 法國杯 +法坛 法壇 +法定准备率 法定準備率 +法布尔 法布爾 +法布施 法佈施 +法律制裁 法律制裁 +法律学系 法律學系 +法律系 法律系 +法律规范 法律規範 +法律面 法律面 +法念 法念 +法拉托 法拉托 +法文系 法文系 +法曲 法曲 +法术 法術 +法术无边 法術無邊 +法柜奇兵 法櫃奇兵 +法理 法理 +法系 法系 +法西斯党 法西斯黨 +法语系 法語系 +法身舍利 法身舍利 +法雨均沾 法雨均霑 +法鲁克 法魯克 +泛了 泛了 +泛亚 泛亞 +泛亮 泛亮 +泛光 泛光 +泛出 泛出 +泛出来 泛出來 +泛函 泛函 +泛动 泛動 +泛化 泛化 +泛区 泛區 +泛听 泛聽 +泛味 泛味 +泛地 泛地 +泛型 泛型 +泛微 泛微 +泛指 泛指 +泛欧 泛歐 +泛水 泛水 +泛水凌山 汎水淩山 +泛池 泛池 +泛油 泛油 +泛泛 泛泛 +泛泰 泛泰 +泛海 泛海 +泛游 泛遊 +泛湖 泛湖 +泛滥 氾濫 +泛点 泛點 +泛爱 泛愛 +泛现 泛現 +泛珠 泛珠 +泛白 泛白 +泛的 泛的 +泛着 泛着 +泛称 泛稱 +泛素 泛素 +泛红 泛紅 +泛绿 泛綠 +泛美 泛美 +泛舟 泛舟 +泛蓝 泛藍 +泛览 泛覽 +泛论 泛論 +泛读 泛讀 +泛谈 泛談 +泛起 泛起 +泛酸 泛酸 +泛青 泛青 +泛非 泛非 +泛音 泛音 +泛黄 泛黃 +泡出 泡出 +泡制 泡製 +泡杯 泡杯 +泡沫发胶 泡沫髮膠 +泡面 泡麪 +泡面哲学 泡麪哲學 +泡面市场 泡麪市場 +波光荡漾 波光盪漾 +波克夏 波克夏 +波克特 波克特 +波兰舞曲 波蘭舞曲 +波勒瓦裘克 波勒瓦裘克 +波发藻 波髮藻 +波哥里卡 波哥里卡 +波塞冬 波塞冬 +波士顿艺术博物馆 波士頓藝術博物館 +波多马克河 波多馬克河 +波娘 波娘 +波尔卡舞曲 波爾卡舞曲 +波尔布特 波爾布特 +波尔干 波爾干 +波尔干地区 波爾干地區 +波布政权 波布政權 +波布那 波布那 +波布那共和国 波布那共和國 +波形板 波形板 +波托马克河 波托馬克河 +波折 波折 +波拉克 波拉克 +波斯里亚 波斯里亞 +波来克 波來克 +波杰曼 波傑曼 +波棱菜 波棱菜 +波洛克 波洛克 +波浪周期 波浪週期 +波涌云乱 波湧雲亂 +波状云 波狀雲 +波荡 波盪 +波诡云谲 波詭雲譎 +波谲云诡 波譎雲詭 +波谷 波谷 +波里 波里 +波里尼西亚 波里尼西亞 +波里尼西亚人 波里尼西亞人 +波里斯 波里斯 +波雷罗舞曲 波雷羅舞曲 +波面 波面 +泣别 泣別 +泣别虞姬 泣別虞姬 +泥于 泥於 +泥土面 泥土面 +泥塑木雕 泥塑木雕 +泥封函谷 泥封函谷 +泥岩 泥岩 +泥板 泥板 +泥板岩 泥板岩 +泥涂 泥塗 +泥涌 泥涌 +泥灰岩 泥灰岩 +泥质岩 泥質岩 +泥质页岩 泥質頁岩 +泥铲 泥鏟 +注上 註上 +注中奖 注中獎 +注云 注云 +注儿 注兒 +注入 注入 +注入式敎学法 注入式教學法 +注冊 註冊 +注冊主任 註冊主任 +注冊单 註冊單 +注冊商标 註冊商標 +注冊手续 註冊手續 +注冊日 註冊日 +注冊用户 注冊用戶 +注冊码 註冊碼 +注冊组 註冊組 +注冊费 註冊費 +注册 註冊 +注册人 註冊人 +注册商标 註冊商標 +注册表 註冊表 +注到 注到 +注名 註名 +注塑 注塑 +注失 註失 +注子 注子 +注定 註定 +注射 注射 +注射剂 注射劑 +注射器 注射器 +注射液 注射液 +注射筒 注射筒 +注射针 注射針 +注射针头 注射針頭 +注心 注心 +注意 注意 +注意事项 注意事項 +注意到 注意到 +注意力 注意力 +注意力缺陷过动症 注意力缺陷過動症 +注意看 注意看 +注慕 注慕 +注批 註批 +注文 註文 +注明 註明 +注本 注本 +注标 註標 +注水 注水 +注油 注油 +注消 注消 +注满 注滿 +注生娘娘 註生娘娘 +注疏 註疏 +注目 注目 +注目礼 注目禮 +注脚 註腳 +注色 注色 +注视 注視 +注解 註解 +注记 註記 +注译 註譯 +注资 注資 +注释 註釋 +注重 注重 +注销 註銷 +注音 注音 +注音一式 注音一式 +注音字母 注音字母 +注音文 注音文 +注音法 注音法 +注音符号 注音符號 +泪出痛肠 淚出痛腸 +泪如泉涌 淚如泉湧 +泪容满面 淚容滿面 +泪干 淚乾 +泪干肠断 淚乾腸斷 +泪流满面 淚流滿面 +泪眼蒙眬 淚眼矇矓 +泪蜡 淚蠟 +泫然欲泣 泫然欲泣 +泫然欲泪 泫然欲淚 +泰克 泰克 +泰勒制度 泰勒制度 +泰国新娘 泰國新娘 +泰坛 泰壇 +泰坦尼克号 泰坦尼克號 +泰山北斗 泰山北斗 +泰山娘娘 泰山娘娘 +泰山梁木 泰山梁木 +泰斗 泰斗 +泰极而否 泰極而否 +泰极还生否乐处又逢悲 泰極還生否樂處又逢悲 +泰爱泰党 泰愛泰黨 +泰特斯安德洛尼克斯 泰特斯安德洛尼克斯 +泰特美术馆 泰特美術館 +泰系各族 泰系各族 +泱郁 泱鬱 +泳坛 泳壇 +泳气钟 泳氣鐘 +泻了 瀉了 +泻出 瀉出 +泻出去 瀉出去 +泻出来 瀉出來 +泻药 瀉藥 +泼出 潑出 +泼出去 潑出去 +泼出来 潑出來 +泼出胆子 潑出膽子 +泼才 潑才 +泼毛团 潑毛團 +泼烟花 潑煙花 +泼脏水 潑髒水 +泼花团 潑花團 +泼贱烟花 潑賤煙花 +泽卤 澤鹵 +泽当 澤當 +泽当镇 澤當鎮 +泽梁 澤梁 +泽渗漓而下降 澤滲灕而下降 +泽里可 澤里可 +洁面乳 潔面乳 +洁面露 潔面露 +洄暗 洄闇 +洄游 洄游 +洋参 洋蔘 +洋场恶少 洋場惡少 +洋布 洋布 +洋干漆 洋乾漆 +洋浦经济开发区 洋浦經濟開發區 +洋烟 洋菸 +洋相尽出 洋相盡出 +洋相百出 洋相百出 +洋紫苏 洋紫蘇 +洋药 洋藥 +洋蜡 洋蠟 +洋面 洋麪 +洒出 灑出 +洒向 灑向 +洒扫 灑掃 +洒水 灑水 +洒洒 灑灑 +洒涤 灑滌 +洒淅 灑淅 +洒濯 灑濯 +洒然 灑然 +洒脱 灑脫 +洗了 洗了 +洗冤集录 洗冤集錄 +洗出 洗出 +洗出作用 洗出作用 +洗出去 洗出去 +洗出来 洗出來 +洗刮 洗刮 +洗发 洗髮 +洗发乳 洗髮乳 +洗发剂 洗髮劑 +洗发动机 洗發動機 +洗发水 洗髮水 +洗发水儿 洗髮水兒 +洗发皂 洗髮皂 +洗发粉 洗髮粉 +洗发精 洗髮精 +洗发膏 洗髮膏 +洗发露 洗髮露 +洗地板 洗地板 +洗头发 洗頭髮 +洗干淨 洗乾淨 +洗心革志 洗心革志 +洗心革面 洗心革面 +洗手不干 洗手不幹 +洗手台 洗手檯 +洗炼 洗煉 +洗练 洗練 +洗脑术 洗腦術 +洗脸台 洗臉檯 +洗荡 洗盪 +洗衣板 洗衣板 +洗钱防制法 洗錢防制法 +洗面 洗面 +洗面乳 洗面乳 +洗面奶 洗面奶 +洗面皂 洗面皂 +洗面革心 洗面革心 +洛克 洛克 +洛克希德 洛克希德 +洛克希德马丁 洛克希德馬丁 +洛克斐勒 洛克斐勒 +洛克比 洛克比 +洛克菲勒 洛克菲勒 +洛克西德 洛克西德 +洛党 洛黨 +洛可可美术 洛可可美術 +洛扎 洛扎 +洛扎县 洛扎縣 +洛皮塔瀑布 洛皮塔瀑布 +洛迪克 洛迪克 +洛钟东应 洛鐘東應 +洛阳师范学院 洛陽師範學院 +洛阳才子 洛陽才子 +洞察其奸 洞察其奸 +洞山良价 洞山良价 +洞烛其奸 洞燭其奸 +洞烛奸邪 洞燭奸邪 +洞窟美术 洞窟美術 +洞见症结 洞見癥結 +洞鉴 洞鑑 +洞鉴古今 洞鑑古今 +津发 津發 +津巴布韦 津巴布韋 +津梁 津樑 +津贴制度 津貼制度 +洪万春 洪萬春 +洪信杰 洪信傑 +洪升 洪昇 +洪士杰 洪士杰 +洪复 洪覆 +洪宪帝制 洪憲帝制 +洪志善 洪志善 +洪志宏 洪志宏 +洪杰鸿 洪傑鴻 +洪泛 洪泛 +洪炉燎发 洪爐燎髮 +洪胄 洪胄 +洪若朴 洪若樸 +洪范 洪範 +洪适 洪适 +洪都百炼生 洪都百鍊生 +洪钟 洪鐘 +洲际杯 洲際盃 +洴澼药 洴澼藥 +活不了 活不了 +活了 活了 +活体肝脏移植 活體肝臟移植 +活出 活出 +活动于 活動於 +活动曲尺 活動曲尺 +活动桌面 活動桌面 +活动看板 活動看板 +活动范围 活動範圍 +活厂经营 活廠經營 +活塞杆 活塞桿 +活干 活幹 +活扣 活釦 +活泛 活泛 +活饥荒 活饑荒 +派克 派克 +派克大衣 派克大衣 +派克斯顿 派克斯頓 +派出 派出 +派出去 派出去 +派出所 派出所 +派出机关 派出機關 +派出来 派出來 +派别 派別 +派发 派發 +派团 派團 +派团参加 派團參加 +派屈克 派屈克 +派屈克节 派屈克節 +派崔克 派崔克 +派彩 派彩 +派拉蒙 派拉蒙 +派拉蒙影 派拉蒙影 +派系 派系 +派翠克 派翠克 +流个 流個 +流了 流了 +流于 流於 +流于形式 流於形式 +流云 流雲 +流亡曲 流亡曲 +流传于世 流傳於世 +流传后世 流傳後世 +流体冶金术 流體冶金術 +流出 流出 +流出去 流出去 +流出来 流出來 +流别 流別 +流向 流向 +流回 流回 +流回去 流回去 +流回来 流回來 +流域面积 流域面積 +流尽 流盡 +流布 流佈 +流干 流乾 +流当 流當 +流当品 流當品 +流征 流徵 +流氓集团 流氓集團 +流水板 流水板 +流水行云 流水行雲 +流泄出来 流泄出來 +流泛 流泛 +流注 流注 +流涎症 流涎症 +流理台 流理臺 +流离遇合 流離遇合 +流程表 流程表 +流纹岩 流紋岩 +流芳后世 流芳後世 +流苏 流蘇 +流苏帐 流蘇帳 +流苏髻 流蘇髻 +流荡 流蕩 +流荡忘反 流蕩忘反 +流血冲突 流血衝突 +流血千里 流血千里 +流血浮尸 流血浮尸 +流血漂卤 流血漂鹵 +流行于 流行於 +流行曲 流行曲 +流行歌曲 流行歌曲 +流行症 流行症 +流觞曲水 流觴曲水 +流通出来 流通出來 +流里流气 流裏流氣 +流量表 流量表 +流露出 流露出 +流露出来 流露出來 +流风余 流風餘 +流风余俗 流風餘俗 +流风余韵 流風餘韻 +流风回雪 流風迴雪 +流鱼出听 流魚出聽 +浅尝 淺嘗 淺嚐 +浅尝则止 淺嘗則止 +浅尝者 淺嘗者 +浅尝辄止 淺嘗輒止 +浅浮雕 淺浮雕 +浅淀 淺澱 +浅雕 淺雕 +浇制 澆製 +浇注 澆注 +浇漓 澆漓 +浇筑 澆築 +浊积岩 濁積岩 +浊臭熏天 濁臭熏天 +测不准 測不準 +测光表 測光表 +测出 測出 +测出来 測出來 +测地曲率 測地曲率 +测地线曲率 測地線曲率 +测录到 測錄到 +测量出 測量出 +测量术 測量術 +测量杆 測量桿 +测量范围 測量範圍 +测验卷 測驗卷 +济世之才 濟世之才 +济困 濟困 +济困扶危 濟困扶危 +济州特别自治道 濟州特別自治道 +济恶 濟惡 +济胜之具 濟勝之具 +浑个 渾個 +浑仪注 渾儀註 +浑朴 渾樸 +浑朴自然 渾樸自然 +浑身发抖 渾身發抖 +浑身发软 渾身發軟 +浑闲事 渾閒事 +浓于 濃於 +浓云 濃雲 +浓云密布 濃雲密佈 +浓发 濃髮 +浓墨重彩 濃墨重彩 +浓暗 濃暗 +浓淡适中 濃淡適中 +浓烟 濃煙 +浓血症 濃血症 +浓郁 濃郁 +浓雾密布 濃霧密佈 +浙江天台县 浙江天台縣 +浙江师范大学 浙江師範大學 +浥注 浥注 +浦发 浦發 +浩克 浩克 +浩叹 浩嘆 +浩如烟气 浩如煙氣 +浩如烟海 浩如煙海 +浩浩荡荡 浩浩蕩蕩 +浩荡 浩蕩 +浪冲 浪衝 +浪又冲 浪又衝 +浪子回头 浪子回頭 +浪子回头金不换 浪子回頭金不換 +浪板 浪板 +浪游 浪遊 +浪漫曲 浪漫曲 +浪琴表 浪琴錶 +浪荡 浪蕩 +浪荡乾坤 浪蕩乾坤 +浪荡子 浪蕩子 +浪荡子式 浪蕩子式 +浪荡灯 浪蕩燈 +浪蝶游蜂 浪蝶游蜂 +浮于 浮於 +浮云 浮雲 +浮云富贵 浮雲富貴 +浮云惊龙 浮雲驚龍 +浮云朝露 浮雲朝露 +浮云游子 浮雲遊子 +浮云翳日 浮雲翳日 +浮云蔽日 浮雲蔽日 +浮借 浮借 +浮出 浮出 +浮动汇率 浮動匯率 +浮台 浮臺 +浮吊 浮吊 +浮夸 浮誇 +浮尸 浮屍 +浮托 浮托 +浮松 浮鬆 +浮梁 浮樑 +浮梁县 浮樑縣 +浮沈 浮沈 +浮泛 浮泛 +浮游 浮游 +浮游动物 浮游動物 +浮游植物 浮游植物 +浮游生物 浮游生物 +浮现出 浮現出 +浮现出来 浮現出來 +浮签 浮簽 +浮荡 浮蕩 +浮词曲说 浮詞曲說 +浮雕 浮雕 +浮雕像 浮雕像 +浮雕墙纸 浮雕牆紙 +浮面 浮面 +浴帘 浴簾 +海上台风警报 海上颱風警報 +海上布雷 海上佈雷 +海上游 海上游 +海上采油 海上採油 +海丰 海豐 +海丰县 海豐縣 +海于格松 海于格松 +海参 海蔘 +海参威 海參威 +海参崴 海參崴 +海台 海臺 +海国图志 海國圖志 +海埔姜 海埔姜 +海宇升平 海宇昇平 +海尔布隆 海爾布隆 +海岳名言 海岳名言 +海带卷 海帶卷 +海干 海乾 +海干河尽 海乾河盡 +海平面 海平面 +海底峡谷 海底峽谷 +海底捞针 海底撈針 +海德里 海德里 +海曲 海曲 +海松 海松 +海水不可斗量 海水不可斗量 +海水淡化厂 海水淡化廠 +海水面 海水面 +海洋开发 海洋開發 +海洋温差发电 海洋溫差發電 +海洋生态系 海洋生態系 +海涂 海塗 +海涂围垦 海塗圍墾 +海淀 海淀 +海淀区 海淀區 +海淀图书城 海淀圖書城 +海湾合作理事会 海灣合作理事會 +海湾布雷 海灣佈雷 +海漂杯 海漂杯 +海百合 海百合 +海立云垂 海立雲垂 +海苔 海苔 +海蒂克伦 海蒂克倫 +海藻虫 海藻蟲 +海蚀台地 海蝕臺地 +海蚀平台 海蝕平臺 +海表 海表 +海西蒙古族藏族自治州 海西蒙古族藏族自治州 +海谷 海谷 +海里 海里 海裏 +海里海外 海裏海外 +海面 海面 +海马回 海馬迴 +海鲜面 海鮮麪 +海默症 海默症 +浸于 浸於 +浸制 浸製 +浸种 浸種 +涂上 塗上 +涂乙 塗乙 +涂了 塗了 +涂写 塗寫 +涂到 塗到 +涂刷 塗刷 +涂去 塗去 +涂善妮 涂善妮 +涂在 塗在 +涂地 塗地 +涂坤 涂坤 +涂壮勋 涂壯勳 +涂壯勳 涂壯勳 +涂天相 涂天相 +涂好 塗好 +涂姓 涂姓 +涂姓技士 塗姓技士 +涂尔干 涂爾幹 +涂层 塗層 +涂居贤 涂居賢 +涂山 塗山 +涂布 塗布 +涂序瑄 涂序瑄 +涂惠元 涂惠元 +涂惠源 涂惠源 +涂惠源雨 涂惠源雨 +涂成 塗成 +涂抹 塗抹 +涂抹诗书 塗抹詩書 +涂掉 塗掉 +涂改 塗改 +涂改无效 塗改無效 +涂敏恆 涂敏恆 +涂敏恒 涂敏恆 +涂文生 涂文生 +涂料 塗料 +涂月 涂月 +涂有 塗有 +涂来涂去 塗來塗去 +涂永辉 涂永輝 +涂油 塗油 +涂油于 塗油於 +涂泽 塗澤 +涂泽民 涂澤民 +涂浆台 塗漿檯 +涂涂 塗塗 +涂涂改改 塗塗改改 +涂消 塗消 +涂满 塗滿 +涂漆 塗漆 +涂潦 塗潦 +涂潭 塗潭 +涂澤民 涂澤民 +涂炭 塗炭 +涂炭生民 塗炭生民 +涂炭生灵 塗炭生靈 +涂着 塗着 +涂窜 塗竄 +涂粉 塗粉 +涂绍煃 涂紹煃 +涂美伦 涂美倫 +涂羽卿 涂羽卿 +涂胶 塗膠 +涂脂抹粉 塗脂抹粉 +涂色 塗色 +涂色板 塗色板 +涂药 塗藥 +涂蜡 塗蠟 +涂謹申 涂謹申 +涂说 塗說 +涂谨申 涂謹申 +涂过 塗過 +涂过去 塗過去 +涂过来 塗過來 +涂逢年 涂逢年 +涂醒哲 涂醒哲 +涂金 塗金 +涂销 塗銷 +涂長望 涂長望 +涂长望 涂長望 +涂附 塗附 +涂饰 塗飾 +涂饰剂 塗飾劑 +涂鴻欽 涂鴻欽 +涂鸦 塗鴉 +涂鸦区 塗鴉區 +涂鸭 塗鴨 +涂鸿钦 涂鴻欽 +涂黑 塗黑 +涅面 涅面 +消了 消了 +消化系统 消化系統 +消噪 消噪 +消息面 消息面 +消折 消折 +消极 消極 +消极性 消極性 +消极论 消極論 +消毒药 消毒藥 +消毒药水 消毒藥水 +消沈 消沈 +消渴症 消渴症 +消灭殆尽 消滅殆盡 +消灭淨尽 消滅淨盡 +消炎药 消炎藥 +消肿药 消腫藥 +消费价格指数 消費價格指數 +消费借贷 消費借貸 +消费合作社 消費合作社 +消费欲 消費慾 +消闲儿 消閒兒 +涉历 涉歷 +涉台 涉臺 +涉谷 涉谷 +涉足于 涉足於 +涌出 湧出 +涌出去 湧出去 +涌出来 湧出來 +涌升流 湧升流 +涌向 湧向 +涌尾 涌尾 +涌来 湧來 +涌现 湧現 +涌现出 湧現出 +涌进 湧進 +涛生云灭 濤生雲滅 +涡虫 渦蟲 +涡虫纲 渦蟲綱 +涡轮喷气发动机 渦輪噴氣發動機 +涡轮轴发动机 渦輪軸發動機 +涤尽 滌盡 +涤瑕荡垢 滌瑕盪垢 +涤瑕荡秽 滌瑕盪穢 +涤秽荡瑕 滌穢盪瑕 +涤荡 滌盪 +涤面 滌面 +润发 潤髮 +涨了 漲了 +涨价 漲價 +涨价归公 漲價歸公 +涨停板 漲停板 +涨出 漲出 +涨升 漲升 +涨回 漲回 +涨回去 漲回去 +涨回来 漲回來 +涨红了脸 漲紅了臉 +涨跌幅限制 漲跌幅限制 +涨过了头 漲過了頭 +涩谷 澀谷 +液体燃料火箭发动机 液體燃料火箭發動機 +液压千斤顶 液壓千斤頂 +液晶板 液晶板 +液晶表 液晶錶 +液面 液麪 +涳蒙 涳濛 +涸干 涸乾 +淀乃不耕之地 澱乃不耕之地 +淀北片 澱北片 +淀山 澱山 +淀山湖 澱山湖 +淀淀 澱澱 +淀积 澱積 +淀积物 澱積物 +淀粉 澱粉 +淀粉样 澱粉樣 +淀粉类 澱粉類 +淀粉类作物 澱粉類作物 +淀粉糖 澱粉糖 +淀粉脢 澱粉脢 +淀粉质 澱粉質 +淀解物 澱解物 +淀谓之滓 澱謂之滓 +淋余土 淋餘土 +淋冲 淋沖 +淋巴系统 淋巴系統 +淋淋漓漓 淋淋漓漓 +淋漓 淋漓 +淋漓尽致 淋漓盡致 +淋漓痛快 淋漓痛快 +淌板船 淌板船 +淑范 淑範 +淑郁 淑郁 +淘尽 淘盡 +淘汰制 淘汰制 +淘闲气 淘閒氣 +淡于 淡於 +淡于名利 淡於名利 +淡入淡出 淡入淡出 +淡出 淡出 +淡出淡入 淡出淡入 +淡彩 淡彩 +淡朱 淡朱 +淡水河系 淡水河系 +淡水生态系 淡水生態系 +淡蒙蒙 淡濛濛 +淨价 淨價 +淨化系统 淨化系統 +淨发 淨髮 +淨尽 淨盡 +淨水厂 淨水廠 +淨流出 淨流出 +淨胜球 淨勝球 +淨面 淨面 +淩云笔 淩雲筆 +淫念 淫念 +淫欲 淫慾 +淫游 淫遊 +淫荡 淫蕩 +淬炼 淬鍊 +淮阴师范学院 淮陰師範學院 +深于 深於 +深仇 深仇 +深仇大恨 深仇大恨 +深入敌后 深入敵後 +深入显出 深入顯出 +深入浅出 深入淺出 +深奸巨猾 深奸巨猾 +深居简出 深居簡出 +深山何处钟 深山何處鐘 +深山出俊鸟 深山出俊鳥 +深山穷谷 深山窮谷 +深念 深念 +深思极虑 深思極慮 +深恶 深惡 +深恶痛嫉 深惡痛嫉 +深恶痛绝 深惡痛絕 +深成岩 深成岩 +深文周纳 深文周納 +深暗 深暗 +深有同感 深有同感 +深沈 深沈 +深沈不露 深沈不露 +深沟墩台 深溝墩臺 +深浅不同 深淺不同 +深海烟囱 深海煙囪 +深涌 深涌 +深渊里 深淵裏 +深秋 深秋 +深色系列 深色系列 +深获 深獲 +深获好评 深獲好評 +深表 深表 +深表同情 深表同情 +深谷 深谷 +淳于 淳于 +淳于意 淳于意 +淳于髡 淳于髡 +淳朴 淳樸 +混了 混了 +混出 混出 +混出去 混出去 +混出来 混出來 +混合 混合 +混合体 混合體 +混合使用 混合使用 +混合列车 混合列車 +混合动力车 混合動力車 +混合器 混合器 +混合型 混合型 +混合失语症 混合失語症 +混合层 混合層 +混合式 混合式 +混合性 混合性 +混合感染 混合感染 +混合林 混合林 +混合模型 混合模型 +混合毒剂 混合毒劑 +混合比 混合比 +混合法 混合法 +混合泳 混合泳 +混合物 混合物 +混合疫苗 混合疫苗 +混合组 混合組 +混合经济 混合經濟 +混合结构 混合結構 +混合肥料 混合肥料 +混合裁判 混合裁判 +混合语 混合語 +混合齿列 混合齒列 +混同 混同 +混同江 混同江 +混炼 混煉 +混虫 混蟲 +混血种 混血種 +添个 添個 +添了 添了 +添枝加叶 添枝加葉 +添枝接叶 添枝接葉 +清丰 清豐 +清丰县 清豐縣 +清了 清了 +清修 清修 +清党 清黨 +清党行动 清黨行動 +清出 清出 +清发 清發 +清台 清檯 +清实录 清實錄 +清异录 清異錄 +清心寡欲 清心寡慾 +清晨杯 清晨盃 +清杆运动 清桿運動 +清査不当党产 清查不當黨產 +清水下杂面 清水下雜麪 +清水烟 清水煙 +清汤挂面 清湯掛麪 +清浊同流 清濁同流 +清理 清理 +清算斗争 清算鬥爭 +清胄 清胄 +清芬志 清芬志 +清贫寡欲 清貧寡欲 +清酒红人面财帛动人心 清酒紅人面財帛動人心 +清闲自在 清閒自在 +清静寡欲 清靜寡欲 +渊淳岳峙 淵淳嶽峙 +渊源录 淵源錄 +渊谷 淵谷 +渊鉴类函 淵鑑類函 +渍已干 漬已乾 +渐升 漸升 +渐暗 漸暗 +渔娘 漁娘 +渔梁 漁梁 +渔民团体 漁民團體 +渔获 漁獲 +渔获量 漁獲量 +渗出 滲出 +渗出来 滲出來 +渗出物 滲出物 +渗出量 滲出量 +渠冲 渠衝 +渡了 渡了 +渡假胜地 渡假勝地 +渡头云 渡頭雲 +渡海小轮 渡海小輪 +渡轮 渡輪 +渥兹尼克 渥茲尼克 +温克 溫克 +温卷 溫卷 +温州师范学院 溫州師範學院 +温布尔登 溫布爾登 +温布尔登网球公开赛 溫布爾登網球公開賽 +温布尔顿 溫布爾頓 +温布敦 溫布敦 +温布里 溫布里 +温布顿 溫布頓 +温布顿赛 溫布頓賽 +温度范围 溫度範圍 +温度表 溫度表 +温得和克 溫得和克 +温根托海 溫根托海 +温祥云 溫祥雲 +港制 港製 +港制品 港製品 +港台 港臺 +港台地区 港臺地區 +港澳台 港澳臺 +渴了 渴了 +渴念 渴念 +渴欲 渴欲 +渴饮饥餐 渴飲飢餐 +游上 游上 +游上去 游上去 +游上来 游上來 +游下 游下 +游下去 游下去 +游下来 游下來 +游丝 遊絲 +游丝飞絮 遊絲飛絮 +游中国 遊中國 +游乃海 游乃海 +游乐 遊樂 +游乐区 遊樂區 +游乐器 遊樂器 +游乐园 遊樂園 +游乐场 遊樂場 +游乐林 遊樂林 +游乡 遊鄉 +游了 遊了 +游云惊龙 遊雲驚龍 +游亚洲 遊亞洲 +游人 遊人 +游人如织 遊人如織 +游仙 遊仙 +游仙区 遊仙區 +游仙枕 遊仙枕 +游仙窟 遊仙窟 +游仙诗 遊仙詩 +游仪 遊儀 +游伴 遊伴 +游侠 遊俠 +游侠骑士 遊俠騎士 +游僧攒住持 游僧攢住持 +游兴 遊興 +游兴正浓 遊興正濃 +游冶 遊冶 +游出 游出 +游击 遊擊 +游击区 游擊區 +游击战 游擊戰 +游击手 游擊手 +游击队 游擊隊 +游刃 遊刃 +游刃有余 遊刃有餘 +游刃有馀 遊刃有餘 +游到 游到 +游动 遊動 +游勇 遊勇 +游北美 遊北美 +游历 遊歷 +游去 游去 +游台湾 遊臺灣 +游吟诗人 遊吟詩人 +游嘴光棍 遊嘴光棍 +游回 游回 +游回去 游回去 +游回来 游回來 +游园 遊園 +游园会 遊園會 +游园惊梦 遊園驚夢 +游囿伦 游囿倫 +游士 遊士 +游头浪子 遊頭浪子 +游奕 遊奕 +游女 遊女 +游子 遊子 +游子吟 遊子吟 +游子天涯 遊子天涯 +游学 遊學 +游学生 遊學生 +游完 游完 +游客 遊客 +游客如织 遊客如織 +游客止步 遊客止步 +游客量 遊客量 +游宦 遊宦 +游尘 游塵 +游尺 遊尺 +游履 游履 +游山 遊山 +游山玩水 遊山玩水 +游幕 遊幕 +游庠 遊庠 +游廊 遊廊 +游开 遊開 +游弋 遊弋 +游徼 遊徼 +游心寓目 遊心寓目 +游心骋目 遊心騁目 +游必有方 遊必有方 +游志宏 游志宏 +游惰 遊惰 +游憩 遊憩 +游憩区 遊憩區 +游戏 遊戲 +游戏三昧 遊戲三昧 +游戏业 遊戲業 +游戏人间 遊戲人間 +游戏包 遊戲包 +游戏区 遊戲區 +游戏场 遊戲場 +游戏尘寰 遊戲塵寰 +游戏机 遊戲機 +游戏机台 遊戲機檯 +游戏池 遊戲池 +游戏王 遊戲王 +游戏町 遊戲町 +游戏规则 遊戲規則 +游戏设备 遊戲設備 +游戏说 遊戲說 +游手 遊手 +游手人户 遊手人戶 +游手好闲 遊手好閒 +游手恣睢 遊手恣睢 +游手游食 遊手遊食 +游扬 遊揚 +游文宏 游文宏 +游方 遊方 +游日 遊日 +游旧 遊舊 +游明金 游明金 +游易网 遊易網 +游星 遊星 +游春 遊春 +游昭钦 游昭欽 +游来 游來 +游来游去 游來游去 +游标 遊標 +游标位置 遊標位置 +游标卡尺 遊標卡尺 +游欧洲 遊歐洲 +游民 遊民 +游民收容所 遊民收容所 +游民改造 遊民改造 +游气 遊氣 +游水 游水 +游河 遊河 +游泮 游泮 +游泳 游泳 +游泳圈 游泳圈 +游泳池 游泳池 +游泳衣 游泳衣 +游泳裤 游泳褲 +游泳课 游泳課 +游泳赛 游泳賽 +游泳镜 游泳鏡 +游泳队 游泳隊 +游泳馆 游泳館 +游游磨磨儿 遊遊磨磨兒 +游湖 遊湖 +游湖借伞 遊湖借傘 +游澳洲 遊澳洲 +游牧 遊牧 +游牧区 遊牧區 +游牧民族 遊牧民族 +游猎 遊獵 +游玩 遊玩 +游畋 遊畋 +游皓玮 游皓瑋 +游盈隆 游盈隆 +游益网 遊益網 +游目 遊目 +游目骋怀 遊目騁懷 +游离 遊離 +游离份子 遊離份子 +游离层 遊離層 +游离电子 遊離電子 +游离票 遊離票 +游离辐射 遊離輻射 +游禽类 游禽類 +游移 遊移 +游移不决 遊移不決 +游移不定 遊移不定 +游程 遊程 +游网 遊網 +游美洲 遊美洲 +游耕 遊耕 +游船 遊船 +游艇 遊艇 +游艇业 遊艇業 +游艇业者 遊艇業者 +游艺 遊藝 +游艺会 遊藝會 +游艺团 遊藝團 +游艺场 遊藝場 +游花插趣 遊花插趣 +游芳来 游芳來 +游荡 遊蕩 +游荡不归 遊蕩不歸 +游营撞尸 遊營撞屍 +游蜂戏蝶 遊蜂戲蝶 +游蜂浪蝶 遊蜂浪蝶 +游行 遊行 +游行到 遊行到 +游行法 遊行法 +游行示众 遊行示衆 +游行示威 遊行示威 +游衍 遊衍 +游街 遊街 +游街示众 遊街示衆 +游观 遊觀 +游览 遊覽 +游览区 遊覽區 +游览胜地 遊覽勝地 +游览车 遊覽車 +游言 遊言 +游记 遊記 +游说 遊說 +游说团 遊說團 +游说团体 遊說團體 +游谈 遊談 +游谈无根 遊談無根 +游资 遊資 +游资氾滥 遊資氾濫 +游赏 遊賞 +游走 遊走 +游踪 遊蹤 +游轮 遊輪 +游辞 遊辭 +游辞浮说 遊辭浮說 +游过 遊過 +游过去 游過去 +游过来 游過來 +游进 遊進 +游进去 游進去 +游进来 游進來 +游逛 遊逛 +游遍 遊遍 +游错 遊錯 +游锡 遊錫 +游锡坤 游錫坤 +游锡堃 游錫堃 +游锡昆 游錫昆 +游隼 遊隼 +游非洲 遊非洲 +游食 遊食 +游食之民 遊食之民 +游香港 遊香港 +游骑 遊騎 +游骑兵 遊騎兵 +游骑兵队 遊騎兵隊 +游骑无归 遊騎無歸 +游魂 遊魂 +游鱼 游魚 +游鸿儒 游鴻儒 +游鸿明 游鴻明 +游龙 游龍 +游龙戏凤 游龍戲鳳 +游龙荣 游龍榮 +渺无人烟 渺無人煙 +湖北师范学院 湖北師範學院 +湖南师范大学 湖南師範大學 +湖州师范学院 湖州師範學院 +湖里 湖裏 +湖里区 湖裏區 +湖面 湖面 +湘帘 湘簾 +湘累 湘累 +湘绣 湘繡 +湛江师范学院 湛江師範學院 +湟潦生苹 湟潦生苹 +湮灭证据 湮滅證據 +湮郁 湮鬱 +湾里 灣裏 +湾里区 灣裏區 +湿地松 溼地松 +湿度表 溼度表 +湿肉伴干柴 溼肉伴乾柴 +溃于 潰於 +溅了 濺了 +源于 源於 +源汇区 源匯區 +源泉万斛 源泉萬斛 +源自于 源自於 +溜个 溜個 +溜了 溜了 +溜冰团 溜冰團 +溜出 溜出 +溜出去 溜出去 +溜出来 溜出來 +溜回 溜回 +溜回去 溜回去 +溜回来 溜回來 +溜溜秋秋 溜溜秋秋 +溜滑板 溜滑板 +溜须 溜鬚 +溜须拍马 溜鬚拍馬 +溟蒙 溟濛 +溢于 溢於 +溢于言表 溢於言表 +溢价 溢價 +溢出 溢出 +溢出来 溢出來 +溢恶 溢惡 +溥天同庆 溥天同慶 +溪涌 溪涌 +溪谷 溪谷 +溯游 溯游 +溲面 溲麪 +溶于 溶於 +溶合 溶合 +溶岩 溶岩 +溶岩流 溶岩流 +溶液聚合 溶液聚合 +溶溶荡荡 溶溶蕩蕩 +溺于 溺於 +溺志 溺志 +溺谷 溺谷 +滃郁 滃鬱 +滇西纵谷 滇西縱谷 +滋补药品 滋補藥品 +滑了 滑了 +滑了一跤 滑了一跤 +滑借 滑藉 +滑出 滑出 +滑出跑道 滑出跑道 +滑动面 滑動面 +滑回 滑回 +滑杆 滑桿 +滑板 滑板 +滑板运动 滑板運動 +滑水板 滑水板 +滑铲 滑鏟 +滑雪术 滑雪術 +滑雪板 滑雪板 +滔滔不尽 滔滔不盡 +滔荡 滔蕩 +滚了 滾了 +滚出 滾出 +滚出去 滾出去 +滚出来 滾出來 +滚回 滾回 +滚回去 滾回去 +滚回来 滾回來 +滚彩蛋 滾彩蛋 +滚成一团 滾成一團 +滚杠 滾槓 +滚杯 滾杯 +滚石合唱团 滾石合唱團 +滞后 滯後 +滞后现象 滯後現象 +满了 滿了 +满于 滿於 +满出 滿出 +满出来 滿出來 +满口称赞 滿口稱讚 +满口胡扯 滿口胡扯 +满口胡柴 滿口胡柴 +满口胡言 滿口胡言 +满口胡说 滿口胡說 +满口脏话 滿口髒話 +满场一致 滿場一致 +满坑满谷 滿坑滿谷 +满城尽带黄金甲 滿城盡帶黃金甲 +满堂彩 滿堂彩 +满天星斗 滿天星斗 +满头洋发 滿頭洋髮 +满好个 滿好個 +满山满谷 滿山滿谷 +满布 滿布 +满布疑云 滿佈疑雲 +满当当 滿當當 +满怀心腹事尽在不言中 滿懷心腹事盡在不言中 +满拚自尽 滿拚自盡 +满杯 滿杯 +满洲里 滿洲里 +满洲里市 滿洲裏市 +满满当当 滿滿當當 +满脸溅朱 滿臉濺朱 +满腹才学 滿腹才學 +满腹疑云 滿腹疑雲 +满面 滿面 +满面堆笑 滿面堆笑 +满面怒容 滿面怒容 +满面愁容 滿面愁容 +满面春生 滿面春生 +满面春风 滿面春風 +满面杀气 滿面殺氣 +满面生春 滿面生春 +满面生花 滿面生花 +满面笑容 滿面笑容 +满面红胀 滿面紅脹 +满面羞惭 滿面羞慚 +满面羞愧 滿面羞愧 +满面通红 滿面通紅 +满面雪霜 滿面雪霜 +满面飞红 滿面飛紅 +滤出 濾出 +滤出去 濾出去 +滤出来 濾出來 +滥发 濫發 +滨松市 濱松市 +滩涂 灘塗 +滴了 滴了 +滴了天 滴了天 +滴修都速 滴修都速 +滴出 滴出 +滴出来 滴出來 +滴向 滴向 +滴干 滴乾 +滴水漏斗 滴水漏斗 +滴注 滴注 +滴羞都苏 滴羞都蘇 +滴苏 滴蘇 +滴虫 滴蟲 +滴里嘟噜 滴里嘟嚕 +滴里搭拉 滴里搭拉 +滴里耷拉 滴里耷拉 +漂了 漂了 +漂向 漂向 +漂布 漂布 +漂摆 漂擺 +漂游 漂游 +漂荡 漂盪 +漂荡子弟 漂蕩子弟 +漆了 漆了 +漆出 漆出 +漆器雕 漆器雕 +漆布 漆布 +漆雕 漆雕 +漆黑一团 漆黑一團 +漏了 漏了 +漏了眼 漏了眼 +漏借 漏借 +漏出 漏出 +漏出去 漏出去 +漏出来 漏出來 +漏尽 漏盡 +漏尽更阑 漏盡更闌 +漏尽通 漏盡通 +漏斗 漏斗 +漏斗器 漏斗器 +漏斗状花冠 漏斗狀花冠 +漏斗管 漏斗管 +漏斗胸 漏斗胸 +漏洞百出 漏洞百出 +漏电保护接地极插座 漏電保護接地極插座 +漏网游鱼 漏網游魚 +漏脯充饥 漏脯充飢 +漏针 漏針 +漏面贼 漏面賊 +漓水 灕水 +漓江 灕江 +漓湘 灕湘 +漓漓拉拉 漓漓拉拉 +漓然 灕然 +演个 演個 +演出 演出 +演出人 演出人 +演出地点 演出地點 +演出来 演出來 +演出者 演出者 +演化出 演化出 +演员表 演員表 +演奏出 演奏出 +演奏台 演奏臺 +演奏曲 演奏曲 +演武修文 演武修文 +演绎出 演繹出 +演讲台 演講臺 +漕挽 漕輓 +漫出 漫出 +漫出来 漫出來 +漫卷 漫卷 +漫天叫价 漫天叫價 +漫天开价 漫天開價 +漫天索价 漫天索價 +漫天要价就地还钱 漫天要價就地還錢 +漫天讨价 漫天討價 +漫布 漫布 +漫录 漫錄 +漫无节制 漫無節制 +漫无限制 漫無限制 +漫游 漫遊 +漫游四方 漫遊四方 +漫游费 漫遊費 +漱口杯 漱口杯 +漱口药水 漱口藥水 +漳州师范学院 漳州師範學院 +漾出 漾出 +潇洒 瀟灑 +潘太克斯 潘太克斯 +潘威志 潘威誌 +潘安白发 潘安白髮 +潘岳 潘岳 +潘嶽白发 潘嶽白髮 +潘谷 潘谷 +潘越云 潘越雲 +潘连周 潘連周 +潘金莲给武松敬酒 潘金蓮給武松敬酒 +潘鬓沈腰 潘鬢沈腰 +潜了 潛了 +潜修 潛修 +潜出 潛出 +潜出去 潛出去 +潜出来 潛出來 +潜台词 潛臺詞 +潜回 潛回 +潜意识历程 潛意識歷程 +潜意识里 潛意識裏 +潜水夫症 潛水夫症 +潜水表 潛水錶 +潜水钟 潛水鐘 +潜水钟表 潛水鐘錶 +潜游 潛游 +潜移暗化 潛移暗化 +潜蛟困凤 潛蛟困鳳 +潟卤 潟鹵 +潭祉叶吉 潭祉叶吉 +潭里 潭裏 +潮力发电 潮力發電 +潮烟 潮菸 +澄澹精致 澄澹精致 +澎湖天后宫 澎湖天后宮 +澒蒙 澒濛 +澥谷 澥谷 +澳新军团 澳新軍團 +澳新军团日 澳新軍團日 +澳洲广播电台 澳洲廣播電臺 +澳门汇业 澳門匯業 +澹台 澹臺 +澹台灭明 澹臺滅明 +澹彩 澹彩 +澹泊寡欲 澹泊寡欲 +澹泊明志 澹泊明志 +澹荡 澹盪 +激于 激於 +激于义愤 激於義憤 +激光二极管 激光二極管 +激出 激出 +激发 激發 +激发出 激發出 +激发出来 激發出來 +激发态 激發態 +激发注射 激發注射 +激发起 激發起 +激发起来 激發起來 +激活整合模型 激活整合模型 +激荡 激盪 +激荡不已 激盪不已 +激荡出 激盪出 +激进党 激進黨 +濒临绝种 瀕臨絕種 +濒于 瀕於 +濒于绝境 瀕於絕境 +濒于绝种 瀕於絕種 +濒危物种 瀕危物種 +濒危野生动植物种国际贸易公约 瀕危野生動植物種國際貿易公約 +濠梁 濠梁 +瀍河回族区 瀍河回族區 +瀑布 瀑布 +瀑布区 瀑布區 +瀑布群 瀑布羣 +瀛台 瀛臺 +瀛表 瀛表 +灌个 灌個 +灌了 灌了 +灌于 灌於 +灌云 灌雲 +灌云县 灌雲縣 +灌出 灌出 +灌出去 灌出去 +灌出来 灌出來 +灌制 灌製 +灌向 灌向 +灌回 灌回 +灌回去 灌回去 +灌录 灌錄 +灌注 灌注 +灌注器 灌注器 +灌溉系统 灌溉系統 +灌溉面积 灌溉面積 +灌药 灌藥 +火中取栗 火中取栗 +火了 火了 +火云 火雲 +火云邪 火雲邪 +火力发电 火力發電 +火力发电厂 火力發電廠 +火山岩 火山岩 +火山爆发 火山爆發 +火山爆发指数 火山爆發指數 +火并 火併 +火彩儿 火彩兒 +火成岩 火成岩 +火折子 火摺子 +火斗 火斗 +火杯 火盃 +火柴杆 火柴桿 +火海战术 火海戰術 +火灭烟消 火滅煙消 +火炬松 火炬松 +火烟 火煙 +火烧云 火燒雲 +火症 火症 +火种 火種 +火签 火籤 +火箭发动 火箭發動 +火箭喷射推进系统 火箭噴射推進系統 +火箭布雷 火箭佈雷 +火绳杆 火繩桿 +火耕水种 火耕水種 +火耕流种 火耕流種 +火药 火藥 +火药味 火藥味 +火药味甚浓 火藥味甚濃 +火药库 火藥庫 +火虫儿 火蟲兒 +火里火去水里水去 火裏火去水裏水去 +火里火发 火裏火發 +火里赤 火裏赤 +火链片 火鏈片 +灭不个 滅不個 +灭尸 滅屍 +灭尽 滅盡 +灭种 滅種 +灭种罪 滅種罪 +灭绝种族 滅絕種族 +灭罪修因 滅罪修因 +灭虫剂 滅蟲劑 +灭虫宁 滅蟲寧 +灯台 燈臺 +灯台不照自己 燈臺不照自己 +灯台不自照 燈臺不自照 +灯彩 燈綵 +灯杆 燈杆 +灯杯 燈杯 +灯火万家 燈火萬家 +灯火管制 燈火管制 +灰云 灰雲 +灰发 灰髮 +灰同协 灰同協 +灰头土面 灰頭土面 +灰头草面 灰頭草面 +灰姑娘 灰姑娘 +灰岩残丘 灰巖殘丘 +灰暗 灰暗 +灰灰暗暗 灰灰暗暗 +灰灰蒙蒙 灰灰濛濛 +灰胡 灰鬍 +灰蒙 灰濛 +灰蒙蒙 灰濛濛 +灰面鵟鹰 灰面鵟鷹 +灰飞烟灭 灰飛煙滅 +灵丹圣药 靈丹聖藥 +灵丹妙药 靈丹妙藥 +灵修 靈脩 +灵台 靈臺 +灵台县 靈臺縣 +灵坛 靈壇 +灵欲 靈慾 +灵药 靈藥 +灵谷寺 靈谷寺 +灵迹 靈蹟 +灸术 灸術 +灸阳谷 灸陽谷 +灾后 災後 +灾害链 災害鏈 +灿烂多彩 燦爛多彩 +炆面 炆麪 +炉台 爐臺 +炊烟 炊煙 +炊烟袅袅 炊煙裊裊 +炊臼之戚 炊臼之鏚 +炎日当空 炎日當空 +炎症 炎症 +炎症性 炎症性 +炒栗子 炒栗子 +炒汇 炒匯 +炒菜铲 炒菜鏟 +炒面 炒麪 +炒面块子 炒麪塊子 +炕席 炕蓆 +炕面砖 炕面磚 +炖了 燉了 +炖药 燉藥 +炭水化合物 炭水化合物 +炭疽杆菌 炭疽桿菌 +炮制 炮製 +炮台 炮臺 +炮炼 炮煉 +炳烛夜游 炳燭夜遊 +炸出 炸出 +炸毁 炸燬 +炸药 炸藥 +炸药箱 炸藥箱 +炸酱面 炸醬麪 +点个 點個 +点了 點了 +点出 點出 +点出去 點出去 +点出来 點出來 +点击一个链接 點擊一個鏈接 +点半钟 點半鐘 +点发 點發 +点名表 點名表 +点回 點回 +点回去 點回去 +点回来 點回來 +点多钟 點多鐘 +点将录 點將錄 +点扎 點扎 +点播曲 點播曲 +点染云烟 點染雲煙 +点核 點核 +点烟 點菸 +点烟器 點菸器 +点线面 點線面 +点里 點裏 +点钟 點鐘 +点集合 點集合 +点面结合 點面結合 +点饥 點飢 +炼丹 煉丹 +炼丹八卦炉 煉丹八卦爐 +炼丹术 煉丹術 +炼之未定 煉之未定 +炼乳 煉乳 +炼冶 鍊冶 +炼制 煉製 +炼制厂 煉製廠 +炼化 煉化 +炼句 煉句 +炼字 煉字 +炼山 煉山 +炼师 鍊師 +炼度 鍊度 +炼形 煉形 +炼气 煉氣 +炼汞 鍊汞 +炼油 煉油 +炼油厂 煉油廠 +炼焦 煉焦 +炼焦厂 煉焦廠 +炼焦炉 煉焦爐 +炼焦煤 煉焦煤 +炼狱 煉獄 +炼石 煉石 +炼石补天 煉石補天 +炼糖 煉糖 +炼糖厂 煉糖廠 +炼药 煉藥 +炼贫 鍊貧 +炼金 鍊金 +炼金术 鍊金術 +炼钢 鍊鋼 +炼钢业 鍊鋼業 +炼钢厂 鍊鋼廠 +炼钢炉 鍊鋼爐 +炼铁 鍊鐵 +炼铁厂 鍊鐵廠 +炼铁炉 鍊鐵爐 +炼铜 鍊銅 +炼铜厂 鍊銅廠 +炼铝 鍊鋁 +炽热火山云 熾熱火山雲 +烂了嘴 爛了嘴 +烂了舌头 爛了舌頭 +烂板乌龟 爛板烏龜 +烂板洋钱 爛板洋錢 +烂游 爛遊 +烈日当空 烈日當空 +烈火干柴 烈火乾柴 +烘了 烘了 +烘云托月 烘雲托月 +烘制 烘製 +烘干 烘乾 +烘干机 烘乾機 +烘托 烘托 +烘托出 烘托出 +烘板 烘板 +烘熏 烘燻 +烛台 燭臺 +烛杯 燭杯 +烛穗 燭穗 +烝尝 烝嘗 +烟丝 菸絲 +烟云 煙雲 +烟云供养 煙雲供養 +烟云过眼 煙雲過眼 +烟供 煙供 +烟傢伙 煙傢伙 +烟具 煙具 +烟农 菸農 +烟卷 菸捲 +烟卷儿 菸捲兒 +烟厂 菸廠 +烟台 煙臺 +烟台地区 煙臺地區 +烟台市 煙臺市 +烟台师范学院 煙臺師範學院 +烟叶 菸葉 +烟合包 煙合包 +烟味 煙味 +烟商 煙商 +烟嘴 菸嘴 +烟嘴儿 菸嘴兒 +烟囱 煙囪 +烟圈 菸圈 +烟土 煙土 +烟夜蛾 煙夜蛾 +烟头 菸頭 +烟子 煙子 +烟客 煙客 +烟害 菸害 +烟尘 煙塵 +烟屁股 菸屁股 +烟岚 煙嵐 +烟岚云岫 煙嵐雲岫 +烟岸 煙岸 +烟幕 煙幕 +烟幕弹 煙幕彈 +烟户 煙戶 +烟斗 菸斗 +烟斗丝 菸斗絲 +烟景 煙景 +烟月 煙月 +烟月场 煙月場 +烟月牌 煙月牌 +烟机 煙機 +烟杆 煙桿 +烟枪 煙槍 +烟枪洞 煙槍洞 +烟柱 煙柱 +烟树 煙樹 +烟毒 煙毒 +烟毒犯 煙毒犯 +烟民 菸民 +烟气 煙氣 +烟油 煙油 +烟泡 煙泡 +烟波 煙波 +烟波万顷 煙波萬頃 +烟波客 煙波客 +烟波浩渺 煙波浩渺 +烟波钓叟 煙波釣叟 +烟波钓徒 煙波釣徒 +烟海 煙海 +烟消云散 煙消雲散 +烟消冰释 煙消冰釋 +烟消火灭 煙消火滅 +烟消雾散 煙消霧散 +烟渚 煙渚 +烟火 煙火 +烟火之警 煙火之警 +烟火气 煙火氣 +烟火秀 煙火秀 +烟火节 煙火節 +烟火邻居 煙火鄰居 +烟火食 煙火食 +烟灯 煙燈 +烟灰 菸灰 +烟灰缸 菸灰缸 +烟煤 煙煤 +烟煴 煙熅 +烟熏 煙燻 +烟熏妆 煙燻妝 +烟熏火燎 煙熏火燎 +烟燄障天 煙燄障天 +烟爨 煙爨 +烟生喉舌 煙生喉舌 +烟瘴 煙瘴 +烟瘾 煙癮 +烟盒 煙盒 +烟硝 煙硝 +烟硝味 煙硝味 +烟碱 菸鹼 +烟碱酸 菸鹼酸 +烟禁 菸禁 +烟穗 煙穗 +烟突 煙突 +烟窝 煙窩 +烟笼雾锁 煙籠霧鎖 +烟筒 煙筒 +烟筒山 煙筒山 +烟管 煙管 +烟管面 煙管麪 +烟篷 煙篷 +烟粉 煙粉 +烟纸店 菸紙店 +烟缕 煙縷 +烟缸 菸缸 +烟肉 煙肉 +烟膏 煙膏 +烟臭 煙臭 +烟臭味 煙臭味 +烟花 煙花 +烟花债 煙花債 +烟花厂 煙花廠 +烟花场 煙花場 +烟花女 煙花女 +烟花寨 煙花寨 +烟花寨主 煙花寨主 +烟花巷 煙花巷 +烟花市 煙花市 +烟花柳巷 煙花柳巷 +烟花窟 煙花窟 +烟花簿 煙花簿 +烟花粉柳 煙花粉柳 +烟花粉黛 煙花粉黛 +烟花行院 煙花行院 +烟花门户 煙花門戶 +烟花队 煙花隊 +烟花阵 煙花陣 +烟花风月 煙花風月 +烟苗 煙苗 +烟草 菸草 +烟草味 菸草味 +烟蒂 菸蒂 +烟蓑雨笠 煙蓑雨笠 +烟蚜 菸蚜 +烟袋 菸袋 +烟袋哨子 菸袋哨子 +烟袋嘴 菸袋嘴 +烟袋嘴儿 菸袋嘴兒 +烟袋杆儿 菸袋桿兒 +烟袋油子 菸袋油子 +烟袋荷包 菸袋荷包 +烟袋锅子 菸袋鍋子 +烟视媚行 煙視媚行 +烟酒 菸酒 +烟酒不沾 煙酒不沾 +烟酒公卖 菸酒公賣 +烟酒公卖局 菸酒公賣局 +烟酒税 菸酒稅 +烟酸 煙酸 +烟锅 煙鍋 +烟雨 煙雨 +烟雨楼 煙雨樓 +烟雾 煙霧 +烟雾剂 煙霧劑 +烟雾弥漫 煙霧瀰漫 +烟雾弹 煙霧彈 +烟雾症 煙霧症 +烟雾迷漫 煙霧迷漫 +烟霏 煙霏 +烟霏雾集 煙霏霧集 +烟霏露结 煙霏露結 +烟霞 煙霞 +烟霞外人 煙霞外人 +烟霞痼疾 煙霞痼疾 +烟霞癖 煙霞癖 +烟霭 煙靄 +烟霾 煙霾 +烟飞星散 煙飛星散 +烟馆 煙館 +烟鬟 煙鬟 +烟鬼 煙鬼 +烤个 烤個 +烤了 烤了 +烤干 烤乾 +烤晒 烤曬 +烤漆板 烤漆板 +烤烟 烤煙 +烤胡椒香肠 烤胡椒香腸 +烤面包 烤麪包 +烤面包机 烤麪包機 +烦了 煩了 +烦复 煩複 +烦恼皆因强出头 煩惱皆因強出頭 +烦死了 煩死了 +烧了 燒了 +烧出 燒出 +烧出去 燒出去 +烧出来 燒出來 +烧制 燒製 +烧尽 燒盡 +烧干 燒乾 +烧录 燒錄 +烧录器 燒錄器 +烧录机 燒錄機 +烧杯 燒杯 +烧杯架 燒杯架 +烧毁 燒燬 +烧炼 燒煉 +烧糊了洗脸水 燒糊了洗臉水 +烩面 燴麪 +烫一个发 燙一個髮 +烫一次发 燙一次髮 +烫个 燙個 +烫个发 燙個髮 +烫出 燙出 +烫发 燙髮 +烫发师 燙髮師 +烫头发 燙頭髮 +烫完发 燙完髮 +烫次发 燙次髮 +烫蜡 燙蠟 +烫衣板 燙衣板 +烫面 燙麪 +烬余 燼餘 +热出病来 熱出病來 +热功当量 熱功當量 +热发光剂量计 熱發光劑量計 +热合 熱合 +热干面 熱乾麪 +热当量 熱當量 +热核 熱核 +热电厂 熱電廠 +热症 熱症 +热脉冲 熱脈衝 +热药 熱藥 +热衷于 熱衷於 +热量表 熱量表 +热闹哄哄 熱鬧哄哄 +烹制 烹製 +烹调术 烹調術 +烽火台 烽火臺 +烽烟 烽煙 +烽烟四起 烽煙四起 +烽烟四起战火纷飞 烽煙四起戰火紛飛 +烽烟遍地 烽煙遍地 +焉耆回族自治县 焉耆回族自治縣 +焊了 焊了 +焊出 焊出 +焊接艺术 焊接藝術 +焕别 煥別 +焕发 煥發 +焕发起来 煥發起來 +焙干 焙乾 +焚修 焚修 +焚化厂 焚化廠 +焚尸 焚屍 +焚尸扬灰 焚屍揚灰 +焚尸案 焚屍案 +焚尸炉 焚屍爐 +焚毁 焚燬 +無言不仇 無言不讎 +焦了 焦了 +焦化厂 焦化廠 +焦干 焦乾 +焦急万分 焦急萬分 +焦获 焦穫 +焦虑症 焦慮症 +焦面大士 焦面大士 +焰彩 焰彩 +然后 然後 +然后就 然後就 +然身死才数月耳 然身死纔數月耳 +煅炼 煅煉 +煎个 煎個 +煎了 煎了 +煎出 煎出 +煎药 煎藥 +煎药法 煎藥法 +煎蛋卷 煎蛋卷 +煎面 煎麪 +煞费周章 煞費周章 +煤核 煤核 +煤气工厂 煤氣工廠 +煤气表 煤氣表 +煤烟 煤煙 +煤系 煤系 +煤铲 煤鏟 +照个 照個 +照了 照了 +照价 照價 +照价征税 照價徵稅 +照价收买 照價收買 +照价收购 照價收購 +照价赔偿 照價賠償 +照入签 照入籤 +照准 照準 +照出 照出 +照出去 照出去 +照出来 照出來 +照占 照佔 +照发 照發 +照台 照臺 +照后镜 照後鏡 +照录 照錄 +照相制版 照相製版 +照相干片 照相乾片 +照相术 照相術 +照签 照簽 +照签不误 照簽不誤 +照表 照表 +照面 照面 +煨干 煨乾 +煨干就湿 煨乾就溼 +煨干避湿 煨乾避溼 +煮个 煮個 +煮出 煮出 +煮出来 煮出來 +煮字疗饥 煮字療飢 +煮沸后 煮沸後 +煮熟的鸭子飞了 煮熟的鴨子飛了 +煮粥焚须 煮粥焚鬚 +煮面 煮麪 +煴斗 熅斗 +熄了 熄了 +熊克武 熊克武 +熊据虎跱 熊據虎跱 +熏习 熏習 +熏人 燻人 +熏制 熏製 +熏天 熏天 +熏染 薰染 +熏沐 薰沐 +熏烝 熏烝 +熏烤 燻烤 +熏熏 熏熏 +熏笼 熏籠 +熏肉 燻肉 +熏腐 熏腐 +熏草 燻草 +熏草纸 燻草紙 +熏蒸 燻蒸 +熏蒸剂 熏蒸劑 +熏蒸室 熏蒸室 +熏衣 薰衣 +熏衣草 薰衣草 +熏赫 燻赫 +熏鑪 燻鑪 +熏陶 薰陶 +熏陶成性 熏陶成性 +熏风 薰風 +熏风徐来 熏風徐來 +熏香 薰香 +熏鱼儿 燻魚兒 +熏鸡 燻雞 +熏黑 燻黑 +熏黑了 燻黑了 +熔于 熔於 +熔合 熔合 +熔岩 熔岩 +熔岩流 熔岩流 +熔岩湖 熔岩湖 +熔岩穹丘 熔岩穹丘 +熔核 熔核 +熔毁 熔燬 +熔炼 熔鍊 +熔炼炉 熔煉爐 +熔融岩浆 熔融岩漿 +熟了 熟了 +熟念 熟念 +熟药 熟藥 +熟读王叔和不如临症多 熟讀王叔和不如臨症多 +熟面人 熟面人 +熟面孔 熟面孔 +熨斗 熨斗 +熬出 熬出 +熬出头 熬出頭 +熬出来 熬出來 +熬制 熬製 +熬姜呷醋 熬薑呷醋 +熬炼 熬煉 +熬药 熬藥 +熬药汤 熬藥湯 +燃尽 燃盡 +燃料处理厂 燃料處理廠 +燃料组合 燃料組合 +燃气电厂 燃氣電廠 +燎发 燎髮 +燔针 燔針 +燕云十六州 燕雲十六州 +燕几 燕几 +燕台 燕臺 +燕巢于幕 燕巢於幕 +燕昭筑台 燕昭築臺 +燕游 燕遊 +燕燕于飞 燕燕于飛 +燕雀安知鸿鹄之志 燕雀安知鴻鵠之志 +燕雀焉知鸿鹄之志 燕雀焉知鴻鵠之志 +爆出 爆出 +爆发 爆發 +爆发出 爆發出 +爆发出来 爆發出來 +爆发力 爆發力 +爆发性 爆發性 +爆发星 爆發星 +爆发音 爆發音 +爆扣 爆扣 +爆破术 爆破術 +爬出 爬出 +爬出去 爬出去 +爬出来 爬出來 +爬升 爬升 +爬回 爬回 +爬满了 爬滿了 +爬虫 爬蟲 +爬虫动物 爬蟲動物 +爬虫类 爬蟲類 +爬虫类动物 爬蟲類動物 +爰历篇 爰歷篇 +爱丽丝梦游记 愛麗絲夢遊記 +爱丽丝漫游奇境记 愛麗絲漫遊奇境記 +爱丽舍宫 愛麗捨宮 +爱之欲其生恶之欲其死 愛之欲其生惡之欲其死 +爱之适足以害之 愛之適足以害之 +爱乐乐团 愛樂樂團 +爱了 愛了 +爱别离苦 愛別離苦 +爱困 愛睏 +爱在心里 愛在心裏 +爱幸 愛幸 +爱弥儿 愛彌兒 +爱彼表 愛彼錶 +爱德蒙 愛德蒙 +爱心刮刮乐 愛心刮刮樂 +爱心彩券 愛心彩券 +爱念 愛念 +爱恶分明 愛惡分明 +爱情征服一切 愛情征服一切 +爱情里 愛情裏 +爱才 愛才 +爱才好士 愛才好士 +爱才如命 愛才如命 +爱才若渴 愛才若渴 +爱抽烟 愛抽菸 +爱欲 愛慾 +爱游玩 愛遊玩 +爱管闲事 愛管閒事 +爱莫大于心死 愛莫大於心死 +爱远恶近 愛遠惡近 +爱里 愛裏 +爱面子 愛面子 +爲了 爲了 +爲幸 爲幸 +爲恶 爲惡 +爵仇 爵仇 +父党 父黨 +父台 父臺 +父子同牝 父子同牝 +父权制 父權制 +父母两系血统主义 父母兩系血統主義 +父母在不远游 父母在不遠游 +父系 父系 +父系亲属 父系親屬 +父系制度 父系制度 +爷娘 爺孃 +爷羹娘饭 爺羹孃飯 +爷饭娘羹 爺飯孃羹 +爹娘 爹孃 +爽荡 爽蕩 +牀头柜 牀頭櫃 +牀头金尽 牀頭金盡 +片云遮顶 片雲遮頂 +片价 片價 +片善小才 片善小才 +片头曲 片頭曲 +片尾曲 片尾曲 +片岩 片岩 +片甲不回 片甲不回 +片石千钧 片石千鈞 +片纸只字 片紙隻字 +片言只字 片言隻字 +片言只语 片言隻語 +片言折狱 片言折獄 +片语只字 片語隻字 +片语只辞 片語隻辭 +片面 片面 +片面之言 片面之言 +片面之词 片面之詞 +片面性 片面性 +片面最惠国 片面最惠國 +片麻岩 片麻岩 +版筑 版築 +版面 版面 +牉合 牉合 +牌价 牌價 +牌子曲 牌子曲 +牌板 牌板 +牌面 牌面 +牒发 牒發 +牖里 牖里 +牙买加胡椒 牙買加胡椒 +牙克石 牙克石 +牙克石市 牙克石市 +牙医系 牙醫系 +牙后慧 牙後慧 +牙周 牙周 +牙周炎 牙周炎 +牙周病 牙周病 +牙机巧制 牙機巧制 +牙板 牙板 +牙签 牙籤 +牙签万轴 牙籤萬軸 +牙签犀轴 牙籤犀軸 +牙签玉轴 牙籤玉軸 +牙签锦轴 牙籤錦軸 +牙籤万轴 牙籤萬軸 +牙缝里 牙縫裏 +牙虫 牙蟲 +牙雕 牙雕 +牙齿咬合不正 牙齒咬合不正 +牛仔布 牛仔布 +牛只 牛隻 +牛后 牛後 +牛回磨转 牛回磨轉 +牛头马面 牛頭馬面 +牛李党争 牛李黨爭 +牛柳面 牛柳麪 +牛肉干 牛肉乾 +牛肉拉面 牛肉拉麪 +牛肉汤面 牛肉湯麪 +牛肉炒面 牛肉炒麪 +牛肉面 牛肉麪 +牛肉面节 牛肉麪節 +牛舍 牛舍 +牛表牛觔 牛表牛觔 +牛角挂书 牛角掛書 +牛角面包 牛角麪包 +牛骥同一皁 牛驥同一皁 +牛骥同槽 牛驥同槽 +牛骥同皁 牛驥同皁 +牛骥同皂 牛驥同皂 +牡丹虽好全仗绿叶扶 牡丹雖好全仗綠葉扶 +牡丹虽好全仗绿叶扶持 牡丹雖好全仗綠葉扶持 +牡丹虽好全凭绿叶扶持 牡丹雖好全憑綠葉扶持 +牡丹虽好终须绿叶扶持 牡丹雖好終須綠葉扶持 +牢靠妥当 牢靠妥當 +牧神午后 牧神午後 +物产丰富 物產豐富 +物件导向 物件導向 +物价 物價 +物价指数 物價指數 +物价督导会报 物價督導會報 +物尽其用 物盡其用 +物极则衰 物極則衰 +物极必反 物極必反 +物欲 物慾 +物欲世界 物慾世界 +物欲横流 物慾橫流 +物流系统 物流系統 +物理 物理 +物理系 物理系 +物种 物種 +物种来由 物種來由 +物种起源 物種起源 +物美价廉 物美價廉 +物腐虫生 物腐蟲生 +物色人才 物色人才 +物阜民丰 物阜民豐 +牲干下 牲幹下 +牵一发 牽一髮 +牵一发而动全身 牽一髮而動全身 +牵三挂四 牽三掛四 +牵了 牽了 +牵五挂四 牽五掛四 +牵出 牽出 +牵出去 牽出去 +牵出来 牽出來 +牵制 牽制 +牵制行动 牽制行動 +牵合 牽合 +牵合附会 牽合附會 +牵回 牽回 +牵回去 牽回去 +牵回来 牽回來 +牵引出 牽引出 +牵引发电机 牽引發電機 +牵彩 牽彩 +牵心挂肠 牽心掛腸 +牵念 牽念 +牵挂 牽掛 +牵机药 牽機藥 +牵籐带叶 牽籐帶葉 +牵系 牽繫 +牵肚挂肠 牽肚掛腸 +牵肠挂肚 牽腸掛肚 +特于 特於 +特价 特價 +特价品 特價品 +特价菜 特價菜 +特使团 特使團 +特克斯 特克斯 +特克斯县 特克斯縣 +特克斯市 特克斯市 +特克斯河 特克斯河 +特内里费 特內里費 +特准 特准 +特出 特出 +特别 特別 +特别任务连 特別任務連 +特别公积 特別公積 +特别公积金 特別公積金 +特别刑法 特別刑法 +特别助理 特別助理 +特别卖力 特別賣力 +特别号 特別號 +特别奖 特別獎 +特别客串 特別客串 +特别座 特別座 +特别待遇 特別待遇 +特别感谢 特別感謝 +特别扣除额 特別扣除額 +特别护士 特別護士 +特别护理 特別護理 +特别报导 特別報導 +特别报道 特別報道 +特别提款权 特別提款權 +特别是 特別是 +特别来宾 特別來賓 +特别法 特別法 +特别版 特別版 +特别组 特別組 +特别股 特別股 +特别致 特別緻 +特别节目 特別節目 +特别行政区 特別行政區 +特别费 特別費 +特别费案 特別費案 +特别长 特別長 +特别门诊 特別門診 +特制 特製 +特制住 特制住 +特制品 特製品 +特制定 特制定 +特制止 特制止 +特制订 特制訂 +特地回 特地回 +特征 特徵 +特征值 特徵值 +特征向量 特徵向量 +特征多项式 特徵多項式 +特征联合 特徵聯合 +特惠价 特惠價 +特惠制度 特惠制度 +特技团 特技團 +特效药 特效藥 +特有种 特有種 +特松加 特松加 +特林布 特林布 +特殊性向 特殊性向 +特殊才能 特殊才能 +特种 特種 +特种作战 特種作戰 +特种兵 特種兵 +特种工艺 特種工藝 +特种文书 特種文書 +特种空勤团 特種空勤團 +特种考试 特種考試 +特种行业 特種行業 +特种警察 特種警察 +特种部队 特種部隊 +特种钢 特種鋼 +特艺彩色 特藝彩色 +特蒙德 特蒙德 +特里 特里 +特里尔 特里爾 +犁板 犁板 +犬只 犬隻 +犬牙相制 犬牙相制 +犯了 犯了 +犯台 犯臺 +犯奸 犯奸 +犯恶 犯惡 +犯罪团伙 犯罪團伙 +犯罪集团 犯罪集團 +犵党 犵黨 +状态参数 狀態參數 +状态表 狀態表 +犹太历 猶太曆 +犹太复国主义 猶太復國主義 +犹太复国主义者 猶太復國主義者 +犹太复国运动 猶太復國運動 +犹如表 猶如錶 +犹如钟 猶如鐘 +犹如钟表 猶如鐘錶 +狂占 狂佔 +狂并潮 狂併潮 +狂想曲 狂想曲 +狂搜 狂搜 +狂牛症 狂牛症 +狂花病叶 狂花病葉 +狂荡 狂蕩 +狂药 狂藥 +狃于 狃於 +狃于成见 狃於成見 +狄仁杰 狄仁傑 +狄克 狄克 +狄克森 狄克森 +狄志杰 狄志杰 +狄拉克 狄拉克 +狄里斯 狄里斯 +狎妓冶游 狎妓冶游 +狎游 狎遊 +狐借虎威 狐藉虎威 +狐朋狗党 狐朋狗黨 +狐群狗党 狐羣狗黨 +狐裘蒙戎 狐裘蒙戎 +狗党狐群 狗黨狐羣 +狗占马坑 狗占馬坑 +狗口里吐不出象牙 狗口裏吐不出象牙 +狗嘴里 狗嘴裏 +狗嘴里还有象牙 狗嘴裏還有象牙 +狗娘养的 狗孃養的 +狗才 狗才 +狗扣 狗釦 +狗杂种 狗雜種 +狗皮膏药 狗皮膏藥 +狗链 狗鏈 +狞恶 獰惡 +狞恶可怖 獰惡可怖 +狠了 狠了 +狠干 狠幹 +狠恶 狠惡 +独具只眼 獨具隻眼 +独出一时 獨出一時 +独出心裁 獨出心裁 +独出机杼 獨出機杼 +独占 獨佔 +独占事业 獨佔事業 +独占市场 獨佔市場 +独占性 獨佔性 +独占权 獨佔權 +独占花魁 獨佔花魁 +独占资本 獨佔資本 +独占鳌头 獨佔鰲頭 +独占鼇头 獨佔鼇頭 +独唱曲 獨唱曲 +独奏曲 獨奏曲 +独尊儒术 獨尊儒術 +独当 獨當 +独当一面 獨當一面 +独挑大梁 獨挑大樑 +独擅胜场 獨擅勝場 +独曲 獨曲 +独根孤种 獨根孤種 +独步当时 獨步當時 +独立党 獨立黨 +独立出来 獨立出來 +独立千古 獨立千古 +独立国家联合体 獨立國家聯合體 +独立悬吊系统 獨立懸吊系統 +独自个 獨自個 +独辟蹊径 獨闢蹊徑 +独钟 獨鍾 +狭心症 狹心症 +狭谷 狹谷 +狮坛 獅壇 +狮身人面像 獅身人面像 +狱里 獄裏 +狼仆 狼僕 +狼卜食 狼卜食 +狼吞虎咽 狼吞虎嚥 +狼心狗幸 狼心狗幸 +狼来了 狼來了 +狼烟 狼煙 +狼烟四起 狼煙四起 +狼狈万状 狼狽萬狀 +狼狈为奸 狼狽爲奸 +狼虎药 狼虎藥 +狼飧虎咽 狼飧虎嚥 +狼餐虎咽 狼餐虎嚥 +猎狩终极 獵狩終極 +猎获 獵獲 +猎获物 獵獲物 +猛个劲 猛個勁 +猛于 猛於 +猛冲 猛衝 +猛升 猛升 +猛可里 猛可裏 +猛回头 猛回頭 +猛地里 猛地裏 +猛干 猛幹 +猛药 猛藥 +猜三划五 猜三划五 +猜出 猜出 +猜出来 猜出來 +猜得出 猜得出 +猜测出 猜測出 +猝发 猝發 +猢狲入布袋 猢猻入布袋 +猥当大任 猥當大任 +猪八戒吃人参果 豬八戒吃人參果 +猪只 豬隻 +猪肉干 豬肉乾 +猪肝面 豬肝麪 +猪脚面 豬腳麪 +猪脚面线 豬腳麪線 +猪舌面 豬舌麪 +猪舍 豬舍 +猪链球菌 豬鏈球菌 +猪链球菌病 豬鏈球菌病 +猫儿见了鱼鲜饭 貓兒見了魚鮮飯 +猫鼠同眠 貓鼠同眠 +猫鼠游戏 貓鼠遊戲 +献丑 獻醜 +献了 獻了 +献出 獻出 +献台 獻臺 +猴面包 猴麪包 +猴面包树 猴麪包樹 +猿鹤沙虫 猿鶴沙蟲 +猿鹤虫沙 猿鶴蟲沙 +獑胡 獑胡 +獠面 獠面 +玄了 玄了 +玄云 玄雲 +玄冬 玄冬 +玄制 玄製 +玄参 玄蔘 +玄机暗藏 玄機暗藏 +玄武岩 玄武岩 +玄武质熔岩 玄武質熔岩 +玄胄 玄胄 +玄针 玄鍼 +玄黄翻复 玄黃翻覆 +率先垂范 率先垂範 +率同 率同 +率团 率團 +率团参加 率團參加 +率土同庆 率土同慶 +玉制 玉製 +玉勒雕鞍 玉勒雕鞍 +玉卮无当 玉卮無當 +玉历 玉曆 +玉参差 玉參差 +玉台 玉臺 +玉台体 玉臺體 +玉台新咏 玉臺新詠 +玉叶金枝 玉葉金枝 +玉叶金柯 玉葉金柯 +玉叶金花 玉葉金花 +玉尺量才 玉尺量才 +玉山杯 玉山杯 +玉帘 玉簾 +玉手纤纤 玉手纖纖 +玉斗 玉斗 +玉杯 玉杯 +玉枝卜寿 玉枝卜壽 +玉石同沉 玉石同沉 +玉石同烬 玉石同燼 +玉石同焚 玉石同焚 +玉米淀粉 玉米澱粉 +玉米面 玉米麪 +玉米须 玉米鬚 +玉纤 玉纖 +玉虫 玉蟲 +玉里 玉里 +玉里镇 玉里鎮 +玉镜台 玉鏡臺 +玉雕 玉雕 +玉面 玉面 +玉面貍 玉面貍 +王于真 王于真 +王云五 王雲五 +王佐之才 王佐之才 +王余鱼 王餘魚 +王侯后 王侯后 +王公贵戚 王公貴戚 +王制 王制 +王台 王臺 +王后 王后 +王太后 王太后 +王婆卖瓜自卖自夸 王婆賣瓜自賣自誇 +王婆子卖了磨 王婆子賣了磨 +王子犯法与庶民同罪 王子犯法與庶民同罪 +王子面 王子麪 +王干发 王乾發 +王幸男 王幸男 +王庄 王莊 +王彩桦 王彩樺 +王彩碧 王彩碧 +王志华 王志華 +王志文 王志文 +王志群 王志羣 +王志贞 王志貞 +王杰 王傑 +王杰胜 王傑勝 +王正杰 王正杰 +王母娘娘 王母娘娘 +王涂发 王塗發 +王熙松 王熙松 +王献极 王獻極 +王秋凤 王秋鳳 +王者风范 王者風範 +王茂松 王茂松 +王蒙 王蒙 +王鉴 王鑑 +玛斯克 瑪斯克 +玛曲 瑪曲 +玛曲县 瑪曲縣 +玛泰克 瑪泰克 +玢岩 玢岩 +玩了 玩了 +玩具厂 玩具廠 +玩出 玩出 +玩出去 玩出去 +玩出来 玩出來 +玩团 玩團 +玩忽 翫忽 +玩物丧志 玩物喪志 +环保斗士 環保鬥士 +环安系 環安系 +环工系 環工系 +环扣 環扣 +环极涡旋 環極渦旋 +环游 環遊 +环游世界 環遊世界 +环球定位系统 環球定位系統 +环面 環面 +环顾四周 環顧四周 +现于 現於 +现代修正主义 現代修正主義 +现代建筑 現代建築 +现代舞团 現代舞團 +现代艺术 現代藝術 +现代集团 現代集團 +现出 現出 +现出原形 現出原形 +现出原身 現出原身 +现制性 現制性 +现场表演 現場表演 +现场采访 現場採訪 +现实面 現實面 +现货价 現貨價 +现进现出 現進現出 +现金流量表 現金流量表 +玳梁 玳梁 +玳瑁梁 玳瑁梁 +玻璃布 玻璃布 +玻璃杯 玻璃杯 +玻璃板 玻璃板 +玻璃柜 玻璃櫃 +玻璃浮雕 玻璃浮雕 +玻璃纤维 玻璃纖維 +玻里尼西 玻里尼西 +玻里尼西亚人 玻里尼西亞人 +珂里 珂里 +珊卓布拉克 珊卓布拉克 +珊瑚虫 珊瑚蟲 +珍同拱璧 珍同拱璧 +珍娜杰克森 珍娜傑克森 +珍珠岩 珍珠岩 +珍珠项链 珍珠項鍊 +珍肴异馔 珍餚異饌 +珐瑯彩 琺瑯彩 +珠帘 珠簾 +珠斗烂班 珠斗爛班 +珠联璧合 珠聯璧合 +珠胎暗结 珠胎暗結 +珠还合浦 珠還合浦 +班代表 班代表 +班克劳夫 班克勞夫 +班克拉夫特 班克拉夫特 +班克斯 班克斯 +班兰叶 班蘭葉 +班别 班別 +班师回朝 班師回朝 +班游 班遊 +班艾伏列克 班艾伏列克 +班艾佛列克 班艾佛列克 +班里 班裏 +球台 球檯 +球后 球后 +球后小 球后小 +球后艾宁 球后艾寧 +球后辛吉丝 球后辛吉絲 +球团 球團 +球团矿 球團礦 +球坛 球壇 +球坛上 球壇上 +球杆 球杆 +球状星团 球狀星團 +球面 球面 +球面三角 球面三角 +球面体 球面體 +球面几何 球面幾何 +球面几何学 球面幾何學 +球面镜 球面鏡 +琅邪台刻石 琅邪臺刻石 +理一个发 理一個髮 +理一次发 理一次髮 +理不胜辞 理不勝辭 +理个 理個 +理个发 理個髮 +理了 理了 +理事长杯 理事長盃 +理出 理出 +理出头绪 理出頭緒 +理发 理髮 +理发匠 理髮匠 +理发厅 理髮廳 +理发员 理髮員 +理发师 理髮師 +理发师傅 理髮師傅 +理发店 理髮店 +理发院 理髮院 +理合 理合 +理固当然 理固當然 +理头发 理頭髮 +理完发 理完髮 +理当 理當 +理当如此 理當如此 +理念 理念 +理所当然 理所當然 +理次发 理次髮 +理胡子 理鬍子 +理致 理致 +琉璃厂 琉璃廠 +琐才 瑣才 +琛板 琛板 +琨玉秋霜 琨玉秋霜 +琴弦 琴絃 +琴断朱弦 琴斷朱絃 +琴斯托霍瓦 琴斯托霍瓦 +琴杆 琴桿 +琴钟 琴鐘 +琵琶别抱 琵琶別抱 +琵琶录 琵琶錄 +琵琶虫 琵琶蟲 +琼台玉宇 瓊臺玉宇 +琼台玉阁 瓊臺玉閣 +琼枝玉叶 瓊枝玉葉 +琼瑶曲 瓊瑤曲 +瑜伽术 瑜伽術 +瑜珈术 瑜珈術 +瑞丰 瑞豐 +瑞云 瑞雲 +瑞克 瑞克 +瑞克希 瑞克希 +瑞士卷 瑞士捲 +瑞征 瑞徵 +瑞气祥云 瑞氣祥雲 +瑞秋 瑞秋 +瑞秋怀兹 瑞秋懷茲 +瑞穗 瑞穗 +瑞穗乡 瑞穗鄉 +瑞签 瑞簽 +瑞贝里 瑞貝里 +瑞郎方面 瑞郎方麪 +瑟瑟发抖 瑟瑟發抖 +瑟瑟秋风 瑟瑟秋風 +瑶台 瑤臺 +瑶台琼室 瑤臺瓊室 +瑶台银阙 瑤臺銀闕 +瑶台镜 瑤臺鏡 +瑶签 瑤籤 +璅虫 璅蟲 +璧合 璧合 +璧合珠联 璧合珠聯 +璧合珠连 璧合珠連 +璧回 璧回 +璧炉台 璧爐臺 +瓠叶 瓠葉 +瓢虫 瓢蟲 +瓦利泰克 瓦利泰克 +瓦历斯 瓦歷斯 +瓦合 瓦合 +瓦合之卒 瓦合之卒 +瓦尔基里 瓦爾基里 +瓦尔达克 瓦爾達克 +瓦尔达克省 瓦爾達克省 +瓦当 瓦當 +瓦当文 瓦當文 +瓦拉干 瓦拉干 +瓦松 瓦松 +瓦特表 瓦特表 +瓦瑞泰克 瓦瑞泰克 +瓦舍 瓦舍 +瓦萨里 瓦薩里 +瓦西里 瓦西里 +瓦西里耶维奇 瓦西裏耶維奇 +瓦解云散 瓦解雲散 +瓦达克 瓦達克 +瓦里 瓦里 +瓦里斯 瓦里斯 +瓮安 甕安 +瓶坠簪折 瓶墜簪折 +瓷杯 瓷杯 +甄别 甄別 +甄别考试 甄別考試 +甄后 甄后 +甄奇录异 甄奇錄異 +甄才品能 甄才品能 +甄选人才 甄選人才 +甕尽杯干 甕盡杯乾 +甕里醯鸡 甕裏醯雞 +甘于 甘於 +甘居下游 甘居下游 +甘巴里 甘巴里 +甘当 甘當 +甘心情愿 甘心情願 +甘愿 甘願 +甘托克 甘托克 +甘谷 甘谷 +甘谷县 甘谷縣 +甚么 甚麼 +甚么都干 甚麼都幹 +甚于 甚於 +甚至于 甚至於 +甚获 甚獲 +甚获好评 甚獲好評 +甜水面 甜水麪 +甜萝卜 甜蘿蔔 +甜面酱 甜麪醬 +甜面醬 甜麪醬 +生个 生個 +生了 生了 +生于 生於 +生于忧患 生於憂患 +生于忧患死于安乐 生於憂患死於安樂 +生产合作 生產合作 +生产合作社 生產合作社 +生产斗争 生產鬥爭 +生产管制 生產管制 +生佛万家 生佛萬家 +生出 生出 +生出来 生出來 +生刍致祭 生芻致祭 +生别死离 生別死離 +生力面 生力麪 +生华发 生華髮 +生发 生髮 +生发剂 生髮劑 +生发水 生髮水 +生发药 生髮藥 +生同衾死同穴 生同衾死同穴 +生命不息战斗不止 生命不息戰鬥不止 +生命共同体 生命共同體 +生命周期 生命週期 +生命在于运动 生命在於運動 +生命征象 生命徵象 +生命表 生命表 +生姜 生薑 +生姜丝 生薑絲 +生姜汁 生薑汁 +生姜片 生薑片 +生字表 生字表 +生布 生布 +生态旅游 生態旅遊 +生态环境游 生態環境游 +生态系 生態系 +生态系统 生態系統 +生情发意 生情發意 +生技医药 生技醫藥 +生旦淨末丑 生旦淨末丑 +生栋复屋 生棟覆屋 +生死别离 生死別離 +生死斗 生死鬥 +生死未卜 生死未卜 +生死轮回 生死輪迴 +生殖洄游 生殖洄游 +生殖系统 生殖系統 +生民涂炭 生民塗炭 +生活杯 生活杯 +生活水准 生活水準 +生活面 生活面 +生涯规划 生涯規劃 +生灵涂地 生靈塗地 +生灵涂炭 生靈塗炭 +生物伦琴当量 生物倫琴當量 +生物制剂 生物製劑 +生物制品 生物製品 +生物合成 生物合成 +生物学系 生物學系 +生物弹药 生物彈藥 +生物技术 生物技術 +生物技术与制药工业发展推动小组 生物技術與製藥工業發展推動小組 +生物时钟 生物時鐘 +生物系 生物系 +生物钟 生物鐘 +生理 生理 +生理时钟 生理時鐘 +生田斗 生田斗 +生离死别 生離死別 +生药 生藥 +生药局 生藥局 +生词表 生詞表 +生迭水准 生迭水準 +生锈 生鏽 +生长板 生長板 +生面 生面 +生面团 生麪糰 +生面孔 生面孔 +用一当十 用一當十 +用不了 用不了 +用于 用於 +用于修饰 用於修飾 +用作配种 用作配種 +用出 用出 +用字不当 用字不當 +用尽 用盡 +用尽心思 用盡心思 +用尽心机 用盡心機 +用尽方法 用盡方法 +用幸福 用幸福 +用志不分 用志不分 +用户数据 用戶數據 +用户界面 用戶界面 +用报台 用報臺 +用搜 用搜 +用来配种 用來配種 +用汇 用匯 +用舍失宜 用舍失宜 +用舍行藏 用舍行藏 +用药 用藥 +用行舍藏 用行舍藏 +用词不当 用詞不當 +甩出 甩出 +甩出去 甩出去 +甩出来 甩出來 +甩发 甩髮 +甩手掌柜 甩手掌櫃 +甪里 甪里 +田园交响曲 田園交響曲 +田园曲 田園曲 +田字面 田字面 +田家庵 田家庵 +田家庵区 田家庵區 +田庄 田莊 +田志兴 田志興 +田梁子 田梁子 +田父之获 田父之獲 +田秋堇 田秋堇 +田种玉 田種玉 +田舍 田舍 +田舍奴 田舍奴 +田舍翁 田舍翁 +田舍郎 田舍郎 +田螺含水过冬 田螺含水過冬 +田谷 田穀 +田里 田裏 +由于 由於 +由余 由余 +由恪志远 由恪志遠 +由表及里 由表及裏 +甲壳虫 甲殼蟲 +甲壳虫类 甲殼蟲類 +甲板 甲板 +甲种 甲種 +甲种体位 甲種體位 +甲种国库券 甲種國庫券 +甲种国民兵役 甲種國民兵役 +甲种维生素 甲種維生素 +甲第连云 甲第連雲 +甲胄 甲冑 +甲胄鱼类 甲冑魚類 +甲虫 甲蟲 +甲虫类 甲蟲類 +甲虫车 甲蟲車 +申复 申覆 +申扎 申扎 +申扎县 申扎縣 +申曲 申曲 +申请表 申請表 +电价 電價 +电冰柜 電冰櫃 +电冲 電衝 +电力厂 電力廠 +电卷星飞 電卷星飛 +电卷风驰 電卷風馳 +电厂 電廠 +电压表 電壓表 +电台 電臺 +电唱针 電唱針 +电复 電覆 +电子云 電子雲 +电子反制 電子反制 +电子学系 電子學系 +电子店面 電子店面 +电子数据交换 電子數據交換 +电子杂志 電子雜誌 +电子游戏 電子遊戲 +电子看板 電子看板 +电子系 電子系 +电子表 電子錶 +电子表单 電子表單 +电子表情 電子表情 +电子表格 電子表格 +电子表示 電子表示 +电子论坛 電子論壇 +电子邮件系统 電子郵件系統 +电子钟 電子鐘 +电子钟表 電子鐘錶 +电宰厂 電宰廠 +电度表 電度表 +电影分级制 電影分級制 +电影制作 電影製作 +电影制片 電影製片 +电影台 電影臺 +电影回顾展 電影回顧展 +电影美术 電影美術 +电影艺术 電影藝術 +电影集团 電影集團 +电机及电子学工程师联合会 電機及電子學工程師聯合會 +电机系 電機系 +电杆 電杆 +电板 電板 +电极 電極 +电检制 電檢制 +电汇 電匯 +电池厂 電池廠 +电池板 電池板 +电流表 電流表 +电热杯 電熱杯 +电熨斗 電熨斗 +电码表 電碼表 +电磁干扰 電磁干擾 +电磁振荡 電磁振盪 +电磁脉冲 電磁脈衝 +电线杆 電線杆 +电缆调制解调器 電纜調制解調器 +电胡刀 電鬍刀 +电脑与电话系统整合 電腦與電話系統整合 +电脑互动艺术 電腦互動藝術 +电脑台 電腦檯 +电脑周边设备 電腦周邊設備 +电脑图书出版业 電腦圖書出版業 +电脑彩喷 電腦彩噴 +电脑游戏 電腦遊戲 +电脑看板 電腦看板 +电脑系统 電腦系統 +电脑系统业 電腦系統業 +电脑绘图技术 電腦繪圖技術 +电脑网志 電腦網誌 +电脑艺术 電腦藝術 +电脑闸道系统 電腦閘道系統 +电荷耦合 電荷耦合 +电荷耦合器件 電荷耦合器件 +电表 電錶 +电视兴奋症 電視興奮症 +电视台 電視臺 +电视柜 電視櫃 +电视游乐器 電視遊樂器 +电视采访 電視採訪 +电话录音 電話錄音 +电话答录机 電話答錄機 +电路板 電路板 +电量表 電量表 +电针 電針 +电针麻醉 電針麻醉 +电钟 電鐘 +电铲 電鏟 +电须刀 電鬚刀 +男仆 男僕 +男佣 男傭 +男佣人 男傭人 +男同学 男同學 +男同志 男同志 +男大当婚 男大當婚 +男女有别 男女有別 +男尸 男屍 +男性厌恶 男性厭惡 +男才女貌 男才女貌 +男生宿舍 男生宿舍 +男用表 男用錶 +男系 男系 +甸后 甸後 +画了 畫了 +画出 畫出 +画出来 畫出來 +画卷 畫卷 +画坛 畫壇 +画布 畫布 +画板 畫板 +画栋雕梁 畫棟雕樑 +画栋飞云 畫棟飛雲 +画梁雕栋 畫樑雕棟 +画法几何 畫法幾何 +画着 畫着 +画表 畫表 +画表格 畫表格 +画阁朱楼 畫閣朱樓 +画面 畫面 +画饼充饥 畫餅充飢 +畅所欲为 暢所欲爲 +畅所欲言 暢所欲言 +畅游 暢遊 +畅销曲 暢銷曲 +界分别观 界分別觀 +界别 界別 +界面 界面 +畎亩下才 畎畝下才 +畏于 畏於 +畏影恶迹 畏影惡跡 +留个 留個 +留中不发 留中不發 +留了 留了 +留余地 留餘地 +留出 留出 +留别 留別 +留发 留髮 +留后 留後 +留后手 留後手 +留后步 留後步 +留后路 留後路 +留头发 留頭髮 +留念 留念 +留种 留種 +留种地 留種地 +留美同学会 留美同學會 +留胡子 留鬍子 +留胡须 留鬍鬚 +留脸面 留臉面 +留芳千古 留芳千古 +留芳后世 留芳後世 +留言板 留言板 +留连不舍 留連不捨 +留针 留針 +留面子 留面子 +畚斗 畚斗 +略低于 略低於 +略同 略同 +略大于 略大於 +略尽情谊 略盡情誼 +略无参商 略無參商 +略有出入 略有出入 +略胜 略勝 +略胜一筹 略勝一籌 +略语表 略語表 +略高于 略高於 +番泻叶 番瀉葉 +畸形发展 畸形發展 +疋先里 疋先裏 +疏于 疏於 +疏于防备 疏於防備 +疏于防范 疏於防範 +疏松 疏鬆 +疏松症 疏鬆症 +疑云 疑雲 +疑云重重 疑雲重重 +疑信参半 疑信參半 +疑凶 疑兇 +疑团 疑團 +疑心生暗鬼 疑心生暗鬼 +疑念 疑念 +疑核 疑核 +疑系 疑係 +疑难杂症 疑難雜症 +疗饥 療飢 +疟原虫 瘧原蟲 +疟虫 瘧蟲 +疥癣虫 疥癬蟲 +疥虫 疥蟲 +疯了 瘋了 +疱疹性咽狭症 皰疹性咽狹症 +疲于 疲於 +疲于奔命 疲於奔命 +疲劳极限 疲勞極限 +疲劳症 疲勞症 +疲困 疲睏 +疵蒙谬累 疵蒙謬累 +疾之如仇 疾之如仇 +疾之若仇 疾之若仇 +疾恶 疾惡 +疾恶好善 疾惡好善 +疾恶如仇 疾惡如仇 +疾恶若仇 疾惡若仇 +疾病控制中心 疾病控制中心 +疾病突发 疾病突發 +疾风扫秋叶 疾風掃秋葉 +病了 病了 +病从口入祸从口出 病從口入禍從口出 +病余 病餘 +病出 病出 +病历 病歷 +病历卡 病歷卡 +病历室 病歷室 +病历表 病歷表 +病原虫 病原蟲 +病发 病發 +病后 病後 +病后初愈 病後初愈 +病后初癒 病後初癒 +病容满面 病容滿面 +病征 病徵 +病愈 病癒 +病毒血症 病毒血症 +病毒防范 病毒防範 +病理 病理 +病症 病症 +病舍 病舍 +病虫 病蟲 +病虫危害 病蟲危害 +病虫害 病蟲害 +症侯群 症侯羣 +症候 症候 +症候群 症候羣 +症状 症狀 +症状性 症狀性 +症结 癥結 +症结点 癥結點 +痊愈 痊癒 +痒了 癢了 +痒疹 癢疹 +痒痒 癢癢 +痔核 痔核 +痕迹 痕跡 +痖弦 瘂弦 +痘疹娘娘 痘疹娘娘 +痛不欲生 痛不欲生 +痛了 痛了 +痛失英才 痛失英才 +痛快淋漓 痛快淋漓 +痛恶 痛惡 +痛毁极诋 痛毀極詆 +痛苦万分 痛苦萬分 +痛赞 痛贊 +痢疾杆菌 痢疾桿菌 +痨虫 癆蟲 +痫症 癇症 +痰症 痰症 +痲痹不了 痲痹不了 +痲痺不了 痲痺不了 +痴呆症 癡呆症 +痴念 癡念 +痴虫 癡蟲 +瘅恶彰善 癉惡彰善 +瘙痒症 瘙癢症 +瘦了 瘦了 +瘦小枯干 瘦小枯乾 +瘫子掉在井里 癱子掉在井裏 +癌症 癌症 +癌症病患 癌症病患 +癌症肿瘤 癌症腫瘤 +癒合 癒合 +癫痫症 癲癇症 +癸丑 癸丑 +登个 登個 +登了 登了 +登云梯 登雲梯 +登出 登出 +登出去 登出去 +登出来 登出來 +登台 登臺 +登台拜将 登臺拜將 +登台演唱 登臺演唱 +登台表演 登臺表演 +登坛 登壇 +登坛拜将 登壇拜將 +登峰造极 登峯造極 +登庸人才 登庸人才 +登录 登錄 +登机手续柜台 登機手續櫃檯 +登极 登極 +登科录 登科錄 +登记表 登記表 +登革出血热 登革出血熱 +登龙术 登龍術 +發表 發表 +白了了 白了了 +白云 白雲 +白云乡 白雲鄉 +白云亲舍 白雲親舍 +白云区 白雲區 +白云孤飞 白雲孤飛 +白云山 白雲山 +白云岩 白雲岩 +白云机场 白雲機場 +白云母 白雲母 +白云片片 白雲片片 +白云石 白雲石 +白云矿区 白雲礦區 +白云苍狗 白雲蒼狗 +白云观 白雲觀 +白僵蚕 白殭蠶 +白兔捣药 白兔搗藥 +白净面皮 白淨面皮 +白刀子进去红刀子出来 白刀子進去紅刀子出來 +白化症 白化症 +白千层 白千層 +白卷 白卷 +白发 白髮 +白发人 白髮人 +白发其事 白發其事 +白发如新 白髮如新 +白发朱颜 白髮朱顏 +白发相守 白髮相守 +白发红颜 白髮紅顏 +白发苍苍 白髮蒼蒼 +白发苍颜 白髮蒼顏 +白发郎潜 白髮郎潛 +白发银须 白髮銀鬚 +白发青衫 白髮青衫 +白发齐眉 白髮齊眉 +白变种 白變種 +白古苏花 白古蘇花 +白合金 白合金 +白喉杆菌 白喉桿菌 +白团 白團 +白团扇 白團扇 +白垩系 白堊系 +白娘子 白娘子 +白布 白布 +白干 白乾 白幹 +白干儿 白乾兒 +白当 白當 +白得发亮 白得發亮 +白搽白折 白搽白折 +白斑症 白斑症 +白日升天 白日昇天 +白日飞升 白日飛昇 +白术 白朮 +白朴 白樸 +白杆兵 白桿兵 +白松 白松 +白板 白板 +白板单吊 白板單吊 +白板天子 白板天子 +白板笔 白板筆 +白果松 白果松 +白洋淀 白洋淀 +白淨面皮 白淨面皮 +白烟 白煙 +白皮松 白皮松 +白种 白種 +白种人 白種人 +白粉面 白粉麪 +白胡 白鬍 +白胡椒 白胡椒 +白色人种 白色人種 +白色系 白色系 +白苏 白蘇 +白苹 白蘋 +白苹洲 白蘋洲 +白药 白藥 +白菜价 白菜價 +白萝卜 白蘿蔔 +白蒙蒙 白濛濛 +白蜡 白蠟 +白蜡明经 白蠟明經 +白蜡杆子 白蠟杆子 +白蜡树 白蠟樹 +白蜡虫 白蠟蟲 +白蜡蜡 白蠟蠟 +白血球过多症 白血球過多症 +白里安 白里安 +白里透红 白裏透紅 +白雪公主症候群 白雪公主症候羣 +白雪曲 白雪曲 +白霉 白黴 +白面 白麪 +白面书生 白面書生 +白面书郎 白面書郎 +白面僧面猴 白面僧面猴 +白面儿 白麪兒 +白面无须 白面無鬚 +白面鼯鼠 白面鼯鼠 +白须 白鬚 +白首北面 白首北面 +白首同归 白首同歸 +白马归周 白馬歸周 +白驹空谷 白駒空谷 +白骨松 白骨松 +白鹤梁 白鶴梁 +白鹤秀才 白鶴秀才 +百万 百萬 +百万之众 百萬之衆 +百万买宅千万买邻 百萬買宅千萬買鄰 +百万位 百萬位 +百万分之一 百萬分之一 +百万吨 百萬噸 +百万吨级核武器 百萬噸級核武器 +百万富翁 百萬富翁 +百万年 百萬年 +百万赫兹 百萬赫茲 +百万雄兵 百萬雄兵 +百万雄师 百萬雄師 +百不当一 百不當一 +百个 百個 +百中百发 百中百發 +百了 百了 +百了千当 百了千當 +百事和合 百事和合 +百余 百餘 +百余只 百餘隻 +百余里 百餘里 +百几个 百幾個 +百出 百出 +百分之一千 百分之一千 +百分制 百分制 +百分表 百分表 +百划 百劃 +百卉千葩 百卉千葩 +百发 百發 +百发百中 百發百中 +百只 百隻 +百只足够 百只足夠 +百叶 百葉 +百叶卷 百葉捲 +百叶窗 百葉窗 +百叶窗帘 百葉窗簾 +百叶箱 百葉箱 +百合 百合 +百合子 百合子 +百合科 百合科 +百合花 百合花 +百合花饰 百合花飾 +百团大战 百團大戰 +百多只 百多隻 +百天后 百天後 +百姿千态 百姿千態 +百媚千娇 百媚千嬌 +百子千孙 百子千孫 +百孔千创 百孔千創 +百孔千疮 百孔千瘡 +百尺竿头更尽一步 百尺竿頭更盡一步 +百岁之后 百歲之後 +百岁千秋 百歲千秋 +百巧千穷 百巧千窮 +百年之后 百年之後 +百年后 百年後 +百年好合 百年好合 +百度表 百度表 +百当 百當 +百念 百念 +百战百胜 百戰百勝 +百扎 百紮 +百折不回 百折不回 +百折不挠 百折不撓 +百折不挫 百折不挫 +百折裙 百摺裙 +百拙千丑 百拙千醜 +百汇 百匯 +百炼 百鍊 +百炼成钢 百鍊成鋼 +百科里 百科裏 +百紫千红 百紫千紅 +百纵千随 百縱千隨 +百老汇 百老匯 +百胜餐饮 百勝餐飲 +百胜餐饮集团 百勝餐飲集團 +百脑汇 百腦匯 +百舍重茧 百舍重繭 +百舍重趼 百舍重趼 +百花历 百花曆 +百花历史 百花歷史 +百花娘子 百花娘子 +百药之长 百藥之長 +百虑一致 百慮一致 +百计千心 百計千心 +百计千方 百計千方 +百计千谋 百計千謀 +百谋千计 百謀千計 +百谷 百穀 +百谷王 百谷王 +百足不僵 百足不僵 +百足之虫 百足之蟲 +百足之虫死而不僵 百足之蟲死而不僵 +百足之虫至死不僵 百足之蟲至死不僵 +百足虫 百足蟲 +百辟 百辟 +百里 百里 +百里之才 百里之才 +百里侯 百里侯 +百里傒 百里傒 +百里挑一 百裏挑一 +百里香 百里香 +百锻千练 百鍛千練 +百面雷 百面雷 +皂化 皂化 +皂白 皁白 +皂荚 皂莢 +皂荚树 皂莢樹 +皂角 皁角 +的一确二 的一確二 +的历 的歷 +的当 的當 +的扣 的扣 +的杯 的杯 +的核 的核 +的泛 的泛 +的的确确 的的確確 +的确 的確 +的确会 的確會 +的确如此 的確如此 +的确是 的確是 +的确良 的確良 +的钟 的鐘 +的黎波里 的黎波里 +皆准 皆準 +皆可作淀 皆可作澱 +皇亲国戚 皇親國戚 +皇冠出版 皇冠出版 +皇冠出版集团 皇冠出版集團 +皇历 皇曆 +皇后 皇后 +皇后区 皇后區 +皇后号 皇后號 +皇后镇 皇后鎮 +皇天后土 皇天后土 +皇太后 皇太后 +皇太极 皇太極 +皇太极清太宗 皇太極清太宗 +皇家加勒比海游轮公司 皇家加勒比海遊輪公司 +皇家马德里 皇家馬德里 +皇庄 皇莊 +皇恩浩荡 皇恩浩蕩 +皇极 皇極 +皇极历 皇極曆 +皇极历史 皇極歷史 +皇极数 皇極數 +皇胄 皇胄 +皇辟 皇辟 +皓发 皓髮 +皓月千里 皓月千里 +皓月当空 皓月當空 +皓齿朱唇 皓齒朱脣 +皖系军阀 皖系軍閥 +皖系战败 皖系戰敗 +皙面 皙面 +皮下出血 皮下出血 +皮下注射 皮下注射 +皮克斯 皮克斯 +皮克林 皮克林 +皮克罗比 皮克羅比 +皮划艇 皮划艇 +皮划艇激流回旋 皮劃艇激流回旋 +皮划艇静水 皮劃艇靜水 +皮制 皮製 +皮制品 皮製品 +皮制服 皮制服 +皮困秋 皮困秋 +皮夹克 皮夾克 +皮尔斯布洛斯南 皮爾斯布洛斯南 +皮层下失语症 皮層下失語症 +皮托管 皮托管 +皮松 皮鬆 +皮松肉紧 皮鬆肉緊 +皮松骨痒 皮鬆骨癢 +皮板儿 皮板兒 +皮特拉克 皮特拉克 +皮里抽肉 皮裏抽肉 +皮里春秋 皮裏春秋 +皮里晋书 皮裏晉書 +皮里膜外 皮裏膜外 +皮里走肉 皮裏走肉 +皮里阳秋 皮裏陽秋 +皮雕 皮雕 +皮面 皮面 +皱别 皺彆 +皱叶欧芹 皺葉歐芹 +皱折 皺摺 +盆吊 盆吊 +盆里 盆裏 +盈余 盈餘 +盈千累万 盈千累萬 +盈千累百 盈千累百 +盈泛 盈泛 +盈盈秋水 盈盈秋水 +盈车嘉穗 盈車嘉穗 +盈馀加征 盈餘加徵 +益于 益於 +益发 益發 +益州名画录 益州名畫錄 +益虫 益蟲 +益觉困难 益覺困難 +益鸟益虫 益鳥益蟲 +盎格鲁撒克逊 盎格魯撒克遜 +盎格鲁萨克逊 盎格魯薩克遜 +盎格鲁萨克逊人 盎格魯薩克遜人 +盎盂相系 盎盂相繫 +盐余 鹽餘 +盐卤 鹽滷 +盐城师范学院 鹽城師範學院 +盐打怎么咸 鹽打怎麼鹹 +盐打怎么咸醋打怎么酸 鹽打怎麼鹹醋打怎麼酸 +盐水选种 鹽水選種 +盐水针 鹽水針 +盐酸克仑特罗 鹽酸克侖特羅 +监修 監修 +监制 監製 +监听系统 監聽系統 +监察御史 監察御史 +监管不周 監管不周 +监管体制 監管體制 +监管范围 監管範圍 +监系 監繫 +盒子里 盒子裏 +盒式录音带 盒式錄音帶 +盒式录音磁带 盒式錄音磁帶 +盒里 盒裏 +盖世之才 蓋世之才 +盖了 蓋了 +盖了又盖 蓋了又蓋 +盖于 蓋於 +盖杯 蓋杯 +盖板 蓋板 +盖维克 蓋維克 +盗录 盜錄 +盗御马 盜御馬 +盗无实据 盜無實據 +盗版党 盜版黨 +盗采 盜採 +盗钟 盜鐘 +盗钟掩耳 盜鐘掩耳 +盘回 盤迴 +盘扣 盤扣 +盘据 盤據 +盘旋曲折 盤旋曲折 +盘曲 盤曲 +盘术 盤術 +盘松 盤松 +盘游 盤遊 +盘获 盤獲 +盘谷 盤谷 +盘里 盤裏 +盘面 盤面 +盛了 盛了 +盛价 盛价 +盛冬 盛冬 +盛德遗范 盛德遺範 +盛极一时 盛極一時 +盛极必衰 盛極必衰 +盛极而衰 盛極而衰 +盛行于 盛行於 +盛赞 盛讚 +盜跖 盜跖 +盟旗制度 盟旗制度 +目前目后 目前目後 +目力表 目力表 +目录 目錄 +目录卡 目錄卡 +目录学 目錄學 +目无余子 目無餘子 +目标价 目標價 +目牛游刃 目牛游刃 +目眦尽裂 目眥盡裂 +目瞪口僵 目瞪口僵 +目瞪舌僵 目瞪舌僵 +目短于自见 目短於自見 +目视云霄 目視雲霄 +目骇耳回 目駭耳回 +盲干 盲幹 +直上青云 直上青雲 +直了 直了 +直于 直於 +直冲 直衝 +直升 直升 +直升机 直升機 +直升飞机 直升飛機 +直发 直髮 +直发女 直髮女 +直发毛 直發毛 +直头布袋 直頭布袋 +直布罗陀 直布羅陀 +直布罗陀海峡 直布羅陀海峽 +直截了当 直截了當 +直捷了当 直捷了當 +直接了当 直接了當 +直接制版 直接制版 +直接参与 直接參與 +直接征税 直接徵稅 +直接数据 直接數據 +直接证据 直接證據 +直摆 直襬 +直杆 直杆 +直流发电机 直流發電機 +直系 直系 +直系亲 直系親 +直系亲属 直系親屬 +直系军阀 直係軍閥 +直系祖先 直系祖先 +直系血亲 直系血親 +直致 直致 +直落布兰雅 直落布蘭雅 +直言尽意 直言盡意 +直言极谏 直言極諫 +直进直出 直進直出 +直链 直鏈 +直销式传销制度 直銷式傳銷制度 +直须 直須 +相为表里 相爲表裏 +相于 相於 +相交满天下知心能几人 相交滿天下知心能幾人 +相克 相剋 +相克制 相剋制 +相克服 相克服 +相关系数 相關係數 +相冲 相沖 +相别 相別 +相别多年 相別多年 +相去万里 相去萬里 +相去无几 相去無幾 +相台 相臺 +相叶雅纪 相葉雅紀 +相合 相合 +相同 相同 +相同点 相同點 +相向 相向 +相奸 相姦 +相对于 相對於 +相对极 相對極 +相差无几 相差無幾 +相干 相干 +相平面 相平面 +相并 相併 +相当 相當 +相当于 相當於 +相当于或大于 相當於或大於 +相当程度 相當程度 +相念 相念 +相托 相托 +相扣 相扣 +相提并论 相提並論 +相斗 相鬥 +相术 相術 +相生相克 相生相剋 +相符合 相符合 +相等于 相等於 +相结合 相結合 +相融合 相融合 +相距千里 相距千里 +相适应 相適應 +相里 相里 +相门出相 相門出相 +相面 相面 +相须为命 相須爲命 +相须而行 相須而行 +盼了 盼了 +盼既示复 盼既示覆 +盾板 盾板 +省个 省個 +省了 省了 +省党部 省黨部 +省出 省出 +省出来 省出來 +省欲去奢 省慾去奢 +省民同胞 省民同胞 +省道台 省道臺 +眉分八彩 眉分八彩 +眉南面北 眉南面北 +眉垂目合 眉垂目合 +眉毛胡子一把抓 眉毛鬍子一把抓 +眉里 眉裏 +眉面 眉面 +看上了 看上了 +看下表 看下錶 +看下钟 看下鐘 +看不出 看不出 +看不出来 看不出來 +看个究竟 看個究竟 +看中了 看中了 +看了 看了 +看了又看 看了又看 +看傻了眼 看傻了眼 +看准 看準 +看出 看出 +看出了神 看出了神 +看出去 看出去 +看出来 看出來 +看台 看臺 +看台股 看臺股 +看向 看向 +看回 看回 +看尽 看盡 +看得出 看得出 +看得出来 看得出來 +看朱成碧 看朱成碧 +看板 看板 +看淡后市 看淡後市 +看终了 看終了 +看花了 看花了 +看表 看錶 +看表面 看表面 +看走了眼 看走了眼 +看钟 看鐘 +看风向 看風向 +看麦娘 看麥娘 +真个 真個 +真主党 真主黨 +真保志 真保志 +真值表 真值表 +真凭实据 真憑實據 +真凶 真兇 +真凶实犯 真兇實犯 +真受不了 真受不了 +真后生动物 真後生動物 +真实面 真實面 +真彩色 真彩色 +真成了 真成了 +真才实学 真才實學 +真服了 真服了 +真核 真核 +真理必胜 真理必勝 +真确 真確 +真草千字文 真草千字文 +真身舍利 真身舍利 +真金不怕火炼 真金不怕火煉 +真面目 真面目 +眠云 眠雲 +眷念 眷念 +眷注 眷注 +眷舍 眷舍 +眺台 眺臺 +眺望台 眺望臺 +眼前花发 眼前花發 +眼动技术 眼動技術 +眼动记录 眼動記錄 +眼同 眼同 +眼周 眼周 +眼圈红了 眼圈紅了 +眼如秋水 眼如秋水 +眼帘 眼簾 +眼干 眼乾 +眼干症 眼乾症 +眼手并用 眼手並用 +眼扎毛 眼扎毛 +眼泛 眼泛 +眼泪往肚子里流 眼淚往肚子裏流 +眼泪洗面 眼淚洗面 +眼球干燥症 眼球乾燥症 +眼看四面 眼看四面 +眼眶里 眼眶裏 +眼睛里 眼睛裏 +眼花了乱 眼花瞭亂 +眼药 眼藥 +眼药水 眼藥水 +眼药膏 眼藥膏 +眼虫 眼蟲 +眼观四面 眼觀四面 +眼迷心荡 眼迷心蕩 +眼酸 眼痠 +眼里 眼裏 +眼里不揉沙子 眼裏不揉沙子 +眼里揉不下沙子 眼裏揉不下沙子 +眼镜布 眼鏡布 +着儿 着兒 +着手于 着手於 +着眼于 着眼於 +着色软体 着色軟體 +着迷于 着迷於 +着重于 着重於 +着重指出 着重指出 +睁一只眼 睜一隻眼 +睟面盎背 睟面盎背 +睡个 睡個 +睡个夠 睡個夠 +睡个痛快 睡個痛快 +睡个觉 睡個覺 +睡了 睡了 +睡了又睡 睡了又睡 +睡游病 睡遊病 +睡病虫 睡病蟲 +睡眠曲 睡眠曲 +睡眠欲 睡眠慾 +睡眠虫 睡眠蟲 +睡眼蒙眬 睡眼矇矓 +睡莲叶 睡蓮葉 +睥睨物表 睥睨物表 +睽合 睽合 +瞄不准 瞄不準 +瞄了 瞄了 +瞄准 瞄準 +瞄准到 瞄準到 +瞄出 瞄出 +瞅下表 瞅下錶 +瞅下钟 瞅下鐘 +瞅不准 瞅不準 +瞇了 瞇了 +瞌睡虫 瞌睡蟲 +瞎了 瞎了 +瞎了眼 瞎了眼 +瞎了眼睛 瞎了眼睛 +瞎扎呼 瞎扎呼 +瞑子里 瞑子裏 +瞒了 瞞了 +瞒哄 瞞哄 +瞒天讨价就地还钱 瞞天討價就地還錢 +瞠乎其后 瞠乎其後 +瞠乎后矣 瞠乎後矣 +瞧不准 瞧不準 +瞧不出 瞧不出 +瞧了 瞧了 +瞧出 瞧出 +瞩托 矚託 +瞪了 瞪了 +瞬发中子 瞬發中子 +瞬发辐射 瞬發輻射 +瞬得彩色电影 瞬得彩色電影 +瞬息万变 瞬息萬變 +瞬息千变 瞬息千變 +瞭望台 瞭望臺 +瞳蒙 瞳矇 +瞻前忽后 瞻前忽後 +瞻前顾后 瞻前顧後 +瞻念 瞻念 +瞿秋白 瞿秋白 +矛头指向 矛頭指向 +矛盾百出 矛盾百出 +矛盾相向 矛盾相向 +矜功负胜 矜功負勝 +矜夸 矜誇 +矜庄 矜莊 +矜才使气 矜才使氣 +矜能负才 矜能負才 +矞云 矞雲 +矢不虚发 矢不虛發 +矢尽兵穷 矢盡兵窮 +矢志 矢志 +矢志不移 矢志不移 +矢无虚发 矢無虛發 +知了 知了 +知人知面 知人知面 +知人知面不知心 知人知面不知心 +知几其神 知幾其神 +知制诰 知制誥 +知名当世 知名當世 +知尽能索 知盡能索 +知往鉴今 知往鑑今 +知情同意 知情同意 +知感不尽 知感不盡 +知无不言言无不尽 知無不言言無不盡 +知行合一 知行合一 +知识范围 知識範圍 +知道了 知道了 +矫制 矯制 +矫情干誉 矯情干譽 +矫正术 矯正術 +矫若游龙 矯若遊龍 +矬个儿 矬個兒 +矬子里头选将军 矬子裏頭選將軍 +短不了 短不了 +短了 短了 +短于 短於 +短价 短價 +短几 短几 +短发 短髮 +短发性 短發性 +短叹 短嘆 +短叹长吁 短嘆長吁 +短后 短後 +短小精干 短小精幹 +短幸 短幸 +短折 短折 +短曲 短曲 +短板 短板 +短纤维 短纖維 +短针 短針 +短须 短鬚 +矮个 矮個 +矮个儿 矮個兒 +矮个子 矮個子 +矮了 矮了 +矮了一截 矮了一截 +矮了半截 矮了半截 +矮冬瓜 矮冬瓜 +矮几 矮几 +矮子里拔将军 矮子裏拔將軍 +矮杆品种 矮桿品種 +石內卜 石內卜 +石几 石几 +石化厂 石化廠 +石台 石臺 +石台县 石臺縣 +石坛 石壇 +石头布 石頭布 +石家庄 石家莊 +石屋制果 石屋製果 +石工术 石工術 +石志伟 石志偉 +石拐 石柺 +石敢当 石敢當 +石松 石松 +石松粉 石松粉 +石板 石板 +石板屋 石板屋 +石板瓦 石板瓦 +石板路 石板路 +石板道 石板道 +石枯松老 石枯松老 +石柜 石櫃 +石梁 石樑 +石棉布 石棉布 +石棉板 石棉板 +石棉症 石棉症 +石油蜡 石油蠟 +石油输出 石油輸出 +石油输出国家组织 石油輸出國家組織 +石油输出国组织 石油輸出國組織 +石灰岩 石灰岩 +石灰岩洞 石灰岩洞 +石炭系 石炭系 +石版术 石版術 +石百合 石百合 +石绵板 石綿板 +石胡荽 石胡荽 +石膏墙板 石膏牆板 +石英卤素灯 石英鹵素燈 +石英岩 石英岩 +石英表 石英錶 +石英钟 石英鐘 +石英钟表 石英鐘錶 +石莼 石蓴 +石蜡 石蠟 +石蜡像 石蠟像 +石针 石針 +石钟乳 石鐘乳 +石雕 石雕 +石雕像 石雕像 +石雕家 石雕家 +石黑彩 石黑彩 +矽岩 矽岩 +矽肺症 矽肺症 +矽谷 矽谷 +矽质岩 矽質岩 +矿物纤维 礦物纖維 +码表 碼錶 碼表 +砂岩 砂岩 +砂布 砂布 +砂锅面 砂鍋麪 +砌合 砌合 +砌合法 砌合法 +砌块建筑 砌塊建築 +砍了 砍了 +砍出 砍出 +砍出去 砍出去 +砍出来 砍出來 +砍向 砍向 +研修 研修 +研修员 研修員 +研修班 研修班 +研几探赜 研幾探賾 +研几析理 研幾析理 +研判出 研判出 +研制 研製 +研制出 研製出 +研制过程 研製過程 +研发 研發 +研发出 研發出 +研发出来 研發出來 +研发替代役 研發替代役 +研发部 研發部 +研发部门 研發部門 +研拟出 研擬出 +研究出 研究出 +研究出来 研究出來 +砖厂 磚廠 +砖雕 磚雕 +砖面 磚面 +砚台 硯臺 +砥志砺行 砥志礪行 +砥据 砥據 +砧板 砧板 +砭灸术 砭灸術 +砭针 砭鍼 +砰当 砰噹 +砲台 砲臺 +破了脸 破了臉 +破产财团 破產財團 +破价 破價 +破发 破發 +破发点 破發點 +破坏欲 破壞慾 +破布 破布 +破布子 破布子 +破折号 破折號 +破格录用 破格錄用 +破盘价 破盤價 +破纪录 破紀錄 +破绽百出 破綻百出 +破茧而出 破繭而出 +破获 破獲 +破蒸笼只会撒气 破蒸籠只會撒氣 +破表 破錶 +破记录 破記錄 +破釜沈舟 破釜沈舟 +破镜重合 破鏡重合 +破面 破面 +破风筝抖起来了 破風箏抖起來了 +砸了 砸了 +砻谷机 礱穀機 +砾岩 礫岩 +硅谷 硅谷 +硅质岩 硅質岩 +硗确 磽确 +硝烟 硝煙 +硝烟弹雨 硝煙彈雨 +硫磺谷 硫磺谷 +硫酸烟碱 硫酸菸鹼 +硬了 硬了 +硬了起来 硬了起來 +硬件平台 硬件平臺 +硬冲 硬衝 +硬化症 硬化症 +硬咽 硬嚥 +硬干 硬幹 +硬彩 硬彩 +硬核 硬核 +硬纸板 硬紙板 +硬肥皂 硬肥皂 +硬质合金 硬質合金 +硬里子 硬裏子 +硬面 硬麪 +硬页岩 硬頁岩 +确乎 確乎 +确保 確保 +确保安全 確保安全 +确信 確信 +确信无疑 確信無疑 +确凿 確鑿 +确凿不移 確鑿不移 +确切 確切 +确切不变 確切不變 +确切性 確切性 +确定 確定 +确定会 確定會 +确定判决 確定判決 +确定性 確定性 +确定故意 確定故意 +确定效应 確定效應 +确定是 確定是 +确定有 確定有 +确定能 確定能 +确实 確實 +确实会 確實會 +确实可靠 確實可靠 +确实在 確實在 +确实性 確實性 +确实是 確實是 +确实有 確實有 +确实能 確實能 +确山县 確山縣 +确当 確當 +确是 確是 +确有 確有 +确有其事 確有其事 +确有其人 確有其人 +确有此事 確有此事 +确瘠 确瘠 +确知 確知 +确确实实 確確實實 +确立 確立 +确系 確係 +确认 確認 +确认为 確認爲 +确认是 確認是 +确论 確論 +确证 確證 +确非 確非 +碌曲 碌曲 +碌曲县 碌曲縣 +碌碌庸才 碌碌庸才 +碍于 礙於 +碍于情面 礙於情面 +碍难照准 礙難照准 +碍面子 礙面子 +碎修儿 碎修兒 +碎发 碎髮 +碎尸万段 碎屍萬段 +碎屑岩 碎屑岩 +碎布 碎布 +碎布条 碎布條 +碑坛 碑壇 +碑志 碑誌 +碑面 碑面 +碗柜 碗櫃 +碗白干 碗白乾 +碗面 碗麪 +碛卤 磧鹵 +碧云 碧雲 +碧云寺 碧雲寺 +碧娜芝.布托 碧娜芝.布托 +碧波万顷 碧波萬頃 +碧波荡漾 碧波盪漾 +碧瓦朱甍 碧瓦朱甍 +碧眼紫须 碧眼紫鬚 +碧眼胡 碧眼胡 +碧眼金发 碧眼金髮 +碧鸡漫志 碧雞漫志 +碰了 碰了 +碰杯 碰杯 +碰碰胡 碰碰胡 +碰钟 碰鐘 +碰面 碰面 +碱性岩 鹼性岩 +碱纤维素 鹼纖維素 +碳氢化合 碳氫化合 +碳氢化合物 碳氫化合物 +碳水化合 碳水化合 +碳水化合物 碳水化合物 +碳的化合物 碳的化合物 +碳纤 碳纖 +碳纤维 碳纖維 +碳酸岩 碳酸岩 +碳链纤维 碳鏈纖維 +碾米厂 碾米廠 +磁制 磁製 +磁北极 磁北極 +磁单极子 磁單極子 +磁南极 磁南極 +磁扣 磁扣 +磁极 磁極 +磁核 磁核 +磁碟作业系统 磁碟作業系統 +磁针 磁針 +磊落轶荡 磊落軼蕩 +磕个响头 磕個響頭 +磕个头 磕個頭 +磕头虫 磕頭蟲 +磨了 磨了 +磨了半截舌头 磨了半截舌頭 +磨出 磨出 +磨制 磨製 +磨制石器 磨製石器 +磨厉以须 磨厲以須 +磨变岩 磨變岩 +磨合 磨合 +磨合期 磨合期 +磨合罗 磨合羅 +磨折 磨折 +磨杵成针 磨杵成針 +磨炼 磨鍊 +磨皮术 磨皮術 +磨石子面 磨石子面 +磨石粗砂岩 磨石粗砂岩 +磨砺以须 磨礪以須 +磨粉厂 磨粉廠 +磨耗症 磨耗症 +磨脊梁 磨脊樑 +磨针溪 磨針溪 +磨铁成针 磨鐵成針 +磬折 磬折 +磬钟 磬鐘 +磷酸盐岩 磷酸鹽岩 +礁岩 礁岩 +示复 示覆 +示威游行 示威遊行 +示范 示範 +示范企业 示範企業 +示范作用 示範作用 +示范动作 示範動作 +示范区 示範區 +示范单位 示範單位 +示范厂 示範廠 +示范园 示範園 +示范园区 示範園區 +示范场 示範場 +示范基地 示範基地 +示范学校 示範學校 +示范岗 示範崗 +示范工程 示範工程 +示范带 示範帶 +示范店 示範店 +示范性 示範性 +示范户 示範戶 +示范效应 示範效應 +示范教学 示範教學 +示范文本 示範文本 +示范村 示範村 +示范校 示範校 +示范法 示範法 +示范点 示範點 +示范片 示範片 +示范班 示範班 +示范田 示範田 +示范社区 示範社區 +示范街 示範街 +示范表演 示範表演 +示范课 示範課 +示范赛 示範賽 +示范项目 示範項目 +礼义生于富足 禮義生於富足 +礼乐射御 禮樂射御 +礼仪规范 禮儀規範 +礼制 禮制 +礼台 禮臺 +礼所当然 禮所當然 +礼数周到 禮數周到 +礼斗 禮斗 +礼赞 禮讚 +礼轻人意重千里送鹅毛 禮輕人意重千里送鵝毛 +社交恐惧症 社交恐懼症 +社交才能 社交才能 +社会主义制度 社會主義制度 +社会价值 社會價值 +社会体系 社會體系 +社会党 社會黨 +社会制度 社會制度 +社会发展 社會發展 +社会团体 社會團體 +社会学系 社會學系 +社会控制 社會控制 +社会整合 社會整合 +社会民主党 社會民主黨 +社会民主党人 社會民主黨人 +社会福利彩券 社會福利彩券 +社会系 社會系 +社会规范 社會規範 +社会调适 社會調適 +社党 社黨 +社区发展 社區發展 +社区电台 社區電臺 +社团 社團 +社团活动 社團活動 +社团课 社團課 +社工系 社工系 +社教系 社教系 +社民党 社民黨 +社里 社裏 +祁奚荐仇 祁奚薦仇 +祇洹精舍 祇洹精舍 +祈仙台 祈仙臺 +祈愿 祈願 +祈祷团 祈禱團 +祖冲之 祖沖之 +祖国光复会 祖國光復會 +祛痰药 祛痰藥 +祛蠹除奸 祛蠹除奸 +祝厘 祝釐 +祝发 祝髮 +祝年丰 祝年豐 +祝愿 祝願 +祝英台 祝英臺 +祝赞 祝讚 +神不守舍 神不守舍 +神人鉴知 神人鑑知 +神出鬼入 神出鬼入 +神出鬼没 神出鬼沒 +神分志夺 神分志奪 +神台 神臺 +神圣同盟 神聖同盟 +神圣周 神聖週 +神坛 神壇 +神头鬼面 神頭鬼面 +神彩奕奕 神彩奕奕 +神志 神志 +神志昏迷 神志昏迷 +神态悠闲 神態悠閒 +神摇魂荡 神搖魂盪 +神曲 神曲 +神曲茶 神麴茶 +神术 神術 +神术妙法 神術妙法 +神术妙策 神術妙策 +神术妙计 神術妙計 +神机妙术 神機妙術 +神杯 神杯 +神游 神遊 +神游太虚 神遊太虛 +神秘 神祕 +神经干 神經幹 +神经战术 神經戰術 +神经症 神經症 +神经系 神經系 +神经系统 神經系統 +神经纤维 神經纖維 +神经纤维瘤 神經纖維瘤 +神胄 神胄 +神荼郁垒 神荼鬱壘 +神迹 神蹟 +神采 神采 +神采奕奕 神采奕奕 +神采奕然 神采奕然 +神采焕发 神采煥發 +神采英拔 神采英拔 +神采飘逸 神采飄逸 +神采飞扬 神采飛揚 +神采骏发 神采駿發 +神雕 神鵰 +神雕侠侣 神鵰俠侶 +神雕像 神雕像 +神魂摇荡 神魂搖盪 +神魂荡漾 神魂盪漾 +神魂荡飏 神魂盪颺 +神魂飘荡 神魂飄蕩 +神魂飞荡 神魂飛蕩 +神魂驰荡 神魂馳蕩 +祥丰街 祥豐街 +祥云 祥雲 +祥云县 祥雲縣 +祥云瑞彩 祥雲瑞彩 +祥云瑞气 祥雲瑞氣 +祥风庆云 祥風慶雲 +票价 票價 +票庄 票莊 +票房价值 票房價值 +票房毒药 票房毒藥 +票房纪录 票房紀錄 +票房记录 票房記錄 +票据 票據 +票据交换 票據交換 +票据交易所 票據交易所 +票据存款 票據存款 +票据法 票據法 +票据行为 票據行爲 +票汇 票匯 +票选出 票選出 +票面 票面 +票面价值 票面價值 +票面值 票面值 +祭东施娘 祭東施娘 +祭了 祭了 +祭五脏庙 祭五臟廟 +祭出 祭出 +祭台 祭臺 +祭司权术 祭司權術 +祭吊 祭弔 +祭吊文 祭弔文 +祭坛 祭壇 +祭尸 祭尸 +祭遵布被 祭遵布被 +祷念 禱唸 +祸于 禍於 +祸从口出 禍從口出 +祸出不测 禍出不測 +祸发萧墙 禍發蕭牆 +祸发齿牙 禍發齒牙 +祸因恶积 禍因惡積 +祸生于忽 禍生於忽 +祸盈恶稔 禍盈惡稔 +祸福吉凶 禍福吉凶 +祸福同门 禍福同門 +祸种 禍種 +祸种头 禍種頭 +祸稔恶盈 禍稔惡盈 +禀复 稟覆 +禁制 禁制 +禁制令 禁制令 +禁制品 禁製品 +禁奸除猾 禁奸除猾 +禁当 禁當 +禁忌站台 禁忌站臺 +禁核 禁核 +禁欲 禁慾 +禁欲主义 禁慾主義 +禁止吸烟 禁止吸菸 +禁止外出 禁止外出 +禁毁 禁燬 +禁毁书 禁燬書 +禁烟 禁菸 +禁烟令 禁菸令 +禁烟节 禁菸節 +禁药 禁藥 +禁药案 禁藥案 +禄丰 祿豐 +禄丰县 祿豐縣 +福克 福克 +福克兰群岛 福克蘭羣島 +福克斯 福克斯 +福克纳 福克納 +福兰克 福蘭克 +福尽灾生 福盡災生 +福布斯 福布斯 +福建师范 福建師範 +福建师范大学 福建師範大學 +福惠双修 福惠雙修 +福无重受日祸有并来时 福無重受日禍有並來時 +福瑞克 福瑞克 +福生于微 福生于微 +福维克 福維克 +福舍 福舍 +福荫 福廕 +禹余粮 禹餘糧 +禹王台 禹王臺 +禹王台区 禹王臺區 +禺谷 禺谷 +离不了 離不了 +离了 離了 +离于 離於 +离别 離別 +离别多年 離別多年 +离别已久 離別已久 +离合 離合 +离合体诗 離合體詩 +离合器 離合器 +离合悲欢 離合悲歡 +离合板 離合板 +离合诗 離合詩 +离奇曲折 離奇曲折 +离娘饭 離娘飯 +离婚同意书 離婚同意書 +离家出走 離家出走 +离岸价 離岸價 +离弦 離弦 +离弦走板儿 離弦走板兒 +离情别绪 離情別緒 +离题万里 離題萬里 +离鸾别凤 離鸞別鳳 +禽困复车 禽困覆車 +禽滑厘 禽滑釐 +禽舍 禽舍 +禾虫 禾蟲 +禾谷 禾穀 +禾谷类作物 禾穀類作物 +秀出 秀出 +秀出班行 秀出班行 +秀发 秀髮 +秀发垂肩 秀髮垂肩 +秀才 秀才 +秀才不出门能知天下事 秀才不出門能知天下事 +秀才人情 秀才人情 +秀才作医如菜作虀 秀才作醫如菜作虀 +秀才造反 秀才造反 +私下里 私下裏 +私了 私了 +私仇 私仇 +私党 私黨 +私心藏奸 私心藏奸 +私念 私念 +私斗 私鬥 +私曲 私曲 +私有制 私有制 +私有财产制 私有財產制 +私欲 私慾 +私自同意 私自同意 +秃发 禿髮 +秃发症 禿髮症 +秃妃之发 禿妃之髮 +秃秃里 禿禿裏 +秉台衡 秉臺衡 +秉烛夜游 秉燭夜遊 +秉鉴 秉鑑 +秋不干 秋不乾 +秋事 秋事 +秋令 秋令 +秋假里 秋假裏 +秋冬 秋冬 +秋决 秋決 +秋凉 秋涼 +秋凉时节 秋涼時節 +秋刀鱼 秋刀魚 +秋分 秋分 +秋分点 秋分點 +秋初 秋初 +秋千 鞦韆 +秋发 秋髮 +秋叶 秋葉 +秋叶原 秋葉原 +秋后 秋後 +秋后算帐 秋後算帳 +秋后算账 秋後算賬 +秋场 秋場 +秋士 秋士 +秋声 秋聲 +秋声赋 秋聲賦 +秋夜 秋夜 +秋天 秋天 +秋天里 秋天裏 +秋娘 秋娘 +秋季 秋季 +秋季学期 秋季學期 +秋季旅行 秋季旅行 +秋季档 秋季檔 +秋季班 秋季班 +秋季赛 秋季賽 +秋官 秋官 +秋审 秋審 +秋山 秋山 +秋川雅史 秋川雅史 +秋庄稼 秋莊稼 +秋征 秋征 +秋心 秋心 +秋思 秋思 +秋意 秋意 +秋意已浓 秋意已濃 +秋成 秋成 +秋扇 秋扇 +秋扇见捐 秋扇見捐 +秋播 秋播 +秋收 秋收 +秋收冬藏 秋收冬藏 +秋收季节 秋收季節 +秋收起义 秋收起義 +秋方 秋方 +秋日 秋日 +秋日里 秋日裏 +秋旱 秋旱 +秋景 秋景 +秋月 秋月 +秋月寒江 秋月寒江 +秋月春风 秋月春風 +秋期 秋期 +秋枫 秋楓 +秋榜 秋榜 +秋毫 秋毫 +秋毫不犯 秋毫不犯 +秋毫之末 秋毫之末 +秋毫无犯 秋毫無犯 +秋气 秋氣 +秋水 秋水 +秋水仙素 秋水仙素 +秋水伊人 秋水伊人 +秋汛 秋汛 +秋河 秋河 +秋波 秋波 +秋波送情 秋波送情 +秋海棠 秋海棠 +秋海棠花 秋海棠花 +秋游 秋遊 +秋灌 秋灌 +秋熟 秋熟 +秋燥 秋燥 +秋牡丹 秋牡丹 +秋瑾 秋瑾 +秋田 秋田 +秋田县 秋田縣 +秋眉 秋眉 +秋石 秋石 +秋社 秋社 +秋禊 秋禊 +秋篠宫 秋篠宮 +秋粮 秋糧 +秋老虎 秋老虎 +秋耕 秋耕 +秋胡 秋胡 +秋胡变文 秋胡變文 +秋胡戏妻 秋胡戲妻 +秋色 秋色 +秋色宜人 秋色宜人 +秋节 秋節 +秋茶 秋茶 +秋草 秋草 +秋草人情 秋草人情 +秋荼 秋荼 +秋荼密网 秋荼密網 +秋莲 秋蓮 +秋菊 秋菊 +秋菊傲霜 秋菊傲霜 +秋菜 秋菜 +秋葵 秋葵 +秋葵荚 秋葵莢 +秋虫 秋蟲 +秋蝉 秋蟬 +秋衣 秋衣 +秋装 秋裝 +秋裤 秋褲 +秋试 秋試 +秋闱 秋闈 +秋阳 秋陽 +秋阴入井干 秋陰入井幹 +秋雨 秋雨 +秋霖 秋霖 +秋霜 秋霜 +秋颜 秋顏 +秋风 秋風 +秋风团扇 秋風團扇 +秋风扫落叶 秋風掃落葉 +秋风落叶 秋風落葉 +秋风辞 秋風辭 +秋风过耳 秋風過耳 +秋风送爽 秋風送爽 +秋风飒飒 秋風颯颯 +秋香 秋香 +秋高气爽 秋高氣爽 +秋高气肃 秋高氣肅 +秋高马肥 秋高馬肥 +秋麻 秋麻 +种上 種上 +种上蒺藜就要扎脚 種上蒺藜就要扎腳 +种下 種下 +种下祸根 種下禍根 +种人 種人 +种仁 種仁 +种公畜 種公畜 +种出 種出 +种出来 種出來 +种切 種切 +种别 種別 +种到 種到 +种名 種名 +种因 種因 +种地 種地 +种姓 種姓 +种姓制 種姓制 +种姓制度 種姓制度 +种子 種子 +种子园 種子園 +种子地 種子地 +种子岛 種子島 +种子植物 種子植物 +种子球员 種子球員 +种子田 種子田 +种子网路 種子網路 +种子选手 種子選手 +种子队 種子隊 +种差 種差 +种师中 种師中 +种师道 种師道 +种庄稼 種莊稼 +种得 種得 +种德 種德 +种性 種性 +种户 種戶 +种放 种放 +种族 種族 +种族中心主义 種族中心主義 +种族主义 種族主義 +种族主义者 種族主義者 +种族偏见 種族偏見 +种族平等 種族平等 +种族歧视 種族歧視 +种族清洗 種族清洗 +种族清除 種族清除 +种族灭绝 種族滅絕 +种族迫害 種族迫害 +种族问题 種族問題 +种族隔离 種族隔離 +种树 種樹 +种植 種植 +种植业 種植業 +种植义齿 種植義齒 +种植区 種植區 +种植园 種植園 +种植户 種植戶 +种概念 種概念 +种源中心 種源中心 +种源论 種源論 +种火又长拄门又短 種火又長拄門又短 +种牛 種牛 +种牛痘 種牛痘 +种猪 種豬 +种玉 種玉 +种瓜得瓜 種瓜得瓜 +种瓜得瓜种豆得豆 種瓜得瓜種豆得豆 +种生 種生 +种田 種田 +种田人家 種田人家 +种畜 種畜 +种痘 種痘 +种的 種的 +种皮 種皮 +种祸 種禍 +种种 種種 +种稻 種稻 +种类 種類 +种籽 種籽 +种系 種系 +种群 種羣 +种肥 種肥 +种花 種花 +种花草 種花草 +种菜 種菜 +种蛋 種蛋 +种谷 種穀 +种豆 種豆 +种豆得豆 種豆得豆 +种起 種起 +种过 種過 +种过去 種過去 +种过来 種過來 +种近乎幻想 種近乎幻想 +种间杂交 種間雜交 +种马 種馬 +种麦得麦 種麥得麥 +种麻 種麻 +科举制 科舉制 +科举制度 科舉制度 +科克 科克 +科克林 科克林 +科别 科別 +科学万能 科學萬能 +科学中药 科學中藥 +科学技术 科學技術 +科学技术是第一生产力 科學技術是第一生產力 +科学技术现代化 科學技術現代化 +科学种田 科學種田 +科学规范 科學規範 +科学面 科學麪 +科尔沁左翼后 科爾沁左翼後 +科尔沁左翼后旗 科爾沁左翼後旗 +科尼賽克 科尼賽克 +科布多 科布多 +科布多河 科布多河 +科布多盆地 科布多盆地 +科托努 科托努 +科技示范户 科技示範戶 +科斗 科斗 +科斗书 科斗書 +科斗文 科斗文 +科特布斯 科特布斯 +科班出身 科班出身 +科目表 科目表 +科系 科系 +科纳克里 科納克里 +科罗拉多大峡谷 科羅拉多大峽谷 +科范 科範 +科迪勒拉山系 科迪勒拉山系 +科际整合 科際整合 +秒表 秒錶 +秒针 秒針 +秒钟 秒鐘 +秕谷 秕穀 +秘制 祕製 +秘密 祕密 +秘录 祕錄 +租价 租價 +租借 租借 +租借人 租借人 +租借地 租借地 +租借法案 租借法案 +租借给 租借給 +租出 租出 +租出去 租出去 +秤平斗满 秤平斗滿 +秤斤注两 秤斤注兩 +秤杆 秤桿 +秤砣虽小压千斤 秤砣雖小壓千斤 +秦吉了 秦吉了 +秦少游 秦少游 +秧针 秧針 +积于忽微 積於忽微 +积云 積雲 +积分制 積分制 +积层云 積層雲 +积恶 積惡 +积恶余殃 積惡餘殃 +积恶馀殃 積惡餘殃 +积极 積極 +积极份子 積極份子 +积极参与 積極參與 +积极参加 積極參加 +积极反应 積極反應 +积极因素 積極因素 +积极型 積極型 +积极性 積極性 +积极论 積極論 +积淀 積澱 +积谷 積穀 +积谷防饥 積穀防饑 +积郁 積鬱 +积里渐里 積裏漸裏 +积金至斗 積金至斗 +积雨云 積雨雲 +称出 稱出 +称制 稱制 +称叹 稱歎 +称心满志 稱心滿志 +称念 稱念 +称愿 稱願 +称王封后 稱王封后 +称谓录 稱謂錄 +称赞 稱讚 +称赞不已 稱讚不已 +移出 移出 +移出去 移出去 +移出来 移出來 +移向 移向 +移回 移回 +移山志 移山志 +移情别恋 移情別戀 +移星换斗 移星換斗 +移植手术 移植手術 +移祸于 移禍於 +秾纤 穠纖 +秾纤合度 穠纖合度 +稀松 稀鬆 +稀松平常 稀鬆平常 +稀松骨质 稀鬆骨質 +稀释后 稀釋後 +稀里 稀里 +稀里哗啦 稀里嘩啦 +稀里打哄 稀里打哄 +稀里糊涂 稀裏糊塗 +程序修宪 程序修憲 +程序控制 程序控制 +程式控制 程式控制 +程式规划 程式規劃 +程朱 程朱 +程砚秋 程硯秋 +稍出 稍出 +稍占上风 稍占上風 +稍后 稍後 +稍干的 稍乾的 +稍感不适 稍感不適 +稍有不准 稍有不準 +稍胜一筹 稍勝一籌 +稍高于 稍高於 +税制 稅制 +税后 稅後 +税捐稽征 稅捐稽徵 +税捐稽征处 稅捐稽徵處 +税种 稅種 +税负制 稅負制 +稔恶不悛 稔惡不悛 +稠云 稠雲 +稳占 穩佔 +稳吃三注 穩吃三注 +稳坐钓鱼台 穩坐釣魚臺 +稳定物价 穩定物價 +稳当 穩當 +稳当性 穩當性 +稳扎 穩紮 +稳扎稳打 穩紮穩打 +稳操胜券 穩操勝券 +稳操胜算 穩操勝算 +稳稳当当 穩穩當當 +稳获 穩獲 +稻种 稻種 +稻穗 稻穗 +稻谷 稻穀 +稽征 稽徵 +稽征处 稽徵處 +稽征所 稽徵所 +稽核 稽覈 +穆克吉 穆克吉 +穆巴拉克 穆巴拉克 +穆斯坦西里 穆斯坦西里 +穆棱 穆棱 +穆罕默德历 穆罕默德曆 +穆罕默德历史 穆罕默德歷史 +穗儿 穗兒 +穗子 穗子 +穗帏飘井干 繐幃飄井幹 +穗帐 繐帳 +穗帷 繐帷 +穗状 穗狀 +穗状花序 穗狀花序 +穗肥 穗肥 +穗花杉 穗花杉 +穗裳 繐裳 +穗轴 穗軸 +穗选 穗選 +穷于 窮於 +穷于应付 窮於應付 +穷兵极武 窮兵極武 +穷兵黩武 窮兵黷武 +穷冬 窮冬 +穷凶恶极 窮兇惡極 +穷凶极恶 窮兇極惡 +穷凶极虐 窮兇極虐 +穷发 窮髮 +穷困 窮困 +穷困人家 窮困人家 +穷天极地 窮天極地 +穷奢极侈 窮奢極侈 +穷奢极多 窮奢極多 +穷奢极欲 窮奢極欲 +穷妙极巧 窮妙極巧 +穷富极贵 窮富極貴 +穷尽 窮盡 +穷山恶水 窮山惡水 +穷工极巧 窮工極巧 +穷幽极微 窮幽極微 +穷当益坚 窮當益堅 +穷当益坚老当益壮 窮當益堅老當益壯 +穷形尽相 窮形盡相 +穷形极状 窮形極狀 +穷本极源 窮本極源 +穷极 窮極 +穷极其妙 窮極其妙 +穷极则变 窮極則變 +穷极无聊 窮極無聊 +穷极要妙 窮極要妙 +穷根寻叶 窮根尋葉 +穷灵尽妙 窮靈盡妙 +穷理尽性 窮理盡性 +穷纤入微 窮纖入微 +穷而后工 窮而後工 +穷贵极富 窮貴極富 +穷追不舍 窮追不捨 +穷里 窮里 +穹谷 穹谷 +空个 空個 +空中交通管制 空中交通管制 +空中交通管制员 空中交通管制員 +空中布雷 空中佈雷 +空中格斗 空中格鬥 +空中管制站 空中管制站 +空了 空了 +空优迷彩 空優迷彩 +空余 空餘 +空军航空技术学院 空軍航空技術學院 +空出 空出 +空出来 空出來 +空前绝后 空前絕後 +空前绝后后 空前絕后後 +空叹 空嘆 +空当 空當 +空当儿 空當兒 +空当子 空當子 +空心汤团 空心湯糰 +空心萝卜 空心蘿蔔 +空手而回 空手而回 +空投布雷 空投佈雷 +空杯 空杯 +空柜子 空櫃子 +空梁落燕泥 空梁落燕泥 +空气喷气发动机 空氣噴氣發動機 +空气缓冲间 空氣緩衝間 +空泛 空泛 +空疏无据 空疏無據 +空空荡荡 空空蕩蕩 +空荡 空蕩 +空荡荡 空蕩蕩 +空蒙 空濛 +空调症 空調症 +空谷 空谷 +空谷幽兰 空谷幽蘭 +空谷足音 空谷足音 +空钟 空鐘 +空间曲线 空間曲線 +空间艺术 空間藝術 +空集合 空集合 +穿不出 穿不出 +穿云裂石 穿雲裂石 +穿出 穿出 +穿出去 穿出去 +穿出来 穿出來 +穿回 穿回 +穿跟斗 穿跟斗 +穿针 穿針 +穿针引线 穿針引線 +穿针走线 穿針走線 +穿鞋的不斗赤脚的 穿鞋的不鬥赤腳的 +穿麻挂孝 穿麻掛孝 +突出 突出 +突出去 突出去 +突出来 突出來 +突出重围 突出重圍 +突升 突升 +突发 突發 +突发事件 突發事件 +突发奇想 突發奇想 +突发性 突發性 +突发状况 突發狀況 +突围而出 突圍而出 +突显出 突顯出 +突袭战术 突襲戰術 +突触后 突觸後 +窃占 竊占 +窃占罪 竊占罪 +窃幸乘宠 竊幸乘寵 +窃据 竊據 +窃钟掩耳 竊鐘掩耳 +窅娘 窅娘 +窒欲 窒慾 +窗台 窗臺 +窗台上 窗臺上 +窗帘 窗簾 +窗帘布 窗簾布 +窗明几亮 窗明几亮 +窗明几净 窗明几淨 +窘困 窘困 +窘态百出 窘態百出 +窜出 竄出 +窜升 竄升 +窜游 竄遊 +窜进窜出 竄進竄出 +窝里 窩裏 +窝里反 窩裏反 +窝里发炮 窩裏發炮 +窝里炮 窩裏炮 +窝里窝囊 窩里窩囊 +窝里翻 窩裏翻 +窝阔台 窩闊臺 +窝阔台汗 窩闊臺汗 +窝阔台汗国 窩闊臺汗國 +窟里拔蛇 窟裏拔蛇 +窥御激夫 窺御激夫 +窦太后 竇太后 +窨子里秋月 窨子裏秋月 +立了 立了 +立于 立於 +立于不败 立於不敗 +立于不败之地 立於不敗之地 +立体几何 立體幾何 +立体身历声 立體身歷聲 +立克次体 立克次體 +立冬 立冬 +立升 立升 +立宪民主党 立憲民主黨 +立当 立當 +立志 立志 +立扎 立扎 +立扫千言 立掃千言 +立方公里 立方公里 +立方厘米 立方厘米 +立杆 立杆 +立杆见影 立杆見影 +立柜 立櫃 +立氏立克次体 立氏立克次體 +立秋 立秋 +立联合医院 立聯合醫院 +立范 立範 +立面 立面 +立面图 立面圖 +竖人毛发 豎人毛髮 +竖柱上梁 豎柱上梁 +竖起脊梁 豎起脊梁 +站个 站個 +站了 站了 +站出 站出 +站出去 站出去 +站出来 站出來 +站台 站臺 +站台票 站臺票 +站干岸儿 站乾岸兒 +站柜台 站櫃檯 +竞争和聚合 競爭和聚合 +竞价 競價 +竞合现象 競合現象 +竞向 競向 +竞斗 競鬥 +竟于 竟於 +竟须 竟須 +章台 章臺 +章台杨柳 章臺楊柳 +章台柳 章臺柳 +章回 章回 +章回体 章回體 +章回小说 章回小說 +章表 章表 +童仆 童僕 +童军团 童軍團 +童蒙 童蒙 +童蒙训 童蒙訓 +童颜鹤发 童顏鶴髮 +竭尽 竭盡 +竭尽全力 竭盡全力 +竭尽力量 竭盡力量 +竭尽心思 竭盡心思 +竭尽所能 竭盡所能 +竭尽棉薄 竭盡棉薄 +竭智尽力 竭智盡力 +竭智尽忠 竭智盡忠 +竭智尽虑 竭智盡慮 +竭诚尽节 竭誠盡節 +端了 端了 +端出 端出 +端出去 端出去 +端出来 端出來 +端庄 端莊 +端杯 端杯 +端系统 端系統 +端面 端面 +竹几 竹几 +竹制 竹製 +竹叶 竹葉 +竹叶青 竹葉青 +竹叶青蛇 竹葉青蛇 +竹叶鲢 竹葉鰱 +竹布 竹布 +竹帘 竹簾 +竹席 竹蓆 +竹扣 竹扣 +竹杠 竹槓 +竹板 竹板 +竹板书 竹板書 +竹板歌 竹板歌 +竹林之游 竹林之遊 +竹笋干 竹筍乾 +竹签 竹籤 +竹篱茅舍 竹籬茅舍 +竹节虫 竹節蟲 +竹苞松茂 竹苞松茂 +竹野內丰 竹野內豐 +笃志 篤志 +笃志好学 篤志好學 +笃志爱古 篤志愛古 +笆斗 笆斗 +笋干 筍乾 +笋里不知茆里 筍裏不知茆裏 +笏板 笏板 +笑个 笑個 +笑个痛快 笑個痛快 +笑了 笑了 +笑了起来 笑了起來 +笑代表拒绝 笑代表拒絕 +笑出 笑出 +笑出来 笑出來 +笑出眼泪 笑出眼淚 +笑口弥勒 笑口彌勒 +笑容满面 笑容滿面 +笑成一团 笑成一團 +笑耍头回 笑耍頭回 +笑话百出 笑話百出 +笑里藏刀 笑裏藏刀 +笑面 笑面 +笑面夜叉 笑面夜叉 +笑面虎 笑面虎 +笔划 筆劃 +笔划检字表 筆劃檢字表 +笔力万钧 筆力萬鈞 +笔卷 筆捲 +笔参造化 筆參造化 +笔录 筆錄 +笔扫千军 筆掃千軍 +笔据 筆據 +笔杆 筆桿 +笔杆子 筆桿子 +笔秃墨干 筆禿墨乾 +笔管面 筆管麪 +笔胜于刀文比武强 筆勝於刀文比武強 +笔致 筆致 +笔迹鉴定 筆跡鑑定 +笙磬同音 笙磬同音 +笛卡儿坐标制 笛卡兒座標制 +笛布斯 笛布斯 +符号表 符號表 +符合 符合 +符合标准 符合標準 +符合美国利益 符合美國利益 +符拉迪沃斯托克 符拉迪沃斯託克 +符拉迪沃斯讬克 符拉迪沃斯託克 +符采 符采 +笨蛋挂 笨蛋掛 +第一个 第一個 +第一个层次 第一個層次 +第一信号系统 第一信號系統 +第一准备金 第一準備金 +第一出 第一齣 +第一千 第一千 +第一千万 第一千萬 +第一卷 第一卷 +第一回 第一回 +第一志愿 第一志願 +第一性征 第一性徵 +第七个 第七個 +第七出 第七齣 +第七回 第七回 +第三个 第三個 +第三出 第三齣 +第三回 第三回 +第九个 第九個 +第九出 第九齣 +第九回 第九回 +第九艺术 第九藝術 +第二个 第二個 +第二出 第二齣 +第二回 第二回 +第二性征 第二性徵 +第五个 第五個 +第五个现代化 第五個現代化 +第五出 第五齣 +第五回 第五回 +第八个 第八個 +第八出 第八齣 +第八回 第八回 +第八艺术 第八藝術 +第六个 第六個 +第六出 第六齣 +第六回 第六回 +第几 第幾 +第几个 第幾個 +第几冊 第幾冊 +第几名 第幾名 +第几回 第幾回 +第几次 第幾次 +第几章 第幾章 +第几节 第幾節 +第几课 第幾課 +第十个 第十個 +第十出 第十齣 +第十回 第十回 +第四个 第四個 +第四出 第四齣 +第四出局 第四出局 +第四台 第四臺 +第四回 第四回 +笺注 箋註 +等个 等個 +等了 等了 +等于 等於 +等于在 等於在 +等于是 等於是 +等于有 等於有 +等于零 等於零 +等价 等價 +等价交换 等價交換 +等价关系 等價關係 +等价物 等價物 +等值价格 等值價格 +等势面 等勢面 +等同 等同 +等同于 等同於 +等周不等式 等周不等式 +等效百万吨当量 等效百萬噸當量 +等级制度 等級制度 +等轴晶系 等軸晶系 +等速圆周运动 等速圓周運動 +等闲之辈 等閒之輩 +等闲人物 等閒人物 +等闲视之 等閒視之 +等高种植 等高種植 +筋斗 筋斗 +筋斗云 筋斗雲 +筋疲力尽 筋疲力盡 +筋面粉 筋麪粉 +筑前 筑前 +筑北 筑北 +筑后 筑後 +筑土墙 築土牆 +筑坛 築壇 +筑坛拜将 築壇拜將 +筑城 築城 +筑堤 築堤 +筑墙 築牆 +筑室 築室 +筑室反耕 築室反耕 +筑室道谋 築室道謀 +筑屋 築屋 +筑州 筑州 +筑巢 築巢 +筑底 築底 +筑底巷 築底巷 +筑後 筑後 +筑成 築成 +筑有 築有 +筑栏 築欄 +筑波 筑波 +筑磕 築磕 +筑筑磕磕 築築磕磕 +筑紫 筑紫 +筑肥 筑肥 +筑西 筑西 +筑起 築起 +筑路 築路 +筑路工程 築路工程 +筑邦 筑邦 +筑阳 筑陽 +筑陽 筑陽 +答不出 答不出 +答出 答出 +答出来 答出來 +答剌苏 答剌蘇 +答卷 答卷 +答复 答覆 +答录机 答錄機 +答案卷 答案卷 +策划 策劃 +策划人 策劃人 +策划者 策劃者 +筛子喂驴 篩子餵驢 +筛板 篩板 +筛检出 篩檢出 +筛选出 篩選出 +筲斗 筲斗 +筵几 筵几 +筹划 籌劃 +筹码面 籌碼面 +签上 簽上 +签上去 簽上去 +签上来 簽上來 +签下 簽下 +签下去 簽下去 +签下来 簽下來 +签书会 簽書會 +签了 簽了 +签些 簽些 +签入 簽入 +签写 簽寫 +签出 簽出 +签到 簽到 +签到处 簽到處 +签到簿 簽到簿 +签单 簽單 +签印 簽印 +签发 簽發 +签发地点 簽發地點 +签发日期 簽發日期 +签名 簽名 +签名会 簽名會 +签名信 簽名信 +签名球 簽名球 +签名簿 簽名簿 +签名运动 簽名運動 +签呈 簽呈 +签唱 簽唱 +签唱会 簽唱會 +签在 簽在 +签好 簽好 +签妥 簽妥 +签子 籤子 +签字 簽字 +签字笔 簽字筆 +签字者 簽字者 +签字费 簽字費 +签完 簽完 +签定 簽定 +签帐 簽帳 +签帐卡 簽帳卡 +签幐 籤幐 +签得 簽得 +签报 簽報 +签押 簽押 +签押房 簽押房 +签收 簽收 +签有 簽有 +签条 籤條 +签注 簽註 +签派室 簽派室 +签爲 簽爲 +签着 簽着 +签章 簽章 +签筒 籤筒 +签约 簽約 +签约人 簽約人 +签约国 簽約國 +签约奖金 簽約獎金 +签约金 簽約金 +签结 簽結 +签署 簽署 +签署人 簽署人 +签署国 簽署國 +签証 簽証 +签订 簽訂 +签证 簽證 +签证费 簽證費 +签诗 籤詩 +签语饼 籤語餅 +签赌 簽賭 +签赌案 簽賭案 +签赌站 簽賭站 +签过 簽過 +签退 簽退 +简余晏 簡余晏 +简别 簡別 +简单明了 簡單明瞭 +简历 簡歷 +简历表 簡歷表 +简字表 簡字表 +简字谱录 簡字譜錄 +简尸 簡屍 +简并 簡併 +简截了当 簡截了當 +简报导览系统 簡報導覽系統 +简易包扎法 簡易包紮法 +简易师范 簡易師範 +简朝仑 簡朝崙 +简朴 簡樸 +简板 簡板 +简氏防务周刊 簡氏防務週刊 +箕山之志 箕山之志 +箕斗 箕斗 +算不了 算不了 +算不出 算不出 +算了 算了 +算了又算 算了又算 +算准 算準 +算出 算出 +算出去 算出去 +算出来 算出來 +算历 算曆 +算发 算髮 +算得了 算得了 +算术 算術 +算术和 算術和 +算术家 算術家 +算术平均 算術平均 +算术平均数 算術平均數 +算术式 算術式 +算术级数 算術級數 +算术课 算術課 +箝制 箝制 +管不了 管不了 +管个 管個 +管乐团 管樂團 +管了 管了 +管人吊脚儿事 管人弔腳兒事 +管制 管制 +管制中心 管制中心 +管制区 管制區 +管制区域 管制區域 +管制员 管制員 +管制品 管制品 +管制塔台 管制塔臺 +管制局 管制局 +管制法 管制法 +管制点 管制點 +管制空域 管制空域 +管制站 管制站 +管制路线 管制路線 +管圆线虫 管圓線蟲 +管城回族区 管城回族區 +管家娘子 管家娘子 +管干 管幹 +管弦 管絃 +管弦乐团 管弦樂團 +管理 管理 +管理人才 管理人才 +管理体制 管理體制 +管理系 管理系 +管理规范 管理規範 +管理资讯系统 管理資訊系統 +管辖范围 管轄範圍 +管道升 管道昇 +管闲事 管閒事 +箭不虚发 箭不虛發 +箭在弦上不得不发 箭在弦上不得不發 +箭无虚发 箭無虛發 +箭杆 箭桿 +箭虫 箭蟲 +箱帘 箱簾 +箱扣 箱釦 +箱梁 箱梁 +箱里 箱裏 +篆烟 篆煙 +篇卷 篇卷 +篡党 篡黨 +篮下三秒钟 籃下三秒鐘 +篮坛 籃壇 +篮板 籃板 +篮板王 籃板王 +篮板球 籃板球 +篮虹杯 籃虹盃 +篷盖布 篷蓋佈 +簇合 簇合 +簌簌发抖 簌簌發抖 +簪笔磬折 簪筆磬折 +簪缨世胄 簪纓世胄 +簳面杖 簳麪杖 +簸荡 簸盪 +簿历 簿歷 +簿录 簿錄 +簿据 簿據 +籧篨戚施 籧篨戚施 +米价 米價 +米克 米克 +米克杰格 米克傑格 +米克森 米克森 +米克诺斯 米克諾斯 +米利托 米利托 +米制 米制 +米卤蛋 米滷蛋 +米厘米突 米釐米突 +米德尔伯里 米德爾伯裏 +米格式战斗机 米格式戰鬥機 +米纳谷 米納谷 +米罗的维纳斯雕像 米羅的維納斯雕像 +米苏里 米蘇里 +米苏里州 米蘇里州 +米虫 米蟲 +米蛀虫 米蛀蟲 +米谷 米穀 +米里 米里 +米雅托维奇 米雅托維奇 +米雕 米雕 +米面 米麪 +类似于 類似於 +类别 類別 +类别的团体 類別的團體 +类同 類同 +类同法 類同法 +类球面 類球面 +粉丝团 粉絲團 +粉丝谷 粉絲谷 +粉团儿 粉團兒 +粉团儿似的 粉團兒似的 +粉彩 粉彩 +粉拳绣腿 粉拳繡腿 +粉板 粉板 +粉砂岩 粉砂岩 +粉签子 粉籤子 +粉红色系 粉紅色系 +粉面 粉面 +粉面朱唇 粉面朱脣 +粉面油头 粉面油頭 +粉饰门面 粉飾門面 +粒变岩 粒變岩 +粗制 粗製 +粗制品 粗製品 +粗制滥造 粗製濫造 +粗卤 粗鹵 +粗布 粗布 +粗布条 粗布條 +粗恶 粗惡 +粗枝大叶 粗枝大葉 +粗毛布 粗毛布 +粗管面 粗管麪 +粗纤维 粗纖維 +粗衣恶食 粗衣惡食 +粗面 粗麪 +粗面岩 粗面岩 +粘合剂 粘合劑 +粘板岩 粘板岩 +粜出 糶出 +粤曲 粵曲 +粤胡 粵胡 +粥厂 粥廠 +粪坑里的石头 糞坑裏的石頭 +粪秽蔑面 糞穢衊面 +粪缸里掷骰子 糞缸裏擲骰子 +粮尽援绝 糧盡援絕 +粮食平准基金 糧食平準基金 +粲夸克 粲夸克 +粽粑叶 粽粑葉 +精于 精於 +精于此道 精於此道 +精兵制 精兵制 +精准 精準 +精准度 精準度 +精制 精製 +精制品 精製品 +精制服 精制服 +精奇里江 精奇里江 +精干 精幹 +精干高效 精幹高效 +精当 精當 +精彩 精彩 +精彩度 精彩度 +精彩生动 精彩生動 +精彩逼人 精彩逼人 +精彩镜头 精彩鏡頭 +精心制作 精心製作 +精心制造 精心製造 +精心杰作 精心傑作 +精悟玄鉴 精悟玄鑑 +精明干练 精明幹練 +精明强干 精明強幹 +精明能干 精明能幹 +精松 精鬆 +精核 精核 +精炼 精煉 +精炼厂 精煉廠 +精炼炉 精煉爐 +精疲力尽 精疲力盡 +精确 精確 +精确到 精確到 +精确度 精確度 +精确性 精確性 +精神分裂症 精神分裂症 +精神官能症 精神官能症 +精神性厌食症 精神性厭食症 +精神焕发 精神煥發 +精神药物 精神藥物 +精致 精緻 +精致化 精緻化 +精致度 精緻度 +精舍 精舍 +精虫 精蟲 +精虫冲脑 精蟲衝腦 +精诚团结 精誠團結 +精辟 精闢 +精通于 精通於 +精采 精采 +精采度 精采度 +精采绝伦 精采絕倫 +精金百炼 精金百煉 +精雕 精雕 +精雕细刻 精雕細刻 +精雕细琢 精雕細琢 +精雕细镂 精雕細鏤 +糅合 糅合 +糊口 餬口 +糊涂 糊塗 +糊涂一时 糊塗一時 +糊涂帐 糊塗帳 +糊涂油蒙心 糊塗油蒙心 +糊涂虫 糊塗蟲 +糊涂蛋 糊塗蛋 +糊涂账 糊塗賬 +糊糊涂涂 糊糊塗塗 +糊里糊涂 糊里糊塗 +糕干 糕乾 +糖厂 糖廠 +糖堆里养的 糖堆裏養的 +糖炒栗子 糖炒栗子 +糖萝卜 糖蘿蔔 +糖醋里脊 糖醋里脊 +糙叶树 糙葉樹 +糙面内质网 糙面內質網 +糟了 糟了 +糟糕了 糟糕了 +糟透了 糟透了 +糟齿类爬虫 糟齒類爬蟲 +糠穗 糠穗 +糯米团 糯米糰 +系一片 係一片 +系一番 係一番 +系一种 係一種 +系一线 繫一線 +系上 繫上 +系世 繫世 +系丝带 繫絲帶 +系个 繫個 +系为 係爲 +系主任 系主任 +系了 繫了 +系争 係爭 +系争物 係爭物 +系于 繫於 +系于一发 繫於一髮 +系住 繫住 +系出名门 系出名門 +系刊 系刊 +系列 系列 +系列化 系列化 +系列战 系列戰 +系列放大器 系列放大器 +系列片 系列片 +系列电视剧 系列電視劇 +系列赛 系列賽 +系列里 系列裏 +系到 繫到 +系务 系務 +系发带 繫髮帶 +系命 繫命 +系囚 繫囚 +系头巾 繫頭巾 +系好 繫好 +系孙 系孫 +系学会 系學會 +系带 繫帶 +系心 繫心 +系念 繫念 +系怀 繫懷 +系恋 繫戀 +系所 系所 +系扣 係扣 +系指 係指 +系捻儿 繫捻兒 +系数 係數 +系族 系族 +系有 繫有 +系条 繫條 +系泊 繫泊 +系爪 繫爪 +系爲 係爲 +系牢 繫牢 +系狱 繫獄 +系璧 系璧 +系留 繫留 +系着 繫着 +系系 繫系 +系紧 繫緊 +系累 繫累 +系结 繫結 +系统 系統 +系统分析 系統分析 +系统分类 系統分類 +系统化 系統化 +系统发育 系統發育 +系统商 系統商 +系统图 系統圖 +系统工程 系統工程 +系统性 系統性 +系统抽样法 系統抽樣法 +系统流程图 系統流程圖 +系统理论 系統理論 +系统级 系統級 +系统论 系統論 +系统设计 系統設計 +系统软体 系統軟體 +系统部 系統部 +系绳 繫繩 +系缆 繫纜 +系缚 繫縛 +系而不食 繫而不食 +系胄 系胄 +系腰 繫腰 +系臂 係臂 +系臂之宠 繫臂之寵 +系船桩 繫船樁 +系花 系花 +系获 係獲 +系裤子 繫褲子 +系裹 繫裹 +系词 系詞 +系谱 系譜 +系趾 繫趾 +系踵 係踵 +系蹄 係蹄 +系辞 繫辭 +系里 系裏 +系铃人 繫鈴人 +系铃解铃 繫鈴解鈴 +系鞋带 繫鞋帶 +系颈 繫頸 +系颈阙庭 係頸闕庭 +系风捕影 繫風捕影 +系风捕景 繫風捕景 +系馆 系館 +系马 繫馬 +紅发 紅髮 +素借 素藉 +素发 素髮 +素志 素志 +素愿 素願 +素未谋面 素未謀面 +素朴 素樸 +素面 素面 素麪 +素面朝天 素面朝天 +素食面 素食麪 +素餐尸位 素餐尸位 +索价 索價 +索价过高 索價過高 +索克 索克 +索克斯队 索克斯隊 +索合 索合 +索夫克 索夫克 +索夫克郡 索夫克郡 +索尔兹伯里平原 索爾茲伯里平原 +索尔兹伯里石环 索爾茲伯里石環 +索尽枯肠 索盡枯腸 +索托 索托 +索杰纳 索傑納 +索福克勒斯 索福克勒斯 +索福克里斯 索福克裏斯 +索里亚 索里亞 +索里士 索里士 +索面 索麪 +索馬里 索馬里 +索马里 索馬里 +索马里亚 索馬里亞 +紧了 緊了 +紧关里 緊關裏 +紧密配合 緊密配合 +紧急制动 緊急制動 +紧急集合 緊急集合 +紧扣 緊扣 +紧挨 緊挨 +紧溜子里 緊溜子裏 +紧系 緊繫 +紧绷 緊繃 +紧绷着 緊繃着 +紧绷绷 緊繃繃 +紧致 緊緻 +紧追不舍 緊追不捨 +紧随其后 緊隨其後 +紫云 紫雲 +紫云乡 紫雲鄉 +紫云苗族布依族自治县 紫云苗族布依族自治縣 +紫云英 紫雲英 +紫台 紫臺 +紫姜 紫薑 +紫微斗数 紫微斗數 +紫穗槐 紫穗槐 +紫苏 紫蘇 +紫苏属 紫蘇屬 +紫苏梅 紫蘇梅 +紫药水 紫藥水 +紫金山天文台 紫金山天文臺 +累了 累了 +累囚 累囚 +累块积苏 累塊積蘇 +累堆 累堆 +累瓦结绳 累瓦結繩 +累积性伤害症候群 累積性傷害症候羣 +累积折耗 累積折耗 +累绁 累紲 +累臣 累臣 +絣扒吊拷 絣扒吊拷 +綑了 綑了 +綑吊 綑吊 +綑扎 綑紮 +緝凶 緝兇 +縻系 縻繫 +繁台 繁臺 +繁复 繁複 +繁征博引 繁徵博引 +繁殖系数 繁殖係數 +繁钟 繁鐘 +繃价 繃價 +繃针 繃針 +纂修 纂修 +纂胄 纂胄 +纠合 糾合 +纡余 紆餘 +纡回 紆迴 +纡曲 紆曲 +纡朱怀金 紆朱懷金 +纡郁 紆鬱 +红丝暗系 紅絲暗繫 +红中白板 紅中白板 +红了 紅了 +红云 紅雲 +红光满面 紅光滿面 +红冬冬 紅鼕鼕 +红发 紅髮 +红发女郎 紅髮女郎 +红叶 紅葉 +红叶之题 紅葉之題 +红叶少棒队 紅葉少棒隊 +红叶村 紅葉村 +红叶杯 紅葉盃 +红叶树 紅葉樹 +红叶题诗 紅葉題詩 +红头发 紅頭髮 +红姑娘 紅姑娘 +红娘 紅娘 +红孩症 紅孩症 +红尘万丈 紅塵萬丈 +红岩 紅巖 +红得发紫 紅得發紫 +红日当午 紅日當午 +红曲 紅曲 +红杏出墙 紅杏出牆 +红杠 紅槓 +红松 紅松 +红极一时 紅極一時 +红牙板 紅牙板 +红眼症 紅眼症 +红种人 紅種人 +红紫乱朱 紅紫亂朱 +红绳系足 紅繩繫足 +红胡子 紅鬍子 +红色娘子军 紅色娘子軍 +红色系 紅色系 +红花绿叶 紅花綠葉 +红药 紅藥 +红药水 紅藥水 +红萝卜 紅蘿蔔 +红萝卜炒辣椒 紅蘿蔔炒辣椒 +红虫 紅蟲 +红运当头 紅運當頭 +红醋栗 紅醋栗 +红钟 紅鐘 +红铃虫 紅鈴蟲 +红霉素 紅黴素 +红面番鸭 紅面番鴨 +红须绿眼 紅鬚綠眼 +纤不盈握 纖不盈握 +纤丽 纖麗 +纤云 纖雲 +纤人 纖人 +纤介 纖介 +纤体 纖體 +纤儿 纖兒 +纤夫 縴夫 +纤妍 纖妍 +纤密 纖密 +纤小 纖小 +纤尘不染 纖塵不染 +纤屑 纖屑 +纤巧 纖巧 +纤度 纖度 +纤弱 纖弱 +纤微 纖微 +纤悉 纖悉 +纤悉无遗 纖悉無遺 +纤户 縴戶 +纤手 纖手 縴手 +纤指 纖指 +纤柔 纖柔 +纤毛 纖毛 +纤毛动力蛋白 纖毛動力蛋白 +纤毛虫 纖毛蟲 +纤毛运动 纖毛運動 +纤毫 纖毫 +纤玉 纖玉 +纤画 纖畫 +纤瘦 纖瘦 +纤离 纖離 +纤秾中度 纖穠中度 +纤纤 纖纖 +纤纤弱质 纖纖弱質 +纤纤玉手 纖纖玉手 +纤细 纖細 +纤细画 纖細畫 +纤维 纖維 +纤维丛 纖維叢 +纤维光学 纖維光學 +纤维化 纖維化 +纤维囊泡症 纖維囊泡症 +纤维工业 纖維工業 +纤维板 纖維板 +纤维植物 纖維植物 +纤维状 纖維狀 +纤维素 纖維素 +纤维细胞 纖維細胞 +纤维肌痛 纖維肌痛 +纤维胶 纖維膠 +纤维蛋原 纖維蛋原 +纤维蛋白 纖維蛋白 +纤维蛋白原 纖維蛋白原 +纤维质 纖維質 +纤维镜 纖維鏡 +纤维长度 纖維長度 +纤美 纖美 +纤腰 纖腰 +纤芥不遗 纖芥不遺 +纤芯直径 纖芯直徑 +纤长 纖長 +纤阿 纖阿 +约克 約克 +约克夏 約克夏 +约克夏猪 約克夏豬 +约克曼 約克曼 +约克维奇 約克維奇 +约克郡 約克郡 +约出 約出 +约占 約佔 +约同 約同 +约当现金 約當現金 +约据 約據 +约柜 約櫃 +约核 約核 +约等于 約等於 +约维克 約維克 +约翰参书 約翰參書 +约翰松 約翰松 +级任制 級任制 +级别 級別 +纪元后 紀元後 +纪历 紀曆 +纪录 紀錄 +纪录下来 紀錄下來 +纪录创造者 紀錄創造者 +纪录器 紀錄器 +纪录点 紀錄點 +纪录片 紀錄片 +纪录片儿 紀錄片兒 +纪录片奖 紀錄片獎 +纪录表 紀錄表 +纪念 紀念 +纪念周 紀念週 +纪里谷 紀里谷 +纯属巧合 純屬巧合 +纯情蜡妹 純情蠟妹 +纯朴 純樸 +纯种 純種 +纯种牛 純種牛 +纯种马 純種馬 +纱厂 紗廠 +纱布 紗布 +纱布口罩 紗布口罩 +纱布绷带 紗布繃帶 +纲鉴 綱鑑 +纳修斯 納修斯 +纳克希班迪 納克希班迪 +纳合 納合 +纳吉布 納吉布 +纳奇录异 納奇錄異 +纳征 納徵 +纳德阿里 納德阿里 +纳扎尔巴耶夫 納扎爾巴耶夫 +纳斯达克 納斯達克 +纳杰夫 納傑夫 +纳波里塔诺 納波里塔諾 +纳米技术 納米技術 +纳粹党 納粹黨 +纳莉台风 納莉颱風 +纳采 納采 +纵出 縱出 +纵切面 縱切面 +纵剖面 縱剖面 +纵向 縱向 +纵情恣欲 縱情恣欲 +纵情遂欲 縱情遂欲 +纵断面 縱斷面 +纵曲枉直 縱曲枉直 +纵梁 縱梁 +纵横交布 縱橫交佈 +纵欲 縱慾 +纵欲主义 縱慾主義 +纵欲无度 縱慾無度 +纵谷 縱谷 +纵谷区 縱谷區 +纷如烟 紛如煙 +纸制 紙製 +纸卷子 紙卷子 +纸叶子 紙葉子 +纸团 紙團 +纸尿布 紙尿布 +纸扎 紙紮 +纸扎店 紙紮店 +纸杯 紙杯 +纸板 紙板 +纸板盒 紙板盒 +纸板部 紙板部 +纸浆厂 紙漿廠 +纸烟 紙菸 +纸雕 紙雕 +纸面 紙面 +纹光针 紋光針 +纹板 紋板 +纹面 紋面 +纺纤 紡纖 +纺纱厂 紡紗廠 +纺织厂 紡織廠 +纺织娘 紡織娘 +纺锤虫 紡錘蟲 +纽几内亚 紐幾內亞 +纽华克 紐華克 +纽瓦克 紐瓦克 +纽芬兰与拉布拉多 紐芬蘭與拉布拉多 +纽蒙特 紐蒙特 +纾困 紓困 +线上 線上 +线团 線團 +线性系统 線性系統 +线性规划 線性規劃 +线虫 線蟲 +练习曲 練習曲 +练了 練了 +练出 練出 +练出来 練出來 +练团室 練團室 +练声曲 練聲曲 +练武术 練武術 +组党 組黨 +组别 組別 +组合 組合 +组合为 組合爲 +组合式 組合式 +组合成 組合成 +组合数学 組合數學 +组合服装 組合服裝 +组合法 組合法 +组合而成 組合而成 +组合菜 組合菜 +组合论 組合論 +组合语言 組合語言 +组合音响 組合音響 +组团 組團 +组曲 組曲 +组立式建筑 組立式建築 +组里 組裏 +细不容发 細不容髮 +细别 細別 +细叶山茶 細葉山茶 +细叶脉 細葉脈 +细叶金午时花 細葉金午時花 +细咽 細嚥 +细如发 細如髮 +细娘 細娘 +细布 細布 +细曲 細曲 +细术 細術 +细炼 細鍊 +细胞周期 細胞週期 +细胞融合 細胞融合 +细致 細緻 +细致入微 細緻入微 +细蒙蒙 細濛濛 +细表 細表 +细袅袅 細嫋嫋 +细针密缕 細針密縷 +细雨蒙蒙 細雨濛濛 +细雨蒙蒙忆当年 細雨濛濛憶當年 +织出 織出 +织布 織布 +织布厂 織布廠 +织布娘 織布娘 +织布机 織布機 +织席 織蓆 +织当访婢 織當訪婢 +织锦回文 織錦回文 +终了 終了 +终于 終於 +终制 終制 +终南别业 終南別業 +终归于 終歸於 +终曲 終曲 +终极 終極 +终极杀阵 終極殺陣 +终极目标 終極目標 +终止症 終止症 +终焉之志 終焉之志 +终端台 終端檯 +终而复始 終而復始 +终身有托 終身有托 +终须 終須 +绉布 縐布 +经世之才 經世之才 +经世致用 經世致用 +经丝彩色显花 經絲彩色顯花 +经典动力系统 經典動力系統 +经制 經制 +经卷 經卷 +经厂本 經廠本 +经历 經歷 +经历过 經歷過 +经历风雨 經歷風雨 +经发 經發 +经合会 經合會 +经合组织 經合組織 +经国之才 經國之才 +经坛 經壇 +经折 經摺 +经折装 經摺裝 +经曲 經曲 +经有云 經有云 +经术 經術 +经板儿 經板兒 +经济之才 經濟之才 +经济体制 經濟體制 +经济体系 經濟體系 +经济制度 經濟制度 +经济制裁 經濟制裁 +经济协力开发机构 經濟協力開發機構 +经济发展 經濟發展 +经济合作与发展组织 經濟合作與發展組織 +经济合作开发组织 經濟合作開發組織 +经济周期 經濟週期 +经济困境 經濟困境 +经济技术 經濟技術 +经济槓杆 經濟槓桿 +经济系 經濟系 +经济范畴 經濟範疇 +经济落后 經濟落後 +经济计划 經濟計劃 +经济部标准检验局 經濟部標準檢驗局 +经济面 經濟面 +经理 經理 +经营决策资讯系统 經營決策資訊系統 +经营范围 經營範圍 +经贸关系 經貿關係 +经验丰富 經驗豐富 +绑回 綁回 +绑回去 綁回去 +绑回来 綁回來 +绑扎 綁紮 +绒布 絨布 +结了 結了 +结仇 結仇 +结伙 結夥 +结伙抢劫 結夥搶劫 +结伴同游 結伴同遊 +结伴同行 結伴同行 +结余 結餘 +结党 結黨 +结党聚群 結黨聚羣 +结党营私 結黨營私 +结党连群 結黨連羣 +结出 結出 +结制 結制 +结发 結髮 +结发事师 結髮事師 +结发人 結髮人 +结发夫妻 結髮夫妻 +结合 結合 +结合为 結合爲 +结合体 結合體 +结合剂 結合劑 +结合实际 結合實際 +结合律 結合律 +结合成 結合成 +结合模型 結合模型 +结合水 結合水 +结合点 結合點 +结合线 結合線 +结合能 結合能 +结合起来 結合起來 +结合过程 結合過程 +结合韵 結合韻 +结合韵母 結合韻母 +结彩 結綵 +结扎 結紮 +结扎手术 結紮手術 +结扎术 結紮術 +结托 結托 +结扣 結釦 +结晶岩 結晶岩 +结核 結核 +结核杆菌 結核桿菌 +结梁子 結樑子 +结汇 結匯 +结汇证 結匯證 +结草虫 結草蟲 +结采 結采 +绕回 繞回 +绕梁 繞樑 +绕梁三日 繞樑三日 +绕梁之音 繞樑之音 +绕梁韵永 繞樑韻永 +绘事后素 繪事後素 +绘出 繪出 +绘制 繪製 +绘制图 繪製圖 +绘图板 繪圖板 +绘彩陶 繪彩陶 +绘画板 繪畫板 +绘里 繪里 +给个棒锤当针认 給個棒錘當針認 +给于 給於 +给价 給價 +给出 給出 +给我干脆 給我乾脆 +给药 給藥 +绚丽多彩 絢麗多彩 +绚烂归于平淡 絢爛歸於平淡 +络合 絡合 +络合物 絡合物 +络绎于途 絡繹於途 +络腮胡 絡腮鬍 +络腮胡子 絡腮鬍子 +绝不相同 絕不相同 +绝世出尘 絕世出塵 +绝于 絕於 +绝后 絕後 +绝后光前 絕後光前 +绝后患 絕後患 +绝后计 絕後計 +绝对参照 絕對參照 +绝岩 絕巖 +绝才 絕才 +绝望已极 絕望已極 +绝症 絕症 +绝种 絕種 +绝缘台 絕緣檯 +绞刑台 絞刑臺 +绞包针 絞包針 +绞尽 絞盡 +绞尽脑汁 絞盡腦汁 +绞干 絞乾 +绞面 絞面 +统一党 統一黨 +统一发票 統一發票 +统一规划 統一規劃 +统一规范 統一規範 +统一计划 統一計劃 +统制 統制 +统合 統合 +统合体 統合體 +统合力 統合力 +统合性 統合性 +统御 統御 +统筹规划 統籌規劃 +统计出 統計出 +统计制图 統計製圖 +统计图表 統計圖表 +统计数据 統計數據 +统计表 統計表 +绢布版 絹布版 +绣像 繡像 +绣出 繡出 +绣口 繡口 +绣帘 繡簾 +绣得 繡得 +绣户 繡戶 +绣房 繡房 +绣毯 繡毯 +绣球 繡球 +绣的 繡的 +绣花 繡花 +绣花针 繡花針 +绣花针儿 繡花針兒 +绣虎雕龙 繡虎雕龍 +绣衣 繡衣 +绣衣御史 繡衣御史 +绣衣朱履 繡衣朱履 +绣起 繡起 +绣针 繡針 +绣阁 繡閣 +绣面 繡面 +绣鞋 繡鞋 +绦虫 絛蟲 +绦虫纲 絛蟲綱 +继天立极 繼天立極 +继志 繼志 +继志述事 繼志述事 +继续干 繼續幹 +绪余 緒餘 +绪胄 緒胄 +续借 續借 +续借手续 續借手續 +续发性 續發性 +续发感染 續發感染 +续后 續後 +续后汉书 續後漢書 +续弦 續絃 +续杯 續杯 +续签 續簽 +续西游记 續西遊記 +续通志 續通志 +绮云 綺雲 +绮想曲 綺想曲 +绰板 綽板 +绰板婆 綽板婆 +绰绰有余 綽綽有餘 +绳扣 繩釦 +维修 維修 +维修区 維修區 +维修费 維修費 +维克 維克 +维克佛瑞柏加 維克佛瑞柏加 +维克利 維克利 +维克托 維克托 +维几尼亚 維幾尼亞 +维几尼亚州 維幾尼亞州 +维基数据 維基數據 +维基物种 維基物種 +维多利亚瀑布 維多利亞瀑布 +维多里欧 維多里歐 +维尔布鲁根 維爾布魯根 +维斗 維斗 +维斯杯 維斯杯 +维杰辛 維傑辛 +维科扬斯克 維科揚斯克 +维系 維繫 +维系人心 維繫人心 +维苏威 維蘇威 +维苏威火山 維蘇威火山 +绵中刺笑里刀 綿中刺笑裏刀 +绵历 綿歷 +绵延不尽 綿延不盡 +绵里藏针 綿裏藏針 +绵里针 綿裏針 +绷住 繃住 +绷场面 繃場面 +绷子 繃子 +绷巴吊拷 繃巴吊拷 +绷带 繃帶 +绷开 繃開 +绷扒吊拷 繃扒吊拷 +绷爬吊拷 繃爬吊拷 +绷紧 繃緊 +绷脸 繃臉 +绸布 綢布 +绸缎庄 綢緞莊 +综合 綜合 +综合业务数字网 綜合業務數字網 +综合体 綜合體 +综合医院 綜合醫院 +综合叙述 綜合敘述 +综合型 綜合型 +综合存款 綜合存款 +综合布线 綜合佈線 +综合平衡 綜合平衡 +综合征 綜合徵 +综合性 綜合性 +综合所得 綜合所得 +综合所得税 綜合所得稅 +综合扩大机 綜合擴大機 +综合报导 綜合報導 +综合报道 綜合報道 +综合服务数位网络 綜合服務數位網絡 +综合杂志 綜合雜誌 +综合法 綜合法 +综合症 綜合症 +综合类 綜合類 +综合艺术 綜合藝術 +综合语 綜合語 +综合课 綜合課 +综合银行 綜合銀行 +综合防治 綜合防治 +综合险 綜合險 +综核 綜覈 +综艺团 綜藝團 +绽出 綻出 +绽放出 綻放出 +绾发 綰髮 +绿云 綠雲 +绿党 綠黨 +绿发 綠髮 +绿叶 綠葉 +绿叶成荫 綠葉成蔭 +绿叶成阴 綠葉成陰 +绿暗红稀 綠暗紅稀 +绿松石 綠松石 +绿游网 綠遊網 +绿烟红雾 綠煙紅霧 +绿蜡 綠蠟 +绿衣黄里 綠衣黃裏 +绿鬓朱颜 綠鬢朱顏 +缀出 綴出 +缀合 綴合 +缆索吊椅 纜索吊椅 +缉凶 緝兇 +缉获 緝獲 +缎面 緞面 +缓了 緩了 +缓冲 緩衝 +缓冲体 緩衝體 +缓冲作用 緩衝作用 +缓冲剂 緩衝劑 +缓冲区 緩衝區 +缓冲器 緩衝器 +缓冲国 緩衝國 +缓冲地 緩衝地 +缓冲地区 緩衝地區 +缓冲地带 緩衝地帶 +缓冲式 緩衝式 +缓冲期 緩衝期 +缓冲液 緩衝液 +缓冲溶液 緩衝溶液 +缓发中子 緩發中子 +缓征 緩徵 +缔造出 締造出 +缕当 縷當 +编个 編個 +编了 編了 +编余 編余 +编余人员 編餘人員 +编修 編修 +编写出 編寫出 +编出 編出 +编出来 編出來 +编列出 編列出 +编制 編制 編製 +编制成 編製成 +编制法 編制法 +编发 編髮 +编录 編錄 +编曲 編曲 +编构出 編構出 +编注 編注 +编目表格 編目表格 +编目记录 編目記錄 +编目记录输入 編目記錄輸入 +编码系统 編碼系統 +编码表 編碼表 +编算出 編算出 +编织出 編織出 +编选出 編選出 +编造出 編造出 +编采 編採 +编钟 編鐘 +缘分已尽 緣分已盡 +缙云 縉雲 +缙云县 縉雲縣 +缜致 縝緻 +缝个 縫個 +缝了 縫了 +缝制 縫製 +缝制成 縫製成 +缝合 縫合 +缝合处 縫合處 +缝合带 縫合帶 +缝合线 縫合線 +缝衣针 縫衣針 +缝里 縫裏 +缝针 縫針 +缝针补线 縫針補線 +缝针迹 縫針跡 +缠回 纏回 +缠斗 纏鬥 +缣缃黄卷 縑緗黃卷 +缥致 縹致 +缦胡 縵胡 +缩合 縮合 +缩回 縮回 +缩回去 縮回去 +缩回来 縮回來 +缩影微卷 縮影微捲 +缩成一团 縮成一團 +缩栗 縮慄 +缪种流传 繆種流傳 +缮修 繕修 +缱绻难舍 繾綣難捨 +缴不出来 繳不出來 +缴出 繳出 +缴出去 繳出去 +缴出来 繳出來 +缴卷 繳卷 +缴回 繳回 +缴白卷 繳白卷 +缴获 繳獲 +缺乏症 缺乏症 +缺氧症 缺氧症 +缺课纪录 缺課紀錄 +缾沉簪折 缾沉簪折 +罂粟种子 罌粟種子 +罄尽 罄盡 +网上杂志 網上雜誌 +网坛 網壇 +网坛史 網壇史 +网布 網布 +网开一面 網開一面 +网开三面 網開三面 +网御 網禦 +网志 網誌 +网志上 網誌上 +网扣 網扣 +网游 網遊 +网状系统 網狀系統 +网管系统 網管系統 +网络技术 網絡技術 +网络操作系统 網絡操作系統 +网络游戏 網絡遊戲 +网络管理系统 網絡管理系統 +网络规划人员 網絡規劃人員 +网罗人才 網羅人才 +网里 網裏 +网际电台 網際電臺 +罔极 罔極 +罗克耶 羅克耶 +罗兴梁 羅興樑 +罗圣杰 羅聖傑 +罗宗胜 羅宗勝 +罗密欧与朱丽叶 羅密歐與朱麗葉 +罗密欧与茱丽叶 羅密歐與茱麗葉 +罗布 羅布 +罗布林卡 羅布林卡 +罗布森 羅布森 +罗布泊 羅布泊 +罗布麻 羅布麻 +罗式几何 羅式幾何 +罗彦杰 羅彥傑 +罗德里奎兹 羅德里奎茲 +罗德里格兹 羅德里格茲 +罗德里格斯 羅德里格斯 +罗德里盖兹 羅德里蓋茲 +罗志恩 羅志恩 +罗志明 羅志明 +罗志祥 羅志祥 +罗志良 羅志良 +罗拉巴克 羅拉巴克 +罗斯托克 羅斯托克 +罗斯托夫 羅斯托夫 +罗时丰 羅時豐 +罗曼蒂克 羅曼蒂克 +罗杰 羅傑 +罗杰斯 羅傑斯 +罗杰斯杯 羅傑斯杯 +罗柜 羅櫃 +罗氏几何 羅氏幾何 +罗汉松 羅漢松 +罗盘针 羅盤針 +罗素克洛 羅素克洛 +罗胡斯 羅胡斯 +罗致 羅致 +罗致人材 羅致人材 +罗致政 羅致政 +罗蒙诺索 羅蒙諾索 +罗西里尼 羅西里尼 +罗迪克 羅迪克 +罗马建筑 羅馬建築 +罚不当罪 罰不當罪 +罚个 罰個 +罚了 罰了 +罚出 罰出 +罚出去 罰出去 +罚出来 罰出來 +罢了 罷了 +罢于 罷於 +罢于奔命 罷於奔命 +罢黜百家独尊儒术 罷黜百家獨尊儒術 +罩杯 罩杯 +罪大恶极 罪大惡極 +罪当万死 罪當萬死 +罪恶 罪惡 +罪恶如山 罪惡如山 +罪恶感 罪惡感 +罪恶深重 罪惡深重 +罪恶滔天 罪惡滔天 +罪恶累累 罪惡累累 +罪恶行径 罪惡行徑 +罪恶贯盈 罪惡貫盈 +罪证确凿 罪證確鑿 +罪该万死 罪該萬死 +置之死地而后生 置之死地而後生 +置之脑后 置之腦後 +置于 置於 +置信系数 置信係數 +置换术 置換術 +置物柜 置物櫃 +置言成范 置言成範 +羁系 羈繫 +羊卜 羊卜 +羊布婚 羊布婚 +羊拐 羊拐 +羊毛出在羊身上 羊毛出在羊身上 +羊瘙痒症 羊瘙癢症 +羊群里跑出骆驼来 羊羣裏跑出駱駝來 +羊肉落在狗嘴里 羊肉落在狗嘴裏 +羊膜穿刺术 羊膜穿刺術 +羊舍 羊舍 +羊角面包 羊角麪包 +羊须疮 羊鬚瘡 +羌胡 羌胡 +美不胜收 美不勝收 +美丑 美醜 +美于 美於 +美仑 美崙 +美仑美奂 美侖美奐 +美利坚合众国 美利堅合衆國 +美制 美製 +美占 美佔 +美发 美髮 +美发业 美髮業 +美发师 美髮師 +美发店 美髮店 +美台 美臺 +美后 美后 +美国制 美國製 +美国参议院 美國參議院 +美国国际开发总署 美國國際開發總署 +美国国际集团 美國國際集團 +美国在台协会 美國在臺協會 +美国存托凭证 美國存託憑證 +美国总统报复权 美國總統報復權 +美国标准交换码 美國標準交換碼 +美国谷 美國谷 +美国资讯交换标准码 美國資訊交換標準碼 +美女如云 美女如雲 +美娇娘 美嬌娘 +美容手术 美容手術 +美容术 美容術 +美恶 美惡 +美才 美才 +美日关系 美日關係 +美术 美術 +美术史 美術史 +美术品 美術品 +美术商 美術商 +美术大师 美術大師 +美术字 美術字 +美术家 美術家 +美术灯 美術燈 +美术班 美術班 +美术电影 美術電影 +美术界 美術界 +美术系 美術系 +美术节 美術節 +美术设计 美術設計 +美术课 美術課 +美术馆 美術館 +美林集团 美林集團 +美沙冬 美沙冬 +美泽鉴人 美澤鑑人 +美洲杯 美洲盃 +美白针 美白針 +美穗 美穗 +美系 美系 +美耐板 美耐板 +美苏 美蘇 +美苏关系 美蘇關係 +美里 美里 +美里达 美里達 +羑里 羑里 +羚羊挂角 羚羊掛角 +羞于 羞於 +羞于启齿 羞於啓齒 +羞以牛后 羞以牛後 +羞恶 羞惡 +羞恶之心 羞惡之心 +羞愧难当 羞愧難當 +羞面见人 羞面見人 +羡余 羨餘 +羡叹 羨歎 +群丑 羣醜 +群众关系 羣衆關係 +群众团体 羣衆團體 +群后 羣后 +群系 羣系 +群而不党 羣而不黨 +群谋咸同 羣謀咸同 +群轻折轴 羣輕折軸 +群辟 羣辟 +群里 羣裏 +群雕 羣雕 +羹里来饭里去 羹裏來飯裏去 +羽毛丰满 羽毛豐滿 +羽毛未丰 羽毛未豐 +羽状复叶 羽狀複葉 +羽翼丰满 羽翼豐滿 +羽翼已丰 羽翼已豐 +羽虫 羽蟲 +翁同和 翁同和 +翁同龢 翁同龢 +翁山苏姬 翁山蘇姬 +翁干晃 翁乾晃 +翁郁容 翁郁容 +翊赞 翊贊 +翕辟 翕闢 +翘了 翹了 +翘出 翹出 +翘出去 翹出去 +翘出来 翹出來 +翘曲 翹曲 +翘翘板 翹翹板 +翠云裘 翠雲裘 +翡翠谷 翡翠谷 +翦彩 翦綵 +翰墨志 翰墨志 +翱游 翱遊 +翱游四海 翱遊四海 +翻个 翻個 +翻了 翻了 +翻云复雨 翻雲覆雨 +翻云覆雨 翻雲覆雨 +翻修 翻修 +翻出 翻出 +翻出去 翻出去 +翻出来 翻出來 +翻卷 翻卷 +翻台 翻檯 +翻复 翻覆 +翻复无常 翻覆無常 +翻天复地 翻天覆地 +翻录 翻錄 +翻手为云 翻手爲雲 +翻手为云覆手变雨 翻手爲雲覆手變雨 +翻手作云复手雨 翻手作雲覆手雨 +翻把恩人当仇人 翻把恩人當仇人 +翻新后 翻新後 +翻来吊去 翻來吊去 +翻来复去 翻來覆去 +翻松 翻鬆 +翻空出奇 翻空出奇 +翻筋斗 翻筋斗 +翻箱倒柜 翻箱倒櫃 +翻觔斗 翻觔斗 +翻译出 翻譯出 +翻跟斗 翻跟斗 +翻过筋斗 翻過筋斗 +翻面 翻面 +翻面皮 翻面皮 +翾风回雪 翾風迴雪 +老不修 老不修 +老个 老個 +老了 老了 +老于 老於 +老于世故 老於世故 +老人失智症 老人失智症 +老人癡呆症 老人癡呆症 +老仆 老僕 +老克 老克 +老八板儿 老八板兒 +老几 老幾 +老医少卜 老醫少卜 +老千 老千 +老古板 老古板 +老台 老臺 +老合儿 老合兒 +老同学 老同學 +老向 老向 +老和尚撞钟 老和尚撞鐘 +老咬虫 老咬蟲 +老大娘 老大娘 +老太婆的裹脚布 老太婆的裹腳布 +老奴才 老奴才 +老奸 老奸 +老奸巨猾 老奸巨猾 +老姑娘 老姑娘 +老姜 老薑 +老娘 老孃 +老娘儿 老孃兒 +老婆娘 老婆娘 +老婆当军 老婆當軍 +老实的终须在 老實的終須在 +老少一同 老少一同 +老少咸宜 老少咸宜 +老干 老幹 +老干妈 老乾媽 +老干部 老幹部 +老年性痴呆症 老年性癡呆症 +老年痴呆症 老年癡呆症 +老年癡呆症 老年癡呆症 +老幼咸宜 老幼咸宜 +老庄 老莊 +老当 老當 +老当益壮 老當益壯 +老态龙钟 老態龍鍾 +老斗 老斗 +老板 老闆 +老板人 老闆人 +老板娘 老闆娘 +老板家 老闆家 +老残游记 老殘遊記 +老气横秋 老氣橫秋 +老烟枪 老煙槍 +老烟鬼 老煙鬼 +老熊当道 老熊當道 +老爷钟 老爺鐘 +老猫鼻子上挂咸鱼 老貓鼻子上掛鹹魚 +老王卖瓜自卖自夸 老王賣瓜自賣自誇 +老皇历 老皇曆 +老米饭捏杀不成团 老米飯捏殺不成團 +老糊涂 老糊塗 +老罴当道 老羆當道 +老而弥坚 老而彌堅 +老胡 老胡 +老腌儿 老醃兒 +老腌瓜 老醃瓜 +老臊胡 老臊胡 +老舍 老舍 +老蒙 老懞 +老虎挂念佛珠 老虎掛念佛珠 +老虎生了翅膀一般 老虎生了翅膀一般 +老蚌出明珠 老蚌出明珠 +老表 老表 +老起面皮 老起面皮 +老郎庵 老郎庵 +老雕 老鵰 +老面子 老面子 +老面孔 老面孔 +老面皮 老面皮 +老骥伏枥志在千里 老驥伏櫪志在千里 +老鸹窝里出凤凰 老鴰窩裏出鳳凰 +考个 考個 +考了 考了 +考信录 考信錄 +考克斯 考克斯 +考出 考出 +考出来 考出來 +考前考后 考前考後 +考卷 考卷 +考卷纸 考卷紙 +考后 考後 +考察团 考察團 +考征 考徵 +考据 考據 +考据学 考據學 +考核 考覈 +考种 考種 +考虑不周 考慮不周 +考虑周到 考慮周到 +考试卷 考試卷 +考试卷子 考試卷子 +考试范围 考試範圍 +者回 者回 +而于 而於 +而云 而云 +而今而后 而今而後 +而克制 而剋制 +而后 而後 +而回 而回 +而胜于蓝 而勝於藍 +耍奸 耍奸 +耍得团团转 耍得團團轉 +耍斗 耍鬥 +耍笔杆 耍筆桿 +耍老千 耍老千 +耐克 耐克 +耐冬 耐冬 +耐多药 耐多藥 +耐多药结核病 耐多藥結核病 +耐热合金 耐熱合金 +耐药性 耐藥性 +耕九余三 耕九餘三 +耕作制度 耕作制度 +耕佣 耕傭 +耕出 耕出 +耕前耡后 耕前耡後 +耕地面积 耕地面積 +耕当问奴 耕當問奴 +耕当问奴织当访婢 耕當問奴織當訪婢 +耕御路 耕御路 +耕种 耕種 +耕获 耕穫 +耗尽 耗盡 +耘荡 耘盪 +耦合 耦合 +耳余 耳餘 +耳刮子 耳刮子 +耳卜 耳卜 +耳后 耳後 +耳提面命 耳提面命 +耳提面训 耳提面訓 +耳朵里冒出脚来 耳朵裏冒出腳來 +耳朵里响 耳朵裏響 +耳檐儿当不的胡帽 耳檐兒當不的胡帽 +耳沈 耳沈 +耳目之欲 耳目之欲 +耳红面赤 耳紅面赤 +耳针 耳針 +耶娘 耶孃 +耶烈万 耶烈萬 +耶稣升天节 耶穌升天節 +耶稣基督后期圣徒教会 耶穌基督後期聖徒教會 +耸了 聳了 +耸了耸 聳了聳 +耸了耸肩 聳了聳肩 +耸入云霄 聳入雲霄 +耸出 聳出 +耻居王后 恥居王後 +耽于 耽於 +耿于 耿於 +耿耿于心 耿耿於心 +耿耿于怀 耿耿於懷 +聊个 聊個 +聊个天 聊個天 +聊个痛快 聊個痛快 +聊复备数 聊復備數 +聊复尔尔 聊復爾爾 +聊复尔耳 聊復爾耳 +聊斋志异 聊齋志異 +聊胜一筹 聊勝一籌 +聊胜于无 聊勝於無 +聊表 聊表 +聊表寸心 聊表寸心 +聊表心意 聊表心意 +聋哑症 聾啞症 +聋虫 聾蟲 +职业代表制 職業代表制 +职业倦怠症 職業倦怠症 +职业团体 職業團體 +职业水准 職業水準 +职别 職別 +职员录 職員錄 +职员表 職員表 +职志 職志 +职权范围 職權範圍 +职系 職系 +职能范围 職能範圍 +职责范围 職責範圍 +聒噪 聒噪 +联于 聯於 +联体别墅 聯體別墅 +联准会 聯準會 +联发科 聯發科 +联合 聯合 +联合企业 聯合企業 +联合会 聯合會 +联合体 聯合體 +联合作战 聯合作戰 +联合促销 聯合促銷 +联合党 聯合黨 +联合內阁 聯合內閣 +联合公报 聯合公報 +联合军演 聯合軍演 +联合利华 聯合利華 +联合制 聯合制 +联合包裹服务公司 聯合包裹服務公司 +联合参谋 聯合參謀 +联合发表 聯合發表 +联合号 聯合號 +联合国 聯合國 +联合国日 聯合國日 +联合国案 聯合國案 +联合声明 聯合聲明 +联合大学 聯合大學 +联合战线 聯合戰線 +联合报 聯合報 +联合报系 聯合報系 +联合政府 聯合政府 +联合文学 聯合文學 +联合晚报 聯合晚報 +联合机 聯合機 +联合演习 聯合演習 +联合王国 聯合王國 +联合目录 聯合目錄 +联合社 聯合社 +联合组织 聯合組織 +联合自强 聯合自強 +联合舰队 聯合艦隊 +联合行 聯合行 +联合行动 聯合行動 +联合通讯社 聯合通訊社 +联合部队 聯合部隊 +联想集团 聯想集團 +联机游戏 聯機遊戲 +联盟党 聯盟黨 +联盟杯 聯盟杯 +联系 聯繫 +联系实际 聯繫實際 +联系方式 聯繫方式 +联系汇率 聯繫匯率 +联系群众 聯繫羣衆 +联赛杯 聯賽盃 +联邦制 聯邦制 +聘任制 聘任制 +聘姑娘 聘姑娘 +聘雇 聘僱 +聚了 聚了 +聚合 聚合 +聚合体 聚合體 +聚合作用 聚合作用 +聚合反应 聚合反應 +聚合果 聚合果 +聚合物 聚合物 +聚合脢 聚合脢 +聚合资讯订阅 聚合資訊訂閱 +聚合起来 聚合起來 +聚合酶 聚合酶 +聚药雄蕊 聚葯雄蕊 +聚酯纤维 聚酯纖維 +聪了 聰了 +聪明一世糊涂一时 聰明一世糊塗一時 +聪明才智 聰明才智 +肃北蒙古族自治县 肅北蒙古族自治縣 +肆奸植党 肆奸植黨 +肆志 肆志 +肇因于 肇因於 +肉丝面 肉絲麪 +肉吊窗 肉吊窗 +肉干 肉乾 +肉松 肉鬆 +肉松罐头 肉鬆罐頭 +肉欲 肉慾 +肉欲主义 肉慾主義 +肉毒杆菌 肉毒桿菌 +肉毒杆菌毒素 肉毒桿菌毒素 +肉毒梭状芽孢杆菌 肉毒梭狀芽孢桿菌 +肉汤面 肉湯麪 +肉穗花序 肉穗花序 +肉羹面 肉羹麪 +肉袒面缚 肉袒面縛 +肉里钱 肉裏錢 +肉重千斤 肉重千斤 +肌原纤维 肌原纖維 +肌理丰盈 肌理豐盈 +肌纤维 肌纖維 +肌纤蛋白 肌纖蛋白 +肌肉发达 肌肉發達 +肌肉松弛剂 肌肉鬆弛劑 +肌肉注射 肌肉注射 +肌肉萎缩症 肌肉萎縮症 +肌腺症 肌腺症 +肐膊只折在袖子里 肐膊只折在袖子裏 +肐膊折了往袖子里藏 肐膊折了往袖子裏藏 +肘后方 肘後方 +肘手链足 肘手鍊足 +肚儿里有勾当 肚兒裏有勾當 +肚子里点灯 肚子裏點燈 +肚皮里 肚皮裏 +肚肠阁落里边 肚腸閣落裏邊 +肚里 肚裏 +肚里一轮 肚裏一輪 +肚里寻思 肚裏尋思 +肚里明白 肚裏明白 +肚里的蛔虫 肚裏的蛔蟲 +肚里说不出来的苦 肚裏說不出來的苦 +肚里踌躇 肚裏躊躇 +肚里雷鸣 肚裏雷鳴 +肚饥 肚飢 +肝吸虫 肝吸蟲 +肝脏 肝臟 +肝脑涂地 肝腦塗地 +肝郁 肝鬱 +肠系膜 腸繫膜 +肠胃药 腸胃藥 +肠脏 腸臟 +股东特别大会 股東特別大會 +股价 股價 +股价指数 股價指數 +股份制 股份制 +股栗 股慄 +股栗肤粟 股栗膚粟 +股票价值 股票價值 +股票价格 股票價格 +股票投资获利率 股票投資獲利率 +肢体冲突 肢體衝突 +肤发 膚髮 +肥了 肥了 +肥冬瘦年 肥冬瘦年 +肥料厂 肥料廠 +肥水不过别人田 肥水不過別人田 +肥皂 肥皂 +肥皂劇 肥皂剧 +肥皂泡 肥皂泡 +肥皂粉 肥皂粉 +肥皂絲 肥皂丝 +肥皂莢 肥皂荚 +肥筑方言 肥筑方言 +肥胖症 肥胖症 +肥虫蚁 肥蟲蟻 +肩并肩 肩並肩 +肩须拍 肩須拍 +肮肮脏脏 骯骯髒髒 +肮脏 骯髒 +肮脏鬼 骯髒鬼 +肯出 肯出 +肯出去 肯出去 +肯出来 肯出來 +肯回 肯回 +肯回去 肯回去 +肯回来 肯回來 +肯定并例句 肯定並例句 +肯干 肯幹 +肯干啊 肯幹啊 +肯德瑞克 肯德瑞克 +育乐台 育樂臺 +育才 育才 +育种 育種 +肴馔 餚饌 +肺出血 肺出血 +肺叶 肺葉 +肺吸虫 肺吸蟲 +肺尘矽症 肺塵矽症 +肺炎克雷伯氏菌 肺炎克雷伯氏菌 +肺脏 肺臟 +肽链 肽鏈 +肾脏 腎臟 +肾脏炎 腎臟炎 +肾脏病 腎臟病 +肾脏癌 腎臟癌 +肾脏科 腎臟科 +肿大症 腫大症 +肿瘤切除术 腫瘤切除術 +胁制 脅制 +胃出血 胃出血 +胃脏 胃臟 +胃药 胃藥 +胃药片 胃藥片 +胃里 胃裏 +胄嗣 胄嗣 +胄子 胄子 +胄序 胄序 +胄族 胄族 +胄甲 冑甲 +胄监 胄監 +胄科 冑科 +胄绪 胄緒 +胄胤 胄胤 +胄裔 胄裔 +胄裔繁衍 胄裔繁衍 +胄阀 胄閥 +胆大于天 膽大於天 +胆大如斗 膽大如斗 +胆石症 膽石症 +背人 揹人 +背他 揹他 +背你 揹你 +背來 揹來 +背债 揹債 +背出 背出 +背出去 揹出去 +背出来 背出來 揹出來 +背前背后 背前背後 +背包 揹包 +背包袱 揹包袱 +背后 背後 +背向 背向 揹向 +背回 揹回 +背回家去 揹回家去 +背地里 背地裏 +背城借一 背城借一 +背她 揹她 +背小孩 揹小孩 +背山面水 背山面水 +背带 揹帶 +背我 揹我 +背暗投明 背暗投明 +背板 背板 +背梁骨 背梁骨 +背榜 揹榜 +背物 揹物 +背着 揹着 +背筐 揹筐 +背篓 揹簍 +背胶布 背膠布 +背负 揹負 +背走 揹走 +背酸 背痠 +背面 背面 +背风面 背風面 +背饥荒 揹饑荒 +胎发 胎髮 +胎里坏 胎裏壞 +胎里富 胎裏富 +胎里毒 胎裏毒 +胎里素 胎裏素 +胎面 胎面 +胖姑娘坐小轿儿 胖姑娘坐小轎兒 +胚叶 胚葉 +胚胎发生 胚胎發生 +胚胎干 胚胎幹 +胜不骄 勝不驕 +胜不骄败不馁 勝不驕敗不餒 +胜之不武 勝之不武 +胜乐金刚 勝樂金剛 +胜了 勝了 +胜事 勝事 +胜于 勝於 +胜仗 勝仗 +胜任 勝任 +胜任愉快 勝任愉快 +胜任能力 勝任能力 +胜会 勝會 +胜似 勝似 +胜出 勝出 +胜利 勝利 +胜利在望 勝利在望 +胜利归来 勝利歸來 +胜利投手 勝利投手 +胜利果实 勝利果實 +胜利组 勝利組 +胜利者 勝利者 +胜利队 勝利隊 +胜券 勝券 +胜券在握 勝券在握 +胜博殿 勝博殿 +胜在 勝在 +胜地 勝地 +胜境 勝境 +胜局 勝局 +胜常 勝常 +胜得 勝得 +胜投数 勝投數 +胜投王 勝投王 +胜景 勝景 +胜朝 勝朝 +胜概 勝概 +胜残去杀 勝殘去殺 +胜流 勝流 +胜游 勝遊 +胜率 勝率 +胜的 勝的 +胜算 勝算 +胜肽 胜肽 +胜落袋 勝落袋 +胜衣 勝衣 +胜诉 勝訴 +胜负 勝負 +胜负乃兵家常事 勝負乃兵家常事 +胜败 勝敗 +胜败乃兵家常事 勝敗乃兵家常事 +胜跡 勝跡 +胜过 勝過 +胜过一个诸葛亮 勝過一個諸葛亮 +胜迹 勝蹟 +胜部 勝部 +胜部冠军 勝部冠軍 +胜键 胜鍵 +胞子虫 胞子蟲 +胞芽杯 胞芽杯 +胡三 胡三 +胡三省 胡三省 +胡为慎 胡爲慎 +胡乐 胡樂 +胡乱 胡亂 +胡二巴越 胡二巴越 +胡云 胡云 +胡亥 胡亥 +胡人 胡人 +胡伶 胡伶 +胡佛 胡佛 +胡作非为 胡作非爲 +胡佩兰 胡佩蘭 +胡佳 胡佳 +胡侃 胡侃 +胡做乔为 胡做喬爲 +胡儿 胡兒 +胡元辉 胡元輝 +胡克 胡克 +胡克定律 胡克定律 +胡克斯特拉 胡克斯特拉 +胡兰成 胡蘭成 +胡力 胡力 +胡匪 鬍匪 +胡卢 胡盧 +胡卢提 胡盧提 +胡厮哄 胡廝哄 +胡厮混 胡廝混 +胡厮缠 胡廝纏 +胡吃海喝 胡吃海喝 +胡吃闷睡 胡吃悶睡 +胡同 衚衕 +胡吣 胡唚 +胡吹 胡吹 +胡吹乱捧 胡吹亂捧 +胡吹乱滂 胡吹亂滂 +胡吹乱诌 胡吹亂謅 +胡吹大气 胡吹大氣 +胡哨 胡哨 +胡喷 胡噴 +胡嘈 胡嘈 +胡噜 胡嚕 +胡国强 胡國強 +胡图族 胡圖族 +胡天 胡天 +胡天胡地 胡天胡地 +胡天胡帝 胡天胡帝 +胡夫 胡夫 +胡如虹 胡如虹 +胡姑姑 胡姑姑 +胡姓 胡姓 +胡姬花 胡姬花 +胡婷婷 胡婷婷 +胡子 鬍子 +胡子工程 鬍子工程 +胡子拉碴 鬍子拉碴 +胡子昂 胡子昂 +胡子渣 鬍子渣 +胡子阿姨 鬍子阿姨 +胡孟轩 胡孟軒 +胡学东 胡學東 +胡宁 胡寧 +胡安国 胡安國 +胡宝元 胡寶元 +胡富雄 胡富雄 +胡幼伟 胡幼偉 +胡幼凤 胡幼鳳 +胡幼幼 胡幼幼 +胡床 胡牀 +胡建雄 胡建雄 +胡弄局 胡弄局 +胡彦斌 胡彥斌 +胡德夫 胡德夫 +胡心夫 胡心夫 +胡志强 胡志強 +胡志明 胡志明 +胡志明市 胡志明市 +胡志隆 胡志隆 +胡忠信 胡忠信 +胡思 胡思 +胡思乱想 胡思亂想 +胡思乱量 胡思亂量 +胡惟庸 胡惟庸 +胡想 胡想 +胡慧中 胡慧中 +胡才勇 胡才勇 +胡扑掩 胡撲掩 +胡扑搭 胡撲搭 +胡打海摔 胡打海摔 +胡托莫 胡托莫 +胡扯 胡扯 +胡扯八溜 胡扯八溜 +胡扯淡 胡扯淡 +胡技烜 胡技烜 +胡抡混闹 胡掄混鬧 +胡拉混扯 胡拉混扯 +胡拨四 胡撥四 +胡掳 胡擄 +胡掳忙乱 胡擄忙亂 +胡搅 胡攪 +胡搅蛮缠 胡攪蠻纏 +胡搞 胡搞 +胡支对 胡支對 +胡支扯叶 胡支扯葉 +胡敲 胡敲 +胡旋舞 胡旋舞 +胡晓菁 胡曉菁 +胡服 胡服 +胡朴安 胡樸安 +胡来 胡來 +胡杨 胡楊 +胡杰 胡杰 +胡林翼 胡林翼 +胡枝子 胡枝子 +胡柏 胡柏 +胡某 胡某 +胡柴 胡柴 +胡根班德 胡根班德 +胡桃 胡桃 +胡桃木 胡桃木 +胡桃科 胡桃科 +胡桃钳 胡桃鉗 +胡桃钳组曲 胡桃鉗組曲 +胡桐 胡桐 +胡梢 鬍梢 +胡梦卜 胡夢卜 +胡梯 胡梯 +胡椒 胡椒 +胡椒子 胡椒子 +胡椒属 胡椒屬 +胡椒盐 胡椒鹽 +胡椒粉 胡椒粉 +胡椒粒 胡椒粒 +胡椒薄荷 胡椒薄荷 +胡椒面 胡椒麪 +胡椒饼 胡椒餅 +胡歌 胡歌 +胡歌野调 胡歌野調 +胡母敬 胡母敬 +胡汉民 胡漢民 +胡浩德 胡浩德 +胡海 胡海 +胡海峰 胡海峯 +胡涂 胡塗 +胡涂虫 胡塗蟲 +胡淑贞 胡淑貞 +胡混 胡混 +胡清晖 胡清暉 +胡渣 鬍渣 +胡温新政 胡溫新政 +胡渰 胡渰 +胡燕妮 胡燕妮 +胡爲 胡爲 +胡牌 胡牌 +胡猜 胡猜 +胡琴 胡琴 +胡琴儿 胡琴兒 +胡瑗 胡瑗 +胡瓜 胡瓜 +胡瓜鱼 胡瓜魚 +胡碴子 鬍碴子 +胡祖庆 胡祖慶 +胡秦 胡秦 +胡突 胡突 +胡立宗 胡立宗 +胡笙 胡笙 +胡笳 胡笳 +胡笳十八拍 胡笳十八拍 +胡粉 胡粉 +胡素秋 胡素秋 +胡紫微 胡紫微 +胡紫薇 胡紫薇 +胡编乱造 胡編亂造 +胡缠 胡纏 +胡羼 胡羼 +胡耀邦 胡耀邦 +胡耈 胡耈 +胡胜川 胡勝川 +胡胜正 胡勝正 +胡胡卢卢 胡胡盧盧 +胡自强 胡自強 +胡臭 胡臭 +胡芦巴 胡蘆巴 +胡荽 胡荽 +胡萝卜 胡蘿蔔 +胡萝卜就烧酒 胡蘿蔔就燒酒 +胡萝卜汁 胡蘿蔔汁 +胡萝卜素 胡蘿蔔素 +胡蓝之狱 胡藍之獄 +胡蔓草 胡蔓草 +胡蔓藤 胡蔓藤 +胡虏 胡虜 +胡蜂 胡蜂 +胡蝶梦 胡蝶夢 +胡行 胡行 +胡行乱作 胡行亂作 +胡言 胡言 +胡言乱语 胡言亂語 +胡言汉语 胡言漢語 +胡讲 胡講 +胡诌 胡謅 +胡诌乱傍 胡謅亂傍 +胡诌乱扯 胡謅亂扯 +胡诌乱说 胡謅亂說 +胡诌乱道 胡謅亂道 +胡诌八扯 胡謅八扯 +胡话 胡話 +胡语 胡語 +胡说 胡說 +胡说乱语 胡說亂語 +胡说乱道 胡說亂道 +胡说八道 胡說八道 +胡说散道 胡說散道 +胡说白道 胡說白道 +胡豆 胡豆 +胡赖 胡賴 +胡越 胡越 +胡越一家 胡越一家 +胡适 胡適 +胡适之 胡適之 +胡适纪念馆 胡適紀念館 +胡遮刺 胡遮刺 +胡鄂公 胡鄂公 +胡里胡涂 胡里胡塗 +胡金龙 胡金龍 +胡铨 胡銓 +胡铺搭 胡鋪搭 +胡锦涛 胡錦濤 +胡长豪 胡長豪 +胡闹 胡鬧 +胡雕刺 胡雕刺 +胡雪岩 胡雪巖 +胡须 鬍鬚 +胡须渣 鬍鬚渣 +胡颓子 胡頹子 +胡风 胡風 +胡饼 胡餅 +胡马 胡馬 +胡马依北风 胡馬依北風 +胡骑 胡騎 +胡髭 鬍髭 +胡髯 鬍髯 +胡麻 胡麻 +胡麻油 胡麻油 +胡麻籽 胡麻籽 +胤胄 胤胄 +胰淀粉酶 胰澱粉酶 +胰脏 胰臟 +胰脏炎 胰臟炎 +胰脏癌 胰臟癌 +胶卷 膠捲 +胶原纤维 膠原纖維 +胶合 膠合 +胶合板 膠合板 +胶布 膠布 +胶布膏 膠布膏 +胶彩画 膠彩畫 +胶莱谷地 膠萊谷地 +胸廓切开术 胸廓切開術 +胸怀坦荡 胸懷坦蕩 +胸怀大志 胸懷大志 +胸无大志 胸無大志 +胸杯 胸杯 +胸罗万象 胸羅萬象 +胸部手术 胸部手術 +胸针 胸針 +胼胚种 胼胚種 +能借 能借 +能克制 能剋制 +能力范围 能力範圍 +能干 能幹 +能干巴巴 能乾巴巴 +能干扰 能干擾 +能干杯 能乾杯 +能干涉 能干涉 +能干着急 能乾着急 +能干耗 能乾耗 +能干脆 能乾脆 +能干预 能干預 +能征善战 能征善戰 +能征惯战 能征慣戰 +能愿动词 能願動詞 +能自制 能自制 +能舍 能捨 +能说不能干 能說不能幹 +脂漏性角化症 脂漏性角化症 +脆快了当 脆快了當 +脆谷乐 脆穀樂 +脉不制肉 脈不制肉 +脉冲 脈衝 +脉冲光 脈衝光 +脉冲式 脈衝式 +脉冲数 脈衝數 +脉冲星 脈衝星 +脉冲电磁场 脈衝電磁場 +脉冲雷达 脈衝雷達 +脉岩 脈岩 +脊梁 脊樑 +脊梁背 脊樑背 +脊梁骨 脊樑骨 +脊百合 脊百合 +脏东西 髒東西 +脏乱 髒亂 +脏乱点 髒亂點 +脏了 髒了 +脏兮兮 髒兮兮 +脏发 髒髮 +脏器 臟器 +脏土 髒土 +脏字 髒字 +脏字儿 髒字兒 +脏弹 髒彈 +脏得 髒得 +脏心 髒心 +脏死 髒死 +脏水 髒水 +脏污 髒污 +脏病 髒病 +脏的 髒的 +脏脏 髒髒 +脏腑 臟腑 +脏词 髒詞 +脏话 髒話 +脏钱 髒錢 +脑出血 腦出血 +脑前额叶 腦前額葉 +脑力激荡 腦力激盪 +脑力激荡术 腦力激盪術 +脑力激荡法 腦力激盪法 +脑后 腦後 +脑回 腦回 +脑子里 腦子裏 +脑干 腦幹 +脑成像技术 腦成像技術 +脑海里 腦海裏 +脑震荡 腦震盪 +脓团 膿團 +脚价 腳價 +脚划船 腳划船 +脚后跟 腳後跟 +脚夫 腳伕 +脚底板 腳底板 +脚底板儿 腳底板兒 +脚扣 腳釦 +脚板 腳板 +脚注 腳註 +脚炼 腳鍊 +脚踏板 腳踏板 +脚酸 腳痠 +脚面 腳面 +脱不了 脫不了 +脱不了身 脫不了身 +脱了 脫了 +脱党 脫黨 +脱出 脫出 +脱出重围 脫出重圍 +脱发 脫髮 +脱发剂 脫髮劑 +脱口而出 脫口而出 +脱困 脫困 +脱尽 脫盡 +脱帽致敬 脫帽致敬 +脱离不了 脫離不了 +脱离关系 脫離關係 +脱蜡 脫蠟 +脱衣舞娘 脫衣舞娘 +脱谷机 脫穀機 +脱身而出 脫身而出 +脱轨而出 脫軌而出 +脱颎而出 脫熲而出 +脱颖而出 脫穎而出 +脸上挂了招牌 臉上掛了招牌 +脸都绿了 臉都綠了 +脸面 臉面 +脸面之情 臉面之情 +脸面无光 臉面無光 +脺脏 脺臟 +脾脏 脾臟 +腊之以为饵 腊之以爲餌 +腊味 臘味 +腊尽 臘盡 +腊尽冬残 臘盡冬殘 +腊斯克 臘斯克 +腊笔 臘筆 +腌䐶 腌䐶 +腌制 醃製 +腌成 醃成 +腌汁 醃汁 +腌泡 醃泡 +腌渍 醃漬 +腌渍物 醃漬物 +腌猪肉 醃豬肉 +腌肉 醃肉 +腌腊 醃臘 +腌臜 腌臢 +腌菜 醃菜 +腌起来 醃起來 +腌过 醃過 +腌酱瓜 醃醬瓜 +腌里巴臜 腌裏巴臢 +腌鱼 醃魚 +腌鱼肉 醃魚肉 +腌黄瓜 醃黃瓜 +腐余 腐餘 +腐女军团 腐女軍團 +腐干 腐乾 +腐恶 腐惡 +腐肠之药 腐腸之藥 +腑脏 腑臟 +腕表 腕錶 +腕道症候群 腕道症候羣 +腕隧道症 腕隧道症 +腕隧道症候群 腕隧道症候羣 +腥黑穗病 腥黑穗病 +腮托 腮托 +腮斗 腮斗 +腰一卷 腰一捲 +腰布 腰布 +腰扣 腰釦 +腰杆 腰桿 +腰杆子 腰桿子 +腰板 腰板 +腰板儿 腰板兒 +腰板脖硬 腰板脖硬 +腰柜 腰櫃 +腰椎间盘突出 腰椎間盤突出 +腰椎间盘突出症 腰椎間盤突出症 +腰系 腰繫 +腰缠万贯 腰纏萬貫 +腰酸 腰痠 +腰里 腰裏 +腰里硬 腰裏硬 +腰间系 腰間繫 +腹板 腹板 +腹泻药 腹瀉藥 +腹语术 腹語術 +腹里 腹裏 +腹面 腹面 +腻了 膩了 +腻云 膩雲 +腼面 靦面 +腼颜事仇 靦顏事仇 +腼颜借命 靦顏借命 +腾云 騰雲 +腾云跨风 騰雲跨風 +腾云驾雾 騰雲駕霧 +腾冲 騰衝 +腾冲县 騰衝縣 +腾出 騰出 +腾出来 騰出來 +腾升 騰昇 +腾捷飞升 騰捷飛升 +腾格里 騰格里 +腾格里山 騰格里山 +腾格里沙漠 騰格裏沙漠 +腾格里湖 騰格里湖 +腿后腱 腿後腱 +腿酸 腿痠 +膊风板 膊風板 +膏药 膏藥 +膏药旗 膏藥旗 +膨土岩 膨土岩 +膨松 膨鬆 +膨松剂 膨鬆劑 +膨胀系数 膨脹係數 +膻中 膻中 +膻中穴 膻中穴 +臀位取胎术 臀位取胎術 +臂一卷 臂一捲 +臣仆 臣僕 +臣服于 臣服於 +臣服于心 臣服於心 +臥云 臥雲 +臥游 臥遊 +臥狼当道 臥狼當道 +臥薪尝胆 臥薪嘗膽 +臧获 臧獲 +臧谷亡羊 臧穀亡羊 +自个 自個 +自个儿 自個兒 +自主旅游 自主旅遊 +自主游 自主遊 +自主系统 自主系統 +自了 自了 +自于 自於 +自交系 自交系 +自修 自修 +自修室 自修室 +自修法 自修法 +自修课 自修課 +自出 自出 +自出一家 自出一家 +自出机杼 自出機杼 +自制 自制 自製 +自制一下 自制一下 +自制下来 自制下來 +自制之力 自制之力 +自制之能 自制之能 +自制力 自制力 +自制炸弹 自製炸彈 +自制的能 自制的能 +自制能力 自制能力 +自动化技术 自動化技術 +自动恢复 自動恢復 +自动挂挡 自動掛擋 +自动控制 自動控制 +自动柜员机 自動櫃員機 +自动离合 自動離合 +自动自发 自動自發 +自动表 自動錶 +自动资料处理系统 自動資料處理系統 +自助旅游 自助旅遊 +自助游 自助遊 +自卖自夸 自賣自誇 +自发 自發 +自发对称破缺 自發對稱破缺 +自发性 自發性 +自发电位 自發電位 +自发运动 自發運動 +自叹 自嘆 +自同寒蝉 自同寒蟬 +自后 自後 +自夸 自誇 +自学成才 自學成才 +自尽 自盡 +自度曲 自度曲 +自当 自當 +自愿 自願 +自愿书 自願書 +自愿就学方案 自願就學方案 +自愿性 自願性 +自愿者 自願者 +自我表现 自我表現 +自我评价 自我評價 +自来水厂 自來水廠 +自核 自核 +自此以后 自此以後 +自此而后 自此而後 +自民党 自民黨 +自治制 自治制 +自注 自注 +自点曲 自點曲 +自然卷 自然捲 +自然历 自然歷 +自然接种 自然接種 +自由亚洲电台 自由亞洲電臺 +自由党 自由黨 +自由意志 自由意志 +自由意志主义 自由意志主義 +自由斗士 自由鬥士 +自由民主党 自由民主黨 +自由组合 自由組合 +自由组合规律 自由組合規律 +自由面 自由面 +自种 自種 +自觉自愿 自覺自願 +自诒伊戚 自詒伊戚 +自贻伊戚 自貽伊戚 +自赞 自贊 +自适 自適 +自适应 自適應 +自选曲 自選曲 +自采 自採 +自闭症 自閉症 +自须 自須 +自食恶果 自食惡果 +自驾汽车出租 自駕汽車出租 +自鸣钟 自鳴鐘 +臭不可当 臭不可當 +臭局 臭侷 +臭气冲天 臭氣沖天 +臭气熏天 臭氣熏天 +臭熏熏 臭燻燻 +臭虫 臭蟲 +至于 至於 +至当 至當 +至愚极陋 至愚極陋 +至极 至極 +至矣尽矣 至矣盡矣 +致上 致上 +致书 致書 +致乱 致亂 +致于 致於 +致仕 致仕 +致以 致以 +致使 致使 +致使动词 致使動詞 +致冷 致冷 +致冷劑 致冷劑 +致函 致函 +致力 致力 +致力于 致力於 +致命 致命 +致命伤 致命傷 +致命处 致命處 +致命性 致命性 +致哀 致哀 +致奠 致奠 +致密 緻密 +致富 致富 +致富之道 致富之道 +致师 致師 +致志 致志 +致思 致思 +致意 致意 +致政 致政 +致敬 致敬 +致歉 致歉 +致死 致死 +致死剂量 致死劑量 +致死性 致死性 +致死性毒剂 致死性毒劑 +致死案 致死案 +致死率 致死率 +致死量 致死量 +致残 致殘 +致理 致理 +致理商专 致理商專 +致理商业专科学校 致理商業專科學校 +致理技术学院 致理技術學院 +致用 致用 +致电 致電 +致畸 致畸 +致疑 致疑 +致病 致病 +致病性 致病性 +致病菌 致病菌 +致癌 致癌 +致癌物 致癌物 +致癌物质 致癌物質 +致知 致知 +致祭 致祭 +致胜 致勝 +致胜率 致勝率 +致胜球 致勝球 +致获 致獲 +致词 致詞 +致详 致詳 +致语 致語 +致谢 致謝 +致贺 致賀 +致赠 致贈 +致身 致身 +致辞 致辭 +致远 致遠 +致远任重 致遠任重 +致送 致送 +臻于 臻於 +臻于完善 臻於完善 +臻于郅治 臻於郅治 +舂谷 舂穀 +舄卤 舄鹵 +舆台 輿臺 +舆地志 輿地志 +舆尸 輿尸 +舆志 輿志 +舌一卷 舌一捲 +舌叶 舌葉 +舌叶音 舌葉音 +舌后 舌後 +舌尖后音 舌尖後音 +舌干唇焦 舌乾脣焦 +舌面 舌面 +舌面元音 舌面元音 +舌面前音 舌面前音 +舌面后音 舌面後音 +舌面如镜 舌面如鏡 +舌面音 舌面音 +舍下 舍下 +舍下他 捨下他 +舍下你 捨下你 +舍下她 捨下她 +舍下我 捨下我 +舍不得 捨不得 +舍亲 舍親 +舍人 舍人 +舍出 捨出 +舍利 舍利 +舍利佛 舍利佛 +舍利塔 舍利塔 +舍利子 舍利子 +舍利子塔 舍利子塔 +舍利弗 舍利弗 +舍去 捨去 +舍命 捨命 +舍命救人 捨命救人 +舍堕 捨墮 +舍妹 舍妹 +舍姪 舍姪 +舍安就危 捨安就危 +舍实 捨實 +舍实求虚 捨實求虛 +舍己 捨己 +舍己为人 捨己爲人 +舍己为公 捨己爲公 +舍己为国 捨己爲國 +舍己从人 捨己從人 +舍己就人 捨己就人 +舍己成人 捨己成人 +舍己救人 捨己救人 +舍己芸人 捨己芸人 +舍弃 捨棄 +舍弗勒 舍弗勒 +舍弟 舍弟 +舍得 捨得 +舍德主义 舍德主義 +舍我其谁 捨我其誰 +舍我复谁 捨我復誰 +舍旧迎新 捨舊迎新 +舍本 捨本 +舍本事末 捨本事末 +舍本逐末 捨本逐末 +舍本问末 捨本問末 +舍正从邪 捨正從邪 +舍死忘生 捨死忘生 +舍生 捨生 +舍生取义 捨生取義 +舍生存义 舍生存義 +舍生忘死 捨生忘死 +舍监 舍監 +舍短从长 捨短從長 +舍短取长 捨短取長 +舍短录长 捨短錄長 +舍短用长 捨短用長 +舍身 捨身 +舍身为国 捨身爲國 +舍身图报 捨身圖報 +舍身报国 捨身報國 +舍身救人 捨身救人 +舍身求法 捨身求法 +舍车保帅 捨車保帥 +舍近务远 捨近務遠 +舍近即远 捨近即遠 +舍近求远 捨近求遠 +舍近谋远 捨近謀遠 +舍间 舍間 +舒卷 舒捲 +舒卷自如 舒捲自如 +舒发 舒發 +舒适 舒適 +舒适度 舒適度 +舒适性 舒適性 +舒适感 舒適感 +舒适音 舒適音 +舒马克 舒馬克 +舔干淨 舔乾淨 +舞出 舞出 +舞台 舞臺 +舞台剧 舞臺劇 +舞台区 舞臺區 +舞台戏 舞臺戲 +舞台效果 舞臺效果 +舞台秀 舞臺秀 +舞台艺术 舞臺藝術 +舞台音乐 舞臺音樂 +舞后 舞后 +舞团 舞團 +舞娘 舞娘 +舞曲 舞曲 +舞榭歌台 舞榭歌臺 +舞水端里 舞水端里 +舞蹈团 舞蹈團 +舞蹈症 舞蹈症 +舞蹈系 舞蹈系 +舟曲 舟曲 +舟曲县 舟曲縣 +舢板 舢板 +舢板运动 舢板運動 +航发中心 航發中心 +航发会 航發會 +航向 航向 +航太系 航太系 +航海历 航海曆 +航海历史 航海歷史 +航海年表 航海年表 +航海日志 航海日誌 +航班表 航班表 +航空术 航空術 +航空母舰战斗群 航空母艦戰鬥羣 +舰只 艦隻 +舳舻千里 舳艫千里 +船不漏针漏针没外人 船不漏針漏針沒外人 +船厂 船廠 +船只 船隻 +船台 船臺 +船员表 船員表 +船夫 船伕 +船娘 船孃 +船期表 船期表 +船板 船板 +船载的金银填不满烟花债 船載的金銀填不滿煙花債 +船边交货价 船邊交貨價 +船钟 船鐘 +艇甲板 艇甲板 +艎板 艎板 +艨冲 艨衝 +良价 良价 +良心发现 良心發現 +良游 良遊 +良田万顷不如薄艺随身 良田萬頃不如薄藝隨身 +良种 良種 +良种繁育 良種繁育 +良药 良藥 +良药苦口 良藥苦口 +良药苦口忠言逆耳 良藥苦口忠言逆耳 +艰困 艱困 +艰巨 艱鉅 +艰苦备尝 艱苦備嚐 +艰苦奋斗 艱苦奮鬥 +艰难困苦 艱難困苦 +艰难曲折 艱難曲折 +色当 色當 +色彩 色彩 +色彩三要素 色彩三要素 +色彩学 色彩學 +色彩缤纷 色彩繽紛 +色彩艳丽 色彩豔麗 +色彩鲜明 色彩鮮明 +色彩鲜艳 色彩鮮豔 +色情杂志 色情雜誌 +色欲 色慾 +色盲症 色盲症 +色系 色系 +艳后 豔后 +艸木丰丰 艸木丰丰 +艺压当行 藝壓當行 +艺坛 藝壇 +艺文志 藝文志 +艺术 藝術 +艺术体操 藝術體操 +艺术化 藝術化 +艺术区 藝術區 +艺术厅 藝術廳 +艺术史 藝術史 +艺术品 藝術品 +艺术团 藝術團 +艺术奖 藝術獎 +艺术字 藝術字 +艺术季 藝術季 +艺术学院 藝術學院 +艺术家 藝術家 +艺术展 藝術展 +艺术性 藝術性 +艺术指导 藝術指導 +艺术村 藝術村 +艺术歌曲 藝術歌曲 +艺术片 藝術片 +艺术界 藝術界 +艺术类 藝術類 +艺术系 藝術系 +艺术美 藝術美 +艺术者 藝術者 +艺术节 藝術節 +艺术街 藝術街 +艺术院 藝術院 +艺术馆 藝術館 +艺穗节 藝穗節 +艾万斯 艾萬斯 +艾伦图克 艾倫圖克 +艾克尔 艾克爾 +艾克斯 艾克斯 +艾克曼 艾克曼 +艾克森 艾克森 +艾克森美孚 艾克森美孚 +艾克雷史东 艾克雷史東 +艾力克 艾力克 +艾力克斯 艾力克斯 +艾回 艾迴 +艾布兰 艾布蘭 +艾布拉莫维奇 艾布拉莫維奇 +艾希克罗 艾希克羅 +艾弥尔 艾彌爾 +艾德蒙斯 艾德蒙斯 +艾德蒙顿 艾德蒙頓 +艾斯托利尔 艾斯托利爾 +艾瑞克 艾瑞克 +艾瑞克森 艾瑞克森 +艾瑞斯托 艾瑞斯托 +艾瑞里 艾瑞里 +艾米里 艾米里 +艾维斯普里斯莱 艾維斯普里斯萊 +艾赛克斯 艾賽克斯 +艾达克 艾達克 +艾里亚森 艾里亞森 +艾里斯 艾里斯 +艾里森 艾里森 +艾里赛宫 艾里賽宮 +节余 節餘 +节制 節制 +节制资本 節制資本 +节奏布鲁斯 節奏布魯斯 +节录 節錄 +节录自 節錄自 +节欲 節慾 +节流踏板 節流踏板 +节目表 節目表 +节节上升 節節上升 +节节胜利 節節勝利 +芍药 芍藥 +芍药花 芍藥花 +芒果干 芒果乾 +芒种 芒種 +芙蓉出水 芙蓉出水 +芟秋 芟秋 +芥子气恶病质 芥子氣惡病質 +芥子纳须弥 芥子納須彌 +芦帘 蘆簾 +芦席 蘆蓆 +芦洲蟹舍 蘆洲蟹舍 +芦花荡 蘆花蕩 +芦荡 蘆蕩 +芧栗 芧栗 +芫荽叶 芫荽葉 +芬郁 芬鬱 +芭丝克华 芭絲克華 +芭托莉 芭托莉 +芭蕉布 芭蕉布 +芭蕾舞团 芭蕾舞團 +芯慧同用 芯慧同用 +芯片厂 芯片廠 +花个 花個 +花了 花了 +花价 花價 +花儿针 花兒針 +花六出 花六出 +花卷 花捲 +花厂 花廠 +花发老 花髮老 +花台 花臺 +花叶 花葉 +花叶病 花葉病 +花哄 花鬨 +花团 花團 +花团锦簇 花團錦簇 +花园里 花園裏 +花坛 花壇 +花坛乡 花壇鄉 +花娘 花娘 +花尽 花盡 +花岗岩 花崗岩 +花岗岩质层 花崗岩質層 +花布 花布 +花布包 花布包 +花庵词选 花菴詞選 +花彩 花彩 +花心萝卜 花心蘿蔔 +花托 花托 +花招百出 花招百出 +花拳绣腿 花拳繡腿 +花旗参 花旗參 +花无百日开人无千日好 花無百日開人無千日好 +花明柳暗 花明柳暗 +花栗鼠 花栗鼠 +花样游泳 花樣游泳 +花样百出 花樣百出 +花椒面 花椒麪 +花烟馆 花煙館 +花盆里 花盆裏 +花种 花種 +花粉症 花粉症 +花红叶绿 花紅葉綠 +花胜 花勝 +花胡同 花衚衕 +花胡瓜 花胡瓜 +花荡 花蕩 +花药 花葯 +花药瓣 花葯瓣 +花莲师范学院 花蓮師範學院 +花藜胡哨 花藜胡哨 +花虫 花蟲 +花车游行 花車遊行 +花采 花采 +花里胡哨 花裏胡哨 +花钟 花鐘 +花雕 花雕 +花雕酒 花雕酒 +花面 花面 +花面狸 花面狸 +花马吊嘴 花馬弔嘴 +花魁娘子 花魁娘子 +芳名录 芳名錄 +芸苔 蕓薹 +芸薹 蕓薹 +芸辉 蕓輝 +苇席 葦蓆 +苇苕系巢 葦苕繫巢 +苍发 蒼髮 +苍术 蒼朮 +苍松 蒼松 +苍松翠柏 蒼松翠柏 +苍生涂炭 蒼生塗炭 +苍翠欲滴 蒼翠欲滴 +苍蝇掐了头 蒼蠅掐了頭 +苍郁 蒼鬱 +苍黄翻复 蒼黃翻覆 +苎麻 苧麻 +苏东启案 蘇東啓案 +苏东坡 蘇東坡 +苏丹 蘇丹 +苏丹人 蘇丹人 +苏丹共和国 蘇丹共和國 +苏丹达佛 蘇丹達佛 +苏丹达佛区 蘇丹達佛區 +苏丽文 蘇麗文 +苏乐明 蘇樂明 +苏乐桃 蘇樂桃 +苏仙区 甦仙區 +苏伊士 蘇伊士 +苏伊士河 蘇伊士河 +苏伊士运河 蘇伊士運河 +苏俄 蘇俄 +苏俄在中国 蘇俄在中國 +苏俊仁 蘇俊仁 +苏俊宾 蘇俊賓 +苏克雷 蘇克雷 +苏公隄 蘇公隄 +苏共 蘇共 +苏凡纳布 蘇凡納布 +苏利南 蘇利南 +苏利南共和国 蘇利南共和國 +苏利文 蘇利文 +苏北 蘇北 +苏区 蘇區 +苏占区 蘇佔區 +苏合香 蘇合香 +苏启荣 蘇啓榮 +苏哈托 蘇哈托 +苏哲毅 蘇哲毅 +苏嘉全 蘇嘉全 +苏圣斌 蘇聖斌 +苏堤 蘇堤 +苏头 蘇頭 +苏妮儿 蘇妮兒 +苏妮妮 蘇妮妮 +苏妮萨 蘇妮薩 +苏姆盖特 蘇姆蓋特 +苏子油 蘇子油 +苏宁 蘇寧 +苏宁电器 蘇寧電器 +苏家 蘇家 +苏家屯 蘇家屯 +苏家屯区 蘇家屯區 +苏家明 蘇家明 +苏富比 蘇富比 +苏富比公司 蘇富比公司 +苏小妹 蘇小妹 +苏尔 蘇爾 +苏尔坦 蘇爾坦 +苏尔奈 蘇爾奈 +苏尼特右旗 蘇尼特右旗 +苏尼特左旗 蘇尼特左旗 +苏峻 蘇峻 +苏州 蘇州 +苏州人 蘇州人 +苏州地区 蘇州地區 +苏州城 蘇州城 +苏州大学 蘇州大學 +苏州市 蘇州市 +苏州弹词 蘇州彈詞 +苏州片 蘇州片 +苏州码 蘇州碼 +苏州码子 蘇州碼子 +苏州评弹 蘇州評彈 +苏州话 蘇州話 +苏巴猜 蘇巴猜 +苏帕瑞 蘇帕瑞 +苏建 蘇建 +苏建和 蘇建和 +苏建忠 蘇建忠 +苏建荣 蘇建榮 +苏式 蘇式 +苏德曼 蘇德曼 +苏必利尔湖 蘇必利爾湖 +苏必略湖 蘇必略湖 +苏志明 蘇志明 +苏志燮 蘇志燮 +苏息 蘇息 +苏恺二七战机 蘇愷二七戰機 +苏打 蘇打 +苏打水 蘇打水 +苏打粉 蘇打粉 +苏打绿 蘇打綠 +苏打饼干 蘇打餅乾 +苏扬托 蘇揚托 +苏报案 蘇報案 +苏拉 蘇拉 +苏拉威 蘇拉威 +苏拉威西 蘇拉威西 +苏拉威西岛 蘇拉威西島 +苏拉朋 蘇拉朋 +苏拉特 蘇拉特 +苏拉育 蘇拉育 +苏拾平 蘇拾平 +苏振平 蘇振平 +苏文生 蘇文生 +苏方 蘇方 +苏昆 蘇崑 +苏易简 蘇易簡 +苏曼殊 蘇曼殊 +苏有朋 蘇有朋 +苏木 蘇木 +苏杭 蘇杭 +苏杯 蘇盃 +苏枋木 蘇枋木 +苏格兰 蘇格蘭 +苏格兰人 蘇格蘭人 +苏格兰场 蘇格蘭場 +苏格兰女王玛丽 蘇格蘭女王瑪麗 +苏格兰帽 蘇格蘭帽 +苏格兰折耳猫 蘇格蘭摺耳貓 +苏格兰王 蘇格蘭王 +苏格兰裙 蘇格蘭裙 +苏格兰队 蘇格蘭隊 +苏格拉底 蘇格拉底 +苏梅岛 蘇梅島 +苏步青 蘇步青 +苏武 蘇武 +苏武牧羊 蘇武牧羊 +苏比克湾 蘇比克灣 +苏氨酸 蘇氨酸 +苏永康 蘇永康 +苏永耀 蘇永耀 +苏永钦 蘇永欽 +苏治芬 蘇治芬 +苏泽光 蘇澤光 +苏洵 蘇洵 +苏海韩潮 蘇海韓潮 +苏澳 蘇澳 +苏澳港 蘇澳港 +苏澳镇 蘇澳鎮 +苏炎坤 蘇炎坤 +苏炳宪 蘇炳憲 +苏焕智 蘇煥智 +苏玲瑶 蘇玲瑤 +苏珊 蘇珊 +苏珊娜 蘇珊娜 +苏珊莎兰登 蘇珊莎蘭登 +苏瓦 蘇瓦 +苏白 蘇白 +苏盈贵 蘇盈貴 +苏禄岛 蘇祿島 +苏福男 蘇福男 +苏秦 蘇秦 +苏秦刺股 蘇秦刺股 +苏立吉 蘇立吉 +苏糖 蘇糖 +苏绣 蘇繡 +苏维埃 蘇維埃 +苏维埃俄国 蘇維埃俄國 +苏维埃社会主义共和国联盟 蘇維埃社會主義共和國聯盟 +苏维埃社会主义共和国联邦 蘇維埃社會主義共和國聯邦 +苏维成 蘇維成 +苏罗河 蘇羅河 +苏美人 蘇美人 +苏美尔 蘇美爾 +苏翊杰 蘇翊傑 +苏联 蘇聯 +苏联之友社 蘇聯之友社 +苏联人 蘇聯人 +苏联共产党 蘇聯共產黨 +苏联最高苏维埃 蘇聯最高蘇維埃 +苏胺酸 蘇胺酸 +苏舜钦 蘇舜欽 +苏芮 蘇芮 +苏花公路 蘇花公路 +苏花高 蘇花高 +苏苏 蘇蘇 +苏莱曼 蘇萊曼 +苏菜 蘇菜 +苏菲 蘇菲 +苏菲亚 蘇菲亞 +苏菲亚罗兰 蘇菲亞羅蘭 +苏菲玛索 蘇菲瑪索 +苏菲雅 蘇菲雅 +苏蕙 蘇蕙 +苏西洛 蘇西洛 +苏谢配 蘇謝配 +苏贞昌 蘇貞昌 +苏超凡 蘇超凡 +苏轩弘 蘇軒弘 +苏轼 蘇軾 +苏辙 蘇轍 +苏达拉 蘇達拉 +苏达索诺 蘇達索諾 +苏迪曼杯 蘇迪曼杯 +苏迪约梭 蘇迪約梭 +苏醒 甦醒 +苏醒剂 甦醒劑 +苏醒过来 甦醒過來 +苏里 蘇里 +苏里南 蘇里南 +苏里南河 蘇裏南河 +苏里安提沙洛索 蘇里安提沙洛索 +苏金达 蘇金達 +苏铁 蘇鐵 +苏镇霖 蘇鎮霖 +苏门答腊 蘇門答臘 +苏门答腊岛 蘇門答臘島 +苏门答腊省 蘇門答臘省 +苏门达腊 蘇門達臘 +苏门达腊岛 蘇門達臘島 +苏门长啸 蘇門長嘯 +苏隄 蘇隄 +苏雷曼 蘇雷曼 +苏非 蘇非 +苏非主义 蘇非主義 +苏非教派 蘇非教派 +苏黎世 蘇黎世 +苏黎世联邦理工学院 蘇黎世聯邦理工學院 +苏黎士 蘇黎士 +苑里 苑裏 +苑里镇 苑裏鎮 +苗栗 苗栗 +苗栗人 苗栗人 +苗栗县 苗栗縣 +苗栗市 苗栗市 +苗种 苗種 +苗胄 苗胄 +苛政猛于虎 苛政猛於虎 +苜蓿长栏干 苜蓿長欄干 +苞叶 苞葉 +苞虫 苞蟲 +苟合 苟合 +苟合取容 苟合取容 +苟同 苟同 +苟容曲从 苟容曲從 +若个 若個 +若于 若於 +若出一辙 若出一轍 +若合符节 若合符節 +若向 若向 +若干 若干 +若干个 若干個 +若干人 若干人 +若干年 若干年 +若虫 若蟲 +苦了 苦了 +苦于 苦於 +苦修 苦修 +苦卤 苦鹵 +苦参 苦蔘 +苦大仇深 苦大仇深 +苦尽甘来 苦盡甘來 +苦干 苦幹 +苦干实干 苦幹實幹 +苦思恶想 苦思惡想 +苦斗 苦鬥 +苦杯 苦杯 +苦海无边回头是岸 苦海無邊回頭是岸 +苦瓜干 苦瓜乾 +苦药 苦藥 +苦读出身 苦讀出身 +苦酒满杯 苦酒滿杯 +苦里 苦裏 +苧悴 薴悴 +苧烯 薴烯 +苫布 苫布 +苯并噻吩 苯並噻吩 +苯酮尿症 苯酮尿症 +英克丝特 英克絲特 +英制 英制 +英占 英佔 +英发 英發 +英国广播电台 英國廣播電臺 +英姿焕发 英姿煥發 +英布 英布 +英才 英才 +英才俊伟 英才俊偉 +英文系 英文系 +英日同盟 英日同盟 +英杰 英傑 +英气风发 英氣風發 +英烈千秋 英烈千秋 +英联合王国 英聯合王國 +英胄 英胄 +英语系 英語系 +英里 英里 +英雄交响曲 英雄交響曲 +英雄只怕病来磨 英雄只怕病來磨 +英雄所见略同 英雄所見略同 +英雄模范 英雄模範 +英雄豪杰 英雄豪傑 +苴布 苴布 +苹叶 蘋葉 +苹婆 蘋婆 +苹果 蘋果 +苹果公司 蘋果公司 +苹果园 蘋果園 +苹果子姜尼 蘋果子姜尼 +苹果干 蘋果乾 +苹果手机 蘋果手機 +苹果树 蘋果樹 +苹果核 蘋果核 +苹果汁 蘋果汁 +苹果派 蘋果派 +苹果电脑 蘋果電腦 +苹果皮 蘋果皮 +苹果绿 蘋果綠 +苹果肉 蘋果肉 +苹果脸 蘋果臉 +苹果螺 蘋果螺 +苹果蠹蛾 蘋果蠹蛾 +苹果迷 蘋果迷 +苹果酒 蘋果酒 +苹果酱 蘋果醬 +苹果酸 蘋果酸 +苹果馅饼 蘋果餡餅 +苹萦 苹縈 +苹风 蘋風 +茂发 茂發 +茂才 茂才 +茂才异等 茂才異等 +茂松 茂松 +茂都淀 茂都澱 +范仲淹 范仲淹 +范伦铁诺 范倫鐵諾 +范佩西 范佩西 +范例 範例 +范光群 范光羣 +范公偁 范公偁 +范公堤 范公堤 +范冰冰 范冰冰 +范可钦 范可欽 +范哈能 范哈能 +范嘉骅 范嘉驊 +范围 範圍 +范围之内 範圍之內 +范围之外 範圍之外 +范围之广 範圍之廣 +范围内 範圍內 +范围属性 範圍屬性 +范围很大 範圍很大 +范围是 範圍是 +范围查询 範圍查詢 +范围调整 範圍調整 +范国铨 范國銓 +范增 范增 +范士丹 范士丹 +范姜 范姜 +范字 範字 +范家 范家 +范宽 范寬 +范小姐 范小姐 +范尼斯特鲁伊 范尼斯特魯伊 +范履霜 范履霜 +范式 範式 +范张鸡黍 范張雞黍 +范德林特 范德林特 +范德格拉夫 范德格拉夫 +范德瓦耳斯 范德瓦耳斯 +范德瓦耳斯力 范德瓦耳斯力 +范德维德 范德維德 +范德萨 范德薩 +范志毅 范志毅 +范性形变 範性形變 +范戈德 范戈德 +范成大 范成大 +范文 範文 +范文同 范文同 +范文正公 范文正公 +范文澜 范文瀾 +范文照 范文照 +范文程 范文程 +范文网 範文網 +范文芳 范文芳 +范文藤 范文藤 +范文虎 范文虎 +范文选读 範文選讀 +范斯坦 范斯坦 +范晓萱 范曉萱 +范晔 范曄 +范本 範本 +范植伟 范植偉 +范植谷 范植谷 +范欣妤 范欣妤 +范正祥 范正祥 +范洪森 范洪森 +范湘暄 范湘暄 +范特尔 范特爾 +范特西 范特西 +范玮琪 范瑋琪 +范琪斐 范琪斐 +范甘迪 范甘迪 +范畴 範疇 +范畴内 範疇內 +范畴论 範疇論 +范登堡 范登堡 +范皓阗 范皓闐 +范筱梵 范筱梵 +范纲武 范綱武 +范织钦 范織欽 +范绮馨 范綺馨 +范范之辈 范範之輩 +范蠡 范蠡 +范进 范進 +范逸臣 范逸臣 +范金 範金 +范鎮 范鎮 +范阳 范陽 +范陈柏 范陳柏 +范雎 范雎 +范靖瑶 范靖瑤 +茄二十八星瓢虫 茄二十八星瓢蟲 +茄克 茄克 +茄克衫 茄克衫 +茄冬 茄冬 +茅以升 茅以升 +茅厕里的石头 茅廁裏的石頭 +茅台 茅臺 +茅台酒 茅臺酒 +茅舍 茅舍 +茅针 茅針 +茈胡 茈胡 +茉莉克 茉莉克 +茎干 莖幹 +茑萝施乔松 蔦蘿施喬松 +茧栗 繭栗 +茧纤维 繭纖維 +茨万吉拉伊 茨萬吉拉伊 +茫茫荡荡 茫茫蕩蕩 +茱丽叶 茱麗葉 +茵借 茵藉 +茶余 茶餘 +茶几 茶几 +茶卤 茶滷 +茶叶 茶葉 +茶叶末 茶葉末 +茶叶末儿 茶葉末兒 +茶叶碱 茶葉鹼 +茶叶罐 茶葉罐 +茶叶蛋 茶葉蛋 +茶已干 茶已乾 +茶庄 茶莊 +茶托 茶托 +茶杯 茶杯 +茶毛虫 茶毛蟲 +茶里王 茶裏王 +茶面 茶麪 +茶面子 茶麪子 +茶馀酒后 茶餘酒後 +茶馀饭后 茶餘飯後 +茹志鹃 茹誌鵑 +荅布 荅布 +荆尸 荊尸 +荆布 荊布 +荆钗布袄 荊釵布襖 +荆钗布裙 荊釵布裙 +荆钗裙布 荊釵裙布 +草丛里 草叢裏 +草原千里 草原千里 +草台班子 草臺班子 +草叶 草葉 +草叶集 草葉集 +草团瓢 草團瓢 +草头药 草頭藥 +草字汇 草字彙 +草履虫 草履蟲 +草席 草蓆 +草庵 草菴 +草枝摆 草枝擺 +草签 草簽 +草舍 草舍 +草草了事 草草了事 +草荐 草荐 +草药 草藥 +草药方 草藥方 +草虫 草蟲 +荐居 荐居 +荐臻 荐臻 +荐饥 荐饑 +荑手纤纤 荑手纖纖 +荒了 荒了 +荒年谷 荒年穀 +荒无人烟 荒無人煙 +荒烟漫草 荒煙漫草 +荒烟蔓草 荒煙蔓草 +荒腔走板 荒腔走板 +荞面 蕎麪 +荞麦面 蕎麥麪 +荡产 蕩產 +荡产倾家 蕩產傾家 +荡出 盪出 +荡到 盪到 +荡口 盪口 +荡垢涤汙 盪垢滌污 +荡复 蕩覆 +荡女 蕩女 +荡妇 蕩婦 +荡子 蕩子 +荡寇 蕩寇 +荡寒 盪寒 +荡尽 蕩盡 +荡平 蕩平 +荡开 盪開 +荡心 蕩心 +荡志 蕩志 +荡悠悠 盪悠悠 +荡散 蕩散 +荡来荡去 盪來盪去 +荡析 蕩析 +荡析离居 蕩析離居 +荡检逾闲 蕩檢逾閑 +荡气回肠 蕩氣迴腸 +荡气回阳 蕩氣迴陽 +荡涤 盪滌 +荡漾 盪漾 +荡漾出 盪漾出 +荡潏 蕩潏 +荡然 蕩然 +荡然无存 蕩然無存 +荡瑕涤秽 蕩瑕滌穢 +荡田 蕩田 +荡秋千 盪鞦韆 +荡舟 盪舟 +荡船 盪船 +荡荡 蕩蕩 +荡荡悠悠 盪盪悠悠 +荡酒 盪酒 +荡风 盪風 +荣升 榮升 +荣幸 榮幸 +荣幸之至 榮幸之至 +荣归故里 榮歸故里 +荣登后座 榮登后座 +荣获 榮獲 +荣获冠军 榮獲冠軍 +荤油蒙了心 葷油蒙了心 +荦确 犖确 +荧郁 熒鬱 +荫生 廕生 +荫监 廕監 +荫蔽 廕庇 +荫袭 廕襲 +药专 藥專 +药业 藥業 +药丸 藥丸 +药事法 藥事法 +药价 藥價 +药价差 藥價差 +药典 藥典 +药兽 藥獸 +药农 藥農 +药到命除 藥到命除 +药到回春 藥到回春 +药到病除 藥到病除 +药剂 藥劑 +药剂士 藥劑士 +药剂学 藥劑學 +药剂师 藥劑師 +药剂量 藥劑量 +药力 藥力 +药包 藥包 +药医 藥醫 +药医不死病佛度有缘人 藥醫不死病佛度有緣人 +药医学系 藥醫學系 +药单 藥單 +药厂 藥廠 +药叉 藥叉 +药发傀儡 藥發傀儡 +药吊子 藥吊子 +药名 藥名 +药味 藥味 +药品 藥品 +药品店 藥品店 +药商 藥商 +药壶 藥壺 +药头 藥頭 +药妆 藥妝 +药妆品 藥妝品 +药妆店 藥妝店 +药婆 藥婆 +药学 藥學 +药学专科学校 藥學專科學校 +药学系 藥學系 +药害 藥害 +药局 藥局 +药师 藥師 +药师佛 藥師佛 +药师如来 藥師如來 +药师经 藥師經 +药师节 藥師節 +药店 藥店 +药引 藥引 +药引子 藥引子 +药性 藥性 +药性气 藥性氣 +药房 藥房 +药捻子 藥捻子 +药政处 藥政處 +药效 藥效 +药效持久 藥效持久 +药方 藥方 +药方儿 藥方兒 +药明康德 藥明康德 +药末 藥末 +药杀 藥殺 +药材 藥材 +药械 藥械 +药检 藥檢 +药检局 藥檢局 +药棉 藥棉 +药死 藥死 +药水 藥水 +药水儿 藥水兒 +药水味 藥水味 +药汁 藥汁 +药油 藥油 +药法 藥法 +药浴 藥浴 +药液 藥液 +药渣 藥渣 +药片 藥片 +药物 藥物 +药物中毒 藥物中毒 +药物学 藥物學 +药物学家 藥物學家 +药物成瘾 藥物成癮 +药物治疗 藥物治療 +药王 藥王 +药王菩萨 藥王菩薩 +药理 藥理 +药理学 藥理學 +药瓶 藥瓶 +药瓶子 藥瓶子 +药用 藥用 +药用价值 藥用價值 +药用植物 藥用植物 +药疗 藥療 +药疹 藥疹 +药瘾 藥癮 +药皂 藥皂 +药监局 藥監局 +药盒 藥盒 +药石 藥石 +药石之言 藥石之言 +药石罔效 藥石罔效 +药科 藥科 +药笼中物 藥籠中物 +药筒 藥筒 +药签 藥籤 +药箭 藥箭 +药箱 藥箱 +药籤 藥籤 +药粉 藥粉 +药糖 藥糖 +药线 藥線 +药罐 藥罐 +药罐子 藥罐子 +药而愈 藥而癒 +药膏 藥膏 +药膛 藥膛 +药膳 藥膳 +药茶 藥茶 +药草 藥草 +药草茶 藥草茶 +药行 藥行 +药衡 藥衡 +药衣子 藥衣子 +药补 藥補 +药袋 藥袋 +药裹关心 藥裹關心 +药言 藥言 +药贩 藥販 +药贴 藥貼 +药费 藥費 +药酒 藥酒 +药量 藥量 +药针 藥針 +药铺 藥鋪 +药锭 藥錠 +药面儿 藥麪兒 +药食同源 藥食同源 +药饵 藥餌 +药饼 藥餅 +药骰 藥骰 +荷叶 荷葉 +荷叶先师 荷葉先師 +荷叶肉 荷葉肉 +荷尔蒙 荷爾蒙 +荷花出水 荷花出水 +荷花淀 荷花澱 +荷里活 荷里活 +荷雷克 荷雷克 +莎玛海耶克 莎瑪海耶克 +莒光周 莒光週 +莜面 莜麪 +莫三比克 莫三比克 +莫三比克人民共和国 莫三比克人民共和國 +莫乃耳合金 莫乃耳合金 +莫余毒也 莫余毒也 +莫信直中直须防人不仁 莫信直中直須防人不仁 +莫克姆湾 莫克姆灣 +莫吉托 莫吉托 +莫布里 莫布里 +莫干山 莫干山 +莫当 莫當 +莫扎特 莫扎特 +莫扎里拉 莫扎里拉 +莫折大提 莫折大提 +莫报万一 莫報萬一 +莫曼斯克 莫曼斯克 +莫杰斯特 莫傑斯特 +莫桑比克 莫桑比克 +莫管闲事 莫管閒事 +莫索里尼 莫索里尼 +莫荷不连续面 莫荷不連續面 +莫莉克 莫莉克 +莫蹪于山而蹪于垤 莫蹪於山而蹪於垤 +莫辨楮叶 莫辨楮葉 +莫过于 莫過於 +莫里 莫里 +莫里叶 莫里葉 +莫里哀 莫里哀 +莫里尼奥 莫里尼奧 +莫里希 莫里希 +莫里斯 莫里斯 +莫里森 莫里森 +莫里纳 莫里納 +莫霍洛维奇不连续面 莫霍洛維奇不連續面 +莫霍面 莫霍面 +莫须 莫須 +莫须有 莫須有 +莱布尼兹 萊布尼茲 +莱彩 萊彩 +莱彩北堂 萊綵北堂 +莱德杯 萊德杯 +莱索托 萊索托 +莱里达 萊里達 +莲台 蓮臺 +莲叶 蓮葉 +莲开并蒂 蓮開並蒂 +莲须 蓮鬚 +获准 獲准 +获刑 獲刑 +获判 獲判 +获判无罪 獲判無罪 +获利 獲利 +获利倍蓰 獲利倍蓰 +获利率 獲利率 +获利王 獲利王 +获到 獲到 +获匪其丑 獲匪其醜 +获取 獲取 +获咎 獲咎 +获嘉 獲嘉 +获嘉县 獲嘉縣 +获奖 獲獎 +获奖人 獲獎人 +获奖率 獲獎率 +获奖者 獲獎者 +获得 獲得 +获得四 獲得四 +获得四坏 獲得四壞 +获得性 獲得性 +获得者 獲得者 +获得胜利 獲得勝利 +获悉 獲悉 +获戾 獲戾 +获报 獲報 +获捷 獲捷 +获救 獲救 +获暴利者 獲暴利者 +获有 獲有 +获益 獲益 +获益不浅 獲益不淺 +获益匪浅 獲益匪淺 +获益者 獲益者 +获益良多 獲益良多 +获知 獲知 +获罪 獲罪 +获胜 獲勝 +获胜者 獲勝者 +获致 獲致 +获赠 獲贈 +获赦 獲赦 +获选 獲選 +获选为 獲選爲 +获邀 獲邀 +获释 獲釋 +获颁 獲頒 +获鹿 獲鹿 +获鹿县 獲鹿縣 +获鹿镇 獲鹿鎮 +莺谷 鶯谷 +莽卤 莽鹵 +莽荡 莽蕩 +菁英杯 菁英盃 +菅野美穗 菅野美穗 +菊坛 菊壇 +菊秋 菊秋 +菌丝体 菌絲體 +菌托 菌托 +菌核 菌核 +菌种 菌種 +菌胶团 菌膠團 +菌血症 菌血症 +菜干 菜乾 +菜板 菜板 +菜瓜布 菜瓜布 +菜种 菜種 +菜系 菜系 +菜肴 菜餚 +菜苔 菜薹 +菜虫 菜蟲 +菜青虫 菜青蟲 +菠棱菜 菠棱菜 +菠萝干 菠蘿乾 +菩提流志 菩提流志 +菲佣 菲傭 +菲利克斯 菲利克斯 +菲利克斯.米达麦亚 菲利克斯.米達麥亞 +菲力克斯 菲力克斯 +菲尼克斯 菲尼克斯 +菲德烈克 菲德烈克 +菲才寡学 菲才寡學 +菲舍尔 菲舍爾 +菲茨杰拉德 菲茨傑拉德 +菲衣恶食 菲衣惡食 +萌发 萌發 +萎缩症 萎縮症 +萎雕 萎雕 +萝卜 蘿蔔 +萝卜头 蘿蔔頭 +萝卜干 蘿蔔乾 +萝卜精 蘿蔔精 +萝卜精头上青 蘿蔔精頭上青 +萝卜糕 蘿蔔糕 +萝卜腿 蘿蔔腿 +萤光板 螢光板 +萤火虫 螢火蟲 +萤火虫儿 螢火蟲兒 +营养价值 營養價值 +营养系 營養系 +营干 營幹 +营建厂 營建廠 +营舍 營舍 +营造出 營造出 +营造出来 營造出來 +营造厂 營造廠 +营造厂商 營造廠商 +萦回 縈迴 +萦系 縈繫 +萧万长 蕭萬長 +萧参 蕭蔘 +萧太后 蕭太后 +萧娘 蕭娘 +萧扎某 蕭扎某 +萧玮志 蕭瑋志 +萧行范篆 蕭行范篆 +萨克 薩克 +萨克号 薩克號 +萨克司风 薩克司風 +萨克斯 薩克斯 +萨克斯管 薩克斯管 +萨克斯风 薩克斯風 +萨克森 薩克森 +萨克森州 薩克森州 +萨克森邦 薩克森邦 +萨克洛夫 薩克洛夫 +萨克洛夫奖 薩克洛夫獎 +萨克管 薩克管 +萨克逊 薩克遜 +萨克逊人 薩克遜人 +萨尔布吕肯 薩爾布呂肯 +萨巴托 薩巴托 +萨布里 薩布里 +萨布里多 薩布里多 +萨格勒布 薩格勒布 +萨瓦里 薩瓦里 +萨迪克 薩迪克 +萨里 薩里 +萨里郡 薩里郡 +落个直过儿 落個直過兒 +落了 落了 +落了灶 落了竈 +落于 落於 +落于下风 落於下風 +落价 落價 +落卷 落卷 +落发 落髮 +落发为僧 落髮爲僧 +落台 落臺 +落叶 落葉 +落叶乔木 落葉喬木 +落叶剂 落葉劑 +落叶层 落葉層 +落叶归根 落葉歸根 +落叶归根家 落葉歸根家 +落叶松 落葉松 +落叶林 落葉林 +落叶果树 落葉果樹 +落叶树 落葉樹 +落叶植物 落葉植物 +落叶知秋 落葉知秋 +落后 落後 +落后国家 落後國家 +落在后面 落在後面 +落地签证 落地簽證 +落托 落托 +落月屋梁 落月屋梁 +落腮胡 落腮鬍 +落落寡合 落落寡合 +落落难合 落落難合 +葑菲之采 葑菲之采 +著录 著錄 +著志 著志 +著称于世 著稱於世 +葛兰素史克 葛蘭素史克 +葛布 葛布 +葛托维纳 葛托維納 +葛拉斯里 葛拉斯里 +葛斯范桑 葛斯范桑 +葛罗托斯基 葛羅托斯基 +葛里芬 葛里芬 +葡占 葡佔 +葡萄叶银莲花 葡萄葉銀蓮花 +葡萄干 葡萄乾 +葡萄干儿 葡萄乾兒 +董氏封发 董氏封髮 +董里府 董里府 +葫芦谷 葫蘆谷 +葫芦里卖甚么药 葫蘆裏賣甚麼藥 +葫芦里卖的甚么药 葫蘆裏賣的甚麼藥 +葱姜蒜 蔥薑蒜 +葱胡子 蔥鬍子 +葱葱郁郁 蔥蔥郁郁 +葱郁 蔥鬱 +葵涌 葵涌 +蒂森克虏伯 蒂森克虜伯 +蒋国梁 蔣國樑 +蒋干 蔣幹 +蒋百里 蔣百里 +蒋舍三径 蔣舍三徑 +蒌叶 蔞葉 +蒐录 蒐錄 +蒙一饭之恩尚杀身以报 蒙一飯之恩尚殺身以報 +蒙上 蒙上 +蒙主宠召 蒙主寵召 +蒙事 矇事 +蒙人 蒙人 +蒙代尔 蒙代爾 +蒙住 矇住 +蒙兀儿 蒙兀兒 +蒙兀儿帝国 蒙兀兒帝國 +蒙养 蒙養 +蒙冤 蒙冤 +蒙冲 蒙衝 +蒙受 蒙受 +蒙叟 蒙叟 +蒙古 蒙古 +蒙古人 蒙古人 +蒙古人民共和国 蒙古人民共和國 +蒙古人种 蒙古人種 +蒙古儿 蒙古兒 +蒙古利亚 蒙古利亞 +蒙古包 蒙古包 +蒙古国 蒙古國 +蒙古地方 蒙古地方 +蒙古大夫 蒙古大夫 +蒙古帝国 蒙古帝國 +蒙古文 蒙古文 +蒙古斑 蒙古斑 +蒙古族 蒙古族 +蒙古症 蒙古症 +蒙古话 蒙古話 +蒙古语 蒙古語 +蒙古高原 蒙古高原 +蒙台梭利 蒙臺梭利 +蒙吏 蒙吏 +蒙哄 蒙哄 +蒙哥 蒙哥 +蒙哥马利 蒙哥馬利 +蒙嘉慧 蒙嘉慧 +蒙在 蒙在 +蒙在鼓里 矇在鼓裏 +蒙地卡罗 蒙地卡羅 +蒙坑 蒙坑 +蒙垢 蒙垢 +蒙城 蒙城 +蒙城县 蒙城縣 +蒙塔丝 蒙塔絲 +蒙塔尼斯 蒙塔尼斯 +蒙塔斯 蒙塔斯 +蒙塔达 蒙塔達 +蒙大拿 蒙大拿 +蒙大拿州 蒙大拿州 +蒙太奇 蒙太奇 +蒙太奇电影 蒙太奇電影 +蒙头 矇頭 +蒙头大睡 矇頭大睡 +蒙头衲被 矇頭衲被 +蒙头转 矇頭轉 +蒙头转向 矇頭轉向 +蒙娜丽莎 蒙娜麗莎 +蒙学 蒙學 +蒙尘 蒙塵 +蒙山 蒙山 +蒙山县 蒙山縣 +蒙巴萨 蒙巴薩 +蒙巴顿 蒙巴頓 +蒙师 蒙師 +蒙帕纳斯 蒙帕納斯 +蒙席 蒙席 +蒙庄 蒙莊 +蒙彼利埃 蒙彼利埃 +蒙得维的亚 蒙得維的亞 +蒙恩 蒙恩 +蒙恬 蒙恬 +蒙恬造笔 蒙恬造筆 +蒙懂 懞懂 +蒙戎 蒙戎 +蒙托罗拉 蒙托羅拉 +蒙拾 蒙拾 +蒙故业 蒙故業 +蒙文 蒙文 +蒙族 蒙族 +蒙昧 矇昧 +蒙昧不清 濛昧不清 +蒙昧无知 矇昧無知 +蒙松雨 濛鬆雨 +蒙求 蒙求 +蒙汗药 蒙汗藥 +蒙汜 濛汜 +蒙混 矇混 +蒙混过关 矇混過關 +蒙爱 蒙愛 +蒙牛 蒙牛 +蒙特 蒙特 +蒙特內哥罗 蒙特內哥羅 +蒙特利 蒙特利 +蒙特利尔 蒙特利爾 +蒙特卡洛 蒙特卡洛 +蒙特卡洛法 蒙特卡洛法 +蒙特卡罗 蒙特卡羅 +蒙特卡罗方法 蒙特卡羅方法 +蒙特塞拉特 蒙特塞拉特 +蒙特娄 蒙特婁 +蒙特维多 蒙特維多 +蒙特贝娄 蒙特貝婁 +蒙特雷 蒙特雷 +蒙特鲁 蒙特魯 +蒙狄维欧 蒙狄維歐 +蒙田 蒙田 +蒙皮 蒙皮 +蒙盖 蒙蓋 +蒙直 懞直 +蒙眬 矇矓 +蒙眼 矇眼 +蒙瞍 矇瞍 +蒙稚 蒙稚 +蒙童 蒙童 +蒙笼 蒙籠 +蒙笼暗碧 蒙籠暗碧 +蒙络 蒙絡 +蒙罗维亚 蒙羅維亞 +蒙羞 蒙羞 +蒙聩 矇聵 +蒙胞 蒙胞 +蒙脸 蒙臉 +蒙自 蒙自 +蒙自县 蒙自縣 +蒙茏 蒙蘢 +蒙药 蒙藥 +蒙菲尔斯 蒙菲爾斯 +蒙蒙 濛濛 矇矇 +蒙蒙亮 矇矇亮 +蒙蒙懂懂 懞懞懂懂 +蒙蒙眬眬 矇矇矓矓 +蒙蒙细雨 濛濛細雨 +蒙蒙谷 濛濛谷 +蒙蒙黑 矇矇黑 +蒙蔽 矇蔽 +蒙藏 蒙藏 +蒙藏同胞 蒙藏同胞 +蒙藏委员 蒙藏委員 +蒙藏委员会 蒙藏委員會 +蒙语 蒙語 +蒙谷 蒙谷 +蒙贝列 蒙貝列 +蒙起 蒙起 +蒙起来 蒙起來 +蒙阴 蒙陰 +蒙阴县 蒙陰縣 +蒙难 蒙難 +蒙难记 蒙難記 +蒙雾 濛霧 +蒙雾露 濛霧露 +蒙面 蒙面 +蒙面人 蒙面人 +蒙面侠 蒙面俠 +蒙面客 蒙面客 +蒙馆 蒙館 +蒙骗 矇騙 +蒙鸿 濛鴻 +蒜发 蒜髮 +蒜苔 蒜薹 +蒲团 蒲團 +蒲扇价增 蒲扇價增 +蒲松龄 蒲松齡 +蒸了 蒸了 +蒸便当 蒸便當 +蒸发 蒸發 +蒸发器 蒸發器 +蒸发掉 蒸發掉 +蒸发散 蒸發散 +蒸发热 蒸發熱 +蒸发皿 蒸發皿 +蒸发空调 蒸發空調 +蒸发计 蒸發計 +蒸发量 蒸發量 +蒸干 蒸乾 +蒸汽熨斗 蒸汽熨斗 +蒸沤历澜 蒸漚歷瀾 +蒸藜出妻 蒸藜出妻 +蒸面 蒸麪 +蒸骨验尸 蒸骨驗屍 +蒿里 蒿里 +蓄势待发 蓄勢待發 +蓄发 蓄髮 +蓄志 蓄志 +蓄胡 蓄鬍 +蓄长发 蓄長髮 +蓄须 蓄鬚 +蓄须明志 蓄鬚明志 +蓊郁 蓊鬱 +蓝发 藍髮 +蓝布 藍布 +蓝托斯 藍托斯 +蓝板 藍板 +蓝淀 藍澱 +蓝田出玉 藍田出玉 +蓝田种玉 藍田種玉 +蓝胡子 藍鬍子 +蓝色系 藍色系 +蓝采和 藍采和 +蓟训历家 薊訓歷家 +蓦然回首 驀然回首 +蓬勃发展 蓬勃發展 +蓬发 蓬髮 +蓬头垢面 蓬頭垢面 +蓬松 蓬鬆 +蓬蓬松松 蓬蓬鬆鬆 +蓬门荆布 蓬門荊布 +蓬首垢面 蓬首垢面 +蔑如 蔑如 +蔑弃 蔑棄 +蔑称 蔑稱 +蔑蒙 蔑蒙 +蔑视 蔑視 +蔗板 蔗板 +蔡丰州 蔡豐州 +蔡仰秋 蔡仰秋 +蔡克嵩 蔡克嵩 +蔡同荣 蔡同榮 +蔡志忠 蔡志忠 +蔡志杰 蔡志傑 +蔡文丰 蔡文豐 +蔡松坡 蔡松坡 +蔡清游 蔡清遊 +蔡秋炎 蔡秋炎 +蔡细历 蔡細歷 +蔷薇十字团 薔薇十字團 +蔼彩 藹彩 +蔽形术 蔽形術 +蔽面 蔽面 +蕃薯叶 蕃薯葉 +蕈状云 蕈狀雲 +蕉叶 蕉葉 +蕉布 蕉布 +蕲向 蘄向 +蕴借 蘊藉 +蕴借含蓄 蘊藉含蓄 +蕴奇待价 蘊奇待價 +薄云 薄雲 +薄干 薄幹 +薄幸 薄倖 +薄幸人 薄倖人 +薄恶 薄惡 +薄曲 薄曲 +薄松松 薄鬆鬆 +薄板 薄板 +薄海同仇 薄海同仇 +薄荷叶 薄荷葉 +薄面 薄面 +薄面含嗔 薄面含嗔 +薙发 薙髮 +薙发令 薙髮令 +薛松干 薛松乾 +薝卜 薝蔔 +薪尽火传 薪盡火傳 +薪资表 薪資表 +薰修 薰脩 +薰莸不同器 薰蕕不同器 +薰莸同器 薰蕕同器 +藉资挹注 藉資挹注 +藏于 藏於 +藏匿于 藏匿於 +藏南纵谷 藏南縱谷 +藏历 藏曆 +藏奸 藏奸 +藏尸 藏屍 +藏幸 藏幸 +藏蒙歌儿 藏矇歌兒 +藏量丰富 藏量豐富 +藏针缝 藏針縫 +藕复 藕覆 +藜藿不采 藜藿不採 +藤制 藤製 +藩台 藩臺 +蘑菇云 蘑菇雲 +虎克 虎克 +虎克党 虎克黨 +虎克定律 虎克定律 +虎兕出柙 虎兕出柙 +虎山艺术馆 虎山藝術館 +虎据 虎據 +虎斗 虎鬥 +虎斗龙争 虎鬥龍爭 +虎甲虫 虎甲蟲 +虎皮松 虎皮松 +虎荡羊群 虎蕩羊羣 +虎须 虎鬚 +虏获 虜獲 +虑周行果 慮周行果 +虑无不周 慮無不周 +虚云大师 虛雲大師 +虚冲 虛沖 +虚发 虛發 +虚夸 虛誇 +虚心使人进步骄傲使人落后 虛心使人進步驕傲使人落後 +虚怀若谷 虛懷若谷 +虚拟通道标志符 虛擬通道標誌符 +虚有其表 虛有其表 +虚症 虛症 +虚荡 虛蕩 +虞歌决别 虞歌決別 +虫书 蟲書 +虫体 蟲體 +虫儿 蟲兒 +虫出 蟲出 +虫卵 蟲卵 +虫吃牙 蟲吃牙 +虫声 蟲聲 +虫媒病毒 蟲媒病毒 +虫媒花 蟲媒花 +虫子 蟲子 +虫子牙 蟲子牙 +虫孔 蟲孔 +虫字旁儿 蟲字旁兒 +虫害 蟲害 +虫情 蟲情 +虫沙微类 蟲沙微類 +虫沙猿鹤 蟲沙猿鶴 +虫漆 蟲漆 +虫灾 蟲災 +虫牙 蟲牙 +虫瘿 蟲癭 +虫白蜡 蟲白蠟 +虫眼 蟲眼 +虫篆 蟲篆 +虫篆之技 蟲篆之技 +虫类 蟲類 +虫胶 蟲膠 +虫臂鼠肝 蟲臂鼠肝 +虫虫 蟲蟲 +虫虫蚁蚁 蟲蟲蟻蟻 +虫蚀 蟲蝕 +虫蚁 蟲蟻 +虫蛭 蟲蛭 +虫豸 蟲豸 +虫部 虫部 +虫霜水旱 蟲霜水旱 +虫鱼 蟲魚 +虫鸟叫声 蟲鳥叫聲 +虫鸣 蟲鳴 +虫鸣水沸 蟲鳴水沸 +虬须 虯鬚 +虮蝨相吊 蟣蝨相弔 +虹彩 虹彩 +虹彩流辉 虹彩流輝 +虹彩炎 虹彩炎 +虹彩膜 虹彩膜 +虽复能复 雖覆能復 +虾干 蝦乾 +虾蟆跳在戥盘子里 蝦蟆跳在戥盤子裏 +虾须 蝦鬚 +蚀船虫 蝕船蟲 +蚁合 蟻合 +蚁后 蟻后 +蚁斗蜗争 蟻鬥蝸爭 +蚁术 蟻術 +蚊动牛斗 蚊動牛鬥 +蚊子遭扇打只为嘴伤人 蚊子遭扇打只爲嘴傷人 +蚊睫之虫 蚊睫之蟲 +蚊虫 蚊蟲 +蚊虫叮咬 蚊蟲叮咬 +蚕种 蠶種 +蚕豆症 蠶豆症 +蚜虫 蚜蟲 +蚵仔面线 蚵仔麪線 +蛀虫 蛀蟲 +蛆虫 蛆蟲 +蛇发女妖 蛇髮女妖 +蛇口蜂针 蛇口蜂針 +蛇皮松 蛇皮松 +蛇纹岩 蛇紋岩 +蛇绿岩 蛇綠岩 +蛇绿混杂岩 蛇綠混雜岩 +蛇绿混杂岩带 蛇綠混雜岩帶 +蛋卷 蛋卷 +蛋彩画 蛋彩畫 +蛋杯 蛋杯 +蛏干 蟶乾 +蛓毛虫 蛓毛蟲 +蛔虫 蛔蟲 +蛔虫病 蛔蟲病 +蛔虫症 蛔蟲症 +蛔虫药 蛔蟲藥 +蛙鼓虫吟 蛙鼓蟲吟 +蛟龙得云雨 蛟龍得雲雨 +蛮干 蠻幹 +蛮干到底 蠻幹到底 +蛮干淨 蠻乾淨 +蛮干爽 蠻乾爽 +蛮针瞎灸 蠻針瞎灸 +蛰虫 蟄蟲 +蛲虫 蟯蟲 +蛲虫病 蟯蟲病 +蜀党 蜀黨 +蜂准 蜂準 +蜂出 蜂出 +蜂午并起 蜂午並起 +蜂后 蜂后 +蜂巢式行动电话系统 蜂巢式行動電話系統 +蜂涌而出 蜂湧而出 +蜂蒙 蜂蒙 +蜂蜡 蜂蠟 +蜗杆 蝸桿 +蜗舍 蝸舍 +蜜蜡 蜜蠟 +蜜里调油 蜜裏調油 +蜡丸 蠟丸 +蜡书 蠟書 +蜡人 蠟人 +蜡人馆 蠟人館 +蜡像 蠟像 +蜡像馆 蠟像館 +蜡光纸 蠟光紙 +蜡原型 蠟原型 +蜡台 蠟臺 +蜡嘴 蠟嘴 +蜡坨儿 蠟坨兒 +蜡坨子 蠟坨子 +蜡头儿 蠟頭兒 +蜡封 蠟封 +蜡屐 蠟屐 +蜡布 蠟布 +蜡弹 蠟彈 +蜡扦 蠟扦 +蜡月 蜡月 +蜡本 蠟本 +蜡板 蠟板 +蜡果 蠟果 +蜡枪头 蠟槍頭 +蜡染 蠟染 +蜡査 蠟查 +蜡梅 蠟梅 +蜡油 蠟油 +蜡泪 蠟淚 +蜡渣 蠟渣 +蜡灯 蠟燈 +蜡炬 蠟炬 +蜡烛 蠟燭 +蜡烛不点不亮 蠟燭不點不亮 +蜡烛台 蠟燭臺 +蜡烛油 蠟燭油 +蜡烛相 蠟燭相 +蜡烛线 蠟燭線 +蜡版 蠟版 +蜡珀 蠟珀 +蜡画 蠟畫 +蜡疗 蠟療 +蜡皮 蠟皮 +蜡祭 蜡祭 +蜡笔 蠟筆 +蜡笔小新 蠟筆小新 +蜡笔画 蠟筆畫 +蜡笺 蠟箋 +蜡纸 蠟紙 +蜡膏 蠟膏 +蜡膜 蠟膜 +蜡芯儿 蠟芯兒 +蜡花 蠟花 +蜡茶 蠟茶 +蜡虫 蠟蟲 +蜡蜂 蠟蜂 +蜡诏 蠟詔 +蜡质 蠟質 +蜡铺 蠟鋪 +蜡黄 蠟黃 +蜡黄色 蠟黃色 +蜰虫 蜰蟲 +蜷曲 蜷曲 +蝎谮 蠍譖 +蝗虫 蝗蟲 +蝗虫过境 蝗蟲過境 +蝨多了不咬债多了不愁 蝨多了不咬債多了不愁 +蝴蝶谷 蝴蝶谷 +蝼蚁得志 螻蟻得志 +融合 融合 +融合为 融合爲 +融合为一 融合爲一 +融合式 融合式 +融合式翼梢小翼 融合式翼梢小翼 +融合线 融合線 +融汇 融匯 +螟虫 螟蟲 +螫针 螫針 +螳臂当车 螳臂當車 +螳螂捕蝉黄雀在后 螳螂捕蟬黃雀在後 +螹胡 螹胡 +螺旋千斤顶 螺旋千斤頂 +螺旋曲面 螺旋曲面 +螺旋杆菌 螺旋桿菌 +螺旋面 螺旋麪 +螺杆 螺桿 +螽斯之征 螽斯之徵 +螾庐曲谈 螾廬曲談 +蟠尾丝虫 蟠尾絲蟲 +蟠尾丝虫症 蟠尾絲蟲症 +蟠据 蟠據 +蟠曲 蟠曲 +蟠桃胜会 蟠桃勝會 +蟠采 蟠采 +蟠龙松 蟠龍松 +蟪蛄不知春秋 蟪蛄不知春秋 +蟭蟟虫 蟭蟟蟲 +蟹黄鲍鱼面 蟹黃鮑魚麪 +蟻后 蟻后 +蟾宫折桂 蟾宮折桂 +蟾彩 蟾彩 +蠁干 蠁幹 +蠓虫 蠓蟲 +蠔涌 蠔涌 +蠕虫 蠕蟲 +蠕虫形 蠕蟲形 +蠢虫 蠢蟲 +蠢蠢欲动 蠢蠢欲動 +蠹书虫 蠹書蟲 +蠹众木折 蠹衆木折 +蠹众而木折隙大而墙坏 蠹衆而木折隙大而牆壞 +蠹啄剖梁柱 蠹啄剖梁柱 +蠹虫 蠹蟲 +血亲复仇 血親復仇 +血仇 血仇 +血余 血餘 +血克帮帮 血克幫幫 +血制品 血製品 +血参 血蔘 +血吸虫 血吸蟲 +血吸虫病 血吸蟲病 +血小板 血小板 +血已干 血已乾 +血才干 血纔乾 +血栓症 血栓症 +血汗工厂 血汗工廠 +血洗台湾 血洗臺灣 +血流如注 血流如注 +血浓于水 血濃於水 +血海尸山 血海屍山 +血海深仇 血海深仇 +血液恐怖症 血液恐怖症 +血症 血癥 +血线虫 血線蟲 +血缘关系 血緣關係 +血肉淋漓 血肉淋漓 +血胄 血胄 +血胡同 血衚衕 +血脂升高症 血脂升高症 +血色素沉积症 血色素沉積症 +衅发萧墙 釁發蕭牆 +衅恶 釁惡 +衅钟 釁鐘 +衅面 釁面 +行万里路 行萬里路 +行万里路胜读万卷书 行萬裏路勝讀萬捲書 +行万里路读万卷书 行萬里路讀萬卷書 +行不苟合 行不苟合 +行业别 行業別 +行业规范 行業規範 +行个方便 行個方便 +行为世范 行爲世範 +行为准则 行爲準則 +行为艺术 行爲藝術 +行为艺术者 行爲藝術者 +行为规范 行爲規範 +行了 行了 +行事历 行事曆 +行事历史 行事歷史 +行于 行於 +行云 行雲 +行云流水 行雲流水 +行伍出身 行伍出身 +行佣 行佣 +行修寺 行修寺 +行兵布阵 行兵佈陣 +行凶 行兇 +行凶前 行兇前 +行凶后 行兇後 +行凶後 行兇後 +行凶杀人 行兇殺人 +行凶者 行兇者 +行动党 行動黨 +行动计划 行動計劃 +行千里路读万卷书 行千裏路讀萬卷書 +行卷 行卷 +行台 行臺 +行合趋同 行合趨同 +行同 行同 +行同狗彘 行同狗彘 +行同狗豨 行同狗豨 +行善不欲人知 行善不欲人知 +行复 行復 +行奸卖俏 行奸賣俏 +行尸 行屍 +行尸视肉 行屍視肉 +行尸走肉 行屍走肉 +行尸走骨 行屍走骨 +行幸 行幸 +行当 行當 +行志 行志 +行情价 行情價 +行情表 行情表 +行成于思 行成於思 +行政区划 行政區劃 +行政区划图 行政區劃圖 +行政当局 行政當局 +行政系 行政系 +行政诉愿 行政訴願 +行有余力 行有餘力 +行李卷 行李捲 +行板 行板 +行游 行遊 +行百里 行百里 +行百里者半于九十 行百里者半於九十 +行短才乔 行短才喬 +行短才高 行短才高 +行程表 行程表 +行药 行藥 +行行出状元 行行出狀元 +行针 行鍼 +行针布线 行鍼佈線 +行针走线 行鍼走線 +行雨朝云 行雨朝雲 +衍声复词 衍聲複詞 +衍极 衍極 +衍生出 衍生出 +衍生出来 衍生出來 +衔哀致诚 銜哀致誠 +衔恨蒙枉 銜恨蒙枉 +衔缺相当 銜缺相當 +街坊邻舍 街坊鄰舍 +街坊邻里 街坊鄰里 +街里街坊 街里街坊 +街面儿 街面兒 +衡量制 衡量制 +衣不兼采 衣不兼采 +衣不完采 衣不完采 +衣不布体 衣不布體 +衣不重采 衣不重采 +衣丰食足 衣豐食足 +衣丰食饱 衣豐食飽 +衣冠云集 衣冠雲集 +衣扣 衣釦 +衣摆 衣襬 +衣斗木 衣斗木 +衣柜 衣櫃 +衣物已干 衣物已乾 +衣物柜 衣物櫃 +衣物渐干 衣物漸乾 +衣绣昼行 衣繡晝行 +衣衫已干 衣衫已乾 +衣锦夜游 衣錦夜游 +衣锦昼游 衣錦晝游 +补于 補於 +补修 補修 +补发 補發 +补回 補回 +补回来 補回來 +补扣 補釦 +补挂朝珠 補掛朝珠 +补气固表 補氣固表 +补注 補註 +补票价 補票價 +补种 補種 +补药 補藥 +补血药 補血藥 +补血针 補血針 +补针 補針 +表亲 表親 +表仪 表儀 +表件 表件 +表侄 表侄 +表停 錶停 +表兄 表兄 +表兄弟 表兄弟 +表冊 表冊 +表册 表冊 +表冠 錶冠 +表决 表決 +表决权 表決權 +表出 表出 +表出来 表出來 +表列 表列 +表列出 表列出 +表功 表功 +表单 表單 +表厂 錶廠 +表叔 表叔 +表同情 表同情 +表哥 表哥 +表唱 表唱 +表土 表土 +表土层 表土層 +表壮不如里壮 表壯不如裏壯 +表壳 錶殼 +表壳儿 錶殼兒 +表头 表頭 +表奏 表奏 +表妹 表妹 +表姊 表姊 +表姊妹 表姊妹 +表姊家 表姊家 +表姐 表姐 +表姐妹 表姐妹 +表姑 表姑 +表姨 表姨 +表姨父 表姨父 +表姪 表姪 +表婶 表嬸 +表嫂 表嫂 +表子 表子 +表字 表字 +表尺 表尺 +表层 表層 +表层水 表層水 +表带 錶帶 +表店 錶店 +表弟 表弟 +表形文字 表形文字 +表彰 表彰 +表彰出来 表彰出來 +表征 表徵 +表德 表德 +表快 錶快 +表态 表態 +表态句 表態句 +表情 表情 +表意 表意 +表意文字 表意文字 +表意符阶段 表意符階段 +表慢 錶慢 +表扬 表揚 +表扬大会 表揚大會 +表报 表報 +表揭 表揭 +表文 表文 +表明 表明 +表明心迹 表明心跡 +表显 表顯 +表本 表本 +表板 錶板 +表格 表格 +表格化公文 表格化公文 +表款 錶款 +表沃夫 表沃夫 +表海 表海 +表演 表演 +表演会 表演會 +表演区 表演區 +表演厅 表演廳 +表演性 表演性 +表演欲 表演慾 +表演秀 表演秀 +表演给 表演給 +表演艺术 表演藝術 +表演赛 表演賽 +表演过火 表演過火 +表照 表照 +表率 表率 +表王 錶王 +表现 表現 +表现为 表現爲 +表现为费 表現爲費 +表现主义 表現主義 +表现出 表現出 +表现出来 表現出來 +表现力 表現力 +表现型 表現型 +表现对象 表現對象 +表现形 表現形 +表现自己 表現自己 +表甥 表甥 +表白 表白 +表的历史 錶的歷史 +表的嘀嗒 錶的嘀嗒 +表皮 表皮 +表皮剥脱素 表皮剝脫素 +表皮层 表皮層 +表盘 錶盤 +表相 表相 +表示 表示 +表示出 表示出 +表示出来 表示出來 +表示层 表示層 +表示敬意 表示敬意 +表礼 表禮 +表章 表章 +表笔 表筆 +表笺 表箋 +表背 表背 +表舅 表舅 +表舅母 表舅母 +表荐 表薦 +表蒙子 錶蒙子 +表行 錶行 +表表 表表 +表襮 表襮 +表观 表觀 +表记 表記 +表记物件 表記物件 +表证 表證 +表识 表識 +表词 表詞 +表语 表語 +表象 表象 +表转 錶轉 +表达 表達 +表达出 表達出 +表达出来 表達出來 +表达力 表達力 +表达失语症 表達失語症 +表达式 表達式 +表达能力 表達能力 +表述 表述 +表速 錶速 +表里 表裏 +表里一致 表裏一致 +表里不一 表裏不一 +表里受敌 表裏受敵 +表里如一 表裏如一 +表里山河 表裏山河 +表里相合 表裏相合 +表里相应 表裏相應 +表里相济 表裏相濟 +表针 錶針 +表链 錶鏈 +表错 表錯 +表错情 表錯情 +表门 表門 +表露 表露 +表露出 表露出 +表露无遗 表露無遺 +表面 表面 +表面上 表面上 +表面信息 表面信息 +表面光洁 表面光潔 +表面化 表面化 +表面外膜 表面外膜 +表面工夫 表面工夫 +表面张力 表面張力 +表面性 表面性 +表面活化剂 表面活化劑 +表面活性剂 表面活性劑 +表面流 表面流 +表面的 表面的 +表面积 表面積 +表面质量 表面質量 +表音 表音 +表音文字 表音文字 +表题 表題 +表饰 表飾 +衬出 襯出 +衬布 襯布 +衬托 襯托 +衬托出 襯托出 +衬托底 襯托底 +衬托物 襯托物 +衬里 襯裏 +衰变曲线 衰變曲線 +衰变链 衰變鏈 +衲被蒙头 衲被蒙頭 +衷于 衷於 +衷曲 衷曲 +衿曲 衿曲 +袁于令 袁于令 +袁友范 袁友范 +袁承志 袁承志 +袁术 袁術 +袅娜 嫋娜 +袅娜纤巧 嫋娜纖巧 +袅娜风流 嫋娜風流 +袅窕 裊窕 +袅绕 裊繞 +袅袅 嫋嫋 +袅袅上升 裊裊上升 +袅袅娉娉 嫋嫋娉娉 +袅袅娜娜 嫋嫋娜娜 +袅袅婷婷 嫋嫋婷婷 +袅袅炊烟 裊裊炊煙 +袋表 袋錶 +袋里 袋裏 +袒露出 袒露出 +袖一卷 袖一捲 +袖扣 袖釦 +袖里 袖裏 +袖里乾坤 袖裏乾坤 +袖里来袖里去 袖裏來袖裏去 +被人背 被人揹 +被动吸烟 被動吸菸 +被动挨打 被動挨打 +被发 被髮 +被发佯狂 被髮佯狂 +被发入山 被髮入山 +被发左衽 被髮左衽 +被发文身 被髮文身 +被发现 被發現 +被发缨冠 被髮纓冠 +被发觉 被發覺 +被发阳狂 被髮陽狂 +被复 被複 +被头散发 被頭散髮 +被害妄想症 被害妄想症 +被干 被幹 +被扣 被扣 +被拐 被拐 +被服厂 被服廠 +被泽蒙庥 被澤蒙庥 +被灾蒙祸 被災蒙禍 +被窝里 被窩裏 +被窝里放屁 被窩裏放屁 +被里 被裏 +被面 被面 +袭击战术 襲擊戰術 +袭卷 襲捲 +裁划 裁劃 +裁制 裁製 +裁并 裁併 +裁样板 裁樣板 +裁衣合帐 裁衣合帳 +裂了 裂了 +裂体吸虫 裂體吸蟲 +裂变同位素 裂變同位素 +裂致 裂致 +裂解厂 裂解廠 +裂谷 裂谷 +裂谷热 裂谷熱 +裂谷热病毒 裂谷熱病毒 +装修 裝修 +装修门面 裝修門面 +装出 裝出 +装出去 裝出去 +装出来 裝出來 +装回 裝回 +装岩机 裝岩機 +装折 裝摺 +装点门面 裝點門面 +装糊涂 裝糊塗 +装订厂 裝訂廠 +装配厂 裝配廠 +装配工厂 裝配工廠 +装门面 裝門面 +裒克 裒剋 +裔胄 裔胄 +裕丰 裕豐 +裘弊金尽 裘弊金盡 +裘馨氏肌肉萎缩症 裘馨氏肌肉萎縮症 +裙布荆钗 裙布荊釵 +裙带关系 裙帶關係 +裙摆 裙襬 +裤扣 褲釦 +裴回 裴回 +裴松之 裴松之 +裴航遇云英 裴航遇雲英 +裴里诺 裴里諾 +裸体女尸 裸體女屍 +裸叶 裸葉 +裸尸 裸屍 +裸岩 裸岩 +裸露出 裸露出 +裹了 裹了 +裹尸 裹屍 +裹尸布 裹屍布 +裹尸马革 裹屍馬革 +裹布 裹布 +裹扎 裹紮 +裹脚布 裹腳布 +褐布 褐布 +褒善贬恶 褒善貶惡 +褒录 褒錄 +褒贤遏恶 褒賢遏惡 +褒赞 褒讚 +褒采一介 褒采一介 +褚人获 褚人獲 +褪前擦后 褪前擦後 +褶子了 褶子了 +褶曲 褶曲 +褶曲山脉 褶曲山脈 +褶皱山系 褶皺山系 +褶皱山系火地岛 褶皺山系火地島 +襄赞 襄贊 +襟曲 襟曲 +西丰 西豐 +西丰县 西豐縣 +西冲 西衝 +西出 西出 +西利古里 西利古里 +西北向 西北向 +西北师范大学 西北師範大學 +西北面 西北面 +西华师范大学 西華師範大學 +西南向 西南向 +西南师范大学 西南師範大學 +西南面 西南面 +西占 西佔 +西厂 西廠 +西历 西曆 +西历纪元 西曆紀元 +西原借款 西原借款 +西发里亚条约 西發里亞條約 +西台 西臺 +西台人 西臺人 +西台古堡 西臺古堡 +西台帝国 西臺帝國 +西后 西后 +西向 西向 +西周 西周 +西周时 西周時 +西周时代 西周時代 +西周时期 西周時期 +西周钟 西周鐘 +西哈努克 西哈努克 +西太后 西太后 +西尼克学派 西尼克學派 +西岳 西嶽 +西征 西征 +西文系 西文系 +西斗铺 西斗鋪 +西方极乐 西方極樂 +西方极乐世界 西方極樂世界 +西晒 西曬 +西曲 西曲 +西来庵 西來庵 +西松 西松 +西松建设 西松建設 +西极 西極 +西格蒙德 西格蒙德 +西欧集团 西歐集團 +西洋参 西洋參 +西涌 西涌 +西游 西遊 +西游补 西遊補 +西游记 西遊記 +西点面包 西點麪包 +西王母娘娘 西王母娘娘 +西米谷 西米谷 +西药 西藥 +西药房 西藥房 +西蒙 西蒙 +西蒙斯 西蒙斯 +西蒙逊 西蒙遜 +西藏百万农奴解放纪念日 西藏百萬農奴解放紀念日 +西西里 西西里 +西西里岛 西西里島 +西谷椰子 西谷椰子 +西谷米 西谷米 +西谷米冻 西谷米凍 +西里 西里 +西里尔 西里爾 +西里尔字母 西裏爾字母 +西里西亚 西里西亞 +西门子电机厂 西門子電機廠 +西除东荡 西除東蕩 +西面 西面 +要么 要麼 +要了 要了 +要价 要價 +要价还价 要價還價 +要克制 要剋制 +要冲 要衝 +要千取万 要千取萬 +要占 要佔 +要占卜 要占卜 +要回 要回 +要干了 要乾了 +要念 要念 +要怎么收获先怎么栽 要怎麼收穫先怎麼栽 +要扣 要扣 +要拐 要拐 +要自制 要自制 +要面子 要面子 +覃天同 覃天同 +覆巢之下无完卵 覆巢之下無完卵 +覆水难收 覆水難收 +覆没 覆沒 +覆盖 覆蓋 +覆盖范围 覆蓋範圍 +覆盖面 覆蓋面 +覆辙 覆轍 +覆雨翻云 覆雨翻雲 +視如寇仇 視如寇讎 +见不到面 見不到面 +见世面 見世面 +见个 見個 +见个情 見個情 +见之不取思之千里 見之不取思之千里 +见了 見了 +见了和尚骂贼秃 見了和尚罵賊禿 +见了新人忘旧人 見了新人忘舊人 +见了面 見了面 +见于 見於 +见几 見幾 +见几而作 見幾而作 +见到面 見到面 +见危致命 見危致命 +见复 見覆 +见尧于墙 見堯於牆 +见得多了 見得多了 +见棱见角 見棱見角 +见物不取失之千里 見物不取失之千里 +见笑于人 見笑於人 +见素抱朴 見素抱樸 +见缝插针 見縫插針 +见见面 見見面 +见过世面 見過世面 +见鉴 見鑒 +见钟不打 見鐘不打 +见钟不打更去炼铜 見鐘不打更去煉銅 +见面 見面 +见面三分情 見面三分情 +见面会 見面會 +见面礼 見面禮 +见马克思 見馬克思 +观众台 觀衆臺 +观光台 觀光臺 +观光周 觀光週 +观光团 觀光團 +观光游憩性资源 觀光遊憩性資源 +观光签证 觀光簽證 +观光胜地 觀光勝地 +观台 觀臺 +观叶植物 觀葉植物 +观后感 觀後感 +观审制度 觀審制度 +观察出来 觀察出來 +观察团 觀察團 +观念 觀念 +观护制度 觀護制度 +观星台 觀星臺 +观景台 觀景臺 +观望台 觀望臺 +观测台 觀測臺 +观礼台 觀禮臺 +观者云集 觀者雲集 +观者如云 觀者如雲 +观象台 觀象臺 +观采 觀採 +观音庵 觀音庵 +规划 規劃 +规划为 規劃爲 +规划人员 規劃人員 +规划出 規劃出 +规划好 規劃好 +规划局 規劃局 +规划成 規劃成 +规划案 規劃案 +规划范围 規劃範圍 +规制 規制 +规复 規復 +规定价格 規定價格 +规定出来 規定出來 +规定地价 規定地價 +规定范围 規定範圍 +规画出 規畫出 +规矩准绳 規矩準繩 +规章制度 規章制度 +规范 規範 +规范企业 規範企業 +规范作用 規範作用 +规范动作 規範動作 +规范化 規範化 +规范化管理 規範化管理 +规范司 規範司 +规范名 規範名 +规范字 規範字 +规范学 規範學 +规范市场 規範市場 +规范性 規範性 +规范性文件 規範性文件 +规范意见 規範意見 +规范执法 規範執法 +规范技术 規範技術 +规范文件 規範文件 +规范理论 規範理論 +规范的 規範的 +规范管理 規範管理 +规范行为 規範行爲 +规范语言 規範語言 +视于 視於 +视力表 視力表 +视同 視同 +视同儿戏 視同兒戲 +视同具文 視同具文 +视同手足 視同手足 +视同秦越 視同秦越 +视同陌路 視同陌路 +视如寇仇 視如寇仇 +视如己出 視如己出 +视杯 視杯 +视空间系统 視空間系統 +视窗基准 視窗基準 +视觉系 視覺系 +视觉艺术 視覺藝術 +视觉适应 視覺適應 +视讯会议系统 視訊會議系統 +视讯系统 視訊系統 +视野范围 視野範圍 +览胜 覽勝 +觉出 覺出 +觉发 覺發 +觉察出 覺察出 +觊幸 覬倖 +觊觎之志 覬覦之志 +觌面 覿面 +觑个意顺 覷個意順 +觑当 覷當 +角化症 角化症 +角斗 角鬥 +角斗场 角鬥場 +角斗士 角鬥士 +角曲尺 角曲尺 +角砾岩 角礫岩 +角膜移植术 角膜移植術 +角色冲突 角色衝突 +角色扮演游戏 角色扮演遊戲 +角落发 角落發 +角落里 角落裏 +角谷猜想 角谷猜想 +角里 角里 +角页岩 角頁岩 +觔斗 觔斗 +觔斗云 觔斗雲 +解了 解了 +解决不了 解決不了 +解决困难 解決困難 +解出 解出 +解出来 解出來 +解到县里 解到縣裏 +解制 解制 +解剑拜仇 解劍拜仇 +解发 解發 +解发佯狂 解髮佯狂 +解困 解困 +解当 解當 +解当铺 解當鋪 +解扣 解釦 +解放出来 解放出來 +解放后 解放後 +解救出来 解救出來 +解析几何 解析幾何 +解析几何学 解析幾何學 +解毒药 解毒藥 +解理方向 解理方向 +解理面 解理面 +解痛药 解痛藥 +解药 解藥 +解酸药 解酸藥 +解铃仍须系铃人 解鈴仍須繫鈴人 +解铃系铃 解鈴繫鈴 +解铃还是系铃人 解鈴還是繫鈴人 +解铃还须系铃人 解鈴還須繫鈴人 +解雇 解僱 +触事面墙 觸事面牆 +触发 觸發 +触发器 觸發器 +触发式 觸發式 +触发引信 觸發引信 +触发清单 觸發清單 +触技曲 觸技曲 +触控板 觸控板 +触斗蛮争 觸鬥蠻爭 +触板 觸板 +触须 觸鬚 +觱发 觱發 +言不尽意 言不盡意 +言且表过 言且表過 +言之不尽 言之不盡 +言之有据 言之有據 +言云 言云 +言出如山 言出如山 +言出必行 言出必行 +言出患入 言出患入 +言出法随 言出法隨 +言大而夸 言大而夸 +言尽于此 言盡於此 +言归于好 言歸於好 +言必有据 言必有據 +言文一致 言文一致 +言无不尽 言無不盡 +言无二价 言無二價 +言行一致 言行一致 +言行合一 言行合一 +言行录 言行錄 +言语失常症 言語失常症 +言辩而确 言辯而确 +言隐于荣华 言隱於榮華 +証据 証據 +詩云 詩云 +詹千慧 詹千慧 +詹姆士布朗 詹姆士布朗 +詹姆斯布朗 詹姆斯布朗 +詹宏志 詹宏志 +詹志宏 詹志宏 +詹志维 詹誌維 +詹氏年鉴 詹氏年鑑 +詹江布尔 詹江布爾 +誊写板 謄寫板 +誊出 謄出 +誊出来 謄出來 +誊录 謄錄 +誊录所 謄錄所 +誓同生死 誓同生死 +誓愿 誓願 +誓无二志 誓無二志 +謷丑 謷醜 +謻台 謻臺 +譆譆出出 譆譆出出 +警世钟 警世鐘 +警察制度 警察制度 +警察广播电台 警察廣播電臺 +警报系统 警報系統 +警报钟 警報鐘 +警民冲突 警民衝突 +警示钟 警示鐘 +警辟 警闢 +警钟 警鐘 +譬似闲 譬似閒 +譬如闲 譬如閒 +计价 計價 +计价器 計價器 +计出万全 計出萬全 +计分板 計分板 +计划 計劃 +计划书 計劃書 +计划图 計劃圖 +计划好 計劃好 +计划性 計劃性 +计划案 計劃案 +计划生育 計劃生育 +计划目标 計劃目標 +计划经济 計劃經濟 +计划署 計劃署 +计划者 計劃者 +计将安出 計將安出 +计尽力穷 計盡力窮 +计无所出 計無所出 +计时表 計時錶 +计白当黑 計白當黑 +计程车共乘制 計程車共乘制 +计穷力尽 計窮力盡 +计穷力极 計窮力極 +计穷虑极 計窮慮極 +计算 計算 +计算出 計算出 +计算出来 計算出來 +计算机制图 計算機製圖 +计算机集成制造 計算機集成製造 +计量制 計量制 +订个 訂個 +订了 訂了 +订于 訂於 +订价 訂價 +订出 訂出 +订出来 訂出來 +订制 訂製 +订制服 訂製服 +订杂志 訂雜誌 +认不出 認不出 +认不出来 認不出來 +认个 認個 +认了 認了 +认准 認準 +认出 認出 +认出来 認出來 +认制修 認製修 +认同 認同 +认同卡 認同卡 +认同度 認同度 +认同感 認同感 +认尸 認屍 +认得出 認得出 +认知神经心里学 認知神經心裏學 +讦发 訐發 +讨个 討個 +讨个分晓 討個分曉 +讨个吉利 討個吉利 +讨了 討了 +讨价 討價 +讨价还价 討價還價 +讨出 討出 +讨出来 討出來 +讨回 討回 +讨彩 討彩 +讨恶剪暴 討惡剪暴 +讨没脸面 討沒臉面 +讨针线 討針線 +讨面皮 討面皮 +让价 讓價 +让位于 讓位於 +让出 讓出 +让出去 讓出去 +让出来 讓出來 +让胡路 讓胡路 +让胡路区 讓胡路區 +讫了 訖了 +讬了 託了 +训兽术 訓獸術 +训练出 訓練出 +训练出来 訓練出來 +训胄 訓胄 +训蒙 訓蒙 +议事录 議事錄 +议事纪录 議事紀錄 +议价 議價 +议价空间 議價空間 +议会制 議會制 +议会斗争 議會鬥爭 +议和团 議和團 +议坛 議壇 +讯息处理系统 訊息處理系統 +讯框传送论坛 訊框傳送論壇 +记不了 記不了 +记了 記了 +记事板 記事板 +记仇 記仇 +记分板 記分板 +记录 記錄 +记录下 記錄下 +记录下来 記錄下來 +记录为 記錄爲 +记录仪 記錄儀 +记录到 記錄到 +记录员 記錄員 +记录器 記錄器 +记录本 記錄本 +记录板 記錄板 +记录片 記錄片 +记录簿 記錄簿 +记念 記念 +记挂 記掛 +记者团 記者團 +讲个 講個 +讲了 講了 +讲价 講價 +讲信修睦 講信修睦 +讲出 講出 +讲出去 講出去 +讲出来 講出來 +讲台 講臺 +讲坛 講壇 +讲情面 講情面 +讲闲话 講閒話 +讲面子 講面子 +讳恶不悛 諱惡不悛 +许下愿心 許下願心 +许久以后 許久以後 +许人丰 許人丰 +许凯克 許凱克 +许历农 許歷農 +许圣杰 許聖杰 +许建发 許建發 +许志华 許志華 +许志彰 許志彰 +许志煌 許志煌 +许志雄 許志雄 +许志鸿 許志鴻 +许愿 許願 +许愿树 許願樹 +许愿池 許願池 +许愿牌 許願牌 +许愿起经 許愿起經 +许振发 許振發 +许智杰 許智傑 +许杰 許傑 +许杰辉 許傑輝 +许胜发 許勝發 +许胜雄 許勝雄 +许至胜 許至勝 +许致强 許致強 +许豪升 許豪升 +许铭杰 許銘傑 +论价 論價 +论千论万 論千論萬 +论坛 論壇 +论坛区 論壇區 +论坛报 論壇報 +论据 論據 +论据不足 論據不足 +论赞 論贊 +设了 設了 +设于 設於 +设党 設黨 +设厂 設廠 +设台 設臺 +设坛 設壇 +设坛祭拜 設壇祭拜 +设朝升殿 設朝升殿 +设柜 設櫃 +设言托意 設言托意 +设计出 設計出 +设计出来 設計出來 +设计系 設計系 +设计规范 設計規範 +设限于 設限於 +设鼓悬钟 設鼓懸鐘 +访华团 訪華團 +访台 訪臺 +访台之旅 訪臺之旅 +访察团 訪察團 +访日团 訪日團 +访问团 訪問團 +访韩团 訪韓團 +诀别 訣別 +诀别书 訣別書 +证于 證於 +证出 證出 +证出来 證出來 +证卷 證卷 +证卷交易所 證卷交易所 +证据 證據 +证据力 證據力 +证据裁判主义 證據裁判主義 +证明了 證明了 +证明出来 證明出來 +评个 評個 +评个分数 評個分數 +评了 評了 +评价 評價 +评价分类 評價分類 +评估板 評估板 +评出 評出 +评出来 評出來 +评分标准 評分標準 +评判出 評判出 +评卷 評卷 +评审团 評審團 +评审团特别奖 評審團特別獎 +评核 評覈 +评注 評註 +评选出 評選出 +评鉴 評鑑 +评鉴为 評鑑爲 +评鉴报告 評鑑報告 +识别 識別 +识别信号 識別信號 +识别力 識別力 +识别区 識別區 +识别号 識別號 +识别字 識別字 +识别码 識別碼 +识别証 識別証 +识别证 識別證 +识多才广 識多才廣 +识微见几 識微見幾 +识才 識才 +识才尊贤 識才尊賢 +识时务者为俊杰 識時務者爲俊傑 +识面 識面 +识面台官 識面臺官 +诈哄 詐哄 +诈奸不及 詐奸不及 +诈尸 詐屍 +诈术 詐術 +诈胡 詐胡 +诉愿 訴願 +诉愿权 訴願權 +诉愿状 訴願狀 +诉说出来 訴說出來 +诉诸于 訴諸於 +诊断出 診斷出 +诊断出来 診斷出來 +诋毁 詆譭 +词余 詞餘 +词干 詞幹 +词干启动 詞幹啓動 +词无枝叶 詞無枝葉 +词曲 詞曲 +词汇 詞彙 +词汇分解 詞彙分解 +词汇判断 詞彙判斷 +词汇判断任务 詞彙判斷任務 +词汇判断作业 詞彙判斷作業 +词汇判断法 詞彙判斷法 +词汇学 詞彙學 +词汇通路 詞彙通路 +词穷理尽 詞窮理盡 +词表 詞表 +词语汇 詞語彙 +词采 詞采 +诏板 詔板 +译制 譯製 +译注 譯註 +诓哄 誆哄 +诔赞 誄讚 +试出 試出 +试出来 試出來 +试制 試製 +试卷 試卷 +试周 試周 +试炼 試煉 +试种 試種 +试算表 試算表 +试胄 試胄 +试药 試藥 +试表 試表 +试验台 試驗檯 +诗云 詩云 +诗云子曰 詩云子曰 +诗以言志 詩以言志 +诗余 詩餘 +诗卷 詩卷 +诗坛 詩壇 +诗才 詩才 +诗言志歌永言 詩言志歌永言 +诗词曲语辞汇释 詩詞曲語辭匯釋 +诗赞 詩讚 +诗钟 詩鐘 +诘曲 詰曲 +诙谐曲 詼諧曲 +诚征 誠徵 +诚朴 誠樸 +诛凶殄逆 誅兇殄逆 +诛凶讨逆 誅兇討逆 +诛尽杀绝 誅盡殺絕 +诛戮殆尽 誅戮殆盡 +话别 話別 +话剧表演 話劇表演 +话又说回来 話又說回來 +话念 話念 +话说回来 話說回來 +话里套话 話裏套話 +话里有话 話裏有話 +话里藏阄 話裏藏鬮 +诠注 詮註 +诠释出 詮釋出 +诡计百出 詭計百出 +诡辩术 詭辯術 +询于 詢於 +询于刍荛 詢於芻蕘 +询价 詢價 +该于 該於 +该党 該黨 +该厂 該廠 +该向 該向 +该回 該回 +该当 該當 +该当何罪 該當何罪 +该扣 該扣 +该钟 該鐘 +该面 該面 +详尽 詳盡 +详尽无遗 詳盡無遺 +详征博引 詳徵博引 +详注 詳註 +详确 詳確 +诬蔑 誣衊 +诬蔑性 誣衊性 +语云 語云 +语出 語出 +语录 語錄 +语意区分量表 語意區分量表 +语意差别量表 語意差別量表 +语有云 語有云 +语汇 語彙 +语法术语 語法術語 +语系 語系 +语言规范 語言規範 +语音合成 語音合成 +语音失语症 語音失語症 +语音数据机 語音數據機 +语音识别 語音識別 +语音输入系统 語音輸入系統 +误尽天下苍生 誤盡天下蒼生 +误差范围 誤差範圍 +诱出 誘出 +诱发 誘發 +诱发型 誘發型 +诱发式 誘發式 +诱奸 誘姦 +诱拐 誘拐 +诱掖后进 誘掖後進 +诱敌战术 誘敵戰術 +诱杀战术 誘殺戰術 +诱虫灯 誘蟲燈 +诱降战术 誘降戰術 +说不了 說不了 +说不准 說不準 +说不出 說不出 +说不出口 說不出口 +说不出来 說不出來 +说不出话来 說不出話來 +说不尽 說不盡 +说了 說了 +说了又说 說了又說 +说了算 說了算 +说出 說出 +说出去 說出去 +说出口 說出口 +说出来 說出來 +说出话来 說出話來 +说千说万 說千說萬 +说单生万岁 說單生萬歲 +说参请 說參請 +说合 說合 +说合了盖儿了 說合了蓋兒了 +说嘴郎中无好药 說嘴郎中無好藥 +说回来 說回來 +说好了 說好了 +说定了 說定了 +说家克计 說家克計 +说尽 說盡 +说岳 說岳 +说岳全传 說岳全傳 +说干便干 說幹便幹 +说教术 說教術 +说文解字注 說文解字注 +说明了 說明了 +说白了 說白了 +说穿了 說穿了 +说话不当话 說話不當話 +说闲话 說閒話 +说雨谈云 說雨談雲 +诵念 誦唸 +诵经台 誦經臺 +请个 請個 +请了 請了 +请出 請出 +请出去 請出去 +请出来 請出來 +请别见怪 請別見怪 +请勿吸烟 請勿吸菸 +请参阅 請參閱 +请向 請向 +请君入瓮 請君入甕 +请回 請回 +请回到 請回到 +请回去 請回去 +请回来 請回來 +请您回复 請您回復 +请愿 請願 +请愿书 請願書 +请愿团 請願團 +请愿权 請願權 +请愿案 請願案 +请托 請託 +请说出 請說出 +诸余 諸餘 +诸葛亮借东风 諸葛亮借東風 +诺瓦克 諾瓦克 +诺福克 諾福克 +诺福克岛 諾福克島 +诺美克斯 諾美克斯 +诺里 諾里 +读万卷书 讀萬卷書 +读万卷书行万里路 讀萬卷書行萬里路 +读不舍手 讀不捨手 +读书三余 讀書三余 +读书种子 讀書種子 +读了 讀了 +读出 讀出 +读出来 讀出來 +读后 讀後 +读后心得 讀後心得 +读后感 讀後感 +读唇术 讀脣術 +读心术 讀心術 +课余 課餘 +课前课后 課前課後 +课卷 課卷 +课后 課後 +课后复习 課後複習 +课后练习 課後練習 +课后辅导 課後輔導 +课征 課徵 +课田制 課田制 +课程标准 課程標準 +课程表 課程表 +课表 課表 +课表上 課表上 +诿过于人 諉過於人 +谁个 誰個 +谁家灶內无烟 誰家竈內無煙 +谁干 誰幹 +谁干净 誰乾淨 +谁干的 誰幹的 +谁笑到最后谁笑得最好 誰笑到最後誰笑得最好 +谁笑在最后谁笑得最好 誰笑在最後誰笑得最好 +调个 調個 +调了 調了 +调价 調價 +调准 調準 +调出 調出 +调出去 調出去 +调出来 調出來 +调制 調製 +调制出 調製出 +调制法 調製法 +调制波 調製波 +调制解调器 調制解調器 +调升 調升 +调卷 調卷 +调发 調發 +调合 調合 +调合漆 調合漆 +调哄 調哄 +调回 調回 +调回去 調回去 +调回来 調回來 +调幅台 調幅臺 +调干 調幹 +调弦 調絃 +调当 調當 +调整范围 調整範圍 +调查团 調查團 +调查范围 調查範圍 +调查表 調查表 +调査出 調查出 +调査团 調查團 +调査表 調查表 +调画出 調畫出 +调色板 調色板 +调药刀 調藥刀 +调表 調錶 +调适 調適 +调配出 調配出 +调钟表 調鐘錶 +调频台 調頻臺 +调频电台 調頻電臺 +谈不出 談不出 +谈了 談了 +谈出 談出 +谈判代表 談判代表 +谈判制度 談判制度 +谈吐有致 談吐有致 +谈征 談徵 +谈得出 談得出 +谈论出 談論出 +谈辞如云 談辭如雲 +谋出路 謀出路 +谋划 謀劃 +谋取面试 謀取面試 +谋定后动 謀定後動 +谋定而后 謀定而後 +谋干 謀幹 +谋而后动 謀而後動 +谋面 謀面 +谎价 謊價 +谎敲才 謊敲才 +谐价 諧價 +谐当 諧當 +谙历 諳歷 +谜团 謎團 +谜面 謎面 +谢了 謝了 +谢克 謝克 +谢克尔 謝克爾 +谢别 謝別 +谢叶配 謝葉配 +谢安折屐 謝安折屐 +谢尔托夫 謝爾托夫 +谢志伟 謝志偉 +谢福松 謝福松 +谢秋华 謝秋華 +谢系 謝系 +谢绝参观 謝絕參觀 +谢苏 謝蘇 +谢苏叶 謝蘇葉 +谢苏配 謝蘇配 +谢表 謝表 +谢里 謝里 +谢里夫 謝里夫 +谣言止于 謠言止於 +谣言止于智者 謠言止於智者 +谦克 謙克 +谦冲 謙沖 +谦冲自牧 謙沖自牧 +谨于心 謹於心 +谨致 謹致 +谨致谢意 謹致謝意 +谬以千里 謬以千里 +谬种 謬種 +谬种流传 謬種流傳 +谬误百出 謬誤百出 +谬赞 謬讚 +谬采虚声 謬採虛聲 +谭嗣同 譚嗣同 +谯周 譙周 +谯周独笑 譙周獨笑 +谱出 譜出 +谱出来 譜出來 +谱录 譜錄 +谱曲 譜曲 +谱系 譜系 +谱系分类法 譜系分類法 +谱表 譜表 +谷中谷 谷中谷 +谷人 穀人 +谷仓 穀倉 +谷保家商 穀保家商 +谷关 谷關 +谷口 谷口 +谷口耕岩 谷口耕岩 +谷圭 穀圭 +谷地 谷地 +谷场 穀場 +谷垣 谷垣 +谷垣祯 谷垣禎 +谷垣祯一 谷垣禎一 +谷城 谷城 +谷城县 谷城縣 +谷壁 谷壁 +谷壳 穀殼 +谷子 穀子 +谷峰 谷峯 +谷川 谷川 +谷底 谷底 +谷日 穀日 +谷旦 穀旦 +谷月涵 谷月涵 +谷树皮 谷樹皮 +谷梁 穀梁 +谷梁传 穀梁傳 +谷歌 谷歌 +谷氨酰胺 谷氨醯胺 +谷氨酸 穀氨酸 +谷永 谷永 +谷湾 谷灣 +谷物 穀物 +谷皮 穀皮 +谷神 穀神 +谷神星 穀神星 +谷穗 穀穗 +谷米 穀米 +谷类 穀類 +谷类作物 穀類作物 +谷粉 穀粉 +谷粒 穀粒 +谷糠 穀糠 +谷舱 穀艙 +谷苗 穀苗 +谷草 穀草 +谷蠡 谷蠡 +谷象 谷象 +谷贱伤农 穀賤傷農 +谷贵饿农 穀貴餓農 +谷贵饿农谷贱伤农 穀貴餓農穀賤傷農 +谷道 穀道 +谷都 谷都 +谷雨 穀雨 +谷风 穀風 谷風 +谷食 穀食 +谷饮 谷飲 +谿谷 谿谷 +豁上干 豁上幹 +豁出 豁出 +豁出去 豁出去 +豁出命干 豁出命幹 +豁出来 豁出來 +豁命干 豁命幹 +豁死干 豁死幹 +豁荡 豁蕩 +豁起来干 豁起來幹 +豆制品 豆製品 +豆姑娘 豆姑娘 +豆娘 豆娘 +豆娘子 豆娘子 +豆干 豆乾 +豆干展 豆乾展 +豆干肉丝 豆干肉絲 +豆签 豆簽 +豆腐干 豆腐乾 +豆面 豆麪 +豉虫 豉蟲 +象征 象徵 +象征主义 象徵主義 +象征性 象徵性 +象征着 象徵着 +象板 象板 +象牙针尖 象牙針尖 +象牙雕 象牙雕 +象箸玉杯 象箸玉杯 +象鼻虫 象鼻蟲 +豪华游 豪華遊 +豪厘千里 豪釐千里 +豪情万丈 豪情萬丈 +豪情壮志 豪情壯志 +豪情逸致 豪情逸致 +豪杰 豪傑 +豪气万丈 豪氣萬丈 +豪气万千 豪氣萬千 +豪气干云 豪氣干雲 +豪门贵胄 豪門貴胄 +豫游 豫遊 +豺狼当涂 豺狼當塗 +豺狼当路 豺狼當路 +豺狼当道 豺狼當道 +貂复额 貂覆額 +貌合心离 貌合心離 +貌合情离 貌合情離 +貌合神离 貌合神離 +貌合行离 貌合行離 +貌同实异 貌同實異 +買凶 買兇 +賈后 賈后 +賢后 賢后 +賨布 賨布 +賸余 賸餘 +賸馀价值 賸餘價值 +贝他系数 貝他係數 +贝伽特症候群 貝伽特症候羣 +贝克 貝克 +贝克休斯 貝克休斯 +贝克勒 貝克勒 +贝克勒耳 貝克勒耳 +贝克尔 貝克爾 +贝克曼 貝克曼 +贝克汉 貝克漢 +贝克汉姆 貝克漢姆 +贝克特 貝克特 +贝卡谷地 貝卡谷地 +贝叶 貝葉 +贝叶书 貝葉書 +贝叶树 貝葉樹 +贝叶棕 貝葉棕 +贝叶经 貝葉經 +贝奇马克 貝奇馬克 +贝娅特丽克丝 貝婭特麗克絲 +贝娜齐尔布托 貝娜齊爾布托 +贝尔托內 貝爾托內 +贝尔杰 貝爾傑 +贝当 貝當 +贝理克 貝理克 +贝胄 貝冑 +贝西克 貝西克 +贝那芬托 貝那芬托 +贝里 貝里 +贝里拉 貝里拉 +贝里斯 貝里斯 +贝雕 貝雕 +贞丰 貞豐 +贞丰县 貞豐縣 +贞卜文字 貞卜文字 +负乘致寇 負乘致寇 +负债累累 負債累累 +负债表 負債表 +负后像 負後像 +负向 負向 +负回馈 負回饋 +负图之托 負圖之托 +负心违愿 負心違願 +负手板 負手板 +负才 負才 +负才任气 負才任氣 +负才使气 負才使氣 +负极 負極 +负气斗狠 負氣鬥狠 +负笈千里 負笈千里 +负荷不了 負荷不了 +负重致远 負重致遠 +负面 負面 +负面性 負面性 +负鼎之愿 負鼎之願 +贡烟 貢菸 +贡献出 貢獻出 +财产价值 財產價值 +财产关系 財產關係 +财产目录 財產目錄 +财划法 財劃法 +财务报表 財務報表 +财团 財團 +财团法人 財團法人 +财布施 財佈施 +财政支出 財政支出 +财殚力尽 財殫力盡 +财竭力尽 財竭力盡 +财金系 財金系 +责任准备 責任準備 +责任制 責任制 +责任范围 責任範圍 +贤后 賢后 +贤奸倒置 賢奸倒置 +贤才 賢才 +贤胄 賢胄 +败于 敗於 +败于垂成 敗於垂成 +败兵折将 敗兵折將 +败军折将 敗軍折將 +败叶 敗葉 +败坏门面 敗壞門面 +败子回头 敗子回頭 +败子回头金不换 敗子回頭金不換 +败血性休克 敗血性休克 +败血症 敗血症 +败血脓毒症 敗血膿毒症 +败部复活 敗部復活 +账面 賬面 +货价 貨價 +货卜 貨卜 +货布 貨布 +货柜 貨櫃 +货柜场 貨櫃場 +货柜屋 貨櫃屋 +货柜船 貨櫃船 +货柜车 貨櫃車 +货柜轮 貨櫃輪 +货物柜 貨物櫃 +货真价实 貨真價實 +质当 質當 +质朴 質樸 +质量规范 質量規範 +贪婪是万恶之源 貪婪是萬惡之源 +贪念 貪念 +贪杯 貪杯 +贪杯惜醉人 貪杯惜醉人 +贪欲 貪慾 +贪欲无艺 貪慾無藝 +贪生恶死 貪生惡死 +贪生舍义 貪生舍義 +贪睡虫 貪睡蟲 +贫嘴恶舌 貧嘴惡舌 +贫困 貧困 +贫困人家 貧困人家 +贫困化 貧困化 +贫困地区 貧困地區 +贫困率 貧困率 +贫寒出身 貧寒出身 +贫血症 貧血症 +贬价 貶價 +购买欲 購買慾 +购回 購回 +购并 購併 +购并案 購併案 +购彩 購彩 +购物台 購物臺 +购物欲 購物慾 +购销差价 購銷差價 +贯云石 貫雲石 +贯注 貫注 +贱价 賤價 +贱价出售 賤價出售 +贱才 賤才 +贱敛贵出 賤斂貴出 +贱敛贵发 賤斂貴發 +贴个 貼個 +贴出 貼出 +贴出去 貼出去 +贴出来 貼出來 +贴后 貼後 +贴布 貼布 +贵了 貴了 +贵价 貴价 +贵州师范大学 貴州師範大學 +贵干 貴幹 +贵幸 貴幸 +贵征 貴徵 +贵戚 貴戚 +贵极人臣 貴極人臣 +贵游子弟 貴遊子弟 +贵胄 貴胄 +贵贱之别 貴賤之別 +贷个 貸個 +贷了 貸了 +贷借 貸借 +贷出 貸出 +贸易伙伴 貿易伙伴 +费了 費了 +费利克斯 費利克斯 +费占 費佔 +费卢杰 費盧傑 +费后 費後 +费周章 費周章 +费尔干纳 費爾干納 +费尔干纳槃地 費爾干納槃地 +费尔干纳盆地 費爾幹納盆地 +费尔法克斯 費爾法克斯 +费尽 費盡 +费尽唇舌 費盡脣舌 +费尽心思 費盡心思 +费尽心机 費盡心機 +费尽精神 費盡精神 +费杰罗 費傑羅 +费洛蒙 費洛蒙 +费玛最后定理 費瑪最後定理 +费舍尔 費舍爾 +费茨派垂克 費茨派垂克 +费达克 費達克 +费里克斯 費里克斯 +费里克斯布朗 費里克斯布朗 +费里尼 費里尼 +费里斯特 費里斯特 +贺后骂殿 賀后罵殿 +贺尔蒙 賀爾蒙 +贺尔蒙针 賀爾蒙針 +贺表 賀表 +贻笑万世 貽笑萬世 +贻笑千古 貽笑千古 +贻笑千秋 貽笑千秋 +贻羞万年 貽羞萬年 +贻范 貽範 +贻范古今 貽範古今 +贼党 賊黨 +贼没种只怕哄 賊沒種只怕哄 +贾克逊 賈克遜 +贾可布斯 賈可布斯 +贾后 賈后 +贾斯克 賈斯克 +贾氏症 賈氏症 +贾第虫 賈第蟲 +贾第虫属 賈第蟲屬 +贾第虫病 賈第蟲病 +贾胡 賈胡 +贾里尔 賈里爾 +贾鸿秋 賈鴻秋 +贿赂并行 賄賂並行 +资产价值 資產價值 +资产组合 資產組合 +资产负债表 資產負債表 +资历 資歷 +资料介面 資料介面 +资料库管理系统 資料庫管理系統 +资料录 資料錄 +资料表 資料表 +资料链结层 資料鏈結層 +资方代表 資方代表 +资治通鉴 資治通鑑 +资源回收 資源回收 +资管系 資管系 +资讯学系 資訊學系 +资讯系 資訊系 +资金占用 資金佔用 +资金面 資金面 +赈饥 賑饑 +赉发 賚發 +赊借 賒借 +赋别 賦別 +赋格曲 賦格曲 +赋诗言志 賦詩言志 +赋闲 賦閒 +赌了 賭了 +赌台 賭檯 +赌咒发愿 賭咒發願 +赌当 賭當 +赌斗 賭鬥 +赌注 賭注 +赌胜 賭勝 +赌身发誓 賭身發誓 +赌钱厂 賭錢廠 +赍发 齎發 +赍志没地 齎志沒地 +赍志而殁 齎志而歿 +赎回 贖回 +赎回权 贖回權 +赎当 贖當 +赎药 贖藥 +赏不当功 賞不當功 +赏了 賞了 +赏同罚异 賞同罰異 +赏善罚恶 賞善罰惡 +赏罚不当 賞罰不當 +赏赞 賞讚 +赏鉴 賞鑑 +赏面子 賞面子 +赐了 賜了 +赐复 賜復 +赐恤 賜卹 +赒急扶困 賙急扶困 +赔个不是 賠個不是 +赔了 賠了 +赔了夫人 賠了夫人 +赔了夫人又折兵 賠了夫人又折兵 +赔出 賠出 +赔尽 賠盡 +赖于 賴於 +赖幸媛 賴幸媛 +赖索托 賴索托 +赖索托王国 賴索托王國 +赖蒙特 賴蒙特 +赚不了 賺不了 +赚个 賺個 +赚个饱 賺個飽 +赚了 賺了 +赚哄 賺哄 +赚回来 賺回來 +赛制 賽制 +赛后 賽後 +赛德克 賽德克 +赛愿 賽願 +赛程表 賽程表 +赛里木湖 賽里木湖 +赛门铁克 賽門鐵克 +赞一句 讚一句 +赞一声 讚一聲 +赞一赞 讚一讚 +赞不绝口 讚不絕口 +赞两句 讚兩句 +赞个不 讚個不 +赞乐 讚樂 +赞了 讚了 +赞伯拉诺 贊伯拉諾 +赞佩 讚佩 +赞佩不已 讚佩不已 +赞助 贊助 +赞助人 贊助人 +赞助商 贊助商 +赞助者 贊助者 +赞口不 讚口不 +赞叹 讚歎 +赞叹不已 讚歎不已 +赞叹声 讚歎聲 +赞同 贊同 +赞呗 讚唄 +赞善 贊善 +赞布拉诺 贊布拉諾 +赞成 贊成 +赞成票 贊成票 +赞成者 贊成者 +赞我 讚我 +赞扬 讚揚 +赞拜 贊拜 +赞普 贊普 +赞歌 讚歌 +赞歎 讚歎 +赞比亚 贊比亞 +赞理 贊理 +赞的 讚的 +赞皇 贊皇 +赞皇县 贊皇縣 +赞礼 贊禮 +赞美 讚美 +赞美有加 讚美有加 +赞美歌 讚美歌 +赞美诗 讚美詩 +赞羡 讚羨 +赞翼 贊翼 +赞自己 讚自己 +赞誉 讚譽 +赞誉为 讚譽爲 +赞许 讚許 +赞词 讚詞 +赞语 讚語 +赞赏 讚賞 +赞赏不已 讚賞不已 +赞辞 讚辭 +赞道 讚道 +赞颂 讚頌 +赠别 贈別 +赡表子 贍表子 +赢不了 贏不了 +赢了 贏了 +赢余 贏餘 +赢出 贏出 +赢回 贏回 +赢回去 贏回去 +赢回来 贏回來 +赢奸卖俏 贏奸賣俏 +赢定了 贏定了 +赢面 贏面 +赣南师范学院 贛南師範學院 +赤地千里 赤地千里 +赤术 赤朮 +赤松 赤松 +赤松子 赤松子 +赤留出律 赤留出律 +赤绳系足 赤繩繫足 +赤道几內亚 赤道幾內亞 +赤道几內亚共和国 赤道幾內亞共和國 +赤道几内亚 赤道幾內亞 +赤道面 赤道面 +赤霉素 赤黴素 +赫克比 赫克比 +赫克迈泰尔 赫克邁泰爾 +赫弗里希 赫弗里希 +赫拉克利特 赫拉克利特 +赫里斯 赫里斯 +赫里斯登科 赫里斯登科 +赫麦汉士台 赫麥漢士臺 +赭面 赭面 +走上台 走上臺 +走下台 走下臺 +走不了 走不了 +走了 走了 +走了和尚走不了庙 走了和尚走不了廟 +走了大褶儿 走了大褶兒 +走了风声 走了風聲 +走了马脚 走了馬腳 +走亲戚 走親戚 +走出 走出 +走出去 走出去 +走出来 走出來 +走千门踏万户 走千門踏萬戶 +走后 走後 +走后门 走後門 +走向 走向 +走向前去 走向前去 +走向前来 走向前來 +走向断层 走向斷層 +走向滑动断层 走向滑動斷層 +走回 走回 +走回去 走回去 +走回头 走回頭 +走回头路 走回頭路 +走回来 走回來 +走回路 走迴路 +走娘家 走孃家 +走廊里 走廊裏 +走来回 走來回 +走板 走板 +走板眼 走板眼 +走肉行尸 走肉行屍 +走马章台 走馬章臺 +走骨行尸 走骨行屍 +赴台 赴臺 +赴曲 赴曲 +赵丰邦 趙豐邦 +赵云 趙雲 +赵五娘 趙五娘 +赵坤郁 趙坤郁 +赵庄 趙莊 +赵志坚 趙志堅 +赵无极 趙無極 +赵治勋 趙治勳 +赵玄坛 趙玄壇 +赶下台 趕下臺 +赶不出 趕不出 +赶不出来 趕不出來 +赶了 趕了 +赶修 趕修 +赶出 趕出 +赶出去 趕出去 +赶出来 趕出來 +赶制 趕製 +赶前不赶后 趕前不趕後 +赶向 趕向 +赶回 趕回 +赶回到 趕回到 +赶回去 趕回去 +赶回来 趕回來 +赶尸 趕屍 +赶尽杀绝 趕盡殺絕 +赶录 趕錄 +赶得出 趕得出 +赶面棍 趕麪棍 +起不了 起不了 +起了 起了 +起价 起價 +起出 起出 +起发性 起發性 +起吊 起吊 +起哄 起鬨 +起因于 起因於 +起复 起復 +起居注 起居注 +起扑杆 起撲桿 +起承转合 起承轉合 +起根发脚 起根發腳 +起模范 起模範 +起死回生 起死回生 +起源于 起源於 +起航出海 起航出海 +起获 起獲 +起跳价 起跳價 +起跳板 起跳板 +趁哄 趁哄 +趁哄打劫 趁哄打劫 +趁愿 趁願 +超世之才 超世之才 +超低价 超低價 +超党派 超黨派 +超准 超準 +超凡出世 超凡出世 +超出 超出 +超出范围 超出範圍 +超前瞄准 超前瞄準 +超前绝后 超前絕後 +超升 超升 +超友谊关系 超友誼關係 +超基性岩 超基性岩 +超大曲道赛 超大曲道賽 +超完美告别 超完美告別 +超尘出俗 超塵出俗 +超平面 超平面 +超手游廊 超手遊廊 +超新星剩余 超新星剩餘 +超杯 超杯 +超然台 超然臺 +超级台风 超級颱風 +超级杯 超級盃 +超级链接 超級鏈接 +超群出众 超羣出衆 +超范围 超範圍 +超计划利润 超計劃利潤 +超赞 超讚 +超链接 超鏈接 +超额录取 超額錄取 +越冬 越冬 +越冬作物 越冬作物 +越出 越出 +越出界线 越出界線 +越发 越發 +越活越回去 越活越回去 +越王尝蓼 越王嘗蓼 +趋于 趨於 +趋于平稳 趨於平穩 +趋于稳定 趨於穩定 +趋前退后 趨前退後 +趋吉避凶 趨吉避凶 +趋同 趨同 +趋向 趨向 +趋舍 趨舍 +趋舍异路 趨舍異路 +趋舍指凑 趨舍指湊 +趋近于 趨近於 +趫才 趫才 +趱干 趲幹 +足不出户 足不出戶 +足不出门 足不出門 +足了十人 足了十人 +足于 足於 +足协杯 足協盃 +足坛 足壇 +足总杯 足總盃 +足食丰衣 足食豐衣 +趸售物价 躉售物價 +趸当 躉當 +趸批卖出 躉批賣出 +趿拉板儿 趿拉板兒 +跃出 躍出 +跃升 躍升 +跃升为 躍升爲 +跃跃欲试 躍躍欲試 +跋前疐后 跋前疐後 +跋前踬后 跋前躓後 +跋涉千里 跋涉千里 +跋胡疐尾 跋胡疐尾 +跌了 跌了 +跌了弹的斑鸠 跌了彈的斑鳩 +跌价 跌價 +跌停板 跌停板 +跌出 跌出 +跌回 跌回 +跌打药 跌打藥 +跌至谷底 跌至谷底 +跌荡 跌蕩 +跌荡不羁 跌蕩不羈 +跌荡放言 跌蕩放言 +跎纤 跎縴 +跑不了 跑不了 +跑了和尚跑不了寺 跑了和尚跑不了寺 +跑了和尚跑不了庙 跑了和尚跑不了廟 +跑出 跑出 +跑出去 跑出去 +跑出来 跑出來 +跑台子 跑檯子 +跑合 跑合 +跑回 跑回 +跑回去 跑回去 +跑回来 跑回來 +跑得了和尚跑不了庙 跑得了和尚跑不了廟 +跑表 跑表 +跖犬吠尧 跖犬吠堯 +跖狗吠尧 跖狗吠堯 +跖蹻 跖蹻 +跗注 跗注 +跗面 跗面 +跛行症 跛行症 +跛鳖千里 跛鱉千里 +跟了 跟了 +跟他一斗 跟他一鬥 +跟出 跟出 +跟出去 跟出去 +跟出来 跟出來 +跟前跟后 跟前跟後 +跟头虫 跟頭蟲 +跟屁虫 跟屁蟲 +跟斗 跟斗 +跨了 跨了 +跨党 跨黨 +跨出 跨出 +跨出去 跨出去 +跨出来 跨出來 +跨向 跨向 +跨媒体合作 跨媒體合作 +跨平台 跨平臺 +跨步向前 跨步向前 +跨通道启动技术 跨通道啓動技術 +跨鹤西游 跨鶴西遊 +跪了 跪了 +跬步千里 跬步千里 +路克 路克 +路克索 路克索 +路志 路誌 +路怒症 路怒症 +路码表 路碼表 +路签 路籤 +路线斗争 路線鬥爭 +路透集团 路透集團 +路里 路里 +路面 路面 +路面等级 路面等級 +跳了 跳了 +跳井自尽 跳井自盡 +跳价 跳價 +跳伞台 跳傘臺 +跳出 跳出 +跳出去 跳出去 +跳出来 跳出來 +跳出火坑 跳出火坑 +跳出釜底进火坑 跳出釜底進火坑 +跳升 跳升 +跳只舞 跳隻舞 +跳台 跳臺 +跳台滑雪 跳臺滑雪 +跳回 跳回 +跳回去 跳回去 +跳回来 跳回來 +跳墙出去 跳牆出去 +跳板 跳板 +跳梁 跳梁 +跳梁小丑 跳樑小醜 +跳梁猖獗之小丑 跳樑猖獗之小醜 +跳楼自尽 跳樓自盡 +跳水台 跳水臺 +跳河自尽 跳河自盡 +跳海自尽 跳海自盡 +跳脱出 跳脫出 +跳脱出来 跳脫出來 +跳荡 跳蕩 +跳表 跳錶 +跳针 跳針 +践极 踐極 +跷了 蹺了 +跷出 蹺出 +跷跷板 蹺蹺板 +跻升 躋升 +跻身于 躋身於 +踅回 踅回 +踅门了户 踅門瞭戶 +踊跃发言 踊躍發言 +踌躇满志 躊躇滿志 +踏了 踏了 +踏出 踏出 +踏出去 踏出去 +踏出来 踏出來 +踏小板凳儿糊险道神 踏小板凳兒糊險道神 +踏板 踏板 +踏板车 踏板車 +踏脚板 踏腳板 +踏足板 踏足板 +踔厉风发 踔厲風發 +踢不出 踢不出 +踢了 踢了 +踢出 踢出 +踢出去 踢出去 +踢出来 踢出來 +踢到铁板 踢到鐵板 +踢向 踢向 +踢回 踢回 +踢回去 踢回去 +踢回来 踢回來 +踩坏了 踩壞了 +踪迹 蹤跡 +踬仆 躓仆 +蹀里蹀斜 蹀里蹀斜 +蹇修 蹇修 +蹈厉之志 蹈厲之志 +蹈厉奋发 蹈厲奮發 +蹦出 蹦出 +蹦出来 蹦出來 +蹪于 蹪於 +蹭棱子 蹭棱子 +蹲了 蹲了 +蹲板 蹲板 +蹻跖 蹻跖 +躁狂抑郁症 躁狂抑鬱症 +躁狂症 躁狂症 +躁郁 躁鬱 +躁郁症 躁鬱症 +躄出 躄出 +躏借 躪藉 +躐胡 躐胡 +身于 身於 +身价 身價 +身价百倍 身價百倍 +身价非凡 身價非凡 +身份识别卡 身份識別卡 +身体发肤 身體髮膚 +身做身当 身做身當 +身历其境 身歷其境 +身历声 身歷聲 +身后 身後 +身后之事 身後之事 +身后事 身後事 +身后萧条 身後蕭條 +身当其境 身當其境 +身当矢石 身當矢石 +身才 身才 +身敎重于言敎 身教重於言教 +身教胜于言教 身教勝於言教 +身有同感 身有同感 +身板 身板 +身板儿 身板兒 +身正为范 身正爲範 +身系囹圄 身繫囹圄 +躬先表率 躬先表率 +躬擐甲胄 躬擐甲冑 +躯干 軀幹 +躯干骨 軀幹骨 +躲一棒槌挨一榔头 躲一棒槌挨一榔頭 +躲不了 躲不了 +躲了雷公遇了霹雳 躲了雷公遇了霹靂 +躲回 躲回 +躲得不知去向 躲得不知去向 +躲清闲 躲清閒 +躲过了风暴又遇了雨 躲過了風暴又遇了雨 +躺个 躺個 +躺出 躺出 +躺出去 躺出去 +躺出来 躺出來 +躺回 躺回 +軟肥皂 软肥皂 +车仔面 車仔麪 +车到没恶路 車到沒惡路 +车厂 車廠 +车厂子 車廠子 +车叶草 車葉草 +车同轨书同文 車同軌書同文 +车后箱 車後箱 +车坛 車壇 +车夫 車伕 +车库里 車庫裏 +车攻马同 車攻馬同 +车斗 車斗 +车无退表 車無退表 +车百合 車百合 +车种 車種 +车站里 車站裏 +车系 車系 +车载斗量 車載斗量 +车里 車裏 +车里雅宾斯克 車里雅賓斯克 +车马夫 車馬伕 +轧制 軋製 +轧钢厂 軋鋼廠 +轨制 軌制 +轨范 軌範 +轨道面 軌道面 +轩辟 軒闢 +转个 轉個 +转个弯 轉個彎 +转了 轉了 +转借 轉借 +转关系 轉關係 +转出 轉出 +转出去 轉出去 +转出来 轉出來 +转动曲柄 轉動曲柄 +转发 轉發 +转台 轉檯 +转向 轉向 +转向信号 轉向信號 +转向器 轉向器 +转向往 轉向往 +转向架 轉向架 +转向灯 轉向燈 +转向离合 轉向離合 +转回 轉回 +转回去 轉回去 +转回来 轉回來 +转圜余地 轉圜餘地 +转干 轉幹 +转录 轉錄 +转念 轉念 +转意回心 轉意回心 +转战千里 轉戰千里 +转托 轉託 +转折 轉折 +转折亲 轉折親 +转折点 轉折點 +转换方向 轉換方向 +转播台 轉播臺 +转斗千里 轉鬥千里 +转日回天 轉日回天 +转汇 轉匯 +转注 轉註 +转注字 轉註字 +转游 轉游 +转系 轉系 +转胜为败 轉勝爲敗 +转败为胜 轉敗爲勝 +转车台 轉車臺 +转速表 轉速錶 +转面无情 轉面無情 +轮休制 輪休制 +轮作制度 輪作制度 +轮值表 輪值表 +轮发 輪發 +轮台 輪臺 +轮台县 輪臺縣 +轮台古城 輪臺古城 +轮唱曲 輪唱曲 +轮回 輪迴 +轮奸 輪姦 +轮旋曲 輪旋曲 +轮流制 輪流制 +轮流干 輪流幹 +轮班制 輪班制 +轮生叶 輪生葉 +轮种 輪種 +轮种法 輪種法 +轮系 輪系 +轮虫 輪蟲 +软不叮当 軟不叮噹 +软件平台 軟件平臺 +软件开发 軟件開發 +软件开发人员 軟件開發人員 +软件技术 軟件技術 +软件系统 軟件系統 +软体出版协会 軟體出版協會 +软困 軟困 +软软松松 軟軟鬆鬆 +软面筋 軟麪筋 +轰了 轟了 +轰出 轟出 +轰出去 轟出去 +轰出来 轟出來 +轴承合金 軸承合金 +轴根系 軸根系 +轴系 軸系 +轴舻千里 軸艫千里 +轴面 軸面 +轶荡 軼蕩 +轸念 軫念 +轻于 輕於 +轻于鸿毛 輕於鴻毛 +轻叹 輕嘆 +轻度台风 輕度颱風 +轻扣 輕釦 +轻松 輕鬆 +轻松地 輕鬆地 +轻松愉快 輕鬆愉快 +轻松自在 輕鬆自在 +轻松自如 輕鬆自如 +轻核 輕核 +轻油裂解工厂 輕油裂解工廠 +轻烟 輕煙 +轻蔑 輕蔑 +轻蔑性 輕蔑性 +轻袅袅 輕嫋嫋 +轻轻松松 輕輕鬆鬆 +载于 載於 +载出 載出 +载出去 載出去 +载出来 載出來 +载浮载沈 載浮載沈 +载满了 載滿了 +载舟复舟 載舟覆舟 +轿夫 轎伕 +辁才 輇才 +较于 較於 +较胜一筹 較勝一籌 +辅导团 輔導團 +辅系 輔系 +辅赞 輔贊 +辈出 輩出 +辈子干 輩子幹 +辉格党 輝格黨 +辉格党人 輝格黨人 +辉绿岩 輝綠岩 +辉长岩 輝長岩 +辍耕录 輟耕錄 +辐射警告标志 輻射警告標志 +辑录 輯錄 +辑录出来 輯錄出來 +输了 輸了 +输入系统 輸入系統 +输入许可制 輸入許可制 +输出 輸出 +输出业 輸出業 +输出入 輸出入 +输出到 輸出到 +输出功率 輸出功率 +输出区 輸出區 +输出去 輸出去 +输出变压 輸出變壓 +输出品 輸出品 +输出国 輸出國 +输出来 輸出來 +输出管 輸出管 +输出表 輸出表 +输出量 輸出量 +输出阻抗 輸出阻抗 +输征 輸征 +辖制 轄制 +辗米厂 輾米廠 +辛丑 辛丑 +辛丑和约 辛丑和約 +辛丑条约 辛丑條約 +辛克 辛克 +辛辣面 辛辣麪 +辛里希 辛里希 +辜濂松 辜濂松 +辞不获命 辭不獲命 +辞丰意雄 辭豐意雄 +辞修 辭修 +辞别 辭別 +辞汇 辭彙 +辞致 辭致 +辞采 辭采 +辟世 辟世 +辟为 闢爲 +辟举 辟舉 +辟书 辟書 +辟人之士 辟人之士 +辟佛 闢佛 +辟作 闢作 +辟出 闢出 +辟划 闢劃 +辟匿 辟匿 +辟历施鞭 辟歷施鞭 +辟召 辟召 +辟君三舍 辟君三舍 +辟命 辟命 +辟咡 辟咡 +辟土 闢土 +辟地 闢地 +辟地开天 闢地開天 +辟室 闢室 +辟廱 辟廱 +辟建 闢建 +辟引 辟引 +辟恶 辟惡 +辟恶除患 辟惡除患 +辟支佛 辟支佛 +辟易 辟易 +辟淫 辟淫 +辟然 辟然 +辟爲 闢爲 +辟田 闢田 +辟筑 闢築 +辟纑 辟纑 +辟色 辟色 +辟芷 辟芷 +辟言 辟言 +辟设 闢設 +辟谣 闢謠 +辟谷 辟穀 +辟谷绝粒 辟穀絕粒 +辟辟 闢辟 +辟违 辟違 +辟逻 辟邏 +辟邪 辟邪 +辟邪以律 闢邪以律 +辟雍 辟雍 +辟雍砚 辟雍硯 +辣哈布 辣哈布 +辣椒面 辣椒麪 +辣胡椒 辣胡椒 +辨出 辨出 +辨别 辨別 +辨别出来 辨別出來 +辨别力 辨別力 +辨别是非 辨別是非 +辨向 辨向 +辨复 辨復 +辨奸论 辨姦論 +辨志 辨志 +辨折 辨折 +辨认出 辨認出 +辨认出来 辨認出來 +辨识出 辨識出 +辩别 辯別 +辩才 辯才 +辩才天 辯才天 +辩才无碍 辯才無礙 +辩斗 辯鬥 +辩论术 辯論術 +辫发 辮髮 +辫穗头 辮穗頭 +辱游 辱游 +边修 邊修 +边境冲突 邊境衝突 +边幅不修 邊幅不修 +边核 邊核 +辽三彩 遼三彩 +辽太后 遼太后 +辽宁师范大学 遼寧師範大學 +辽沈 遼瀋 +达克 達克 +达克龙 達克龍 +达尔罕茂明安联合旗 達爾罕茂明安聯合旗 +达布洛沃斯基 達布洛沃斯基 +达欣杯 達欣盃 +达沃斯论坛 達沃斯論壇 +达瓦党 達瓦黨 +达致 達致 +迁了 遷了 +迁于 遷於 +迁出 遷出 +迁出去 遷出去 +迁出来 遷出來 +迁升 遷升 +迁厂 遷廠 +迁台 遷臺 +迁回 遷回 +迁回去 遷回去 +迁回来 遷回來 +迁就于 遷就於 +迁怒于 遷怒於 +迁怒于人 遷怒於人 +迁思回虑 遷思迴慮 +迂回 迂迴 +迂回奔袭 迂回奔襲 +迂回战术 迂迴戰術 +迂回曲折 迂迴曲折 +迂徊战术 迂徊戰術 +迂曲 迂曲 +迂迂曲曲 迂迂曲曲 +迅即出发 迅即出發 +迅速发展 迅速發展 +过不了 過不了 +过世面 過世面 +过了 過了 +过了这个村儿没这个店儿 過了這個村兒沒這個店兒 +过了这村没这店 過了這村沒這店 +过了青春无少年 過了青春無少年 +过于 過於 +过云雨 過雲雨 +过人才略 過人才略 +过傢伙 過傢伙 +过冬 過冬 +过冲 過沖 +过几 過幾 +过出 過出 +过动症 過動症 +过历 過歷 +过去了 過去了 +过后 過後 +过境签证 過境簽證 +过失致死 過失致死 +过干瘾 過乾癮 +过庭录 過庭錄 +过当 過當 +过当防卫 過當防衛 +过录 過錄 +过得了 過得了 +过敏性休克 過敏性休克 +过敏症 過敏症 +过杆 過杆 +过松 過鬆 +过桥抽板 過橋抽板 +过梁 過樑 +过水面 過水麪 +过河抽板 過河抽板 +过滤出来 過濾出來 +过滤嘴香烟 過濾嘴香菸 +过眼云烟 過眼雲煙 +过眼烟云 過眼煙雲 +过耳秋风 過耳秋風 +过蒙 過蒙 +迈了 邁了 +迈克 邁克 +迈克尔 邁克爾 +迈克尔克莱顿 邁克爾克萊頓 +迈克尔杰克逊 邁克爾傑克遜 +迈出 邁出 +迈向 邁向 +迈科里 邁科里 +迎出 迎出 +迎合 迎合 +迎合人心 迎合人心 +迎向 迎向 +迎向前去 迎向前去 +迎回 迎回 +迎奸卖俏 迎奸賣俏 +迎宾曲 迎賓曲 +迎斗灯 迎斗燈 +迎春曲 迎春曲 +迎面 迎面 +迎面而来 迎面而來 +运出 運出 +运出去 運出去 +运出来 運出來 +运出运费 運出運費 +运动党 運動黨 +运回 運回 +运回去 運回去 +运回来 運回來 +运用之妙在于一心 運用之妙在於一心 +运用于 運用於 +运筹决胜 運籌決勝 +运筹千里 運籌千里 +运输系统 運輸系統 +运输设备修护费 運輸設備修護費 +近乎同步 近乎同步 +近乎同步数位阶层 近乎同步數位階層 +近了 近了 +近于 近於 +近似于 近似於 +近几年 近幾年 +近几年来 近幾年來 +近思录 近思錄 +近日無仇 近日無讎 +近日里 近日裏 +近朱者赤 近朱者赤 +近朱者赤近墨者黑 近朱者赤近墨者黑 +近朱近墨 近朱近墨 +近水楼台 近水樓臺 +近视眼生了瞎子 近視眼生了瞎子 +返台 返臺 +返吟复吟 返吟復吟 +返回 返回 +返复 返復 +返朴 返樸 +返照回光 返照回光 +返还占有 返還占有 +返里 返里 +返魂乏术 返魂乏術 +还不出 還不出 +还乡团 還鄉團 +还了 還了 +还了得 還了得 +还于 還於 +还价 還價 +还修 還修 +还冲 還衝 +还出 還出 +还出去 還出去 +还出来 還出來 +还占 還佔 +还原熔炼 還原熔煉 +还发 還發 +还向 還向 +还回 還回 +还愿 還願 +还愿意 還願意 +还政于民 還政於民 +还淳反朴 還淳反樸 +还淳返朴 還淳返樸 +还珠合浦 還珠合浦 +还辟 還辟 +还采 還採 +这一个 這一個 +这个 這個 +这个当儿 這個當兒 +这个挡口 這個擋口 +这个月 這個月 +这个那个 這個那個 +这么 這麼 +这么个 這麼個 +这么干 這麼幹 +这么着 這麼着 +这些个 這些個 +这伙人 這夥人 +这几个 這幾個 +这几个人 這幾個人 +这几个月 這幾個月 +这几天 這幾天 +这几次 這幾次 +这出剧 這齣劇 +这出好戏 這齣好戲 +这出电影 這齣電影 +这只 這隻 +这只不 這只不 +这只是 這只是 +这回 這回 +这回事 這回事 +这当儿 這當兒 +这方面 這方面 +这杯 這杯 +这注 這注 +这种 這種 +这种事 這種事 +这种人 這種人 +这种方式 這種方式 +这般干法 這般幹法 +这还了得 這還了得 +这里 這裏 +这里会 這裏會 +这里在 這裏在 +这里是 這裏是 +这里有 這裏有 +这里能 這裏能 +这钟 這鐘 +进一步规范 進一步規範 +进不了 進不了 +进了 進了 +进了天堂 進了天堂 +进价 進價 +进修 進修 +进修班 進修班 +进出 進出 +进出口 進出口 +进出口商 進出口商 +进出境 進出境 +进占 進佔 +进厂 進廠 +进发 進發 +进口加签权 進口加簽權 +进士出身 進士出身 +进幸 進幸 +进度表 進度表 +进得了 進得了 +进德修业 進德修業 +进步伙伴展 進步夥伴展 +进步党 進步黨 +进行曲 進行曲 +进货价 進貨價 +进货让价 進貨讓價 +进货退出 進貨退出 +进货退回 進貨退回 +进进出出 進進出出 +进退失据 進退失據 +进退无据 進退無據 +进退维谷 進退維谷 +进香团 進香團 +远东技术学院 遠東技術學院 +远于 遠於 +远亲近戚 遠親近戚 +远别 遠別 +远县才至 遠縣纔至 +远处夸称近方卖弄 遠處誇稱近方賣弄 +远引曲喻 遠引曲喻 +远征 遠征 +远征军 遠征軍 +远志 遠志 +远恶 遠惡 +远房亲戚 遠房親戚 +远打周折 遠打周折 +远期外汇 遠期外匯 +远水救不了近火 遠水救不了近火 +远游 遠遊 +远程登录 遠程登錄 +远端监控系统 遠端監控系統 +远端签入 遠端簽入 +远胄 遠胄 +远胜 遠勝 +远距图书服务系统 遠距圖書服務系統 +远远落后 遠遠落後 +远隔千里 遠隔千里 +违禁药品 違禁藥品 +违章建筑 違章建築 +违纪参选 違紀參選 +连三并四 連三併四 +连个 連個 +连了 連了 +连于 連於 +连云 連雲 +连云区 連雲區 +连云叠嶂 連雲疊嶂 +连云港 連雲港 +连云港市 連雲港市 +连出 連出 +连升 連升 +连占 連佔 +连卷 連卷 +连发 連發 +连台 連臺 +连台好戏 連臺好戲 +连台本戏 連臺本戲 +连合 連合 +连同 連同 +连哄带骗 連哄帶騙 +连回 連回 +连城之价 連城之價 +连带关系 連帶關係 +连年丰收 連年豐收 +连庄 連莊 +连战连胜 連戰連勝 +连杆 連桿 +连杆机构 連桿機構 +连枝分叶 連枝分葉 +连枝带叶 連枝帶葉 +连根拔出 連根拔出 +连珠合璧 連珠合璧 +连登云路 連登雲路 +连种 連種 +连系 連繫 +连系词 連繫詞 +连系起来 連繫起來 +连胜 連勝 +连胜文 連勝文 +连采 連採 +连镳并轸 連鑣並軫 +连须胡子 連鬚鬍子 +连鬓胡子 連鬢鬍子 +连鬼也不见一个 連鬼也不見一個 +迟了 遲了 +迟发性损伤 遲發性損傷 +迟回 遲迴 +迟回观望 遲回觀望 +迢迢千里 迢迢千里 +迥不相同 迥不相同 +迥乎不同 迥乎不同 +迥别 迥別 +迥然不同 迥然不同 +迥然回异 迥然迴異 +迥然有别 迥然有別 +迦叶 迦葉 +迦叶佛 迦葉佛 +迦叶尊者 迦葉尊者 +迪克 迪克 +迪克斯 迪克斯 +迪化厂 迪化廠 +迪吉苏斯 迪吉蘇斯 +迪拉萨布里 迪拉薩布里 +迪雅巴克 迪雅巴克 +迪黑苏斯 迪黑蘇斯 +迫于 迫於 +迫于形势 迫於形勢 +迫于眉睫 迫於眉睫 +迭出迭入 迭出迭入 +迭有发现 迭有發現 +迭有斩获 迭有斬獲 +迭见杂出 迭見雜出 +迷了 迷了 +迷了心窍 迷了心竅 +迷于 迷於 +迷团 迷團 +迷奸 迷姦 +迷幻药 迷幻藥 +迷彩 迷彩 +迷彩服 迷彩服 +迷彩裤 迷彩褲 +迷暗 迷暗 +迷胡 迷胡 +迷药 迷藥 +迷蒙 迷濛 +迷迷蒙蒙 迷迷濛濛 +迷魂药 迷魂藥 +迸出 迸出 +迸发 迸發 +迸发出 迸發出 +迹蹈 蹟蹈 +追凶 追兇 +追出 追出 +追向 追向 +追回 追回 +追念 追念 +追思弥撒 追思彌撒 +追査出 追查出 +追求幸福 追求幸福 +退伍军人症 退伍軍人症 +退伙 退夥 +退党 退黨 +退出 退出 +退出运行 退出運行 +退前缩后 退前縮後 +退后 退後 +退向 退向 +退回 退回 +退团 退團 +退居幕后 退居幕後 +退徙三舍 退徙三舍 +退有后言 退有後言 +退烧药 退燒藥 +退藏于密 退藏於密 +退避三舍 退避三舍 +退针 退針 +送个 送個 +送了 送了 +送修 送修 +送出 送出 +送别 送別 +送君千里 送君千里 +送回 送回 +送客出门 送客出門 +送客台 送客臺 +送报夫 送報伕 +送秋波 送秋波 +适不适合 適不適合 +适中 適中 +适中下怀 適中下懷 +适之 適之 +适于 適於 +适人 適人 +适从 適從 +适任 適任 +适值 適值 +适切 適切 +适口 適口 +适可而止 適可而止 +适合 適合 +适合于 適合於 +适合者 適合者 +适婚 適婚 +适婚年龄 適婚年齡 +适婚期 適婚期 +适婚者 適婚者 +适孙 適孫 +适宜 適宜 +适应 適應 +适应力 適應力 +适应性 適應性 +适应期 適應期 +适应环境 適應環境 +适应症 適應症 +适度 適度 +适度微调 適度微調 +适当 適當 +适当地 適當地 +适当性 適當性 +适当的 適當的 +适当范围 適當範圍 +适得其反 適得其反 +适得其所 適得其所 +适性 適性 +适意 適意 +适才 適才 +适时 適時 +适时地 適時地 +适材适用 適材適用 +适来 適來 +适法性 適法性 +适然 適然 +适用 適用 +适用于 適用於 +适用性 適用性 +适用者 適用者 +适用范围 適用範圍 +适者 適者 +适者生存 適者生存 +适航性 適航性 +适航指令 適航指令 +适逢 適逢 +适逢其会 適逢其會 +适配器 適配器 +适配层 適配層 +适量 適量 +适销 適銷 +适销对路 適銷對路 +适间 適間 +适闷 適悶 +适龄 適齡 +逃不了 逃不了 +逃不出 逃不出 +逃不出手掌心 逃不出手掌心 +逃了 逃了 +逃债台 逃債臺 +逃出 逃出 +逃出去 逃出去 +逃出来 逃出來 +逃出生天 逃出生天 +逃出虎口 逃出虎口 +逃回 逃回 +逃脱出 逃脫出 +逆价差 逆價差 +逆党 逆黨 +逆入平出 逆入平出 +逆向 逆向 +逆向公车 逆向公車 +逆向思考 逆向思考 +逆向拥塞通知 逆向擁塞通知 +逆向整合 逆向整合 +逆向行驶 逆向行駛 +逆折 逆折 +逆时针 逆時針 +逆转录 逆轉錄 +逆转录病毒 逆轉錄病毒 +逆转录酶 逆轉錄酶 +逆钟 逆鐘 +逆钟向 逆鐘向 +选个 選個 +选举人团 選舉人團 +选举制 選舉制 +选举制度 選舉制度 +选修 選修 +选修科 選修科 +选修科目 選修科目 +选修课 選修課 +选出 選出 +选出来 選出來 +选后 選後 +选录 選錄 +选手表决 選手表決 +选手表明 選手表明 +选手表现 選手表現 +选手表示 選手表示 +选手表达 選手表達 +选才 選才 +选拔出 選拔出 +选拔干部 選拔幹部 +选择范围 選擇範圍 +选曲 選曲 +选校不选系 選校不選系 +选民代表 選民代表 +选民参加率 選民參加率 +选派代表 選派代表 +选种 選種 +选系 選系 +选系不选校 選系不選校 +选美皇后 選美皇后 +逊于 遜於 +逊克 遜克 +逊克县 遜克縣 +逊志时敏 遜志時敏 +逋发 逋髮 +逋荡 逋蕩 +逍遥游 逍遙遊 +透了 透了 +透出 透出 +透出去 透出去 +透出来 透出來 +透漏出 透漏出 +透辟 透闢 +透露出 透露出 +逐个 逐個 +逐出 逐出 +逐出门墙 逐出門牆 +逐末舍本 逐末捨本 +逐步升级 逐步升級 +递了 遞了 +递出 遞出 +递出去 遞出去 +递出来 遞出來 +递升 遞升 +递向 遞向 +递回 遞迴 +递回去 遞回去 +递回来 遞回來 +递推关系 遞推關係 +递解出境 遞解出境 +逗人发笑 逗人發笑 +通了 通了 +通事舍人 通事舍人 +通于 通於 +通人达才 通人達才 +通便药 通便藥 +通信技术 通信技術 +通信系统 通信系統 +通党库 通黨庫 +通力合作 通力合作 +通历 通曆 +通合一气 通合一氣 +通同 通同 +通同一气 通同一氣 +通向 通向 +通奸 通姦 +通奸罪 通姦罪 +通布图 通佈圖 +通庄 通莊 +通心面 通心麪 +通志 通志 +通志馆 通志館 +通才 通才 +通才教育 通才教育 +通才练识 通才練識 +通汇 通匯 +通用汉字标准交换码 通用漢字標準交換碼 +通用资源识别号 通用資源識別號 +通盘计划 通盤計劃 +通联记录 通聯記錄 +通讯录 通訊錄 +通讯系统 通訊系統 +通过事后 通過事後 +通鉴 通鑑 +逛了 逛了 +逛出 逛出 +逛出去 逛出去 +逛出来 逛出來 +逛回 逛回 +逛回去 逛回去 +逛回来 逛回來 +逛荡 逛蕩 +逞凶 逞兇 +逞凶斗狠 逞兇鬥狠 +逞凶鬥狠 逞兇鬥狠 +逞异夸能 逞異誇能 +逞志 逞志 +逞恶 逞惡 +逞欲 逞欲 +速克达 速克達 +速去速回 速去速回 +速回 速回 +速食面 速食麪 +造价 造價 +造出 造出 +造出来 造出來 +造型艺术 造型藝術 +造天立极 造天立極 +造就人才 造就人才 +造就出 造就出 +造岩矿物 造岩礦物 +造币厂 造幣廠 +造形艺术 造形藝術 +造曲 造麴 +造极登峰 造極登峯 +造福万民 造福萬民 +造纸厂 造紙廠 +造纸术 造紙術 +造船厂 造船廠 +造船系 造船系 +造血干 造血幹 +造血干细胞 造血幹細胞 +造钟 造鐘 +造钟表 造鐘錶 +逢人只说三分话 逢人只說三分話 +逢低卖出 逢低賣出 +逢凶化吉 逢凶化吉 +逢君之恶 逢君之惡 +逢蒙 逢蒙 +逢高卖出 逢高賣出 +連亘 連亙 +逮系 逮繫 +逮获 逮獲 +逸出 逸出 +逸出功 逸出功 +逸周书 逸周書 +逸才 逸才 +逸欲 逸欲 +逸游自恣 逸游自恣 +逸群之才 逸羣之才 +逸致 逸緻 +逻辑链路控制 邏輯鏈路控制 +逼上梁山 逼上梁山 +逼下台 逼下臺 +逼了 逼了 +逼出 逼出 +逼出去 逼出去 +逼出来 逼出來 +逼向 逼向 +逼回 逼回 +逼回去 逼回去 +逼回来 逼回來 +逼并 逼併 +逾出 逾出 +逾闲荡检 逾閑蕩檢 +遂其所愿 遂其所願 +遂愿 遂願 +遄征 遄征 +遇合 遇合 +遇风后 遇風後 +遍于 遍於 +遍历 遍歷 +遍布 遍佈 +遏云 遏雲 +遏云社 遏雲社 +遏制 遏制 +遏恶扬善 遏惡揚善 +遐布 遐布 +遐志 遐志 +遐胄 遐胄 +道不了 道不了 +道不出 道不出 +道不同不相为谋 道不同不相爲謀 +道克鲁 道克魯 +道出 道出 +道别 道別 +道合志同 道合志同 +道同志合 道同志合 +道听涂说 道聽塗說 +道尔顿制 道爾頓制 +道尽 道盡 +道尽涂殚 道盡塗殫 +道尽途穷 道盡途窮 +道德发展 道德發展 +道德困境 道德困境 +道德规范 道德規範 +道曲 道曲 +道术 道術 +道格拉斯麦克阿瑟 道格拉斯麥克阿瑟 +道种智 道種智 +道范 道範 +道范长昭 道範長昭 +道里 道里 +道里区 道里區 +遗传钟 遺傳鐘 +遗体告别式 遺體告別式 +遗害万年 遺害萬年 +遗志 遺志 +遗忘症 遺忘症 +遗念 遺念 +遗恨千古 遺恨千古 +遗愿 遺願 +遗才 遺才 +遗胄 遺胄 +遗臭万代 遺臭萬代 +遗臭万年 遺臭萬年 +遗臭万载 遺臭萬載 +遗臭千年 遺臭千年 +遗范 遺範 +遗葑菲采 遺葑菲采 +遗表 遺表 +遗迹 遺蹟 +遗风余 遺風餘 +遣发 遣發 +遣回 遣回 +遣送出境 遣送出境 +遣送回 遣送回 +遣送回国 遣送回國 +遥地里 遙地裏 +遥念 遙念 +遥测技术 遙測技術 +遥胄 遙胄 +遥遥华胄 遙遙華胄 +遨游 遨遊 +遨游四海 遨遊四海 +遨游天下 遨遊天下 +遭人暗算 遭人暗算 +遭致 遭致 +遮不了 遮不了 +遮丑 遮醜 +遮光板 遮光板 +遮前掩后 遮前掩後 +遮场面 遮場面 +遮复 遮覆 +遮头盖面 遮頭蓋面 +遮护板 遮護板 +遮挽 遮挽 +遮羞布 遮羞布 +遮道挽留 遮道挽留 +遮阳板 遮陽板 +遮面 遮面 +遴选出 遴選出 +遴选出来 遴選出來 +避不见面 避不見面 +避了 避了 +避凶就吉 避凶就吉 +避凶趋吉 避凶趨吉 +避向 避向 +避孕药 避孕藥 +避恶 避惡 +避暑胜地 避暑勝地 +避雷针 避雷針 +避风台 避風臺 +邀天之幸 邀天之幸 +邅回 邅回 +邋里邋遢 邋里邋遢 +邑里 邑里 +邓布利多 鄧布利多 +邢台 邢臺 +邢台县 邢臺縣 +邢台地区 邢臺地區 +邢台市 邢臺市 +那个 那個 +那个人 那個人 +那个猫儿不吃腥 那個貓兒不吃腥 +那个耗子不偷油 那個耗子不偷油 +那么 那麼 +那么干 那麼幹 +那么着 那麼着 +那伙人 那夥人 +那借 那借 +那几 那幾 +那几个 那幾個 +那几天 那幾天 +那几次 那幾次 +那出剧 那齣劇 +那出好戏 那齣好戲 +那出电影 那齣電影 +那卷 那捲 +那只 那隻 +那只是 那只是 +那只有 那只有 +那台 那臺 +那回 那回 +那当儿 那當兒 +那斯达克 那斯達克 +那方面 那方面 +那曲 那曲 +那曲县 那曲縣 +那曲地区 那曲地區 +那曲市 那曲市 +那杯 那杯 +那种 那種 +那种人 那種人 +那维克 那維克 +那里 那裏 +邪不干正 邪不干正 +邪不胜正 邪不勝正 +邪念 邪念 +邪恶 邪惡 +邪恶轴心 邪惡軸心 +邪曲 邪曲 +邪术 邪術 +邪辟 邪辟 +邮政储金转存制度 郵政儲金轉存制度 +邮政划拨 郵政劃撥 +邮政汇票 郵政匯票 +邮汇 郵匯 +邮汇局 郵匯局 +邮购价格 郵購價格 +邮购目录 郵購目錄 +邱富郁 邱富郁 +邱正杰 邱正傑 +邱胜琦 邱勝琦 +邱胜翊 邱勝翊 +邱郁婷 邱郁婷 +邵廷采 邵廷采 +邵杰 邵傑 +邵维杰 邵維傑 +邸舍 邸舍 +邻曲 鄰曲 +邻舍 鄰舍 +邻里 鄰里 +邻里乡党 鄰里鄉黨 +邻里长 鄰里長 +郁伊 鬱伊 +郁勃 鬱勃 +郁卒 鬱卒 +郁南 鬱南 +郁南县 鬱南縣 +郁哉 郁哉 +郁垒 鬱壘 +郁堙不偶 鬱堙不偶 +郁塞 鬱塞 +郁律 鬱律 +郁悒 鬱悒 +郁愤 鬱憤 +郁抑 鬱抑 +郁挹 鬱挹 +郁朴 郁樸 +郁李 郁李 +郁林 鬱林 +郁气 鬱氣 +郁江 鬱江 +郁沉沉 鬱沉沉 +郁泱 鬱泱 +郁火 鬱火 +郁烈 郁烈 +郁热 鬱熱 +郁燠 鬱燠 +郁症 鬱症 +郁离子 郁離子 +郁积 鬱積 +郁穆 郁穆 +郁纡 鬱紆 +郁结 鬱結 +郁蒸 鬱蒸 +郁蓊 鬱蓊 +郁血 鬱血 +郁达夫 郁達夫 +郁邑 鬱邑 +郁郁 鬱郁 +郁郁不乐 鬱鬱不樂 +郁郁不平 鬱鬱不平 +郁郁寡欢 鬱鬱寡歡 +郁郁而终 鬱鬱而終 +郁郁菲菲 郁郁菲菲 +郁郁葱葱 鬱鬱蔥蔥 +郁郁青青 郁郁青青 +郁金 鬱金 +郁金香 鬱金香 +郁闭 鬱閉 +郁闭度 鬱閉度 +郁闷 鬱悶 +郁闷不乐 鬱悶不樂 +郁陶 鬱陶 +郁馥 郁馥 +郁黑 鬱黑 +郇山隐修会 郇山隱修會 +郊坛 郊壇 +郊坛下窑 郊壇下窯 +郊游 郊遊 +郎个 郎個 +郎之万 郎之萬 +郎当 郎當 +郎才女姿 郎才女姿 +郎才女貌 郎才女貌 +郎潜白发 郎潛白髮 +郑丞杰 鄭丞傑 +郑丰喜 鄭豐喜 +郑余豪 鄭余豪 +郑俊杰 鄭俊傑 +郑克塽 鄭克塽 +郑克爽 鄭克爽 +郑凯云 鄭凱云 +郑卫之曲 鄭衛之曲 +郑家钟 鄭家鐘 +郑幸娟 鄭幸娟 +郑庄公 鄭莊公 +郑志龙 鄭志龍 +郑明修 鄭明修 +郑易里 鄭易里 +郑杰文 鄭傑文 +郑板桥 鄭板橋 +郑梦准 鄭夢準 +郑苹如 鄭蘋如 +郑荣松 鄭榮松 +郑重宣布 鄭重宣佈 +郘钟 郘鐘 +郡县制 郡縣制 +郡县制度 郡縣制度 +郡国制 郡國制 +部党 部黨 +部发 部發 +部曲 部曲 +部胡林 部胡林 +部落发 部落發 +部落同盟 部落同盟 +郭勇志 郭勇志 +郭台成 郭臺成 +郭台铭 郭臺銘 +郭子干 郭子乾 +郭志明 郭志明 +郭松焘 郭松燾 +郭泓志 郭泓志 +郭采洁 郭采潔 +都于 都於 +都俞吁咈 都俞吁咈 +都出 都出 +都出去 都出去 +都出来 都出來 +都卜勒 都卜勒 +都发 都發 +都发局 都發局 +都发局长 都發局長 +都受了 都受了 +都向 都向 +都回 都回 +都回去 都回去 +都回来 都回來 +都市计划 都市計劃 +都必须 都必須 +都念 都念 +都肯干 都肯幹 +都舍下 都捨下 +鄂托克 鄂托克 +鄂托克前旗 鄂托克前旗 +鄂托克旗 鄂托克旗 +鄂温克族 鄂溫克族 +鄂温克族自治旗 鄂溫克族自治旗 +鄂温克语 鄂溫克語 +鄂霍次克海 鄂霍次克海 +鄭凱云 鄭凱云 +酋长制度 酋長制度 +酌古御今 酌古御今 +配了 配了 +配享千秋 配享千秋 +配件挂勾 配件掛勾 +配位化合物 配位化合物 +配出 配出 +配出来 配出來 +配制 配製 +配制饲料 配制飼料 +配发 配發 +配合 配合 +配合上 配合上 +配合度 配合度 +配合款 配合款 +配合着 配合着 +配合禁忌 配合禁忌 +配合起来 配合起來 +配合题 配合題 +配水干管 配水幹管 +配水系统 配水系統 +配种 配種 +配种季节 配種季節 +配给制度 配給制度 +配膳台 配膳檯 +配药 配藥 +配药师 配藥師 +配送范围 配送範圍 +酒入舌出 酒入舌出 +酒厂 酒廠 +酒后 酒後 +酒后吐真言 酒後吐真言 +酒后失态 酒後失態 +酒后失言 酒後失言 +酒后驾车 酒後駕車 +酒后驾驶 酒後駕駛 +酒困 酒困 +酒坛 酒罈 +酒娘子 酒娘子 +酒已干 酒已乾 +酒帘 酒帘 +酒帘子 酒帘子 +酒干了 酒乾了 +酒干尽 酒乾盡 +酒干掉 酒乾掉 +酒恶 酒惡 +酒曲 酒麴 +酒有别肠 酒有別腸 +酒杯 酒杯 +酒柜 酒櫃 +酒气冲天 酒氣沖天 +酒气熏人 酒氣熏人 +酒注子 酒注子 +酒游花 酒游花 +酒病酒药医 酒病酒藥醫 +酒肴 酒餚 +酒胡 酒胡 +酒药 酒藥 +酒逢知己千钟少 酒逢知己千鍾少 +酒逢知己千锺少话不投机半句多 酒逢知己千鍾少話不投機半句多 +酒醴曲蘖 酒醴麴櫱 +酒面 酒面 +酒食征逐 酒食徵逐 +酝借 醞藉 +酝酿出 醞釀出 +酣嬉淋漓 酣嬉淋漓 +酣畅淋漓 酣暢淋漓 +酥松 酥鬆 +酥松可口 酥鬆可口 +酥松油脂 酥鬆油脂 +酥签 酥簽 +酩子里 酩子裏 +酮体症 酮體症 +酷刑折磨 酷刑折磨 +酷毙了 酷斃了 +酸懒 痠懶 +酸疼 痠疼 +酸痛 痠痛 +酸软 痠軟 +酸酸咸咸 酸酸鹹鹹 +酸麻 痠麻 +酿出 釀出 +酿制 釀製 +酿造出来 釀造出來 +酿酒厂 釀酒廠 +醇朴 醇樸 +醇郁 醇郁 +醉于 醉於 +醉心于 醉心於 +醉熏熏 醉熏熏 +醋坛 醋罈 +醋坛子 醋罈子 +醋娘子要食杨梅 醋娘子要食楊梅 +醋栗 醋栗 +醋酸纤维 醋酸纖維 +醒吾技术学院 醒吾技術學院 +醒狮团 醒獅團 +醣厂 醣廠 +醮坛 醮壇 +醯鸡甕里 醯雞甕裏 +醲郁 醲郁 +采下 採下 +采下去 採下去 +采下来 採下來 +采为 採爲 +采买 採買 +采伐 採伐 +采住 採住 +采信 採信 +采光 採光 +采光剖璞 采光剖璞 +采兰赠芍 采蘭贈芍 +采兰赠药 採蘭贈藥 +采写 採寫 +采到 採到 +采制 採製 +采办 採辦 +采区 採區 +采去 採去 +采及葑菲 采及葑菲 +采取 採取 +采取措施 採取措施 +采取行动 採取行動 +采回 採回 +采回去 採回去 +采回来 採回來 +采在 採在 +采地 采地 +采场 採場 +采声 采聲 +采头 采頭 +采女 采女 +采好 採好 +采录 採錄 +采得 採得 +采择 採擇 +采拾 採拾 +采挖 採挖 +采掘 採掘 +采摘 採摘 +采摭 採摭 +采撷 採擷 +采收 採收 +采收期 採收期 +采收率 採收率 +采料 採料 +采景 採景 +采暖 採暖 +采果 採果 +采树种 採樹種 +采样 採樣 +采样法 採樣法 +采样率 採樣率 +采桑 採桑 +采棉机 採棉機 +采椽不斲 采椽不斲 +采樵人 採樵人 +采气 採氣 +采水 採水 +采油 採油 +采烈 采烈 +采煤 採煤 +采煤矿 採煤礦 +采爲 採爲 +采猎 採獵 +采珠 採珠 +采珠人 採珠人 +采生折割 採生折割 +采用 採用 +采用到 採用到 +采用率 採用率 +采的 採的 +采盐 採鹽 +采石 採石 +采石之役 采石之役 +采石之战 采石之戰 +采石之戰 采石之戰 +采石厂 採石廠 +采石场 採石場 +采矿 採礦 +采矿业 採礦業 +采矿场 採礦場 +采矿工 採礦工 +采矿工业 採礦工業 +采矿工程 採礦工程 +采矿方法 採礦方法 +采砂场 採砂場 +采种 採種 +采稿 採稿 +采空区 採空區 +采空采穗 採空採穗 +采精 採精 +采納 採納 +采纳 採納 +采给 採給 +采绿 采綠 +采缉 采緝 +采编 採編 +采脂 採脂 +采色 采色 +采芑 采芑 +采花 採花 +采花贼 採花賊 +采芹 采芹 +采芹人 採芹人 +采苓 采苓 +采茶 採茶 +采茶戏 採茶戲 +采茶歌 採茶歌 +采药 採藥 +采药人 採藥人 +采莲 採蓮 +采莲曲 採蓮曲 +采莲船 採蓮船 +采获 採獲 +采菊 採菊 +采菽 采菽 +采葛 采葛 +采薇 采薇 +采薪 採薪 +采薪之忧 采薪之憂 +采薪之疾 采薪之疾 +采蘩 采蘩 +采蜜 採蜜 +采血 採血 +采行 採行 +采衣 采衣 +采补 採補 +采认 採認 +采访 採訪 +采访使 採訪使 +采访员 採訪員 +采访团 採訪團 +采访新闻 採訪新聞 +采访权 採訪權 +采访编辑 採訪編輯 +采访记者 採訪記者 +采证 採證 +采诗 采詩 +采购 採購 +采购供应 採購供應 +采购员 採購員 +采购团 採購團 +采购案 採購案 +采购法 採購法 +采购站 採購站 +采购规则 採購規則 +采购量 採購量 +采过 採過 +采过去 採過去 +采过来 採過來 +采运 採運 +采选 採選 +采邑 采邑 +采采 采采 +采金 採金 +采铁 採鐵 +采集 採集 +采集到 採集到 +采集法 採集法 +采集起来 採集起來 +采风 採風 +采风录 采風錄 +采风问俗 採風問俗 +采食 採食 +釉下彩 釉下彩 +釉彩 釉彩 +釉药 釉藥 +释出 釋出 +释卷 釋卷 +释放出 釋放出 +释放出来 釋放出來 +释放出狱 釋放出獄 +释迦佛也恼下莲台 釋迦佛也惱下蓮臺 +里亚 里亞 +里人 里人 +里仁 里仁 +里仁为美 里仁爲美 +里克特 里克特 +里党 里黨 +里兹 里茲 +里出外进 裏出外進 +里加 里加 +里勾外连 裏勾外連 +里包恩 里包恩 +里名 里名 +里君 里君 +里咽 裏咽 +里士满 里士滿 +里外 裏外 +里奇蒙 里奇蒙 +里契蒙 里契蒙 +里奥 里奧 +里奥斯 里奧斯 +里奥格兰德 里奧格蘭德 +里子 裏子 +里实 裏實 +里宰 里宰 +里尔 里爾 +里尔队 里爾隊 +里尼 里尼 +里层 裏層 +里居 里居 +里屋 裏屋 +里巷 里巷 +里布 里布 +里希特霍芬 里希特霍芬 +里带 裏帶 +里应外合 裏應外合 +里廉 裏廉 +里弄 里弄 +里弗赛德 里弗賽德 +里弦 裏弦 +里急后重 裏急後重 +里手 裏手 +里扣 里扣 +里拉 里拉 +里挑一 裏挑一 +里斯 里斯 +里斯本 里斯本 +里昂 里昂 +里昂市 里昂市 +里昂队 里昂隊 +里木店 里木店 +里根 里根 +里欧 里歐 +里欧斯 里歐斯 +里正 里正 +里氏 里氏 +里氏震级 里氏震級 +里民 里民 +里民大会 里民大會 +里海 裏海 +里港 里港 +里港乡 里港鄉 +里牵绵 裏牽綿 +里特维宁科 里特維寧科 +里瓦几亚条约 里瓦幾亞條約 +里瓦尔多 裏瓦爾多 +里社 里社 +里科 里科 +里程 里程 +里程碑 里程碑 +里程碑式 里程碑式 +里程表 里程錶 +里程计 里程計 +里约 里約 +里约热內卢 里約熱內盧 +里约热内卢 里約熱內盧 +里纳 里納 +里维拉 里維拉 +里美 里美 +里老 里老 +里耳 里耳 +里肌 里肌 +里胥 里胥 +里脊 裏脊 +里脊肉 裏脊肉 +里舍 里舍 +里蒙诺夫 里蒙諾夫 +里虚 裏虛 +里衣 裏衣 +里言 裏言 +里语 里語 +里谈巷议 里談巷議 +里谚 里諺 +里豪 里豪 +里贝利 里貝利 +里贾纳 里賈納 +里路 里路 +里踢 裏踢 +里边 裏邊 +里边儿 裏邊兒 +里进外出 裏進外出 +里通外国 裏通外國 +里通外敌 裏通外敵 +里邻长 里鄰長 +里里 裏裏 +里里外外 裏裏外外 +里长 里長 +里长伯 里長伯 +里门 里門 +里闬 里閈 +里间 裏間 +里闾 里閭 +里面 裏面 +里面儿 裏面兒 +重于 重於 +重于泰山 重於泰山 +重价 重價 +重估后 重估後 +重修 重修 +重修旧好 重修舊好 +重出 重出 +重划 重劃 +重划区 重劃區 +重划局 重劃局 +重制 重製 +重力摆 重力擺 +重历旧游 重歷舊遊 +重发 重發 +重台 重臺 +重合 重合 +重回 重回 +重复 重複 +重复使用 重複使用 +重复启动效应 重複啓動效應 +重复式 重複式 +重复本 重複本 +重复法 重複法 +重复节 重複節 +重复记录 重複記錄 +重复语境 重複語境 +重复课税 重複課稅 +重定向 重定向 +重岩叠嶂 重巖疊嶂 +重庆师范大学 重慶師範大學 +重当 重當 +重托 重託 +重扣 重扣 +重折 重摺 +重新装修 重新裝修 +重新评价 重新評價 +重涂 重塗 +重游 重遊 +重游旧地 重遊舊地 +重点采访 重點採訪 +重生爷娘 重生爺孃 +重症 重症 +重罗面 重羅麪 +重置价格 重置價格 +重获 重獲 +重见复出 重見複出 +重蹈复辙 重蹈覆轍 +重重困难 重重困難 +重锤 重錘 +野台 野臺 +野台戏 野臺戲 +野合 野合 +野外定向 野外定向 +野姜 野薑 +野姜花 野薑花 +野无遗才 野無遺才 +野游 野遊 +野种 野種 +野胡萝卜 野胡蘿蔔 +野草闲花 野草閒花 +野获编 野獲編 +野鹤闲云 野鶴閒雲 +量了 量了 +量入为出 量入爲出 +量出 量出 +量出制入 量出制入 +量回 量回 +量回去 量回去 +量回来 量回來 +量才录用 量才錄用 +量材录用 量材錄用 +量杯 量杯 +量表 量表 +量雨表 量雨表 +金万福 金萬福 +金乌西坠玉兔东升 金烏西墜玉兔東昇 +金云母 金雲母 +金仆姑 金僕姑 +金仑溪 金崙溪 +金价 金價 +金伯利岩 金伯利岩 +金光党 金光黨 +金创药 金創藥 +金升圭 金昇圭 +金升渊 金升淵 +金印如斗 金印如斗 +金发 金髮 +金发女郎 金髮女郎 +金发碧眼 金髮碧眼 +金台 金臺 +金台区 金臺區 +金叶 金葉 +金合欢 金合歡 +金周成 金周成 +金坛 金壇 +金坛市 金壇市 +金基范 金基範 +金头银面 金頭銀面 +金属制 金屬製 +金属杆 金屬桿 +金属板 金屬板 +金布道 金布道 +金斗 金斗 +金曲 金曲 +金曲奖 金曲獎 +金本位制 金本位制 +金杯 金盃 金杯 +金枝玉叶 金枝玉葉 +金柜 金櫃 +金柜石室 金櫃石室 +金榜挂名 金榜掛名 +金正云 金正雲 +金氏纪录 金氏紀錄 +金玉其表 金玉其表 +金甲虫 金甲蟲 +金疮药 金瘡藥 +金盏银台 金盞銀臺 +金石录 金石錄 +金穗奖 金穗獎 +金粉楼台 金粉樓臺 +金线虫 金線蟲 +金胄 金胄 +金花虫 金花蟲 +金范 金範 +金虫 金蟲 +金融杠杆 金融槓桿 +金融系统 金融系統 +金衡制 金衡制 +金表 金錶 +金表态 金表態 +金表情 金表情 +金表扬 金表揚 +金表明 金表明 +金表演 金表演 +金表现 金表現 +金表示 金表示 +金表达 金表達 +金表露 金表露 +金表面 金表面 +金装玉里 金裝玉裏 +金谷 金谷 +金谷园 金谷園 +金谷堕楼 金谷墮樓 +金谷酒数 金谷酒數 +金里奇 金裏奇 +金针 金針 +金针山 金針山 +金针度人 金針度人 +金针花 金針花 +金针菇 金針菇 +金针菜 金針菜 +金钟 金鐘 +金钟罩 金鐘罩 +金钟铲 金鐘鏟 +金钱万能 金錢萬能 +金钱挂帅 金錢掛帥 +金钱松 金錢松 +金钱游戏 金錢遊戲 +金链 金鍊 +金面 金面 +金马仑道 金馬崙道 +金马克 金馬克 +釜底游魂 釜底遊魂 +釜底游鱼 釜底游魚 +釜里之鱼 釜裏之魚 +鉴于 鑑於 +鉴别 鑑別 +鉴别力 鑑別力 +鉴别器 鑑別器 +鉴别能力 鑑別能力 +鉴古推今 鑑古推今 +鉴堂 鑑堂 +鉴定 鑑定 +鉴定为 鑑定爲 +鉴定书 鑑定書 +鉴定人 鑑定人 +鉴定委员会 鑑定委員會 +鉴定考试 鑑定考試 +鉴宝 鑑寶 +鉴察 鑑察 +鉴往知来 鑑往知來 +鉴戒 鑑戒 +鉴明 鑑明 +鉴核备査 鑑核備查 +鉴此 鑑此 +鉴毛辨色 鑑毛辨色 +鉴泉 鑑泉 +鉴湖 鑑湖 +鉴湖女侠 鑑湖女俠 +鉴照 鑑照 +鉴相 鑑相 +鉴真 鑑真 +鉴真和尚 鑑真和尚 +鉴藏印 鑑藏印 +鉴证 鑑證 +鉴识 鑑識 +鉴诫 鑑誡 +鉴谅 鑑諒 +鉴貌辨色 鑑貌辨色 +鉴赏 鑑賞 +鉴赏力 鑑賞力 +鉴赏印 鑑賞印 +鉴赏家 鑑賞家 +鉴赏能力 鑑賞能力 +鉴频 鑑頻 +鉴频器 鑑頻器 +銀发 銀髮 +针关 鍼關 +针具 針具 +针刺 針刺 +针刺麻醉 針刺麻醉 +针剂 針劑 +针口 鍼口 +针叶 針葉 +针叶林 針葉林 +针叶树 針葉樹 +针叶植物 針葉植物 +针头 針頭 +针孔 針孔 +针孔摄影机 針孔攝影機 +针孔照像 針孔照像 +针孔照像机 針孔照像機 +针孔现象 針孔現象 +针对 針對 +针对于 針對於 +针对性 針對性 +针尖 針尖 +针尖儿 針尖兒 +针工 針工 +针布 針布 +针形叶 針形葉 +针扣 針釦 +针指 針指 +针挑刀挖 針挑刀挖 +针梳机 針梳機 +针毡 針氈 +针法 針法 +针灸 鍼灸 +针灸铜人 鍼灸銅人 +针灸麻醉 鍼灸麻醉 +针炙 針炙 +针状 針狀 +针状物 針狀物 +针盘 針盤 +针眼 針眼 +针眼子 針眼子 +针砭 鍼砭 +针神 針神 +针笔 針筆 +针笔匠 針筆匠 +针筒 針筒 +针箍 針箍 +针箍儿 針箍兒 +针线 針線 +针线包 針線包 +针线娘 針線娘 +针线活 針線活 +针线活计 針線活計 +针线盒 針線盒 +针线箔篱 針線箔籬 +针织 針織 +针织厂 針織廠 +针织品 針織品 +针织料 針織料 +针脚 針腳 +针芒 鍼芒 +针芥相投 鍼芥相投 +针针见血 針針見血 +针铓 針鋩 +针锋 針鋒 +针锋相对 針鋒相對 +针锋相投 針鋒相投 +针阳谷 鍼陽谷 +针饵莫减 針餌莫減 +针骨 針骨 +针鱼 針魚 +针黹 針黹 +针黹纺绩 針黹紡績 +针鼹 針鼴 +针鼻 針鼻 +针鼻儿 針鼻兒 +钉个 釘個 +钉书针 釘書針 +钉了 釘了 +钉合 釘合 +钉扣 釘釦 +钉锤 釘錘 +钓个 釣個 +钓了 釣了 +钓游旧地 釣遊舊地 +钓鱼台 釣魚臺 +钓鱼台列岛 釣魚臺列島 +钓鱼杆 釣魚杆 +钗云 釵雲 +钛合金 鈦合金 +钜万 鉅萬 +钞录 鈔錄 +钟上 鐘上 +钟下 鐘下 +钟不 鐘不 +钟不扣不鸣 鐘不扣不鳴 +钟不撞不鸣 鐘不撞不鳴 +钟不敲不响 鐘不敲不響 +钟不空则哑 鐘不空則啞 +钟乐 鐘樂 +钟乳洞 鐘乳洞 +钟乳石 鐘乳石 +钟体 鐘體 +钟停 鐘停 +钟关 鐘關 +钟匠 鐘匠 +钟发音 鐘發音 +钟口 鐘口 +钟响 鐘響 +钟响声 鐘響聲 +钟在寺里 鐘在寺裏 +钟塔 鐘塔 +钟壁 鐘壁 +钟声 鐘聲 +钟太 鐘太 +钟头 鐘頭 +钟好 鐘好 +钟山 鐘山 +钟山区 鐘山區 +钟山县 鐘山縣 +钟左右 鐘左右 +钟差 鐘差 +钟座 鐘座 +钟形 鐘形 +钟形虫 鐘形蟲 +钟律 鐘律 +钟快 鐘快 +钟情 鍾情 +钟意 鐘意 +钟慢 鐘慢 +钟摆 鐘擺 +钟敲 鐘敲 +钟无豔 鍾無豔 +钟有 鐘有 +钟楚红 鐘楚紅 +钟楼 鐘樓 +钟楼区 鐘樓區 +钟楼怪人 鐘樓怪人 +钟模 鐘模 +钟欣桐 鍾欣桐 +钟没 鐘沒 +钟漏 鐘漏 +钟点 鐘點 +钟点房 鐘點房 +钟点费 鐘點費 +钟爱 鍾愛 +钟王 鐘王 +钟珮瑄 鐘珮瑄 +钟琴 鐘琴 +钟的 鐘的 +钟盘 鐘盤 +钟相 鐘相 +钟磬 鐘磬 +钟祥 鍾祥 +钟祥县 鍾祥縣 +钟祥市 鍾祥市 +钟福松 鐘福松 +钟纽 鐘紐 +钟罩 鐘罩 +钟腰 鐘腰 +钟螺 鐘螺 +钟行 鐘行 +钟表 鐘錶 +钟表停 鐘錶停 +钟表盘 鐘表盤 +钟被 鐘被 +钟调 鐘調 +钟身 鐘身 +钟速 鐘速 +钟面 鐘面 +钟顶 鐘頂 +钟馗 鍾馗 +钟鸣 鐘鳴 +钟鸣漏尽 鐘鳴漏盡 +钟鸣鼎食 鐘鳴鼎食 +钟鼎 鐘鼎 +钟鼎之家 鐘鼎之家 +钟鼎人家 鐘鼎人家 +钟鼎山林 鐘鼎山林 +钟鼎文 鐘鼎文 +钟鼎款识 鐘鼎款識 +钟鼎高门 鐘鼎高門 +钟鼓 鐘鼓 +钟鼓齐鸣 鐘鼓齊鳴 +钢制 鋼製 +钢制品 鋼製品 +钢扣 鋼釦 +钢曲尺 鋼曲尺 +钢杯 鋼杯 +钢板 鋼板 +钢梁 鋼樑 +钢琴曲 鋼琴曲 +钢种 鋼種 +钢笔杆 鋼筆桿 +钢针 鋼針 +钢铁厂 鋼鐵廠 +钢铲 鋼鏟 +钥匙链 鑰匙鏈 +钧复 鈞覆 +钧鉴 鈞鑒 +钩党 鉤黨 +钩心斗角 鉤心鬥角 +钩深致远 鉤深致遠 +钩花点叶 鉤花點葉 +钩虫 鉤蟲 +钩虫病 鉤蟲病 +钩针 鉤針 +钮扣 鈕釦 +钱复 錢復 +钱布 錢布 +钱庄 錢莊 +钱板儿 錢板兒 +钱柜 錢櫃 +钱柜杂志 錢櫃雜誌 +钱玄同 錢玄同 +钱眼里安身 錢眼裏安身 +钱范 錢範 +钱谷 錢穀 +钱过北斗 錢過北斗 +钱钟书 錢鍾書 +钳制 鉗制 +钻井平台 鑽井平臺 +钻出 鑽出 +钻台 鑽臺 +钻心虫 鑽心蟲 +钻懒帮闲 鑽懶幫閒 +钻杆 鑽桿 +钻皮出羽 鑽皮出羽 +钻石项链 鑽石項鍊 +钿合 鈿合 +钿头云篦 鈿頭雲篦 +铁云藏龟 鐵雲藏龜 +铁价 鐵價 +铁制 鐵製 +铁厂 鐵廠 +铁叶 鐵葉 +铁合金 鐵合金 +铁娘子 鐵娘子 +铁托 鐵托 +铁扣 鐵釦 +铁拐 鐵柺 +铁杆 鐵桿 +铁杠 鐵槓 +铁板 鐵板 +铁板大鼓 鐵板大鼓 +铁板快书 鐵板快書 +铁板注脚 鐵板註腳 +铁板烧 鐵板燒 +铁板牛柳 鐵板牛柳 +铁板牛肉 鐵板牛肉 +铁板茄子 鐵板茄子 +铁板路 鐵板路 +铁板面 鐵板麪 +铁柜 鐵櫃 +铁栏杆 鐵欄杆 +铁甲虫 鐵甲蟲 +铁索郎当 鐵索郎當 +铁胃团 鐵胃團 +铁苏木 鐵蘇木 +铁路干线 鐵路幹線 +铁针 鐵針 +铁钟 鐵鐘 +铁铲 鐵鏟 +铁链 鐵鏈 +铁锤 鐵錘 +铁雕 鐵雕 +铁面 鐵面 +铁面判官 鐵面判官 +铁面御史 鐵面御史 +铁面无情 鐵面無情 +铁面无私 鐵面無私 +铃虫 鈴蟲 +铅制 鉛製 +铅字合金 鉛字合金 +铅板 鉛板 +铉台 鉉臺 +铜制 銅製 +铜制品 銅製品 +铜厂 銅廠 +铜叶 銅葉 +铜山西崩洛钟东应 銅山西崩洛鐘東應 +铜扣 銅釦 +铜斗儿 銅斗兒 +铜斗儿家缘 銅斗兒家緣 +铜板 銅板 +铜梁 銅梁 +铜梁县 銅梁縣 +铜琵铁板 銅琵鐵板 +铜范 銅範 +铜钟 銅鐘 +铜雀台 銅雀臺 +铜雕 銅雕 +铝制 鋁製 +铝制品 鋁製品 +铝合金 鋁合金 +铝板 鋁板 +铠胄 鎧冑 +铯钟 銫鐘 +铰链 鉸鏈 +铰链叶 鉸鏈葉 +铲下 剷下 +铲伤 剷傷 +铲倒 剷倒 +铲出 剷出 +铲凿 剷鑿 +铲刀 剷刀 +铲刈 剷刈 +铲土 剷土 +铲土机 鏟土機 +铲头 鏟頭 +铲子 鏟子 +铲射 剷射 +铲平 剷平 +铲抢 剷搶 +铲掉 剷掉 +铲斗 剷鬥 +铲断 剷斷 +铲板 剷板 +铲煤 剷煤 +铲球 剷球 +铲草 剷草 +铲起 剷起 +铲车 剷車 +铲运机 鏟運機 +铲运车 鏟運車 +铲铲 剷剷 +铲除 剷除 +铲雪 剷雪 +铲雪车 鏟雪車 +银丝卷 銀絲捲 +银价 銀價 +银制 銀製 +银发 銀髮 +银发产业 銀髮產業 +银发族 銀髮族 +银台 銀臺 +银合欢 銀合歡 +银团 銀團 +银本位制 銀本位制 +银朱 銀硃 +银杯 銀盃 銀杯 +银杯羽化 銀杯羽化 +银板 銀板 +银柜 銀櫃 +银核 銀核 +银河系 銀河系 +银纤维 銀纖維 +银色冲浪手 銀色衝浪手 +银行体系资金 銀行體系資金 +银行借款 銀行借款 +银行利害关系人 銀行利害關係人 +银行团 銀行團 +银行存折 銀行存摺 +银针 銀針 +银须 銀鬚 +铸币厂 鑄幣廠 +铸造出 鑄造出 +铸钟 鑄鐘 +铺了 鋪了 +铺伙 鋪夥 +铺出 鋪出 +铺出去 鋪出去 +铺出来 鋪出來 +铺向 鋪向 +铺地板 鋪地板 +铺板 鋪板 +铺盖卷儿 鋪蓋捲兒 +铺眉蒙眼 鋪眉蒙眼 +铺锦列绣 鋪錦列繡 +铺面 鋪面 +铺面临街房 鋪面臨街房 +铺面房 鋪面房 +链传动 鏈傳動 +链反应 鏈反應 +链坠 鍊墜 +链套 鏈套 +链子 鏈子 +链式 鏈式 +链式反应 鏈式反應 +链式裂变反应 鏈式裂變反應 +链形 鍊形 +链扣 鏈釦 +链接 鏈接 +链条 鏈條 +链椎 鏈椎 +链烃 鏈烴 +链环 鏈環 +链球 鏈球 +链球菌 鏈球菌 +链甲 鍊甲 +链罩 鏈罩 +链表 鏈表 +链路 鏈路 +链路层 鏈路層 +链轨 鏈軌 +链轮 鏈輪 +链钳子 鏈鉗子 +链锁 鏈鎖 +链锁反应 鏈鎖反應 +链锯 鏈鋸 +链霉素 鏈黴素 +销了 銷了 +销出 銷出 +销售价格 銷售價格 +销售时点情报系统 銷售時點情報系統 +销回 銷回 +销回去 銷回去 +销回来 銷回來 +销志 銷志 +销毁 銷燬 +销货折扣 銷貨折扣 +锁扣 鎖釦 +锁柜 鎖櫃 +锁链 鎖鏈 +锄奸 鋤奸 +锄铲 鋤鏟 +锅伙 鍋伙 +锅台 鍋臺 +锅庄 鍋莊 +锅烟 鍋煙 +锅烟子 鍋煙子 +锅铲 鍋鏟 +锆合金 鋯合金 +锈病 鏽病 +锈菌 鏽菌 +锈蚀 鏽蝕 +锋出 鋒出 +锋发韵流 鋒發韻流 +锋芒所向 鋒芒所向 +锋面 鋒面 +锋面雨 鋒面雨 +锌板 鋅板 +锐不可当 銳不可當 +锐志 銳志 +锐未可当 銳未可當 +锕系元素 錒系元素 +错不了 錯不了 +错了 錯了 +错了又错 錯了又錯 +错别字 錯別字 +错化合物 錯化合物 +错彩镂金 錯彩鏤金 +错综复杂 錯綜複雜 +错落有致 錯落有致 +错觉结合 錯覺結合 +错觉结合的词 錯覺結合的詞 +错误百出 錯誤百出 +错误的结合 錯誤的結合 +锚杆 錨杆 +锚虫 錨蟲 +锚链 錨鏈 +锚链孔 錨鏈孔 +锡克拜 錫克拜 +锡克教 錫克教 +锡克族 錫克族 +锡当河 錫當河 +锡杯 錫杯 +锤儿 錘兒 +锤头 錘頭 +锤子 錘子 +锤炼 錘鍊 +锥虫病 錐蟲病 +锥面 錐面 +锦囊佳制 錦囊佳製 +锦回文 錦迴文 +锦熏笼 錦熏籠 +锦绣 錦繡 +锦绣花园 錦繡花園 +锦胡同 錦衚衕 +锯了 鋸了 +锯了嘴的葫芦 鋸了嘴的葫蘆 +锯出 鋸出 +锯木厂 鋸木廠 +锲而不舍 鍥而不捨 +锹形虫 鍬形蟲 +锺万梅 鍾萬梅 +锺重发 鍾重發 +锺馗 鍾馗 +锻炼 鍛鍊 +锻炼出 鍛煉出 +锻炼身体 鍛鍊身體 +镁合金 鎂合金 +镂冰雕朽 鏤冰雕朽 +镂彩摛文 鏤彩摛文 +镂月裁云 鏤月裁雲 +镂金错采 鏤金錯采 +镇台 鎮臺 +镇宁布依族苗族自治县 鎮寧布依族苗族自治縣 +镇定药 鎮定藥 +镇痛药 鎮痛藥 +镇荣里 鎮榮里 +镇静药 鎮靜藥 +镍合金 鎳合金 +镕岩 鎔岩 +镜台 鏡臺 +镜框舞台 鏡框舞臺 +镜里孤鸾 鏡裏孤鸞 +镜鉴 鏡鑑 +镜面 鏡面 +镜面呢 鏡面呢 +镧系元素 鑭系元素 +镭射印表机 鐳射印表機 +镰仓 鎌倉 +镰形血球贫血症 鐮形血球貧血症 +镰状细胞血症 鐮狀細胞血症 +镶了 鑲了 +镶板 鑲板 +长丰 長豐 +长丰县 長豐縣 +长了 長了 +长于 長於 +长他人志气灭自己威风 長他人志氣滅自己威風 +长几 長几 +长出 長出 +长出来 長出來 +长卷 長卷 +长历 長曆 +长发 長髮 +长发屯 長發屯 +长发镇 長發鎮 +长叹 長嘆 +长吁 長吁 +长吁短叹 長吁短嘆 +长君之恶 長君之惡 +长头布 長頭布 +长寿烟 長壽菸 +长寿面 長壽麪 +长干巷 長干巷 +长干曲 長干曲 +长征 長征 +长征军 長征軍 +长恶不悛 長惡不悛 +长才 長才 +长春师范学院 長春師範學院 +长期借款 長期借款 +长板 長板 +长板凳 長板凳 +长林丰草 長林豐草 +长歌当哭 長歌當哭 +长江后浪 長江後浪 +长江后浪催前浪一代新人换旧人 長江後浪催前浪一代新人換舊人 +长烟 長煙 +长烟一空 長煙一空 +长生药 長生藥 +长程计划 長程計劃 +长绳系日 長繩繫日 +长绳系景 長繩繫景 +长胡 長鬍 +长虫 長蟲 +长谷 長谷 +长谷川 長谷川 +长辔远御 長轡遠御 +长针 長針 +长须 長鬚 +长须鲸 長鬚鯨 +长风万里 長風萬里 +開發周期 開發週期 +门前门后 門前門後 +门吊儿 門吊兒 +门帘 門簾 +门当户对 門當戶對 +门扣 門扣 +门拐 門拐 +门斗 門斗 +门板 門板 +门殚户尽 門殫戶盡 +门皁 門皁 +门胄 門胄 +门里 門裏 +门里人 門裏人 +门里出身 門裏出身 +门里安心 門裏安心 +门里门外 門裏門外 +门面 門面 +门面话 門面話 +闪了 閃了 +闪出 閃出 +闪含语系 閃含語系 +闪念 閃念 +闪电战术 閃電戰術 +闪闪发光 閃閃發光 +闫怀礼 閆懷禮 +闭一只眼 閉一隻眼 +闭卷 閉卷 +闭卷考 閉卷考 +闭卷考试 閉卷考試 +闭合 閉合 +闭合电路 閉合電路 +闭门家里坐祸从天上来 閉門家裏坐禍從天上來 +闭面 閉面 +问个 問個 +问个问题 問個問題 +问了 問了 +问出 問出 +问卜 問卜 +问卷 問卷 +问卷大调査 問卷大調查 +问卷调査 問卷調查 +问卷调査表 問卷調查表 +问当 問當 +问政于民 問政於民 +问舍求田 問舍求田 +问道于盲 問道於盲 +闯出 闖出 +闯出去 闖出去 +闯出来 闖出來 +闯炼 闖鍊 +闯荡 闖蕩 +闯荡江湖 闖蕩江湖 +闯进闯出 闖進闖出 +闲下来 閒下來 +闲不住 閒不住 +闲云孤鹤 閒雲孤鶴 +闲云野鹤 閒雲野鶴 +闲人免进 閒人免進 +闲余 閒餘 +闲庭信步 閒庭信步 +闲情逸致 閒情逸致 +闲情逸趣 閒情逸趣 +闲打牙儿 閒打牙兒 +闲扯淡 閒扯淡 +闲是闲非 閒是閒非 +闲杂人员 閒雜人員 +闲杂人等 閒雜人等 +闲来无事 閒來無事 +闲淘气 閒淘氣 +闲游 閒遊 +闲理会 閒理會 +闲盘儿 閒盤兒 +闲磕牙 閒磕牙 +闲篇儿 閒篇兒 +闲置不用 閒置不用 +闲聊天 閒聊天 +闲聒七 閒聒七 +闲花野草 閒花野草 +闲茶浪酒 閒茶浪酒 +闲荡 閒蕩 +闲言乱语 閒言亂語 +闲言碎语 閒言碎語 +闲言长语 閒言長語 +闲言闲事 閒言閒事 +闲言闲语 閒言閒語 +闲话家常 閒話家常 +闲话少说 閒話少說 +闲适 閒適 +闲邪存诚 閒邪存誠 +间不容发 間不容髮 +间充质干细胞 間充質幹細胞 +间出 間出 +间别 間別 +间叶干 間葉幹 +间奏曲 間奏曲 +间接证据 間接證據 +间深里 間深裏 +间里 間裏 +闵凶 閔凶 +闵子里 閔子裏 +闵采尔 閔采爾 +闷出 悶出 +闷在心里 悶在心裏 +闷板 悶板 +闷着头儿干 悶着頭兒幹 +闷表 悶錶 +闸板 閘板 +闹个 鬧個 +闹了半天鬼 鬧了半天鬼 +闹出 鬧出 +闹出去 鬧出去 +闹出来 鬧出來 +闹出笑话 鬧出笑話 +闹别扭 鬧彆扭 +闹台 鬧臺 +闹哄 鬧鬨 +闹哄哄 鬧哄哄 +闹拧了 鬧擰了 +闹着玩儿 鬧着玩兒 +闹表 鬧錶 +闹钟 鬧鐘 +闹铃时钟 鬧鈴時鐘 +闹饥荒 鬧饑荒 +闺范 閨範 +闻了 聞了 +闻出 聞出 +闻名于世 聞名於世 +闻风后 聞風後 +闽台 閩臺 +闽台地区 閩臺地區 +闾党姻娅 閭黨姻婭 +闾里 閭里 +阀杆 閥杆 +阃范 閫範 +阅兵台 閱兵臺 +阅卷 閱卷 +阅卷组 閱卷組 +阅历 閱歷 +阉党 閹黨 +阎云浚 閻雲浚 +阎王好见小鬼难当 閻王好見小鬼難當 +阎罗王面前须没放回的鬼 閻羅王面前須沒放回的鬼 +阐发 闡發 +阑尾切除术 闌尾切除術 +阑干 闌干 +阔别 闊別 +阔别多年 闊別多年 +阔叶林 闊葉林 +阔叶树 闊葉樹 +阙里 闕里 +阜新蒙古族自治县 阜新蒙古族自治縣 +阜阳师范学院 阜陽師範學院 +队别 隊別 +阡表 阡表 +阨困 阨困 +阮咸 阮咸 +防不胜防 防不勝防 +防个 防個 +防了 防了 +防人之口甚于防川 防人之口甚於防川 +防修 防修 +防制 防制 +防制法 防制法 +防卫过当 防衛過當 +防台 防颱 +防守战术 防守戰術 +防御 防禦 +防御力 防禦力 +防御工事 防禦工事 +防御性 防禦性 +防御战 防禦戰 +防御术 防禦術 +防御率 防禦率 +防御率王 防禦率王 +防御网 防禦網 +防患于未然 防患於未然 +防护团 防護團 +防护面具 防護面具 +防晒 防曬 +防毒斗篷 防毒斗篷 +防毒面具 防毒面具 +防民之口甚于防川 防民之口甚於防川 +防水布 防水布 +防水表 防水錶 +防滑链 防滑鏈 +防火布 防火布 +防火系统 防火系統 +防疫针 防疫針 +防秋 防秋 +防空识别区 防空識別區 +防范 防範 +防范体系 防範體系 +防范得宜 防範得宜 +防范意识 防範意識 +防范控制 防範控制 +防范措施 防範措施 +防范未然 防範未然 +防身术 防身術 +防锁死煞车系统 防鎖死煞車系統 +防锈 防鏽 +防雨布 防雨布 +阳历 陽曆 +阳历年 陽曆年 +阳台 陽臺 +阳台云雨 陽臺雲雨 +阳台春梦 陽臺春夢 +阳春面 陽春麪 +阳曲 陽曲 +阳曲县 陽曲縣 +阳极 陽極 +阳极射线 陽極射線 +阳极板 陽極板 +阳极泥 陽極泥 +阳电极 陽電極 +阳秋 陽秋 +阳虚发热 陽虛發熱 +阳谷 陽穀 陽谷 +阳谷县 陽穀縣 +阳谷穴 陽谷穴 +阳面 陽面 +阴丹布 陰丹布 +阴云 陰雲 +阴占 陰占 +阴历 陰曆 +阴历年 陰曆年 +阴山背后 陰山背後 +阴干 陰乾 +阴恶 陰惡 +阴暗 陰暗 +阴暗处 陰暗處 +阴暗面 陰暗面 +阴极 陰極 +阴极射线 陰極射線 +阴极管 陰極管 +阴核 陰核 +阴沈 陰沈 +阴沈沈 陰沈沈 +阴沟里翻船 陰溝裏翻船 +阴离子界面活性剂 陰離子界面活性劑 +阴胜则寒 陰勝則寒 +阴虚发热 陰虛發熱 +阴郁 陰鬱 +阴阳历 陰陽曆 +阴阳合历 陰陽合曆 +阴阴暗暗 陰陰暗暗 +阴阴沈沈 陰陰沈沈 +阴雕 陰雕 +阴面 陰面 +阵云 陣雲 +阵发性 陣發性 +阵线党 陣線黨 +阵面上 陣面上 +阶梯计价 階梯計價 +阶级斗争 階級鬥爭 +阻于 阻於 +阻修 阻修 +阻挡不了 阻擋不了 +阻止不了 阻止不了 +阿云 阿雲 +阿什克隆 阿什克隆 +阿仙药 阿仙藥 +阿信曲 阿信曲 +阿修罗 阿修羅 +阿修罗道 阿修羅道 +阿克伦 阿克倫 +阿克伦河 阿克倫河 +阿克塞县 阿克塞縣 +阿克塞哈萨克族自治县 阿克塞哈薩克族自治縣 +阿克拉 阿克拉 +阿克苏 阿克蘇 +阿克苏地区 阿克蘇地區 +阿克苏市 阿克蘇市 +阿克苏河 阿克蘇河 +阿克赛钦 阿克賽欽 +阿克达 阿克達 +阿克陶 阿克陶 +阿克陶县 阿克陶縣 +阿党 阿黨 +阿兹海默氏症 阿茲海默氏症 +阿兹海默症 阿茲海默症 +阿兹海默症病患 阿茲海默症病患 +阿列克西斯 阿列克西斯 +阿利托 阿利托 +阿加莎克里斯蒂 阿加莎克里斯蒂 +阿卜杜拉 阿卜杜拉 +阿卡提里 阿卡提里 +阿历山大 阿歷山大 +阿叶德 阿葉德 +阿合奇 阿合奇 +阿合奇县 阿合奇縣 +阿咸 阿咸 +阿奇里斯 阿奇里斯 +阿娘 阿孃 +阿尔发粒子 阿爾發粒子 +阿尔梅里亚 阿爾梅里亞 +阿尔汉格尔斯克州 阿爾漢格爾斯克州 +阿尔茨海默氏症 阿爾茨海默氏症 +阿尔茨海默症 阿爾茨海默症 +阿布 阿布 +阿布加 阿布加 +阿布叔醇 阿布叔醇 +阿布哈兹 阿布哈茲 +阿布尔 阿布爾 +阿布扎比 阿布扎比 +阿布扎比市 阿布扎比市 +阿布杜拉 阿布杜拉 +阿布杜拉曼 阿布杜拉曼 +阿布沙伊夫 阿布沙伊夫 +阿布沙耶夫 阿布沙耶夫 +阿布瑞 阿布瑞 +阿布瑞尤 阿布瑞尤 +阿布贝卡 阿布貝卡 +阿布贾 阿布賈 +阿布贾里布 阿布賈里布 +阿布达 阿布達 +阿布达比 阿布達比 +阿布雷尤 阿布雷尤 +阿弥陀佛 阿彌陀佛 +阿弥陀如来 阿彌陀如來 +阿弥陀经 阿彌陀經 +阿志 阿志 +阿意曲从 阿意曲從 +阿扎伦卡 阿紮倫卡 +阿扎尼亚 阿扎尼亞 +阿托品 阿托品 +阿拉伯共同市场 阿拉伯共同市場 +阿拉伯联合大公国 阿拉伯聯合大公國 +阿拉伯联合酋长国 阿拉伯聯合酋長國 +阿拉克 阿拉克 +阿拉干山脉 阿拉乾山脈 +阿斗 阿斗 +阿斯图里亚斯 阿斯圖里亞斯 +阿旺曲培 阿旺曲培 +阿旺曲沛 阿旺曲沛 +阿曼苏丹国 阿曼蘇丹國 +阿朱 阿朱 +阿杰 阿杰 +阿松森岛 阿松森島 +阿柏克兹亚 阿柏克茲亞 +阿森松岛 阿森松島 +阿波罗计划 阿波羅計劃 +阿滋海默症 阿滋海默症 +阿瓦里德 阿瓦里德 +阿秋 阿秋 +阿米巴原虫 阿米巴原蟲 +阿米纳达布 阿米納達布 +阿耳忒弥斯 阿耳忒彌斯 +阿胡斯 阿胡斯 +阿芝特克人 阿芝特剋人 +阿芝特克语 阿芝特剋語 +阿苏 阿蘇 +阿苏山 阿蘇山 +阿苏火山 阿蘇火山 +阿蒙 阿蒙 +阿谀苟合 阿諛苟合 +阿贾克斯 阿賈克斯 +阿赫蒂萨里 阿赫蒂薩裏 +阿里 阿里 +阿里亚斯 阿里亞斯 +阿里地区 阿里地區 +阿里山 阿里山 +阿里山之歌 阿里山之歌 +阿里山乡 阿里山鄉 +阿里山区 阿里山區 +阿里山山脉 阿里山山脈 +阿里巴巴 阿里巴巴 +阿里巴巴与四十大盗 阿里巴巴與四十大盜 +阿里斯托芬 阿里斯托芬 +阿里斯托芳 阿里斯託芳 +阿里曼 阿里曼 +阿里桑那 阿里桑那 +阿里郎 阿里郎 +附了 附了 +附于 附於 +附会假借 附會假借 +附加价值 附加價值 +附合 附合 +附录 附錄 +附注 附註 +附膻逐秽 附膻逐穢 +附膻逐腥 附膻逐腥 +附膻逐臭 附膻逐臭 +附致语 附致語 +附表 附表 +附面层 附面層 +际会风云 際會風雲 +陆丰 陸豐 +陆丰市 陸豐市 +陆云 陸雲 +陆云浩 陸雲浩 +陆克文 陸克文 +陆均松 陸均松 +陆征祥 陸徵祥 +陆梁 陸梁 +陆游 陸游 +陆讋水栗 陸讋水慄 +陆龟蒙 陸龜蒙 +陇种 隴種 +陈万松 陳萬松 +陈万立 陳萬立 +陈三五娘 陳三五娘 +陈世杰 陳世杰 +陈义丰 陳義豐 +陈云 陳雲 +陈云林 陳雲林 +陈云程 陳雲程 +陈俊杰 陳俊傑 +陈克帆 陳克帆 +陈冲 陳沖 +陈列台 陳列臺 +陈升 陳昇 +陈同海 陳同海 +陈后主 陳後主 +陈嘉爵沈培智 陳嘉爵沈培智 +陈尸 陳屍 +陈尹杰 陳尹杰 +陈布雷 陳布雷 +陈希同 陳希同 +陈幸 陳幸 +陈幸妤 陳幸妤 +陈幸嫚 陳倖嫚 +陈建志 陳建志 +陈志伟 陳志偉 +陈志勇 陳志勇 +陈志声 陳志聲 +陈志强 陳志強 +陈志忠 陳志忠 +陈志明 陳志明 +陈志玮 陳志瑋 +陈志维 陳志維 +陈志诚 陳志誠 +陈志豪 陳志豪 +陈志远 陳志遠 +陈志鸿 陳志鴻 +陈情表 陳情表 +陈木胜 陳木勝 +陈杰 陳杰 +陈永丰 陳永豐 +陈汉升 陳漢昇 +陈瀛钟 陳瀛鐘 +陈炼 陳鍊 +陈秋婷 陳秋婷 +陈秋扬 陳秋揚 +陈秋火 陳秋火 +陈胜 陳勝 +陈胜在 陳勝在 +陈胜宏 陳勝宏 +陈胜福 陳勝福 +陈致中 陳致中 +陈致远 陳致遠 +陈荣杰 陳榮傑 +陈谷子烂芝麻 陳穀子爛芝麻 +陈郁秀 陳郁秀 +陈隆志 陳隆志 +陈面谟 陳面謨 +陈鼎击钟 陳鼎擊鐘 +降了 降了 +降于 降於 +降价 降價 +降价出售 降價出售 +降价求售 降價求售 +降升调 降升調 +降压药 降壓藥 +降噪 降噪 +降回 降回 +降回到 降回到 +降回去 降回去 +降回来 降回來 +降志辱身 降志辱身 +降血压药 降血壓藥 +降血脂药 降血脂藥 +降表 降表 +限于 限於 +限价 限價 +限制 限制 +限制住 限制住 +限制住居 限制住居 +限制器 限制器 +限制式 限制式 +限制性 限制性 +限制是 限制是 +限制类 限制類 +限制级 限制級 +限制词 限制詞 +限制选举 限制選舉 +限制酶 限制酶 +限制酶图谱 限制酶圖譜 +限尽 限盡 +陕西师范大学 陝西師範大學 +陕飞集团 陝飛集團 +陡然升高 陡然升高 +院子里 院子裏 +院系 院系 +院里 院裏 +除不尽 除不盡 +除了 除了 +除奸 除奸 +除恶 除惡 +除恶务尽 除惡務盡 +除恶务本 除惡務本 +除恶扶善 除惡扶善 +除旧布新 除舊佈新 +除臭药 除臭藥 +除虫剂 除蟲劑 +除虫菊 除蟲菊 +陨获 隕穫 +险恶 險惡 +险症 險症 +险胜 險勝 +陪了 陪了 +陪出 陪出 +陪吊 陪弔 +陪同 陪同 +陪同到 陪同到 +陪审制 陪審制 +陪审制度 陪審制度 +陪审团 陪審團 +陵云 陵雲 +陵土未干 陵土未乾 +陵折 陵折 +陵谷 陵谷 +陶制 陶製 +陶土制品 陶土製品 +陶庵梦忆 陶庵夢憶 +陶朱公 陶朱公 +陶板屋 陶板屋 +陶菲克 陶菲克 +陷之死地而后生 陷之死地而後生 +陷于 陷於 +陷入困境 陷入困境 +隆乳手术 隆乳手術 +隆冬 隆冬 +隆准 隆準 +隆准许 隆准許 +隆回 隆回 +隆回县 隆回縣 +隆极 隆極 +隆河谷地 隆河谷地 +随之而后 隨之而後 +随于 隨於 +随口胡诌 隨口胡謅 +随同 隨同 +随后 隨後 +随后就到 隨後就到 +随后就去 隨後就去 +随后就来 隨後就來 +随心所欲 隨心所欲 +随想曲 隨想曲 +随才器使 隨才器使 +随时制宜 隨時制宜 +隐于 隱於 +隐修士 隱修士 +隐修院 隱修院 +隐几 隱几 +隐占 隱佔 +隐名合伙 隱名合夥 +隐形涂料 隱形塗料 +隐恶扬善 隱惡揚善 +隐暗 隱暗 +隐睪症 隱睪症 +隐翅虫 隱翅蟲 +隐身术 隱身術 +隔了 隔了 +隔出 隔出 +隔出来 隔出來 +隔别 隔別 +隔向 隔向 +隔周 隔週 +隔山观虎斗 隔山觀虎鬥 +隔年的皇历 隔年的皇曆 +隔年皇历 隔年皇曆 +隔房同辈 隔房同輩 +隔断板 隔斷板 +隔板 隔板 +隔热板 隔熱板 +隔舱板 隔艙板 +隔音板 隔音板 +隧道尽头的光亮 隧道盡頭的光亮 +隧道症 隧道症 +隶仆 隸僕 +隶属于 隸屬於 +难了 難了 +难于 難於 +难于上天 難於上天 +难于接近 難於接近 +难于登天 難於登天 +难以出口 難以出口 +难住了 難住了 +难偿所愿 難償所願 +难出 難出 +难出手心 難出手心 +难分难舍 難分難捨 +难割难舍 難割難捨 +难咽 難嚥 +难容于 難容於 +难当 難當 +难当重任 難當重任 +难得糊涂 難得糊塗 +难挨 難捱 +难控制 難控制 +难施面目 難施面目 +难易适中 難易適中 +难舍 難捨 +难舍难分 難捨難分 +难舍难离 難捨難離 +难荫 難廕 +雀噪 雀噪 +雁荡 雁蕩 +雁荡山 雁蕩山 +雄师百万 雄師百萬 +雄心万丈 雄心萬丈 +雄心壮志 雄心壯志 +雄才 雄才 +雄才大略 雄才大略 +雄据一方 雄據一方 +雄斗斗 雄斗斗 +雄胜 雄勝 +雅人深致 雅人深致 +雅克 雅克 +雅克萨 雅克薩 +雅库次克 雅庫次克 +雅游 雅游 +雅筑 雅筑 +雅致 雅緻 +雅舍 雅舍 +雅范 雅範 +雅鲁藏布 雅魯藏布 +雅鲁藏布大峡谷 雅魯藏布大峽谷 +雅鲁藏布江 雅魯藏布江 +集中托运 集中托運 +集了 集了 +集于 集於 +集于一身 集於一身 +集会游行法 集會遊行法 +集体强奸 集體強姦 +集合 集合 +集合令 集合令 +集合体 集合體 +集合到 集合到 +集合号 集合號 +集合名词 集合名詞 +集合地点 集合地點 +集合式 集合式 +集合时间 集合時間 +集合点 集合點 +集合论 集合論 +集合起来 集合起來 +集团 集團 +集团主义 集團主義 +集团军 集團軍 +集团案 集團案 +集团结婚 集團結婚 +集团股 集團股 +集录 集錄 +集注 集註 +集游法 集遊法 +集电极 集電極 +集训团 集訓團 +集资合建 集資合建 +雇主 僱主 +雇于 僱於 +雇人 僱人 +雇佣 僱傭 +雇农 僱農 +雇到 僱到 +雇员 僱員 +雇工 僱工 +雇用 僱用 +雌核 雌核 +雌雄同体 雌雄同體 +雌雄同体人 雌雄同體人 +雌雄同株 雌雄同株 +雍容闲雅 雍容閒雅 +雕丧 雕喪 +雕丽 雕麗 +雕云 雕雲 +雕像 雕像 +雕具座 鵰具座 +雕出 雕出 +雕凿 雕鑿 +雕刻 雕刻 +雕刻出 雕刻出 +雕刻刀 雕刻刀 +雕刻匠 雕刻匠 +雕刻品 雕刻品 +雕刻家 雕刻家 +雕刻师 雕刻師 +雕刻术 雕刻術 +雕刻画 雕刻畫 +雕励 雕勵 +雕啄 雕啄 +雕塑 雕塑 +雕塑品 雕塑品 +雕塑家 雕塑家 +雕墙 雕牆 +雕工 雕工 +雕弓 雕弓 +雕心雁爪 鵰心雁爪 +雕悍 鵰悍 +雕戈 雕戈 +雕成 雕成 +雕敝 雕敝 +雕板 雕板 +雕栏 雕欄 +雕梁 雕樑 +雕梁画柱 雕樑畫柱 +雕梁画栋 雕樑畫棟 +雕楹碧槛 雕楹碧檻 +雕残 雕殘 +雕漆 雕漆 +雕版 雕版 +雕版印刷 雕版印刷 +雕琢 雕琢 +雕瑑 雕瑑 +雕砌 雕砌 +雕空 雕空 +雕章缋句 雕章繢句 +雕章镂句 雕章鏤句 +雕簇 雕簇 +雕绘 雕繪 +雕翎 鵰翎 +雕翎扇 鵰翎扇 +雕肝琢肾 雕肝琢腎 +雕肝琢膂 雕肝琢膂 +雕肝镂肾 雕肝鏤腎 +雕胡米 雕胡米 +雕色 雕色 +雕花 雕花 +雕花漆彩 雕花漆彩 +雕虫 雕蟲 +雕虫小技 雕蟲小技 +雕虫小艺 雕蟲小藝 +雕虫篆 雕蟲篆 +雕虫篆刻 雕蟲篆刻 +雕蚶镂蛤 雕蚶鏤蛤 +雕谢 雕謝 +雕镂 雕鏤 +雕镌 雕鐫 +雕零 雕零 +雕青 雕青 +雕题 雕題 +雕飕 雕颼 +雕饰 雕飾 +雕饰品 雕飾品 +雕骚 雕騷 +雕鹗 鵰鶚 +雕龙 雕龍 +雨云 雨雲 +雨余芳草斜阳 雨餘芳草斜陽 +雨刮 雨刮 +雨后 雨後 +雨后春笋 雨後春筍 +雨层云 雨層雲 +雨布 雨布 +雨散云收 雨散雲收 +雨村曲话 雨村曲話 +雨泽下注 雨澤下注 +雨约云期 雨約雲期 +雨花台 雨花臺 +雨花台区 雨花臺區 +雨露均沾 雨露均霑 +雨魄云魂 雨魄雲魂 +雩坛 雩壇 +雪松 雪松 +雪板 雪板 +雪柜 雪櫃 +雪狮子向火 雪獅子向火 +雪窗萤几 雪窗螢几 +雪耻复国 雪恥復國 +雪耻报仇 雪恥報仇 +雪茄烟 雪茄煙 +雪里 雪裏 +雪里红 雪裏紅 +雪里蕻 雪裏蕻 +雪里送炭 雪裏送炭 +雪铲 雪鏟 +零个 零個 +零件厂 零件廠 +零余 零餘 +零余子 零餘子 +零只 零隻 +零周期 零週期 +零售价 零售價 +零售价格 零售價格 +零多只 零多隻 +零天后 零天後 +零布 零布 +零曲率 零曲率 +零系数 零係數 +雷云 雷雲 +雷克 雷克 +雷克南 雷克南 +雷克坦跑道 雷克坦跑道 +雷克斯 雷克斯 +雷克斯暴龙 雷克斯暴龍 +雷克萨斯 雷克薩斯 +雷克雅维克 雷克雅維克 +雷同 雷同 +雷夫范恩斯 雷夫范恩斯 +雷射血管成形术 雷射血管成形術 +雷德克里夫 雷德克里夫 +雷扎耶湖 雷扎耶湖 +雷文克劳 雷文克勞 +雷昂卡发洛 雷昂卡發洛 +雷神进行曲 雷神進行曲 +雷蒙 雷蒙 +雷蒙德 雷蒙德 +雷蒙德电 雷蒙德電 +雷贾帕克斯 雷賈帕克斯 +雷达搜索 雷達搜索 +雷雨云 雷雨雲 +雷霆万钧 雷霆萬鈞 +雷霆万钧之势 雷霆萬鈞之勢 +雷马克 雷馬克 +雾台 霧臺 +雾台乡 霧臺鄉 +雾蒙蒙 霧濛濛 +雾里 霧裏 +雾里看花 霧裏看花 +雾锁云埋 霧鎖雲埋 +需才孔亟 需才孔亟 +需求面 需求面 +需要是发明之母 需要是發明之母 +霁范 霽範 +霁范永存 霽範永存 +霄壤之别 霄壤之別 +震于 震於 +震天价响 震天價響 +震旦方向 震旦方向 +震栗 震慄 +震波曲线 震波曲線 +震源机制 震源機制 +震耳欲聋 震耳欲聾 +震荡 震盪 +震荡不安 震盪不安 +震荡性 震盪性 +霉干菜 黴乾菜 +霉毒 黴毒 +霉气冲天 黴氣沖天 +霉素 黴素 +霉菌 黴菌 +霉运当头 黴運當頭 +霉黑 黴黑 +霉黧 黴黧 +霍乱杆菌 霍亂桿菌 +霍克松 霍克松 +霍克海姆 霍克海姆 +霍尔布鲁克 霍爾布魯克 +霍布斯 霍布斯 +霍布森 霍布森 +霍普曼杯 霍普曼杯 +霍里 霍里 +霑体涂足 霑體塗足 +霓裳羽衣曲 霓裳羽衣曲 +霜叶 霜葉 +霞云 霞雲 +霞彩 霞彩 +霞表 霞表 +露丑 露醜 +露了 露了 +露出 露出 +露出了狐狸尾巴 露出了狐狸尾巴 +露出原形 露出原形 +露出去 露出去 +露出来 露出來 +露出破绽 露出破綻 +露出马脚 露出馬腳 +露台 露臺 +露台弟子 露臺弟子 +露复 露覆 +露天开采 露天開採 +露尸 露屍 +露布 露布 +露才 露才 +露才扬己 露才揚己 +露板 露板 +露营休闲车旅游 露營休閒車旅遊 +露面 露面 +露面抛头 露面拋頭 +霸占 霸佔 +霸占住 霸佔住 +霸才 霸才 +霸据 霸據 +霸术 霸術 +霸王别姬 霸王別姬 +霸陵折柳 霸陵折柳 +霹雳游侠 霹靂遊俠 +青云 青雲 +青云之器 青雲之器 +青云之士 青雲之士 +青云志 青雲志 +青云直上 青雲直上 +青云谱 青雲譜 +青云谱区 青雲譜區 +青出于蓝 青出於藍 +青出于蓝而胜于蓝 青出於藍而勝於藍 +青发 青發 +青叶 青葉 +青少年团 青少年團 +青山一发 青山一髮 +青帘 青帘 +青年党 青年黨 +青年团 青年團 +青年救国团 青年救國團 +青康滇纵谷高原 青康滇縱谷高原 +青杠 青槓 +青松 青松 +青果合作社 青果合作社 +青海师范大学 青海師範大學 +青灯黄卷 青燈黃卷 +青烟 青煙 +青瓦台 青瓦臺 +青石板 青石板 +青红皂白 青紅皁白 +青苹 青苹 +青苹果 青蘋果 +青虫 青蟲 +青蝇吊客 青蠅弔客 +青过于蓝 青過於藍 +青钱万选 青錢萬選 +青霉 青黴 +青霉素 青黴素 +青面獠牙 青面獠牙 +青鞋布袜 青鞋布襪 +靖康传信录 靖康傳信錄 +靖康要录 靖康要錄 +静以制动 靜以制動 +静修 靜修 +静极思动 靜極思動 +静脉曲张 靜脈曲張 +静脉注入 靜脈注入 +静脉注射 靜脈注射 +静脉血栓症 靜脈血栓症 +静舍 靜舍 +静荡荡 靜蕩蕩 +静配合 靜配合 +静默致哀 靜默致哀 +非于 非於 +非借不可 非借不可 +非党人士 非黨人士 +非党员 非黨員 +非出 非出 +非出不可 非出不可 +非占不可 非佔不可 +非发不可 非發不可 +非发光体 非發光體 +非合并 非合併 +非同 非同 +非同儿戏 非同兒戲 +非同容易 非同容易 +非同寻常 非同尋常 +非同小可 非同小可 +非同步 非同步 +非吸烟 非吸菸 +非层岩 非層巖 +非师范 非師範 +非师范类 非師範類 +非当 非當 +非当不可 非當不可 +非形象艺术 非形象藝術 +非意相干 非意相干 +非才 非才 +非据 非據 +非杠杆化 非槓桿化 +非标准 非標準 +非核 非核 +非欧几何 非歐幾何 +非欧几何学 非歐幾何學 +非法勾当 非法勾當 +非洲出血热 非洲出血熱 +非洲团结组织 非洲團結組織 +非洲大裂谷 非洲大裂谷 +非洲开发银行 非洲開發銀行 +非洲锥虫病 非洲錐蟲病 +非涂不可 非塗不可 +非游离辐射伤害 非游離輻射傷害 +非确定性 非確定性 +非种子 非種子 +非签不可 非簽不可 +非致命 非致命 +非营业支出 非營業支出 +非规范 非規範 +非词重复测验 非詞重復測驗 +非贸易创汇 非貿易創匯 +靠了 靠了 +靠前面 靠前面 +靠后 靠後 +靠后面 靠後面 +靠外面 靠外面 +靠外面走 靠外面走 +靠水面 靠水面 +靠里面 靠裏面 +靠里面走 靠裏面走 +靡不有初鲜克有终 靡不有初鮮克有終 +靡然向风 靡然向風 +面上 面上 +面上无光 面上無光 +面不改容 面不改容 +面不改色 面不改色 +面世 面世 +面临 面臨 +面临到 面臨到 +面临困难 面臨困難 +面交 面交 +面人 麪人 +面人儿 麪人兒 +面从 面從 +面价 麪價 +面会 面會 +面值 面值 +面儿 面兒 麪兒 +面允 面允 +面光 面光 +面具 面具 +面分 面分 +面刺 面刺 +面前 面前 +面包 麪包 +面包刀 麪包刀 +面包屑 麪包屑 +面包师 麪包師 +面包师傅 麪包師傅 +面包店 麪包店 +面包心 麪包心 +面包房 麪包房 +面包树 麪包樹 +面包渣 麪包渣 +面包片 麪包片 +面包皮 麪包皮 +面包粉 麪包粉 +面包花 麪包花 +面包车 麪包車 +面北 面北 +面北眉南 面北眉南 +面厂 麪廠 +面叙 面敘 +面向 面向 +面向对象的技术 面嚮對象的技術 +面向对象语言 面嚮對象語言 +面向连接 面向連接 +面君 面君 +面听 面聽 +面呈 面呈 +面告 面告 +面命耳提 面命耳提 +面商 面商 +面善 面善 +面善心恶 面善心惡 +面善心狠 面善心狠 +面嘱 面囑 +面嘴 面嘴 +面团 麪糰 +面团团 面團團 +面圆耳大 面圓耳大 +面圣 面聖 +面坊 麪坊 +面坯儿 麪坯兒 +面型 面型 +面垢 面垢 +面塑 麪塑 +面墙 面牆 +面墙而立 面牆而立 +面壁 面壁 +面壁下帷 面壁下帷 +面壁功深 面壁功深 +面壁坐禅 面壁坐禪 +面壁思过 面壁思過 +面奏 面奏 +面如 面如 +面如傅粉 面如傅粉 +面如冠玉 面如冠玉 +面如噀血 面如噀血 +面如土色 面如土色 +面如敷粉 面如敷粉 +面如桃花 面如桃花 +面如槁木 面如槁木 +面如死灰 面如死灰 +面如灰土 面如灰土 +面如白纸 面如白紙 +面如白蜡 面如白蠟 +面如美玉 面如美玉 +面如重枣 面如重棗 +面如金纸 面如金紙 +面如铁色 面如鐵色 +面嫩 面嫩 +面子 面子 +面子上 面子上 +面子上的人 面子上的人 +面子上的差使 面子上的差使 +面子上的话 面子上的話 +面子情儿 面子情兒 +面子药 麪子藥 +面子话 面子話 +面孔 面孔 +面容 面容 +面宽 面寬 +面对 面對 +面对现实 面對現實 +面对面 面對面 +面尘 面塵 +面山 面山 +面巾 面巾 +面市 面市 +面带 面帶 +面带微笑 面帶微笑 +面带忧容 面帶憂容 +面带愁容 面帶愁容 +面带病容 面帶病容 +面带笑容 面帶笑容 +面店 麪店 +面庞 面龐 +面弱 面弱 +面形 面形 +面影 面影 +面心立方最密堆积 面心立方最密堆積 +面恶 面惡 +面恶心善 面惡心善 +面情 面情 +面折 面折 +面折廷争 面折廷爭 +面授 面授 +面授机宜 面授機宜 +面摊 麪攤 +面摊子 麪攤子 +面数 面數 +面料 面料 +面斥 面斥 +面方口阔 面方口闊 +面旋 面旋 +面无 面無 +面无人色 面無人色 +面无血色 面無血色 +面无表情 面無表情 +面晤 面晤 +面月印记 面月印記 +面有 面有 +面有喜色 面有喜色 +面有忧色 面有憂色 +面有菜色 面有菜色 +面有难色 面有難色 +面朋 面朋 +面朝 面朝 +面杖 麪杖 +面杖吹火 麪杖吹火 +面条 麪條 +面条儿 麪條兒 +面条目 麪條目 +面板 面板 +面板厂 面板廠 +面板股 面板股 +面染 面染 +面桌 面桌 +面條目 面條目 +面水 面水 +面汤 麪湯 +面泛 面泛 +面洽 面洽 +面浆 麪漿 +面海 面海 +面灰 麪灰 +面点 麪點 +面点师 麪點師 +面点王 麪點王 +面熟 面熟 +面版 面版 +面甜 面甜 +面生 面生 +面生不熟 面生不熟 +面疔 面疔 +面疙瘩 麪疙瘩 +面疱 面皰 +面白无须 面白無鬚 +面皂 面皂 +面皮 麪皮 +面皮厚 面皮厚 +面皮失色 面皮失色 +面皮焦黄 面皮焦黃 +面皮薄 面皮薄 +面皮铁青 面皮鐵青 +面盆 面盆 +面盘 面盤 +面目 面目 +面目一新 面目一新 +面目全非 面目全非 +面目可憎 面目可憎 +面目清秀 面目清秀 +面目狰狞 面目猙獰 +面目黄瘦 面目黃瘦 +面相 面相 +面码儿 麪碼兒 +面碗 麪碗 +面票 麪票 +面禀 面稟 +面积 面積 +面积分 面積分 +面筋 麪筋 +面粉 麪粉 +面粉袋 麪粉袋 +面糊 麪糊 +面红 面紅 +面红耳热 面紅耳熱 +面红耳赤 面紅耳赤 +面红过耳 面紅過耳 +面红面赤 面紅面赤 +面纱 面紗 +面纸 面紙 +面缚 面縛 +面缚舆榇 面縛輿櫬 +面缚衔璧 面縛銜璧 +面缸 麪缸 +面罄 面罄 +面罩 面罩 +面肥 麪肥 +面膜 面膜 +面致 面致 +面般 面般 +面色 面色 +面色发白 面色發白 +面色如土 面色如土 +面色如生 面色如生 +面色如金纸 面色如金紙 +面色苍白 面色蒼白 +面若春花 面若春花 +面茶 麪茶 +面薄 面薄 +面薄腰纤 面薄腰纖 +面衣 面衣 +面西 面西 +面见 面見 +面见江东 面見江東 +面誉 面譽 +面誉背毁 面譽背譭 +面议 面議 +面试 面試 +面试会 面試會 +面试官 面試官 +面试工作 面試工作 +面请 面請 +面谀 面諛 +面谈 面談 +面谒 面謁 +面谕 面諭 +面谢 面謝 +面貌 面貌 +面貌一新 面貌一新 +面貌全非 面貌全非 +面质 面質 +面辞 面辭 +面邀 面邀 +面部 面部 +面部表情 面部表情 +面酱 麪醬 +面重 面重 +面门 面門 +面阔口方 面闊口方 +面陈 面陳 +面霜 面霜 +面露不悦 面露不悅 +面霸 麪霸 +面青唇白 面青脣白 +面面 面面 +面面俱全 面面俱全 +面面俱到 面面俱到 +面面俱圆 面面俱圓 +面面厮觑 面面廝覷 +面面相窥 面面相窺 +面面相觑 面面相覷 +面面观 面面觀 +面靥 面靨 +面颊 面頰 +面颜 面顏 +面额 面額 +面食 麪食 +面食类 麪食類 +面饰 面飾 +面饺 麪餃 +面饼 麪餅 +面馆 麪館 +面首 面首 +面驾 面駕 +面黄 面黃 +面黄唇白 面黃脣白 +面黄肌瘦 面黃肌瘦 +面黄肌闳 面黃肌閎 +革出 革出 +革出山门 革出山門 +革出教门 革出教門 +革制品 革製品 +革命党 革命黨 +革命党人 革命黨人 +革命发展 革命發展 +革命发展阶段论 革命發展階段論 +革命干劲 革命幹勁 +革命意志 革命意志 +革命斗志 革命鬥志 +革命积极 革命積極 +革命积极性 革命積極性 +革面 革面 +革面洗心 革面洗心 +靴后跟 靴後跟 +靶台 靶臺 +靶台上 靶臺上 +鞋厂 鞋廠 +鞋扣 鞋釦 +鞋柜 鞋櫃 +鞋里 鞋裏 +鞋面 鞋面 +鞠躬尽力 鞠躬盡力 +鞠躬尽悴 鞠躬盡悴 +鞠躬尽瘁 鞠躬盡瘁 +鞠躬尽瘁死而后已 鞠躬盡瘁死而後已 +鞣制 鞣製 +鞭尸 鞭屍 +鞭毛虫 鞭毛蟲 +鞭虫 鞭蟲 +鞭辟入里 鞭辟入裏 +鞭辟近里 鞭辟近裏 +韦后 韋后 +韦娘 韋娘 +韦布 韋布 +韦布匹夫 韋布匹夫 +韦布斯特 韋布斯特 +韦庄 韋莊 +韦陟朵云 韋陟朵雲 +韧皮纤维 韌皮纖維 +韩侂胄 韓侂冑 +韩信登坛 韓信登壇 +韩制 韓製 +韩升洙 韓昇洙 +韩国制 韓國製 +韩国联合通讯社 韓國聯合通訊社 +韩复矩 韓復榘 +韩宗志 韓宗志 +韩山师范学院 韓山師範學院 +韩巴里 韓巴里 +韩干 韓幹 +韩干画马 韓幹畫馬 +韩幸霖 韓幸霖 +韩康卖药 韓康賣藥 +韩彩英 韓彩英 +韩海苏潮 韓海蘇潮 +韩立克 韓立克 +韩蒙德 韓蒙德 +韫椟待价 韞櫝待價 +韬戈卷甲 韜戈卷甲 +音乐台 音樂臺 +音乐团 音樂團 +音乐系 音樂系 +音像制品 音像製品 +音准 音準 +音同 音同 +音声如钟 音聲如鐘 +音系 音系 +韵致 韻致 +韶山冲 韶山沖 +韶钢松山 韶鋼松山 +頁面 頁面 +页岩 頁岩 +页面 頁面 +顶个 頂個 +顶了 頂了 +顶凶 頂兇 +顶叶 頂葉 +顶回 頂回 +顶回去 頂回去 +顶回来 頂回來 +顶多 頂多 +顶夸克 頂夸克 +顶板 頂板 +顶核 頂核 +顶梁柱 頂樑柱 +顶梁骨走了真魂 頂梁骨走了真魂 +顶针 頂針 +顶针儿 頂針兒 +顶针挨住 頂針捱住 +顶门针 頂門針 +顶面 頂面 +项别骓 項別騅 +项庄 項莊 +项庄舞剑志在沛公 項莊舞劍志在沛公 +项梁 項梁 +项目表 項目表 +项链 項鍊 +顺于 順於 +顺发 順發 +顺向 順向 +顺当 順當 +顺德者吉逆天者凶 順德者吉逆天者凶 +顺时针 順時針 +顺时钟 順時鐘 +顺朱儿 順硃兒 +顺河回族区 順河回族區 +顺适 順適 +顺钟向 順鐘向 +顺风后 順風後 +须不是 須不是 +须发 鬚髮 +须发展 須發展 +须发文 須發文 +须发皆白 鬚髮皆白 +须发表 須發表 +须后水 鬚後水 +须子 鬚子 +须将有日思无日 須將有日思無日 +须弥 須彌 +须弥山 須彌山 +须弥座 須彌座 +须待 須待 +须得 須得 +须捷 須捷 +须是 須是 +须根 鬚根 +须根据 須根據 +须毛 鬚毛 +须然 須然 +须生 鬚生 +须用 須用 +须留 須留 +须眉 鬚眉 +须知 須知 +须索 須索 +须胡 鬚鬍 +须至 須至 +须臾 須臾 +须菩堤 須菩堤 +须虑 須慮 +须要 須要 +须陀洹 須陀洹 +须须 鬚鬚 +须髯 鬚髯 +须髯如戟 鬚髯如戟 +须鲨 鬚鯊 +须鲸 鬚鯨 +顽卤 頑鹵 +顽症 頑症 +顽童历险记 頑童歷險記 +顽筑舞笈 頑筑舞笈 +顽蒙 頑蒙 +顾不了 顧不了 +顾借 顧藉 +顾前不顾后 顧前不顧後 +顾前顾后 顧前顧後 +顾后瞻前 顧後瞻前 +顾复之恩 顧復之恩 +顾念 顧念 +顾曲 顧曲 +顾曲周郎 顧曲周郎 +顾正秋 顧正秋 +顾问团 顧問團 +顾面子 顧面子 +顾颜面 顧顏面 +顿了 頓了 +顿涅斯克 頓涅斯克 +顿涅茨克 頓涅茨克 +颁出 頒出 +颁发 頒發 +颁发奖品 頒發獎品 +颁发奖杯 頒發獎盃 +颁发奖牌 頒發獎牌 +颁发奖状 頒發獎狀 +颁发奖金 頒發獎金 +颁奖台 頒獎臺 +颁布 頒佈 +颂系 頌繫 +颂赞 頌讚 +预借 預借 +预制 預製 +预制构件 預製構件 +预卜 預卜 +预后 預後 +预征 預徵 +预想出 預想出 +预托证券 預託證券 +预扣 預扣 +预料出 預料出 +预期收入票据 預期收入票據 +预测出 預測出 +预算表 預算表 +预警系统 預警系統 +预防接种 預防接種 +预防注射 預防注射 +预防针 預防針 +颅盖內出血 顱蓋內出血 +颅顶叶 顱頂葉 +领出 領出 +领出去 領出去 +领出来 領出來 +领台 領檯 +领回 領回 +领回去 領回去 +领回来 領回來 +领域里 領域裏 +领导制度 領導制度 +领导干部 領導幹部 +领带针 領帶針 +领悟出 領悟出 +领扣 領釦 +领据 領據 +领略出 領略出 +领表 領表 +领表格 領表格 +领袖欲 領袖慾 +颇复 頗覆 +颇欲 頗欲 +颈链 頸鍊 +颊面 頰面 +颊须 頰鬚 +频危物种 頻危物種 +频数分布 頻數分佈 +频率合成 頻率合成 +频率调制 頻率調製 +颖脱而出 穎脫而出 +题个 題個 +题了 題了 +题名录 題名錄 +题库系统 題庫系統 +题材范围 題材範圍 +题材面 題材面 +题签 題簽 +颛制 顓制 +颛蒙 顓蒙 +颜回 顏回 +颜志麟 顏志麟 +颜范 顏範 +颜面 顏面 +颜面扫地 顏面掃地 +颜面神经 顏面神經 +颜面角 顏面角 +颜面骨 顏面骨 +额发 額髮 +额征 額徵 +额我略历 額我略曆 +额我略历史 額我略歷史 +额贺福志郎 額賀福志郎 +额面 額面 +颟里颟顸 顢里顢頇 +颠乾倒坤 顛乾倒坤 +颠仆 顛仆 +颠倒乾坤 顛倒乾坤 +颠儿面 顛兒面 +颠复 顛覆 +颠复性 顛覆性 +颠番面皮 顛番面皮 +颠覆 顛覆 +颠连困苦 顛連困苦 +颠颠仆仆 顛顛仆仆 +颤栗 顫慄 +風采 風采 +风举云摇 風舉雲搖 +风云 風雲 +风云不测 風雲不測 +风云之志 風雲之志 +风云人物 風雲人物 +风云人物奖 風雲人物獎 +风云变幻 風雲變幻 +风云变态 風雲變態 +风云变色 風雲變色 +风云叱咤 風雲叱吒 +风云开阖 風雲開闔 +风云感会 風雲感會 +风云月露 風雲月露 +风云气候 風雲氣候 +风云突变 風雲突變 +风云车 風雲車 +风云际会 風雲際會 +风从虎云从龙 風從虎雲從龍 +风入松 風入松 +风兴云蒸 風興雲蒸 +风刮 風颳 +风力发电 風力發電 +风卷 風捲 +风卷残云 風捲殘雲 +风发 風發 +风后 風后 +风向 風向 +风向器 風向器 +风向标 風向標 +风向球 風向球 +风向袋 風向袋 +风向针 風向針 +风吹两面倒 風吹兩面倒 +风吹砂子迷了眼 風吹砂子迷了眼 +风团 風團 +风土志 風土誌 +风在那里起雨在那里落 風在那裏起雨在那裏落 +风尘仆仆 風塵僕僕 +风尘恶俗 風塵惡俗 +风尘表物 風塵表物 +风干 風乾 +风干机 風乾機 +风情万种 風情萬種 +风成砂岩 風成砂岩 +风扫落叶 風掃落葉 +风斗 風斗 +风月宝鉴 風月寶鑑 +风水术 風水術 +风流云散 風流雲散 +风流别致 風流別致 +风流千古 風流千古 +风流才子 風流才子 +风流标致 風流標致 +风流蕴借 風流蘊藉 +风流酝借 風流醞藉 +风浪板 風浪板 +风湿症 風溼症 +风溼性心脏病 風溼性心臟病 +风烟 風煙 +风物志 風物誌 +风胡子 風胡子 +风致 風致 +风范 風範 +风药 風藥 +风虎云龙 風虎雲龍 +风起云布 風起雲布 +风起云涌 風起雲湧 +风起云蒸 風起雲蒸 +风轻云淡 風輕雲淡 +风轻云淨 風輕雲淨 +风速表 風速表 +风采 風采 +风采堂堂 風采堂堂 +风里 風裏 +风里杨花 風裏楊花 +风里言 風裏言 +风里语 風裏語 +风铲 風鏟 +风险与收益的关系 風險與收益的關係 +风险防范 風險防範 +风雨同舟 風雨同舟 +风雨欲来 風雨欲來 +风靡云涌 風靡雲湧 +风靡云蒸 風靡雲蒸 +风飞云会 風飛雲會 +风马云车 風馬雲車 +风马牛不相干 風馬牛不相干 +风驰电卷 風馳電卷 +飘出 飄出 +飘向 飄向 +飘回 飄回 +飘摆 飄擺 +飘游 飄遊 +飘游四海 飄遊四海 +飘然出世 飄然出世 +飘荡 飄蕩 +飘飘欲仙 飄飄欲仙 +飘飘荡荡 飄飄蕩蕩 +飙升 飆升 +飙发电举 飆發電舉 +飞个 飛個 +飞了 飛了 +飞云 飛雲 +飞云掣电 飛雲掣電 +飞出 飛出 +飞出个未来 飛出個未來 +飞出去 飛出去 +飞出来 飛出來 +飞刍挽粒 飛芻輓粒 +飞刍挽粟 飛芻輓粟 +飞刍挽粮 飛芻輓糧 +飞升 飛昇 +飞向 飛向 +飞回 飛回 +飞回去 飛回去 +飞回来 飛回來 +飞征 飛征 +飞必冲天 飛必沖天 +飞扎 飛紮 +飞梁 飛樑 +飞烟传 飛煙傳 +飞燕游龙 飛燕游龍 +飞粮挽秣 飛糧輓秣 +飞腾之药 飛騰之藥 +飞航资料记录器 飛航資料記錄器 +飞虫 飛蟲 +飞蚊症 飛蚊症 +飞行云 飛行雲 +飞行甲板 飛行甲板 +飞行记录 飛行記錄 +飞行记录仪 飛行記錄儀 +飞行记录器 飛行記錄器 +飞行钟 飛行鐘 +飞谷 飛谷 +飞车党 飛車黨 +飞针走线 飛針走線 +飞铲 飛鏟 +飞鸟尽良弓藏 飛鳥盡良弓藏 +飞龙乘云 飛龍乘雲 +食不下咽 食不下咽 +食不充饥 食不充飢 +食不糊口 食不餬口 +食品厂 食品廠 +食品药品监督局 食品藥品監督局 +食品药品监督管理局 食品藥品監督管理局 +食心虫 食心蟲 +食日万钱 食日萬錢 +食欲 食慾 +食欲不佳 食慾不佳 +食欲不振 食慾不振 +食物及药品管理局 食物及藥品管理局 +食物柜 食物櫃 +食物链 食物鏈 +食用蜡烛木 食用蠟燭木 +食虫植物 食蟲植物 +食虫目 食蟲目 +食虫虻 食蟲虻 +食货志 食貨志 +食野之苹 食野之苹 +食面 食麪 +飮胄 飮冑 +餍于游乐 饜於游樂 +餐台 餐檯 +餐松啖柏 餐松啖柏 +餐松食柏 餐松食柏 +餐松饮涧 餐松飲澗 +饥不可食寒不可衣 飢不可食寒不可衣 +饥不择食 飢不擇食 +饥冻交切 飢凍交切 +饥困 飢困 +饥寒 飢寒 +饥寒交切 飢寒交切 +饥寒交迫 飢寒交迫 +饥年 饑年 +饥民 饑民 +饥渴 飢渴 +饥渴交攻 飢渴交攻 +饥渴交迫 飢渴交迫 +饥溺 飢溺 +饥火 飢火 +饥火中焚 飢火中焚 +饥火烧肠 飢火燒腸 +饥者易为食 飢者易爲食 +饥者甘糟糠 飢者甘糟糠 +饥肠 飢腸 +饥肠辘辘 飢腸轆轆 +饥色 飢色 +饥荒 饑荒 +饥虎扑食 飢虎撲食 +饥附饱飏 飢附飽颺 +饥餐渴饮 飢餐渴飲 +饥饱 飢飽 +饥饿 飢餓 +饥饿三十 飢餓三十 +饥饿感 飢餓感 +饥馁 飢餒 +饥馑 饑饉 +饥馑之岁 饑饉之歲 +饥馑荐臻 饑饉薦臻 +饥鹰饿虎 飢鷹餓虎 +饬回 飭回 +饭后 飯後 +饭后服用 飯後服用 +饭后漱口 飯後漱口 +饭后百步走 飯後百步走 +饭后钟 飯後鐘 +饭团 飯糰 +饭庄 飯莊 +饭店回葱 飯店回蔥 +饭店里买葱 飯店裏買蔥 +饭饱生余事 飯飽生餘事 +饮弹自尽 飲彈自盡 +饮杯 飲杯 +饮水曲肱 飲水曲肱 +饯别 餞別 +饰扣 飾釦 +饰板 飾板 +饰面 飾面 +饱人不知饿人饥 飽人不知餓人飢 +饱合 飽合 +饱和化合物 飽和化合物 +饱学秀才 飽學秀才 +饱尝 飽嘗 飽嚐 +饱当知人饥 飽當知人飢 +饱暖思淫欲 飽暖思淫慾 +饱暖生淫欲 飽暖生淫慾 +饱汉不知饿汉饥 飽漢不知餓漢飢 +饲养标准 飼養標準 +饲喂 飼餵 +饶舌歌曲 饒舌歌曲 +饼干 餅乾 +饼干店 餅乾店 +饼干盒 餅乾盒 +饿死了 餓死了 +饿殍枕借 餓殍枕藉 +饿虎饥鹰 餓虎飢鷹 +馂余 餕餘 +馄饨面 餛飩麪 +馆舍 館舍 +馆谷 館穀 +馆里 館裏 +馆际互借 館際互借 +馋涎欲垂 饞涎欲垂 +馋涎欲滴 饞涎欲滴 +首丘夙愿 首丘夙願 +首发 首發 +首只 首隻 +首台 首臺 +首尔 首爾 +首席代表 首席代表 +首开纪录 首開紀錄 +首当 首當 +首当其冲 首當其衝 +首恶 首惡 +首部曲 首部曲 +首都师范大学 首都師範大學 +首都杯 首都盃 +首长制 首長制 +首面 首面 +首须 首須 +香干 香乾 +香愿 香願 +香斗 香斗 +香格里拉 香格里拉 +香格里拉县 香格裏拉縣 +香格里拉怡咖啡 香格里拉怡咖啡 +香榭丽舍 香榭麗舍 +香榭丽舍大街 香榭麗舍大街 +香榭里大道 香榭里大道 +香港工会联合会 香港工會聯合會 +香港游 香港遊 +香港电台 香港電臺 +香港贸易发展局 香港貿易發展局 +香烟 香菸 +香烟不绝 香煙不絕 +香烟后代 香煙後代 +香烟头 香菸頭 +香烟盒 香菸盒 +香熏 香薰 +香熏疗法 香薰療法 +香皂 香皂 +香菜叶 香菜葉 +香蜡 香蠟 +香蜡店 香蠟店 +香蜡纸马 香蠟紙馬 +香蜡铺 香蠟鋪 +香郁 香郁 +馥郁 馥郁 +馬占山 馬占山 +馬格里布 馬格里布 +马丁尼克 馬丁尼克 +马丁杜里荷 馬丁杜里荷 +马云 馬雲 +马修连恩 馬修連恩 +马修麦费狄恩 馬修麥費狄恩 +马克 馬克 +马克吐温 馬克吐溫 +马克安东尼 馬克安東尼 +马克安诺 馬克安諾 +马克思 馬克思 +马克思主义 馬克思主義 +马克思列宁主义 馬克思列寧主義 +马克数 馬克數 +马克斯 馬克斯 +马克斯主义 馬克斯主義 +马克斯威尔 馬克斯威爾 +马克斯普朗克 馬克斯普朗克 +马克杯 馬克杯 +马克沁 馬克沁 +马克沁机枪 馬克沁機槍 +马克笔 馬克筆 +马克西米连 馬克西米連 +马利布 馬利布 +马占山 馬占山 +马厂 馬廠 +马厝卡舞曲 馬厝卡舞曲 +马可波罗游记 馬可波羅遊記 +马台 馬臺 +马吊 馬吊 +马后 馬後 +马后炮 馬後炮 +马后砲 馬後砲 +马后练服 馬后練服 +马噶尔尼使团 馬噶爾尼使團 +马太受难曲 馬太受難曲 +马夫 馬伕 +马头娘 馬頭娘 +马尔克奥雷利 馬爾克奧雷利 +马尔扎赫 馬爾扎赫 +马尔谷 馬爾谷 +马尼托巴 馬尼托巴 +马尾松 馬尾松 +马布 馬布 +马布瑞 馬布瑞 +马干 馬乾 +马德里 馬德里 +马德里队 馬德里隊 +马志英 馬志英 +马戏团 馬戲團 +马戏团表演 馬戲團表演 +马戏表演 馬戲表演 +马戛尔尼使团 馬戛爾尼使團 +马扎 馬紮 +马扎尔 馬扎爾 +马扎尔语 馬扎爾語 +马托格罗索 馬託格羅索 +马拉巴栗 馬拉巴栗 +马拉松 馬拉松 +马拉松式 馬拉松式 +马拉松组 馬拉松組 +马拉松赛 馬拉松賽 +马拉松赛跑 馬拉松賽跑 +马提尼克 馬提尼克 +马斯垂克 馬斯垂剋 +马斯垂克条约 馬斯垂克條約 +马斯特里赫特 馬斯特裏赫特 +马普托 馬普托 +马术 馬術 +马术赛 馬術賽 +马朱罗 馬朱羅 +马杆 馬杆 +马来亚玻里尼西亚语系 馬來亞玻里尼西亞語系 +马杰明 馬傑明 +马格里布 馬格里布 +马桶里 馬桶裏 +马死黄金尽 馬死黃金盡 +马致远 馬致遠 +马苏 馬蘇 +马苏德 馬蘇德 +马苏里拉 馬蘇裏拉 +马表 馬錶 +马车夫 馬車伕 +马里亚纳 馬里亞納 +马里亚纳海沟 馬裏亞納海溝 +马里亚纳群岛 馬里亞納羣島 +马里克 馬里克 +马里兰 馬里蘭 +马里兰州 馬里蘭州 +马里内斯科 馬里內斯科 +马里奇 馬里奇 +马里奥 馬里奧 +马里安纳海沟 馬里安納海溝 +马里布 馬里布 +马里斯 馬里斯 +马面 馬面 +马面战棚 馬面戰棚 +马革裹尸 馬革裹屍 +马鬣松 馬鬣松 +驭兽术 馭獸術 +驭夫有术 馭夫有術 +驱出 驅出 +驱恶向善 驅惡向善 +驱虫 驅蟲 +驱虫剂 驅蟲劑 +驱虫效率 驅蟲效率 +驱逐出 驅逐出 +驱逐出境 驅逐出境 +驳回 駁回 +驳回去 駁回去 +驳回来 駁回來 +驳面子 駁面子 +驴前马后 驢前馬後 +驴蒙虎皮 驢蒙虎皮 +驶出 駛出 +驶向 駛向 +驶回 駛回 +驻台 駐臺 +驻扎 駐紮 +驻扎地 駐紮地 +驻车制动 駐車制動 +驻颜有术 駐顏有術 +驽马十舍 駑馬十舍 +驾了 駕了 +驾云 駕雲 +驾回 駕回 +驾回去 駕回去 +驾回来 駕回來 +驾娘 駕娘 +驾御 駕御 +驾雾腾云 駕霧騰雲 +驾鹤西游 駕鶴西遊 +骀借 駘藉 +骀荡 駘蕩 +骂个 罵個 +骂了 罵了 +骋凶骋势 騁兇騁勢 +骋志 騁志 +验出 驗出 +验尸 驗屍 +验尸官 驗屍官 +验收规范 驗收規範 +验核 驗覈 +骏业宏发 駿業宏發 +骏发 駿發 +骏豪集团 駿豪集團 +骏马雕鞍 駿馬雕鞍 +骑了 騎了 +骑兵团 騎兵團 +骑出 騎出 +骑出去 騎出去 +骑出来 騎出來 +骑回 騎回 +骑回去 騎回去 +骑回来 騎回來 +骑士团 騎士團 +骑术 騎術 +骗不了 騙不了 +骗了 騙了 +骗人布 騙人布 +骗出 騙出 +骗出去 騙出去 +骗出来 騙出來 +骗回 騙回 +骗回去 騙回去 +骗回来 騙回來 +骗拐 騙拐 +骗术 騙術 +骗术奇谭 騙術奇譚 +骨坛 骨罈 +骨头里挣出来的钱才做得肉 骨頭裏掙出來的錢纔做得肉 +骨子里 骨子裏 +骨子里头 骨子裏頭 +骨岩岩 骨巖巖 +骨干 骨幹 +骨干分子 骨幹分子 +骨干网路 骨幹網路 +骨折 骨折 +骨灰坛 骨灰罈 +骨肉团圆 骨肉團圓 +骨肉团聚 骨肉團聚 +骨肉团𪢮 骨肉團圞 +骨质疏松 骨質疏鬆 +骨质疏松症 骨質疏鬆症 +骨质石化症 骨質石化症 +骨质软化症 骨質軟化症 +骨里骨碌 骨裏骨碌 +骨针 骨針 +骺软骨板 骺軟骨板 +骾朴 骾朴 +髀肉复生 髀肉復生 +高个 高個 +高个儿 高個兒 +高个子 高個子 +高丽参 高麗蔘 +高了 高了 +高于 高於 +高云 高雲 +高价 高價 +高价位 高價位 +高价股 高價股 +高几 高几 +高出 高出 +高升 高升 +高参 高參 +高发 高發 +高台 高臺 +高台县 高臺縣 +高周波 高週波 +高唱入云 高唱入雲 +高坛 高壇 +高处不胜寒 高處不勝寒 +高学历 高學歷 +高尔基复合体 高爾基複合體 +高尔察克 高爾察克 +高层云 高層雲 +高层建筑 高層建築 +高山症 高山症 +高岸深谷 高岸深谷 +高干 高幹 +高干扰 高干擾 +高干预 高干預 +高度自制 高度自制 +高度表 高度表 +高志尚 高志尚 +高志纲 高志綱 +高志航 高志航 +高志鹏 高志鵬 +高性价 高性價 +高手如云 高手如雲 +高才 高才 +高才生 高才生 +高技术 高技術 +高抬身价 高擡身價 +高挂 高掛 +高政升 高政昇 +高杆 高杆 +高杠 高槓 +高柏松 高柏松 +高标准 高標準 +高梁 高梁 +高梁川 高梁川 +高梁市 高梁市 +高梁米 高梁米 +高梁酒 高梁酒 +高歌一曲 高歌一曲 +高步云衢 高步雲衢 +高水准 高水準 +高清愿 高清愿 +高球杯 高球杯 +高票当选 高票當選 +高积云 高積雲 +高等师范 高等師範 +高筋面粉 高筋麪粉 +高纤 高纖 +高纤维 高纖維 +高级管理人才 高級管理人才 +高耸入云 高聳入雲 +高胄 高胄 +高能烈性炸药 高能烈性炸藥 +高脂血症 高脂血症 +高脚杯 高腳杯 +高致病性 高致病性 +高致病性禽 高致病性禽 +高良姜 高良薑 +高英杰 高英傑 +高血压症 高血壓症 +高血压药 高血壓藥 +高血脂症 高血脂症 +高跳台 高跳臺 +高郁淨 高郁淨 +髡发 髡髮 +髭胡 髭鬍 +髭须 髭鬚 +髯胡 髯鬍 +髹饰录 髹飾錄 +髼松 髼鬆 +鬅松 鬅鬆 +鬈发 鬈髮 +鬈曲 鬈曲 +鬒发 鬒髮 +鬓云 鬢雲 +鬓发 鬢髮 +鬓发如银 鬢髮如銀 +鬓发皆白 鬢髮皆白 +鬓发皓然 鬢髮皓然 +鬼出电入 鬼出電入 +鬼录 鬼錄 +鬼怕恶人 鬼怕惡人 +鬼才 鬼才 +鬼气冲天 鬼氣沖天 +鬼片当道 鬼片當道 +鬼胡油 鬼胡油 +鬼胡由 鬼胡由 +鬼谷子 鬼谷子 +鬼迷了张天师 鬼迷了張天師 +鬼针草 鬼針草 +鬼门上占卦 鬼門上占卦 +魁人党 魁人黨 +魁北克 魁北克 +魁北克市 魁北克市 +魁北克省 魁北克省 +魂不守舍 魂不守舍 +魂牵梦系 魂牽夢繫 +魏克 魏克 +魏克菲尔 魏克菲爾 +魏台复 魏臺復 +魏幸雄 魏幸雄 +魏征 魏徵 +魏斯里史奈普 魏斯里史奈普 +魏明谷 魏明谷 +魏郁奇 魏郁奇 +魔仆 魔僕 +魔合罗 魔合羅 +魔术 魔術 +魔术家 魔術家 +魔术师 魔術師 +魔术数字 魔術數字 +魔术方块 魔術方塊 +魔术棒 魔術棒 +魔术秀 魔術秀 +魔术蛇 魔術蛇 +魔术贴 魔術貼 +魔术队 魔術隊 +魔板 魔板 +魔表 魔錶 +魔赛克 魔賽克 +鰂魚涌 鰂魚涌 +鱼丸粗面 魚丸粗麪 +鱼台 魚臺 +鱼台县 魚臺縣 +鱼头参政 魚頭參政 +鱼尾板 魚尾板 +鱼干 魚乾 +鱼松 魚鬆 +鱼板 魚板 +鱼梁 魚梁 +鱼沈雁杳 魚沈雁杳 +鱼游釜中 魚游釜中 +鱼游釜底 魚游釜底 +鱼种 魚種 +鱼篮宝卷 魚籃寶卷 +鱼肉乡里 魚肉鄉里 +鱼胄 魚冑 +鱼虫 魚蟲 +鱼贯而出 魚貫而出 +鱼鳞松 魚鱗松 +鱼鼓简板 魚鼓簡板 +鲁克 魯克 +鲁克斯 魯克斯 +鲁毕克方块 魯畢克方塊 +鲁般手里调大斧 魯般手裏調大斧 +鲁适维 魯適維 +鲇鱼 鮎魚 +鲋鱼困涸辙难待西江水 鮒魚困涸轍難待西江水 +鲍德里亚 鮑德里亞 +鲜于 鮮于 +鲜彩 鮮彩 +鲜明个性 鮮明個性 +鲜胄 鮮胄 +鲜血淋漓 鮮血淋漓 +鲜谷王 鮮穀王 +鲸蜡 鯨蠟 +鲸须 鯨鬚 +鳃叶 鰓葉 +鳌头独占 鰲頭獨佔 +鳌里夺尊 鰲裏奪尊 +鳝鱼面 鱔魚麪 +鳞叶 鱗葉 +鳞游 鱗游 +鳞虫 鱗蟲 +鳣舍 鱣舍 +鸟卜 鳥卜 +鸟尽弓藏 鳥盡弓藏 +鸟松 鳥松 +鸟松乡 鳥松鄉 +鸟虫书 鳥蟲書 +鸟里鸟气 鳥裏鳥氣 +鸟面鹄形 鳥面鵠形 +鸠占鹊巢 鳩佔鵲巢 +鸠合 鳩合 +鸠形鹄面 鳩形鵠面 +鸡丝 雞絲 +鸡丝面 雞絲麪 +鸡争鹅斗 雞爭鵝鬥 +鸡兔同笼 雞兔同籠 +鸡口牛后 雞口牛後 +鸡只 雞隻 +鸡同鸭讲 雞同鴨講 +鸡吵鹅斗 雞吵鵝鬥 +鸡奸 雞姦 +鸡尸牛从 雞尸牛從 +鸡犬俱升 雞犬俱升 +鸡犬升天 雞犬升天 +鸡犬识新丰 雞犬識新豐 +鸡皮栗子 雞皮栗子 +鸡皮鹤发 雞皮鶴髮 +鸡肤鹤发 雞膚鶴髮 +鸡腿面 雞腿麪 +鸡舍 雞舍 +鸡虫得失 雞蟲得失 +鸡蛋里挑骨头 雞蛋裏挑骨頭 +鸡蛋面 雞蛋麪 +鸣咽 鳴咽 +鸣榔板 鳴榔板 +鸣钟 鳴鐘 +鸣钟列鼎 鳴鐘列鼎 +鸦片烟 鴉片煙 +鸦窝里出凤凰 鴉窩裏出鳳凰 +鸭子划水 鴨子划水 +鸭跖草 鴨跖草 +鸳鸯折颈 鴛鴦折頸 +鸷虫 鷙蟲 +鸿志 鴻志 +鸿案相庄 鴻案相莊 +鸿篇巨制 鴻篇鉅製 +鸿篇巨著 鴻篇鉅著 +鸿胄 鴻胄 +鸿范 鴻範 +鸿蒙 鴻蒙 +鸿运当头 鴻運當頭 +鸿鹄之志 鴻鵠之志 +鸿鹄大志 鴻鵠大志 +鹄发 鵠髮 +鹄志 鵠志 +鹄面 鵠面 +鹄面鸟形 鵠面鳥形 +鹄面鸠形 鵠面鳩形 +鹅准 鵝準 +鹊噪 鵲噪 +鹊巢鸠占 鵲巢鳩佔 +鹍鸡曲 鵾雞曲 +鹏程万里 鵬程萬里 +鹘仑吞枣 鶻崙吞棗 +鹤发 鶴髮 +鹤发童颜 鶴髮童顏 +鹤吊 鶴弔 +鹤板 鶴板 +鹤骨松姿 鶴骨松姿 +鹰嘴豆面粉 鷹嘴豆麪粉 +鹰扬万里 鷹揚萬里 +鹰架栈台 鷹架棧臺 +鹰雕 鷹鵰 +鹿台 鹿臺 +鹿谷 鹿谷 +鹿谷乡 鹿谷鄉 +鹿车共挽 鹿車共挽 +鹿门采药 鹿門采藥 +麟台 麟臺 +麟游 麟遊 +麟游县 麟遊縣 +麟种 麟種 +麦个子 麥個子 +麦克 麥克 +麦克伦堡 麥克倫堡 +麦克尼尔 麥克尼爾 +麦克拉伦 麥克拉倫 +麦克斯 麥克斯 +麦克斯韦 麥克斯韋 +麦克林 麥克林 +麦克林登 麥克林登 +麦克格雷格 麥克格雷格 +麦克白 麥克白 +麦克白夫人 麥克白夫人 +麦克米兰 麥克米蘭 +麦克维 麥克維 +麦克罗尼西亚人 麥克羅尼西亞人 +麦克贝 麥克貝 +麦克连 麥克連 +麦克道格拉斯 麥克道格拉斯 +麦克阿瑟 麥克阿瑟 +麦克雷兰 麥克雷蘭 +麦克雷兰说 麥克雷蘭說 +麦克风 麥克風 +麦冬 麥冬 +麦卡托 麥卡托 +麦可杰克森 麥可傑克森 +麦可维克 麥可維克 +麦布莱 麥布萊 +麦当乐 麥當樂 +麦当劳 麥當勞 +麦当劳叔叔 麥當勞叔叔 +麦当娜 麥當娜 +麦托姆 麥托姆 +麦格里 麥格里 +麦特克 麥特克 +麦特戴蒙 麥特戴蒙 +麦秋 麥秋 +麦科里 麥科里 +麦穗 麥穗 +麦穗两歧 麥穗兩歧 +麦考马克 麥考馬克 +麦考马克说 麥考馬克說 +麦达克斯 麥達克斯 +麸曲 麩曲 +麸皮面包 麩皮麪包 +麻了花儿 麻了花兒 +麻做一团 麻做一團 +麻叶皮 麻葉皮 +麻吉死党 麻吉死黨 +麻团 麻團 +麻姑仙坛记 麻姑仙壇記 +麻婆子的裹脚布 麻婆子的裹腳布 +麻布 麻布 +麻布袋 麻布袋 +麻杆 麻桿 +麻栗坡 麻栗坡 +麻栗坡县 麻栗坡縣 +麻油厂 麻油廠 +麻涌 麻涌 +麻痹不了 麻痹不了 +麻痺不了 麻痺不了 +麻胡 麻胡 +麻药 麻藥 +麻酱面 麻醬麪 +麻醉药 麻醉藥 +麻醉药品 麻醉藥品 +麻醉针 麻醉針 +麻雀在后 麻雀在後 +麻雀虽小五脏俱全 麻雀雖小五臟俱全 +麾之即去招则须来 麾之即去招則須來 +黃鈺筑 黃鈺筑 +黃长发 黃長發 +黄上丰 黃上豐 +黄世杰 黃世傑 +黄东梁 黃東樑 +黄了 黃了 +黄仁杰 黃仁傑 +黄仕杰 黃仕傑 +黄俊杰 黃俊杰 +黄克强 黃克強 +黄凤秋 黃鳳秋 +黄卷 黃卷 +黄卷青灯 黃卷青燈 +黄历 黃曆 +黄发 黃髮 +黄发儿齿 黃髮兒齒 +黄发垂髫 黃髮垂髫 +黄发鲐背 黃髮鮐背 +黄同纸 黃同紙 +黄嘉千 黃嘉千 +黄天荡 黃天蕩 +黄山谷 黃山谷 +黄岩 黃岩 +黄岩区 黃巖區 +黄岩岛 黃巖島 +黄州寒食诗卷 黃州寒食詩卷 +黄干黑瘦 黃乾黑瘦 +黄志中 黃志中 +黄志伟 黃志偉 +黄志勇 黃志勇 +黄志强 黃志強 +黄志成 黃志成 +黄志玮 黃志瑋 +黄志芳 黃志芳 +黄志雄 黃志雄 +黄志鹏 黃志鵬 +黄志龙 黃志龍 +黄旭升 黃旭昇 +黄明志 黃明志 +黄曲毒素 黃麴毒素 +黄曲霉 黃麴黴 +黄曲霉毒素 黃麴黴毒素 +黄曲霉菌 黃麴黴菌 +黄有才 黃有才 +黄松 黃松 +黄梁 黃梁 +黄梁梦 黃梁夢 +黄梁美梦 黃樑美夢 +黄毛团儿 黃毛團兒 +黄沙盖面 黃沙蓋面 +黄河大合唱 黃河大合唱 +黄炎贵胄 黃炎貴胄 +黄珮筑 黃珮筑 +黄白之术 黃白之術 +黄石大峡谷 黃石大峽谷 +黄石瀑布 黃石瀑布 +黄秋庆 黃秋慶 +黄秋燕 黃秋燕 +黄秋生 黃秋生 +黄秋葵 黃秋葵 +黄种 黃種 +黄种人 黃種人 +黄老治术 黃老治術 +黄育杰 黃育杰 +黄色人种 黃色人種 +黄色炸药 黃色炸藥 +黄花后生 黃花後生 +黄英杰 黃英傑 +黄莺出谷 黃鶯出谷 +黄菓树瀑布 黃菓樹瀑布 +黄蜡 黃蠟 +黄蝶翠谷 黃蝶翠谷 +黄表纸 黃表紙 +黄运杰 黃運傑 +黄适卓 黃適卓 +黄道周 黃道周 +黄郁涵 黃郁涵 +黄郁茹 黃郁茹 +黄金入柜 黃金入櫃 +黄金台 黃金臺 +黄金周 黃金週 +黄金存折 黃金存摺 +黄金表 黃金錶 +黄钟 黃鐘 +黄钟大吕 黃鐘大呂 +黄钟毁弃 黃鐘譭棄 +黄钟长弃 黃鐘長棄 +黄钰筑 黃鈺筑 +黄雀在后 黃雀在後 +黄须 黃鬚 +黄鹰抓住了鹞子的脚 黃鷹抓住了鷂子的腳 +黉舍 黌舍 +黍谷生春 黍谷生春 +黎明前的黑暗 黎明前的黑暗 +黎曼几何 黎曼幾何 +黎曼几何学 黎曼幾何學 +黎曼曲面 黎曼曲面 +黎曼面 黎曼面 +黎涌 黎涌 +黏了 黏了 +黏合 黏合 +黏合剂 黏合劑 +黏合力 黏合力 +黏合成 黏合成 +黑不溜秋 黑不溜秋 +黑了 黑了 +黑云 黑雲 +黑云母 黑雲母 +黑亮发 黑亮髮 +黑克索斯 黑克索斯 +黑加仑 黑加侖 +黑发 黑髮 +黑发人 黑髮人 +黑头虫 黑頭蟲 +黑奴吁天录 黑奴籲天錄 +黑尿症 黑尿症 +黑布 黑布 +黑手党 黑手黨 +黑暗 黑暗 +黑暗世界 黑暗世界 +黑暗大陆 黑暗大陸 +黑暗时代 黑暗時代 +黑暗期 黑暗期 +黑暗面 黑暗面 +黑曜岩 黑曜岩 +黑杰克 黑傑克 +黑松 黑松 +黑松汽水 黑松汽水 +黑松沙士 黑松沙士 +黑板 黑板 +黑板报 黑板報 +黑板擦 黑板擦 +黑板树 黑板樹 +黑气冲天 黑氣沖天 +黑沈沈 黑沈沈 +黑漆一团 黑漆一團 +黑漆板凳 黑漆板凳 +黑烟 黑煙 +黑种 黑種 +黑种人 黑種人 +黑穗病 黑穗病 +黑胡椒 黑胡椒 +黑色棘皮症 黑色棘皮症 +黑色火药 黑色火藥 +黑色系 黑色系 +黑豹党 黑豹黨 +黑醋栗 黑醋栗 +黑里 黑裏 +黑面 黑麪 +黑面包 黑麪包 +黑面琵鹭 黑面琵鷺 +黑须 黑鬚 +黔南布依族苗族自治州 黔南布依族苗族自治州 +黔西南布依族苗族自治州 黔西南布依族苗族自治州 +默克 默克 +默克尔 默克爾 +默哀致意 默哀致意 +默多克 默多克 +默念 默唸 +黛粉叶 黛粉葉 +黝暗 黝暗 +黥布 黥布 +黥面 黥面 +黮暗 黮闇 +黯然欲绝 黯然欲絕 +鼇头独占 鼇頭獨占 +鼎折足 鼎折足 +鼎泰丰 鼎泰豐 +鼎食鸣钟 鼎食鳴鐘 +鼓不打不响钟不撞不鸣 鼓不打不響鐘不撞不鳴 +鼓出 鼓出 +鼓出来 鼓出來 +鼓台 鼓臺 +鼓噪 鼓譟 +鼓子曲 鼓子曲 +鼓板 鼓板 +鼓盆之戚 鼓盆之戚 +鼓腹而游 鼓腹而遊 +鼓荡 鼓盪 +鼓足干劲 鼓足幹勁 +鼓里 鼓裏 +鼓面 鼓面 +鼠得克 鼠得克 +鼠曲草 鼠麴草 +鼠疫杆菌 鼠疫桿菌 +鼠肝虫臂 鼠肝蟲臂 +鼠药 鼠藥 +鼠面人 鼠面人 +鼻中出火 鼻中出火 +鼻准 鼻準 +鼻出血 鼻出血 +鼻咽 鼻咽 +鼻头出火 鼻頭出火 +鼻子上挂鲞鱼 鼻子上掛鯗魚 +鼻子里笑 鼻子裏笑 +鼻无梁柱 鼻無梁柱 +鼻梁 鼻樑 +鼻梁儿 鼻樑兒 +鼻梁骨 鼻樑骨 +鼻烟 鼻菸 +鼻烟壶 鼻菸壺 +鼻烟盒 鼻菸盒 +鼻针疗法 鼻針療法 +齐克果 齊克果 +齐克隆 齊克隆 +齐出 齊出 +齐发 齊發 +齐发式 齊發式 +齐名并价 齊名並價 +齐后破环 齊后破環 +齐头并进 齊頭並進 +齐姜 齊姜 +齐庄 齊莊 +齐心合力 齊心合力 +齐心同力 齊心同力 +齐心并力 齊心併力 +齐打伙儿 齊打夥兒 +齐梁世界 齊梁世界 +齐梁体 齊梁體 +齐民要术 齊民要術 +齐烟九点 齊煙九點 +齐王舍牛 齊王捨牛 +齐足并驰 齊足並馳 +齐足并驱 齊足並驅 +齐驱并驾 齊驅並駕 +齐驱并骤 齊驅並驟 +齧合 齧合 +齧蘗吞针 齧蘗吞針 +齿危发秀 齒危髮秀 +齿发 齒髮 +齿录 齒錄 +齿条千斤顶 齒條千斤頂 +齿胄 齒胄 +齿落发白 齒落髮白 +龄虫 齡蟲 +龙争虎斗 龍爭虎鬥 +龙凤之表 龍鳳之表 +龙利叶 龍利葉 +龙卷 龍捲 +龙卷风 龍捲風 +龙发堂 龍發堂 +龙团 龍團 +龙困浅滩 龍困淺灘 +龙岩 龍巖 +龙岩市 龍巖市 +龙岩村 龍巖村 +龙嵩叶 龍嵩葉 +龙斗虎伤 龍鬥虎傷 +龙无云而不行 龍無雲而不行 +龙游 龍游 +龙游县 龍游縣 +龙游浅水 龍游淺水 +龙烟铁矿 龍煙鐵礦 +龙眼干 龍眼乾 +龙种 龍種 +龙胄 龍胄 +龙胜县 龍勝縣 +龙虎并伏 龍虎並伏 +龙虎斗 龍虎鬥 +龙虾面 龍蝦麪 +龙里 龍里 +龙里县 龍里縣 +龙钟 龍鍾 +龙门吊 龍門吊 +龙须 龍鬚 +龙须友 龍鬚友 +龙须沟 龍鬚溝 +龙须茶 龍鬚茶 +龙须草 龍鬚草 +龙须菜 龍鬚菜 +龙须面 龍鬚麪 +龙龛手鉴 龍龕手鑑 +龚照胜 龔照勝 +龚胜 龔勝 +龟卜 龜卜 +龟鉴 龜鑑 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TSCharacters.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TSCharacters.txt new file mode 100644 index 0000000000000000000000000000000000000000..5dc2b2b1855efe22eb7360da119ab7a564aea8a7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TSCharacters.txt @@ -0,0 +1,4014 @@ +㑮 𫝈 +㑯 㑔 +㑳 㑇 +㑶 㐹 +㒓 𠉂 +㓄 𪠟 +㓨 刾 +㔋 𪟎 +㖮 𪠵 +㗲 𠵾 +㗿 𪡛 +㘉 𠰱 +㘓 𪢌 +㘔 𫬐 +㘚 㘎 +㛝 𫝦 +㜄 㚯 +㜏 㛣 +㜐 𫝧 +㜗 𡞋 +㜢 𡞱 +㜷 𡝠 +㞞 𪨊 +㟺 𪩇 +㠏 㟆 +㢗 𪪑 +㢝 𢋈 +㥮 㤘 +㦎 𢛯 +㦛 𢗓 +㦞 𪫷 +㨻 𪮃 +㩋 𪮋 +㩜 㨫 +㩳 㧐 +㩵 擜 +㪎 𪯋 +㯤 𣘐 +㰙 𣗙 +㵗 𣳆 +㵾 𪷍 +㶆 𫞛 +㷍 𤆢 +㷿 𤈷 +㸇 𤎺 +㹽 𫞣 +㺏 𤠋 +㺜 𪺻 +㻶 𪼋 +㿖 𪽮 +㿗 𤻊 +㿧 𤽯 +䀉 𥁢 +䀹 𥅴 +䁪 𥇢 +䁻 䀥 +䂎 𥎝 +䃮 鿎 +䅐 𫀨 +䅳 𫀬 +䆉 𫁂 +䉑 𫁲 +䉙 𥬀 +䉬 𫂈 +䉲 𥮜 +䉶 𫁷 +䊭 𥺅 +䊷 䌶 +䊺 𫄚 +䋃 𫄜 +䋔 𫄞 +䋙 䌺 +䋚 䌻 +䋦 𫄩 +䋹 䌿 +䋻 䌾 +䋼 𫄮 +䋿 𦈓 +䌈 𦈖 +䌋 𦈘 +䌖 𦈜 +䌝 𦈟 +䌟 𦈞 +䌥 𦈠 +䌰 𦈙 +䍤 𫅅 +䍦 䍠 +䍽 𦍠 +䎙 𫅭 +䎱 䎬 +䕤 𫟕 +䕳 𦰴 +䖅 𫟑 +䗅 𫊪 +䗿 𧉞 +䙔 𫋲 +䙡 䙌 +䙱 𧜭 +䚩 𫌯 +䛄 𫍠 +䛳 𫍫 +䜀 䜧 +䜖 𫟢 +䝭 𫎧 +䝻 𧹕 +䝼 䞍 +䞈 𧹑 +䞋 𫎪 +䞓 𫎭 +䟃 𫎺 +䟆 𫎳 +䟐 𫎱 +䠆 𫏃 +䠱 𨅛 +䡐 𫟤 +䡩 𫟥 +䡵 𫟦 +䢨 𨑹 +䤤 𫟺 +䥄 𫠀 +䥇 䦂 +䥑 鿏 +䥗 𫔋 +䥩 𨱖 +䥯 𫔆 +䥱 䥾 +䦘 𨸄 +䦛 䦶 +䦟 䦷 +䦯 𫔵 +䦳 𨷿 +䧢 𨸟 +䪊 𫖅 +䪏 𩏼 +䪗 𩐀 +䪘 𩏿 +䪴 𫖫 +䪾 𫖬 +䫀 𫖱 +䫂 𫖰 +䫟 𫖲 +䫴 𩖗 +䫶 𫖺 +䫻 𫗇 +䫾 𫠈 +䬓 𫗊 +䬘 𩙮 +䬝 𩙯 +䬞 𩙧 +䬧 𫗟 +䭀 𩠇 +䭃 𩠈 +䭑 𫗱 +䭔 𫗰 +䭿 𩧭 +䮄 𫠊 +䮝 𩧰 +䮞 𩨁 +䮠 𩧿 +䮫 𩨇 +䮰 𫘮 +䮳 𩨏 +䮾 𩧪 +䯀 䯅 +䯤 𩩈 +䰾 鲃 +䱀 𫚐 +䱁 𫚏 +䱙 𩾈 +䱧 𫚠 +䱬 𩾊 +䱰 𩾋 +䱷 䲣 +䱸 𫠑 +䱽 䲝 +䲁 鳚 +䲅 𫚜 +䲖 𩾂 +䲘 鳤 +䲰 𪉂 +䳜 𫛬 +䳢 𫛰 +䳤 𫛮 +䳧 𫛺 +䳫 𫛼 +䴉 鹮 +䴋 𫜅 +䴬 𪎈 +䴱 𫜒 +䴴 𪎋 +䴽 𫜔 +䵳 𪑅 +䵴 𫜙 +䶕 𫜨 +䶲 𫜳 +丟 丢 +並 并 +乾 干 乾 +亂 乱 +亙 亘 +亞 亚 +佇 伫 +佈 布 +佔 占 +併 并 +來 来 +侖 仑 +侶 侣 +侷 局 +俁 俣 +係 系 +俓 𠇹 +俔 伣 +俠 侠 +俥 伡 +俬 私 +倀 伥 +倆 俩 +倈 俫 +倉 仓 +個 个 +們 们 +倖 幸 +倫 伦 +倲 㑈 +偉 伟 +偑 㐽 +側 侧 +偵 侦 +偽 伪 +傌 㐷 +傑 杰 +傖 伧 +傘 伞 +備 备 +傢 家 +傭 佣 +傯 偬 +傳 传 +傴 伛 +債 债 +傷 伤 +傾 倾 +僂 偻 +僅 仅 +僉 佥 +僑 侨 +僕 仆 +僞 伪 +僥 侥 +僨 偾 +僱 雇 +價 价 +儀 仪 +儁 俊 +儂 侬 +億 亿 +儈 侩 +儉 俭 +儎 傤 +儐 傧 +儔 俦 +儕 侪 +儘 尽 侭 +償 偿 +儣 𠆲 +優 优 +儭 𠋆 +儲 储 +儷 俪 +儸 㑩 +儺 傩 +儻 傥 +儼 俨 +兇 凶 +兌 兑 +兒 儿 +兗 兖 +內 内 +兩 两 +冊 册 +冑 胄 +冪 幂 +凈 净 +凍 冻 +凙 𪞝 +凜 凛 +凱 凯 +別 别 +刪 删 +剄 刭 +則 则 +剋 克 +剎 刹 +剗 刬 +剛 刚 +剝 剥 +剮 剐 +剴 剀 +創 创 +剷 铲 +剾 𠛅 +劃 划 㓰 +劇 剧 +劉 刘 +劊 刽 +劌 刿 +劍 剑 +劏 㓥 +劑 剂 +劚 㔉 +勁 劲 +勑 𠡠 +動 动 +務 务 +勛 勋 +勝 胜 +勞 劳 +勢 势 +勣 𪟝 +勩 勚 +勱 劢 +勳 勋 +勵 励 +勸 劝 +勻 匀 +匭 匦 +匯 汇 +匱 匮 +區 区 +協 协 +卹 恤 +卻 却 +卽 即 +厙 厍 +厠 厕 +厤 历 +厭 厌 +厲 厉 +厴 厣 +參 参 +叄 叁 +叢 丛 +吒 咤 +吳 吴 +吶 呐 +呂 吕 +咼 呙 +員 员 +哯 𠯟 +唄 呗 +唓 𪠳 +唸 念 +問 问 +啓 启 +啞 哑 +啟 启 +啢 唡 +喎 㖞 +喚 唤 +喪 丧 +喫 吃 +喬 乔 +單 单 +喲 哟 +嗆 呛 +嗇 啬 +嗊 唝 +嗎 吗 +嗚 呜 +嗩 唢 +嗰 𠮶 +嗶 哔 +嗹 𪡏 +嘆 叹 +嘍 喽 +嘓 啯 +嘔 呕 +嘖 啧 +嘗 尝 +嘜 唛 +嘩 哗 +嘪 𪡃 +嘮 唠 +嘯 啸 +嘰 叽 +嘳 𪡞 +嘵 哓 +嘸 呒 +嘺 𪡀 +嘽 啴 +噁 恶 +噅 𠯠 +噓 嘘 +噚 㖊 +噝 咝 +噞 𪡋 +噠 哒 +噥 哝 +噦 哕 +噯 嗳 +噲 哙 +噴 喷 +噸 吨 +噹 当 𪠽 +嚀 咛 +嚇 吓 +嚌 哜 +嚐 尝 +嚕 噜 +嚙 啮 +嚛 𪠸 +嚥 咽 +嚦 呖 +嚧 𠰷 +嚨 咙 +嚮 向 +嚲 亸 +嚳 喾 +嚴 严 +嚶 嘤 +嚽 𪢕 +囀 啭 +囁 嗫 +囂 嚣 +囃 𠱞 +囅 冁 +囈 呓 +囉 啰 +囌 苏 +囑 嘱 +囒 𪢠 +囪 囱 +圇 囵 +國 国 +圍 围 +園 园 +圓 圆 +圖 图 +團 团 +圞 𪢮 +埡 垭 +埬 𪣆 +埰 采 +執 执 +堅 坚 +堊 垩 +堖 垴 +堚 𪣒 +堝 埚 +堯 尧 +報 报 +場 场 +塊 块 +塋 茔 +塏 垲 +塒 埘 +塗 涂 +塚 冢 +塢 坞 +塤 埙 +塵 尘 +塹 堑 +塿 𪣻 +墊 垫 +墜 坠 +墮 堕 +墰 坛 +墲 𪢸 +墳 坟 +墶 垯 +墻 墙 +墾 垦 +壇 坛 +壈 𡒄 +壋 垱 +壎 埙 +壓 压 +壗 𡋤 +壘 垒 +壙 圹 +壚 垆 +壜 坛 +壞 坏 +壟 垄 +壠 垅 +壢 坜 +壣 𪤚 +壩 坝 +壪 塆 +壯 壮 +壺 壶 +壼 壸 +壽 寿 +夠 够 +夢 梦 +夥 伙 夥 +夾 夹 +奐 奂 +奧 奥 +奩 奁 +奪 夺 +奬 奖 +奮 奋 +奼 姹 +妝 妆 +姍 姗 +姦 奸 +娛 娱 +婁 娄 +婡 𫝫 +婦 妇 +婭 娅 +媈 𫝨 +媧 娲 +媯 妫 +媰 㛀 +媼 媪 +媽 妈 +嫋 袅 +嫗 妪 +嫵 妩 +嫺 娴 +嫻 娴 +嫿 婳 +嬀 妫 +嬃 媭 +嬇 𫝬 +嬈 娆 +嬋 婵 +嬌 娇 +嬙 嫱 +嬡 嫒 +嬣 𪥰 +嬤 嬷 +嬦 𫝩 +嬪 嫔 +嬰 婴 +嬸 婶 +嬻 𪥿 +孃 娘 +孄 𫝮 +孆 𫝭 +孇 𪥫 +孋 㛤 +孌 娈 +孎 𡠟 +孫 孙 +學 学 +孻 𡥧 +孾 𪧀 +孿 孪 +宮 宫 +寀 采 +寠 𪧘 +寢 寝 +實 实 +寧 宁 +審 审 +寫 写 +寬 宽 +寵 宠 +寶 宝 +將 将 +專 专 +尋 寻 +對 对 +導 导 +尷 尴 +屆 届 +屍 尸 +屓 屃 +屜 屉 +屢 屡 +層 层 +屨 屦 +屩 𪨗 +屬 属 +岡 冈 +峯 峰 +峴 岘 +島 岛 +峽 峡 +崍 崃 +崑 昆 +崗 岗 +崙 仑 𪨧 +崢 峥 +崬 岽 +嵐 岚 +嵗 岁 +嵼 𡶴 +嵾 㟥 +嶁 嵝 +嶄 崭 +嶇 岖 +嶈 𡺃 +嶔 嵚 +嶗 崂 +嶘 𡺄 +嶠 峤 +嶢 峣 +嶧 峄 +嶨 峃 +嶮 崄 +嶸 嵘 +嶹 𫝵 +嶺 岭 +嶼 屿 +嶽 岳 +巊 𪩎 +巋 岿 +巒 峦 +巔 巅 +巖 岩 +巗 𪨷 +巘 𪩘 +巰 巯 +巹 卺 +帥 帅 +師 师 +帳 帐 +帶 带 +幀 帧 +幃 帏 +幓 㡎 +幗 帼 +幘 帻 +幝 𪩷 +幟 帜 +幣 币 +幩 𪩸 +幫 帮 +幬 帱 +幹 干 +幾 几 +庫 库 +廁 厕 +廂 厢 +廄 厩 +廈 厦 +廎 庼 +廕 荫 +廚 厨 +廝 厮 +廟 庙 +廠 厂 +廡 庑 +廢 废 +廣 广 +廧 𪪞 +廩 廪 +廬 庐 𪪏 +廳 厅 +弒 弑 +弔 吊 +弳 弪 +張 张 +強 强 +彃 𪪼 +彆 别 +彈 弹 +彌 弥 +彎 弯 +彔 录 +彙 汇 +彠 彟 +彥 彦 +彫 雕 +彲 彨 +彷 彷 仿 +彿 佛 +後 后 +徑 径 +從 从 +徠 徕 +復 复 +徵 征 徵 +徹 彻 +徿 𪫌 +恆 恒 +恥 耻 +悅 悦 +悞 悮 +悵 怅 +悶 闷 +悽 凄 +惡 恶 +惱 恼 +惲 恽 +惻 恻 +愛 爱 +愜 惬 +愨 悫 +愴 怆 +愷 恺 +愻 𢙏 +愾 忾 +慄 栗 +態 态 +慍 愠 +慘 惨 +慚 惭 +慟 恸 +慣 惯 +慤 悫 +慪 怄 +慫 怂 +慮 虑 +慳 悭 +慶 庆 +慺 㥪 +慼 戚 +慾 欲 +憂 忧 +憊 惫 +憐 怜 +憑 凭 +憒 愦 +憖 慭 +憚 惮 +憢 𢙒 +憤 愤 +憫 悯 +憮 怃 +憲 宪 +憶 忆 +憸 𪫺 +憹 𢙐 +懀 𢙓 +懇 恳 +應 应 +懌 怿 +懍 懔 +懎 𢠁 +懞 蒙 +懟 怼 +懣 懑 +懤 㤽 +懨 恹 +懲 惩 +懶 懒 +懷 怀 +懸 悬 +懺 忏 +懼 惧 +懾 慑 +戀 恋 +戇 戆 +戔 戋 +戧 戗 +戩 戬 +戰 战 𢧐 +戱 戯 +戲 戏 +戶 户 +拋 抛 +挩 捝 +挱 挲 +挾 挟 +捨 舍 +捫 扪 +捱 挨 +捲 卷 +掃 扫 +掄 抡 +掆 㧏 +掗 挜 +掙 挣 +掚 𪭵 +掛 挂 +採 采 +揀 拣 +揚 扬 +換 换 +揮 挥 +揯 搄 +損 损 +搖 摇 +搗 捣 +搵 揾 +搶 抢 +摋 𢫬 +摐 𪭢 +摑 掴 +摜 掼 +摟 搂 +摯 挚 +摳 抠 +摶 抟 +摺 折 +摻 掺 +撈 捞 +撊 𪭾 +撏 挦 +撐 撑 +撓 挠 +撝 㧑 +撟 挢 +撣 掸 +撥 拨 +撧 𪮖 +撫 抚 +撲 扑 +撳 揿 +撻 挞 +撾 挝 +撿 捡 +擁 拥 +擄 掳 +擇 择 +擊 击 +擋 挡 +擓 㧟 +擔 担 +據 据 +擟 𪭧 +擠 挤 +擣 捣 𢭏 +擫 𢬍 +擬 拟 +擯 摈 +擰 拧 +擱 搁 +擲 掷 +擴 扩 +擷 撷 +擺 摆 +擻 擞 +擼 撸 +擽 㧰 +擾 扰 +攄 摅 +攆 撵 +攋 𪮶 +攏 拢 +攔 拦 +攖 撄 +攙 搀 +攛 撺 +攜 携 +攝 摄 +攢 攒 +攣 挛 +攤 摊 +攪 搅 +攬 揽 +敎 教 +敓 敚 +敗 败 +敘 叙 +敵 敌 +數 数 +斂 敛 +斃 毙 +斅 𢽾 +斆 敩 +斕 斓 +斬 斩 +斷 断 +斸 𣃁 +於 于 於 +旂 旗 +旣 既 +昇 升 +時 时 +晉 晋 +晝 昼 +暈 晕 +暉 晖 +暘 旸 +暢 畅 +暫 暂 +曄 晔 +曆 历 +曇 昙 +曉 晓 +曊 𪰶 +曏 向 +曖 暧 +曠 旷 +曥 𣆐 +曨 昽 +曬 晒 +書 书 +會 会 +朥 𦛨 +朧 胧 +朮 术 +東 东 +枴 拐 +柵 栅 +柺 拐 +査 查 +桱 𣐕 +桿 杆 +梔 栀 +梖 𪱷 +梘 枧 +條 条 +梟 枭 +梲 棁 +棄 弃 +棊 棋 +棖 枨 +棗 枣 +棟 栋 +棡 㭎 +棧 栈 +棲 栖 +棶 梾 +椏 桠 +椲 㭏 +楇 𣒌 +楊 杨 +楓 枫 +楨 桢 +業 业 +極 极 +榘 矩 +榦 干 +榪 杩 +榮 荣 +榲 榅 +榿 桤 +構 构 +槍 枪 +槓 杠 +槤 梿 +槧 椠 +槨 椁 +槫 𣏢 +槮 椮 +槳 桨 +槶 椢 +槼 椝 +樁 桩 +樂 乐 +樅 枞 +樑 梁 +樓 楼 +標 标 +樞 枢 +樠 𣗊 +樢 㭤 +樣 样 +樤 𣔌 +樧 榝 +樫 㭴 +樳 桪 +樸 朴 +樹 树 +樺 桦 +樿 椫 +橈 桡 +橋 桥 +機 机 +橢 椭 +橫 横 +橯 𣓿 +檁 檩 +檉 柽 +檔 档 +檜 桧 +檟 槚 +檢 检 +檣 樯 +檭 𣘴 +檮 梼 +檯 台 +檳 槟 +檵 𪲛 +檸 柠 +檻 槛 +櫃 柜 +櫅 𪲎 +櫓 橹 +櫚 榈 +櫛 栉 +櫝 椟 +櫞 橼 +櫟 栎 +櫠 𪲮 +櫥 橱 +櫧 槠 +櫨 栌 +櫪 枥 +櫫 橥 +櫬 榇 +櫱 蘖 +櫳 栊 +櫸 榉 +櫻 樱 +欄 栏 +欅 榉 +欇 𪳍 +權 权 +欍 𣐤 +欏 椤 +欐 𪲔 +欑 𪴙 +欒 栾 +欓 𣗋 +欖 榄 +欘 𣚚 +欞 棂 +欽 钦 +歎 叹 +歐 欧 +歟 欤 +歡 欢 +歲 岁 +歷 历 +歸 归 +歿 殁 +殘 残 +殞 殒 +殢 𣨼 +殤 殇 +殨 㱮 +殫 殚 +殭 僵 +殮 殓 +殯 殡 +殰 㱩 +殲 歼 +殺 杀 +殻 壳 +殼 壳 +毀 毁 +毆 殴 +毊 𪵑 +毿 毵 +氂 牦 +氈 毡 +氌 氇 +氣 气 +氫 氢 +氬 氩 +氭 𣱝 +氳 氲 +氾 泛 +汎 泛 +汙 污 +決 决 +沒 没 +沖 冲 +況 况 +泝 溯 +洩 泄 +洶 汹 +浹 浃 +涇 泾 +涗 涚 +涼 凉 +淒 凄 +淚 泪 +淥 渌 +淨 净 +淩 凌 +淪 沦 +淵 渊 +淶 涞 +淺 浅 +渙 涣 +減 减 +渢 沨 +渦 涡 +測 测 +渾 浑 +湊 凑 +湋 𣲗 +湞 浈 +湧 涌 +湯 汤 +溈 沩 +準 准 +溝 沟 +溡 𪶄 +溫 温 +溮 浉 +溳 涢 +溼 湿 +滄 沧 +滅 灭 +滌 涤 +滎 荥 +滙 汇 +滬 沪 +滯 滞 +滲 渗 +滷 卤 +滸 浒 +滻 浐 +滾 滚 +滿 满 +漁 渔 +漊 溇 +漚 沤 +漢 汉 +漣 涟 +漬 渍 +漲 涨 +漵 溆 +漸 渐 +漿 浆 +潁 颍 +潑 泼 +潔 洁 +潕 𣲘 +潙 沩 +潚 㴋 +潛 潜 +潣 𫞗 +潤 润 +潯 浔 +潰 溃 +潷 滗 +潿 涠 +澀 涩 +澅 𣶩 +澆 浇 +澇 涝 +澐 沄 +澗 涧 +澠 渑 +澤 泽 +澦 滪 +澩 泶 +澬 𫞚 +澮 浍 +澱 淀 +澾 㳠 +濁 浊 +濃 浓 +濄 㳡 +濆 𣸣 +濕 湿 +濘 泞 +濚 溁 +濛 蒙 +濜 浕 +濟 济 +濤 涛 +濧 㳔 +濫 滥 +濰 潍 +濱 滨 +濺 溅 +濼 泺 +濾 滤 +濿 𪵱 +瀂 澛 +瀃 𣽷 +瀅 滢 +瀆 渎 +瀇 㲿 +瀉 泻 +瀋 沈 渖 +瀏 浏 +瀕 濒 +瀘 泸 +瀝 沥 +瀟 潇 +瀠 潆 +瀦 潴 +瀧 泷 +瀨 濑 +瀰 弥 㳽 +瀲 潋 +瀾 澜 +灃 沣 +灄 滠 +灍 𫞝 +灑 洒 +灒 𪷽 +灕 漓 +灘 滩 +灙 𣺼 +灝 灏 +灡 㳕 +灣 湾 +灤 滦 +灧 滟 +灩 滟 +災 灾 +為 为 +烏 乌 +烴 烃 +無 无 +煇 𪸩 +煉 炼 +煒 炜 +煙 烟 +煢 茕 +煥 焕 +煩 烦 +煬 炀 +煱 㶽 +熂 𪸕 +熅 煴 +熉 𤈶 +熌 𤇄 +熒 荧 +熓 𤆡 +熗 炝 +熚 𤇹 +熡 𤋏 +熱 热 +熲 颎 +熾 炽 +燁 烨 +燈 灯 +燉 炖 +燒 烧 +燙 烫 +燜 焖 +營 营 +燦 灿 +燬 毁 +燭 烛 +燴 烩 +燶 㶶 +燻 熏 +燼 烬 +燾 焘 +爃 𫞡 +爄 𤇃 +爇 𦶟 +爍 烁 +爐 炉 +爖 𤇭 +爛 烂 +爥 𪹳 +爧 𫞠 +爭 争 +爲 为 +爺 爷 +爾 尔 +牀 床 +牆 墙 +牘 牍 +牴 牴 抵 +牽 牵 +犖 荦 +犛 牦 +犞 𪺭 +犢 犊 +犧 牺 +狀 状 +狹 狭 +狽 狈 +猌 𪺽 +猙 狰 +猶 犹 +猻 狲 +獁 犸 +獃 呆 +獄 狱 +獅 狮 +獊 𪺷 +獎 奖 +獨 独 +獩 𤞃 +獪 狯 +獫 猃 +獮 狝 +獰 狞 +獱 㺍 +獲 获 +獵 猎 +獷 犷 +獸 兽 +獺 獭 +獻 献 +獼 猕 +玀 猡 +玁 𤞤 +珼 𫞥 +現 现 +琱 雕 +琺 珐 +琿 珲 +瑋 玮 +瑒 玚 +瑣 琐 +瑤 瑶 +瑩 莹 +瑪 玛 +瑲 玱 +瑻 𪻲 +瑽 𪻐 +璉 琏 +璊 𫞩 +璝 𪻺 +璡 琎 +璣 玑 +璦 瑷 +璫 珰 +璯 㻅 +環 环 +璵 玙 +璸 瑸 +璼 𫞨 +璽 玺 +璾 𫞦 +璿 璇 +瓄 𪻨 +瓊 琼 +瓏 珑 +瓔 璎 +瓕 𤦀 +瓚 瓒 +瓛 𤩽 +甌 瓯 +甕 瓮 +產 产 +産 产 +甦 苏 +甯 宁 +畝 亩 +畢 毕 +畫 画 划 +異 异 +畵 画 +當 当 +畼 𪽈 +疇 畴 +疊 叠 +痙 痉 +痠 酸 +痮 𪽪 +痾 疴 +瘂 痖 +瘋 疯 +瘍 疡 +瘓 痪 +瘞 瘗 +瘡 疮 +瘧 疟 +瘮 瘆 +瘱 𪽷 +瘲 疭 +瘺 瘘 +瘻 瘘 +療 疗 +癆 痨 +癇 痫 +癉 瘅 +癐 𤶊 +癒 愈 +癘 疠 +癟 瘪 +癡 痴 +癢 痒 +癤 疖 +癥 症 +癧 疬 +癩 癞 +癬 癣 +癭 瘿 +癮 瘾 +癰 痈 +癱 瘫 +癲 癫 +發 发 +皁 皂 +皚 皑 +皟 𤾀 +皰 疱 +皸 皲 +皺 皱 +盃 杯 +盜 盗 +盞 盏 +盡 尽 +監 监 +盤 盘 +盧 卢 +盨 𪾔 +盪 荡 +眝 𪾣 +眞 真 +眥 眦 +眾 众 +睍 𪾢 +睏 困 +睜 睁 +睞 睐 +瞘 眍 +瞜 䁖 +瞞 瞒 +瞤 𥆧 +瞭 瞭 了 +瞶 瞆 +瞼 睑 +矇 蒙 +矉 𪾸 +矑 𪾦 +矓 眬 +矚 瞩 +矯 矫 +硃 朱 +硜 硁 +硤 硖 +硨 砗 +硯 砚 +碕 埼 +碙 𥐻 +碩 硕 +碭 砀 +碸 砜 +確 确 +碼 码 +碽 䂵 +磑 硙 +磚 砖 +磠 硵 +磣 碜 +磧 碛 +磯 矶 +磽 硗 +磾 䃅 +礄 硚 +礆 硷 +礎 础 +礒 𥐟 +礙 碍 +礦 矿 +礪 砺 +礫 砾 +礬 矾 +礮 𪿫 +礱 砻 +祇 祇 只 +祕 秘 +祿 禄 +禍 祸 +禎 祯 +禕 祎 +禡 祃 +禦 御 +禪 禅 +禮 礼 +禰 祢 +禱 祷 +禿 秃 +秈 籼 +稅 税 +稈 秆 +稏 䅉 +稜 棱 +稟 禀 +種 种 +稱 称 +穀 谷 +穇 䅟 +穌 稣 +積 积 +穎 颖 +穠 秾 +穡 穑 +穢 秽 +穩 稳 +穫 获 +穭 穞 +窩 窝 +窪 洼 +窮 穷 +窯 窑 +窵 窎 +窶 窭 +窺 窥 +竄 窜 +竅 窍 +竇 窦 +竈 灶 +竊 窃 +竚 𥩟 +竪 竖 +竱 𫁟 +競 竞 +筆 笔 +筍 笋 +筧 笕 +筴 䇲 +箇 个 +箋 笺 +箏 筝 +節 节 +範 范 +築 筑 +篋 箧 +篔 筼 +篘 𥬠 +篠 筿 +篤 笃 +篩 筛 +篳 筚 +篸 𥮾 +簀 箦 +簂 𫂆 +簍 篓 +簑 蓑 +簞 箪 +簡 简 +簢 𫂃 +簣 篑 +簫 箫 +簹 筜 +簽 签 +簾 帘 +籃 篮 +籅 𥫣 +籋 𥬞 +籌 筹 +籔 䉤 +籙 箓 +籛 篯 +籜 箨 +籟 籁 +籠 笼 +籤 签 +籩 笾 +籪 簖 +籬 篱 +籮 箩 +籲 吁 +粵 粤 +糉 粽 +糝 糁 +糞 粪 +糧 粮 +糰 团 +糲 粝 +糴 籴 +糶 粜 +糹 纟 +糺 𫄙 +糾 纠 +紀 纪 +紂 纣 +約 约 +紅 红 +紆 纡 +紇 纥 +紈 纨 +紉 纫 +紋 纹 +納 纳 +紐 纽 +紓 纾 +純 纯 +紕 纰 +紖 纼 +紗 纱 +紘 纮 +紙 纸 +級 级 +紛 纷 +紜 纭 +紝 纴 +紟 𫄛 +紡 纺 +紬 䌷 +紮 扎 +細 细 +紱 绂 +紲 绁 +紳 绅 +紵 纻 +紹 绍 +紺 绀 +紼 绋 +紿 绐 +絀 绌 +絁 𫄟 +終 终 +絃 弦 +組 组 +絅 䌹 +絆 绊 +絍 𫟃 +絎 绗 +結 结 +絕 绝 +絙 𫄠 +絛 绦 +絝 绔 +絞 绞 +絡 络 +絢 绚 +絥 𫄢 +給 给 +絧 𫄡 +絨 绒 +絰 绖 +統 统 +絲 丝 +絳 绛 +絶 绝 +絹 绢 +絺 𫄨 +綀 𦈌 +綁 绑 +綃 绡 +綆 绠 +綇 𦈋 +綈 绨 +綉 绣 +綋 𫟄 +綌 绤 +綏 绥 +綐 䌼 +綑 捆 +經 经 +綖 𫄧 +綜 综 +綞 缍 +綟 𫄫 +綠 绿 +綡 𫟅 +綢 绸 +綣 绻 +綫 线 +綬 绶 +維 维 +綯 绹 +綰 绾 +綱 纲 +網 网 +綳 绷 +綴 缀 +綵 彩 䌽 +綸 纶 +綹 绺 +綺 绮 +綻 绽 +綽 绰 +綾 绫 +綿 绵 +緄 绲 +緇 缁 +緊 紧 +緋 绯 +緍 𦈏 +緑 绿 +緒 绪 +緓 绬 +緔 绱 +緗 缃 +緘 缄 +緙 缂 +線 线 缐 +緝 缉 +緞 缎 +緟 𫟆 +締 缔 +緡 缗 +緣 缘 +緤 𫄬 +緦 缌 +編 编 +緩 缓 +緬 缅 +緮 𫄭 +緯 纬 +緰 𦈕 +緱 缑 +緲 缈 +練 练 +緶 缏 +緷 𦈉 +緸 𦈑 +緹 缇 +緻 致 +緼 缊 +縈 萦 +縉 缙 +縊 缢 +縋 缒 +縍 𫄰 +縎 𦈔 +縐 绉 +縑 缣 +縕 缊 +縗 缞 +縛 缚 +縝 缜 +縞 缟 +縟 缛 +縣 县 +縧 绦 +縫 缝 +縬 𦈚 +縭 缡 +縮 缩 +縰 𫄳 +縱 纵 +縲 缧 +縳 䌸 +縴 纤 +縵 缦 +縶 絷 +縷 缕 +縸 𫄲 +縹 缥 +縺 𦈐 +總 总 +績 绩 +繂 𫄴 +繃 绷 +繅 缫 +繆 缪 +繈 𫄶 +繏 𦈝 +繐 𰬸 +繒 缯 +繓 𦈛 +織 织 +繕 缮 +繚 缭 +繞 绕 +繟 𦈎 +繡 绣 +繢 缋 +繨 𫄤 +繩 绳 +繪 绘 +繫 系 +繬 𫄱 +繭 茧 +繮 缰 +繯 缳 +繰 缲 +繳 缴 +繶 𫄷 +繷 𫄣 +繸 䍁 +繹 绎 +繻 𦈡 +繼 继 +繽 缤 +繾 缱 +繿 䍀 +纁 𫄸 +纇 颣 +纈 缬 +纊 纩 +續 续 +纍 累 +纏 缠 +纓 缨 +纔 才 +纖 纤 +纗 𫄹 +纘 缵 +纚 𫄥 +纜 缆 +缽 钵 +罃 䓨 +罈 坛 +罌 罂 +罎 坛 +罰 罚 +罵 骂 +罷 罢 +羅 罗 +羆 罴 +羈 羁 +羋 芈 +羣 群 +羥 羟 +羨 羡 +義 义 +羵 𫅗 +羶 膻 +習 习 +翫 玩 +翬 翚 +翹 翘 +翽 翙 +耬 耧 +耮 耢 +聖 圣 +聞 闻 +聯 联 +聰 聪 +聲 声 +聳 耸 +聵 聩 +聶 聂 +職 职 +聹 聍 +聻 𫆏 +聽 听 +聾 聋 +肅 肃 +脅 胁 +脈 脉 +脛 胫 +脣 唇 +脥 𣍰 +脩 修 +脫 脱 +脹 胀 +腎 肾 +腖 胨 +腡 脶 +腦 脑 +腪 𣍯 +腫 肿 +腳 脚 +腸 肠 +膃 腽 +膕 腘 +膚 肤 +膞 䏝 +膠 胶 +膢 𦝼 +膩 腻 +膹 𪱥 +膽 胆 +膾 脍 +膿 脓 +臉 脸 +臍 脐 +臏 膑 +臗 𣎑 +臘 腊 +臚 胪 +臟 脏 +臠 脔 +臢 臜 +臥 卧 +臨 临 +臺 台 +與 与 +興 兴 +舉 举 +舊 旧 +舘 馆 +艙 舱 +艣 𫇛 +艤 舣 +艦 舰 +艫 舻 +艱 艰 +艷 艳 +芻 刍 +苧 苎 +茲 兹 +荊 荆 +莊 庄 +莖 茎 +莢 荚 +莧 苋 +菕 𰰨 +華 华 +菴 庵 +菸 烟 +萇 苌 +萊 莱 +萬 万 +萴 荝 +萵 莴 +葉 叶 +葒 荭 +葝 𫈎 +葤 荮 +葦 苇 +葯 药 +葷 荤 +蒍 𫇭 +蒐 搜 +蒓 莼 +蒔 莳 +蒕 蒀 +蒞 莅 +蒭 𫇴 +蒼 苍 +蓀 荪 +蓆 席 +蓋 盖 +蓧 𦰏 +蓮 莲 +蓯 苁 +蓴 莼 +蓽 荜 +蔔 卜 +蔘 参 +蔞 蒌 +蔣 蒋 +蔥 葱 +蔦 茑 +蔭 荫 +蔯 𫈟 +蔿 𫇭 +蕁 荨 +蕆 蒇 +蕎 荞 +蕒 荬 +蕓 芸 +蕕 莸 +蕘 荛 +蕝 𫈵 +蕢 蒉 +蕩 荡 +蕪 芜 +蕭 萧 +蕳 𫈉 +蕷 蓣 +蕽 𫇽 +薀 蕰 +薆 𫉁 +薈 荟 +薊 蓟 +薌 芗 +薑 姜 +薔 蔷 +薘 荙 +薟 莶 +薦 荐 +薩 萨 +薳 䓕 +薴 苧 +薵 䓓 +薹 苔 薹 +薺 荠 +藉 藉 借 +藍 蓝 +藎 荩 +藝 艺 +藥 药 +藪 薮 +藭 䓖 +藴 蕴 +藶 苈 +藷 𫉄 +藹 蔼 +藺 蔺 +蘀 萚 +蘄 蕲 +蘆 芦 +蘇 苏 +蘊 蕴 +蘋 苹 蘋 +蘚 藓 +蘞 蔹 +蘟 𦻕 +蘢 茏 +蘭 兰 +蘺 蓠 +蘿 萝 +虆 蔂 +處 处 +虛 虚 +虜 虏 +號 号 +虧 亏 +虯 虬 +蛺 蛱 +蛻 蜕 +蜆 蚬 +蝕 蚀 +蝟 猬 +蝦 虾 +蝨 虱 +蝸 蜗 +螄 蛳 +螞 蚂 +螢 萤 +螮 䗖 +螻 蝼 +螿 螀 +蟂 𫋇 +蟄 蛰 +蟈 蝈 +蟎 螨 +蟘 𫋌 +蟜 𫊸 +蟣 虮 +蟬 蝉 +蟯 蛲 +蟲 虫 +蟳 𫊻 +蟶 蛏 +蟻 蚁 +蠀 𧏗 +蠁 蚃 +蠅 蝇 +蠆 虿 +蠍 蝎 +蠐 蛴 +蠑 蝾 +蠔 蚝 +蠙 𧏖 +蠟 蜡 +蠣 蛎 +蠦 𫊮 +蠨 蟏 +蠱 蛊 +蠶 蚕 +蠻 蛮 +蠾 𧑏 +衆 众 +衊 蔑 +術 术 +衕 同 +衚 胡 +衛 卫 +衝 冲 +衹 衹 只 +袞 衮 +裊 袅 +裏 里 +補 补 +裝 装 +裡 里 +製 制 +複 复 +褌 裈 +褘 袆 +褲 裤 +褳 裢 +褸 褛 +褻 亵 +襀 𫌀 +襇 裥 +襉 裥 +襏 袯 +襓 𫋹 +襖 袄 +襗 𫋷 +襘 𫋻 +襝 裣 +襠 裆 +襤 褴 +襪 袜 +襬 摆 䙓 +襯 衬 +襰 𧝝 +襲 袭 +襴 襕 +襵 𫌇 +覆 覆 复 +覈 核 +見 见 +覎 觃 +規 规 +覓 觅 +視 视 +覘 觇 +覛 𫌪 +覡 觋 +覥 觍 +覦 觎 +親 亲 +覬 觊 +覯 觏 +覲 觐 +覷 觑 +覹 𫌭 +覺 觉 +覼 𫌨 +覽 览 +覿 觌 +觀 观 +觴 觞 +觶 觯 +觸 触 +訁 讠 +訂 订 +訃 讣 +計 计 +訊 讯 +訌 讧 +討 讨 +訐 讦 +訑 𫍙 +訒 讱 +訓 训 +訕 讪 +訖 讫 +託 托 讬 +記 记 +訛 讹 +訜 𫍛 +訝 讶 +訞 𫍚 +訟 讼 +訢 䜣 +訣 诀 +訥 讷 +訨 𫟞 +訩 讻 +訪 访 +設 设 +許 许 +訴 诉 +訶 诃 +診 诊 +註 注 +証 证 +詀 𧮪 +詁 诂 +詆 诋 +詊 𫟟 +詎 讵 +詐 诈 +詑 𫍡 +詒 诒 +詓 𫍜 +詔 诏 +評 评 +詖 诐 +詗 诇 +詘 诎 +詛 诅 +詞 词 +詠 咏 +詡 诩 +詢 询 +詣 诣 +試 试 +詩 诗 +詫 诧 +詬 诟 +詭 诡 +詮 诠 +詰 诘 +話 话 +該 该 +詳 详 +詵 诜 +詷 𫍣 +詼 诙 +詿 诖 +誂 𫍥 +誄 诔 +誅 诛 +誆 诓 +誇 夸 +誋 𫍪 +誌 志 +認 认 +誑 诳 +誒 诶 +誕 诞 +誘 诱 +誚 诮 +語 语 +誠 诚 +誡 诫 +誣 诬 +誤 误 +誥 诰 +誦 诵 +誨 诲 +說 说 +誫 𫍨 +説 说 +誰 谁 +課 课 +誳 𫍮 +誴 𫟡 +誶 谇 +誷 𫍬 +誹 诽 +誺 𫍧 +誼 谊 +誾 訚 +調 调 +諂 谄 +諄 谆 +談 谈 +諉 诿 +請 请 +諍 诤 +諏 诹 +諑 诼 +諒 谅 +論 论 +諗 谂 +諛 谀 +諜 谍 +諝 谞 +諞 谝 +諡 谥 +諢 诨 +諣 𫍩 +諤 谔 +諥 𫍳 +諦 谛 +諧 谐 +諫 谏 𫍝 +諭 谕 +諮 咨 谘 +諯 𫍱 +諰 𫍰 +諱 讳 +諳 谙 +諴 𫍯 +諶 谌 +諷 讽 +諸 诸 +諺 谚 +諼 谖 +諾 诺 +謀 谋 +謁 谒 +謂 谓 +謄 誊 +謅 诌 +謆 𫍸 +謉 𫍷 +謊 谎 +謎 谜 +謏 𫍲 +謐 谧 +謔 谑 +謖 谡 +謗 谤 +謙 谦 +謚 谥 +講 讲 +謝 谢 +謠 谣 +謡 谣 +謨 谟 +謫 谪 +謬 谬 +謭 谫 +謯 𫍹 +謱 𫍴 +謳 讴 +謸 𫍵 +謹 谨 +謾 谩 +譁 哗 +譂 𫟠 +譅 𰶎 +譆 𫍻 +證 证 +譊 𫍢 +譎 谲 +譏 讥 +譑 𫍤 +譖 谮 +識 识 +譙 谯 +譚 谭 +譜 谱 +譞 𫍽 +譟 噪 +譨 𫍦 +譫 谵 +譭 毁 +譯 译 +議 议 +譴 谴 +護 护 +譸 诪 +譽 誉 +譾 谫 𫍿 +讀 读 +讅 谉 +變 变 +讋 詟 +讌 䜩 +讎 雠 +讒 谗 +讓 让 +讕 谰 +讖 谶 +讚 赞 +讜 谠 +讞 谳 +豈 岂 +豎 竖 +豐 丰 +豔 艳 +豬 猪 +豵 𫎆 +豶 豮 +貓 猫 +貗 𫎌 +貙 䝙 +貝 贝 +貞 贞 +貟 贠 +負 负 +財 财 +貢 贡 +貧 贫 +貨 货 +販 贩 +貪 贪 +貫 贯 +責 责 +貯 贮 +貰 贳 +貲 赀 +貳 贰 +貴 贵 +貶 贬 +買 买 𧹒 +貸 贷 +貺 贶 +費 费 +貼 贴 +貽 贻 +貿 贸 +賀 贺 +賁 贲 +賂 赂 +賃 赁 +賄 贿 +賅 赅 +資 资 +賈 贾 +賊 贼 +賑 赈 +賒 赊 +賓 宾 +賕 赇 +賙 赒 +賚 赉 +賜 赐 +賝 𫎩 +賞 赏 +賟 𧹖 +賠 赔 +賡 赓 +賢 贤 +賣 卖 +賤 贱 +賦 赋 +賧 赕 +質 质 +賫 赍 +賬 账 +賭 赌 +賰 䞐 +賴 赖 +賵 赗 +賺 赚 +賻 赙 +購 购 +賽 赛 +賾 赜 +贃 𧹗 +贄 贽 +贅 赘 +贇 赟 +贈 赠 +贉 𫎫 +贊 赞 +贋 赝 +贍 赡 +贏 赢 +贐 赆 +贑 𫎬 +贓 赃 +贔 赑 +贖 赎 +贗 赝 +贚 𫎦 +贛 赣 +贜 赃 +赬 赪 +趕 赶 +趙 赵 +趨 趋 +趲 趱 +跡 迹 +踐 践 +踰 逾 +踴 踊 +蹌 跄 +蹔 𫏐 +蹕 跸 +蹟 迹 +蹠 跖 +蹣 蹒 +蹤 踪 +蹳 𫏆 +蹺 跷 +蹻 𫏋 +躂 跶 +躉 趸 +躊 踌 +躋 跻 +躍 跃 +躎 䟢 +躑 踯 +躒 跞 +躓 踬 +躕 蹰 +躘 𨀁 +躚 跹 +躝 𨅬 +躡 蹑 +躥 蹿 +躦 躜 +躪 躏 +軀 躯 +軉 𨉗 +車 车 +軋 轧 +軌 轨 +軍 军 +軏 𫐄 +軑 轪 +軒 轩 +軔 轫 +軕 𫐅 +軗 𨐅 +軛 轭 +軜 𫐇 +軟 软 +軤 轷 +軨 𫐉 +軫 轸 +軬 𫐊 +軲 轱 +軷 𫐈 +軸 轴 +軹 轵 +軺 轺 +軻 轲 +軼 轶 +軾 轼 +軿 𫐌 +較 较 +輄 𨐈 +輅 辂 +輇 辁 +輈 辀 +載 载 +輊 轾 +輋 𪨶 +輒 辄 +輓 挽 +輔 辅 +輕 轻 +輖 𫐏 +輗 𫐐 +輛 辆 +輜 辎 +輝 辉 +輞 辋 +輟 辍 +輢 𫐎 +輥 辊 +輦 辇 +輨 𫐑 +輩 辈 +輪 轮 +輬 辌 +輮 𫐓 +輯 辑 +輳 辏 +輷 𫐒 +輸 输 +輻 辐 +輼 辒 +輾 辗 +輿 舆 +轀 辒 +轂 毂 +轄 辖 +轅 辕 +轆 辘 +轇 𫐖 +轉 转 +轊 𫐕 +轍 辙 +轎 轿 +轐 𫐗 +轔 辚 +轗 𫐘 +轟 轰 +轠 𫐙 +轡 辔 +轢 轹 +轣 𫐆 +轤 轳 +辦 办 +辭 辞 +辮 辫 +辯 辩 +農 农 +迴 回 +逕 迳 +這 这 +連 连 +週 周 +進 进 +遊 游 +運 运 +過 过 +達 达 +違 违 +遙 遥 +遜 逊 +遞 递 +遠 远 +遡 溯 +適 适 +遱 𫐷 +遲 迟 +遷 迁 +選 选 +遺 遗 +遼 辽 +邁 迈 +還 还 +邇 迩 +邊 边 +邏 逻 +邐 逦 +郟 郏 +郵 邮 +鄆 郓 +鄉 乡 +鄒 邹 +鄔 邬 +鄖 郧 +鄟 𫑘 +鄧 邓 +鄭 郑 +鄰 邻 +鄲 郸 +鄳 𫑡 +鄴 邺 +鄶 郐 +鄺 邝 +酇 酂 +酈 郦 +醃 腌 +醖 酝 +醜 丑 +醞 酝 +醟 蒏 +醣 糖 +醫 医 +醬 酱 +醱 酦 +醶 𫑷 +釀 酿 +釁 衅 +釃 酾 +釅 酽 +釋 释 +釐 厘 +釒 钅 +釓 钆 +釔 钇 +釕 钌 +釗 钊 +釘 钉 +釙 钋 +釚 𫟲 +針 针 +釟 𫓥 +釣 钓 +釤 钐 +釦 扣 +釧 钏 +釨 𫓦 +釩 钒 +釲 𫟳 +釳 𨰿 +釵 钗 +釷 钍 +釹 钕 +釺 钎 +釾 䥺 +鈀 钯 +鈁 钫 +鈃 钘 +鈄 钭 +鈅 钥 +鈆 𫓪 +鈇 𫓧 +鈈 钚 +鈉 钠 +鈋 𨱂 +鈍 钝 +鈎 钩 +鈐 钤 +鈑 钣 +鈒 钑 +鈔 钞 +鈕 钮 +鈖 𫟴 +鈗 𫟵 +鈛 𫓨 +鈞 钧 +鈠 𨱁 +鈡 钟 +鈣 钙 +鈥 钬 +鈦 钛 +鈧 钪 +鈮 铌 +鈯 𨱄 +鈰 铈 +鈲 𨱃 +鈳 钶 +鈴 铃 +鈷 钴 +鈸 钹 +鈹 铍 +鈺 钰 +鈽 钸 +鈾 铀 +鈿 钿 +鉀 钾 +鉁 𨱅 +鉅 巨 钜 +鉆 钻 +鉈 铊 +鉉 铉 +鉋 铇 +鉍 铋 +鉑 铂 +鉔 𫓬 +鉕 钷 +鉗 钳 +鉚 铆 +鉛 铅 +鉝 𫟷 +鉞 钺 +鉠 𫓭 +鉢 钵 +鉤 钩 +鉦 钲 +鉬 钼 +鉭 钽 +鉳 锫 +鉶 铏 +鉷 𫟹 +鉸 铰 +鉺 铒 +鉻 铬 +鉽 𫟸 +鉾 𫓴 +鉿 铪 +銀 银 +銁 𫓲 +銂 𫟻 +銃 铳 +銅 铜 +銈 𫓯 +銊 𫓰 +銍 铚 +銏 𫟶 +銑 铣 +銓 铨 +銖 铢 +銘 铭 +銚 铫 +銛 铦 +銜 衔 +銠 铑 +銣 铷 +銥 铱 +銦 铟 +銨 铵 +銩 铥 +銪 铕 +銫 铯 +銬 铐 +銱 铞 +銳 锐 +銶 𨱇 +銷 销 +銹 锈 +銻 锑 +銼 锉 +鋁 铝 +鋂 𰾄 +鋃 锒 +鋅 锌 +鋇 钡 +鋉 𨱈 +鋌 铤 +鋏 铗 +鋒 锋 +鋗 𫓶 +鋙 铻 +鋝 锊 +鋟 锓 +鋠 𫓵 +鋣 铘 +鋤 锄 +鋥 锃 +鋦 锔 +鋨 锇 +鋩 铓 +鋪 铺 +鋭 锐 +鋮 铖 +鋯 锆 +鋰 锂 +鋱 铽 +鋶 锍 +鋸 锯 +鋼 钢 +錀 𬬭 +錁 锞 +錂 𨱋 +錄 录 +錆 锖 +錇 锫 +錈 锩 +錏 铔 +錐 锥 +錒 锕 +錕 锟 +錘 锤 +錙 锱 +錚 铮 +錛 锛 +錜 𫓻 +錝 𫓽 +錟 锬 +錠 锭 +錡 锜 +錢 钱 +錤 𫓹 +錥 𫓾 +錦 锦 +錨 锚 +錩 锠 +錫 锡 +錮 锢 +錯 错 +録 录 +錳 锰 +錶 表 +錸 铼 +錼 镎 +錽 𫓸 +鍀 锝 +鍁 锨 +鍃 锪 +鍄 𨱉 +鍅 钫 +鍆 钔 +鍇 锴 +鍈 锳 +鍉 𫔂 +鍊 炼 链 𫔀 +鍋 锅 +鍍 镀 +鍒 𫔄 +鍔 锷 +鍘 铡 +鍚 钖 +鍛 锻 +鍠 锽 +鍤 锸 +鍥 锲 +鍩 锘 +鍬 锹 +鍮 𨱎 +鍰 锾 +鍵 键 +鍶 锶 +鍺 锗 +鍼 针 +鍾 钟 锺 +鎂 镁 +鎄 锿 +鎇 镅 +鎈 𫟿 +鎊 镑 +鎌 镰 +鎍 𫔅 +鎔 镕 +鎖 锁 +鎘 镉 +鎙 𫔈 +鎚 锤 +鎛 镈 +鎝 𨱏 +鎞 𫔇 +鎡 镃 +鎢 钨 +鎣 蓥 +鎦 镏 +鎧 铠 +鎩 铩 +鎪 锼 +鎬 镐 +鎭 镇 +鎮 镇 +鎯 𨱍 +鎰 镒 +鎲 镋 +鎳 镍 +鎵 镓 +鎶 鿔 +鎷 𨰾 +鎸 镌 +鎿 镎 +鏃 镞 +鏆 𨱌 +鏇 旋 镟 +鏈 链 +鏉 𨱒 +鏌 镆 +鏍 镙 +鏐 镠 +鏑 镝 +鏗 铿 +鏘 锵 +鏚 𬭭 +鏜 镗 +鏝 镘 +鏞 镛 +鏟 铲 +鏡 镜 +鏢 镖 +鏤 镂 +鏥 𫔊 +鏦 𫓩 +鏨 錾 +鏰 镚 +鏵 铧 +鏷 镤 +鏹 镪 +鏺 䥽 +鏽 锈 +鏾 𫔌 +鐃 铙 +鐄 𨱑 +鐇 𫔍 +鐈 𫓱 +鐋 铴 +鐍 𫔎 +鐎 𨱓 +鐏 𨱔 +鐐 镣 +鐒 铹 +鐓 镦 +鐔 镡 +鐘 钟 +鐙 镫 +鐝 镢 +鐠 镨 +鐥 䦅 +鐦 锎 +鐧 锏 +鐨 镄 +鐪 𫓺 +鐫 镌 +鐮 镰 +鐯 䦃 +鐲 镯 +鐳 镭 +鐵 铁 +鐶 镮 +鐸 铎 +鐺 铛 +鐼 𫔁 +鐽 𫟼 +鐿 镱 +鑀 𰾭 +鑄 铸 +鑉 𫠁 +鑊 镬 +鑌 镔 +鑑 鉴 +鑒 鉴 +鑔 镲 +鑕 锧 +鑞 镴 +鑠 铄 +鑣 镳 +鑥 镥 +鑪 𬬻 +鑭 镧 +鑰 钥 +鑱 镵 +鑲 镶 +鑴 𫔔 +鑷 镊 +鑹 镩 +鑼 锣 +鑽 钻 +鑾 銮 +鑿 凿 +钁 镢 䦆 +钂 镋 +長 长 +門 门 +閂 闩 +閃 闪 +閆 闫 +閈 闬 +閉 闭 +開 开 𫔭 +閌 闶 +閍 𨸂 +閎 闳 +閏 闰 +閐 𨸃 +閑 闲 +閒 闲 𫔮 +間 间 +閔 闵 +閗 𫔯 +閘 闸 +閝 𫠂 +閞 𫔰 +閡 阂 +閣 阁 +閤 合 +閥 阀 +閨 闺 +閩 闽 +閫 阃 +閬 阆 +閭 闾 +閱 阅 +閲 阅 +閵 𫔴 +閶 阊 +閹 阉 +閻 阎 +閼 阏 +閽 阍 +閾 阈 +閿 阌 +闃 阒 +闆 板 +闇 暗 +闈 闱 +闊 阔 +闋 阕 +闌 阑 +闍 阇 +闐 阗 +闑 𫔶 +闒 阘 +闓 闿 +闔 阖 +闕 阙 +闖 闯 +關 关 +闞 阚 +闠 阓 +闡 阐 +闢 辟 +闤 阛 +闥 闼 +阪 阪 坂 +陘 陉 +陝 陕 +陞 升 +陣 阵 +陰 阴 +陳 陈 +陸 陆 +陽 阳 +隉 陧 +隊 队 +階 阶 +隕 陨 +際 际 +隨 随 +險 险 +隯 陦 +隱 隐 +隴 陇 +隸 隶 +隻 只 +雋 隽 +雖 虽 +雙 双 +雛 雏 +雜 杂 +雞 鸡 +離 离 +難 难 +雲 云 +電 电 +霑 沾 +霢 霡 +霣 𫕥 +霧 雾 +霼 𪵣 +霽 霁 +靂 雳 +靄 霭 +靆 叇 +靈 灵 +靉 叆 +靚 靓 +靜 静 +靝 靔 +靦 腼 䩄 +靧 𫖃 +靨 靥 +鞏 巩 +鞝 绱 +鞦 秋 +鞽 鞒 +鞾 𫖇 +韁 缰 +韃 鞑 +韆 千 +韉 鞯 +韋 韦 +韌 韧 +韍 韨 +韓 韩 +韙 韪 +韚 𫠅 +韛 𫖔 +韜 韬 +韝 鞲 𫖕 +韞 韫 +韠 𫖒 +韻 韵 +響 响 +頁 页 +頂 顶 +頃 顷 +項 项 +順 顺 +頇 顸 +須 须 +頊 顼 +頌 颂 +頍 𫠆 +頎 颀 +頏 颃 +預 预 +頑 顽 +頒 颁 +頓 顿 +頗 颇 +領 领 +頜 颌 +頡 颉 +頤 颐 +頦 颏 +頫 𫖯 +頭 头 +頮 颒 +頰 颊 +頲 颋 +頴 颕 +頵 𫖳 +頷 颔 +頸 颈 +頹 颓 +頻 频 +頽 颓 +顂 𩓋 +顃 𩖖 +顅 𫖶 +顆 颗 +題 题 +額 额 +顎 颚 +顏 颜 +顒 颙 +顓 颛 +顔 颜 +顗 𫖮 +願 愿 𫖸 +顙 颡 +顛 颠 +類 类 +顢 颟 +顣 𫖹 +顥 颢 +顧 顾 +顫 颤 +顬 颥 +顯 显 +顰 颦 +顱 颅 +顳 颞 +顴 颧 +風 风 +颭 飐 +颮 飑 +颯 飒 +颰 𩙥 +颱 台 +颳 刮 +颶 飓 +颷 𩙪 +颸 飔 +颺 飏 +颻 飖 +颼 飕 +颾 𩙫 +飀 飗 +飄 飘 +飆 飙 +飈 飚 +飋 𫗋 +飛 飞 +飠 饣 +飢 饥 +飣 饤 +飥 饦 +飦 𫗞 +飩 饨 +飪 饪 +飫 饫 +飭 饬 +飯 饭 +飱 飧 +飲 饮 +飴 饴 +飵 𫗢 +飶 𫗣 +飼 饲 +飽 饱 +飾 饰 +飿 饳 +餃 饺 +餄 饸 +餅 饼 +餈 糍 +餉 饷 +養 养 +餌 饵 +餎 饹 +餏 饻 +餑 饽 +餒 馁 +餓 饿 +餔 𫗦 +餕 馂 +餖 饾 +餗 𫗧 +餘 余 馀 +餚 肴 +餛 馄 +餜 馃 +餞 饯 +餡 馅 +餦 𫗠 +餧 𫗪 +館 馆 +餪 𫗬 +餫 𫗥 +餬 糊 𫗫 +餭 𫗮 +餱 糇 𫗯 +餳 饧 +餵 喂 𫗭 +餶 馉 +餷 馇 +餸 𩠌 +餺 馎 +餼 饩 +餾 馏 +餿 馊 +饁 馌 +饃 馍 +饅 馒 +饈 馐 +饉 馑 +饊 馓 +饋 馈 +饌 馔 +饑 饥 +饒 饶 +饗 飨 +饘 𫗴 +饜 餍 +饞 馋 +饟 𫗵 +饠 𫗩 +饢 馕 +馬 马 +馭 驭 +馮 冯 +馯 𫘛 +馱 驮 +馳 驰 +馴 驯 +馹 驲 +馼 𫘜 +駁 驳 +駃 𫘝 +駊 𫘟 +駎 𩧨 +駐 驻 +駑 驽 +駒 驹 +駔 驵 +駕 驾 +駘 骀 +駙 驸 +駚 𩧫 +駛 驶 +駝 驼 +駞 𫘞 +駟 驷 +駡 骂 +駢 骈 +駤 𫘠 +駧 𩧲 +駩 𩧴 +駫 𫘡 +駭 骇 +駰 骃 +駱 骆 +駶 𩧺 +駸 骎 +駻 𫘣 +駿 骏 +騁 骋 +騂 骍 +騃 𫘤 +騄 𫘧 +騅 骓 +騉 𫘥 +騊 𫘦 +騌 骔 +騍 骒 +騎 骑 +騏 骐 +騔 𩨀 +騖 骛 +騙 骗 +騚 𩨊 +騜 𫘩 +騝 𩨃 +騟 𩨈 +騠 𫘨 +騤 骙 +騧 䯄 +騪 𩨄 +騫 骞 +騭 骘 +騮 骝 +騰 腾 +騱 𫘬 +騴 𫘫 +騵 𫘪 +騶 驺 +騷 骚 +騸 骟 +騻 𫘭 +騼 𫠋 +騾 骡 +驀 蓦 +驁 骜 +驂 骖 +驃 骠 +驄 骢 𩨂 +驅 驱 +驊 骅 +驋 𩧯 +驌 骕 +驍 骁 +驏 骣 +驓 𫘯 +驕 骄 +驗 验 +驙 𫘰 +驚 惊 +驛 驿 +驟 骤 +驢 驴 +驤 骧 +驥 骥 +驦 骦 +驨 𫘱 +驪 骊 +驫 骉 +骯 肮 +髏 髅 +髒 脏 +體 体 +髕 髌 +髖 髋 +髮 发 +鬆 松 +鬍 胡 +鬖 𩭹 +鬚 须 +鬠 𫘽 +鬢 鬓 +鬥 斗 +鬧 闹 +鬨 哄 +鬩 阋 +鬮 阄 +鬱 郁 +鬹 鬶 +魎 魉 +魘 魇 +魚 鱼 +魛 鱽 +魟 𫚉 +魢 鱾 +魥 𩽹 +魦 𫚌 +魨 鲀 +魯 鲁 +魴 鲂 +魵 𫚍 +魷 鱿 +魺 鲄 +魽 𫠐 +鮁 鲅 +鮃 鲆 +鮄 𫚒 +鮅 𫚑 +鮆 𫚖 +鮊 鲌 +鮋 鲉 +鮍 鲏 +鮎 鲇 +鮐 鲐 +鮑 鲍 +鮒 鲋 +鮓 鲊 +鮚 鲒 +鮜 鲘 +鮝 鲞 +鮞 鲕 +鮟 𩽾 +鮣 䲟 +鮤 𫚓 +鮦 鲖 +鮪 鲔 +鮫 鲛 +鮭 鲑 +鮮 鲜 +鮯 𫚗 +鮰 𫚔 +鮳 鲓 +鮵 𫚛 +鮶 鲪 +鮸 𩾃 +鮺 鲝 +鮿 𫚚 +鯀 鲧 +鯁 鲠 +鯄 𩾁 +鯆 𫚙 +鯇 鲩 +鯉 鲤 +鯊 鲨 +鯒 鲬 +鯔 鲻 +鯕 鲯 +鯖 鲭 +鯗 鲞 +鯛 鲷 +鯝 鲴 +鯞 𫚡 +鯡 鲱 +鯢 鲵 +鯤 鲲 +鯧 鲳 +鯨 鲸 +鯪 鲮 +鯫 鲰 +鯬 𫚞 +鯰 鲶 +鯱 𩾇 +鯴 鲺 +鯶 𩽼 +鯷 鳀 +鯽 鲫 +鯾 𫚣 +鯿 鳊 +鰁 鳈 +鰂 鲗 +鰃 鳂 +鰆 䲠 +鰈 鲽 +鰉 鳇 +鰋 𫚢 +鰌 䲡 +鰍 鳅 +鰏 鲾 +鰐 鳄 +鰑 𫚊 +鰒 鳆 +鰓 鳃 +鰕 𫚥 +鰛 鳁 +鰜 鳒 +鰟 鳑 +鰠 鳋 +鰣 鲥 +鰤 𫚕 +鰥 鳏 +鰦 𫚤 +鰧 䲢 +鰨 鳎 +鰩 鳐 +鰫 𫚦 +鰭 鳍 +鰮 鳁 +鰱 鲢 +鰲 鳌 +鰳 鳓 +鰵 鳘 +鰷 鲦 +鰹 鲣 +鰺 鲹 +鰻 鳗 +鰼 鳛 +鰽 𫚧 +鰾 鳔 +鱂 鳉 +鱄 𫚋 +鱅 鳙 +鱆 𫠒 +鱇 𩾌 +鱈 鳕 +鱉 鳖 +鱊 𫚪 +鱒 鳟 +鱔 鳝 +鱖 鳜 +鱗 鳞 +鱘 鲟 +鱝 鲼 +鱟 鲎 +鱠 鲙 +鱢 𫚫 +鱣 鳣 +鱤 鳡 +鱧 鳢 +鱨 鲿 +鱭 鲚 +鱮 𫚈 +鱯 鳠 +鱲 𫚭 +鱷 鳄 +鱸 鲈 +鱺 鲡 +鳥 鸟 +鳧 凫 +鳩 鸠 +鳬 凫 +鳲 鸤 +鳳 凤 +鳴 鸣 +鳶 鸢 +鳷 𫛛 +鳼 𪉃 +鳽 𫛚 +鳾 䴓 +鴀 𫛜 +鴃 𫛞 +鴅 𫛝 +鴆 鸩 +鴇 鸨 +鴉 鸦 +鴐 𫛤 +鴒 鸰 +鴔 𫛡 +鴕 鸵 +鴗 𫁡 +鴛 鸳 +鴜 𪉈 +鴝 鸲 +鴞 鸮 +鴟 鸱 +鴣 鸪 +鴥 𫛣 +鴦 鸯 +鴨 鸭 +鴮 𫛦 +鴯 鸸 +鴰 鸹 +鴲 𪉆 +鴳 𫛩 +鴴 鸻 +鴷 䴕 +鴻 鸿 +鴽 𫛪 +鴿 鸽 +鵁 䴔 +鵂 鸺 +鵃 鸼 +鵊 𫛥 +鵐 鹀 +鵑 鹃 +鵒 鹆 +鵓 鹁 +鵚 𪉍 +鵜 鹈 +鵝 鹅 +鵟 𫛭 +鵠 鹄 +鵡 鹉 +鵧 𫛨 +鵩 𫛳 +鵪 鹌 +鵫 𫛱 +鵬 鹏 +鵮 鹐 +鵯 鹎 +鵰 雕 𫛲 +鵲 鹊 +鵷 鹓 +鵾 鹍 +鶄 䴖 +鶇 鸫 +鶉 鹑 +鶊 鹒 +鶌 𫛵 +鶒 𫛶 +鶓 鹋 +鶖 鹙 +鶗 𫛸 +鶘 鹕 +鶚 鹗 +鶡 鹖 +鶥 鹛 +鶦 𫛷 +鶩 鹜 +鶪 䴗 +鶬 鸧 +鶭 𫛯 +鶯 莺 +鶰 𫛫 +鶲 鹟 +鶴 鹤 +鶹 鹠 +鶺 鹡 +鶻 鹘 +鶼 鹣 +鶿 鹚 +鷀 鹚 +鷁 鹢 +鷂 鹞 +鷄 鸡 +鷅 𫛽 +鷉 䴘 +鷊 鹝 +鷐 𫜀 +鷓 鹧 +鷔 𪉑 +鷖 鹥 +鷗 鸥 +鷙 鸷 +鷚 鹨 +鷣 𫜃 +鷤 𫛴 +鷥 鸶 +鷦 鹪 +鷨 𪉊 +鷩 𫜁 +鷫 鹔 +鷯 鹩 +鷲 鹫 +鷳 鹇 +鷴 鹇 +鷷 𫜄 +鷸 鹬 +鷹 鹰 +鷺 鹭 +鷽 鸴 +鷿 𬸯 +鸂 㶉 +鸇 鹯 +鸊 䴙 +鸋 𫛢 +鸌 鹱 +鸏 鹲 +鸕 鸬 +鸗 𫛟 +鸘 鹴 +鸚 鹦 +鸛 鹳 +鸝 鹂 +鸞 鸾 +鹵 卤 +鹹 咸 +鹺 鹾 +鹼 碱 +鹽 盐 +麗 丽 +麥 麦 +麨 𪎊 +麩 麸 +麪 面 麺 +麫 面 +麬 𤿲 +麯 曲 +麲 𪎉 +麳 𪎌 +麴 曲 麹 +麵 面 麺 +麷 𫜑 +麼 么 麽 +麽 么 麽 +黃 黄 +黌 黉 +點 点 +黨 党 +黲 黪 +黴 霉 +黶 黡 +黷 黩 +黽 黾 +黿 鼋 +鼂 鼌 +鼉 鼍 +鼕 冬 +鼴 鼹 +齊 齐 +齋 斋 +齎 赍 +齏 齑 +齒 齿 +齔 龀 +齕 龁 +齗 龂 +齙 龅 +齜 龇 +齟 龃 +齠 龆 +齡 龄 +齣 出 +齦 龈 +齧 啮 𫜩 +齩 𫜪 +齪 龊 +齬 龉 +齭 𫜭 +齯 𫠜 +齰 𫜬 +齲 龋 +齴 𫜮 +齶 腭 +齷 龌 +齾 𫜰 +龍 龙 +龎 厐 +龐 庞 +龑 䶮 +龓 𫜲 +龔 龚 +龕 龛 +龜 龟 +龭 𩨎 +龯 𨱆 +鿁 䜤 +鿓 鿒 +𠁞 𠀾 +𠌥 𠆿 +𠏢 𠉗 +𠐊 𫝋 +𠗣 㓆 +𠞆 𠛆 +𠠎 𠚳 +𠬙 𪠡 +𠽃 𪠺 +𠿕 𪜎 +𡂡 𪢒 +𡃄 𪡺 +𡃕 𠴛 +𡃤 𪢐 +𡄔 𠴢 +𡄣 𠵸 +𡅏 𠲥 +𡅯 𪢖 +𡑭 𡋗 +𡓁 𪤄 +𡓾 𡋀 +𡔖 𡍣 +𡞵 㛟 +𡟫 𫝪 +𡠹 㛿 +𡢃 㛠 +𡮉 𡭜 +𡮣 𡭬 +𡳳 𡳃 +𡸗 𪨩 +𡹬 𪨹 +𡻕 岁 +𡽗 𡸃 +𡾱 㟜 +𡿖 𪩛 +𢍰 𪪴 +𢠼 𢙑 +𢣐 𪬚 +𢣚 𢘝 +𢣭 𢘞 +𢤩 𪫡 +𢤱 𢘙 +𢤿 𪬯 +𢯷 𪭝 +𢶒 𪭯 +𢶫 𢫞 +𢷮 𢫊 +𢹿 𢬦 +𢺳 𪮳 +𣈶 暅 +𣋋 𣈣 +𣍐 𫧃 +𣙎 㭣 +𣜬 𪳗 +𣝕 𣘷 +𣞻 𣘓 +𣠩 𣞎 +𣠲 𣑶 +𣯩 𣯣 +𣯴 𣭤 +𣯶 毶 +𣽏 𪶮 +𣾷 㳢 +𣿉 𣶫 +𤁣 𣺽 +𤄷 𪶒 +𤅶 𣷷 +𤑳 𤎻 +𤑹 𪹀 +𤒎 𤊀 +𤒻 𪹹 +𤓌 𪹠 +𤓎 𤎺 +𤓩 𤊰 +𤘀 𪺣 +𤛮 𤙯 +𤛱 𫞢 +𤜆 𪺪 +𤠮 𪺸 +𤢟 𤝢 +𤢻 𢢐 +𤩂 𫞧 +𤪺 㻘 +𤫩 㻏 +𤬅 𪼴 +𤳷 𪽝 +𤳸 𤳄 +𤷃 𪽭 +𤸫 𤶧 +𤺔 𪽴 +𥊝 𥅿 +𥌃 𥅘 +𥏝 𪿊 +𥕥 𥐰 +𥖅 𥐯 +𥖲 𪿞 +𥗇 𪿵 +𥜐 𫀓 +𥜰 𫀌 +𥞵 𥞦 +𥢢 䅪 +𥢶 𫞷 +𥢷 𫀮 +𥨐 𥧂 +𥪂 𥩺 +𥯤 𫁳 +𥴨 𫂖 +𥴼 𫁺 +𥵃 𥱔 +𥵊 𥭉 +𥶽 𫁱 +𥸠 𥮋 +𥻦 𫂿 +𥼽 𥹥 +𥽖 𥺇 +𥾯 𫄝 +𥿊 𦈈 +𦀖 𫄦 +𦂅 𦈒 +𦃄 𦈗 +𦃩 𫄯 +𦅇 𫄪 +𦅈 𫄵 +𦆲 𫟇 +𦒀 𫅥 +𦔖 𫅼 +𦘧 𡳒 +𦟼 𫆝 +𦠅 𫞅 +𦡝 𫆫 +𦢈 𣍨 +𦣎 𦟗 +𦧺 𫇘 +𦪙 䑽 +𦪽 𦨩 +𦱌 𫇪 +𦾟 𦶻 +𧎈 𧌥 +𧒯 𫊹 +𧔥 𧒭 +𧕟 𧉐 +𧜗 䘞 +𧜵 䙊 +𧝞 䘛 +𧞫 𫌋 +𧟀 𧝧 +𧡴 𫌫 +𧢄 𫌬 +𧦝 𫍞 +𧦧 𫍟 +𧩕 𫍭 +𧩙 䜥 +𧩼 𫍶 +𧫝 𫍺 +𧬤 𫍼 +𧭈 𫍾 +𧭹 𫍐 +𧳟 𧳕 +𧵳 䞌 +𧶔 𧹓 +𧶧 䞎 +𧷎 𪠀 +𧸘 𫎨 +𧹈 𪥠 +𧽯 𫎸 +𨂐 𫏌 +𨄣 𨀱 +𨅍 𨁴 +𨆪 𫏕 +𨇁 𧿈 +𨇞 𨅫 +𨇤 𫏨 +𨇰 𫏞 +𨇽 𫏑 +𨈊 𨂺 +𨈌 𨄄 +𨊰 䢀 +𨊸 䢁 +𨊻 𨐆 +𨋢 䢂 +𨌈 𫐍 +𨍰 𫐔 +𨎌 𫐋 +𨎮 𨐉 +𨏠 𨐇 +𨏥 𨐊 +𨞺 𫟫 +𨟊 𫟬 +𨢿 𨡙 +𨣈 𨡺 +𨣞 𨟳 +𨣧 𨠨 +𨤻 𨤰 +𨥛 𨱀 +𨥟 𫓫 +𨦫 䦀 +𨧀 𬭊 +𨧜 䦁 +𨧰 𫟽 +𨧱 𨱊 +𨨏 𬭛 +𨨛 𫓼 +𨨢 𫓿 +𨩰 𫟾 +𨪕 𫓮 +𨫒 𨱐 +𨬖 𫔏 +𨭆 𬭶 +𨭎 𬭳 +𨭖 𫔑 +𨭸 𫔐 +𨮂 𨱕 +𨮳 𫔒 +𨯅 䥿 +𨯟 𫔓 +𨰃 𫔉 +𨰋 𫓳 +𨰥 𫔕 +𨰲 𫔃 +𨲳 𫔖 +𨳑 𨸁 +𨳕 𨸀 +𨴗 𨸅 +𨴹 𫔲 +𨵩 𨸆 +𨵸 𨸇 +𨶀 𨸉 +𨶏 𨸊 +𨶮 𨸌 +𨶲 𨸋 +𨷲 𨸎 +𨼳 𫔽 +𨽏 𨸘 +𩀨 𫕚 +𩅙 𫕨 +𩎖 𫖑 +𩎢 𩏾 +𩏂 𫖓 +𩏠 𫖖 +𩏪 𩏽 +𩏷 𫃗 +𩑔 𫖪 +𩒎 𫖭 +𩓣 𩖕 +𩓥 𫖵 +𩔑 𫖷 +𩔳 𫖴 +𩖰 𫠇 +𩗀 𩙦 +𩗓 𫗈 +𩗴 𫗉 +𩘀 𩙩 +𩘝 𩙭 +𩘹 𩙨 +𩘺 𩙬 +𩙈 𩙰 +𩚛 𩟿 +𩚥 𩠀 +𩚩 𫗡 +𩚵 𩠁 +𩛆 𩠂 +𩛌 𫗤 +𩛡 𫗨 +𩛩 𩠃 +𩜇 𩠉 +𩜦 𩠆 +𩜵 𩠊 +𩝔 𩠋 +𩝽 𫗳 +𩞄 𩠎 +𩞦 𩠏 +𩞯 䭪 +𩟐 𩠅 +𩟗 𫗚 +𩠴 𩠠 +𩡣 𩡖 +𩡺 𩧦 +𩢡 𩧬 +𩢴 𩧵 +𩢸 𩧳 +𩢾 𩧮 +𩣏 𩧶 +𩣑 䯃 +𩣫 𩧸 +𩣵 𩧻 +𩣺 𩧼 +𩤊 𩧩 +𩤙 𩨆 +𩤲 𩨉 +𩤸 𩨅 +𩥄 𩨋 +𩥇 𩨍 +𩥉 𩧱 +𩥑 𩨌 +𩦠 𫠌 +𩧆 𩨐 +𩭙 𩬣 +𩯁 𫙂 +𩯳 𩯒 +𩰀 𩬤 +𩰹 𩰰 +𩳤 𩲒 +𩴵 𩴌 +𩵦 𫠏 +𩵩 𩽺 +𩵹 𩽻 +𩶁 𫚎 +𩶘 䲞 +𩶰 𩽿 +𩶱 𩽽 +𩷰 𩾄 +𩸃 𩾅 +𩸄 𫚝 +𩸡 𫚟 +𩸦 𩾆 +𩻗 𫚨 +𩻬 𫚩 +𩻮 𫚘 +𩼶 𫚬 +𩽇 𩾎 +𩿅 𫠖 +𩿤 𫛠 +𩿪 𪉄 +𪀖 𫛧 +𪀦 𪉅 +𪀾 𪉋 +𪁈 𪉉 +𪁖 𪉌 +𪂆 𪉎 +𪃍 𪉐 +𪃏 𪉏 +𪃒 𫛻 +𪃧 𫛹 +𪄆 𪉔 +𪄕 𪉒 +𪅂 𫜂 +𪆷 𫛾 +𪇳 𪉕 +𪈼 𱊜 +𪉸 𫜊 +𪋿 𫧮 +𪌭 𫜓 +𪍠 𫜕 +𪓰 𫜟 +𪔵 𪔭 +𪘀 𪚏 +𪘯 𪚐 +𪙏 𫜯 +𪟖 𠛾 +𪷓 𣶭 +𫒡 𫓷 +𫜦 𫜫 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TSPhrases.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TSPhrases.txt new file mode 100644 index 0000000000000000000000000000000000000000..dee97540c2170d612e2bc8c07417cc2387eea50b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TSPhrases.txt @@ -0,0 +1,276 @@ +一目瞭然 一目了然 +上鍊 上链 +不瞭解 不了解 +么麼 幺麽 +么麽 幺麽 +乾乾淨淨 干干净净 +乾乾脆脆 干干脆脆 +乾元 乾元 +乾卦 乾卦 +乾嘉 乾嘉 +乾圖 乾图 +乾坤 乾坤 +乾坤一擲 乾坤一掷 +乾坤再造 乾坤再造 +乾坤大挪移 乾坤大挪移 +乾宅 乾宅 +乾斷 乾断 +乾旦 乾旦 +乾曜 乾曜 +乾清宮 乾清宫 +乾盛世 乾盛世 +乾紅 乾红 +乾綱 乾纲 +乾縣 乾县 +乾象 乾象 +乾造 乾造 +乾道 乾道 +乾陵 乾陵 +乾隆 乾隆 +乾隆年間 乾隆年间 +乾隆皇帝 乾隆皇帝 +以免藉口 以免借口 +以功覆過 以功复过 +侔德覆載 侔德复载 +傢俱 家具 +傷亡枕藉 伤亡枕藉 +八濛山 八濛山 +凌藉 凌借 +出醜狼藉 出丑狼藉 +函覆 函复 +千鍾粟 千锺粟 +反反覆覆 反反复复 +反覆 反复 +反覆思維 反复思维 +反覆思量 反复思量 +反覆性 反复性 +名覆金甌 名复金瓯 +哪吒 哪吒 +回覆 回复 +壺裏乾坤 壶里乾坤 +大目乾連冥間救母變文 大目乾连冥间救母变文 +宫商角徵羽 宫商角徵羽 +射覆 射复 +尼乾陀 尼乾陀 +幺麼 幺麽 +幺麼小丑 幺麽小丑 +幺麼小醜 幺麽小丑 +康乾 康乾 +張法乾 张法乾 +彷彿 仿佛 +彷徨 彷徨 +徵弦 徵弦 +徵絃 徵弦 +徵羽摩柯 徵羽摩柯 +徵聲 徵声 +徵調 徵调 +徵音 徵音 +情有獨鍾 情有独钟 情有独锺 +憑藉 凭借 +憑藉着 凭借着 +手鍊 手链 +扭轉乾坤 扭转乾坤 +找藉口 找借口 +拉鍊 拉链 +拉鍊工程 拉链工程 +拜覆 拜复 +據瞭解 据了解 +文錦覆阱 文锦复阱 +於世成 於世成 +於乎 於乎 +於仲完 於仲完 +於倫 於伦 +於其一 於其一 +於則 於则 +於勇明 於勇明 +於呼哀哉 於呼哀哉 +於單 於单 +於坦 於坦 +於崇文 於崇文 +於忠祥 於忠祥 +於惟一 於惟一 +於戲 於戏 +於敖 於敖 +於梨華 於梨华 +於清言 於清言 +於潛 於潜 +於琳 於琳 +於穆 於穆 +於竹屋 於竹屋 +於菟 於菟 +於邑 於邑 +於陵子 於陵子 +旋乾轉坤 旋乾转坤 +旋轉乾坤 旋转乾坤 +旋轉乾坤之力 旋转乾坤之力 +明瞭 明了 +明覆 明复 +書中自有千鍾粟 书中自有千锺粟 +有序 有序 +朝乾夕惕 朝乾夕惕 +木吒 木吒 +李乾德 李乾德 +李澤鉅 李泽钜 +李鍊福 李链福 +李鍾郁 李锺郁 +樊於期 樊於期 +沈沒 沉没 +沈沒成本 沉没成本 +沈積 沉积 +沈船 沉船 +沈默 沉默 +流徵 流徵 +浪蕩乾坤 浪荡乾坤 +滑藉 滑借 +無序 无序 +牴牾 抵牾 +牴觸 抵触 +狐藉虎威 狐借虎威 +珍珠項鍊 珍珠项链 +甚鉅 甚钜 +申覆 申复 +畢昇 毕昇 +發覆 发复 +盼既示覆 盼既示复 +瞭如 了如 +瞭如指掌 了如指掌 +瞭望 瞭望 +瞭然 了然 +瞭然於心 了然于心 +瞭若指掌 了若指掌 +瞭解 了解 +瞭解到 了解到 +示覆 示复 +神祇 神祇 +稟覆 禀复 +答覆 答复 +篤麼 笃麽 +簡單明瞭 简单明了 +籌畫 筹划 +素藉 素借 +老態龍鍾 老态龙钟 老态龙锺 +肘手鍊足 肘手链足 +茵藉 茵借 +萬鍾 万锺 +蒜薹 蒜薹 +蕓薹 芸薹 +蕩覆 荡复 +蕭乾 萧乾 +藉代 借代 +藉以 借以 +藉助 借助 +藉助於 借助于 +藉卉 借卉 +藉口 借口 +藉喻 借喻 +藉寇兵 借寇兵 +藉寇兵齎盜糧 借寇兵赍盗粮 +藉手 借手 +藉據 借据 +藉故 借故 +藉故推辭 借故推辞 +藉方 借方 +藉條 借条 +藉槁 借槁 +藉機 借机 +藉此 借此 +藉此機會 借此机会 +藉甚 借甚 +藉由 借由 +藉着 借着 +藉端 借端 +藉端生事 借端生事 +藉箸代籌 借箸代筹 +藉草枕塊 借草枕块 +藉藉 藉藉 +藉藉无名 藉藉无名 +藉詞 借词 +藉讀 借读 +藉資 借资 +衹得 只得 +衹見樹木 只见树木 +衹見樹木不見森林 只见树木不见森林 +袖裏乾坤 袖里乾坤 +覆上 复上 +覆住 复住 +覆信 复信 +覆冒 复冒 +覆呈 复呈 +覆命 复命 +覆墓 复墓 +覆宗 复宗 +覆帳 复帐 +覆幬 复帱 +覆成 复成 +覆按 复按 +覆文 复文 +覆杯 复杯 +覆校 复校 +覆瓿 复瓿 +覆盂 复盂 +覆盆 覆盆 +覆盆子 覆盆子 +覆盤 覆盘 +覆育 复育 +覆蕉尋鹿 复蕉寻鹿 +覆逆 复逆 +覆醢 复醢 +覆醬瓿 复酱瓿 +覆電 复电 +覆露 复露 +覆鹿尋蕉 复鹿寻蕉 +覆鹿遺蕉 复鹿遗蕉 +覆鼎 复鼎 +見覆 见复 +角徵 角徵 +角徵羽 角徵羽 +計畫 计划 +變徵 变徵 +變徵之聲 变徵之声 +變徵之音 变徵之音 +貂覆額 貂复额 +買臣覆水 买臣复水 +踅門瞭戶 踅门了户 +躪藉 躏借 +郭子乾 郭子乾 +酒逢知己千鍾少 酒逢知己千锺少 +酒逢知己千鍾少話不投機半句多 酒逢知己千锺少话不投机半句多 +醞藉 酝借 +重覆 重复 +金吒 金吒 +金鍊 金链 +鈞覆 钧复 +鉅子 钜子 +鉅萬 钜万 +鉅防 钜防 +鉸鍊 铰链 +銀鍊 银链 +錢鍾書 钱锺书 +鍊墜 链坠 +鍊子 链子 +鍊形 链形 +鍊條 链条 +鍊錘 链锤 +鍊鎖 链锁 +鍛鍾 锻锺 +鍾繇 钟繇 锺繇 +鍾萬梅 锺万梅 +鍾重發 锺重发 +鍾鍛 锺锻 +鍾馗 锺馗 +鎖鍊 锁链 +鐵鍊 铁链 +鑽石項鍊 钻石项链 +雁杳魚沈 雁杳鱼沉 +雖覆能復 虽覆能复 +電覆 电复 +露覆 露复 +項鍊 项链 +頗覆 颇复 +頸鍊 颈链 +顛乾倒坤 颠乾倒坤 +顛倒乾坤 颠倒乾坤 +顧藉 顾借 +麼些族 麽些族 +黄鍾公 黄锺公 +龍鍾 龙钟 龙锺 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWPhrasesIT.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWPhrasesIT.txt new file mode 100644 index 0000000000000000000000000000000000000000..609341ee8d19052f08ea4966382247285e586ce6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWPhrasesIT.txt @@ -0,0 +1,386 @@ +PN結 PN接面 +SQL注入 SQL隱碼攻擊 +SQL注入攻擊 SQL隱碼攻擊 +U盤 隨身碟 +三極管 三極體 +下拉列表 下拉選單 +並行計算 平行計算 +中間件 中介軟體 +串口 串列埠 +串行 序列 +串行端口 串列埠 +主引導記錄 主開機記錄 +主板 主機板 +二極管 二極體 +互聯網 網際網路 +交互 互動 +交互式 互動式 +人工智能 人工智慧 +代碼 程式碼 代碼 +代碼頁 內碼表 +以太網 乙太網 +任務欄 工作列 +任務管理器 工作管理員 +仿真 模擬 +位圖 點陣圖 +低級 低階 低級 +便攜式 行動式 攜帶型 +保存 儲存 +信噪比 訊雜比 +信息 資訊 +信息安全 資訊保安 +信息技術 資訊科技 +信息論 資訊理論 +信號 訊號 信號 +信道 通道 +傳感 感測 +像素 畫素 +僞代碼 虛擬碼 +優先級 優先順序 +優化 最佳化 +元數據 後設資料 +元編程 超程式設計 +光標 游標 +光盤 光碟 +光驅 光碟機 +免提 擴音 +內存 記憶體 +內核 核心 +內置 內建 +內聯函數 行內函數 +全局 全域性 +全角 全形 +兼容 相容 +冒泡排序 氣泡排序 +函數 函式 +函數式編程 函數語言程式設計 +刀片服務器 刀鋒伺服器 +分佈式 分散式 +分區 分割槽 +分辨率 解析度 +刷新 重新整理 +刻錄 燒錄 +前綴 字首 +剪切 剪下 +剪貼板 剪貼簿 +創建 建立 +加載 載入 +半角 半形 +博客 部落格 +卸載 解除安裝 +原代碼 原始碼 +參數 引數 +參數表 參數列 +句柄 控制代碼 +可視化 視覺化 +呼出 撥出 +呼叫轉移 來電轉駁 +命令式編程 指令式程式設計 +命令行 命令列 +命名空間 名稱空間 +哈希 雜湊 +單片機 微控制器 +回調 回撥 +固件 韌體 +圖像 影象 +圖庫 相簿 +圖標 圖示 +在線 線上 +地址 地址 位址 +地址欄 位址列 +城域網 都會網路 +堆棧 堆疊 +場效應管 場效電晶體 +壁紙 桌布 壁紙 +外置 外接 +外鍵 外來鍵 +多任務 多工 +多態 多型 +多線程 多執行緒 +字庫 字型檔 +字段 欄位 +字符 字元 +字符串 字串 +字符集 字符集 +字節 位元組 +字體 字型 +存儲 儲存 +存盤 存檔 +宏 宏 巨集 +宏內核 單核心 +寄存器 暫存器 +密鑰 金鑰 +實例 例項 實例 +實模式 真實模式 +審覈 稽覈 +寫保護 防寫 +寬帶 寬頻 +尋址 定址 +對話框 對話方塊 +對象 物件 對象 +導入 匯入 +導出 匯出 +局域網 區域網 +局部 區域性 +屏幕 螢幕 +屏蔽 遮蔽 +嵌套 巢狀 +布爾 布林 +帶寬 頻寬 +引導程序 載入程式 +彙編 彙編 組譯 +彙編語言 組合語言 +後綴 字尾 +循環 迴圈 循環 +性價比 價效比 +性能 效能 +截取 擷取 +截屏 截圖 +打印 列印 +打印機 印表機 +打開 開啟 打開 +批量 批次 +拋出 丟擲 +拷貝 複製 +持久性 永續性 +指針 指標 +捲積 摺積 +掃描儀 掃描器 +掛斷 結束通話 +採樣 取樣 +採樣率 取樣率 +接口 介面 +控件 控制元件 +插件 外掛 +搜索 搜尋 +操作數 運算元 +操作符 運算子 +操作系統 作業系統 +擴展 擴充套件 +擴展名 副檔名 +支持 支援 +支持者 支持者 +散列 雜湊 +數字 數字 數位 +數字印刷 數位印刷 +數字電子 數位電子 +數字電路 數位電路 +數據 資料 +數據倉庫 資料倉儲 +數據報 資料包 +數據庫 資料庫 +數據挖掘 資料探勘 +數據源 資料來源 +數組 陣列 +文件 檔案 +文件名 檔名 +文件夾 資料夾 +文件擴展名 副檔名 +文字處理 文書處理 +文本 文字 +文檔 文件 +映射 對映 +時分多址 分時多重進接 +時分複用 分時多工 +時鐘頻率 時脈頻率 +晶閘管 閘流體 +晶體管 電晶體 +智能 智慧 +最終用戶 終端使用者 +有損壓縮 有失真壓縮 +服務器 伺服器 +本地代碼 原生代碼 +析構函數 解構函式 +枚舉 列舉 +查找 查詢 +查看 檢視 +桌面型 桌上型 +構造函數 建構函式 +標識符 識別符號 +模塊 模組 +模擬 模擬 類比 +模擬電子 類比電子 +模擬電路 類比電路 +權限 許可權 +正則表達式 正規表示式 +死機 宕機 +殺毒 防毒 +比特 位元 +比特幣 比特幣 +比特率 位元率 +波分複用 波長分波多工 +消息 訊息 消息 +添加 新增 +源代碼 原始碼 +源文件 原始檔 +源碼 原始碼 +溢出 溢位 +滾動條 捲軸 +演示文稿 簡報 +激光 鐳射 +激活 啟用 +無損壓縮 無失真壓縮 +物理內存 實體記憶體 +物理地址 實體地址 +狀態欄 狀態列 +用戶 使用者 +用戶名 使用者名稱 +界面 介面 +異步 非同步 +登錄 登入 +發佈 釋出 +發送 傳送 +皮膚 面板 +盤片 碟片 +盤符 碟符 +目標代碼 目的碼 +相冊 相簿 +矢量 向量 +知識產權 智慧財產權 +短信 簡訊 +硬件 硬體 +硬盤 硬碟 +碼分多址 分碼多重進接 +碼率 位元速率 +磁盤 磁碟 +磁道 磁軌 +社區 社羣 社區 +移動硬盤 行動硬碟 +移動網絡 行動網路 +移動資料 行動資料 +移動通信 行動通訊 +移動電話 行動電話 +程序 程式 +程序員 程式設計師 +空分多址 分空間多重進接 +空分複用 空間多工 +窗口 視窗 +端口 埠 +筆記本電腦 膝上型電腦 +算子 運算元 +算法 演算法 +範式 正規化 +粘貼 貼上 粘貼 +紅心大戰 傷心小棧 +組件 元件 +綁定 繫結 +網上鄰居 網路上的芳鄰 +網卡 網絡卡 +網吧 網咖 +網絡 網路 +網關 閘道器 +線程 執行緒 +編程 程式設計 +編程語言 程式語言 +緩存 快取 +縮略圖 縮圖 +縮進 縮排 +總線 匯流排 +缺省 預設 +聯繫 聯絡 +聯繫歷史 通話記錄 +聲卡 音效卡 +聲明 宣告 +脫機 離線 +腳本 指令碼 +自動轉屏 自動旋轉螢幕 +臺式機 桌上型電腦 +航天飛機 太空梭 +芯片 晶片 +花屏 破圖 +菜單 選單 菜單 +萬維網 全球資訊網 +藍屏 藍色畫面 +藍牙 藍芽 +虛函數 虛擬函式 +虛擬機 虛擬機器 +表達式 表示式 運算式 +複印 影印 +複選按鈕 覈取按鈕 +複選框 覈取方塊 +視圖 檢視 +視頻 影片 視訊 +解釋器 直譯器 +觸摸 觸控 +觸摸屏 觸控式螢幕 +計算機安全 電腦保安 +計算機科學 電腦科學 +訪問 訪問 存取 +設備 裝置 +設置 設定 +註冊機 序號產生器 +註冊表 登錄檔 +註銷 登出 +調制 調變 +調度 排程 +調用 呼叫 +調色板 調色盤 +調製解調器 數據機 +調試 除錯 偵錯 +調試器 偵錯程式 +變量 變數 +軟件 軟體 +軟驅 軟碟機 +轉義字符 跳脫字元 +通信 通訊 +通訊卡 通話卡 +通配符 萬用字元 +連接 連線 +連接器 聯結器 +進制 進位制 +進程 程序 進程 +運算符 運算子 +運行 執行 +過程式編程 程序式程式設計 +遞歸 遞迴 +遠程 遠端 +適配器 介面卡 +邏輯門 邏輯閘 +重命名 重新命名 +重裝 重灌 +重載 過載 +金屬氧化物半導體 金氧半導體 +錄像 錄影 +鏈接 連結 +鏈表 連結串列 +鏡像 映象 +門戶網站 入口網站 +門電路 閘電路 +閃存 快閃記憶體 +關係數據庫 關聯式資料庫 +隊列 佇列 +集成 整合 +集成電路 積體電路 +集羣 叢集 +雲存儲 雲端儲存 +雲計算 雲端計算 +面向對象 物件導向 +面向過程 程序導向 +音頻 音訊 +頁眉 頁首 +頁腳 頁尾 +項目 專案 +預處理器 前處理器 +頭文件 標頭檔案 +頻分多址 分頻多重進接 +頻分複用 分頻多工 +類型 型別 +類模板 類别範本 +顯像管 映象管 +顯卡 顯示卡 +顯存 視訊記憶體 +飛行模式 飛航模式 +首席信息官 資訊長 +首席執行官 執行長 +首席技術官 技術長 +首席運營官 營運長 +高性能計算 高效能運算 +高清 高畫質 +高端 高階 進階 +高級 高階 進階 高級 +高速緩存 快取記憶體 +黑客 駭客 +默認 預設 +默認值 預設值 +點擊 點選 +鼠標 滑鼠 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWPhrasesName.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWPhrasesName.txt new file mode 100644 index 0000000000000000000000000000000000000000..6437a5531ec0bf8859fdd489a3f725c6814f37d3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWPhrasesName.txt @@ -0,0 +1,84 @@ +乍得 查德 +也門 葉門 +仙童半導體 快捷半導體 +伯利茲 貝里斯 +佛得角 維德角 +傅里葉 傅立葉 +克羅地亞 克羅埃西亞 +列支敦士登 列支敦斯登 +利比里亞 賴比瑞亞 +加納 迦納 +加蓬 加彭 +博茨瓦納 波札那 +卡塔爾 卡達 +危地馬拉 瓜地馬拉 +厄瓜多爾 厄瓜多 +厄立特里亞 厄利垂亞 +吉布堤 吉布地 +哈薩克斯坦 哈薩克 +哥斯達黎加 哥斯大黎加 +喫茶小舖 喫茶小舖 +圖瓦盧 吐瓦魯 +土庫曼斯坦 土庫曼 +圭亞那 蓋亞那 +坦桑尼亞 坦尚尼亞 +埃塞俄比亞 衣索比亞 +基里巴斯 吉里巴斯 +塔吉克斯坦 塔吉克 +塞拉利昂 獅子山 +塞浦路斯 塞普勒斯 +塞舌爾 塞席爾 +多米尼加 多明尼加 +安提瓜和巴布達 安地卡及巴布達 +尼日利亞 奈及利亞 +尼日爾 尼日 +岡比亞 甘比亞 +巴巴多斯 巴貝多 +巴布亞新幾內亞 巴布亞紐幾內亞 +布基納法索 布吉納法索 +布隆迪 蒲隆地 +帕勞 帛琉 +幾內亞比紹 幾內亞比索 +意大利 義大利 +所羅門羣島 索羅門羣島 +文萊 汶萊 +斯威士蘭 史瓦濟蘭 +斯洛文尼亞 斯洛維尼亞 +新西蘭 紐西蘭 +格林納達 格瑞那達 +格魯吉亞 喬治亞 +歐拉 尤拉 +毛里塔尼亞 茅利塔尼亞 +毛里求斯 模里西斯 +沙特阿拉伯 沙烏地阿拉伯 +波斯尼亞黑塞哥維那 波士尼亞赫塞哥維納 +津巴布韋 辛巴威 +洪都拉斯 宏都拉斯 +溫納圖萬 那杜 +烏茲別克斯坦 烏茲別克 +特立尼達和多巴哥 千里達及托巴哥 +瑙魯 諾魯 +瓦努阿圖 萬那杜 +盧旺達 盧安達 +科摩羅 葛摩 +科特迪瓦 象牙海岸 +突尼斯 突尼西亞 +純喫茶 純喫茶 +索馬里 索馬利亞 +老撾 寮國 +聖基茨和尼維斯 聖克里斯多福及尼維斯 +聖文森特和格林納丁斯 聖文森及格瑞那丁 +聖盧西亞 聖露西亞 +聖馬力諾 聖馬利諾 +肯尼亞 肯亞 +莫桑比克 莫三比克 +萊索托 賴索托 +萬象 永珍 +蘇里南 蘇利南 +貝寧 貝南 +贊比亞 尚比亞 +阿塞拜疆 亞塞拜然 +阿拉伯聯合酋長國 阿拉伯聯合大公國 +香農 夏農 +馬爾代夫 馬爾地夫 +馬里共和國 馬利共和國 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWPhrasesOther.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWPhrasesOther.txt new file mode 100644 index 0000000000000000000000000000000000000000..265bf1ad8755d25fef398a7f46fddbdb1ac88b10 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWPhrasesOther.txt @@ -0,0 +1,36 @@ +元音 母音 +冰棍 冰棒 +出租車 計程車 +咖喱 咖哩 +塑料 塑膠 +奔馳 賓士 +奶酪 乳酪 +幾率 機率 +方便麪 泡麵 速食麵 +李彥宏 李彥宏 +概率 機率 +海內存知己 海內存知己 +涼菜 冷盤 +的士 計程車 +砹 砈 +硅 矽 +程序不正義 程序不正義 +程序正義 程序正義 +空氣淨化器 空氣清淨機 +納米 奈米 +自行車 腳踏車 +詞組 片語 +蹦極 高空彈跳 +輔音 子音 +通過 透過 通過 +酰 醯 +鈁 鍅 +鈈 鈽 +錇 鉳 +鍀 鎝 +鎄 鑀 +鎇 鋂 +鎿 錼 +鐦 鉲 +鑥 鎦 +黃宏 黃宏 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWVariants.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWVariants.txt new file mode 100644 index 0000000000000000000000000000000000000000..023a0687b6c637a96d6b157f53bb98dec00d3166 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWVariants.txt @@ -0,0 +1,39 @@ +僞 偽 +啓 啟 +喫 吃 +嫺 嫻 +嬀 媯 +峯 峰 +幺 么 +擡 抬 +棱 稜 +檐 簷 +污 汙 +泄 洩 +潙 溈 +潨 潀 +爲 為 +牀 床 +痹 痺 +癡 痴 +皁 皂 +着 著 +睾 睪 +祕 秘 +竈 灶 +糉 粽 +繮 韁 +纔 才 +羣 群 +脣 唇 +蔘 參 +蔿 蒍 +衆 眾 +裏 裡 +覈 核 +踊 踴 +鉢 缽 +鍼 針 +鮎 鯰 +麪 麵 +齶 顎 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWVariantsRevPhrases.txt b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWVariantsRevPhrases.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec94209def88ec848786f126b962a3ddf3bc04dd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/dictionary/TWVariantsRevPhrases.txt @@ -0,0 +1,68 @@ +一口吃個 一口喫個 +一口吃成 一口喫成 +一家三口 一家三口 +一家五口 一家五口 +一家六口 一家六口 +一家四口 一家四口 +凶事 凶事 +凶信 凶信 +凶兆 凶兆 +凶吉 凶吉 +凶地 凶地 +凶多吉少 凶多吉少 +凶宅 凶宅 +凶年 凶年 +凶德 凶德 +凶怪 凶怪 +凶日 凶日 +凶服 凶服 +凶歲 凶歲 +凶死 凶死 +凶氣 凶氣 +凶煞 凶煞 +凶燄 凶燄 +凶神 凶神 +凶禮 凶禮 +凶耗 凶耗 +凶肆 凶肆 +凶荒 凶荒 +凶訊 凶訊 +凶豎 凶豎 +凶身 凶身 +凶逆 凶逆 +凶門 凶門 +口吃 口吃 +吃口 喫口 吃口 +吃口令 吃口令 +吃口飯 喫口飯 +吃吃 喫喫 吃吃 +吃子 喫子 吃子 +合著 合著 +吉凶 吉凶 +名著 名著 +四凶 四凶 +大凶 大凶 +巨著 巨著 +張口 張口 +昭著 昭著 +歲凶 歲凶 +胃口 胃口 +著作 著作 +著名 著名 +著式 著式 +著志 著志 +著於 著於 +著書 著書 +著白 著白 +著稱 著稱 +著者 著者 +著述 著述 +著錄 著錄 +蹇吃 蹇吃 +逢凶 逢凶 +避凶 避凶 +鄧艾吃 鄧艾吃 +鉅著 鉅著 +開口 開口 +閔凶 閔凶 +顯著 顯著 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/icon/opencc.svg b/Packages/SwiftyOpenCC/OpenCC/data/icon/opencc.svg new file mode 100644 index 0000000000000000000000000000000000000000..cff146d04ead133394306418b4784a427107f099 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/icon/opencc.svg @@ -0,0 +1,39 @@ + + + +]> + + + + + + + diff --git a/Packages/SwiftyOpenCC/OpenCC/data/scheme/st_multi.txt b/Packages/SwiftyOpenCC/OpenCC/data/scheme/st_multi.txt new file mode 100644 index 0000000000000000000000000000000000000000..d316bbacd6e4bf2a68daec2ac36484f982a3f90c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/scheme/st_multi.txt @@ -0,0 +1,207 @@ +划 劃 畫 划 「划」讀音hua2,意義爲「撥水前進」、「合算」。「劃」讀作hua2時,意義爲「戳傷」,讀作hua4是意義爲「分界」、「設計」。「畫」基本意義爲「繪畫」。 劃分 劃破 圖畫 畫押 划船 划算 +卤 滷 鹵 「滷」特別作爲一種烹調方法,「鹵」用作其他意義或化學元素。 滷汁 滷肉 鹵素 +历 歷 曆 「日曆」作「曆」,與歷史有關用「歷」。 萬年曆 歷史 +发 發 髮 與毛髮有關用「髮」,其餘意義爲「發」。 發財 發送 頭髮 令人髮指 +只 只 隻 「隻」用作量詞,「只」爲副詞「僅」。 船隻 隻言片語 只有 僅只 +台 臺 檯 颱 台 與「平地」有關用「臺」,與「櫃檯」有關用「檯」,與「颱風」有關用「颱」。「台」爲罕用字。 看臺 高臺 電視臺 寫字檯 颱風 兄台 天台山 五臺山 臺灣 +后 後 后 與「帝王」、「帝王配偶」有關用「后」,與「時間先後」有關用「後」。 皇后 以後 +坛 壇 罈 「罈」爲一種容器,其餘意義爲「壇」。 祭壇 論壇 罈子 酒罈 +复 復 複 覆 表示重疊意義用「複」,表示往返意義用「復」,表示「翻倒」、「遮蓋」用「覆」。 複製 重複 反復 恢復 覆蓋 傾覆 翻雲覆雨 反覆無常 +尽 盡 儘 「儘」用於「放開」、「最大限度」之意。其餘用「盡」。 儘管 儘量 極盡 自盡 盡頭 +干 幹 乾 干 榦 「干」本意爲盾牌,意義與武器有關。「乾」意義爲「水分少」。「幹」意義爲「主幹」或爲動詞。「榦」特別用於「版榦」。 干戈 干涉 干擾 干預 乾燥 乾貨 骨幹 幹部 幹活 版榦 +并 並 併 并 「併」特比用於「合併」之義,其餘一般作「並」。 並且 兼併 吞併 并州 兼容并包 +当 當 噹 「噹」用於擬聲詞,其餘用「當」。 叮噹 噹啷 當然 當年 應當 +志 志 誌 與記錄有關用「誌」,其餘用「志」。 志向 志氣 雜誌 日誌 +汇 匯 彙 「彙」爲「相同種類聚集成的東西」,「匯」傾向於「水流匯合」一動作。 辭彙 彙編 彙報 匯合 匯款 +系 系 係 繫 「係」強調「關係」,「系」爲一個整體,「繫」與連接有關。 系統 係數 干係 關係 聯繫 維繫 繫鞋帶 +脏 髒 臟 「臟」讀音zang4,意義爲「身體器官」,「髒」讀音zang1,意義爲「不乾淨」。 內臟 骯髒 +荡 蕩 盪 與「洗滌」、「搖動」有掛用「盪」,其餘用「蕩」。 盪漾 盪滌 動盪 掃蕩 放蕩 蕩然無存 蕩氣迴腸 +获 獲 穫 「獲」一般用於動詞,「穫」一般用於名詞。 不勞而獲 獲益 收穫 +采 採 采 「採」用於動詞,其餘用「采」。 採集 博採眾長 丰采 神采奕奕 +里 裏 里 「裏」與「外」相對,其餘用「里」。 里程 故里 裏外 +钟 鍾 鐘 「鍾」意義爲聚集,「鐘」爲一種樂器。 鍾情 鍾愛 鐘鼓 掩耳盜鐘 +饥 飢 饑 「飢」意義爲「吃不飽」,「饑」意義爲「穀物不熟」。 飢餓 饑荒 饑饉 +丰 豐 丰 表示「美好的容貌的姿態」用「丰」,其餘一般爲「豐」。 丰采 丰姿 豐富 五穀豐登 張三丰 +丑 醜 丑 「丑」用於十二地支和戲角色,「醜」爲「不美」。 小丑 丑角 辛丑條約 醜陋 醜惡 +了 了 瞭 「了」意義爲「完畢」、「完全」。「瞭」讀作liao3時意義爲「明白」、「清楚」,讀作liao4時意義爲「遠看」。 不了了之 了無牽掛 明瞭 瞭解 一目瞭然 瞭望 +借 借 藉 「依賴、假借、草墊」之意用「藉」,其餘一般用「借」。(習慣用法區別) 慰藉 藉口 憑藉 借住 借題發揮 借刀殺人 +克 克 剋 與「戰勝」、「約束」、「傷害」有關意義用「剋」,其餘用「克」。 克服 以柔克剛 千克 攻剋 剋扣 剋夫 +准 準 准 「准」只用於「允許」意義,其餘用「準」。 准許 不准 準備 標準 +刮 刮 颳 「吹襲」用「颳」,其餘用「刮」。 颳風 冰前颳雪 刮鬍子 刮痧 耳刮子 +制 制 製 「製」只用於「製作」相關意義,其餘用「制」。 制度 控制 製作 +吁 籲 吁 「呼喊﹑請求」用「籲」,讀音yu4,「歎氣」用「吁」,讀音xu1。 長吁短歎 呼籲 籲請 +吊 吊 弔 「弔」只用於「祭奠死者」相關意義,其餘用「吊」。 吊車 上吊 弔唁 弔喪 +团 團 糰 與「食品」有關用「糰」,其餘用團。 飯糰 糯米糰 團體 社團 +困 困 睏 「睏」特指「瞌睡」,其餘用「困」。 困擾 困局 貧困 睏意 睏倦 +布 佈 布 「布」爲「紡織品」,其餘用「佈」。 棉布 發佈 佈置 擺佈 遍佈 +御 御 禦 與「抵抗」有關用「禦」,其餘用「御」。 御馬 御用 防禦 抵禦 +斗 鬭 斗 「斗」爲一種容積計量單位,「鬭」表示「鬭爭」之意。 五斗米 車載斗量 鬭爭 戰鬭 +曲 曲 麯 「麯」與釀酒有關,其餘用「曲」。 樂曲 曲直 酒麯 大麯 +松 鬆 松 「松」爲一種樹木名詞,「鬆」與「緊」相對、 松樹 雪松 輕鬆 肉鬆 +淀 澱 淀 「淀」之意義爲「淺水」,其餘用「澱」。 澱粉 沉澱 海淀區 白洋淀 +纤 纖 縴 表示「細小」用「纖」,讀作xian1。表示拉船用「縴」,讀作qian4。 纖維 光纖 縴夫 +致 致 緻 與「細密」、「意趣」有關用「緻」,其餘用致。 導致 致敬 精緻 緻密 別緻 雅緻 +蔑 蔑 衊 表示「血污」、「誹謗」用「衊」,其餘意義用「蔑」。 輕蔑 蔑視 誣衊 +仇 仇 讎 與「校對」有關用「讎」,其餘用「仇」。 仇恨 報仇 讎校 仇讎 +冬 冬 鼕 「鼕」爲鼓聲擬聲詞,其餘用「冬」。 隆冬 冬暖夏涼 鼕鼕 +咸 咸 鹹 「鹹」意義與「淡」相對,其餘用「咸」。 老少咸宜 鹹淡 +云 雲 云 「云」意義爲「說」,其餘用「雲」。 人云亦云 雲霧 +仆 僕 仆 「仆」意義爲「跌倒」,讀音pu1,「僕」爲「供人使喚的人」,讀音pu2。 前仆後繼 仆街 奴僕 公僕 風塵僕僕 +舍 舍 捨 「捨」讀作she3,用於「放棄」意義,其餘用「舍」,讀作she4,古文亦同「捨」。 宿舍 村舍 退避三舍 捨弃 舍我其誰 不舍晝夜 +签 籤 簽 「簽」用於動詞,表示「題字題名」,其餘用「籤」。 簽名 簽證 標籤 書籤 牙籤 +折 折 摺 與「叠」有關用「摺」,與「斷」有關用「折」。 摺紙 摺扇 存摺 折斷 折腰 折服 打折 損兵折將 +谷 谷 穀 表示「兩山之間」的地域用「谷」,表示農作物時用「穀」。 山谷 稻穀 +几 幾 几 「几」只用作「茶几」。表示「幾乎」、「幾個」意義用「幾」。 茶几 幾乎 幾個 +辟 闢 辟 「闢」用於「開墾」、「駁斥」意義。其餘用「辟」。 開闢 闢謠 另闢蹊徑 精闢 辟邪 鞭辟入裏 +奸 奸 姦 「姦」只用於淫亂之意,其餘用「奸」。 漢奸 狼狽爲奸 強姦 +游 遊 游 「游」與「水」有關,其餘用「遊」。 游泳 上游 遊戲 遊蕩 +佣 傭 佣 「傭」爲「僕役」,讀音yong1,「佣」爲「中間人」,讀音yong4。 傭人 雇傭 傭兵 佣金 +苏 蘇 囌 甦 「甦」與「醒」、「恢復」有關,「囌」用於「嚕囌」(囉唆),其餘用「蘇」。 甦醒 甦生 復甦 嚕囌 蘇州 屠蘇 蘇俄 +回 回 迴 與「旋轉」、「返迴」有關用「迴」,其餘用「回」。 迴合 迴光返照 迴旋 迴避 回答 回族 回絕 +面 面 麪 「面」意義爲「臉」、「外表」,「麪」爲小麥磨成的粉。 臉面 麪條 麪粉 +向 向 嚮 曏 「曏」表示「從前」,「嚮」表示「引導」、「傾向」,其餘用「向」。 曏者 嚮導 嚮往 嚮晦 方向 意向 向晚 向背 向來 +伙 夥 伙 「伙」只用於「伙食」、「工具」相關意義,其餘用「夥」。 夥同 夥伴 小夥子 伙食 包伙 傢伙 +郁 鬱 郁 與「文采豐盛」、「濃烈」有關意義用「郁」,其餘用「鬱」。 馥郁 郁郁乎文哉 鬱結 憂鬱 鬱金香 鬱悶 鬱郁 +朴 樸 朴 表示「原本的」意義用「樸」,其他音義用「朴」。 樸素 純樸 質樸 朴刀 朴姓 朴硝 +才 才 纔 表示「方」、「僅」用「纔」,其餘用「才」。 才俊 才幹 才能 纔能 剛纔 方纔 +朱 朱 硃 「硃」用於與「硃砂」有關意義,其餘用「朱」。 硃砂 近朱者赤 +别 別 彆 「彆」讀音bie4,與「彆扭」有關,其餘用「別」。 區別 彆扭 +卷 捲 卷 「捲」表示彎曲,讀音juan3,其餘用「卷」,讀音juan4。 席捲 捲土重來 花捲 試卷 卷帙 讀萬卷書 +蒙 蒙 矇 濛 懞 表示「欺騙」、「猜測」、「盲」用「矇」,表示「細雨」用「濛」,表示「老實」用「懞」,其餘意義用「蒙」。 矇騙 矇蔽 矇混 濛濛細雨 涳濛 懞直 蒙受 蒙昧 啓蒙 蒙古 +征 徵 征 與「召集」和「蹟象」有關用「徵」,與「遠征」、「討伐」有關用「征」。 征服 遠征 徵兵 徵收 徵兆 特徵 徵詢 +症 症 癥 「癥」爲一種「腹中結硬塊的疾病」,讀音zheng1。一般病症用「症」,讀音zheng4。 絕症 癌症 對症下藥 癥結 +恶 惡 噁 「噁心」用「噁」,其餘一般用「惡」。 善惡 噁心 二噁英 +注 注 註 與「記錄」有關意義用「註」,其餘用「注」。 注意 注入 關注 註冊 註釋 命中註定 +哄 哄 鬨 與「眾人喧鬧」有關用「鬨」,讀音hong4,其餘用「哄」。 哄騙 哄孩子 起鬨 一鬨而散 +参 參 蔘 「蔘」表示一種植物,其餘用「參」。 參與 參數 內参 海参崴 人蔘 黃金蔘 +腌 醃 腌 「腌」用於「腌臢」,表示一種食物加工方法用「醃」。 腌臢 醃漬 醃肉 +彩 彩 綵 表示「五彩的絲織品」用「綵」,其餘用「彩」。 張燈結綵 綵頭 剪綵 彩票 五彩繽紛 +占 佔 占 與巫術有關用「占」,讀音zhan1,其餘用「佔」,讀音zhan4。 占卜 占星 佔領 佔據 +欲 欲 慾 「慾」只用於「情慾」有關意義,其餘用「欲」。 獸慾 慾火 貪欲 暢所欲言 震耳欲聾 +扎 扎 紮 表示「纏束」、「軍隊屯駐」用「紮」,其餘用「扎」。 駐紮 包紮 安營紮寨 扎針 扎花 掙扎 +熏 熏 燻 「燻」特指一種烹飪方法,其餘用「熏」。 熏陶 利慾熏心 臭氣熏天 燻肉 +赞 贊 讚 與「表揚」有關意義用「讚」,其餘用「贊」。 贊助 贊同 讚美 +尝 嘗 嚐 與「喫」、「品嚐」有關意義用「嚐」,其餘用「嘗」。 嘗試 品嚐 +吃 喫 吃 解作「食」時用「喫」,解作「言蹇難也」時用「吃」。 喫飯 喫水 口吃 +烟 煙 菸 「煙」用於一般煙霧,與「菸草」有關時用「菸」。 煙霧 菸草 香菸 +周 周 週 賙 與「週期」有關用「週」,濟助他人用「賙」,其餘意義爲「周」。 周朝 眾所周知 週歲 週而復始 賙濟 +柜 櫃 柜 表示收藏東西的傢具時作「櫃」,表示一種落葉喬木用「柜」。 書櫃 柜柳 +喂 餵 喂 表示「餵養」時用「餵」,「喂」僅用作語氣詞。 餵豬 喂! +幸 幸 倖 「倖」專指「意外地成功或避免」,其餘一般用「幸」。 倖免 倖存 僥倖 倖運 幸福 寵幸 慶幸 +凶 兇 凶 與占卜吉凶有關用「凶」,與「殺害」有關用「兇」。 凶宅 吉凶 兇殺 兇器 行兇 +杰 傑 杰 「杰」常用於人名,表示「出眾」用「傑」。 傑出 俊傑 傑作 李連杰 周杰倫 狄仁杰 +针 針 鍼 「鍼」用於以砭石製成的針,其餘均作「針」。 針線 針鋒相對 鍼砭 鍼灸 +戚 戚 慼 鏚 表示「憂愁」、「悲傷」用「慼」,「鏚」爲一種武器,其他意義用「戚」。 悲慼 慼慼 干鏚羽旄 戚繼光 親戚 +托 托 託 與「捧呈」、「承受」有關用「托」,與「寄」、「委任」有關用「託」。 襯托 槍托 寄託 託付 推託 +挨 挨 捱 表示「承受」、「拖延」、「抗拒」有關用「捱」,讀爲ai2,其餘用「挨」,讀爲ai1。 挨家挨戶 捱打 +挽 挽 輓 與「哀悼死者」有關用「輓」,其餘意義爲「挽」。 挽救 力挽狂瀾 輓聯 哀輓 +栗 慄 栗 表示「因恐懼而發抖」用「慄」,其餘意義用「栗」。 板栗 火中取栗 戰慄 不寒而慄 +炼 煉 鍊 專指「熔鍊金屬」時用「鍊」,一般意義用「煉」。 鍊鐵 淬鍊 煉乳 修煉 +链 鏈 鍊 「鏈」用作一般的「金屬繩狀物」,「鍊」專指首飾。 鎖鏈 鏈接 項鍊 金手鍊 +穗 穗 繐 「繐」用作「結紮成的裝飾物」,其餘用「穗」。 麥穗 帽繐 +雕 彫 鵰 「鵰」爲一種猛禽,與「彫刻」有關時用「彫」。 一箭雙鵰 彫刻 彫蟲小技 +梁 樑 梁 與「橋樑」、「棟樑」有關用「樑」,其餘意義爲「梁」。 樑上君子 鼻樑 大梁城 梁朝 梁山 +升 升 昇 「昇」字帶有濃烈喜慶氣氛,其餘用「升」。 上升 一升水 旭日東昇 歌舞昇平 +摆 擺 襬 表示「衣服下緣的部分」用「襬」,其餘用「擺」。 搖擺 擺放 裙襬 下襬 +岩 巖 岩 「岩」只用於「岩石」相關意義,其餘用「巖」。 沉積岩 岩漿 巖壁 中空成巖 +娘 娘 孃 「孃」意義爲「母親」,其餘用「娘」。 老孃 爹孃 孃家 姑娘 娘子 婆娘 舞娘 +僵 僵 殭 「殭」意義爲「不腐朽的屍體」,其餘用「僵」。 殭屍 殭蠶 僵硬 僵局 李代桃僵 百足之蟲,死而不僵 +药 藥 葯 「葯」特指「花的雄蕊中貯藏花粉的部份」,其餘用「藥」。 醫藥 良藥 芍藥 藥到病除 花葯 +余 餘 余 「余」爲第一人稱代詞或地名。 剩餘 多餘 余吾鎮 +蜡 蠟 蜡 「蜡」只用於「蜡月」。 蠟燭 蜂蠟 石蠟 蜡月 +出 出 齣 「齣」只用於「一齣戲」。 出入 出道 一齣戲 +卜 卜 蔔 「蔔」只用於「蘿蔔」。 占卜 卜辭 蘿蔔 +同 同 衕 「衕」只用於「衚衕」。 大同 衚衕 +板 板 闆 「闆」只用於「老闆」。 板塊 老闆 +漓 漓 灕 「灕」只用於「灕江」。 大汗淋漓 淋漓盡致 灕江 灕水 +术 術 朮 「朮」僅用於中藥名「白朮」相關。 法術 白朮 兀朮 +仑 侖 崙 表示「崑崙」時用崙。 崑崙 加侖 +秋 秋 鞦 「鞦」只用於「鞦韆」。 秋季 鞦韆 +千 千 韆 「韆」只用於「鞦韆」。 千萬 鞦韆 +帘 簾 帘 表示旗幟狀的標識用「帘」。 窗簾 珠簾 酒帘 +庵 庵 菴 「菴」只用作「菴藹」,讀作an4。 尼姑庵 菴藹 +尸 屍 尸 「尸」表示「主持」、「佔用」。 屍體 尸位素餐 +胡 胡 衚 鬍 「衚」只用於「衚衕」,「鬍」只用於「鬍鬚」。 胡人 胡亂 衚衕 鬍鬚 +须 須 鬚 「鬚」只用於「鬍鬚」。 必須 鬍鬚 +据 據 据 「据」只用於「拮据」。 數據 根據 拮据 +筑 築 筑 「筑」爲古代一種樂器,其餘用「築」。 建築 築巢 擊筑 +夸 誇 夸 「夸」見於古文和專有名詞。 誇大 誇獎 夸父 夸克 +苹 蘋 苹 「苹」、「蘋」爲兩種不同的植物。 蘋果 白蘋 苹縈 食野之苹 +袅 裊 嫋 與「嬌柔」、「婉轉」有關用「嫋」,其餘意義用「裊」。 嫋娜 餘音嫋嫋 裊繞 +暗 暗 闇 與「愚昧」有關意義用「闇」,其餘用「暗」。 闇昧 愚闇 偏信則闇 棄暗投明 暗號 暗示 黑暗 +冲 衝 沖 冲 與「撞擊」有關用「衝」,與「水流」有關用「沖」,「冲」見於古文。 要衝 衝突 俯衝 沖牛奶 +表 表 錶 「錶」用作「鐘錶」,其餘用「表」。 表達 表示 代表 手錶 +杆 杆 桿 表示細長的棍狀物,「杆」讀音gan1,傾向於較大的,「桿」讀音gan3,傾向於較小的。 球杆 旗杆 電線杆 筆桿 杠桿 大腸桿菌 +鉴 鑒 鑑 用於「鏡子」、「圖章」意義時用「鑑」,其他引申意義均用「鑒」。 銅鑑 印鑑 借鑒 鑒定 明鑒 鑒賞 殷鑒不遠 +搜 搜 蒐 「搜」意義爲「尋找」,與「聚集」和其他意義有關用「蒐」。 搜身 搜尋 蒐集 蒐羅 蒐購 春蒐 +杯 杯 盃 「盃」特別用於「獎盃」 獎盃 冠軍盃 世界盃 +铲 剷 鏟 「剷」用作動詞意義 剷除 鏟子 +扣 扣 釦 「釦」表示衣服上的結 鈕釦 +念 念 唸 與「讀」相近意義用「唸」 唸書 唸經 思念 繫念 +杠 杠 槓 「杠」特別用於「牀杠」 牀杠 +泛 泛 氾 表示「漂浮」「顯現」用「泛」,表示「大水」用「氾」 廣泛 泛舟 泛藍 氾濫 +核 核 覈 與「校對」相關意義用「覈」 覈實 覈對 覈算 考覈 +巨 巨 鉅 「鉅」與金屬有關,或用於固定名詞區別 艱鉅 鉅變 鉅鹿 鉅款 鉅貪 鉅富 鉅子 +叹 嘆 歎 悲傷有關用「嘆」,其他用「歎」 哀嘆 感嘆 仰天長嘆 嘆息 嘆氣 吟歎 詠歎 歎賞 歎爲觀止 歎羨 讚歎 +价 價 价 表示僕役用「价」 小价 貴价 盛价 價格 +私 私 俬 室內使用的器具 傢俬 +局 局 侷 表示「狹小」用「侷」 大局 侷促 侷限 +拐 拐 柺 與「柺杖」有關用「柺」 柺杖 鐵柺李 拐彎 +弦 弦 絃 「絃」專指樂器 管絃 琴絃 續絃 箭在弦上 弦月 +哗 譁 嘩 擬聲詞用「嘩」 嘩啦 譁然 喧譁 譁眾取寵 +凄 悽 淒 傾向於悲慘用「悽」,寒冷用「淒」 淒涼 悽慘 悽楚 悽惻 +家 家 傢 「傢」爲「家」某些意義的分化字 傢俬、傢具、傢伙 +席 席 蓆 「蓆」特指涼蓆 涼蓆 草蓆 +酸 酸 痠 肢體疼痛用「痠」 痠痛 腰痠 +噪 噪 譟 壯大聲勢用「譟」 鼓譟 譟詐 譟動 聒噪 噪音 +咽 咽 嚥 「嚥」用於「吞嚥」之意 下嚥 嗚咽 咽喉 +愈 愈 癒 「癒」表示恢復 癒合 治癒 +凌 凌 淩 「淩」作姓氏 淩氏 +毁 毀 譭 燬 與「燒」、「熔」有關用「燬」。「譭」表示「污衊」。 禁燬 燒燬 詆譭 譭譽參半 譭棄 +苔 苔 薹 「苔」爲「附着在地面上的真菌藻類共生體」,「薹」爲「中央部分所長出來的莖」。 青苔 苔原 苔藓 蒜薹 蕓薹 菜薹 +糊 糊 餬 「填飽肚子」用「餬」。 養家餬口 +抵 抵 牴 「牴」本意爲「有角的獸類用角碰撞」,引申爲「衝突」。 牴觸 牴牾 +恤 恤 卹 「卹」用作「撫慰」「賑濟」,「恤」用作「憂慮」「憐憫」。 體恤 憂國恤民 撫卹 卹金 振窮卹貧 +荫 蔭 廕 表示「庇護」「父祖恩澤」用「廕」。 廕庇 封妻廕子 +皂 皁 皂 「皂」專指肥皂。 香皂 皂莢樹 青紅皁白 +芸 芸 蕓 「蕓」只用作「蕓薹」。 蕓薹 蕓香 +背 背 揹 「揹」作動詞,表示「負荷」,讀陰平聲。 揹黑鍋 揹負 +夫 夫 伕 「伕」指「出苦力的人」。 車伕 轎伕 腳伕 +迹 蹟 跡 「蹟」特指「前人留下的事物」。 遺蹟 事蹟 奇蹟 +涌 湧 涌 「湧」本作「涌」,後分化。「湧」爲「水上溢」;「涌」爲「小河」,讀音chong1。 湧起 洶湧 浪湧 東涌 +录 錄 彔 「彔」爲雕刻木材,見於古文。 +极 極 极 「极」見於古文。 +愿 願 愿 「愿」見於古文,意義爲「忠厚」﹑「謹慎」。 +胜 勝 胜 「胜」爲「腥」之本字。 +确 確 确 「确」見於古文。 +叶 葉 叶 「叶」爲「協」古異體。 +虫 蟲 虫 「虫」爲「虺」的古字。 +厂 廠 厂 「厂」爲「庵」的古字。 +修 修 脩 「脩」指「乾肉」或「酬金」,古通「修」。 +价 價 价 「价」古義爲僕人。 +合 合 閤 「閤」見於古文,意義爲「宮殿」、「邊門」。 +适 適 适 「适」爲一古字,意義爲「迅速」。 +弥 彌 瀰 「瀰」爲「水深滿的樣子」,只見於古文。 +厘 釐 厘 「厘」見於古文。 +涂 塗 涂 「涂」見於姓氏和古文。 +个 個 箇 个 「箇」用於「箇中」地名「箇舊」,「个」見於古文。 +于 於 于 「于」見於姓氏和古文。 +党 黨 党 「党」只用於「党項族」或姓氏。 +种 種 种 「种」爲姓氏,其餘用「種」。 +万 萬 万 「万」只用於複姓「万俟」。 +范 範 范 「范」只用於姓氏,其餘用「範」。 +沈 瀋 沈 「瀋」意義爲「汁」,亦是河流名,「沈」作姓氏(讀作shen3時)。 +姜 姜 薑 「姜」爲姓氏,「薑」爲一種植物調味料。 +闲 閒 閑 「閑」「閒」在一般意義上爲異體字,其他意義見於古文或通假。 +证 證 証 証諫、士尉以証君 +佑 佑 祐 福祉用「祐」。嘉祐 僧祐 +谥 諡 謚 「諡」用於「諡號」,「謚」見於古文。 +熏 熏 燻 「熏」可用於「煙燻」或「薰香」義。 +旋 旋 鏇 「旋」用於「旋轉」等。「鏇」用於「旋轉削切」等。 +沾 沾 霑 「雨水浸潤」、「受恩」等義用「霑」,「浸溼」等義通用,「接觸」「染上」「帶有」等義用「沾」。 +跖 跖 蹠 「腳掌」等以「蹠」為正字。「跖」可用於人名,如「盜跖」。 +玩 玩 翫 「鬆懈、輕忽」用「翫」,其餘「玩」「翫」通用。 +璇 璇 璿 星名用「璇」。「天文儀」、「美玉」義可互通。二字皆有用於人名。 天璇 +它 它 牠 對動物的第三人稱用「牠」。 +蝎 蠍 蝎 「蝎」另兼正字義為「木中蠹蟲」。 +唇 脣 唇 「嘴脣」以「脣」為正字。「唇」另義為「驚駭」,讀作zhēn。 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/scheme/ts_multi.txt b/Packages/SwiftyOpenCC/OpenCC/data/scheme/ts_multi.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ac401fdbb8ba4ce0dffb608fab3fc317e4d7a28 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/scheme/ts_multi.txt @@ -0,0 +1,12 @@ +畫 画 划 +覆 覆 复 +藉 藉 借 +乾 乾 干 +瞭 瞭 了 +鍊 炼 链 +蘋 苹 蘋 +於 于 於 +鉅 巨 钜 +衹 衹 只 +著 着 著 +沈 沈 沉 diff --git a/Packages/SwiftyOpenCC/OpenCC/data/scheme/variant.txt b/Packages/SwiftyOpenCC/OpenCC/data/scheme/variant.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e0a0334573d21a5d7e0ec9a6e3f21b56c86262d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/scheme/variant.txt @@ -0,0 +1,147 @@ +丟 丟 丢 +並 並 竝 +幷 并 幷 +僞 偽 僞 +兌 兌 兑 +內 內 内 +冊 冊 册 +冢 冢 塚 +剁 剁 刴 +剋 剋 尅 +劃 劃 𠟱 劐 𠜻 +劍 劍 劎 劒 剣 剱 劔 +匯 匯 滙 +升 升 陞 阩 𧿘 +只 只 𠮡 𠷓 +呆 呆 獃 +啓 啓 啟 +回 回 囘 囬 +囪 囪 囱 +垛 垛 垜 +埼 埼 碕 崎 隑 +壩 垻 壩 +壺 壷 壺 +夠 够 夠 +嫋 嫋 嬝 +嬀 媯 嬀 +嬤 嬤 嬷 +崙 崙 崘 +嶽 嶽 𡶓 𡶳 𡴳 +廁 廁 厠 +愨 愨 慤 𣪎 +戶 戶 户 戸 +挆 挆 挅 +捂 捂 摀 +擔 擔 担 +擡 擡 抬 +曬 曬 晒 +朵 朵 朶 +杴 杴 鍁 𣞘 +查 査 查 +棱 棱 稜 +殼 㱿 殻 殼 㱿 𣪊 +污 汙 污 汚 +泄 泄 洩 +涌 湧 涌 +溯 溯 泝 +潙 溈 潙 +煙 煙 烟 +爲 爲 為 +牀 牀 床 +牆 牆 墻 +獎 獎 奬 𤟌 㢡 +產 產 産 +畫 畫 畵 𤱪 𨽶 𤲯 +瘻 瘻 瘺 +癡 癡 痴 +衆 衆 眾 +禿 禿 秃 +秋 秋 龝 秌 +秘 祕 秘 +竈 竈 灶 +累 累 纍 +絕 絕 絶 𢇍 𠤉 +絛 絛 縧 +綠 綠 緑 +綫 線 綫 +繃 繃 綳 +繡 繡 綉 +繮 繮 韁 +罈 罈 墰 罎 壜 +罵 罵 駡 +羣 羣 群 +考 考 攷 +脣 脣 唇 +蓴 蓴 蒓 +蘊 蘊 藴 +裏 裏 裡 +說 說 説 +謠 謠 謡 䚻 +譾 譾 謭 +豎 豎 竪 +豔 艷 豔 豓 +贓 贓 贜 +贗 贗 贋 偐 +跺 跺 跥 +踊 踴 踊 +躲 躲 躱 +逾 逾 踰 +醞 醞 醖 +醯 酰 醯 +鉢 鉢 缽 +鉤 鉤 鈎 +銳 銳 鋭 +錄 錄 録 +錘 錘 鎚 +鏽 鏥 銹 鏽 +鐫 鐫 鎸 鋑 𥍯 +钁 钁 鐝 +閱 閱 閲 +阪 坂 阪 +僱 僱 雇 +雕 雕 彫 琱 +雞 雞 鷄 鶏 +鞝 鞝 緔 +頹 頹 頽 +顏 顏 顔 +館 館 舘 +鬥 鬭 鬥 鬭 闘 +鬨 鬨 閧 +鯗 鯗 鮝 +鱷 鱷 鰐 𧍞 +鳧 鳧 鳬 +鶿 鶿 鷀 +鹼 鹼 礆 碱 +麴 麯 麴 +麪 麪 麵 +麼 麽 麼 +黴 黴 霉 +齎 齎 賫 +捻 捻 撚 +柺 柺 枴 +棲 棲 栖 +臥 臥 卧 +教 教 敎 +勳 勳 勛 +剿 剿 勦 +甕 甕 瓮 +餚 餚 肴 +鼴 鼴 鼹 +蔥 葱 蔥 +搗 擣 搗 +螂 蜋 螂 +溼 濕 溼 +羶 羶 羴 +痺 痺 痹 +蝨 虱 蝨 +檐 檐 簷 +暱 昵 暱 +灩 灩 灎 灧 +齧 嚙 齧 +彝 彝 彞 +檾 檾 苘 䔛 +餈 餈 糍 +拋 拋 抛 +糉 糉 粽 +峯 峰 峯 +鵰 鵰 雕 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/data/scripts/common.py b/Packages/SwiftyOpenCC/OpenCC/data/scripts/common.py new file mode 100644 index 0000000000000000000000000000000000000000..addd3c02b392d3c04d9237cdaad4a3efa4a9930a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/scripts/common.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +import codecs +import sys + + +def sort_items(input_filename, output_filename): + input_file = codecs.open(input_filename, "r", encoding="utf-8") + dic = {} + + for line in input_file: + if len(line) == 0 or line == '\n': + continue + try: + key, value = line.split("\t") + except ValueError: + print(line) + while value[-1] == "\n" or value[-1] == "\r": + value = value[:-1] + dic[key] = value + + input_file.close() + + output_file = open(output_filename, "wb") + + for key in sorted(dic.keys()): + line = key + "\t" + dic[key] + "\n" + output_file.write(line.encode('utf-8')) + + output_file.close() + + +def reverse_items(input_filename, output_filename): + input_file = codecs.open(input_filename, "r", encoding="utf-8") + dic = {} + + for line in input_file: + if len(line) == 0: + continue + key, value = line.split("\t") + while value[-1] == "\n" or value[-1] == "\r": + value = value[:-1] + + value_list = value.split(" ") + for value in value_list: + if value in dic: + dic[value].append(key) + else: + dic[value] = [key] + + input_file.close() + + output_file = open(output_filename, "wb") + + for key in sorted(dic.keys()): + line = key + "\t" + " ".join(dic[key]) + "\n" + output_file.write(line.encode('utf-8')) + + output_file.close() + + +def find_target_items(input_filename, keyword): + input_file = codecs.open(input_filename, "r", encoding="utf-8") + for line in input_file: + if len(line) == 0: + continue + key, value = line.split("\t") + while value[-1] == "\n" or value[-1] == "\r": + value = value[:-1] + + value_list = value.split(" ") + for value in value_list: + if keyword in value: + sys.stdout.write(line) + + input_file.close() diff --git a/Packages/SwiftyOpenCC/OpenCC/data/scripts/find_target.py b/Packages/SwiftyOpenCC/OpenCC/data/scripts/find_target.py new file mode 100755 index 0000000000000000000000000000000000000000..4244949c32cffea2e9d5d15970834b286ae53bbb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/scripts/find_target.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +from common import find_target_items + +if len(sys.argv) != 3: + print("Find the value keyword in all pairs") + print(("Usage: ", sys.argv[0], "[input] [keyword]")) + exit(1) + +find_target_items(sys.argv[1], sys.argv[2]) diff --git a/Packages/SwiftyOpenCC/OpenCC/data/scripts/merge.py b/Packages/SwiftyOpenCC/OpenCC/data/scripts/merge.py new file mode 100755 index 0000000000000000000000000000000000000000..680c90e8688bcb789f70763a84b110bdcf65fef4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/scripts/merge.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import codecs +import sys + +from common import sort_items + +if len(sys.argv) < 4: + print("Merge and sort all text dictionaries") + print(("Usage: ", sys.argv[0], "[input1] [input2] ... [inputN] [output]")) + exit(1) + +all_lines = [] +for i in range(1, len(sys.argv) - 1): + input_file = codecs.open(sys.argv[i], "r", encoding="utf-8") + for line in input_file: + all_lines += line + input_file.close() + all_lines += '\n' + +output_filename = sys.argv[-1] +output_file = open(output_filename, "wb") +for line in all_lines: + output_file.write(line.encode('utf-8')) +output_file.close() + +sort_items(output_filename, output_filename) diff --git a/Packages/SwiftyOpenCC/OpenCC/data/scripts/reverse.py b/Packages/SwiftyOpenCC/OpenCC/data/scripts/reverse.py new file mode 100755 index 0000000000000000000000000000000000000000..746f887d33db95c3952d9de7ea7b2816d792880c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/scripts/reverse.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys + +from common import reverse_items + +if len(sys.argv) != 3: + print("Reverse key and value of all pairs") + print(("Usage: ", sys.argv[0], "[input] [output]")) + exit(1) + +reverse_items(sys.argv[1], sys.argv[2]) diff --git a/Packages/SwiftyOpenCC/OpenCC/data/scripts/sort.py b/Packages/SwiftyOpenCC/OpenCC/data/scripts/sort.py new file mode 100755 index 0000000000000000000000000000000000000000..f7d4dc5699e0e56fe05748dd6372f91a14590a35 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/scripts/sort.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import sys + +from common import sort_items + +if len(sys.argv) < 2: + print("Sort the dictionary") + print(("Usage: ", sys.argv[0], "[input] ([output])")) + exit(1) + +input = sys.argv[1] + +if len(sys.argv) < 3: + output = input +else: + output = sys.argv[2] + +sort_items(input, output) diff --git a/Packages/SwiftyOpenCC/OpenCC/data/scripts/sort_all.py b/Packages/SwiftyOpenCC/OpenCC/data/scripts/sort_all.py new file mode 100755 index 0000000000000000000000000000000000000000..20d82fd3c32cc528d2260b97cec2b92e199a915c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/data/scripts/sort_all.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import glob +import sys + +from common import sort_items + +if len(sys.argv) < 2: + print("Sort the dictionary") + print(("Usage: ", sys.argv[0], "[directory]")) + exit(1) + +dirtectory = sys.argv[1] +files = glob.glob(dirtectory + "/*") +for filename in files: + print(filename) + sort_items(filename, filename) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/darts-clone/darts.h b/Packages/SwiftyOpenCC/OpenCC/deps/darts-clone/darts.h new file mode 100644 index 0000000000000000000000000000000000000000..d47b0e36d41553e3f2f451d209f9b99dac1d9432 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/darts-clone/darts.h @@ -0,0 +1,1898 @@ +#ifndef DARTS_H_ +#define DARTS_H_ + +#include +#include +#include + +#define DARTS_VERSION "0.32" + +// DARTS_THROW() throws a whose message starts with the +// file name and the line number. For example, DARTS_THROW("error message") at +// line 123 of "darts.h" throws a which has a pointer to +// "darts.h:123: exception: error message". The message is available by using +// what() as well as that of . +#define DARTS_INT_TO_STR(value) #value +#define DARTS_LINE_TO_STR(line) DARTS_INT_TO_STR(line) +#define DARTS_LINE_STR DARTS_LINE_TO_STR(__LINE__) +#define DARTS_THROW(msg) throw Darts::Details::Exception( \ + __FILE__ ":" DARTS_LINE_STR ": exception: " msg) + +namespace Darts { + +// The following namespace hides the internal types and classes. +namespace Details { + +// This header assumes that and are 32-bit integer types. +// +// Darts-clone keeps values associated with keys. The type of the values is +// . Note that the values must be positive integers because the +// most significant bit (MSB) of each value is used to represent whether the +// corresponding unit is a leaf or not. Also, the keys are represented by +// sequences of s. is the unsigned type of . +typedef char char_type; +typedef unsigned char uchar_type; +typedef int value_type; + +// The main structure of Darts-clone is an array of s, and the +// unit type is actually a wrapper of . +typedef size_t id_type; + +// is the type of callback functions for reporting the +// progress of building a dictionary. See also build() of . +// The 1st argument receives the progress value and the 2nd argument receives +// the maximum progress value. A usage example is to show the progress +// percentage, 100.0 * (the 1st argument) / (the 2nd argument). +typedef int (*progress_func_type)(std::size_t, std::size_t); + +// is the type of double-array units and it is a wrapper of +// in practice. +class DoubleArrayUnit { + public: + DoubleArrayUnit() : unit_() {} + + // has_leaf() returns whether a leaf unit is immediately derived from the + // unit (true) or not (false). + bool has_leaf() const { + return ((unit_ >> 8) & 1) == 1; + } + // value() returns the value stored in the unit, and thus value() is + // available when and only when the unit is a leaf unit. + value_type value() const { + return static_cast(unit_ & ((1U << 31) - 1)); + } + + // label() returns the label associted with the unit. Note that a leaf unit + // always returns an invalid label. For this feature, leaf unit's label() + // returns an that has the MSB of 1. + id_type label() const { + return unit_ & ((1U << 31) | 0xFF); + } + // offset() returns the offset from the unit to its derived units. + id_type offset() const { + return (unit_ >> 10) << ((unit_ & (1U << 9)) >> 6); + } + + private: + id_type unit_; + + // Copyable. +}; + +// Darts-clone throws an for memory allocation failure, invalid +// arguments or a too large offset. The last case means that there are too many +// keys in the given set of keys. Note that the `msg' of must be a +// constant or static string because an keeps only a pointer to +// that string. +class Exception : public std::exception { + public: + explicit Exception(const char *msg = NULL) throw() : msg_(msg) {} + Exception(const Exception &rhs) throw() : msg_(rhs.msg_) {} + virtual ~Exception() throw() {} + + // overrides what() of . + virtual const char *what() const throw() { + return (msg_ != NULL) ? msg_ : ""; + } + + private: + const char *msg_; + + // Disallows operator=. + Exception &operator=(const Exception &); +}; + +} // namespace Details + +// is the interface of Darts-clone. Note that other +// classes should not be accessed from outside. +// +// has 4 template arguments but only the 3rd one is used as +// the type of values. Note that the given is used only from outside, and +// the internal value type is not changed from . +// In build(), given values are casted from to +// by using static_cast. On the other hand, values are casted from +// to in searching dictionaries. +template +class DoubleArrayImpl { + public: + // Even if this is changed, the internal value type is still + // . Other types, such as 64-bit integer types + // and floating-point number types, should not be used. + typedef T value_type; + // A key is reprenseted by a sequence of s. For example, + // exactMatchSearch() takes a . + typedef Details::char_type key_type; + // In searching dictionaries, the values associated with the matched keys are + // stored into or returned as s. + typedef value_type result_type; + + // enables applications to get the lengths of the matched + // keys in addition to the values. + struct result_pair_type { + value_type value; + std::size_t length; + }; + + // The constructor initializes member variables with 0 and NULLs. + DoubleArrayImpl() : size_(0), array_(NULL), buf_(NULL) {} + // The destructor frees memory allocated for units and then initializes + // member variables with 0 and NULLs. + virtual ~DoubleArrayImpl() { + clear(); + } + + // has 2 kinds of set_result()s. The 1st set_result() is to + // set a value to a . The 2nd set_result() is to set a value and + // a length to a . By using set_result()s, search methods + // can return the 2 kinds of results in the same way. + // Why the set_result()s are non-static? It is for compatibility. + // + // The 1st set_result() takes a length as the 3rd argument but it is not + // used. If a compiler does a good job, codes for getting the length may be + // removed. + void set_result(value_type *result, value_type value, std::size_t) const { + *result = value; + } + // The 2nd set_result() uses both `value' and `length'. + void set_result(result_pair_type *result, + value_type value, std::size_t length) const { + result->value = value; + result->length = length; + } + + // set_array() calls clear() in order to free memory allocated to the old + // array and then sets a new array. This function is useful to set a memory- + // mapped array. Note that the array set by set_array() is not freed in + // clear() and the destructor of . + // set_array() can also set the size of the new array but the size is not + // used in search methods. So it works well even if the 2nd argument is 0 or + // omitted. Remember that size() and total_size() returns 0 in such a case. + void set_array(const void *ptr, std::size_t size = 0) { + clear(); + array_ = static_cast(ptr); + size_ = size; + } + // array() returns a pointer to the array of units. + const void *array() const { + return array_; + } + + // clear() frees memory allocated to units and then initializes member + // variables with 0 and NULLs. Note that clear() does not free memory if the + // array of units was set by set_array(). In such a case, `array_' is not + // NULL and `buf_' is NULL. + void clear() { + size_ = 0; + array_ = NULL; + if (buf_ != NULL) { + delete[] buf_; + buf_ = NULL; + } + } + + // unit_size() returns the size of each unit. The size must be 4 bytes. + std::size_t unit_size() const { + return sizeof(unit_type); + } + // size() returns the number of units. It can be 0 if set_array() is used. + std::size_t size() const { + return size_; + } + // total_size() returns the number of bytes allocated to the array of units. + // It can be 0 if set_array() is used. + std::size_t total_size() const { + return unit_size() * size(); + } + // nonzero_size() exists for compatibility. It always returns the number of + // units because it takes long time to count the number of non-zero units. + std::size_t nonzero_size() const { + return size(); + } + + // build() constructs a dictionary from given key-value pairs. If `lengths' + // is NULL, `keys' is handled as an array of zero-terminated strings. If + // `values' is NULL, the index in `keys' is associated with each key, i.e. + // the ith key has (i - 1) as its value. + // Note that the key-value pairs must be arranged in key order and the values + // must not be negative. Also, if there are duplicate keys, only the first + // pair will be stored in the resultant dictionary. + // `progress_func' is a pointer to a callback function. If it is not NULL, + // it will be called in build() so that the caller can check the progress of + // dictionary construction. For details, please see the definition of + // . + // The return value of build() is 0, and it indicates the success of the + // operation. Otherwise, build() throws a , which is a + // derived class of . + // build() uses another construction algorithm if `values' is not NULL. In + // this case, Darts-clone uses a Directed Acyclic Word Graph (DAWG) instead + // of a trie because a DAWG is likely to be more compact than a trie. + int build(std::size_t num_keys, const key_type * const *keys, + const std::size_t *lengths = NULL, const value_type *values = NULL, + Details::progress_func_type progress_func = NULL); + + // open() reads an array of units from the specified file. And if it goes + // well, the old array will be freed and replaced with the new array read + // from the file. `offset' specifies the number of bytes to be skipped before + // reading an array. `size' specifies the number of bytes to be read from the + // file. If the `size' is 0, the whole file will be read. + // open() returns 0 iff the operation succeeds. Otherwise, it returns a + // non-zero value or throws a . The exception is thrown + // when and only when a memory allocation fails. + int open(const char *file_name, const char *mode = "rb", + std::size_t offset = 0, std::size_t size = 0); + // save() writes the array of units into the specified file. `offset' + // specifies the number of bytes to be skipped before writing the array. + // open() returns 0 iff the operation succeeds. Otherwise, it returns a + // non-zero value. + int save(const char *file_name, const char *mode = "wb", + std::size_t offset = 0) const; + + // The 1st exactMatchSearch() tests whether the given key exists or not, and + // if it exists, its value and length are set to `result'. Otherwise, the + // value and the length of `result' are set to -1 and 0 respectively. + // Note that if `length' is 0, `key' is handled as a zero-terminated string. + // `node_pos' specifies the start position of matching. This argument enables + // the combination of exactMatchSearch() and traverse(). For example, if you + // want to test "xyzA", "xyzBC", and "xyzDE", you can use traverse() to get + // the node position corresponding to "xyz" and then you can use + // exactMatchSearch() to test "A", "BC", and "DE" from that position. + // Note that the length of `result' indicates the length from the `node_pos'. + // In the above example, the lengths are { 1, 2, 2 }, not { 4, 5, 5 }. + template + void exactMatchSearch(const key_type *key, U &result, + std::size_t length = 0, std::size_t node_pos = 0) const { + result = exactMatchSearch(key, length, node_pos); + } + // The 2nd exactMatchSearch() returns a result instead of updating the 2nd + // argument. So, the following exactMatchSearch() has only 3 arguments. + template + inline U exactMatchSearch(const key_type *key, std::size_t length = 0, + std::size_t node_pos = 0) const; + + // commonPrefixSearch() searches for keys which match a prefix of the given + // string. If `length' is 0, `key' is handled as a zero-terminated string. + // The values and the lengths of at most `max_num_results' matched keys are + // stored in `results'. commonPrefixSearch() returns the number of matched + // keys. Note that the return value can be larger than `max_num_results' if + // there are more than `max_num_results' matches. If you want to get all the + // results, allocate more spaces and call commonPrefixSearch() again. + // `node_pos' works as well as in exactMatchSearch(). + template + inline std::size_t commonPrefixSearch(const key_type *key, U *results, + std::size_t max_num_results, std::size_t length = 0, + std::size_t node_pos = 0) const; + + // In Darts-clone, a dictionary is a deterministic finite-state automaton + // (DFA) and traverse() tests transitions on the DFA. The initial state is + // `node_pos' and traverse() chooses transitions labeled key[key_pos], + // key[key_pos + 1], ... in order. If there is not a transition labeled + // key[key_pos + i], traverse() terminates the transitions at that state and + // returns -2. Otherwise, traverse() ends without a termination and returns + // -1 or a nonnegative value, -1 indicates that the final state was not an + // accept state. When a nonnegative value is returned, it is the value + // associated with the final accept state. That is, traverse() returns the + // value associated with the given key if it exists. Note that traverse() + // updates `node_pos' and `key_pos' after each transition. + inline value_type traverse(const key_type *key, std::size_t &node_pos, + std::size_t &key_pos, std::size_t length = 0) const; + + private: + typedef Details::uchar_type uchar_type; + typedef Details::id_type id_type; + typedef Details::DoubleArrayUnit unit_type; + + std::size_t size_; + const unit_type *array_; + unit_type *buf_; + + // Disallows copy and assignment. + DoubleArrayImpl(const DoubleArrayImpl &); + DoubleArrayImpl &operator=(const DoubleArrayImpl &); +}; + +// is the typical instance of . It uses +// as the type of values and it is suitable for most cases. +typedef DoubleArrayImpl DoubleArray; + +// The interface section ends here. For using Darts-clone, there is no need +// to read the remaining section, which gives the implementation of +// Darts-clone. + +// +// Member functions of DoubleArrayImpl (except build()). +// + +template +int DoubleArrayImpl::open(const char *file_name, + const char *mode, std::size_t offset, std::size_t size) { +#ifdef _MSC_VER + std::FILE *file; + if (::fopen_s(&file, file_name, mode) != 0) { + return -1; + } +#else + std::FILE *file = std::fopen(file_name, mode); + if (file == NULL) { + return -1; + } +#endif + + if (size == 0) { + if (std::fseek(file, 0, SEEK_END) != 0) { + std::fclose(file); + return -1; + } + size = std::ftell(file) - offset; + } + + if (std::fseek(file, offset, SEEK_SET) != 0) { + std::fclose(file); + return -1; + } + + size /= unit_size(); + unit_type *buf; + try { + buf = new unit_type[size]; + } catch (const std::bad_alloc &) { + std::fclose(file); + DARTS_THROW("failed to open double-array: std::bad_alloc"); + } + + if (std::fread(buf, unit_size(), size, file) != size) { + std::fclose(file); + delete[] buf; + return -1; + } + std::fclose(file); + + clear(); + + size_ = size; + array_ = buf; + buf_ = buf; + return 0; +} + +template +int DoubleArrayImpl::save(const char *file_name, + const char *mode, std::size_t) const { + if (size() == 0) { + return -1; + } + +#ifdef _MSC_VER + std::FILE *file; + if (::fopen_s(&file, file_name, mode) != 0) { + return -1; + } +#else + std::FILE *file = std::fopen(file_name, mode); + if (file == NULL) { + return -1; + } +#endif + + if (std::fwrite(array_, unit_size(), size(), file) != size()) { + std::fclose(file); + return -1; + } + std::fclose(file); + return 0; +} + +template +template +inline U DoubleArrayImpl::exactMatchSearch(const key_type *key, + std::size_t length, std::size_t node_pos) const { + U result; + set_result(&result, static_cast(-1), 0); + + unit_type unit = array_[node_pos]; + if (length != 0) { + for (std::size_t i = 0; i < length; ++i) { + node_pos ^= unit.offset() ^ static_cast(key[i]); + unit = array_[node_pos]; + if (unit.label() != static_cast(key[i])) { + return result; + } + } + } else { + for ( ; key[length] != '\0'; ++length) { + node_pos ^= unit.offset() ^ static_cast(key[length]); + unit = array_[node_pos]; + if (unit.label() != static_cast(key[length])) { + return result; + } + } + } + + if (!unit.has_leaf()) { + return result; + } + unit = array_[node_pos ^ unit.offset()]; + set_result(&result, static_cast(unit.value()), length); + return result; +} + +template +template +inline std::size_t DoubleArrayImpl::commonPrefixSearch( + const key_type *key, U *results, std::size_t max_num_results, + std::size_t length, std::size_t node_pos) const { + std::size_t num_results = 0; + + unit_type unit = array_[node_pos]; + node_pos ^= unit.offset(); + if (length != 0) { + for (std::size_t i = 0; i < length; ++i) { + node_pos ^= static_cast(key[i]); + unit = array_[node_pos]; + if (unit.label() != static_cast(key[i])) { + return num_results; + } + + node_pos ^= unit.offset(); + if (unit.has_leaf()) { + if (num_results < max_num_results) { + set_result(&results[num_results], static_cast( + array_[node_pos].value()), i + 1); + } + ++num_results; + } + } + } else { + for ( ; key[length] != '\0'; ++length) { + node_pos ^= static_cast(key[length]); + unit = array_[node_pos]; + if (unit.label() != static_cast(key[length])) { + return num_results; + } + + node_pos ^= unit.offset(); + if (unit.has_leaf()) { + if (num_results < max_num_results) { + set_result(&results[num_results], static_cast( + array_[node_pos].value()), length + 1); + } + ++num_results; + } + } + } + + return num_results; +} + +template +inline typename DoubleArrayImpl::value_type +DoubleArrayImpl::traverse(const key_type *key, + std::size_t &node_pos, std::size_t &key_pos, std::size_t length) const { + id_type id = static_cast(node_pos); + unit_type unit = array_[id]; + + if (length != 0) { + for ( ; key_pos < length; ++key_pos) { + id ^= unit.offset() ^ static_cast(key[key_pos]); + unit = array_[id]; + if (unit.label() != static_cast(key[key_pos])) { + return static_cast(-2); + } + node_pos = id; + } + } else { + for ( ; key[key_pos] != '\0'; ++key_pos) { + id ^= unit.offset() ^ static_cast(key[key_pos]); + unit = array_[id]; + if (unit.label() != static_cast(key[key_pos])) { + return static_cast(-2); + } + node_pos = id; + } + } + + if (!unit.has_leaf()) { + return static_cast(-1); + } + unit = array_[id ^ unit.offset()]; + return static_cast(unit.value()); +} + +namespace Details { + +// +// Memory management of array. +// + +template +class AutoArray { + public: + explicit AutoArray(T *array = NULL) : array_(array) {} + ~AutoArray() { + clear(); + } + + const T &operator[](std::size_t id) const { + return array_[id]; + } + T &operator[](std::size_t id) { + return array_[id]; + } + + bool empty() const { + return array_ == NULL; + } + + void clear() { + if (array_ != NULL) { + delete[] array_; + array_ = NULL; + } + } + void swap(AutoArray *array) { + T *temp = array_; + array_ = array->array_; + array->array_ = temp; + } + void reset(T *array = NULL) { + AutoArray(array).swap(this); + } + + private: + T *array_; + + // Disallows copy and assignment. + AutoArray(const AutoArray &); + AutoArray &operator=(const AutoArray &); +}; + +// +// Memory management of resizable array. +// + +template +class AutoPool { + public: + AutoPool() : buf_(), size_(0), capacity_(0) {} + ~AutoPool() { clear(); } + + const T &operator[](std::size_t id) const { + return *(reinterpret_cast(&buf_[0]) + id); + } + T &operator[](std::size_t id) { + return *(reinterpret_cast(&buf_[0]) + id); + } + + bool empty() const { + return size_ == 0; + } + std::size_t size() const { + return size_; + } + + void clear() { + resize(0); + buf_.clear(); + size_ = 0; + capacity_ = 0; + } + + void push_back(const T &value) { + append(value); + } + void pop_back() { + (*this)[--size_].~T(); + } + + void append() { + if (size_ == capacity_) + resize_buf(size_ + 1); + new(&(*this)[size_++]) T; + } + void append(const T &value) { + if (size_ == capacity_) + resize_buf(size_ + 1); + new(&(*this)[size_++]) T(value); + } + + void resize(std::size_t size) { + while (size_ > size) { + (*this)[--size_].~T(); + } + if (size > capacity_) { + resize_buf(size); + } + while (size_ < size) { + new(&(*this)[size_++]) T; + } + } + void resize(std::size_t size, const T &value) { + while (size_ > size) { + (*this)[--size_].~T(); + } + if (size > capacity_) { + resize_buf(size); + } + while (size_ < size) { + new(&(*this)[size_++]) T(value); + } + } + + void reserve(std::size_t size) { + if (size > capacity_) { + resize_buf(size); + } + } + + private: + AutoArray buf_; + std::size_t size_; + std::size_t capacity_; + + // Disallows copy and assignment. + AutoPool(const AutoPool &); + AutoPool &operator=(const AutoPool &); + + void resize_buf(std::size_t size); +}; + +template +void AutoPool::resize_buf(std::size_t size) { + std::size_t capacity; + if (size >= capacity_ * 2) { + capacity = size; + } else { + capacity = 1; + while (capacity < size) { + capacity <<= 1; + } + } + + AutoArray buf; + try { + buf.reset(new char[sizeof(T) * capacity]); + } catch (const std::bad_alloc &) { + DARTS_THROW("failed to resize pool: std::bad_alloc"); + } + + if (size_ > 0) { + T *src = reinterpret_cast(&buf_[0]); + T *dest = reinterpret_cast(&buf[0]); + for (std::size_t i = 0; i < size_; ++i) { + new(&dest[i]) T(src[i]); + src[i].~T(); + } + } + + buf_.swap(&buf); + capacity_ = capacity; +} + +// +// Memory management of stack. +// + +template +class AutoStack { + public: + AutoStack() : pool_() {} + ~AutoStack() { + clear(); + } + + const T &top() const { + return pool_[size() - 1]; + } + T &top() { + return pool_[size() - 1]; + } + + bool empty() const { + return pool_.empty(); + } + std::size_t size() const { + return pool_.size(); + } + + void push(const T &value) { + pool_.push_back(value); + } + void pop() { + pool_.pop_back(); + } + + void clear() { + pool_.clear(); + } + + private: + AutoPool pool_; + + // Disallows copy and assignment. + AutoStack(const AutoStack &); + AutoStack &operator=(const AutoStack &); +}; + +// +// Succinct bit vector. +// + +class BitVector { + public: + BitVector() : units_(), ranks_(), num_ones_(0), size_(0) {} + ~BitVector() { + clear(); + } + + bool operator[](std::size_t id) const { + return (units_[id / UNIT_SIZE] >> (id % UNIT_SIZE) & 1) == 1; + } + + id_type rank(std::size_t id) const { + std::size_t unit_id = id / UNIT_SIZE; + return ranks_[unit_id] + pop_count(units_[unit_id] + & (~0U >> (UNIT_SIZE - (id % UNIT_SIZE) - 1))); + } + + void set(std::size_t id, bool bit) { + if (bit) { + units_[id / UNIT_SIZE] |= 1U << (id % UNIT_SIZE); + } else { + units_[id / UNIT_SIZE] &= ~(1U << (id % UNIT_SIZE)); + } + } + + bool empty() const { + return units_.empty(); + } + std::size_t num_ones() const { + return num_ones_; + } + std::size_t size() const { + return size_; + } + + void append() { + if ((size_ % UNIT_SIZE) == 0) { + units_.append(0); + } + ++size_; + } + void build(); + + void clear() { + units_.clear(); + ranks_.clear(); + } + + private: + enum { UNIT_SIZE = sizeof(id_type) * 8 }; + + AutoPool units_; + AutoArray ranks_; + std::size_t num_ones_; + std::size_t size_; + + // Disallows copy and assignment. + BitVector(const BitVector &); + BitVector &operator=(const BitVector &); + + static id_type pop_count(id_type unit) { + unit = ((unit & 0xAAAAAAAA) >> 1) + (unit & 0x55555555); + unit = ((unit & 0xCCCCCCCC) >> 2) + (unit & 0x33333333); + unit = ((unit >> 4) + unit) & 0x0F0F0F0F; + unit += unit >> 8; + unit += unit >> 16; + return unit & 0xFF; + } +}; + +inline void BitVector::build() { + try { + ranks_.reset(new id_type[units_.size()]); + } catch (const std::bad_alloc &) { + DARTS_THROW("failed to build rank index: std::bad_alloc"); + } + + num_ones_ = 0; + for (std::size_t i = 0; i < units_.size(); ++i) { + ranks_[i] = num_ones_; + num_ones_ += pop_count(units_[i]); + } +} + +// +// Keyset. +// + +template +class Keyset { + public: + Keyset(std::size_t num_keys, const char_type * const *keys, + const std::size_t *lengths, const T *values) : + num_keys_(num_keys), keys_(keys), lengths_(lengths), values_(values) {} + + std::size_t num_keys() const { + return num_keys_; + } + const char_type *keys(std::size_t id) const { + return keys_[id]; + } + uchar_type keys(std::size_t key_id, std::size_t char_id) const { + if (has_lengths() && char_id >= lengths_[key_id]) + return '\0'; + return keys_[key_id][char_id]; + } + + bool has_lengths() const { + return lengths_ != NULL; + } + std::size_t lengths(std::size_t id) const { + if (has_lengths()) { + return lengths_[id]; + } + std::size_t length = 0; + while (keys_[id][length] != '\0') { + ++length; + } + return length; + } + + bool has_values() const { + return values_ != NULL; + } + value_type values(std::size_t id) const { + if (has_values()) { + return static_cast(values_[id]); + } + return static_cast(id); + } + + private: + std::size_t num_keys_; + const char_type * const * keys_; + const std::size_t *lengths_; + const T *values_; + + // Disallows copy and assignment. + Keyset(const Keyset &); + Keyset &operator=(const Keyset &); +}; + +// +// Node of Directed Acyclic Word Graph (DAWG). +// + +class DawgNode { + public: + DawgNode() : child_(0), sibling_(0), label_('\0'), + is_state_(false), has_sibling_(false) {} + + void set_child(id_type child) { + child_ = child; + } + void set_sibling(id_type sibling) { + sibling_ = sibling; + } + void set_value(value_type value) { + child_ = value; + } + void set_label(uchar_type label) { + label_ = label; + } + void set_is_state(bool is_state) { + is_state_ = is_state; + } + void set_has_sibling(bool has_sibling) { + has_sibling_ = has_sibling; + } + + id_type child() const { + return child_; + } + id_type sibling() const { + return sibling_; + } + value_type value() const { + return static_cast(child_); + } + uchar_type label() const { + return label_; + } + bool is_state() const { + return is_state_; + } + bool has_sibling() const { + return has_sibling_; + } + + id_type unit() const { + if (label_ == '\0') { + return (child_ << 1) | (has_sibling_ ? 1 : 0); + } + return (child_ << 2) | (is_state_ ? 2 : 0) | (has_sibling_ ? 1 : 0); + } + + private: + id_type child_; + id_type sibling_; + uchar_type label_; + bool is_state_; + bool has_sibling_; + + // Copyable. +}; + +// +// Fixed unit of Directed Acyclic Word Graph (DAWG). +// + +class DawgUnit { + public: + explicit DawgUnit(id_type unit = 0) : unit_(unit) {} + DawgUnit(const DawgUnit &unit) : unit_(unit.unit_) {} + + DawgUnit &operator=(id_type unit) { + unit_ = unit; + return *this; + } + + id_type unit() const { + return unit_; + } + + id_type child() const { + return unit_ >> 2; + } + bool has_sibling() const { + return (unit_ & 1) == 1; + } + value_type value() const { + return static_cast(unit_ >> 1); + } + bool is_state() const { + return (unit_ & 2) == 2; + } + + private: + id_type unit_; + + // Copyable. +}; + +// +// Directed Acyclic Word Graph (DAWG) builder. +// + +class DawgBuilder { + public: + DawgBuilder() : nodes_(), units_(), labels_(), is_intersections_(), + table_(), node_stack_(), recycle_bin_(), num_states_(0) {} + ~DawgBuilder() { + clear(); + } + + id_type root() const { + return 0; + } + + id_type child(id_type id) const { + return units_[id].child(); + } + id_type sibling(id_type id) const { + return units_[id].has_sibling() ? (id + 1) : 0; + } + int value(id_type id) const { + return units_[id].value(); + } + + bool is_leaf(id_type id) const { + return label(id) == '\0'; + } + uchar_type label(id_type id) const { + return labels_[id]; + } + + bool is_intersection(id_type id) const { + return is_intersections_[id]; + } + id_type intersection_id(id_type id) const { + return is_intersections_.rank(id) - 1; + } + + std::size_t num_intersections() const { + return is_intersections_.num_ones(); + } + + std::size_t size() const { + return units_.size(); + } + + void init(); + void finish(); + + void insert(const char *key, std::size_t length, value_type value); + + void clear(); + + private: + enum { INITIAL_TABLE_SIZE = 1 << 10 }; + + AutoPool nodes_; + AutoPool units_; + AutoPool labels_; + BitVector is_intersections_; + AutoPool table_; + AutoStack node_stack_; + AutoStack recycle_bin_; + std::size_t num_states_; + + // Disallows copy and assignment. + DawgBuilder(const DawgBuilder &); + DawgBuilder &operator=(const DawgBuilder &); + + void flush(id_type id); + + void expand_table(); + + id_type find_unit(id_type id, id_type *hash_id) const; + id_type find_node(id_type node_id, id_type *hash_id) const; + + bool are_equal(id_type node_id, id_type unit_id) const; + + id_type hash_unit(id_type id) const; + id_type hash_node(id_type id) const; + + id_type append_node(); + id_type append_unit(); + + void free_node(id_type id) { + recycle_bin_.push(id); + } + + static id_type hash(id_type key) { + key = ~key + (key << 15); // key = (key << 15) - key - 1; + key = key ^ (key >> 12); + key = key + (key << 2); + key = key ^ (key >> 4); + key = key * 2057; // key = (key + (key << 3)) + (key << 11); + key = key ^ (key >> 16); + return key; + } +}; + +inline void DawgBuilder::init() { + table_.resize(INITIAL_TABLE_SIZE, 0); + + append_node(); + append_unit(); + + num_states_ = 1; + + nodes_[0].set_label(0xFF); + node_stack_.push(0); +} + +inline void DawgBuilder::finish() { + flush(0); + + units_[0] = nodes_[0].unit(); + labels_[0] = nodes_[0].label(); + + nodes_.clear(); + table_.clear(); + node_stack_.clear(); + recycle_bin_.clear(); + + is_intersections_.build(); +} + +inline void DawgBuilder::insert(const char *key, std::size_t length, + value_type value) { + if (value < 0) { + DARTS_THROW("failed to insert key: negative value"); + } else if (length == 0) { + DARTS_THROW("failed to insert key: zero-length key"); + } + + id_type id = 0; + std::size_t key_pos = 0; + + for ( ; key_pos <= length; ++key_pos) { + id_type child_id = nodes_[id].child(); + if (child_id == 0) { + break; + } + + uchar_type key_label = static_cast(key[key_pos]); + if (key_pos < length && key_label == '\0') { + DARTS_THROW("failed to insert key: invalid null character"); + } + + uchar_type unit_label = nodes_[child_id].label(); + if (key_label < unit_label) { + DARTS_THROW("failed to insert key: wrong key order"); + } else if (key_label > unit_label) { + nodes_[child_id].set_has_sibling(true); + flush(child_id); + break; + } + id = child_id; + } + + if (key_pos > length) { + return; + } + + for ( ; key_pos <= length; ++key_pos) { + uchar_type key_label = static_cast( + (key_pos < length) ? key[key_pos] : '\0'); + id_type child_id = append_node(); + + if (nodes_[id].child() == 0) { + nodes_[child_id].set_is_state(true); + } + nodes_[child_id].set_sibling(nodes_[id].child()); + nodes_[child_id].set_label(key_label); + nodes_[id].set_child(child_id); + node_stack_.push(child_id); + + id = child_id; + } + nodes_[id].set_value(value); +} + +inline void DawgBuilder::clear() { + nodes_.clear(); + units_.clear(); + labels_.clear(); + is_intersections_.clear(); + table_.clear(); + node_stack_.clear(); + recycle_bin_.clear(); + num_states_ = 0; +} + +inline void DawgBuilder::flush(id_type id) { + while (node_stack_.top() != id) { + id_type node_id = node_stack_.top(); + node_stack_.pop(); + + if (num_states_ >= table_.size() - (table_.size() >> 2)) { + expand_table(); + } + + id_type num_siblings = 0; + for (id_type i = node_id; i != 0; i = nodes_[i].sibling()) { + ++num_siblings; + } + + id_type hash_id; + id_type match_id = find_node(node_id, &hash_id); + if (match_id != 0) { + is_intersections_.set(match_id, true); + } else { + id_type unit_id = 0; + for (id_type i = 0; i < num_siblings; ++i) { + unit_id = append_unit(); + } + for (id_type i = node_id; i != 0; i = nodes_[i].sibling()) { + units_[unit_id] = nodes_[i].unit(); + labels_[unit_id] = nodes_[i].label(); + --unit_id; + } + match_id = unit_id + 1; + table_[hash_id] = match_id; + ++num_states_; + } + + for (id_type i = node_id, next; i != 0; i = next) { + next = nodes_[i].sibling(); + free_node(i); + } + + nodes_[node_stack_.top()].set_child(match_id); + } + node_stack_.pop(); +} + +inline void DawgBuilder::expand_table() { + std::size_t table_size = table_.size() << 1; + table_.clear(); + table_.resize(table_size, 0); + + for (std::size_t i = 1; i < units_.size(); ++i) { + id_type id = static_cast(i); + if (labels_[id] == '\0' || units_[id].is_state()) { + id_type hash_id; + find_unit(id, &hash_id); + table_[hash_id] = id; + } + } +} + +inline id_type DawgBuilder::find_unit(id_type id, id_type *hash_id) const { + *hash_id = hash_unit(id) % table_.size(); + for ( ; ; *hash_id = (*hash_id + 1) % table_.size()) { + id_type unit_id = table_[*hash_id]; + if (unit_id == 0) { + break; + } + + // There must not be the same unit. + } + return 0; +} + +inline id_type DawgBuilder::find_node(id_type node_id, + id_type *hash_id) const { + *hash_id = hash_node(node_id) % table_.size(); + for ( ; ; *hash_id = (*hash_id + 1) % table_.size()) { + id_type unit_id = table_[*hash_id]; + if (unit_id == 0) { + break; + } + + if (are_equal(node_id, unit_id)) { + return unit_id; + } + } + return 0; +} + +inline bool DawgBuilder::are_equal(id_type node_id, id_type unit_id) const { + for (id_type i = nodes_[node_id].sibling(); i != 0; + i = nodes_[i].sibling()) { + if (units_[unit_id].has_sibling() == false) { + return false; + } + ++unit_id; + } + if (units_[unit_id].has_sibling() == true) { + return false; + } + + for (id_type i = node_id; i != 0; i = nodes_[i].sibling(), --unit_id) { + if (nodes_[i].unit() != units_[unit_id].unit() || + nodes_[i].label() != labels_[unit_id]) { + return false; + } + } + return true; +} + +inline id_type DawgBuilder::hash_unit(id_type id) const { + id_type hash_value = 0; + for ( ; id != 0; ++id) { + id_type unit = units_[id].unit(); + uchar_type label = labels_[id]; + hash_value ^= hash((label << 24) ^ unit); + + if (units_[id].has_sibling() == false) { + break; + } + } + return hash_value; +} + +inline id_type DawgBuilder::hash_node(id_type id) const { + id_type hash_value = 0; + for ( ; id != 0; id = nodes_[id].sibling()) { + id_type unit = nodes_[id].unit(); + uchar_type label = nodes_[id].label(); + hash_value ^= hash((label << 24) ^ unit); + } + return hash_value; +} + +inline id_type DawgBuilder::append_unit() { + is_intersections_.append(); + units_.append(); + labels_.append(); + + return static_cast(is_intersections_.size() - 1); +} + +inline id_type DawgBuilder::append_node() { + id_type id; + if (recycle_bin_.empty()) { + id = static_cast(nodes_.size()); + nodes_.append(); + } else { + id = recycle_bin_.top(); + nodes_[id] = DawgNode(); + recycle_bin_.pop(); + } + return id; +} + +// +// Unit of double-array builder. +// + +class DoubleArrayBuilderUnit { + public: + DoubleArrayBuilderUnit() : unit_(0) {} + + void set_has_leaf(bool has_leaf) { + if (has_leaf) { + unit_ |= 1U << 8; + } else { + unit_ &= ~(1U << 8); + } + } + void set_value(value_type value) { + unit_ = value | (1U << 31); + } + void set_label(uchar_type label) { + unit_ = (unit_ & ~0xFFU) | label; + } + void set_offset(id_type offset) { + if (offset >= 1U << 29) { + DARTS_THROW("failed to modify unit: too large offset"); + } + unit_ &= (1U << 31) | (1U << 8) | 0xFF; + if (offset < 1U << 21) { + unit_ |= (offset << 10); + } else { + unit_ |= (offset << 2) | (1U << 9); + } + } + + private: + id_type unit_; + + // Copyable. +}; + +// +// Extra unit of double-array builder. +// + +class DoubleArrayBuilderExtraUnit { + public: + DoubleArrayBuilderExtraUnit() : prev_(0), next_(0), + is_fixed_(false), is_used_(false) {} + + void set_prev(id_type prev) { + prev_ = prev; + } + void set_next(id_type next) { + next_ = next; + } + void set_is_fixed(bool is_fixed) { + is_fixed_ = is_fixed; + } + void set_is_used(bool is_used) { + is_used_ = is_used; + } + + id_type prev() const { + return prev_; + } + id_type next() const { + return next_; + } + bool is_fixed() const { + return is_fixed_; + } + bool is_used() const { + return is_used_; + } + + private: + id_type prev_; + id_type next_; + bool is_fixed_; + bool is_used_; + + // Copyable. +}; + +// +// DAWG -> double-array converter. +// + +class DoubleArrayBuilder { + public: + explicit DoubleArrayBuilder(progress_func_type progress_func) + : progress_func_(progress_func), units_(), extras_(), labels_(), + table_(), extras_head_(0) {} + ~DoubleArrayBuilder() { + clear(); + } + + template + void build(const Keyset &keyset); + void copy(std::size_t *size_ptr, DoubleArrayUnit **buf_ptr) const; + + void clear(); + + private: + enum { BLOCK_SIZE = 256 }; + enum { NUM_EXTRA_BLOCKS = 16 }; + enum { NUM_EXTRAS = BLOCK_SIZE * NUM_EXTRA_BLOCKS }; + + enum { UPPER_MASK = 0xFF << 21 }; + enum { LOWER_MASK = 0xFF }; + + typedef DoubleArrayBuilderUnit unit_type; + typedef DoubleArrayBuilderExtraUnit extra_type; + + progress_func_type progress_func_; + AutoPool units_; + AutoArray extras_; + AutoPool labels_; + AutoArray table_; + id_type extras_head_; + + // Disallows copy and assignment. + DoubleArrayBuilder(const DoubleArrayBuilder &); + DoubleArrayBuilder &operator=(const DoubleArrayBuilder &); + + std::size_t num_blocks() const { + return units_.size() / BLOCK_SIZE; + } + + const extra_type &extras(id_type id) const { + return extras_[id % NUM_EXTRAS]; + } + extra_type &extras(id_type id) { + return extras_[id % NUM_EXTRAS]; + } + + template + void build_dawg(const Keyset &keyset, DawgBuilder *dawg_builder); + void build_from_dawg(const DawgBuilder &dawg); + void build_from_dawg(const DawgBuilder &dawg, + id_type dawg_id, id_type dic_id); + id_type arrange_from_dawg(const DawgBuilder &dawg, + id_type dawg_id, id_type dic_id); + + template + void build_from_keyset(const Keyset &keyset); + template + void build_from_keyset(const Keyset &keyset, std::size_t begin, + std::size_t end, std::size_t depth, id_type dic_id); + template + id_type arrange_from_keyset(const Keyset &keyset, std::size_t begin, + std::size_t end, std::size_t depth, id_type dic_id); + + id_type find_valid_offset(id_type id) const; + bool is_valid_offset(id_type id, id_type offset) const; + + void reserve_id(id_type id); + void expand_units(); + + void fix_all_blocks(); + void fix_block(id_type block_id); +}; + +template +void DoubleArrayBuilder::build(const Keyset &keyset) { + if (keyset.has_values()) { + Details::DawgBuilder dawg_builder; + build_dawg(keyset, &dawg_builder); + build_from_dawg(dawg_builder); + dawg_builder.clear(); + } else { + build_from_keyset(keyset); + } +} + +inline void DoubleArrayBuilder::copy(std::size_t *size_ptr, + DoubleArrayUnit **buf_ptr) const { + if (size_ptr != NULL) { + *size_ptr = units_.size(); + } + if (buf_ptr != NULL) { + *buf_ptr = new DoubleArrayUnit[units_.size()]; + unit_type *units = reinterpret_cast(*buf_ptr); + for (std::size_t i = 0; i < units_.size(); ++i) { + units[i] = units_[i]; + } + } +} + +inline void DoubleArrayBuilder::clear() { + units_.clear(); + extras_.clear(); + labels_.clear(); + table_.clear(); + extras_head_ = 0; +} + +template +void DoubleArrayBuilder::build_dawg(const Keyset &keyset, + DawgBuilder *dawg_builder) { + dawg_builder->init(); + for (std::size_t i = 0; i < keyset.num_keys(); ++i) { + dawg_builder->insert(keyset.keys(i), keyset.lengths(i), keyset.values(i)); + if (progress_func_ != NULL) { + progress_func_(i + 1, keyset.num_keys() + 1); + } + } + dawg_builder->finish(); +} + +inline void DoubleArrayBuilder::build_from_dawg(const DawgBuilder &dawg) { + std::size_t num_units = 1; + while (num_units < dawg.size()) { + num_units <<= 1; + } + units_.reserve(num_units); + + table_.reset(new id_type[dawg.num_intersections()]); + for (std::size_t i = 0; i < dawg.num_intersections(); ++i) { + table_[i] = 0; + } + + extras_.reset(new extra_type[NUM_EXTRAS]); + + reserve_id(0); + extras(0).set_is_used(true); + units_[0].set_offset(1); + units_[0].set_label('\0'); + + if (dawg.child(dawg.root()) != 0) { + build_from_dawg(dawg, dawg.root(), 0); + } + + fix_all_blocks(); + + extras_.clear(); + labels_.clear(); + table_.clear(); +} + +inline void DoubleArrayBuilder::build_from_dawg(const DawgBuilder &dawg, + id_type dawg_id, id_type dic_id) { + id_type dawg_child_id = dawg.child(dawg_id); + if (dawg.is_intersection(dawg_child_id)) { + id_type intersection_id = dawg.intersection_id(dawg_child_id); + id_type offset = table_[intersection_id]; + if (offset != 0) { + offset ^= dic_id; + if (!(offset & UPPER_MASK) || !(offset & LOWER_MASK)) { + if (dawg.is_leaf(dawg_child_id)) { + units_[dic_id].set_has_leaf(true); + } + units_[dic_id].set_offset(offset); + return; + } + } + } + + id_type offset = arrange_from_dawg(dawg, dawg_id, dic_id); + if (dawg.is_intersection(dawg_child_id)) { + table_[dawg.intersection_id(dawg_child_id)] = offset; + } + + do { + uchar_type child_label = dawg.label(dawg_child_id); + id_type dic_child_id = offset ^ child_label; + if (child_label != '\0') { + build_from_dawg(dawg, dawg_child_id, dic_child_id); + } + dawg_child_id = dawg.sibling(dawg_child_id); + } while (dawg_child_id != 0); +} + +inline id_type DoubleArrayBuilder::arrange_from_dawg(const DawgBuilder &dawg, + id_type dawg_id, id_type dic_id) { + labels_.resize(0); + + id_type dawg_child_id = dawg.child(dawg_id); + while (dawg_child_id != 0) { + labels_.append(dawg.label(dawg_child_id)); + dawg_child_id = dawg.sibling(dawg_child_id); + } + + id_type offset = find_valid_offset(dic_id); + units_[dic_id].set_offset(dic_id ^ offset); + + dawg_child_id = dawg.child(dawg_id); + for (std::size_t i = 0; i < labels_.size(); ++i) { + id_type dic_child_id = offset ^ labels_[i]; + reserve_id(dic_child_id); + + if (dawg.is_leaf(dawg_child_id)) { + units_[dic_id].set_has_leaf(true); + units_[dic_child_id].set_value(dawg.value(dawg_child_id)); + } else { + units_[dic_child_id].set_label(labels_[i]); + } + + dawg_child_id = dawg.sibling(dawg_child_id); + } + extras(offset).set_is_used(true); + + return offset; +} + +template +void DoubleArrayBuilder::build_from_keyset(const Keyset &keyset) { + std::size_t num_units = 1; + while (num_units < keyset.num_keys()) { + num_units <<= 1; + } + units_.reserve(num_units); + + extras_.reset(new extra_type[NUM_EXTRAS]); + + reserve_id(0); + extras(0).set_is_used(true); + units_[0].set_offset(1); + units_[0].set_label('\0'); + + if (keyset.num_keys() > 0) { + build_from_keyset(keyset, 0, keyset.num_keys(), 0, 0); + } + + fix_all_blocks(); + + extras_.clear(); + labels_.clear(); +} + +template +void DoubleArrayBuilder::build_from_keyset(const Keyset &keyset, + std::size_t begin, std::size_t end, std::size_t depth, id_type dic_id) { + id_type offset = arrange_from_keyset(keyset, begin, end, depth, dic_id); + + while (begin < end) { + if (keyset.keys(begin, depth) != '\0') { + break; + } + ++begin; + } + if (begin == end) { + return; + } + + std::size_t last_begin = begin; + uchar_type last_label = keyset.keys(begin, depth); + while (++begin < end) { + uchar_type label = keyset.keys(begin, depth); + if (label != last_label) { + build_from_keyset(keyset, last_begin, begin, + depth + 1, offset ^ last_label); + last_begin = begin; + last_label = keyset.keys(begin, depth); + } + } + build_from_keyset(keyset, last_begin, end, depth + 1, offset ^ last_label); +} + +template +id_type DoubleArrayBuilder::arrange_from_keyset(const Keyset &keyset, + std::size_t begin, std::size_t end, std::size_t depth, id_type dic_id) { + labels_.resize(0); + + value_type value = -1; + for (std::size_t i = begin; i < end; ++i) { + uchar_type label = keyset.keys(i, depth); + if (label == '\0') { + if (keyset.has_lengths() && depth < keyset.lengths(i)) { + DARTS_THROW("failed to build double-array: " + "invalid null character"); + } else if (keyset.values(i) < 0) { + DARTS_THROW("failed to build double-array: negative value"); + } + + if (value == -1) { + value = keyset.values(i); + } + if (progress_func_ != NULL) { + progress_func_(i + 1, keyset.num_keys() + 1); + } + } + + if (labels_.empty()) { + labels_.append(label); + } else if (label != labels_[labels_.size() - 1]) { + if (label < labels_[labels_.size() - 1]) { + DARTS_THROW("failed to build double-array: wrong key order"); + } + labels_.append(label); + } + } + + id_type offset = find_valid_offset(dic_id); + units_[dic_id].set_offset(dic_id ^ offset); + + for (std::size_t i = 0; i < labels_.size(); ++i) { + id_type dic_child_id = offset ^ labels_[i]; + reserve_id(dic_child_id); + if (labels_[i] == '\0') { + units_[dic_id].set_has_leaf(true); + units_[dic_child_id].set_value(value); + } else { + units_[dic_child_id].set_label(labels_[i]); + } + } + extras(offset).set_is_used(true); + + return offset; +} + +inline id_type DoubleArrayBuilder::find_valid_offset(id_type id) const { + if (extras_head_ >= units_.size()) { + return units_.size() | (id & LOWER_MASK); + } + + id_type unfixed_id = extras_head_; + do { + id_type offset = unfixed_id ^ labels_[0]; + if (is_valid_offset(id, offset)) { + return offset; + } + unfixed_id = extras(unfixed_id).next(); + } while (unfixed_id != extras_head_); + + return units_.size() | (id & LOWER_MASK); +} + +inline bool DoubleArrayBuilder::is_valid_offset(id_type id, + id_type offset) const { + if (extras(offset).is_used()) { + return false; + } + + id_type rel_offset = id ^ offset; + if ((rel_offset & LOWER_MASK) && (rel_offset & UPPER_MASK)) { + return false; + } + + for (std::size_t i = 1; i < labels_.size(); ++i) { + if (extras(offset ^ labels_[i]).is_fixed()) { + return false; + } + } + + return true; +} + +inline void DoubleArrayBuilder::reserve_id(id_type id) { + if (id >= units_.size()) { + expand_units(); + } + + if (id == extras_head_) { + extras_head_ = extras(id).next(); + if (extras_head_ == id) { + extras_head_ = units_.size(); + } + } + extras(extras(id).prev()).set_next(extras(id).next()); + extras(extras(id).next()).set_prev(extras(id).prev()); + extras(id).set_is_fixed(true); +} + +inline void DoubleArrayBuilder::expand_units() { + id_type src_num_units = units_.size(); + id_type src_num_blocks = num_blocks(); + + id_type dest_num_units = src_num_units + BLOCK_SIZE; + id_type dest_num_blocks = src_num_blocks + 1; + + if (dest_num_blocks > NUM_EXTRA_BLOCKS) { + fix_block(src_num_blocks - NUM_EXTRA_BLOCKS); + } + + units_.resize(dest_num_units); + + if (dest_num_blocks > NUM_EXTRA_BLOCKS) { + for (std::size_t id = src_num_units; id < dest_num_units; ++id) { + extras(id).set_is_used(false); + extras(id).set_is_fixed(false); + } + } + + for (id_type i = src_num_units + 1; i < dest_num_units; ++i) { + extras(i - 1).set_next(i); + extras(i).set_prev(i - 1); + } + + extras(src_num_units).set_prev(dest_num_units - 1); + extras(dest_num_units - 1).set_next(src_num_units); + + extras(src_num_units).set_prev(extras(extras_head_).prev()); + extras(dest_num_units - 1).set_next(extras_head_); + + extras(extras(extras_head_).prev()).set_next(src_num_units); + extras(extras_head_).set_prev(dest_num_units - 1); +} + +inline void DoubleArrayBuilder::fix_all_blocks() { + id_type begin = 0; + if (num_blocks() > NUM_EXTRA_BLOCKS) { + begin = num_blocks() - NUM_EXTRA_BLOCKS; + } + id_type end = num_blocks(); + + for (id_type block_id = begin; block_id != end; ++block_id) { + fix_block(block_id); + } +} + +inline void DoubleArrayBuilder::fix_block(id_type block_id) { + id_type begin = block_id * BLOCK_SIZE; + id_type end = begin + BLOCK_SIZE; + + id_type unused_offset = 0; + for (id_type offset = begin; offset != end; ++offset) { + if (!extras(offset).is_used()) { + unused_offset = offset; + break; + } + } + + for (id_type id = begin; id != end; ++id) { + if (!extras(id).is_fixed()) { + reserve_id(id); + units_[id].set_label(static_cast(id ^ unused_offset)); + } + } +} + +} // namespace Details + +// +// Member function build() of DoubleArrayImpl. +// + +template +int DoubleArrayImpl::build(std::size_t num_keys, + const key_type * const *keys, const std::size_t *lengths, + const value_type *values, Details::progress_func_type progress_func) { + Details::Keyset keyset(num_keys, keys, lengths, values); + + Details::DoubleArrayBuilder builder(progress_func); + builder.build(keyset); + + std::size_t size = 0; + unit_type *buf = NULL; + builder.copy(&size, &buf); + + clear(); + + size_ = size; + array_ = buf; + buf_ = buf; + + if (progress_func != NULL) { + progress_func(num_keys + 1, num_keys + 1); + } + + return 0; +} + +} // namespace Darts + +#undef DARTS_INT_TO_STR +#undef DARTS_LINE_TO_STR +#undef DARTS_LINE_STR +#undef DARTS_THROW + +#endif // DARTS_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.clang-format b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..e7d00feaa08a95073ddce4101383715098496154 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.clang-format @@ -0,0 +1,5 @@ +--- +Language: Cpp +BasedOnStyle: Google +PointerAlignment: Left +... diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.github/ISSUE_TEMPLATE/bug_report.md b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000000000000000000000000000000000..6c2ced9b2ec5bee5e9c76972ef2c3eb4bbc083e5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG]" +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**System** +Which OS, compiler, and compiler version are you using: + - OS: + - Compiler and version: + +**To reproduce** +Steps to reproduce the behavior: +1. sync to commit ... +2. cmake/bazel... +3. make ... +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.github/ISSUE_TEMPLATE/feature_request.md b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000000000000000000000000000000000..9e8ab6a673f6b2321e01afb7803377387bdb6488 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[FR]" +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.gitignore b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..a7716e3d5d8d7aa4bad0f84680bef207c4b3f773 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.gitignore @@ -0,0 +1,62 @@ +*.a +*.so +*.so.?* +*.dll +*.exe +*.dylib +*.cmake +!/cmake/*.cmake +!/test/AssemblyTests.cmake +*~ +*.swp +*.pyc +__pycache__ + +# lcov +*.lcov +/lcov + +# cmake files. +/Testing +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake + +# makefiles. +Makefile + +# in-source build. +bin/ +lib/ +/test/*_test + +# exuberant ctags. +tags + +# YouCompleteMe configuration. +.ycm_extra_conf.pyc + +# ninja generated files. +.ninja_deps +.ninja_log +build.ninja +install_manifest.txt +rules.ninja + +# bazel output symlinks. +bazel-* + +# out-of-source build top-level folders. +build/ +_build/ +build*/ + +# in-source dependencies +/googletest/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +CMakeSettings.json + +# Visual Studio Code cache/options directory +.vscode/ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.travis-libcxx-setup.sh b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.travis-libcxx-setup.sh new file mode 100644 index 0000000000000000000000000000000000000000..a591743c6a6ba93566c21eb1bbe17ab5cee08b7a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.travis-libcxx-setup.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# Install a newer CMake version +curl -sSL https://cmake.org/files/v3.6/cmake-3.6.1-Linux-x86_64.sh -o install-cmake.sh +chmod +x install-cmake.sh +sudo ./install-cmake.sh --prefix=/usr/local --skip-license + +# Checkout LLVM sources +git clone --depth=1 https://github.com/llvm-mirror/llvm.git llvm-source +git clone --depth=1 https://github.com/llvm-mirror/libcxx.git llvm-source/projects/libcxx +git clone --depth=1 https://github.com/llvm-mirror/libcxxabi.git llvm-source/projects/libcxxabi + +# Setup libc++ options +if [ -z "$BUILD_32_BITS" ]; then + export BUILD_32_BITS=OFF && echo disabling 32 bit build +fi + +# Build and install libc++ (Use unstable ABI for better sanitizer coverage) +mkdir llvm-build && cd llvm-build +cmake -DCMAKE_C_COMPILER=${C_COMPILER} -DCMAKE_CXX_COMPILER=${COMPILER} \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr \ + -DLIBCXX_ABI_UNSTABLE=ON \ + -DLLVM_USE_SANITIZER=${LIBCXX_SANITIZER} \ + -DLLVM_BUILD_32_BITS=${BUILD_32_BITS} \ + ../llvm-source +make cxx -j2 +sudo make install-cxxabi install-cxx +cd ../ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.travis.yml b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..f220a7df61502f98ad3a1002a321a714552cdf7c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.travis.yml @@ -0,0 +1,231 @@ +sudo: required +dist: trusty +language: cpp + +matrix: + include: + - compiler: gcc + addons: + apt: + packages: + - lcov + env: COMPILER=g++ C_COMPILER=gcc BUILD_TYPE=Coverage + - compiler: gcc + env: COMPILER=g++ C_COMPILER=gcc BUILD_TYPE=Debug + - compiler: gcc + env: COMPILER=g++ C_COMPILER=gcc BUILD_TYPE=Release + - compiler: gcc + addons: + apt: + packages: + - g++-multilib + - libc6:i386 + env: + - COMPILER=g++ + - C_COMPILER=gcc + - BUILD_TYPE=Debug + - BUILD_32_BITS=ON + - EXTRA_FLAGS="-m32" + - compiler: gcc + addons: + apt: + packages: + - g++-multilib + - libc6:i386 + env: + - COMPILER=g++ + - C_COMPILER=gcc + - BUILD_TYPE=Release + - BUILD_32_BITS=ON + - EXTRA_FLAGS="-m32" + - compiler: gcc + env: + - INSTALL_GCC6_FROM_PPA=1 + - COMPILER=g++-6 C_COMPILER=gcc-6 BUILD_TYPE=Debug + - ENABLE_SANITIZER=1 + - EXTRA_FLAGS="-fno-omit-frame-pointer -g -O2 -fsanitize=undefined,address -fuse-ld=gold" + - compiler: clang + env: COMPILER=clang++ C_COMPILER=clang BUILD_TYPE=Debug + - compiler: clang + env: COMPILER=clang++ C_COMPILER=clang BUILD_TYPE=Release + # Clang w/ libc++ + - compiler: clang + dist: xenial + addons: + apt: + packages: + clang-3.8 + env: + - INSTALL_GCC6_FROM_PPA=1 + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug + - LIBCXX_BUILD=1 + - EXTRA_CXX_FLAGS="-stdlib=libc++" + - compiler: clang + dist: xenial + addons: + apt: + packages: + clang-3.8 + env: + - INSTALL_GCC6_FROM_PPA=1 + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Release + - LIBCXX_BUILD=1 + - EXTRA_CXX_FLAGS="-stdlib=libc++" + # Clang w/ 32bit libc++ + - compiler: clang + dist: xenial + addons: + apt: + packages: + - clang-3.8 + - g++-multilib + - libc6:i386 + env: + - INSTALL_GCC6_FROM_PPA=1 + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug + - LIBCXX_BUILD=1 + - BUILD_32_BITS=ON + - EXTRA_FLAGS="-m32" + - EXTRA_CXX_FLAGS="-stdlib=libc++" + # Clang w/ 32bit libc++ + - compiler: clang + dist: xenial + addons: + apt: + packages: + - clang-3.8 + - g++-multilib + - libc6:i386 + env: + - INSTALL_GCC6_FROM_PPA=1 + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Release + - LIBCXX_BUILD=1 + - BUILD_32_BITS=ON + - EXTRA_FLAGS="-m32" + - EXTRA_CXX_FLAGS="-stdlib=libc++" + # Clang w/ libc++, ASAN, UBSAN + - compiler: clang + dist: xenial + addons: + apt: + packages: + clang-3.8 + env: + - INSTALL_GCC6_FROM_PPA=1 + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug + - LIBCXX_BUILD=1 LIBCXX_SANITIZER="Undefined;Address" + - ENABLE_SANITIZER=1 + - EXTRA_FLAGS="-g -O2 -fno-omit-frame-pointer -fsanitize=undefined,address -fno-sanitize-recover=all" + - EXTRA_CXX_FLAGS="-stdlib=libc++" + - UBSAN_OPTIONS=print_stacktrace=1 + # Clang w/ libc++ and MSAN + - compiler: clang + dist: xenial + addons: + apt: + packages: + clang-3.8 + env: + - INSTALL_GCC6_FROM_PPA=1 + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug + - LIBCXX_BUILD=1 LIBCXX_SANITIZER=MemoryWithOrigins + - ENABLE_SANITIZER=1 + - EXTRA_FLAGS="-g -O2 -fno-omit-frame-pointer -fsanitize=memory -fsanitize-memory-track-origins" + - EXTRA_CXX_FLAGS="-stdlib=libc++" + # Clang w/ libc++ and MSAN + - compiler: clang + dist: xenial + addons: + apt: + packages: + clang-3.8 + env: + - INSTALL_GCC6_FROM_PPA=1 + - COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=RelWithDebInfo + - LIBCXX_BUILD=1 LIBCXX_SANITIZER=Thread + - ENABLE_SANITIZER=1 + - EXTRA_FLAGS="-g -O2 -fno-omit-frame-pointer -fsanitize=thread -fno-sanitize-recover=all" + - EXTRA_CXX_FLAGS="-stdlib=libc++" + - os: osx + osx_image: xcode8.3 + compiler: clang + env: + - COMPILER=clang++ BUILD_TYPE=Debug + - os: osx + osx_image: xcode8.3 + compiler: clang + env: + - COMPILER=clang++ BUILD_TYPE=Release + - os: osx + osx_image: xcode8.3 + compiler: clang + env: + - COMPILER=clang++ + - BUILD_TYPE=Release + - BUILD_32_BITS=ON + - EXTRA_FLAGS="-m32" + - os: osx + osx_image: xcode9.4 + compiler: gcc + env: + - COMPILER=g++-7 C_COMPILER=gcc-7 BUILD_TYPE=Debug + +before_script: + - if [ -n "${LIBCXX_BUILD}" ]; then + source .travis-libcxx-setup.sh; + fi + - if [ -n "${ENABLE_SANITIZER}" ]; then + export EXTRA_OPTIONS="-DBENCHMARK_ENABLE_ASSEMBLY_TESTS=OFF"; + else + export EXTRA_OPTIONS=""; + fi + - mkdir -p build && cd build + +before_install: + - if [ -z "$BUILD_32_BITS" ]; then + export BUILD_32_BITS=OFF && echo disabling 32 bit build; + fi + - if [ -n "${INSTALL_GCC6_FROM_PPA}" ]; then + sudo add-apt-repository -y "ppa:ubuntu-toolchain-r/test"; + sudo apt-get update --option Acquire::Retries=100 --option Acquire::http::Timeout="60"; + fi + +install: + - if [ -n "${INSTALL_GCC6_FROM_PPA}" ]; then + travis_wait sudo -E apt-get -yq --no-install-suggests --no-install-recommends install g++-6; + fi + - if [ "${TRAVIS_OS_NAME}" == "linux" -a "${BUILD_32_BITS}" == "OFF" ]; then + travis_wait sudo -E apt-get -y --no-install-suggests --no-install-recommends install llvm-3.9-tools; + sudo cp /usr/lib/llvm-3.9/bin/FileCheck /usr/local/bin/; + fi + - if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then + PATH=~/.local/bin:${PATH}; + pip install --user --upgrade pip; + travis_wait pip install --user cpp-coveralls; + fi + - if [ "${C_COMPILER}" == "gcc-7" -a "${TRAVIS_OS_NAME}" == "osx" ]; then + rm -f /usr/local/include/c++; + brew update; + travis_wait brew install gcc@7; + fi + - if [ "${TRAVIS_OS_NAME}" == "linux" ]; then + sudo apt-get update -qq; + sudo apt-get install -qq unzip cmake3; + wget https://github.com/bazelbuild/bazel/releases/download/0.10.1/bazel-0.10.1-installer-linux-x86_64.sh --output-document bazel-installer.sh; + travis_wait sudo bash bazel-installer.sh; + fi + - if [ "${TRAVIS_OS_NAME}" == "osx" ]; then + curl -L -o bazel-installer.sh https://github.com/bazelbuild/bazel/releases/download/0.10.1/bazel-0.10.1-installer-darwin-x86_64.sh; + travis_wait sudo bash bazel-installer.sh; + fi + +script: + - cmake -DCMAKE_C_COMPILER=${C_COMPILER} -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_C_FLAGS="${EXTRA_FLAGS}" -DCMAKE_CXX_FLAGS="${EXTRA_FLAGS} ${EXTRA_CXX_FLAGS}" -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON -DBENCHMARK_BUILD_32_BITS=${BUILD_32_BITS} ${EXTRA_OPTIONS} .. + - make + - ctest -C ${BUILD_TYPE} --output-on-failure + - bazel test -c dbg --define google_benchmark.have_regex=posix --announce_rc --verbose_failures --test_output=errors --keep_going //test/... + +after_success: + - if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then + coveralls --include src --include include --gcov-options '\-lp' --root .. --build-root .; + fi diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.ycm_extra_conf.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.ycm_extra_conf.py new file mode 100644 index 0000000000000000000000000000000000000000..5649ddcc749f0002829c02e6b7b10c6cd93bf7a5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/.ycm_extra_conf.py @@ -0,0 +1,115 @@ +import os +import ycm_core + +# These are the compilation flags that will be used in case there's no +# compilation database set (by default, one is not set). +# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. +flags = [ +'-Wall', +'-Werror', +'-pedantic-errors', +'-std=c++0x', +'-fno-strict-aliasing', +'-O3', +'-DNDEBUG', +# ...and the same thing goes for the magic -x option which specifies the +# language that the files to be compiled are written in. This is mostly +# relevant for c++ headers. +# For a C project, you would set this to 'c' instead of 'c++'. +'-x', 'c++', +'-I', 'include', +'-isystem', '/usr/include', +'-isystem', '/usr/local/include', +] + + +# Set this to the absolute path to the folder (NOT the file!) containing the +# compile_commands.json file to use that instead of 'flags'. See here for +# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html +# +# Most projects will NOT need to set this to anything; you can just change the +# 'flags' list of compilation flags. Notice that YCM itself uses that approach. +compilation_database_folder = '' + +if os.path.exists( compilation_database_folder ): + database = ycm_core.CompilationDatabase( compilation_database_folder ) +else: + database = None + +SOURCE_EXTENSIONS = [ '.cc' ] + +def DirectoryOfThisScript(): + return os.path.dirname( os.path.abspath( __file__ ) ) + + +def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): + if not working_directory: + return list( flags ) + new_flags = [] + make_next_absolute = False + path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] + for flag in flags: + new_flag = flag + + if make_next_absolute: + make_next_absolute = False + if not flag.startswith( '/' ): + new_flag = os.path.join( working_directory, flag ) + + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + + if flag.startswith( path_flag ): + path = flag[ len( path_flag ): ] + new_flag = path_flag + os.path.join( working_directory, path ) + break + + if new_flag: + new_flags.append( new_flag ) + return new_flags + + +def IsHeaderFile( filename ): + extension = os.path.splitext( filename )[ 1 ] + return extension in [ '.h', '.hxx', '.hpp', '.hh' ] + + +def GetCompilationInfoForFile( filename ): + # The compilation_commands.json file generated by CMake does not have entries + # for header files. So we do our best by asking the db for flags for a + # corresponding source file, if any. If one exists, the flags for that file + # should be good enough. + if IsHeaderFile( filename ): + basename = os.path.splitext( filename )[ 0 ] + for extension in SOURCE_EXTENSIONS: + replacement_file = basename + extension + if os.path.exists( replacement_file ): + compilation_info = database.GetCompilationInfoForFile( + replacement_file ) + if compilation_info.compiler_flags_: + return compilation_info + return None + return database.GetCompilationInfoForFile( filename ) + + +def FlagsForFile( filename, **kwargs ): + if database: + # Bear in mind that compilation_info.compiler_flags_ does NOT return a + # python list, but a "list-like" StringVec object + compilation_info = GetCompilationInfoForFile( filename ) + if not compilation_info: + return None + + final_flags = MakeRelativePathsInFlagsAbsolute( + compilation_info.compiler_flags_, + compilation_info.compiler_working_dir_ ) + else: + relative_to = DirectoryOfThisScript() + final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) + + return { + 'flags': final_flags, + 'do_cache': True + } diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/AUTHORS b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/AUTHORS new file mode 100644 index 0000000000000000000000000000000000000000..89205a1adba2419147da9d1200ee85244f87c816 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/AUTHORS @@ -0,0 +1,56 @@ +# This is the official list of benchmark authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. +# +# Names should be added to this file as: +# Name or Organization +# The email address is not required for organizations. +# +# Please keep the list sorted. + +Albert Pretorius +Alex Steele +Andriy Berestovskyy +Arne Beer +Carto +Christopher Seymour +Colin Braley +Daniel Harvey +David Coeurjolly +Deniz Evrenci +Dirac Research +Dominik Czarnota +Eric Backus +Eric Fiselier +Eugene Zhuk +Evgeny Safronov +Federico Ficarelli +Felix Homann +Gergő Szitár +Google Inc. +International Business Machines Corporation +Ismael Jimenez Martinez +Jern-Kuan Leong +JianXiong Zhou +Joao Paulo Magalhaes +Jordan Williams +Jussi Knuuttila +Kaito Udagawa +Kishan Kumar +Lei Xu +Matt Clarkson +Maxim Vafin +MongoDB Inc. +Nick Hutchinson +Oleksandr Sochka +Ori Livneh +Paul Redmond +Radoslav Yovchev +Roman Lebedev +Sayan Bhattacharjee +Shuo Chen +Steinar H. Gunderson +Stripe, Inc. +Yixuan Qiu +Yusuke Suzuki +Zbigniew Skowron diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/BUILD.bazel b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/BUILD.bazel new file mode 100644 index 0000000000000000000000000000000000000000..d97a019bee70b505c5e6a7f8e083f096407c2dd0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/BUILD.bazel @@ -0,0 +1,44 @@ +licenses(["notice"]) + +config_setting( + name = "windows", + values = { + "cpu": "x64_windows", + }, + visibility = [":__subpackages__"], +) + +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "benchmark", + srcs = glob( + [ + "src/*.cc", + "src/*.h", + ], + exclude = ["src/benchmark_main.cc"], + ), + hdrs = ["include/benchmark/benchmark.h"], + linkopts = select({ + ":windows": ["-DEFAULTLIB:shlwapi.lib"], + "//conditions:default": ["-pthread"], + }), + strip_include_prefix = "include", + visibility = ["//visibility:public"], +) + +cc_library( + name = "benchmark_main", + srcs = ["src/benchmark_main.cc"], + hdrs = ["include/benchmark/benchmark.h"], + strip_include_prefix = "include", + visibility = ["//visibility:public"], + deps = [":benchmark"], +) + +cc_library( + name = "benchmark_internal_headers", + hdrs = glob(["src/*.h"]), + visibility = ["//test:__pkg__"], +) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..68ee589b9d5849c8bf89354fac1b2da1165aeadc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/CMakeLists.txt @@ -0,0 +1,279 @@ +cmake_minimum_required (VERSION 3.5.1) + +foreach(p + CMP0048 # OK to clear PROJECT_VERSION on project() + CMP0054 # CMake 3.1 + CMP0056 # export EXE_LINKER_FLAGS to try_run + CMP0057 # Support no if() IN_LIST operator + CMP0063 # Honor visibility properties for all targets + CMP0077 # Allow option() overrides in importing projects + ) + if(POLICY ${p}) + cmake_policy(SET ${p} NEW) + endif() +endforeach() + +project (benchmark CXX) + +option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." OFF) +option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON) +option(BENCHMARK_ENABLE_LTO "Enable link time optimisation of the benchmark library." OFF) +option(BENCHMARK_USE_LIBCXX "Build and test using libc++ as the standard library." OFF) +if(NOT MSVC) + option(BENCHMARK_BUILD_32_BITS "Build a 32 bit version of the library." OFF) +else() + set(BENCHMARK_BUILD_32_BITS OFF CACHE BOOL "Build a 32 bit version of the library - unsupported when using MSVC)" FORCE) +endif() +option(BENCHMARK_ENABLE_INSTALL "Enable installation of benchmark. (Projects embedding benchmark may want to turn this OFF.)" ON) + +# Allow unmet dependencies to be met using CMake's ExternalProject mechanics, which +# may require downloading the source code. +option(BENCHMARK_DOWNLOAD_DEPENDENCIES "Allow the downloading and in-tree building of unmet dependencies" OFF) + +# This option can be used to disable building and running unit tests which depend on gtest +# in cases where it is not possible to build or find a valid version of gtest. +option(BENCHMARK_ENABLE_GTEST_TESTS "Enable building the unit tests which depend on gtest" ON) + +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +set(ENABLE_ASSEMBLY_TESTS_DEFAULT OFF) +function(should_enable_assembly_tests) + if(CMAKE_BUILD_TYPE) + string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER) + if (${CMAKE_BUILD_TYPE_LOWER} MATCHES "coverage") + # FIXME: The --coverage flag needs to be removed when building assembly + # tests for this to work. + return() + endif() + endif() + if (MSVC) + return() + elseif(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + return() + elseif(NOT CMAKE_SIZEOF_VOID_P EQUAL 8) + # FIXME: Make these work on 32 bit builds + return() + elseif(BENCHMARK_BUILD_32_BITS) + # FIXME: Make these work on 32 bit builds + return() + endif() + find_program(LLVM_FILECHECK_EXE FileCheck) + if (LLVM_FILECHECK_EXE) + set(LLVM_FILECHECK_EXE "${LLVM_FILECHECK_EXE}" CACHE PATH "llvm filecheck" FORCE) + message(STATUS "LLVM FileCheck Found: ${LLVM_FILECHECK_EXE}") + else() + message(STATUS "Failed to find LLVM FileCheck") + return() + endif() + set(ENABLE_ASSEMBLY_TESTS_DEFAULT ON PARENT_SCOPE) +endfunction() +should_enable_assembly_tests() + +# This option disables the building and running of the assembly verification tests +option(BENCHMARK_ENABLE_ASSEMBLY_TESTS "Enable building and running the assembly tests" + ${ENABLE_ASSEMBLY_TESTS_DEFAULT}) + +# Make sure we can import out CMake functions +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + + +# Read the git tags to determine the project version +include(GetGitVersion) +get_git_version(GIT_VERSION) + +# Tell the user what versions we are using +string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" VERSION ${GIT_VERSION}) +message(STATUS "Version: ${VERSION}") + +# The version of the libraries +set(GENERIC_LIB_VERSION ${VERSION}) +string(SUBSTRING ${VERSION} 0 1 GENERIC_LIB_SOVERSION) + +# Import our CMake modules +include(CheckCXXCompilerFlag) +include(AddCXXCompilerFlag) +include(CXXFeatureCheck) + +if (BENCHMARK_BUILD_32_BITS) + add_required_cxx_compiler_flag(-m32) +endif() + +if (MSVC) + # Turn compiler warnings up to 11 + string(REGEX REPLACE "[-/]W[1-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + + if (NOT BENCHMARK_ENABLE_EXCEPTIONS) + add_cxx_compiler_flag(-EHs-) + add_cxx_compiler_flag(-EHa-) + add_definitions(-D_HAS_EXCEPTIONS=0) + endif() + # Link time optimisation + if (BENCHMARK_ENABLE_LTO) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") + set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /GL") + string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO}") + set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") + string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}") + set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") + string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") + set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") + + set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /GL") + set(CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL "${CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL} /LTCG") + set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} /LTCG") + endif() +else() + # Try and enable C++11. Don't use C++14 because it doesn't work in some + # configurations. + add_cxx_compiler_flag(-std=c++11) + if (NOT HAVE_CXX_FLAG_STD_CXX11) + add_cxx_compiler_flag(-std=c++0x) + endif() + + # Turn compiler warnings up to 11 + add_cxx_compiler_flag(-Wall) + add_cxx_compiler_flag(-Wextra) + add_cxx_compiler_flag(-Wshadow) + add_cxx_compiler_flag(-Werror RELEASE) + add_cxx_compiler_flag(-Werror RELWITHDEBINFO) + add_cxx_compiler_flag(-Werror MINSIZEREL) + # Disabled until googletest (gmock) stops emitting variadic macro warnings + #add_cxx_compiler_flag(-pedantic) + #add_cxx_compiler_flag(-pedantic-errors) + add_cxx_compiler_flag(-Wshorten-64-to-32) + add_cxx_compiler_flag(-fstrict-aliasing) + # Disable warnings regarding deprecated parts of the library while building + # and testing those parts of the library. + add_cxx_compiler_flag(-Wno-deprecated-declarations) + if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + # Intel silently ignores '-Wno-deprecated-declarations', + # warning no. 1786 must be explicitly disabled. + # See #631 for rationale. + add_cxx_compiler_flag(-wd1786) + endif() + # Disable deprecation warnings for release builds (when -Werror is enabled). + add_cxx_compiler_flag(-Wno-deprecated RELEASE) + add_cxx_compiler_flag(-Wno-deprecated RELWITHDEBINFO) + add_cxx_compiler_flag(-Wno-deprecated MINSIZEREL) + if (NOT BENCHMARK_ENABLE_EXCEPTIONS) + add_cxx_compiler_flag(-fno-exceptions) + endif() + + if (HAVE_CXX_FLAG_FSTRICT_ALIASING) + if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel") #ICC17u2: Many false positives for Wstrict-aliasing + add_cxx_compiler_flag(-Wstrict-aliasing) + endif() + endif() + # ICC17u2: overloaded virtual function "benchmark::Fixture::SetUp" is only partially overridden + # (because of deprecated overload) + add_cxx_compiler_flag(-wd654) + add_cxx_compiler_flag(-Wthread-safety) + if (HAVE_CXX_FLAG_WTHREAD_SAFETY) + cxx_feature_check(THREAD_SAFETY_ATTRIBUTES) + endif() + + # On most UNIX like platforms g++ and clang++ define _GNU_SOURCE as a + # predefined macro, which turns on all of the wonderful libc extensions. + # However g++ doesn't do this in Cygwin so we have to define it ourselfs + # since we depend on GNU/POSIX/BSD extensions. + if (CYGWIN) + add_definitions(-D_GNU_SOURCE=1) + endif() + + if (QNXNTO) + add_definitions(-D_QNX_SOURCE) + endif() + + # Link time optimisation + if (BENCHMARK_ENABLE_LTO) + add_cxx_compiler_flag(-flto) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + find_program(GCC_AR gcc-ar) + if (GCC_AR) + set(CMAKE_AR ${GCC_AR}) + endif() + find_program(GCC_RANLIB gcc-ranlib) + if (GCC_RANLIB) + set(CMAKE_RANLIB ${GCC_RANLIB}) + endif() + elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + include(llvm-toolchain) + endif() + endif() + + # Coverage build type + set(BENCHMARK_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG}" + CACHE STRING "Flags used by the C++ compiler during coverage builds." + FORCE) + set(BENCHMARK_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" + CACHE STRING "Flags used for linking binaries during coverage builds." + FORCE) + set(BENCHMARK_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" + CACHE STRING "Flags used by the shared libraries linker during coverage builds." + FORCE) + mark_as_advanced( + BENCHMARK_CXX_FLAGS_COVERAGE + BENCHMARK_EXE_LINKER_FLAGS_COVERAGE + BENCHMARK_SHARED_LINKER_FLAGS_COVERAGE) + set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING + "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.") + add_cxx_compiler_flag(--coverage COVERAGE) +endif() + +if (BENCHMARK_USE_LIBCXX) + if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + add_cxx_compiler_flag(-stdlib=libc++) + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") + add_cxx_compiler_flag(-nostdinc++) + message(WARNING "libc++ header path must be manually specified using CMAKE_CXX_FLAGS") + # Adding -nodefaultlibs directly to CMAKE__LINKER_FLAGS will break + # configuration checks such as 'find_package(Threads)' + list(APPEND BENCHMARK_CXX_LINKER_FLAGS -nodefaultlibs) + # -lc++ cannot be added directly to CMAKE__LINKER_FLAGS because + # linker flags appear before all linker inputs and -lc++ must appear after. + list(APPEND BENCHMARK_CXX_LIBRARIES c++) + else() + message(FATAL_ERROR "-DBENCHMARK_USE_LIBCXX:BOOL=ON is not supported for compiler") + endif() +endif(BENCHMARK_USE_LIBCXX) + +# C++ feature checks +# Determine the correct regular expression engine to use +cxx_feature_check(STD_REGEX) +cxx_feature_check(GNU_POSIX_REGEX) +cxx_feature_check(POSIX_REGEX) +if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX) + message(FATAL_ERROR "Failed to determine the source files for the regular expression backend") +endif() +if (NOT BENCHMARK_ENABLE_EXCEPTIONS AND HAVE_STD_REGEX + AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX) + message(WARNING "Using std::regex with exceptions disabled is not fully supported") +endif() +cxx_feature_check(STEADY_CLOCK) +# Ensure we have pthreads +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +# Set up directories +include_directories(${PROJECT_SOURCE_DIR}/include) + +# Build the targets +add_subdirectory(src) + +if (BENCHMARK_ENABLE_TESTING) + enable_testing() + if (BENCHMARK_ENABLE_GTEST_TESTS AND + NOT (TARGET gtest AND TARGET gtest_main AND + TARGET gmock AND TARGET gmock_main)) + include(GoogleTest) + endif() + add_subdirectory(test) +endif() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/CONTRIBUTING.md b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..43de4c9d4709ad4a9162e68f2ba19c9d1b7e1834 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/CONTRIBUTING.md @@ -0,0 +1,58 @@ +# How to contribute # + +We'd love to accept your patches and contributions to this project. There are +a just a few small guidelines you need to follow. + + +## Contributor License Agreement ## + +Contributions to any Google project must be accompanied by a Contributor +License Agreement. This is not a copyright **assignment**, it simply gives +Google permission to use and redistribute your contributions as part of the +project. + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual + CLA][]. + + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA][]. + +You generally only need to submit a CLA once, so if you've already submitted +one (even if it was for a different project), you probably don't need to do it +again. + +[individual CLA]: https://developers.google.com/open-source/cla/individual +[corporate CLA]: https://developers.google.com/open-source/cla/corporate + +Once your CLA is submitted (or if you already submitted one for +another Google project), make a commit adding yourself to the +[AUTHORS][] and [CONTRIBUTORS][] files. This commit can be part +of your first [pull request][]. + +[AUTHORS]: AUTHORS +[CONTRIBUTORS]: CONTRIBUTORS + + +## Submitting a patch ## + + 1. It's generally best to start by opening a new issue describing the bug or + feature you're intending to fix. Even if you think it's relatively minor, + it's helpful to know what people are working on. Mention in the initial + issue that you are planning to work on that bug or feature so that it can + be assigned to you. + + 1. Follow the normal process of [forking][] the project, and setup a new + branch to work in. It's important that each group of changes be done in + separate branches in order to ensure that a pull request only includes the + commits related to that bug or feature. + + 1. Do your best to have [well-formed commit messages][] for each change. + This provides consistency throughout the project, and ensures that commit + messages are able to be formatted properly by various git tools. + + 1. Finally, push the commits to your fork and submit a [pull request][]. + +[forking]: https://help.github.com/articles/fork-a-repo +[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html +[pull request]: https://help.github.com/articles/creating-a-pull-request diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/CONTRIBUTORS b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/CONTRIBUTORS new file mode 100644 index 0000000000000000000000000000000000000000..88f7eee06cac4028d9550904f5a3e35de53d4792 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/CONTRIBUTORS @@ -0,0 +1,78 @@ +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# Names should be added to this file only after verifying that +# the individual or the individual's organization has agreed to +# the appropriate Contributor License Agreement, found here: +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# The agreement for individuals can be filled out on the web. +# +# When adding J Random Contributor's name to this file, +# either J's name or J's organization's name should be +# added to the AUTHORS file, depending on whether the +# individual or corporate CLA was used. +# +# Names should be added to this file as: +# Name +# +# Please keep the list sorted. + +Albert Pretorius +Alex Steele +Andriy Berestovskyy +Arne Beer +Billy Robert O'Neal III +Chris Kennelly +Christopher Seymour +Colin Braley +Cyrille Faucheux +Daniel Harvey +David Coeurjolly +Deniz Evrenci +Dominic Hamon +Dominik Czarnota +Eric Backus +Eric Fiselier +Eugene Zhuk +Evgeny Safronov +Federico Ficarelli +Felix Homann +Geoffrey Martin-Noble +Gergő Szitár +Hannes Hauswedell +Ismael Jimenez Martinez +Jern-Kuan Leong +JianXiong Zhou +Joao Paulo Magalhaes +John Millikin +Jordan Williams +Jussi Knuuttila +Kai Wolf +Kaito Udagawa +Kishan Kumar +Lei Xu +Matt Clarkson +Maxim Vafin +Nick Hutchinson +Oleksandr Sochka +Ori Livneh +Pascal Leroy +Paul Redmond +Pierre Phaneuf +Radoslav Yovchev +Raul Marin +Ray Glover +Robert Guo +Roman Lebedev +Sayan Bhattacharjee +Shuo Chen +Tobias Ulvgård +Tom Madams +Yixuan Qiu +Yusuke Suzuki +Zbigniew Skowron diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/LICENSE b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..d645695673349e3947e8e5ae42332d0ac3164cd7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/README.md b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/README.md new file mode 100644 index 0000000000000000000000000000000000000000..02a3bfad8036ff3cf875e5c73c1d1227e96106c6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/README.md @@ -0,0 +1,1300 @@ +# Benchmark + +[![Build Status](https://travis-ci.org/google/benchmark.svg?branch=master)](https://travis-ci.org/google/benchmark) +[![Build status](https://ci.appveyor.com/api/projects/status/u0qsyp7t1tk7cpxs/branch/master?svg=true)](https://ci.appveyor.com/project/google/benchmark/branch/master) +[![Coverage Status](https://coveralls.io/repos/google/benchmark/badge.svg)](https://coveralls.io/r/google/benchmark) +[![slackin](https://slackin-iqtfqnpzxd.now.sh/badge.svg)](https://slackin-iqtfqnpzxd.now.sh/) + +A library to benchmark code snippets, similar to unit tests. Example: + +```c++ +#include + +static void BM_SomeFunction(benchmark::State& state) { + // Perform setup here + for (auto _ : state) { + // This code gets timed + SomeFunction(); + } +} +// Register the function as a benchmark +BENCHMARK(BM_SomeFunction); +// Run the benchmark +BENCHMARK_MAIN(); +``` + +To get started, see [Requirements](#requirements) and +[Installation](#installation). See [Usage](#usage) for a full example and the +[User Guide](#user-guide) for a more comprehensive feature overview. + +It may also help to read the [Google Test documentation](https://github.com/google/googletest/blob/master/googletest/docs/primer.md) +as some of the structural aspects of the APIs are similar. + +### Resources + +[Discussion group](https://groups.google.com/d/forum/benchmark-discuss) + +IRC channel: [freenode](https://freenode.net) #googlebenchmark + +[Additional Tooling Documentation](docs/tools.md) + +[Assembly Testing Documentation](docs/AssemblyTests.md) + +## Requirements + +The library can be used with C++03. However, it requires C++11 to build, +including compiler and standard library support. + +The following minimum versions are required to build the library: + +* GCC 4.8 +* Clang 3.4 +* Visual Studio 14 2015 +* Intel 2015 Update 1 + +See [Platform-Specific Build Instructions](#platform-specific-build-instructions). + +## Installation + +This describes the installation process using cmake. As pre-requisites, you'll +need git and cmake installed. + +_See [dependencies.md](dependencies.md) for more details regarding supported +versions of build tools._ + +```bash +# Check out the library. +$ git clone https://github.com/google/benchmark.git +# Benchmark requires Google Test as a dependency. Add the source tree as a subdirectory. +$ git clone https://github.com/google/googletest.git benchmark/googletest +# Go to the library root directory +$ cd benchmark +# Make a build directory to place the build output. +$ mkdir build && cd build +# Generate a Makefile with cmake. +# Use cmake -G to generate a different file type. +$ cmake ../ +# Build the library. +# Use make -j to speed up the build process, e.g. make -j8 . +$ make +``` +This builds the `benchmark` and `benchmark_main` libraries and tests. +On a unix system, the build directory should now look something like this: + +``` +/benchmark + /build + /src + /libbenchmark.a + /libbenchmark_main.a + /test + ... +``` + +Next, you can run the tests to check the build. + +```bash +$ make test +``` + +If you want to install the library globally, also run: + +``` +sudo make install +``` + +Note that Google Benchmark requires Google Test to build and run the tests. This +dependency can be provided two ways: + +* Checkout the Google Test sources into `benchmark/googletest` as above. +* Otherwise, if `-DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON` is specified during + configuration, the library will automatically download and build any required + dependencies. + +If you do not wish to build and run the tests, add `-DBENCHMARK_ENABLE_GTEST_TESTS=OFF` +to `CMAKE_ARGS`. + +### Debug vs Release + +By default, benchmark builds as a debug library. You will see a warning in the +output when this is the case. To build it as a release library instead, use: + +``` +cmake -DCMAKE_BUILD_TYPE=Release +``` + +To enable link-time optimisation, use + +``` +cmake -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_ENABLE_LTO=true +``` + +If you are using gcc, you might need to set `GCC_AR` and `GCC_RANLIB` cmake +cache variables, if autodetection fails. + +If you are using clang, you may need to set `LLVMAR_EXECUTABLE`, +`LLVMNM_EXECUTABLE` and `LLVMRANLIB_EXECUTABLE` cmake cache variables. + + +### Stable and Experimental Library Versions + +The main branch contains the latest stable version of the benchmarking library; +the API of which can be considered largely stable, with source breaking changes +being made only upon the release of a new major version. + +Newer, experimental, features are implemented and tested on the +[`v2` branch](https://github.com/google/benchmark/tree/v2). Users who wish +to use, test, and provide feedback on the new features are encouraged to try +this branch. However, this branch provides no stability guarantees and reserves +the right to change and break the API at any time. + +## Usage + +### Basic usage + +Define a function that executes the code to measure, register it as a benchmark +function using the `BENCHMARK` macro, and ensure an appropriate `main` function +is available: + +```c++ +#include + +static void BM_StringCreation(benchmark::State& state) { + for (auto _ : state) + std::string empty_string; +} +// Register the function as a benchmark +BENCHMARK(BM_StringCreation); + +// Define another benchmark +static void BM_StringCopy(benchmark::State& state) { + std::string x = "hello"; + for (auto _ : state) + std::string copy(x); +} +BENCHMARK(BM_StringCopy); + +BENCHMARK_MAIN(); +``` + +To run the benchmark, compile and link against the `benchmark` library +(libbenchmark.a/.so). If you followed the build steps above, this library will +be under the build directory you created. + +```bash +# Example on linux after running the build steps above. Assumes the +# `benchmark` and `build` directories are under the current directory. +$ g++ mybenchmark.cc -std=c++11 -isystem benchmark/include \ + -Lbenchmark/build/src -lbenchmark -lpthread -o mybenchmark +``` + +Alternatively, link against the `benchmark_main` library and remove +`BENCHMARK_MAIN();` above to get the same behavior. + +The compiled executable will run all benchmarks by default. Pass the `--help` +flag for option information or see the guide below. + +### Usage with CMake + +If using CMake, it is recommended to link against the project-provided +`benchmark::benchmark` and `benchmark::benchmark_main` targets using +`target_link_libraries`. +It is possible to use ```find_package``` to import an installed version of the +library. +```cmake +find_package(benchmark REQUIRED) +``` +Alternatively, ```add_subdirectory``` will incorporate the library directly in +to one's CMake project. +```cmake +add_subdirectory(benchmark) +``` +Either way, link to the library as follows. +```cmake +target_link_libraries(MyTarget benchmark::benchmark) +``` + +## Platform Specific Build Instructions + +### Building with GCC + +When the library is built using GCC it is necessary to link with the pthread +library due to how GCC implements `std::thread`. Failing to link to pthread will +lead to runtime exceptions (unless you're using libc++), not linker errors. See +[issue #67](https://github.com/google/benchmark/issues/67) for more details. You +can link to pthread by adding `-pthread` to your linker command. Note, you can +also use `-lpthread`, but there are potential issues with ordering of command +line parameters if you use that. + +### Building with Visual Studio 2015 or 2017 + +The `shlwapi` library (`-lshlwapi`) is required to support a call to `CPUInfo` which reads the registry. Either add `shlwapi.lib` under `[ Configuration Properties > Linker > Input ]`, or use the following: + +``` +// Alternatively, can add libraries using linker options. +#ifdef _WIN32 +#pragma comment ( lib, "Shlwapi.lib" ) +#ifdef _DEBUG +#pragma comment ( lib, "benchmarkd.lib" ) +#else +#pragma comment ( lib, "benchmark.lib" ) +#endif +#endif +``` + +Can also use the graphical version of CMake: +* Open `CMake GUI`. +* Under `Where to build the binaries`, same path as source plus `build`. +* Under `CMAKE_INSTALL_PREFIX`, same path as source plus `install`. +* Click `Configure`, `Generate`, `Open Project`. +* If build fails, try deleting entire directory and starting again, or unticking options to build less. + +### Building with Intel 2015 Update 1 or Intel System Studio Update 4 + +See instructions for building with Visual Studio. Once built, right click on the solution and change the build to Intel. + +### Building on Solaris + +If you're running benchmarks on solaris, you'll want the kstat library linked in +too (`-lkstat`). + +## User Guide + +### Command Line + +[Output Formats](#output-formats) + +[Output Files](#output-files) + +[Running Benchmarks](#running-benchmarks) + +[Running a Subset of Benchmarks](#running-a-subset-of-benchmarks) + +[Result Comparison](#result-comparison) + +### Library + +[Runtime and Reporting Considerations](#runtime-and-reporting-considerations) + +[Passing Arguments](#passing-arguments) + +[Calculating Asymptotic Complexity](#asymptotic-complexity) + +[Templated Benchmarks](#templated-benchmarks) + +[Fixtures](#fixtures) + +[Custom Counters](#custom-counters) + +[Multithreaded Benchmarks](#multithreaded-benchmarks) + +[CPU Timers](#cpu-timers) + +[Manual Timing](#manual-timing) + +[Setting the Time Unit](#setting-the-time-unit) + +[Preventing Optimization](#preventing-optimization) + +[Reporting Statistics](#reporting-statistics) + +[Custom Statistics](#custom-statistics) + +[Using RegisterBenchmark](#using-register-benchmark) + +[Exiting with an Error](#exiting-with-an-error) + +[A Faster KeepRunning Loop](#a-faster-keep-running-loop) + +[Disabling CPU Frequency Scaling](#disabling-cpu-frequency-scaling) + + + + +### Output Formats + +The library supports multiple output formats. Use the +`--benchmark_format=` flag (or set the +`BENCHMARK_FORMAT=` environment variable) to set +the format type. `console` is the default format. + +The Console format is intended to be a human readable format. By default +the format generates color output. Context is output on stderr and the +tabular data on stdout. Example tabular output looks like: + +``` +Benchmark Time(ns) CPU(ns) Iterations +---------------------------------------------------------------------- +BM_SetInsert/1024/1 28928 29349 23853 133.097kB/s 33.2742k items/s +BM_SetInsert/1024/8 32065 32913 21375 949.487kB/s 237.372k items/s +BM_SetInsert/1024/10 33157 33648 21431 1.13369MB/s 290.225k items/s +``` + +The JSON format outputs human readable json split into two top level attributes. +The `context` attribute contains information about the run in general, including +information about the CPU and the date. +The `benchmarks` attribute contains a list of every benchmark run. Example json +output looks like: + +```json +{ + "context": { + "date": "2015/03/17-18:40:25", + "num_cpus": 40, + "mhz_per_cpu": 2801, + "cpu_scaling_enabled": false, + "build_type": "debug" + }, + "benchmarks": [ + { + "name": "BM_SetInsert/1024/1", + "iterations": 94877, + "real_time": 29275, + "cpu_time": 29836, + "bytes_per_second": 134066, + "items_per_second": 33516 + }, + { + "name": "BM_SetInsert/1024/8", + "iterations": 21609, + "real_time": 32317, + "cpu_time": 32429, + "bytes_per_second": 986770, + "items_per_second": 246693 + }, + { + "name": "BM_SetInsert/1024/10", + "iterations": 21393, + "real_time": 32724, + "cpu_time": 33355, + "bytes_per_second": 1199226, + "items_per_second": 299807 + } + ] +} +``` + +The CSV format outputs comma-separated values. The `context` is output on stderr +and the CSV itself on stdout. Example CSV output looks like: + +``` +name,iterations,real_time,cpu_time,bytes_per_second,items_per_second,label +"BM_SetInsert/1024/1",65465,17890.7,8407.45,475768,118942, +"BM_SetInsert/1024/8",116606,18810.1,9766.64,3.27646e+06,819115, +"BM_SetInsert/1024/10",106365,17238.4,8421.53,4.74973e+06,1.18743e+06, +``` + + + +### Output Files + +Write benchmark results to a file with the `--benchmark_out=` option +(or set `BENCHMARK_OUT`). Specify the output format with +`--benchmark_out_format={json|console|csv}` (or set +`BENCHMARK_OUT_FORMAT={json|console|csv}`). Note that specifying +`--benchmark_out` does not suppress the console output. + + + +### Running Benchmarks + +Benchmarks are executed by running the produced binaries. Benchmarks binaries, +by default, accept options that may be specified either through their command +line interface or by setting environment variables before execution. For every +`--option_flag=` CLI switch, a corresponding environment variable +`OPTION_FLAG=` exist and is used as default if set (CLI switches always + prevails). A complete list of CLI options is available running benchmarks + with the `--help` switch. + + + +### Running a Subset of Benchmarks + +The `--benchmark_filter=` option (or `BENCHMARK_FILTER=` +environment variable) can be used to only run the benchmarks that match +the specified ``. For example: + +```bash +$ ./run_benchmarks.x --benchmark_filter=BM_memcpy/32 +Run on (1 X 2300 MHz CPU ) +2016-06-25 19:34:24 +Benchmark Time CPU Iterations +---------------------------------------------------- +BM_memcpy/32 11 ns 11 ns 79545455 +BM_memcpy/32k 2181 ns 2185 ns 324074 +BM_memcpy/32 12 ns 12 ns 54687500 +BM_memcpy/32k 1834 ns 1837 ns 357143 +``` + + + +### Result comparison + +It is possible to compare the benchmarking results. +See [Additional Tooling Documentation](docs/tools.md) + + + +### Runtime and Reporting Considerations + +When the benchmark binary is executed, each benchmark function is run serially. +The number of iterations to run is determined dynamically by running the +benchmark a few times and measuring the time taken and ensuring that the +ultimate result will be statistically stable. As such, faster benchmark +functions will be run for more iterations than slower benchmark functions, and +the number of iterations is thus reported. + +In all cases, the number of iterations for which the benchmark is run is +governed by the amount of time the benchmark takes. Concretely, the number of +iterations is at least one, not more than 1e9, until CPU time is greater than +the minimum time, or the wallclock time is 5x minimum time. The minimum time is +set per benchmark by calling `MinTime` on the registered benchmark object. + +Average timings are then reported over the iterations run. If multiple +repetitions are requested using the `--benchmark_repetitions` command-line +option, or at registration time, the benchmark function will be run several +times and statistical results across these repetitions will also be reported. + +As well as the per-benchmark entries, a preamble in the report will include +information about the machine on which the benchmarks are run. + + + +### Passing Arguments + +Sometimes a family of benchmarks can be implemented with just one routine that +takes an extra argument to specify which one of the family of benchmarks to +run. For example, the following code defines a family of benchmarks for +measuring the speed of `memcpy()` calls of different lengths: + +```c++ +static void BM_memcpy(benchmark::State& state) { + char* src = new char[state.range(0)]; + char* dst = new char[state.range(0)]; + memset(src, 'x', state.range(0)); + for (auto _ : state) + memcpy(dst, src, state.range(0)); + state.SetBytesProcessed(int64_t(state.iterations()) * + int64_t(state.range(0))); + delete[] src; + delete[] dst; +} +BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10); +``` + +The preceding code is quite repetitive, and can be replaced with the following +short-hand. The following invocation will pick a few appropriate arguments in +the specified range and will generate a benchmark for each such argument. + +```c++ +BENCHMARK(BM_memcpy)->Range(8, 8<<10); +``` + +By default the arguments in the range are generated in multiples of eight and +the command above selects [ 8, 64, 512, 4k, 8k ]. In the following code the +range multiplier is changed to multiples of two. + +```c++ +BENCHMARK(BM_memcpy)->RangeMultiplier(2)->Range(8, 8<<10); +``` + +Now arguments generated are [ 8, 16, 32, 64, 128, 256, 512, 1024, 2k, 4k, 8k ]. + +The preceding code shows a method of defining a sparse range. The following +example shows a method of defining a dense range. It is then used to benchmark +the performance of `std::vector` initialization for uniformly increasing sizes. + +```c++ +static void BM_DenseRange(benchmark::State& state) { + for(auto _ : state) { + std::vector v(state.range(0), state.range(0)); + benchmark::DoNotOptimize(v.data()); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_DenseRange)->DenseRange(0, 1024, 128); +``` + +Now arguments generated are [ 0, 128, 256, 384, 512, 640, 768, 896, 1024 ]. + +You might have a benchmark that depends on two or more inputs. For example, the +following code defines a family of benchmarks for measuring the speed of set +insertion. + +```c++ +static void BM_SetInsert(benchmark::State& state) { + std::set data; + for (auto _ : state) { + state.PauseTiming(); + data = ConstructRandomSet(state.range(0)); + state.ResumeTiming(); + for (int j = 0; j < state.range(1); ++j) + data.insert(RandomNumber()); + } +} +BENCHMARK(BM_SetInsert) + ->Args({1<<10, 128}) + ->Args({2<<10, 128}) + ->Args({4<<10, 128}) + ->Args({8<<10, 128}) + ->Args({1<<10, 512}) + ->Args({2<<10, 512}) + ->Args({4<<10, 512}) + ->Args({8<<10, 512}); +``` + +The preceding code is quite repetitive, and can be replaced with the following +short-hand. The following macro will pick a few appropriate arguments in the +product of the two specified ranges and will generate a benchmark for each such +pair. + +```c++ +BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {128, 512}}); +``` + +For more complex patterns of inputs, passing a custom function to `Apply` allows +programmatic specification of an arbitrary set of arguments on which to run the +benchmark. The following example enumerates a dense range on one parameter, +and a sparse range on the second. + +```c++ +static void CustomArguments(benchmark::internal::Benchmark* b) { + for (int i = 0; i <= 10; ++i) + for (int j = 32; j <= 1024*1024; j *= 8) + b->Args({i, j}); +} +BENCHMARK(BM_SetInsert)->Apply(CustomArguments); +``` + +#### Passing Arbitrary Arguments to a Benchmark + +In C++11 it is possible to define a benchmark that takes an arbitrary number +of extra arguments. The `BENCHMARK_CAPTURE(func, test_case_name, ...args)` +macro creates a benchmark that invokes `func` with the `benchmark::State` as +the first argument followed by the specified `args...`. +The `test_case_name` is appended to the name of the benchmark and +should describe the values passed. + +```c++ +template +void BM_takes_args(benchmark::State& state, ExtraArgs&&... extra_args) { + [...] +} +// Registers a benchmark named "BM_takes_args/int_string_test" that passes +// the specified values to `extra_args`. +BENCHMARK_CAPTURE(BM_takes_args, int_string_test, 42, std::string("abc")); +``` + +Note that elements of `...args` may refer to global variables. Users should +avoid modifying global state inside of a benchmark. + + + +### Calculating Asymptotic Complexity (Big O) + +Asymptotic complexity might be calculated for a family of benchmarks. The +following code will calculate the coefficient for the high-order term in the +running time and the normalized root-mean square error of string comparison. + +```c++ +static void BM_StringCompare(benchmark::State& state) { + std::string s1(state.range(0), '-'); + std::string s2(state.range(0), '-'); + for (auto _ : state) { + benchmark::DoNotOptimize(s1.compare(s2)); + } + state.SetComplexityN(state.range(0)); +} +BENCHMARK(BM_StringCompare) + ->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity(benchmark::oN); +``` + +As shown in the following invocation, asymptotic complexity might also be +calculated automatically. + +```c++ +BENCHMARK(BM_StringCompare) + ->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity(); +``` + +The following code will specify asymptotic complexity with a lambda function, +that might be used to customize high-order term calculation. + +```c++ +BENCHMARK(BM_StringCompare)->RangeMultiplier(2) + ->Range(1<<10, 1<<18)->Complexity([](benchmark::IterationCount n)->double{return n; }); +``` + + + +### Templated Benchmarks + +This example produces and consumes messages of size `sizeof(v)` `range_x` +times. It also outputs throughput in the absence of multiprogramming. + +```c++ +template void BM_Sequential(benchmark::State& state) { + Q q; + typename Q::value_type v; + for (auto _ : state) { + for (int i = state.range(0); i--; ) + q.push(v); + for (int e = state.range(0); e--; ) + q.Wait(&v); + } + // actually messages, not bytes: + state.SetBytesProcessed( + static_cast(state.iterations())*state.range(0)); +} +BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue)->Range(1<<0, 1<<10); +``` + +Three macros are provided for adding benchmark templates. + +```c++ +#ifdef BENCHMARK_HAS_CXX11 +#define BENCHMARK_TEMPLATE(func, ...) // Takes any number of parameters. +#else // C++ < C++11 +#define BENCHMARK_TEMPLATE(func, arg1) +#endif +#define BENCHMARK_TEMPLATE1(func, arg1) +#define BENCHMARK_TEMPLATE2(func, arg1, arg2) +``` + + + +### Fixtures + +Fixture tests are created by first defining a type that derives from +`::benchmark::Fixture` and then creating/registering the tests using the +following macros: + +* `BENCHMARK_F(ClassName, Method)` +* `BENCHMARK_DEFINE_F(ClassName, Method)` +* `BENCHMARK_REGISTER_F(ClassName, Method)` + +For Example: + +```c++ +class MyFixture : public benchmark::Fixture { +public: + void SetUp(const ::benchmark::State& state) { + } + + void TearDown(const ::benchmark::State& state) { + } +}; + +BENCHMARK_F(MyFixture, FooTest)(benchmark::State& st) { + for (auto _ : st) { + ... + } +} + +BENCHMARK_DEFINE_F(MyFixture, BarTest)(benchmark::State& st) { + for (auto _ : st) { + ... + } +} +/* BarTest is NOT registered */ +BENCHMARK_REGISTER_F(MyFixture, BarTest)->Threads(2); +/* BarTest is now registered */ +``` + +#### Templated Fixtures + +Also you can create templated fixture by using the following macros: + +* `BENCHMARK_TEMPLATE_F(ClassName, Method, ...)` +* `BENCHMARK_TEMPLATE_DEFINE_F(ClassName, Method, ...)` + +For example: + +```c++ +template +class MyFixture : public benchmark::Fixture {}; + +BENCHMARK_TEMPLATE_F(MyFixture, IntTest, int)(benchmark::State& st) { + for (auto _ : st) { + ... + } +} + +BENCHMARK_TEMPLATE_DEFINE_F(MyFixture, DoubleTest, double)(benchmark::State& st) { + for (auto _ : st) { + ... + } +} + +BENCHMARK_REGISTER_F(MyFixture, DoubleTest)->Threads(2); +``` + + + +### Custom Counters + +You can add your own counters with user-defined names. The example below +will add columns "Foo", "Bar" and "Baz" in its output: + +```c++ +static void UserCountersExample1(benchmark::State& state) { + double numFoos = 0, numBars = 0, numBazs = 0; + for (auto _ : state) { + // ... count Foo,Bar,Baz events + } + state.counters["Foo"] = numFoos; + state.counters["Bar"] = numBars; + state.counters["Baz"] = numBazs; +} +``` + +The `state.counters` object is a `std::map` with `std::string` keys +and `Counter` values. The latter is a `double`-like class, via an implicit +conversion to `double&`. Thus you can use all of the standard arithmetic +assignment operators (`=,+=,-=,*=,/=`) to change the value of each counter. + +In multithreaded benchmarks, each counter is set on the calling thread only. +When the benchmark finishes, the counters from each thread will be summed; +the resulting sum is the value which will be shown for the benchmark. + +The `Counter` constructor accepts three parameters: the value as a `double` +; a bit flag which allows you to show counters as rates, and/or as per-thread +iteration, and/or as per-thread averages, and/or iteration invariants, +and/or finally inverting the result; and a flag specifying the 'unit' - i.e. +is 1k a 1000 (default, `benchmark::Counter::OneK::kIs1000`), or 1024 +(`benchmark::Counter::OneK::kIs1024`)? + +```c++ + // sets a simple counter + state.counters["Foo"] = numFoos; + + // Set the counter as a rate. It will be presented divided + // by the duration of the benchmark. + // Meaning: per one second, how many 'foo's are processed? + state.counters["FooRate"] = Counter(numFoos, benchmark::Counter::kIsRate); + + // Set the counter as a rate. It will be presented divided + // by the duration of the benchmark, and the result inverted. + // Meaning: how many seconds it takes to process one 'foo'? + state.counters["FooInvRate"] = Counter(numFoos, benchmark::Counter::kIsRate | benchmark::Counter::kInvert); + + // Set the counter as a thread-average quantity. It will + // be presented divided by the number of threads. + state.counters["FooAvg"] = Counter(numFoos, benchmark::Counter::kAvgThreads); + + // There's also a combined flag: + state.counters["FooAvgRate"] = Counter(numFoos,benchmark::Counter::kAvgThreadsRate); + + // This says that we process with the rate of state.range(0) bytes every iteration: + state.counters["BytesProcessed"] = Counter(state.range(0), benchmark::Counter::kIsIterationInvariantRate, benchmark::Counter::OneK::kIs1024); +``` + +When you're compiling in C++11 mode or later you can use `insert()` with +`std::initializer_list`: + +```c++ + // With C++11, this can be done: + state.counters.insert({{"Foo", numFoos}, {"Bar", numBars}, {"Baz", numBazs}}); + // ... instead of: + state.counters["Foo"] = numFoos; + state.counters["Bar"] = numBars; + state.counters["Baz"] = numBazs; +``` + +#### Counter Reporting + +When using the console reporter, by default, user counters are printed at +the end after the table, the same way as ``bytes_processed`` and +``items_processed``. This is best for cases in which there are few counters, +or where there are only a couple of lines per benchmark. Here's an example of +the default output: + +``` +------------------------------------------------------------------------------ +Benchmark Time CPU Iterations UserCounters... +------------------------------------------------------------------------------ +BM_UserCounter/threads:8 2248 ns 10277 ns 68808 Bar=16 Bat=40 Baz=24 Foo=8 +BM_UserCounter/threads:1 9797 ns 9788 ns 71523 Bar=2 Bat=5 Baz=3 Foo=1024m +BM_UserCounter/threads:2 4924 ns 9842 ns 71036 Bar=4 Bat=10 Baz=6 Foo=2 +BM_UserCounter/threads:4 2589 ns 10284 ns 68012 Bar=8 Bat=20 Baz=12 Foo=4 +BM_UserCounter/threads:8 2212 ns 10287 ns 68040 Bar=16 Bat=40 Baz=24 Foo=8 +BM_UserCounter/threads:16 1782 ns 10278 ns 68144 Bar=32 Bat=80 Baz=48 Foo=16 +BM_UserCounter/threads:32 1291 ns 10296 ns 68256 Bar=64 Bat=160 Baz=96 Foo=32 +BM_UserCounter/threads:4 2615 ns 10307 ns 68040 Bar=8 Bat=20 Baz=12 Foo=4 +BM_Factorial 26 ns 26 ns 26608979 40320 +BM_Factorial/real_time 26 ns 26 ns 26587936 40320 +BM_CalculatePiRange/1 16 ns 16 ns 45704255 0 +BM_CalculatePiRange/8 73 ns 73 ns 9520927 3.28374 +BM_CalculatePiRange/64 609 ns 609 ns 1140647 3.15746 +BM_CalculatePiRange/512 4900 ns 4901 ns 142696 3.14355 +``` + +If this doesn't suit you, you can print each counter as a table column by +passing the flag `--benchmark_counters_tabular=true` to the benchmark +application. This is best for cases in which there are a lot of counters, or +a lot of lines per individual benchmark. Note that this will trigger a +reprinting of the table header any time the counter set changes between +individual benchmarks. Here's an example of corresponding output when +`--benchmark_counters_tabular=true` is passed: + +``` +--------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations Bar Bat Baz Foo +--------------------------------------------------------------------------------------- +BM_UserCounter/threads:8 2198 ns 9953 ns 70688 16 40 24 8 +BM_UserCounter/threads:1 9504 ns 9504 ns 73787 2 5 3 1 +BM_UserCounter/threads:2 4775 ns 9550 ns 72606 4 10 6 2 +BM_UserCounter/threads:4 2508 ns 9951 ns 70332 8 20 12 4 +BM_UserCounter/threads:8 2055 ns 9933 ns 70344 16 40 24 8 +BM_UserCounter/threads:16 1610 ns 9946 ns 70720 32 80 48 16 +BM_UserCounter/threads:32 1192 ns 9948 ns 70496 64 160 96 32 +BM_UserCounter/threads:4 2506 ns 9949 ns 70332 8 20 12 4 +-------------------------------------------------------------- +Benchmark Time CPU Iterations +-------------------------------------------------------------- +BM_Factorial 26 ns 26 ns 26392245 40320 +BM_Factorial/real_time 26 ns 26 ns 26494107 40320 +BM_CalculatePiRange/1 15 ns 15 ns 45571597 0 +BM_CalculatePiRange/8 74 ns 74 ns 9450212 3.28374 +BM_CalculatePiRange/64 595 ns 595 ns 1173901 3.15746 +BM_CalculatePiRange/512 4752 ns 4752 ns 147380 3.14355 +BM_CalculatePiRange/4k 37970 ns 37972 ns 18453 3.14184 +BM_CalculatePiRange/32k 303733 ns 303744 ns 2305 3.14162 +BM_CalculatePiRange/256k 2434095 ns 2434186 ns 288 3.1416 +BM_CalculatePiRange/1024k 9721140 ns 9721413 ns 71 3.14159 +BM_CalculatePi/threads:8 2255 ns 9943 ns 70936 +``` + +Note above the additional header printed when the benchmark changes from +``BM_UserCounter`` to ``BM_Factorial``. This is because ``BM_Factorial`` does +not have the same counter set as ``BM_UserCounter``. + + + +### Multithreaded Benchmarks + +In a multithreaded test (benchmark invoked by multiple threads simultaneously), +it is guaranteed that none of the threads will start until all have reached +the start of the benchmark loop, and all will have finished before any thread +exits the benchmark loop. (This behavior is also provided by the `KeepRunning()` +API) As such, any global setup or teardown can be wrapped in a check against the thread +index: + +```c++ +static void BM_MultiThreaded(benchmark::State& state) { + if (state.thread_index == 0) { + // Setup code here. + } + for (auto _ : state) { + // Run the test as normal. + } + if (state.thread_index == 0) { + // Teardown code here. + } +} +BENCHMARK(BM_MultiThreaded)->Threads(2); +``` + +If the benchmarked code itself uses threads and you want to compare it to +single-threaded code, you may want to use real-time ("wallclock") measurements +for latency comparisons: + +```c++ +BENCHMARK(BM_test)->Range(8, 8<<10)->UseRealTime(); +``` + +Without `UseRealTime`, CPU time is used by default. + + + +### CPU Timers + +By default, the CPU timer only measures the time spent by the main thread. +If the benchmark itself uses threads internally, this measurement may not +be what you are looking for. Instead, there is a way to measure the total +CPU usage of the process, by all the threads. + +```c++ +void callee(int i); + +static void MyMain(int size) { +#pragma omp parallel for + for(int i = 0; i < size; i++) + callee(i); +} + +static void BM_OpenMP(benchmark::State& state) { + for (auto _ : state) + MyMain(state.range(0)); +} + +// Measure the time spent by the main thread, use it to decide for how long to +// run the benchmark loop. Depending on the internal implementation detail may +// measure to anywhere from near-zero (the overhead spent before/after work +// handoff to worker thread[s]) to the whole single-thread time. +BENCHMARK(BM_OpenMP)->Range(8, 8<<10); + +// Measure the user-visible time, the wall clock (literally, the time that +// has passed on the clock on the wall), use it to decide for how long to +// run the benchmark loop. This will always be meaningful, an will match the +// time spent by the main thread in single-threaded case, in general decreasing +// with the number of internal threads doing the work. +BENCHMARK(BM_OpenMP)->Range(8, 8<<10)->UseRealTime(); + +// Measure the total CPU consumption, use it to decide for how long to +// run the benchmark loop. This will always measure to no less than the +// time spent by the main thread in single-threaded case. +BENCHMARK(BM_OpenMP)->Range(8, 8<<10)->MeasureProcessCPUTime(); + +// A mixture of the last two. Measure the total CPU consumption, but use the +// wall clock to decide for how long to run the benchmark loop. +BENCHMARK(BM_OpenMP)->Range(8, 8<<10)->MeasureProcessCPUTime()->UseRealTime(); +``` + +#### Controlling Timers + +Normally, the entire duration of the work loop (`for (auto _ : state) {}`) +is measured. But sometimes, it is necessary to do some work inside of +that loop, every iteration, but without counting that time to the benchmark time. +That is possible, although it is not recommended, since it has high overhead. + +```c++ +static void BM_SetInsert_With_Timer_Control(benchmark::State& state) { + std::set data; + for (auto _ : state) { + state.PauseTiming(); // Stop timers. They will not count until they are resumed. + data = ConstructRandomSet(state.range(0)); // Do something that should not be measured + state.ResumeTiming(); // And resume timers. They are now counting again. + // The rest will be measured. + for (int j = 0; j < state.range(1); ++j) + data.insert(RandomNumber()); + } +} +BENCHMARK(BM_SetInsert_With_Timer_Control)->Ranges({{1<<10, 8<<10}, {128, 512}}); +``` + + + +### Manual Timing + +For benchmarking something for which neither CPU time nor real-time are +correct or accurate enough, completely manual timing is supported using +the `UseManualTime` function. + +When `UseManualTime` is used, the benchmarked code must call +`SetIterationTime` once per iteration of the benchmark loop to +report the manually measured time. + +An example use case for this is benchmarking GPU execution (e.g. OpenCL +or CUDA kernels, OpenGL or Vulkan or Direct3D draw calls), which cannot +be accurately measured using CPU time or real-time. Instead, they can be +measured accurately using a dedicated API, and these measurement results +can be reported back with `SetIterationTime`. + +```c++ +static void BM_ManualTiming(benchmark::State& state) { + int microseconds = state.range(0); + std::chrono::duration sleep_duration { + static_cast(microseconds) + }; + + for (auto _ : state) { + auto start = std::chrono::high_resolution_clock::now(); + // Simulate some useful workload with a sleep + std::this_thread::sleep_for(sleep_duration); + auto end = std::chrono::high_resolution_clock::now(); + + auto elapsed_seconds = + std::chrono::duration_cast>( + end - start); + + state.SetIterationTime(elapsed_seconds.count()); + } +} +BENCHMARK(BM_ManualTiming)->Range(1, 1<<17)->UseManualTime(); +``` + + + +### Setting the Time Unit + +If a benchmark runs a few milliseconds it may be hard to visually compare the +measured times, since the output data is given in nanoseconds per default. In +order to manually set the time unit, you can specify it manually: + +```c++ +BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); +``` + + + +### Preventing Optimization + +To prevent a value or expression from being optimized away by the compiler +the `benchmark::DoNotOptimize(...)` and `benchmark::ClobberMemory()` +functions can be used. + +```c++ +static void BM_test(benchmark::State& state) { + for (auto _ : state) { + int x = 0; + for (int i=0; i < 64; ++i) { + benchmark::DoNotOptimize(x += i); + } + } +} +``` + +`DoNotOptimize()` forces the *result* of `` to be stored in either +memory or a register. For GNU based compilers it acts as read/write barrier +for global memory. More specifically it forces the compiler to flush pending +writes to memory and reload any other values as necessary. + +Note that `DoNotOptimize()` does not prevent optimizations on `` +in any way. `` may even be removed entirely when the result is already +known. For example: + +```c++ + /* Example 1: `` is removed entirely. */ + int foo(int x) { return x + 42; } + while (...) DoNotOptimize(foo(0)); // Optimized to DoNotOptimize(42); + + /* Example 2: Result of '' is only reused */ + int bar(int) __attribute__((const)); + while (...) DoNotOptimize(bar(0)); // Optimized to: + // int __result__ = bar(0); + // while (...) DoNotOptimize(__result__); +``` + +The second tool for preventing optimizations is `ClobberMemory()`. In essence +`ClobberMemory()` forces the compiler to perform all pending writes to global +memory. Memory managed by block scope objects must be "escaped" using +`DoNotOptimize(...)` before it can be clobbered. In the below example +`ClobberMemory()` prevents the call to `v.push_back(42)` from being optimized +away. + +```c++ +static void BM_vector_push_back(benchmark::State& state) { + for (auto _ : state) { + std::vector v; + v.reserve(1); + benchmark::DoNotOptimize(v.data()); // Allow v.data() to be clobbered. + v.push_back(42); + benchmark::ClobberMemory(); // Force 42 to be written to memory. + } +} +``` + +Note that `ClobberMemory()` is only available for GNU or MSVC based compilers. + + + +### Statistics: Reporting the Mean, Median and Standard Deviation of Repeated Benchmarks + +By default each benchmark is run once and that single result is reported. +However benchmarks are often noisy and a single result may not be representative +of the overall behavior. For this reason it's possible to repeatedly rerun the +benchmark. + +The number of runs of each benchmark is specified globally by the +`--benchmark_repetitions` flag or on a per benchmark basis by calling +`Repetitions` on the registered benchmark object. When a benchmark is run more +than once the mean, median and standard deviation of the runs will be reported. + +Additionally the `--benchmark_report_aggregates_only={true|false}`, +`--benchmark_display_aggregates_only={true|false}` flags or +`ReportAggregatesOnly(bool)`, `DisplayAggregatesOnly(bool)` functions can be +used to change how repeated tests are reported. By default the result of each +repeated run is reported. When `report aggregates only` option is `true`, +only the aggregates (i.e. mean, median and standard deviation, maybe complexity +measurements if they were requested) of the runs is reported, to both the +reporters - standard output (console), and the file. +However when only the `display aggregates only` option is `true`, +only the aggregates are displayed in the standard output, while the file +output still contains everything. +Calling `ReportAggregatesOnly(bool)` / `DisplayAggregatesOnly(bool)` on a +registered benchmark object overrides the value of the appropriate flag for that +benchmark. + + + +### Custom Statistics + +While having mean, median and standard deviation is nice, this may not be +enough for everyone. For example you may want to know what the largest +observation is, e.g. because you have some real-time constraints. This is easy. +The following code will specify a custom statistic to be calculated, defined +by a lambda function. + +```c++ +void BM_spin_empty(benchmark::State& state) { + for (auto _ : state) { + for (int x = 0; x < state.range(0); ++x) { + benchmark::DoNotOptimize(x); + } + } +} + +BENCHMARK(BM_spin_empty) + ->ComputeStatistics("max", [](const std::vector& v) -> double { + return *(std::max_element(std::begin(v), std::end(v))); + }) + ->Arg(512); +``` + + + +### Using RegisterBenchmark(name, fn, args...) + +The `RegisterBenchmark(name, func, args...)` function provides an alternative +way to create and register benchmarks. +`RegisterBenchmark(name, func, args...)` creates, registers, and returns a +pointer to a new benchmark with the specified `name` that invokes +`func(st, args...)` where `st` is a `benchmark::State` object. + +Unlike the `BENCHMARK` registration macros, which can only be used at the global +scope, the `RegisterBenchmark` can be called anywhere. This allows for +benchmark tests to be registered programmatically. + +Additionally `RegisterBenchmark` allows any callable object to be registered +as a benchmark. Including capturing lambdas and function objects. + +For Example: +```c++ +auto BM_test = [](benchmark::State& st, auto Inputs) { /* ... */ }; + +int main(int argc, char** argv) { + for (auto& test_input : { /* ... */ }) + benchmark::RegisterBenchmark(test_input.name(), BM_test, test_input); + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); +} +``` + + + +### Exiting with an Error + +When errors caused by external influences, such as file I/O and network +communication, occur within a benchmark the +`State::SkipWithError(const char* msg)` function can be used to skip that run +of benchmark and report the error. Note that only future iterations of the +`KeepRunning()` are skipped. For the ranged-for version of the benchmark loop +Users must explicitly exit the loop, otherwise all iterations will be performed. +Users may explicitly return to exit the benchmark immediately. + +The `SkipWithError(...)` function may be used at any point within the benchmark, +including before and after the benchmark loop. Moreover, if `SkipWithError(...)` +has been used, it is not required to reach the benchmark loop and one may return +from the benchmark function early. + +For example: + +```c++ +static void BM_test(benchmark::State& state) { + auto resource = GetResource(); + if (!resource.good()) { + state.SkipWithError("Resource is not good!"); + // KeepRunning() loop will not be entered. + } + while (state.KeepRunning()) { + auto data = resource.read_data(); + if (!resource.good()) { + state.SkipWithError("Failed to read data!"); + break; // Needed to skip the rest of the iteration. + } + do_stuff(data); + } +} + +static void BM_test_ranged_fo(benchmark::State & state) { + auto resource = GetResource(); + if (!resource.good()) { + state.SkipWithError("Resource is not good!"); + return; // Early return is allowed when SkipWithError() has been used. + } + for (auto _ : state) { + auto data = resource.read_data(); + if (!resource.good()) { + state.SkipWithError("Failed to read data!"); + break; // REQUIRED to prevent all further iterations. + } + do_stuff(data); + } +} +``` + + +### A Faster KeepRunning Loop + +In C++11 mode, a ranged-based for loop should be used in preference to +the `KeepRunning` loop for running the benchmarks. For example: + +```c++ +static void BM_Fast(benchmark::State &state) { + for (auto _ : state) { + FastOperation(); + } +} +BENCHMARK(BM_Fast); +``` + +The reason the ranged-for loop is faster than using `KeepRunning`, is +because `KeepRunning` requires a memory load and store of the iteration count +ever iteration, whereas the ranged-for variant is able to keep the iteration count +in a register. + +For example, an empty inner loop of using the ranged-based for method looks like: + +```asm +# Loop Init + mov rbx, qword ptr [r14 + 104] + call benchmark::State::StartKeepRunning() + test rbx, rbx + je .LoopEnd +.LoopHeader: # =>This Inner Loop Header: Depth=1 + add rbx, -1 + jne .LoopHeader +.LoopEnd: +``` + +Compared to an empty `KeepRunning` loop, which looks like: + +```asm +.LoopHeader: # in Loop: Header=BB0_3 Depth=1 + cmp byte ptr [rbx], 1 + jne .LoopInit +.LoopBody: # =>This Inner Loop Header: Depth=1 + mov rax, qword ptr [rbx + 8] + lea rcx, [rax + 1] + mov qword ptr [rbx + 8], rcx + cmp rax, qword ptr [rbx + 104] + jb .LoopHeader + jmp .LoopEnd +.LoopInit: + mov rdi, rbx + call benchmark::State::StartKeepRunning() + jmp .LoopBody +.LoopEnd: +``` + +Unless C++03 compatibility is required, the ranged-for variant of writing +the benchmark loop should be preferred. + + + +### Disabling CPU Frequency Scaling + +If you see this error: + +``` +***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead. +``` + +you might want to disable the CPU frequency scaling while running the benchmark: + +```bash +sudo cpupower frequency-set --governor performance +./mybench +sudo cpupower frequency-set --governor powersave +``` diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/WORKSPACE b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/WORKSPACE new file mode 100644 index 0000000000000000000000000000000000000000..dc6ea02b95b4cef5d63aa12782bb781a5f7f8238 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/WORKSPACE @@ -0,0 +1,30 @@ +workspace(name = "com_github_google_benchmark") + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "rules_cc", + strip_prefix = "rules_cc-a508235df92e71d537fcbae0c7c952ea6957a912", + urls = ["https://github.com/bazelbuild/rules_cc/archive/a508235df92e71d537fcbae0c7c952ea6957a912.zip"], +) + +http_archive( + name = "com_google_googletest", + strip_prefix = "googletest-3f0cf6b62ad1eb50d8736538363d3580dd640c3e", + urls = ["https://github.com/google/googletest/archive/3f0cf6b62ad1eb50d8736538363d3580dd640c3e.zip"], +) + +http_archive( + name = "pybind11", + build_file = "@//bindings/python:pybind11.BUILD", + sha256 = "1eed57bc6863190e35637290f97a20c81cfe4d9090ac0a24f3bbf08f265eb71d", + strip_prefix = "pybind11-2.4.3", + urls = ["https://github.com/pybind/pybind11/archive/v2.4.3.tar.gz"], +) + +new_local_repository( + name = "python_headers", + build_file = "@//bindings/python:python_headers.BUILD", + path = "/usr/include/python3.6", # May be overwritten by setup.py. +) + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/_config.yml b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/_config.yml new file mode 100644 index 0000000000000000000000000000000000000000..18854876c67fdee2dbd3d0448dc69a530d5f30a7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-midnight \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/appveyor.yml b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/appveyor.yml new file mode 100644 index 0000000000000000000000000000000000000000..81da955f028154bd241ffccd1ed56dc18edf545e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/appveyor.yml @@ -0,0 +1,50 @@ +version: '{build}' + +image: Visual Studio 2017 + +configuration: + - Debug + - Release + +environment: + matrix: + - compiler: msvc-15-seh + generator: "Visual Studio 15 2017" + + - compiler: msvc-15-seh + generator: "Visual Studio 15 2017 Win64" + + - compiler: msvc-14-seh + generator: "Visual Studio 14 2015" + + - compiler: msvc-14-seh + generator: "Visual Studio 14 2015 Win64" + + - compiler: gcc-5.3.0-posix + generator: "MinGW Makefiles" + cxx_path: 'C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin' + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + +matrix: + fast_finish: true + +install: + # git bash conflicts with MinGW makefiles + - if "%generator%"=="MinGW Makefiles" (set "PATH=%PATH:C:\Program Files\Git\usr\bin;=%") + - if not "%cxx_path%"=="" (set "PATH=%PATH%;%cxx_path%") + +build_script: + - md _build -Force + - cd _build + - echo %configuration% + - cmake -G "%generator%" "-DCMAKE_BUILD_TYPE=%configuration%" -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON .. + - cmake --build . --config %configuration% + +test_script: + - ctest --build-config %configuration% --timeout 300 --output-on-failure + +artifacts: + - path: '_build/CMakeFiles/*.log' + name: logs + - path: '_build/Testing/**/*.xml' + name: test_results diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/benchmark/__init__.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/benchmark/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..27f76e05673b4c49514c8b61cfe3232da711598d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/benchmark/__init__.py @@ -0,0 +1,62 @@ +# Copyright 2020 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Python benchmarking utilities. + +Example usage: + import benchmark + + @benchmark.register + def my_benchmark(state): + ... # Code executed outside `while` loop is not timed. + + while state: + ... # Code executed within `while` loop is timed. + + if __name__ == '__main__': + benchmark.main() +""" + +from absl import app +from benchmark import _benchmark + +__all__ = [ + "register", + "main", +] + +__version__ = "0.1.0" + + +def register(f=None, *, name=None): + if f is None: + return lambda f: register(f, name=name) + if name is None: + name = f.__name__ + _benchmark.RegisterBenchmark(name, f) + return f + + +def _flags_parser(argv): + argv = _benchmark.Initialize(argv) + return app.parse_flags_with_usage(argv) + + +def _run_benchmarks(argv): + if len(argv) > 1: + raise app.UsageError('Too many command-line arguments.') + return _benchmark.RunSpecifiedBenchmarks() + + +def main(argv=None): + return app.run(_run_benchmarks, argv=argv, flags_parser=_flags_parser) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/benchmark/benchmark.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/benchmark/benchmark.cc new file mode 100644 index 0000000000000000000000000000000000000000..ef955596598d1f1459b3bcd7b7a41c9a4a308698 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/benchmark/benchmark.cc @@ -0,0 +1,47 @@ +// Benchmark for Python. + +#include "benchmark/benchmark.h" +#include "pybind11/pybind11.h" +#include "pybind11/stl.h" + +namespace { +namespace py = ::pybind11; + +std::vector Initialize(const std::vector& argv) { + // The `argv` pointers here become invalid when this function returns, but + // benchmark holds the pointer to `argv[0]`. We create a static copy of it + // so it persists, and replace the pointer below. + static std::string executable_name(argv[0]); + std::vector ptrs; + ptrs.reserve(argv.size()); + for (auto& arg : argv) { + ptrs.push_back(const_cast(arg.c_str())); + } + ptrs[0] = const_cast(executable_name.c_str()); + int argc = static_cast(argv.size()); + benchmark::Initialize(&argc, ptrs.data()); + std::vector remaining_argv; + remaining_argv.reserve(argc); + for (int i = 0; i < argc; ++i) { + remaining_argv.emplace_back(ptrs[i]); + } + return remaining_argv; +} + +void RegisterBenchmark(const char* name, py::function f) { + benchmark::RegisterBenchmark(name, [f](benchmark::State& state) { + f(&state); + }); +} + +PYBIND11_MODULE(_benchmark, m) { + m.def("Initialize", Initialize); + m.def("RegisterBenchmark", RegisterBenchmark); + m.def("RunSpecifiedBenchmarks", + []() { benchmark::RunSpecifiedBenchmarks(); }); + + py::class_(m, "State") + .def("__bool__", &benchmark::State::KeepRunning) + .def_property_readonly("keep_running", &benchmark::State::KeepRunning); +}; +} // namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/benchmark/example.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/benchmark/example.py new file mode 100644 index 0000000000000000000000000000000000000000..24da12780a5b236404eed86706fb59e0e7a20724 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/benchmark/example.py @@ -0,0 +1,32 @@ +# Copyright 2020 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Example of Python using C++ benchmark framework.""" + +import benchmark + + +@benchmark.register +def empty(state): + while state: + pass + + +@benchmark.register +def sum_million(state): + while state: + sum(range(1_000_000)) + + +if __name__ == '__main__': + benchmark.main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/build_defs.bzl b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/build_defs.bzl new file mode 100644 index 0000000000000000000000000000000000000000..45907aaa5e2d893e876d9bd1f1148ee704dedf2d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/build_defs.bzl @@ -0,0 +1,25 @@ +_SHARED_LIB_SUFFIX = { + "//conditions:default": ".so", + "//:windows": ".dll", +} + +def py_extension(name, srcs, hdrs = [], copts = [], features = [], deps = []): + for shared_lib_suffix in _SHARED_LIB_SUFFIX.values(): + shared_lib_name = name + shared_lib_suffix + native.cc_binary( + name = shared_lib_name, + linkshared = 1, + linkstatic = 1, + srcs = srcs + hdrs, + copts = copts, + features = features, + deps = deps, + ) + + return native.py_library( + name = name, + data = select({ + platform: [name + shared_lib_suffix] + for platform, shared_lib_suffix in _SHARED_LIB_SUFFIX.items() + }), + ) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/pybind11.BUILD b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/pybind11.BUILD new file mode 100644 index 0000000000000000000000000000000000000000..bc833500383a2caa7fdbb8ca04a1dcd84cb06358 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/pybind11.BUILD @@ -0,0 +1,20 @@ +cc_library( + name = "pybind11", + hdrs = glob( + include = [ + "include/pybind11/*.h", + "include/pybind11/detail/*.h", + ], + exclude = [ + "include/pybind11/common.h", + "include/pybind11/eigen.h", + ], + ), + copts = [ + "-fexceptions", + "-Wno-undefined-inline", + "-Wno-pragma-once-outside-header", + ], + includes = ["include"], + visibility = ["//visibility:public"], +) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/python_headers.BUILD b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/python_headers.BUILD new file mode 100644 index 0000000000000000000000000000000000000000..9c34cf6ca4bd36d3f977e245c098933d1bc97793 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/python_headers.BUILD @@ -0,0 +1,6 @@ +cc_library( + name = "python_headers", + hdrs = glob(["**/*.h"]), + includes = ["."], + visibility = ["//visibility:public"], +) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/requirements.txt b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5bbe7eca5ceac2788a1dc99723e25ba6f9d0a91 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/bindings/python/requirements.txt @@ -0,0 +1,2 @@ +absl-py>=0.7.1 + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/AddCXXCompilerFlag.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/AddCXXCompilerFlag.cmake new file mode 100644 index 0000000000000000000000000000000000000000..d0d2099814402a3fc54ed2be2b61cd4f31d5c5f7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/AddCXXCompilerFlag.cmake @@ -0,0 +1,74 @@ +# - Adds a compiler flag if it is supported by the compiler +# +# This function checks that the supplied compiler flag is supported and then +# adds it to the corresponding compiler flags +# +# add_cxx_compiler_flag( []) +# +# - Example +# +# include(AddCXXCompilerFlag) +# add_cxx_compiler_flag(-Wall) +# add_cxx_compiler_flag(-no-strict-aliasing RELEASE) +# Requires CMake 2.6+ + +if(__add_cxx_compiler_flag) + return() +endif() +set(__add_cxx_compiler_flag INCLUDED) + +include(CheckCXXCompilerFlag) + +function(mangle_compiler_flag FLAG OUTPUT) + string(TOUPPER "HAVE_CXX_FLAG_${FLAG}" SANITIZED_FLAG) + string(REPLACE "+" "X" SANITIZED_FLAG ${SANITIZED_FLAG}) + string(REGEX REPLACE "[^A-Za-z_0-9]" "_" SANITIZED_FLAG ${SANITIZED_FLAG}) + string(REGEX REPLACE "_+" "_" SANITIZED_FLAG ${SANITIZED_FLAG}) + set(${OUTPUT} "${SANITIZED_FLAG}" PARENT_SCOPE) +endfunction(mangle_compiler_flag) + +function(add_cxx_compiler_flag FLAG) + mangle_compiler_flag("${FLAG}" MANGLED_FLAG) + set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}") + check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG}) + set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}") + if(${MANGLED_FLAG}) + set(VARIANT ${ARGV1}) + if(ARGV1) + string(TOUPPER "_${VARIANT}" VARIANT) + endif() + set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${BENCHMARK_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE) + endif() +endfunction() + +function(add_required_cxx_compiler_flag FLAG) + mangle_compiler_flag("${FLAG}" MANGLED_FLAG) + set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}") + check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG}) + set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}") + if(${MANGLED_FLAG}) + set(VARIANT ${ARGV1}) + if(ARGV1) + string(TOUPPER "_${VARIANT}" VARIANT) + endif() + set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE) + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}" PARENT_SCOPE) + else() + message(FATAL_ERROR "Required flag '${FLAG}' is not supported by the compiler") + endif() +endfunction() + +function(check_cxx_warning_flag FLAG) + mangle_compiler_flag("${FLAG}" MANGLED_FLAG) + set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") + # Add -Werror to ensure the compiler generates an error if the warning flag + # doesn't exist. + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror ${FLAG}") + check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG}) + set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}") +endfunction() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/CXXFeatureCheck.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/CXXFeatureCheck.cmake new file mode 100644 index 0000000000000000000000000000000000000000..059d510dd98a169b9e483c5fa8ea024ce6de4a0b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/CXXFeatureCheck.cmake @@ -0,0 +1,64 @@ +# - Compile and run code to check for C++ features +# +# This functions compiles a source file under the `cmake` folder +# and adds the corresponding `HAVE_[FILENAME]` flag to the CMake +# environment +# +# cxx_feature_check( []) +# +# - Example +# +# include(CXXFeatureCheck) +# cxx_feature_check(STD_REGEX) +# Requires CMake 2.8.12+ + +if(__cxx_feature_check) + return() +endif() +set(__cxx_feature_check INCLUDED) + +function(cxx_feature_check FILE) + string(TOLOWER ${FILE} FILE) + string(TOUPPER ${FILE} VAR) + string(TOUPPER "HAVE_${VAR}" FEATURE) + if (DEFINED HAVE_${VAR}) + set(HAVE_${VAR} 1 PARENT_SCOPE) + add_definitions(-DHAVE_${VAR}) + return() + endif() + + if (NOT DEFINED COMPILE_${FEATURE}) + message(STATUS "Performing Test ${FEATURE}") + if(CMAKE_CROSSCOMPILING) + try_compile(COMPILE_${FEATURE} + ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp + CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS} + LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES}) + if(COMPILE_${FEATURE}) + message(WARNING + "If you see build failures due to cross compilation, try setting HAVE_${VAR} to 0") + set(RUN_${FEATURE} 0 CACHE INTERNAL "") + else() + set(RUN_${FEATURE} 1 CACHE INTERNAL "") + endif() + else() + message(STATUS "Performing Test ${FEATURE}") + try_run(RUN_${FEATURE} COMPILE_${FEATURE} + ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp + CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS} + LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES}) + endif() + endif() + + if(RUN_${FEATURE} EQUAL 0) + message(STATUS "Performing Test ${FEATURE} -- success") + set(HAVE_${VAR} 1 PARENT_SCOPE) + add_definitions(-DHAVE_${VAR}) + else() + if(NOT COMPILE_${FEATURE}) + message(STATUS "Performing Test ${FEATURE} -- failed to compile") + else() + message(STATUS "Performing Test ${FEATURE} -- compiled but failed to run") + endif() + endif() +endfunction() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/Config.cmake.in b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/Config.cmake.in new file mode 100644 index 0000000000000000000000000000000000000000..6e9256eea8a2dafc9bf15171b68ebae428e791b6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/Config.cmake.in @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake") diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/GetGitVersion.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/GetGitVersion.cmake new file mode 100644 index 0000000000000000000000000000000000000000..4f10f226d7a78fbb1e9fc5cb58adfa13b82ec71c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/GetGitVersion.cmake @@ -0,0 +1,54 @@ +# - Returns a version string from Git tags +# +# This function inspects the annotated git tags for the project and returns a string +# into a CMake variable +# +# get_git_version() +# +# - Example +# +# include(GetGitVersion) +# get_git_version(GIT_VERSION) +# +# Requires CMake 2.8.11+ +find_package(Git) + +if(__get_git_version) + return() +endif() +set(__get_git_version INCLUDED) + +function(get_git_version var) + if(GIT_EXECUTABLE) + execute_process(COMMAND ${GIT_EXECUTABLE} describe --match "v[0-9]*.[0-9]*.[0-9]*" --abbrev=8 + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + RESULT_VARIABLE status + OUTPUT_VARIABLE GIT_VERSION + ERROR_QUIET) + if(${status}) + set(GIT_VERSION "v0.0.0") + else() + string(STRIP ${GIT_VERSION} GIT_VERSION) + string(REGEX REPLACE "-[0-9]+-g" "-" GIT_VERSION ${GIT_VERSION}) + endif() + + # Work out if the repository is dirty + execute_process(COMMAND ${GIT_EXECUTABLE} update-index -q --refresh + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_QUIET + ERROR_QUIET) + execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD -- + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE GIT_DIFF_INDEX + ERROR_QUIET) + string(COMPARE NOTEQUAL "${GIT_DIFF_INDEX}" "" GIT_DIRTY) + if (${GIT_DIRTY}) + set(GIT_VERSION "${GIT_VERSION}-dirty") + endif() + else() + set(GIT_VERSION "v0.0.0") + endif() + + message(STATUS "git Version: ${GIT_VERSION}") + set(${var} ${GIT_VERSION} PARENT_SCOPE) +endfunction() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/GoogleTest.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/GoogleTest.cmake new file mode 100644 index 0000000000000000000000000000000000000000..dd611fc875f19d48559f4399e53720abeb0eafcf --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/GoogleTest.cmake @@ -0,0 +1,41 @@ +# Download and unpack googletest at configure time +set(GOOGLETEST_PREFIX "${benchmark_BINARY_DIR}/third_party/googletest") +configure_file(${benchmark_SOURCE_DIR}/cmake/GoogleTest.cmake.in ${GOOGLETEST_PREFIX}/CMakeLists.txt @ONLY) + +set(GOOGLETEST_PATH "${CMAKE_CURRENT_SOURCE_DIR}/googletest" CACHE PATH "") # Mind the quotes +execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" + -DALLOW_DOWNLOADING_GOOGLETEST=${BENCHMARK_DOWNLOAD_DEPENDENCIES} -DGOOGLETEST_PATH:PATH=${GOOGLETEST_PATH} . + RESULT_VARIABLE result + WORKING_DIRECTORY ${GOOGLETEST_PREFIX} +) + +if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") +endif() + +execute_process( + COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${GOOGLETEST_PREFIX} +) + +if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") +endif() + +# Prevent overriding the parent project's compiler/linker +# settings on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +include(${GOOGLETEST_PREFIX}/googletest-paths.cmake) + +# Add googletest directly to our build. This defines +# the gtest and gtest_main targets. +add_subdirectory(${GOOGLETEST_SOURCE_DIR} + ${GOOGLETEST_BINARY_DIR} + EXCLUDE_FROM_ALL) + +set_target_properties(gtest PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $) +set_target_properties(gtest_main PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $) +set_target_properties(gmock PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $) +set_target_properties(gmock_main PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/GoogleTest.cmake.in b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/GoogleTest.cmake.in new file mode 100644 index 0000000000000000000000000000000000000000..28818ee293840fd4400ad1e4e0cbdac73bcb2060 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/GoogleTest.cmake.in @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(googletest-download NONE) + +# Enable ExternalProject CMake module +include(ExternalProject) + +option(ALLOW_DOWNLOADING_GOOGLETEST "If googletest src tree is not found in location specified by GOOGLETEST_PATH, do fetch the archive from internet" OFF) +set(GOOGLETEST_PATH "/usr/src/googletest" CACHE PATH + "Path to the googletest root tree. Should contain googletest and googlemock subdirs. And CMakeLists.txt in root, and in both of these subdirs") + +# Download and install GoogleTest + +message(STATUS "Looking for Google Test sources") +message(STATUS "Looking for Google Test sources in ${GOOGLETEST_PATH}") +if(EXISTS "${GOOGLETEST_PATH}" AND IS_DIRECTORY "${GOOGLETEST_PATH}" AND EXISTS "${GOOGLETEST_PATH}/CMakeLists.txt" AND + EXISTS "${GOOGLETEST_PATH}/googletest" AND IS_DIRECTORY "${GOOGLETEST_PATH}/googletest" AND EXISTS "${GOOGLETEST_PATH}/googletest/CMakeLists.txt" AND + EXISTS "${GOOGLETEST_PATH}/googlemock" AND IS_DIRECTORY "${GOOGLETEST_PATH}/googlemock" AND EXISTS "${GOOGLETEST_PATH}/googlemock/CMakeLists.txt") + message(STATUS "Found Google Test in ${GOOGLETEST_PATH}") + + ExternalProject_Add( + googletest + PREFIX "${CMAKE_BINARY_DIR}" + DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/download" + SOURCE_DIR "${GOOGLETEST_PATH}" # use existing src dir. + BINARY_DIR "${CMAKE_BINARY_DIR}/build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) +else() + if(NOT ALLOW_DOWNLOADING_GOOGLETEST) + message(SEND_ERROR "Did not find Google Test sources! Either pass correct path in GOOGLETEST_PATH, or enable ALLOW_DOWNLOADING_GOOGLETEST, or disable BENCHMARK_ENABLE_GTEST_TESTS / BENCHMARK_ENABLE_TESTING.") + else() + message(WARNING "Did not find Google Test sources! Fetching from web...") + ExternalProject_Add( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + PREFIX "${CMAKE_BINARY_DIR}" + STAMP_DIR "${CMAKE_BINARY_DIR}/stamp" + DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/download" + SOURCE_DIR "${CMAKE_BINARY_DIR}/src" + BINARY_DIR "${CMAKE_BINARY_DIR}/build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) + endif() +endif() + +ExternalProject_Get_Property(googletest SOURCE_DIR BINARY_DIR) +file(WRITE googletest-paths.cmake +"set(GOOGLETEST_SOURCE_DIR \"${SOURCE_DIR}\") +set(GOOGLETEST_BINARY_DIR \"${BINARY_DIR}\") +") diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/benchmark.pc.in b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/benchmark.pc.in new file mode 100644 index 0000000000000000000000000000000000000000..43ca8f91d7051d430bb32f263b08bda537edf317 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/benchmark.pc.in @@ -0,0 +1,12 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: @PROJECT_NAME@ +Description: Google microbenchmark framework +Version: @VERSION@ + +Libs: -L${libdir} -lbenchmark +Libs.private: -lpthread +Cflags: -I${includedir} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/gnu_posix_regex.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/gnu_posix_regex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5b91cdab7c2a383afccc2b63ddc4bd98aa64bc4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/gnu_posix_regex.cpp @@ -0,0 +1,12 @@ +#include +#include +int main() { + std::string str = "test0159"; + regex_t re; + int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB); + if (ec != 0) { + return ec; + } + return regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0; +} + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/llvm-toolchain.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/llvm-toolchain.cmake new file mode 100644 index 0000000000000000000000000000000000000000..fc119e52fd26a59786b3480f3e6c64c72b78ad8d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/llvm-toolchain.cmake @@ -0,0 +1,8 @@ +find_package(LLVMAr REQUIRED) +set(CMAKE_AR "${LLVMAR_EXECUTABLE}" CACHE FILEPATH "" FORCE) + +find_package(LLVMNm REQUIRED) +set(CMAKE_NM "${LLVMNM_EXECUTABLE}" CACHE FILEPATH "" FORCE) + +find_package(LLVMRanLib REQUIRED) +set(CMAKE_RANLIB "${LLVMRANLIB_EXECUTABLE}" CACHE FILEPATH "" FORCE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/posix_regex.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/posix_regex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..466dc62560a27d003b9dd083f0a356b44a4fb83f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/posix_regex.cpp @@ -0,0 +1,14 @@ +#include +#include +int main() { + std::string str = "test0159"; + regex_t re; + int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB); + if (ec != 0) { + return ec; + } + int ret = regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0; + regfree(&re); + return ret; +} + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/split_list.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/split_list.cmake new file mode 100644 index 0000000000000000000000000000000000000000..67aed3fdc8579b7d9a6f06a73fa9b6844976e691 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/split_list.cmake @@ -0,0 +1,3 @@ +macro(split_list listname) + string(REPLACE ";" " " ${listname} "${${listname}}") +endmacro() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/std_regex.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/std_regex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..696f2a26bce02fbcec39ee1786c151400290b31e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/std_regex.cpp @@ -0,0 +1,10 @@ +#include +#include +int main() { + const std::string str = "test0159"; + std::regex re; + re = std::regex("^[a-z]+[0-9]+$", + std::regex_constants::extended | std::regex_constants::nosubs); + return std::regex_search(str, re) ? 0 : -1; +} + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/steady_clock.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/steady_clock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..66d50d17e9e61f32cbe1df801906a5b8052ce279 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/steady_clock.cpp @@ -0,0 +1,7 @@ +#include + +int main() { + typedef std::chrono::steady_clock Clock; + Clock::time_point tp = Clock::now(); + ((void)tp); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/thread_safety_attributes.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/thread_safety_attributes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46161babdb10017d4b0bad8b1eb9bdaf40aad629 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/cmake/thread_safety_attributes.cpp @@ -0,0 +1,4 @@ +#define HAVE_THREAD_SAFETY_ATTRIBUTES +#include "../src/mutex.h" + +int main() {} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..15b92ca91aab9c7a49430f23699160db0c8c4ffd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.11) +project(cmake_wrapper) + +include(conanbuildinfo.cmake) +conan_basic_setup() + +include(${CMAKE_SOURCE_DIR}/CMakeListsOriginal.txt) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/test_package/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/test_package/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..089a6c729d255c520018ef52c825c6d1b981aa1f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/test_package/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.8.11) +project(test_package) + +set(CMAKE_VERBOSE_MAKEFILE TRUE) + +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +conan_basic_setup() + +add_executable(${PROJECT_NAME} test_package.cpp) +target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS}) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/test_package/conanfile.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/test_package/conanfile.py new file mode 100644 index 0000000000000000000000000000000000000000..d63f4088c9968001760deb1adab4c724a49145a0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/test_package/conanfile.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from conans import ConanFile, CMake +import os + + +class TestPackageConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "cmake" + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + bin_path = os.path.join("bin", "test_package") + self.run(bin_path, run_environment=True) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/test_package/test_package.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/test_package/test_package.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4fa7ec0bf9d3cd14fe0e3a9153bdcbc1bfc91d67 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conan/test_package/test_package.cpp @@ -0,0 +1,18 @@ +#include "benchmark/benchmark.h" + +void BM_StringCreation(benchmark::State& state) { + while (state.KeepRunning()) + std::string empty_string; +} + +BENCHMARK(BM_StringCreation); + +void BM_StringCopy(benchmark::State& state) { + std::string x = "hello"; + while (state.KeepRunning()) + std::string copy(x); +} + +BENCHMARK(BM_StringCopy); + +BENCHMARK_MAIN(); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conanfile.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conanfile.py new file mode 100644 index 0000000000000000000000000000000000000000..e31fc5268ada6223c58e0e18184dd098b2809dba --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/conanfile.py @@ -0,0 +1,79 @@ +from conans import ConanFile, CMake, tools +from conans.errors import ConanInvalidConfiguration +import shutil +import os + + +class GoogleBenchmarkConan(ConanFile): + name = "benchmark" + description = "A microbenchmark support library." + topics = ("conan", "benchmark", "google", "microbenchmark") + url = "https://github.com/google/benchmark" + homepage = "https://github.com/google/benchmark" + author = "Google Inc." + license = "Apache-2.0" + exports_sources = ["*"] + generators = "cmake" + + settings = "arch", "build_type", "compiler", "os" + options = { + "shared": [True, False], + "fPIC": [True, False], + "enable_lto": [True, False], + "enable_exceptions": [True, False] + } + default_options = {"shared": False, "fPIC": True, "enable_lto": False, "enable_exceptions": True} + + _build_subfolder = "." + + def source(self): + # Wrap the original CMake file to call conan_basic_setup + shutil.move("CMakeLists.txt", "CMakeListsOriginal.txt") + shutil.move(os.path.join("conan", "CMakeLists.txt"), "CMakeLists.txt") + + def config_options(self): + if self.settings.os == "Windows": + if self.settings.compiler == "Visual Studio" and float(self.settings.compiler.version.value) <= 12: + raise ConanInvalidConfiguration("{} {} does not support Visual Studio <= 12".format(self.name, self.version)) + del self.options.fPIC + + def configure(self): + if self.settings.os == "Windows" and self.options.shared: + raise ConanInvalidConfiguration("Windows shared builds are not supported right now, see issue #639") + + def _configure_cmake(self): + cmake = CMake(self) + + cmake.definitions["BENCHMARK_ENABLE_TESTING"] = "OFF" + cmake.definitions["BENCHMARK_ENABLE_GTEST_TESTS"] = "OFF" + cmake.definitions["BENCHMARK_ENABLE_LTO"] = "ON" if self.options.enable_lto else "OFF" + cmake.definitions["BENCHMARK_ENABLE_EXCEPTIONS"] = "ON" if self.options.enable_exceptions else "OFF" + + # See https://github.com/google/benchmark/pull/638 for Windows 32 build explanation + if self.settings.os != "Windows": + cmake.definitions["BENCHMARK_BUILD_32_BITS"] = "ON" if "64" not in str(self.settings.arch) else "OFF" + cmake.definitions["BENCHMARK_USE_LIBCXX"] = "ON" if (str(self.settings.compiler.libcxx) == "libc++") else "OFF" + else: + cmake.definitions["BENCHMARK_USE_LIBCXX"] = "OFF" + + cmake.configure(build_folder=self._build_subfolder) + return cmake + + def build(self): + cmake = self._configure_cmake() + cmake.build() + + def package(self): + cmake = self._configure_cmake() + cmake.install() + + self.copy(pattern="LICENSE", dst="licenses") + + def package_info(self): + self.cpp_info.libs = tools.collect_libs(self) + if self.settings.os == "Linux": + self.cpp_info.libs.extend(["pthread", "rt"]) + elif self.settings.os == "Windows": + self.cpp_info.libs.append("shlwapi") + elif self.settings.os == "SunOS": + self.cpp_info.libs.append("kstat") diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/dependencies.md b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/dependencies.md new file mode 100644 index 0000000000000000000000000000000000000000..6289b4e3548bb3a27ed9591766b19f006ec7ea6b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/dependencies.md @@ -0,0 +1,18 @@ +# Build tool dependency policy + +To ensure the broadest compatibility when building the benchmark library, but +still allow forward progress, we require any build tooling to be available for: + +* Debian stable AND +* The last two Ubuntu LTS releases AND + +Currently, this means using build tool versions that are available for Ubuntu +16.04 (Xenial), Ubuntu 18.04 (Bionic), and Debian stretch. + +_Note, [travis](.travis.yml) runs under Ubuntu 14.04 (Trusty) for linux builds._ + +## cmake +The current supported version is cmake 3.5.1 as of 2018-06-06. + +_Note, this version is also available for Ubuntu 14.04, the previous Ubuntu LTS +release, as `cmake3`._ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/docs/AssemblyTests.md b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/docs/AssemblyTests.md new file mode 100644 index 0000000000000000000000000000000000000000..1fbdc269b53d66dc1f490536bb68084767c0f85c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/docs/AssemblyTests.md @@ -0,0 +1,147 @@ +# Assembly Tests + +The Benchmark library provides a number of functions whose primary +purpose in to affect assembly generation, including `DoNotOptimize` +and `ClobberMemory`. In addition there are other functions, +such as `KeepRunning`, for which generating good assembly is paramount. + +For these functions it's important to have tests that verify the +correctness and quality of the implementation. This requires testing +the code generated by the compiler. + +This document describes how the Benchmark library tests compiler output, +as well as how to properly write new tests. + + +## Anatomy of a Test + +Writing a test has two steps: + +* Write the code you want to generate assembly for. +* Add `// CHECK` lines to match against the verified assembly. + +Example: +```c++ + +// CHECK-LABEL: test_add: +extern "C" int test_add() { + extern int ExternInt; + return ExternInt + 1; + + // CHECK: movl ExternInt(%rip), %eax + // CHECK: addl %eax + // CHECK: ret +} + +``` + +#### LLVM Filecheck + +[LLVM's Filecheck](https://llvm.org/docs/CommandGuide/FileCheck.html) +is used to test the generated assembly against the `// CHECK` lines +specified in the tests source file. Please see the documentation +linked above for information on how to write `CHECK` directives. + +#### Tips and Tricks: + +* Tests should match the minimal amount of output required to establish +correctness. `CHECK` directives don't have to match on the exact next line +after the previous match, so tests should omit checks for unimportant +bits of assembly. ([`CHECK-NEXT`](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-next-directive) +can be used to ensure a match occurs exactly after the previous match). + +* The tests are compiled with `-O3 -g0`. So we're only testing the +optimized output. + +* The assembly output is further cleaned up using `tools/strip_asm.py`. +This removes comments, assembler directives, and unused labels before +the test is run. + +* The generated and stripped assembly file for a test is output under +`/test/.s` + +* Filecheck supports using [`CHECK` prefixes](https://llvm.org/docs/CommandGuide/FileCheck.html#cmdoption-check-prefixes) +to specify lines that should only match in certain situations. +The Benchmark tests use `CHECK-CLANG` and `CHECK-GNU` for lines that +are only expected to match Clang or GCC's output respectively. Normal +`CHECK` lines match against all compilers. (Note: `CHECK-NOT` and +`CHECK-LABEL` are NOT prefixes. They are versions of non-prefixed +`CHECK` lines) + +* Use `extern "C"` to disable name mangling for specific functions. This +makes them easier to name in the `CHECK` lines. + + +## Problems Writing Portable Tests + +Writing tests which check the code generated by a compiler are +inherently non-portable. Different compilers and even different compiler +versions may generate entirely different code. The Benchmark tests +must tolerate this. + +LLVM Filecheck provides a number of mechanisms to help write +"more portable" tests; including [matching using regular expressions](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-pattern-matching-syntax), +allowing the creation of [named variables](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-variables) +for later matching, and [checking non-sequential matches](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-dag-directive). + +#### Capturing Variables + +For example, say GCC stores a variable in a register but Clang stores +it in memory. To write a test that tolerates both cases we "capture" +the destination of the store, and then use the captured expression +to write the remainder of the test. + +```c++ +// CHECK-LABEL: test_div_no_op_into_shr: +extern "C" void test_div_no_op_into_shr(int value) { + int divisor = 2; + benchmark::DoNotOptimize(divisor); // hide the value from the optimizer + return value / divisor; + + // CHECK: movl $2, [[DEST:.*]] + // CHECK: idivl [[DEST]] + // CHECK: ret +} +``` + +#### Using Regular Expressions to Match Differing Output + +Often tests require testing assembly lines which may subtly differ +between compilers or compiler versions. A common example of this +is matching stack frame addresses. In this case regular expressions +can be used to match the differing bits of output. For example: + +```c++ +int ExternInt; +struct Point { int x, y, z; }; + +// CHECK-LABEL: test_store_point: +extern "C" void test_store_point() { + Point p{ExternInt, ExternInt, ExternInt}; + benchmark::DoNotOptimize(p); + + // CHECK: movl ExternInt(%rip), %eax + // CHECK: movl %eax, -{{[0-9]+}}(%rsp) + // CHECK: movl %eax, -{{[0-9]+}}(%rsp) + // CHECK: movl %eax, -{{[0-9]+}}(%rsp) + // CHECK: ret +} +``` + +## Current Requirements and Limitations + +The tests require Filecheck to be installed along the `PATH` of the +build machine. Otherwise the tests will be disabled. + +Additionally, as mentioned in the previous section, codegen tests are +inherently non-portable. Currently the tests are limited to: + +* x86_64 targets. +* Compiled with GCC or Clang + +Further work could be done, at least on a limited basis, to extend the +tests to other architectures and compilers (using `CHECK` prefixes). + +Furthermore, the tests fail for builds which specify additional flags +that modify code generation, including `--coverage` or `-fsanitize=`. + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/docs/_config.yml b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/docs/_config.yml new file mode 100644 index 0000000000000000000000000000000000000000..18854876c67fdee2dbd3d0448dc69a530d5f30a7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-midnight \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/docs/tools.md b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/docs/tools.md new file mode 100644 index 0000000000000000000000000000000000000000..4a3b2e9bd2c9cc1cbe9380fac9a259be6469b6a6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/docs/tools.md @@ -0,0 +1,199 @@ +# Benchmark Tools + +## compare.py + +The `compare.py` can be used to compare the result of benchmarks. + +**NOTE**: the utility relies on the scipy package which can be installed using [these instructions](https://www.scipy.org/install.html). + +### Displaying aggregates only + +The switch `-a` / `--display_aggregates_only` can be used to control the +displayment of the normal iterations vs the aggregates. When passed, it will +be passthrough to the benchmark binaries to be run, and will be accounted for +in the tool itself; only the aggregates will be displayed, but not normal runs. +It only affects the display, the separate runs will still be used to calculate +the U test. + +### Modes of operation + +There are three modes of operation: + +1. Just compare two benchmarks +The program is invoked like: + +``` bash +$ compare.py benchmarks [benchmark options]... +``` +Where `` and `` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file. + +`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes. + +Example output: +``` +$ ./compare.py benchmarks ./a.out ./a.out +RUNNING: ./a.out --benchmark_out=/tmp/tmprBT5nW +Run on (8 X 4000 MHz CPU s) +2017-11-07 21:16:44 +------------------------------------------------------ +Benchmark Time CPU Iterations +------------------------------------------------------ +BM_memcpy/8 36 ns 36 ns 19101577 211.669MB/s +BM_memcpy/64 76 ns 76 ns 9412571 800.199MB/s +BM_memcpy/512 84 ns 84 ns 8249070 5.64771GB/s +BM_memcpy/1024 116 ns 116 ns 6181763 8.19505GB/s +BM_memcpy/8192 643 ns 643 ns 1062855 11.8636GB/s +BM_copy/8 222 ns 222 ns 3137987 34.3772MB/s +BM_copy/64 1608 ns 1608 ns 432758 37.9501MB/s +BM_copy/512 12589 ns 12589 ns 54806 38.7867MB/s +BM_copy/1024 25169 ns 25169 ns 27713 38.8003MB/s +BM_copy/8192 201165 ns 201112 ns 3486 38.8466MB/s +RUNNING: ./a.out --benchmark_out=/tmp/tmpt1wwG_ +Run on (8 X 4000 MHz CPU s) +2017-11-07 21:16:53 +------------------------------------------------------ +Benchmark Time CPU Iterations +------------------------------------------------------ +BM_memcpy/8 36 ns 36 ns 19397903 211.255MB/s +BM_memcpy/64 73 ns 73 ns 9691174 839.635MB/s +BM_memcpy/512 85 ns 85 ns 8312329 5.60101GB/s +BM_memcpy/1024 118 ns 118 ns 6438774 8.11608GB/s +BM_memcpy/8192 656 ns 656 ns 1068644 11.6277GB/s +BM_copy/8 223 ns 223 ns 3146977 34.2338MB/s +BM_copy/64 1611 ns 1611 ns 435340 37.8751MB/s +BM_copy/512 12622 ns 12622 ns 54818 38.6844MB/s +BM_copy/1024 25257 ns 25239 ns 27779 38.6927MB/s +BM_copy/8192 205013 ns 205010 ns 3479 38.108MB/s +Comparing ./a.out to ./a.out +Benchmark Time CPU Time Old Time New CPU Old CPU New +------------------------------------------------------------------------------------------------------ +BM_memcpy/8 +0.0020 +0.0020 36 36 36 36 +BM_memcpy/64 -0.0468 -0.0470 76 73 76 73 +BM_memcpy/512 +0.0081 +0.0083 84 85 84 85 +BM_memcpy/1024 +0.0098 +0.0097 116 118 116 118 +BM_memcpy/8192 +0.0200 +0.0203 643 656 643 656 +BM_copy/8 +0.0046 +0.0042 222 223 222 223 +BM_copy/64 +0.0020 +0.0020 1608 1611 1608 1611 +BM_copy/512 +0.0027 +0.0026 12589 12622 12589 12622 +BM_copy/1024 +0.0035 +0.0028 25169 25257 25169 25239 +BM_copy/8192 +0.0191 +0.0194 201165 205013 201112 205010 +``` + +What it does is for the every benchmark from the first run it looks for the benchmark with exactly the same name in the second run, and then compares the results. If the names differ, the benchmark is omitted from the diff. +As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`. + +2. Compare two different filters of one benchmark +The program is invoked like: + +``` bash +$ compare.py filters [benchmark options]... +``` +Where `` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file. + +Where `` and `` are the same regex filters that you would pass to the `[--benchmark_filter=]` parameter of the benchmark binary. + +`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes. + +Example output: +``` +$ ./compare.py filters ./a.out BM_memcpy BM_copy +RUNNING: ./a.out --benchmark_filter=BM_memcpy --benchmark_out=/tmp/tmpBWKk0k +Run on (8 X 4000 MHz CPU s) +2017-11-07 21:37:28 +------------------------------------------------------ +Benchmark Time CPU Iterations +------------------------------------------------------ +BM_memcpy/8 36 ns 36 ns 17891491 211.215MB/s +BM_memcpy/64 74 ns 74 ns 9400999 825.646MB/s +BM_memcpy/512 87 ns 87 ns 8027453 5.46126GB/s +BM_memcpy/1024 111 ns 111 ns 6116853 8.5648GB/s +BM_memcpy/8192 657 ns 656 ns 1064679 11.6247GB/s +RUNNING: ./a.out --benchmark_filter=BM_copy --benchmark_out=/tmp/tmpAvWcOM +Run on (8 X 4000 MHz CPU s) +2017-11-07 21:37:33 +---------------------------------------------------- +Benchmark Time CPU Iterations +---------------------------------------------------- +BM_copy/8 227 ns 227 ns 3038700 33.6264MB/s +BM_copy/64 1640 ns 1640 ns 426893 37.2154MB/s +BM_copy/512 12804 ns 12801 ns 55417 38.1444MB/s +BM_copy/1024 25409 ns 25407 ns 27516 38.4365MB/s +BM_copy/8192 202986 ns 202990 ns 3454 38.4871MB/s +Comparing BM_memcpy to BM_copy (from ./a.out) +Benchmark Time CPU Time Old Time New CPU Old CPU New +-------------------------------------------------------------------------------------------------------------------- +[BM_memcpy vs. BM_copy]/8 +5.2829 +5.2812 36 227 36 227 +[BM_memcpy vs. BM_copy]/64 +21.1719 +21.1856 74 1640 74 1640 +[BM_memcpy vs. BM_copy]/512 +145.6487 +145.6097 87 12804 87 12801 +[BM_memcpy vs. BM_copy]/1024 +227.1860 +227.1776 111 25409 111 25407 +[BM_memcpy vs. BM_copy]/8192 +308.1664 +308.2898 657 202986 656 202990 +``` + +As you can see, it applies filter to the benchmarks, both when running the benchmark, and before doing the diff. And to make the diff work, the matches are replaced with some common string. Thus, you can compare two different benchmark families within one benchmark binary. +As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`. + +3. Compare filter one from benchmark one to filter two from benchmark two: +The program is invoked like: + +``` bash +$ compare.py filters [benchmark options]... +``` + +Where `` and `` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file. + +Where `` and `` are the same regex filters that you would pass to the `[--benchmark_filter=]` parameter of the benchmark binary. + +`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes. + +Example output: +``` +$ ./compare.py benchmarksfiltered ./a.out BM_memcpy ./a.out BM_copy +RUNNING: ./a.out --benchmark_filter=BM_memcpy --benchmark_out=/tmp/tmp_FvbYg +Run on (8 X 4000 MHz CPU s) +2017-11-07 21:38:27 +------------------------------------------------------ +Benchmark Time CPU Iterations +------------------------------------------------------ +BM_memcpy/8 37 ns 37 ns 18953482 204.118MB/s +BM_memcpy/64 74 ns 74 ns 9206578 828.245MB/s +BM_memcpy/512 91 ns 91 ns 8086195 5.25476GB/s +BM_memcpy/1024 120 ns 120 ns 5804513 7.95662GB/s +BM_memcpy/8192 664 ns 664 ns 1028363 11.4948GB/s +RUNNING: ./a.out --benchmark_filter=BM_copy --benchmark_out=/tmp/tmpDfL5iE +Run on (8 X 4000 MHz CPU s) +2017-11-07 21:38:32 +---------------------------------------------------- +Benchmark Time CPU Iterations +---------------------------------------------------- +BM_copy/8 230 ns 230 ns 2985909 33.1161MB/s +BM_copy/64 1654 ns 1653 ns 419408 36.9137MB/s +BM_copy/512 13122 ns 13120 ns 53403 37.2156MB/s +BM_copy/1024 26679 ns 26666 ns 26575 36.6218MB/s +BM_copy/8192 215068 ns 215053 ns 3221 36.3283MB/s +Comparing BM_memcpy (from ./a.out) to BM_copy (from ./a.out) +Benchmark Time CPU Time Old Time New CPU Old CPU New +-------------------------------------------------------------------------------------------------------------------- +[BM_memcpy vs. BM_copy]/8 +5.1649 +5.1637 37 230 37 230 +[BM_memcpy vs. BM_copy]/64 +21.4352 +21.4374 74 1654 74 1653 +[BM_memcpy vs. BM_copy]/512 +143.6022 +143.5865 91 13122 91 13120 +[BM_memcpy vs. BM_copy]/1024 +221.5903 +221.4790 120 26679 120 26666 +[BM_memcpy vs. BM_copy]/8192 +322.9059 +323.0096 664 215068 664 215053 +``` +This is a mix of the previous two modes, two (potentially different) benchmark binaries are run, and a different filter is applied to each one. +As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`. + +### U test + +If there is a sufficient repetition count of the benchmarks, the tool can do +a [U Test](https://en.wikipedia.org/wiki/Mann%E2%80%93Whitney_U_test), of the +null hypothesis that it is equally likely that a randomly selected value from +one sample will be less than or greater than a randomly selected value from a +second sample. + +If the calculated p-value is below this value is lower than the significance +level alpha, then the result is said to be statistically significant and the +null hypothesis is rejected. Which in other words means that the two benchmarks +aren't identical. + +**WARNING**: requires **LARGE** (no less than 9) number of repetitions to be +meaningful! diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/include/benchmark/benchmark.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/include/benchmark/benchmark.h new file mode 100644 index 0000000000000000000000000000000000000000..e5f67789588129f24075e6a84d5e48bff88dc7c7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/include/benchmark/benchmark.h @@ -0,0 +1,1589 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Support for registering benchmarks for functions. + +/* Example usage: +// Define a function that executes the code to be measured a +// specified number of times: +static void BM_StringCreation(benchmark::State& state) { + for (auto _ : state) + std::string empty_string; +} + +// Register the function as a benchmark +BENCHMARK(BM_StringCreation); + +// Define another benchmark +static void BM_StringCopy(benchmark::State& state) { + std::string x = "hello"; + for (auto _ : state) + std::string copy(x); +} +BENCHMARK(BM_StringCopy); + +// Augment the main() program to invoke benchmarks if specified +// via the --benchmarks command line flag. E.g., +// my_unittest --benchmark_filter=all +// my_unittest --benchmark_filter=BM_StringCreation +// my_unittest --benchmark_filter=String +// my_unittest --benchmark_filter='Copy|Creation' +int main(int argc, char** argv) { + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + return 0; +} + +// Sometimes a family of microbenchmarks can be implemented with +// just one routine that takes an extra argument to specify which +// one of the family of benchmarks to run. For example, the following +// code defines a family of microbenchmarks for measuring the speed +// of memcpy() calls of different lengths: + +static void BM_memcpy(benchmark::State& state) { + char* src = new char[state.range(0)]; char* dst = new char[state.range(0)]; + memset(src, 'x', state.range(0)); + for (auto _ : state) + memcpy(dst, src, state.range(0)); + state.SetBytesProcessed(state.iterations() * state.range(0)); + delete[] src; delete[] dst; +} +BENCHMARK(BM_memcpy)->Arg(8)->Arg(64)->Arg(512)->Arg(1<<10)->Arg(8<<10); + +// The preceding code is quite repetitive, and can be replaced with the +// following short-hand. The following invocation will pick a few +// appropriate arguments in the specified range and will generate a +// microbenchmark for each such argument. +BENCHMARK(BM_memcpy)->Range(8, 8<<10); + +// You might have a microbenchmark that depends on two inputs. For +// example, the following code defines a family of microbenchmarks for +// measuring the speed of set insertion. +static void BM_SetInsert(benchmark::State& state) { + set data; + for (auto _ : state) { + state.PauseTiming(); + data = ConstructRandomSet(state.range(0)); + state.ResumeTiming(); + for (int j = 0; j < state.range(1); ++j) + data.insert(RandomNumber()); + } +} +BENCHMARK(BM_SetInsert) + ->Args({1<<10, 128}) + ->Args({2<<10, 128}) + ->Args({4<<10, 128}) + ->Args({8<<10, 128}) + ->Args({1<<10, 512}) + ->Args({2<<10, 512}) + ->Args({4<<10, 512}) + ->Args({8<<10, 512}); + +// The preceding code is quite repetitive, and can be replaced with +// the following short-hand. The following macro will pick a few +// appropriate arguments in the product of the two specified ranges +// and will generate a microbenchmark for each such pair. +BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {128, 512}}); + +// For more complex patterns of inputs, passing a custom function +// to Apply allows programmatic specification of an +// arbitrary set of arguments to run the microbenchmark on. +// The following example enumerates a dense range on +// one parameter, and a sparse range on the second. +static void CustomArguments(benchmark::internal::Benchmark* b) { + for (int i = 0; i <= 10; ++i) + for (int j = 32; j <= 1024*1024; j *= 8) + b->Args({i, j}); +} +BENCHMARK(BM_SetInsert)->Apply(CustomArguments); + +// Templated microbenchmarks work the same way: +// Produce then consume 'size' messages 'iters' times +// Measures throughput in the absence of multiprogramming. +template int BM_Sequential(benchmark::State& state) { + Q q; + typename Q::value_type v; + for (auto _ : state) { + for (int i = state.range(0); i--; ) + q.push(v); + for (int e = state.range(0); e--; ) + q.Wait(&v); + } + // actually messages, not bytes: + state.SetBytesProcessed(state.iterations() * state.range(0)); +} +BENCHMARK_TEMPLATE(BM_Sequential, WaitQueue)->Range(1<<0, 1<<10); + +Use `Benchmark::MinTime(double t)` to set the minimum time used to run the +benchmark. This option overrides the `benchmark_min_time` flag. + +void BM_test(benchmark::State& state) { + ... body ... +} +BENCHMARK(BM_test)->MinTime(2.0); // Run for at least 2 seconds. + +In a multithreaded test, it is guaranteed that none of the threads will start +until all have reached the loop start, and all will have finished before any +thread exits the loop body. As such, any global setup or teardown you want to +do can be wrapped in a check against the thread index: + +static void BM_MultiThreaded(benchmark::State& state) { + if (state.thread_index == 0) { + // Setup code here. + } + for (auto _ : state) { + // Run the test as normal. + } + if (state.thread_index == 0) { + // Teardown code here. + } +} +BENCHMARK(BM_MultiThreaded)->Threads(4); + + +If a benchmark runs a few milliseconds it may be hard to visually compare the +measured times, since the output data is given in nanoseconds per default. In +order to manually set the time unit, you can specify it manually: + +BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); +*/ + +#ifndef BENCHMARK_BENCHMARK_H_ +#define BENCHMARK_BENCHMARK_H_ + +// The _MSVC_LANG check should detect Visual Studio 2015 Update 3 and newer. +#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) +#define BENCHMARK_HAS_CXX11 +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BENCHMARK_HAS_CXX11) +#include +#include +#include +#endif + +#if defined(_MSC_VER) +#include // for _ReadWriteBarrier +#endif + +#ifndef BENCHMARK_HAS_CXX11 +#define BENCHMARK_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + TypeName& operator=(const TypeName&) +#else +#define BENCHMARK_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&) = delete; \ + TypeName& operator=(const TypeName&) = delete +#endif + +#if defined(__GNUC__) +#define BENCHMARK_UNUSED __attribute__((unused)) +#define BENCHMARK_ALWAYS_INLINE __attribute__((always_inline)) +#define BENCHMARK_NOEXCEPT noexcept +#define BENCHMARK_NOEXCEPT_OP(x) noexcept(x) +#elif defined(_MSC_VER) && !defined(__clang__) +#define BENCHMARK_UNUSED +#define BENCHMARK_ALWAYS_INLINE __forceinline +#if _MSC_VER >= 1900 +#define BENCHMARK_NOEXCEPT noexcept +#define BENCHMARK_NOEXCEPT_OP(x) noexcept(x) +#else +#define BENCHMARK_NOEXCEPT +#define BENCHMARK_NOEXCEPT_OP(x) +#endif +#define __func__ __FUNCTION__ +#else +#define BENCHMARK_UNUSED +#define BENCHMARK_ALWAYS_INLINE +#define BENCHMARK_NOEXCEPT +#define BENCHMARK_NOEXCEPT_OP(x) +#endif + +#define BENCHMARK_INTERNAL_TOSTRING2(x) #x +#define BENCHMARK_INTERNAL_TOSTRING(x) BENCHMARK_INTERNAL_TOSTRING2(x) + +#if defined(__GNUC__) || defined(__clang__) +#define BENCHMARK_BUILTIN_EXPECT(x, y) __builtin_expect(x, y) +#define BENCHMARK_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) +#else +#define BENCHMARK_BUILTIN_EXPECT(x, y) x +#define BENCHMARK_DEPRECATED_MSG(msg) +#define BENCHMARK_WARNING_MSG(msg) \ + __pragma(message(__FILE__ "(" BENCHMARK_INTERNAL_TOSTRING( \ + __LINE__) ") : warning note: " msg)) +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#define BENCHMARK_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if defined(__GNUC__) || __has_builtin(__builtin_unreachable) +#define BENCHMARK_UNREACHABLE() __builtin_unreachable() +#elif defined(_MSC_VER) +#define BENCHMARK_UNREACHABLE() __assume(false) +#else +#define BENCHMARK_UNREACHABLE() ((void)0) +#endif + +namespace benchmark { +class BenchmarkReporter; +class MemoryManager; + +void Initialize(int* argc, char** argv); + +// Report to stdout all arguments in 'argv' as unrecognized except the first. +// Returns true there is at least on unrecognized argument (i.e. 'argc' > 1). +bool ReportUnrecognizedArguments(int argc, char** argv); + +// Generate a list of benchmarks matching the specified --benchmark_filter flag +// and if --benchmark_list_tests is specified return after printing the name +// of each matching benchmark. Otherwise run each matching benchmark and +// report the results. +// +// The second and third overload use the specified 'display_reporter' and +// 'file_reporter' respectively. 'file_reporter' will write to the file +// specified +// by '--benchmark_output'. If '--benchmark_output' is not given the +// 'file_reporter' is ignored. +// +// RETURNS: The number of matching benchmarks. +size_t RunSpecifiedBenchmarks(); +size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter); +size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, + BenchmarkReporter* file_reporter); + +// Register a MemoryManager instance that will be used to collect and report +// allocation measurements for benchmark runs. +void RegisterMemoryManager(MemoryManager* memory_manager); + +namespace internal { +class Benchmark; +class BenchmarkImp; +class BenchmarkFamilies; + +void UseCharPointer(char const volatile*); + +// Take ownership of the pointer and register the benchmark. Return the +// registered benchmark. +Benchmark* RegisterBenchmarkInternal(Benchmark*); + +// Ensure that the standard streams are properly initialized in every TU. +int InitializeStreams(); +BENCHMARK_UNUSED static int stream_init_anchor = InitializeStreams(); + +} // namespace internal + +#if (!defined(__GNUC__) && !defined(__clang__)) || defined(__pnacl__) || \ + defined(__EMSCRIPTEN__) +#define BENCHMARK_HAS_NO_INLINE_ASSEMBLY +#endif + +// The DoNotOptimize(...) function can be used to prevent a value or +// expression from being optimized away by the compiler. This function is +// intended to add little to no overhead. +// See: https://youtu.be/nXaxk27zwlk?t=2441 +#ifndef BENCHMARK_HAS_NO_INLINE_ASSEMBLY +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { + asm volatile("" : : "r,m"(value) : "memory"); +} + +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) { +#if defined(__clang__) + asm volatile("" : "+r,m"(value) : : "memory"); +#else + asm volatile("" : "+m,r"(value) : : "memory"); +#endif +} + +// Force the compiler to flush pending writes to global memory. Acts as an +// effective read/write barrier +inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { + asm volatile("" : : : "memory"); +} +#elif defined(_MSC_VER) +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { + internal::UseCharPointer(&reinterpret_cast(value)); + _ReadWriteBarrier(); +} + +inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() { _ReadWriteBarrier(); } +#else +template +inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { + internal::UseCharPointer(&reinterpret_cast(value)); +} +// FIXME Add ClobberMemory() for non-gnu and non-msvc compilers +#endif + +// This class is used for user-defined counters. +class Counter { + public: + enum Flags { + kDefaults = 0, + // Mark the counter as a rate. It will be presented divided + // by the duration of the benchmark. + kIsRate = 1U << 0U, + // Mark the counter as a thread-average quantity. It will be + // presented divided by the number of threads. + kAvgThreads = 1U << 1U, + // Mark the counter as a thread-average rate. See above. + kAvgThreadsRate = kIsRate | kAvgThreads, + // Mark the counter as a constant value, valid/same for *every* iteration. + // When reporting, it will be *multiplied* by the iteration count. + kIsIterationInvariant = 1U << 2U, + // Mark the counter as a constant rate. + // When reporting, it will be *multiplied* by the iteration count + // and then divided by the duration of the benchmark. + kIsIterationInvariantRate = kIsRate | kIsIterationInvariant, + // Mark the counter as a iteration-average quantity. + // It will be presented divided by the number of iterations. + kAvgIterations = 1U << 3U, + // Mark the counter as a iteration-average rate. See above. + kAvgIterationsRate = kIsRate | kAvgIterations, + + // In the end, invert the result. This is always done last! + kInvert = 1U << 31U + }; + + enum OneK { + // 1'000 items per 1k + kIs1000 = 1000, + // 1'024 items per 1k + kIs1024 = 1024 + }; + + double value; + Flags flags; + OneK oneK; + + BENCHMARK_ALWAYS_INLINE + Counter(double v = 0., Flags f = kDefaults, OneK k = kIs1000) + : value(v), flags(f), oneK(k) {} + + BENCHMARK_ALWAYS_INLINE operator double const&() const { return value; } + BENCHMARK_ALWAYS_INLINE operator double&() { return value; } +}; + +// A helper for user code to create unforeseen combinations of Flags, without +// having to do this cast manually each time, or providing this operator. +Counter::Flags inline operator|(const Counter::Flags& LHS, + const Counter::Flags& RHS) { + return static_cast(static_cast(LHS) | + static_cast(RHS)); +} + +// This is the container for the user-defined counters. +typedef std::map UserCounters; + +// TimeUnit is passed to a benchmark in order to specify the order of magnitude +// for the measured time. +enum TimeUnit { kNanosecond, kMicrosecond, kMillisecond }; + +// BigO is passed to a benchmark in order to specify the asymptotic +// computational +// complexity for the benchmark. In case oAuto is selected, complexity will be +// calculated automatically to the best fit. +enum BigO { oNone, o1, oN, oNSquared, oNCubed, oLogN, oNLogN, oAuto, oLambda }; + +typedef uint64_t IterationCount; + +// BigOFunc is passed to a benchmark in order to specify the asymptotic +// computational complexity for the benchmark. +typedef double(BigOFunc)(IterationCount); + +// StatisticsFunc is passed to a benchmark in order to compute some descriptive +// statistics over all the measurements of some type +typedef double(StatisticsFunc)(const std::vector&); + +namespace internal { +struct Statistics { + std::string name_; + StatisticsFunc* compute_; + + Statistics(const std::string& name, StatisticsFunc* compute) + : name_(name), compute_(compute) {} +}; + +struct BenchmarkInstance; +class ThreadTimer; +class ThreadManager; + +enum AggregationReportMode +#if defined(BENCHMARK_HAS_CXX11) + : unsigned +#else +#endif +{ + // The mode has not been manually specified + ARM_Unspecified = 0, + // The mode is user-specified. + // This may or may not be set when the following bit-flags are set. + ARM_Default = 1U << 0U, + // File reporter should only output aggregates. + ARM_FileReportAggregatesOnly = 1U << 1U, + // Display reporter should only output aggregates + ARM_DisplayReportAggregatesOnly = 1U << 2U, + // Both reporters should only display aggregates. + ARM_ReportAggregatesOnly = + ARM_FileReportAggregatesOnly | ARM_DisplayReportAggregatesOnly +}; + +} // namespace internal + +// State is passed to a running Benchmark and contains state for the +// benchmark to use. +class State { + public: + struct StateIterator; + friend struct StateIterator; + + // Returns iterators used to run each iteration of a benchmark using a + // C++11 ranged-based for loop. These functions should not be called directly. + // + // REQUIRES: The benchmark has not started running yet. Neither begin nor end + // have been called previously. + // + // NOTE: KeepRunning may not be used after calling either of these functions. + BENCHMARK_ALWAYS_INLINE StateIterator begin(); + BENCHMARK_ALWAYS_INLINE StateIterator end(); + + // Returns true if the benchmark should continue through another iteration. + // NOTE: A benchmark may not return from the test until KeepRunning() has + // returned false. + bool KeepRunning(); + + // Returns true iff the benchmark should run n more iterations. + // REQUIRES: 'n' > 0. + // NOTE: A benchmark must not return from the test until KeepRunningBatch() + // has returned false. + // NOTE: KeepRunningBatch() may overshoot by up to 'n' iterations. + // + // Intended usage: + // while (state.KeepRunningBatch(1000)) { + // // process 1000 elements + // } + bool KeepRunningBatch(IterationCount n); + + // REQUIRES: timer is running and 'SkipWithError(...)' has not been called + // by the current thread. + // Stop the benchmark timer. If not called, the timer will be + // automatically stopped after the last iteration of the benchmark loop. + // + // For threaded benchmarks the PauseTiming() function only pauses the timing + // for the current thread. + // + // NOTE: The "real time" measurement is per-thread. If different threads + // report different measurements the largest one is reported. + // + // NOTE: PauseTiming()/ResumeTiming() are relatively + // heavyweight, and so their use should generally be avoided + // within each benchmark iteration, if possible. + void PauseTiming(); + + // REQUIRES: timer is not running and 'SkipWithError(...)' has not been called + // by the current thread. + // Start the benchmark timer. The timer is NOT running on entrance to the + // benchmark function. It begins running after control flow enters the + // benchmark loop. + // + // NOTE: PauseTiming()/ResumeTiming() are relatively + // heavyweight, and so their use should generally be avoided + // within each benchmark iteration, if possible. + void ResumeTiming(); + + // REQUIRES: 'SkipWithError(...)' has not been called previously by the + // current thread. + // Report the benchmark as resulting in an error with the specified 'msg'. + // After this call the user may explicitly 'return' from the benchmark. + // + // If the ranged-for style of benchmark loop is used, the user must explicitly + // break from the loop, otherwise all future iterations will be run. + // If the 'KeepRunning()' loop is used the current thread will automatically + // exit the loop at the end of the current iteration. + // + // For threaded benchmarks only the current thread stops executing and future + // calls to `KeepRunning()` will block until all threads have completed + // the `KeepRunning()` loop. If multiple threads report an error only the + // first error message is used. + // + // NOTE: Calling 'SkipWithError(...)' does not cause the benchmark to exit + // the current scope immediately. If the function is called from within + // the 'KeepRunning()' loop the current iteration will finish. It is the users + // responsibility to exit the scope as needed. + void SkipWithError(const char* msg); + + // Returns true if an error has been reported with 'SkipWithError(...)'. + bool error_occurred() const { return error_occurred_; } + + // REQUIRES: called exactly once per iteration of the benchmarking loop. + // Set the manually measured time for this benchmark iteration, which + // is used instead of automatically measured time if UseManualTime() was + // specified. + // + // For threaded benchmarks the final value will be set to the largest + // reported values. + void SetIterationTime(double seconds); + + // Set the number of bytes processed by the current benchmark + // execution. This routine is typically called once at the end of a + // throughput oriented benchmark. + // + // REQUIRES: a benchmark has exited its benchmarking loop. + BENCHMARK_ALWAYS_INLINE + void SetBytesProcessed(int64_t bytes) { + counters["bytes_per_second"] = + Counter(static_cast(bytes), Counter::kIsRate, Counter::kIs1024); + } + + BENCHMARK_ALWAYS_INLINE + int64_t bytes_processed() const { + if (counters.find("bytes_per_second") != counters.end()) + return static_cast(counters.at("bytes_per_second")); + return 0; + } + + // If this routine is called with complexity_n > 0 and complexity report is + // requested for the + // family benchmark, then current benchmark will be part of the computation + // and complexity_n will + // represent the length of N. + BENCHMARK_ALWAYS_INLINE + void SetComplexityN(int64_t complexity_n) { complexity_n_ = complexity_n; } + + BENCHMARK_ALWAYS_INLINE + int64_t complexity_length_n() const { return complexity_n_; } + + // If this routine is called with items > 0, then an items/s + // label is printed on the benchmark report line for the currently + // executing benchmark. It is typically called at the end of a processing + // benchmark where a processing items/second output is desired. + // + // REQUIRES: a benchmark has exited its benchmarking loop. + BENCHMARK_ALWAYS_INLINE + void SetItemsProcessed(int64_t items) { + counters["items_per_second"] = + Counter(static_cast(items), benchmark::Counter::kIsRate); + } + + BENCHMARK_ALWAYS_INLINE + int64_t items_processed() const { + if (counters.find("items_per_second") != counters.end()) + return static_cast(counters.at("items_per_second")); + return 0; + } + + // If this routine is called, the specified label is printed at the + // end of the benchmark report line for the currently executing + // benchmark. Example: + // static void BM_Compress(benchmark::State& state) { + // ... + // double compress = input_size / output_size; + // state.SetLabel(StrFormat("compress:%.1f%%", 100.0*compression)); + // } + // Produces output that looks like: + // BM_Compress 50 50 14115038 compress:27.3% + // + // REQUIRES: a benchmark has exited its benchmarking loop. + void SetLabel(const char* label); + + void BENCHMARK_ALWAYS_INLINE SetLabel(const std::string& str) { + this->SetLabel(str.c_str()); + } + + // Range arguments for this run. CHECKs if the argument has been set. + BENCHMARK_ALWAYS_INLINE + int64_t range(std::size_t pos = 0) const { + assert(range_.size() > pos); + return range_[pos]; + } + + BENCHMARK_DEPRECATED_MSG("use 'range(0)' instead") + int64_t range_x() const { return range(0); } + + BENCHMARK_DEPRECATED_MSG("use 'range(1)' instead") + int64_t range_y() const { return range(1); } + + BENCHMARK_ALWAYS_INLINE + IterationCount iterations() const { + if (BENCHMARK_BUILTIN_EXPECT(!started_, false)) { + return 0; + } + return max_iterations - total_iterations_ + batch_leftover_; + } + + private + : // items we expect on the first cache line (ie 64 bytes of the struct) + // When total_iterations_ is 0, KeepRunning() and friends will return false. + // May be larger than max_iterations. + IterationCount total_iterations_; + + // When using KeepRunningBatch(), batch_leftover_ holds the number of + // iterations beyond max_iters that were run. Used to track + // completed_iterations_ accurately. + IterationCount batch_leftover_; + + public: + const IterationCount max_iterations; + + private: + bool started_; + bool finished_; + bool error_occurred_; + + private: // items we don't need on the first cache line + std::vector range_; + + int64_t complexity_n_; + + public: + // Container for user-defined counters. + UserCounters counters; + // Index of the executing thread. Values from [0, threads). + const int thread_index; + // Number of threads concurrently executing the benchmark. + const int threads; + + private: + State(IterationCount max_iters, const std::vector& ranges, + int thread_i, int n_threads, internal::ThreadTimer* timer, + internal::ThreadManager* manager); + + void StartKeepRunning(); + // Implementation of KeepRunning() and KeepRunningBatch(). + // is_batch must be true unless n is 1. + bool KeepRunningInternal(IterationCount n, bool is_batch); + void FinishKeepRunning(); + internal::ThreadTimer* timer_; + internal::ThreadManager* manager_; + + friend struct internal::BenchmarkInstance; +}; + +inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunning() { + return KeepRunningInternal(1, /*is_batch=*/false); +} + +inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningBatch(IterationCount n) { + return KeepRunningInternal(n, /*is_batch=*/true); +} + +inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningInternal(IterationCount n, + bool is_batch) { + // total_iterations_ is set to 0 by the constructor, and always set to a + // nonzero value by StartKepRunning(). + assert(n > 0); + // n must be 1 unless is_batch is true. + assert(is_batch || n == 1); + if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ >= n, true)) { + total_iterations_ -= n; + return true; + } + if (!started_) { + StartKeepRunning(); + if (!error_occurred_ && total_iterations_ >= n) { + total_iterations_ -= n; + return true; + } + } + // For non-batch runs, total_iterations_ must be 0 by now. + if (is_batch && total_iterations_ != 0) { + batch_leftover_ = n - total_iterations_; + total_iterations_ = 0; + return true; + } + FinishKeepRunning(); + return false; +} + +struct State::StateIterator { + struct BENCHMARK_UNUSED Value {}; + typedef std::forward_iterator_tag iterator_category; + typedef Value value_type; + typedef Value reference; + typedef Value pointer; + typedef std::ptrdiff_t difference_type; + + private: + friend class State; + BENCHMARK_ALWAYS_INLINE + StateIterator() : cached_(0), parent_() {} + + BENCHMARK_ALWAYS_INLINE + explicit StateIterator(State* st) + : cached_(st->error_occurred_ ? 0 : st->max_iterations), parent_(st) {} + + public: + BENCHMARK_ALWAYS_INLINE + Value operator*() const { return Value(); } + + BENCHMARK_ALWAYS_INLINE + StateIterator& operator++() { + assert(cached_ > 0); + --cached_; + return *this; + } + + BENCHMARK_ALWAYS_INLINE + bool operator!=(StateIterator const&) const { + if (BENCHMARK_BUILTIN_EXPECT(cached_ != 0, true)) return true; + parent_->FinishKeepRunning(); + return false; + } + + private: + IterationCount cached_; + State* const parent_; +}; + +inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::begin() { + return StateIterator(this); +} +inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::end() { + StartKeepRunning(); + return StateIterator(); +} + +namespace internal { + +typedef void(Function)(State&); + +// ------------------------------------------------------ +// Benchmark registration object. The BENCHMARK() macro expands +// into an internal::Benchmark* object. Various methods can +// be called on this object to change the properties of the benchmark. +// Each method returns "this" so that multiple method calls can +// chained into one expression. +class Benchmark { + public: + virtual ~Benchmark(); + + // Note: the following methods all return "this" so that multiple + // method calls can be chained together in one expression. + + // Run this benchmark once with "x" as the extra argument passed + // to the function. + // REQUIRES: The function passed to the constructor must accept an arg1. + Benchmark* Arg(int64_t x); + + // Run this benchmark with the given time unit for the generated output report + Benchmark* Unit(TimeUnit unit); + + // Run this benchmark once for a number of values picked from the + // range [start..limit]. (start and limit are always picked.) + // REQUIRES: The function passed to the constructor must accept an arg1. + Benchmark* Range(int64_t start, int64_t limit); + + // Run this benchmark once for all values in the range [start..limit] with + // specific step + // REQUIRES: The function passed to the constructor must accept an arg1. + Benchmark* DenseRange(int64_t start, int64_t limit, int step = 1); + + // Run this benchmark once with "args" as the extra arguments passed + // to the function. + // REQUIRES: The function passed to the constructor must accept arg1, arg2 ... + Benchmark* Args(const std::vector& args); + + // Equivalent to Args({x, y}) + // NOTE: This is a legacy C++03 interface provided for compatibility only. + // New code should use 'Args'. + Benchmark* ArgPair(int64_t x, int64_t y) { + std::vector args; + args.push_back(x); + args.push_back(y); + return Args(args); + } + + // Run this benchmark once for a number of values picked from the + // ranges [start..limit]. (starts and limits are always picked.) + // REQUIRES: The function passed to the constructor must accept arg1, arg2 ... + Benchmark* Ranges(const std::vector >& ranges); + + // Equivalent to ArgNames({name}) + Benchmark* ArgName(const std::string& name); + + // Set the argument names to display in the benchmark name. If not called, + // only argument values will be shown. + Benchmark* ArgNames(const std::vector& names); + + // Equivalent to Ranges({{lo1, hi1}, {lo2, hi2}}). + // NOTE: This is a legacy C++03 interface provided for compatibility only. + // New code should use 'Ranges'. + Benchmark* RangePair(int64_t lo1, int64_t hi1, int64_t lo2, int64_t hi2) { + std::vector > ranges; + ranges.push_back(std::make_pair(lo1, hi1)); + ranges.push_back(std::make_pair(lo2, hi2)); + return Ranges(ranges); + } + + // Pass this benchmark object to *func, which can customize + // the benchmark by calling various methods like Arg, Args, + // Threads, etc. + Benchmark* Apply(void (*func)(Benchmark* benchmark)); + + // Set the range multiplier for non-dense range. If not called, the range + // multiplier kRangeMultiplier will be used. + Benchmark* RangeMultiplier(int multiplier); + + // Set the minimum amount of time to use when running this benchmark. This + // option overrides the `benchmark_min_time` flag. + // REQUIRES: `t > 0` and `Iterations` has not been called on this benchmark. + Benchmark* MinTime(double t); + + // Specify the amount of iterations that should be run by this benchmark. + // REQUIRES: 'n > 0' and `MinTime` has not been called on this benchmark. + // + // NOTE: This function should only be used when *exact* iteration control is + // needed and never to control or limit how long a benchmark runs, where + // `--benchmark_min_time=N` or `MinTime(...)` should be used instead. + Benchmark* Iterations(IterationCount n); + + // Specify the amount of times to repeat this benchmark. This option overrides + // the `benchmark_repetitions` flag. + // REQUIRES: `n > 0` + Benchmark* Repetitions(int n); + + // Specify if each repetition of the benchmark should be reported separately + // or if only the final statistics should be reported. If the benchmark + // is not repeated then the single result is always reported. + // Applies to *ALL* reporters (display and file). + Benchmark* ReportAggregatesOnly(bool value = true); + + // Same as ReportAggregatesOnly(), but applies to display reporter only. + Benchmark* DisplayAggregatesOnly(bool value = true); + + // By default, the CPU time is measured only for the main thread, which may + // be unrepresentative if the benchmark uses threads internally. If called, + // the total CPU time spent by all the threads will be measured instead. + // By default, the only the main thread CPU time will be measured. + Benchmark* MeasureProcessCPUTime(); + + // If a particular benchmark should use the Wall clock instead of the CPU time + // (be it either the CPU time of the main thread only (default), or the + // total CPU usage of the benchmark), call this method. If called, the elapsed + // (wall) time will be used to control how many iterations are run, and in the + // printing of items/second or MB/seconds values. + // If not called, the CPU time used by the benchmark will be used. + Benchmark* UseRealTime(); + + // If a benchmark must measure time manually (e.g. if GPU execution time is + // being + // measured), call this method. If called, each benchmark iteration should + // call + // SetIterationTime(seconds) to report the measured time, which will be used + // to control how many iterations are run, and in the printing of items/second + // or MB/second values. + Benchmark* UseManualTime(); + + // Set the asymptotic computational complexity for the benchmark. If called + // the asymptotic computational complexity will be shown on the output. + Benchmark* Complexity(BigO complexity = benchmark::oAuto); + + // Set the asymptotic computational complexity for the benchmark. If called + // the asymptotic computational complexity will be shown on the output. + Benchmark* Complexity(BigOFunc* complexity); + + // Add this statistics to be computed over all the values of benchmark run + Benchmark* ComputeStatistics(std::string name, StatisticsFunc* statistics); + + // Support for running multiple copies of the same benchmark concurrently + // in multiple threads. This may be useful when measuring the scaling + // of some piece of code. + + // Run one instance of this benchmark concurrently in t threads. + Benchmark* Threads(int t); + + // Pick a set of values T from [min_threads,max_threads]. + // min_threads and max_threads are always included in T. Run this + // benchmark once for each value in T. The benchmark run for a + // particular value t consists of t threads running the benchmark + // function concurrently. For example, consider: + // BENCHMARK(Foo)->ThreadRange(1,16); + // This will run the following benchmarks: + // Foo in 1 thread + // Foo in 2 threads + // Foo in 4 threads + // Foo in 8 threads + // Foo in 16 threads + Benchmark* ThreadRange(int min_threads, int max_threads); + + // For each value n in the range, run this benchmark once using n threads. + // min_threads and max_threads are always included in the range. + // stride specifies the increment. E.g. DenseThreadRange(1, 8, 3) starts + // a benchmark with 1, 4, 7 and 8 threads. + Benchmark* DenseThreadRange(int min_threads, int max_threads, int stride = 1); + + // Equivalent to ThreadRange(NumCPUs(), NumCPUs()) + Benchmark* ThreadPerCpu(); + + virtual void Run(State& state) = 0; + + protected: + explicit Benchmark(const char* name); + Benchmark(Benchmark const&); + void SetName(const char* name); + + int ArgsCnt() const; + + private: + friend class BenchmarkFamilies; + + std::string name_; + AggregationReportMode aggregation_report_mode_; + std::vector arg_names_; // Args for all benchmark runs + std::vector > args_; // Args for all benchmark runs + TimeUnit time_unit_; + int range_multiplier_; + double min_time_; + IterationCount iterations_; + int repetitions_; + bool measure_process_cpu_time_; + bool use_real_time_; + bool use_manual_time_; + BigO complexity_; + BigOFunc* complexity_lambda_; + std::vector statistics_; + std::vector thread_counts_; + + Benchmark& operator=(Benchmark const&); +}; + +} // namespace internal + +// Create and register a benchmark with the specified 'name' that invokes +// the specified functor 'fn'. +// +// RETURNS: A pointer to the registered benchmark. +internal::Benchmark* RegisterBenchmark(const char* name, + internal::Function* fn); + +#if defined(BENCHMARK_HAS_CXX11) +template +internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn); +#endif + +// Remove all registered benchmarks. All pointers to previously registered +// benchmarks are invalidated. +void ClearRegisteredBenchmarks(); + +namespace internal { +// The class used to hold all Benchmarks created from static function. +// (ie those created using the BENCHMARK(...) macros. +class FunctionBenchmark : public Benchmark { + public: + FunctionBenchmark(const char* name, Function* func) + : Benchmark(name), func_(func) {} + + virtual void Run(State& st); + + private: + Function* func_; +}; + +#ifdef BENCHMARK_HAS_CXX11 +template +class LambdaBenchmark : public Benchmark { + public: + virtual void Run(State& st) { lambda_(st); } + + private: + template + LambdaBenchmark(const char* name, OLambda&& lam) + : Benchmark(name), lambda_(std::forward(lam)) {} + + LambdaBenchmark(LambdaBenchmark const&) = delete; + + private: + template + friend Benchmark* ::benchmark::RegisterBenchmark(const char*, Lam&&); + + Lambda lambda_; +}; +#endif + +} // namespace internal + +inline internal::Benchmark* RegisterBenchmark(const char* name, + internal::Function* fn) { + return internal::RegisterBenchmarkInternal( + ::new internal::FunctionBenchmark(name, fn)); +} + +#ifdef BENCHMARK_HAS_CXX11 +template +internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn) { + using BenchType = + internal::LambdaBenchmark::type>; + return internal::RegisterBenchmarkInternal( + ::new BenchType(name, std::forward(fn))); +} +#endif + +#if defined(BENCHMARK_HAS_CXX11) && \ + (!defined(BENCHMARK_GCC_VERSION) || BENCHMARK_GCC_VERSION >= 409) +template +internal::Benchmark* RegisterBenchmark(const char* name, Lambda&& fn, + Args&&... args) { + return benchmark::RegisterBenchmark( + name, [=](benchmark::State& st) { fn(st, args...); }); +} +#else +#define BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK +#endif + +// The base class for all fixture tests. +class Fixture : public internal::Benchmark { + public: + Fixture() : internal::Benchmark("") {} + + virtual void Run(State& st) { + this->SetUp(st); + this->BenchmarkCase(st); + this->TearDown(st); + } + + // These will be deprecated ... + virtual void SetUp(const State&) {} + virtual void TearDown(const State&) {} + // ... In favor of these. + virtual void SetUp(State& st) { SetUp(const_cast(st)); } + virtual void TearDown(State& st) { TearDown(const_cast(st)); } + + protected: + virtual void BenchmarkCase(State&) = 0; +}; + +} // namespace benchmark + +// ------------------------------------------------------ +// Macro to register benchmarks + +// Check that __COUNTER__ is defined and that __COUNTER__ increases by 1 +// every time it is expanded. X + 1 == X + 0 is used in case X is defined to be +// empty. If X is empty the expression becomes (+1 == +0). +#if defined(__COUNTER__) && (__COUNTER__ + 1 == __COUNTER__ + 0) +#define BENCHMARK_PRIVATE_UNIQUE_ID __COUNTER__ +#else +#define BENCHMARK_PRIVATE_UNIQUE_ID __LINE__ +#endif + +// Helpers for generating unique variable names +#define BENCHMARK_PRIVATE_NAME(n) \ + BENCHMARK_PRIVATE_CONCAT(_benchmark_, BENCHMARK_PRIVATE_UNIQUE_ID, n) +#define BENCHMARK_PRIVATE_CONCAT(a, b, c) BENCHMARK_PRIVATE_CONCAT2(a, b, c) +#define BENCHMARK_PRIVATE_CONCAT2(a, b, c) a##b##c + +#define BENCHMARK_PRIVATE_DECLARE(n) \ + static ::benchmark::internal::Benchmark* BENCHMARK_PRIVATE_NAME(n) \ + BENCHMARK_UNUSED + +#define BENCHMARK(n) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + new ::benchmark::internal::FunctionBenchmark(#n, n))) + +// Old-style macros +#define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a)) +#define BENCHMARK_WITH_ARG2(n, a1, a2) BENCHMARK(n)->Args({(a1), (a2)}) +#define BENCHMARK_WITH_UNIT(n, t) BENCHMARK(n)->Unit((t)) +#define BENCHMARK_RANGE(n, lo, hi) BENCHMARK(n)->Range((lo), (hi)) +#define BENCHMARK_RANGE2(n, l1, h1, l2, h2) \ + BENCHMARK(n)->RangePair({{(l1), (h1)}, {(l2), (h2)}}) + +#ifdef BENCHMARK_HAS_CXX11 + +// Register a benchmark which invokes the function specified by `func` +// with the additional arguments specified by `...`. +// +// For example: +// +// template ` +// void BM_takes_args(benchmark::State& state, ExtraArgs&&... extra_args) { +// [...] +//} +// /* Registers a benchmark named "BM_takes_args/int_string_test` */ +// BENCHMARK_CAPTURE(BM_takes_args, int_string_test, 42, std::string("abc")); +#define BENCHMARK_CAPTURE(func, test_case_name, ...) \ + BENCHMARK_PRIVATE_DECLARE(func) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + new ::benchmark::internal::FunctionBenchmark( \ + #func "/" #test_case_name, \ + [](::benchmark::State& st) { func(st, __VA_ARGS__); }))) + +#endif // BENCHMARK_HAS_CXX11 + +// This will register a benchmark for a templatized function. For example: +// +// template +// void BM_Foo(int iters); +// +// BENCHMARK_TEMPLATE(BM_Foo, 1); +// +// will register BM_Foo<1> as a benchmark. +#define BENCHMARK_TEMPLATE1(n, a) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + new ::benchmark::internal::FunctionBenchmark(#n "<" #a ">", n))) + +#define BENCHMARK_TEMPLATE2(n, a, b) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + new ::benchmark::internal::FunctionBenchmark(#n "<" #a "," #b ">", \ + n))) + +#ifdef BENCHMARK_HAS_CXX11 +#define BENCHMARK_TEMPLATE(n, ...) \ + BENCHMARK_PRIVATE_DECLARE(n) = \ + (::benchmark::internal::RegisterBenchmarkInternal( \ + new ::benchmark::internal::FunctionBenchmark( \ + #n "<" #__VA_ARGS__ ">", n<__VA_ARGS__>))) +#else +#define BENCHMARK_TEMPLATE(n, a) BENCHMARK_TEMPLATE1(n, a) +#endif + +#define BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ + class BaseClass##_##Method##_Benchmark : public BaseClass { \ + public: \ + BaseClass##_##Method##_Benchmark() : BaseClass() { \ + this->SetName(#BaseClass "/" #Method); \ + } \ + \ + protected: \ + virtual void BenchmarkCase(::benchmark::State&); \ + }; + +#define BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ + class BaseClass##_##Method##_Benchmark : public BaseClass { \ + public: \ + BaseClass##_##Method##_Benchmark() : BaseClass() { \ + this->SetName(#BaseClass "<" #a ">/" #Method); \ + } \ + \ + protected: \ + virtual void BenchmarkCase(::benchmark::State&); \ + }; + +#define BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ + class BaseClass##_##Method##_Benchmark : public BaseClass { \ + public: \ + BaseClass##_##Method##_Benchmark() : BaseClass() { \ + this->SetName(#BaseClass "<" #a "," #b ">/" #Method); \ + } \ + \ + protected: \ + virtual void BenchmarkCase(::benchmark::State&); \ + }; + +#ifdef BENCHMARK_HAS_CXX11 +#define BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, ...) \ + class BaseClass##_##Method##_Benchmark : public BaseClass<__VA_ARGS__> { \ + public: \ + BaseClass##_##Method##_Benchmark() : BaseClass<__VA_ARGS__>() { \ + this->SetName(#BaseClass "<" #__VA_ARGS__ ">/" #Method); \ + } \ + \ + protected: \ + virtual void BenchmarkCase(::benchmark::State&); \ + }; +#else +#define BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(n, a) \ + BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(n, a) +#endif + +#define BENCHMARK_DEFINE_F(BaseClass, Method) \ + BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ + void BaseClass##_##Method##_Benchmark::BenchmarkCase + +#define BENCHMARK_TEMPLATE1_DEFINE_F(BaseClass, Method, a) \ + BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ + void BaseClass##_##Method##_Benchmark::BenchmarkCase + +#define BENCHMARK_TEMPLATE2_DEFINE_F(BaseClass, Method, a, b) \ + BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ + void BaseClass##_##Method##_Benchmark::BenchmarkCase + +#ifdef BENCHMARK_HAS_CXX11 +#define BENCHMARK_TEMPLATE_DEFINE_F(BaseClass, Method, ...) \ + BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, __VA_ARGS__) \ + void BaseClass##_##Method##_Benchmark::BenchmarkCase +#else +#define BENCHMARK_TEMPLATE_DEFINE_F(BaseClass, Method, a) \ + BENCHMARK_TEMPLATE1_DEFINE_F(BaseClass, Method, a) +#endif + +#define BENCHMARK_REGISTER_F(BaseClass, Method) \ + BENCHMARK_PRIVATE_REGISTER_F(BaseClass##_##Method##_Benchmark) + +#define BENCHMARK_PRIVATE_REGISTER_F(TestName) \ + BENCHMARK_PRIVATE_DECLARE(TestName) = \ + (::benchmark::internal::RegisterBenchmarkInternal(new TestName())) + +// This macro will define and register a benchmark within a fixture class. +#define BENCHMARK_F(BaseClass, Method) \ + BENCHMARK_PRIVATE_DECLARE_F(BaseClass, Method) \ + BENCHMARK_REGISTER_F(BaseClass, Method); \ + void BaseClass##_##Method##_Benchmark::BenchmarkCase + +#define BENCHMARK_TEMPLATE1_F(BaseClass, Method, a) \ + BENCHMARK_TEMPLATE1_PRIVATE_DECLARE_F(BaseClass, Method, a) \ + BENCHMARK_REGISTER_F(BaseClass, Method); \ + void BaseClass##_##Method##_Benchmark::BenchmarkCase + +#define BENCHMARK_TEMPLATE2_F(BaseClass, Method, a, b) \ + BENCHMARK_TEMPLATE2_PRIVATE_DECLARE_F(BaseClass, Method, a, b) \ + BENCHMARK_REGISTER_F(BaseClass, Method); \ + void BaseClass##_##Method##_Benchmark::BenchmarkCase + +#ifdef BENCHMARK_HAS_CXX11 +#define BENCHMARK_TEMPLATE_F(BaseClass, Method, ...) \ + BENCHMARK_TEMPLATE_PRIVATE_DECLARE_F(BaseClass, Method, __VA_ARGS__) \ + BENCHMARK_REGISTER_F(BaseClass, Method); \ + void BaseClass##_##Method##_Benchmark::BenchmarkCase +#else +#define BENCHMARK_TEMPLATE_F(BaseClass, Method, a) \ + BENCHMARK_TEMPLATE1_F(BaseClass, Method, a) +#endif + +// Helper macro to create a main routine in a test that runs the benchmarks +#define BENCHMARK_MAIN() \ + int main(int argc, char** argv) { \ + ::benchmark::Initialize(&argc, argv); \ + if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; \ + ::benchmark::RunSpecifiedBenchmarks(); \ + } \ + int main(int, char**) + +// ------------------------------------------------------ +// Benchmark Reporters + +namespace benchmark { + +struct CPUInfo { + struct CacheInfo { + std::string type; + int level; + int size; + int num_sharing; + }; + + int num_cpus; + double cycles_per_second; + std::vector caches; + bool scaling_enabled; + std::vector load_avg; + + static const CPUInfo& Get(); + + private: + CPUInfo(); + BENCHMARK_DISALLOW_COPY_AND_ASSIGN(CPUInfo); +}; + +// Adding Struct for System Information +struct SystemInfo { + std::string name; + static const SystemInfo& Get(); + + private: + SystemInfo(); + BENCHMARK_DISALLOW_COPY_AND_ASSIGN(SystemInfo); +}; + +// BenchmarkName contains the components of the Benchmark's name +// which allows individual fields to be modified or cleared before +// building the final name using 'str()'. +struct BenchmarkName { + std::string function_name; + std::string args; + std::string min_time; + std::string iterations; + std::string repetitions; + std::string time_type; + std::string threads; + + // Return the full name of the benchmark with each non-empty + // field separated by a '/' + std::string str() const; +}; + +// Interface for custom benchmark result printers. +// By default, benchmark reports are printed to stdout. However an application +// can control the destination of the reports by calling +// RunSpecifiedBenchmarks and passing it a custom reporter object. +// The reporter object must implement the following interface. +class BenchmarkReporter { + public: + struct Context { + CPUInfo const& cpu_info; + SystemInfo const& sys_info; + // The number of chars in the longest benchmark name. + size_t name_field_width; + static const char* executable_name; + Context(); + }; + + struct Run { + static const int64_t no_repetition_index = -1; + enum RunType { RT_Iteration, RT_Aggregate }; + + Run() + : run_type(RT_Iteration), + error_occurred(false), + iterations(1), + threads(1), + time_unit(kNanosecond), + real_accumulated_time(0), + cpu_accumulated_time(0), + max_heapbytes_used(0), + complexity(oNone), + complexity_lambda(), + complexity_n(0), + report_big_o(false), + report_rms(false), + counters(), + has_memory_result(false), + allocs_per_iter(0.0), + max_bytes_used(0) {} + + std::string benchmark_name() const; + BenchmarkName run_name; + RunType run_type; + std::string aggregate_name; + std::string report_label; // Empty if not set by benchmark. + bool error_occurred; + std::string error_message; + + IterationCount iterations; + int64_t threads; + int64_t repetition_index; + int64_t repetitions; + TimeUnit time_unit; + double real_accumulated_time; + double cpu_accumulated_time; + + // Return a value representing the real time per iteration in the unit + // specified by 'time_unit'. + // NOTE: If 'iterations' is zero the returned value represents the + // accumulated time. + double GetAdjustedRealTime() const; + + // Return a value representing the cpu time per iteration in the unit + // specified by 'time_unit'. + // NOTE: If 'iterations' is zero the returned value represents the + // accumulated time. + double GetAdjustedCPUTime() const; + + // This is set to 0.0 if memory tracing is not enabled. + double max_heapbytes_used; + + // Keep track of arguments to compute asymptotic complexity + BigO complexity; + BigOFunc* complexity_lambda; + int64_t complexity_n; + + // what statistics to compute from the measurements + const std::vector* statistics; + + // Inform print function whether the current run is a complexity report + bool report_big_o; + bool report_rms; + + UserCounters counters; + + // Memory metrics. + bool has_memory_result; + double allocs_per_iter; + int64_t max_bytes_used; + }; + + // Construct a BenchmarkReporter with the output stream set to 'std::cout' + // and the error stream set to 'std::cerr' + BenchmarkReporter(); + + // Called once for every suite of benchmarks run. + // The parameter "context" contains information that the + // reporter may wish to use when generating its report, for example the + // platform under which the benchmarks are running. The benchmark run is + // never started if this function returns false, allowing the reporter + // to skip runs based on the context information. + virtual bool ReportContext(const Context& context) = 0; + + // Called once for each group of benchmark runs, gives information about + // cpu-time and heap memory usage during the benchmark run. If the group + // of runs contained more than two entries then 'report' contains additional + // elements representing the mean and standard deviation of those runs. + // Additionally if this group of runs was the last in a family of benchmarks + // 'reports' contains additional entries representing the asymptotic + // complexity and RMS of that benchmark family. + virtual void ReportRuns(const std::vector& report) = 0; + + // Called once and only once after ever group of benchmarks is run and + // reported. + virtual void Finalize() {} + + // REQUIRES: The object referenced by 'out' is valid for the lifetime + // of the reporter. + void SetOutputStream(std::ostream* out) { + assert(out); + output_stream_ = out; + } + + // REQUIRES: The object referenced by 'err' is valid for the lifetime + // of the reporter. + void SetErrorStream(std::ostream* err) { + assert(err); + error_stream_ = err; + } + + std::ostream& GetOutputStream() const { return *output_stream_; } + + std::ostream& GetErrorStream() const { return *error_stream_; } + + virtual ~BenchmarkReporter(); + + // Write a human readable string to 'out' representing the specified + // 'context'. + // REQUIRES: 'out' is non-null. + static void PrintBasicContext(std::ostream* out, Context const& context); + + private: + std::ostream* output_stream_; + std::ostream* error_stream_; +}; + +// Simple reporter that outputs benchmark data to the console. This is the +// default reporter used by RunSpecifiedBenchmarks(). +class ConsoleReporter : public BenchmarkReporter { + public: + enum OutputOptions { + OO_None = 0, + OO_Color = 1, + OO_Tabular = 2, + OO_ColorTabular = OO_Color | OO_Tabular, + OO_Defaults = OO_ColorTabular + }; + explicit ConsoleReporter(OutputOptions opts_ = OO_Defaults) + : output_options_(opts_), + name_field_width_(0), + prev_counters_(), + printed_header_(false) {} + + virtual bool ReportContext(const Context& context); + virtual void ReportRuns(const std::vector& reports); + + protected: + virtual void PrintRunData(const Run& report); + virtual void PrintHeader(const Run& report); + + OutputOptions output_options_; + size_t name_field_width_; + UserCounters prev_counters_; + bool printed_header_; +}; + +class JSONReporter : public BenchmarkReporter { + public: + JSONReporter() : first_report_(true) {} + virtual bool ReportContext(const Context& context); + virtual void ReportRuns(const std::vector& reports); + virtual void Finalize(); + + private: + void PrintRunData(const Run& report); + + bool first_report_; +}; + +class BENCHMARK_DEPRECATED_MSG( + "The CSV Reporter will be removed in a future release") CSVReporter + : public BenchmarkReporter { + public: + CSVReporter() : printed_header_(false) {} + virtual bool ReportContext(const Context& context); + virtual void ReportRuns(const std::vector& reports); + + private: + void PrintRunData(const Run& report); + + bool printed_header_; + std::set user_counter_names_; +}; + +// If a MemoryManager is registered, it can be used to collect and report +// allocation metrics for a run of the benchmark. +class MemoryManager { + public: + struct Result { + Result() : num_allocs(0), max_bytes_used(0) {} + + // The number of allocations made in total between Start and Stop. + int64_t num_allocs; + + // The peak memory use between Start and Stop. + int64_t max_bytes_used; + }; + + virtual ~MemoryManager() {} + + // Implement this to start recording allocation information. + virtual void Start() = 0; + + // Implement this to stop recording and fill out the given Result structure. + virtual void Stop(Result* result) = 0; +}; + +inline const char* GetTimeUnitString(TimeUnit unit) { + switch (unit) { + case kMillisecond: + return "ms"; + case kMicrosecond: + return "us"; + case kNanosecond: + return "ns"; + } + BENCHMARK_UNREACHABLE(); +} + +inline double GetTimeUnitMultiplier(TimeUnit unit) { + switch (unit) { + case kMillisecond: + return 1e3; + case kMicrosecond: + return 1e6; + case kNanosecond: + return 1e9; + } + BENCHMARK_UNREACHABLE(); +} + +} // namespace benchmark + +#endif // BENCHMARK_BENCHMARK_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/mingw.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/mingw.py new file mode 100644 index 0000000000000000000000000000000000000000..65cf4b874563ab807dcf74763b082be8ee37f354 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/mingw.py @@ -0,0 +1,320 @@ +#! /usr/bin/env python +# encoding: utf-8 + +import argparse +import errno +import logging +import os +import platform +import re +import sys +import subprocess +import tempfile + +try: + import winreg +except ImportError: + import _winreg as winreg +try: + import urllib.request as request +except ImportError: + import urllib as request +try: + import urllib.parse as parse +except ImportError: + import urlparse as parse + +class EmptyLogger(object): + ''' + Provides an implementation that performs no logging + ''' + def debug(self, *k, **kw): + pass + def info(self, *k, **kw): + pass + def warn(self, *k, **kw): + pass + def error(self, *k, **kw): + pass + def critical(self, *k, **kw): + pass + def setLevel(self, *k, **kw): + pass + +urls = ( + 'http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20' + 'targetting%20Win32/Personal%20Builds/mingw-builds/installer/' + 'repository.txt', + 'http://downloads.sourceforge.net/project/mingwbuilds/host-windows/' + 'repository.txt' +) +''' +A list of mingw-build repositories +''' + +def repository(urls = urls, log = EmptyLogger()): + ''' + Downloads and parse mingw-build repository files and parses them + ''' + log.info('getting mingw-builds repository') + versions = {} + re_sourceforge = re.compile(r'http://sourceforge.net/projects/([^/]+)/files') + re_sub = r'http://downloads.sourceforge.net/project/\1' + for url in urls: + log.debug(' - requesting: %s', url) + socket = request.urlopen(url) + repo = socket.read() + if not isinstance(repo, str): + repo = repo.decode(); + socket.close() + for entry in repo.split('\n')[:-1]: + value = entry.split('|') + version = tuple([int(n) for n in value[0].strip().split('.')]) + version = versions.setdefault(version, {}) + arch = value[1].strip() + if arch == 'x32': + arch = 'i686' + elif arch == 'x64': + arch = 'x86_64' + arch = version.setdefault(arch, {}) + threading = arch.setdefault(value[2].strip(), {}) + exceptions = threading.setdefault(value[3].strip(), {}) + revision = exceptions.setdefault(int(value[4].strip()[3:]), + re_sourceforge.sub(re_sub, value[5].strip())) + return versions + +def find_in_path(file, path=None): + ''' + Attempts to find an executable in the path + ''' + if platform.system() == 'Windows': + file += '.exe' + if path is None: + path = os.environ.get('PATH', '') + if type(path) is type(''): + path = path.split(os.pathsep) + return list(filter(os.path.exists, + map(lambda dir, file=file: os.path.join(dir, file), path))) + +def find_7zip(log = EmptyLogger()): + ''' + Attempts to find 7zip for unpacking the mingw-build archives + ''' + log.info('finding 7zip') + path = find_in_path('7z') + if not path: + key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\7-Zip') + path, _ = winreg.QueryValueEx(key, 'Path') + path = [os.path.join(path, '7z.exe')] + log.debug('found \'%s\'', path[0]) + return path[0] + +find_7zip() + +def unpack(archive, location, log = EmptyLogger()): + ''' + Unpacks a mingw-builds archive + ''' + sevenzip = find_7zip(log) + log.info('unpacking %s', os.path.basename(archive)) + cmd = [sevenzip, 'x', archive, '-o' + location, '-y'] + log.debug(' - %r', cmd) + with open(os.devnull, 'w') as devnull: + subprocess.check_call(cmd, stdout = devnull) + +def download(url, location, log = EmptyLogger()): + ''' + Downloads and unpacks a mingw-builds archive + ''' + log.info('downloading MinGW') + log.debug(' - url: %s', url) + log.debug(' - location: %s', location) + + re_content = re.compile(r'attachment;[ \t]*filename=(")?([^"]*)(")?[\r\n]*') + + stream = request.urlopen(url) + try: + content = stream.getheader('Content-Disposition') or '' + except AttributeError: + content = stream.headers.getheader('Content-Disposition') or '' + matches = re_content.match(content) + if matches: + filename = matches.group(2) + else: + parsed = parse.urlparse(stream.geturl()) + filename = os.path.basename(parsed.path) + + try: + os.makedirs(location) + except OSError as e: + if e.errno == errno.EEXIST and os.path.isdir(location): + pass + else: + raise + + archive = os.path.join(location, filename) + with open(archive, 'wb') as out: + while True: + buf = stream.read(1024) + if not buf: + break + out.write(buf) + unpack(archive, location, log = log) + os.remove(archive) + + possible = os.path.join(location, 'mingw64') + if not os.path.exists(possible): + possible = os.path.join(location, 'mingw32') + if not os.path.exists(possible): + raise ValueError('Failed to find unpacked MinGW: ' + possible) + return possible + +def root(location = None, arch = None, version = None, threading = None, + exceptions = None, revision = None, log = EmptyLogger()): + ''' + Returns the root folder of a specific version of the mingw-builds variant + of gcc. Will download the compiler if needed + ''' + + # Get the repository if we don't have all the information + if not (arch and version and threading and exceptions and revision): + versions = repository(log = log) + + # Determine some defaults + version = version or max(versions.keys()) + if not arch: + arch = platform.machine().lower() + if arch == 'x86': + arch = 'i686' + elif arch == 'amd64': + arch = 'x86_64' + if not threading: + keys = versions[version][arch].keys() + if 'posix' in keys: + threading = 'posix' + elif 'win32' in keys: + threading = 'win32' + else: + threading = keys[0] + if not exceptions: + keys = versions[version][arch][threading].keys() + if 'seh' in keys: + exceptions = 'seh' + elif 'sjlj' in keys: + exceptions = 'sjlj' + else: + exceptions = keys[0] + if revision is None: + revision = max(versions[version][arch][threading][exceptions].keys()) + if not location: + location = os.path.join(tempfile.gettempdir(), 'mingw-builds') + + # Get the download url + url = versions[version][arch][threading][exceptions][revision] + + # Tell the user whatzzup + log.info('finding MinGW %s', '.'.join(str(v) for v in version)) + log.debug(' - arch: %s', arch) + log.debug(' - threading: %s', threading) + log.debug(' - exceptions: %s', exceptions) + log.debug(' - revision: %s', revision) + log.debug(' - url: %s', url) + + # Store each specific revision differently + slug = '{version}-{arch}-{threading}-{exceptions}-rev{revision}' + slug = slug.format( + version = '.'.join(str(v) for v in version), + arch = arch, + threading = threading, + exceptions = exceptions, + revision = revision + ) + if arch == 'x86_64': + root_dir = os.path.join(location, slug, 'mingw64') + elif arch == 'i686': + root_dir = os.path.join(location, slug, 'mingw32') + else: + raise ValueError('Unknown MinGW arch: ' + arch) + + # Download if needed + if not os.path.exists(root_dir): + downloaded = download(url, os.path.join(location, slug), log = log) + if downloaded != root_dir: + raise ValueError('The location of mingw did not match\n%s\n%s' + % (downloaded, root_dir)) + + return root_dir + +def str2ver(string): + ''' + Converts a version string into a tuple + ''' + try: + version = tuple(int(v) for v in string.split('.')) + if len(version) is not 3: + raise ValueError() + except ValueError: + raise argparse.ArgumentTypeError( + 'please provide a three digit version string') + return version + +def main(): + ''' + Invoked when the script is run directly by the python interpreter + ''' + parser = argparse.ArgumentParser( + description = 'Downloads a specific version of MinGW', + formatter_class = argparse.ArgumentDefaultsHelpFormatter + ) + parser.add_argument('--location', + help = 'the location to download the compiler to', + default = os.path.join(tempfile.gettempdir(), 'mingw-builds')) + parser.add_argument('--arch', required = True, choices = ['i686', 'x86_64'], + help = 'the target MinGW architecture string') + parser.add_argument('--version', type = str2ver, + help = 'the version of GCC to download') + parser.add_argument('--threading', choices = ['posix', 'win32'], + help = 'the threading type of the compiler') + parser.add_argument('--exceptions', choices = ['sjlj', 'seh', 'dwarf'], + help = 'the method to throw exceptions') + parser.add_argument('--revision', type=int, + help = 'the revision of the MinGW release') + group = parser.add_mutually_exclusive_group() + group.add_argument('-v', '--verbose', action='store_true', + help='increase the script output verbosity') + group.add_argument('-q', '--quiet', action='store_true', + help='only print errors and warning') + args = parser.parse_args() + + # Create the logger + logger = logging.getLogger('mingw') + handler = logging.StreamHandler() + formatter = logging.Formatter('%(message)s') + handler.setFormatter(formatter) + logger.addHandler(handler) + logger.setLevel(logging.INFO) + if args.quiet: + logger.setLevel(logging.WARN) + if args.verbose: + logger.setLevel(logging.DEBUG) + + # Get MinGW + root_dir = root(location = args.location, arch = args.arch, + version = args.version, threading = args.threading, + exceptions = args.exceptions, revision = args.revision, + log = logger) + + sys.stdout.write('%s\n' % os.path.join(root_dir, 'bin')) + +if __name__ == '__main__': + try: + main() + except IOError as e: + sys.stderr.write('IO error: %s\n' % e) + sys.exit(1) + except OSError as e: + sys.stderr.write('OS error: %s\n' % e) + sys.exit(1) + except KeyboardInterrupt as e: + sys.stderr.write('Killed\n') + sys.exit(1) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/releasing.md b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/releasing.md new file mode 100644 index 0000000000000000000000000000000000000000..f0cd7010e3a905c0cfdddb9b33da5c31ed1dff9e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/releasing.md @@ -0,0 +1,16 @@ +# How to release + +* Make sure you're on master and synced to HEAD +* Ensure the project builds and tests run (sanity check only, obviously) + * `parallel -j0 exec ::: test/*_test` can help ensure everything at least + passes +* Prepare release notes + * `git log $(git describe --abbrev=0 --tags)..HEAD` gives you the list of + commits between the last annotated tag and HEAD + * Pick the most interesting. +* Create a release through github's interface + * Note this will create a lightweight tag. + * Update this to an annotated tag: + * `git pull --tags` + * `git tag -a -f ` + * `git push --force origin` diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/setup.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..f4c063346a46da860005b39f022aecad7ded12d8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/setup.py @@ -0,0 +1,124 @@ +import os +import posixpath +import re +import shutil +import sys + +from distutils import sysconfig +import setuptools +from setuptools.command import build_ext + + +here = os.path.dirname(os.path.abspath(__file__)) + + +IS_WINDOWS = sys.platform.startswith('win') + + +def _get_version(): + """Parse the version string from __init__.py.""" + with open(os.path.join(here, 'bindings', 'python', 'benchmark', '__init__.py')) as f: + try: + version_line = next( + line for line in f if line.startswith('__version__')) + except StopIteration: + raise ValueError('__version__ not defined in __init__.py') + else: + ns = {} + exec(version_line, ns) # pylint: disable=exec-used + return ns['__version__'] + + +def _parse_requirements(path): + with open(os.path.join(here, path)) as f: + return [ + line.rstrip() for line in f + if not (line.isspace() or line.startswith('#')) + ] + + +class BazelExtension(setuptools.Extension): + """A C/C++ extension that is defined as a Bazel BUILD target.""" + + def __init__(self, name, bazel_target): + self.bazel_target = bazel_target + self.relpath, self.target_name = ( + posixpath.relpath(bazel_target, '//').split(':')) + setuptools.Extension.__init__(self, name, sources=[]) + + +class BuildBazelExtension(build_ext.build_ext): + """A command that runs Bazel to build a C/C++ extension.""" + + def run(self): + for ext in self.extensions: + self.bazel_build(ext) + build_ext.build_ext.run(self) + + def bazel_build(self, ext): + with open('WORKSPACE', 'r') as f: + workspace_contents = f.read() + + with open('WORKSPACE', 'w') as f: + f.write(re.sub( + r'(?<=path = ").*(?=", # May be overwritten by setup\.py\.)', + sysconfig.get_python_inc().replace(os.path.sep, posixpath.sep), + workspace_contents)) + + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + + bazel_argv = [ + 'bazel', + 'build', + ext.bazel_target, + '--symlink_prefix=' + os.path.join(self.build_temp, 'bazel-'), + '--compilation_mode=' + ('dbg' if self.debug else 'opt'), + ] + + if IS_WINDOWS: + # Link with python*.lib. + for library_dir in self.library_dirs: + bazel_argv.append('--linkopt=/LIBPATH:' + library_dir) + + self.spawn(bazel_argv) + + shared_lib_suffix = '.dll' if IS_WINDOWS else '.so' + ext_bazel_bin_path = os.path.join( + self.build_temp, 'bazel-bin', + ext.relpath, ext.target_name + shared_lib_suffix) + ext_dest_path = self.get_ext_fullpath(ext.name) + ext_dest_dir = os.path.dirname(ext_dest_path) + if not os.path.exists(ext_dest_dir): + os.makedirs(ext_dest_dir) + shutil.copyfile(ext_bazel_bin_path, ext_dest_path) + + +setuptools.setup( + name='google-benchmark', + version=_get_version(), + url='https://github.com/google/benchmark', + description='A library to benchmark code snippets.', + author='Google', + author_email='benchmark-py@google.com', + # Contained modules and scripts. + package_dir={'': 'bindings/python'}, + packages=setuptools.find_packages('bindings/python'), + install_requires=_parse_requirements('bindings/python/requirements.txt'), + cmdclass=dict(build_ext=BuildBazelExtension), + ext_modules=[BazelExtension('benchmark._benchmark', '//bindings/python/benchmark:_benchmark')], + zip_safe=False, + # PyPI package information. + classifiers=[ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Topic :: Software Development :: Testing', + 'Topic :: System :: Benchmark', + ], + license='Apache 2.0', + keywords='benchmark', +) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..35d559eeae1e4ec3f20bcf3703858ea28ed10d3e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/CMakeLists.txt @@ -0,0 +1,114 @@ +# Allow the source files to find headers in src/ +include(GNUInstallDirs) +include_directories(${PROJECT_SOURCE_DIR}/src) + +if (DEFINED BENCHMARK_CXX_LINKER_FLAGS) + list(APPEND CMAKE_SHARED_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}) + list(APPEND CMAKE_MODULE_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}) +endif() + +file(GLOB + SOURCE_FILES + *.cc + ${PROJECT_SOURCE_DIR}/include/benchmark/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/*.h) +file(GLOB BENCHMARK_MAIN "benchmark_main.cc") +foreach(item ${BENCHMARK_MAIN}) + list(REMOVE_ITEM SOURCE_FILES "${item}") +endforeach() + +add_library(benchmark ${SOURCE_FILES}) +add_library(benchmark::benchmark ALIAS benchmark) +set_target_properties(benchmark PROPERTIES + OUTPUT_NAME "benchmark" + VERSION ${GENERIC_LIB_VERSION} + SOVERSION ${GENERIC_LIB_SOVERSION} +) +target_include_directories(benchmark PUBLIC + $ + ) + +# Link threads. +target_link_libraries(benchmark ${BENCHMARK_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +find_library(LIBRT rt) +if(LIBRT) + target_link_libraries(benchmark ${LIBRT}) +endif() + +if(CMAKE_BUILD_TYPE) + string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UPPER) +endif() +if(NOT CMAKE_THREAD_LIBS_INIT AND "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}" MATCHES ".*-fsanitize=[^ ]*address.*") + message(WARNING "CMake's FindThreads.cmake did not fail, but CMAKE_THREAD_LIBS_INIT ended up being empty. This was fixed in https://github.com/Kitware/CMake/commit/d53317130e84898c5328c237186dbd995aaf1c12 Let's guess that -pthread is sufficient.") + target_link_libraries(benchmark -pthread) +endif() + +# We need extra libraries on Windows +if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + target_link_libraries(benchmark shlwapi) +endif() + +# We need extra libraries on Solaris +if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS") + target_link_libraries(benchmark kstat) +endif() + +# Benchmark main library +add_library(benchmark_main "benchmark_main.cc") +add_library(benchmark::benchmark_main ALIAS benchmark_main) +set_target_properties(benchmark_main PROPERTIES + OUTPUT_NAME "benchmark_main" + VERSION ${GENERIC_LIB_VERSION} + SOVERSION ${GENERIC_LIB_SOVERSION} +) +target_include_directories(benchmark PUBLIC + $ + ) +target_link_libraries(benchmark_main benchmark::benchmark) + + +set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") + +set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake") +set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake") +set(pkg_config "${generated_dir}/${PROJECT_NAME}.pc") +set(targets_export_name "${PROJECT_NAME}Targets") + +set(namespace "${PROJECT_NAME}::") + +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${version_config}" VERSION ${GENERIC_LIB_VERSION} COMPATIBILITY SameMajorVersion +) + +configure_file("${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in" "${project_config}" @ONLY) +configure_file("${PROJECT_SOURCE_DIR}/cmake/benchmark.pc.in" "${pkg_config}" @ONLY) + +if (BENCHMARK_ENABLE_INSTALL) + # Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable) + install( + TARGETS benchmark benchmark_main + EXPORT ${targets_export_name} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + + install( + DIRECTORY "${PROJECT_SOURCE_DIR}/include/benchmark" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.*h") + + install( + FILES "${project_config}" "${version_config}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + + install( + FILES "${pkg_config}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + + install( + EXPORT "${targets_export_name}" + NAMESPACE "${namespace}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") +endif() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/arraysize.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/arraysize.h new file mode 100644 index 0000000000000000000000000000000000000000..51a50f2dff271a01b57bc280404bfeab0ed1ab4c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/arraysize.h @@ -0,0 +1,33 @@ +#ifndef BENCHMARK_ARRAYSIZE_H_ +#define BENCHMARK_ARRAYSIZE_H_ + +#include "internal_macros.h" + +namespace benchmark { +namespace internal { +// The arraysize(arr) macro returns the # of elements in an array arr. +// The expression is a compile-time constant, and therefore can be +// used in defining new arrays, for example. If you use arraysize on +// a pointer by mistake, you will get a compile-time error. +// + +// This template function declaration is used in defining arraysize. +// Note that the function doesn't need an implementation, as we only +// use its type. +template +char (&ArraySizeHelper(T (&array)[N]))[N]; + +// That gcc wants both of these prototypes seems mysterious. VC, for +// its part, can't decide which to use (another mystery). Matching of +// template overloads: the final frontier. +#ifndef COMPILER_MSVC +template +char (&ArraySizeHelper(const T (&array)[N]))[N]; +#endif + +#define arraysize(array) (sizeof(::benchmark::internal::ArraySizeHelper(array))) + +} // end namespace internal +} // end namespace benchmark + +#endif // BENCHMARK_ARRAYSIZE_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark.cc new file mode 100644 index 0000000000000000000000000000000000000000..1c049f2884401d07342332d0d9e0cab840914f0a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark.cc @@ -0,0 +1,499 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" +#include "benchmark_api_internal.h" +#include "benchmark_runner.h" +#include "internal_macros.h" + +#ifndef BENCHMARK_OS_WINDOWS +#ifndef BENCHMARK_OS_FUCHSIA +#include +#endif +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "check.h" +#include "colorprint.h" +#include "commandlineflags.h" +#include "complexity.h" +#include "counter.h" +#include "internal_macros.h" +#include "log.h" +#include "mutex.h" +#include "re.h" +#include "statistics.h" +#include "string_util.h" +#include "thread_manager.h" +#include "thread_timer.h" + +// Print a list of benchmarks. This option overrides all other options. +DEFINE_bool(benchmark_list_tests, false); + +// A regular expression that specifies the set of benchmarks to execute. If +// this flag is empty, or if this flag is the string \"all\", all benchmarks +// linked into the binary are run. +DEFINE_string(benchmark_filter, "."); + +// Minimum number of seconds we should run benchmark before results are +// considered significant. For cpu-time based tests, this is the lower bound +// on the total cpu time used by all threads that make up the test. For +// real-time based tests, this is the lower bound on the elapsed time of the +// benchmark execution, regardless of number of threads. +DEFINE_double(benchmark_min_time, 0.5); + +// The number of runs of each benchmark. If greater than 1, the mean and +// standard deviation of the runs will be reported. +DEFINE_int32(benchmark_repetitions, 1); + +// Report the result of each benchmark repetitions. When 'true' is specified +// only the mean, standard deviation, and other statistics are reported for +// repeated benchmarks. Affects all reporters. +DEFINE_bool(benchmark_report_aggregates_only, false); + +// Display the result of each benchmark repetitions. When 'true' is specified +// only the mean, standard deviation, and other statistics are displayed for +// repeated benchmarks. Unlike benchmark_report_aggregates_only, only affects +// the display reporter, but *NOT* file reporter, which will still contain +// all the output. +DEFINE_bool(benchmark_display_aggregates_only, false); + +// The format to use for console output. +// Valid values are 'console', 'json', or 'csv'. +DEFINE_string(benchmark_format, "console"); + +// The format to use for file output. +// Valid values are 'console', 'json', or 'csv'. +DEFINE_string(benchmark_out_format, "json"); + +// The file to write additional output to. +DEFINE_string(benchmark_out, ""); + +// Whether to use colors in the output. Valid values: +// 'true'/'yes'/1, 'false'/'no'/0, and 'auto'. 'auto' means to use colors if +// the output is being sent to a terminal and the TERM environment variable is +// set to a terminal type that supports colors. +DEFINE_string(benchmark_color, "auto"); + +// Whether to use tabular format when printing user counters to the console. +// Valid values: 'true'/'yes'/1, 'false'/'no'/0. Defaults to false. +DEFINE_bool(benchmark_counters_tabular, false); + +// The level of verbose logging to output +DEFINE_int32(v, 0); + +namespace benchmark { + +namespace internal { + +// FIXME: wouldn't LTO mess this up? +void UseCharPointer(char const volatile*) {} + +} // namespace internal + +State::State(IterationCount max_iters, const std::vector& ranges, + int thread_i, int n_threads, internal::ThreadTimer* timer, + internal::ThreadManager* manager) + : total_iterations_(0), + batch_leftover_(0), + max_iterations(max_iters), + started_(false), + finished_(false), + error_occurred_(false), + range_(ranges), + complexity_n_(0), + counters(), + thread_index(thread_i), + threads(n_threads), + timer_(timer), + manager_(manager) { + CHECK(max_iterations != 0) << "At least one iteration must be run"; + CHECK_LT(thread_index, threads) << "thread_index must be less than threads"; + + // Note: The use of offsetof below is technically undefined until C++17 + // because State is not a standard layout type. However, all compilers + // currently provide well-defined behavior as an extension (which is + // demonstrated since constexpr evaluation must diagnose all undefined + // behavior). However, GCC and Clang also warn about this use of offsetof, + // which must be suppressed. +#if defined(__INTEL_COMPILER) +#pragma warning push +#pragma warning(disable : 1875) +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif + // Offset tests to ensure commonly accessed data is on the first cache line. + const int cache_line_size = 64; + static_assert(offsetof(State, error_occurred_) <= + (cache_line_size - sizeof(error_occurred_)), + ""); +#if defined(__INTEL_COMPILER) +#pragma warning pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +} + +void State::PauseTiming() { + // Add in time accumulated so far + CHECK(started_ && !finished_ && !error_occurred_); + timer_->StopTimer(); +} + +void State::ResumeTiming() { + CHECK(started_ && !finished_ && !error_occurred_); + timer_->StartTimer(); +} + +void State::SkipWithError(const char* msg) { + CHECK(msg); + error_occurred_ = true; + { + MutexLock l(manager_->GetBenchmarkMutex()); + if (manager_->results.has_error_ == false) { + manager_->results.error_message_ = msg; + manager_->results.has_error_ = true; + } + } + total_iterations_ = 0; + if (timer_->running()) timer_->StopTimer(); +} + +void State::SetIterationTime(double seconds) { + timer_->SetIterationTime(seconds); +} + +void State::SetLabel(const char* label) { + MutexLock l(manager_->GetBenchmarkMutex()); + manager_->results.report_label_ = label; +} + +void State::StartKeepRunning() { + CHECK(!started_ && !finished_); + started_ = true; + total_iterations_ = error_occurred_ ? 0 : max_iterations; + manager_->StartStopBarrier(); + if (!error_occurred_) ResumeTiming(); +} + +void State::FinishKeepRunning() { + CHECK(started_ && (!finished_ || error_occurred_)); + if (!error_occurred_) { + PauseTiming(); + } + // Total iterations has now wrapped around past 0. Fix this. + total_iterations_ = 0; + finished_ = true; + manager_->StartStopBarrier(); +} + +namespace internal { +namespace { + +void RunBenchmarks(const std::vector& benchmarks, + BenchmarkReporter* display_reporter, + BenchmarkReporter* file_reporter) { + // Note the file_reporter can be null. + CHECK(display_reporter != nullptr); + + // Determine the width of the name field using a minimum width of 10. + bool might_have_aggregates = FLAGS_benchmark_repetitions > 1; + size_t name_field_width = 10; + size_t stat_field_width = 0; + for (const BenchmarkInstance& benchmark : benchmarks) { + name_field_width = + std::max(name_field_width, benchmark.name.str().size()); + might_have_aggregates |= benchmark.repetitions > 1; + + for (const auto& Stat : *benchmark.statistics) + stat_field_width = std::max(stat_field_width, Stat.name_.size()); + } + if (might_have_aggregates) name_field_width += 1 + stat_field_width; + + // Print header here + BenchmarkReporter::Context context; + context.name_field_width = name_field_width; + + // Keep track of running times of all instances of current benchmark + std::vector complexity_reports; + + // We flush streams after invoking reporter methods that write to them. This + // ensures users get timely updates even when streams are not line-buffered. + auto flushStreams = [](BenchmarkReporter* reporter) { + if (!reporter) return; + std::flush(reporter->GetOutputStream()); + std::flush(reporter->GetErrorStream()); + }; + + if (display_reporter->ReportContext(context) && + (!file_reporter || file_reporter->ReportContext(context))) { + flushStreams(display_reporter); + flushStreams(file_reporter); + + for (const auto& benchmark : benchmarks) { + RunResults run_results = RunBenchmark(benchmark, &complexity_reports); + + auto report = [&run_results](BenchmarkReporter* reporter, + bool report_aggregates_only) { + assert(reporter); + // If there are no aggregates, do output non-aggregates. + report_aggregates_only &= !run_results.aggregates_only.empty(); + if (!report_aggregates_only) + reporter->ReportRuns(run_results.non_aggregates); + if (!run_results.aggregates_only.empty()) + reporter->ReportRuns(run_results.aggregates_only); + }; + + report(display_reporter, run_results.display_report_aggregates_only); + if (file_reporter) + report(file_reporter, run_results.file_report_aggregates_only); + + flushStreams(display_reporter); + flushStreams(file_reporter); + } + } + display_reporter->Finalize(); + if (file_reporter) file_reporter->Finalize(); + flushStreams(display_reporter); + flushStreams(file_reporter); +} + +// Disable deprecated warnings temporarily because we need to reference +// CSVReporter but don't want to trigger -Werror=-Wdeprecated-declarations +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +std::unique_ptr CreateReporter( + std::string const& name, ConsoleReporter::OutputOptions output_opts) { + typedef std::unique_ptr PtrType; + if (name == "console") { + return PtrType(new ConsoleReporter(output_opts)); + } else if (name == "json") { + return PtrType(new JSONReporter); + } else if (name == "csv") { + return PtrType(new CSVReporter); + } else { + std::cerr << "Unexpected format: '" << name << "'\n"; + std::exit(1); + } +} + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +} // end namespace + +bool IsZero(double n) { + return std::abs(n) < std::numeric_limits::epsilon(); +} + +ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color) { + int output_opts = ConsoleReporter::OO_Defaults; + auto is_benchmark_color = [force_no_color]() -> bool { + if (force_no_color) { + return false; + } + if (FLAGS_benchmark_color == "auto") { + return IsColorTerminal(); + } + return IsTruthyFlagValue(FLAGS_benchmark_color); + }; + if (is_benchmark_color()) { + output_opts |= ConsoleReporter::OO_Color; + } else { + output_opts &= ~ConsoleReporter::OO_Color; + } + if (FLAGS_benchmark_counters_tabular) { + output_opts |= ConsoleReporter::OO_Tabular; + } else { + output_opts &= ~ConsoleReporter::OO_Tabular; + } + return static_cast(output_opts); +} + +} // end namespace internal + +size_t RunSpecifiedBenchmarks() { + return RunSpecifiedBenchmarks(nullptr, nullptr); +} + +size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter) { + return RunSpecifiedBenchmarks(display_reporter, nullptr); +} + +size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter, + BenchmarkReporter* file_reporter) { + std::string spec = FLAGS_benchmark_filter; + if (spec.empty() || spec == "all") + spec = "."; // Regexp that matches all benchmarks + + // Setup the reporters + std::ofstream output_file; + std::unique_ptr default_display_reporter; + std::unique_ptr default_file_reporter; + if (!display_reporter) { + default_display_reporter = internal::CreateReporter( + FLAGS_benchmark_format, internal::GetOutputOptions()); + display_reporter = default_display_reporter.get(); + } + auto& Out = display_reporter->GetOutputStream(); + auto& Err = display_reporter->GetErrorStream(); + + std::string const& fname = FLAGS_benchmark_out; + if (fname.empty() && file_reporter) { + Err << "A custom file reporter was provided but " + "--benchmark_out= was not specified." + << std::endl; + std::exit(1); + } + if (!fname.empty()) { + output_file.open(fname); + if (!output_file.is_open()) { + Err << "invalid file name: '" << fname << std::endl; + std::exit(1); + } + if (!file_reporter) { + default_file_reporter = internal::CreateReporter( + FLAGS_benchmark_out_format, ConsoleReporter::OO_None); + file_reporter = default_file_reporter.get(); + } + file_reporter->SetOutputStream(&output_file); + file_reporter->SetErrorStream(&output_file); + } + + std::vector benchmarks; + if (!FindBenchmarksInternal(spec, &benchmarks, &Err)) return 0; + + if (benchmarks.empty()) { + Err << "Failed to match any benchmarks against regex: " << spec << "\n"; + return 0; + } + + if (FLAGS_benchmark_list_tests) { + for (auto const& benchmark : benchmarks) + Out << benchmark.name.str() << "\n"; + } else { + internal::RunBenchmarks(benchmarks, display_reporter, file_reporter); + } + + return benchmarks.size(); +} + +void RegisterMemoryManager(MemoryManager* manager) { + internal::memory_manager = manager; +} + +namespace internal { + +void PrintUsageAndExit() { + fprintf(stdout, + "benchmark" + " [--benchmark_list_tests={true|false}]\n" + " [--benchmark_filter=]\n" + " [--benchmark_min_time=]\n" + " [--benchmark_repetitions=]\n" + " [--benchmark_report_aggregates_only={true|false}]\n" + " [--benchmark_display_aggregates_only={true|false}]\n" + " [--benchmark_format=]\n" + " [--benchmark_out=]\n" + " [--benchmark_out_format=]\n" + " [--benchmark_color={auto|true|false}]\n" + " [--benchmark_counters_tabular={true|false}]\n" + " [--v=]\n"); + exit(0); +} + +void ParseCommandLineFlags(int* argc, char** argv) { + using namespace benchmark; + BenchmarkReporter::Context::executable_name = + (argc && *argc > 0) ? argv[0] : "unknown"; + for (int i = 1; argc && i < *argc; ++i) { + if (ParseBoolFlag(argv[i], "benchmark_list_tests", + &FLAGS_benchmark_list_tests) || + ParseStringFlag(argv[i], "benchmark_filter", &FLAGS_benchmark_filter) || + ParseDoubleFlag(argv[i], "benchmark_min_time", + &FLAGS_benchmark_min_time) || + ParseInt32Flag(argv[i], "benchmark_repetitions", + &FLAGS_benchmark_repetitions) || + ParseBoolFlag(argv[i], "benchmark_report_aggregates_only", + &FLAGS_benchmark_report_aggregates_only) || + ParseBoolFlag(argv[i], "benchmark_display_aggregates_only", + &FLAGS_benchmark_display_aggregates_only) || + ParseStringFlag(argv[i], "benchmark_format", &FLAGS_benchmark_format) || + ParseStringFlag(argv[i], "benchmark_out", &FLAGS_benchmark_out) || + ParseStringFlag(argv[i], "benchmark_out_format", + &FLAGS_benchmark_out_format) || + ParseStringFlag(argv[i], "benchmark_color", &FLAGS_benchmark_color) || + // "color_print" is the deprecated name for "benchmark_color". + // TODO: Remove this. + ParseStringFlag(argv[i], "color_print", &FLAGS_benchmark_color) || + ParseBoolFlag(argv[i], "benchmark_counters_tabular", + &FLAGS_benchmark_counters_tabular) || + ParseInt32Flag(argv[i], "v", &FLAGS_v)) { + for (int j = i; j != *argc - 1; ++j) argv[j] = argv[j + 1]; + + --(*argc); + --i; + } else if (IsFlag(argv[i], "help")) { + PrintUsageAndExit(); + } + } + for (auto const* flag : + {&FLAGS_benchmark_format, &FLAGS_benchmark_out_format}) + if (*flag != "console" && *flag != "json" && *flag != "csv") { + PrintUsageAndExit(); + } + if (FLAGS_benchmark_color.empty()) { + PrintUsageAndExit(); + } +} + +int InitializeStreams() { + static std::ios_base::Init init; + return 0; +} + +} // end namespace internal + +void Initialize(int* argc, char** argv) { + internal::ParseCommandLineFlags(argc, argv); + internal::LogLevel() = FLAGS_v; +} + +bool ReportUnrecognizedArguments(int argc, char** argv) { + for (int i = 1; i < argc; ++i) { + fprintf(stderr, "%s: error: unrecognized command-line flag: %s\n", argv[0], + argv[i]); + } + return argc > 1; +} + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_api_internal.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_api_internal.cc new file mode 100644 index 0000000000000000000000000000000000000000..d468a257e39c38e797e0fac9d072658687a0be6e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_api_internal.cc @@ -0,0 +1,15 @@ +#include "benchmark_api_internal.h" + +namespace benchmark { +namespace internal { + +State BenchmarkInstance::Run(IterationCount iters, int thread_id, + internal::ThreadTimer* timer, + internal::ThreadManager* manager) const { + State st(iters, arg, thread_id, threads, timer, manager); + benchmark->Run(st); + return st; +} + +} // internal +} // benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_api_internal.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_api_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..264eff95c5cc0407991783378d9a38e1d7975519 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_api_internal.h @@ -0,0 +1,53 @@ +#ifndef BENCHMARK_API_INTERNAL_H +#define BENCHMARK_API_INTERNAL_H + +#include "benchmark/benchmark.h" +#include "commandlineflags.h" + +#include +#include +#include +#include +#include +#include + +namespace benchmark { +namespace internal { + +// Information kept per benchmark we may want to run +struct BenchmarkInstance { + BenchmarkName name; + Benchmark* benchmark; + AggregationReportMode aggregation_report_mode; + std::vector arg; + TimeUnit time_unit; + int range_multiplier; + bool measure_process_cpu_time; + bool use_real_time; + bool use_manual_time; + BigO complexity; + BigOFunc* complexity_lambda; + UserCounters counters; + const std::vector* statistics; + bool last_benchmark_instance; + int repetitions; + double min_time; + IterationCount iterations; + int threads; // Number of concurrent threads to us + + State Run(IterationCount iters, int thread_id, internal::ThreadTimer* timer, + internal::ThreadManager* manager) const; +}; + +bool FindBenchmarksInternal(const std::string& re, + std::vector* benchmarks, + std::ostream* Err); + +bool IsZero(double n); + +ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color = false); + +} // end namespace internal +} // end namespace benchmark + +#endif // BENCHMARK_API_INTERNAL_H diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_main.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_main.cc new file mode 100644 index 0000000000000000000000000000000000000000..b3b247831496f610234e6153697d199a88d6ebc4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_main.cc @@ -0,0 +1,17 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" + +BENCHMARK_MAIN(); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_name.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_name.cc new file mode 100644 index 0000000000000000000000000000000000000000..2a17ebce277f56c90926aa190ebe5392de17b463 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_name.cc @@ -0,0 +1,58 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +namespace benchmark { + +namespace { + +// Compute the total size of a pack of std::strings +size_t size_impl() { return 0; } + +template +size_t size_impl(const Head& head, const Tail&... tail) { + return head.size() + size_impl(tail...); +} + +// Join a pack of std::strings using a delimiter +// TODO: use absl::StrJoin +void join_impl(std::string&, char) {} + +template +void join_impl(std::string& s, const char delimiter, const Head& head, + const Tail&... tail) { + if (!s.empty() && !head.empty()) { + s += delimiter; + } + + s += head; + + join_impl(s, delimiter, tail...); +} + +template +std::string join(char delimiter, const Ts&... ts) { + std::string s; + s.reserve(sizeof...(Ts) + size_impl(ts...)); + join_impl(s, delimiter, ts...); + return s; +} +} // namespace + +std::string BenchmarkName::str() const { + return join('/', function_name, args, min_time, iterations, repetitions, + time_type, threads); +} +} // namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_register.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_register.cc new file mode 100644 index 0000000000000000000000000000000000000000..cca39b2215517d31435d5b76688acf00cad291a0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_register.cc @@ -0,0 +1,506 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark_register.h" + +#ifndef BENCHMARK_OS_WINDOWS +#ifndef BENCHMARK_OS_FUCHSIA +#include +#endif +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif +#include + +#include "benchmark/benchmark.h" +#include "benchmark_api_internal.h" +#include "check.h" +#include "commandlineflags.h" +#include "complexity.h" +#include "internal_macros.h" +#include "log.h" +#include "mutex.h" +#include "re.h" +#include "statistics.h" +#include "string_util.h" +#include "timers.h" + +namespace benchmark { + +namespace { +// For non-dense Range, intermediate values are powers of kRangeMultiplier. +static const int kRangeMultiplier = 8; +// The size of a benchmark family determines is the number of inputs to repeat +// the benchmark on. If this is "large" then warn the user during configuration. +static const size_t kMaxFamilySize = 100; +} // end namespace + +namespace internal { + +//=============================================================================// +// BenchmarkFamilies +//=============================================================================// + +// Class for managing registered benchmarks. Note that each registered +// benchmark identifies a family of related benchmarks to run. +class BenchmarkFamilies { + public: + static BenchmarkFamilies* GetInstance(); + + // Registers a benchmark family and returns the index assigned to it. + size_t AddBenchmark(std::unique_ptr family); + + // Clear all registered benchmark families. + void ClearBenchmarks(); + + // Extract the list of benchmark instances that match the specified + // regular expression. + bool FindBenchmarks(std::string re, + std::vector* benchmarks, + std::ostream* Err); + + private: + BenchmarkFamilies() {} + + std::vector> families_; + Mutex mutex_; +}; + +BenchmarkFamilies* BenchmarkFamilies::GetInstance() { + static BenchmarkFamilies instance; + return &instance; +} + +size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr family) { + MutexLock l(mutex_); + size_t index = families_.size(); + families_.push_back(std::move(family)); + return index; +} + +void BenchmarkFamilies::ClearBenchmarks() { + MutexLock l(mutex_); + families_.clear(); + families_.shrink_to_fit(); +} + +bool BenchmarkFamilies::FindBenchmarks( + std::string spec, std::vector* benchmarks, + std::ostream* ErrStream) { + CHECK(ErrStream); + auto& Err = *ErrStream; + // Make regular expression out of command-line flag + std::string error_msg; + Regex re; + bool isNegativeFilter = false; + if (spec[0] == '-') { + spec.replace(0, 1, ""); + isNegativeFilter = true; + } + if (!re.Init(spec, &error_msg)) { + Err << "Could not compile benchmark re: " << error_msg << std::endl; + return false; + } + + // Special list of thread counts to use when none are specified + const std::vector one_thread = {1}; + + MutexLock l(mutex_); + for (std::unique_ptr& family : families_) { + // Family was deleted or benchmark doesn't match + if (!family) continue; + + if (family->ArgsCnt() == -1) { + family->Args({}); + } + const std::vector* thread_counts = + (family->thread_counts_.empty() + ? &one_thread + : &static_cast&>(family->thread_counts_)); + const size_t family_size = family->args_.size() * thread_counts->size(); + // The benchmark will be run at least 'family_size' different inputs. + // If 'family_size' is very large warn the user. + if (family_size > kMaxFamilySize) { + Err << "The number of inputs is very large. " << family->name_ + << " will be repeated at least " << family_size << " times.\n"; + } + // reserve in the special case the regex ".", since we know the final + // family size. + if (spec == ".") benchmarks->reserve(family_size); + + for (auto const& args : family->args_) { + for (int num_threads : *thread_counts) { + BenchmarkInstance instance; + instance.name.function_name = family->name_; + instance.benchmark = family.get(); + instance.aggregation_report_mode = family->aggregation_report_mode_; + instance.arg = args; + instance.time_unit = family->time_unit_; + instance.range_multiplier = family->range_multiplier_; + instance.min_time = family->min_time_; + instance.iterations = family->iterations_; + instance.repetitions = family->repetitions_; + instance.measure_process_cpu_time = family->measure_process_cpu_time_; + instance.use_real_time = family->use_real_time_; + instance.use_manual_time = family->use_manual_time_; + instance.complexity = family->complexity_; + instance.complexity_lambda = family->complexity_lambda_; + instance.statistics = &family->statistics_; + instance.threads = num_threads; + + // Add arguments to instance name + size_t arg_i = 0; + for (auto const& arg : args) { + if (!instance.name.args.empty()) { + instance.name.args += '/'; + } + + if (arg_i < family->arg_names_.size()) { + const auto& arg_name = family->arg_names_[arg_i]; + if (!arg_name.empty()) { + instance.name.args += StrFormat("%s:", arg_name.c_str()); + } + } + + instance.name.args += StrFormat("%" PRId64, arg); + ++arg_i; + } + + if (!IsZero(family->min_time_)) + instance.name.min_time = + StrFormat("min_time:%0.3f", family->min_time_); + if (family->iterations_ != 0) { + instance.name.iterations = + StrFormat("iterations:%lu", + static_cast(family->iterations_)); + } + if (family->repetitions_ != 0) + instance.name.repetitions = + StrFormat("repeats:%d", family->repetitions_); + + if (family->measure_process_cpu_time_) { + instance.name.time_type = "process_time"; + } + + if (family->use_manual_time_) { + if (!instance.name.time_type.empty()) { + instance.name.time_type += '/'; + } + instance.name.time_type += "manual_time"; + } else if (family->use_real_time_) { + if (!instance.name.time_type.empty()) { + instance.name.time_type += '/'; + } + instance.name.time_type += "real_time"; + } + + // Add the number of threads used to the name + if (!family->thread_counts_.empty()) { + instance.name.threads = StrFormat("threads:%d", instance.threads); + } + + const auto full_name = instance.name.str(); + if ((re.Match(full_name) && !isNegativeFilter) || + (!re.Match(full_name) && isNegativeFilter)) { + instance.last_benchmark_instance = (&args == &family->args_.back()); + benchmarks->push_back(std::move(instance)); + } + } + } + } + return true; +} + +Benchmark* RegisterBenchmarkInternal(Benchmark* bench) { + std::unique_ptr bench_ptr(bench); + BenchmarkFamilies* families = BenchmarkFamilies::GetInstance(); + families->AddBenchmark(std::move(bench_ptr)); + return bench; +} + +// FIXME: This function is a hack so that benchmark.cc can access +// `BenchmarkFamilies` +bool FindBenchmarksInternal(const std::string& re, + std::vector* benchmarks, + std::ostream* Err) { + return BenchmarkFamilies::GetInstance()->FindBenchmarks(re, benchmarks, Err); +} + +//=============================================================================// +// Benchmark +//=============================================================================// + +Benchmark::Benchmark(const char* name) + : name_(name), + aggregation_report_mode_(ARM_Unspecified), + time_unit_(kNanosecond), + range_multiplier_(kRangeMultiplier), + min_time_(0), + iterations_(0), + repetitions_(0), + measure_process_cpu_time_(false), + use_real_time_(false), + use_manual_time_(false), + complexity_(oNone), + complexity_lambda_(nullptr) { + ComputeStatistics("mean", StatisticsMean); + ComputeStatistics("median", StatisticsMedian); + ComputeStatistics("stddev", StatisticsStdDev); +} + +Benchmark::~Benchmark() {} + +Benchmark* Benchmark::Arg(int64_t x) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); + args_.push_back({x}); + return this; +} + +Benchmark* Benchmark::Unit(TimeUnit unit) { + time_unit_ = unit; + return this; +} + +Benchmark* Benchmark::Range(int64_t start, int64_t limit) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); + std::vector arglist; + AddRange(&arglist, start, limit, range_multiplier_); + + for (int64_t i : arglist) { + args_.push_back({i}); + } + return this; +} + +Benchmark* Benchmark::Ranges( + const std::vector>& ranges) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast(ranges.size())); + std::vector> arglists(ranges.size()); + std::size_t total = 1; + for (std::size_t i = 0; i < ranges.size(); i++) { + AddRange(&arglists[i], ranges[i].first, ranges[i].second, + range_multiplier_); + total *= arglists[i].size(); + } + + std::vector ctr(arglists.size(), 0); + + for (std::size_t i = 0; i < total; i++) { + std::vector tmp; + tmp.reserve(arglists.size()); + + for (std::size_t j = 0; j < arglists.size(); j++) { + tmp.push_back(arglists[j].at(ctr[j])); + } + + args_.push_back(std::move(tmp)); + + for (std::size_t j = 0; j < arglists.size(); j++) { + if (ctr[j] + 1 < arglists[j].size()) { + ++ctr[j]; + break; + } + ctr[j] = 0; + } + } + return this; +} + +Benchmark* Benchmark::ArgName(const std::string& name) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); + arg_names_ = {name}; + return this; +} + +Benchmark* Benchmark::ArgNames(const std::vector& names) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast(names.size())); + arg_names_ = names; + return this; +} + +Benchmark* Benchmark::DenseRange(int64_t start, int64_t limit, int step) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == 1); + CHECK_LE(start, limit); + for (int64_t arg = start; arg <= limit; arg += step) { + args_.push_back({arg}); + } + return this; +} + +Benchmark* Benchmark::Args(const std::vector& args) { + CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast(args.size())); + args_.push_back(args); + return this; +} + +Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) { + custom_arguments(this); + return this; +} + +Benchmark* Benchmark::RangeMultiplier(int multiplier) { + CHECK(multiplier > 1); + range_multiplier_ = multiplier; + return this; +} + +Benchmark* Benchmark::MinTime(double t) { + CHECK(t > 0.0); + CHECK(iterations_ == 0); + min_time_ = t; + return this; +} + +Benchmark* Benchmark::Iterations(IterationCount n) { + CHECK(n > 0); + CHECK(IsZero(min_time_)); + iterations_ = n; + return this; +} + +Benchmark* Benchmark::Repetitions(int n) { + CHECK(n > 0); + repetitions_ = n; + return this; +} + +Benchmark* Benchmark::ReportAggregatesOnly(bool value) { + aggregation_report_mode_ = value ? ARM_ReportAggregatesOnly : ARM_Default; + return this; +} + +Benchmark* Benchmark::DisplayAggregatesOnly(bool value) { + // If we were called, the report mode is no longer 'unspecified', in any case. + aggregation_report_mode_ = static_cast( + aggregation_report_mode_ | ARM_Default); + + if (value) { + aggregation_report_mode_ = static_cast( + aggregation_report_mode_ | ARM_DisplayReportAggregatesOnly); + } else { + aggregation_report_mode_ = static_cast( + aggregation_report_mode_ & ~ARM_DisplayReportAggregatesOnly); + } + + return this; +} + +Benchmark* Benchmark::MeasureProcessCPUTime() { + // Can be used together with UseRealTime() / UseManualTime(). + measure_process_cpu_time_ = true; + return this; +} + +Benchmark* Benchmark::UseRealTime() { + CHECK(!use_manual_time_) + << "Cannot set UseRealTime and UseManualTime simultaneously."; + use_real_time_ = true; + return this; +} + +Benchmark* Benchmark::UseManualTime() { + CHECK(!use_real_time_) + << "Cannot set UseRealTime and UseManualTime simultaneously."; + use_manual_time_ = true; + return this; +} + +Benchmark* Benchmark::Complexity(BigO complexity) { + complexity_ = complexity; + return this; +} + +Benchmark* Benchmark::Complexity(BigOFunc* complexity) { + complexity_lambda_ = complexity; + complexity_ = oLambda; + return this; +} + +Benchmark* Benchmark::ComputeStatistics(std::string name, + StatisticsFunc* statistics) { + statistics_.emplace_back(name, statistics); + return this; +} + +Benchmark* Benchmark::Threads(int t) { + CHECK_GT(t, 0); + thread_counts_.push_back(t); + return this; +} + +Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) { + CHECK_GT(min_threads, 0); + CHECK_GE(max_threads, min_threads); + + AddRange(&thread_counts_, min_threads, max_threads, 2); + return this; +} + +Benchmark* Benchmark::DenseThreadRange(int min_threads, int max_threads, + int stride) { + CHECK_GT(min_threads, 0); + CHECK_GE(max_threads, min_threads); + CHECK_GE(stride, 1); + + for (auto i = min_threads; i < max_threads; i += stride) { + thread_counts_.push_back(i); + } + thread_counts_.push_back(max_threads); + return this; +} + +Benchmark* Benchmark::ThreadPerCpu() { + thread_counts_.push_back(CPUInfo::Get().num_cpus); + return this; +} + +void Benchmark::SetName(const char* name) { name_ = name; } + +int Benchmark::ArgsCnt() const { + if (args_.empty()) { + if (arg_names_.empty()) return -1; + return static_cast(arg_names_.size()); + } + return static_cast(args_.front().size()); +} + +//=============================================================================// +// FunctionBenchmark +//=============================================================================// + +void FunctionBenchmark::Run(State& st) { func_(st); } + +} // end namespace internal + +void ClearRegisteredBenchmarks() { + internal::BenchmarkFamilies::GetInstance()->ClearBenchmarks(); +} + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_register.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_register.h new file mode 100644 index 0000000000000000000000000000000000000000..61377d74230410db33d2b9fa7316c43aedabcb9e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_register.h @@ -0,0 +1,107 @@ +#ifndef BENCHMARK_REGISTER_H +#define BENCHMARK_REGISTER_H + +#include + +#include "check.h" + +namespace benchmark { +namespace internal { + +// Append the powers of 'mult' in the closed interval [lo, hi]. +// Returns iterator to the start of the inserted range. +template +typename std::vector::iterator +AddPowers(std::vector* dst, T lo, T hi, int mult) { + CHECK_GE(lo, 0); + CHECK_GE(hi, lo); + CHECK_GE(mult, 2); + + const size_t start_offset = dst->size(); + + static const T kmax = std::numeric_limits::max(); + + // Space out the values in multiples of "mult" + for (T i = 1; i <= hi; i *= mult) { + if (i >= lo) { + dst->push_back(i); + } + // Break the loop here since multiplying by + // 'mult' would move outside of the range of T + if (i > kmax / mult) break; + } + + return dst->begin() + start_offset; +} + +template +void AddNegatedPowers(std::vector* dst, T lo, T hi, int mult) { + // We negate lo and hi so we require that they cannot be equal to 'min'. + CHECK_GT(lo, std::numeric_limits::min()); + CHECK_GT(hi, std::numeric_limits::min()); + CHECK_GE(hi, lo); + CHECK_LE(hi, 0); + + // Add positive powers, then negate and reverse. + // Casts necessary since small integers get promoted + // to 'int' when negating. + const auto lo_complement = static_cast(-lo); + const auto hi_complement = static_cast(-hi); + + const auto it = AddPowers(dst, hi_complement, lo_complement, mult); + + std::for_each(it, dst->end(), [](T& t) { t *= -1; }); + std::reverse(it, dst->end()); +} + +template +void AddRange(std::vector* dst, T lo, T hi, int mult) { + static_assert(std::is_integral::value && std::is_signed::value, + "Args type must be a signed integer"); + + CHECK_GE(hi, lo); + CHECK_GE(mult, 2); + + // Add "lo" + dst->push_back(lo); + + // Handle lo == hi as a special case, so we then know + // lo < hi and so it is safe to add 1 to lo and subtract 1 + // from hi without falling outside of the range of T. + if (lo == hi) return; + + // Ensure that lo_inner <= hi_inner below. + if (lo + 1 == hi) { + dst->push_back(hi); + return; + } + + // Add all powers of 'mult' in the range [lo+1, hi-1] (inclusive). + const auto lo_inner = static_cast(lo + 1); + const auto hi_inner = static_cast(hi - 1); + + // Insert negative values + if (lo_inner < 0) { + AddNegatedPowers(dst, lo_inner, std::min(hi_inner, T{-1}), mult); + } + + // Treat 0 as a special case (see discussion on #762). + if (lo <= 0 && hi >= 0) { + dst->push_back(0); + } + + // Insert positive values + if (hi_inner > 0) { + AddPowers(dst, std::max(lo_inner, T{1}), hi_inner, mult); + } + + // Add "hi" (if different from last value). + if (hi != dst->back()) { + dst->push_back(hi); + } +} + +} // namespace internal +} // namespace benchmark + +#endif // BENCHMARK_REGISTER_H diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_runner.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_runner.cc new file mode 100644 index 0000000000000000000000000000000000000000..7bc6b6329ef4307411932d5535c57f7e1a7b25d5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_runner.cc @@ -0,0 +1,362 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark_runner.h" +#include "benchmark/benchmark.h" +#include "benchmark_api_internal.h" +#include "internal_macros.h" + +#ifndef BENCHMARK_OS_WINDOWS +#ifndef BENCHMARK_OS_FUCHSIA +#include +#endif +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "check.h" +#include "colorprint.h" +#include "commandlineflags.h" +#include "complexity.h" +#include "counter.h" +#include "internal_macros.h" +#include "log.h" +#include "mutex.h" +#include "re.h" +#include "statistics.h" +#include "string_util.h" +#include "thread_manager.h" +#include "thread_timer.h" + +namespace benchmark { + +namespace internal { + +MemoryManager* memory_manager = nullptr; + +namespace { + +static constexpr IterationCount kMaxIterations = 1000000000; + +BenchmarkReporter::Run CreateRunReport( + const benchmark::internal::BenchmarkInstance& b, + const internal::ThreadManager::Result& results, + IterationCount memory_iterations, + const MemoryManager::Result& memory_result, double seconds, + int64_t repetition_index) { + // Create report about this benchmark run. + BenchmarkReporter::Run report; + + report.run_name = b.name; + report.error_occurred = results.has_error_; + report.error_message = results.error_message_; + report.report_label = results.report_label_; + // This is the total iterations across all threads. + report.iterations = results.iterations; + report.time_unit = b.time_unit; + report.threads = b.threads; + report.repetition_index = repetition_index; + report.repetitions = b.repetitions; + + if (!report.error_occurred) { + if (b.use_manual_time) { + report.real_accumulated_time = results.manual_time_used; + } else { + report.real_accumulated_time = results.real_time_used; + } + report.cpu_accumulated_time = results.cpu_time_used; + report.complexity_n = results.complexity_n; + report.complexity = b.complexity; + report.complexity_lambda = b.complexity_lambda; + report.statistics = b.statistics; + report.counters = results.counters; + + if (memory_iterations > 0) { + report.has_memory_result = true; + report.allocs_per_iter = + memory_iterations ? static_cast(memory_result.num_allocs) / + memory_iterations + : 0; + report.max_bytes_used = memory_result.max_bytes_used; + } + + internal::Finish(&report.counters, results.iterations, seconds, b.threads); + } + return report; +} + +// Execute one thread of benchmark b for the specified number of iterations. +// Adds the stats collected for the thread into *total. +void RunInThread(const BenchmarkInstance* b, IterationCount iters, + int thread_id, ThreadManager* manager) { + internal::ThreadTimer timer( + b->measure_process_cpu_time + ? internal::ThreadTimer::CreateProcessCpuTime() + : internal::ThreadTimer::Create()); + State st = b->Run(iters, thread_id, &timer, manager); + CHECK(st.error_occurred() || st.iterations() >= st.max_iterations) + << "Benchmark returned before State::KeepRunning() returned false!"; + { + MutexLock l(manager->GetBenchmarkMutex()); + internal::ThreadManager::Result& results = manager->results; + results.iterations += st.iterations(); + results.cpu_time_used += timer.cpu_time_used(); + results.real_time_used += timer.real_time_used(); + results.manual_time_used += timer.manual_time_used(); + results.complexity_n += st.complexity_length_n(); + internal::Increment(&results.counters, st.counters); + } + manager->NotifyThreadComplete(); +} + +class BenchmarkRunner { + public: + BenchmarkRunner(const benchmark::internal::BenchmarkInstance& b_, + std::vector* complexity_reports_) + : b(b_), + complexity_reports(*complexity_reports_), + min_time(!IsZero(b.min_time) ? b.min_time : FLAGS_benchmark_min_time), + repeats(b.repetitions != 0 ? b.repetitions + : FLAGS_benchmark_repetitions), + has_explicit_iteration_count(b.iterations != 0), + pool(b.threads - 1), + iters(has_explicit_iteration_count ? b.iterations : 1) { + run_results.display_report_aggregates_only = + (FLAGS_benchmark_report_aggregates_only || + FLAGS_benchmark_display_aggregates_only); + run_results.file_report_aggregates_only = + FLAGS_benchmark_report_aggregates_only; + if (b.aggregation_report_mode != internal::ARM_Unspecified) { + run_results.display_report_aggregates_only = + (b.aggregation_report_mode & + internal::ARM_DisplayReportAggregatesOnly); + run_results.file_report_aggregates_only = + (b.aggregation_report_mode & internal::ARM_FileReportAggregatesOnly); + } + + for (int repetition_num = 0; repetition_num < repeats; repetition_num++) { + DoOneRepetition(repetition_num); + } + + // Calculate additional statistics + run_results.aggregates_only = ComputeStats(run_results.non_aggregates); + + // Maybe calculate complexity report + if ((b.complexity != oNone) && b.last_benchmark_instance) { + auto additional_run_stats = ComputeBigO(complexity_reports); + run_results.aggregates_only.insert(run_results.aggregates_only.end(), + additional_run_stats.begin(), + additional_run_stats.end()); + complexity_reports.clear(); + } + } + + RunResults&& get_results() { return std::move(run_results); } + + private: + RunResults run_results; + + const benchmark::internal::BenchmarkInstance& b; + std::vector& complexity_reports; + + const double min_time; + const int repeats; + const bool has_explicit_iteration_count; + + std::vector pool; + + IterationCount iters; // preserved between repetitions! + // So only the first repetition has to find/calculate it, + // the other repetitions will just use that precomputed iteration count. + + struct IterationResults { + internal::ThreadManager::Result results; + IterationCount iters; + double seconds; + }; + IterationResults DoNIterations() { + VLOG(2) << "Running " << b.name.str() << " for " << iters << "\n"; + + std::unique_ptr manager; + manager.reset(new internal::ThreadManager(b.threads)); + + // Run all but one thread in separate threads + for (std::size_t ti = 0; ti < pool.size(); ++ti) { + pool[ti] = std::thread(&RunInThread, &b, iters, static_cast(ti + 1), + manager.get()); + } + // And run one thread here directly. + // (If we were asked to run just one thread, we don't create new threads.) + // Yes, we need to do this here *after* we start the separate threads. + RunInThread(&b, iters, 0, manager.get()); + + // The main thread has finished. Now let's wait for the other threads. + manager->WaitForAllThreads(); + for (std::thread& thread : pool) thread.join(); + + IterationResults i; + // Acquire the measurements/counters from the manager, UNDER THE LOCK! + { + MutexLock l(manager->GetBenchmarkMutex()); + i.results = manager->results; + } + + // And get rid of the manager. + manager.reset(); + + // Adjust real/manual time stats since they were reported per thread. + i.results.real_time_used /= b.threads; + i.results.manual_time_used /= b.threads; + // If we were measuring whole-process CPU usage, adjust the CPU time too. + if (b.measure_process_cpu_time) i.results.cpu_time_used /= b.threads; + + VLOG(2) << "Ran in " << i.results.cpu_time_used << "/" + << i.results.real_time_used << "\n"; + + // So for how long were we running? + i.iters = iters; + // Base decisions off of real time if requested by this benchmark. + i.seconds = i.results.cpu_time_used; + if (b.use_manual_time) { + i.seconds = i.results.manual_time_used; + } else if (b.use_real_time) { + i.seconds = i.results.real_time_used; + } + + return i; + } + + IterationCount PredictNumItersNeeded(const IterationResults& i) const { + // See how much iterations should be increased by. + // Note: Avoid division by zero with max(seconds, 1ns). + double multiplier = min_time * 1.4 / std::max(i.seconds, 1e-9); + // If our last run was at least 10% of FLAGS_benchmark_min_time then we + // use the multiplier directly. + // Otherwise we use at most 10 times expansion. + // NOTE: When the last run was at least 10% of the min time the max + // expansion should be 14x. + bool is_significant = (i.seconds / min_time) > 0.1; + multiplier = is_significant ? multiplier : std::min(10.0, multiplier); + if (multiplier <= 1.0) multiplier = 2.0; + + // So what seems to be the sufficiently-large iteration count? Round up. + const IterationCount max_next_iters = static_cast( + std::lround(std::max(multiplier * static_cast(i.iters), + static_cast(i.iters) + 1.0))); + // But we do have *some* sanity limits though.. + const IterationCount next_iters = std::min(max_next_iters, kMaxIterations); + + VLOG(3) << "Next iters: " << next_iters << ", " << multiplier << "\n"; + return next_iters; // round up before conversion to integer. + } + + bool ShouldReportIterationResults(const IterationResults& i) const { + // Determine if this run should be reported; + // Either it has run for a sufficient amount of time + // or because an error was reported. + return i.results.has_error_ || + i.iters >= kMaxIterations || // Too many iterations already. + i.seconds >= min_time || // The elapsed time is large enough. + // CPU time is specified but the elapsed real time greatly exceeds + // the minimum time. + // Note that user provided timers are except from this sanity check. + ((i.results.real_time_used >= 5 * min_time) && !b.use_manual_time); + } + + void DoOneRepetition(int64_t repetition_index) { + const bool is_the_first_repetition = repetition_index == 0; + IterationResults i; + + // We *may* be gradually increasing the length (iteration count) + // of the benchmark until we decide the results are significant. + // And once we do, we report those last results and exit. + // Please do note that the if there are repetitions, the iteration count + // is *only* calculated for the *first* repetition, and other repetitions + // simply use that precomputed iteration count. + for (;;) { + i = DoNIterations(); + + // Do we consider the results to be significant? + // If we are doing repetitions, and the first repetition was already done, + // it has calculated the correct iteration time, so we have run that very + // iteration count just now. No need to calculate anything. Just report. + // Else, the normal rules apply. + const bool results_are_significant = !is_the_first_repetition || + has_explicit_iteration_count || + ShouldReportIterationResults(i); + + if (results_are_significant) break; // Good, let's report them! + + // Nope, bad iteration. Let's re-estimate the hopefully-sufficient + // iteration count, and run the benchmark again... + + iters = PredictNumItersNeeded(i); + assert(iters > i.iters && + "if we did more iterations than we want to do the next time, " + "then we should have accepted the current iteration run."); + } + + // Oh, one last thing, we need to also produce the 'memory measurements'.. + MemoryManager::Result memory_result; + IterationCount memory_iterations = 0; + if (memory_manager != nullptr) { + // Only run a few iterations to reduce the impact of one-time + // allocations in benchmarks that are not properly managed. + memory_iterations = std::min(16, iters); + memory_manager->Start(); + std::unique_ptr manager; + manager.reset(new internal::ThreadManager(1)); + RunInThread(&b, memory_iterations, 0, manager.get()); + manager->WaitForAllThreads(); + manager.reset(); + + memory_manager->Stop(&memory_result); + } + + // Ok, now actualy report. + BenchmarkReporter::Run report = + CreateRunReport(b, i.results, memory_iterations, memory_result, + i.seconds, repetition_index); + + if (!report.error_occurred && b.complexity != oNone) + complexity_reports.push_back(report); + + run_results.non_aggregates.push_back(report); + } +}; + +} // end namespace + +RunResults RunBenchmark( + const benchmark::internal::BenchmarkInstance& b, + std::vector* complexity_reports) { + internal::BenchmarkRunner r(b, complexity_reports); + return r.get_results(); +} + +} // end namespace internal + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_runner.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_runner.h new file mode 100644 index 0000000000000000000000000000000000000000..96e8282a11aa88db0a4c16bb66647b1d2b1f398a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/benchmark_runner.h @@ -0,0 +1,51 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_RUNNER_H_ +#define BENCHMARK_RUNNER_H_ + +#include "benchmark_api_internal.h" +#include "internal_macros.h" + +DECLARE_double(benchmark_min_time); + +DECLARE_int32(benchmark_repetitions); + +DECLARE_bool(benchmark_report_aggregates_only); + +DECLARE_bool(benchmark_display_aggregates_only); + +namespace benchmark { + +namespace internal { + +extern MemoryManager* memory_manager; + +struct RunResults { + std::vector non_aggregates; + std::vector aggregates_only; + + bool display_report_aggregates_only = false; + bool file_report_aggregates_only = false; +}; + +RunResults RunBenchmark( + const benchmark::internal::BenchmarkInstance& b, + std::vector* complexity_reports); + +} // namespace internal + +} // end namespace benchmark + +#endif // BENCHMARK_RUNNER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/check.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/check.h new file mode 100644 index 0000000000000000000000000000000000000000..f5f8253f8040d5a5c0490b8d6ce3cfa1badb04b9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/check.h @@ -0,0 +1,82 @@ +#ifndef CHECK_H_ +#define CHECK_H_ + +#include +#include +#include + +#include "internal_macros.h" +#include "log.h" + +namespace benchmark { +namespace internal { + +typedef void(AbortHandlerT)(); + +inline AbortHandlerT*& GetAbortHandler() { + static AbortHandlerT* handler = &std::abort; + return handler; +} + +BENCHMARK_NORETURN inline void CallAbortHandler() { + GetAbortHandler()(); + std::abort(); // fallback to enforce noreturn +} + +// CheckHandler is the class constructed by failing CHECK macros. CheckHandler +// will log information about the failures and abort when it is destructed. +class CheckHandler { + public: + CheckHandler(const char* check, const char* file, const char* func, int line) + : log_(GetErrorLogInstance()) { + log_ << file << ":" << line << ": " << func << ": Check `" << check + << "' failed. "; + } + + LogType& GetLog() { return log_; } + + BENCHMARK_NORETURN ~CheckHandler() BENCHMARK_NOEXCEPT_OP(false) { + log_ << std::endl; + CallAbortHandler(); + } + + CheckHandler& operator=(const CheckHandler&) = delete; + CheckHandler(const CheckHandler&) = delete; + CheckHandler() = delete; + + private: + LogType& log_; +}; + +} // end namespace internal +} // end namespace benchmark + +// The CHECK macro returns a std::ostream object that can have extra information +// written to it. +#ifndef NDEBUG +#define CHECK(b) \ + (b ? ::benchmark::internal::GetNullLogInstance() \ + : ::benchmark::internal::CheckHandler(#b, __FILE__, __func__, __LINE__) \ + .GetLog()) +#else +#define CHECK(b) ::benchmark::internal::GetNullLogInstance() +#endif + +// clang-format off +// preserve whitespacing between operators for alignment +#define CHECK_EQ(a, b) CHECK((a) == (b)) +#define CHECK_NE(a, b) CHECK((a) != (b)) +#define CHECK_GE(a, b) CHECK((a) >= (b)) +#define CHECK_LE(a, b) CHECK((a) <= (b)) +#define CHECK_GT(a, b) CHECK((a) > (b)) +#define CHECK_LT(a, b) CHECK((a) < (b)) + +#define CHECK_FLOAT_EQ(a, b, eps) CHECK(std::fabs((a) - (b)) < (eps)) +#define CHECK_FLOAT_NE(a, b, eps) CHECK(std::fabs((a) - (b)) >= (eps)) +#define CHECK_FLOAT_GE(a, b, eps) CHECK((a) - (b) > -(eps)) +#define CHECK_FLOAT_LE(a, b, eps) CHECK((b) - (a) > -(eps)) +#define CHECK_FLOAT_GT(a, b, eps) CHECK((a) - (b) > (eps)) +#define CHECK_FLOAT_LT(a, b, eps) CHECK((b) - (a) > (eps)) +//clang-format on + +#endif // CHECK_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/colorprint.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/colorprint.cc new file mode 100644 index 0000000000000000000000000000000000000000..fff6a98818b84ba6b63d405ddca5fead8a3a6aeb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/colorprint.cc @@ -0,0 +1,188 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "colorprint.h" + +#include +#include +#include +#include +#include +#include + +#include "check.h" +#include "internal_macros.h" + +#ifdef BENCHMARK_OS_WINDOWS +#include +#include +#else +#include +#endif // BENCHMARK_OS_WINDOWS + +namespace benchmark { +namespace { +#ifdef BENCHMARK_OS_WINDOWS +typedef WORD PlatformColorCode; +#else +typedef const char* PlatformColorCode; +#endif + +PlatformColorCode GetPlatformColorCode(LogColor color) { +#ifdef BENCHMARK_OS_WINDOWS + switch (color) { + case COLOR_RED: + return FOREGROUND_RED; + case COLOR_GREEN: + return FOREGROUND_GREEN; + case COLOR_YELLOW: + return FOREGROUND_RED | FOREGROUND_GREEN; + case COLOR_BLUE: + return FOREGROUND_BLUE; + case COLOR_MAGENTA: + return FOREGROUND_BLUE | FOREGROUND_RED; + case COLOR_CYAN: + return FOREGROUND_BLUE | FOREGROUND_GREEN; + case COLOR_WHITE: // fall through to default + default: + return 0; + } +#else + switch (color) { + case COLOR_RED: + return "1"; + case COLOR_GREEN: + return "2"; + case COLOR_YELLOW: + return "3"; + case COLOR_BLUE: + return "4"; + case COLOR_MAGENTA: + return "5"; + case COLOR_CYAN: + return "6"; + case COLOR_WHITE: + return "7"; + default: + return nullptr; + }; +#endif +} + +} // end namespace + +std::string FormatString(const char* msg, va_list args) { + // we might need a second shot at this, so pre-emptivly make a copy + va_list args_cp; + va_copy(args_cp, args); + + std::size_t size = 256; + char local_buff[256]; + auto ret = vsnprintf(local_buff, size, msg, args_cp); + + va_end(args_cp); + + // currently there is no error handling for failure, so this is hack. + CHECK(ret >= 0); + + if (ret == 0) // handle empty expansion + return {}; + else if (static_cast(ret) < size) + return local_buff; + else { + // we did not provide a long enough buffer on our first attempt. + size = (size_t)ret + 1; // + 1 for the null byte + std::unique_ptr buff(new char[size]); + ret = vsnprintf(buff.get(), size, msg, args); + CHECK(ret > 0 && ((size_t)ret) < size); + return buff.get(); + } +} + +std::string FormatString(const char* msg, ...) { + va_list args; + va_start(args, msg); + auto tmp = FormatString(msg, args); + va_end(args); + return tmp; +} + +void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + ColorPrintf(out, color, fmt, args); + va_end(args); +} + +void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, + va_list args) { +#ifdef BENCHMARK_OS_WINDOWS + ((void)out); // suppress unused warning + + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); + SetConsoleTextAttribute(stdout_handle, + GetPlatformColorCode(color) | FOREGROUND_INTENSITY); + vprintf(fmt, args); + + fflush(stdout); + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + const char* color_code = GetPlatformColorCode(color); + if (color_code) out << FormatString("\033[0;3%sm", color_code); + out << FormatString(fmt, args) << "\033[m"; +#endif +} + +bool IsColorTerminal() { +#if BENCHMARK_OS_WINDOWS + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return 0 != _isatty(_fileno(stdout)); +#else + // On non-Windows platforms, we rely on the TERM variable. This list of + // supported TERM values is copied from Google Test: + // . + const char* const SUPPORTED_TERM_VALUES[] = { + "xterm", "xterm-color", "xterm-256color", + "screen", "screen-256color", "tmux", + "tmux-256color", "rxvt-unicode", "rxvt-unicode-256color", + "linux", "cygwin", + }; + + const char* const term = getenv("TERM"); + + bool term_supports_color = false; + for (const char* candidate : SUPPORTED_TERM_VALUES) { + if (term && 0 == strcmp(term, candidate)) { + term_supports_color = true; + break; + } + } + + return 0 != isatty(fileno(stdout)) && term_supports_color; +#endif // BENCHMARK_OS_WINDOWS +} + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/colorprint.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/colorprint.h new file mode 100644 index 0000000000000000000000000000000000000000..9f6fab9b342268dc7d246aa9e5d265c136e7853a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/colorprint.h @@ -0,0 +1,33 @@ +#ifndef BENCHMARK_COLORPRINT_H_ +#define BENCHMARK_COLORPRINT_H_ + +#include +#include +#include + +namespace benchmark { +enum LogColor { + COLOR_DEFAULT, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE +}; + +std::string FormatString(const char* msg, va_list args); +std::string FormatString(const char* msg, ...); + +void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, + va_list args); +void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...); + +// Returns true if stdout appears to be a terminal that supports colored +// output, false otherwise. +bool IsColorTerminal(); + +} // end namespace benchmark + +#endif // BENCHMARK_COLORPRINT_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/commandlineflags.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/commandlineflags.cc new file mode 100644 index 0000000000000000000000000000000000000000..3380a127a81ee3ca1345fe004c39098d68e3db43 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/commandlineflags.cc @@ -0,0 +1,228 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "commandlineflags.h" + +#include +#include +#include +#include +#include +#include + +namespace benchmark { +namespace { + +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const std::string& src_text, const char* str, int32_t* value) { + // Parses the environment variable as a decimal integer. + char* end = nullptr; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + std::cerr << src_text << " is expected to be a 32-bit integer, " + << "but actually has value \"" << str << "\".\n"; + return false; + } + + // Is the parsed value in the range of an Int32? + const int32_t result = static_cast(long_value); + if (long_value == std::numeric_limits::max() || + long_value == std::numeric_limits::min() || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + std::cerr << src_text << " is expected to be a 32-bit integer, " + << "but actually has value \"" << str << "\", " + << "which overflows.\n"; + return false; + } + + *value = result; + return true; +} + +// Parses 'str' for a double. If successful, writes the result to *value and +// returns true; otherwise leaves *value unchanged and returns false. +bool ParseDouble(const std::string& src_text, const char* str, double* value) { + // Parses the environment variable as a decimal integer. + char* end = nullptr; + const double double_value = strtod(str, &end); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + std::cerr << src_text << " is expected to be a double, " + << "but actually has value \"" << str << "\".\n"; + return false; + } + + *value = double_value; + return true; +} + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "BENCHMARK_FOO" in the open-source version. +static std::string FlagToEnvVar(const char* flag) { + const std::string flag_str(flag); + + std::string env_var; + for (size_t i = 0; i != flag_str.length(); ++i) + env_var += static_cast(::toupper(flag_str.c_str()[i])); + + return "BENCHMARK_" + env_var; +} + +} // namespace + +bool BoolFromEnv(const char* flag, bool default_val) { + const std::string env_var = FlagToEnvVar(flag); + const char* const value_str = getenv(env_var.c_str()); + return value_str == nullptr ? default_val : IsTruthyFlagValue(value_str); +} + +int32_t Int32FromEnv(const char* flag, int32_t default_val) { + const std::string env_var = FlagToEnvVar(flag); + const char* const value_str = getenv(env_var.c_str()); + int32_t value = default_val; + if (value_str == nullptr || + !ParseInt32(std::string("Environment variable ") + env_var, value_str, + &value)) { + return default_val; + } + return value; +} + +double DoubleFromEnv(const char* flag, double default_val) { + const std::string env_var = FlagToEnvVar(flag); + const char* const value_str = getenv(env_var.c_str()); + double value = default_val; + if (value_str == nullptr || + !ParseDouble(std::string("Environment variable ") + env_var, value_str, + &value)) { + return default_val; + } + return value; +} + +const char* StringFromEnv(const char* flag, const char* default_val) { + const std::string env_var = FlagToEnvVar(flag); + const char* const value = getenv(env_var.c_str()); + return value == nullptr ? default_val : value; +} + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or nullptr if the parsing failed. +const char* ParseFlagValue(const char* str, const char* flag, + bool def_optional) { + // str and flag must not be nullptr. + if (str == nullptr || flag == nullptr) return nullptr; + + // The flag must start with "--". + const std::string flag_str = std::string("--") + std::string(flag); + const size_t flag_len = flag_str.length(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) return flag_end; + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return nullptr; + + // Returns the string after "=". + return flag_end + 1; +} + +bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == nullptr) return false; + + // Converts the string value to a bool. + *value = IsTruthyFlagValue(value_str); + return true; +} + +bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == nullptr) return false; + + // Sets *value to the value of the flag. + return ParseInt32(std::string("The value of flag --") + flag, value_str, + value); +} + +bool ParseDoubleFlag(const char* str, const char* flag, double* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == nullptr) return false; + + // Sets *value to the value of the flag. + return ParseDouble(std::string("The value of flag --") + flag, value_str, + value); +} + +bool ParseStringFlag(const char* str, const char* flag, std::string* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == nullptr) return false; + + *value = value_str; + return true; +} + +bool IsFlag(const char* str, const char* flag) { + return (ParseFlagValue(str, flag, true) != nullptr); +} + +bool IsTruthyFlagValue(const std::string& value) { + if (value.size() == 1) { + char v = value[0]; + return isalnum(v) && + !(v == '0' || v == 'f' || v == 'F' || v == 'n' || v == 'N'); + } else if (!value.empty()) { + std::string value_lower(value); + std::transform(value_lower.begin(), value_lower.end(), value_lower.begin(), + [](char c) { return static_cast(::tolower(c)); }); + return !(value_lower == "false" || value_lower == "no" || + value_lower == "off"); + } else + return true; +} + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/commandlineflags.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/commandlineflags.h new file mode 100644 index 0000000000000000000000000000000000000000..3a1f6a8dbc9d05933f6cb2929820236df1f634a6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/commandlineflags.h @@ -0,0 +1,103 @@ +#ifndef BENCHMARK_COMMANDLINEFLAGS_H_ +#define BENCHMARK_COMMANDLINEFLAGS_H_ + +#include +#include + +// Macro for referencing flags. +#define FLAG(name) FLAGS_##name + +// Macros for declaring flags. +#define DECLARE_bool(name) extern bool FLAG(name) +#define DECLARE_int32(name) extern int32_t FLAG(name) +#define DECLARE_double(name) extern double FLAG(name) +#define DECLARE_string(name) extern std::string FLAG(name) + +// Macros for defining flags. +#define DEFINE_bool(name, default_val) \ + bool FLAG(name) = \ + benchmark::BoolFromEnv(#name, default_val) +#define DEFINE_int32(name, default_val) \ + int32_t FLAG(name) = \ + benchmark::Int32FromEnv(#name, default_val) +#define DEFINE_double(name, default_val) \ + double FLAG(name) = \ + benchmark::DoubleFromEnv(#name, default_val) +#define DEFINE_string(name, default_val) \ + std::string FLAG(name) = \ + benchmark::StringFromEnv(#name, default_val) + +namespace benchmark { + +// Parses a bool from the environment variable +// corresponding to the given flag. +// +// If the variable exists, returns IsTruthyFlagValue() value; if not, +// returns the given default value. +bool BoolFromEnv(const char* flag, bool default_val); + +// Parses an Int32 from the environment variable +// corresponding to the given flag. +// +// If the variable exists, returns ParseInt32() value; if not, returns +// the given default value. +int32_t Int32FromEnv(const char* flag, int32_t default_val); + +// Parses an Double from the environment variable +// corresponding to the given flag. +// +// If the variable exists, returns ParseDouble(); if not, returns +// the given default value. +double DoubleFromEnv(const char* flag, double default_val); + +// Parses a string from the environment variable +// corresponding to the given flag. +// +// If variable exists, returns its value; if not, returns +// the given default value. +const char* StringFromEnv(const char* flag, const char* default_val); + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true if it passes IsTruthyValue(). +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseBoolFlag(const char* str, const char* flag, bool* value); + +// Parses a string for an Int32 flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, int32_t* value); + +// Parses a string for a Double flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseDoubleFlag(const char* str, const char* flag, double* value); + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseStringFlag(const char* str, const char* flag, std::string* value); + +// Returns true if the string matches the flag. +bool IsFlag(const char* str, const char* flag); + +// Returns true unless value starts with one of: '0', 'f', 'F', 'n' or 'N', or +// some non-alphanumeric character. Also returns false if the value matches +// one of 'no', 'false', 'off' (case-insensitive). As a special case, also +// returns true if value is the empty string. +bool IsTruthyFlagValue(const std::string& value); + +} // end namespace benchmark + +#endif // BENCHMARK_COMMANDLINEFLAGS_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/complexity.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/complexity.cc new file mode 100644 index 0000000000000000000000000000000000000000..aeed67f0c7075bb7299345cf64e47e4f30a2d27d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/complexity.cc @@ -0,0 +1,238 @@ +// Copyright 2016 Ismael Jimenez Martinez. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Source project : https://github.com/ismaelJimenez/cpp.leastsq +// Adapted to be used with google benchmark + +#include "benchmark/benchmark.h" + +#include +#include +#include "check.h" +#include "complexity.h" + +namespace benchmark { + +// Internal function to calculate the different scalability forms +BigOFunc* FittingCurve(BigO complexity) { + static const double kLog2E = 1.44269504088896340736; + switch (complexity) { + case oN: + return [](IterationCount n) -> double { return static_cast(n); }; + case oNSquared: + return [](IterationCount n) -> double { return std::pow(n, 2); }; + case oNCubed: + return [](IterationCount n) -> double { return std::pow(n, 3); }; + case oLogN: + /* Note: can't use log2 because Android's GNU STL lacks it */ + return + [](IterationCount n) { return kLog2E * log(static_cast(n)); }; + case oNLogN: + /* Note: can't use log2 because Android's GNU STL lacks it */ + return [](IterationCount n) { + return kLog2E * n * log(static_cast(n)); + }; + case o1: + default: + return [](IterationCount) { return 1.0; }; + } +} + +// Function to return an string for the calculated complexity +std::string GetBigOString(BigO complexity) { + switch (complexity) { + case oN: + return "N"; + case oNSquared: + return "N^2"; + case oNCubed: + return "N^3"; + case oLogN: + return "lgN"; + case oNLogN: + return "NlgN"; + case o1: + return "(1)"; + default: + return "f(N)"; + } +} + +// Find the coefficient for the high-order term in the running time, by +// minimizing the sum of squares of relative error, for the fitting curve +// given by the lambda expression. +// - n : Vector containing the size of the benchmark tests. +// - time : Vector containing the times for the benchmark tests. +// - fitting_curve : lambda expression (e.g. [](int64_t n) {return n; };). + +// For a deeper explanation on the algorithm logic, please refer to +// https://en.wikipedia.org/wiki/Least_squares#Least_squares,_regression_analysis_and_statistics + +LeastSq MinimalLeastSq(const std::vector& n, + const std::vector& time, + BigOFunc* fitting_curve) { + double sigma_gn = 0.0; + double sigma_gn_squared = 0.0; + double sigma_time = 0.0; + double sigma_time_gn = 0.0; + + // Calculate least square fitting parameter + for (size_t i = 0; i < n.size(); ++i) { + double gn_i = fitting_curve(n[i]); + sigma_gn += gn_i; + sigma_gn_squared += gn_i * gn_i; + sigma_time += time[i]; + sigma_time_gn += time[i] * gn_i; + } + + LeastSq result; + result.complexity = oLambda; + + // Calculate complexity. + result.coef = sigma_time_gn / sigma_gn_squared; + + // Calculate RMS + double rms = 0.0; + for (size_t i = 0; i < n.size(); ++i) { + double fit = result.coef * fitting_curve(n[i]); + rms += pow((time[i] - fit), 2); + } + + // Normalized RMS by the mean of the observed values + double mean = sigma_time / n.size(); + result.rms = sqrt(rms / n.size()) / mean; + + return result; +} + +// Find the coefficient for the high-order term in the running time, by +// minimizing the sum of squares of relative error. +// - n : Vector containing the size of the benchmark tests. +// - time : Vector containing the times for the benchmark tests. +// - complexity : If different than oAuto, the fitting curve will stick to +// this one. If it is oAuto, it will be calculated the best +// fitting curve. +LeastSq MinimalLeastSq(const std::vector& n, + const std::vector& time, const BigO complexity) { + CHECK_EQ(n.size(), time.size()); + CHECK_GE(n.size(), 2); // Do not compute fitting curve is less than two + // benchmark runs are given + CHECK_NE(complexity, oNone); + + LeastSq best_fit; + + if (complexity == oAuto) { + std::vector fit_curves = {oLogN, oN, oNLogN, oNSquared, oNCubed}; + + // Take o1 as default best fitting curve + best_fit = MinimalLeastSq(n, time, FittingCurve(o1)); + best_fit.complexity = o1; + + // Compute all possible fitting curves and stick to the best one + for (const auto& fit : fit_curves) { + LeastSq current_fit = MinimalLeastSq(n, time, FittingCurve(fit)); + if (current_fit.rms < best_fit.rms) { + best_fit = current_fit; + best_fit.complexity = fit; + } + } + } else { + best_fit = MinimalLeastSq(n, time, FittingCurve(complexity)); + best_fit.complexity = complexity; + } + + return best_fit; +} + +std::vector ComputeBigO( + const std::vector& reports) { + typedef BenchmarkReporter::Run Run; + std::vector results; + + if (reports.size() < 2) return results; + + // Accumulators. + std::vector n; + std::vector real_time; + std::vector cpu_time; + + // Populate the accumulators. + for (const Run& run : reports) { + CHECK_GT(run.complexity_n, 0) << "Did you forget to call SetComplexityN?"; + n.push_back(run.complexity_n); + real_time.push_back(run.real_accumulated_time / run.iterations); + cpu_time.push_back(run.cpu_accumulated_time / run.iterations); + } + + LeastSq result_cpu; + LeastSq result_real; + + if (reports[0].complexity == oLambda) { + result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity_lambda); + result_real = MinimalLeastSq(n, real_time, reports[0].complexity_lambda); + } else { + result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity); + result_real = MinimalLeastSq(n, real_time, result_cpu.complexity); + } + + // Drop the 'args' when reporting complexity. + auto run_name = reports[0].run_name; + run_name.args.clear(); + + // Get the data from the accumulator to BenchmarkReporter::Run's. + Run big_o; + big_o.run_name = run_name; + big_o.run_type = BenchmarkReporter::Run::RT_Aggregate; + big_o.repetitions = reports[0].repetitions; + big_o.repetition_index = Run::no_repetition_index; + big_o.threads = reports[0].threads; + big_o.aggregate_name = "BigO"; + big_o.report_label = reports[0].report_label; + big_o.iterations = 0; + big_o.real_accumulated_time = result_real.coef; + big_o.cpu_accumulated_time = result_cpu.coef; + big_o.report_big_o = true; + big_o.complexity = result_cpu.complexity; + + // All the time results are reported after being multiplied by the + // time unit multiplier. But since RMS is a relative quantity it + // should not be multiplied at all. So, here, we _divide_ it by the + // multiplier so that when it is multiplied later the result is the + // correct one. + double multiplier = GetTimeUnitMultiplier(reports[0].time_unit); + + // Only add label to mean/stddev if it is same for all runs + Run rms; + rms.run_name = run_name; + rms.run_type = BenchmarkReporter::Run::RT_Aggregate; + rms.aggregate_name = "RMS"; + rms.report_label = big_o.report_label; + rms.iterations = 0; + rms.repetition_index = Run::no_repetition_index; + rms.repetitions = reports[0].repetitions; + rms.threads = reports[0].threads; + rms.real_accumulated_time = result_real.rms / multiplier; + rms.cpu_accumulated_time = result_cpu.rms / multiplier; + rms.report_rms = true; + rms.complexity = result_cpu.complexity; + // don't forget to keep the time unit, or we won't be able to + // recover the correct value. + rms.time_unit = reports[0].time_unit; + + results.push_back(big_o); + results.push_back(rms); + return results; +} + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/complexity.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/complexity.h new file mode 100644 index 0000000000000000000000000000000000000000..df29b48d29b4e54c1142dc46fc03380356f6eb49 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/complexity.h @@ -0,0 +1,55 @@ +// Copyright 2016 Ismael Jimenez Martinez. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Source project : https://github.com/ismaelJimenez/cpp.leastsq +// Adapted to be used with google benchmark + +#ifndef COMPLEXITY_H_ +#define COMPLEXITY_H_ + +#include +#include + +#include "benchmark/benchmark.h" + +namespace benchmark { + +// Return a vector containing the bigO and RMS information for the specified +// list of reports. If 'reports.size() < 2' an empty vector is returned. +std::vector ComputeBigO( + const std::vector& reports); + +// This data structure will contain the result returned by MinimalLeastSq +// - coef : Estimated coeficient for the high-order term as +// interpolated from data. +// - rms : Normalized Root Mean Squared Error. +// - complexity : Scalability form (e.g. oN, oNLogN). In case a scalability +// form has been provided to MinimalLeastSq this will return +// the same value. In case BigO::oAuto has been selected, this +// parameter will return the best fitting curve detected. + +struct LeastSq { + LeastSq() : coef(0.0), rms(0.0), complexity(oNone) {} + + double coef; + double rms; + BigO complexity; +}; + +// Function to return an string for the calculated complexity +std::string GetBigOString(BigO complexity); + +} // end namespace benchmark + +#endif // COMPLEXITY_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/console_reporter.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/console_reporter.cc new file mode 100644 index 0000000000000000000000000000000000000000..6fd764525e814b03da44e371fb0987611e987437 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/console_reporter.cc @@ -0,0 +1,177 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "check.h" +#include "colorprint.h" +#include "commandlineflags.h" +#include "complexity.h" +#include "counter.h" +#include "internal_macros.h" +#include "string_util.h" +#include "timers.h" + +namespace benchmark { + +bool ConsoleReporter::ReportContext(const Context& context) { + name_field_width_ = context.name_field_width; + printed_header_ = false; + prev_counters_.clear(); + + PrintBasicContext(&GetErrorStream(), context); + +#ifdef BENCHMARK_OS_WINDOWS + if ((output_options_ & OO_Color) && &std::cout != &GetOutputStream()) { + GetErrorStream() + << "Color printing is only supported for stdout on windows." + " Disabling color printing\n"; + output_options_ = static_cast< OutputOptions >(output_options_ & ~OO_Color); + } +#endif + + return true; +} + +void ConsoleReporter::PrintHeader(const Run& run) { + std::string str = FormatString("%-*s %13s %15s %12s", static_cast(name_field_width_), + "Benchmark", "Time", "CPU", "Iterations"); + if(!run.counters.empty()) { + if(output_options_ & OO_Tabular) { + for(auto const& c : run.counters) { + str += FormatString(" %10s", c.first.c_str()); + } + } else { + str += " UserCounters..."; + } + } + std::string line = std::string(str.length(), '-'); + GetOutputStream() << line << "\n" << str << "\n" << line << "\n"; +} + +void ConsoleReporter::ReportRuns(const std::vector& reports) { + for (const auto& run : reports) { + // print the header: + // --- if none was printed yet + bool print_header = !printed_header_; + // --- or if the format is tabular and this run + // has different fields from the prev header + print_header |= (output_options_ & OO_Tabular) && + (!internal::SameNames(run.counters, prev_counters_)); + if (print_header) { + printed_header_ = true; + prev_counters_ = run.counters; + PrintHeader(run); + } + // As an alternative to printing the headers like this, we could sort + // the benchmarks by header and then print. But this would require + // waiting for the full results before printing, or printing twice. + PrintRunData(run); + } +} + +static void IgnoreColorPrint(std::ostream& out, LogColor, const char* fmt, + ...) { + va_list args; + va_start(args, fmt); + out << FormatString(fmt, args); + va_end(args); +} + + +static std::string FormatTime(double time) { + // Align decimal places... + if (time < 1.0) { + return FormatString("%10.3f", time); + } + if (time < 10.0) { + return FormatString("%10.2f", time); + } + if (time < 100.0) { + return FormatString("%10.1f", time); + } + return FormatString("%10.0f", time); +} + +void ConsoleReporter::PrintRunData(const Run& result) { + typedef void(PrinterFn)(std::ostream&, LogColor, const char*, ...); + auto& Out = GetOutputStream(); + PrinterFn* printer = (output_options_ & OO_Color) ? + (PrinterFn*)ColorPrintf : IgnoreColorPrint; + auto name_color = + (result.report_big_o || result.report_rms) ? COLOR_BLUE : COLOR_GREEN; + printer(Out, name_color, "%-*s ", name_field_width_, + result.benchmark_name().c_str()); + + if (result.error_occurred) { + printer(Out, COLOR_RED, "ERROR OCCURRED: \'%s\'", + result.error_message.c_str()); + printer(Out, COLOR_DEFAULT, "\n"); + return; + } + + const double real_time = result.GetAdjustedRealTime(); + const double cpu_time = result.GetAdjustedCPUTime(); + const std::string real_time_str = FormatTime(real_time); + const std::string cpu_time_str = FormatTime(cpu_time); + + + if (result.report_big_o) { + std::string big_o = GetBigOString(result.complexity); + printer(Out, COLOR_YELLOW, "%10.2f %-4s %10.2f %-4s ", real_time, big_o.c_str(), + cpu_time, big_o.c_str()); + } else if (result.report_rms) { + printer(Out, COLOR_YELLOW, "%10.0f %-4s %10.0f %-4s ", real_time * 100, "%", + cpu_time * 100, "%"); + } else { + const char* timeLabel = GetTimeUnitString(result.time_unit); + printer(Out, COLOR_YELLOW, "%s %-4s %s %-4s ", real_time_str.c_str(), timeLabel, + cpu_time_str.c_str(), timeLabel); + } + + if (!result.report_big_o && !result.report_rms) { + printer(Out, COLOR_CYAN, "%10lld", result.iterations); + } + + for (auto& c : result.counters) { + const std::size_t cNameLen = std::max(std::string::size_type(10), + c.first.length()); + auto const& s = HumanReadableNumber(c.second.value, c.second.oneK); + const char* unit = ""; + if (c.second.flags & Counter::kIsRate) + unit = (c.second.flags & Counter::kInvert) ? "s" : "/s"; + if (output_options_ & OO_Tabular) { + printer(Out, COLOR_DEFAULT, " %*s%s", cNameLen - strlen(unit), s.c_str(), + unit); + } else { + printer(Out, COLOR_DEFAULT, " %s=%s%s", c.first.c_str(), s.c_str(), unit); + } + } + + if (!result.report_label.empty()) { + printer(Out, COLOR_DEFAULT, " %s", result.report_label.c_str()); + } + + printer(Out, COLOR_DEFAULT, "\n"); +} + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/counter.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/counter.cc new file mode 100644 index 0000000000000000000000000000000000000000..cf5b78ee3ac6b461d79a2dc61120851164dc9542 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/counter.cc @@ -0,0 +1,80 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "counter.h" + +namespace benchmark { +namespace internal { + +double Finish(Counter const& c, IterationCount iterations, double cpu_time, + double num_threads) { + double v = c.value; + if (c.flags & Counter::kIsRate) { + v /= cpu_time; + } + if (c.flags & Counter::kAvgThreads) { + v /= num_threads; + } + if (c.flags & Counter::kIsIterationInvariant) { + v *= iterations; + } + if (c.flags & Counter::kAvgIterations) { + v /= iterations; + } + + if (c.flags & Counter::kInvert) { // Invert is *always* last. + v = 1.0 / v; + } + return v; +} + +void Finish(UserCounters* l, IterationCount iterations, double cpu_time, + double num_threads) { + for (auto& c : *l) { + c.second.value = Finish(c.second, iterations, cpu_time, num_threads); + } +} + +void Increment(UserCounters* l, UserCounters const& r) { + // add counters present in both or just in *l + for (auto& c : *l) { + auto it = r.find(c.first); + if (it != r.end()) { + c.second.value = c.second + it->second; + } + } + // add counters present in r, but not in *l + for (auto const& tc : r) { + auto it = l->find(tc.first); + if (it == l->end()) { + (*l)[tc.first] = tc.second; + } + } +} + +bool SameNames(UserCounters const& l, UserCounters const& r) { + if (&l == &r) return true; + if (l.size() != r.size()) { + return false; + } + for (auto const& c : l) { + if (r.find(c.first) == r.end()) { + return false; + } + } + return true; +} + +} // end namespace internal +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/counter.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/counter.h new file mode 100644 index 0000000000000000000000000000000000000000..1f5a58e31f0caf9af6650512fc25ed489c783939 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/counter.h @@ -0,0 +1,32 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_COUNTER_H_ +#define BENCHMARK_COUNTER_H_ + +#include "benchmark/benchmark.h" + +namespace benchmark { + +// these counter-related functions are hidden to reduce API surface. +namespace internal { +void Finish(UserCounters* l, IterationCount iterations, double time, + double num_threads); +void Increment(UserCounters* l, UserCounters const& r); +bool SameNames(UserCounters const& l, UserCounters const& r); +} // end namespace internal + +} // end namespace benchmark + +#endif // BENCHMARK_COUNTER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/csv_reporter.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/csv_reporter.cc new file mode 100644 index 0000000000000000000000000000000000000000..af2c18fc8a6eeb7fa974c2d0eff56dd6c3861ca1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/csv_reporter.cc @@ -0,0 +1,154 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" +#include "complexity.h" + +#include +#include +#include +#include +#include +#include + +#include "check.h" +#include "string_util.h" +#include "timers.h" + +// File format reference: http://edoceo.com/utilitas/csv-file-format. + +namespace benchmark { + +namespace { +std::vector elements = { + "name", "iterations", "real_time", "cpu_time", + "time_unit", "bytes_per_second", "items_per_second", "label", + "error_occurred", "error_message"}; +} // namespace + +std::string CsvEscape(const std::string & s) { + std::string tmp; + tmp.reserve(s.size() + 2); + for (char c : s) { + switch (c) { + case '"' : tmp += "\"\""; break; + default : tmp += c; break; + } + } + return '"' + tmp + '"'; +} + +bool CSVReporter::ReportContext(const Context& context) { + PrintBasicContext(&GetErrorStream(), context); + return true; +} + +void CSVReporter::ReportRuns(const std::vector& reports) { + std::ostream& Out = GetOutputStream(); + + if (!printed_header_) { + // save the names of all the user counters + for (const auto& run : reports) { + for (const auto& cnt : run.counters) { + if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second") + continue; + user_counter_names_.insert(cnt.first); + } + } + + // print the header + for (auto B = elements.begin(); B != elements.end();) { + Out << *B++; + if (B != elements.end()) Out << ","; + } + for (auto B = user_counter_names_.begin(); + B != user_counter_names_.end();) { + Out << ",\"" << *B++ << "\""; + } + Out << "\n"; + + printed_header_ = true; + } else { + // check that all the current counters are saved in the name set + for (const auto& run : reports) { + for (const auto& cnt : run.counters) { + if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second") + continue; + CHECK(user_counter_names_.find(cnt.first) != user_counter_names_.end()) + << "All counters must be present in each run. " + << "Counter named \"" << cnt.first + << "\" was not in a run after being added to the header"; + } + } + } + + // print results for each run + for (const auto& run : reports) { + PrintRunData(run); + } +} + +void CSVReporter::PrintRunData(const Run& run) { + std::ostream& Out = GetOutputStream(); + Out << CsvEscape(run.benchmark_name()) << ","; + if (run.error_occurred) { + Out << std::string(elements.size() - 3, ','); + Out << "true,"; + Out << CsvEscape(run.error_message) << "\n"; + return; + } + + // Do not print iteration on bigO and RMS report + if (!run.report_big_o && !run.report_rms) { + Out << run.iterations; + } + Out << ","; + + Out << run.GetAdjustedRealTime() << ","; + Out << run.GetAdjustedCPUTime() << ","; + + // Do not print timeLabel on bigO and RMS report + if (run.report_big_o) { + Out << GetBigOString(run.complexity); + } else if (!run.report_rms) { + Out << GetTimeUnitString(run.time_unit); + } + Out << ","; + + if (run.counters.find("bytes_per_second") != run.counters.end()) { + Out << run.counters.at("bytes_per_second"); + } + Out << ","; + if (run.counters.find("items_per_second") != run.counters.end()) { + Out << run.counters.at("items_per_second"); + } + Out << ","; + if (!run.report_label.empty()) { + Out << CsvEscape(run.report_label); + } + Out << ",,"; // for error_occurred and error_message + + // Print user counters + for (const auto& ucn : user_counter_names_) { + auto it = run.counters.find(ucn); + if (it == run.counters.end()) { + Out << ","; + } else { + Out << "," << it->second; + } + } + Out << '\n'; +} + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/cycleclock.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/cycleclock.h new file mode 100644 index 0000000000000000000000000000000000000000..179c67cd614a659a2687264c9c98855f4e7aceac --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/cycleclock.h @@ -0,0 +1,206 @@ +// ---------------------------------------------------------------------- +// CycleClock +// A CycleClock tells you the current time in Cycles. The "time" +// is actually time since power-on. This is like time() but doesn't +// involve a system call and is much more precise. +// +// NOTE: Not all cpu/platform/kernel combinations guarantee that this +// clock increments at a constant rate or is synchronized across all logical +// cpus in a system. +// +// If you need the above guarantees, please consider using a different +// API. There are efforts to provide an interface which provides a millisecond +// granularity and implemented as a memory read. A memory read is generally +// cheaper than the CycleClock for many architectures. +// +// Also, in some out of order CPU implementations, the CycleClock is not +// serializing. So if you're trying to count at cycles granularity, your +// data might be inaccurate due to out of order instruction execution. +// ---------------------------------------------------------------------- + +#ifndef BENCHMARK_CYCLECLOCK_H_ +#define BENCHMARK_CYCLECLOCK_H_ + +#include + +#include "benchmark/benchmark.h" +#include "internal_macros.h" + +#if defined(BENCHMARK_OS_MACOSX) +#include +#endif +// For MSVC, we want to use '_asm rdtsc' when possible (since it works +// with even ancient MSVC compilers), and when not possible the +// __rdtsc intrinsic, declared in . Unfortunately, in some +// environments, and have conflicting +// declarations of some other intrinsics, breaking compilation. +// Therefore, we simply declare __rdtsc ourselves. See also +// http://connect.microsoft.com/VisualStudio/feedback/details/262047 +#if defined(COMPILER_MSVC) && !defined(_M_IX86) +extern "C" uint64_t __rdtsc(); +#pragma intrinsic(__rdtsc) +#endif + +#if !defined(BENCHMARK_OS_WINDOWS) || defined(BENCHMARK_OS_MINGW) +#include +#include +#endif + +#ifdef BENCHMARK_OS_EMSCRIPTEN +#include +#endif + +namespace benchmark { +// NOTE: only i386 and x86_64 have been well tested. +// PPC, sparc, alpha, and ia64 are based on +// http://peter.kuscsik.com/wordpress/?p=14 +// with modifications by m3b. See also +// https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h +namespace cycleclock { +// This should return the number of cycles since power-on. Thread-safe. +inline BENCHMARK_ALWAYS_INLINE int64_t Now() { +#if defined(BENCHMARK_OS_MACOSX) + // this goes at the top because we need ALL Macs, regardless of + // architecture, to return the number of "mach time units" that + // have passed since startup. See sysinfo.cc where + // InitializeSystemInfo() sets the supposed cpu clock frequency of + // macs to the number of mach time units per second, not actual + // CPU clock frequency (which can change in the face of CPU + // frequency scaling). Also note that when the Mac sleeps, this + // counter pauses; it does not continue counting, nor does it + // reset to zero. + return mach_absolute_time(); +#elif defined(BENCHMARK_OS_EMSCRIPTEN) + // this goes above x86-specific code because old versions of Emscripten + // define __x86_64__, although they have nothing to do with it. + return static_cast(emscripten_get_now() * 1e+6); +#elif defined(__i386__) + int64_t ret; + __asm__ volatile("rdtsc" : "=A"(ret)); + return ret; +#elif defined(__x86_64__) || defined(__amd64__) + uint64_t low, high; + __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); + return (high << 32) | low; +#elif defined(__powerpc__) || defined(__ppc__) + // This returns a time-base, which is not always precisely a cycle-count. +#if defined(__powerpc64__) || defined(__ppc64__) + int64_t tb; + asm volatile("mfspr %0, 268" : "=r"(tb)); + return tb; +#else + uint32_t tbl, tbu0, tbu1; + asm volatile( + "mftbu %0\n" + "mftbl %1\n" + "mftbu %2" + : "=r"(tbu0), "=r"(tbl), "=r"(tbu1)); + tbl &= -static_cast(tbu0 == tbu1); + // high 32 bits in tbu1; low 32 bits in tbl (tbu0 is no longer needed) + return (static_cast(tbu1) << 32) | tbl; +#endif +#elif defined(__sparc__) + int64_t tick; + asm(".byte 0x83, 0x41, 0x00, 0x00"); + asm("mov %%g1, %0" : "=r"(tick)); + return tick; +#elif defined(__ia64__) + int64_t itc; + asm("mov %0 = ar.itc" : "=r"(itc)); + return itc; +#elif defined(COMPILER_MSVC) && defined(_M_IX86) + // Older MSVC compilers (like 7.x) don't seem to support the + // __rdtsc intrinsic properly, so I prefer to use _asm instead + // when I know it will work. Otherwise, I'll use __rdtsc and hope + // the code is being compiled with a non-ancient compiler. + _asm rdtsc +#elif defined(COMPILER_MSVC) + return __rdtsc(); +#elif defined(BENCHMARK_OS_NACL) + // Native Client validator on x86/x86-64 allows RDTSC instructions, + // and this case is handled above. Native Client validator on ARM + // rejects MRC instructions (used in the ARM-specific sequence below), + // so we handle it here. Portable Native Client compiles to + // architecture-agnostic bytecode, which doesn't provide any + // cycle counter access mnemonics. + + // Native Client does not provide any API to access cycle counter. + // Use clock_gettime(CLOCK_MONOTONIC, ...) instead of gettimeofday + // because is provides nanosecond resolution (which is noticable at + // least for PNaCl modules running on x86 Mac & Linux). + // Initialize to always return 0 if clock_gettime fails. + struct timespec ts = {0, 0}; + clock_gettime(CLOCK_MONOTONIC, &ts); + return static_cast(ts.tv_sec) * 1000000000 + ts.tv_nsec; +#elif defined(__aarch64__) + // System timer of ARMv8 runs at a different frequency than the CPU's. + // The frequency is fixed, typically in the range 1-50MHz. It can be + // read at CNTFRQ special register. We assume the OS has set up + // the virtual timer properly. + int64_t virtual_timer_value; + asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value)); + return virtual_timer_value; +#elif defined(__ARM_ARCH) + // V6 is the earliest arch that has a standard cyclecount + // Native Client validator doesn't allow MRC instructions. +#if (__ARM_ARCH >= 6) + uint32_t pmccntr; + uint32_t pmuseren; + uint32_t pmcntenset; + // Read the user mode perf monitor counter access permissions. + asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); + if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. + asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); + if (pmcntenset & 0x80000000ul) { // Is it counting? + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); + // The counter is set up to count every 64th cycle + return static_cast(pmccntr) * 64; // Should optimize to << 6 + } + } +#endif + struct timeval tv; + gettimeofday(&tv, nullptr); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; +#elif defined(__mips__) + // mips apparently only allows rdtsc for superusers, so we fall + // back to gettimeofday. It's possible clock_gettime would be better. + struct timeval tv; + gettimeofday(&tv, nullptr); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; +#elif defined(__s390__) // Covers both s390 and s390x. + // Return the CPU clock. + uint64_t tsc; + asm("stck %0" : "=Q"(tsc) : : "cc"); + return tsc; +#elif defined(__riscv) // RISC-V + // Use RDCYCLE (and RDCYCLEH on riscv32) +#if __riscv_xlen == 32 + uint32_t cycles_lo, cycles_hi0, cycles_hi1; + // This asm also includes the PowerPC overflow handling strategy, as above. + // Implemented in assembly because Clang insisted on branching. + asm volatile( + "rdcycleh %0\n" + "rdcycle %1\n" + "rdcycleh %2\n" + "sub %0, %0, %2\n" + "seqz %0, %0\n" + "sub %0, zero, %0\n" + "and %1, %1, %0\n" + : "=r"(cycles_hi0), "=r"(cycles_lo), "=r"(cycles_hi1)); + return (static_cast(cycles_hi1) << 32) | cycles_lo; +#else + uint64_t cycles; + asm volatile("rdcycle %0" : "=r"(cycles)); + return cycles; +#endif +#else +// The soft failover to a generic implementation is automatic only for ARM. +// For other platforms the developer is expected to make an attempt to create +// a fast implementation and use generic version if nothing better is available. +#error You need to define CycleTimer for your OS and CPU +#endif +} +} // end namespace cycleclock +} // end namespace benchmark + +#endif // BENCHMARK_CYCLECLOCK_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/internal_macros.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/internal_macros.h new file mode 100644 index 0000000000000000000000000000000000000000..6adf00d0569d5c862ff115008e4d3e5af5481937 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/internal_macros.h @@ -0,0 +1,94 @@ +#ifndef BENCHMARK_INTERNAL_MACROS_H_ +#define BENCHMARK_INTERNAL_MACROS_H_ + +#include "benchmark/benchmark.h" + +/* Needed to detect STL */ +#include + +// clang-format off + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if defined(__clang__) + #if !defined(COMPILER_CLANG) + #define COMPILER_CLANG + #endif +#elif defined(_MSC_VER) + #if !defined(COMPILER_MSVC) + #define COMPILER_MSVC + #endif +#elif defined(__GNUC__) + #if !defined(COMPILER_GCC) + #define COMPILER_GCC + #endif +#endif + +#if __has_feature(cxx_attributes) + #define BENCHMARK_NORETURN [[noreturn]] +#elif defined(__GNUC__) + #define BENCHMARK_NORETURN __attribute__((noreturn)) +#elif defined(COMPILER_MSVC) + #define BENCHMARK_NORETURN __declspec(noreturn) +#else + #define BENCHMARK_NORETURN +#endif + +#if defined(__CYGWIN__) + #define BENCHMARK_OS_CYGWIN 1 +#elif defined(_WIN32) + #define BENCHMARK_OS_WINDOWS 1 + #if defined(__MINGW32__) + #define BENCHMARK_OS_MINGW 1 + #endif +#elif defined(__APPLE__) + #define BENCHMARK_OS_APPLE 1 + #include "TargetConditionals.h" + #if defined(TARGET_OS_MAC) + #define BENCHMARK_OS_MACOSX 1 + #if defined(TARGET_OS_IPHONE) + #define BENCHMARK_OS_IOS 1 + #endif + #endif +#elif defined(__FreeBSD__) + #define BENCHMARK_OS_FREEBSD 1 +#elif defined(__NetBSD__) + #define BENCHMARK_OS_NETBSD 1 +#elif defined(__OpenBSD__) + #define BENCHMARK_OS_OPENBSD 1 +#elif defined(__linux__) + #define BENCHMARK_OS_LINUX 1 +#elif defined(__native_client__) + #define BENCHMARK_OS_NACL 1 +#elif defined(__EMSCRIPTEN__) + #define BENCHMARK_OS_EMSCRIPTEN 1 +#elif defined(__rtems__) + #define BENCHMARK_OS_RTEMS 1 +#elif defined(__Fuchsia__) +#define BENCHMARK_OS_FUCHSIA 1 +#elif defined (__SVR4) && defined (__sun) +#define BENCHMARK_OS_SOLARIS 1 +#elif defined(__QNX__) +#define BENCHMARK_OS_QNX 1 +#endif + +#if defined(__ANDROID__) && defined(__GLIBCXX__) +#define BENCHMARK_STL_ANDROID_GNUSTL 1 +#endif + +#if !__has_feature(cxx_exceptions) && !defined(__cpp_exceptions) \ + && !defined(__EXCEPTIONS) + #define BENCHMARK_HAS_NO_EXCEPTIONS +#endif + +#if defined(COMPILER_CLANG) || defined(COMPILER_GCC) + #define BENCHMARK_MAYBE_UNUSED __attribute__((unused)) +#else + #define BENCHMARK_MAYBE_UNUSED +#endif + +// clang-format on + +#endif // BENCHMARK_INTERNAL_MACROS_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/json_reporter.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/json_reporter.cc new file mode 100644 index 0000000000000000000000000000000000000000..e5f3c352488fae00bc5769ff4735171f88927536 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/json_reporter.cc @@ -0,0 +1,253 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" +#include "complexity.h" + +#include +#include +#include +#include // for setprecision +#include +#include +#include +#include +#include + +#include "string_util.h" +#include "timers.h" + +namespace benchmark { + +namespace { + +std::string StrEscape(const std::string & s) { + std::string tmp; + tmp.reserve(s.size()); + for (char c : s) { + switch (c) { + case '\b': tmp += "\\b"; break; + case '\f': tmp += "\\f"; break; + case '\n': tmp += "\\n"; break; + case '\r': tmp += "\\r"; break; + case '\t': tmp += "\\t"; break; + case '\\': tmp += "\\\\"; break; + case '"' : tmp += "\\\""; break; + default : tmp += c; break; + } + } + return tmp; +} + +std::string FormatKV(std::string const& key, std::string const& value) { + return StrFormat("\"%s\": \"%s\"", StrEscape(key).c_str(), StrEscape(value).c_str()); +} + +std::string FormatKV(std::string const& key, const char* value) { + return StrFormat("\"%s\": \"%s\"", StrEscape(key).c_str(), StrEscape(value).c_str()); +} + +std::string FormatKV(std::string const& key, bool value) { + return StrFormat("\"%s\": %s", StrEscape(key).c_str(), value ? "true" : "false"); +} + +std::string FormatKV(std::string const& key, int64_t value) { + std::stringstream ss; + ss << '"' << StrEscape(key) << "\": " << value; + return ss.str(); +} + +std::string FormatKV(std::string const& key, IterationCount value) { + std::stringstream ss; + ss << '"' << StrEscape(key) << "\": " << value; + return ss.str(); +} + +std::string FormatKV(std::string const& key, double value) { + std::stringstream ss; + ss << '"' << StrEscape(key) << "\": "; + + if (std::isnan(value)) + ss << (value < 0 ? "-" : "") << "NaN"; + else if (std::isinf(value)) + ss << (value < 0 ? "-" : "") << "Infinity"; + else { + const auto max_digits10 = + std::numeric_limits::max_digits10; + const auto max_fractional_digits10 = max_digits10 - 1; + ss << std::scientific << std::setprecision(max_fractional_digits10) + << value; + } + return ss.str(); +} + +int64_t RoundDouble(double v) { return std::lround(v); } + +} // end namespace + +bool JSONReporter::ReportContext(const Context& context) { + std::ostream& out = GetOutputStream(); + + out << "{\n"; + std::string inner_indent(2, ' '); + + // Open context block and print context information. + out << inner_indent << "\"context\": {\n"; + std::string indent(4, ' '); + + std::string walltime_value = LocalDateTimeString(); + out << indent << FormatKV("date", walltime_value) << ",\n"; + + out << indent << FormatKV("host_name", context.sys_info.name) << ",\n"; + + if (Context::executable_name) { + out << indent << FormatKV("executable", Context::executable_name) << ",\n"; + } + + CPUInfo const& info = context.cpu_info; + out << indent << FormatKV("num_cpus", static_cast(info.num_cpus)) + << ",\n"; + out << indent + << FormatKV("mhz_per_cpu", + RoundDouble(info.cycles_per_second / 1000000.0)) + << ",\n"; + out << indent << FormatKV("cpu_scaling_enabled", info.scaling_enabled) + << ",\n"; + + out << indent << "\"caches\": [\n"; + indent = std::string(6, ' '); + std::string cache_indent(8, ' '); + for (size_t i = 0; i < info.caches.size(); ++i) { + auto& CI = info.caches[i]; + out << indent << "{\n"; + out << cache_indent << FormatKV("type", CI.type) << ",\n"; + out << cache_indent << FormatKV("level", static_cast(CI.level)) + << ",\n"; + out << cache_indent + << FormatKV("size", static_cast(CI.size)) << ",\n"; + out << cache_indent + << FormatKV("num_sharing", static_cast(CI.num_sharing)) + << "\n"; + out << indent << "}"; + if (i != info.caches.size() - 1) out << ","; + out << "\n"; + } + indent = std::string(4, ' '); + out << indent << "],\n"; + out << indent << "\"load_avg\": ["; + for (auto it = info.load_avg.begin(); it != info.load_avg.end();) { + out << *it++; + if (it != info.load_avg.end()) out << ","; + } + out << "],\n"; + +#if defined(NDEBUG) + const char build_type[] = "release"; +#else + const char build_type[] = "debug"; +#endif + out << indent << FormatKV("library_build_type", build_type) << "\n"; + // Close context block and open the list of benchmarks. + out << inner_indent << "},\n"; + out << inner_indent << "\"benchmarks\": [\n"; + return true; +} + +void JSONReporter::ReportRuns(std::vector const& reports) { + if (reports.empty()) { + return; + } + std::string indent(4, ' '); + std::ostream& out = GetOutputStream(); + if (!first_report_) { + out << ",\n"; + } + first_report_ = false; + + for (auto it = reports.begin(); it != reports.end(); ++it) { + out << indent << "{\n"; + PrintRunData(*it); + out << indent << '}'; + auto it_cp = it; + if (++it_cp != reports.end()) { + out << ",\n"; + } + } +} + +void JSONReporter::Finalize() { + // Close the list of benchmarks and the top level object. + GetOutputStream() << "\n ]\n}\n"; +} + +void JSONReporter::PrintRunData(Run const& run) { + std::string indent(6, ' '); + std::ostream& out = GetOutputStream(); + out << indent << FormatKV("name", run.benchmark_name()) << ",\n"; + out << indent << FormatKV("run_name", run.run_name.str()) << ",\n"; + out << indent << FormatKV("run_type", [&run]() -> const char* { + switch (run.run_type) { + case BenchmarkReporter::Run::RT_Iteration: + return "iteration"; + case BenchmarkReporter::Run::RT_Aggregate: + return "aggregate"; + } + BENCHMARK_UNREACHABLE(); + }()) << ",\n"; + out << indent << FormatKV("repetitions", run.repetitions) << ",\n"; + if (run.run_type != BenchmarkReporter::Run::RT_Aggregate) { + out << indent << FormatKV("repetition_index", run.repetition_index) + << ",\n"; + } + out << indent << FormatKV("threads", run.threads) << ",\n"; + if (run.run_type == BenchmarkReporter::Run::RT_Aggregate) { + out << indent << FormatKV("aggregate_name", run.aggregate_name) << ",\n"; + } + if (run.error_occurred) { + out << indent << FormatKV("error_occurred", run.error_occurred) << ",\n"; + out << indent << FormatKV("error_message", run.error_message) << ",\n"; + } + if (!run.report_big_o && !run.report_rms) { + out << indent << FormatKV("iterations", run.iterations) << ",\n"; + out << indent << FormatKV("real_time", run.GetAdjustedRealTime()) << ",\n"; + out << indent << FormatKV("cpu_time", run.GetAdjustedCPUTime()); + out << ",\n" + << indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit)); + } else if (run.report_big_o) { + out << indent << FormatKV("cpu_coefficient", run.GetAdjustedCPUTime()) + << ",\n"; + out << indent << FormatKV("real_coefficient", run.GetAdjustedRealTime()) + << ",\n"; + out << indent << FormatKV("big_o", GetBigOString(run.complexity)) << ",\n"; + out << indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit)); + } else if (run.report_rms) { + out << indent << FormatKV("rms", run.GetAdjustedCPUTime()); + } + + for (auto& c : run.counters) { + out << ",\n" << indent << FormatKV(c.first, c.second); + } + + if (run.has_memory_result) { + out << ",\n" << indent << FormatKV("allocs_per_iter", run.allocs_per_iter); + out << ",\n" << indent << FormatKV("max_bytes_used", run.max_bytes_used); + } + + if (!run.report_label.empty()) { + out << ",\n" << indent << FormatKV("label", run.report_label); + } + out << '\n'; +} + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/log.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/log.h new file mode 100644 index 0000000000000000000000000000000000000000..47d0c35c01826dfa0a401f5a90adda6c71c1d8c4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/log.h @@ -0,0 +1,74 @@ +#ifndef BENCHMARK_LOG_H_ +#define BENCHMARK_LOG_H_ + +#include +#include + +#include "benchmark/benchmark.h" + +namespace benchmark { +namespace internal { + +typedef std::basic_ostream&(EndLType)(std::basic_ostream&); + +class LogType { + friend LogType& GetNullLogInstance(); + friend LogType& GetErrorLogInstance(); + + // FIXME: Add locking to output. + template + friend LogType& operator<<(LogType&, Tp const&); + friend LogType& operator<<(LogType&, EndLType*); + + private: + LogType(std::ostream* out) : out_(out) {} + std::ostream* out_; + BENCHMARK_DISALLOW_COPY_AND_ASSIGN(LogType); +}; + +template +LogType& operator<<(LogType& log, Tp const& value) { + if (log.out_) { + *log.out_ << value; + } + return log; +} + +inline LogType& operator<<(LogType& log, EndLType* m) { + if (log.out_) { + *log.out_ << m; + } + return log; +} + +inline int& LogLevel() { + static int log_level = 0; + return log_level; +} + +inline LogType& GetNullLogInstance() { + static LogType log(nullptr); + return log; +} + +inline LogType& GetErrorLogInstance() { + static LogType log(&std::clog); + return log; +} + +inline LogType& GetLogInstanceForLevel(int level) { + if (level <= LogLevel()) { + return GetErrorLogInstance(); + } + return GetNullLogInstance(); +} + +} // end namespace internal +} // end namespace benchmark + +// clang-format off +#define VLOG(x) \ + (::benchmark::internal::GetLogInstanceForLevel(x) << "-- LOG(" << x << "):" \ + " ") +// clang-format on +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/mutex.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/mutex.h new file mode 100644 index 0000000000000000000000000000000000000000..3fac79aea412c0952435aa1a2b1ac9fb82da3d2e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/mutex.h @@ -0,0 +1,155 @@ +#ifndef BENCHMARK_MUTEX_H_ +#define BENCHMARK_MUTEX_H_ + +#include +#include + +#include "check.h" + +// Enable thread safety attributes only with clang. +// The attributes can be safely erased when compiling with other compilers. +#if defined(HAVE_THREAD_SAFETY_ATTRIBUTES) +#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) + +#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) + +#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) + +#define ACQUIRED_BEFORE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) + +#define ACQUIRED_AFTER(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) + +#define REQUIRES(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) + +#define REQUIRES_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) + +#define ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) + +#define ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) + +#define RELEASE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) + +#define RELEASE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) + +#define TRY_ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) + +#define TRY_ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) + +#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) + +#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) + +#define ASSERT_SHARED_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) + +#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +#define NO_THREAD_SAFETY_ANALYSIS \ + THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) + +namespace benchmark { + +typedef std::condition_variable Condition; + +// NOTE: Wrappers for std::mutex and std::unique_lock are provided so that +// we can annotate them with thread safety attributes and use the +// -Wthread-safety warning with clang. The standard library types cannot be +// used directly because they do not provide the required annotations. +class CAPABILITY("mutex") Mutex { + public: + Mutex() {} + + void lock() ACQUIRE() { mut_.lock(); } + void unlock() RELEASE() { mut_.unlock(); } + std::mutex& native_handle() { return mut_; } + + private: + std::mutex mut_; +}; + +class SCOPED_CAPABILITY MutexLock { + typedef std::unique_lock MutexLockImp; + + public: + MutexLock(Mutex& m) ACQUIRE(m) : ml_(m.native_handle()) {} + ~MutexLock() RELEASE() {} + MutexLockImp& native_handle() { return ml_; } + + private: + MutexLockImp ml_; +}; + +class Barrier { + public: + Barrier(int num_threads) : running_threads_(num_threads) {} + + // Called by each thread + bool wait() EXCLUDES(lock_) { + bool last_thread = false; + { + MutexLock ml(lock_); + last_thread = createBarrier(ml); + } + if (last_thread) phase_condition_.notify_all(); + return last_thread; + } + + void removeThread() EXCLUDES(lock_) { + MutexLock ml(lock_); + --running_threads_; + if (entered_ != 0) phase_condition_.notify_all(); + } + + private: + Mutex lock_; + Condition phase_condition_; + int running_threads_; + + // State for barrier management + int phase_number_ = 0; + int entered_ = 0; // Number of threads that have entered this barrier + + // Enter the barrier and wait until all other threads have also + // entered the barrier. Returns iff this is the last thread to + // enter the barrier. + bool createBarrier(MutexLock& ml) REQUIRES(lock_) { + CHECK_LT(entered_, running_threads_); + entered_++; + if (entered_ < running_threads_) { + // Wait for all threads to enter + int phase_number_cp = phase_number_; + auto cb = [this, phase_number_cp]() { + return this->phase_number_ > phase_number_cp || + entered_ == running_threads_; // A thread has aborted in error + }; + phase_condition_.wait(ml.native_handle(), cb); + if (phase_number_ > phase_number_cp) return false; + // else (running_threads_ == entered_) and we are the last thread. + } + // Last thread has reached the barrier + phase_number_++; + entered_ = 0; + return true; + } +}; + +} // end namespace benchmark + +#endif // BENCHMARK_MUTEX_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/re.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/re.h new file mode 100644 index 0000000000000000000000000000000000000000..fbe25037b46386e170dcb0d874a93e8d0260dfe9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/re.h @@ -0,0 +1,158 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef BENCHMARK_RE_H_ +#define BENCHMARK_RE_H_ + +#include "internal_macros.h" + +// clang-format off + +#if !defined(HAVE_STD_REGEX) && \ + !defined(HAVE_GNU_POSIX_REGEX) && \ + !defined(HAVE_POSIX_REGEX) + // No explicit regex selection; detect based on builtin hints. + #if defined(BENCHMARK_OS_LINUX) || defined(BENCHMARK_OS_APPLE) + #define HAVE_POSIX_REGEX 1 + #elif __cplusplus >= 199711L + #define HAVE_STD_REGEX 1 + #endif +#endif + +// Prefer C regex libraries when compiling w/o exceptions so that we can +// correctly report errors. +#if defined(BENCHMARK_HAS_NO_EXCEPTIONS) && \ + defined(BENCHMARK_HAVE_STD_REGEX) && \ + (defined(HAVE_GNU_POSIX_REGEX) || defined(HAVE_POSIX_REGEX)) + #undef HAVE_STD_REGEX +#endif + +#if defined(HAVE_STD_REGEX) + #include +#elif defined(HAVE_GNU_POSIX_REGEX) + #include +#elif defined(HAVE_POSIX_REGEX) + #include +#else +#error No regular expression backend was found! +#endif + +// clang-format on + +#include + +#include "check.h" + +namespace benchmark { + +// A wrapper around the POSIX regular expression API that provides automatic +// cleanup +class Regex { + public: + Regex() : init_(false) {} + + ~Regex(); + + // Compile a regular expression matcher from spec. Returns true on success. + // + // On failure (and if error is not nullptr), error is populated with a human + // readable error message if an error occurs. + bool Init(const std::string& spec, std::string* error); + + // Returns whether str matches the compiled regular expression. + bool Match(const std::string& str); + + private: + bool init_; +// Underlying regular expression object +#if defined(HAVE_STD_REGEX) + std::regex re_; +#elif defined(HAVE_POSIX_REGEX) || defined(HAVE_GNU_POSIX_REGEX) + regex_t re_; +#else +#error No regular expression backend implementation available +#endif +}; + +#if defined(HAVE_STD_REGEX) + +inline bool Regex::Init(const std::string& spec, std::string* error) { +#ifdef BENCHMARK_HAS_NO_EXCEPTIONS + ((void)error); // suppress unused warning +#else + try { +#endif + re_ = std::regex(spec, std::regex_constants::extended); + init_ = true; +#ifndef BENCHMARK_HAS_NO_EXCEPTIONS +} +catch (const std::regex_error& e) { + if (error) { + *error = e.what(); + } +} +#endif +return init_; +} + +inline Regex::~Regex() {} + +inline bool Regex::Match(const std::string& str) { + if (!init_) { + return false; + } + return std::regex_search(str, re_); +} + +#else +inline bool Regex::Init(const std::string& spec, std::string* error) { + int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB); + if (ec != 0) { + if (error) { + size_t needed = regerror(ec, &re_, nullptr, 0); + char* errbuf = new char[needed]; + regerror(ec, &re_, errbuf, needed); + + // regerror returns the number of bytes necessary to null terminate + // the string, so we move that when assigning to error. + CHECK_NE(needed, 0); + error->assign(errbuf, needed - 1); + + delete[] errbuf; + } + + return false; + } + + init_ = true; + return true; +} + +inline Regex::~Regex() { + if (init_) { + regfree(&re_); + } +} + +inline bool Regex::Match(const std::string& str) { + if (!init_) { + return false; + } + return regexec(&re_, str.c_str(), 0, nullptr, 0) == 0; +} +#endif + +} // end namespace benchmark + +#endif // BENCHMARK_RE_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/reporter.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/reporter.cc new file mode 100644 index 0000000000000000000000000000000000000000..0b54fa421adba52d9c6cbb73f1a5cdfce7005a0b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/reporter.cc @@ -0,0 +1,105 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" +#include "timers.h" + +#include + +#include +#include +#include + +#include "check.h" +#include "string_util.h" + +namespace benchmark { + +BenchmarkReporter::BenchmarkReporter() + : output_stream_(&std::cout), error_stream_(&std::cerr) {} + +BenchmarkReporter::~BenchmarkReporter() {} + +void BenchmarkReporter::PrintBasicContext(std::ostream *out, + Context const &context) { + CHECK(out) << "cannot be null"; + auto &Out = *out; + + Out << LocalDateTimeString() << "\n"; + + if (context.executable_name) + Out << "Running " << context.executable_name << "\n"; + + const CPUInfo &info = context.cpu_info; + Out << "Run on (" << info.num_cpus << " X " + << (info.cycles_per_second / 1000000.0) << " MHz CPU " + << ((info.num_cpus > 1) ? "s" : "") << ")\n"; + if (info.caches.size() != 0) { + Out << "CPU Caches:\n"; + for (auto &CInfo : info.caches) { + Out << " L" << CInfo.level << " " << CInfo.type << " " + << (CInfo.size / 1024) << " KiB"; + if (CInfo.num_sharing != 0) + Out << " (x" << (info.num_cpus / CInfo.num_sharing) << ")"; + Out << "\n"; + } + } + if (!info.load_avg.empty()) { + Out << "Load Average: "; + for (auto It = info.load_avg.begin(); It != info.load_avg.end();) { + Out << StrFormat("%.2f", *It++); + if (It != info.load_avg.end()) Out << ", "; + } + Out << "\n"; + } + + if (info.scaling_enabled) { + Out << "***WARNING*** CPU scaling is enabled, the benchmark " + "real time measurements may be noisy and will incur extra " + "overhead.\n"; + } + +#ifndef NDEBUG + Out << "***WARNING*** Library was built as DEBUG. Timings may be " + "affected.\n"; +#endif +} + +// No initializer because it's already initialized to NULL. +const char *BenchmarkReporter::Context::executable_name; + +BenchmarkReporter::Context::Context() + : cpu_info(CPUInfo::Get()), sys_info(SystemInfo::Get()) {} + +std::string BenchmarkReporter::Run::benchmark_name() const { + std::string name = run_name.str(); + if (run_type == RT_Aggregate) { + name += "_" + aggregate_name; + } + return name; +} + +double BenchmarkReporter::Run::GetAdjustedRealTime() const { + double new_time = real_accumulated_time * GetTimeUnitMultiplier(time_unit); + if (iterations != 0) new_time /= static_cast(iterations); + return new_time; +} + +double BenchmarkReporter::Run::GetAdjustedCPUTime() const { + double new_time = cpu_accumulated_time * GetTimeUnitMultiplier(time_unit); + if (iterations != 0) new_time /= static_cast(iterations); + return new_time; +} + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/sleep.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/sleep.cc new file mode 100644 index 0000000000000000000000000000000000000000..1512ac90f7eadfce7e75af9cc19b158841a844db --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/sleep.cc @@ -0,0 +1,51 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sleep.h" + +#include +#include +#include + +#include "internal_macros.h" + +#ifdef BENCHMARK_OS_WINDOWS +#include +#endif + +namespace benchmark { +#ifdef BENCHMARK_OS_WINDOWS +// Window's Sleep takes milliseconds argument. +void SleepForMilliseconds(int milliseconds) { Sleep(milliseconds); } +void SleepForSeconds(double seconds) { + SleepForMilliseconds(static_cast(kNumMillisPerSecond * seconds)); +} +#else // BENCHMARK_OS_WINDOWS +void SleepForMicroseconds(int microseconds) { + struct timespec sleep_time; + sleep_time.tv_sec = microseconds / kNumMicrosPerSecond; + sleep_time.tv_nsec = (microseconds % kNumMicrosPerSecond) * kNumNanosPerMicro; + while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) + ; // Ignore signals and wait for the full interval to elapse. +} + +void SleepForMilliseconds(int milliseconds) { + SleepForMicroseconds(milliseconds * kNumMicrosPerMilli); +} + +void SleepForSeconds(double seconds) { + SleepForMicroseconds(static_cast(seconds * kNumMicrosPerSecond)); +} +#endif // BENCHMARK_OS_WINDOWS +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/sleep.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/sleep.h new file mode 100644 index 0000000000000000000000000000000000000000..f98551afe28491f41077dbfaa2b526231061968b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/sleep.h @@ -0,0 +1,15 @@ +#ifndef BENCHMARK_SLEEP_H_ +#define BENCHMARK_SLEEP_H_ + +namespace benchmark { +const int kNumMillisPerSecond = 1000; +const int kNumMicrosPerMilli = 1000; +const int kNumMicrosPerSecond = kNumMillisPerSecond * 1000; +const int kNumNanosPerMicro = 1000; +const int kNumNanosPerSecond = kNumNanosPerMicro * kNumMicrosPerSecond; + +void SleepForMilliseconds(int milliseconds); +void SleepForSeconds(double seconds); +} // end namespace benchmark + +#endif // BENCHMARK_SLEEP_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/statistics.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/statistics.cc new file mode 100644 index 0000000000000000000000000000000000000000..bd5a3d659725ddfea73425b13ebc8f478e2c22cd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/statistics.cc @@ -0,0 +1,193 @@ +// Copyright 2016 Ismael Jimenez Martinez. All rights reserved. +// Copyright 2017 Roman Lebedev. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "benchmark/benchmark.h" + +#include +#include +#include +#include +#include +#include "check.h" +#include "statistics.h" + +namespace benchmark { + +auto StatisticsSum = [](const std::vector& v) { + return std::accumulate(v.begin(), v.end(), 0.0); +}; + +double StatisticsMean(const std::vector& v) { + if (v.empty()) return 0.0; + return StatisticsSum(v) * (1.0 / v.size()); +} + +double StatisticsMedian(const std::vector& v) { + if (v.size() < 3) return StatisticsMean(v); + std::vector copy(v); + + auto center = copy.begin() + v.size() / 2; + std::nth_element(copy.begin(), center, copy.end()); + + // did we have an odd number of samples? + // if yes, then center is the median + // it no, then we are looking for the average between center and the value + // before + if (v.size() % 2 == 1) return *center; + auto center2 = copy.begin() + v.size() / 2 - 1; + std::nth_element(copy.begin(), center2, copy.end()); + return (*center + *center2) / 2.0; +} + +// Return the sum of the squares of this sample set +auto SumSquares = [](const std::vector& v) { + return std::inner_product(v.begin(), v.end(), v.begin(), 0.0); +}; + +auto Sqr = [](const double dat) { return dat * dat; }; +auto Sqrt = [](const double dat) { + // Avoid NaN due to imprecision in the calculations + if (dat < 0.0) return 0.0; + return std::sqrt(dat); +}; + +double StatisticsStdDev(const std::vector& v) { + const auto mean = StatisticsMean(v); + if (v.empty()) return mean; + + // Sample standard deviation is undefined for n = 1 + if (v.size() == 1) return 0.0; + + const double avg_squares = SumSquares(v) * (1.0 / v.size()); + return Sqrt(v.size() / (v.size() - 1.0) * (avg_squares - Sqr(mean))); +} + +std::vector ComputeStats( + const std::vector& reports) { + typedef BenchmarkReporter::Run Run; + std::vector results; + + auto error_count = + std::count_if(reports.begin(), reports.end(), + [](Run const& run) { return run.error_occurred; }); + + if (reports.size() - error_count < 2) { + // We don't report aggregated data if there was a single run. + return results; + } + + // Accumulators. + std::vector real_accumulated_time_stat; + std::vector cpu_accumulated_time_stat; + + real_accumulated_time_stat.reserve(reports.size()); + cpu_accumulated_time_stat.reserve(reports.size()); + + // All repetitions should be run with the same number of iterations so we + // can take this information from the first benchmark. + const IterationCount run_iterations = reports.front().iterations; + // create stats for user counters + struct CounterStat { + Counter c; + std::vector s; + }; + std::map counter_stats; + for (Run const& r : reports) { + for (auto const& cnt : r.counters) { + auto it = counter_stats.find(cnt.first); + if (it == counter_stats.end()) { + counter_stats.insert({cnt.first, {cnt.second, std::vector{}}}); + it = counter_stats.find(cnt.first); + it->second.s.reserve(reports.size()); + } else { + CHECK_EQ(counter_stats[cnt.first].c.flags, cnt.second.flags); + } + } + } + + // Populate the accumulators. + for (Run const& run : reports) { + CHECK_EQ(reports[0].benchmark_name(), run.benchmark_name()); + CHECK_EQ(run_iterations, run.iterations); + if (run.error_occurred) continue; + real_accumulated_time_stat.emplace_back(run.real_accumulated_time); + cpu_accumulated_time_stat.emplace_back(run.cpu_accumulated_time); + // user counters + for (auto const& cnt : run.counters) { + auto it = counter_stats.find(cnt.first); + CHECK_NE(it, counter_stats.end()); + it->second.s.emplace_back(cnt.second); + } + } + + // Only add label if it is same for all runs + std::string report_label = reports[0].report_label; + for (std::size_t i = 1; i < reports.size(); i++) { + if (reports[i].report_label != report_label) { + report_label = ""; + break; + } + } + + const double iteration_rescale_factor = + double(reports.size()) / double(run_iterations); + + for (const auto& Stat : *reports[0].statistics) { + // Get the data from the accumulator to BenchmarkReporter::Run's. + Run data; + data.run_name = reports[0].run_name; + data.run_type = BenchmarkReporter::Run::RT_Aggregate; + data.threads = reports[0].threads; + data.repetitions = reports[0].repetitions; + data.repetition_index = Run::no_repetition_index; + data.aggregate_name = Stat.name_; + data.report_label = report_label; + + // It is incorrect to say that an aggregate is computed over + // run's iterations, because those iterations already got averaged. + // Similarly, if there are N repetitions with 1 iterations each, + // an aggregate will be computed over N measurements, not 1. + // Thus it is best to simply use the count of separate reports. + data.iterations = reports.size(); + + data.real_accumulated_time = Stat.compute_(real_accumulated_time_stat); + data.cpu_accumulated_time = Stat.compute_(cpu_accumulated_time_stat); + + // We will divide these times by data.iterations when reporting, but the + // data.iterations is not nessesairly the scale of these measurements, + // because in each repetition, these timers are sum over all the iterations. + // And if we want to say that the stats are over N repetitions and not + // M iterations, we need to multiply these by (N/M). + data.real_accumulated_time *= iteration_rescale_factor; + data.cpu_accumulated_time *= iteration_rescale_factor; + + data.time_unit = reports[0].time_unit; + + // user counters + for (auto const& kv : counter_stats) { + // Do *NOT* rescale the custom counters. They are already properly scaled. + const auto uc_stat = Stat.compute_(kv.second.s); + auto c = Counter(uc_stat, counter_stats[kv.first].c.flags, + counter_stats[kv.first].c.oneK); + data.counters[kv.first] = c; + } + + results.push_back(data); + } + + return results; +} + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/statistics.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/statistics.h new file mode 100644 index 0000000000000000000000000000000000000000..7eccc85536a5f0d25fc014da196375d6f3888429 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/statistics.h @@ -0,0 +1,37 @@ +// Copyright 2016 Ismael Jimenez Martinez. All rights reserved. +// Copyright 2017 Roman Lebedev. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef STATISTICS_H_ +#define STATISTICS_H_ + +#include + +#include "benchmark/benchmark.h" + +namespace benchmark { + +// Return a vector containing the mean, median and standard devation information +// (and any user-specified info) for the specified list of reports. If 'reports' +// contains less than two non-errored runs an empty vector is returned +std::vector ComputeStats( + const std::vector& reports); + +double StatisticsMean(const std::vector& v); +double StatisticsMedian(const std::vector& v); +double StatisticsStdDev(const std::vector& v); + +} // end namespace benchmark + +#endif // STATISTICS_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/string_util.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/string_util.cc new file mode 100644 index 0000000000000000000000000000000000000000..ac60b5588f0968ce70a9d3dbb3b352b629fff177 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/string_util.cc @@ -0,0 +1,255 @@ +#include "string_util.h" + +#include +#ifdef BENCHMARK_STL_ANDROID_GNUSTL +#include +#endif +#include +#include +#include +#include +#include + +#include "arraysize.h" + +namespace benchmark { +namespace { + +// kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta. +const char kBigSIUnits[] = "kMGTPEZY"; +// Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi. +const char kBigIECUnits[] = "KMGTPEZY"; +// milli, micro, nano, pico, femto, atto, zepto, yocto. +const char kSmallSIUnits[] = "munpfazy"; + +// We require that all three arrays have the same size. +static_assert(arraysize(kBigSIUnits) == arraysize(kBigIECUnits), + "SI and IEC unit arrays must be the same size"); +static_assert(arraysize(kSmallSIUnits) == arraysize(kBigSIUnits), + "Small SI and Big SI unit arrays must be the same size"); + +static const int64_t kUnitsSize = arraysize(kBigSIUnits); + +void ToExponentAndMantissa(double val, double thresh, int precision, + double one_k, std::string* mantissa, + int64_t* exponent) { + std::stringstream mantissa_stream; + + if (val < 0) { + mantissa_stream << "-"; + val = -val; + } + + // Adjust threshold so that it never excludes things which can't be rendered + // in 'precision' digits. + const double adjusted_threshold = + std::max(thresh, 1.0 / std::pow(10.0, precision)); + const double big_threshold = adjusted_threshold * one_k; + const double small_threshold = adjusted_threshold; + // Values in ]simple_threshold,small_threshold[ will be printed as-is + const double simple_threshold = 0.01; + + if (val > big_threshold) { + // Positive powers + double scaled = val; + for (size_t i = 0; i < arraysize(kBigSIUnits); ++i) { + scaled /= one_k; + if (scaled <= big_threshold) { + mantissa_stream << scaled; + *exponent = i + 1; + *mantissa = mantissa_stream.str(); + return; + } + } + mantissa_stream << val; + *exponent = 0; + } else if (val < small_threshold) { + // Negative powers + if (val < simple_threshold) { + double scaled = val; + for (size_t i = 0; i < arraysize(kSmallSIUnits); ++i) { + scaled *= one_k; + if (scaled >= small_threshold) { + mantissa_stream << scaled; + *exponent = -static_cast(i + 1); + *mantissa = mantissa_stream.str(); + return; + } + } + } + mantissa_stream << val; + *exponent = 0; + } else { + mantissa_stream << val; + *exponent = 0; + } + *mantissa = mantissa_stream.str(); +} + +std::string ExponentToPrefix(int64_t exponent, bool iec) { + if (exponent == 0) return ""; + + const int64_t index = (exponent > 0 ? exponent - 1 : -exponent - 1); + if (index >= kUnitsSize) return ""; + + const char* array = + (exponent > 0 ? (iec ? kBigIECUnits : kBigSIUnits) : kSmallSIUnits); + if (iec) + return array[index] + std::string("i"); + else + return std::string(1, array[index]); +} + +std::string ToBinaryStringFullySpecified(double value, double threshold, + int precision, double one_k = 1024.0) { + std::string mantissa; + int64_t exponent; + ToExponentAndMantissa(value, threshold, precision, one_k, &mantissa, + &exponent); + return mantissa + ExponentToPrefix(exponent, false); +} + +} // end namespace + +void AppendHumanReadable(int n, std::string* str) { + std::stringstream ss; + // Round down to the nearest SI prefix. + ss << ToBinaryStringFullySpecified(n, 1.0, 0); + *str += ss.str(); +} + +std::string HumanReadableNumber(double n, double one_k) { + // 1.1 means that figures up to 1.1k should be shown with the next unit down; + // this softens edge effects. + // 1 means that we should show one decimal place of precision. + return ToBinaryStringFullySpecified(n, 1.1, 1, one_k); +} + +std::string StrFormatImp(const char* msg, va_list args) { + // we might need a second shot at this, so pre-emptivly make a copy + va_list args_cp; + va_copy(args_cp, args); + + // TODO(ericwf): use std::array for first attempt to avoid one memory + // allocation guess what the size might be + std::array local_buff; + std::size_t size = local_buff.size(); + // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation + // in the android-ndk + auto ret = vsnprintf(local_buff.data(), size, msg, args_cp); + + va_end(args_cp); + + // handle empty expansion + if (ret == 0) return std::string{}; + if (static_cast(ret) < size) + return std::string(local_buff.data()); + + // we did not provide a long enough buffer on our first attempt. + // add 1 to size to account for null-byte in size cast to prevent overflow + size = static_cast(ret) + 1; + auto buff_ptr = std::unique_ptr(new char[size]); + // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation + // in the android-ndk + ret = vsnprintf(buff_ptr.get(), size, msg, args); + return std::string(buff_ptr.get()); +} + +std::string StrFormat(const char* format, ...) { + va_list args; + va_start(args, format); + std::string tmp = StrFormatImp(format, args); + va_end(args); + return tmp; +} + +#ifdef BENCHMARK_STL_ANDROID_GNUSTL +/* + * GNU STL in Android NDK lacks support for some C++11 functions, including + * stoul, stoi, stod. We reimplement them here using C functions strtoul, + * strtol, strtod. Note that reimplemented functions are in benchmark:: + * namespace, not std:: namespace. + */ +unsigned long stoul(const std::string& str, size_t* pos, int base) { + /* Record previous errno */ + const int oldErrno = errno; + errno = 0; + + const char* strStart = str.c_str(); + char* strEnd = const_cast(strStart); + const unsigned long result = strtoul(strStart, &strEnd, base); + + const int strtoulErrno = errno; + /* Restore previous errno */ + errno = oldErrno; + + /* Check for errors and return */ + if (strtoulErrno == ERANGE) { + throw std::out_of_range( + "stoul failed: " + str + " is outside of range of unsigned long"); + } else if (strEnd == strStart || strtoulErrno != 0) { + throw std::invalid_argument( + "stoul failed: " + str + " is not an integer"); + } + if (pos != nullptr) { + *pos = static_cast(strEnd - strStart); + } + return result; +} + +int stoi(const std::string& str, size_t* pos, int base) { + /* Record previous errno */ + const int oldErrno = errno; + errno = 0; + + const char* strStart = str.c_str(); + char* strEnd = const_cast(strStart); + const long result = strtol(strStart, &strEnd, base); + + const int strtolErrno = errno; + /* Restore previous errno */ + errno = oldErrno; + + /* Check for errors and return */ + if (strtolErrno == ERANGE || long(int(result)) != result) { + throw std::out_of_range( + "stoul failed: " + str + " is outside of range of int"); + } else if (strEnd == strStart || strtolErrno != 0) { + throw std::invalid_argument( + "stoul failed: " + str + " is not an integer"); + } + if (pos != nullptr) { + *pos = static_cast(strEnd - strStart); + } + return int(result); +} + +double stod(const std::string& str, size_t* pos) { + /* Record previous errno */ + const int oldErrno = errno; + errno = 0; + + const char* strStart = str.c_str(); + char* strEnd = const_cast(strStart); + const double result = strtod(strStart, &strEnd); + + /* Restore previous errno */ + const int strtodErrno = errno; + errno = oldErrno; + + /* Check for errors and return */ + if (strtodErrno == ERANGE) { + throw std::out_of_range( + "stoul failed: " + str + " is outside of range of int"); + } else if (strEnd == strStart || strtodErrno != 0) { + throw std::invalid_argument( + "stoul failed: " + str + " is not an integer"); + } + if (pos != nullptr) { + *pos = static_cast(strEnd - strStart); + } + return result; +} +#endif + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/string_util.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/string_util.h new file mode 100644 index 0000000000000000000000000000000000000000..09d7b4bd2a90f2fc1b27ce03dcf0484b1056e2ca --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/string_util.h @@ -0,0 +1,59 @@ +#ifndef BENCHMARK_STRING_UTIL_H_ +#define BENCHMARK_STRING_UTIL_H_ + +#include +#include +#include +#include "internal_macros.h" + +namespace benchmark { + +void AppendHumanReadable(int n, std::string* str); + +std::string HumanReadableNumber(double n, double one_k = 1024.0); + +#if defined(__MINGW32__) +__attribute__((format(__MINGW_PRINTF_FORMAT, 1, 2))) +#elif defined(__GNUC__) +__attribute__((format(printf, 1, 2))) +#endif +std::string +StrFormat(const char* format, ...); + +inline std::ostream& StrCatImp(std::ostream& out) BENCHMARK_NOEXCEPT { + return out; +} + +template +inline std::ostream& StrCatImp(std::ostream& out, First&& f, Rest&&... rest) { + out << std::forward(f); + return StrCatImp(out, std::forward(rest)...); +} + +template +inline std::string StrCat(Args&&... args) { + std::ostringstream ss; + StrCatImp(ss, std::forward(args)...); + return ss.str(); +} + +#ifdef BENCHMARK_STL_ANDROID_GNUSTL +/* + * GNU STL in Android NDK lacks support for some C++11 functions, including + * stoul, stoi, stod. We reimplement them here using C functions strtoul, + * strtol, strtod. Note that reimplemented functions are in benchmark:: + * namespace, not std:: namespace. + */ +unsigned long stoul(const std::string& str, size_t* pos = nullptr, + int base = 10); +int stoi(const std::string& str, size_t* pos = nullptr, int base = 10); +double stod(const std::string& str, size_t* pos = nullptr); +#else +using std::stoul; +using std::stoi; +using std::stod; +#endif + +} // end namespace benchmark + +#endif // BENCHMARK_STRING_UTIL_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/sysinfo.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/sysinfo.cc new file mode 100644 index 0000000000000000000000000000000000000000..5b7c4af780a5dd7b03df6cb123d81af45988b735 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/sysinfo.cc @@ -0,0 +1,708 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal_macros.h" + +#ifdef BENCHMARK_OS_WINDOWS +#include +#undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA +#include +#include +#include +#else +#include +#ifndef BENCHMARK_OS_FUCHSIA +#include +#endif +#include +#include // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD +#include +#if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX || \ + defined BENCHMARK_OS_NETBSD || defined BENCHMARK_OS_OPENBSD +#define BENCHMARK_HAS_SYSCTL +#include +#endif +#endif +#if defined(BENCHMARK_OS_SOLARIS) +#include +#endif +#if defined(BENCHMARK_OS_QNX) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "check.h" +#include "cycleclock.h" +#include "internal_macros.h" +#include "log.h" +#include "sleep.h" +#include "string_util.h" + +namespace benchmark { +namespace { + +void PrintImp(std::ostream& out) { out << std::endl; } + +template +void PrintImp(std::ostream& out, First&& f, Rest&&... rest) { + out << std::forward(f); + PrintImp(out, std::forward(rest)...); +} + +template +BENCHMARK_NORETURN void PrintErrorAndDie(Args&&... args) { + PrintImp(std::cerr, std::forward(args)...); + std::exit(EXIT_FAILURE); +} + +#ifdef BENCHMARK_HAS_SYSCTL + +/// ValueUnion - A type used to correctly alias the byte-for-byte output of +/// `sysctl` with the result type it's to be interpreted as. +struct ValueUnion { + union DataT { + uint32_t uint32_value; + uint64_t uint64_value; + // For correct aliasing of union members from bytes. + char bytes[8]; + }; + using DataPtr = std::unique_ptr; + + // The size of the data union member + its trailing array size. + size_t Size; + DataPtr Buff; + + public: + ValueUnion() : Size(0), Buff(nullptr, &std::free) {} + + explicit ValueUnion(size_t BuffSize) + : Size(sizeof(DataT) + BuffSize), + Buff(::new (std::malloc(Size)) DataT(), &std::free) {} + + ValueUnion(ValueUnion&& other) = default; + + explicit operator bool() const { return bool(Buff); } + + char* data() const { return Buff->bytes; } + + std::string GetAsString() const { return std::string(data()); } + + int64_t GetAsInteger() const { + if (Size == sizeof(Buff->uint32_value)) + return static_cast(Buff->uint32_value); + else if (Size == sizeof(Buff->uint64_value)) + return static_cast(Buff->uint64_value); + BENCHMARK_UNREACHABLE(); + } + + uint64_t GetAsUnsigned() const { + if (Size == sizeof(Buff->uint32_value)) + return Buff->uint32_value; + else if (Size == sizeof(Buff->uint64_value)) + return Buff->uint64_value; + BENCHMARK_UNREACHABLE(); + } + + template + std::array GetAsArray() { + const int ArrSize = sizeof(T) * N; + CHECK_LE(ArrSize, Size); + std::array Arr; + std::memcpy(Arr.data(), data(), ArrSize); + return Arr; + } +}; + +ValueUnion GetSysctlImp(std::string const& Name) { +#if defined BENCHMARK_OS_OPENBSD + int mib[2]; + + mib[0] = CTL_HW; + if ((Name == "hw.ncpu") || (Name == "hw.cpuspeed")){ + ValueUnion buff(sizeof(int)); + + if (Name == "hw.ncpu") { + mib[1] = HW_NCPU; + } else { + mib[1] = HW_CPUSPEED; + } + + if (sysctl(mib, 2, buff.data(), &buff.Size, nullptr, 0) == -1) { + return ValueUnion(); + } + return buff; + } + return ValueUnion(); +#else + size_t CurBuffSize = 0; + if (sysctlbyname(Name.c_str(), nullptr, &CurBuffSize, nullptr, 0) == -1) + return ValueUnion(); + + ValueUnion buff(CurBuffSize); + if (sysctlbyname(Name.c_str(), buff.data(), &buff.Size, nullptr, 0) == 0) + return buff; + return ValueUnion(); +#endif +} + +BENCHMARK_MAYBE_UNUSED +bool GetSysctl(std::string const& Name, std::string* Out) { + Out->clear(); + auto Buff = GetSysctlImp(Name); + if (!Buff) return false; + Out->assign(Buff.data()); + return true; +} + +template ::value>::type> +bool GetSysctl(std::string const& Name, Tp* Out) { + *Out = 0; + auto Buff = GetSysctlImp(Name); + if (!Buff) return false; + *Out = static_cast(Buff.GetAsUnsigned()); + return true; +} + +template +bool GetSysctl(std::string const& Name, std::array* Out) { + auto Buff = GetSysctlImp(Name); + if (!Buff) return false; + *Out = Buff.GetAsArray(); + return true; +} +#endif + +template +bool ReadFromFile(std::string const& fname, ArgT* arg) { + *arg = ArgT(); + std::ifstream f(fname.c_str()); + if (!f.is_open()) return false; + f >> *arg; + return f.good(); +} + +bool CpuScalingEnabled(int num_cpus) { + // We don't have a valid CPU count, so don't even bother. + if (num_cpus <= 0) return false; +#ifdef BENCHMARK_OS_QNX + return false; +#endif +#ifndef BENCHMARK_OS_WINDOWS + // On Linux, the CPUfreq subsystem exposes CPU information as files on the + // local file system. If reading the exported files fails, then we may not be + // running on Linux, so we silently ignore all the read errors. + std::string res; + for (int cpu = 0; cpu < num_cpus; ++cpu) { + std::string governor_file = + StrCat("/sys/devices/system/cpu/cpu", cpu, "/cpufreq/scaling_governor"); + if (ReadFromFile(governor_file, &res) && res != "performance") return true; + } +#endif + return false; +} + +int CountSetBitsInCPUMap(std::string Val) { + auto CountBits = [](std::string Part) { + using CPUMask = std::bitset; + Part = "0x" + Part; + CPUMask Mask(benchmark::stoul(Part, nullptr, 16)); + return static_cast(Mask.count()); + }; + size_t Pos; + int total = 0; + while ((Pos = Val.find(',')) != std::string::npos) { + total += CountBits(Val.substr(0, Pos)); + Val = Val.substr(Pos + 1); + } + if (!Val.empty()) { + total += CountBits(Val); + } + return total; +} + +BENCHMARK_MAYBE_UNUSED +std::vector GetCacheSizesFromKVFS() { + std::vector res; + std::string dir = "/sys/devices/system/cpu/cpu0/cache/"; + int Idx = 0; + while (true) { + CPUInfo::CacheInfo info; + std::string FPath = StrCat(dir, "index", Idx++, "/"); + std::ifstream f(StrCat(FPath, "size").c_str()); + if (!f.is_open()) break; + std::string suffix; + f >> info.size; + if (f.fail()) + PrintErrorAndDie("Failed while reading file '", FPath, "size'"); + if (f.good()) { + f >> suffix; + if (f.bad()) + PrintErrorAndDie( + "Invalid cache size format: failed to read size suffix"); + else if (f && suffix != "K") + PrintErrorAndDie("Invalid cache size format: Expected bytes ", suffix); + else if (suffix == "K") + info.size *= 1024; + } + if (!ReadFromFile(StrCat(FPath, "type"), &info.type)) + PrintErrorAndDie("Failed to read from file ", FPath, "type"); + if (!ReadFromFile(StrCat(FPath, "level"), &info.level)) + PrintErrorAndDie("Failed to read from file ", FPath, "level"); + std::string map_str; + if (!ReadFromFile(StrCat(FPath, "shared_cpu_map"), &map_str)) + PrintErrorAndDie("Failed to read from file ", FPath, "shared_cpu_map"); + info.num_sharing = CountSetBitsInCPUMap(map_str); + res.push_back(info); + } + + return res; +} + +#ifdef BENCHMARK_OS_MACOSX +std::vector GetCacheSizesMacOSX() { + std::vector res; + std::array CacheCounts{{0, 0, 0, 0}}; + GetSysctl("hw.cacheconfig", &CacheCounts); + + struct { + std::string name; + std::string type; + int level; + uint64_t num_sharing; + } Cases[] = {{"hw.l1dcachesize", "Data", 1, CacheCounts[1]}, + {"hw.l1icachesize", "Instruction", 1, CacheCounts[1]}, + {"hw.l2cachesize", "Unified", 2, CacheCounts[2]}, + {"hw.l3cachesize", "Unified", 3, CacheCounts[3]}}; + for (auto& C : Cases) { + int val; + if (!GetSysctl(C.name, &val)) continue; + CPUInfo::CacheInfo info; + info.type = C.type; + info.level = C.level; + info.size = val; + info.num_sharing = static_cast(C.num_sharing); + res.push_back(std::move(info)); + } + return res; +} +#elif defined(BENCHMARK_OS_WINDOWS) +std::vector GetCacheSizesWindows() { + std::vector res; + DWORD buffer_size = 0; + using PInfo = SYSTEM_LOGICAL_PROCESSOR_INFORMATION; + using CInfo = CACHE_DESCRIPTOR; + + using UPtr = std::unique_ptr; + GetLogicalProcessorInformation(nullptr, &buffer_size); + UPtr buff((PInfo*)malloc(buffer_size), &std::free); + if (!GetLogicalProcessorInformation(buff.get(), &buffer_size)) + PrintErrorAndDie("Failed during call to GetLogicalProcessorInformation: ", + GetLastError()); + + PInfo* it = buff.get(); + PInfo* end = buff.get() + (buffer_size / sizeof(PInfo)); + + for (; it != end; ++it) { + if (it->Relationship != RelationCache) continue; + using BitSet = std::bitset; + BitSet B(it->ProcessorMask); + // To prevent duplicates, only consider caches where CPU 0 is specified + if (!B.test(0)) continue; + CInfo* Cache = &it->Cache; + CPUInfo::CacheInfo C; + C.num_sharing = static_cast(B.count()); + C.level = Cache->Level; + C.size = Cache->Size; + switch (Cache->Type) { + case CacheUnified: + C.type = "Unified"; + break; + case CacheInstruction: + C.type = "Instruction"; + break; + case CacheData: + C.type = "Data"; + break; + case CacheTrace: + C.type = "Trace"; + break; + default: + C.type = "Unknown"; + break; + } + res.push_back(C); + } + return res; +} +#elif BENCHMARK_OS_QNX +std::vector GetCacheSizesQNX() { + std::vector res; + struct cacheattr_entry *cache = SYSPAGE_ENTRY(cacheattr); + uint32_t const elsize = SYSPAGE_ELEMENT_SIZE(cacheattr); + int num = SYSPAGE_ENTRY_SIZE(cacheattr) / elsize ; + for(int i = 0; i < num; ++i ) { + CPUInfo::CacheInfo info; + switch (cache->flags){ + case CACHE_FLAG_INSTR : + info.type = "Instruction"; + info.level = 1; + break; + case CACHE_FLAG_DATA : + info.type = "Data"; + info.level = 1; + break; + case CACHE_FLAG_UNIFIED : + info.type = "Unified"; + info.level = 2; + case CACHE_FLAG_SHARED : + info.type = "Shared"; + info.level = 3; + default : + continue; + break; + } + info.size = cache->line_size * cache->num_lines; + info.num_sharing = 0; + res.push_back(std::move(info)); + cache = SYSPAGE_ARRAY_ADJ_OFFSET(cacheattr, cache, elsize); + } + return res; +} +#endif + +std::vector GetCacheSizes() { +#ifdef BENCHMARK_OS_MACOSX + return GetCacheSizesMacOSX(); +#elif defined(BENCHMARK_OS_WINDOWS) + return GetCacheSizesWindows(); +#elif defined(BENCHMARK_OS_QNX) + return GetCacheSizesQNX(); +#else + return GetCacheSizesFromKVFS(); +#endif +} + +std::string GetSystemName() { +#if defined(BENCHMARK_OS_WINDOWS) + std::string str; + const unsigned COUNT = MAX_COMPUTERNAME_LENGTH+1; + TCHAR hostname[COUNT] = {'\0'}; + DWORD DWCOUNT = COUNT; + if (!GetComputerName(hostname, &DWCOUNT)) + return std::string(""); +#ifndef UNICODE + str = std::string(hostname, DWCOUNT); +#else + //Using wstring_convert, Is deprecated in C++17 + using convert_type = std::codecvt_utf8; + std::wstring_convert converter; + std::wstring wStr(hostname, DWCOUNT); + str = converter.to_bytes(wStr); +#endif + return str; +#else // defined(BENCHMARK_OS_WINDOWS) +#ifndef HOST_NAME_MAX +#ifdef BENCHMARK_HAS_SYSCTL // BSD/Mac Doesnt have HOST_NAME_MAX defined +#define HOST_NAME_MAX 64 +#elif defined(BENCHMARK_OS_NACL) +#define HOST_NAME_MAX 64 +#elif defined(BENCHMARK_OS_QNX) +#define HOST_NAME_MAX 154 +#elif defined(BENCHMARK_OS_RTEMS) +#define HOST_NAME_MAX 256 +#else +#warning "HOST_NAME_MAX not defined. using 64" +#define HOST_NAME_MAX 64 +#endif +#endif // def HOST_NAME_MAX + char hostname[HOST_NAME_MAX]; + int retVal = gethostname(hostname, HOST_NAME_MAX); + if (retVal != 0) return std::string(""); + return std::string(hostname); +#endif // Catch-all POSIX block. +} + +int GetNumCPUs() { +#ifdef BENCHMARK_HAS_SYSCTL + int NumCPU = -1; + if (GetSysctl("hw.ncpu", &NumCPU)) return NumCPU; + fprintf(stderr, "Err: %s\n", strerror(errno)); + std::exit(EXIT_FAILURE); +#elif defined(BENCHMARK_OS_WINDOWS) + SYSTEM_INFO sysinfo; + // Use memset as opposed to = {} to avoid GCC missing initializer false + // positives. + std::memset(&sysinfo, 0, sizeof(SYSTEM_INFO)); + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; // number of logical + // processors in the current + // group +#elif defined(BENCHMARK_OS_SOLARIS) + // Returns -1 in case of a failure. + int NumCPU = sysconf(_SC_NPROCESSORS_ONLN); + if (NumCPU < 0) { + fprintf(stderr, + "sysconf(_SC_NPROCESSORS_ONLN) failed with error: %s\n", + strerror(errno)); + } + return NumCPU; +#elif defined(BENCHMARK_OS_QNX) + return static_cast(_syspage_ptr->num_cpu); +#else + int NumCPUs = 0; + int MaxID = -1; + std::ifstream f("/proc/cpuinfo"); + if (!f.is_open()) { + std::cerr << "failed to open /proc/cpuinfo\n"; + return -1; + } + const std::string Key = "processor"; + std::string ln; + while (std::getline(f, ln)) { + if (ln.empty()) continue; + size_t SplitIdx = ln.find(':'); + std::string value; +#if defined(__s390__) + // s390 has another format in /proc/cpuinfo + // it needs to be parsed differently + if (SplitIdx != std::string::npos) value = ln.substr(Key.size()+1,SplitIdx-Key.size()-1); +#else + if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1); +#endif + if (ln.size() >= Key.size() && ln.compare(0, Key.size(), Key) == 0) { + NumCPUs++; + if (!value.empty()) { + int CurID = benchmark::stoi(value); + MaxID = std::max(CurID, MaxID); + } + } + } + if (f.bad()) { + std::cerr << "Failure reading /proc/cpuinfo\n"; + return -1; + } + if (!f.eof()) { + std::cerr << "Failed to read to end of /proc/cpuinfo\n"; + return -1; + } + f.close(); + + if ((MaxID + 1) != NumCPUs) { + fprintf(stderr, + "CPU ID assignments in /proc/cpuinfo seem messed up." + " This is usually caused by a bad BIOS.\n"); + } + return NumCPUs; +#endif + BENCHMARK_UNREACHABLE(); +} + +double GetCPUCyclesPerSecond() { +#if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN + long freq; + + // If the kernel is exporting the tsc frequency use that. There are issues + // where cpuinfo_max_freq cannot be relied on because the BIOS may be + // exporintg an invalid p-state (on x86) or p-states may be used to put the + // processor in a new mode (turbo mode). Essentially, those frequencies + // cannot always be relied upon. The same reasons apply to /proc/cpuinfo as + // well. + if (ReadFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq) + // If CPU scaling is in effect, we want to use the *maximum* frequency, + // not whatever CPU speed some random processor happens to be using now. + || ReadFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", + &freq)) { + // The value is in kHz (as the file name suggests). For example, on a + // 2GHz warpstation, the file contains the value "2000000". + return freq * 1000.0; + } + + const double error_value = -1; + double bogo_clock = error_value; + + std::ifstream f("/proc/cpuinfo"); + if (!f.is_open()) { + std::cerr << "failed to open /proc/cpuinfo\n"; + return error_value; + } + + auto startsWithKey = [](std::string const& Value, std::string const& Key) { + if (Key.size() > Value.size()) return false; + auto Cmp = [&](char X, char Y) { + return std::tolower(X) == std::tolower(Y); + }; + return std::equal(Key.begin(), Key.end(), Value.begin(), Cmp); + }; + + std::string ln; + while (std::getline(f, ln)) { + if (ln.empty()) continue; + size_t SplitIdx = ln.find(':'); + std::string value; + if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1); + // When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only + // accept positive values. Some environments (virtual machines) report zero, + // which would cause infinite looping in WallTime_Init. + if (startsWithKey(ln, "cpu MHz")) { + if (!value.empty()) { + double cycles_per_second = benchmark::stod(value) * 1000000.0; + if (cycles_per_second > 0) return cycles_per_second; + } + } else if (startsWithKey(ln, "bogomips")) { + if (!value.empty()) { + bogo_clock = benchmark::stod(value) * 1000000.0; + if (bogo_clock < 0.0) bogo_clock = error_value; + } + } + } + if (f.bad()) { + std::cerr << "Failure reading /proc/cpuinfo\n"; + return error_value; + } + if (!f.eof()) { + std::cerr << "Failed to read to end of /proc/cpuinfo\n"; + return error_value; + } + f.close(); + // If we found the bogomips clock, but nothing better, we'll use it (but + // we're not happy about it); otherwise, fallback to the rough estimation + // below. + if (bogo_clock >= 0.0) return bogo_clock; + +#elif defined BENCHMARK_HAS_SYSCTL + constexpr auto* FreqStr = +#if defined(BENCHMARK_OS_FREEBSD) || defined(BENCHMARK_OS_NETBSD) + "machdep.tsc_freq"; +#elif defined BENCHMARK_OS_OPENBSD + "hw.cpuspeed"; +#else + "hw.cpufrequency"; +#endif + unsigned long long hz = 0; +#if defined BENCHMARK_OS_OPENBSD + if (GetSysctl(FreqStr, &hz)) return hz * 1000000; +#else + if (GetSysctl(FreqStr, &hz)) return hz; +#endif + fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n", + FreqStr, strerror(errno)); + +#elif defined BENCHMARK_OS_WINDOWS + // In NT, read MHz from the registry. If we fail to do so or we're in win9x + // then make a crude estimate. + DWORD data, data_size = sizeof(data); + if (IsWindowsXPOrGreater() && + SUCCEEDED( + SHGetValueA(HKEY_LOCAL_MACHINE, + "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", + "~MHz", nullptr, &data, &data_size))) + return static_cast((int64_t)data * + (int64_t)(1000 * 1000)); // was mhz +#elif defined (BENCHMARK_OS_SOLARIS) + kstat_ctl_t *kc = kstat_open(); + if (!kc) { + std::cerr << "failed to open /dev/kstat\n"; + return -1; + } + kstat_t *ksp = kstat_lookup(kc, (char*)"cpu_info", -1, (char*)"cpu_info0"); + if (!ksp) { + std::cerr << "failed to lookup in /dev/kstat\n"; + return -1; + } + if (kstat_read(kc, ksp, NULL) < 0) { + std::cerr << "failed to read from /dev/kstat\n"; + return -1; + } + kstat_named_t *knp = + (kstat_named_t*)kstat_data_lookup(ksp, (char*)"current_clock_Hz"); + if (!knp) { + std::cerr << "failed to lookup data in /dev/kstat\n"; + return -1; + } + if (knp->data_type != KSTAT_DATA_UINT64) { + std::cerr << "current_clock_Hz is of unexpected data type: " + << knp->data_type << "\n"; + return -1; + } + double clock_hz = knp->value.ui64; + kstat_close(kc); + return clock_hz; +#elif defined (BENCHMARK_OS_QNX) + return static_cast((int64_t)(SYSPAGE_ENTRY(cpuinfo)->speed) * + (int64_t)(1000 * 1000)); +#endif + // If we've fallen through, attempt to roughly estimate the CPU clock rate. + const int estimate_time_ms = 1000; + const auto start_ticks = cycleclock::Now(); + SleepForMilliseconds(estimate_time_ms); + return static_cast(cycleclock::Now() - start_ticks); +} + +std::vector GetLoadAvg() { +#if (defined BENCHMARK_OS_FREEBSD || defined(BENCHMARK_OS_LINUX) || \ + defined BENCHMARK_OS_MACOSX || defined BENCHMARK_OS_NETBSD || \ + defined BENCHMARK_OS_OPENBSD) && !defined(__ANDROID__) + constexpr int kMaxSamples = 3; + std::vector res(kMaxSamples, 0.0); + const int nelem = getloadavg(res.data(), kMaxSamples); + if (nelem < 1) { + res.clear(); + } else { + res.resize(nelem); + } + return res; +#else + return {}; +#endif +} + +} // end namespace + +const CPUInfo& CPUInfo::Get() { + static const CPUInfo* info = new CPUInfo(); + return *info; +} + +CPUInfo::CPUInfo() + : num_cpus(GetNumCPUs()), + cycles_per_second(GetCPUCyclesPerSecond()), + caches(GetCacheSizes()), + scaling_enabled(CpuScalingEnabled(num_cpus)), + load_avg(GetLoadAvg()) {} + + +const SystemInfo& SystemInfo::Get() { + static const SystemInfo* info = new SystemInfo(); + return *info; +} + +SystemInfo::SystemInfo() : name(GetSystemName()) {} +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/thread_manager.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/thread_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..28e2dd53aff2c4585ed8e6f894667ad8d239d063 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/thread_manager.h @@ -0,0 +1,64 @@ +#ifndef BENCHMARK_THREAD_MANAGER_H +#define BENCHMARK_THREAD_MANAGER_H + +#include + +#include "benchmark/benchmark.h" +#include "mutex.h" + +namespace benchmark { +namespace internal { + +class ThreadManager { + public: + explicit ThreadManager(int num_threads) + : alive_threads_(num_threads), start_stop_barrier_(num_threads) {} + + Mutex& GetBenchmarkMutex() const RETURN_CAPABILITY(benchmark_mutex_) { + return benchmark_mutex_; + } + + bool StartStopBarrier() EXCLUDES(end_cond_mutex_) { + return start_stop_barrier_.wait(); + } + + void NotifyThreadComplete() EXCLUDES(end_cond_mutex_) { + start_stop_barrier_.removeThread(); + if (--alive_threads_ == 0) { + MutexLock lock(end_cond_mutex_); + end_condition_.notify_all(); + } + } + + void WaitForAllThreads() EXCLUDES(end_cond_mutex_) { + MutexLock lock(end_cond_mutex_); + end_condition_.wait(lock.native_handle(), + [this]() { return alive_threads_ == 0; }); + } + + public: + struct Result { + IterationCount iterations = 0; + double real_time_used = 0; + double cpu_time_used = 0; + double manual_time_used = 0; + int64_t complexity_n = 0; + std::string report_label_; + std::string error_message_; + bool has_error_ = false; + UserCounters counters; + }; + GUARDED_BY(GetBenchmarkMutex()) Result results; + + private: + mutable Mutex benchmark_mutex_; + std::atomic alive_threads_; + Barrier start_stop_barrier_; + Mutex end_cond_mutex_; + Condition end_condition_; +}; + +} // namespace internal +} // namespace benchmark + +#endif // BENCHMARK_THREAD_MANAGER_H diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/thread_timer.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/thread_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..1703ca0d6f877bfbe9249354581f374c3ea1164e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/thread_timer.h @@ -0,0 +1,86 @@ +#ifndef BENCHMARK_THREAD_TIMER_H +#define BENCHMARK_THREAD_TIMER_H + +#include "check.h" +#include "timers.h" + +namespace benchmark { +namespace internal { + +class ThreadTimer { + explicit ThreadTimer(bool measure_process_cpu_time_) + : measure_process_cpu_time(measure_process_cpu_time_) {} + + public: + static ThreadTimer Create() { + return ThreadTimer(/*measure_process_cpu_time_=*/false); + } + static ThreadTimer CreateProcessCpuTime() { + return ThreadTimer(/*measure_process_cpu_time_=*/true); + } + + // Called by each thread + void StartTimer() { + running_ = true; + start_real_time_ = ChronoClockNow(); + start_cpu_time_ = ReadCpuTimerOfChoice(); + } + + // Called by each thread + void StopTimer() { + CHECK(running_); + running_ = false; + real_time_used_ += ChronoClockNow() - start_real_time_; + // Floating point error can result in the subtraction producing a negative + // time. Guard against that. + cpu_time_used_ += + std::max(ReadCpuTimerOfChoice() - start_cpu_time_, 0); + } + + // Called by each thread + void SetIterationTime(double seconds) { manual_time_used_ += seconds; } + + bool running() const { return running_; } + + // REQUIRES: timer is not running + double real_time_used() const { + CHECK(!running_); + return real_time_used_; + } + + // REQUIRES: timer is not running + double cpu_time_used() const { + CHECK(!running_); + return cpu_time_used_; + } + + // REQUIRES: timer is not running + double manual_time_used() const { + CHECK(!running_); + return manual_time_used_; + } + + private: + double ReadCpuTimerOfChoice() const { + if (measure_process_cpu_time) return ProcessCPUUsage(); + return ThreadCPUUsage(); + } + + // should the thread, or the process, time be measured? + const bool measure_process_cpu_time; + + bool running_ = false; // Is the timer running + double start_real_time_ = 0; // If running_ + double start_cpu_time_ = 0; // If running_ + + // Accumulated time so far (does not contain current slice if running_) + double real_time_used_ = 0; + double cpu_time_used_ = 0; + // Manually set iteration time. User sets this with SetIterationTime(seconds). + double manual_time_used_ = 0; +}; + +} // namespace internal +} // namespace benchmark + +#endif // BENCHMARK_THREAD_TIMER_H diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/timers.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/timers.cc new file mode 100644 index 0000000000000000000000000000000000000000..7613ff92c6ef053e9c1388f3b58e0f33033bff49 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/timers.cc @@ -0,0 +1,217 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "timers.h" +#include "internal_macros.h" + +#ifdef BENCHMARK_OS_WINDOWS +#include +#undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA +#include +#include +#else +#include +#ifndef BENCHMARK_OS_FUCHSIA +#include +#endif +#include +#include // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD +#include +#if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX +#include +#endif +#if defined(BENCHMARK_OS_MACOSX) +#include +#include +#include +#endif +#endif + +#ifdef BENCHMARK_OS_EMSCRIPTEN +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "check.h" +#include "log.h" +#include "sleep.h" +#include "string_util.h" + +namespace benchmark { + +// Suppress unused warnings on helper functions. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +namespace { +#if defined(BENCHMARK_OS_WINDOWS) +double MakeTime(FILETIME const& kernel_time, FILETIME const& user_time) { + ULARGE_INTEGER kernel; + ULARGE_INTEGER user; + kernel.HighPart = kernel_time.dwHighDateTime; + kernel.LowPart = kernel_time.dwLowDateTime; + user.HighPart = user_time.dwHighDateTime; + user.LowPart = user_time.dwLowDateTime; + return (static_cast(kernel.QuadPart) + + static_cast(user.QuadPart)) * + 1e-7; +} +#elif !defined(BENCHMARK_OS_FUCHSIA) +double MakeTime(struct rusage const& ru) { + return (static_cast(ru.ru_utime.tv_sec) + + static_cast(ru.ru_utime.tv_usec) * 1e-6 + + static_cast(ru.ru_stime.tv_sec) + + static_cast(ru.ru_stime.tv_usec) * 1e-6); +} +#endif +#if defined(BENCHMARK_OS_MACOSX) +double MakeTime(thread_basic_info_data_t const& info) { + return (static_cast(info.user_time.seconds) + + static_cast(info.user_time.microseconds) * 1e-6 + + static_cast(info.system_time.seconds) + + static_cast(info.system_time.microseconds) * 1e-6); +} +#endif +#if defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_THREAD_CPUTIME_ID) +double MakeTime(struct timespec const& ts) { + return ts.tv_sec + (static_cast(ts.tv_nsec) * 1e-9); +} +#endif + +BENCHMARK_NORETURN static void DiagnoseAndExit(const char* msg) { + std::cerr << "ERROR: " << msg << std::endl; + std::exit(EXIT_FAILURE); +} + +} // end namespace + +double ProcessCPUUsage() { +#if defined(BENCHMARK_OS_WINDOWS) + HANDLE proc = GetCurrentProcess(); + FILETIME creation_time; + FILETIME exit_time; + FILETIME kernel_time; + FILETIME user_time; + if (GetProcessTimes(proc, &creation_time, &exit_time, &kernel_time, + &user_time)) + return MakeTime(kernel_time, user_time); + DiagnoseAndExit("GetProccessTimes() failed"); +#elif defined(BENCHMARK_OS_EMSCRIPTEN) + // clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) returns 0 on Emscripten. + // Use Emscripten-specific API. Reported CPU time would be exactly the + // same as total time, but this is ok because there aren't long-latency + // syncronous system calls in Emscripten. + return emscripten_get_now() * 1e-3; +#elif defined(CLOCK_PROCESS_CPUTIME_ID) && !defined(BENCHMARK_OS_MACOSX) + // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. See + // https://github.com/google/benchmark/pull/292 + struct timespec spec; + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0) + return MakeTime(spec); + DiagnoseAndExit("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) failed"); +#else + struct rusage ru; + if (getrusage(RUSAGE_SELF, &ru) == 0) return MakeTime(ru); + DiagnoseAndExit("getrusage(RUSAGE_SELF, ...) failed"); +#endif +} + +double ThreadCPUUsage() { +#if defined(BENCHMARK_OS_WINDOWS) + HANDLE this_thread = GetCurrentThread(); + FILETIME creation_time; + FILETIME exit_time; + FILETIME kernel_time; + FILETIME user_time; + GetThreadTimes(this_thread, &creation_time, &exit_time, &kernel_time, + &user_time); + return MakeTime(kernel_time, user_time); +#elif defined(BENCHMARK_OS_MACOSX) + // FIXME We want to use clock_gettime, but its not available in MacOS 10.11. See + // https://github.com/google/benchmark/pull/292 + mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; + thread_basic_info_data_t info; + mach_port_t thread = pthread_mach_thread_np(pthread_self()); + if (thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &count) == + KERN_SUCCESS) { + return MakeTime(info); + } + DiagnoseAndExit("ThreadCPUUsage() failed when evaluating thread_info"); +#elif defined(BENCHMARK_OS_EMSCRIPTEN) + // Emscripten doesn't support traditional threads + return ProcessCPUUsage(); +#elif defined(BENCHMARK_OS_RTEMS) + // RTEMS doesn't support CLOCK_THREAD_CPUTIME_ID. See + // https://github.com/RTEMS/rtems/blob/master/cpukit/posix/src/clockgettime.c + return ProcessCPUUsage(); +#elif defined(BENCHMARK_OS_SOLARIS) + struct rusage ru; + if (getrusage(RUSAGE_LWP, &ru) == 0) return MakeTime(ru); + DiagnoseAndExit("getrusage(RUSAGE_LWP, ...) failed"); +#elif defined(CLOCK_THREAD_CPUTIME_ID) + struct timespec ts; + if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) return MakeTime(ts); + DiagnoseAndExit("clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...) failed"); +#else +#error Per-thread timing is not available on your system. +#endif +} + +namespace { + +std::string DateTimeString(bool local) { + typedef std::chrono::system_clock Clock; + std::time_t now = Clock::to_time_t(Clock::now()); + const std::size_t kStorageSize = 128; + char storage[kStorageSize]; + std::size_t written; + + if (local) { +#if defined(BENCHMARK_OS_WINDOWS) + written = + std::strftime(storage, sizeof(storage), "%x %X", ::localtime(&now)); +#else + std::tm timeinfo; + ::localtime_r(&now, &timeinfo); + written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo); +#endif + } else { +#if defined(BENCHMARK_OS_WINDOWS) + written = std::strftime(storage, sizeof(storage), "%x %X", ::gmtime(&now)); +#else + std::tm timeinfo; + ::gmtime_r(&now, &timeinfo); + written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo); +#endif + } + CHECK(written < kStorageSize); + ((void)written); // prevent unused variable in optimized mode. + return std::string(storage); +} + +} // end namespace + +std::string LocalDateTimeString() { return DateTimeString(true); } + +} // end namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/timers.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/timers.h new file mode 100644 index 0000000000000000000000000000000000000000..65606ccd93d14f7bfa50d900c3e6a7a3a52b0c26 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/src/timers.h @@ -0,0 +1,48 @@ +#ifndef BENCHMARK_TIMERS_H +#define BENCHMARK_TIMERS_H + +#include +#include + +namespace benchmark { + +// Return the CPU usage of the current process +double ProcessCPUUsage(); + +// Return the CPU usage of the children of the current process +double ChildrenCPUUsage(); + +// Return the CPU usage of the current thread +double ThreadCPUUsage(); + +#if defined(HAVE_STEADY_CLOCK) +template +struct ChooseSteadyClock { + typedef std::chrono::high_resolution_clock type; +}; + +template <> +struct ChooseSteadyClock { + typedef std::chrono::steady_clock type; +}; +#endif + +struct ChooseClockType { +#if defined(HAVE_STEADY_CLOCK) + typedef ChooseSteadyClock<>::type type; +#else + typedef std::chrono::high_resolution_clock type; +#endif +}; + +inline double ChronoClockNow() { + typedef ChooseClockType::type ClockType; + using FpSeconds = std::chrono::duration; + return FpSeconds(ClockType::now().time_since_epoch()).count(); +} + +std::string LocalDateTimeString(); + +} // end namespace benchmark + +#endif // BENCHMARK_TIMERS_H diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/AssemblyTests.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/AssemblyTests.cmake new file mode 100644 index 0000000000000000000000000000000000000000..3d078586f1de1494650b73447bedd711b1c1c651 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/AssemblyTests.cmake @@ -0,0 +1,46 @@ + +include(split_list) + +set(ASM_TEST_FLAGS "") +check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG) +if (BENCHMARK_HAS_O3_FLAG) + list(APPEND ASM_TEST_FLAGS -O3) +endif() + +check_cxx_compiler_flag(-g0 BENCHMARK_HAS_G0_FLAG) +if (BENCHMARK_HAS_G0_FLAG) + list(APPEND ASM_TEST_FLAGS -g0) +endif() + +check_cxx_compiler_flag(-fno-stack-protector BENCHMARK_HAS_FNO_STACK_PROTECTOR_FLAG) +if (BENCHMARK_HAS_FNO_STACK_PROTECTOR_FLAG) + list(APPEND ASM_TEST_FLAGS -fno-stack-protector) +endif() + +split_list(ASM_TEST_FLAGS) +string(TOUPPER "${CMAKE_CXX_COMPILER_ID}" ASM_TEST_COMPILER) + +macro(add_filecheck_test name) + cmake_parse_arguments(ARG "" "" "CHECK_PREFIXES" ${ARGV}) + add_library(${name} OBJECT ${name}.cc) + set_target_properties(${name} PROPERTIES COMPILE_FLAGS "-S ${ASM_TEST_FLAGS}") + set(ASM_OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${name}.s") + add_custom_target(copy_${name} ALL + COMMAND ${PROJECT_SOURCE_DIR}/tools/strip_asm.py + $ + ${ASM_OUTPUT_FILE} + BYPRODUCTS ${ASM_OUTPUT_FILE}) + add_dependencies(copy_${name} ${name}) + if (NOT ARG_CHECK_PREFIXES) + set(ARG_CHECK_PREFIXES "CHECK") + endif() + foreach(prefix ${ARG_CHECK_PREFIXES}) + add_test(NAME run_${name}_${prefix} + COMMAND + ${LLVM_FILECHECK_EXE} ${name}.cc + --input-file=${ASM_OUTPUT_FILE} + --check-prefixes=CHECK,CHECK-${ASM_TEST_COMPILER} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + endforeach() +endmacro() + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d228b85cbfa4fad1115c51302e135cdd8afa31c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/CMakeLists.txt @@ -0,0 +1,260 @@ +# Enable the tests + +find_package(Threads REQUIRED) +include(CheckCXXCompilerFlag) + +# NOTE: Some tests use `` to perform the test. Therefore we must +# strip -DNDEBUG from the default CMake flags in DEBUG mode. +string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) +if( NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) + add_definitions( -UNDEBUG ) + add_definitions(-DTEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS) + # Also remove /D NDEBUG to avoid MSVC warnings about conflicting defines. + foreach (flags_var_to_scrub + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS_MINSIZEREL) + string (REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " " + "${flags_var_to_scrub}" "${${flags_var_to_scrub}}") + endforeach() +endif() + +check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG) +set(BENCHMARK_O3_FLAG "") +if (BENCHMARK_HAS_O3_FLAG) + set(BENCHMARK_O3_FLAG "-O3") +endif() + +# NOTE: These flags must be added after find_package(Threads REQUIRED) otherwise +# they will break the configuration check. +if (DEFINED BENCHMARK_CXX_LINKER_FLAGS) + list(APPEND CMAKE_EXE_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}) +endif() + +add_library(output_test_helper STATIC output_test_helper.cc output_test.h) + +macro(compile_benchmark_test name) + add_executable(${name} "${name}.cc") + target_link_libraries(${name} benchmark::benchmark ${CMAKE_THREAD_LIBS_INIT}) +endmacro(compile_benchmark_test) + +macro(compile_benchmark_test_with_main name) + add_executable(${name} "${name}.cc") + target_link_libraries(${name} benchmark::benchmark_main) +endmacro(compile_benchmark_test_with_main) + +macro(compile_output_test name) + add_executable(${name} "${name}.cc" output_test.h) + target_link_libraries(${name} output_test_helper benchmark::benchmark + ${BENCHMARK_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +endmacro(compile_output_test) + +# Demonstration executable +compile_benchmark_test(benchmark_test) +add_test(NAME benchmark COMMAND benchmark_test --benchmark_min_time=0.01) + +compile_benchmark_test(filter_test) +macro(add_filter_test name filter expect) + add_test(NAME ${name} COMMAND filter_test --benchmark_min_time=0.01 --benchmark_filter=${filter} ${expect}) + add_test(NAME ${name}_list_only COMMAND filter_test --benchmark_list_tests --benchmark_filter=${filter} ${expect}) +endmacro(add_filter_test) + +add_filter_test(filter_simple "Foo" 3) +add_filter_test(filter_simple_negative "-Foo" 2) +add_filter_test(filter_suffix "BM_.*" 4) +add_filter_test(filter_suffix_negative "-BM_.*" 1) +add_filter_test(filter_regex_all ".*" 5) +add_filter_test(filter_regex_all_negative "-.*" 0) +add_filter_test(filter_regex_blank "" 5) +add_filter_test(filter_regex_blank_negative "-" 0) +add_filter_test(filter_regex_none "monkey" 0) +add_filter_test(filter_regex_none_negative "-monkey" 5) +add_filter_test(filter_regex_wildcard ".*Foo.*" 3) +add_filter_test(filter_regex_wildcard_negative "-.*Foo.*" 2) +add_filter_test(filter_regex_begin "^BM_.*" 4) +add_filter_test(filter_regex_begin_negative "-^BM_.*" 1) +add_filter_test(filter_regex_begin2 "^N" 1) +add_filter_test(filter_regex_begin2_negative "-^N" 4) +add_filter_test(filter_regex_end ".*Ba$" 1) +add_filter_test(filter_regex_end_negative "-.*Ba$" 4) + +compile_benchmark_test(options_test) +add_test(NAME options_benchmarks COMMAND options_test --benchmark_min_time=0.01) + +compile_benchmark_test(basic_test) +add_test(NAME basic_benchmark COMMAND basic_test --benchmark_min_time=0.01) + +compile_benchmark_test(diagnostics_test) +add_test(NAME diagnostics_test COMMAND diagnostics_test --benchmark_min_time=0.01) + +compile_benchmark_test(skip_with_error_test) +add_test(NAME skip_with_error_test COMMAND skip_with_error_test --benchmark_min_time=0.01) + +compile_benchmark_test(donotoptimize_test) +# Some of the issues with DoNotOptimize only occur when optimization is enabled +check_cxx_compiler_flag(-O3 BENCHMARK_HAS_O3_FLAG) +if (BENCHMARK_HAS_O3_FLAG) + set_target_properties(donotoptimize_test PROPERTIES COMPILE_FLAGS "-O3") +endif() +add_test(NAME donotoptimize_test COMMAND donotoptimize_test --benchmark_min_time=0.01) + +compile_benchmark_test(fixture_test) +add_test(NAME fixture_test COMMAND fixture_test --benchmark_min_time=0.01) + +compile_benchmark_test(register_benchmark_test) +add_test(NAME register_benchmark_test COMMAND register_benchmark_test --benchmark_min_time=0.01) + +compile_benchmark_test(map_test) +add_test(NAME map_test COMMAND map_test --benchmark_min_time=0.01) + +compile_benchmark_test(multiple_ranges_test) +add_test(NAME multiple_ranges_test COMMAND multiple_ranges_test --benchmark_min_time=0.01) + +compile_benchmark_test_with_main(link_main_test) +add_test(NAME link_main_test COMMAND link_main_test --benchmark_min_time=0.01) + +compile_output_test(reporter_output_test) +add_test(NAME reporter_output_test COMMAND reporter_output_test --benchmark_min_time=0.01) + +compile_output_test(templated_fixture_test) +add_test(NAME templated_fixture_test COMMAND templated_fixture_test --benchmark_min_time=0.01) + +compile_output_test(user_counters_test) +add_test(NAME user_counters_test COMMAND user_counters_test --benchmark_min_time=0.01) + +compile_output_test(internal_threading_test) +add_test(NAME internal_threading_test COMMAND internal_threading_test --benchmark_min_time=0.01) + +compile_output_test(report_aggregates_only_test) +add_test(NAME report_aggregates_only_test COMMAND report_aggregates_only_test --benchmark_min_time=0.01) + +compile_output_test(display_aggregates_only_test) +add_test(NAME display_aggregates_only_test COMMAND display_aggregates_only_test --benchmark_min_time=0.01) + +compile_output_test(user_counters_tabular_test) +add_test(NAME user_counters_tabular_test COMMAND user_counters_tabular_test --benchmark_counters_tabular=true --benchmark_min_time=0.01) + +compile_output_test(user_counters_thousands_test) +add_test(NAME user_counters_thousands_test COMMAND user_counters_thousands_test --benchmark_min_time=0.01) + +compile_output_test(memory_manager_test) +add_test(NAME memory_manager_test COMMAND memory_manager_test --benchmark_min_time=0.01) + +check_cxx_compiler_flag(-std=c++03 BENCHMARK_HAS_CXX03_FLAG) +if (BENCHMARK_HAS_CXX03_FLAG) + compile_benchmark_test(cxx03_test) + set_target_properties(cxx03_test + PROPERTIES + CXX_STANDARD 98 + CXX_STANDARD_REQUIRED YES) + # libstdc++ provides different definitions within between dialects. When + # LTO is enabled and -Werror is specified GCC diagnoses this ODR violation + # causing the test to fail to compile. To prevent this we explicitly disable + # the warning. + check_cxx_compiler_flag(-Wno-odr BENCHMARK_HAS_WNO_ODR) + if (BENCHMARK_ENABLE_LTO AND BENCHMARK_HAS_WNO_ODR) + set_target_properties(cxx03_test + PROPERTIES + LINK_FLAGS "-Wno-odr") + endif() + add_test(NAME cxx03 COMMAND cxx03_test --benchmark_min_time=0.01) +endif() + +# Attempt to work around flaky test failures when running on Appveyor servers. +if (DEFINED ENV{APPVEYOR}) + set(COMPLEXITY_MIN_TIME "0.5") +else() + set(COMPLEXITY_MIN_TIME "0.01") +endif() +compile_output_test(complexity_test) +add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark_min_time=${COMPLEXITY_MIN_TIME}) + +############################################################################### +# GoogleTest Unit Tests +############################################################################### + +if (BENCHMARK_ENABLE_GTEST_TESTS) + macro(compile_gtest name) + add_executable(${name} "${name}.cc") + target_link_libraries(${name} benchmark::benchmark + gmock_main ${CMAKE_THREAD_LIBS_INIT}) + endmacro(compile_gtest) + + macro(add_gtest name) + compile_gtest(${name}) + add_test(NAME ${name} COMMAND ${name}) + endmacro() + + add_gtest(benchmark_gtest) + add_gtest(benchmark_name_gtest) + add_gtest(commandlineflags_gtest) + add_gtest(statistics_gtest) + add_gtest(string_util_gtest) +endif(BENCHMARK_ENABLE_GTEST_TESTS) + +############################################################################### +# Assembly Unit Tests +############################################################################### + +if (BENCHMARK_ENABLE_ASSEMBLY_TESTS) + if (NOT LLVM_FILECHECK_EXE) + message(FATAL_ERROR "LLVM FileCheck is required when including this file") + endif() + include(AssemblyTests.cmake) + add_filecheck_test(donotoptimize_assembly_test) + add_filecheck_test(state_assembly_test) + add_filecheck_test(clobber_memory_assembly_test) +endif() + + + +############################################################################### +# Code Coverage Configuration +############################################################################### + +# Add the coverage command(s) +if(CMAKE_BUILD_TYPE) + string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER) +endif() +if (${CMAKE_BUILD_TYPE_LOWER} MATCHES "coverage") + find_program(GCOV gcov) + find_program(LCOV lcov) + find_program(GENHTML genhtml) + find_program(CTEST ctest) + if (GCOV AND LCOV AND GENHTML AND CTEST AND HAVE_CXX_FLAG_COVERAGE) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/lcov/index.html + COMMAND ${LCOV} -q -z -d . + COMMAND ${LCOV} -q --no-external -c -b "${CMAKE_SOURCE_DIR}" -d . -o before.lcov -i + COMMAND ${CTEST} --force-new-ctest-process + COMMAND ${LCOV} -q --no-external -c -b "${CMAKE_SOURCE_DIR}" -d . -o after.lcov + COMMAND ${LCOV} -q -a before.lcov -a after.lcov --output-file final.lcov + COMMAND ${LCOV} -q -r final.lcov "'${CMAKE_SOURCE_DIR}/test/*'" -o final.lcov + COMMAND ${GENHTML} final.lcov -o lcov --demangle-cpp --sort -p "${CMAKE_BINARY_DIR}" -t benchmark + DEPENDS filter_test benchmark_test options_test basic_test fixture_test cxx03_test complexity_test + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Running LCOV" + ) + add_custom_target(coverage + DEPENDS ${CMAKE_BINARY_DIR}/lcov/index.html + COMMENT "LCOV report at lcov/index.html" + ) + message(STATUS "Coverage command added") + else() + if (HAVE_CXX_FLAG_COVERAGE) + set(CXX_FLAG_COVERAGE_MESSAGE supported) + else() + set(CXX_FLAG_COVERAGE_MESSAGE unavailable) + endif() + message(WARNING + "Coverage not available:\n" + " gcov: ${GCOV}\n" + " lcov: ${LCOV}\n" + " genhtml: ${GENHTML}\n" + " ctest: ${CTEST}\n" + " --coverage flag: ${CXX_FLAG_COVERAGE_MESSAGE}") + endif() +endif() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/basic_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/basic_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..5f3dd1a3ee94cfabbdbd6508472726fca7517beb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/basic_test.cc @@ -0,0 +1,136 @@ + +#include "benchmark/benchmark.h" + +#define BASIC_BENCHMARK_TEST(x) BENCHMARK(x)->Arg(8)->Arg(512)->Arg(8192) + +void BM_empty(benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize(state.iterations()); + } +} +BENCHMARK(BM_empty); +BENCHMARK(BM_empty)->ThreadPerCpu(); + +void BM_spin_empty(benchmark::State& state) { + for (auto _ : state) { + for (int x = 0; x < state.range(0); ++x) { + benchmark::DoNotOptimize(x); + } + } +} +BASIC_BENCHMARK_TEST(BM_spin_empty); +BASIC_BENCHMARK_TEST(BM_spin_empty)->ThreadPerCpu(); + +void BM_spin_pause_before(benchmark::State& state) { + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + for (auto _ : state) { + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + } +} +BASIC_BENCHMARK_TEST(BM_spin_pause_before); +BASIC_BENCHMARK_TEST(BM_spin_pause_before)->ThreadPerCpu(); + +void BM_spin_pause_during(benchmark::State& state) { + for (auto _ : state) { + state.PauseTiming(); + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + state.ResumeTiming(); + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + } +} +BASIC_BENCHMARK_TEST(BM_spin_pause_during); +BASIC_BENCHMARK_TEST(BM_spin_pause_during)->ThreadPerCpu(); + +void BM_pause_during(benchmark::State& state) { + for (auto _ : state) { + state.PauseTiming(); + state.ResumeTiming(); + } +} +BENCHMARK(BM_pause_during); +BENCHMARK(BM_pause_during)->ThreadPerCpu(); +BENCHMARK(BM_pause_during)->UseRealTime(); +BENCHMARK(BM_pause_during)->UseRealTime()->ThreadPerCpu(); + +void BM_spin_pause_after(benchmark::State& state) { + for (auto _ : state) { + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + } + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } +} +BASIC_BENCHMARK_TEST(BM_spin_pause_after); +BASIC_BENCHMARK_TEST(BM_spin_pause_after)->ThreadPerCpu(); + +void BM_spin_pause_before_and_after(benchmark::State& state) { + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + for (auto _ : state) { + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } + } + for (int i = 0; i < state.range(0); ++i) { + benchmark::DoNotOptimize(i); + } +} +BASIC_BENCHMARK_TEST(BM_spin_pause_before_and_after); +BASIC_BENCHMARK_TEST(BM_spin_pause_before_and_after)->ThreadPerCpu(); + +void BM_empty_stop_start(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_empty_stop_start); +BENCHMARK(BM_empty_stop_start)->ThreadPerCpu(); + + +void BM_KeepRunning(benchmark::State& state) { + benchmark::IterationCount iter_count = 0; + assert(iter_count == state.iterations()); + while (state.KeepRunning()) { + ++iter_count; + } + assert(iter_count == state.iterations()); +} +BENCHMARK(BM_KeepRunning); + +void BM_KeepRunningBatch(benchmark::State& state) { + // Choose a prime batch size to avoid evenly dividing max_iterations. + const benchmark::IterationCount batch_size = 101; + benchmark::IterationCount iter_count = 0; + while (state.KeepRunningBatch(batch_size)) { + iter_count += batch_size; + } + assert(state.iterations() == iter_count); +} +BENCHMARK(BM_KeepRunningBatch); + +void BM_RangedFor(benchmark::State& state) { + benchmark::IterationCount iter_count = 0; + for (auto _ : state) { + ++iter_count; + } + assert(iter_count == state.max_iterations); +} +BENCHMARK(BM_RangedFor); + +// Ensure that StateIterator provides all the necessary typedefs required to +// instantiate std::iterator_traits. +static_assert(std::is_same< + typename std::iterator_traits::value_type, + typename benchmark::State::StateIterator::value_type>::value, ""); + +BENCHMARK_MAIN(); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/benchmark_gtest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/benchmark_gtest.cc new file mode 100644 index 0000000000000000000000000000000000000000..9557b20ec7d93979413eac7adaffa90362734174 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/benchmark_gtest.cc @@ -0,0 +1,128 @@ +#include + +#include "../src/benchmark_register.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace benchmark { +namespace internal { +namespace { + +TEST(AddRangeTest, Simple) { + std::vector dst; + AddRange(&dst, 1, 2, 2); + EXPECT_THAT(dst, testing::ElementsAre(1, 2)); +} + +TEST(AddRangeTest, Simple64) { + std::vector dst; + AddRange(&dst, static_cast(1), static_cast(2), 2); + EXPECT_THAT(dst, testing::ElementsAre(1, 2)); +} + +TEST(AddRangeTest, Advanced) { + std::vector dst; + AddRange(&dst, 5, 15, 2); + EXPECT_THAT(dst, testing::ElementsAre(5, 8, 15)); +} + +TEST(AddRangeTest, Advanced64) { + std::vector dst; + AddRange(&dst, static_cast(5), static_cast(15), 2); + EXPECT_THAT(dst, testing::ElementsAre(5, 8, 15)); +} + +TEST(AddRangeTest, FullRange8) { + std::vector dst; + AddRange(&dst, int8_t{1}, std::numeric_limits::max(), 8); + EXPECT_THAT(dst, testing::ElementsAre(1, 8, 64, 127)); +} + +TEST(AddRangeTest, FullRange64) { + std::vector dst; + AddRange(&dst, int64_t{1}, std::numeric_limits::max(), 1024); + EXPECT_THAT( + dst, testing::ElementsAre(1LL, 1024LL, 1048576LL, 1073741824LL, + 1099511627776LL, 1125899906842624LL, + 1152921504606846976LL, 9223372036854775807LL)); +} + +TEST(AddRangeTest, NegativeRanges) { + std::vector dst; + AddRange(&dst, -8, 0, 2); + EXPECT_THAT(dst, testing::ElementsAre(-8, -4, -2, -1, 0)); +} + +TEST(AddRangeTest, StrictlyNegative) { + std::vector dst; + AddRange(&dst, -8, -1, 2); + EXPECT_THAT(dst, testing::ElementsAre(-8, -4, -2, -1)); +} + +TEST(AddRangeTest, SymmetricNegativeRanges) { + std::vector dst; + AddRange(&dst, -8, 8, 2); + EXPECT_THAT(dst, testing::ElementsAre(-8, -4, -2, -1, 0, 1, 2, 4, 8)); +} + +TEST(AddRangeTest, SymmetricNegativeRangesOddMult) { + std::vector dst; + AddRange(&dst, -30, 32, 5); + EXPECT_THAT(dst, testing::ElementsAre(-30, -25, -5, -1, 0, 1, 5, 25, 32)); +} + +TEST(AddRangeTest, NegativeRangesAsymmetric) { + std::vector dst; + AddRange(&dst, -3, 5, 2); + EXPECT_THAT(dst, testing::ElementsAre(-3, -2, -1, 0, 1, 2, 4, 5)); +} + +TEST(AddRangeTest, NegativeRangesLargeStep) { + // Always include -1, 0, 1 when crossing zero. + std::vector dst; + AddRange(&dst, -8, 8, 10); + EXPECT_THAT(dst, testing::ElementsAre(-8, -1, 0, 1, 8)); +} + +TEST(AddRangeTest, ZeroOnlyRange) { + std::vector dst; + AddRange(&dst, 0, 0, 2); + EXPECT_THAT(dst, testing::ElementsAre(0)); +} + +TEST(AddRangeTest, NegativeRange64) { + std::vector dst; + AddRange(&dst, -4, 4, 2); + EXPECT_THAT(dst, testing::ElementsAre(-4, -2, -1, 0, 1, 2, 4)); +} + +TEST(AddRangeTest, NegativeRangePreservesExistingOrder) { + // If elements already exist in the range, ensure we don't change + // their ordering by adding negative values. + std::vector dst = {1, 2, 3}; + AddRange(&dst, -2, 2, 2); + EXPECT_THAT(dst, testing::ElementsAre(1, 2, 3, -2, -1, 0, 1, 2)); +} + +TEST(AddRangeTest, FullNegativeRange64) { + std::vector dst; + const auto min = std::numeric_limits::min(); + const auto max = std::numeric_limits::max(); + AddRange(&dst, min, max, 1024); + EXPECT_THAT( + dst, testing::ElementsAreArray(std::vector{ + min, -1152921504606846976LL, -1125899906842624LL, + -1099511627776LL, -1073741824LL, -1048576LL, -1024LL, -1LL, 0LL, + 1LL, 1024LL, 1048576LL, 1073741824LL, 1099511627776LL, + 1125899906842624LL, 1152921504606846976LL, max})); +} + +TEST(AddRangeTest, Simple8) { + std::vector dst; + AddRange(&dst, 1, 8, 2); + EXPECT_THAT(dst, testing::ElementsAre(1, 2, 4, 8)); +} + +} // namespace +} // namespace internal +} // namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/benchmark_name_gtest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/benchmark_name_gtest.cc new file mode 100644 index 0000000000000000000000000000000000000000..afb401c1f5328cecf284449d99a9716dc1eea419 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/benchmark_name_gtest.cc @@ -0,0 +1,74 @@ +#include "benchmark/benchmark.h" +#include "gtest/gtest.h" + +namespace { + +using namespace benchmark; +using namespace benchmark::internal; + +TEST(BenchmarkNameTest, Empty) { + const auto name = BenchmarkName(); + EXPECT_EQ(name.str(), std::string()); +} + +TEST(BenchmarkNameTest, FunctionName) { + auto name = BenchmarkName(); + name.function_name = "function_name"; + EXPECT_EQ(name.str(), "function_name"); +} + +TEST(BenchmarkNameTest, FunctionNameAndArgs) { + auto name = BenchmarkName(); + name.function_name = "function_name"; + name.args = "some_args:3/4/5"; + EXPECT_EQ(name.str(), "function_name/some_args:3/4/5"); +} + +TEST(BenchmarkNameTest, MinTime) { + auto name = BenchmarkName(); + name.function_name = "function_name"; + name.args = "some_args:3/4"; + name.min_time = "min_time:3.4s"; + EXPECT_EQ(name.str(), "function_name/some_args:3/4/min_time:3.4s"); +} + +TEST(BenchmarkNameTest, Iterations) { + auto name = BenchmarkName(); + name.function_name = "function_name"; + name.min_time = "min_time:3.4s"; + name.iterations = "iterations:42"; + EXPECT_EQ(name.str(), "function_name/min_time:3.4s/iterations:42"); +} + +TEST(BenchmarkNameTest, Repetitions) { + auto name = BenchmarkName(); + name.function_name = "function_name"; + name.min_time = "min_time:3.4s"; + name.repetitions = "repetitions:24"; + EXPECT_EQ(name.str(), "function_name/min_time:3.4s/repetitions:24"); +} + +TEST(BenchmarkNameTest, TimeType) { + auto name = BenchmarkName(); + name.function_name = "function_name"; + name.min_time = "min_time:3.4s"; + name.time_type = "hammer_time"; + EXPECT_EQ(name.str(), "function_name/min_time:3.4s/hammer_time"); +} + +TEST(BenchmarkNameTest, Threads) { + auto name = BenchmarkName(); + name.function_name = "function_name"; + name.min_time = "min_time:3.4s"; + name.threads = "threads:256"; + EXPECT_EQ(name.str(), "function_name/min_time:3.4s/threads:256"); +} + +TEST(BenchmarkNameTest, TestEmptyFunctionName) { + auto name = BenchmarkName(); + name.args = "first:3/second:4"; + name.threads = "threads:22"; + EXPECT_EQ(name.str(), "first:3/second:4/threads:22"); +} + +} // end namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/benchmark_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/benchmark_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..3cd4f5565fa1c9d9882bf3c220c2c305d0fdfeee --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/benchmark_test.cc @@ -0,0 +1,245 @@ +#include "benchmark/benchmark.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__GNUC__) +#define BENCHMARK_NOINLINE __attribute__((noinline)) +#else +#define BENCHMARK_NOINLINE +#endif + +namespace { + +int BENCHMARK_NOINLINE Factorial(uint32_t n) { + return (n == 1) ? 1 : n * Factorial(n - 1); +} + +double CalculatePi(int depth) { + double pi = 0.0; + for (int i = 0; i < depth; ++i) { + double numerator = static_cast(((i % 2) * 2) - 1); + double denominator = static_cast((2 * i) - 1); + pi += numerator / denominator; + } + return (pi - 1.0) * 4; +} + +std::set ConstructRandomSet(int64_t size) { + std::set s; + for (int i = 0; i < size; ++i) s.insert(s.end(), i); + return s; +} + +std::mutex test_vector_mu; +std::vector* test_vector = nullptr; + +} // end namespace + +static void BM_Factorial(benchmark::State& state) { + int fac_42 = 0; + for (auto _ : state) fac_42 = Factorial(8); + // Prevent compiler optimizations + std::stringstream ss; + ss << fac_42; + state.SetLabel(ss.str()); +} +BENCHMARK(BM_Factorial); +BENCHMARK(BM_Factorial)->UseRealTime(); + +static void BM_CalculatePiRange(benchmark::State& state) { + double pi = 0.0; + for (auto _ : state) pi = CalculatePi(static_cast(state.range(0))); + std::stringstream ss; + ss << pi; + state.SetLabel(ss.str()); +} +BENCHMARK_RANGE(BM_CalculatePiRange, 1, 1024 * 1024); + +static void BM_CalculatePi(benchmark::State& state) { + static const int depth = 1024; + for (auto _ : state) { + benchmark::DoNotOptimize(CalculatePi(static_cast(depth))); + } +} +BENCHMARK(BM_CalculatePi)->Threads(8); +BENCHMARK(BM_CalculatePi)->ThreadRange(1, 32); +BENCHMARK(BM_CalculatePi)->ThreadPerCpu(); + +static void BM_SetInsert(benchmark::State& state) { + std::set data; + for (auto _ : state) { + state.PauseTiming(); + data = ConstructRandomSet(state.range(0)); + state.ResumeTiming(); + for (int j = 0; j < state.range(1); ++j) data.insert(rand()); + } + state.SetItemsProcessed(state.iterations() * state.range(1)); + state.SetBytesProcessed(state.iterations() * state.range(1) * sizeof(int)); +} + +// Test many inserts at once to reduce the total iterations needed. Otherwise, the slower, +// non-timed part of each iteration will make the benchmark take forever. +BENCHMARK(BM_SetInsert)->Ranges({{1 << 10, 8 << 10}, {128, 512}}); + +template +static void BM_Sequential(benchmark::State& state) { + ValueType v = 42; + for (auto _ : state) { + Container c; + for (int64_t i = state.range(0); --i;) c.push_back(v); + } + const int64_t items_processed = state.iterations() * state.range(0); + state.SetItemsProcessed(items_processed); + state.SetBytesProcessed(items_processed * sizeof(v)); +} +BENCHMARK_TEMPLATE2(BM_Sequential, std::vector, int) + ->Range(1 << 0, 1 << 10); +BENCHMARK_TEMPLATE(BM_Sequential, std::list)->Range(1 << 0, 1 << 10); +// Test the variadic version of BENCHMARK_TEMPLATE in C++11 and beyond. +#ifdef BENCHMARK_HAS_CXX11 +BENCHMARK_TEMPLATE(BM_Sequential, std::vector, int)->Arg(512); +#endif + +static void BM_StringCompare(benchmark::State& state) { + size_t len = static_cast(state.range(0)); + std::string s1(len, '-'); + std::string s2(len, '-'); + for (auto _ : state) benchmark::DoNotOptimize(s1.compare(s2)); +} +BENCHMARK(BM_StringCompare)->Range(1, 1 << 20); + +static void BM_SetupTeardown(benchmark::State& state) { + if (state.thread_index == 0) { + // No need to lock test_vector_mu here as this is running single-threaded. + test_vector = new std::vector(); + } + int i = 0; + for (auto _ : state) { + std::lock_guard l(test_vector_mu); + if (i % 2 == 0) + test_vector->push_back(i); + else + test_vector->pop_back(); + ++i; + } + if (state.thread_index == 0) { + delete test_vector; + } +} +BENCHMARK(BM_SetupTeardown)->ThreadPerCpu(); + +static void BM_LongTest(benchmark::State& state) { + double tracker = 0.0; + for (auto _ : state) { + for (int i = 0; i < state.range(0); ++i) + benchmark::DoNotOptimize(tracker += i); + } +} +BENCHMARK(BM_LongTest)->Range(1 << 16, 1 << 28); + +static void BM_ParallelMemset(benchmark::State& state) { + int64_t size = state.range(0) / static_cast(sizeof(int)); + int thread_size = static_cast(size) / state.threads; + int from = thread_size * state.thread_index; + int to = from + thread_size; + + if (state.thread_index == 0) { + test_vector = new std::vector(static_cast(size)); + } + + for (auto _ : state) { + for (int i = from; i < to; i++) { + // No need to lock test_vector_mu as ranges + // do not overlap between threads. + benchmark::DoNotOptimize(test_vector->at(i) = 1); + } + } + + if (state.thread_index == 0) { + delete test_vector; + } +} +BENCHMARK(BM_ParallelMemset)->Arg(10 << 20)->ThreadRange(1, 4); + +static void BM_ManualTiming(benchmark::State& state) { + int64_t slept_for = 0; + int64_t microseconds = state.range(0); + std::chrono::duration sleep_duration{ + static_cast(microseconds)}; + + for (auto _ : state) { + auto start = std::chrono::high_resolution_clock::now(); + // Simulate some useful workload with a sleep + std::this_thread::sleep_for( + std::chrono::duration_cast(sleep_duration)); + auto end = std::chrono::high_resolution_clock::now(); + + auto elapsed = + std::chrono::duration_cast>(end - start); + + state.SetIterationTime(elapsed.count()); + slept_for += microseconds; + } + state.SetItemsProcessed(slept_for); +} +BENCHMARK(BM_ManualTiming)->Range(1, 1 << 14)->UseRealTime(); +BENCHMARK(BM_ManualTiming)->Range(1, 1 << 14)->UseManualTime(); + +#ifdef BENCHMARK_HAS_CXX11 + +template +void BM_with_args(benchmark::State& state, Args&&...) { + for (auto _ : state) { + } +} +BENCHMARK_CAPTURE(BM_with_args, int_test, 42, 43, 44); +BENCHMARK_CAPTURE(BM_with_args, string_and_pair_test, std::string("abc"), + std::pair(42, 3.8)); + +void BM_non_template_args(benchmark::State& state, int, double) { + while(state.KeepRunning()) {} +} +BENCHMARK_CAPTURE(BM_non_template_args, basic_test, 0, 0); + +#endif // BENCHMARK_HAS_CXX11 + +static void BM_DenseThreadRanges(benchmark::State& st) { + switch (st.range(0)) { + case 1: + assert(st.threads == 1 || st.threads == 2 || st.threads == 3); + break; + case 2: + assert(st.threads == 1 || st.threads == 3 || st.threads == 4); + break; + case 3: + assert(st.threads == 5 || st.threads == 8 || st.threads == 11 || + st.threads == 14); + break; + default: + assert(false && "Invalid test case number"); + } + while (st.KeepRunning()) { + } +} +BENCHMARK(BM_DenseThreadRanges)->Arg(1)->DenseThreadRange(1, 3); +BENCHMARK(BM_DenseThreadRanges)->Arg(2)->DenseThreadRange(1, 4, 2); +BENCHMARK(BM_DenseThreadRanges)->Arg(3)->DenseThreadRange(5, 14, 3); + +BENCHMARK_MAIN(); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/clobber_memory_assembly_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/clobber_memory_assembly_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..f41911a39ce739efc37939b82b1dc7111cb1c8de --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/clobber_memory_assembly_test.cc @@ -0,0 +1,64 @@ +#include + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wreturn-type" +#endif + +extern "C" { + +extern int ExternInt; +extern int ExternInt2; +extern int ExternInt3; + +} + +// CHECK-LABEL: test_basic: +extern "C" void test_basic() { + int x; + benchmark::DoNotOptimize(&x); + x = 101; + benchmark::ClobberMemory(); + // CHECK: leaq [[DEST:[^,]+]], %rax + // CHECK: movl $101, [[DEST]] + // CHECK: ret +} + +// CHECK-LABEL: test_redundant_store: +extern "C" void test_redundant_store() { + ExternInt = 3; + benchmark::ClobberMemory(); + ExternInt = 51; + // CHECK-DAG: ExternInt + // CHECK-DAG: movl $3 + // CHECK: movl $51 +} + +// CHECK-LABEL: test_redundant_read: +extern "C" void test_redundant_read() { + int x; + benchmark::DoNotOptimize(&x); + x = ExternInt; + benchmark::ClobberMemory(); + x = ExternInt2; + // CHECK: leaq [[DEST:[^,]+]], %rax + // CHECK: ExternInt(%rip) + // CHECK: movl %eax, [[DEST]] + // CHECK-NOT: ExternInt2 + // CHECK: ret +} + +// CHECK-LABEL: test_redundant_read2: +extern "C" void test_redundant_read2() { + int x; + benchmark::DoNotOptimize(&x); + x = ExternInt; + benchmark::ClobberMemory(); + x = ExternInt2; + benchmark::ClobberMemory(); + // CHECK: leaq [[DEST:[^,]+]], %rax + // CHECK: ExternInt(%rip) + // CHECK: movl %eax, [[DEST]] + // CHECK: ExternInt2(%rip) + // CHECK: movl %eax, [[DEST]] + // CHECK: ret +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/commandlineflags_gtest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/commandlineflags_gtest.cc new file mode 100644 index 0000000000000000000000000000000000000000..36bdb44595becfc420707b9b8923c065726f8ede --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/commandlineflags_gtest.cc @@ -0,0 +1,201 @@ +#include + +#include "../src/commandlineflags.h" +#include "../src/internal_macros.h" +#include "gtest/gtest.h" + +namespace benchmark { +namespace { + +#if defined(BENCHMARK_OS_WINDOWS) +int setenv(const char* name, const char* value, int overwrite) { + if (!overwrite) { + // NOTE: getenv_s is far superior but not available under mingw. + char* env_value = getenv(name); + if (env_value == nullptr) { + return -1; + } + } + return _putenv_s(name, value); +} + +int unsetenv(const char* name) { + return _putenv_s(name, ""); +} + +#endif // BENCHMARK_OS_WINDOWS + +TEST(BoolFromEnv, Default) { + ASSERT_EQ(unsetenv("BENCHMARK_NOT_IN_ENV"), 0); + EXPECT_EQ(BoolFromEnv("not_in_env", true), true); +} + +TEST(BoolFromEnv, False) { + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "0", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "N", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "n", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "NO", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "No", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "no", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "F", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "f", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "FALSE", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "False", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "false", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "OFF", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "Off", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "off", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", true), false); + unsetenv("BENCHMARK_IN_ENV"); +} + +TEST(BoolFromEnv, True) { + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "1", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "Y", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "y", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "YES", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "Yes", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "yes", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "T", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "t", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "TRUE", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "True", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "true", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "ON", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "On", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "on", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); + +#ifndef BENCHMARK_OS_WINDOWS + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "", 1), 0); + EXPECT_EQ(BoolFromEnv("in_env", false), true); + unsetenv("BENCHMARK_IN_ENV"); +#endif +} + +TEST(Int32FromEnv, NotInEnv) { + ASSERT_EQ(unsetenv("BENCHMARK_NOT_IN_ENV"), 0); + EXPECT_EQ(Int32FromEnv("not_in_env", 42), 42); +} + +TEST(Int32FromEnv, InvalidInteger) { + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "foo", 1), 0); + EXPECT_EQ(Int32FromEnv("in_env", 42), 42); + unsetenv("BENCHMARK_IN_ENV"); +} + +TEST(Int32FromEnv, ValidInteger) { + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "42", 1), 0); + EXPECT_EQ(Int32FromEnv("in_env", 64), 42); + unsetenv("BENCHMARK_IN_ENV"); +} + +TEST(DoubleFromEnv, NotInEnv) { + ASSERT_EQ(unsetenv("BENCHMARK_NOT_IN_ENV"), 0); + EXPECT_EQ(DoubleFromEnv("not_in_env", 0.51), 0.51); +} + +TEST(DoubleFromEnv, InvalidReal) { + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "foo", 1), 0); + EXPECT_EQ(DoubleFromEnv("in_env", 0.51), 0.51); + unsetenv("BENCHMARK_IN_ENV"); +} + +TEST(DoubleFromEnv, ValidReal) { + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "0.51", 1), 0); + EXPECT_EQ(DoubleFromEnv("in_env", 0.71), 0.51); + unsetenv("BENCHMARK_IN_ENV"); +} + +TEST(StringFromEnv, Default) { + ASSERT_EQ(unsetenv("BENCHMARK_NOT_IN_ENV"), 0); + EXPECT_STREQ(StringFromEnv("not_in_env", "foo"), "foo"); +} + +TEST(StringFromEnv, Valid) { + ASSERT_EQ(setenv("BENCHMARK_IN_ENV", "foo", 1), 0); + EXPECT_STREQ(StringFromEnv("in_env", "bar"), "foo"); + unsetenv("BENCHMARK_IN_ENV"); +} + +} // namespace +} // namespace benchmark diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/complexity_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/complexity_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..5681fdcf34e1345496e0bc9bdcd45a251db86702 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/complexity_test.cc @@ -0,0 +1,213 @@ +#undef NDEBUG +#include +#include +#include +#include +#include +#include "benchmark/benchmark.h" +#include "output_test.h" + +namespace { + +#define ADD_COMPLEXITY_CASES(...) \ + int CONCAT(dummy, __LINE__) = AddComplexityTest(__VA_ARGS__) + +int AddComplexityTest(std::string test_name, std::string big_o_test_name, + std::string rms_test_name, std::string big_o) { + SetSubstitutions({{"%name", test_name}, + {"%bigo_name", big_o_test_name}, + {"%rms_name", rms_test_name}, + {"%bigo_str", "[ ]* %float " + big_o}, + {"%bigo", big_o}, + {"%rms", "[ ]*[0-9]+ %"}}); + AddCases( + TC_ConsoleOut, + {{"^%bigo_name %bigo_str %bigo_str[ ]*$"}, + {"^%bigo_name", MR_Not}, // Assert we we didn't only matched a name. + {"^%rms_name %rms %rms[ ]*$", MR_Next}}); + AddCases(TC_JSONOut, {{"\"name\": \"%bigo_name\",$"}, + {"\"run_name\": \"%name\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": %int,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"BigO\",$", MR_Next}, + {"\"cpu_coefficient\": %float,$", MR_Next}, + {"\"real_coefficient\": %float,$", MR_Next}, + {"\"big_o\": \"%bigo\",$", MR_Next}, + {"\"time_unit\": \"ns\"$", MR_Next}, + {"}", MR_Next}, + {"\"name\": \"%rms_name\",$"}, + {"\"run_name\": \"%name\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": %int,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"RMS\",$", MR_Next}, + {"\"rms\": %float$", MR_Next}, + {"}", MR_Next}}); + AddCases(TC_CSVOut, {{"^\"%bigo_name\",,%float,%float,%bigo,,,,,$"}, + {"^\"%bigo_name\"", MR_Not}, + {"^\"%rms_name\",,%float,%float,,,,,,$", MR_Next}}); + return 0; +} + +} // end namespace + +// ========================================================================= // +// --------------------------- Testing BigO O(1) --------------------------- // +// ========================================================================= // + +void BM_Complexity_O1(benchmark::State& state) { + for (auto _ : state) { + for (int i = 0; i < 1024; ++i) { + benchmark::DoNotOptimize(&i); + } + } + state.SetComplexityN(state.range(0)); +} +BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity(benchmark::o1); +BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity(); +BENCHMARK(BM_Complexity_O1) + ->Range(1, 1 << 18) + ->Complexity([](benchmark::IterationCount) { return 1.0; }); + +const char *one_test_name = "BM_Complexity_O1"; +const char *big_o_1_test_name = "BM_Complexity_O1_BigO"; +const char *rms_o_1_test_name = "BM_Complexity_O1_RMS"; +const char *enum_big_o_1 = "\\([0-9]+\\)"; +// FIXME: Tolerate both '(1)' and 'lgN' as output when the complexity is auto +// deduced. +// See https://github.com/google/benchmark/issues/272 +const char *auto_big_o_1 = "(\\([0-9]+\\))|(lgN)"; +const char *lambda_big_o_1 = "f\\(N\\)"; + +// Add enum tests +ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, + enum_big_o_1); + +// Add auto enum tests +ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, + auto_big_o_1); + +// Add lambda tests +ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, + lambda_big_o_1); + +// ========================================================================= // +// --------------------------- Testing BigO O(N) --------------------------- // +// ========================================================================= // + +std::vector ConstructRandomVector(int64_t size) { + std::vector v; + v.reserve(static_cast(size)); + for (int i = 0; i < size; ++i) { + v.push_back(static_cast(std::rand() % size)); + } + return v; +} + +void BM_Complexity_O_N(benchmark::State& state) { + auto v = ConstructRandomVector(state.range(0)); + // Test worst case scenario (item not in vector) + const int64_t item_not_in_vector = state.range(0) * 2; + for (auto _ : state) { + benchmark::DoNotOptimize(std::find(v.begin(), v.end(), item_not_in_vector)); + } + state.SetComplexityN(state.range(0)); +} +BENCHMARK(BM_Complexity_O_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity(benchmark::oN); +BENCHMARK(BM_Complexity_O_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity([](benchmark::IterationCount n) -> double { + return static_cast(n); + }); +BENCHMARK(BM_Complexity_O_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity(); + +const char *n_test_name = "BM_Complexity_O_N"; +const char *big_o_n_test_name = "BM_Complexity_O_N_BigO"; +const char *rms_o_n_test_name = "BM_Complexity_O_N_RMS"; +const char *enum_auto_big_o_n = "N"; +const char *lambda_big_o_n = "f\\(N\\)"; + +// Add enum tests +ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name, + enum_auto_big_o_n); + +// Add lambda tests +ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name, + lambda_big_o_n); + +// ========================================================================= // +// ------------------------- Testing BigO O(N*lgN) ------------------------- // +// ========================================================================= // + +static void BM_Complexity_O_N_log_N(benchmark::State& state) { + auto v = ConstructRandomVector(state.range(0)); + for (auto _ : state) { + std::sort(v.begin(), v.end()); + } + state.SetComplexityN(state.range(0)); +} +static const double kLog2E = 1.44269504088896340736; +BENCHMARK(BM_Complexity_O_N_log_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity(benchmark::oNLogN); +BENCHMARK(BM_Complexity_O_N_log_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity([](benchmark::IterationCount n) { + return kLog2E * n * log(static_cast(n)); + }); +BENCHMARK(BM_Complexity_O_N_log_N) + ->RangeMultiplier(2) + ->Range(1 << 10, 1 << 16) + ->Complexity(); + +const char *n_lg_n_test_name = "BM_Complexity_O_N_log_N"; +const char *big_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N_BigO"; +const char *rms_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N_RMS"; +const char *enum_auto_big_o_n_lg_n = "NlgN"; +const char *lambda_big_o_n_lg_n = "f\\(N\\)"; + +// Add enum tests +ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name, + rms_o_n_lg_n_test_name, enum_auto_big_o_n_lg_n); + +// Add lambda tests +ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name, + rms_o_n_lg_n_test_name, lambda_big_o_n_lg_n); + +// ========================================================================= // +// -------- Testing formatting of Complexity with captured args ------------ // +// ========================================================================= // + +void BM_ComplexityCaptureArgs(benchmark::State& state, int n) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + state.SetComplexityN(n); +} + +BENCHMARK_CAPTURE(BM_ComplexityCaptureArgs, capture_test, 100) + ->Complexity(benchmark::oN) + ->Ranges({{1, 2}, {3, 4}}); + +const std::string complexity_capture_name = + "BM_ComplexityCaptureArgs/capture_test"; + +ADD_COMPLEXITY_CASES(complexity_capture_name, complexity_capture_name + "_BigO", + complexity_capture_name + "_RMS", "N"); + +// ========================================================================= // +// --------------------------- TEST CASES END ------------------------------ // +// ========================================================================= // + +int main(int argc, char *argv[]) { RunOutputTests(argc, argv); } diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/cxx03_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/cxx03_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..c4c9a52273e3a6ddc68813bc62ee0fc1cd6f3392 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/cxx03_test.cc @@ -0,0 +1,63 @@ +#undef NDEBUG +#include +#include + +#include "benchmark/benchmark.h" + +#if __cplusplus >= 201103L +#error C++11 or greater detected. Should be C++03. +#endif + +#ifdef BENCHMARK_HAS_CXX11 +#error C++11 or greater detected by the library. BENCHMARK_HAS_CXX11 is defined. +#endif + +void BM_empty(benchmark::State& state) { + while (state.KeepRunning()) { + volatile benchmark::IterationCount x = state.iterations(); + ((void)x); + } +} +BENCHMARK(BM_empty); + +// The new C++11 interface for args/ranges requires initializer list support. +// Therefore we provide the old interface to support C++03. +void BM_old_arg_range_interface(benchmark::State& state) { + assert((state.range(0) == 1 && state.range(1) == 2) || + (state.range(0) == 5 && state.range(1) == 6)); + while (state.KeepRunning()) { + } +} +BENCHMARK(BM_old_arg_range_interface)->ArgPair(1, 2)->RangePair(5, 5, 6, 6); + +template +void BM_template2(benchmark::State& state) { + BM_empty(state); +} +BENCHMARK_TEMPLATE2(BM_template2, int, long); + +template +void BM_template1(benchmark::State& state) { + BM_empty(state); +} +BENCHMARK_TEMPLATE(BM_template1, long); +BENCHMARK_TEMPLATE1(BM_template1, int); + +template +struct BM_Fixture : public ::benchmark::Fixture { +}; + +BENCHMARK_TEMPLATE_F(BM_Fixture, BM_template1, long)(benchmark::State& state) { + BM_empty(state); +} +BENCHMARK_TEMPLATE1_F(BM_Fixture, BM_template2, int)(benchmark::State& state) { + BM_empty(state); +} + +void BM_counters(benchmark::State& state) { + BM_empty(state); + state.counters["Foo"] = 2; +} +BENCHMARK(BM_counters); + +BENCHMARK_MAIN(); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/diagnostics_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/diagnostics_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..dd64a336553157dfac9fc327f451030fc10a48cd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/diagnostics_test.cc @@ -0,0 +1,80 @@ +// Testing: +// State::PauseTiming() +// State::ResumeTiming() +// Test that CHECK's within these function diagnose when they are called +// outside of the KeepRunning() loop. +// +// NOTE: Users should NOT include or use src/check.h. This is only done in +// order to test library internals. + +#include +#include + +#include "../src/check.h" +#include "benchmark/benchmark.h" + +#if defined(__GNUC__) && !defined(__EXCEPTIONS) +#define TEST_HAS_NO_EXCEPTIONS +#endif + +void TestHandler() { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::logic_error(""); +#else + std::abort(); +#endif +} + +void try_invalid_pause_resume(benchmark::State& state) { +#if !defined(TEST_BENCHMARK_LIBRARY_HAS_NO_ASSERTIONS) && !defined(TEST_HAS_NO_EXCEPTIONS) + try { + state.PauseTiming(); + std::abort(); + } catch (std::logic_error const&) { + } + try { + state.ResumeTiming(); + std::abort(); + } catch (std::logic_error const&) { + } +#else + (void)state; // avoid unused warning +#endif +} + +void BM_diagnostic_test(benchmark::State& state) { + static bool called_once = false; + + if (called_once == false) try_invalid_pause_resume(state); + + for (auto _ : state) { + benchmark::DoNotOptimize(state.iterations()); + } + + if (called_once == false) try_invalid_pause_resume(state); + + called_once = true; +} +BENCHMARK(BM_diagnostic_test); + + +void BM_diagnostic_test_keep_running(benchmark::State& state) { + static bool called_once = false; + + if (called_once == false) try_invalid_pause_resume(state); + + while(state.KeepRunning()) { + benchmark::DoNotOptimize(state.iterations()); + } + + if (called_once == false) try_invalid_pause_resume(state); + + called_once = true; +} +BENCHMARK(BM_diagnostic_test_keep_running); + +int main(int argc, char* argv[]) { + benchmark::internal::GetAbortHandler() = &TestHandler; + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/display_aggregates_only_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/display_aggregates_only_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..3c36d3f03c1178b3fb7fea31f6409c4be5136e21 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/display_aggregates_only_test.cc @@ -0,0 +1,43 @@ + +#undef NDEBUG +#include +#include + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// Ok this test is super ugly. We want to check what happens with the file +// reporter in the presence of DisplayAggregatesOnly(). +// We do not care about console output, the normal tests check that already. + +void BM_SummaryRepeat(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_SummaryRepeat)->Repetitions(3)->DisplayAggregatesOnly(); + +int main(int argc, char* argv[]) { + const std::string output = GetFileReporterOutput(argc, argv); + + if (SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3") != 6 || + SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3\"") != 3 || + SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_mean\"") != 1 || + SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_median\"") != + 1 || + SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_stddev\"") != + 1) { + std::cout << "Precondition mismatch. Expected to only find 6 " + "occurrences of \"BM_SummaryRepeat/repeats:3\" substring:\n" + "\"name\": \"BM_SummaryRepeat/repeats:3\", " + "\"name\": \"BM_SummaryRepeat/repeats:3\", " + "\"name\": \"BM_SummaryRepeat/repeats:3\", " + "\"name\": \"BM_SummaryRepeat/repeats:3_mean\", " + "\"name\": \"BM_SummaryRepeat/repeats:3_median\", " + "\"name\": \"BM_SummaryRepeat/repeats:3_stddev\"\nThe entire " + "output:\n"; + std::cout << output; + return 1; + } + + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/donotoptimize_assembly_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/donotoptimize_assembly_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..d4b0bab70e7733bfaad73c2d425ee6c49a6c298f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/donotoptimize_assembly_test.cc @@ -0,0 +1,163 @@ +#include + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wreturn-type" +#endif + +extern "C" { + +extern int ExternInt; +extern int ExternInt2; +extern int ExternInt3; + +inline int Add42(int x) { return x + 42; } + +struct NotTriviallyCopyable { + NotTriviallyCopyable(); + explicit NotTriviallyCopyable(int x) : value(x) {} + NotTriviallyCopyable(NotTriviallyCopyable const&); + int value; +}; + +struct Large { + int value; + int data[2]; +}; + +} +// CHECK-LABEL: test_with_rvalue: +extern "C" void test_with_rvalue() { + benchmark::DoNotOptimize(Add42(0)); + // CHECK: movl $42, %eax + // CHECK: ret +} + +// CHECK-LABEL: test_with_large_rvalue: +extern "C" void test_with_large_rvalue() { + benchmark::DoNotOptimize(Large{ExternInt, {ExternInt, ExternInt}}); + // CHECK: ExternInt(%rip) + // CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]] + // CHECK: movl %eax, -{{[0-9]+}}(%[[REG]]) + // CHECK: movl %eax, -{{[0-9]+}}(%[[REG]]) + // CHECK: ret +} + +// CHECK-LABEL: test_with_non_trivial_rvalue: +extern "C" void test_with_non_trivial_rvalue() { + benchmark::DoNotOptimize(NotTriviallyCopyable(ExternInt)); + // CHECK: mov{{l|q}} ExternInt(%rip) + // CHECK: ret +} + +// CHECK-LABEL: test_with_lvalue: +extern "C" void test_with_lvalue() { + int x = 101; + benchmark::DoNotOptimize(x); + // CHECK-GNU: movl $101, %eax + // CHECK-CLANG: movl $101, -{{[0-9]+}}(%[[REG:[a-z]+]]) + // CHECK: ret +} + +// CHECK-LABEL: test_with_large_lvalue: +extern "C" void test_with_large_lvalue() { + Large L{ExternInt, {ExternInt, ExternInt}}; + benchmark::DoNotOptimize(L); + // CHECK: ExternInt(%rip) + // CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]]) + // CHECK: movl %eax, -{{[0-9]+}}(%[[REG]]) + // CHECK: movl %eax, -{{[0-9]+}}(%[[REG]]) + // CHECK: ret +} + +// CHECK-LABEL: test_with_non_trivial_lvalue: +extern "C" void test_with_non_trivial_lvalue() { + NotTriviallyCopyable NTC(ExternInt); + benchmark::DoNotOptimize(NTC); + // CHECK: ExternInt(%rip) + // CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]]) + // CHECK: ret +} + +// CHECK-LABEL: test_with_const_lvalue: +extern "C" void test_with_const_lvalue() { + const int x = 123; + benchmark::DoNotOptimize(x); + // CHECK: movl $123, %eax + // CHECK: ret +} + +// CHECK-LABEL: test_with_large_const_lvalue: +extern "C" void test_with_large_const_lvalue() { + const Large L{ExternInt, {ExternInt, ExternInt}}; + benchmark::DoNotOptimize(L); + // CHECK: ExternInt(%rip) + // CHECK: movl %eax, -{{[0-9]+}}(%[[REG:[a-z]+]]) + // CHECK: movl %eax, -{{[0-9]+}}(%[[REG]]) + // CHECK: movl %eax, -{{[0-9]+}}(%[[REG]]) + // CHECK: ret +} + +// CHECK-LABEL: test_with_non_trivial_const_lvalue: +extern "C" void test_with_non_trivial_const_lvalue() { + const NotTriviallyCopyable Obj(ExternInt); + benchmark::DoNotOptimize(Obj); + // CHECK: mov{{q|l}} ExternInt(%rip) + // CHECK: ret +} + +// CHECK-LABEL: test_div_by_two: +extern "C" int test_div_by_two(int input) { + int divisor = 2; + benchmark::DoNotOptimize(divisor); + return input / divisor; + // CHECK: movl $2, [[DEST:.*]] + // CHECK: idivl [[DEST]] + // CHECK: ret +} + +// CHECK-LABEL: test_inc_integer: +extern "C" int test_inc_integer() { + int x = 0; + for (int i=0; i < 5; ++i) + benchmark::DoNotOptimize(++x); + // CHECK: movl $1, [[DEST:.*]] + // CHECK: {{(addl \$1,|incl)}} [[DEST]] + // CHECK: {{(addl \$1,|incl)}} [[DEST]] + // CHECK: {{(addl \$1,|incl)}} [[DEST]] + // CHECK: {{(addl \$1,|incl)}} [[DEST]] + // CHECK-CLANG: movl [[DEST]], %eax + // CHECK: ret + return x; +} + +// CHECK-LABEL: test_pointer_rvalue +extern "C" void test_pointer_rvalue() { + // CHECK: movl $42, [[DEST:.*]] + // CHECK: leaq [[DEST]], %rax + // CHECK-CLANG: movq %rax, -{{[0-9]+}}(%[[REG:[a-z]+]]) + // CHECK: ret + int x = 42; + benchmark::DoNotOptimize(&x); +} + +// CHECK-LABEL: test_pointer_const_lvalue: +extern "C" void test_pointer_const_lvalue() { + // CHECK: movl $42, [[DEST:.*]] + // CHECK: leaq [[DEST]], %rax + // CHECK-CLANG: movq %rax, -{{[0-9]+}}(%[[REG:[a-z]+]]) + // CHECK: ret + int x = 42; + int * const xp = &x; + benchmark::DoNotOptimize(xp); +} + +// CHECK-LABEL: test_pointer_lvalue: +extern "C" void test_pointer_lvalue() { + // CHECK: movl $42, [[DEST:.*]] + // CHECK: leaq [[DEST]], %rax + // CHECK-CLANG: movq %rax, -{{[0-9]+}}(%[[REG:[a-z+]+]]) + // CHECK: ret + int x = 42; + int *xp = &x; + benchmark::DoNotOptimize(xp); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/donotoptimize_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/donotoptimize_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..2ce92d1c72beda40a2275e4fe465375a9ae2e64d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/donotoptimize_test.cc @@ -0,0 +1,52 @@ +#include "benchmark/benchmark.h" + +#include + +namespace { +#if defined(__GNUC__) +std::uint64_t double_up(const std::uint64_t x) __attribute__((const)); +#endif +std::uint64_t double_up(const std::uint64_t x) { return x * 2; } +} + +// Using DoNotOptimize on types like BitRef seem to cause a lot of problems +// with the inline assembly on both GCC and Clang. +struct BitRef { + int index; + unsigned char &byte; + +public: + static BitRef Make() { + static unsigned char arr[2] = {}; + BitRef b(1, arr[0]); + return b; + } +private: + BitRef(int i, unsigned char& b) : index(i), byte(b) {} +}; + +int main(int, char*[]) { + // this test verifies compilation of DoNotOptimize() for some types + + char buffer8[8] = ""; + benchmark::DoNotOptimize(buffer8); + + char buffer20[20] = ""; + benchmark::DoNotOptimize(buffer20); + + char buffer1024[1024] = ""; + benchmark::DoNotOptimize(buffer1024); + benchmark::DoNotOptimize(&buffer1024[0]); + + int x = 123; + benchmark::DoNotOptimize(x); + benchmark::DoNotOptimize(&x); + benchmark::DoNotOptimize(x += 42); + + benchmark::DoNotOptimize(double_up(x)); + + // These tests are to e + benchmark::DoNotOptimize(BitRef::Make()); + BitRef lval = BitRef::Make(); + benchmark::DoNotOptimize(lval); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/filter_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/filter_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..0e27065c1558eff5797e52f631d24ed19c53d664 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/filter_test.cc @@ -0,0 +1,104 @@ +#include "benchmark/benchmark.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace { + +class TestReporter : public benchmark::ConsoleReporter { + public: + virtual bool ReportContext(const Context& context) { + return ConsoleReporter::ReportContext(context); + }; + + virtual void ReportRuns(const std::vector& report) { + ++count_; + ConsoleReporter::ReportRuns(report); + }; + + TestReporter() : count_(0) {} + + virtual ~TestReporter() {} + + size_t GetCount() const { return count_; } + + private: + mutable size_t count_; +}; + +} // end namespace + +static void NoPrefix(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(NoPrefix); + +static void BM_Foo(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_Foo); + +static void BM_Bar(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_Bar); + +static void BM_FooBar(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_FooBar); + +static void BM_FooBa(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_FooBa); + +int main(int argc, char **argv) { + bool list_only = false; + for (int i = 0; i < argc; ++i) + list_only |= std::string(argv[i]).find("--benchmark_list_tests") != + std::string::npos; + + benchmark::Initialize(&argc, argv); + + TestReporter test_reporter; + const size_t returned_count = + benchmark::RunSpecifiedBenchmarks(&test_reporter); + + if (argc == 2) { + // Make sure we ran all of the tests + std::stringstream ss(argv[1]); + size_t expected_return; + ss >> expected_return; + + if (returned_count != expected_return) { + std::cerr << "ERROR: Expected " << expected_return + << " tests to match the filter but returned_count = " + << returned_count << std::endl; + return -1; + } + + const size_t expected_reports = list_only ? 0 : expected_return; + const size_t reports_count = test_reporter.GetCount(); + if (reports_count != expected_reports) { + std::cerr << "ERROR: Expected " << expected_reports + << " tests to be run but reported_count = " << reports_count + << std::endl; + return -1; + } + } + + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/fixture_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/fixture_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..1462b10f02f96325354344f07d8c494ee7f8f345 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/fixture_test.cc @@ -0,0 +1,49 @@ + +#include "benchmark/benchmark.h" + +#include +#include + +class MyFixture : public ::benchmark::Fixture { + public: + void SetUp(const ::benchmark::State& state) { + if (state.thread_index == 0) { + assert(data.get() == nullptr); + data.reset(new int(42)); + } + } + + void TearDown(const ::benchmark::State& state) { + if (state.thread_index == 0) { + assert(data.get() != nullptr); + data.reset(); + } + } + + ~MyFixture() { assert(data == nullptr); } + + std::unique_ptr data; +}; + +BENCHMARK_F(MyFixture, Foo)(benchmark::State &st) { + assert(data.get() != nullptr); + assert(*data == 42); + for (auto _ : st) { + } +} + +BENCHMARK_DEFINE_F(MyFixture, Bar)(benchmark::State& st) { + if (st.thread_index == 0) { + assert(data.get() != nullptr); + assert(*data == 42); + } + for (auto _ : st) { + assert(data.get() != nullptr); + assert(*data == 42); + } + st.SetItemsProcessed(st.range(0)); +} +BENCHMARK_REGISTER_F(MyFixture, Bar)->Arg(42); +BENCHMARK_REGISTER_F(MyFixture, Bar)->Arg(42)->ThreadPerCpu(); + +BENCHMARK_MAIN(); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/internal_threading_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/internal_threading_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..039d7c14a8c48105b96344fe4355a71cc95bf1b9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/internal_threading_test.cc @@ -0,0 +1,184 @@ + +#undef NDEBUG + +#include +#include +#include "../src/timers.h" +#include "benchmark/benchmark.h" +#include "output_test.h" + +static const std::chrono::duration time_frame(50); +static const double time_frame_in_sec( + std::chrono::duration_cast>>( + time_frame) + .count()); + +void MyBusySpinwait() { + const auto start = benchmark::ChronoClockNow(); + + while (true) { + const auto now = benchmark::ChronoClockNow(); + const auto elapsed = now - start; + + if (std::chrono::duration(elapsed) >= + time_frame) + return; + } +} + +// ========================================================================= // +// --------------------------- TEST CASES BEGIN ---------------------------- // +// ========================================================================= // + +// ========================================================================= // +// BM_MainThread + +void BM_MainThread(benchmark::State& state) { + for (auto _ : state) { + MyBusySpinwait(); + state.SetIterationTime(time_frame_in_sec); + } + state.counters["invtime"] = + benchmark::Counter{1, benchmark::Counter::kIsRate}; +} + +BENCHMARK(BM_MainThread)->Iterations(1)->Threads(1); +BENCHMARK(BM_MainThread)->Iterations(1)->Threads(1)->UseRealTime(); +BENCHMARK(BM_MainThread)->Iterations(1)->Threads(1)->UseManualTime(); +BENCHMARK(BM_MainThread)->Iterations(1)->Threads(1)->MeasureProcessCPUTime(); +BENCHMARK(BM_MainThread) + ->Iterations(1) + ->Threads(1) + ->MeasureProcessCPUTime() + ->UseRealTime(); +BENCHMARK(BM_MainThread) + ->Iterations(1) + ->Threads(1) + ->MeasureProcessCPUTime() + ->UseManualTime(); + +BENCHMARK(BM_MainThread)->Iterations(1)->Threads(2); +BENCHMARK(BM_MainThread)->Iterations(1)->Threads(2)->UseRealTime(); +BENCHMARK(BM_MainThread)->Iterations(1)->Threads(2)->UseManualTime(); +BENCHMARK(BM_MainThread)->Iterations(1)->Threads(2)->MeasureProcessCPUTime(); +BENCHMARK(BM_MainThread) + ->Iterations(1) + ->Threads(2) + ->MeasureProcessCPUTime() + ->UseRealTime(); +BENCHMARK(BM_MainThread) + ->Iterations(1) + ->Threads(2) + ->MeasureProcessCPUTime() + ->UseManualTime(); + +// ========================================================================= // +// BM_WorkerThread + +void BM_WorkerThread(benchmark::State& state) { + for (auto _ : state) { + std::thread Worker(&MyBusySpinwait); + Worker.join(); + state.SetIterationTime(time_frame_in_sec); + } + state.counters["invtime"] = + benchmark::Counter{1, benchmark::Counter::kIsRate}; +} + +BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(1); +BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(1)->UseRealTime(); +BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(1)->UseManualTime(); +BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(1)->MeasureProcessCPUTime(); +BENCHMARK(BM_WorkerThread) + ->Iterations(1) + ->Threads(1) + ->MeasureProcessCPUTime() + ->UseRealTime(); +BENCHMARK(BM_WorkerThread) + ->Iterations(1) + ->Threads(1) + ->MeasureProcessCPUTime() + ->UseManualTime(); + +BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(2); +BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(2)->UseRealTime(); +BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(2)->UseManualTime(); +BENCHMARK(BM_WorkerThread)->Iterations(1)->Threads(2)->MeasureProcessCPUTime(); +BENCHMARK(BM_WorkerThread) + ->Iterations(1) + ->Threads(2) + ->MeasureProcessCPUTime() + ->UseRealTime(); +BENCHMARK(BM_WorkerThread) + ->Iterations(1) + ->Threads(2) + ->MeasureProcessCPUTime() + ->UseManualTime(); + +// ========================================================================= // +// BM_MainThreadAndWorkerThread + +void BM_MainThreadAndWorkerThread(benchmark::State& state) { + for (auto _ : state) { + std::thread Worker(&MyBusySpinwait); + MyBusySpinwait(); + Worker.join(); + state.SetIterationTime(time_frame_in_sec); + } + state.counters["invtime"] = + benchmark::Counter{1, benchmark::Counter::kIsRate}; +} + +BENCHMARK(BM_MainThreadAndWorkerThread)->Iterations(1)->Threads(1); +BENCHMARK(BM_MainThreadAndWorkerThread) + ->Iterations(1) + ->Threads(1) + ->UseRealTime(); +BENCHMARK(BM_MainThreadAndWorkerThread) + ->Iterations(1) + ->Threads(1) + ->UseManualTime(); +BENCHMARK(BM_MainThreadAndWorkerThread) + ->Iterations(1) + ->Threads(1) + ->MeasureProcessCPUTime(); +BENCHMARK(BM_MainThreadAndWorkerThread) + ->Iterations(1) + ->Threads(1) + ->MeasureProcessCPUTime() + ->UseRealTime(); +BENCHMARK(BM_MainThreadAndWorkerThread) + ->Iterations(1) + ->Threads(1) + ->MeasureProcessCPUTime() + ->UseManualTime(); + +BENCHMARK(BM_MainThreadAndWorkerThread)->Iterations(1)->Threads(2); +BENCHMARK(BM_MainThreadAndWorkerThread) + ->Iterations(1) + ->Threads(2) + ->UseRealTime(); +BENCHMARK(BM_MainThreadAndWorkerThread) + ->Iterations(1) + ->Threads(2) + ->UseManualTime(); +BENCHMARK(BM_MainThreadAndWorkerThread) + ->Iterations(1) + ->Threads(2) + ->MeasureProcessCPUTime(); +BENCHMARK(BM_MainThreadAndWorkerThread) + ->Iterations(1) + ->Threads(2) + ->MeasureProcessCPUTime() + ->UseRealTime(); +BENCHMARK(BM_MainThreadAndWorkerThread) + ->Iterations(1) + ->Threads(2) + ->MeasureProcessCPUTime() + ->UseManualTime(); + +// ========================================================================= // +// ---------------------------- TEST CASES END ----------------------------- // +// ========================================================================= // + +int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/link_main_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/link_main_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..241ad5c3905e9f4ca7dfa95f58428c9ba93b9e59 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/link_main_test.cc @@ -0,0 +1,8 @@ +#include "benchmark/benchmark.h" + +void BM_empty(benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize(state.iterations()); + } +} +BENCHMARK(BM_empty); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/map_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/map_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..dbf7982a3686e0aba0380134a6de236852f66ca4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/map_test.cc @@ -0,0 +1,57 @@ +#include "benchmark/benchmark.h" + +#include +#include + +namespace { + +std::map ConstructRandomMap(int size) { + std::map m; + for (int i = 0; i < size; ++i) { + m.insert(std::make_pair(std::rand() % size, std::rand() % size)); + } + return m; +} + +} // namespace + +// Basic version. +static void BM_MapLookup(benchmark::State& state) { + const int size = static_cast(state.range(0)); + std::map m; + for (auto _ : state) { + state.PauseTiming(); + m = ConstructRandomMap(size); + state.ResumeTiming(); + for (int i = 0; i < size; ++i) { + benchmark::DoNotOptimize(m.find(std::rand() % size)); + } + } + state.SetItemsProcessed(state.iterations() * size); +} +BENCHMARK(BM_MapLookup)->Range(1 << 3, 1 << 12); + +// Using fixtures. +class MapFixture : public ::benchmark::Fixture { + public: + void SetUp(const ::benchmark::State& st) { + m = ConstructRandomMap(static_cast(st.range(0))); + } + + void TearDown(const ::benchmark::State&) { m.clear(); } + + std::map m; +}; + +BENCHMARK_DEFINE_F(MapFixture, Lookup)(benchmark::State& state) { + const int size = static_cast(state.range(0)); + for (auto _ : state) { + for (int i = 0; i < size; ++i) { + benchmark::DoNotOptimize(m.find(std::rand() % size)); + } + } + state.SetItemsProcessed(state.iterations() * size); +} +BENCHMARK_REGISTER_F(MapFixture, Lookup)->Range(1 << 3, 1 << 12); + +BENCHMARK_MAIN(); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/memory_manager_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/memory_manager_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..90bed16cffd8844de9ec47543208ea0b1bf76676 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/memory_manager_test.cc @@ -0,0 +1,44 @@ +#include + +#include "../src/check.h" +#include "benchmark/benchmark.h" +#include "output_test.h" + +class TestMemoryManager : public benchmark::MemoryManager { + void Start() {} + void Stop(Result* result) { + result->num_allocs = 42; + result->max_bytes_used = 42000; + } +}; + +void BM_empty(benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize(state.iterations()); + } +} +BENCHMARK(BM_empty); + +ADD_CASES(TC_ConsoleOut, {{"^BM_empty %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_empty\",$"}, + {"\"run_name\": \"BM_empty\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"allocs_per_iter\": %float,$", MR_Next}, + {"\"max_bytes_used\": 42000$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_empty\",%csv_report$"}}); + +int main(int argc, char* argv[]) { + std::unique_ptr mm(new TestMemoryManager()); + + benchmark::RegisterMemoryManager(mm.get()); + RunOutputTests(argc, argv); + benchmark::RegisterMemoryManager(nullptr); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/multiple_ranges_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/multiple_ranges_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..b25f40eb520aa4f2980b6bd36c72cfa623f2f9dd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/multiple_ranges_test.cc @@ -0,0 +1,96 @@ +#include "benchmark/benchmark.h" + +#include +#include +#include +#include + +class MultipleRangesFixture : public ::benchmark::Fixture { + public: + MultipleRangesFixture() + : expectedValues({{1, 3, 5}, + {1, 3, 8}, + {1, 3, 15}, + {2, 3, 5}, + {2, 3, 8}, + {2, 3, 15}, + {1, 4, 5}, + {1, 4, 8}, + {1, 4, 15}, + {2, 4, 5}, + {2, 4, 8}, + {2, 4, 15}, + {1, 7, 5}, + {1, 7, 8}, + {1, 7, 15}, + {2, 7, 5}, + {2, 7, 8}, + {2, 7, 15}, + {7, 6, 3}}) {} + + void SetUp(const ::benchmark::State& state) { + std::vector ranges = {state.range(0), state.range(1), + state.range(2)}; + + assert(expectedValues.find(ranges) != expectedValues.end()); + + actualValues.insert(ranges); + } + + // NOTE: This is not TearDown as we want to check after _all_ runs are + // complete. + virtual ~MultipleRangesFixture() { + if (actualValues != expectedValues) { + std::cout << "EXPECTED\n"; + for (auto v : expectedValues) { + std::cout << "{"; + for (int64_t iv : v) { + std::cout << iv << ", "; + } + std::cout << "}\n"; + } + std::cout << "ACTUAL\n"; + for (auto v : actualValues) { + std::cout << "{"; + for (int64_t iv : v) { + std::cout << iv << ", "; + } + std::cout << "}\n"; + } + } + } + + std::set> expectedValues; + std::set> actualValues; +}; + +BENCHMARK_DEFINE_F(MultipleRangesFixture, Empty)(benchmark::State& state) { + for (auto _ : state) { + int64_t product = state.range(0) * state.range(1) * state.range(2); + for (int64_t x = 0; x < product; x++) { + benchmark::DoNotOptimize(x); + } + } +} + +BENCHMARK_REGISTER_F(MultipleRangesFixture, Empty) + ->RangeMultiplier(2) + ->Ranges({{1, 2}, {3, 7}, {5, 15}}) + ->Args({7, 6, 3}); + +void BM_CheckDefaultArgument(benchmark::State& state) { + // Test that the 'range()' without an argument is the same as 'range(0)'. + assert(state.range() == state.range(0)); + assert(state.range() != state.range(1)); + for (auto _ : state) { + } +} +BENCHMARK(BM_CheckDefaultArgument)->Ranges({{1, 5}, {6, 10}}); + +static void BM_MultipleRanges(benchmark::State& st) { + for (auto _ : st) { + } +} +BENCHMARK(BM_MultipleRanges)->Ranges({{5, 5}, {6, 6}}); + +BENCHMARK_MAIN(); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/options_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/options_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..7bfc235465b1715e01755f75b53fd094acdf0bb8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/options_test.cc @@ -0,0 +1,75 @@ +#include "benchmark/benchmark.h" +#include +#include + +#if defined(NDEBUG) +#undef NDEBUG +#endif +#include + +void BM_basic(benchmark::State& state) { + for (auto _ : state) { + } +} + +void BM_basic_slow(benchmark::State& state) { + std::chrono::milliseconds sleep_duration(state.range(0)); + for (auto _ : state) { + std::this_thread::sleep_for( + std::chrono::duration_cast(sleep_duration)); + } +} + +BENCHMARK(BM_basic); +BENCHMARK(BM_basic)->Arg(42); +BENCHMARK(BM_basic_slow)->Arg(10)->Unit(benchmark::kNanosecond); +BENCHMARK(BM_basic_slow)->Arg(100)->Unit(benchmark::kMicrosecond); +BENCHMARK(BM_basic_slow)->Arg(1000)->Unit(benchmark::kMillisecond); +BENCHMARK(BM_basic)->Range(1, 8); +BENCHMARK(BM_basic)->RangeMultiplier(2)->Range(1, 8); +BENCHMARK(BM_basic)->DenseRange(10, 15); +BENCHMARK(BM_basic)->Args({42, 42}); +BENCHMARK(BM_basic)->Ranges({{64, 512}, {64, 512}}); +BENCHMARK(BM_basic)->MinTime(0.7); +BENCHMARK(BM_basic)->UseRealTime(); +BENCHMARK(BM_basic)->ThreadRange(2, 4); +BENCHMARK(BM_basic)->ThreadPerCpu(); +BENCHMARK(BM_basic)->Repetitions(3); +BENCHMARK(BM_basic) + ->RangeMultiplier(std::numeric_limits::max()) + ->Range(std::numeric_limits::min(), + std::numeric_limits::max()); + +// Negative ranges +BENCHMARK(BM_basic)->Range(-64, -1); +BENCHMARK(BM_basic)->RangeMultiplier(4)->Range(-8, 8); +BENCHMARK(BM_basic)->DenseRange(-2, 2, 1); +BENCHMARK(BM_basic)->Ranges({{-64, 1}, {-8, -1}}); + +void CustomArgs(benchmark::internal::Benchmark* b) { + for (int i = 0; i < 10; ++i) { + b->Arg(i); + } +} + +BENCHMARK(BM_basic)->Apply(CustomArgs); + +void BM_explicit_iteration_count(benchmark::State& state) { + // Test that benchmarks specified with an explicit iteration count are + // only run once. + static bool invoked_before = false; + assert(!invoked_before); + invoked_before = true; + + // Test that the requested iteration count is respected. + assert(state.max_iterations == 42); + size_t actual_iterations = 0; + for (auto _ : state) + ++actual_iterations; + assert(state.iterations() == state.max_iterations); + assert(state.iterations() == 42); + +} +BENCHMARK(BM_explicit_iteration_count)->Iterations(42); + +BENCHMARK_MAIN(); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/output_test.h b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/output_test.h new file mode 100644 index 0000000000000000000000000000000000000000..9385761b214c784745f97976344a6a1e97b5681c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/output_test.h @@ -0,0 +1,213 @@ +#ifndef TEST_OUTPUT_TEST_H +#define TEST_OUTPUT_TEST_H + +#undef NDEBUG +#include +#include +#include +#include +#include +#include +#include + +#include "../src/re.h" +#include "benchmark/benchmark.h" + +#define CONCAT2(x, y) x##y +#define CONCAT(x, y) CONCAT2(x, y) + +#define ADD_CASES(...) int CONCAT(dummy, __LINE__) = ::AddCases(__VA_ARGS__) + +#define SET_SUBSTITUTIONS(...) \ + int CONCAT(dummy, __LINE__) = ::SetSubstitutions(__VA_ARGS__) + +enum MatchRules { + MR_Default, // Skip non-matching lines until a match is found. + MR_Next, // Match must occur on the next line. + MR_Not // No line between the current position and the next match matches + // the regex +}; + +struct TestCase { + TestCase(std::string re, int rule = MR_Default); + + std::string regex_str; + int match_rule; + std::string substituted_regex; + std::shared_ptr regex; +}; + +enum TestCaseID { + TC_ConsoleOut, + TC_ConsoleErr, + TC_JSONOut, + TC_JSONErr, + TC_CSVOut, + TC_CSVErr, + + TC_NumID // PRIVATE +}; + +// Add a list of test cases to be run against the output specified by +// 'ID' +int AddCases(TestCaseID ID, std::initializer_list il); + +// Add or set a list of substitutions to be performed on constructed regex's +// See 'output_test_helper.cc' for a list of default substitutions. +int SetSubstitutions( + std::initializer_list> il); + +// Run all output tests. +void RunOutputTests(int argc, char* argv[]); + +// Count the number of 'pat' substrings in the 'haystack' string. +int SubstrCnt(const std::string& haystack, const std::string& pat); + +// Run registered benchmarks with file reporter enabled, and return the content +// outputted by the file reporter. +std::string GetFileReporterOutput(int argc, char* argv[]); + +// ========================================================================= // +// ------------------------- Results checking ------------------------------ // +// ========================================================================= // + +// Call this macro to register a benchmark for checking its results. This +// should be all that's needed. It subscribes a function to check the (CSV) +// results of a benchmark. This is done only after verifying that the output +// strings are really as expected. +// bm_name_pattern: a name or a regex pattern which will be matched against +// all the benchmark names. Matching benchmarks +// will be the subject of a call to checker_function +// checker_function: should be of type ResultsCheckFn (see below) +#define CHECK_BENCHMARK_RESULTS(bm_name_pattern, checker_function) \ + size_t CONCAT(dummy, __LINE__) = AddChecker(bm_name_pattern, checker_function) + +struct Results; +typedef std::function ResultsCheckFn; + +size_t AddChecker(const char* bm_name_pattern, ResultsCheckFn fn); + +// Class holding the results of a benchmark. +// It is passed in calls to checker functions. +struct Results { + // the benchmark name + std::string name; + // the benchmark fields + std::map values; + + Results(const std::string& n) : name(n) {} + + int NumThreads() const; + + double NumIterations() const; + + typedef enum { kCpuTime, kRealTime } BenchmarkTime; + + // get cpu_time or real_time in seconds + double GetTime(BenchmarkTime which) const; + + // get the real_time duration of the benchmark in seconds. + // it is better to use fuzzy float checks for this, as the float + // ASCII formatting is lossy. + double DurationRealTime() const { + return NumIterations() * GetTime(kRealTime); + } + // get the cpu_time duration of the benchmark in seconds + double DurationCPUTime() const { + return NumIterations() * GetTime(kCpuTime); + } + + // get the string for a result by name, or nullptr if the name + // is not found + const std::string* Get(const char* entry_name) const { + auto it = values.find(entry_name); + if (it == values.end()) return nullptr; + return &it->second; + } + + // get a result by name, parsed as a specific type. + // NOTE: for counters, use GetCounterAs instead. + template + T GetAs(const char* entry_name) const; + + // counters are written as doubles, so they have to be read first + // as a double, and only then converted to the asked type. + template + T GetCounterAs(const char* entry_name) const { + double dval = GetAs(entry_name); + T tval = static_cast(dval); + return tval; + } +}; + +template +T Results::GetAs(const char* entry_name) const { + auto* sv = Get(entry_name); + CHECK(sv != nullptr && !sv->empty()); + std::stringstream ss; + ss << *sv; + T out; + ss >> out; + CHECK(!ss.fail()); + return out; +} + +//---------------------------------- +// Macros to help in result checking. Do not use them with arguments causing +// side-effects. + +// clang-format off + +#define _CHECK_RESULT_VALUE(entry, getfn, var_type, var_name, relationship, value) \ + CONCAT(CHECK_, relationship) \ + (entry.getfn< var_type >(var_name), (value)) << "\n" \ + << __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n" \ + << __FILE__ << ":" << __LINE__ << ": " \ + << "expected (" << #var_type << ")" << (var_name) \ + << "=" << (entry).getfn< var_type >(var_name) \ + << " to be " #relationship " to " << (value) << "\n" + +// check with tolerance. eps_factor is the tolerance window, which is +// interpreted relative to value (eg, 0.1 means 10% of value). +#define _CHECK_FLOAT_RESULT_VALUE(entry, getfn, var_type, var_name, relationship, value, eps_factor) \ + CONCAT(CHECK_FLOAT_, relationship) \ + (entry.getfn< var_type >(var_name), (value), (eps_factor) * (value)) << "\n" \ + << __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n" \ + << __FILE__ << ":" << __LINE__ << ": " \ + << "expected (" << #var_type << ")" << (var_name) \ + << "=" << (entry).getfn< var_type >(var_name) \ + << " to be " #relationship " to " << (value) << "\n" \ + << __FILE__ << ":" << __LINE__ << ": " \ + << "with tolerance of " << (eps_factor) * (value) \ + << " (" << (eps_factor)*100. << "%), " \ + << "but delta was " << ((entry).getfn< var_type >(var_name) - (value)) \ + << " (" << (((entry).getfn< var_type >(var_name) - (value)) \ + / \ + ((value) > 1.e-5 || value < -1.e-5 ? value : 1.e-5)*100.) \ + << "%)" + +#define CHECK_RESULT_VALUE(entry, var_type, var_name, relationship, value) \ + _CHECK_RESULT_VALUE(entry, GetAs, var_type, var_name, relationship, value) + +#define CHECK_COUNTER_VALUE(entry, var_type, var_name, relationship, value) \ + _CHECK_RESULT_VALUE(entry, GetCounterAs, var_type, var_name, relationship, value) + +#define CHECK_FLOAT_RESULT_VALUE(entry, var_name, relationship, value, eps_factor) \ + _CHECK_FLOAT_RESULT_VALUE(entry, GetAs, double, var_name, relationship, value, eps_factor) + +#define CHECK_FLOAT_COUNTER_VALUE(entry, var_name, relationship, value, eps_factor) \ + _CHECK_FLOAT_RESULT_VALUE(entry, GetCounterAs, double, var_name, relationship, value, eps_factor) + +// clang-format on + +// ========================================================================= // +// --------------------------- Misc Utilities ------------------------------ // +// ========================================================================= // + +namespace { + +const char* const dec_re = "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"; + +} // end namespace + +#endif // TEST_OUTPUT_TEST_H diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/output_test_helper.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/output_test_helper.cc new file mode 100644 index 0000000000000000000000000000000000000000..f99b3a826134757c458a576d1b9b36d3e09a5e68 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/output_test_helper.cc @@ -0,0 +1,515 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../src/benchmark_api_internal.h" +#include "../src/check.h" // NOTE: check.h is for internal use only! +#include "../src/re.h" // NOTE: re.h is for internal use only +#include "output_test.h" + +// ========================================================================= // +// ------------------------------ Internals -------------------------------- // +// ========================================================================= // +namespace internal { +namespace { + +using TestCaseList = std::vector; + +// Use a vector because the order elements are added matters during iteration. +// std::map/unordered_map don't guarantee that. +// For example: +// SetSubstitutions({{"%HelloWorld", "Hello"}, {"%Hello", "Hi"}}); +// Substitute("%HelloWorld") // Always expands to Hello. +using SubMap = std::vector>; + +TestCaseList& GetTestCaseList(TestCaseID ID) { + // Uses function-local statics to ensure initialization occurs + // before first use. + static TestCaseList lists[TC_NumID]; + return lists[ID]; +} + +SubMap& GetSubstitutions() { + // Don't use 'dec_re' from header because it may not yet be initialized. + // clang-format off + static std::string safe_dec_re = "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"; + static std::string time_re = "([0-9]+[.])?[0-9]+"; + static SubMap map = { + {"%float", "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"}, + // human-readable float + {"%hrfloat", "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?[kMGTPEZYmunpfazy]?"}, + {"%int", "[ ]*[0-9]+"}, + {" %s ", "[ ]+"}, + {"%time", "[ ]*" + time_re + "[ ]+ns"}, + {"%console_report", "[ ]*" + time_re + "[ ]+ns [ ]*" + time_re + "[ ]+ns [ ]*[0-9]+"}, + {"%console_time_only_report", "[ ]*" + time_re + "[ ]+ns [ ]*" + time_re + "[ ]+ns"}, + {"%console_us_report", "[ ]*" + time_re + "[ ]+us [ ]*" + time_re + "[ ]+us [ ]*[0-9]+"}, + {"%console_us_time_only_report", "[ ]*" + time_re + "[ ]+us [ ]*" + time_re + "[ ]+us"}, + {"%csv_header", + "name,iterations,real_time,cpu_time,time_unit,bytes_per_second," + "items_per_second,label,error_occurred,error_message"}, + {"%csv_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns,,,,,"}, + {"%csv_us_report", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",us,,,,,"}, + {"%csv_bytes_report", + "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns," + safe_dec_re + ",,,,"}, + {"%csv_items_report", + "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns,," + safe_dec_re + ",,,"}, + {"%csv_bytes_items_report", + "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns," + safe_dec_re + + "," + safe_dec_re + ",,,"}, + {"%csv_label_report_begin", "[0-9]+," + safe_dec_re + "," + safe_dec_re + ",ns,,,"}, + {"%csv_label_report_end", ",,"}}; + // clang-format on + return map; +} + +std::string PerformSubstitutions(std::string source) { + SubMap const& subs = GetSubstitutions(); + using SizeT = std::string::size_type; + for (auto const& KV : subs) { + SizeT pos; + SizeT next_start = 0; + while ((pos = source.find(KV.first, next_start)) != std::string::npos) { + next_start = pos + KV.second.size(); + source.replace(pos, KV.first.size(), KV.second); + } + } + return source; +} + +void CheckCase(std::stringstream& remaining_output, TestCase const& TC, + TestCaseList const& not_checks) { + std::string first_line; + bool on_first = true; + std::string line; + while (remaining_output.eof() == false) { + CHECK(remaining_output.good()); + std::getline(remaining_output, line); + if (on_first) { + first_line = line; + on_first = false; + } + for (const auto& NC : not_checks) { + CHECK(!NC.regex->Match(line)) + << "Unexpected match for line \"" << line << "\" for MR_Not regex \"" + << NC.regex_str << "\"" + << "\n actual regex string \"" << TC.substituted_regex << "\"" + << "\n started matching near: " << first_line; + } + if (TC.regex->Match(line)) return; + CHECK(TC.match_rule != MR_Next) + << "Expected line \"" << line << "\" to match regex \"" << TC.regex_str + << "\"" + << "\n actual regex string \"" << TC.substituted_regex << "\"" + << "\n started matching near: " << first_line; + } + CHECK(remaining_output.eof() == false) + << "End of output reached before match for regex \"" << TC.regex_str + << "\" was found" + << "\n actual regex string \"" << TC.substituted_regex << "\"" + << "\n started matching near: " << first_line; +} + +void CheckCases(TestCaseList const& checks, std::stringstream& output) { + std::vector not_checks; + for (size_t i = 0; i < checks.size(); ++i) { + const auto& TC = checks[i]; + if (TC.match_rule == MR_Not) { + not_checks.push_back(TC); + continue; + } + CheckCase(output, TC, not_checks); + not_checks.clear(); + } +} + +class TestReporter : public benchmark::BenchmarkReporter { + public: + TestReporter(std::vector reps) + : reporters_(reps) {} + + virtual bool ReportContext(const Context& context) { + bool last_ret = false; + bool first = true; + for (auto rep : reporters_) { + bool new_ret = rep->ReportContext(context); + CHECK(first || new_ret == last_ret) + << "Reports return different values for ReportContext"; + first = false; + last_ret = new_ret; + } + (void)first; + return last_ret; + } + + void ReportRuns(const std::vector& report) { + for (auto rep : reporters_) rep->ReportRuns(report); + } + void Finalize() { + for (auto rep : reporters_) rep->Finalize(); + } + + private: + std::vector reporters_; +}; +} // namespace + +} // end namespace internal + +// ========================================================================= // +// -------------------------- Results checking ----------------------------- // +// ========================================================================= // + +namespace internal { + +// Utility class to manage subscribers for checking benchmark results. +// It works by parsing the CSV output to read the results. +class ResultsChecker { + public: + struct PatternAndFn : public TestCase { // reusing TestCase for its regexes + PatternAndFn(const std::string& rx, ResultsCheckFn fn_) + : TestCase(rx), fn(fn_) {} + ResultsCheckFn fn; + }; + + std::vector check_patterns; + std::vector results; + std::vector field_names; + + void Add(const std::string& entry_pattern, ResultsCheckFn fn); + + void CheckResults(std::stringstream& output); + + private: + void SetHeader_(const std::string& csv_header); + void SetValues_(const std::string& entry_csv_line); + + std::vector SplitCsv_(const std::string& line); +}; + +// store the static ResultsChecker in a function to prevent initialization +// order problems +ResultsChecker& GetResultsChecker() { + static ResultsChecker rc; + return rc; +} + +// add a results checker for a benchmark +void ResultsChecker::Add(const std::string& entry_pattern, ResultsCheckFn fn) { + check_patterns.emplace_back(entry_pattern, fn); +} + +// check the results of all subscribed benchmarks +void ResultsChecker::CheckResults(std::stringstream& output) { + // first reset the stream to the start + { + auto start = std::stringstream::pos_type(0); + // clear before calling tellg() + output.clear(); + // seek to zero only when needed + if (output.tellg() > start) output.seekg(start); + // and just in case + output.clear(); + } + // now go over every line and publish it to the ResultsChecker + std::string line; + bool on_first = true; + while (output.eof() == false) { + CHECK(output.good()); + std::getline(output, line); + if (on_first) { + SetHeader_(line); // this is important + on_first = false; + continue; + } + SetValues_(line); + } + // finally we can call the subscribed check functions + for (const auto& p : check_patterns) { + VLOG(2) << "--------------------------------\n"; + VLOG(2) << "checking for benchmarks matching " << p.regex_str << "...\n"; + for (const auto& r : results) { + if (!p.regex->Match(r.name)) { + VLOG(2) << p.regex_str << " is not matched by " << r.name << "\n"; + continue; + } else { + VLOG(2) << p.regex_str << " is matched by " << r.name << "\n"; + } + VLOG(1) << "Checking results of " << r.name << ": ... \n"; + p.fn(r); + VLOG(1) << "Checking results of " << r.name << ": OK.\n"; + } + } +} + +// prepare for the names in this header +void ResultsChecker::SetHeader_(const std::string& csv_header) { + field_names = SplitCsv_(csv_header); +} + +// set the values for a benchmark +void ResultsChecker::SetValues_(const std::string& entry_csv_line) { + if (entry_csv_line.empty()) return; // some lines are empty + CHECK(!field_names.empty()); + auto vals = SplitCsv_(entry_csv_line); + CHECK_EQ(vals.size(), field_names.size()); + results.emplace_back(vals[0]); // vals[0] is the benchmark name + auto& entry = results.back(); + for (size_t i = 1, e = vals.size(); i < e; ++i) { + entry.values[field_names[i]] = vals[i]; + } +} + +// a quick'n'dirty csv splitter (eliminating quotes) +std::vector ResultsChecker::SplitCsv_(const std::string& line) { + std::vector out; + if (line.empty()) return out; + if (!field_names.empty()) out.reserve(field_names.size()); + size_t prev = 0, pos = line.find_first_of(','), curr = pos; + while (pos != line.npos) { + CHECK(curr > 0); + if (line[prev] == '"') ++prev; + if (line[curr - 1] == '"') --curr; + out.push_back(line.substr(prev, curr - prev)); + prev = pos + 1; + pos = line.find_first_of(',', pos + 1); + curr = pos; + } + curr = line.size(); + if (line[prev] == '"') ++prev; + if (line[curr - 1] == '"') --curr; + out.push_back(line.substr(prev, curr - prev)); + return out; +} + +} // end namespace internal + +size_t AddChecker(const char* bm_name, ResultsCheckFn fn) { + auto& rc = internal::GetResultsChecker(); + rc.Add(bm_name, fn); + return rc.results.size(); +} + +int Results::NumThreads() const { + auto pos = name.find("/threads:"); + if (pos == name.npos) return 1; + auto end = name.find('/', pos + 9); + std::stringstream ss; + ss << name.substr(pos + 9, end); + int num = 1; + ss >> num; + CHECK(!ss.fail()); + return num; +} + +double Results::NumIterations() const { + return GetAs("iterations"); +} + +double Results::GetTime(BenchmarkTime which) const { + CHECK(which == kCpuTime || which == kRealTime); + const char* which_str = which == kCpuTime ? "cpu_time" : "real_time"; + double val = GetAs(which_str); + auto unit = Get("time_unit"); + CHECK(unit); + if (*unit == "ns") { + return val * 1.e-9; + } else if (*unit == "us") { + return val * 1.e-6; + } else if (*unit == "ms") { + return val * 1.e-3; + } else if (*unit == "s") { + return val; + } else { + CHECK(1 == 0) << "unknown time unit: " << *unit; + return 0; + } +} + +// ========================================================================= // +// -------------------------- Public API Definitions------------------------ // +// ========================================================================= // + +TestCase::TestCase(std::string re, int rule) + : regex_str(std::move(re)), + match_rule(rule), + substituted_regex(internal::PerformSubstitutions(regex_str)), + regex(std::make_shared()) { + std::string err_str; + regex->Init(substituted_regex, &err_str); + CHECK(err_str.empty()) << "Could not construct regex \"" << substituted_regex + << "\"" + << "\n originally \"" << regex_str << "\"" + << "\n got error: " << err_str; +} + +int AddCases(TestCaseID ID, std::initializer_list il) { + auto& L = internal::GetTestCaseList(ID); + L.insert(L.end(), il); + return 0; +} + +int SetSubstitutions( + std::initializer_list> il) { + auto& subs = internal::GetSubstitutions(); + for (auto KV : il) { + bool exists = false; + KV.second = internal::PerformSubstitutions(KV.second); + for (auto& EKV : subs) { + if (EKV.first == KV.first) { + EKV.second = std::move(KV.second); + exists = true; + break; + } + } + if (!exists) subs.push_back(std::move(KV)); + } + return 0; +} + +// Disable deprecated warnings temporarily because we need to reference +// CSVReporter but don't want to trigger -Werror=-Wdeprecated-declarations +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif +void RunOutputTests(int argc, char* argv[]) { + using internal::GetTestCaseList; + benchmark::Initialize(&argc, argv); + auto options = benchmark::internal::GetOutputOptions(/*force_no_color*/ true); + benchmark::ConsoleReporter CR(options); + benchmark::JSONReporter JR; + benchmark::CSVReporter CSVR; + struct ReporterTest { + const char* name; + std::vector& output_cases; + std::vector& error_cases; + benchmark::BenchmarkReporter& reporter; + std::stringstream out_stream; + std::stringstream err_stream; + + ReporterTest(const char* n, std::vector& out_tc, + std::vector& err_tc, + benchmark::BenchmarkReporter& br) + : name(n), output_cases(out_tc), error_cases(err_tc), reporter(br) { + reporter.SetOutputStream(&out_stream); + reporter.SetErrorStream(&err_stream); + } + } TestCases[] = { + {"ConsoleReporter", GetTestCaseList(TC_ConsoleOut), + GetTestCaseList(TC_ConsoleErr), CR}, + {"JSONReporter", GetTestCaseList(TC_JSONOut), GetTestCaseList(TC_JSONErr), + JR}, + {"CSVReporter", GetTestCaseList(TC_CSVOut), GetTestCaseList(TC_CSVErr), + CSVR}, + }; + + // Create the test reporter and run the benchmarks. + std::cout << "Running benchmarks...\n"; + internal::TestReporter test_rep({&CR, &JR, &CSVR}); + benchmark::RunSpecifiedBenchmarks(&test_rep); + + for (auto& rep_test : TestCases) { + std::string msg = std::string("\nTesting ") + rep_test.name + " Output\n"; + std::string banner(msg.size() - 1, '-'); + std::cout << banner << msg << banner << "\n"; + + std::cerr << rep_test.err_stream.str(); + std::cout << rep_test.out_stream.str(); + + internal::CheckCases(rep_test.error_cases, rep_test.err_stream); + internal::CheckCases(rep_test.output_cases, rep_test.out_stream); + + std::cout << "\n"; + } + + // now that we know the output is as expected, we can dispatch + // the checks to subscribees. + auto& csv = TestCases[2]; + // would use == but gcc spits a warning + CHECK(std::strcmp(csv.name, "CSVReporter") == 0); + internal::GetResultsChecker().CheckResults(csv.out_stream); +} + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +int SubstrCnt(const std::string& haystack, const std::string& pat) { + if (pat.length() == 0) return 0; + int count = 0; + for (size_t offset = haystack.find(pat); offset != std::string::npos; + offset = haystack.find(pat, offset + pat.length())) + ++count; + return count; +} + +static char ToHex(int ch) { + return ch < 10 ? static_cast('0' + ch) + : static_cast('a' + (ch - 10)); +} + +static char RandomHexChar() { + static std::mt19937 rd{std::random_device{}()}; + static std::uniform_int_distribution mrand{0, 15}; + return ToHex(mrand(rd)); +} + +static std::string GetRandomFileName() { + std::string model = "test.%%%%%%"; + for (auto & ch : model) { + if (ch == '%') + ch = RandomHexChar(); + } + return model; +} + +static bool FileExists(std::string const& name) { + std::ifstream in(name.c_str()); + return in.good(); +} + +static std::string GetTempFileName() { + // This function attempts to avoid race conditions where two tests + // create the same file at the same time. However, it still introduces races + // similar to tmpnam. + int retries = 3; + while (--retries) { + std::string name = GetRandomFileName(); + if (!FileExists(name)) + return name; + } + std::cerr << "Failed to create unique temporary file name" << std::endl; + std::abort(); +} + +std::string GetFileReporterOutput(int argc, char* argv[]) { + std::vector new_argv(argv, argv + argc); + assert(static_cast(argc) == new_argv.size()); + + std::string tmp_file_name = GetTempFileName(); + std::cout << "Will be using this as the tmp file: " << tmp_file_name << '\n'; + + std::string tmp = "--benchmark_out="; + tmp += tmp_file_name; + new_argv.emplace_back(const_cast(tmp.c_str())); + + argc = int(new_argv.size()); + + benchmark::Initialize(&argc, new_argv.data()); + benchmark::RunSpecifiedBenchmarks(); + + // Read the output back from the file, and delete the file. + std::ifstream tmp_stream(tmp_file_name); + std::string output = std::string((std::istreambuf_iterator(tmp_stream)), + std::istreambuf_iterator()); + std::remove(tmp_file_name.c_str()); + + return output; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/register_benchmark_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/register_benchmark_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..3ac5b21fb348b0b884ac57fa7502c3d4be90aec4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/register_benchmark_test.cc @@ -0,0 +1,184 @@ + +#undef NDEBUG +#include +#include + +#include "../src/check.h" // NOTE: check.h is for internal use only! +#include "benchmark/benchmark.h" + +namespace { + +class TestReporter : public benchmark::ConsoleReporter { + public: + virtual void ReportRuns(const std::vector& report) { + all_runs_.insert(all_runs_.end(), begin(report), end(report)); + ConsoleReporter::ReportRuns(report); + } + + std::vector all_runs_; +}; + +struct TestCase { + std::string name; + const char* label; + // Note: not explicit as we rely on it being converted through ADD_CASES. + TestCase(const char* xname) : TestCase(xname, nullptr) {} + TestCase(const char* xname, const char* xlabel) + : name(xname), label(xlabel) {} + + typedef benchmark::BenchmarkReporter::Run Run; + + void CheckRun(Run const& run) const { + // clang-format off + CHECK(name == run.benchmark_name()) << "expected " << name << " got " + << run.benchmark_name(); + if (label) { + CHECK(run.report_label == label) << "expected " << label << " got " + << run.report_label; + } else { + CHECK(run.report_label == ""); + } + // clang-format on + } +}; + +std::vector ExpectedResults; + +int AddCases(std::initializer_list const& v) { + for (auto N : v) { + ExpectedResults.push_back(N); + } + return 0; +} + +#define CONCAT(x, y) CONCAT2(x, y) +#define CONCAT2(x, y) x##y +#define ADD_CASES(...) int CONCAT(dummy, __LINE__) = AddCases({__VA_ARGS__}) + +} // end namespace + +typedef benchmark::internal::Benchmark* ReturnVal; + +//----------------------------------------------------------------------------// +// Test RegisterBenchmark with no additional arguments +//----------------------------------------------------------------------------// +void BM_function(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_function); +ReturnVal dummy = benchmark::RegisterBenchmark( + "BM_function_manual_registration", BM_function); +ADD_CASES({"BM_function"}, {"BM_function_manual_registration"}); + +//----------------------------------------------------------------------------// +// Test RegisterBenchmark with additional arguments +// Note: GCC <= 4.8 do not support this form of RegisterBenchmark because they +// reject the variadic pack expansion of lambda captures. +//----------------------------------------------------------------------------// +#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK + +void BM_extra_args(benchmark::State& st, const char* label) { + for (auto _ : st) { + } + st.SetLabel(label); +} +int RegisterFromFunction() { + std::pair cases[] = { + {"test1", "One"}, {"test2", "Two"}, {"test3", "Three"}}; + for (auto const& c : cases) + benchmark::RegisterBenchmark(c.first, &BM_extra_args, c.second); + return 0; +} +int dummy2 = RegisterFromFunction(); +ADD_CASES({"test1", "One"}, {"test2", "Two"}, {"test3", "Three"}); + +#endif // BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK + +//----------------------------------------------------------------------------// +// Test RegisterBenchmark with different callable types +//----------------------------------------------------------------------------// + +struct CustomFixture { + void operator()(benchmark::State& st) { + for (auto _ : st) { + } + } +}; + +void TestRegistrationAtRuntime() { +#ifdef BENCHMARK_HAS_CXX11 + { + CustomFixture fx; + benchmark::RegisterBenchmark("custom_fixture", fx); + AddCases({"custom_fixture"}); + } +#endif +#ifndef BENCHMARK_HAS_NO_VARIADIC_REGISTER_BENCHMARK + { + const char* x = "42"; + auto capturing_lam = [=](benchmark::State& st) { + for (auto _ : st) { + } + st.SetLabel(x); + }; + benchmark::RegisterBenchmark("lambda_benchmark", capturing_lam); + AddCases({{"lambda_benchmark", x}}); + } +#endif +} + +// Test that all benchmarks, registered at either during static init or runtime, +// are run and the results are passed to the reported. +void RunTestOne() { + TestRegistrationAtRuntime(); + + TestReporter test_reporter; + benchmark::RunSpecifiedBenchmarks(&test_reporter); + + typedef benchmark::BenchmarkReporter::Run Run; + auto EB = ExpectedResults.begin(); + + for (Run const& run : test_reporter.all_runs_) { + assert(EB != ExpectedResults.end()); + EB->CheckRun(run); + ++EB; + } + assert(EB == ExpectedResults.end()); +} + +// Test that ClearRegisteredBenchmarks() clears all previously registered +// benchmarks. +// Also test that new benchmarks can be registered and ran afterwards. +void RunTestTwo() { + assert(ExpectedResults.size() != 0 && + "must have at least one registered benchmark"); + ExpectedResults.clear(); + benchmark::ClearRegisteredBenchmarks(); + + TestReporter test_reporter; + size_t num_ran = benchmark::RunSpecifiedBenchmarks(&test_reporter); + assert(num_ran == 0); + assert(test_reporter.all_runs_.begin() == test_reporter.all_runs_.end()); + + TestRegistrationAtRuntime(); + num_ran = benchmark::RunSpecifiedBenchmarks(&test_reporter); + assert(num_ran == ExpectedResults.size()); + + typedef benchmark::BenchmarkReporter::Run Run; + auto EB = ExpectedResults.begin(); + + for (Run const& run : test_reporter.all_runs_) { + assert(EB != ExpectedResults.end()); + EB->CheckRun(run); + ++EB; + } + assert(EB == ExpectedResults.end()); +} + +int main(int argc, char* argv[]) { + benchmark::Initialize(&argc, argv); + + RunTestOne(); + RunTestTwo(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/report_aggregates_only_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/report_aggregates_only_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..9646b9be534ddac7261982b9330ea2946a017315 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/report_aggregates_only_test.cc @@ -0,0 +1,39 @@ + +#undef NDEBUG +#include +#include + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// Ok this test is super ugly. We want to check what happens with the file +// reporter in the presence of ReportAggregatesOnly(). +// We do not care about console output, the normal tests check that already. + +void BM_SummaryRepeat(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_SummaryRepeat)->Repetitions(3)->ReportAggregatesOnly(); + +int main(int argc, char* argv[]) { + const std::string output = GetFileReporterOutput(argc, argv); + + if (SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3") != 3 || + SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_mean\"") != 1 || + SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_median\"") != + 1 || + SubstrCnt(output, "\"name\": \"BM_SummaryRepeat/repeats:3_stddev\"") != + 1) { + std::cout << "Precondition mismatch. Expected to only find three " + "occurrences of \"BM_SummaryRepeat/repeats:3\" substring:\n" + "\"name\": \"BM_SummaryRepeat/repeats:3_mean\", " + "\"name\": \"BM_SummaryRepeat/repeats:3_median\", " + "\"name\": \"BM_SummaryRepeat/repeats:3_stddev\"\nThe entire " + "output:\n"; + std::cout << output; + return 1; + } + + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/reporter_output_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/reporter_output_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..1a96b5f0bf6117f1d649e3dae41b65eedc1b9171 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/reporter_output_test.cc @@ -0,0 +1,748 @@ + +#undef NDEBUG +#include + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// ========================================================================= // +// ---------------------- Testing Prologue Output -------------------------- // +// ========================================================================= // + +ADD_CASES(TC_ConsoleOut, {{"^[-]+$", MR_Next}, + {"^Benchmark %s Time %s CPU %s Iterations$", MR_Next}, + {"^[-]+$", MR_Next}}); +static int AddContextCases() { + AddCases(TC_ConsoleErr, + { + {"%int[-/]%int[-/]%int %int:%int:%int$", MR_Default}, + {"Running .*/reporter_output_test(\\.exe)?$", MR_Next}, + {"Run on \\(%int X %float MHz CPU s?\\)", MR_Next}, + }); + AddCases(TC_JSONOut, + {{"^\\{", MR_Default}, + {"\"context\":", MR_Next}, + {"\"date\": \"", MR_Next}, + {"\"host_name\":", MR_Next}, + {"\"executable\": \".*(/|\\\\)reporter_output_test(\\.exe)?\",", + MR_Next}, + {"\"num_cpus\": %int,$", MR_Next}, + {"\"mhz_per_cpu\": %float,$", MR_Next}, + {"\"cpu_scaling_enabled\": ", MR_Next}, + {"\"caches\": \\[$", MR_Next}}); + auto const& Info = benchmark::CPUInfo::Get(); + auto const& Caches = Info.caches; + if (!Caches.empty()) { + AddCases(TC_ConsoleErr, {{"CPU Caches:$", MR_Next}}); + } + for (size_t I = 0; I < Caches.size(); ++I) { + std::string num_caches_str = + Caches[I].num_sharing != 0 ? " \\(x%int\\)$" : "$"; + AddCases(TC_ConsoleErr, + {{"L%int (Data|Instruction|Unified) %int KiB" + num_caches_str, + MR_Next}}); + AddCases(TC_JSONOut, {{"\\{$", MR_Next}, + {"\"type\": \"", MR_Next}, + {"\"level\": %int,$", MR_Next}, + {"\"size\": %int,$", MR_Next}, + {"\"num_sharing\": %int$", MR_Next}, + {"}[,]{0,1}$", MR_Next}}); + } + AddCases(TC_JSONOut, {{"],$"}}); + auto const& LoadAvg = Info.load_avg; + if (!LoadAvg.empty()) { + AddCases(TC_ConsoleErr, + {{"Load Average: (%float, ){0,2}%float$", MR_Next}}); + } + AddCases(TC_JSONOut, {{"\"load_avg\": \\[(%float,?){0,3}],$", MR_Next}}); + return 0; +} +int dummy_register = AddContextCases(); +ADD_CASES(TC_CSVOut, {{"%csv_header"}}); + +// ========================================================================= // +// ------------------------ Testing Basic Output --------------------------- // +// ========================================================================= // + +void BM_basic(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_basic); + +ADD_CASES(TC_ConsoleOut, {{"^BM_basic %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_basic\",$"}, + {"\"run_name\": \"BM_basic\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\"$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_basic\",%csv_report$"}}); + +// ========================================================================= // +// ------------------------ Testing Bytes per Second Output ---------------- // +// ========================================================================= // + +void BM_bytes_per_second(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + state.SetBytesProcessed(1); +} +BENCHMARK(BM_bytes_per_second); + +ADD_CASES(TC_ConsoleOut, {{"^BM_bytes_per_second %console_report " + "bytes_per_second=%float[kM]{0,1}/s$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_bytes_per_second\",$"}, + {"\"run_name\": \"BM_bytes_per_second\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bytes_per_second\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_bytes_per_second\",%csv_bytes_report$"}}); + +// ========================================================================= // +// ------------------------ Testing Items per Second Output ---------------- // +// ========================================================================= // + +void BM_items_per_second(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + state.SetItemsProcessed(1); +} +BENCHMARK(BM_items_per_second); + +ADD_CASES(TC_ConsoleOut, {{"^BM_items_per_second %console_report " + "items_per_second=%float[kM]{0,1}/s$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_items_per_second\",$"}, + {"\"run_name\": \"BM_items_per_second\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"items_per_second\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_items_per_second\",%csv_items_report$"}}); + +// ========================================================================= // +// ------------------------ Testing Label Output --------------------------- // +// ========================================================================= // + +void BM_label(benchmark::State& state) { + for (auto _ : state) { + } + state.SetLabel("some label"); +} +BENCHMARK(BM_label); + +ADD_CASES(TC_ConsoleOut, {{"^BM_label %console_report some label$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_label\",$"}, + {"\"run_name\": \"BM_label\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"label\": \"some label\"$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_label\",%csv_label_report_begin\"some " + "label\"%csv_label_report_end$"}}); + +// ========================================================================= // +// ------------------------ Testing Error Output --------------------------- // +// ========================================================================= // + +void BM_error(benchmark::State& state) { + state.SkipWithError("message"); + for (auto _ : state) { + } +} +BENCHMARK(BM_error); +ADD_CASES(TC_ConsoleOut, {{"^BM_error[ ]+ERROR OCCURRED: 'message'$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_error\",$"}, + {"\"run_name\": \"BM_error\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"error_occurred\": true,$", MR_Next}, + {"\"error_message\": \"message\",$", MR_Next}}); + +ADD_CASES(TC_CSVOut, {{"^\"BM_error\",,,,,,,,true,\"message\"$"}}); + +// ========================================================================= // +// ------------------------ Testing No Arg Name Output ----------------------- +// // +// ========================================================================= // + +void BM_no_arg_name(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_no_arg_name)->Arg(3); +ADD_CASES(TC_ConsoleOut, {{"^BM_no_arg_name/3 %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_no_arg_name/3\",$"}, + {"\"run_name\": \"BM_no_arg_name/3\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_no_arg_name/3\",%csv_report$"}}); + +// ========================================================================= // +// ------------------------ Testing Arg Name Output ----------------------- // +// ========================================================================= // + +void BM_arg_name(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_arg_name)->ArgName("first")->Arg(3); +ADD_CASES(TC_ConsoleOut, {{"^BM_arg_name/first:3 %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_arg_name/first:3\",$"}, + {"\"run_name\": \"BM_arg_name/first:3\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_arg_name/first:3\",%csv_report$"}}); + +// ========================================================================= // +// ------------------------ Testing Arg Names Output ----------------------- // +// ========================================================================= // + +void BM_arg_names(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_arg_names)->Args({2, 5, 4})->ArgNames({"first", "", "third"}); +ADD_CASES(TC_ConsoleOut, + {{"^BM_arg_names/first:2/5/third:4 %console_report$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_arg_names/first:2/5/third:4\",$"}, + {"\"run_name\": \"BM_arg_names/first:2/5/third:4\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_arg_names/first:2/5/third:4\",%csv_report$"}}); + +// ========================================================================= // +// ------------------------ Testing Big Args Output ------------------------ // +// ========================================================================= // + +void BM_BigArgs(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_BigArgs)->RangeMultiplier(2)->Range(1U << 30U, 1U << 31U); +ADD_CASES(TC_ConsoleOut, {{"^BM_BigArgs/1073741824 %console_report$"}, + {"^BM_BigArgs/2147483648 %console_report$"}}); + +// ========================================================================= // +// ----------------------- Testing Complexity Output ----------------------- // +// ========================================================================= // + +void BM_Complexity_O1(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + state.SetComplexityN(state.range(0)); +} +BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity(benchmark::o1); +SET_SUBSTITUTIONS({{"%bigOStr", "[ ]* %float \\([0-9]+\\)"}, + {"%RMS", "[ ]*[0-9]+ %"}}); +ADD_CASES(TC_ConsoleOut, {{"^BM_Complexity_O1_BigO %bigOStr %bigOStr[ ]*$"}, + {"^BM_Complexity_O1_RMS %RMS %RMS[ ]*$"}}); + +// ========================================================================= // +// ----------------------- Testing Aggregate Output ------------------------ // +// ========================================================================= // + +// Test that non-aggregate data is printed by default +void BM_Repeat(benchmark::State& state) { + for (auto _ : state) { + } +} +// need two repetitions min to be able to output any aggregate output +BENCHMARK(BM_Repeat)->Repetitions(2); +ADD_CASES(TC_ConsoleOut, + {{"^BM_Repeat/repeats:2 %console_report$"}, + {"^BM_Repeat/repeats:2 %console_report$"}, + {"^BM_Repeat/repeats:2_mean %console_time_only_report [ ]*2$"}, + {"^BM_Repeat/repeats:2_median %console_time_only_report [ ]*2$"}, + {"^BM_Repeat/repeats:2_stddev %console_time_only_report [ ]*2$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Repeat/repeats:2\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:2\"", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:2\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:2\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"repetition_index\": 1,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:2_mean\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:2\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"mean\",$", MR_Next}, + {"\"iterations\": 2,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:2_median\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:2\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"median\",$", MR_Next}, + {"\"iterations\": 2,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:2_stddev\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:2\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"stddev\",$", MR_Next}, + {"\"iterations\": 2,$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Repeat/repeats:2\",%csv_report$"}, + {"^\"BM_Repeat/repeats:2\",%csv_report$"}, + {"^\"BM_Repeat/repeats:2_mean\",%csv_report$"}, + {"^\"BM_Repeat/repeats:2_median\",%csv_report$"}, + {"^\"BM_Repeat/repeats:2_stddev\",%csv_report$"}}); +// but for two repetitions, mean and median is the same, so let's repeat.. +BENCHMARK(BM_Repeat)->Repetitions(3); +ADD_CASES(TC_ConsoleOut, + {{"^BM_Repeat/repeats:3 %console_report$"}, + {"^BM_Repeat/repeats:3 %console_report$"}, + {"^BM_Repeat/repeats:3 %console_report$"}, + {"^BM_Repeat/repeats:3_mean %console_time_only_report [ ]*3$"}, + {"^BM_Repeat/repeats:3_median %console_time_only_report [ ]*3$"}, + {"^BM_Repeat/repeats:3_stddev %console_time_only_report [ ]*3$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Repeat/repeats:3\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:3\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:3\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:3\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"repetition_index\": 1,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:3\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:3\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"repetition_index\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:3_mean\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:3\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"mean\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:3_median\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:3\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"median\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:3_stddev\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:3\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"stddev\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Repeat/repeats:3\",%csv_report$"}, + {"^\"BM_Repeat/repeats:3\",%csv_report$"}, + {"^\"BM_Repeat/repeats:3\",%csv_report$"}, + {"^\"BM_Repeat/repeats:3_mean\",%csv_report$"}, + {"^\"BM_Repeat/repeats:3_median\",%csv_report$"}, + {"^\"BM_Repeat/repeats:3_stddev\",%csv_report$"}}); +// median differs between even/odd number of repetitions, so just to be sure +BENCHMARK(BM_Repeat)->Repetitions(4); +ADD_CASES(TC_ConsoleOut, + {{"^BM_Repeat/repeats:4 %console_report$"}, + {"^BM_Repeat/repeats:4 %console_report$"}, + {"^BM_Repeat/repeats:4 %console_report$"}, + {"^BM_Repeat/repeats:4 %console_report$"}, + {"^BM_Repeat/repeats:4_mean %console_time_only_report [ ]*4$"}, + {"^BM_Repeat/repeats:4_median %console_time_only_report [ ]*4$"}, + {"^BM_Repeat/repeats:4_stddev %console_time_only_report [ ]*4$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Repeat/repeats:4\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:4\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 4,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:4\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:4\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 4,$", MR_Next}, + {"\"repetition_index\": 1,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:4\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:4\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 4,$", MR_Next}, + {"\"repetition_index\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:4\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:4\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 4,$", MR_Next}, + {"\"repetition_index\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:4_mean\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:4\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 4,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"mean\",$", MR_Next}, + {"\"iterations\": 4,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:4_median\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:4\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 4,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"median\",$", MR_Next}, + {"\"iterations\": 4,$", MR_Next}, + {"\"name\": \"BM_Repeat/repeats:4_stddev\",$"}, + {"\"run_name\": \"BM_Repeat/repeats:4\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 4,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"stddev\",$", MR_Next}, + {"\"iterations\": 4,$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Repeat/repeats:4\",%csv_report$"}, + {"^\"BM_Repeat/repeats:4\",%csv_report$"}, + {"^\"BM_Repeat/repeats:4\",%csv_report$"}, + {"^\"BM_Repeat/repeats:4\",%csv_report$"}, + {"^\"BM_Repeat/repeats:4_mean\",%csv_report$"}, + {"^\"BM_Repeat/repeats:4_median\",%csv_report$"}, + {"^\"BM_Repeat/repeats:4_stddev\",%csv_report$"}}); + +// Test that a non-repeated test still prints non-aggregate results even when +// only-aggregate reports have been requested +void BM_RepeatOnce(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_RepeatOnce)->Repetitions(1)->ReportAggregatesOnly(); +ADD_CASES(TC_ConsoleOut, {{"^BM_RepeatOnce/repeats:1 %console_report$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_RepeatOnce/repeats:1\",$"}, + {"\"run_name\": \"BM_RepeatOnce/repeats:1\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 1,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_RepeatOnce/repeats:1\",%csv_report$"}}); + +// Test that non-aggregate data is not reported +void BM_SummaryRepeat(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_SummaryRepeat)->Repetitions(3)->ReportAggregatesOnly(); +ADD_CASES( + TC_ConsoleOut, + {{".*BM_SummaryRepeat/repeats:3 ", MR_Not}, + {"^BM_SummaryRepeat/repeats:3_mean %console_time_only_report [ ]*3$"}, + {"^BM_SummaryRepeat/repeats:3_median %console_time_only_report [ ]*3$"}, + {"^BM_SummaryRepeat/repeats:3_stddev %console_time_only_report [ ]*3$"}}); +ADD_CASES(TC_JSONOut, + {{".*BM_SummaryRepeat/repeats:3 ", MR_Not}, + {"\"name\": \"BM_SummaryRepeat/repeats:3_mean\",$"}, + {"\"run_name\": \"BM_SummaryRepeat/repeats:3\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"mean\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}, + {"\"name\": \"BM_SummaryRepeat/repeats:3_median\",$"}, + {"\"run_name\": \"BM_SummaryRepeat/repeats:3\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"median\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}, + {"\"name\": \"BM_SummaryRepeat/repeats:3_stddev\",$"}, + {"\"run_name\": \"BM_SummaryRepeat/repeats:3\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"stddev\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{".*BM_SummaryRepeat/repeats:3 ", MR_Not}, + {"^\"BM_SummaryRepeat/repeats:3_mean\",%csv_report$"}, + {"^\"BM_SummaryRepeat/repeats:3_median\",%csv_report$"}, + {"^\"BM_SummaryRepeat/repeats:3_stddev\",%csv_report$"}}); + +// Test that non-aggregate data is not displayed. +// NOTE: this test is kinda bad. we are only testing the display output. +// But we don't check that the file output still contains everything... +void BM_SummaryDisplay(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_SummaryDisplay)->Repetitions(2)->DisplayAggregatesOnly(); +ADD_CASES( + TC_ConsoleOut, + {{".*BM_SummaryDisplay/repeats:2 ", MR_Not}, + {"^BM_SummaryDisplay/repeats:2_mean %console_time_only_report [ ]*2$"}, + {"^BM_SummaryDisplay/repeats:2_median %console_time_only_report [ ]*2$"}, + {"^BM_SummaryDisplay/repeats:2_stddev %console_time_only_report [ ]*2$"}}); +ADD_CASES(TC_JSONOut, + {{".*BM_SummaryDisplay/repeats:2 ", MR_Not}, + {"\"name\": \"BM_SummaryDisplay/repeats:2_mean\",$"}, + {"\"run_name\": \"BM_SummaryDisplay/repeats:2\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"mean\",$", MR_Next}, + {"\"iterations\": 2,$", MR_Next}, + {"\"name\": \"BM_SummaryDisplay/repeats:2_median\",$"}, + {"\"run_name\": \"BM_SummaryDisplay/repeats:2\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"median\",$", MR_Next}, + {"\"iterations\": 2,$", MR_Next}, + {"\"name\": \"BM_SummaryDisplay/repeats:2_stddev\",$"}, + {"\"run_name\": \"BM_SummaryDisplay/repeats:2\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"stddev\",$", MR_Next}, + {"\"iterations\": 2,$", MR_Next}}); +ADD_CASES(TC_CSVOut, + {{".*BM_SummaryDisplay/repeats:2 ", MR_Not}, + {"^\"BM_SummaryDisplay/repeats:2_mean\",%csv_report$"}, + {"^\"BM_SummaryDisplay/repeats:2_median\",%csv_report$"}, + {"^\"BM_SummaryDisplay/repeats:2_stddev\",%csv_report$"}}); + +// Test repeats with custom time unit. +void BM_RepeatTimeUnit(benchmark::State& state) { + for (auto _ : state) { + } +} +BENCHMARK(BM_RepeatTimeUnit) + ->Repetitions(3) + ->ReportAggregatesOnly() + ->Unit(benchmark::kMicrosecond); +ADD_CASES( + TC_ConsoleOut, + {{".*BM_RepeatTimeUnit/repeats:3 ", MR_Not}, + {"^BM_RepeatTimeUnit/repeats:3_mean %console_us_time_only_report [ ]*3$"}, + {"^BM_RepeatTimeUnit/repeats:3_median %console_us_time_only_report [ " + "]*3$"}, + {"^BM_RepeatTimeUnit/repeats:3_stddev %console_us_time_only_report [ " + "]*3$"}}); +ADD_CASES(TC_JSONOut, + {{".*BM_RepeatTimeUnit/repeats:3 ", MR_Not}, + {"\"name\": \"BM_RepeatTimeUnit/repeats:3_mean\",$"}, + {"\"run_name\": \"BM_RepeatTimeUnit/repeats:3\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"mean\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}, + {"\"time_unit\": \"us\",?$"}, + {"\"name\": \"BM_RepeatTimeUnit/repeats:3_median\",$"}, + {"\"run_name\": \"BM_RepeatTimeUnit/repeats:3\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"median\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}, + {"\"time_unit\": \"us\",?$"}, + {"\"name\": \"BM_RepeatTimeUnit/repeats:3_stddev\",$"}, + {"\"run_name\": \"BM_RepeatTimeUnit/repeats:3\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"stddev\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}, + {"\"time_unit\": \"us\",?$"}}); +ADD_CASES(TC_CSVOut, + {{".*BM_RepeatTimeUnit/repeats:3 ", MR_Not}, + {"^\"BM_RepeatTimeUnit/repeats:3_mean\",%csv_us_report$"}, + {"^\"BM_RepeatTimeUnit/repeats:3_median\",%csv_us_report$"}, + {"^\"BM_RepeatTimeUnit/repeats:3_stddev\",%csv_us_report$"}}); + +// ========================================================================= // +// -------------------- Testing user-provided statistics ------------------- // +// ========================================================================= // + +const auto UserStatistics = [](const std::vector& v) { + return v.back(); +}; +void BM_UserStats(benchmark::State& state) { + for (auto _ : state) { + state.SetIterationTime(150 / 10e8); + } +} +// clang-format off +BENCHMARK(BM_UserStats) + ->Repetitions(3) + ->Iterations(5) + ->UseManualTime() + ->ComputeStatistics("", UserStatistics); +// clang-format on + +// check that user-provided stats is calculated, and is after the default-ones +// empty string as name is intentional, it would sort before anything else +ADD_CASES(TC_ConsoleOut, {{"^BM_UserStats/iterations:5/repeats:3/manual_time [ " + "]* 150 ns %time [ ]*5$"}, + {"^BM_UserStats/iterations:5/repeats:3/manual_time [ " + "]* 150 ns %time [ ]*5$"}, + {"^BM_UserStats/iterations:5/repeats:3/manual_time [ " + "]* 150 ns %time [ ]*5$"}, + {"^BM_UserStats/iterations:5/repeats:3/" + "manual_time_mean [ ]* 150 ns %time [ ]*3$"}, + {"^BM_UserStats/iterations:5/repeats:3/" + "manual_time_median [ ]* 150 ns %time [ ]*3$"}, + {"^BM_UserStats/iterations:5/repeats:3/" + "manual_time_stddev [ ]* 0.000 ns %time [ ]*3$"}, + {"^BM_UserStats/iterations:5/repeats:3/manual_time_ " + "[ ]* 150 ns %time [ ]*3$"}}); +ADD_CASES( + TC_JSONOut, + {{"\"name\": \"BM_UserStats/iterations:5/repeats:3/manual_time\",$"}, + {"\"run_name\": \"BM_UserStats/iterations:5/repeats:3/manual_time\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": 5,$", MR_Next}, + {"\"real_time\": 1\\.5(0)*e\\+(0)*2,$", MR_Next}, + {"\"name\": \"BM_UserStats/iterations:5/repeats:3/manual_time\",$"}, + {"\"run_name\": \"BM_UserStats/iterations:5/repeats:3/manual_time\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"repetition_index\": 1,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": 5,$", MR_Next}, + {"\"real_time\": 1\\.5(0)*e\\+(0)*2,$", MR_Next}, + {"\"name\": \"BM_UserStats/iterations:5/repeats:3/manual_time\",$"}, + {"\"run_name\": \"BM_UserStats/iterations:5/repeats:3/manual_time\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"repetition_index\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": 5,$", MR_Next}, + {"\"real_time\": 1\\.5(0)*e\\+(0)*2,$", MR_Next}, + {"\"name\": \"BM_UserStats/iterations:5/repeats:3/manual_time_mean\",$"}, + {"\"run_name\": \"BM_UserStats/iterations:5/repeats:3/manual_time\",$", + MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"mean\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}, + {"\"real_time\": 1\\.5(0)*e\\+(0)*2,$", MR_Next}, + {"\"name\": \"BM_UserStats/iterations:5/repeats:3/manual_time_median\",$"}, + {"\"run_name\": \"BM_UserStats/iterations:5/repeats:3/manual_time\",$", + MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"median\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}, + {"\"real_time\": 1\\.5(0)*e\\+(0)*2,$", MR_Next}, + {"\"name\": \"BM_UserStats/iterations:5/repeats:3/manual_time_stddev\",$"}, + {"\"run_name\": \"BM_UserStats/iterations:5/repeats:3/manual_time\",$", + MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"stddev\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"name\": \"BM_UserStats/iterations:5/repeats:3/manual_time_\",$"}, + {"\"run_name\": \"BM_UserStats/iterations:5/repeats:3/manual_time\",$", + MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 3,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"\",$", MR_Next}, + {"\"iterations\": 3,$", MR_Next}, + {"\"real_time\": 1\\.5(0)*e\\+(0)*2,$", MR_Next}}); +ADD_CASES( + TC_CSVOut, + {{"^\"BM_UserStats/iterations:5/repeats:3/manual_time\",%csv_report$"}, + {"^\"BM_UserStats/iterations:5/repeats:3/manual_time\",%csv_report$"}, + {"^\"BM_UserStats/iterations:5/repeats:3/manual_time\",%csv_report$"}, + {"^\"BM_UserStats/iterations:5/repeats:3/manual_time_mean\",%csv_report$"}, + {"^\"BM_UserStats/iterations:5/repeats:3/" + "manual_time_median\",%csv_report$"}, + {"^\"BM_UserStats/iterations:5/repeats:3/" + "manual_time_stddev\",%csv_report$"}, + {"^\"BM_UserStats/iterations:5/repeats:3/manual_time_\",%csv_report$"}}); + +// ========================================================================= // +// ------------------------- Testing StrEscape JSON ------------------------ // +// ========================================================================= // +#if 0 // enable when csv testing code correctly handles multi-line fields +void BM_JSON_Format(benchmark::State& state) { + state.SkipWithError("val\b\f\n\r\t\\\"with\"es,capes"); + for (auto _ : state) { + } +} +BENCHMARK(BM_JSON_Format); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_JSON_Format\",$"}, + {"\"run_name\": \"BM_JSON_Format\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"error_occurred\": true,$", MR_Next}, + {R"("error_message": "val\\b\\f\\n\\r\\t\\\\\\"with\\"es,capes",$)", MR_Next}}); +#endif +// ========================================================================= // +// -------------------------- Testing CsvEscape ---------------------------- // +// ========================================================================= // + +void BM_CSV_Format(benchmark::State& state) { + state.SkipWithError("\"freedom\""); + for (auto _ : state) { + } +} +BENCHMARK(BM_CSV_Format); +ADD_CASES(TC_CSVOut, {{"^\"BM_CSV_Format\",,,,,,,,true,\"\"\"freedom\"\"\"$"}}); + +// ========================================================================= // +// --------------------------- TEST CASES END ------------------------------ // +// ========================================================================= // + +int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/skip_with_error_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/skip_with_error_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..97a2e3c03b9e5138dc4f720ae9e2760d246d1ee2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/skip_with_error_test.cc @@ -0,0 +1,195 @@ + +#undef NDEBUG +#include +#include + +#include "../src/check.h" // NOTE: check.h is for internal use only! +#include "benchmark/benchmark.h" + +namespace { + +class TestReporter : public benchmark::ConsoleReporter { + public: + virtual bool ReportContext(const Context& context) { + return ConsoleReporter::ReportContext(context); + }; + + virtual void ReportRuns(const std::vector& report) { + all_runs_.insert(all_runs_.end(), begin(report), end(report)); + ConsoleReporter::ReportRuns(report); + } + + TestReporter() {} + virtual ~TestReporter() {} + + mutable std::vector all_runs_; +}; + +struct TestCase { + std::string name; + bool error_occurred; + std::string error_message; + + typedef benchmark::BenchmarkReporter::Run Run; + + void CheckRun(Run const& run) const { + CHECK(name == run.benchmark_name()) + << "expected " << name << " got " << run.benchmark_name(); + CHECK(error_occurred == run.error_occurred); + CHECK(error_message == run.error_message); + if (error_occurred) { + // CHECK(run.iterations == 0); + } else { + CHECK(run.iterations != 0); + } + } +}; + +std::vector ExpectedResults; + +int AddCases(const char* base_name, std::initializer_list const& v) { + for (auto TC : v) { + TC.name = base_name + TC.name; + ExpectedResults.push_back(std::move(TC)); + } + return 0; +} + +#define CONCAT(x, y) CONCAT2(x, y) +#define CONCAT2(x, y) x##y +#define ADD_CASES(...) int CONCAT(dummy, __LINE__) = AddCases(__VA_ARGS__) + +} // end namespace + +void BM_error_no_running(benchmark::State& state) { + state.SkipWithError("error message"); +} +BENCHMARK(BM_error_no_running); +ADD_CASES("BM_error_no_running", {{"", true, "error message"}}); + +void BM_error_before_running(benchmark::State& state) { + state.SkipWithError("error message"); + while (state.KeepRunning()) { + assert(false); + } +} +BENCHMARK(BM_error_before_running); +ADD_CASES("BM_error_before_running", {{"", true, "error message"}}); + +void BM_error_before_running_batch(benchmark::State& state) { + state.SkipWithError("error message"); + while (state.KeepRunningBatch(17)) { + assert(false); + } +} +BENCHMARK(BM_error_before_running_batch); +ADD_CASES("BM_error_before_running_batch", {{"", true, "error message"}}); + +void BM_error_before_running_range_for(benchmark::State& state) { + state.SkipWithError("error message"); + for (auto _ : state) { + assert(false); + } +} +BENCHMARK(BM_error_before_running_range_for); +ADD_CASES("BM_error_before_running_range_for", {{"", true, "error message"}}); + +void BM_error_during_running(benchmark::State& state) { + int first_iter = true; + while (state.KeepRunning()) { + if (state.range(0) == 1 && state.thread_index <= (state.threads / 2)) { + assert(first_iter); + first_iter = false; + state.SkipWithError("error message"); + } else { + state.PauseTiming(); + state.ResumeTiming(); + } + } +} +BENCHMARK(BM_error_during_running)->Arg(1)->Arg(2)->ThreadRange(1, 8); +ADD_CASES("BM_error_during_running", {{"/1/threads:1", true, "error message"}, + {"/1/threads:2", true, "error message"}, + {"/1/threads:4", true, "error message"}, + {"/1/threads:8", true, "error message"}, + {"/2/threads:1", false, ""}, + {"/2/threads:2", false, ""}, + {"/2/threads:4", false, ""}, + {"/2/threads:8", false, ""}}); + +void BM_error_during_running_ranged_for(benchmark::State& state) { + assert(state.max_iterations > 3 && "test requires at least a few iterations"); + int first_iter = true; + // NOTE: Users should not write the for loop explicitly. + for (auto It = state.begin(), End = state.end(); It != End; ++It) { + if (state.range(0) == 1) { + assert(first_iter); + first_iter = false; + state.SkipWithError("error message"); + // Test the unfortunate but documented behavior that the ranged-for loop + // doesn't automatically terminate when SkipWithError is set. + assert(++It != End); + break; // Required behavior + } + } +} +BENCHMARK(BM_error_during_running_ranged_for)->Arg(1)->Arg(2)->Iterations(5); +ADD_CASES("BM_error_during_running_ranged_for", + {{"/1/iterations:5", true, "error message"}, + {"/2/iterations:5", false, ""}}); + +void BM_error_after_running(benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize(state.iterations()); + } + if (state.thread_index <= (state.threads / 2)) + state.SkipWithError("error message"); +} +BENCHMARK(BM_error_after_running)->ThreadRange(1, 8); +ADD_CASES("BM_error_after_running", {{"/threads:1", true, "error message"}, + {"/threads:2", true, "error message"}, + {"/threads:4", true, "error message"}, + {"/threads:8", true, "error message"}}); + +void BM_error_while_paused(benchmark::State& state) { + bool first_iter = true; + while (state.KeepRunning()) { + if (state.range(0) == 1 && state.thread_index <= (state.threads / 2)) { + assert(first_iter); + first_iter = false; + state.PauseTiming(); + state.SkipWithError("error message"); + } else { + state.PauseTiming(); + state.ResumeTiming(); + } + } +} +BENCHMARK(BM_error_while_paused)->Arg(1)->Arg(2)->ThreadRange(1, 8); +ADD_CASES("BM_error_while_paused", {{"/1/threads:1", true, "error message"}, + {"/1/threads:2", true, "error message"}, + {"/1/threads:4", true, "error message"}, + {"/1/threads:8", true, "error message"}, + {"/2/threads:1", false, ""}, + {"/2/threads:2", false, ""}, + {"/2/threads:4", false, ""}, + {"/2/threads:8", false, ""}}); + +int main(int argc, char* argv[]) { + benchmark::Initialize(&argc, argv); + + TestReporter test_reporter; + benchmark::RunSpecifiedBenchmarks(&test_reporter); + + typedef benchmark::BenchmarkReporter::Run Run; + auto EB = ExpectedResults.begin(); + + for (Run const& run : test_reporter.all_runs_) { + assert(EB != ExpectedResults.end()); + EB->CheckRun(run); + ++EB; + } + assert(EB == ExpectedResults.end()); + + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/state_assembly_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/state_assembly_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..7ddbb3b2a92c83db270eaf58bc9b03b1483d59dd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/state_assembly_test.cc @@ -0,0 +1,68 @@ +#include + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wreturn-type" +#endif + +// clang-format off +extern "C" { + extern int ExternInt; + benchmark::State& GetState(); + void Fn(); +} +// clang-format on + +using benchmark::State; + +// CHECK-LABEL: test_for_auto_loop: +extern "C" int test_for_auto_loop() { + State& S = GetState(); + int x = 42; + // CHECK: [[CALL:call(q)*]] _ZN9benchmark5State16StartKeepRunningEv + // CHECK-NEXT: testq %rbx, %rbx + // CHECK-NEXT: je [[LOOP_END:.*]] + + for (auto _ : S) { + // CHECK: .L[[LOOP_HEAD:[a-zA-Z0-9_]+]]: + // CHECK-GNU-NEXT: subq $1, %rbx + // CHECK-CLANG-NEXT: {{(addq \$1, %rax|incq %rax|addq \$-1, %rbx)}} + // CHECK-NEXT: jne .L[[LOOP_HEAD]] + benchmark::DoNotOptimize(x); + } + // CHECK: [[LOOP_END]]: + // CHECK: [[CALL]] _ZN9benchmark5State17FinishKeepRunningEv + + // CHECK: movl $101, %eax + // CHECK: ret + return 101; +} + +// CHECK-LABEL: test_while_loop: +extern "C" int test_while_loop() { + State& S = GetState(); + int x = 42; + + // CHECK: j{{(e|mp)}} .L[[LOOP_HEADER:[a-zA-Z0-9_]+]] + // CHECK-NEXT: .L[[LOOP_BODY:[a-zA-Z0-9_]+]]: + while (S.KeepRunning()) { + // CHECK-GNU-NEXT: subq $1, %[[IREG:[a-z]+]] + // CHECK-CLANG-NEXT: {{(addq \$-1,|decq)}} %[[IREG:[a-z]+]] + // CHECK: movq %[[IREG]], [[DEST:.*]] + benchmark::DoNotOptimize(x); + } + // CHECK-DAG: movq [[DEST]], %[[IREG]] + // CHECK-DAG: testq %[[IREG]], %[[IREG]] + // CHECK-DAG: jne .L[[LOOP_BODY]] + // CHECK-DAG: .L[[LOOP_HEADER]]: + + // CHECK: cmpb $0 + // CHECK-NEXT: jne .L[[LOOP_END:[a-zA-Z0-9_]+]] + // CHECK: [[CALL:call(q)*]] _ZN9benchmark5State16StartKeepRunningEv + + // CHECK: .L[[LOOP_END]]: + // CHECK: [[CALL]] _ZN9benchmark5State17FinishKeepRunningEv + + // CHECK: movl $101, %eax + // CHECK: ret + return 101; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/statistics_gtest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/statistics_gtest.cc new file mode 100644 index 0000000000000000000000000000000000000000..3ddc72dd7ac625878febe48dee6e117a853c56e4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/statistics_gtest.cc @@ -0,0 +1,28 @@ +//===---------------------------------------------------------------------===// +// statistics_test - Unit tests for src/statistics.cc +//===---------------------------------------------------------------------===// + +#include "../src/statistics.h" +#include "gtest/gtest.h" + +namespace { +TEST(StatisticsTest, Mean) { + EXPECT_DOUBLE_EQ(benchmark::StatisticsMean({42, 42, 42, 42}), 42.0); + EXPECT_DOUBLE_EQ(benchmark::StatisticsMean({1, 2, 3, 4}), 2.5); + EXPECT_DOUBLE_EQ(benchmark::StatisticsMean({1, 2, 5, 10, 10, 14}), 7.0); +} + +TEST(StatisticsTest, Median) { + EXPECT_DOUBLE_EQ(benchmark::StatisticsMedian({42, 42, 42, 42}), 42.0); + EXPECT_DOUBLE_EQ(benchmark::StatisticsMedian({1, 2, 3, 4}), 2.5); + EXPECT_DOUBLE_EQ(benchmark::StatisticsMedian({1, 2, 5, 10, 10}), 5.0); +} + +TEST(StatisticsTest, StdDev) { + EXPECT_DOUBLE_EQ(benchmark::StatisticsStdDev({101, 101, 101, 101}), 0.0); + EXPECT_DOUBLE_EQ(benchmark::StatisticsStdDev({1, 2, 3}), 1.0); + EXPECT_DOUBLE_EQ(benchmark::StatisticsStdDev({2.5, 2.4, 3.3, 4.2, 5.1}), + 1.151086443322134); +} + +} // end namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/string_util_gtest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/string_util_gtest.cc new file mode 100644 index 0000000000000000000000000000000000000000..01bf155d8c9aae9010c01079ad249822482effc9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/string_util_gtest.cc @@ -0,0 +1,153 @@ +//===---------------------------------------------------------------------===// +// statistics_test - Unit tests for src/statistics.cc +//===---------------------------------------------------------------------===// + +#include "../src/string_util.h" +#include "../src/internal_macros.h" +#include "gtest/gtest.h" + +namespace { +TEST(StringUtilTest, stoul) { + { + size_t pos = 0; + EXPECT_EQ(0ul, benchmark::stoul("0", &pos)); + EXPECT_EQ(1ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(7ul, benchmark::stoul("7", &pos)); + EXPECT_EQ(1ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(135ul, benchmark::stoul("135", &pos)); + EXPECT_EQ(3ul, pos); + } +#if ULONG_MAX == 0xFFFFFFFFul + { + size_t pos = 0; + EXPECT_EQ(0xFFFFFFFFul, benchmark::stoul("4294967295", &pos)); + EXPECT_EQ(10ul, pos); + } +#elif ULONG_MAX == 0xFFFFFFFFFFFFFFFFul + { + size_t pos = 0; + EXPECT_EQ(0xFFFFFFFFFFFFFFFFul, benchmark::stoul("18446744073709551615", &pos)); + EXPECT_EQ(20ul, pos); + } +#endif + { + size_t pos = 0; + EXPECT_EQ(10ul, benchmark::stoul("1010", &pos, 2)); + EXPECT_EQ(4ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(520ul, benchmark::stoul("1010", &pos, 8)); + EXPECT_EQ(4ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(1010ul, benchmark::stoul("1010", &pos, 10)); + EXPECT_EQ(4ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(4112ul, benchmark::stoul("1010", &pos, 16)); + EXPECT_EQ(4ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(0xBEEFul, benchmark::stoul("BEEF", &pos, 16)); + EXPECT_EQ(4ul, pos); + } +#ifndef BENCHMARK_HAS_NO_EXCEPTIONS + { + ASSERT_THROW(benchmark::stoul("this is a test"), std::invalid_argument); + } +#endif +} + +TEST(StringUtilTest, stoi) { + { + size_t pos = 0; + EXPECT_EQ(0, benchmark::stoi("0", &pos)); + EXPECT_EQ(1ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(-17, benchmark::stoi("-17", &pos)); + EXPECT_EQ(3ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(1357, benchmark::stoi("1357", &pos)); + EXPECT_EQ(4ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(10, benchmark::stoi("1010", &pos, 2)); + EXPECT_EQ(4ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(520, benchmark::stoi("1010", &pos, 8)); + EXPECT_EQ(4ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(1010, benchmark::stoi("1010", &pos, 10)); + EXPECT_EQ(4ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(4112, benchmark::stoi("1010", &pos, 16)); + EXPECT_EQ(4ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(0xBEEF, benchmark::stoi("BEEF", &pos, 16)); + EXPECT_EQ(4ul, pos); + } +#ifndef BENCHMARK_HAS_NO_EXCEPTIONS + { + ASSERT_THROW(benchmark::stoi("this is a test"), std::invalid_argument); + } +#endif +} + +TEST(StringUtilTest, stod) { + { + size_t pos = 0; + EXPECT_EQ(0.0, benchmark::stod("0", &pos)); + EXPECT_EQ(1ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(-84.0, benchmark::stod("-84", &pos)); + EXPECT_EQ(3ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(1234.0, benchmark::stod("1234", &pos)); + EXPECT_EQ(4ul, pos); + } + { + size_t pos = 0; + EXPECT_EQ(1.5, benchmark::stod("1.5", &pos)); + EXPECT_EQ(3ul, pos); + } + { + size_t pos = 0; + /* Note: exactly representable as double */ + EXPECT_EQ(-1.25e+9, benchmark::stod("-1.25e+9", &pos)); + EXPECT_EQ(8ul, pos); + } +#ifndef BENCHMARK_HAS_NO_EXCEPTIONS + { + ASSERT_THROW(benchmark::stod("this is a test"), std::invalid_argument); + } +#endif +} + +} // end namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/templated_fixture_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/templated_fixture_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..fe9865cc776f3532dbe8873758f97d27cf12fc19 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/templated_fixture_test.cc @@ -0,0 +1,28 @@ + +#include "benchmark/benchmark.h" + +#include +#include + +template +class MyFixture : public ::benchmark::Fixture { + public: + MyFixture() : data(0) {} + + T data; +}; + +BENCHMARK_TEMPLATE_F(MyFixture, Foo, int)(benchmark::State& st) { + for (auto _ : st) { + data += 1; + } +} + +BENCHMARK_TEMPLATE_DEFINE_F(MyFixture, Bar, double)(benchmark::State& st) { + for (auto _ : st) { + data += 1.0; + } +} +BENCHMARK_REGISTER_F(MyFixture, Bar); + +BENCHMARK_MAIN(); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/user_counters_tabular_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/user_counters_tabular_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..18373c0aac7b333d8957d16175e89335844af21c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/user_counters_tabular_test.cc @@ -0,0 +1,285 @@ + +#undef NDEBUG + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// @todo: this checks the full output at once; the rule for +// CounterSet1 was failing because it was not matching "^[-]+$". +// @todo: check that the counters are vertically aligned. +ADD_CASES( + TC_ConsoleOut, + { + // keeping these lines long improves readability, so: + // clang-format off + {"^[-]+$", MR_Next}, + {"^Benchmark %s Time %s CPU %s Iterations %s Bar %s Bat %s Baz %s Foo %s Frob %s Lob$", MR_Next}, + {"^[-]+$", MR_Next}, + {"^BM_Counters_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_Counters_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_Counters_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_Counters_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_Counters_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next}, + {"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next}, + {"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next}, + {"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next}, + {"^BM_CounterRates_Tabular/threads:%int %console_report [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s [ ]*%hrfloat/s$", MR_Next}, + {"^[-]+$", MR_Next}, + {"^Benchmark %s Time %s CPU %s Iterations %s Bar %s Baz %s Foo$", MR_Next}, + {"^[-]+$", MR_Next}, + {"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet0_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet1_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^[-]+$", MR_Next}, + {"^Benchmark %s Time %s CPU %s Iterations %s Bat %s Baz %s Foo$", MR_Next}, + {"^[-]+$", MR_Next}, + {"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$", MR_Next}, + {"^BM_CounterSet2_Tabular/threads:%int %console_report [ ]*%hrfloat [ ]*%hrfloat [ ]*%hrfloat$"}, + // clang-format on + }); +ADD_CASES(TC_CSVOut, {{"%csv_header," + "\"Bar\",\"Bat\",\"Baz\",\"Foo\",\"Frob\",\"Lob\""}}); + +// ========================================================================= // +// ------------------------- Tabular Counters Output ----------------------- // +// ========================================================================= // + +void BM_Counters_Tabular(benchmark::State& state) { + for (auto _ : state) { + } + namespace bm = benchmark; + state.counters.insert({ + {"Foo", {1, bm::Counter::kAvgThreads}}, + {"Bar", {2, bm::Counter::kAvgThreads}}, + {"Baz", {4, bm::Counter::kAvgThreads}}, + {"Bat", {8, bm::Counter::kAvgThreads}}, + {"Frob", {16, bm::Counter::kAvgThreads}}, + {"Lob", {32, bm::Counter::kAvgThreads}}, + }); +} +BENCHMARK(BM_Counters_Tabular)->ThreadRange(1, 16); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_Tabular/threads:%int\",$"}, + {"\"run_name\": \"BM_Counters_Tabular/threads:%int\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"Bar\": %float,$", MR_Next}, + {"\"Bat\": %float,$", MR_Next}, + {"\"Baz\": %float,$", MR_Next}, + {"\"Foo\": %float,$", MR_Next}, + {"\"Frob\": %float,$", MR_Next}, + {"\"Lob\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Tabular/threads:%int\",%csv_report," + "%float,%float,%float,%float,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckTabular(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 1); + CHECK_COUNTER_VALUE(e, int, "Bar", EQ, 2); + CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 4); + CHECK_COUNTER_VALUE(e, int, "Bat", EQ, 8); + CHECK_COUNTER_VALUE(e, int, "Frob", EQ, 16); + CHECK_COUNTER_VALUE(e, int, "Lob", EQ, 32); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Tabular/threads:%int", &CheckTabular); + +// ========================================================================= // +// -------------------- Tabular+Rate Counters Output ----------------------- // +// ========================================================================= // + +void BM_CounterRates_Tabular(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + namespace bm = benchmark; + state.counters.insert({ + {"Foo", {1, bm::Counter::kAvgThreadsRate}}, + {"Bar", {2, bm::Counter::kAvgThreadsRate}}, + {"Baz", {4, bm::Counter::kAvgThreadsRate}}, + {"Bat", {8, bm::Counter::kAvgThreadsRate}}, + {"Frob", {16, bm::Counter::kAvgThreadsRate}}, + {"Lob", {32, bm::Counter::kAvgThreadsRate}}, + }); +} +BENCHMARK(BM_CounterRates_Tabular)->ThreadRange(1, 16); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_CounterRates_Tabular/threads:%int\",$"}, + {"\"run_name\": \"BM_CounterRates_Tabular/threads:%int\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"Bar\": %float,$", MR_Next}, + {"\"Bat\": %float,$", MR_Next}, + {"\"Baz\": %float,$", MR_Next}, + {"\"Foo\": %float,$", MR_Next}, + {"\"Frob\": %float,$", MR_Next}, + {"\"Lob\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_CounterRates_Tabular/threads:%int\",%csv_report," + "%float,%float,%float,%float,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckTabularRate(Results const& e) { + double t = e.DurationCPUTime(); + CHECK_FLOAT_COUNTER_VALUE(e, "Foo", EQ, 1. / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "Bar", EQ, 2. / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "Baz", EQ, 4. / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "Bat", EQ, 8. / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "Frob", EQ, 16. / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "Lob", EQ, 32. / t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_CounterRates_Tabular/threads:%int", + &CheckTabularRate); + +// ========================================================================= // +// ------------------------- Tabular Counters Output ----------------------- // +// ========================================================================= // + +// set only some of the counters +void BM_CounterSet0_Tabular(benchmark::State& state) { + for (auto _ : state) { + } + namespace bm = benchmark; + state.counters.insert({ + {"Foo", {10, bm::Counter::kAvgThreads}}, + {"Bar", {20, bm::Counter::kAvgThreads}}, + {"Baz", {40, bm::Counter::kAvgThreads}}, + }); +} +BENCHMARK(BM_CounterSet0_Tabular)->ThreadRange(1, 16); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_CounterSet0_Tabular/threads:%int\",$"}, + {"\"run_name\": \"BM_CounterSet0_Tabular/threads:%int\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"Bar\": %float,$", MR_Next}, + {"\"Baz\": %float,$", MR_Next}, + {"\"Foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_CounterSet0_Tabular/threads:%int\",%csv_report," + "%float,,%float,%float,,"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckSet0(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 10); + CHECK_COUNTER_VALUE(e, int, "Bar", EQ, 20); + CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 40); +} +CHECK_BENCHMARK_RESULTS("BM_CounterSet0_Tabular", &CheckSet0); + +// again. +void BM_CounterSet1_Tabular(benchmark::State& state) { + for (auto _ : state) { + } + namespace bm = benchmark; + state.counters.insert({ + {"Foo", {15, bm::Counter::kAvgThreads}}, + {"Bar", {25, bm::Counter::kAvgThreads}}, + {"Baz", {45, bm::Counter::kAvgThreads}}, + }); +} +BENCHMARK(BM_CounterSet1_Tabular)->ThreadRange(1, 16); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_CounterSet1_Tabular/threads:%int\",$"}, + {"\"run_name\": \"BM_CounterSet1_Tabular/threads:%int\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"Bar\": %float,$", MR_Next}, + {"\"Baz\": %float,$", MR_Next}, + {"\"Foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_CounterSet1_Tabular/threads:%int\",%csv_report," + "%float,,%float,%float,,"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckSet1(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 15); + CHECK_COUNTER_VALUE(e, int, "Bar", EQ, 25); + CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 45); +} +CHECK_BENCHMARK_RESULTS("BM_CounterSet1_Tabular/threads:%int", &CheckSet1); + +// ========================================================================= // +// ------------------------- Tabular Counters Output ----------------------- // +// ========================================================================= // + +// set only some of the counters, different set now. +void BM_CounterSet2_Tabular(benchmark::State& state) { + for (auto _ : state) { + } + namespace bm = benchmark; + state.counters.insert({ + {"Foo", {10, bm::Counter::kAvgThreads}}, + {"Bat", {30, bm::Counter::kAvgThreads}}, + {"Baz", {40, bm::Counter::kAvgThreads}}, + }); +} +BENCHMARK(BM_CounterSet2_Tabular)->ThreadRange(1, 16); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_CounterSet2_Tabular/threads:%int\",$"}, + {"\"run_name\": \"BM_CounterSet2_Tabular/threads:%int\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"Bat\": %float,$", MR_Next}, + {"\"Baz\": %float,$", MR_Next}, + {"\"Foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_CounterSet2_Tabular/threads:%int\",%csv_report," + ",%float,%float,%float,,"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckSet2(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "Foo", EQ, 10); + CHECK_COUNTER_VALUE(e, int, "Bat", EQ, 30); + CHECK_COUNTER_VALUE(e, int, "Baz", EQ, 40); +} +CHECK_BENCHMARK_RESULTS("BM_CounterSet2_Tabular", &CheckSet2); + +// ========================================================================= // +// --------------------------- TEST CASES END ------------------------------ // +// ========================================================================= // + +int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/user_counters_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/user_counters_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..5699f4f5e118966e764ddb5ba4a89e0f01e5d159 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/user_counters_test.cc @@ -0,0 +1,531 @@ + +#undef NDEBUG + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// ========================================================================= // +// ---------------------- Testing Prologue Output -------------------------- // +// ========================================================================= // + +// clang-format off + +ADD_CASES(TC_ConsoleOut, + {{"^[-]+$", MR_Next}, + {"^Benchmark %s Time %s CPU %s Iterations UserCounters...$", MR_Next}, + {"^[-]+$", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"%csv_header,\"bar\",\"foo\""}}); + +// clang-format on + +// ========================================================================= // +// ------------------------- Simple Counters Output ------------------------ // +// ========================================================================= // + +void BM_Counters_Simple(benchmark::State& state) { + for (auto _ : state) { + } + state.counters["foo"] = 1; + state.counters["bar"] = 2 * (double)state.iterations(); +} +BENCHMARK(BM_Counters_Simple); +ADD_CASES(TC_ConsoleOut, + {{"^BM_Counters_Simple %console_report bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Counters_Simple\",$"}, + {"\"run_name\": \"BM_Counters_Simple\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Simple\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckSimple(Results const& e) { + double its = e.NumIterations(); + CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1); + // check that the value of bar is within 0.1% of the expected value + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * its, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Simple", &CheckSimple); + +// ========================================================================= // +// --------------------- Counters+Items+Bytes/s Output --------------------- // +// ========================================================================= // + +namespace { +int num_calls1 = 0; +} +void BM_Counters_WithBytesAndItemsPSec(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + state.counters["foo"] = 1; + state.counters["bar"] = ++num_calls1; + state.SetBytesProcessed(364); + state.SetItemsProcessed(150); +} +BENCHMARK(BM_Counters_WithBytesAndItemsPSec); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_WithBytesAndItemsPSec %console_report " + "bar=%hrfloat bytes_per_second=%hrfloat/s " + "foo=%hrfloat items_per_second=%hrfloat/s$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_WithBytesAndItemsPSec\",$"}, + {"\"run_name\": \"BM_Counters_WithBytesAndItemsPSec\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"bytes_per_second\": %float,$", MR_Next}, + {"\"foo\": %float,$", MR_Next}, + {"\"items_per_second\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_WithBytesAndItemsPSec\"," + "%csv_bytes_items_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckBytesAndItemsPSec(Results const& e) { + double t = e.DurationCPUTime(); // this (and not real time) is the time used + CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1); + CHECK_COUNTER_VALUE(e, int, "bar", EQ, num_calls1); + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_RESULT_VALUE(e, "bytes_per_second", EQ, 364. / t, 0.001); + CHECK_FLOAT_RESULT_VALUE(e, "items_per_second", EQ, 150. / t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_WithBytesAndItemsPSec", + &CheckBytesAndItemsPSec); + +// ========================================================================= // +// ------------------------- Rate Counters Output -------------------------- // +// ========================================================================= // + +void BM_Counters_Rate(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kIsRate}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kIsRate}; +} +BENCHMARK(BM_Counters_Rate); +ADD_CASES( + TC_ConsoleOut, + {{"^BM_Counters_Rate %console_report bar=%hrfloat/s foo=%hrfloat/s$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Counters_Rate\",$"}, + {"\"run_name\": \"BM_Counters_Rate\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_Rate\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckRate(Results const& e) { + double t = e.DurationCPUTime(); // this (and not real time) is the time used + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Rate", &CheckRate); + +// ========================================================================= // +// ----------------------- Inverted Counters Output ------------------------ // +// ========================================================================= // + +void BM_Invert(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{0.0001, bm::Counter::kInvert}; + state.counters["bar"] = bm::Counter{10000, bm::Counter::kInvert}; +} +BENCHMARK(BM_Invert); +ADD_CASES(TC_ConsoleOut, + {{"^BM_Invert %console_report bar=%hrfloatu foo=%hrfloatk$"}}); +ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Invert\",$"}, + {"\"run_name\": \"BM_Invert\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Invert\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckInvert(Results const& e) { + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 10000, 0.0001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 0.0001, 0.0001); +} +CHECK_BENCHMARK_RESULTS("BM_Invert", &CheckInvert); + +// ========================================================================= // +// ------------------------- InvertedRate Counters Output +// -------------------------- // +// ========================================================================= // + +void BM_Counters_InvertedRate(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + namespace bm = benchmark; + state.counters["foo"] = + bm::Counter{1, bm::Counter::kIsRate | bm::Counter::kInvert}; + state.counters["bar"] = + bm::Counter{8192, bm::Counter::kIsRate | bm::Counter::kInvert}; +} +BENCHMARK(BM_Counters_InvertedRate); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_InvertedRate %console_report " + "bar=%hrfloats foo=%hrfloats$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_InvertedRate\",$"}, + {"\"run_name\": \"BM_Counters_InvertedRate\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, + {{"^\"BM_Counters_InvertedRate\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckInvertedRate(Results const& e) { + double t = e.DurationCPUTime(); // this (and not real time) is the time used + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, t / 8192.0, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_InvertedRate", &CheckInvertedRate); + +// ========================================================================= // +// ------------------------- Thread Counters Output ------------------------ // +// ========================================================================= // + +void BM_Counters_Threads(benchmark::State& state) { + for (auto _ : state) { + } + state.counters["foo"] = 1; + state.counters["bar"] = 2; +} +BENCHMARK(BM_Counters_Threads)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_Threads/threads:%int %console_report " + "bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_Threads/threads:%int\",$"}, + {"\"run_name\": \"BM_Counters_Threads/threads:%int\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES( + TC_CSVOut, + {{"^\"BM_Counters_Threads/threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckThreads(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "foo", EQ, e.NumThreads()); + CHECK_COUNTER_VALUE(e, int, "bar", EQ, 2 * e.NumThreads()); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Threads/threads:%int", &CheckThreads); + +// ========================================================================= // +// ---------------------- ThreadAvg Counters Output ------------------------ // +// ========================================================================= // + +void BM_Counters_AvgThreads(benchmark::State& state) { + for (auto _ : state) { + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgThreads}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgThreads}; +} +BENCHMARK(BM_Counters_AvgThreads)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgThreads/threads:%int " + "%console_report bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_AvgThreads/threads:%int\",$"}, + {"\"run_name\": \"BM_Counters_AvgThreads/threads:%int\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES( + TC_CSVOut, + {{"^\"BM_Counters_AvgThreads/threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckAvgThreads(Results const& e) { + CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1); + CHECK_COUNTER_VALUE(e, int, "bar", EQ, 2); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreads/threads:%int", + &CheckAvgThreads); + +// ========================================================================= // +// ---------------------- ThreadAvg Counters Output ------------------------ // +// ========================================================================= // + +void BM_Counters_AvgThreadsRate(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgThreadsRate}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgThreadsRate}; +} +BENCHMARK(BM_Counters_AvgThreadsRate)->ThreadRange(1, 8); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgThreadsRate/threads:%int " + "%console_report bar=%hrfloat/s foo=%hrfloat/s$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_AvgThreadsRate/threads:%int\",$"}, + {"\"run_name\": \"BM_Counters_AvgThreadsRate/threads:%int\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgThreadsRate/" + "threads:%int\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckAvgThreadsRate(Results const& e) { + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / e.DurationCPUTime(), 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / e.DurationCPUTime(), 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreadsRate/threads:%int", + &CheckAvgThreadsRate); + +// ========================================================================= // +// ------------------- IterationInvariant Counters Output ------------------ // +// ========================================================================= // + +void BM_Counters_IterationInvariant(benchmark::State& state) { + for (auto _ : state) { + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kIsIterationInvariant}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kIsIterationInvariant}; +} +BENCHMARK(BM_Counters_IterationInvariant); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_IterationInvariant %console_report " + "bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_IterationInvariant\",$"}, + {"\"run_name\": \"BM_Counters_IterationInvariant\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, + {{"^\"BM_Counters_IterationInvariant\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckIterationInvariant(Results const& e) { + double its = e.NumIterations(); + // check that the values are within 0.1% of the expected value + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, its, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * its, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_IterationInvariant", + &CheckIterationInvariant); + +// ========================================================================= // +// ----------------- IterationInvariantRate Counters Output ---------------- // +// ========================================================================= // + +void BM_Counters_kIsIterationInvariantRate(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + namespace bm = benchmark; + state.counters["foo"] = + bm::Counter{1, bm::Counter::kIsIterationInvariantRate}; + state.counters["bar"] = + bm::Counter{2, bm::Counter::kIsRate | bm::Counter::kIsIterationInvariant}; +} +BENCHMARK(BM_Counters_kIsIterationInvariantRate); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_kIsIterationInvariantRate " + "%console_report bar=%hrfloat/s foo=%hrfloat/s$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_kIsIterationInvariantRate\",$"}, + {"\"run_name\": \"BM_Counters_kIsIterationInvariantRate\",$", + MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_kIsIterationInvariantRate\",%csv_report," + "%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckIsIterationInvariantRate(Results const& e) { + double its = e.NumIterations(); + double t = e.DurationCPUTime(); // this (and not real time) is the time used + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, its * 1. / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, its * 2. / t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_kIsIterationInvariantRate", + &CheckIsIterationInvariantRate); + +// ========================================================================= // +// ------------------- AvgIterations Counters Output ------------------ // +// ========================================================================= // + +void BM_Counters_AvgIterations(benchmark::State& state) { + for (auto _ : state) { + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgIterations}; + state.counters["bar"] = bm::Counter{2, bm::Counter::kAvgIterations}; +} +BENCHMARK(BM_Counters_AvgIterations); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_AvgIterations %console_report " + "bar=%hrfloat foo=%hrfloat$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_AvgIterations\",$"}, + {"\"run_name\": \"BM_Counters_AvgIterations\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, + {{"^\"BM_Counters_AvgIterations\",%csv_report,%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckAvgIterations(Results const& e) { + double its = e.NumIterations(); + // check that the values are within 0.1% of the expected value + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / its, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / its, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_AvgIterations", &CheckAvgIterations); + +// ========================================================================= // +// ----------------- AvgIterationsRate Counters Output ---------------- // +// ========================================================================= // + +void BM_Counters_kAvgIterationsRate(benchmark::State& state) { + for (auto _ : state) { + // This test requires a non-zero CPU time to avoid divide-by-zero + benchmark::DoNotOptimize(state.iterations()); + } + namespace bm = benchmark; + state.counters["foo"] = bm::Counter{1, bm::Counter::kAvgIterationsRate}; + state.counters["bar"] = + bm::Counter{2, bm::Counter::kIsRate | bm::Counter::kAvgIterations}; +} +BENCHMARK(BM_Counters_kAvgIterationsRate); +ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_kAvgIterationsRate " + "%console_report bar=%hrfloat/s foo=%hrfloat/s$"}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_kAvgIterationsRate\",$"}, + {"\"run_name\": \"BM_Counters_kAvgIterationsRate\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 0,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"bar\": %float,$", MR_Next}, + {"\"foo\": %float$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_kAvgIterationsRate\",%csv_report," + "%float,%float$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckAvgIterationsRate(Results const& e) { + double its = e.NumIterations(); + double t = e.DurationCPUTime(); // this (and not real time) is the time used + // check that the values are within 0.1% of the expected values + CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / its / t, 0.001); + CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / its / t, 0.001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_kAvgIterationsRate", + &CheckAvgIterationsRate); + +// ========================================================================= // +// --------------------------- TEST CASES END ------------------------------ // +// ========================================================================= // + +int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/user_counters_thousands_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/user_counters_thousands_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..21d8285dedcd7cb2330d88a1038d03c629dcd2b0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/test/user_counters_thousands_test.cc @@ -0,0 +1,173 @@ + +#undef NDEBUG + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// ========================================================================= // +// ------------------------ Thousands Customisation ------------------------ // +// ========================================================================= // + +void BM_Counters_Thousands(benchmark::State& state) { + for (auto _ : state) { + } + namespace bm = benchmark; + state.counters.insert({ + {"t0_1000000DefaultBase", + bm::Counter(1000 * 1000, bm::Counter::kDefaults)}, + {"t1_1000000Base1000", bm::Counter(1000 * 1000, bm::Counter::kDefaults, + benchmark::Counter::OneK::kIs1000)}, + {"t2_1000000Base1024", bm::Counter(1000 * 1000, bm::Counter::kDefaults, + benchmark::Counter::OneK::kIs1024)}, + {"t3_1048576Base1000", bm::Counter(1024 * 1024, bm::Counter::kDefaults, + benchmark::Counter::OneK::kIs1000)}, + {"t4_1048576Base1024", bm::Counter(1024 * 1024, bm::Counter::kDefaults, + benchmark::Counter::OneK::kIs1024)}, + }); +} +BENCHMARK(BM_Counters_Thousands)->Repetitions(2); +ADD_CASES( + TC_ConsoleOut, + { + {"^BM_Counters_Thousands/repeats:2 %console_report " + "t0_1000000DefaultBase=1000k " + "t1_1000000Base1000=1000k t2_1000000Base1024=976.56[23]k " + "t3_1048576Base1000=1048.58k t4_1048576Base1024=1024k$"}, + {"^BM_Counters_Thousands/repeats:2 %console_report " + "t0_1000000DefaultBase=1000k " + "t1_1000000Base1000=1000k t2_1000000Base1024=976.56[23]k " + "t3_1048576Base1000=1048.58k t4_1048576Base1024=1024k$"}, + {"^BM_Counters_Thousands/repeats:2_mean %console_report " + "t0_1000000DefaultBase=1000k t1_1000000Base1000=1000k " + "t2_1000000Base1024=976.56[23]k t3_1048576Base1000=1048.58k " + "t4_1048576Base1024=1024k$"}, + {"^BM_Counters_Thousands/repeats:2_median %console_report " + "t0_1000000DefaultBase=1000k t1_1000000Base1000=1000k " + "t2_1000000Base1024=976.56[23]k t3_1048576Base1000=1048.58k " + "t4_1048576Base1024=1024k$"}, + {"^BM_Counters_Thousands/repeats:2_stddev %console_time_only_report [ " + "]*2 t0_1000000DefaultBase=0 t1_1000000Base1000=0 " + "t2_1000000Base1024=0 t3_1048576Base1000=0 t4_1048576Base1024=0$"}, + }); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_Thousands/repeats:2\",$"}, + {"\"run_name\": \"BM_Counters_Thousands/repeats:2\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"repetition_index\": 0,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"t0_1000000DefaultBase\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t1_1000000Base1000\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t2_1000000Base1024\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t3_1048576Base1000\": 1\\.048576(0)*e\\+(0)*6,$", MR_Next}, + {"\"t4_1048576Base1024\": 1\\.048576(0)*e\\+(0)*6$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_Thousands/repeats:2\",$"}, + {"\"run_name\": \"BM_Counters_Thousands/repeats:2\",$", MR_Next}, + {"\"run_type\": \"iteration\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"repetition_index\": 1,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"iterations\": %int,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"t0_1000000DefaultBase\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t1_1000000Base1000\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t2_1000000Base1024\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t3_1048576Base1000\": 1\\.048576(0)*e\\+(0)*6,$", MR_Next}, + {"\"t4_1048576Base1024\": 1\\.048576(0)*e\\+(0)*6$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_Thousands/repeats:2_mean\",$"}, + {"\"run_name\": \"BM_Counters_Thousands/repeats:2\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"mean\",$", MR_Next}, + {"\"iterations\": 2,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"t0_1000000DefaultBase\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t1_1000000Base1000\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t2_1000000Base1024\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t3_1048576Base1000\": 1\\.048576(0)*e\\+(0)*6,$", MR_Next}, + {"\"t4_1048576Base1024\": 1\\.048576(0)*e\\+(0)*6$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_Thousands/repeats:2_median\",$"}, + {"\"run_name\": \"BM_Counters_Thousands/repeats:2\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"median\",$", MR_Next}, + {"\"iterations\": 2,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"t0_1000000DefaultBase\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t1_1000000Base1000\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t2_1000000Base1024\": 1\\.(0)*e\\+(0)*6,$", MR_Next}, + {"\"t3_1048576Base1000\": 1\\.048576(0)*e\\+(0)*6,$", MR_Next}, + {"\"t4_1048576Base1024\": 1\\.048576(0)*e\\+(0)*6$", MR_Next}, + {"}", MR_Next}}); +ADD_CASES(TC_JSONOut, + {{"\"name\": \"BM_Counters_Thousands/repeats:2_stddev\",$"}, + {"\"run_name\": \"BM_Counters_Thousands/repeats:2\",$", MR_Next}, + {"\"run_type\": \"aggregate\",$", MR_Next}, + {"\"repetitions\": 2,$", MR_Next}, + {"\"threads\": 1,$", MR_Next}, + {"\"aggregate_name\": \"stddev\",$", MR_Next}, + {"\"iterations\": 2,$", MR_Next}, + {"\"real_time\": %float,$", MR_Next}, + {"\"cpu_time\": %float,$", MR_Next}, + {"\"time_unit\": \"ns\",$", MR_Next}, + {"\"t0_1000000DefaultBase\": 0\\.(0)*e\\+(0)*,$", MR_Next}, + {"\"t1_1000000Base1000\": 0\\.(0)*e\\+(0)*,$", MR_Next}, + {"\"t2_1000000Base1024\": 0\\.(0)*e\\+(0)*,$", MR_Next}, + {"\"t3_1048576Base1000\": 0\\.(0)*e\\+(0)*,$", MR_Next}, + {"\"t4_1048576Base1024\": 0\\.(0)*e\\+(0)*$", MR_Next}, + {"}", MR_Next}}); + +ADD_CASES( + TC_CSVOut, + {{"^\"BM_Counters_Thousands/" + "repeats:2\",%csv_report,1e\\+(0)*6,1e\\+(0)*6,1e\\+(0)*6,1\\.04858e\\+(" + "0)*6,1\\.04858e\\+(0)*6$"}, + {"^\"BM_Counters_Thousands/" + "repeats:2\",%csv_report,1e\\+(0)*6,1e\\+(0)*6,1e\\+(0)*6,1\\.04858e\\+(" + "0)*6,1\\.04858e\\+(0)*6$"}, + {"^\"BM_Counters_Thousands/" + "repeats:2_mean\",%csv_report,1e\\+(0)*6,1e\\+(0)*6,1e\\+(0)*6,1\\." + "04858e\\+(0)*6,1\\.04858e\\+(0)*6$"}, + {"^\"BM_Counters_Thousands/" + "repeats:2_median\",%csv_report,1e\\+(0)*6,1e\\+(0)*6,1e\\+(0)*6,1\\." + "04858e\\+(0)*6,1\\.04858e\\+(0)*6$"}, + {"^\"BM_Counters_Thousands/repeats:2_stddev\",%csv_report,0,0,0,0,0$"}}); +// VS2013 does not allow this function to be passed as a lambda argument +// to CHECK_BENCHMARK_RESULTS() +void CheckThousands(Results const& e) { + if (e.name != "BM_Counters_Thousands/repeats:2") + return; // Do not check the aggregates! + + // check that the values are within 0.01% of the expected values + CHECK_FLOAT_COUNTER_VALUE(e, "t0_1000000DefaultBase", EQ, 1000 * 1000, + 0.0001); + CHECK_FLOAT_COUNTER_VALUE(e, "t1_1000000Base1000", EQ, 1000 * 1000, 0.0001); + CHECK_FLOAT_COUNTER_VALUE(e, "t2_1000000Base1024", EQ, 1000 * 1000, 0.0001); + CHECK_FLOAT_COUNTER_VALUE(e, "t3_1048576Base1000", EQ, 1024 * 1024, 0.0001); + CHECK_FLOAT_COUNTER_VALUE(e, "t4_1048576Base1024", EQ, 1024 * 1024, 0.0001); +} +CHECK_BENCHMARK_RESULTS("BM_Counters_Thousands", &CheckThousands); + +// ========================================================================= // +// --------------------------- TEST CASES END ------------------------------ // +// ========================================================================= // + +int main(int argc, char* argv[]) { RunOutputTests(argc, argv); } diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/compare.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/compare.py new file mode 100755 index 0000000000000000000000000000000000000000..539ace6fb163b730eb0eccf1922a5d8e6c50a3ba --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/compare.py @@ -0,0 +1,408 @@ +#!/usr/bin/env python + +import unittest +""" +compare.py - versatile benchmark output compare tool +""" + +import argparse +from argparse import ArgumentParser +import sys +import gbench +from gbench import util, report +from gbench.util import * + + +def check_inputs(in1, in2, flags): + """ + Perform checking on the user provided inputs and diagnose any abnormalities + """ + in1_kind, in1_err = classify_input_file(in1) + in2_kind, in2_err = classify_input_file(in2) + output_file = find_benchmark_flag('--benchmark_out=', flags) + output_type = find_benchmark_flag('--benchmark_out_format=', flags) + if in1_kind == IT_Executable and in2_kind == IT_Executable and output_file: + print(("WARNING: '--benchmark_out=%s' will be passed to both " + "benchmarks causing it to be overwritten") % output_file) + if in1_kind == IT_JSON and in2_kind == IT_JSON and len(flags) > 0: + print("WARNING: passing optional flags has no effect since both " + "inputs are JSON") + if output_type is not None and output_type != 'json': + print(("ERROR: passing '--benchmark_out_format=%s' to 'compare.py`" + " is not supported.") % output_type) + sys.exit(1) + + +def create_parser(): + parser = ArgumentParser( + description='versatile benchmark output compare tool') + + parser.add_argument( + '-a', + '--display_aggregates_only', + dest='display_aggregates_only', + action="store_true", + help="If there are repetitions, by default, we display everything - the" + " actual runs, and the aggregates computed. Sometimes, it is " + "desirable to only view the aggregates. E.g. when there are a lot " + "of repetitions. Do note that only the display is affected. " + "Internally, all the actual runs are still used, e.g. for U test.") + + utest = parser.add_argument_group() + utest.add_argument( + '--no-utest', + dest='utest', + default=True, + action="store_false", + help="The tool can do a two-tailed Mann-Whitney U test with the null hypothesis that it is equally likely that a randomly selected value from one sample will be less than or greater than a randomly selected value from a second sample.\nWARNING: requires **LARGE** (no less than {}) number of repetitions to be meaningful!\nThe test is being done by default, if at least {} repetitions were done.\nThis option can disable the U Test.".format(report.UTEST_OPTIMAL_REPETITIONS, report.UTEST_MIN_REPETITIONS)) + alpha_default = 0.05 + utest.add_argument( + "--alpha", + dest='utest_alpha', + default=alpha_default, + type=float, + help=("significance level alpha. if the calculated p-value is below this value, then the result is said to be statistically significant and the null hypothesis is rejected.\n(default: %0.4f)") % + alpha_default) + + subparsers = parser.add_subparsers( + help='This tool has multiple modes of operation:', + dest='mode') + + parser_a = subparsers.add_parser( + 'benchmarks', + help='The most simple use-case, compare all the output of these two benchmarks') + baseline = parser_a.add_argument_group( + 'baseline', 'The benchmark baseline') + baseline.add_argument( + 'test_baseline', + metavar='test_baseline', + type=argparse.FileType('r'), + nargs=1, + help='A benchmark executable or JSON output file') + contender = parser_a.add_argument_group( + 'contender', 'The benchmark that will be compared against the baseline') + contender.add_argument( + 'test_contender', + metavar='test_contender', + type=argparse.FileType('r'), + nargs=1, + help='A benchmark executable or JSON output file') + parser_a.add_argument( + 'benchmark_options', + metavar='benchmark_options', + nargs=argparse.REMAINDER, + help='Arguments to pass when running benchmark executables') + + parser_b = subparsers.add_parser( + 'filters', help='Compare filter one with the filter two of benchmark') + baseline = parser_b.add_argument_group( + 'baseline', 'The benchmark baseline') + baseline.add_argument( + 'test', + metavar='test', + type=argparse.FileType('r'), + nargs=1, + help='A benchmark executable or JSON output file') + baseline.add_argument( + 'filter_baseline', + metavar='filter_baseline', + type=str, + nargs=1, + help='The first filter, that will be used as baseline') + contender = parser_b.add_argument_group( + 'contender', 'The benchmark that will be compared against the baseline') + contender.add_argument( + 'filter_contender', + metavar='filter_contender', + type=str, + nargs=1, + help='The second filter, that will be compared against the baseline') + parser_b.add_argument( + 'benchmark_options', + metavar='benchmark_options', + nargs=argparse.REMAINDER, + help='Arguments to pass when running benchmark executables') + + parser_c = subparsers.add_parser( + 'benchmarksfiltered', + help='Compare filter one of first benchmark with filter two of the second benchmark') + baseline = parser_c.add_argument_group( + 'baseline', 'The benchmark baseline') + baseline.add_argument( + 'test_baseline', + metavar='test_baseline', + type=argparse.FileType('r'), + nargs=1, + help='A benchmark executable or JSON output file') + baseline.add_argument( + 'filter_baseline', + metavar='filter_baseline', + type=str, + nargs=1, + help='The first filter, that will be used as baseline') + contender = parser_c.add_argument_group( + 'contender', 'The benchmark that will be compared against the baseline') + contender.add_argument( + 'test_contender', + metavar='test_contender', + type=argparse.FileType('r'), + nargs=1, + help='The second benchmark executable or JSON output file, that will be compared against the baseline') + contender.add_argument( + 'filter_contender', + metavar='filter_contender', + type=str, + nargs=1, + help='The second filter, that will be compared against the baseline') + parser_c.add_argument( + 'benchmark_options', + metavar='benchmark_options', + nargs=argparse.REMAINDER, + help='Arguments to pass when running benchmark executables') + + return parser + + +def main(): + # Parse the command line flags + parser = create_parser() + args, unknown_args = parser.parse_known_args() + if args.mode is None: + parser.print_help() + exit(1) + assert not unknown_args + benchmark_options = args.benchmark_options + + if args.mode == 'benchmarks': + test_baseline = args.test_baseline[0].name + test_contender = args.test_contender[0].name + filter_baseline = '' + filter_contender = '' + + # NOTE: if test_baseline == test_contender, you are analyzing the stdev + + description = 'Comparing %s to %s' % (test_baseline, test_contender) + elif args.mode == 'filters': + test_baseline = args.test[0].name + test_contender = args.test[0].name + filter_baseline = args.filter_baseline[0] + filter_contender = args.filter_contender[0] + + # NOTE: if filter_baseline == filter_contender, you are analyzing the + # stdev + + description = 'Comparing %s to %s (from %s)' % ( + filter_baseline, filter_contender, args.test[0].name) + elif args.mode == 'benchmarksfiltered': + test_baseline = args.test_baseline[0].name + test_contender = args.test_contender[0].name + filter_baseline = args.filter_baseline[0] + filter_contender = args.filter_contender[0] + + # NOTE: if test_baseline == test_contender and + # filter_baseline == filter_contender, you are analyzing the stdev + + description = 'Comparing %s (from %s) to %s (from %s)' % ( + filter_baseline, test_baseline, filter_contender, test_contender) + else: + # should never happen + print("Unrecognized mode of operation: '%s'" % args.mode) + parser.print_help() + exit(1) + + check_inputs(test_baseline, test_contender, benchmark_options) + + if args.display_aggregates_only: + benchmark_options += ['--benchmark_display_aggregates_only=true'] + + options_baseline = [] + options_contender = [] + + if filter_baseline and filter_contender: + options_baseline = ['--benchmark_filter=%s' % filter_baseline] + options_contender = ['--benchmark_filter=%s' % filter_contender] + + # Run the benchmarks and report the results + json1 = json1_orig = gbench.util.run_or_load_benchmark( + test_baseline, benchmark_options + options_baseline) + json2 = json2_orig = gbench.util.run_or_load_benchmark( + test_contender, benchmark_options + options_contender) + + # Now, filter the benchmarks so that the difference report can work + if filter_baseline and filter_contender: + replacement = '[%s vs. %s]' % (filter_baseline, filter_contender) + json1 = gbench.report.filter_benchmark( + json1_orig, filter_baseline, replacement) + json2 = gbench.report.filter_benchmark( + json2_orig, filter_contender, replacement) + + # Diff and output + output_lines = gbench.report.generate_difference_report( + json1, json2, args.display_aggregates_only, + args.utest, args.utest_alpha) + print(description) + for ln in output_lines: + print(ln) + + +class TestParser(unittest.TestCase): + def setUp(self): + self.parser = create_parser() + testInputs = os.path.join( + os.path.dirname( + os.path.realpath(__file__)), + 'gbench', + 'Inputs') + self.testInput0 = os.path.join(testInputs, 'test1_run1.json') + self.testInput1 = os.path.join(testInputs, 'test1_run2.json') + + def test_benchmarks_basic(self): + parsed = self.parser.parse_args( + ['benchmarks', self.testInput0, self.testInput1]) + self.assertFalse(parsed.display_aggregates_only) + self.assertTrue(parsed.utest) + self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.test_baseline[0].name, self.testInput0) + self.assertEqual(parsed.test_contender[0].name, self.testInput1) + self.assertFalse(parsed.benchmark_options) + + def test_benchmarks_basic_without_utest(self): + parsed = self.parser.parse_args( + ['--no-utest', 'benchmarks', self.testInput0, self.testInput1]) + self.assertFalse(parsed.display_aggregates_only) + self.assertFalse(parsed.utest) + self.assertEqual(parsed.utest_alpha, 0.05) + self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.test_baseline[0].name, self.testInput0) + self.assertEqual(parsed.test_contender[0].name, self.testInput1) + self.assertFalse(parsed.benchmark_options) + + def test_benchmarks_basic_display_aggregates_only(self): + parsed = self.parser.parse_args( + ['-a', 'benchmarks', self.testInput0, self.testInput1]) + self.assertTrue(parsed.display_aggregates_only) + self.assertTrue(parsed.utest) + self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.test_baseline[0].name, self.testInput0) + self.assertEqual(parsed.test_contender[0].name, self.testInput1) + self.assertFalse(parsed.benchmark_options) + + def test_benchmarks_basic_with_utest_alpha(self): + parsed = self.parser.parse_args( + ['--alpha=0.314', 'benchmarks', self.testInput0, self.testInput1]) + self.assertFalse(parsed.display_aggregates_only) + self.assertTrue(parsed.utest) + self.assertEqual(parsed.utest_alpha, 0.314) + self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.test_baseline[0].name, self.testInput0) + self.assertEqual(parsed.test_contender[0].name, self.testInput1) + self.assertFalse(parsed.benchmark_options) + + def test_benchmarks_basic_without_utest_with_utest_alpha(self): + parsed = self.parser.parse_args( + ['--no-utest', '--alpha=0.314', 'benchmarks', self.testInput0, self.testInput1]) + self.assertFalse(parsed.display_aggregates_only) + self.assertFalse(parsed.utest) + self.assertEqual(parsed.utest_alpha, 0.314) + self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.test_baseline[0].name, self.testInput0) + self.assertEqual(parsed.test_contender[0].name, self.testInput1) + self.assertFalse(parsed.benchmark_options) + + def test_benchmarks_with_remainder(self): + parsed = self.parser.parse_args( + ['benchmarks', self.testInput0, self.testInput1, 'd']) + self.assertFalse(parsed.display_aggregates_only) + self.assertTrue(parsed.utest) + self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.test_baseline[0].name, self.testInput0) + self.assertEqual(parsed.test_contender[0].name, self.testInput1) + self.assertEqual(parsed.benchmark_options, ['d']) + + def test_benchmarks_with_remainder_after_doubleminus(self): + parsed = self.parser.parse_args( + ['benchmarks', self.testInput0, self.testInput1, '--', 'e']) + self.assertFalse(parsed.display_aggregates_only) + self.assertTrue(parsed.utest) + self.assertEqual(parsed.mode, 'benchmarks') + self.assertEqual(parsed.test_baseline[0].name, self.testInput0) + self.assertEqual(parsed.test_contender[0].name, self.testInput1) + self.assertEqual(parsed.benchmark_options, ['e']) + + def test_filters_basic(self): + parsed = self.parser.parse_args( + ['filters', self.testInput0, 'c', 'd']) + self.assertFalse(parsed.display_aggregates_only) + self.assertTrue(parsed.utest) + self.assertEqual(parsed.mode, 'filters') + self.assertEqual(parsed.test[0].name, self.testInput0) + self.assertEqual(parsed.filter_baseline[0], 'c') + self.assertEqual(parsed.filter_contender[0], 'd') + self.assertFalse(parsed.benchmark_options) + + def test_filters_with_remainder(self): + parsed = self.parser.parse_args( + ['filters', self.testInput0, 'c', 'd', 'e']) + self.assertFalse(parsed.display_aggregates_only) + self.assertTrue(parsed.utest) + self.assertEqual(parsed.mode, 'filters') + self.assertEqual(parsed.test[0].name, self.testInput0) + self.assertEqual(parsed.filter_baseline[0], 'c') + self.assertEqual(parsed.filter_contender[0], 'd') + self.assertEqual(parsed.benchmark_options, ['e']) + + def test_filters_with_remainder_after_doubleminus(self): + parsed = self.parser.parse_args( + ['filters', self.testInput0, 'c', 'd', '--', 'f']) + self.assertFalse(parsed.display_aggregates_only) + self.assertTrue(parsed.utest) + self.assertEqual(parsed.mode, 'filters') + self.assertEqual(parsed.test[0].name, self.testInput0) + self.assertEqual(parsed.filter_baseline[0], 'c') + self.assertEqual(parsed.filter_contender[0], 'd') + self.assertEqual(parsed.benchmark_options, ['f']) + + def test_benchmarksfiltered_basic(self): + parsed = self.parser.parse_args( + ['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e']) + self.assertFalse(parsed.display_aggregates_only) + self.assertTrue(parsed.utest) + self.assertEqual(parsed.mode, 'benchmarksfiltered') + self.assertEqual(parsed.test_baseline[0].name, self.testInput0) + self.assertEqual(parsed.filter_baseline[0], 'c') + self.assertEqual(parsed.test_contender[0].name, self.testInput1) + self.assertEqual(parsed.filter_contender[0], 'e') + self.assertFalse(parsed.benchmark_options) + + def test_benchmarksfiltered_with_remainder(self): + parsed = self.parser.parse_args( + ['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e', 'f']) + self.assertFalse(parsed.display_aggregates_only) + self.assertTrue(parsed.utest) + self.assertEqual(parsed.mode, 'benchmarksfiltered') + self.assertEqual(parsed.test_baseline[0].name, self.testInput0) + self.assertEqual(parsed.filter_baseline[0], 'c') + self.assertEqual(parsed.test_contender[0].name, self.testInput1) + self.assertEqual(parsed.filter_contender[0], 'e') + self.assertEqual(parsed.benchmark_options[0], 'f') + + def test_benchmarksfiltered_with_remainder_after_doubleminus(self): + parsed = self.parser.parse_args( + ['benchmarksfiltered', self.testInput0, 'c', self.testInput1, 'e', '--', 'g']) + self.assertFalse(parsed.display_aggregates_only) + self.assertTrue(parsed.utest) + self.assertEqual(parsed.mode, 'benchmarksfiltered') + self.assertEqual(parsed.test_baseline[0].name, self.testInput0) + self.assertEqual(parsed.filter_baseline[0], 'c') + self.assertEqual(parsed.test_contender[0].name, self.testInput1) + self.assertEqual(parsed.filter_contender[0], 'e') + self.assertEqual(parsed.benchmark_options[0], 'g') + + +if __name__ == '__main__': + # unittest.main() + main() + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 +# kate: tab-width: 4; replace-tabs on; indent-width 4; tab-indents: off; +# kate: indent-mode python; remove-trailing-spaces modified; diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test1_run1.json b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test1_run1.json new file mode 100644 index 0000000000000000000000000000000000000000..601e327aefb5967976028655a9cc649b5ec60cfb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test1_run1.json @@ -0,0 +1,119 @@ +{ + "context": { + "date": "2016-08-02 17:44:46", + "num_cpus": 4, + "mhz_per_cpu": 4228, + "cpu_scaling_enabled": false, + "library_build_type": "release" + }, + "benchmarks": [ + { + "name": "BM_SameTimes", + "iterations": 1000, + "real_time": 10, + "cpu_time": 10, + "time_unit": "ns" + }, + { + "name": "BM_2xFaster", + "iterations": 1000, + "real_time": 50, + "cpu_time": 50, + "time_unit": "ns" + }, + { + "name": "BM_2xSlower", + "iterations": 1000, + "real_time": 50, + "cpu_time": 50, + "time_unit": "ns" + }, + { + "name": "BM_1PercentFaster", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_1PercentSlower", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_10PercentFaster", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_10PercentSlower", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_100xSlower", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_100xFaster", + "iterations": 1000, + "real_time": 10000, + "cpu_time": 10000, + "time_unit": "ns" + }, + { + "name": "BM_10PercentCPUToTime", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_ThirdFaster", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "MyComplexityTest_BigO", + "run_name": "MyComplexityTest", + "run_type": "aggregate", + "aggregate_name": "BigO", + "cpu_coefficient": 4.2749856294592886e+00, + "real_coefficient": 6.4789275289789780e+00, + "big_o": "N", + "time_unit": "ns" + }, + { + "name": "MyComplexityTest_RMS", + "run_name": "MyComplexityTest", + "run_type": "aggregate", + "aggregate_name": "RMS", + "rms": 4.5097802512472874e-03 + }, + { + "name": "BM_NotBadTimeUnit", + "iterations": 1000, + "real_time": 0.4, + "cpu_time": 0.5, + "time_unit": "s" + }, + { + "name": "BM_DifferentTimeUnit", + "iterations": 1, + "real_time": 1, + "cpu_time": 1, + "time_unit": "s" + } + ] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test1_run2.json b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test1_run2.json new file mode 100644 index 0000000000000000000000000000000000000000..3cbcf39b0c93845cc6b826651d0f66fa0b57b3cd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test1_run2.json @@ -0,0 +1,119 @@ +{ + "context": { + "date": "2016-08-02 17:44:46", + "num_cpus": 4, + "mhz_per_cpu": 4228, + "cpu_scaling_enabled": false, + "library_build_type": "release" + }, + "benchmarks": [ + { + "name": "BM_SameTimes", + "iterations": 1000, + "real_time": 10, + "cpu_time": 10, + "time_unit": "ns" + }, + { + "name": "BM_2xFaster", + "iterations": 1000, + "real_time": 25, + "cpu_time": 25, + "time_unit": "ns" + }, + { + "name": "BM_2xSlower", + "iterations": 20833333, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_1PercentFaster", + "iterations": 1000, + "real_time": 98.9999999, + "cpu_time": 98.9999999, + "time_unit": "ns" + }, + { + "name": "BM_1PercentSlower", + "iterations": 1000, + "real_time": 100.9999999, + "cpu_time": 100.9999999, + "time_unit": "ns" + }, + { + "name": "BM_10PercentFaster", + "iterations": 1000, + "real_time": 90, + "cpu_time": 90, + "time_unit": "ns" + }, + { + "name": "BM_10PercentSlower", + "iterations": 1000, + "real_time": 110, + "cpu_time": 110, + "time_unit": "ns" + }, + { + "name": "BM_100xSlower", + "iterations": 1000, + "real_time": 1.0000e+04, + "cpu_time": 1.0000e+04, + "time_unit": "ns" + }, + { + "name": "BM_100xFaster", + "iterations": 1000, + "real_time": 100, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_10PercentCPUToTime", + "iterations": 1000, + "real_time": 110, + "cpu_time": 90, + "time_unit": "ns" + }, + { + "name": "BM_ThirdFaster", + "iterations": 1000, + "real_time": 66.665, + "cpu_time": 66.664, + "time_unit": "ns" + }, + { + "name": "MyComplexityTest_BigO", + "run_name": "MyComplexityTest", + "run_type": "aggregate", + "aggregate_name": "BigO", + "cpu_coefficient": 5.6215779594361486e+00, + "real_coefficient": 5.6288314793554610e+00, + "big_o": "N", + "time_unit": "ns" + }, + { + "name": "MyComplexityTest_RMS", + "run_name": "MyComplexityTest", + "run_type": "aggregate", + "aggregate_name": "RMS", + "rms": 3.3128901852342174e-03 + }, + { + "name": "BM_NotBadTimeUnit", + "iterations": 1000, + "real_time": 0.04, + "cpu_time": 0.6, + "time_unit": "s" + }, + { + "name": "BM_DifferentTimeUnit", + "iterations": 1, + "real_time": 1, + "cpu_time": 1, + "time_unit": "ns" + } + ] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test2_run.json b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test2_run.json new file mode 100644 index 0000000000000000000000000000000000000000..15bc69803049338769865f25593fb26de04ef696 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test2_run.json @@ -0,0 +1,81 @@ +{ + "context": { + "date": "2016-08-02 17:44:46", + "num_cpus": 4, + "mhz_per_cpu": 4228, + "cpu_scaling_enabled": false, + "library_build_type": "release" + }, + "benchmarks": [ + { + "name": "BM_Hi", + "iterations": 1234, + "real_time": 42, + "cpu_time": 24, + "time_unit": "ms" + }, + { + "name": "BM_Zero", + "iterations": 1000, + "real_time": 10, + "cpu_time": 10, + "time_unit": "ns" + }, + { + "name": "BM_Zero/4", + "iterations": 4000, + "real_time": 40, + "cpu_time": 40, + "time_unit": "ns" + }, + { + "name": "Prefix/BM_Zero", + "iterations": 2000, + "real_time": 20, + "cpu_time": 20, + "time_unit": "ns" + }, + { + "name": "Prefix/BM_Zero/3", + "iterations": 3000, + "real_time": 30, + "cpu_time": 30, + "time_unit": "ns" + }, + { + "name": "BM_One", + "iterations": 5000, + "real_time": 5, + "cpu_time": 5, + "time_unit": "ns" + }, + { + "name": "BM_One/4", + "iterations": 2000, + "real_time": 20, + "cpu_time": 20, + "time_unit": "ns" + }, + { + "name": "Prefix/BM_One", + "iterations": 1000, + "real_time": 10, + "cpu_time": 10, + "time_unit": "ns" + }, + { + "name": "Prefix/BM_One/3", + "iterations": 1500, + "real_time": 15, + "cpu_time": 15, + "time_unit": "ns" + }, + { + "name": "BM_Bye", + "iterations": 5321, + "real_time": 11, + "cpu_time": 63, + "time_unit": "ns" + } + ] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test3_run0.json b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test3_run0.json new file mode 100644 index 0000000000000000000000000000000000000000..49f8b061437f83705f357ba61bf364770aa3d0ac --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test3_run0.json @@ -0,0 +1,65 @@ +{ + "context": { + "date": "2016-08-02 17:44:46", + "num_cpus": 4, + "mhz_per_cpu": 4228, + "cpu_scaling_enabled": false, + "library_build_type": "release" + }, + "benchmarks": [ + { + "name": "BM_One", + "run_type": "aggregate", + "iterations": 1000, + "real_time": 10, + "cpu_time": 100, + "time_unit": "ns" + }, + { + "name": "BM_Two", + "iterations": 1000, + "real_time": 9, + "cpu_time": 90, + "time_unit": "ns" + }, + { + "name": "BM_Two", + "iterations": 1000, + "real_time": 8, + "cpu_time": 86, + "time_unit": "ns" + }, + { + "name": "short", + "run_type": "aggregate", + "iterations": 1000, + "real_time": 8, + "cpu_time": 80, + "time_unit": "ns" + }, + { + "name": "short", + "run_type": "aggregate", + "iterations": 1000, + "real_time": 8, + "cpu_time": 77, + "time_unit": "ns" + }, + { + "name": "medium", + "run_type": "iteration", + "iterations": 1000, + "real_time": 8, + "cpu_time": 80, + "time_unit": "ns" + }, + { + "name": "medium", + "run_type": "iteration", + "iterations": 1000, + "real_time": 9, + "cpu_time": 82, + "time_unit": "ns" + } + ] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test3_run1.json b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test3_run1.json new file mode 100644 index 0000000000000000000000000000000000000000..acc5ba17aed1842edde30f9a70def99d0bfa7457 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/Inputs/test3_run1.json @@ -0,0 +1,65 @@ +{ + "context": { + "date": "2016-08-02 17:44:46", + "num_cpus": 4, + "mhz_per_cpu": 4228, + "cpu_scaling_enabled": false, + "library_build_type": "release" + }, + "benchmarks": [ + { + "name": "BM_One", + "iterations": 1000, + "real_time": 9, + "cpu_time": 110, + "time_unit": "ns" + }, + { + "name": "BM_Two", + "run_type": "aggregate", + "iterations": 1000, + "real_time": 10, + "cpu_time": 89, + "time_unit": "ns" + }, + { + "name": "BM_Two", + "iterations": 1000, + "real_time": 7, + "cpu_time": 72, + "time_unit": "ns" + }, + { + "name": "short", + "run_type": "aggregate", + "iterations": 1000, + "real_time": 7, + "cpu_time": 75, + "time_unit": "ns" + }, + { + "name": "short", + "run_type": "aggregate", + "iterations": 762, + "real_time": 4.54, + "cpu_time": 66.6, + "time_unit": "ns" + }, + { + "name": "short", + "run_type": "iteration", + "iterations": 1000, + "real_time": 800, + "cpu_time": 1, + "time_unit": "ns" + }, + { + "name": "medium", + "run_type": "iteration", + "iterations": 1200, + "real_time": 5, + "cpu_time": 53, + "time_unit": "ns" + } + ] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/__init__.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..fce1a1acfbb33452050cdb94b677461c2f9ef399 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/__init__.py @@ -0,0 +1,8 @@ +"""Google Benchmark tooling""" + +__author__ = 'Eric Fiselier' +__email__ = 'eric@efcs.ca' +__versioninfo__ = (0, 5, 0) +__version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev' + +__all__ = [] diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/report.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/report.py new file mode 100644 index 0000000000000000000000000000000000000000..5bd3a8d85d68a270a65eae9b28845219ec35034f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/report.py @@ -0,0 +1,541 @@ +import unittest +"""report.py - Utilities for reporting statistics about benchmark results +""" +import os +import re +import copy + +from scipy.stats import mannwhitneyu + + +class BenchmarkColor(object): + def __init__(self, name, code): + self.name = name + self.code = code + + def __repr__(self): + return '%s%r' % (self.__class__.__name__, + (self.name, self.code)) + + def __format__(self, format): + return self.code + + +# Benchmark Colors Enumeration +BC_NONE = BenchmarkColor('NONE', '') +BC_MAGENTA = BenchmarkColor('MAGENTA', '\033[95m') +BC_CYAN = BenchmarkColor('CYAN', '\033[96m') +BC_OKBLUE = BenchmarkColor('OKBLUE', '\033[94m') +BC_OKGREEN = BenchmarkColor('OKGREEN', '\033[32m') +BC_HEADER = BenchmarkColor('HEADER', '\033[92m') +BC_WARNING = BenchmarkColor('WARNING', '\033[93m') +BC_WHITE = BenchmarkColor('WHITE', '\033[97m') +BC_FAIL = BenchmarkColor('FAIL', '\033[91m') +BC_ENDC = BenchmarkColor('ENDC', '\033[0m') +BC_BOLD = BenchmarkColor('BOLD', '\033[1m') +BC_UNDERLINE = BenchmarkColor('UNDERLINE', '\033[4m') + +UTEST_MIN_REPETITIONS = 2 +UTEST_OPTIMAL_REPETITIONS = 9 # Lowest reasonable number, More is better. +UTEST_COL_NAME = "_pvalue" + + +def color_format(use_color, fmt_str, *args, **kwargs): + """ + Return the result of 'fmt_str.format(*args, **kwargs)' after transforming + 'args' and 'kwargs' according to the value of 'use_color'. If 'use_color' + is False then all color codes in 'args' and 'kwargs' are replaced with + the empty string. + """ + assert use_color is True or use_color is False + if not use_color: + args = [arg if not isinstance(arg, BenchmarkColor) else BC_NONE + for arg in args] + kwargs = {key: arg if not isinstance(arg, BenchmarkColor) else BC_NONE + for key, arg in kwargs.items()} + return fmt_str.format(*args, **kwargs) + + +def find_longest_name(benchmark_list): + """ + Return the length of the longest benchmark name in a given list of + benchmark JSON objects + """ + longest_name = 1 + for bc in benchmark_list: + if len(bc['name']) > longest_name: + longest_name = len(bc['name']) + return longest_name + + +def calculate_change(old_val, new_val): + """ + Return a float representing the decimal change between old_val and new_val. + """ + if old_val == 0 and new_val == 0: + return 0.0 + if old_val == 0: + return float(new_val - old_val) / (float(old_val + new_val) / 2) + return float(new_val - old_val) / abs(old_val) + + +def filter_benchmark(json_orig, family, replacement=""): + """ + Apply a filter to the json, and only leave the 'family' of benchmarks. + """ + regex = re.compile(family) + filtered = {} + filtered['benchmarks'] = [] + for be in json_orig['benchmarks']: + if not regex.search(be['name']): + continue + filteredbench = copy.deepcopy(be) # Do NOT modify the old name! + filteredbench['name'] = regex.sub(replacement, filteredbench['name']) + filtered['benchmarks'].append(filteredbench) + return filtered + + +def get_unique_benchmark_names(json): + """ + While *keeping* the order, give all the unique 'names' used for benchmarks. + """ + seen = set() + uniqued = [x['name'] for x in json['benchmarks'] + if x['name'] not in seen and + (seen.add(x['name']) or True)] + return uniqued + + +def intersect(list1, list2): + """ + Given two lists, get a new list consisting of the elements only contained + in *both of the input lists*, while preserving the ordering. + """ + return [x for x in list1 if x in list2] + + +def is_potentially_comparable_benchmark(x): + return ('time_unit' in x and 'real_time' in x and 'cpu_time' in x) + + +def partition_benchmarks(json1, json2): + """ + While preserving the ordering, find benchmarks with the same names in + both of the inputs, and group them. + (i.e. partition/filter into groups with common name) + """ + json1_unique_names = get_unique_benchmark_names(json1) + json2_unique_names = get_unique_benchmark_names(json2) + names = intersect(json1_unique_names, json2_unique_names) + partitions = [] + for name in names: + time_unit = None + # Pick the time unit from the first entry of the lhs benchmark. + # We should be careful not to crash with unexpected input. + for x in json1['benchmarks']: + if (x['name'] == name and is_potentially_comparable_benchmark(x)): + time_unit = x['time_unit'] + break + if time_unit is None: + continue + # Filter by name and time unit. + # All the repetitions are assumed to be comparable. + lhs = [x for x in json1['benchmarks'] if x['name'] == name and + x['time_unit'] == time_unit] + rhs = [x for x in json2['benchmarks'] if x['name'] == name and + x['time_unit'] == time_unit] + partitions.append([lhs, rhs]) + return partitions + + +def extract_field(partition, field_name): + # The count of elements may be different. We want *all* of them. + lhs = [x[field_name] for x in partition[0]] + rhs = [x[field_name] for x in partition[1]] + return [lhs, rhs] + +def calc_utest(timings_cpu, timings_time): + min_rep_cnt = min(len(timings_time[0]), + len(timings_time[1]), + len(timings_cpu[0]), + len(timings_cpu[1])) + + # Does *everything* has at least UTEST_MIN_REPETITIONS repetitions? + if min_rep_cnt < UTEST_MIN_REPETITIONS: + return False, None, None + + time_pvalue = mannwhitneyu( + timings_time[0], timings_time[1], alternative='two-sided').pvalue + cpu_pvalue = mannwhitneyu( + timings_cpu[0], timings_cpu[1], alternative='two-sided').pvalue + + return (min_rep_cnt >= UTEST_OPTIMAL_REPETITIONS), cpu_pvalue, time_pvalue + +def print_utest(partition, utest_alpha, first_col_width, use_color=True): + def get_utest_color(pval): + return BC_FAIL if pval >= utest_alpha else BC_OKGREEN + + timings_time = extract_field(partition, 'real_time') + timings_cpu = extract_field(partition, 'cpu_time') + have_optimal_repetitions, cpu_pvalue, time_pvalue = calc_utest(timings_cpu, timings_time) + + # Check if we failed miserably with minimum required repetitions for utest + if not have_optimal_repetitions and cpu_pvalue is None and time_pvalue is None: + return [] + + dsc = "U Test, Repetitions: {} vs {}".format( + len(timings_cpu[0]), len(timings_cpu[1])) + dsc_color = BC_OKGREEN + + # We still got some results to show but issue a warning about it. + if not have_optimal_repetitions: + dsc_color = BC_WARNING + dsc += ". WARNING: Results unreliable! {}+ repetitions recommended.".format( + UTEST_OPTIMAL_REPETITIONS) + + special_str = "{}{:<{}s}{endc}{}{:16.4f}{endc}{}{:16.4f}{endc}{} {}" + + last_name = partition[0][0]['name'] + return [color_format(use_color, + special_str, + BC_HEADER, + "{}{}".format(last_name, UTEST_COL_NAME), + first_col_width, + get_utest_color(time_pvalue), time_pvalue, + get_utest_color(cpu_pvalue), cpu_pvalue, + dsc_color, dsc, + endc=BC_ENDC)] + + +def generate_difference_report( + json1, + json2, + display_aggregates_only=False, + utest=False, + utest_alpha=0.05, + use_color=True): + """ + Calculate and report the difference between each test of two benchmarks + runs specified as 'json1' and 'json2'. + """ + assert utest is True or utest is False + first_col_width = find_longest_name(json1['benchmarks']) + + def find_test(name): + for b in json2['benchmarks']: + if b['name'] == name: + return b + return None + + first_col_width = max( + first_col_width, + len('Benchmark')) + first_col_width += len(UTEST_COL_NAME) + first_line = "{:<{}s}Time CPU Time Old Time New CPU Old CPU New".format( + 'Benchmark', 12 + first_col_width) + output_strs = [first_line, '-' * len(first_line)] + + partitions = partition_benchmarks(json1, json2) + for partition in partitions: + # Careful, we may have different repetition count. + for i in range(min(len(partition[0]), len(partition[1]))): + bn = partition[0][i] + other_bench = partition[1][i] + + # *If* we were asked to only display aggregates, + # and if it is non-aggregate, then skip it. + if display_aggregates_only and 'run_type' in bn and 'run_type' in other_bench: + assert bn['run_type'] == other_bench['run_type'] + if bn['run_type'] != 'aggregate': + continue + + fmt_str = "{}{:<{}s}{endc}{}{:+16.4f}{endc}{}{:+16.4f}{endc}{:14.0f}{:14.0f}{endc}{:14.0f}{:14.0f}" + + def get_color(res): + if res > 0.05: + return BC_FAIL + elif res > -0.07: + return BC_WHITE + else: + return BC_CYAN + + tres = calculate_change(bn['real_time'], other_bench['real_time']) + cpures = calculate_change(bn['cpu_time'], other_bench['cpu_time']) + output_strs += [color_format(use_color, + fmt_str, + BC_HEADER, + bn['name'], + first_col_width, + get_color(tres), + tres, + get_color(cpures), + cpures, + bn['real_time'], + other_bench['real_time'], + bn['cpu_time'], + other_bench['cpu_time'], + endc=BC_ENDC)] + + # After processing the whole partition, if requested, do the U test. + if utest: + output_strs += print_utest(partition, + utest_alpha=utest_alpha, + first_col_width=first_col_width, + use_color=use_color) + + return output_strs + + +############################################################################### +# Unit tests + + +class TestGetUniqueBenchmarkNames(unittest.TestCase): + def load_results(self): + import json + testInputs = os.path.join( + os.path.dirname( + os.path.realpath(__file__)), + 'Inputs') + testOutput = os.path.join(testInputs, 'test3_run0.json') + with open(testOutput, 'r') as f: + json = json.load(f) + return json + + def test_basic(self): + expect_lines = [ + 'BM_One', + 'BM_Two', + 'short', # These two are not sorted + 'medium', # These two are not sorted + ] + json = self.load_results() + output_lines = get_unique_benchmark_names(json) + print("\n") + print("\n".join(output_lines)) + self.assertEqual(len(output_lines), len(expect_lines)) + for i in range(0, len(output_lines)): + self.assertEqual(expect_lines[i], output_lines[i]) + + +class TestReportDifference(unittest.TestCase): + def load_results(self): + import json + testInputs = os.path.join( + os.path.dirname( + os.path.realpath(__file__)), + 'Inputs') + testOutput1 = os.path.join(testInputs, 'test1_run1.json') + testOutput2 = os.path.join(testInputs, 'test1_run2.json') + with open(testOutput1, 'r') as f: + json1 = json.load(f) + with open(testOutput2, 'r') as f: + json2 = json.load(f) + return json1, json2 + + def test_basic(self): + expect_lines = [ + ['BM_SameTimes', '+0.0000', '+0.0000', '10', '10', '10', '10'], + ['BM_2xFaster', '-0.5000', '-0.5000', '50', '25', '50', '25'], + ['BM_2xSlower', '+1.0000', '+1.0000', '50', '100', '50', '100'], + ['BM_1PercentFaster', '-0.0100', '-0.0100', '100', '99', '100', '99'], + ['BM_1PercentSlower', '+0.0100', '+0.0100', '100', '101', '100', '101'], + ['BM_10PercentFaster', '-0.1000', '-0.1000', '100', '90', '100', '90'], + ['BM_10PercentSlower', '+0.1000', '+0.1000', '100', '110', '100', '110'], + ['BM_100xSlower', '+99.0000', '+99.0000', + '100', '10000', '100', '10000'], + ['BM_100xFaster', '-0.9900', '-0.9900', + '10000', '100', '10000', '100'], + ['BM_10PercentCPUToTime', '+0.1000', + '-0.1000', '100', '110', '100', '90'], + ['BM_ThirdFaster', '-0.3333', '-0.3334', '100', '67', '100', '67'], + ['BM_NotBadTimeUnit', '-0.9000', '+0.2000', '0', '0', '0', '1'], + ] + json1, json2 = self.load_results() + output_lines_with_header = generate_difference_report( + json1, json2, use_color=False) + output_lines = output_lines_with_header[2:] + print("\n") + print("\n".join(output_lines_with_header)) + self.assertEqual(len(output_lines), len(expect_lines)) + for i in range(0, len(output_lines)): + parts = [x for x in output_lines[i].split(' ') if x] + self.assertEqual(len(parts), 7) + self.assertEqual(expect_lines[i], parts) + + +class TestReportDifferenceBetweenFamilies(unittest.TestCase): + def load_result(self): + import json + testInputs = os.path.join( + os.path.dirname( + os.path.realpath(__file__)), + 'Inputs') + testOutput = os.path.join(testInputs, 'test2_run.json') + with open(testOutput, 'r') as f: + json = json.load(f) + return json + + def test_basic(self): + expect_lines = [ + ['.', '-0.5000', '-0.5000', '10', '5', '10', '5'], + ['./4', '-0.5000', '-0.5000', '40', '20', '40', '20'], + ['Prefix/.', '-0.5000', '-0.5000', '20', '10', '20', '10'], + ['Prefix/./3', '-0.5000', '-0.5000', '30', '15', '30', '15'], + ] + json = self.load_result() + json1 = filter_benchmark(json, "BM_Z.ro", ".") + json2 = filter_benchmark(json, "BM_O.e", ".") + output_lines_with_header = generate_difference_report( + json1, json2, use_color=False) + output_lines = output_lines_with_header[2:] + print("\n") + print("\n".join(output_lines_with_header)) + self.assertEqual(len(output_lines), len(expect_lines)) + for i in range(0, len(output_lines)): + parts = [x for x in output_lines[i].split(' ') if x] + self.assertEqual(len(parts), 7) + self.assertEqual(expect_lines[i], parts) + + +class TestReportDifferenceWithUTest(unittest.TestCase): + def load_results(self): + import json + testInputs = os.path.join( + os.path.dirname( + os.path.realpath(__file__)), + 'Inputs') + testOutput1 = os.path.join(testInputs, 'test3_run0.json') + testOutput2 = os.path.join(testInputs, 'test3_run1.json') + with open(testOutput1, 'r') as f: + json1 = json.load(f) + with open(testOutput2, 'r') as f: + json2 = json.load(f) + return json1, json2 + + def test_utest(self): + expect_lines = [] + expect_lines = [ + ['BM_One', '-0.1000', '+0.1000', '10', '9', '100', '110'], + ['BM_Two', '+0.1111', '-0.0111', '9', '10', '90', '89'], + ['BM_Two', '-0.1250', '-0.1628', '8', '7', '86', '72'], + ['BM_Two_pvalue', + '0.6985', + '0.6985', + 'U', + 'Test,', + 'Repetitions:', + '2', + 'vs', + '2.', + 'WARNING:', + 'Results', + 'unreliable!', + '9+', + 'repetitions', + 'recommended.'], + ['short', '-0.1250', '-0.0625', '8', '7', '80', '75'], + ['short', '-0.4325', '-0.1351', '8', '5', '77', '67'], + ['short_pvalue', + '0.7671', + '0.1489', + 'U', + 'Test,', + 'Repetitions:', + '2', + 'vs', + '3.', + 'WARNING:', + 'Results', + 'unreliable!', + '9+', + 'repetitions', + 'recommended.'], + ['medium', '-0.3750', '-0.3375', '8', '5', '80', '53'], + ] + json1, json2 = self.load_results() + output_lines_with_header = generate_difference_report( + json1, json2, utest=True, utest_alpha=0.05, use_color=False) + output_lines = output_lines_with_header[2:] + print("\n") + print("\n".join(output_lines_with_header)) + self.assertEqual(len(output_lines), len(expect_lines)) + for i in range(0, len(output_lines)): + parts = [x for x in output_lines[i].split(' ') if x] + self.assertEqual(expect_lines[i], parts) + + +class TestReportDifferenceWithUTestWhileDisplayingAggregatesOnly( + unittest.TestCase): + def load_results(self): + import json + testInputs = os.path.join( + os.path.dirname( + os.path.realpath(__file__)), + 'Inputs') + testOutput1 = os.path.join(testInputs, 'test3_run0.json') + testOutput2 = os.path.join(testInputs, 'test3_run1.json') + with open(testOutput1, 'r') as f: + json1 = json.load(f) + with open(testOutput2, 'r') as f: + json2 = json.load(f) + return json1, json2 + + def test_utest(self): + expect_lines = [] + expect_lines = [ + ['BM_One', '-0.1000', '+0.1000', '10', '9', '100', '110'], + ['BM_Two', '+0.1111', '-0.0111', '9', '10', '90', '89'], + ['BM_Two', '-0.1250', '-0.1628', '8', '7', '86', '72'], + ['BM_Two_pvalue', + '0.6985', + '0.6985', + 'U', + 'Test,', + 'Repetitions:', + '2', + 'vs', + '2.', + 'WARNING:', + 'Results', + 'unreliable!', + '9+', + 'repetitions', + 'recommended.'], + ['short', '-0.1250', '-0.0625', '8', '7', '80', '75'], + ['short', '-0.4325', '-0.1351', '8', '5', '77', '67'], + ['short_pvalue', + '0.7671', + '0.1489', + 'U', + 'Test,', + 'Repetitions:', + '2', + 'vs', + '3.', + 'WARNING:', + 'Results', + 'unreliable!', + '9+', + 'repetitions', + 'recommended.'], + ] + json1, json2 = self.load_results() + output_lines_with_header = generate_difference_report( + json1, json2, display_aggregates_only=True, + utest=True, utest_alpha=0.05, use_color=False) + output_lines = output_lines_with_header[2:] + print("\n") + print("\n".join(output_lines_with_header)) + self.assertEqual(len(output_lines), len(expect_lines)) + for i in range(0, len(output_lines)): + parts = [x for x in output_lines[i].split(' ') if x] + self.assertEqual(expect_lines[i], parts) + + +if __name__ == '__main__': + unittest.main() + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 +# kate: tab-width: 4; replace-tabs on; indent-width 4; tab-indents: off; +# kate: indent-mode python; remove-trailing-spaces modified; diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/util.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/util.py new file mode 100644 index 0000000000000000000000000000000000000000..1f8e8e2c47968bec538052897d51358a2fdf1245 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/gbench/util.py @@ -0,0 +1,164 @@ +"""util.py - General utilities for running, loading, and processing benchmarks +""" +import json +import os +import tempfile +import subprocess +import sys + +# Input file type enumeration +IT_Invalid = 0 +IT_JSON = 1 +IT_Executable = 2 + +_num_magic_bytes = 2 if sys.platform.startswith('win') else 4 + + +def is_executable_file(filename): + """ + Return 'True' if 'filename' names a valid file which is likely + an executable. A file is considered an executable if it starts with the + magic bytes for a EXE, Mach O, or ELF file. + """ + if not os.path.isfile(filename): + return False + with open(filename, mode='rb') as f: + magic_bytes = f.read(_num_magic_bytes) + if sys.platform == 'darwin': + return magic_bytes in [ + b'\xfe\xed\xfa\xce', # MH_MAGIC + b'\xce\xfa\xed\xfe', # MH_CIGAM + b'\xfe\xed\xfa\xcf', # MH_MAGIC_64 + b'\xcf\xfa\xed\xfe', # MH_CIGAM_64 + b'\xca\xfe\xba\xbe', # FAT_MAGIC + b'\xbe\xba\xfe\xca' # FAT_CIGAM + ] + elif sys.platform.startswith('win'): + return magic_bytes == b'MZ' + else: + return magic_bytes == b'\x7FELF' + + +def is_json_file(filename): + """ + Returns 'True' if 'filename' names a valid JSON output file. + 'False' otherwise. + """ + try: + with open(filename, 'r') as f: + json.load(f) + return True + except BaseException: + pass + return False + + +def classify_input_file(filename): + """ + Return a tuple (type, msg) where 'type' specifies the classified type + of 'filename'. If 'type' is 'IT_Invalid' then 'msg' is a human readable + string represeting the error. + """ + ftype = IT_Invalid + err_msg = None + if not os.path.exists(filename): + err_msg = "'%s' does not exist" % filename + elif not os.path.isfile(filename): + err_msg = "'%s' does not name a file" % filename + elif is_executable_file(filename): + ftype = IT_Executable + elif is_json_file(filename): + ftype = IT_JSON + else: + err_msg = "'%s' does not name a valid benchmark executable or JSON file" % filename + return ftype, err_msg + + +def check_input_file(filename): + """ + Classify the file named by 'filename' and return the classification. + If the file is classified as 'IT_Invalid' print an error message and exit + the program. + """ + ftype, msg = classify_input_file(filename) + if ftype == IT_Invalid: + print("Invalid input file: %s" % msg) + sys.exit(1) + return ftype + + +def find_benchmark_flag(prefix, benchmark_flags): + """ + Search the specified list of flags for a flag matching `` and + if it is found return the arg it specifies. If specified more than once the + last value is returned. If the flag is not found None is returned. + """ + assert prefix.startswith('--') and prefix.endswith('=') + result = None + for f in benchmark_flags: + if f.startswith(prefix): + result = f[len(prefix):] + return result + + +def remove_benchmark_flags(prefix, benchmark_flags): + """ + Return a new list containing the specified benchmark_flags except those + with the specified prefix. + """ + assert prefix.startswith('--') and prefix.endswith('=') + return [f for f in benchmark_flags if not f.startswith(prefix)] + + +def load_benchmark_results(fname): + """ + Read benchmark output from a file and return the JSON object. + REQUIRES: 'fname' names a file containing JSON benchmark output. + """ + with open(fname, 'r') as f: + return json.load(f) + + +def run_benchmark(exe_name, benchmark_flags): + """ + Run a benchmark specified by 'exe_name' with the specified + 'benchmark_flags'. The benchmark is run directly as a subprocess to preserve + real time console output. + RETURNS: A JSON object representing the benchmark output + """ + output_name = find_benchmark_flag('--benchmark_out=', + benchmark_flags) + is_temp_output = False + if output_name is None: + is_temp_output = True + thandle, output_name = tempfile.mkstemp() + os.close(thandle) + benchmark_flags = list(benchmark_flags) + \ + ['--benchmark_out=%s' % output_name] + + cmd = [exe_name] + benchmark_flags + print("RUNNING: %s" % ' '.join(cmd)) + exitCode = subprocess.call(cmd) + if exitCode != 0: + print('TEST FAILED...') + sys.exit(exitCode) + json_res = load_benchmark_results(output_name) + if is_temp_output: + os.unlink(output_name) + return json_res + + +def run_or_load_benchmark(filename, benchmark_flags): + """ + Get the results for a specified benchmark. If 'filename' specifies + an executable benchmark then the results are generated by running the + benchmark. Otherwise 'filename' must name a valid JSON output file, + which is loaded and the result returned. + """ + ftype = check_input_file(filename) + if ftype == IT_JSON: + return load_benchmark_results(filename) + elif ftype == IT_Executable: + return run_benchmark(filename, benchmark_flags) + else: + assert False # This branch is unreachable diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/strip_asm.py b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/strip_asm.py new file mode 100755 index 0000000000000000000000000000000000000000..9030550b43bece88d41bac337e26004a109232d5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/google-benchmark/tools/strip_asm.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python + +""" +strip_asm.py - Cleanup ASM output for the specified file +""" + +from argparse import ArgumentParser +import sys +import os +import re + +def find_used_labels(asm): + found = set() + label_re = re.compile("\s*j[a-z]+\s+\.L([a-zA-Z0-9][a-zA-Z0-9_]*)") + for l in asm.splitlines(): + m = label_re.match(l) + if m: + found.add('.L%s' % m.group(1)) + return found + + +def normalize_labels(asm): + decls = set() + label_decl = re.compile("^[.]{0,1}L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)") + for l in asm.splitlines(): + m = label_decl.match(l) + if m: + decls.add(m.group(0)) + if len(decls) == 0: + return asm + needs_dot = next(iter(decls))[0] != '.' + if not needs_dot: + return asm + for ld in decls: + asm = re.sub("(^|\s+)" + ld + "(?=:|\s)", '\\1.' + ld, asm) + return asm + + +def transform_labels(asm): + asm = normalize_labels(asm) + used_decls = find_used_labels(asm) + new_asm = '' + label_decl = re.compile("^\.L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)") + for l in asm.splitlines(): + m = label_decl.match(l) + if not m or m.group(0) in used_decls: + new_asm += l + new_asm += '\n' + return new_asm + + +def is_identifier(tk): + if len(tk) == 0: + return False + first = tk[0] + if not first.isalpha() and first != '_': + return False + for i in range(1, len(tk)): + c = tk[i] + if not c.isalnum() and c != '_': + return False + return True + +def process_identifiers(l): + """ + process_identifiers - process all identifiers and modify them to have + consistent names across all platforms; specifically across ELF and MachO. + For example, MachO inserts an additional understore at the beginning of + names. This function removes that. + """ + parts = re.split(r'([a-zA-Z0-9_]+)', l) + new_line = '' + for tk in parts: + if is_identifier(tk): + if tk.startswith('__Z'): + tk = tk[1:] + elif tk.startswith('_') and len(tk) > 1 and \ + tk[1].isalpha() and tk[1] != 'Z': + tk = tk[1:] + new_line += tk + return new_line + + +def process_asm(asm): + """ + Strip the ASM of unwanted directives and lines + """ + new_contents = '' + asm = transform_labels(asm) + + # TODO: Add more things we want to remove + discard_regexes = [ + re.compile("\s+\..*$"), # directive + re.compile("\s*#(NO_APP|APP)$"), #inline ASM + re.compile("\s*#.*$"), # comment line + re.compile("\s*\.globa?l\s*([.a-zA-Z_][a-zA-Z0-9$_.]*)"), #global directive + re.compile("\s*\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)"), + ] + keep_regexes = [ + + ] + fn_label_def = re.compile("^[a-zA-Z_][a-zA-Z0-9_.]*:") + for l in asm.splitlines(): + # Remove Mach-O attribute + l = l.replace('@GOTPCREL', '') + add_line = True + for reg in discard_regexes: + if reg.match(l) is not None: + add_line = False + break + for reg in keep_regexes: + if reg.match(l) is not None: + add_line = True + break + if add_line: + if fn_label_def.match(l) and len(new_contents) != 0: + new_contents += '\n' + l = process_identifiers(l) + new_contents += l + new_contents += '\n' + return new_contents + +def main(): + parser = ArgumentParser( + description='generate a stripped assembly file') + parser.add_argument( + 'input', metavar='input', type=str, nargs=1, + help='An input assembly file') + parser.add_argument( + 'out', metavar='output', type=str, nargs=1, + help='The output file') + args, unknown_args = parser.parse_known_args() + input = args.input[0] + output = args.out[0] + if not os.path.isfile(input): + print(("ERROR: input file '%s' does not exist") % input) + sys.exit(1) + contents = None + with open(input, 'r') as f: + contents = f.read() + new_contents = process_asm(contents) + with open(output, 'w') as f: + f.write(new_contents) + + +if __name__ == '__main__': + main() + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 +# kate: tab-width: 4; replace-tabs on; indent-width 4; tab-indents: off; +# kate: indent-mode python; remove-trailing-spaces modified; diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..db292946a59453e09929229c1fbdb3701f2bd6ab --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/CMakeLists.txt @@ -0,0 +1,328 @@ +######################################################################## +# Note: CMake support is community-based. The maintainers do not use CMake +# internally. +# +# CMake build script for Google Test. +# +# To run the tests for Google Test itself on Linux, use 'make test' or +# ctest. You can select which tests to run using 'ctest -R regex'. +# For more options, run 'ctest --help'. + +# When other libraries are using a shared version of runtime libraries, +# Google Test also has to use one. +option( + gtest_force_shared_crt + "Use shared (DLL) run-time lib even when Google Test is built as static lib." + OFF) + +option(gtest_build_tests "Build all of gtest's own tests." OFF) + +option(gtest_build_samples "Build gtest's sample programs." OFF) + +option(gtest_disable_pthreads "Disable uses of pthreads in gtest." OFF) + +option( + gtest_hide_internal_symbols + "Build gtest with internal symbols hidden in shared libraries." + OFF) + +# Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build(). +include(cmake/hermetic_build.cmake OPTIONAL) + +if (COMMAND pre_project_set_up_hermetic_build) + pre_project_set_up_hermetic_build() +endif() + +######################################################################## +# +# Project-wide settings + +# Name of the project. +# +# CMake files in this project can refer to the root source directory +# as ${gtest_SOURCE_DIR} and to the root binary directory as +# ${gtest_BINARY_DIR}. +# Language "C" is required for find_package(Threads). + +# Project version: + +if (CMAKE_VERSION VERSION_LESS 3.0) + project(gtest CXX C) + set(PROJECT_VERSION ${GOOGLETEST_VERSION}) +else() + cmake_policy(SET CMP0048 NEW) + project(gtest VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C) +endif() +cmake_minimum_required(VERSION 2.6.4) + +if (POLICY CMP0063) # Visibility + cmake_policy(SET CMP0063 NEW) +endif (POLICY CMP0063) + +if (COMMAND set_up_hermetic_build) + set_up_hermetic_build() +endif() + +# These commands only run if this is the main project +if(CMAKE_PROJECT_NAME STREQUAL "gtest" OR CMAKE_PROJECT_NAME STREQUAL "googletest-distribution") + + # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to + # make it prominent in the GUI. + option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) + +else() + + mark_as_advanced( + gtest_force_shared_crt + gtest_build_tests + gtest_build_samples + gtest_disable_pthreads + gtest_hide_internal_symbols) + +endif() + + +if (gtest_hide_internal_symbols) + set(CMAKE_CXX_VISIBILITY_PRESET hidden) + set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) +endif() + +# Define helper functions and macros used by Google Test. +include(cmake/internal_utils.cmake) + +config_compiler_and_linker() # Defined in internal_utils.cmake. + +# Create the CMake package file descriptors. +if (INSTALL_GTEST) + include(CMakePackageConfigHelpers) + set(cmake_package_name GTest) + set(targets_export_name ${cmake_package_name}Targets CACHE INTERNAL "") + set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated" CACHE INTERNAL "") + set(cmake_files_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${cmake_package_name}") + set(version_file "${generated_dir}/${cmake_package_name}ConfigVersion.cmake") + write_basic_package_version_file(${version_file} VERSION ${GOOGLETEST_VERSION} COMPATIBILITY AnyNewerVersion) + install(EXPORT ${targets_export_name} + NAMESPACE ${cmake_package_name}:: + DESTINATION ${cmake_files_install_dir}) + set(config_file "${generated_dir}/${cmake_package_name}Config.cmake") + configure_package_config_file("${gtest_SOURCE_DIR}/cmake/Config.cmake.in" + "${config_file}" INSTALL_DESTINATION ${cmake_files_install_dir}) + install(FILES ${version_file} ${config_file} + DESTINATION ${cmake_files_install_dir}) +endif() + +# Where Google Test's .h files can be found. +set(gtest_build_include_dirs + "${gtest_SOURCE_DIR}/include" + "${gtest_SOURCE_DIR}") +include_directories(${gtest_build_include_dirs}) + +######################################################################## +# +# Defines the gtest & gtest_main libraries. User tests should link +# with one of them. + +# Google Test libraries. We build them using more strict warnings than what +# are used for other targets, to ensure that gtest can be compiled by a user +# aggressive about warnings. +cxx_library(gtest "${cxx_strict}" src/gtest-all.cc) +cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc) +# If the CMake version supports it, attach header directory information +# to the targets for when we are part of a parent build (ie being pulled +# in via add_subdirectory() rather than being a standalone build). +if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") + target_include_directories(gtest SYSTEM INTERFACE + "$" + "$/${CMAKE_INSTALL_INCLUDEDIR}>") + target_include_directories(gtest_main SYSTEM INTERFACE + "$" + "$/${CMAKE_INSTALL_INCLUDEDIR}>") +endif() +target_link_libraries(gtest_main PUBLIC gtest) + +######################################################################## +# +# Install rules +install_project(gtest gtest_main) + +######################################################################## +# +# Samples on how to link user tests with gtest or gtest_main. +# +# They are not built by default. To build them, set the +# gtest_build_samples option to ON. You can do it by running ccmake +# or specifying the -Dgtest_build_samples=ON flag when running cmake. + +if (gtest_build_samples) + cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc) + cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc) + cxx_executable(sample3_unittest samples gtest_main) + cxx_executable(sample4_unittest samples gtest_main samples/sample4.cc) + cxx_executable(sample5_unittest samples gtest_main samples/sample1.cc) + cxx_executable(sample6_unittest samples gtest_main) + cxx_executable(sample7_unittest samples gtest_main) + cxx_executable(sample8_unittest samples gtest_main) + cxx_executable(sample9_unittest samples gtest) + cxx_executable(sample10_unittest samples gtest) +endif() + +######################################################################## +# +# Google Test's own tests. +# +# You can skip this section if you aren't interested in testing +# Google Test itself. +# +# The tests are not built by default. To build them, set the +# gtest_build_tests option to ON. You can do it by running ccmake +# or specifying the -Dgtest_build_tests=ON flag when running cmake. + +if (gtest_build_tests) + # This must be set in the root directory for the tests to be run by + # 'make test' or ctest. + enable_testing() + + if (WIN32) + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$/RunTest.ps1" + CONTENT +"$project_bin = \"${CMAKE_BINARY_DIR}/bin/$\" +$env:Path = \"$project_bin;$env:Path\" +& $args") + elseif (MINGW OR CYGWIN) + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/RunTest.ps1" + CONTENT +"$project_bin = (cygpath --windows ${CMAKE_BINARY_DIR}/bin) +$env:Path = \"$project_bin;$env:Path\" +& $args") + endif() + + ############################################################ + # C++ tests built with standard compiler flags. + + cxx_test(googletest-death-test-test gtest_main) + cxx_test(gtest_environment_test gtest) + cxx_test(googletest-filepath-test gtest_main) + cxx_test(googletest-listener-test gtest_main) + cxx_test(gtest_main_unittest gtest_main) + cxx_test(googletest-message-test gtest_main) + cxx_test(gtest_no_test_unittest gtest) + cxx_test(googletest-options-test gtest_main) + cxx_test(googletest-param-test-test gtest + test/googletest-param-test2-test.cc) + cxx_test(googletest-port-test gtest_main) + cxx_test(gtest_pred_impl_unittest gtest_main) + cxx_test(gtest_premature_exit_test gtest + test/gtest_premature_exit_test.cc) + cxx_test(googletest-printers-test gtest_main) + cxx_test(gtest_prod_test gtest_main + test/production.cc) + cxx_test(gtest_repeat_test gtest) + cxx_test(gtest_sole_header_test gtest_main) + cxx_test(gtest_stress_test gtest) + cxx_test(googletest-test-part-test gtest_main) + cxx_test(gtest_throw_on_failure_ex_test gtest) + cxx_test(gtest-typed-test_test gtest_main + test/gtest-typed-test2_test.cc) + cxx_test(gtest_unittest gtest_main) + cxx_test(gtest-unittest-api_test gtest) + cxx_test(gtest_skip_in_environment_setup_test gtest_main) + cxx_test(gtest_skip_test gtest_main) + + ############################################################ + # C++ tests built with non-standard compiler flags. + + # MSVC 7.1 does not support STL with exceptions disabled. + if (NOT MSVC OR MSVC_VERSION GREATER 1310) + cxx_library(gtest_no_exception "${cxx_no_exception}" + src/gtest-all.cc) + cxx_library(gtest_main_no_exception "${cxx_no_exception}" + src/gtest-all.cc src/gtest_main.cc) + endif() + cxx_library(gtest_main_no_rtti "${cxx_no_rtti}" + src/gtest-all.cc src/gtest_main.cc) + + cxx_test_with_flags(gtest-death-test_ex_nocatch_test + "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0" + gtest test/googletest-death-test_ex_test.cc) + cxx_test_with_flags(gtest-death-test_ex_catch_test + "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1" + gtest test/googletest-death-test_ex_test.cc) + + cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}" + gtest_main_no_rtti test/gtest_unittest.cc) + + cxx_shared_library(gtest_dll "${cxx_default}" + src/gtest-all.cc src/gtest_main.cc) + + cxx_executable_with_flags(gtest_dll_test_ "${cxx_default}" + gtest_dll test/gtest_all_test.cc) + set_target_properties(gtest_dll_test_ + PROPERTIES + COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") + + ############################################################ + # Python tests. + + cxx_executable(googletest-break-on-failure-unittest_ test gtest) + py_test(googletest-break-on-failure-unittest) + + py_test(gtest_skip_environment_check_output_test) + + # Visual Studio .NET 2003 does not support STL with exceptions disabled. + if (NOT MSVC OR MSVC_VERSION GREATER 1310) # 1310 is Visual Studio .NET 2003 + cxx_executable_with_flags( + googletest-catch-exceptions-no-ex-test_ + "${cxx_no_exception}" + gtest_main_no_exception + test/googletest-catch-exceptions-test_.cc) + endif() + + cxx_executable_with_flags( + googletest-catch-exceptions-ex-test_ + "${cxx_exception}" + gtest_main + test/googletest-catch-exceptions-test_.cc) + py_test(googletest-catch-exceptions-test) + + cxx_executable(googletest-color-test_ test gtest) + py_test(googletest-color-test) + + cxx_executable(googletest-env-var-test_ test gtest) + py_test(googletest-env-var-test) + + cxx_executable(googletest-filter-unittest_ test gtest) + py_test(googletest-filter-unittest) + + cxx_executable(gtest_help_test_ test gtest_main) + py_test(gtest_help_test) + + cxx_executable(googletest-list-tests-unittest_ test gtest) + py_test(googletest-list-tests-unittest) + + cxx_executable(googletest-output-test_ test gtest) + py_test(googletest-output-test --no_stacktrace_support) + + cxx_executable(googletest-shuffle-test_ test gtest) + py_test(googletest-shuffle-test) + + # MSVC 7.1 does not support STL with exceptions disabled. + if (NOT MSVC OR MSVC_VERSION GREATER 1310) + cxx_executable(googletest-throw-on-failure-test_ test gtest_no_exception) + set_target_properties(googletest-throw-on-failure-test_ + PROPERTIES + COMPILE_FLAGS "${cxx_no_exception}") + py_test(googletest-throw-on-failure-test) + endif() + + cxx_executable(googletest-uninitialized-test_ test gtest) + py_test(googletest-uninitialized-test) + + cxx_executable(gtest_xml_outfile1_test_ test gtest_main) + cxx_executable(gtest_xml_outfile2_test_ test gtest_main) + py_test(gtest_xml_outfiles_test) + py_test(googletest-json-outfiles-test) + + cxx_executable(gtest_xml_output_unittest_ test gtest) + py_test(gtest_xml_output_unittest --no_stacktrace_support) + py_test(googletest-json-output-unittest --no_stacktrace_support) +endif() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/CONTRIBUTORS b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/CONTRIBUTORS new file mode 100644 index 0000000000000000000000000000000000000000..feae2fc04410dc308e464aa256fe1f2d31edc988 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/CONTRIBUTORS @@ -0,0 +1,37 @@ +# This file contains a list of people who've made non-trivial +# contribution to the Google C++ Testing Framework project. People +# who commit code to the project are encouraged to add their names +# here. Please keep the list sorted by first names. + +Ajay Joshi +Balázs Dán +Bharat Mediratta +Chandler Carruth +Chris Prince +Chris Taylor +Dan Egnor +Eric Roman +Hady Zalek +Jeffrey Yasskin +Jói Sigurðsson +Keir Mierle +Keith Ray +Kenton Varda +Manuel Klimek +Markus Heule +Mika Raento +Miklós Fazekas +Pasi Valminen +Patrick Hanna +Patrick Riley +Peter Kaminski +Preston Jackson +Rainer Klaffenboeck +Russ Cox +Russ Rufer +Sean Mcafee +Sigurður Ásgeirsson +Tracy Bialik +Vadim Berman +Vlad Losev +Zhanyong Wan diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/LICENSE b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..1941a11f8ce94389160b458927a29ba217542818 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/LICENSE @@ -0,0 +1,28 @@ +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/README.md b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/README.md new file mode 100644 index 0000000000000000000000000000000000000000..766ddc1e074dca76dcb6db03785fe9bf2924641e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/README.md @@ -0,0 +1,244 @@ +### Generic Build Instructions + +#### Setup + +To build Google Test and your tests that use it, you need to tell your build +system where to find its headers and source files. The exact way to do it +depends on which build system you use, and is usually straightforward. + +### Build with CMake + +Google Test comes with a CMake build script ( +[CMakeLists.txt](https://github.com/google/googletest/blob/master/CMakeLists.txt)) +that can be used on a wide range of platforms ("C" stands for cross-platform.). +If you don't have CMake installed already, you can download it for free from +. + +CMake works by generating native makefiles or build projects that can be used in +the compiler environment of your choice. You can either build Google Test as a +standalone project or it can be incorporated into an existing CMake build for +another project. + +#### Standalone CMake Project + +When building Google Test as a standalone project, the typical workflow starts +with: + + mkdir mybuild # Create a directory to hold the build output. + cd mybuild + cmake ${GTEST_DIR} # Generate native build scripts. + +If you want to build Google Test's samples, you should replace the last command +with + + cmake -Dgtest_build_samples=ON ${GTEST_DIR} + +If you are on a \*nix system, you should now see a Makefile in the current +directory. Just type 'make' to build gtest. + +If you use Windows and have Visual Studio installed, a `gtest.sln` file and +several `.vcproj` files will be created. You can then build them using Visual +Studio. + +On Mac OS X with Xcode installed, a `.xcodeproj` file will be generated. + +#### Incorporating Into An Existing CMake Project + +If you want to use gtest in a project which already uses CMake, then a more +robust and flexible approach is to build gtest as part of that project directly. +This is done by making the GoogleTest source code available to the main build +and adding it using CMake's `add_subdirectory()` command. This has the +significant advantage that the same compiler and linker settings are used +between gtest and the rest of your project, so issues associated with using +incompatible libraries (eg debug/release), etc. are avoided. This is +particularly useful on Windows. Making GoogleTest's source code available to the +main build can be done a few different ways: + +* Download the GoogleTest source code manually and place it at a known + location. This is the least flexible approach and can make it more difficult + to use with continuous integration systems, etc. +* Embed the GoogleTest source code as a direct copy in the main project's + source tree. This is often the simplest approach, but is also the hardest to + keep up to date. Some organizations may not permit this method. +* Add GoogleTest as a git submodule or equivalent. This may not always be + possible or appropriate. Git submodules, for example, have their own set of + advantages and drawbacks. +* Use CMake to download GoogleTest as part of the build's configure step. This + is just a little more complex, but doesn't have the limitations of the other + methods. + +The last of the above methods is implemented with a small piece of CMake code in +a separate file (e.g. `CMakeLists.txt.in`) which is copied to the build area and +then invoked as a sub-build _during the CMake stage_. That directory is then +pulled into the main build with `add_subdirectory()`. For example: + +New file `CMakeLists.txt.in`: + +```cmake +cmake_minimum_required(VERSION 2.8.2) + +project(googletest-download NONE) + +include(ExternalProject) +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) +``` + +Existing build's `CMakeLists.txt`: + +```cmake +# Download and unpack googletest at configure time +configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) +execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) +if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") +endif() +execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) +if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") +endif() + +# Prevent overriding the parent project's compiler/linker +# settings on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# Add googletest directly to our build. This defines +# the gtest and gtest_main targets. +add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src + ${CMAKE_CURRENT_BINARY_DIR}/googletest-build + EXCLUDE_FROM_ALL) + +# The gtest/gtest_main targets carry header search path +# dependencies automatically when using CMake 2.8.11 or +# later. Otherwise we have to add them here ourselves. +if (CMAKE_VERSION VERSION_LESS 2.8.11) + include_directories("${gtest_SOURCE_DIR}/include") +endif() + +# Now simply link against gtest or gtest_main as needed. Eg +add_executable(example example.cpp) +target_link_libraries(example gtest_main) +add_test(NAME example_test COMMAND example) +``` + +Note that this approach requires CMake 2.8.2 or later due to its use of the +`ExternalProject_Add()` command. The above technique is discussed in more detail +in [this separate article](http://crascit.com/2015/07/25/cmake-gtest/) which +also contains a link to a fully generalized implementation of the technique. + +##### Visual Studio Dynamic vs Static Runtimes + +By default, new Visual Studio projects link the C runtimes dynamically but +Google Test links them statically. This will generate an error that looks +something like the following: gtest.lib(gtest-all.obj) : error LNK2038: mismatch +detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value +'MDd_DynamicDebug' in main.obj + +Google Test already has a CMake option for this: `gtest_force_shared_crt` + +Enabling this option will make gtest link the runtimes dynamically too, and +match the project in which it is included. + +#### C++ Standard Version + +An environment that supports C++11 is required in order to successfully build +Google Test. One way to ensure this is to specify the standard in the top-level +project, for example by using the `set(CMAKE_CXX_STANDARD 11)` command. If this +is not feasible, for example in a C project using Google Test for validation, +then it can be specified by adding it to the options for cmake via the +`DCMAKE_CXX_FLAGS` option. + +### Tweaking Google Test + +Google Test can be used in diverse environments. The default configuration may +not work (or may not work well) out of the box in some environments. However, +you can easily tweak Google Test by defining control macros on the compiler +command line. Generally, these macros are named like `GTEST_XYZ` and you define +them to either 1 or 0 to enable or disable a certain feature. + +We list the most frequently used macros below. For a complete list, see file +[include/gtest/internal/gtest-port.h](https://github.com/google/googletest/blob/master/googletest/include/gtest/internal/gtest-port.h). + +### Multi-threaded Tests + +Google Test is thread-safe where the pthread library is available. After +`#include "gtest/gtest.h"`, you can check the +`GTEST_IS_THREADSAFE` macro to see whether this is the case (yes if the macro is +`#defined` to 1, no if it's undefined.). + +If Google Test doesn't correctly detect whether pthread is available in your +environment, you can force it with + + -DGTEST_HAS_PTHREAD=1 + +or + + -DGTEST_HAS_PTHREAD=0 + +When Google Test uses pthread, you may need to add flags to your compiler and/or +linker to select the pthread library, or you'll get link errors. If you use the +CMake script or the deprecated Autotools script, this is taken care of for you. +If you use your own build script, you'll need to read your compiler and linker's +manual to figure out what flags to add. + +### As a Shared Library (DLL) + +Google Test is compact, so most users can build and link it as a static library +for the simplicity. You can choose to use Google Test as a shared library (known +as a DLL on Windows) if you prefer. + +To compile *gtest* as a shared library, add + + -DGTEST_CREATE_SHARED_LIBRARY=1 + +to the compiler flags. You'll also need to tell the linker to produce a shared +library instead - consult your linker's manual for how to do it. + +To compile your *tests* that use the gtest shared library, add + + -DGTEST_LINKED_AS_SHARED_LIBRARY=1 + +to the compiler flags. + +Note: while the above steps aren't technically necessary today when using some +compilers (e.g. GCC), they may become necessary in the future, if we decide to +improve the speed of loading the library (see + for details). Therefore you are recommended +to always add the above flags when using Google Test as a shared library. +Otherwise a future release of Google Test may break your build script. + +### Avoiding Macro Name Clashes + +In C++, macros don't obey namespaces. Therefore two libraries that both define a +macro of the same name will clash if you `#include` both definitions. In case a +Google Test macro clashes with another library, you can force Google Test to +rename its macro to avoid the conflict. + +Specifically, if both Google Test and some other code define macro FOO, you can +add + + -DGTEST_DONT_DEFINE_FOO=1 + +to the compiler flags to tell Google Test to change the macro's name from `FOO` +to `GTEST_FOO`. Currently `FOO` can be `FAIL`, `SUCCEED`, or `TEST`. For +example, with `-DGTEST_DONT_DEFINE_TEST=1`, you'll need to write + + GTEST_TEST(SomeTest, DoesThis) { ... } + +instead of + + TEST(SomeTest, DoesThis) { ... } + +in order to define a test. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/Config.cmake.in b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/Config.cmake.in new file mode 100644 index 0000000000000000000000000000000000000000..12be4498b1a079681a129e31b17c57e18126a63a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/Config.cmake.in @@ -0,0 +1,9 @@ +@PACKAGE_INIT@ +include(CMakeFindDependencyMacro) +if (@GTEST_HAS_PTHREAD@) + set(THREADS_PREFER_PTHREAD_FLAG @THREADS_PREFER_PTHREAD_FLAG@) + find_dependency(Threads) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake") +check_required_components("@project_name@") diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/gtest.pc.in b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/gtest.pc.in new file mode 100644 index 0000000000000000000000000000000000000000..9aae29e267f01ef79f1aee7f6d1d3acbb3b1ec35 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/gtest.pc.in @@ -0,0 +1,10 @@ +prefix=${pcfiledir}/../.. +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: gtest +Description: GoogleTest (without main() function) +Version: @PROJECT_VERSION@ +URL: https://github.com/google/googletest +Libs: -L${libdir} -lgtest @CMAKE_THREAD_LIBS_INIT@ +Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ @CMAKE_THREAD_LIBS_INIT@ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/gtest_main.pc.in b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/gtest_main.pc.in new file mode 100644 index 0000000000000000000000000000000000000000..915f2973af799dc035f3d966d3d601c6c3109a50 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/gtest_main.pc.in @@ -0,0 +1,11 @@ +prefix=${pcfiledir}/../.. +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: gtest_main +Description: GoogleTest (with main() function) +Version: @PROJECT_VERSION@ +URL: https://github.com/google/googletest +Requires: gtest +Libs: -L${libdir} -lgtest_main @CMAKE_THREAD_LIBS_INIT@ +Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ @CMAKE_THREAD_LIBS_INIT@ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/internal_utils.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/internal_utils.cmake new file mode 100644 index 0000000000000000000000000000000000000000..2f70f0b084b99e3a231e3d01593c0dee9c7228b6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/internal_utils.cmake @@ -0,0 +1,358 @@ +# Defines functions and macros useful for building Google Test and +# Google Mock. +# +# Note: +# +# - This file will be run twice when building Google Mock (once via +# Google Test's CMakeLists.txt, and once via Google Mock's). +# Therefore it shouldn't have any side effects other than defining +# the functions and macros. +# +# - The functions/macros defined in this file may depend on Google +# Test and Google Mock's option() definitions, and thus must be +# called *after* the options have been defined. + +if (POLICY CMP0054) + cmake_policy(SET CMP0054 NEW) +endif (POLICY CMP0054) + +# Tweaks CMake's default compiler/linker settings to suit Google Test's needs. +# +# This must be a macro(), as inside a function string() can only +# update variables in the function scope. +macro(fix_default_compiler_settings_) + if (MSVC) + # For MSVC, CMake sets certain flags to defaults we want to override. + # This replacement code is taken from sample in the CMake Wiki at + # https://gitlab.kitware.com/cmake/community/wikis/FAQ#dynamic-replace. + foreach (flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt) + # When Google Test is built as a shared library, it should also use + # shared runtime libraries. Otherwise, it may end up with multiple + # copies of runtime library data in different modules, resulting in + # hard-to-find crashes. When it is built as a static library, it is + # preferable to use CRT as static libraries, as we don't have to rely + # on CRT DLLs being available. CMake always defaults to using shared + # CRT libraries, so we override that default here. + string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}") + endif() + + # We prefer more strict warning checking for building Google Test. + # Replaces /W3 with /W4 in defaults. + string(REPLACE "/W3" "/W4" ${flag_var} "${${flag_var}}") + + # Prevent D9025 warning for targets that have exception handling + # turned off (/EHs-c- flag). Where required, exceptions are explicitly + # re-enabled using the cxx_exception_flags variable. + string(REPLACE "/EHsc" "" ${flag_var} "${${flag_var}}") + endforeach() + endif() +endmacro() + +# Defines the compiler/linker flags used to build Google Test and +# Google Mock. You can tweak these definitions to suit your need. A +# variable's value is empty before it's explicitly assigned to. +macro(config_compiler_and_linker) + # Note: pthreads on MinGW is not supported, even if available + # instead, we use windows threading primitives + unset(GTEST_HAS_PTHREAD) + if (NOT gtest_disable_pthreads AND NOT MINGW) + # Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT. + find_package(Threads) + if (CMAKE_USE_PTHREADS_INIT) + set(GTEST_HAS_PTHREAD ON) + endif() + endif() + + fix_default_compiler_settings_() + if (MSVC) + # Newlines inside flags variables break CMake's NMake generator. + # TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds. + set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J -Zi") + set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32") + set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN") + set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1") + set(cxx_no_exception_flags "-EHs-c- -D_HAS_EXCEPTIONS=0") + set(cxx_no_rtti_flags "-GR-") + # Suppress "unreachable code" warning + # http://stackoverflow.com/questions/3232669 explains the issue. + set(cxx_base_flags "${cxx_base_flags} -wd4702") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(cxx_base_flags "-Wall -Wshadow -Werror -Wconversion") + set(cxx_exception_flags "-fexceptions") + set(cxx_no_exception_flags "-fno-exceptions") + set(cxx_strict_flags "-W -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wunused-parameter -Wcast-align -Wchar-subscripts -Winline -Wredundant-decls") + set(cxx_no_rtti_flags "-fno-rtti") + elseif (CMAKE_COMPILER_IS_GNUCXX) + set(cxx_base_flags "-Wall -Wshadow -Werror") + if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.0) + set(cxx_base_flags "${cxx_base_flags} -Wno-error=dangling-else") + endif() + set(cxx_exception_flags "-fexceptions") + set(cxx_no_exception_flags "-fno-exceptions") + # Until version 4.3.2, GCC doesn't define a macro to indicate + # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI + # explicitly. + set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0") + set(cxx_strict_flags + "-Wextra -Wno-unused-parameter -Wno-missing-field-initializers") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") + set(cxx_exception_flags "-features=except") + # Sun Pro doesn't provide macros to indicate whether exceptions and + # RTTI are enabled, so we define GTEST_HAS_* explicitly. + set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0") + set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR + CMAKE_CXX_COMPILER_ID STREQUAL "XL") + # CMake 2.8 changes Visual Age's compiler ID to "XL". + set(cxx_exception_flags "-qeh") + set(cxx_no_exception_flags "-qnoeh") + # Until version 9.0, Visual Age doesn't define a macro to indicate + # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI + # explicitly. + set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "HP") + set(cxx_base_flags "-AA -mt") + set(cxx_exception_flags "-DGTEST_HAS_EXCEPTIONS=1") + set(cxx_no_exception_flags "+noeh -DGTEST_HAS_EXCEPTIONS=0") + # RTTI can not be disabled in HP aCC compiler. + set(cxx_no_rtti_flags "") + endif() + + # The pthreads library is available and allowed? + if (DEFINED GTEST_HAS_PTHREAD) + set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=1") + else() + set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=0") + endif() + set(cxx_base_flags "${cxx_base_flags} ${GTEST_HAS_PTHREAD_MACRO}") + + # For building gtest's own tests and samples. + set(cxx_exception "${cxx_base_flags} ${cxx_exception_flags}") + set(cxx_no_exception + "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}") + set(cxx_default "${cxx_exception}") + set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}") + + # For building the gtest libraries. + set(cxx_strict "${cxx_default} ${cxx_strict_flags}") +endmacro() + +# Defines the gtest & gtest_main libraries. User tests should link +# with one of them. +function(cxx_library_with_type name type cxx_flags) + # type can be either STATIC or SHARED to denote a static or shared library. + # ARGN refers to additional arguments after 'cxx_flags'. + add_library(${name} ${type} ${ARGN}) + set_target_properties(${name} + PROPERTIES + COMPILE_FLAGS "${cxx_flags}") + # Generate debug library name with a postfix. + set_target_properties(${name} + PROPERTIES + DEBUG_POSTFIX "d") + # Set the output directory for build artifacts + set_target_properties(${name} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + # make PDBs match library name + get_target_property(pdb_debug_postfix ${name} DEBUG_POSTFIX) + set_target_properties(${name} + PROPERTIES + PDB_NAME "${name}" + PDB_NAME_DEBUG "${name}${pdb_debug_postfix}" + COMPILE_PDB_NAME "${name}" + COMPILE_PDB_NAME_DEBUG "${name}${pdb_debug_postfix}") + + if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED") + set_target_properties(${name} + PROPERTIES + COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1") + if (NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") + target_compile_definitions(${name} INTERFACE + $) + endif() + endif() + if (DEFINED GTEST_HAS_PTHREAD) + if ("${CMAKE_VERSION}" VERSION_LESS "3.1.0") + set(threads_spec ${CMAKE_THREAD_LIBS_INIT}) + else() + set(threads_spec Threads::Threads) + endif() + target_link_libraries(${name} PUBLIC ${threads_spec}) + endif() +endfunction() + +######################################################################## +# +# Helper functions for creating build targets. + +function(cxx_shared_library name cxx_flags) + cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN}) +endfunction() + +function(cxx_library name cxx_flags) + cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN}) +endfunction() + +# cxx_executable_with_flags(name cxx_flags libs srcs...) +# +# creates a named C++ executable that depends on the given libraries and +# is built from the given source files with the given compiler flags. +function(cxx_executable_with_flags name cxx_flags libs) + add_executable(${name} ${ARGN}) + if (MSVC) + # BigObj required for tests. + set(cxx_flags "${cxx_flags} -bigobj") + endif() + if (cxx_flags) + set_target_properties(${name} + PROPERTIES + COMPILE_FLAGS "${cxx_flags}") + endif() + if (BUILD_SHARED_LIBS) + set_target_properties(${name} + PROPERTIES + COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") + endif() + # To support mixing linking in static and dynamic libraries, link each + # library in with an extra call to target_link_libraries. + foreach (lib "${libs}") + target_link_libraries(${name} ${lib}) + endforeach() +endfunction() + +# cxx_executable(name dir lib srcs...) +# +# creates a named target that depends on the given libs and is built +# from the given source files. dir/name.cc is implicitly included in +# the source file list. +function(cxx_executable name dir libs) + cxx_executable_with_flags( + ${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN}) +endfunction() + +# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE. +find_package(PythonInterp) + +# cxx_test_with_flags(name cxx_flags libs srcs...) +# +# creates a named C++ test that depends on the given libs and is built +# from the given source files with the given compiler flags. +function(cxx_test_with_flags name cxx_flags libs) + cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN}) + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND "powershell" "-Command" "${CMAKE_CURRENT_BINARY_DIR}/$/RunTest.ps1" "$") + else() + add_test(NAME ${name} + COMMAND "$") + endif() +endfunction() + +# cxx_test(name libs srcs...) +# +# creates a named test target that depends on the given libs and is +# built from the given source files. Unlike cxx_test_with_flags, +# test/name.cc is already implicitly included in the source file list. +function(cxx_test name libs) + cxx_test_with_flags("${name}" "${cxx_default}" "${libs}" + "test/${name}.cc" ${ARGN}) +endfunction() + +# py_test(name) +# +# creates a Python test with the given name whose main module is in +# test/name.py. It does nothing if Python is not installed. +function(py_test name) + if (PYTHONINTERP_FOUND) + if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 3.1) + if (CMAKE_CONFIGURATION_TYPES) + # Multi-configuration build generators as for Visual Studio save + # output in a subdirectory of CMAKE_CURRENT_BINARY_DIR (Debug, + # Release etc.), so we have to provide it here. + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND powershell -Command ${CMAKE_CURRENT_BINARY_DIR}/$/RunTest.ps1 + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/$ ${ARGN}) + else() + add_test(NAME ${name} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/$ ${ARGN}) + endif() + else (CMAKE_CONFIGURATION_TYPES) + # Single-configuration build generators like Makefile generators + # don't have subdirs below CMAKE_CURRENT_BINARY_DIR. + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND powershell -Command ${CMAKE_CURRENT_BINARY_DIR}/RunTest.ps1 + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR} ${ARGN}) + else() + add_test(NAME ${name} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR} ${ARGN}) + endif() + endif (CMAKE_CONFIGURATION_TYPES) + else() + # ${CMAKE_CURRENT_BINARY_DIR} is known at configuration time, so we can + # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known + # only at ctest runtime (by calling ctest -c ), so + # we have to escape $ to delay variable substitution here. + if (WIN32 OR MINGW) + add_test(NAME ${name} + COMMAND powershell -Command ${CMAKE_CURRENT_BINARY_DIR}/RunTest.ps1 + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE} ${ARGN}) + else() + add_test(NAME ${name} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py + --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE} ${ARGN}) + endif() + endif() + endif(PYTHONINTERP_FOUND) +endfunction() + +# install_project(targets...) +# +# Installs the specified targets and configures the associated pkgconfig files. +function(install_project) + if(INSTALL_GTEST) + install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + # Install the project targets. + install(TARGETS ${ARGN} + EXPORT ${targets_export_name} + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") + if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + # Install PDBs + foreach(t ${ARGN}) + get_target_property(t_pdb_name ${t} COMPILE_PDB_NAME) + get_target_property(t_pdb_name_debug ${t} COMPILE_PDB_NAME_DEBUG) + get_target_property(t_pdb_output_directory ${t} PDB_OUTPUT_DIRECTORY) + install(FILES + "${t_pdb_output_directory}/\${CMAKE_INSTALL_CONFIG_NAME}/$<$:${t_pdb_name_debug}>$<$>:${t_pdb_name}>.pdb" + DESTINATION ${CMAKE_INSTALL_LIBDIR} + OPTIONAL) + endforeach() + endif() + # Configure and install pkgconfig files. + foreach(t ${ARGN}) + set(configured_pc "${generated_dir}/${t}.pc") + configure_file("${PROJECT_SOURCE_DIR}/cmake/${t}.pc.in" + "${configured_pc}" @ONLY) + install(FILES "${configured_pc}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + endforeach() + endif() +endfunction() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/libgtest.la.in b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/libgtest.la.in new file mode 100644 index 0000000000000000000000000000000000000000..840c83885f989a02a0ab3073a74e65bc04ddf3e1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/cmake/libgtest.la.in @@ -0,0 +1,21 @@ +# libgtest.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.6 + +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Names of this library. +library_names='libgtest.so' + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='@CMAKE_INSTALL_FULL_LIBDIR@' diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/advanced.md b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/advanced.md new file mode 100644 index 0000000000000000000000000000000000000000..3e5f779d0ac8381afcb6837d952eba955f0f8d0c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/advanced.md @@ -0,0 +1,2567 @@ +# Advanced googletest Topics + + + +## Introduction + +Now that you have read the [googletest Primer](primer.md) and learned how to +write tests using googletest, it's time to learn some new tricks. This document +will show you more assertions as well as how to construct complex failure +messages, propagate fatal failures, reuse and speed up your test fixtures, and +use various flags with your tests. + +## More Assertions + +This section covers some less frequently used, but still significant, +assertions. + +### Explicit Success and Failure + +These three assertions do not actually test a value or expression. Instead, they +generate a success or failure directly. Like the macros that actually perform a +test, you may stream a custom failure message into them. + +```c++ +SUCCEED(); +``` + +Generates a success. This does **NOT** make the overall test succeed. A test is +considered successful only if none of its assertions fail during its execution. + +NOTE: `SUCCEED()` is purely documentary and currently doesn't generate any +user-visible output. However, we may add `SUCCEED()` messages to googletest's +output in the future. + +```c++ +FAIL(); +ADD_FAILURE(); +ADD_FAILURE_AT("file_path", line_number); +``` + +`FAIL()` generates a fatal failure, while `ADD_FAILURE()` and `ADD_FAILURE_AT()` +generate a nonfatal failure. These are useful when control flow, rather than a +Boolean expression, determines the test's success or failure. For example, you +might want to write something like: + +```c++ +switch(expression) { + case 1: + ... some checks ... + case 2: + ... some other checks ... + default: + FAIL() << "We shouldn't get here."; +} +``` + +NOTE: you can only use `FAIL()` in functions that return `void`. See the +[Assertion Placement section](#assertion-placement) for more information. + +### Exception Assertions + +These are for verifying that a piece of code throws (or does not throw) an +exception of the given type: + +Fatal assertion | Nonfatal assertion | Verifies +------------------------------------------ | ------------------------------------------ | -------- +`ASSERT_THROW(statement, exception_type);` | `EXPECT_THROW(statement, exception_type);` | `statement` throws an exception of the given type +`ASSERT_ANY_THROW(statement);` | `EXPECT_ANY_THROW(statement);` | `statement` throws an exception of any type +`ASSERT_NO_THROW(statement);` | `EXPECT_NO_THROW(statement);` | `statement` doesn't throw any exception + +Examples: + +```c++ +ASSERT_THROW(Foo(5), bar_exception); + +EXPECT_NO_THROW({ + int n = 5; + Bar(&n); +}); +``` + +**Availability**: requires exceptions to be enabled in the build environment + +### Predicate Assertions for Better Error Messages + +Even though googletest has a rich set of assertions, they can never be complete, +as it's impossible (nor a good idea) to anticipate all scenarios a user might +run into. Therefore, sometimes a user has to use `EXPECT_TRUE()` to check a +complex expression, for lack of a better macro. This has the problem of not +showing you the values of the parts of the expression, making it hard to +understand what went wrong. As a workaround, some users choose to construct the +failure message by themselves, streaming it into `EXPECT_TRUE()`. However, this +is awkward especially when the expression has side-effects or is expensive to +evaluate. + +googletest gives you three different options to solve this problem: + +#### Using an Existing Boolean Function + +If you already have a function or functor that returns `bool` (or a type that +can be implicitly converted to `bool`), you can use it in a *predicate +assertion* to get the function arguments printed for free: + + + +| Fatal assertion | Nonfatal assertion | Verifies | +| --------------------------------- | --------------------------------- | --------------------------- | +| `ASSERT_PRED1(pred1, val1)` | `EXPECT_PRED1(pred1, val1)` | `pred1(val1)` is true | +| `ASSERT_PRED2(pred2, val1, val2)` | `EXPECT_PRED2(pred2, val1, val2)` | `pred1(val1, val2)` is true | +| `...` | `...` | `...` | + + +In the above, `predn` is an `n`-ary predicate function or functor, where `val1`, +`val2`, ..., and `valn` are its arguments. The assertion succeeds if the +predicate returns `true` when applied to the given arguments, and fails +otherwise. When the assertion fails, it prints the value of each argument. In +either case, the arguments are evaluated exactly once. + +Here's an example. Given + +```c++ +// Returns true if m and n have no common divisors except 1. +bool MutuallyPrime(int m, int n) { ... } + +const int a = 3; +const int b = 4; +const int c = 10; +``` + +the assertion + +```c++ + EXPECT_PRED2(MutuallyPrime, a, b); +``` + +will succeed, while the assertion + +```c++ + EXPECT_PRED2(MutuallyPrime, b, c); +``` + +will fail with the message + +```none +MutuallyPrime(b, c) is false, where +b is 4 +c is 10 +``` + +> NOTE: +> +> 1. If you see a compiler error "no matching function to call" when using +> `ASSERT_PRED*` or `EXPECT_PRED*`, please see +> [this](faq.md#the-compiler-complains-no-matching-function-to-call-when-i-use-assert-pred-how-do-i-fix-it) +> for how to resolve it. + +#### Using a Function That Returns an AssertionResult + +While `EXPECT_PRED*()` and friends are handy for a quick job, the syntax is not +satisfactory: you have to use different macros for different arities, and it +feels more like Lisp than C++. The `::testing::AssertionResult` class solves +this problem. + +An `AssertionResult` object represents the result of an assertion (whether it's +a success or a failure, and an associated message). You can create an +`AssertionResult` using one of these factory functions: + +```c++ +namespace testing { + +// Returns an AssertionResult object to indicate that an assertion has +// succeeded. +AssertionResult AssertionSuccess(); + +// Returns an AssertionResult object to indicate that an assertion has +// failed. +AssertionResult AssertionFailure(); + +} +``` + +You can then use the `<<` operator to stream messages to the `AssertionResult` +object. + +To provide more readable messages in Boolean assertions (e.g. `EXPECT_TRUE()`), +write a predicate function that returns `AssertionResult` instead of `bool`. For +example, if you define `IsEven()` as: + +```c++ +::testing::AssertionResult IsEven(int n) { + if ((n % 2) == 0) + return ::testing::AssertionSuccess(); + else + return ::testing::AssertionFailure() << n << " is odd"; +} +``` + +instead of: + +```c++ +bool IsEven(int n) { + return (n % 2) == 0; +} +``` + +the failed assertion `EXPECT_TRUE(IsEven(Fib(4)))` will print: + +```none +Value of: IsEven(Fib(4)) + Actual: false (3 is odd) +Expected: true +``` + +instead of a more opaque + +```none +Value of: IsEven(Fib(4)) + Actual: false +Expected: true +``` + +If you want informative messages in `EXPECT_FALSE` and `ASSERT_FALSE` as well +(one third of Boolean assertions in the Google code base are negative ones), and +are fine with making the predicate slower in the success case, you can supply a +success message: + +```c++ +::testing::AssertionResult IsEven(int n) { + if ((n % 2) == 0) + return ::testing::AssertionSuccess() << n << " is even"; + else + return ::testing::AssertionFailure() << n << " is odd"; +} +``` + +Then the statement `EXPECT_FALSE(IsEven(Fib(6)))` will print + +```none + Value of: IsEven(Fib(6)) + Actual: true (8 is even) + Expected: false +``` + +#### Using a Predicate-Formatter + +If you find the default message generated by `(ASSERT|EXPECT)_PRED*` and +`(ASSERT|EXPECT)_(TRUE|FALSE)` unsatisfactory, or some arguments to your +predicate do not support streaming to `ostream`, you can instead use the +following *predicate-formatter assertions* to *fully* customize how the message +is formatted: + +Fatal assertion | Nonfatal assertion | Verifies +------------------------------------------------ | ------------------------------------------------ | -------- +`ASSERT_PRED_FORMAT1(pred_format1, val1);` | `EXPECT_PRED_FORMAT1(pred_format1, val1);` | `pred_format1(val1)` is successful +`ASSERT_PRED_FORMAT2(pred_format2, val1, val2);` | `EXPECT_PRED_FORMAT2(pred_format2, val1, val2);` | `pred_format2(val1, val2)` is successful +`...` | `...` | ... + +The difference between this and the previous group of macros is that instead of +a predicate, `(ASSERT|EXPECT)_PRED_FORMAT*` take a *predicate-formatter* +(`pred_formatn`), which is a function or functor with the signature: + +```c++ +::testing::AssertionResult PredicateFormattern(const char* expr1, + const char* expr2, + ... + const char* exprn, + T1 val1, + T2 val2, + ... + Tn valn); +``` + +where `val1`, `val2`, ..., and `valn` are the values of the predicate arguments, +and `expr1`, `expr2`, ..., and `exprn` are the corresponding expressions as they +appear in the source code. The types `T1`, `T2`, ..., and `Tn` can be either +value types or reference types. For example, if an argument has type `Foo`, you +can declare it as either `Foo` or `const Foo&`, whichever is appropriate. + +As an example, let's improve the failure message in `MutuallyPrime()`, which was +used with `EXPECT_PRED2()`: + +```c++ +// Returns the smallest prime common divisor of m and n, +// or 1 when m and n are mutually prime. +int SmallestPrimeCommonDivisor(int m, int n) { ... } + +// A predicate-formatter for asserting that two integers are mutually prime. +::testing::AssertionResult AssertMutuallyPrime(const char* m_expr, + const char* n_expr, + int m, + int n) { + if (MutuallyPrime(m, n)) return ::testing::AssertionSuccess(); + + return ::testing::AssertionFailure() << m_expr << " and " << n_expr + << " (" << m << " and " << n << ") are not mutually prime, " + << "as they have a common divisor " << SmallestPrimeCommonDivisor(m, n); +} +``` + +With this predicate-formatter, we can use + +```c++ + EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c); +``` + +to generate the message + +```none +b and c (4 and 10) are not mutually prime, as they have a common divisor 2. +``` + +As you may have realized, many of the built-in assertions we introduced earlier +are special cases of `(EXPECT|ASSERT)_PRED_FORMAT*`. In fact, most of them are +indeed defined using `(EXPECT|ASSERT)_PRED_FORMAT*`. + +### Floating-Point Comparison + +Comparing floating-point numbers is tricky. Due to round-off errors, it is very +unlikely that two floating-points will match exactly. Therefore, `ASSERT_EQ` 's +naive comparison usually doesn't work. And since floating-points can have a wide +value range, no single fixed error bound works. It's better to compare by a +fixed relative error bound, except for values close to 0 due to the loss of +precision there. + +In general, for floating-point comparison to make sense, the user needs to +carefully choose the error bound. If they don't want or care to, comparing in +terms of Units in the Last Place (ULPs) is a good default, and googletest +provides assertions to do this. Full details about ULPs are quite long; if you +want to learn more, see +[here](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). + +#### Floating-Point Macros + + + +| Fatal assertion | Nonfatal assertion | Verifies | +| ------------------------------- | ------------------------------- | ---------------------------------------- | +| `ASSERT_FLOAT_EQ(val1, val2);` | `EXPECT_FLOAT_EQ(val1, val2);` | the two `float` values are almost equal | +| `ASSERT_DOUBLE_EQ(val1, val2);` | `EXPECT_DOUBLE_EQ(val1, val2);` | the two `double` values are almost equal | + + + +By "almost equal" we mean the values are within 4 ULP's from each other. + +The following assertions allow you to choose the acceptable error bound: + + + +| Fatal assertion | Nonfatal assertion | Verifies | +| ------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------- | +| `ASSERT_NEAR(val1, val2, abs_error);` | `EXPECT_NEAR(val1, val2, abs_error);` | the difference between `val1` and `val2` doesn't exceed the given absolute error | + + + +#### Floating-Point Predicate-Format Functions + +Some floating-point operations are useful, but not that often used. In order to +avoid an explosion of new macros, we provide them as predicate-format functions +that can be used in predicate assertion macros (e.g. `EXPECT_PRED_FORMAT2`, +etc). + +```c++ +EXPECT_PRED_FORMAT2(::testing::FloatLE, val1, val2); +EXPECT_PRED_FORMAT2(::testing::DoubleLE, val1, val2); +``` + +Verifies that `val1` is less than, or almost equal to, `val2`. You can replace +`EXPECT_PRED_FORMAT2` in the above table with `ASSERT_PRED_FORMAT2`. + +### Asserting Using gMock Matchers + +[gMock](../../googlemock) comes with a library of matchers for validating +arguments passed to mock objects. A gMock *matcher* is basically a predicate +that knows how to describe itself. It can be used in these assertion macros: + + + +| Fatal assertion | Nonfatal assertion | Verifies | +| ------------------------------ | ------------------------------ | --------------------- | +| `ASSERT_THAT(value, matcher);` | `EXPECT_THAT(value, matcher);` | value matches matcher | + + + +For example, `StartsWith(prefix)` is a matcher that matches a string starting +with `prefix`, and you can write: + +```c++ +using ::testing::StartsWith; +... + // Verifies that Foo() returns a string starting with "Hello". + EXPECT_THAT(Foo(), StartsWith("Hello")); +``` + +Read this +[recipe](../../googlemock/docs/cook_book.md#using-matchers-in-googletest-assertions) +in the gMock Cookbook for more details. + +gMock has a rich set of matchers. You can do many things googletest cannot do +alone with them. For a list of matchers gMock provides, read +[this](../../googlemock/docs/cook_book.md##using-matchers). It's easy to write +your [own matchers](../../googlemock/docs/cook_book.md#NewMatchers) too. + +gMock is bundled with googletest, so you don't need to add any build dependency +in order to take advantage of this. Just include `"testing/base/public/gmock.h"` +and you're ready to go. + +### More String Assertions + +(Please read the [previous](#asserting-using-gmock-matchers) section first if +you haven't.) + +You can use the gMock +[string matchers](../../googlemock/docs/cheat_sheet.md#string-matchers) with +`EXPECT_THAT()` or `ASSERT_THAT()` to do more string comparison tricks +(sub-string, prefix, suffix, regular expression, and etc). For example, + +```c++ +using ::testing::HasSubstr; +using ::testing::MatchesRegex; +... + ASSERT_THAT(foo_string, HasSubstr("needle")); + EXPECT_THAT(bar_string, MatchesRegex("\\w*\\d+")); +``` + +If the string contains a well-formed HTML or XML document, you can check whether +its DOM tree matches an +[XPath expression](http://www.w3.org/TR/xpath/#contents): + +```c++ +// Currently still in //template/prototemplate/testing:xpath_matcher +#include "template/prototemplate/testing/xpath_matcher.h" +using prototemplate::testing::MatchesXPath; +EXPECT_THAT(html_string, MatchesXPath("//a[text()='click here']")); +``` + +### Windows HRESULT assertions + +These assertions test for `HRESULT` success or failure. + +Fatal assertion | Nonfatal assertion | Verifies +-------------------------------------- | -------------------------------------- | -------- +`ASSERT_HRESULT_SUCCEEDED(expression)` | `EXPECT_HRESULT_SUCCEEDED(expression)` | `expression` is a success `HRESULT` +`ASSERT_HRESULT_FAILED(expression)` | `EXPECT_HRESULT_FAILED(expression)` | `expression` is a failure `HRESULT` + +The generated output contains the human-readable error message associated with +the `HRESULT` code returned by `expression`. + +You might use them like this: + +```c++ +CComPtr shell; +ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application")); +CComVariant empty; +ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty)); +``` + +### Type Assertions + +You can call the function + +```c++ +::testing::StaticAssertTypeEq(); +``` + +to assert that types `T1` and `T2` are the same. The function does nothing if +the assertion is satisfied. If the types are different, the function call will +fail to compile, the compiler error message will say that +`type1 and type2 are not the same type` and most likely (depending on the compiler) +show you the actual values of `T1` and `T2`. This is mainly useful inside +template code. + +**Caveat**: When used inside a member function of a class template or a function +template, `StaticAssertTypeEq()` is effective only if the function is +instantiated. For example, given: + +```c++ +template class Foo { + public: + void Bar() { ::testing::StaticAssertTypeEq(); } +}; +``` + +the code: + +```c++ +void Test1() { Foo foo; } +``` + +will not generate a compiler error, as `Foo::Bar()` is never actually +instantiated. Instead, you need: + +```c++ +void Test2() { Foo foo; foo.Bar(); } +``` + +to cause a compiler error. + +### Assertion Placement + +You can use assertions in any C++ function. In particular, it doesn't have to be +a method of the test fixture class. The one constraint is that assertions that +generate a fatal failure (`FAIL*` and `ASSERT_*`) can only be used in +void-returning functions. This is a consequence of Google's not using +exceptions. By placing it in a non-void function you'll get a confusing compile +error like `"error: void value not ignored as it ought to be"` or `"cannot +initialize return object of type 'bool' with an rvalue of type 'void'"` or +`"error: no viable conversion from 'void' to 'string'"`. + +If you need to use fatal assertions in a function that returns non-void, one +option is to make the function return the value in an out parameter instead. For +example, you can rewrite `T2 Foo(T1 x)` to `void Foo(T1 x, T2* result)`. You +need to make sure that `*result` contains some sensible value even when the +function returns prematurely. As the function now returns `void`, you can use +any assertion inside of it. + +If changing the function's type is not an option, you should just use assertions +that generate non-fatal failures, such as `ADD_FAILURE*` and `EXPECT_*`. + +NOTE: Constructors and destructors are not considered void-returning functions, +according to the C++ language specification, and so you may not use fatal +assertions in them; you'll get a compilation error if you try. Instead, either +call `abort` and crash the entire test executable, or put the fatal assertion in +a `SetUp`/`TearDown` function; see +[constructor/destructor vs. `SetUp`/`TearDown`](faq.md#CtorVsSetUp) + +WARNING: A fatal assertion in a helper function (private void-returning method) +called from a constructor or destructor does not does not terminate the current +test, as your intuition might suggest: it merely returns from the constructor or +destructor early, possibly leaving your object in a partially-constructed or +partially-destructed state! You almost certainly want to `abort` or use +`SetUp`/`TearDown` instead. + +## Teaching googletest How to Print Your Values + +When a test assertion such as `EXPECT_EQ` fails, googletest prints the argument +values to help you debug. It does this using a user-extensible value printer. + +This printer knows how to print built-in C++ types, native arrays, STL +containers, and any type that supports the `<<` operator. For other types, it +prints the raw bytes in the value and hopes that you the user can figure it out. + +As mentioned earlier, the printer is *extensible*. That means you can teach it +to do a better job at printing your particular type than to dump the bytes. To +do that, define `<<` for your type: + +```c++ +#include + +namespace foo { + +class Bar { // We want googletest to be able to print instances of this. +... + // Create a free inline friend function. + friend std::ostream& operator<<(std::ostream& os, const Bar& bar) { + return os << bar.DebugString(); // whatever needed to print bar to os + } +}; + +// If you can't declare the function in the class it's important that the +// << operator is defined in the SAME namespace that defines Bar. C++'s look-up +// rules rely on that. +std::ostream& operator<<(std::ostream& os, const Bar& bar) { + return os << bar.DebugString(); // whatever needed to print bar to os +} + +} // namespace foo +``` + +Sometimes, this might not be an option: your team may consider it bad style to +have a `<<` operator for `Bar`, or `Bar` may already have a `<<` operator that +doesn't do what you want (and you cannot change it). If so, you can instead +define a `PrintTo()` function like this: + +```c++ +#include + +namespace foo { + +class Bar { + ... + friend void PrintTo(const Bar& bar, std::ostream* os) { + *os << bar.DebugString(); // whatever needed to print bar to os + } +}; + +// If you can't declare the function in the class it's important that PrintTo() +// is defined in the SAME namespace that defines Bar. C++'s look-up rules rely +// on that. +void PrintTo(const Bar& bar, std::ostream* os) { + *os << bar.DebugString(); // whatever needed to print bar to os +} + +} // namespace foo +``` + +If you have defined both `<<` and `PrintTo()`, the latter will be used when +googletest is concerned. This allows you to customize how the value appears in +googletest's output without affecting code that relies on the behavior of its +`<<` operator. + +If you want to print a value `x` using googletest's value printer yourself, just +call `::testing::PrintToString(x)`, which returns an `std::string`: + +```c++ +vector > bar_ints = GetBarIntVector(); + +EXPECT_TRUE(IsCorrectBarIntVector(bar_ints)) + << "bar_ints = " << ::testing::PrintToString(bar_ints); +``` + +## Death Tests + +In many applications, there are assertions that can cause application failure if +a condition is not met. These sanity checks, which ensure that the program is in +a known good state, are there to fail at the earliest possible time after some +program state is corrupted. If the assertion checks the wrong condition, then +the program may proceed in an erroneous state, which could lead to memory +corruption, security holes, or worse. Hence it is vitally important to test that +such assertion statements work as expected. + +Since these precondition checks cause the processes to die, we call such tests +_death tests_. More generally, any test that checks that a program terminates +(except by throwing an exception) in an expected fashion is also a death test. + +Note that if a piece of code throws an exception, we don't consider it "death" +for the purpose of death tests, as the caller of the code could catch the +exception and avoid the crash. If you want to verify exceptions thrown by your +code, see [Exception Assertions](#ExceptionAssertions). + +If you want to test `EXPECT_*()/ASSERT_*()` failures in your test code, see +Catching Failures + +### How to Write a Death Test + +googletest has the following macros to support death tests: + +Fatal assertion | Nonfatal assertion | Verifies +------------------------------------------------ | ------------------------------------------------ | -------- +`ASSERT_DEATH(statement, matcher);` | `EXPECT_DEATH(statement, matcher);` | `statement` crashes with the given error +`ASSERT_DEATH_IF_SUPPORTED(statement, matcher);` | `EXPECT_DEATH_IF_SUPPORTED(statement, matcher);` | if death tests are supported, verifies that `statement` crashes with the given error; otherwise verifies nothing +`ASSERT_EXIT(statement, predicate, matcher);` | `EXPECT_EXIT(statement, predicate, matcher);` | `statement` exits with the given error, and its exit code matches `predicate` + +where `statement` is a statement that is expected to cause the process to die, +`predicate` is a function or function object that evaluates an integer exit +status, and `matcher` is either a GMock matcher matching a `const std::string&` +or a (Perl) regular expression - either of which is matched against the stderr +output of `statement`. For legacy reasons, a bare string (i.e. with no matcher) +is interpreted as `ContainsRegex(str)`, **not** `Eq(str)`. Note that `statement` +can be *any valid statement* (including *compound statement*) and doesn't have +to be an expression. + +As usual, the `ASSERT` variants abort the current test function, while the +`EXPECT` variants do not. + +> NOTE: We use the word "crash" here to mean that the process terminates with a +> *non-zero* exit status code. There are two possibilities: either the process +> has called `exit()` or `_exit()` with a non-zero value, or it may be killed by +> a signal. +> +> This means that if `*statement*` terminates the process with a 0 exit code, it +> is *not* considered a crash by `EXPECT_DEATH`. Use `EXPECT_EXIT` instead if +> this is the case, or if you want to restrict the exit code more precisely. + +A predicate here must accept an `int` and return a `bool`. The death test +succeeds only if the predicate returns `true`. googletest defines a few +predicates that handle the most common cases: + +```c++ +::testing::ExitedWithCode(exit_code) +``` + +This expression is `true` if the program exited normally with the given exit +code. + +```c++ +::testing::KilledBySignal(signal_number) // Not available on Windows. +``` + +This expression is `true` if the program was killed by the given signal. + +The `*_DEATH` macros are convenient wrappers for `*_EXIT` that use a predicate +that verifies the process' exit code is non-zero. + +Note that a death test only cares about three things: + +1. does `statement` abort or exit the process? +2. (in the case of `ASSERT_EXIT` and `EXPECT_EXIT`) does the exit status + satisfy `predicate`? Or (in the case of `ASSERT_DEATH` and `EXPECT_DEATH`) + is the exit status non-zero? And +3. does the stderr output match `regex`? + +In particular, if `statement` generates an `ASSERT_*` or `EXPECT_*` failure, it +will **not** cause the death test to fail, as googletest assertions don't abort +the process. + +To write a death test, simply use one of the above macros inside your test +function. For example, + +```c++ +TEST(MyDeathTest, Foo) { + // This death test uses a compound statement. + ASSERT_DEATH({ + int n = 5; + Foo(&n); + }, "Error on line .* of Foo()"); +} + +TEST(MyDeathTest, NormalExit) { + EXPECT_EXIT(NormalExit(), ::testing::ExitedWithCode(0), "Success"); +} + +TEST(MyDeathTest, KillMyself) { + EXPECT_EXIT(KillMyself(), ::testing::KilledBySignal(SIGKILL), + "Sending myself unblockable signal"); +} +``` + +verifies that: + +* calling `Foo(5)` causes the process to die with the given error message, +* calling `NormalExit()` causes the process to print `"Success"` to stderr and + exit with exit code 0, and +* calling `KillMyself()` kills the process with signal `SIGKILL`. + +The test function body may contain other assertions and statements as well, if +necessary. + +### Death Test Naming + +IMPORTANT: We strongly recommend you to follow the convention of naming your +**test suite** (not test) `*DeathTest` when it contains a death test, as +demonstrated in the above example. The +[Death Tests And Threads](#death-tests-and-threads) section below explains why. + +If a test fixture class is shared by normal tests and death tests, you can use +`using` or `typedef` to introduce an alias for the fixture class and avoid +duplicating its code: + +```c++ +class FooTest : public ::testing::Test { ... }; + +using FooDeathTest = FooTest; + +TEST_F(FooTest, DoesThis) { + // normal test +} + +TEST_F(FooDeathTest, DoesThat) { + // death test +} +``` + +### Regular Expression Syntax + +On POSIX systems (e.g. Linux, Cygwin, and Mac), googletest uses the +[POSIX extended regular expression](http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04) +syntax. To learn about this syntax, you may want to read this +[Wikipedia entry](http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions). + +On Windows, googletest uses its own simple regular expression implementation. It +lacks many features. For example, we don't support union (`"x|y"`), grouping +(`"(xy)"`), brackets (`"[xy]"`), and repetition count (`"x{5,7}"`), among +others. Below is what we do support (`A` denotes a literal character, period +(`.`), or a single `\\ ` escape sequence; `x` and `y` denote regular +expressions.): + +Expression | Meaning +---------- | -------------------------------------------------------------- +`c` | matches any literal character `c` +`\\d` | matches any decimal digit +`\\D` | matches any character that's not a decimal digit +`\\f` | matches `\f` +`\\n` | matches `\n` +`\\r` | matches `\r` +`\\s` | matches any ASCII whitespace, including `\n` +`\\S` | matches any character that's not a whitespace +`\\t` | matches `\t` +`\\v` | matches `\v` +`\\w` | matches any letter, `_`, or decimal digit +`\\W` | matches any character that `\\w` doesn't match +`\\c` | matches any literal character `c`, which must be a punctuation +`.` | matches any single character except `\n` +`A?` | matches 0 or 1 occurrences of `A` +`A*` | matches 0 or many occurrences of `A` +`A+` | matches 1 or many occurrences of `A` +`^` | matches the beginning of a string (not that of each line) +`$` | matches the end of a string (not that of each line) +`xy` | matches `x` followed by `y` + +To help you determine which capability is available on your system, googletest +defines macros to govern which regular expression it is using. The macros are: +`GTEST_USES_SIMPLE_RE=1` or `GTEST_USES_POSIX_RE=1`. If you want your death +tests to work in all cases, you can either `#if` on these macros or use the more +limited syntax only. + +### How It Works + +Under the hood, `ASSERT_EXIT()` spawns a new process and executes the death test +statement in that process. The details of how precisely that happens depend on +the platform and the variable ::testing::GTEST_FLAG(death_test_style) (which is +initialized from the command-line flag `--gtest_death_test_style`). + +* On POSIX systems, `fork()` (or `clone()` on Linux) is used to spawn the + child, after which: + * If the variable's value is `"fast"`, the death test statement is + immediately executed. + * If the variable's value is `"threadsafe"`, the child process re-executes + the unit test binary just as it was originally invoked, but with some + extra flags to cause just the single death test under consideration to + be run. +* On Windows, the child is spawned using the `CreateProcess()` API, and + re-executes the binary to cause just the single death test under + consideration to be run - much like the `threadsafe` mode on POSIX. + +Other values for the variable are illegal and will cause the death test to fail. +Currently, the flag's default value is **"fast"** + +1. the child's exit status satisfies the predicate, and +2. the child's stderr matches the regular expression. + +If the death test statement runs to completion without dying, the child process +will nonetheless terminate, and the assertion fails. + +### Death Tests And Threads + +The reason for the two death test styles has to do with thread safety. Due to +well-known problems with forking in the presence of threads, death tests should +be run in a single-threaded context. Sometimes, however, it isn't feasible to +arrange that kind of environment. For example, statically-initialized modules +may start threads before main is ever reached. Once threads have been created, +it may be difficult or impossible to clean them up. + +googletest has three features intended to raise awareness of threading issues. + +1. A warning is emitted if multiple threads are running when a death test is + encountered. +2. Test suites with a name ending in "DeathTest" are run before all other + tests. +3. It uses `clone()` instead of `fork()` to spawn the child process on Linux + (`clone()` is not available on Cygwin and Mac), as `fork()` is more likely + to cause the child to hang when the parent process has multiple threads. + +It's perfectly fine to create threads inside a death test statement; they are +executed in a separate process and cannot affect the parent. + +### Death Test Styles + +The "threadsafe" death test style was introduced in order to help mitigate the +risks of testing in a possibly multithreaded environment. It trades increased +test execution time (potentially dramatically so) for improved thread safety. + +The automated testing framework does not set the style flag. You can choose a +particular style of death tests by setting the flag programmatically: + +```c++ +testing::FLAGS_gtest_death_test_style="threadsafe" +``` + +You can do this in `main()` to set the style for all death tests in the binary, +or in individual tests. Recall that flags are saved before running each test and +restored afterwards, so you need not do that yourself. For example: + +```c++ +int main(int argc, char** argv) { + InitGoogle(argv[0], &argc, &argv, true); + ::testing::FLAGS_gtest_death_test_style = "fast"; + return RUN_ALL_TESTS(); +} + +TEST(MyDeathTest, TestOne) { + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + // This test is run in the "threadsafe" style: + ASSERT_DEATH(ThisShouldDie(), ""); +} + +TEST(MyDeathTest, TestTwo) { + // This test is run in the "fast" style: + ASSERT_DEATH(ThisShouldDie(), ""); +} +``` + +### Caveats + +The `statement` argument of `ASSERT_EXIT()` can be any valid C++ statement. If +it leaves the current function via a `return` statement or by throwing an +exception, the death test is considered to have failed. Some googletest macros +may return from the current function (e.g. `ASSERT_TRUE()`), so be sure to avoid +them in `statement`. + +Since `statement` runs in the child process, any in-memory side effect (e.g. +modifying a variable, releasing memory, etc) it causes will *not* be observable +in the parent process. In particular, if you release memory in a death test, +your program will fail the heap check as the parent process will never see the +memory reclaimed. To solve this problem, you can + +1. try not to free memory in a death test; +2. free the memory again in the parent process; or +3. do not use the heap checker in your program. + +Due to an implementation detail, you cannot place multiple death test assertions +on the same line; otherwise, compilation will fail with an unobvious error +message. + +Despite the improved thread safety afforded by the "threadsafe" style of death +test, thread problems such as deadlock are still possible in the presence of +handlers registered with `pthread_atfork(3)`. + + +## Using Assertions in Sub-routines + +### Adding Traces to Assertions + +If a test sub-routine is called from several places, when an assertion inside it +fails, it can be hard to tell which invocation of the sub-routine the failure is +from. You can alleviate this problem using extra logging or custom failure +messages, but that usually clutters up your tests. A better solution is to use +the `SCOPED_TRACE` macro or the `ScopedTrace` utility: + +```c++ +SCOPED_TRACE(message); +ScopedTrace trace("file_path", line_number, message); +``` + +where `message` can be anything streamable to `std::ostream`. `SCOPED_TRACE` +macro will cause the current file name, line number, and the given message to be +added in every failure message. `ScopedTrace` accepts explicit file name and +line number in arguments, which is useful for writing test helpers. The effect +will be undone when the control leaves the current lexical scope. + +For example, + +```c++ +10: void Sub1(int n) { +11: EXPECT_EQ(Bar(n), 1); +12: EXPECT_EQ(Bar(n + 1), 2); +13: } +14: +15: TEST(FooTest, Bar) { +16: { +17: SCOPED_TRACE("A"); // This trace point will be included in +18: // every failure in this scope. +19: Sub1(1); +20: } +21: // Now it won't. +22: Sub1(9); +23: } +``` + +could result in messages like these: + +```none +path/to/foo_test.cc:11: Failure +Value of: Bar(n) +Expected: 1 + Actual: 2 + Trace: +path/to/foo_test.cc:17: A + +path/to/foo_test.cc:12: Failure +Value of: Bar(n + 1) +Expected: 2 + Actual: 3 +``` + +Without the trace, it would've been difficult to know which invocation of +`Sub1()` the two failures come from respectively. (You could add an extra +message to each assertion in `Sub1()` to indicate the value of `n`, but that's +tedious.) + +Some tips on using `SCOPED_TRACE`: + +1. With a suitable message, it's often enough to use `SCOPED_TRACE` at the + beginning of a sub-routine, instead of at each call site. +2. When calling sub-routines inside a loop, make the loop iterator part of the + message in `SCOPED_TRACE` such that you can know which iteration the failure + is from. +3. Sometimes the line number of the trace point is enough for identifying the + particular invocation of a sub-routine. In this case, you don't have to + choose a unique message for `SCOPED_TRACE`. You can simply use `""`. +4. You can use `SCOPED_TRACE` in an inner scope when there is one in the outer + scope. In this case, all active trace points will be included in the failure + messages, in reverse order they are encountered. +5. The trace dump is clickable in Emacs - hit `return` on a line number and + you'll be taken to that line in the source file! + +### Propagating Fatal Failures + +A common pitfall when using `ASSERT_*` and `FAIL*` is not understanding that +when they fail they only abort the _current function_, not the entire test. For +example, the following test will segfault: + +```c++ +void Subroutine() { + // Generates a fatal failure and aborts the current function. + ASSERT_EQ(1, 2); + + // The following won't be executed. + ... +} + +TEST(FooTest, Bar) { + Subroutine(); // The intended behavior is for the fatal failure + // in Subroutine() to abort the entire test. + + // The actual behavior: the function goes on after Subroutine() returns. + int* p = NULL; + *p = 3; // Segfault! +} +``` + +To alleviate this, googletest provides three different solutions. You could use +either exceptions, the `(ASSERT|EXPECT)_NO_FATAL_FAILURE` assertions or the +`HasFatalFailure()` function. They are described in the following two +subsections. + +#### Asserting on Subroutines with an exception + +The following code can turn ASSERT-failure into an exception: + +```c++ +class ThrowListener : public testing::EmptyTestEventListener { + void OnTestPartResult(const testing::TestPartResult& result) override { + if (result.type() == testing::TestPartResult::kFatalFailure) { + throw testing::AssertionException(result); + } + } +}; +int main(int argc, char** argv) { + ... + testing::UnitTest::GetInstance()->listeners().Append(new ThrowListener); + return RUN_ALL_TESTS(); +} +``` + +This listener should be added after other listeners if you have any, otherwise +they won't see failed `OnTestPartResult`. + +#### Asserting on Subroutines + +As shown above, if your test calls a subroutine that has an `ASSERT_*` failure +in it, the test will continue after the subroutine returns. This may not be what +you want. + +Often people want fatal failures to propagate like exceptions. For that +googletest offers the following macros: + +Fatal assertion | Nonfatal assertion | Verifies +------------------------------------- | ------------------------------------- | -------- +`ASSERT_NO_FATAL_FAILURE(statement);` | `EXPECT_NO_FATAL_FAILURE(statement);` | `statement` doesn't generate any new fatal failures in the current thread. + +Only failures in the thread that executes the assertion are checked to determine +the result of this type of assertions. If `statement` creates new threads, +failures in these threads are ignored. + +Examples: + +```c++ +ASSERT_NO_FATAL_FAILURE(Foo()); + +int i; +EXPECT_NO_FATAL_FAILURE({ + i = Bar(); +}); +``` + +Assertions from multiple threads are currently not supported on Windows. + +#### Checking for Failures in the Current Test + +`HasFatalFailure()` in the `::testing::Test` class returns `true` if an +assertion in the current test has suffered a fatal failure. This allows +functions to catch fatal failures in a sub-routine and return early. + +```c++ +class Test { + public: + ... + static bool HasFatalFailure(); +}; +``` + +The typical usage, which basically simulates the behavior of a thrown exception, +is: + +```c++ +TEST(FooTest, Bar) { + Subroutine(); + // Aborts if Subroutine() had a fatal failure. + if (HasFatalFailure()) return; + + // The following won't be executed. + ... +} +``` + +If `HasFatalFailure()` is used outside of `TEST()` , `TEST_F()` , or a test +fixture, you must add the `::testing::Test::` prefix, as in: + +```c++ +if (::testing::Test::HasFatalFailure()) return; +``` + +Similarly, `HasNonfatalFailure()` returns `true` if the current test has at +least one non-fatal failure, and `HasFailure()` returns `true` if the current +test has at least one failure of either kind. + +## Logging Additional Information + +In your test code, you can call `RecordProperty("key", value)` to log additional +information, where `value` can be either a string or an `int`. The *last* value +recorded for a key will be emitted to the +[XML output](#generating-an-xml-report) if you specify one. For example, the +test + +```c++ +TEST_F(WidgetUsageTest, MinAndMaxWidgets) { + RecordProperty("MaximumWidgets", ComputeMaxUsage()); + RecordProperty("MinimumWidgets", ComputeMinUsage()); +} +``` + +will output XML like this: + +```xml + ... + + ... +``` + +> NOTE: +> +> * `RecordProperty()` is a static member of the `Test` class. Therefore it +> needs to be prefixed with `::testing::Test::` if used outside of the +> `TEST` body and the test fixture class. +> * `*key*` must be a valid XML attribute name, and cannot conflict with the +> ones already used by googletest (`name`, `status`, `time`, `classname`, +> `type_param`, and `value_param`). +> * Calling `RecordProperty()` outside of the lifespan of a test is allowed. +> If it's called outside of a test but between a test suite's +> `SetUpTestSuite()` and `TearDownTestSuite()` methods, it will be +> attributed to the XML element for the test suite. If it's called outside +> of all test suites (e.g. in a test environment), it will be attributed to +> the top-level XML element. + +## Sharing Resources Between Tests in the Same Test Suite + +googletest creates a new test fixture object for each test in order to make +tests independent and easier to debug. However, sometimes tests use resources +that are expensive to set up, making the one-copy-per-test model prohibitively +expensive. + +If the tests don't change the resource, there's no harm in their sharing a +single resource copy. So, in addition to per-test set-up/tear-down, googletest +also supports per-test-suite set-up/tear-down. To use it: + +1. In your test fixture class (say `FooTest` ), declare as `static` some member + variables to hold the shared resources. +2. Outside your test fixture class (typically just below it), define those + member variables, optionally giving them initial values. +3. In the same test fixture class, define a `static void SetUpTestSuite()` + function (remember not to spell it as **`SetupTestSuite`** with a small + `u`!) to set up the shared resources and a `static void TearDownTestSuite()` + function to tear them down. + +That's it! googletest automatically calls `SetUpTestSuite()` before running the +*first test* in the `FooTest` test suite (i.e. before creating the first +`FooTest` object), and calls `TearDownTestSuite()` after running the *last test* +in it (i.e. after deleting the last `FooTest` object). In between, the tests can +use the shared resources. + +Remember that the test order is undefined, so your code can't depend on a test +preceding or following another. Also, the tests must either not modify the state +of any shared resource, or, if they do modify the state, they must restore the +state to its original value before passing control to the next test. + +Here's an example of per-test-suite set-up and tear-down: + +```c++ +class FooTest : public ::testing::Test { + protected: + // Per-test-suite set-up. + // Called before the first test in this test suite. + // Can be omitted if not needed. + static void SetUpTestSuite() { + shared_resource_ = new ...; + } + + // Per-test-suite tear-down. + // Called after the last test in this test suite. + // Can be omitted if not needed. + static void TearDownTestSuite() { + delete shared_resource_; + shared_resource_ = NULL; + } + + // You can define per-test set-up logic as usual. + virtual void SetUp() { ... } + + // You can define per-test tear-down logic as usual. + virtual void TearDown() { ... } + + // Some expensive resource shared by all tests. + static T* shared_resource_; +}; + +T* FooTest::shared_resource_ = NULL; + +TEST_F(FooTest, Test1) { + ... you can refer to shared_resource_ here ... +} + +TEST_F(FooTest, Test2) { + ... you can refer to shared_resource_ here ... +} +``` + +NOTE: Though the above code declares `SetUpTestSuite()` protected, it may +sometimes be necessary to declare it public, such as when using it with +`TEST_P`. + +## Global Set-Up and Tear-Down + +Just as you can do set-up and tear-down at the test level and the test suite +level, you can also do it at the test program level. Here's how. + +First, you subclass the `::testing::Environment` class to define a test +environment, which knows how to set-up and tear-down: + +```c++ +class Environment : public ::testing::Environment { + public: + virtual ~Environment() {} + + // Override this to define how to set up the environment. + void SetUp() override {} + + // Override this to define how to tear down the environment. + void TearDown() override {} +}; +``` + +Then, you register an instance of your environment class with googletest by +calling the `::testing::AddGlobalTestEnvironment()` function: + +```c++ +Environment* AddGlobalTestEnvironment(Environment* env); +``` + +Now, when `RUN_ALL_TESTS()` is called, it first calls the `SetUp()` method of +each environment object, then runs the tests if none of the environments +reported fatal failures and `GTEST_SKIP()` was not called. `RUN_ALL_TESTS()` +always calls `TearDown()` with each environment object, regardless of whether or +not the tests were run. + +It's OK to register multiple environment objects. In this suite, their `SetUp()` +will be called in the order they are registered, and their `TearDown()` will be +called in the reverse order. + +Note that googletest takes ownership of the registered environment objects. +Therefore **do not delete them** by yourself. + +You should call `AddGlobalTestEnvironment()` before `RUN_ALL_TESTS()` is called, +probably in `main()`. If you use `gtest_main`, you need to call this before +`main()` starts for it to take effect. One way to do this is to define a global +variable like this: + +```c++ +::testing::Environment* const foo_env = + ::testing::AddGlobalTestEnvironment(new FooEnvironment); +``` + +However, we strongly recommend you to write your own `main()` and call +`AddGlobalTestEnvironment()` there, as relying on initialization of global +variables makes the code harder to read and may cause problems when you register +multiple environments from different translation units and the environments have +dependencies among them (remember that the compiler doesn't guarantee the order +in which global variables from different translation units are initialized). + +## Value-Parameterized Tests + +*Value-parameterized tests* allow you to test your code with different +parameters without writing multiple copies of the same test. This is useful in a +number of situations, for example: + +* You have a piece of code whose behavior is affected by one or more + command-line flags. You want to make sure your code performs correctly for + various values of those flags. +* You want to test different implementations of an OO interface. +* You want to test your code over various inputs (a.k.a. data-driven testing). + This feature is easy to abuse, so please exercise your good sense when doing + it! + +### How to Write Value-Parameterized Tests + +To write value-parameterized tests, first you should define a fixture class. It +must be derived from both `testing::Test` and `testing::WithParamInterface` +(the latter is a pure interface), where `T` is the type of your parameter +values. For convenience, you can just derive the fixture class from +`testing::TestWithParam`, which itself is derived from both `testing::Test` +and `testing::WithParamInterface`. `T` can be any copyable type. If it's a +raw pointer, you are responsible for managing the lifespan of the pointed +values. + +NOTE: If your test fixture defines `SetUpTestSuite()` or `TearDownTestSuite()` +they must be declared **public** rather than **protected** in order to use +`TEST_P`. + +```c++ +class FooTest : + public testing::TestWithParam { + // You can implement all the usual fixture class members here. + // To access the test parameter, call GetParam() from class + // TestWithParam. +}; + +// Or, when you want to add parameters to a pre-existing fixture class: +class BaseTest : public testing::Test { + ... +}; +class BarTest : public BaseTest, + public testing::WithParamInterface { + ... +}; +``` + +Then, use the `TEST_P` macro to define as many test patterns using this fixture +as you want. The `_P` suffix is for "parameterized" or "pattern", whichever you +prefer to think. + +```c++ +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} +``` + +Finally, you can use `INSTANTIATE_TEST_SUITE_P` to instantiate the test suite +with any set of parameters you want. googletest defines a number of functions +for generating test parameters. They return what we call (surprise!) *parameter +generators*. Here is a summary of them, which are all in the `testing` +namespace: + + + +| Parameter Generator | Behavior | +| ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| `Range(begin, end [, step])` | Yields values `{begin, begin+step, begin+step+step, ...}`. The values do not include `end`. `step` defaults to 1. | +| `Values(v1, v2, ..., vN)` | Yields values `{v1, v2, ..., vN}`. | +| `ValuesIn(container)` and `ValuesIn(begin,end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)` | +| `Bool()` | Yields sequence `{false, true}`. | +| `Combine(g1, g2, ..., gN)` | Yields all combinations (Cartesian product) as std\:\:tuples of the values generated by the `N` generators. | + + + +For more details, see the comments at the definitions of these functions. + +The following statement will instantiate tests from the `FooTest` test suite +each with parameter values `"meeny"`, `"miny"`, and `"moe"`. + +```c++ +INSTANTIATE_TEST_SUITE_P(InstantiationName, + FooTest, + testing::Values("meeny", "miny", "moe")); +``` + +NOTE: The code above must be placed at global or namespace scope, not at +function scope. + +NOTE: Don't forget this step! If you do your test will silently pass, but none +of its suites will ever run! + +To distinguish different instances of the pattern (yes, you can instantiate it +more than once), the first argument to `INSTANTIATE_TEST_SUITE_P` is a prefix +that will be added to the actual test suite name. Remember to pick unique +prefixes for different instantiations. The tests from the instantiation above +will have these names: + +* `InstantiationName/FooTest.DoesBlah/0` for `"meeny"` +* `InstantiationName/FooTest.DoesBlah/1` for `"miny"` +* `InstantiationName/FooTest.DoesBlah/2` for `"moe"` +* `InstantiationName/FooTest.HasBlahBlah/0` for `"meeny"` +* `InstantiationName/FooTest.HasBlahBlah/1` for `"miny"` +* `InstantiationName/FooTest.HasBlahBlah/2` for `"moe"` + +You can use these names in [`--gtest_filter`](#running-a-subset-of-the-tests). + +This statement will instantiate all tests from `FooTest` again, each with +parameter values `"cat"` and `"dog"`: + +```c++ +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_SUITE_P(AnotherInstantiationName, FooTest, + testing::ValuesIn(pets)); +``` + +The tests from the instantiation above will have these names: + +* `AnotherInstantiationName/FooTest.DoesBlah/0` for `"cat"` +* `AnotherInstantiationName/FooTest.DoesBlah/1` for `"dog"` +* `AnotherInstantiationName/FooTest.HasBlahBlah/0` for `"cat"` +* `AnotherInstantiationName/FooTest.HasBlahBlah/1` for `"dog"` + +Please note that `INSTANTIATE_TEST_SUITE_P` will instantiate *all* tests in the +given test suite, whether their definitions come before or *after* the +`INSTANTIATE_TEST_SUITE_P` statement. + +You can see [sample7_unittest.cc] and [sample8_unittest.cc] for more examples. + +[sample7_unittest.cc]: ../samples/sample7_unittest.cc "Parameterized Test example" +[sample8_unittest.cc]: ../samples/sample8_unittest.cc "Parameterized Test example with multiple parameters" + +### Creating Value-Parameterized Abstract Tests + +In the above, we define and instantiate `FooTest` in the *same* source file. +Sometimes you may want to define value-parameterized tests in a library and let +other people instantiate them later. This pattern is known as *abstract tests*. +As an example of its application, when you are designing an interface you can +write a standard suite of abstract tests (perhaps using a factory function as +the test parameter) that all implementations of the interface are expected to +pass. When someone implements the interface, they can instantiate your suite to +get all the interface-conformance tests for free. + +To define abstract tests, you should organize your code like this: + +1. Put the definition of the parameterized test fixture class (e.g. `FooTest`) + in a header file, say `foo_param_test.h`. Think of this as *declaring* your + abstract tests. +2. Put the `TEST_P` definitions in `foo_param_test.cc`, which includes + `foo_param_test.h`. Think of this as *implementing* your abstract tests. + +Once they are defined, you can instantiate them by including `foo_param_test.h`, +invoking `INSTANTIATE_TEST_SUITE_P()`, and depending on the library target that +contains `foo_param_test.cc`. You can instantiate the same abstract test suite +multiple times, possibly in different source files. + +### Specifying Names for Value-Parameterized Test Parameters + +The optional last argument to `INSTANTIATE_TEST_SUITE_P()` allows the user to +specify a function or functor that generates custom test name suffixes based on +the test parameters. The function should accept one argument of type +`testing::TestParamInfo`, and return `std::string`. + +`testing::PrintToStringParamName` is a builtin test suffix generator that +returns the value of `testing::PrintToString(GetParam())`. It does not work for +`std::string` or C strings. + +NOTE: test names must be non-empty, unique, and may only contain ASCII +alphanumeric characters. In particular, they +[should not contain underscores](faq.md#why-should-test-suite-names-and-test-names-not-contain-underscore) + +```c++ +class MyTestSuite : public testing::TestWithParam {}; + +TEST_P(MyTestSuite, MyTest) +{ + std::cout << "Example Test Param: " << GetParam() << std::endl; +} + +INSTANTIATE_TEST_SUITE_P(MyGroup, MyTestSuite, testing::Range(0, 10), + testing::PrintToStringParamName()); +``` + +Providing a custom functor allows for more control over test parameter name +generation, especially for types where the automatic conversion does not +generate helpful parameter names (e.g. strings as demonstrated above). The +following example illustrates this for multiple parameters, an enumeration type +and a string, and also demonstrates how to combine generators. It uses a lambda +for conciseness: + +```c++ +enum class MyType { MY_FOO = 0, MY_BAR = 1 }; + +class MyTestSuite : public testing::TestWithParam> { +}; + +INSTANTIATE_TEST_SUITE_P( + MyGroup, MyTestSuite, + testing::Combine( + testing::Values(MyType::VALUE_0, MyType::VALUE_1), + testing::ValuesIn("", "")), + [](const testing::TestParamInfo& info) { + string name = absl::StrCat( + std::get<0>(info.param) == MY_FOO ? "Foo" : "Bar", "_", + std::get<1>(info.param)); + absl::c_replace_if(name, [](char c) { return !std::isalnum(c); }, '_'); + return name; + }); +``` + +## Typed Tests + +Suppose you have multiple implementations of the same interface and want to make +sure that all of them satisfy some common requirements. Or, you may have defined +several types that are supposed to conform to the same "concept" and you want to +verify it. In both cases, you want the same test logic repeated for different +types. + +While you can write one `TEST` or `TEST_F` for each type you want to test (and +you may even factor the test logic into a function template that you invoke from +the `TEST`), it's tedious and doesn't scale: if you want `m` tests over `n` +types, you'll end up writing `m*n` `TEST`s. + +*Typed tests* allow you to repeat the same test logic over a list of types. You +only need to write the test logic once, although you must know the type list +when writing typed tests. Here's how you do it: + +First, define a fixture class template. It should be parameterized by a type. +Remember to derive it from `::testing::Test`: + +```c++ +template +class FooTest : public ::testing::Test { + public: + ... + typedef std::list List; + static T shared_; + T value_; +}; +``` + +Next, associate a list of types with the test suite, which will be repeated for +each type in the list: + +```c++ +using MyTypes = ::testing::Types; +TYPED_TEST_SUITE(FooTest, MyTypes); +``` + +The type alias (`using` or `typedef`) is necessary for the `TYPED_TEST_SUITE` +macro to parse correctly. Otherwise the compiler will think that each comma in +the type list introduces a new macro argument. + +Then, use `TYPED_TEST()` instead of `TEST_F()` to define a typed test for this +test suite. You can repeat this as many times as you want: + +```c++ +TYPED_TEST(FooTest, DoesBlah) { + // Inside a test, refer to the special name TypeParam to get the type + // parameter. Since we are inside a derived class template, C++ requires + // us to visit the members of FooTest via 'this'. + TypeParam n = this->value_; + + // To visit static members of the fixture, add the 'TestFixture::' + // prefix. + n += TestFixture::shared_; + + // To refer to typedefs in the fixture, add the 'typename TestFixture::' + // prefix. The 'typename' is required to satisfy the compiler. + typename TestFixture::List values; + + values.push_back(n); + ... +} + +TYPED_TEST(FooTest, HasPropertyA) { ... } +``` + +You can see [sample6_unittest.cc] for a complete example. + +[sample6_unittest.cc]: ../samples/sample6_unittest.cc "Typed Test example" + +## Type-Parameterized Tests + +*Type-parameterized tests* are like typed tests, except that they don't require +you to know the list of types ahead of time. Instead, you can define the test +logic first and instantiate it with different type lists later. You can even +instantiate it more than once in the same program. + +If you are designing an interface or concept, you can define a suite of +type-parameterized tests to verify properties that any valid implementation of +the interface/concept should have. Then, the author of each implementation can +just instantiate the test suite with their type to verify that it conforms to +the requirements, without having to write similar tests repeatedly. Here's an +example: + +First, define a fixture class template, as we did with typed tests: + +```c++ +template +class FooTest : public ::testing::Test { + ... +}; +``` + +Next, declare that you will define a type-parameterized test suite: + +```c++ +TYPED_TEST_SUITE_P(FooTest); +``` + +Then, use `TYPED_TEST_P()` to define a type-parameterized test. You can repeat +this as many times as you want: + +```c++ +TYPED_TEST_P(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + TypeParam n = 0; + ... +} + +TYPED_TEST_P(FooTest, HasPropertyA) { ... } +``` + +Now the tricky part: you need to register all test patterns using the +`REGISTER_TYPED_TEST_SUITE_P` macro before you can instantiate them. The first +argument of the macro is the test suite name; the rest are the names of the +tests in this test suite: + +```c++ +REGISTER_TYPED_TEST_SUITE_P(FooTest, + DoesBlah, HasPropertyA); +``` + +Finally, you are free to instantiate the pattern with the types you want. If you +put the above code in a header file, you can `#include` it in multiple C++ +source files and instantiate it multiple times. + +```c++ +typedef ::testing::Types MyTypes; +INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); +``` + +To distinguish different instances of the pattern, the first argument to the +`INSTANTIATE_TYPED_TEST_SUITE_P` macro is a prefix that will be added to the +actual test suite name. Remember to pick unique prefixes for different +instances. + +In the special case where the type list contains only one type, you can write +that type directly without `::testing::Types<...>`, like this: + +```c++ +INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int); +``` + +You can see [sample6_unittest.cc] for a complete example. + +## Testing Private Code + +If you change your software's internal implementation, your tests should not +break as long as the change is not observable by users. Therefore, **per the +black-box testing principle, most of the time you should test your code through +its public interfaces.** + +**If you still find yourself needing to test internal implementation code, +consider if there's a better design.** The desire to test internal +implementation is often a sign that the class is doing too much. Consider +extracting an implementation class, and testing it. Then use that implementation +class in the original class. + +If you absolutely have to test non-public interface code though, you can. There +are two cases to consider: + +* Static functions ( *not* the same as static member functions!) or unnamed + namespaces, and +* Private or protected class members + +To test them, we use the following special techniques: + +* Both static functions and definitions/declarations in an unnamed namespace + are only visible within the same translation unit. To test them, you can + `#include` the entire `.cc` file being tested in your `*_test.cc` file. + (#including `.cc` files is not a good way to reuse code - you should not do + this in production code!) + + However, a better approach is to move the private code into the + `foo::internal` namespace, where `foo` is the namespace your project + normally uses, and put the private declarations in a `*-internal.h` file. + Your production `.cc` files and your tests are allowed to include this + internal header, but your clients are not. This way, you can fully test your + internal implementation without leaking it to your clients. + +* Private class members are only accessible from within the class or by + friends. To access a class' private members, you can declare your test + fixture as a friend to the class and define accessors in your fixture. Tests + using the fixture can then access the private members of your production + class via the accessors in the fixture. Note that even though your fixture + is a friend to your production class, your tests are not automatically + friends to it, as they are technically defined in sub-classes of the + fixture. + + Another way to test private members is to refactor them into an + implementation class, which is then declared in a `*-internal.h` file. Your + clients aren't allowed to include this header but your tests can. Such is + called the + [Pimpl](https://www.gamedev.net/articles/programming/general-and-gameplay-programming/the-c-pimpl-r1794/) + (Private Implementation) idiom. + + Or, you can declare an individual test as a friend of your class by adding + this line in the class body: + + ```c++ + FRIEND_TEST(TestSuiteName, TestName); + ``` + + For example, + + ```c++ + // foo.h + class Foo { + ... + private: + FRIEND_TEST(FooTest, BarReturnsZeroOnNull); + + int Bar(void* x); + }; + + // foo_test.cc + ... + TEST(FooTest, BarReturnsZeroOnNull) { + Foo foo; + EXPECT_EQ(foo.Bar(NULL), 0); // Uses Foo's private member Bar(). + } + ``` + + Pay special attention when your class is defined in a namespace, as you + should define your test fixtures and tests in the same namespace if you want + them to be friends of your class. For example, if the code to be tested + looks like: + + ```c++ + namespace my_namespace { + + class Foo { + friend class FooTest; + FRIEND_TEST(FooTest, Bar); + FRIEND_TEST(FooTest, Baz); + ... definition of the class Foo ... + }; + + } // namespace my_namespace + ``` + + Your test code should be something like: + + ```c++ + namespace my_namespace { + + class FooTest : public ::testing::Test { + protected: + ... + }; + + TEST_F(FooTest, Bar) { ... } + TEST_F(FooTest, Baz) { ... } + + } // namespace my_namespace + ``` + +## "Catching" Failures + +If you are building a testing utility on top of googletest, you'll want to test +your utility. What framework would you use to test it? googletest, of course. + +The challenge is to verify that your testing utility reports failures correctly. +In frameworks that report a failure by throwing an exception, you could catch +the exception and assert on it. But googletest doesn't use exceptions, so how do +we test that a piece of code generates an expected failure? + +gunit-spi.h contains some constructs to do this. After #including this header, +you can use + +```c++ + EXPECT_FATAL_FAILURE(statement, substring); +``` + +to assert that `statement` generates a fatal (e.g. `ASSERT_*`) failure in the +current thread whose message contains the given `substring`, or use + +```c++ + EXPECT_NONFATAL_FAILURE(statement, substring); +``` + +if you are expecting a non-fatal (e.g. `EXPECT_*`) failure. + +Only failures in the current thread are checked to determine the result of this +type of expectations. If `statement` creates new threads, failures in these +threads are also ignored. If you want to catch failures in other threads as +well, use one of the following macros instead: + +```c++ + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substring); + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substring); +``` + +NOTE: Assertions from multiple threads are currently not supported on Windows. + +For technical reasons, there are some caveats: + +1. You cannot stream a failure message to either macro. + +2. `statement` in `EXPECT_FATAL_FAILURE{_ON_ALL_THREADS}()` cannot reference + local non-static variables or non-static members of `this` object. + +3. `statement` in `EXPECT_FATAL_FAILURE{_ON_ALL_THREADS}()` cannot return a + value. + +## Registering tests programmatically + +The `TEST` macros handle the vast majority of all use cases, but there are few +were runtime registration logic is required. For those cases, the framework +provides the `::testing::RegisterTest` that allows callers to register arbitrary +tests dynamically. + +This is an advanced API only to be used when the `TEST` macros are insufficient. +The macros should be preferred when possible, as they avoid most of the +complexity of calling this function. + +It provides the following signature: + +```c++ +template +TestInfo* RegisterTest(const char* test_suite_name, const char* test_name, + const char* type_param, const char* value_param, + const char* file, int line, Factory factory); +``` + +The `factory` argument is a factory callable (move-constructible) object or +function pointer that creates a new instance of the Test object. It handles +ownership to the caller. The signature of the callable is `Fixture*()`, where +`Fixture` is the test fixture class for the test. All tests registered with the +same `test_suite_name` must return the same fixture type. This is checked at +runtime. + +The framework will infer the fixture class from the factory and will call the +`SetUpTestSuite` and `TearDownTestSuite` for it. + +Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is +undefined. + +Use case example: + +```c++ +class MyFixture : public ::testing::Test { + public: + // All of these optional, just like in regular macro usage. + static void SetUpTestSuite() { ... } + static void TearDownTestSuite() { ... } + void SetUp() override { ... } + void TearDown() override { ... } +}; + +class MyTest : public MyFixture { + public: + explicit MyTest(int data) : data_(data) {} + void TestBody() override { ... } + + private: + int data_; +}; + +void RegisterMyTests(const std::vector& values) { + for (int v : values) { + ::testing::RegisterTest( + "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, + std::to_string(v).c_str(), + __FILE__, __LINE__, + // Important to use the fixture type as the return type here. + [=]() -> MyFixture* { return new MyTest(v); }); + } +} +... +int main(int argc, char** argv) { + std::vector values_to_test = LoadValuesFromConfig(); + RegisterMyTests(values_to_test); + ... + return RUN_ALL_TESTS(); +} +``` +## Getting the Current Test's Name + +Sometimes a function may need to know the name of the currently running test. +For example, you may be using the `SetUp()` method of your test fixture to set +the golden file name based on which test is running. The `::testing::TestInfo` +class has this information: + +```c++ +namespace testing { + +class TestInfo { + public: + // Returns the test suite name and the test name, respectively. + // + // Do NOT delete or free the return value - it's managed by the + // TestInfo class. + const char* test_suite_name() const; + const char* name() const; +}; + +} +``` + +To obtain a `TestInfo` object for the currently running test, call +`current_test_info()` on the `UnitTest` singleton object: + +```c++ + // Gets information about the currently running test. + // Do NOT delete the returned object - it's managed by the UnitTest class. + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + + + printf("We are in test %s of test suite %s.\n", + test_info->name(), + test_info->test_suite_name()); +``` + +`current_test_info()` returns a null pointer if no test is running. In +particular, you cannot find the test suite name in `TestSuiteSetUp()`, +`TestSuiteTearDown()` (where you know the test suite name implicitly), or +functions called from them. + +## Extending googletest by Handling Test Events + +googletest provides an **event listener API** to let you receive notifications +about the progress of a test program and test failures. The events you can +listen to include the start and end of the test program, a test suite, or a test +method, among others. You may use this API to augment or replace the standard +console output, replace the XML output, or provide a completely different form +of output, such as a GUI or a database. You can also use test events as +checkpoints to implement a resource leak checker, for example. + +### Defining Event Listeners + +To define a event listener, you subclass either testing::TestEventListener or +testing::EmptyTestEventListener The former is an (abstract) interface, where +*each pure virtual method can be overridden to handle a test event* (For +example, when a test starts, the `OnTestStart()` method will be called.). The +latter provides an empty implementation of all methods in the interface, such +that a subclass only needs to override the methods it cares about. + +When an event is fired, its context is passed to the handler function as an +argument. The following argument types are used: + +* UnitTest reflects the state of the entire test program, +* TestSuite has information about a test suite, which can contain one or more + tests, +* TestInfo contains the state of a test, and +* TestPartResult represents the result of a test assertion. + +An event handler function can examine the argument it receives to find out +interesting information about the event and the test program's state. + +Here's an example: + +```c++ + class MinimalistPrinter : public ::testing::EmptyTestEventListener { + // Called before a test starts. + virtual void OnTestStart(const ::testing::TestInfo& test_info) { + printf("*** Test %s.%s starting.\n", + test_info.test_suite_name(), test_info.name()); + } + + // Called after a failed assertion or a SUCCESS(). + virtual void OnTestPartResult(const ::testing::TestPartResult& test_part_result) { + printf("%s in %s:%d\n%s\n", + test_part_result.failed() ? "*** Failure" : "Success", + test_part_result.file_name(), + test_part_result.line_number(), + test_part_result.summary()); + } + + // Called after a test ends. + virtual void OnTestEnd(const ::testing::TestInfo& test_info) { + printf("*** Test %s.%s ending.\n", + test_info.test_suite_name(), test_info.name()); + } + }; +``` + +### Using Event Listeners + +To use the event listener you have defined, add an instance of it to the +googletest event listener list (represented by class TestEventListeners - note +the "s" at the end of the name) in your `main()` function, before calling +`RUN_ALL_TESTS()`: + +```c++ +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + // Gets hold of the event listener list. + ::testing::TestEventListeners& listeners = + ::testing::UnitTest::GetInstance()->listeners(); + // Adds a listener to the end. googletest takes the ownership. + listeners.Append(new MinimalistPrinter); + return RUN_ALL_TESTS(); +} +``` + +There's only one problem: the default test result printer is still in effect, so +its output will mingle with the output from your minimalist printer. To suppress +the default printer, just release it from the event listener list and delete it. +You can do so by adding one line: + +```c++ + ... + delete listeners.Release(listeners.default_result_printer()); + listeners.Append(new MinimalistPrinter); + return RUN_ALL_TESTS(); +``` + +Now, sit back and enjoy a completely different output from your tests. For more +details, see [sample9_unittest.cc]. + +[sample9_unittest.cc]: ../samples/sample9_unittest.cc "Event listener example" + +You may append more than one listener to the list. When an `On*Start()` or +`OnTestPartResult()` event is fired, the listeners will receive it in the order +they appear in the list (since new listeners are added to the end of the list, +the default text printer and the default XML generator will receive the event +first). An `On*End()` event will be received by the listeners in the *reverse* +order. This allows output by listeners added later to be framed by output from +listeners added earlier. + +### Generating Failures in Listeners + +You may use failure-raising macros (`EXPECT_*()`, `ASSERT_*()`, `FAIL()`, etc) +when processing an event. There are some restrictions: + +1. You cannot generate any failure in `OnTestPartResult()` (otherwise it will + cause `OnTestPartResult()` to be called recursively). +2. A listener that handles `OnTestPartResult()` is not allowed to generate any + failure. + +When you add listeners to the listener list, you should put listeners that +handle `OnTestPartResult()` *before* listeners that can generate failures. This +ensures that failures generated by the latter are attributed to the right test +by the former. + +See [sample10_unittest.cc] for an example of a failure-raising listener. + +[sample10_unittest.cc]: ../samples/sample10_unittest.cc "Failure-raising listener example" + +## Running Test Programs: Advanced Options + +googletest test programs are ordinary executables. Once built, you can run them +directly and affect their behavior via the following environment variables +and/or command line flags. For the flags to work, your programs must call +`::testing::InitGoogleTest()` before calling `RUN_ALL_TESTS()`. + +To see a list of supported flags and their usage, please run your test program +with the `--help` flag. You can also use `-h`, `-?`, or `/?` for short. + +If an option is specified both by an environment variable and by a flag, the +latter takes precedence. + +### Selecting Tests + +#### Listing Test Names + +Sometimes it is necessary to list the available tests in a program before +running them so that a filter may be applied if needed. Including the flag +`--gtest_list_tests` overrides all other flags and lists tests in the following +format: + +```none +TestSuite1. + TestName1 + TestName2 +TestSuite2. + TestName +``` + +None of the tests listed are actually run if the flag is provided. There is no +corresponding environment variable for this flag. + +#### Running a Subset of the Tests + +By default, a googletest program runs all tests the user has defined. Sometimes, +you want to run only a subset of the tests (e.g. for debugging or quickly +verifying a change). If you set the `GTEST_FILTER` environment variable or the +`--gtest_filter` flag to a filter string, googletest will only run the tests +whose full names (in the form of `TestSuiteName.TestName`) match the filter. + +The format of a filter is a '`:`'-separated list of wildcard patterns (called +the *positive patterns*) optionally followed by a '`-`' and another +'`:`'-separated pattern list (called the *negative patterns*). A test matches +the filter if and only if it matches any of the positive patterns but does not +match any of the negative patterns. + +A pattern may contain `'*'` (matches any string) or `'?'` (matches any single +character). For convenience, the filter `'*-NegativePatterns'` can be also +written as `'-NegativePatterns'`. + +For example: + +* `./foo_test` Has no flag, and thus runs all its tests. +* `./foo_test --gtest_filter=*` Also runs everything, due to the single + match-everything `*` value. +* `./foo_test --gtest_filter=FooTest.*` Runs everything in test suite + `FooTest` . +* `./foo_test --gtest_filter=*Null*:*Constructor*` Runs any test whose full + name contains either `"Null"` or `"Constructor"` . +* `./foo_test --gtest_filter=-*DeathTest.*` Runs all non-death tests. +* `./foo_test --gtest_filter=FooTest.*-FooTest.Bar` Runs everything in test + suite `FooTest` except `FooTest.Bar`. +* `./foo_test --gtest_filter=FooTest.*:BarTest.*-FooTest.Bar:BarTest.Foo` Runs + everything in test suite `FooTest` except `FooTest.Bar` and everything in + test suite `BarTest` except `BarTest.Foo`. + +#### Temporarily Disabling Tests + +If you have a broken test that you cannot fix right away, you can add the +`DISABLED_` prefix to its name. This will exclude it from execution. This is +better than commenting out the code or using `#if 0`, as disabled tests are +still compiled (and thus won't rot). + +If you need to disable all tests in a test suite, you can either add `DISABLED_` +to the front of the name of each test, or alternatively add it to the front of +the test suite name. + +For example, the following tests won't be run by googletest, even though they +will still be compiled: + +```c++ +// Tests that Foo does Abc. +TEST(FooTest, DISABLED_DoesAbc) { ... } + +class DISABLED_BarTest : public ::testing::Test { ... }; + +// Tests that Bar does Xyz. +TEST_F(DISABLED_BarTest, DoesXyz) { ... } +``` + +NOTE: This feature should only be used for temporary pain-relief. You still have +to fix the disabled tests at a later date. As a reminder, googletest will print +a banner warning you if a test program contains any disabled tests. + +TIP: You can easily count the number of disabled tests you have using `gsearch` +and/or `grep`. This number can be used as a metric for improving your test +quality. + +#### Temporarily Enabling Disabled Tests + +To include disabled tests in test execution, just invoke the test program with +the `--gtest_also_run_disabled_tests` flag or set the +`GTEST_ALSO_RUN_DISABLED_TESTS` environment variable to a value other than `0`. +You can combine this with the `--gtest_filter` flag to further select which +disabled tests to run. + +### Repeating the Tests + +Once in a while you'll run into a test whose result is hit-or-miss. Perhaps it +will fail only 1% of the time, making it rather hard to reproduce the bug under +a debugger. This can be a major source of frustration. + +The `--gtest_repeat` flag allows you to repeat all (or selected) test methods in +a program many times. Hopefully, a flaky test will eventually fail and give you +a chance to debug. Here's how to use it: + +```none +$ foo_test --gtest_repeat=1000 +Repeat foo_test 1000 times and don't stop at failures. + +$ foo_test --gtest_repeat=-1 +A negative count means repeating forever. + +$ foo_test --gtest_repeat=1000 --gtest_break_on_failure +Repeat foo_test 1000 times, stopping at the first failure. This +is especially useful when running under a debugger: when the test +fails, it will drop into the debugger and you can then inspect +variables and stacks. + +$ foo_test --gtest_repeat=1000 --gtest_filter=FooBar.* +Repeat the tests whose name matches the filter 1000 times. +``` + +If your test program contains +[global set-up/tear-down](#global-set-up-and-tear-down) code, it will be +repeated in each iteration as well, as the flakiness may be in it. You can also +specify the repeat count by setting the `GTEST_REPEAT` environment variable. + +### Shuffling the Tests + +You can specify the `--gtest_shuffle` flag (or set the `GTEST_SHUFFLE` +environment variable to `1`) to run the tests in a program in a random order. +This helps to reveal bad dependencies between tests. + +By default, googletest uses a random seed calculated from the current time. +Therefore you'll get a different order every time. The console output includes +the random seed value, such that you can reproduce an order-related test failure +later. To specify the random seed explicitly, use the `--gtest_random_seed=SEED` +flag (or set the `GTEST_RANDOM_SEED` environment variable), where `SEED` is an +integer in the range [0, 99999]. The seed value 0 is special: it tells +googletest to do the default behavior of calculating the seed from the current +time. + +If you combine this with `--gtest_repeat=N`, googletest will pick a different +random seed and re-shuffle the tests in each iteration. + +### Controlling Test Output + +#### Colored Terminal Output + +googletest can use colors in its terminal output to make it easier to spot the +important information: + + +...
+ [----------] 1 test from + FooTest
+ [ RUN      ] + FooTest.DoesAbc
+ [       OK ] + FooTest.DoesAbc
+ [----------] + 2 tests from BarTest
+ [ RUN      ] + BarTest.HasXyzProperty
+ [       OK ] + BarTest.HasXyzProperty
+ [ RUN      ] + BarTest.ReturnsTrueOnSuccess ... some error messages ...
+ [   FAILED ] + BarTest.ReturnsTrueOnSuccess ...
+ [==========] + 30 tests from 14 test suites ran.
+ [   PASSED ] + 28 tests.
+ [   FAILED ] + 2 tests, listed below:
+ [   FAILED ] + BarTest.ReturnsTrueOnSuccess
+ [   FAILED ] + AnotherTest.DoesXyz
+
+ 2 FAILED TESTS +
+
+ +You can set the `GTEST_COLOR` environment variable or the `--gtest_color` +command line flag to `yes`, `no`, or `auto` (the default) to enable colors, +disable colors, or let googletest decide. When the value is `auto`, googletest +will use colors if and only if the output goes to a terminal and (on non-Windows +platforms) the `TERM` environment variable is set to `xterm` or `xterm-color`. + +#### Suppressing the Elapsed Time + +By default, googletest prints the time it takes to run each test. To disable +that, run the test program with the `--gtest_print_time=0` command line flag, or +set the GTEST_PRINT_TIME environment variable to `0`. + +#### Suppressing UTF-8 Text Output + +In case of assertion failures, googletest prints expected and actual values of +type `string` both as hex-encoded strings as well as in readable UTF-8 text if +they contain valid non-ASCII UTF-8 characters. If you want to suppress the UTF-8 +text because, for example, you don't have an UTF-8 compatible output medium, run +the test program with `--gtest_print_utf8=0` or set the `GTEST_PRINT_UTF8` +environment variable to `0`. + + + +#### Generating an XML Report + +googletest can emit a detailed XML report to a file in addition to its normal +textual output. The report contains the duration of each test, and thus can help +you identify slow tests. The report is also used by the http://unittest +dashboard to show per-test-method error messages. + +To generate the XML report, set the `GTEST_OUTPUT` environment variable or the +`--gtest_output` flag to the string `"xml:path_to_output_file"`, which will +create the file at the given location. You can also just use the string `"xml"`, +in which case the output can be found in the `test_detail.xml` file in the +current directory. + +If you specify a directory (for example, `"xml:output/directory/"` on Linux or +`"xml:output\directory\"` on Windows), googletest will create the XML file in +that directory, named after the test executable (e.g. `foo_test.xml` for test +program `foo_test` or `foo_test.exe`). If the file already exists (perhaps left +over from a previous run), googletest will pick a different name (e.g. +`foo_test_1.xml`) to avoid overwriting it. + +The report is based on the `junitreport` Ant task. Since that format was +originally intended for Java, a little interpretation is required to make it +apply to googletest tests, as shown here: + +```xml + + + + + + + + + +``` + +* The root `` element corresponds to the entire test program. +* `` elements correspond to googletest test suites. +* `` elements correspond to googletest test functions. + +For instance, the following program + +```c++ +TEST(MathTest, Addition) { ... } +TEST(MathTest, Subtraction) { ... } +TEST(LogicTest, NonContradiction) { ... } +``` + +could generate this report: + +```xml + + + + + ... + ... + + + + + + + + + +``` + +Things to note: + +* The `tests` attribute of a `` or `` element tells how + many test functions the googletest program or test suite contains, while the + `failures` attribute tells how many of them failed. + +* The `time` attribute expresses the duration of the test, test suite, or + entire test program in seconds. + +* The `timestamp` attribute records the local date and time of the test + execution. + +* Each `` element corresponds to a single failed googletest + assertion. + +#### Generating a JSON Report + +googletest can also emit a JSON report as an alternative format to XML. To +generate the JSON report, set the `GTEST_OUTPUT` environment variable or the +`--gtest_output` flag to the string `"json:path_to_output_file"`, which will +create the file at the given location. You can also just use the string +`"json"`, in which case the output can be found in the `test_detail.json` file +in the current directory. + +The report format conforms to the following JSON Schema: + +```json +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "definitions": { + "TestCase": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "tests": { "type": "integer" }, + "failures": { "type": "integer" }, + "disabled": { "type": "integer" }, + "time": { "type": "string" }, + "testsuite": { + "type": "array", + "items": { + "$ref": "#/definitions/TestInfo" + } + } + } + }, + "TestInfo": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "status": { + "type": "string", + "enum": ["RUN", "NOTRUN"] + }, + "time": { "type": "string" }, + "classname": { "type": "string" }, + "failures": { + "type": "array", + "items": { + "$ref": "#/definitions/Failure" + } + } + } + }, + "Failure": { + "type": "object", + "properties": { + "failures": { "type": "string" }, + "type": { "type": "string" } + } + } + }, + "properties": { + "tests": { "type": "integer" }, + "failures": { "type": "integer" }, + "disabled": { "type": "integer" }, + "errors": { "type": "integer" }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "time": { "type": "string" }, + "name": { "type": "string" }, + "testsuites": { + "type": "array", + "items": { + "$ref": "#/definitions/TestCase" + } + } + } +} +``` + +The report uses the format that conforms to the following Proto3 using the +[JSON encoding](https://developers.google.com/protocol-buffers/docs/proto3#json): + +```proto +syntax = "proto3"; + +package googletest; + +import "google/protobuf/timestamp.proto"; +import "google/protobuf/duration.proto"; + +message UnitTest { + int32 tests = 1; + int32 failures = 2; + int32 disabled = 3; + int32 errors = 4; + google.protobuf.Timestamp timestamp = 5; + google.protobuf.Duration time = 6; + string name = 7; + repeated TestCase testsuites = 8; +} + +message TestCase { + string name = 1; + int32 tests = 2; + int32 failures = 3; + int32 disabled = 4; + int32 errors = 5; + google.protobuf.Duration time = 6; + repeated TestInfo testsuite = 7; +} + +message TestInfo { + string name = 1; + enum Status { + RUN = 0; + NOTRUN = 1; + } + Status status = 2; + google.protobuf.Duration time = 3; + string classname = 4; + message Failure { + string failures = 1; + string type = 2; + } + repeated Failure failures = 5; +} +``` + +For instance, the following program + +```c++ +TEST(MathTest, Addition) { ... } +TEST(MathTest, Subtraction) { ... } +TEST(LogicTest, NonContradiction) { ... } +``` + +could generate this report: + +```json +{ + "tests": 3, + "failures": 1, + "errors": 0, + "time": "0.035s", + "timestamp": "2011-10-31T18:52:42Z", + "name": "AllTests", + "testsuites": [ + { + "name": "MathTest", + "tests": 2, + "failures": 1, + "errors": 0, + "time": "0.015s", + "testsuite": [ + { + "name": "Addition", + "status": "RUN", + "time": "0.007s", + "classname": "", + "failures": [ + { + "message": "Value of: add(1, 1)\n Actual: 3\nExpected: 2", + "type": "" + }, + { + "message": "Value of: add(1, -1)\n Actual: 1\nExpected: 0", + "type": "" + } + ] + }, + { + "name": "Subtraction", + "status": "RUN", + "time": "0.005s", + "classname": "" + } + ] + }, + { + "name": "LogicTest", + "tests": 1, + "failures": 0, + "errors": 0, + "time": "0.005s", + "testsuite": [ + { + "name": "NonContradiction", + "status": "RUN", + "time": "0.005s", + "classname": "" + } + ] + } + ] +} +``` + +IMPORTANT: The exact format of the JSON document is subject to change. + +### Controlling How Failures Are Reported + +#### Turning Assertion Failures into Break-Points + +When running test programs under a debugger, it's very convenient if the +debugger can catch an assertion failure and automatically drop into interactive +mode. googletest's *break-on-failure* mode supports this behavior. + +To enable it, set the `GTEST_BREAK_ON_FAILURE` environment variable to a value +other than `0`. Alternatively, you can use the `--gtest_break_on_failure` +command line flag. + +#### Disabling Catching Test-Thrown Exceptions + +googletest can be used either with or without exceptions enabled. If a test +throws a C++ exception or (on Windows) a structured exception (SEH), by default +googletest catches it, reports it as a test failure, and continues with the next +test method. This maximizes the coverage of a test run. Also, on Windows an +uncaught exception will cause a pop-up window, so catching the exceptions allows +you to run the tests automatically. + +When debugging the test failures, however, you may instead want the exceptions +to be handled by the debugger, such that you can examine the call stack when an +exception is thrown. To achieve that, set the `GTEST_CATCH_EXCEPTIONS` +environment variable to `0`, or use the `--gtest_catch_exceptions=0` flag when +running the tests. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/faq.md b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/faq.md new file mode 100644 index 0000000000000000000000000000000000000000..960a827989c9993a2f65758b0bc1bf73e31592c9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/faq.md @@ -0,0 +1,753 @@ +# Googletest FAQ + + + +## Why should test suite names and test names not contain underscore? + +Underscore (`_`) is special, as C++ reserves the following to be used by the +compiler and the standard library: + +1. any identifier that starts with an `_` followed by an upper-case letter, and +2. any identifier that contains two consecutive underscores (i.e. `__`) + *anywhere* in its name. + +User code is *prohibited* from using such identifiers. + +Now let's look at what this means for `TEST` and `TEST_F`. + +Currently `TEST(TestSuiteName, TestName)` generates a class named +`TestSuiteName_TestName_Test`. What happens if `TestSuiteName` or `TestName` +contains `_`? + +1. If `TestSuiteName` starts with an `_` followed by an upper-case letter (say, + `_Foo`), we end up with `_Foo_TestName_Test`, which is reserved and thus + invalid. +2. If `TestSuiteName` ends with an `_` (say, `Foo_`), we get + `Foo__TestName_Test`, which is invalid. +3. If `TestName` starts with an `_` (say, `_Bar`), we get + `TestSuiteName__Bar_Test`, which is invalid. +4. If `TestName` ends with an `_` (say, `Bar_`), we get + `TestSuiteName_Bar__Test`, which is invalid. + +So clearly `TestSuiteName` and `TestName` cannot start or end with `_` +(Actually, `TestSuiteName` can start with `_` -- as long as the `_` isn't +followed by an upper-case letter. But that's getting complicated. So for +simplicity we just say that it cannot start with `_`.). + +It may seem fine for `TestSuiteName` and `TestName` to contain `_` in the +middle. However, consider this: + +```c++ +TEST(Time, Flies_Like_An_Arrow) { ... } +TEST(Time_Flies, Like_An_Arrow) { ... } +``` + +Now, the two `TEST`s will both generate the same class +(`Time_Flies_Like_An_Arrow_Test`). That's not good. + +So for simplicity, we just ask the users to avoid `_` in `TestSuiteName` and +`TestName`. The rule is more constraining than necessary, but it's simple and +easy to remember. It also gives googletest some wiggle room in case its +implementation needs to change in the future. + +If you violate the rule, there may not be immediate consequences, but your test +may (just may) break with a new compiler (or a new version of the compiler you +are using) or with a new version of googletest. Therefore it's best to follow +the rule. + +## Why does googletest support `EXPECT_EQ(NULL, ptr)` and `ASSERT_EQ(NULL, ptr)` but not `EXPECT_NE(NULL, ptr)` and `ASSERT_NE(NULL, ptr)`? + +First of all you can use `EXPECT_NE(nullptr, ptr)` and `ASSERT_NE(nullptr, +ptr)`. This is the preferred syntax in the style guide because nullptr does not +have the type problems that NULL does. Which is why NULL does not work. + +Due to some peculiarity of C++, it requires some non-trivial template meta +programming tricks to support using `NULL` as an argument of the `EXPECT_XX()` +and `ASSERT_XX()` macros. Therefore we only do it where it's most needed +(otherwise we make the implementation of googletest harder to maintain and more +error-prone than necessary). + +The `EXPECT_EQ()` macro takes the *expected* value as its first argument and the +*actual* value as the second. It's reasonable that someone wants to write +`EXPECT_EQ(NULL, some_expression)`, and this indeed was requested several times. +Therefore we implemented it. + +The need for `EXPECT_NE(NULL, ptr)` isn't nearly as strong. When the assertion +fails, you already know that `ptr` must be `NULL`, so it doesn't add any +information to print `ptr` in this case. That means `EXPECT_TRUE(ptr != NULL)` +works just as well. + +If we were to support `EXPECT_NE(NULL, ptr)`, for consistency we'll have to +support `EXPECT_NE(ptr, NULL)` as well, as unlike `EXPECT_EQ`, we don't have a +convention on the order of the two arguments for `EXPECT_NE`. This means using +the template meta programming tricks twice in the implementation, making it even +harder to understand and maintain. We believe the benefit doesn't justify the +cost. + +Finally, with the growth of the gMock matcher library, we are encouraging people +to use the unified `EXPECT_THAT(value, matcher)` syntax more often in tests. One +significant advantage of the matcher approach is that matchers can be easily +combined to form new matchers, while the `EXPECT_NE`, etc, macros cannot be +easily combined. Therefore we want to invest more in the matchers than in the +`EXPECT_XX()` macros. + +## I need to test that different implementations of an interface satisfy some common requirements. Should I use typed tests or value-parameterized tests? + +For testing various implementations of the same interface, either typed tests or +value-parameterized tests can get it done. It's really up to you the user to +decide which is more convenient for you, depending on your particular case. Some +rough guidelines: + +* Typed tests can be easier to write if instances of the different + implementations can be created the same way, modulo the type. For example, + if all these implementations have a public default constructor (such that + you can write `new TypeParam`), or if their factory functions have the same + form (e.g. `CreateInstance()`). +* Value-parameterized tests can be easier to write if you need different code + patterns to create different implementations' instances, e.g. `new Foo` vs + `new Bar(5)`. To accommodate for the differences, you can write factory + function wrappers and pass these function pointers to the tests as their + parameters. +* When a typed test fails, the default output includes the name of the type, + which can help you quickly identify which implementation is wrong. + Value-parameterized tests only show the number of the failed iteration by + default. You will need to define a function that returns the iteration name + and pass it as the third parameter to INSTANTIATE_TEST_SUITE_P to have more + useful output. +* When using typed tests, you need to make sure you are testing against the + interface type, not the concrete types (in other words, you want to make + sure `implicit_cast(my_concrete_impl)` works, not just that + `my_concrete_impl` works). It's less likely to make mistakes in this area + when using value-parameterized tests. + +I hope I didn't confuse you more. :-) If you don't mind, I'd suggest you to give +both approaches a try. Practice is a much better way to grasp the subtle +differences between the two tools. Once you have some concrete experience, you +can much more easily decide which one to use the next time. + +## I got some run-time errors about invalid proto descriptors when using `ProtocolMessageEquals`. Help! + +**Note:** `ProtocolMessageEquals` and `ProtocolMessageEquiv` are *deprecated* +now. Please use `EqualsProto`, etc instead. + +`ProtocolMessageEquals` and `ProtocolMessageEquiv` were redefined recently and +are now less tolerant of invalid protocol buffer definitions. In particular, if +you have a `foo.proto` that doesn't fully qualify the type of a protocol message +it references (e.g. `message` where it should be `message`), you +will now get run-time errors like: + +``` +... descriptor.cc:...] Invalid proto descriptor for file "path/to/foo.proto": +... descriptor.cc:...] blah.MyMessage.my_field: ".Bar" is not defined. +``` + +If you see this, your `.proto` file is broken and needs to be fixed by making +the types fully qualified. The new definition of `ProtocolMessageEquals` and +`ProtocolMessageEquiv` just happen to reveal your bug. + +## My death test modifies some state, but the change seems lost after the death test finishes. Why? + +Death tests (`EXPECT_DEATH`, etc) are executed in a sub-process s.t. the +expected crash won't kill the test program (i.e. the parent process). As a +result, any in-memory side effects they incur are observable in their respective +sub-processes, but not in the parent process. You can think of them as running +in a parallel universe, more or less. + +In particular, if you use mocking and the death test statement invokes some mock +methods, the parent process will think the calls have never occurred. Therefore, +you may want to move your `EXPECT_CALL` statements inside the `EXPECT_DEATH` +macro. + +## EXPECT_EQ(htonl(blah), blah_blah) generates weird compiler errors in opt mode. Is this a googletest bug? + +Actually, the bug is in `htonl()`. + +According to `'man htonl'`, `htonl()` is a *function*, which means it's valid to +use `htonl` as a function pointer. However, in opt mode `htonl()` is defined as +a *macro*, which breaks this usage. + +Worse, the macro definition of `htonl()` uses a `gcc` extension and is *not* +standard C++. That hacky implementation has some ad hoc limitations. In +particular, it prevents you from writing `Foo()`, where `Foo` +is a template that has an integral argument. + +The implementation of `EXPECT_EQ(a, b)` uses `sizeof(... a ...)` inside a +template argument, and thus doesn't compile in opt mode when `a` contains a call +to `htonl()`. It is difficult to make `EXPECT_EQ` bypass the `htonl()` bug, as +the solution must work with different compilers on various platforms. + +`htonl()` has some other problems as described in `//util/endian/endian.h`, +which defines `ghtonl()` to replace it. `ghtonl()` does the same thing `htonl()` +does, only without its problems. We suggest you to use `ghtonl()` instead of +`htonl()`, both in your tests and production code. + +`//util/endian/endian.h` also defines `ghtons()`, which solves similar problems +in `htons()`. + +Don't forget to add `//util/endian` to the list of dependencies in the `BUILD` +file wherever `ghtonl()` and `ghtons()` are used. The library consists of a +single header file and will not bloat your binary. + +## The compiler complains about "undefined references" to some static const member variables, but I did define them in the class body. What's wrong? + +If your class has a static data member: + +```c++ +// foo.h +class Foo { + ... + static const int kBar = 100; +}; +``` + +You also need to define it *outside* of the class body in `foo.cc`: + +```c++ +const int Foo::kBar; // No initializer here. +``` + +Otherwise your code is **invalid C++**, and may break in unexpected ways. In +particular, using it in googletest comparison assertions (`EXPECT_EQ`, etc) will +generate an "undefined reference" linker error. The fact that "it used to work" +doesn't mean it's valid. It just means that you were lucky. :-) + +## Can I derive a test fixture from another? + +Yes. + +Each test fixture has a corresponding and same named test suite. This means only +one test suite can use a particular fixture. Sometimes, however, multiple test +cases may want to use the same or slightly different fixtures. For example, you +may want to make sure that all of a GUI library's test suites don't leak +important system resources like fonts and brushes. + +In googletest, you share a fixture among test suites by putting the shared logic +in a base test fixture, then deriving from that base a separate fixture for each +test suite that wants to use this common logic. You then use `TEST_F()` to write +tests using each derived fixture. + +Typically, your code looks like this: + +```c++ +// Defines a base test fixture. +class BaseTest : public ::testing::Test { + protected: + ... +}; + +// Derives a fixture FooTest from BaseTest. +class FooTest : public BaseTest { + protected: + void SetUp() override { + BaseTest::SetUp(); // Sets up the base fixture first. + ... additional set-up work ... + } + + void TearDown() override { + ... clean-up work for FooTest ... + BaseTest::TearDown(); // Remember to tear down the base fixture + // after cleaning up FooTest! + } + + ... functions and variables for FooTest ... +}; + +// Tests that use the fixture FooTest. +TEST_F(FooTest, Bar) { ... } +TEST_F(FooTest, Baz) { ... } + +... additional fixtures derived from BaseTest ... +``` + +If necessary, you can continue to derive test fixtures from a derived fixture. +googletest has no limit on how deep the hierarchy can be. + +For a complete example using derived test fixtures, see +[sample5_unittest.cc](../samples/sample5_unittest.cc). + +## My compiler complains "void value not ignored as it ought to be." What does this mean? + +You're probably using an `ASSERT_*()` in a function that doesn't return `void`. +`ASSERT_*()` can only be used in `void` functions, due to exceptions being +disabled by our build system. Please see more details +[here](advanced.md#assertion-placement). + +## My death test hangs (or seg-faults). How do I fix it? + +In googletest, death tests are run in a child process and the way they work is +delicate. To write death tests you really need to understand how they work. +Please make sure you have read [this](advanced.md#how-it-works). + +In particular, death tests don't like having multiple threads in the parent +process. So the first thing you can try is to eliminate creating threads outside +of `EXPECT_DEATH()`. For example, you may want to use mocks or fake objects +instead of real ones in your tests. + +Sometimes this is impossible as some library you must use may be creating +threads before `main()` is even reached. In this case, you can try to minimize +the chance of conflicts by either moving as many activities as possible inside +`EXPECT_DEATH()` (in the extreme case, you want to move everything inside), or +leaving as few things as possible in it. Also, you can try to set the death test +style to `"threadsafe"`, which is safer but slower, and see if it helps. + +If you go with thread-safe death tests, remember that they rerun the test +program from the beginning in the child process. Therefore make sure your +program can run side-by-side with itself and is deterministic. + +In the end, this boils down to good concurrent programming. You have to make +sure that there is no race conditions or dead locks in your program. No silver +bullet - sorry! + +## Should I use the constructor/destructor of the test fixture or SetUp()/TearDown()? {#CtorVsSetUp} + +The first thing to remember is that googletest does **not** reuse the same test +fixture object across multiple tests. For each `TEST_F`, googletest will create +a **fresh** test fixture object, immediately call `SetUp()`, run the test body, +call `TearDown()`, and then delete the test fixture object. + +When you need to write per-test set-up and tear-down logic, you have the choice +between using the test fixture constructor/destructor or `SetUp()/TearDown()`. +The former is usually preferred, as it has the following benefits: + +* By initializing a member variable in the constructor, we have the option to + make it `const`, which helps prevent accidental changes to its value and + makes the tests more obviously correct. +* In case we need to subclass the test fixture class, the subclass' + constructor is guaranteed to call the base class' constructor *first*, and + the subclass' destructor is guaranteed to call the base class' destructor + *afterward*. With `SetUp()/TearDown()`, a subclass may make the mistake of + forgetting to call the base class' `SetUp()/TearDown()` or call them at the + wrong time. + +You may still want to use `SetUp()/TearDown()` in the following cases: + +* C++ does not allow virtual function calls in constructors and destructors. + You can call a method declared as virtual, but it will not use dynamic + dispatch, it will use the definition from the class the constructor of which + is currently executing. This is because calling a virtual method before the + derived class constructor has a chance to run is very dangerous - the + virtual method might operate on uninitialized data. Therefore, if you need + to call a method that will be overridden in a derived class, you have to use + `SetUp()/TearDown()`. +* In the body of a constructor (or destructor), it's not possible to use the + `ASSERT_xx` macros. Therefore, if the set-up operation could cause a fatal + test failure that should prevent the test from running, it's necessary to + use `abort` and abort the whole test executable, + or to use `SetUp()` instead of a constructor. +* If the tear-down operation could throw an exception, you must use + `TearDown()` as opposed to the destructor, as throwing in a destructor leads + to undefined behavior and usually will kill your program right away. Note + that many standard libraries (like STL) may throw when exceptions are + enabled in the compiler. Therefore you should prefer `TearDown()` if you + want to write portable tests that work with or without exceptions. +* The googletest team is considering making the assertion macros throw on + platforms where exceptions are enabled (e.g. Windows, Mac OS, and Linux + client-side), which will eliminate the need for the user to propagate + failures from a subroutine to its caller. Therefore, you shouldn't use + googletest assertions in a destructor if your code could run on such a + platform. + +## The compiler complains "no matching function to call" when I use ASSERT_PRED*. How do I fix it? + +If the predicate function you use in `ASSERT_PRED*` or `EXPECT_PRED*` is +overloaded or a template, the compiler will have trouble figuring out which +overloaded version it should use. `ASSERT_PRED_FORMAT*` and +`EXPECT_PRED_FORMAT*` don't have this problem. + +If you see this error, you might want to switch to +`(ASSERT|EXPECT)_PRED_FORMAT*`, which will also give you a better failure +message. If, however, that is not an option, you can resolve the problem by +explicitly telling the compiler which version to pick. + +For example, suppose you have + +```c++ +bool IsPositive(int n) { + return n > 0; +} + +bool IsPositive(double x) { + return x > 0; +} +``` + +you will get a compiler error if you write + +```c++ +EXPECT_PRED1(IsPositive, 5); +``` + +However, this will work: + +```c++ +EXPECT_PRED1(static_cast(IsPositive), 5); +``` + +(The stuff inside the angled brackets for the `static_cast` operator is the type +of the function pointer for the `int`-version of `IsPositive()`.) + +As another example, when you have a template function + +```c++ +template +bool IsNegative(T x) { + return x < 0; +} +``` + +you can use it in a predicate assertion like this: + +```c++ +ASSERT_PRED1(IsNegative, -5); +``` + +Things are more interesting if your template has more than one parameters. The +following won't compile: + +```c++ +ASSERT_PRED2(GreaterThan, 5, 0); +``` + +as the C++ pre-processor thinks you are giving `ASSERT_PRED2` 4 arguments, which +is one more than expected. The workaround is to wrap the predicate function in +parentheses: + +```c++ +ASSERT_PRED2((GreaterThan), 5, 0); +``` + +## My compiler complains about "ignoring return value" when I call RUN_ALL_TESTS(). Why? + +Some people had been ignoring the return value of `RUN_ALL_TESTS()`. That is, +instead of + +```c++ + return RUN_ALL_TESTS(); +``` + +they write + +```c++ + RUN_ALL_TESTS(); +``` + +This is **wrong and dangerous**. The testing services needs to see the return +value of `RUN_ALL_TESTS()` in order to determine if a test has passed. If your +`main()` function ignores it, your test will be considered successful even if it +has a googletest assertion failure. Very bad. + +We have decided to fix this (thanks to Michael Chastain for the idea). Now, your +code will no longer be able to ignore `RUN_ALL_TESTS()` when compiled with +`gcc`. If you do so, you'll get a compiler error. + +If you see the compiler complaining about you ignoring the return value of +`RUN_ALL_TESTS()`, the fix is simple: just make sure its value is used as the +return value of `main()`. + +But how could we introduce a change that breaks existing tests? Well, in this +case, the code was already broken in the first place, so we didn't break it. :-) + +## My compiler complains that a constructor (or destructor) cannot return a value. What's going on? + +Due to a peculiarity of C++, in order to support the syntax for streaming +messages to an `ASSERT_*`, e.g. + +```c++ + ASSERT_EQ(1, Foo()) << "blah blah" << foo; +``` + +we had to give up using `ASSERT*` and `FAIL*` (but not `EXPECT*` and +`ADD_FAILURE*`) in constructors and destructors. The workaround is to move the +content of your constructor/destructor to a private void member function, or +switch to `EXPECT_*()` if that works. This +[section](advanced.md#assertion-placement) in the user's guide explains it. + +## My SetUp() function is not called. Why? + +C++ is case-sensitive. Did you spell it as `Setup()`? + +Similarly, sometimes people spell `SetUpTestSuite()` as `SetupTestSuite()` and +wonder why it's never called. + + +## I have several test suites which share the same test fixture logic, do I have to define a new test fixture class for each of them? This seems pretty tedious. + +You don't have to. Instead of + +```c++ +class FooTest : public BaseTest {}; + +TEST_F(FooTest, Abc) { ... } +TEST_F(FooTest, Def) { ... } + +class BarTest : public BaseTest {}; + +TEST_F(BarTest, Abc) { ... } +TEST_F(BarTest, Def) { ... } +``` + +you can simply `typedef` the test fixtures: + +```c++ +typedef BaseTest FooTest; + +TEST_F(FooTest, Abc) { ... } +TEST_F(FooTest, Def) { ... } + +typedef BaseTest BarTest; + +TEST_F(BarTest, Abc) { ... } +TEST_F(BarTest, Def) { ... } +``` + +## googletest output is buried in a whole bunch of LOG messages. What do I do? + +The googletest output is meant to be a concise and human-friendly report. If +your test generates textual output itself, it will mix with the googletest +output, making it hard to read. However, there is an easy solution to this +problem. + +Since `LOG` messages go to stderr, we decided to let googletest output go to +stdout. This way, you can easily separate the two using redirection. For +example: + +```shell +$ ./my_test > gtest_output.txt +``` + +## Why should I prefer test fixtures over global variables? + +There are several good reasons: + +1. It's likely your test needs to change the states of its global variables. + This makes it difficult to keep side effects from escaping one test and + contaminating others, making debugging difficult. By using fixtures, each + test has a fresh set of variables that's different (but with the same + names). Thus, tests are kept independent of each other. +2. Global variables pollute the global namespace. +3. Test fixtures can be reused via subclassing, which cannot be done easily + with global variables. This is useful if many test suites have something in + common. + +## What can the statement argument in ASSERT_DEATH() be? + +`ASSERT_DEATH(*statement*, *regex*)` (or any death assertion macro) can be used +wherever `*statement*` is valid. So basically `*statement*` can be any C++ +statement that makes sense in the current context. In particular, it can +reference global and/or local variables, and can be: + +* a simple function call (often the case), +* a complex expression, or +* a compound statement. + +Some examples are shown here: + +```c++ +// A death test can be a simple function call. +TEST(MyDeathTest, FunctionCall) { + ASSERT_DEATH(Xyz(5), "Xyz failed"); +} + +// Or a complex expression that references variables and functions. +TEST(MyDeathTest, ComplexExpression) { + const bool c = Condition(); + ASSERT_DEATH((c ? Func1(0) : object2.Method("test")), + "(Func1|Method) failed"); +} + +// Death assertions can be used any where in a function. In +// particular, they can be inside a loop. +TEST(MyDeathTest, InsideLoop) { + // Verifies that Foo(0), Foo(1), ..., and Foo(4) all die. + for (int i = 0; i < 5; i++) { + EXPECT_DEATH_M(Foo(i), "Foo has \\d+ errors", + ::testing::Message() << "where i is " << i); + } +} + +// A death assertion can contain a compound statement. +TEST(MyDeathTest, CompoundStatement) { + // Verifies that at lease one of Bar(0), Bar(1), ..., and + // Bar(4) dies. + ASSERT_DEATH({ + for (int i = 0; i < 5; i++) { + Bar(i); + } + }, + "Bar has \\d+ errors"); +} +``` + +gtest-death-test_test.cc contains more examples if you are interested. + +## I have a fixture class `FooTest`, but `TEST_F(FooTest, Bar)` gives me error ``"no matching function for call to `FooTest::FooTest()'"``. Why? + +Googletest needs to be able to create objects of your test fixture class, so it +must have a default constructor. Normally the compiler will define one for you. +However, there are cases where you have to define your own: + +* If you explicitly declare a non-default constructor for class `FooTest` + (`DISALLOW_EVIL_CONSTRUCTORS()` does this), then you need to define a + default constructor, even if it would be empty. +* If `FooTest` has a const non-static data member, then you have to define the + default constructor *and* initialize the const member in the initializer + list of the constructor. (Early versions of `gcc` doesn't force you to + initialize the const member. It's a bug that has been fixed in `gcc 4`.) + +## Why does ASSERT_DEATH complain about previous threads that were already joined? + +With the Linux pthread library, there is no turning back once you cross the line +from single thread to multiple threads. The first time you create a thread, a +manager thread is created in addition, so you get 3, not 2, threads. Later when +the thread you create joins the main thread, the thread count decrements by 1, +but the manager thread will never be killed, so you still have 2 threads, which +means you cannot safely run a death test. + +The new NPTL thread library doesn't suffer from this problem, as it doesn't +create a manager thread. However, if you don't control which machine your test +runs on, you shouldn't depend on this. + +## Why does googletest require the entire test suite, instead of individual tests, to be named *DeathTest when it uses ASSERT_DEATH? + +googletest does not interleave tests from different test suites. That is, it +runs all tests in one test suite first, and then runs all tests in the next test +suite, and so on. googletest does this because it needs to set up a test suite +before the first test in it is run, and tear it down afterwords. Splitting up +the test case would require multiple set-up and tear-down processes, which is +inefficient and makes the semantics unclean. + +If we were to determine the order of tests based on test name instead of test +case name, then we would have a problem with the following situation: + +```c++ +TEST_F(FooTest, AbcDeathTest) { ... } +TEST_F(FooTest, Uvw) { ... } + +TEST_F(BarTest, DefDeathTest) { ... } +TEST_F(BarTest, Xyz) { ... } +``` + +Since `FooTest.AbcDeathTest` needs to run before `BarTest.Xyz`, and we don't +interleave tests from different test suites, we need to run all tests in the +`FooTest` case before running any test in the `BarTest` case. This contradicts +with the requirement to run `BarTest.DefDeathTest` before `FooTest.Uvw`. + +## But I don't like calling my entire test suite \*DeathTest when it contains both death tests and non-death tests. What do I do? + +You don't have to, but if you like, you may split up the test suite into +`FooTest` and `FooDeathTest`, where the names make it clear that they are +related: + +```c++ +class FooTest : public ::testing::Test { ... }; + +TEST_F(FooTest, Abc) { ... } +TEST_F(FooTest, Def) { ... } + +using FooDeathTest = FooTest; + +TEST_F(FooDeathTest, Uvw) { ... EXPECT_DEATH(...) ... } +TEST_F(FooDeathTest, Xyz) { ... ASSERT_DEATH(...) ... } +``` + +## googletest prints the LOG messages in a death test's child process only when the test fails. How can I see the LOG messages when the death test succeeds? + +Printing the LOG messages generated by the statement inside `EXPECT_DEATH()` +makes it harder to search for real problems in the parent's log. Therefore, +googletest only prints them when the death test has failed. + +If you really need to see such LOG messages, a workaround is to temporarily +break the death test (e.g. by changing the regex pattern it is expected to +match). Admittedly, this is a hack. We'll consider a more permanent solution +after the fork-and-exec-style death tests are implemented. + +## The compiler complains about "no match for 'operator<<'" when I use an assertion. What gives? + +If you use a user-defined type `FooType` in an assertion, you must make sure +there is an `std::ostream& operator<<(std::ostream&, const FooType&)` function +defined such that we can print a value of `FooType`. + +In addition, if `FooType` is declared in a name space, the `<<` operator also +needs to be defined in the *same* name space. See https://abseil.io/tips/49 for details. + +## How do I suppress the memory leak messages on Windows? + +Since the statically initialized googletest singleton requires allocations on +the heap, the Visual C++ memory leak detector will report memory leaks at the +end of the program run. The easiest way to avoid this is to use the +`_CrtMemCheckpoint` and `_CrtMemDumpAllObjectsSince` calls to not report any +statically initialized heap objects. See MSDN for more details and additional +heap check/debug routines. + +## How can my code detect if it is running in a test? + +If you write code that sniffs whether it's running in a test and does different +things accordingly, you are leaking test-only logic into production code and +there is no easy way to ensure that the test-only code paths aren't run by +mistake in production. Such cleverness also leads to +[Heisenbugs](https://en.wikipedia.org/wiki/Heisenbug). Therefore we strongly +advise against the practice, and googletest doesn't provide a way to do it. + +In general, the recommended way to cause the code to behave differently under +test is [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection). You can inject +different functionality from the test and from the production code. Since your +production code doesn't link in the for-test logic at all (the +[`testonly`](https://docs.bazel.build/versions/master/be/common-definitions.html#common.testonly) attribute for BUILD targets helps to ensure +that), there is no danger in accidentally running it. + +However, if you *really*, *really*, *really* have no choice, and if you follow +the rule of ending your test program names with `_test`, you can use the +*horrible* hack of sniffing your executable name (`argv[0]` in `main()`) to know +whether the code is under test. + +## How do I temporarily disable a test? + +If you have a broken test that you cannot fix right away, you can add the +DISABLED_ prefix to its name. This will exclude it from execution. This is +better than commenting out the code or using #if 0, as disabled tests are still +compiled (and thus won't rot). + +To include disabled tests in test execution, just invoke the test program with +the --gtest_also_run_disabled_tests flag. + +## Is it OK if I have two separate `TEST(Foo, Bar)` test methods defined in different namespaces? + +Yes. + +The rule is **all test methods in the same test suite must use the same fixture +class.** This means that the following is **allowed** because both tests use the +same fixture class (`::testing::Test`). + +```c++ +namespace foo { +TEST(CoolTest, DoSomething) { + SUCCEED(); +} +} // namespace foo + +namespace bar { +TEST(CoolTest, DoSomething) { + SUCCEED(); +} +} // namespace bar +``` + +However, the following code is **not allowed** and will produce a runtime error +from googletest because the test methods are using different test fixture +classes with the same test suite name. + +```c++ +namespace foo { +class CoolTest : public ::testing::Test {}; // Fixture foo::CoolTest +TEST_F(CoolTest, DoSomething) { + SUCCEED(); +} +} // namespace foo + +namespace bar { +class CoolTest : public ::testing::Test {}; // Fixture: bar::CoolTest +TEST_F(CoolTest, DoSomething) { + SUCCEED(); +} +} // namespace bar +``` diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/pkgconfig.md b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/pkgconfig.md new file mode 100644 index 0000000000000000000000000000000000000000..6dc0673889c43d03fc66564b4f64510143688820 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/pkgconfig.md @@ -0,0 +1,141 @@ +## Using GoogleTest from various build systems + +GoogleTest comes with pkg-config files that can be used to determine all +necessary flags for compiling and linking to GoogleTest (and GoogleMock). +Pkg-config is a standardised plain-text format containing + +* the includedir (-I) path +* necessary macro (-D) definitions +* further required flags (-pthread) +* the library (-L) path +* the library (-l) to link to + +All current build systems support pkg-config in one way or another. For all +examples here we assume you want to compile the sample +`samples/sample3_unittest.cc`. + +### CMake + +Using `pkg-config` in CMake is fairly easy: + +```cmake +cmake_minimum_required(VERSION 3.0) + +cmake_policy(SET CMP0048 NEW) +project(my_gtest_pkgconfig VERSION 0.0.1 LANGUAGES CXX) + +find_package(PkgConfig) +pkg_search_module(GTEST REQUIRED gtest_main) + +add_executable(testapp samples/sample3_unittest.cc) +target_link_libraries(testapp ${GTEST_LDFLAGS}) +target_compile_options(testapp PUBLIC ${GTEST_CFLAGS}) + +include(CTest) +add_test(first_and_only_test testapp) +``` + +It is generally recommended that you use `target_compile_options` + `_CFLAGS` +over `target_include_directories` + `_INCLUDE_DIRS` as the former includes not +just -I flags (GoogleTest might require a macro indicating to internal headers +that all libraries have been compiled with threading enabled. In addition, +GoogleTest might also require `-pthread` in the compiling step, and as such +splitting the pkg-config `Cflags` variable into include dirs and macros for +`target_compile_definitions()` might still miss this). The same recommendation +goes for using `_LDFLAGS` over the more commonplace `_LIBRARIES`, which happens +to discard `-L` flags and `-pthread`. + +### Autotools + +Finding GoogleTest in Autoconf and using it from Automake is also fairly easy: + +In your `configure.ac`: + +``` +AC_PREREQ([2.69]) +AC_INIT([my_gtest_pkgconfig], [0.0.1]) +AC_CONFIG_SRCDIR([samples/sample3_unittest.cc]) +AC_PROG_CXX + +PKG_CHECK_MODULES([GTEST], [gtest_main]) + +AM_INIT_AUTOMAKE([foreign subdir-objects]) +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT +``` + +and in your `Makefile.am`: + +``` +check_PROGRAMS = testapp +TESTS = $(check_PROGRAMS) + +testapp_SOURCES = samples/sample3_unittest.cc +testapp_CXXFLAGS = $(GTEST_CFLAGS) +testapp_LDADD = $(GTEST_LIBS) +``` + +### Meson + +Meson natively uses pkgconfig to query dependencies: + +``` +project('my_gtest_pkgconfig', 'cpp', version : '0.0.1') + +gtest_dep = dependency('gtest_main') + +testapp = executable( + 'testapp', + files(['samples/sample3_unittest.cc']), + dependencies : gtest_dep, + install : false) + +test('first_and_only_test', testapp) +``` + +### Plain Makefiles + +Since `pkg-config` is a small Unix command-line utility, it can be used in +handwritten `Makefile`s too: + +```makefile +GTEST_CFLAGS = `pkg-config --cflags gtest_main` +GTEST_LIBS = `pkg-config --libs gtest_main` + +.PHONY: tests all + +tests: all + ./testapp + +all: testapp + +testapp: testapp.o + $(CXX) $(CXXFLAGS) $(LDFLAGS) $< -o $@ $(GTEST_LIBS) + +testapp.o: samples/sample3_unittest.cc + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $< -c -o $@ $(GTEST_CFLAGS) +``` + +### Help! pkg-config can't find GoogleTest! + +Let's say you have a `CMakeLists.txt` along the lines of the one in this +tutorial and you try to run `cmake`. It is very possible that you get a failure +along the lines of: + +``` +-- Checking for one of the modules 'gtest_main' +CMake Error at /usr/share/cmake/Modules/FindPkgConfig.cmake:640 (message): + None of the required 'gtest_main' found +``` + +These failures are common if you installed GoogleTest yourself and have not +sourced it from a distro or other package manager. If so, you need to tell +pkg-config where it can find the `.pc` files containing the information. Say you +installed GoogleTest to `/usr/local`, then it might be that the `.pc` files are +installed under `/usr/local/lib64/pkgconfig`. If you set + +``` +export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig +``` + +pkg-config will also try to look in `PKG_CONFIG_PATH` to find `gtest_main.pc`. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/primer.md b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/primer.md new file mode 100644 index 0000000000000000000000000000000000000000..0317692bbb0f041b1d120eae18dfb446755ae393 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/primer.md @@ -0,0 +1,567 @@ +# Googletest Primer + +## Introduction: Why googletest? + +*googletest* helps you write better C++ tests. + +googletest is a testing framework developed by the Testing Technology team with +Google's specific requirements and constraints in mind. Whether you work on +Linux, Windows, or a Mac, if you write C++ code, googletest can help you. And it +supports *any* kind of tests, not just unit tests. + +So what makes a good test, and how does googletest fit in? We believe: + +1. Tests should be *independent* and *repeatable*. It's a pain to debug a test + that succeeds or fails as a result of other tests. googletest isolates the + tests by running each of them on a different object. When a test fails, + googletest allows you to run it in isolation for quick debugging. +2. Tests should be well *organized* and reflect the structure of the tested + code. googletest groups related tests into test suites that can share data + and subroutines. This common pattern is easy to recognize and makes tests + easy to maintain. Such consistency is especially helpful when people switch + projects and start to work on a new code base. +3. Tests should be *portable* and *reusable*. Google has a lot of code that is + platform-neutral; its tests should also be platform-neutral. googletest + works on different OSes, with different compilers, with or without + exceptions, so googletest tests can work with a variety of configurations. +4. When tests fail, they should provide as much *information* about the problem + as possible. googletest doesn't stop at the first test failure. Instead, it + only stops the current test and continues with the next. You can also set up + tests that report non-fatal failures after which the current test continues. + Thus, you can detect and fix multiple bugs in a single run-edit-compile + cycle. +5. The testing framework should liberate test writers from housekeeping chores + and let them focus on the test *content*. googletest automatically keeps + track of all tests defined, and doesn't require the user to enumerate them + in order to run them. +6. Tests should be *fast*. With googletest, you can reuse shared resources + across tests and pay for the set-up/tear-down only once, without making + tests depend on each other. + +Since googletest is based on the popular xUnit architecture, you'll feel right +at home if you've used JUnit or PyUnit before. If not, it will take you about 10 +minutes to learn the basics and get started. So let's go! + +## Beware of the nomenclature + +_Note:_ There might be some confusion arising from different definitions of the +terms _Test_, _Test Case_ and _Test Suite_, so beware of misunderstanding these. + +Historically, googletest started to use the term _Test Case_ for grouping +related tests, whereas current publications, including International Software +Testing Qualifications Board ([ISTQB](http://www.istqb.org/)) materials and +various textbooks on software quality, use the term +_[Test Suite][istqb test suite]_ for this. + +The related term _Test_, as it is used in googletest, corresponds to the term +_[Test Case][istqb test case]_ of ISTQB and others. + +The term _Test_ is commonly of broad enough sense, including ISTQB's definition +of _Test Case_, so it's not much of a problem here. But the term _Test Case_ as +was used in Google Test is of contradictory sense and thus confusing. + +googletest recently started replacing the term _Test Case_ with _Test Suite_. +The preferred API is *TestSuite*. The older TestCase API is being slowly +deprecated and refactored away. + +So please be aware of the different definitions of the terms: + + + +Meaning | googletest Term | [ISTQB](http://www.istqb.org/) Term +:----------------------------------------------------------------------------------- | :---------------------- | :---------------------------------- +Exercise a particular program path with specific input values and verify the results | [TEST()](#simple-tests) | [Test Case][istqb test case] + + + +[istqb test case]: http://glossary.istqb.org/en/search/test%20case +[istqb test suite]: http://glossary.istqb.org/en/search/test%20suite + +## Basic Concepts + +When using googletest, you start by writing *assertions*, which are statements +that check whether a condition is true. An assertion's result can be *success*, +*nonfatal failure*, or *fatal failure*. If a fatal failure occurs, it aborts the +current function; otherwise the program continues normally. + +*Tests* use assertions to verify the tested code's behavior. If a test crashes +or has a failed assertion, then it *fails*; otherwise it *succeeds*. + +A *test suite* contains one or many tests. You should group your tests into test +suites that reflect the structure of the tested code. When multiple tests in a +test suite need to share common objects and subroutines, you can put them into a +*test fixture* class. + +A *test program* can contain multiple test suites. + +We'll now explain how to write a test program, starting at the individual +assertion level and building up to tests and test suites. + +## Assertions + +googletest assertions are macros that resemble function calls. You test a class +or function by making assertions about its behavior. When an assertion fails, +googletest prints the assertion's source file and line number location, along +with a failure message. You may also supply a custom failure message which will +be appended to googletest's message. + +The assertions come in pairs that test the same thing but have different effects +on the current function. `ASSERT_*` versions generate fatal failures when they +fail, and **abort the current function**. `EXPECT_*` versions generate nonfatal +failures, which don't abort the current function. Usually `EXPECT_*` are +preferred, as they allow more than one failure to be reported in a test. +However, you should use `ASSERT_*` if it doesn't make sense to continue when the +assertion in question fails. + +Since a failed `ASSERT_*` returns from the current function immediately, +possibly skipping clean-up code that comes after it, it may cause a space leak. +Depending on the nature of the leak, it may or may not be worth fixing - so keep +this in mind if you get a heap checker error in addition to assertion errors. + +To provide a custom failure message, simply stream it into the macro using the +`<<` operator or a sequence of such operators. An example: + +```c++ +ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length"; + +for (int i = 0; i < x.size(); ++i) { + EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i; +} +``` + +Anything that can be streamed to an `ostream` can be streamed to an assertion +macro--in particular, C strings and `string` objects. If a wide string +(`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is +streamed to an assertion, it will be translated to UTF-8 when printed. + +### Basic Assertions + +These assertions do basic true/false condition testing. + +Fatal assertion | Nonfatal assertion | Verifies +-------------------------- | -------------------------- | -------------------- +`ASSERT_TRUE(condition);` | `EXPECT_TRUE(condition);` | `condition` is true +`ASSERT_FALSE(condition);` | `EXPECT_FALSE(condition);` | `condition` is false + +Remember, when they fail, `ASSERT_*` yields a fatal failure and returns from the +current function, while `EXPECT_*` yields a nonfatal failure, allowing the +function to continue running. In either case, an assertion failure means its +containing test fails. + +**Availability**: Linux, Windows, Mac. + +### Binary Comparison + +This section describes assertions that compare two values. + +Fatal assertion | Nonfatal assertion | Verifies +------------------------ | ------------------------ | -------------- +`ASSERT_EQ(val1, val2);` | `EXPECT_EQ(val1, val2);` | `val1 == val2` +`ASSERT_NE(val1, val2);` | `EXPECT_NE(val1, val2);` | `val1 != val2` +`ASSERT_LT(val1, val2);` | `EXPECT_LT(val1, val2);` | `val1 < val2` +`ASSERT_LE(val1, val2);` | `EXPECT_LE(val1, val2);` | `val1 <= val2` +`ASSERT_GT(val1, val2);` | `EXPECT_GT(val1, val2);` | `val1 > val2` +`ASSERT_GE(val1, val2);` | `EXPECT_GE(val1, val2);` | `val1 >= val2` + +Value arguments must be comparable by the assertion's comparison operator or +you'll get a compiler error. We used to require the arguments to support the +`<<` operator for streaming to an `ostream`, but this is no longer necessary. If +`<<` is supported, it will be called to print the arguments when the assertion +fails; otherwise googletest will attempt to print them in the best way it can. +For more details and how to customize the printing of the arguments, see the +[documentation](../../googlemock/docs/cook_book.md#teaching-gmock-how-to-print-your-values). + +These assertions can work with a user-defined type, but only if you define the +corresponding comparison operator (e.g., `==` or `<`). Since this is discouraged +by the Google +[C++ Style Guide](https://google.github.io/styleguide/cppguide.html#Operator_Overloading), +you may need to use `ASSERT_TRUE()` or `EXPECT_TRUE()` to assert the equality of +two objects of a user-defined type. + +However, when possible, `ASSERT_EQ(actual, expected)` is preferred to +`ASSERT_TRUE(actual == expected)`, since it tells you `actual` and `expected`'s +values on failure. + +Arguments are always evaluated exactly once. Therefore, it's OK for the +arguments to have side effects. However, as with any ordinary C/C++ function, +the arguments' evaluation order is undefined (i.e., the compiler is free to +choose any order), and your code should not depend on any particular argument +evaluation order. + +`ASSERT_EQ()` does pointer equality on pointers. If used on two C strings, it +tests if they are in the same memory location, not if they have the same value. +Therefore, if you want to compare C strings (e.g. `const char*`) by value, use +`ASSERT_STREQ()`, which will be described later on. In particular, to assert +that a C string is `NULL`, use `ASSERT_STREQ(c_string, NULL)`. Consider using +`ASSERT_EQ(c_string, nullptr)` if c++11 is supported. To compare two `string` +objects, you should use `ASSERT_EQ`. + +When doing pointer comparisons use `*_EQ(ptr, nullptr)` and `*_NE(ptr, nullptr)` +instead of `*_EQ(ptr, NULL)` and `*_NE(ptr, NULL)`. This is because `nullptr` is +typed, while `NULL` is not. See the [FAQ](faq.md) for more details. + +If you're working with floating point numbers, you may want to use the floating +point variations of some of these macros in order to avoid problems caused by +rounding. See [Advanced googletest Topics](advanced.md) for details. + +Macros in this section work with both narrow and wide string objects (`string` +and `wstring`). + +**Availability**: Linux, Windows, Mac. + +**Historical note**: Before February 2016 `*_EQ` had a convention of calling it +as `ASSERT_EQ(expected, actual)`, so lots of existing code uses this order. Now +`*_EQ` treats both parameters in the same way. + +### String Comparison + +The assertions in this group compare two **C strings**. If you want to compare +two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead. + + + +| Fatal assertion | Nonfatal assertion | Verifies | +| -------------------------- | ------------------------------ | -------------------------------------------------------- | +| `ASSERT_STREQ(str1,str2);` | `EXPECT_STREQ(str1,str2);` | the two C strings have the same content | +| `ASSERT_STRNE(str1,str2);` | `EXPECT_STRNE(str1,str2);` | the two C strings have different contents | +| `ASSERT_STRCASEEQ(str1,str2);` | `EXPECT_STRCASEEQ(str1,str2);` | the two C strings have the same content, ignoring case | +| `ASSERT_STRCASENE(str1,str2);` | `EXPECT_STRCASENE(str1,str2);` | the two C strings have different contents, ignoring case | + + + +Note that "CASE" in an assertion name means that case is ignored. A `NULL` +pointer and an empty string are considered *different*. + +`*STREQ*` and `*STRNE*` also accept wide C strings (`wchar_t*`). If a comparison +of two wide strings fails, their values will be printed as UTF-8 narrow strings. + +**Availability**: Linux, Windows, Mac. + +**See also**: For more string comparison tricks (substring, prefix, suffix, and +regular expression matching, for example), see [this](advanced.md) in the +Advanced googletest Guide. + +## Simple Tests + +To create a test: + +1. Use the `TEST()` macro to define and name a test function. These are + ordinary C++ functions that don't return a value. +2. In this function, along with any valid C++ statements you want to include, + use the various googletest assertions to check values. +3. The test's result is determined by the assertions; if any assertion in the + test fails (either fatally or non-fatally), or if the test crashes, the + entire test fails. Otherwise, it succeeds. + +```c++ +TEST(TestSuiteName, TestName) { + ... test body ... +} +``` + +`TEST()` arguments go from general to specific. The *first* argument is the name +of the test suite, and the *second* argument is the test's name within the test +case. Both names must be valid C++ identifiers, and they should not contain +any underscores (`_`). A test's *full name* consists of its containing test suite and +its individual name. Tests from different test suites can have the same +individual name. + +For example, let's take a simple integer function: + +```c++ +int Factorial(int n); // Returns the factorial of n +``` + +A test suite for this function might look like: + +```c++ +// Tests factorial of 0. +TEST(FactorialTest, HandlesZeroInput) { + EXPECT_EQ(Factorial(0), 1); +} + +// Tests factorial of positive numbers. +TEST(FactorialTest, HandlesPositiveInput) { + EXPECT_EQ(Factorial(1), 1); + EXPECT_EQ(Factorial(2), 2); + EXPECT_EQ(Factorial(3), 6); + EXPECT_EQ(Factorial(8), 40320); +} +``` + +googletest groups the test results by test suites, so logically related tests +should be in the same test suite; in other words, the first argument to their +`TEST()` should be the same. In the above example, we have two tests, +`HandlesZeroInput` and `HandlesPositiveInput`, that belong to the same test +suite `FactorialTest`. + +When naming your test suites and tests, you should follow the same convention as +for +[naming functions and classes](https://google.github.io/styleguide/cppguide.html#Function_Names). + +**Availability**: Linux, Windows, Mac. + +## Test Fixtures: Using the Same Data Configuration for Multiple Tests {#same-data-multiple-tests} + +If you find yourself writing two or more tests that operate on similar data, you +can use a *test fixture*. This allows you to reuse the same configuration of +objects for several different tests. + +To create a fixture: + +1. Derive a class from `::testing::Test` . Start its body with `protected:`, as + we'll want to access fixture members from sub-classes. +2. Inside the class, declare any objects you plan to use. +3. If necessary, write a default constructor or `SetUp()` function to prepare + the objects for each test. A common mistake is to spell `SetUp()` as + **`Setup()`** with a small `u` - Use `override` in C++11 to make sure you + spelled it correctly. +4. If necessary, write a destructor or `TearDown()` function to release any + resources you allocated in `SetUp()` . To learn when you should use the + constructor/destructor and when you should use `SetUp()/TearDown()`, read + the [FAQ](faq.md#CtorVsSetUp). +5. If needed, define subroutines for your tests to share. + +When using a fixture, use `TEST_F()` instead of `TEST()` as it allows you to +access objects and subroutines in the test fixture: + +```c++ +TEST_F(TestFixtureName, TestName) { + ... test body ... +} +``` + +Like `TEST()`, the first argument is the test suite name, but for `TEST_F()` +this must be the name of the test fixture class. You've probably guessed: `_F` +is for fixture. + +Unfortunately, the C++ macro system does not allow us to create a single macro +that can handle both types of tests. Using the wrong macro causes a compiler +error. + +Also, you must first define a test fixture class before using it in a +`TEST_F()`, or you'll get the compiler error "`virtual outside class +declaration`". + +For each test defined with `TEST_F()`, googletest will create a *fresh* test +fixture at runtime, immediately initialize it via `SetUp()`, run the test, +clean up by calling `TearDown()`, and then delete the test fixture. Note that +different tests in the same test suite have different test fixture objects, and +googletest always deletes a test fixture before it creates the next one. +googletest does **not** reuse the same test fixture for multiple tests. Any +changes one test makes to the fixture do not affect other tests. + +As an example, let's write tests for a FIFO queue class named `Queue`, which has +the following interface: + +```c++ +template // E is the element type. +class Queue { + public: + Queue(); + void Enqueue(const E& element); + E* Dequeue(); // Returns NULL if the queue is empty. + size_t size() const; + ... +}; +``` + +First, define a fixture class. By convention, you should give it the name +`FooTest` where `Foo` is the class being tested. + +```c++ +class QueueTest : public ::testing::Test { + protected: + void SetUp() override { + q1_.Enqueue(1); + q2_.Enqueue(2); + q2_.Enqueue(3); + } + + // void TearDown() override {} + + Queue q0_; + Queue q1_; + Queue q2_; +}; +``` + +In this case, `TearDown()` is not needed since we don't have to clean up after +each test, other than what's already done by the destructor. + +Now we'll write tests using `TEST_F()` and this fixture. + +```c++ +TEST_F(QueueTest, IsEmptyInitially) { + EXPECT_EQ(q0_.size(), 0); +} + +TEST_F(QueueTest, DequeueWorks) { + int* n = q0_.Dequeue(); + EXPECT_EQ(n, nullptr); + + n = q1_.Dequeue(); + ASSERT_NE(n, nullptr); + EXPECT_EQ(*n, 1); + EXPECT_EQ(q1_.size(), 0); + delete n; + + n = q2_.Dequeue(); + ASSERT_NE(n, nullptr); + EXPECT_EQ(*n, 2); + EXPECT_EQ(q2_.size(), 1); + delete n; +} +``` + +The above uses both `ASSERT_*` and `EXPECT_*` assertions. The rule of thumb is +to use `EXPECT_*` when you want the test to continue to reveal more errors after +the assertion failure, and use `ASSERT_*` when continuing after failure doesn't +make sense. For example, the second assertion in the `Dequeue` test is +`ASSERT_NE(nullptr, n)`, as we need to dereference the pointer `n` later, which +would lead to a segfault when `n` is `NULL`. + +When these tests run, the following happens: + +1. googletest constructs a `QueueTest` object (let's call it `t1`). +2. `t1.SetUp()` initializes `t1`. +3. The first test (`IsEmptyInitially`) runs on `t1`. +4. `t1.TearDown()` cleans up after the test finishes. +5. `t1` is destructed. +6. The above steps are repeated on another `QueueTest` object, this time + running the `DequeueWorks` test. + +**Availability**: Linux, Windows, Mac. + +## Invoking the Tests + +`TEST()` and `TEST_F()` implicitly register their tests with googletest. So, +unlike with many other C++ testing frameworks, you don't have to re-list all +your defined tests in order to run them. + +After defining your tests, you can run them with `RUN_ALL_TESTS()`, which +returns `0` if all the tests are successful, or `1` otherwise. Note that +`RUN_ALL_TESTS()` runs *all tests* in your link unit--they can be from +different test suites, or even different source files. + +When invoked, the `RUN_ALL_TESTS()` macro: + +* Saves the state of all googletest flags. + +* Creates a test fixture object for the first test. + +* Initializes it via `SetUp()`. + +* Runs the test on the fixture object. + +* Cleans up the fixture via `TearDown()`. + +* Deletes the fixture. + +* Restores the state of all googletest flags. + +* Repeats the above steps for the next test, until all tests have run. + +If a fatal failure happens the subsequent steps will be skipped. + +> IMPORTANT: You must **not** ignore the return value of `RUN_ALL_TESTS()`, or +> you will get a compiler error. The rationale for this design is that the +> automated testing service determines whether a test has passed based on its +> exit code, not on its stdout/stderr output; thus your `main()` function must +> return the value of `RUN_ALL_TESTS()`. +> +> Also, you should call `RUN_ALL_TESTS()` only **once**. Calling it more than +> once conflicts with some advanced googletest features (e.g., thread-safe +> [death tests](advanced.md#death-tests)) and thus is not supported. + +**Availability**: Linux, Windows, Mac. + +## Writing the main() Function + +Write your own main() function, which should return the value of +`RUN_ALL_TESTS()`. + +You can start from this boilerplate: + +```c++ +#include "this/package/foo.h" +#include "gtest/gtest.h" + +namespace { + +// The fixture for testing class Foo. +class FooTest : public ::testing::Test { + protected: + // You can remove any or all of the following functions if its body + // is empty. + + FooTest() { + // You can do set-up work for each test here. + } + + ~FooTest() override { + // You can do clean-up work that doesn't throw exceptions here. + } + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + void SetUp() override { + // Code here will be called immediately after the constructor (right + // before each test). + } + + void TearDown() override { + // Code here will be called immediately after each test (right + // before the destructor). + } + + // Objects declared here can be used by all tests in the test suite for Foo. +}; + +// Tests that the Foo::Bar() method does Abc. +TEST_F(FooTest, MethodBarDoesAbc) { + const std::string input_filepath = "this/package/testdata/myinputfile.dat"; + const std::string output_filepath = "this/package/testdata/myoutputfile.dat"; + Foo f; + EXPECT_EQ(f.Bar(input_filepath, output_filepath), 0); +} + +// Tests that Foo does Xyz. +TEST_F(FooTest, DoesXyz) { + // Exercises the Xyz feature of Foo. +} + +} // namespace + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +``` + +The `::testing::InitGoogleTest()` function parses the command line for +googletest flags, and removes all recognized flags. This allows the user to +control a test program's behavior via various flags, which we'll cover in +the [AdvancedGuide](advanced.md). You **must** call this function before calling +`RUN_ALL_TESTS()`, or the flags won't be properly initialized. + +On Windows, `InitGoogleTest()` also works with wide strings, so it can be used +in programs compiled in `UNICODE` mode as well. + +But maybe you think that writing all those main() functions is too much work? We +agree with you completely, and that's why Google Test provides a basic +implementation of main(). If it fits your needs, then just link your test with +gtest\_main library and you are good to go. + +NOTE: `ParseGUnitFlags()` is deprecated in favor of `InitGoogleTest()`. + +## Known Limitations + +* Google Test is designed to be thread-safe. The implementation is thread-safe + on systems where the `pthreads` library is available. It is currently + _unsafe_ to use Google Test assertions from two threads concurrently on + other systems (e.g. Windows). In most tests this is not an issue as usually + the assertions are done in the main thread. If you want to help, you can + volunteer to implement the necessary synchronization primitives in + `gtest-port.h` for your platform. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/pump_manual.md b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/pump_manual.md new file mode 100644 index 0000000000000000000000000000000000000000..10b3c5ff084925803d10d659f0c2234991590f37 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/pump_manual.md @@ -0,0 +1,190 @@ +Pump is Useful for Meta Programming. + +# The Problem + +Template and macro libraries often need to define many classes, functions, or +macros that vary only (or almost only) in the number of arguments they take. +It's a lot of repetitive, mechanical, and error-prone work. + +Variadic templates and variadic macros can alleviate the problem. However, while +both are being considered by the C++ committee, neither is in the standard yet +or widely supported by compilers. Thus they are often not a good choice, +especially when your code needs to be portable. And their capabilities are still +limited. + +As a result, authors of such libraries often have to write scripts to generate +their implementation. However, our experience is that it's tedious to write such +scripts, which tend to reflect the structure of the generated code poorly and +are often hard to read and edit. For example, a small change needed in the +generated code may require some non-intuitive, non-trivial changes in the +script. This is especially painful when experimenting with the code. + +# Our Solution + +Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta +Programming, or Practical Utility for Meta Programming, whichever you prefer) is +a simple meta-programming tool for C++. The idea is that a programmer writes a +`foo.pump` file which contains C++ code plus meta code that manipulates the C++ +code. The meta code can handle iterations over a range, nested iterations, local +meta variable definitions, simple arithmetic, and conditional expressions. You +can view it as a small Domain-Specific Language. The meta language is designed +to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, for example) and +concise, making Pump code intuitive and easy to maintain. + +## Highlights + +* The implementation is in a single Python script and thus ultra portable: no + build or installation is needed and it works cross platforms. +* Pump tries to be smart with respect to + [Google's style guide](https://github.com/google/styleguide): it breaks long + lines (easy to have when they are generated) at acceptable places to fit + within 80 columns and indent the continuation lines correctly. +* The format is human-readable and more concise than XML. +* The format works relatively well with Emacs' C++ mode. + +## Examples + +The following Pump code (where meta keywords start with `$`, `[[` and `]]` are +meta brackets, and `$$` starts a meta comment that ends with the line): + +``` +$var n = 3 $$ Defines a meta variable n. +$range i 0..n $$ Declares the range of meta iterator i (inclusive). +$for i [[ + $$ Meta loop. +// Foo$i does blah for $i-ary predicates. +$range j 1..i +template +class Foo$i { +$if i == 0 [[ + blah a; +]] $elif i <= 2 [[ + blah b; +]] $else [[ + blah c; +]] +}; + +]] +``` + +will be translated by the Pump compiler to: + +```cpp +// Foo0 does blah for 0-ary predicates. +template +class Foo0 { + blah a; +}; + +// Foo1 does blah for 1-ary predicates. +template +class Foo1 { + blah b; +}; + +// Foo2 does blah for 2-ary predicates. +template +class Foo2 { + blah b; +}; + +// Foo3 does blah for 3-ary predicates. +template +class Foo3 { + blah c; +}; +``` + +In another example, + +``` +$range i 1..n +Func($for i + [[a$i]]); +$$ The text between i and [[ is the separator between iterations. +``` + +will generate one of the following lines (without the comments), depending on +the value of `n`: + +```cpp +Func(); // If n is 0. +Func(a1); // If n is 1. +Func(a1 + a2); // If n is 2. +Func(a1 + a2 + a3); // If n is 3. +// And so on... +``` + +## Constructs + +We support the following meta programming constructs: + +| `$var id = exp` | Defines a named constant value. `$id` is | +: : valid util the end of the current meta : +: : lexical block. : +| :------------------------------- | :--------------------------------------- | +| `$range id exp..exp` | Sets the range of an iteration variable, | +: : which can be reused in multiple loops : +: : later. : +| `$for id sep [[ code ]]` | Iteration. The range of `id` must have | +: : been defined earlier. `$id` is valid in : +: : `code`. : +| `$($)` | Generates a single `$` character. | +| `$id` | Value of the named constant or iteration | +: : variable. : +| `$(exp)` | Value of the expression. | +| `$if exp [[ code ]] else_branch` | Conditional. | +| `[[ code ]]` | Meta lexical block. | +| `cpp_code` | Raw C++ code. | +| `$$ comment` | Meta comment. | + +**Note:** To give the user some freedom in formatting the Pump source code, Pump +ignores a new-line character if it's right after `$for foo` or next to `[[` or +`]]`. Without this rule you'll often be forced to write very long lines to get +the desired output. Therefore sometimes you may need to insert an extra new-line +in such places for a new-line to show up in your output. + +## Grammar + +```ebnf +code ::= atomic_code* +atomic_code ::= $var id = exp + | $var id = [[ code ]] + | $range id exp..exp + | $for id sep [[ code ]] + | $($) + | $id + | $(exp) + | $if exp [[ code ]] else_branch + | [[ code ]] + | cpp_code +sep ::= cpp_code | empty_string +else_branch ::= $else [[ code ]] + | $elif exp [[ code ]] else_branch + | empty_string +exp ::= simple_expression_in_Python_syntax +``` + +## Code + +You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). +It is still very unpolished and lacks automated tests, although it has been +successfully used many times. If you find a chance to use it in your project, +please let us know what you think! We also welcome help on improving Pump. + +## Real Examples + +You can find real-world applications of Pump in +[Google Test](https://github.com/google/googletest/tree/master/googletest) and +[Google Mock](https://github.com/google/googletest/tree/master/googlemock). The +source file `foo.h.pump` generates `foo.h`. + +## Tips + +* If a meta variable is followed by a letter or digit, you can separate them + using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` + generate `Foo1Helper` when `j` is 1. +* To avoid extra-long Pump source lines, you can break a line anywhere you + want by inserting `[[]]` followed by a new line. Since any new-line + character next to `[[` or `]]` is ignored, the generated code won't contain + this new line. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/samples.md b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/samples.md new file mode 100644 index 0000000000000000000000000000000000000000..aaa5883830b6d6cb6d33104de3d2206288d8d41e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/docs/samples.md @@ -0,0 +1,22 @@ +# Googletest Samples {#samples} + +If you're like us, you'd like to look at +[googletest samples.](https://github.com/google/googletest/tree/master/googletest/samples) +The sample directory has a number of well-commented samples showing how to use a +variety of googletest features. + +* Sample #1 shows the basic steps of using googletest to test C++ functions. +* Sample #2 shows a more complex unit test for a class with multiple member + functions. +* Sample #3 uses a test fixture. +* Sample #4 teaches you how to use googletest and `googletest.h` together to + get the best of both libraries. +* Sample #5 puts shared testing logic in a base test fixture, and reuses it in + derived fixtures. +* Sample #6 demonstrates type-parameterized tests. +* Sample #7 teaches the basics of value-parameterized tests. +* Sample #8 shows using `Combine()` in value-parameterized tests. +* Sample #9 shows use of the listener API to modify Google Test's console + output and the use of its reflection API to inspect test results. +* Sample #10 shows use of the listener API to implement a primitive memory + leak checker. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-death-test.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-death-test.h new file mode 100644 index 0000000000000000000000000000000000000000..dc878ffbb3ae56a2b91b930b71a7cbb503222a46 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-death-test.h @@ -0,0 +1,343 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines the public API for death tests. It is +// #included by gtest.h so a user doesn't need to include this +// directly. +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ + +#include "gtest/internal/gtest-death-test-internal.h" + +namespace testing { + +// This flag controls the style of death tests. Valid values are "threadsafe", +// meaning that the death test child process will re-execute the test binary +// from the start, running only a single death test, or "fast", +// meaning that the child process will execute the test logic immediately +// after forking. +GTEST_DECLARE_string_(death_test_style); + +#if GTEST_HAS_DEATH_TEST + +namespace internal { + +// Returns a Boolean value indicating whether the caller is currently +// executing in the context of the death test child process. Tools such as +// Valgrind heap checkers may need this to modify their behavior in death +// tests. IMPORTANT: This is an internal utility. Using it may break the +// implementation of death tests. User code MUST NOT use it. +GTEST_API_ bool InDeathTestChild(); + +} // namespace internal + +// The following macros are useful for writing death tests. + +// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is +// executed: +// +// 1. It generates a warning if there is more than one active +// thread. This is because it's safe to fork() or clone() only +// when there is a single thread. +// +// 2. The parent process clone()s a sub-process and runs the death +// test in it; the sub-process exits with code 0 at the end of the +// death test, if it hasn't exited already. +// +// 3. The parent process waits for the sub-process to terminate. +// +// 4. The parent process checks the exit code and error message of +// the sub-process. +// +// Examples: +// +// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); +// for (int i = 0; i < 5; i++) { +// EXPECT_DEATH(server.ProcessRequest(i), +// "Invalid request .* in ProcessRequest()") +// << "Failed to die on request " << i; +// } +// +// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); +// +// bool KilledBySIGHUP(int exit_code) { +// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; +// } +// +// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); +// +// On the regular expressions used in death tests: +// +// GOOGLETEST_CM0005 DO NOT DELETE +// On POSIX-compliant systems (*nix), we use the library, +// which uses the POSIX extended regex syntax. +// +// On other platforms (e.g. Windows or Mac), we only support a simple regex +// syntax implemented as part of Google Test. This limited +// implementation should be enough most of the time when writing +// death tests; though it lacks many features you can find in PCRE +// or POSIX extended regex syntax. For example, we don't support +// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and +// repetition count ("x{5,7}"), among others. +// +// Below is the syntax that we do support. We chose it to be a +// subset of both PCRE and POSIX extended regex, so it's easy to +// learn wherever you come from. In the following: 'A' denotes a +// literal character, period (.), or a single \\ escape sequence; +// 'x' and 'y' denote regular expressions; 'm' and 'n' are for +// natural numbers. +// +// c matches any literal character c +// \\d matches any decimal digit +// \\D matches any character that's not a decimal digit +// \\f matches \f +// \\n matches \n +// \\r matches \r +// \\s matches any ASCII whitespace, including \n +// \\S matches any character that's not a whitespace +// \\t matches \t +// \\v matches \v +// \\w matches any letter, _, or decimal digit +// \\W matches any character that \\w doesn't match +// \\c matches any literal character c, which must be a punctuation +// . matches any single character except \n +// A? matches 0 or 1 occurrences of A +// A* matches 0 or many occurrences of A +// A+ matches 1 or many occurrences of A +// ^ matches the beginning of a string (not that of each line) +// $ matches the end of a string (not that of each line) +// xy matches x followed by y +// +// If you accidentally use PCRE or POSIX extended regex features +// not implemented by us, you will get a run-time failure. In that +// case, please try to rewrite your regular expression within the +// above syntax. +// +// This implementation is *not* meant to be as highly tuned or robust +// as a compiled regex library, but should perform well enough for a +// death test, which already incurs significant overhead by launching +// a child process. +// +// Known caveats: +// +// A "threadsafe" style death test obtains the path to the test +// program from argv[0] and re-executes it in the sub-process. For +// simplicity, the current implementation doesn't search the PATH +// when launching the sub-process. This means that the user must +// invoke the test program via a path that contains at least one +// path separator (e.g. path/to/foo_test and +// /absolute/path/to/bar_test are fine, but foo_test is not). This +// is rarely a problem as people usually don't put the test binary +// directory in PATH. +// + +// Asserts that a given statement causes the program to exit, with an +// integer exit status that satisfies predicate, and emitting error output +// that matches regex. +# define ASSERT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) + +// Like ASSERT_EXIT, but continues on to successive tests in the +// test suite, if any: +# define EXPECT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) + +// Asserts that a given statement causes the program to exit, either by +// explicitly exiting with a nonzero exit code or being killed by a +// signal, and emitting error output that matches regex. +# define ASSERT_DEATH(statement, regex) \ + ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Like ASSERT_DEATH, but continues on to successive tests in the +// test suite, if any: +# define EXPECT_DEATH(statement, regex) \ + EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: + +// Tests that an exit code describes a normal exit with a given exit code. +class GTEST_API_ ExitedWithCode { + public: + explicit ExitedWithCode(int exit_code); + bool operator()(int exit_status) const; + private: + // No implementation - assignment is unsupported. + void operator=(const ExitedWithCode& other); + + const int exit_code_; +}; + +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA +// Tests that an exit code describes an exit due to termination by a +// given signal. +// GOOGLETEST_CM0006 DO NOT DELETE +class GTEST_API_ KilledBySignal { + public: + explicit KilledBySignal(int signum); + bool operator()(int exit_status) const; + private: + const int signum_; +}; +# endif // !GTEST_OS_WINDOWS + +// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. +// The death testing framework causes this to have interesting semantics, +// since the sideeffects of the call are only visible in opt mode, and not +// in debug mode. +// +// In practice, this can be used to test functions that utilize the +// LOG(DFATAL) macro using the following style: +// +// int DieInDebugOr12(int* sideeffect) { +// if (sideeffect) { +// *sideeffect = 12; +// } +// LOG(DFATAL) << "death"; +// return 12; +// } +// +// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) { +// int sideeffect = 0; +// // Only asserts in dbg. +// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); +// +// #ifdef NDEBUG +// // opt-mode has sideeffect visible. +// EXPECT_EQ(12, sideeffect); +// #else +// // dbg-mode no visible sideeffect. +// EXPECT_EQ(0, sideeffect); +// #endif +// } +// +// This will assert that DieInDebugReturn12InOpt() crashes in debug +// mode, usually due to a DCHECK or LOG(DFATAL), but returns the +// appropriate fallback value (12 in this case) in opt mode. If you +// need to test that a function has appropriate side-effects in opt +// mode, include assertions against the side-effects. A general +// pattern for this is: +// +// EXPECT_DEBUG_DEATH({ +// // Side-effects here will have an effect after this statement in +// // opt mode, but none in debug mode. +// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); +// }, "death"); +// +# ifdef NDEBUG + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + GTEST_EXECUTE_STATEMENT_(statement, regex) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + GTEST_EXECUTE_STATEMENT_(statement, regex) + +# else + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + EXPECT_DEATH(statement, regex) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + ASSERT_DEATH(statement, regex) + +# endif // NDEBUG for EXPECT_DEBUG_DEATH +#endif // GTEST_HAS_DEATH_TEST + +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters +// on systems that support death tests. This allows one to write such a macro on +// a system that does not support death tests and be sure that it will compile +// on a death-test supporting system. It is exposed publicly so that systems +// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST +// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and +// ASSERT_DEATH_IF_SUPPORTED. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter if and only if EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + +// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and +// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if +// death tests are supported; otherwise they just issue a warning. This is +// useful when you are combining death test assertions with normal test +// assertions in one test. +#if GTEST_HAS_DEATH_TEST +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + EXPECT_DEATH(statement, regex) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + ASSERT_DEATH(statement, regex) +#else +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, ) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return) +#endif + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-matchers.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-matchers.h new file mode 100644 index 0000000000000000000000000000000000000000..9de6c2e10a20da85aeb95887d6095a2b8010b4a5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-matchers.h @@ -0,0 +1,750 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file implements just enough of the matcher interface to allow +// EXPECT_DEATH and friends to accept a matcher argument. + +// IWYU pragma: private, include "testing/base/public/gunit.h" +// IWYU pragma: friend third_party/googletest/googlemock/.* +// IWYU pragma: friend third_party/googletest/googletest/.* + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ + +#include +#include +#include +#include + +#include "gtest/gtest-printers.h" +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" + +// MSVC warning C5046 is new as of VS2017 version 15.8. +#if defined(_MSC_VER) && _MSC_VER >= 1915 +#define GTEST_MAYBE_5046_ 5046 +#else +#define GTEST_MAYBE_5046_ +#endif + +GTEST_DISABLE_MSC_WARNINGS_PUSH_( + 4251 GTEST_MAYBE_5046_ /* class A needs to have dll-interface to be used by + clients of class B */ + /* Symbol involving type with internal linkage not defined */) + +namespace testing { + +// To implement a matcher Foo for type T, define: +// 1. a class FooMatcherImpl that implements the +// MatcherInterface interface, and +// 2. a factory function that creates a Matcher object from a +// FooMatcherImpl*. +// +// The two-level delegation design makes it possible to allow a user +// to write "v" instead of "Eq(v)" where a Matcher is expected, which +// is impossible if we pass matchers by pointers. It also eases +// ownership management as Matcher objects can now be copied like +// plain values. + +// MatchResultListener is an abstract class. Its << operator can be +// used by a matcher to explain why a value matches or doesn't match. +// +class MatchResultListener { + public: + // Creates a listener object with the given underlying ostream. The + // listener does not own the ostream, and does not dereference it + // in the constructor or destructor. + explicit MatchResultListener(::std::ostream* os) : stream_(os) {} + virtual ~MatchResultListener() = 0; // Makes this class abstract. + + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener& operator<<(const T& x) { + if (stream_ != nullptr) *stream_ << x; + return *this; + } + + // Returns the underlying ostream. + ::std::ostream* stream() { return stream_; } + + // Returns true if and only if the listener is interested in an explanation + // of the match result. A matcher's MatchAndExplain() method can use + // this information to avoid generating the explanation when no one + // intends to hear it. + bool IsInterested() const { return stream_ != nullptr; } + + private: + ::std::ostream* const stream_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); +}; + +inline MatchResultListener::~MatchResultListener() { +} + +// An instance of a subclass of this knows how to describe itself as a +// matcher. +class MatcherDescriberInterface { + public: + virtual ~MatcherDescriberInterface() {} + + // Describes this matcher to an ostream. The function should print + // a verb phrase that describes the property a value matching this + // matcher should have. The subject of the verb phrase is the value + // being matched. For example, the DescribeTo() method of the Gt(7) + // matcher prints "is greater than 7". + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. For + // example, if the description of this matcher is "is greater than + // 7", the negated description could be "is not greater than 7". + // You are not required to override this when implementing + // MatcherInterface, but it is highly advised so that your matcher + // can produce good error messages. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not ("; + DescribeTo(os); + *os << ")"; + } +}; + +// The implementation of a matcher. +template +class MatcherInterface : public MatcherDescriberInterface { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener' if necessary (see the next paragraph), in + // the form of a non-restrictive relative clause ("which ...", + // "whose ...", etc) that describes x. For example, the + // MatchAndExplain() method of the Pointee(...) matcher should + // generate an explanation like "which points to ...". + // + // Implementations of MatchAndExplain() should add an explanation of + // the match result *if and only if* they can provide additional + // information that's not already present (or not obvious) in the + // print-out of x and the matcher's description. Whether the match + // succeeds is not a factor in deciding whether an explanation is + // needed, as sometimes the caller needs to print a failure message + // when the match succeeds (e.g. when the matcher is used inside + // Not()). + // + // For example, a "has at least 10 elements" matcher should explain + // what the actual element count is, regardless of the match result, + // as it is useful information to the reader; on the other hand, an + // "is empty" matcher probably only needs to explain what the actual + // size is when the match fails, as it's redundant to say that the + // size is 0 when the value is already known to be empty. + // + // You should override this method when defining a new matcher. + // + // It's the responsibility of the caller (Google Test) to guarantee + // that 'listener' is not NULL. This helps to simplify a matcher's + // implementation when it doesn't care about the performance, as it + // can talk to 'listener' without checking its validity first. + // However, in order to implement dummy listeners efficiently, + // listener->stream() may be NULL. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; + + // Inherits these methods from MatcherDescriberInterface: + // virtual void DescribeTo(::std::ostream* os) const = 0; + // virtual void DescribeNegationTo(::std::ostream* os) const; +}; + +namespace internal { + +// Converts a MatcherInterface to a MatcherInterface. +template +class MatcherInterfaceAdapter : public MatcherInterface { + public: + explicit MatcherInterfaceAdapter(const MatcherInterface* impl) + : impl_(impl) {} + ~MatcherInterfaceAdapter() override { delete impl_; } + + void DescribeTo(::std::ostream* os) const override { impl_->DescribeTo(os); } + + void DescribeNegationTo(::std::ostream* os) const override { + impl_->DescribeNegationTo(os); + } + + bool MatchAndExplain(const T& x, + MatchResultListener* listener) const override { + return impl_->MatchAndExplain(x, listener); + } + + private: + const MatcherInterface* const impl_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatcherInterfaceAdapter); +}; + +struct AnyEq { + template + bool operator()(const A& a, const B& b) const { return a == b; } +}; +struct AnyNe { + template + bool operator()(const A& a, const B& b) const { return a != b; } +}; +struct AnyLt { + template + bool operator()(const A& a, const B& b) const { return a < b; } +}; +struct AnyGt { + template + bool operator()(const A& a, const B& b) const { return a > b; } +}; +struct AnyLe { + template + bool operator()(const A& a, const B& b) const { return a <= b; } +}; +struct AnyGe { + template + bool operator()(const A& a, const B& b) const { return a >= b; } +}; + +// A match result listener that ignores the explanation. +class DummyMatchResultListener : public MatchResultListener { + public: + DummyMatchResultListener() : MatchResultListener(nullptr) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); +}; + +// A match result listener that forwards the explanation to a given +// ostream. The difference between this and MatchResultListener is +// that the former is concrete. +class StreamMatchResultListener : public MatchResultListener { + public: + explicit StreamMatchResultListener(::std::ostream* os) + : MatchResultListener(os) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); +}; + +// An internal class for implementing Matcher, which will derive +// from it. We put functionalities common to all Matcher +// specializations here to avoid code duplication. +template +class MatcherBase { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener'. + bool MatchAndExplain(const T& x, MatchResultListener* listener) const { + return impl_->MatchAndExplain(x, listener); + } + + // Returns true if and only if this matcher matches x. + bool Matches(const T& x) const { + DummyMatchResultListener dummy; + return MatchAndExplain(x, &dummy); + } + + // Describes this matcher to an ostream. + void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + + // Describes the negation of this matcher to an ostream. + void DescribeNegationTo(::std::ostream* os) const { + impl_->DescribeNegationTo(os); + } + + // Explains why x matches, or doesn't match, the matcher. + void ExplainMatchResultTo(const T& x, ::std::ostream* os) const { + StreamMatchResultListener listener(os); + MatchAndExplain(x, &listener); + } + + // Returns the describer for this matcher object; retains ownership + // of the describer, which is only guaranteed to be alive when + // this matcher object is alive. + const MatcherDescriberInterface* GetDescriber() const { + return impl_.get(); + } + + protected: + MatcherBase() {} + + // Constructs a matcher from its implementation. + explicit MatcherBase(const MatcherInterface* impl) : impl_(impl) {} + + template + explicit MatcherBase( + const MatcherInterface* impl, + typename std::enable_if::value>::type* = + nullptr) + : impl_(new internal::MatcherInterfaceAdapter(impl)) {} + + MatcherBase(const MatcherBase&) = default; + MatcherBase& operator=(const MatcherBase&) = default; + MatcherBase(MatcherBase&&) = default; + MatcherBase& operator=(MatcherBase&&) = default; + + virtual ~MatcherBase() {} + + private: + std::shared_ptr> impl_; +}; + +} // namespace internal + +// A Matcher is a copyable and IMMUTABLE (except by assignment) +// object that can check whether a value of type T matches. The +// implementation of Matcher is just a std::shared_ptr to const +// MatcherInterface. Don't inherit from Matcher! +template +class Matcher : public internal::MatcherBase { + public: + // Constructs a null matcher. Needed for storing Matcher objects in STL + // containers. A default-constructed matcher is not yet initialized. You + // cannot use it until a valid value has been assigned to it. + explicit Matcher() {} // NOLINT + + // Constructs a matcher from its implementation. + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + template + explicit Matcher( + const MatcherInterface* impl, + typename std::enable_if::value>::type* = + nullptr) + : internal::MatcherBase(impl) {} + + // Implicit constructor here allows people to write + // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes + Matcher(T value); // NOLINT +}; + +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a std::string +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +#if GTEST_HAS_ABSL +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass absl::string_views directly. + Matcher(absl::string_view s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass absl::string_views directly. + Matcher(absl::string_view s); // NOLINT +}; +#endif // GTEST_HAS_ABSL + +// Prints a matcher in a human-readable format. +template +std::ostream& operator<<(std::ostream& os, const Matcher& matcher) { + matcher.DescribeTo(&os); + return os; +} + +// The PolymorphicMatcher class template makes it easy to implement a +// polymorphic matcher (i.e. a matcher that can match values of more +// than one type, e.g. Eq(n) and NotNull()). +// +// To define a polymorphic matcher, a user should provide an Impl +// class that has a DescribeTo() method and a DescribeNegationTo() +// method, and define a member function (or member function template) +// +// bool MatchAndExplain(const Value& value, +// MatchResultListener* listener) const; +// +// See the definition of NotNull() for a complete example. +template +class PolymorphicMatcher { + public: + explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {} + + // Returns a mutable reference to the underlying matcher + // implementation object. + Impl& mutable_impl() { return impl_; } + + // Returns an immutable reference to the underlying matcher + // implementation object. + const Impl& impl() const { return impl_; } + + template + operator Matcher() const { + return Matcher(new MonomorphicImpl(impl_)); + } + + private: + template + class MonomorphicImpl : public MatcherInterface { + public: + explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} + + virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); } + + virtual void DescribeNegationTo(::std::ostream* os) const { + impl_.DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const { + return impl_.MatchAndExplain(x, listener); + } + + private: + const Impl impl_; + }; + + Impl impl_; +}; + +// Creates a matcher from its implementation. +// DEPRECATED: Especially in the generic code, prefer: +// Matcher(new MyMatcherImpl(...)); +// +// MakeMatcher may create a Matcher that accepts its argument by value, which +// leads to unnecessary copies & lack of support for non-copyable types. +template +inline Matcher MakeMatcher(const MatcherInterface* impl) { + return Matcher(impl); +} + +// Creates a polymorphic matcher from its implementation. This is +// easier to use than the PolymorphicMatcher constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicMatcher(foo); +// vs +// PolymorphicMatcher(foo); +template +inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { + return PolymorphicMatcher(impl); +} + +namespace internal { +// Implements a matcher that compares a given value with a +// pre-supplied value using one of the ==, <=, <, etc, operators. The +// two values being compared don't have to have the same type. +// +// The matcher defined here is polymorphic (for example, Eq(5) can be +// used to match an int, a short, a double, etc). Therefore we use +// a template type conversion operator in the implementation. +// +// The following template definition assumes that the Rhs parameter is +// a "bare" type (i.e. neither 'const T' nor 'T&'). +template +class ComparisonBase { + public: + explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {} + template + operator Matcher() const { + return Matcher(new Impl(rhs_)); + } + + private: + template + static const T& Unwrap(const T& v) { return v; } + template + static const T& Unwrap(std::reference_wrapper v) { return v; } + + template + class Impl : public MatcherInterface { + public: + explicit Impl(const Rhs& rhs) : rhs_(rhs) {} + bool MatchAndExplain(Lhs lhs, + MatchResultListener* /* listener */) const override { + return Op()(lhs, Unwrap(rhs_)); + } + void DescribeTo(::std::ostream* os) const override { + *os << D::Desc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + void DescribeNegationTo(::std::ostream* os) const override { + *os << D::NegatedDesc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + + private: + Rhs rhs_; + }; + Rhs rhs_; +}; + +template +class EqMatcher : public ComparisonBase, Rhs, AnyEq> { + public: + explicit EqMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyEq>(rhs) { } + static const char* Desc() { return "is equal to"; } + static const char* NegatedDesc() { return "isn't equal to"; } +}; +template +class NeMatcher : public ComparisonBase, Rhs, AnyNe> { + public: + explicit NeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyNe>(rhs) { } + static const char* Desc() { return "isn't equal to"; } + static const char* NegatedDesc() { return "is equal to"; } +}; +template +class LtMatcher : public ComparisonBase, Rhs, AnyLt> { + public: + explicit LtMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyLt>(rhs) { } + static const char* Desc() { return "is <"; } + static const char* NegatedDesc() { return "isn't <"; } +}; +template +class GtMatcher : public ComparisonBase, Rhs, AnyGt> { + public: + explicit GtMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyGt>(rhs) { } + static const char* Desc() { return "is >"; } + static const char* NegatedDesc() { return "isn't >"; } +}; +template +class LeMatcher : public ComparisonBase, Rhs, AnyLe> { + public: + explicit LeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyLe>(rhs) { } + static const char* Desc() { return "is <="; } + static const char* NegatedDesc() { return "isn't <="; } +}; +template +class GeMatcher : public ComparisonBase, Rhs, AnyGe> { + public: + explicit GeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyGe>(rhs) { } + static const char* Desc() { return "is >="; } + static const char* NegatedDesc() { return "isn't >="; } +}; + +// Implements polymorphic matchers MatchesRegex(regex) and +// ContainsRegex(regex), which can be used as a Matcher as long as +// T can be converted to a string. +class MatchesRegexMatcher { + public: + MatchesRegexMatcher(const RE* regex, bool full_match) + : regex_(regex), full_match_(full_match) {} + +#if GTEST_HAS_ABSL + bool MatchAndExplain(const absl::string_view& s, + MatchResultListener* listener) const { + return MatchAndExplain(std::string(s), listener); + } +#endif // GTEST_HAS_ABSL + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != nullptr && MatchAndExplain(std::string(s), listener); + } + + // Matches anything that can convert to std::string. + // + // This is a template, not just a plain function with const std::string&, + // because absl::string_view has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const std::string& s2(s); + return full_match_ ? RE::FullMatch(s2, *regex_) + : RE::PartialMatch(s2, *regex_); + } + + void DescribeTo(::std::ostream* os) const { + *os << (full_match_ ? "matches" : "contains") << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't " << (full_match_ ? "match" : "contain") + << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + private: + const std::shared_ptr regex_; + const bool full_match_; +}; +} // namespace internal + +// Matches a string that fully matches regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher MatchesRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true)); +} +inline PolymorphicMatcher MatchesRegex( + const std::string& regex) { + return MatchesRegex(new internal::RE(regex)); +} + +// Matches a string that contains regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher ContainsRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false)); +} +inline PolymorphicMatcher ContainsRegex( + const std::string& regex) { + return ContainsRegex(new internal::RE(regex)); +} + +// Creates a polymorphic matcher that matches anything equal to x. +// Note: if the parameter of Eq() were declared as const T&, Eq("foo") +// wouldn't compile. +template +inline internal::EqMatcher Eq(T x) { return internal::EqMatcher(x); } + +// Constructs a Matcher from a 'value' of type T. The constructed +// matcher matches any value that's equal to 'value'. +template +Matcher::Matcher(T value) { *this = Eq(value); } + +// Creates a monomorphic matcher that matches anything with type Lhs +// and equal to rhs. A user may need to use this instead of Eq(...) +// in order to resolve an overloading ambiguity. +// +// TypedEq(x) is just a convenient short-hand for Matcher(Eq(x)) +// or Matcher(x), but more readable than the latter. +// +// We could define similar monomorphic matchers for other comparison +// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do +// it yet as those are used much less than Eq() in practice. A user +// can always write Matcher(Lt(5)) to be explicit about the type, +// for example. +template +inline Matcher TypedEq(const Rhs& rhs) { return Eq(rhs); } + +// Creates a polymorphic matcher that matches anything >= x. +template +inline internal::GeMatcher Ge(Rhs x) { + return internal::GeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything > x. +template +inline internal::GtMatcher Gt(Rhs x) { + return internal::GtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything <= x. +template +inline internal::LeMatcher Le(Rhs x) { + return internal::LeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything < x. +template +inline internal::LtMatcher Lt(Rhs x) { + return internal::LtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything != x. +template +inline internal::NeMatcher Ne(Rhs x) { + return internal::NeMatcher(x); +} +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046 + +#endif // GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-message.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-message.h new file mode 100644 index 0000000000000000000000000000000000000000..4a80e11e6b2db017a27271002ae54c41d29b4a26 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-message.h @@ -0,0 +1,218 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines the Message class. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ + +#include +#include + +#include "gtest/internal/gtest-port.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +// Ensures that there is at least one operator<< in the global namespace. +// See Message& operator<<(...) below for why. +void operator<<(const testing::internal::Secret&, int); + +namespace testing { + +// The Message class works like an ostream repeater. +// +// Typical usage: +// +// 1. You stream a bunch of values to a Message object. +// It will remember the text in a stringstream. +// 2. Then you stream the Message object to an ostream. +// This causes the text in the Message to be streamed +// to the ostream. +// +// For example; +// +// testing::Message foo; +// foo << 1 << " != " << 2; +// std::cout << foo; +// +// will print "1 != 2". +// +// Message is not intended to be inherited from. In particular, its +// destructor is not virtual. +// +// Note that stringstream behaves differently in gcc and in MSVC. You +// can stream a NULL char pointer to it in the former, but not in the +// latter (it causes an access violation if you do). The Message +// class hides this difference by treating a NULL char pointer as +// "(null)". +class GTEST_API_ Message { + private: + // The type of basic IO manipulators (endl, ends, and flush) for + // narrow streams. + typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); + + public: + // Constructs an empty Message. + Message(); + + // Copy constructor. + Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT + *ss_ << msg.GetString(); + } + + // Constructs a Message from a C-string. + explicit Message(const char* str) : ss_(new ::std::stringstream) { + *ss_ << str; + } + + // Streams a non-pointer value to this object. + template + inline Message& operator <<(const T& val) { + // Some libraries overload << for STL containers. These + // overloads are defined in the global namespace instead of ::std. + // + // C++'s symbol lookup rule (i.e. Koenig lookup) says that these + // overloads are visible in either the std namespace or the global + // namespace, but not other namespaces, including the testing + // namespace which Google Test's Message class is in. + // + // To allow STL containers (and other types that has a << operator + // defined in the global namespace) to be used in Google Test + // assertions, testing::Message must access the custom << operator + // from the global namespace. With this using declaration, + // overloads of << defined in the global namespace and those + // visible via Koenig lookup are both exposed in this function. + using ::operator <<; + *ss_ << val; + return *this; + } + + // Streams a pointer value to this object. + // + // This function is an overload of the previous one. When you + // stream a pointer to a Message, this definition will be used as it + // is more specialized. (The C++ Standard, section + // [temp.func.order].) If you stream a non-pointer, then the + // previous definition will be used. + // + // The reason for this overload is that streaming a NULL pointer to + // ostream is undefined behavior. Depending on the compiler, you + // may get "0", "(nil)", "(null)", or an access violation. To + // ensure consistent result across compilers, we always treat NULL + // as "(null)". + template + inline Message& operator <<(T* const& pointer) { // NOLINT + if (pointer == nullptr) { + *ss_ << "(null)"; + } else { + *ss_ << pointer; + } + return *this; + } + + // Since the basic IO manipulators are overloaded for both narrow + // and wide streams, we have to provide this specialized definition + // of operator <<, even though its body is the same as the + // templatized version above. Without this definition, streaming + // endl or other basic IO manipulators to Message will confuse the + // compiler. + Message& operator <<(BasicNarrowIoManip val) { + *ss_ << val; + return *this; + } + + // Instead of 1/0, we want to see true/false for bool values. + Message& operator <<(bool b) { + return *this << (b ? "true" : "false"); + } + + // These two overloads allow streaming a wide C string to a Message + // using the UTF-8 encoding. + Message& operator <<(const wchar_t* wide_c_str); + Message& operator <<(wchar_t* wide_c_str); + +#if GTEST_HAS_STD_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::std::wstring& wstr); +#endif // GTEST_HAS_STD_WSTRING + + // Gets the text streamed to this object so far as an std::string. + // Each '\0' character in the buffer is replaced with "\\0". + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + std::string GetString() const; + + private: + // We'll hold the text streamed to this object here. + const std::unique_ptr< ::std::stringstream> ss_; + + // We declare (but don't implement) this to prevent the compiler + // from implementing the assignment operator. + void operator=(const Message&); +}; + +// Streams a Message to an ostream. +inline std::ostream& operator <<(std::ostream& os, const Message& sb) { + return os << sb.GetString(); +} + +namespace internal { + +// Converts a streamable value to an std::string. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +template +std::string StreamableToString(const T& streamable) { + return (Message() << streamable).GetString(); +} + +} // namespace internal +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-param-test.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-param-test.h new file mode 100644 index 0000000000000000000000000000000000000000..c2e6eae3d8326e5553598c65ae85a4ed085281e0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-param-test.h @@ -0,0 +1,503 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Macros and functions for implementing parameterized tests +// in Google C++ Testing and Mocking Framework (Google Test) +// +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// GOOGLETEST_CM0001 DO NOT DELETE +#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ + + +// Value-parameterized tests allow you to test your code with different +// parameters without writing multiple copies of the same test. +// +// Here is how you use value-parameterized tests: + +#if 0 + +// To write value-parameterized tests, first you should define a fixture +// class. It is usually derived from testing::TestWithParam (see below for +// another inheritance scheme that's sometimes useful in more complicated +// class hierarchies), where the type of your parameter values. +// TestWithParam is itself derived from testing::Test. T can be any +// copyable type. If it's a raw pointer, you are responsible for managing the +// lifespan of the pointed values. + +class FooTest : public ::testing::TestWithParam { + // You can implement all the usual class fixture members here. +}; + +// Then, use the TEST_P macro to define as many parameterized tests +// for this fixture as you want. The _P suffix is for "parameterized" +// or "pattern", whichever you prefer to think. + +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} + +// Finally, you can use INSTANTIATE_TEST_SUITE_P to instantiate the test +// case with any set of parameters you want. Google Test defines a number +// of functions for generating test parameters. They return what we call +// (surprise!) parameter generators. Here is a summary of them, which +// are all in the testing namespace: +// +// +// Range(begin, end [, step]) - Yields values {begin, begin+step, +// begin+step+step, ...}. The values do not +// include end. step defaults to 1. +// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. +// ValuesIn(container) - Yields values from a C-style array, an STL +// ValuesIn(begin,end) container, or an iterator range [begin, end). +// Bool() - Yields sequence {false, true}. +// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product +// for the math savvy) of the values generated +// by the N generators. +// +// For more details, see comments at the definitions of these functions below +// in this file. +// +// The following statement will instantiate tests from the FooTest test suite +// each with parameter values "meeny", "miny", and "moe". + +INSTANTIATE_TEST_SUITE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); + +// To distinguish different instances of the pattern, (yes, you +// can instantiate it more than once) the first argument to the +// INSTANTIATE_TEST_SUITE_P macro is a prefix that will be added to the +// actual test suite name. Remember to pick unique prefixes for different +// instantiations. The tests from the instantiation above will have +// these names: +// +// * InstantiationName/FooTest.DoesBlah/0 for "meeny" +// * InstantiationName/FooTest.DoesBlah/1 for "miny" +// * InstantiationName/FooTest.DoesBlah/2 for "moe" +// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" +// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" +// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" +// +// You can use these names in --gtest_filter. +// +// This statement will instantiate all tests from FooTest again, each +// with parameter values "cat" and "dog": + +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_SUITE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); + +// The tests from the instantiation above will have these names: +// +// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" +// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" +// +// Please note that INSTANTIATE_TEST_SUITE_P will instantiate all tests +// in the given test suite, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_SUITE_P statement. +// +// Please also note that generator expressions (including parameters to the +// generators) are evaluated in InitGoogleTest(), after main() has started. +// This allows the user on one hand, to adjust generator parameters in order +// to dynamically determine a set of tests to run and on the other hand, +// give the user a chance to inspect the generated tests with Google Test +// reflection API before RUN_ALL_TESTS() is executed. +// +// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc +// for more examples. +// +// In the future, we plan to publish the API for defining new parameter +// generators. But for now this interface remains part of the internal +// implementation and is subject to change. +// +// +// A parameterized test fixture must be derived from testing::Test and from +// testing::WithParamInterface, where T is the type of the parameter +// values. Inheriting from TestWithParam satisfies that requirement because +// TestWithParam inherits from both Test and WithParamInterface. In more +// complicated hierarchies, however, it is occasionally useful to inherit +// separately from Test and WithParamInterface. For example: + +class BaseTest : public ::testing::Test { + // You can inherit all the usual members for a non-parameterized test + // fixture here. +}; + +class DerivedTest : public BaseTest, public ::testing::WithParamInterface { + // The usual test fixture members go here too. +}; + +TEST_F(BaseTest, HasFoo) { + // This is an ordinary non-parameterized test. +} + +TEST_P(DerivedTest, DoesBlah) { + // GetParam works just the same here as if you inherit from TestWithParam. + EXPECT_TRUE(foo.Blah(GetParam())); +} + +#endif // 0 + +#include +#include + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-param-util.h" +#include "gtest/internal/gtest-port.h" + +namespace testing { + +// Functions producing parameter generators. +// +// Google Test uses these generators to produce parameters for value- +// parameterized tests. When a parameterized test suite is instantiated +// with a particular generator, Google Test creates and runs tests +// for each element in the sequence produced by the generator. +// +// In the following sample, tests from test suite FooTest are instantiated +// each three times with parameter values 3, 5, and 8: +// +// class FooTest : public TestWithParam { ... }; +// +// TEST_P(FooTest, TestThis) { +// } +// TEST_P(FooTest, TestThat) { +// } +// INSTANTIATE_TEST_SUITE_P(TestSequence, FooTest, Values(3, 5, 8)); +// + +// Range() returns generators providing sequences of values in a range. +// +// Synopsis: +// Range(start, end) +// - returns a generator producing a sequence of values {start, start+1, +// start+2, ..., }. +// Range(start, end, step) +// - returns a generator producing a sequence of values {start, start+step, +// start+step+step, ..., }. +// Notes: +// * The generated sequences never include end. For example, Range(1, 5) +// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) +// returns a generator producing {1, 3, 5, 7}. +// * start and end must have the same type. That type may be any integral or +// floating-point type or a user defined type satisfying these conditions: +// * It must be assignable (have operator=() defined). +// * It must have operator+() (operator+(int-compatible type) for +// two-operand version). +// * It must have operator<() defined. +// Elements in the resulting sequences will also have that type. +// * Condition start < end must be satisfied in order for resulting sequences +// to contain any elements. +// +template +internal::ParamGenerator Range(T start, T end, IncrementT step) { + return internal::ParamGenerator( + new internal::RangeGenerator(start, end, step)); +} + +template +internal::ParamGenerator Range(T start, T end) { + return Range(start, end, 1); +} + +// ValuesIn() function allows generation of tests with parameters coming from +// a container. +// +// Synopsis: +// ValuesIn(const T (&array)[N]) +// - returns a generator producing sequences with elements from +// a C-style array. +// ValuesIn(const Container& container) +// - returns a generator producing sequences with elements from +// an STL-style container. +// ValuesIn(Iterator begin, Iterator end) +// - returns a generator producing sequences with elements from +// a range [begin, end) defined by a pair of STL-style iterators. These +// iterators can also be plain C pointers. +// +// Please note that ValuesIn copies the values from the containers +// passed in and keeps them to generate tests in RUN_ALL_TESTS(). +// +// Examples: +// +// This instantiates tests from test suite StringTest +// each with C-string values of "foo", "bar", and "baz": +// +// const char* strings[] = {"foo", "bar", "baz"}; +// INSTANTIATE_TEST_SUITE_P(StringSequence, StringTest, ValuesIn(strings)); +// +// This instantiates tests from test suite StlStringTest +// each with STL strings with values "a" and "b": +// +// ::std::vector< ::std::string> GetParameterStrings() { +// ::std::vector< ::std::string> v; +// v.push_back("a"); +// v.push_back("b"); +// return v; +// } +// +// INSTANTIATE_TEST_SUITE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); +// +// +// This will also instantiate tests from CharTest +// each with parameter values 'a' and 'b': +// +// ::std::list GetParameterChars() { +// ::std::list list; +// list.push_back('a'); +// list.push_back('b'); +// return list; +// } +// ::std::list l = GetParameterChars(); +// INSTANTIATE_TEST_SUITE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); +// +template +internal::ParamGenerator< + typename std::iterator_traits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end) { + typedef typename std::iterator_traits::value_type ParamType; + return internal::ParamGenerator( + new internal::ValuesInIteratorRangeGenerator(begin, end)); +} + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]) { + return ValuesIn(array, array + N); +} + +template +internal::ParamGenerator ValuesIn( + const Container& container) { + return ValuesIn(container.begin(), container.end()); +} + +// Values() allows generating tests from explicitly specified list of +// parameters. +// +// Synopsis: +// Values(T v1, T v2, ..., T vN) +// - returns a generator producing sequences with elements v1, v2, ..., vN. +// +// For example, this instantiates tests from test suite BarTest each +// with values "one", "two", and "three": +// +// INSTANTIATE_TEST_SUITE_P(NumSequence, +// BarTest, +// Values("one", "two", "three")); +// +// This instantiates tests from test suite BazTest each with values 1, 2, 3.5. +// The exact type of values will depend on the type of parameter in BazTest. +// +// INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// +// +template +internal::ValueArray Values(T... v) { + return internal::ValueArray(std::move(v)...); +} + +// Bool() allows generating tests with parameters in a set of (false, true). +// +// Synopsis: +// Bool() +// - returns a generator producing sequences with elements {false, true}. +// +// It is useful when testing code that depends on Boolean flags. Combinations +// of multiple flags can be tested when several Bool()'s are combined using +// Combine() function. +// +// In the following example all tests in the test suite FlagDependentTest +// will be instantiated twice with parameters false and true. +// +// class FlagDependentTest : public testing::TestWithParam { +// virtual void SetUp() { +// external_flag = GetParam(); +// } +// } +// INSTANTIATE_TEST_SUITE_P(BoolSequence, FlagDependentTest, Bool()); +// +inline internal::ParamGenerator Bool() { + return Values(false, true); +} + +// Combine() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements. +// +// Synopsis: +// Combine(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// std::tuple where T1, T2, ..., TN are the types +// of elements from sequences produces by gen1, gen2, ..., genN. +// +// Combine can have up to 10 arguments. +// +// Example: +// +// This will instantiate tests in test suite AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// class AnimalTest +// : public testing::TestWithParam > {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +// This will instantiate tests in FlagDependentTest with all variations of two +// Boolean flags: +// +// class FlagDependentTest +// : public testing::TestWithParam > { +// virtual void SetUp() { +// // Assigns external_flag_1 and external_flag_2 values from the tuple. +// std::tie(external_flag_1, external_flag_2) = GetParam(); +// } +// }; +// +// TEST_P(FlagDependentTest, TestFeature1) { +// // Test your code using external_flag_1 and external_flag_2 here. +// } +// INSTANTIATE_TEST_SUITE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template +internal::CartesianProductHolder Combine(const Generator&... g) { + return internal::CartesianProductHolder(g...); +} + +#define TEST_P(test_suite_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public test_suite_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + virtual void TestBody(); \ + \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder( \ + #test_suite_name, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestPattern( \ + GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name), \ + new ::testing::internal::TestMetaFactory()); \ + return 0; \ + } \ + static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() + +// The last argument to INSTANTIATE_TEST_SUITE_P allows the user to specify +// generator and an optional function or functor that generates custom test name +// suffixes based on the test parameters. Such a function or functor should +// accept one argument of type testing::TestParamInfo, and +// return std::string. +// +// testing::PrintToStringParamName is a builtin test suffix generator that +// returns the value of testing::PrintToString(GetParam()). +// +// Note: test names must be non-empty, unique, and may only contain ASCII +// alphanumeric characters or underscore. Because PrintToString adds quotes +// to std::string and C strings, it won't work for these types. + +#define GTEST_EXPAND_(arg) arg +#define GTEST_GET_FIRST_(first, ...) first +#define GTEST_GET_SECOND_(first, second, ...) second + +#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \ + static ::testing::internal::ParamGenerator \ + gtest_##prefix##test_suite_name##_EvalGenerator_() { \ + return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \ + } \ + static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo& info) { \ + if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName, \ + DUMMY_PARAM_))); \ + auto t = std::make_tuple(__VA_ARGS__); \ + static_assert(std::tuple_size::value <= 2, \ + "Too Many Args!"); \ + } \ + return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName, \ + DUMMY_PARAM_))))(info); \ + } \ + static int gtest_##prefix##test_suite_name##_dummy_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder( \ + #test_suite_name, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestSuiteInstantiation( \ + #prefix, >est_##prefix##test_suite_name##_EvalGenerator_, \ + >est_##prefix##test_suite_name##_EvalGenerateName_, \ + __FILE__, __LINE__) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TEST_CASE_P \ + static_assert(::testing::internal::InstantiateTestCase_P_IsDeprecated(), \ + ""); \ + INSTANTIATE_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-printers.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-printers.h new file mode 100644 index 0000000000000000000000000000000000000000..56a05450ef5e4ce13f5915c7acd5ef3e1a3655a9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-printers.h @@ -0,0 +1,928 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Google Test - The Google C++ Testing and Mocking Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// A user can teach this function how to print a class type T by +// defining either operator<<() or PrintTo() in the namespace that +// defines T. More specifically, the FIRST defined function in the +// following list will be used (assuming T is defined in namespace +// foo): +// +// 1. foo::PrintTo(const T&, ostream*) +// 2. operator<<(ostream&, const T&) defined in either foo or the +// global namespace. +// +// However if T is an STL-style container then it is printed element-wise +// unless foo::PrintTo(const T&, ostream*) is defined. Note that +// operator<<() is ignored for container types. +// +// If none of the above is defined, it will print the debug string of +// the value if it is a protocol buffer, or print the raw bytes in the +// value otherwise. +// +// To aid debugging: when T is a reference type, the address of the +// value is also printed; when T is a (const) char pointer, both the +// pointer value and the NUL-terminated string it points to are +// printed. +// +// We also provide some convenient wrappers: +// +// // Prints a value to a string. For a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// std::string ::testing::PrintToString(const T& value); +// +// // Prints a value tersely: for a reference type, the referenced +// // value (but not the address) is printed; for a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); +// +// // Prints value using the type inferred by the compiler. The difference +// // from UniversalTersePrint() is that this function prints both the +// // pointer and the NUL-terminated string for a (const or not) char pointer. +// void ::testing::internal::UniversalPrint(const T& value, ostream*); +// +// // Prints the fields of a tuple tersely to a string vector, one +// // element for each field. Tuple support must be enabled in +// // gtest-port.h. +// std::vector UniversalTersePrintTupleFieldsToStrings( +// const Tuple& value); +// +// Known limitation: +// +// The print primitives print the elements of an STL-style container +// using the compiler-inferred type of *iter where iter is a +// const_iterator of the container. When const_iterator is an input +// iterator but not a forward iterator, this inferred type may not +// match value_type, and the print output may be incorrect. In +// practice, this is rarely a problem as for most containers +// const_iterator is a forward iterator. We'll fix this if there's an +// actual need for it. Note that this fix cannot rely on value_type +// being defined as many user-defined container types don't have +// value_type. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ + +#include +#include // NOLINT +#include +#include +#include +#include +#include +#include +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" + +#if GTEST_HAS_ABSL +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/variant.h" +#endif // GTEST_HAS_ABSL + +namespace testing { + +// Definitions in the 'internal' and 'internal2' name spaces are +// subject to change without notice. DO NOT USE THEM IN USER CODE! +namespace internal2 { + +// Prints the given number of bytes in the given object to the given +// ostream. +GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, + size_t count, + ::std::ostream* os); + +// For selecting which printer to use when a given type has neither << +// nor PrintTo(). +enum TypeKind { + kProtobuf, // a protobuf type + kConvertibleToInteger, // a type implicitly convertible to BiggestInt + // (e.g. a named or unnamed enum type) +#if GTEST_HAS_ABSL + kConvertibleToStringView, // a type implicitly convertible to + // absl::string_view +#endif + kOtherType // anything else +}; + +// TypeWithoutFormatter::PrintValue(value, os) is called +// by the universal printer to print a value of type T when neither +// operator<< nor PrintTo() is defined for T, where kTypeKind is the +// "kind" of T as defined by enum TypeKind. +template +class TypeWithoutFormatter { + public: + // This default version is called when kTypeKind is kOtherType. + static void PrintValue(const T& value, ::std::ostream* os) { + PrintBytesInObjectTo( + static_cast( + reinterpret_cast(std::addressof(value))), + sizeof(value), os); + } +}; + +// We print a protobuf using its ShortDebugString() when the string +// doesn't exceed this many characters; otherwise we print it using +// DebugString() for better readability. +const size_t kProtobufOneLinerMaxLength = 50; + +template +class TypeWithoutFormatter { + public: + static void PrintValue(const T& value, ::std::ostream* os) { + std::string pretty_str = value.ShortDebugString(); + if (pretty_str.length() > kProtobufOneLinerMaxLength) { + pretty_str = "\n" + value.DebugString(); + } + *os << ("<" + pretty_str + ">"); + } +}; + +template +class TypeWithoutFormatter { + public: + // Since T has no << operator or PrintTo() but can be implicitly + // converted to BiggestInt, we print it as a BiggestInt. + // + // Most likely T is an enum type (either named or unnamed), in which + // case printing it as an integer is the desired behavior. In case + // T is not an enum, printing it as an integer is the best we can do + // given that it has no user-defined printer. + static void PrintValue(const T& value, ::std::ostream* os) { + const internal::BiggestInt kBigInt = value; + *os << kBigInt; + } +}; + +#if GTEST_HAS_ABSL +template +class TypeWithoutFormatter { + public: + // Since T has neither operator<< nor PrintTo() but can be implicitly + // converted to absl::string_view, we print it as a absl::string_view. + // + // Note: the implementation is further below, as it depends on + // internal::PrintTo symbol which is defined later in the file. + static void PrintValue(const T& value, ::std::ostream* os); +}; +#endif + +// Prints the given value to the given ostream. If the value is a +// protocol message, its debug string is printed; if it's an enum or +// of a type implicitly convertible to BiggestInt, it's printed as an +// integer; otherwise the bytes in the value are printed. This is +// what UniversalPrinter::Print() does when it knows nothing about +// type T and T has neither << operator nor PrintTo(). +// +// A user can override this behavior for a class type Foo by defining +// a << operator in the namespace where Foo is defined. +// +// We put this operator in namespace 'internal2' instead of 'internal' +// to simplify the implementation, as much code in 'internal' needs to +// use << in STL, which would conflict with our own << were it defined +// in 'internal'. +// +// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If +// we define it to take an std::ostream instead, we'll get an +// "ambiguous overloads" compiler error when trying to print a type +// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether +// operator<<(std::ostream&, const T&) or +// operator<<(std::basic_stream, const Foo&) is more +// specific. +template +::std::basic_ostream& operator<<( + ::std::basic_ostream& os, const T& x) { + TypeWithoutFormatter::value + ? kProtobuf + : std::is_convertible< + const T&, internal::BiggestInt>::value + ? kConvertibleToInteger + : +#if GTEST_HAS_ABSL + std::is_convertible< + const T&, absl::string_view>::value + ? kConvertibleToStringView + : +#endif + kOtherType)>::PrintValue(x, &os); + return os; +} + +} // namespace internal2 +} // namespace testing + +// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up +// magic needed for implementing UniversalPrinter won't work. +namespace testing_internal { + +// Used to print a value that is not an STL-style container when the +// user doesn't define PrintTo() for it. +template +void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { + // With the following statement, during unqualified name lookup, + // testing::internal2::operator<< appears as if it was declared in + // the nearest enclosing namespace that contains both + // ::testing_internal and ::testing::internal2, i.e. the global + // namespace. For more details, refer to the C++ Standard section + // 7.3.4-1 [namespace.udir]. This allows us to fall back onto + // testing::internal2::operator<< in case T doesn't come with a << + // operator. + // + // We cannot write 'using ::testing::internal2::operator<<;', which + // gcc 3.3 fails to compile due to a compiler bug. + using namespace ::testing::internal2; // NOLINT + + // Assuming T is defined in namespace foo, in the next statement, + // the compiler will consider all of: + // + // 1. foo::operator<< (thanks to Koenig look-up), + // 2. ::operator<< (as the current namespace is enclosed in ::), + // 3. testing::internal2::operator<< (thanks to the using statement above). + // + // The operator<< whose type matches T best will be picked. + // + // We deliberately allow #2 to be a candidate, as sometimes it's + // impossible to define #1 (e.g. when foo is ::std, defining + // anything in it is undefined behavior unless you are a compiler + // vendor.). + *os << value; +} + +} // namespace testing_internal + +namespace testing { +namespace internal { + +// FormatForComparison::Format(value) formats a +// value of type ToPrint that is an operand of a comparison assertion +// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in +// the comparison, and is used to help determine the best way to +// format the value. In particular, when the value is a C string +// (char pointer) and the other operand is an STL string object, we +// want to format the C string as a string, since we know it is +// compared by value with the string object. If the value is a char +// pointer but the other operand is not an STL string object, we don't +// know whether the pointer is supposed to point to a NUL-terminated +// string, and thus want to print it as a pointer to be safe. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// The default case. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint& value) { + return ::testing::PrintToString(value); + } +}; + +// Array. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint* value) { + return FormatForComparison::Format(value); + } +}; + +// By default, print C string as pointers to be safe, as we don't know +// whether they actually point to a NUL-terminated string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ + template \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(static_cast(value)); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ + +// If a C string is compared with an STL string object, we know it's meant +// to point to a NUL-terminated string, and thus can print it as a string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ + template <> \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(value); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); + +#if GTEST_HAS_STD_WSTRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); +#endif + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char* or void*, and print it as a C string when it is compared +// against an std::string object, for example. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +std::string FormatForComparisonFailureMessage( + const T1& value, const T2& /* other_operand */) { + return FormatForComparison::Format(value); +} + +// UniversalPrinter::Print(value, ostream_ptr) prints the given +// value to the given ostream. The caller must ensure that +// 'ostream_ptr' is not NULL, or the behavior is undefined. +// +// We define UniversalPrinter as a class template (as opposed to a +// function template), as we need to partially specialize it for +// reference types, which cannot be done with function templates. +template +class UniversalPrinter; + +template +void UniversalPrint(const T& value, ::std::ostream* os); + +enum DefaultPrinterType { + kPrintContainer, + kPrintPointer, + kPrintFunctionPointer, + kPrintOther, +}; +template struct WrapPrinterType {}; + +// Used to print an STL-style container when the user doesn't define +// a PrintTo() for it. +template +void DefaultPrintTo(WrapPrinterType /* dummy */, + const C& container, ::std::ostream* os) { + const size_t kMaxCount = 32; // The maximum number of elements to print. + *os << '{'; + size_t count = 0; + for (typename C::const_iterator it = container.begin(); + it != container.end(); ++it, ++count) { + if (count > 0) { + *os << ','; + if (count == kMaxCount) { // Enough has been printed. + *os << " ..."; + break; + } + } + *os << ' '; + // We cannot call PrintTo(*it, os) here as PrintTo() doesn't + // handle *it being a native array. + internal::UniversalPrint(*it, os); + } + + if (count > 0) { + *os << ' '; + } + *os << '}'; +} + +// Used to print a pointer that is neither a char pointer nor a member +// pointer, when the user doesn't define PrintTo() for it. (A member +// variable pointer or member function pointer doesn't really point to +// a location in the address space. Their representation is +// implementation-defined. Therefore they will be printed as raw +// bytes.) +template +void DefaultPrintTo(WrapPrinterType /* dummy */, + T* p, ::std::ostream* os) { + if (p == nullptr) { + *os << "NULL"; + } else { + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } +} +template +void DefaultPrintTo(WrapPrinterType /* dummy */, + T* p, ::std::ostream* os) { + if (p == nullptr) { + *os << "NULL"; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. + *os << reinterpret_cast(p); + } +} + +// Used to print a non-container, non-pointer value when the user +// doesn't define PrintTo() for it. +template +void DefaultPrintTo(WrapPrinterType /* dummy */, + const T& value, ::std::ostream* os) { + ::testing_internal::DefaultPrintNonContainerTo(value, os); +} + +// Prints the given value using the << operator if it has one; +// otherwise prints the bytes in it. This is what +// UniversalPrinter::Print() does when PrintTo() is not specialized +// or overloaded for type T. +// +// A user can override this behavior for a class type Foo by defining +// an overload of PrintTo() in the namespace where Foo is defined. We +// give the user this option as sometimes defining a << operator for +// Foo is not desirable (e.g. the coding style may prevent doing it, +// or there is already a << operator but it doesn't do what the user +// wants). +template +void PrintTo(const T& value, ::std::ostream* os) { + // DefaultPrintTo() is overloaded. The type of its first argument + // determines which version will be picked. + // + // Note that we check for container types here, prior to we check + // for protocol message types in our operator<<. The rationale is: + // + // For protocol messages, we want to give people a chance to + // override Google Mock's format by defining a PrintTo() or + // operator<<. For STL containers, other formats can be + // incompatible with Google Mock's format for the container + // elements; therefore we check for container types here to ensure + // that our format is used. + // + // Note that MSVC and clang-cl do allow an implicit conversion from + // pointer-to-function to pointer-to-object, but clang-cl warns on it. + // So don't use ImplicitlyConvertible if it can be helped since it will + // cause this warning, and use a separate overload of DefaultPrintTo for + // function pointers so that the `*os << p` in the object pointer overload + // doesn't cause that warning either. + DefaultPrintTo( + WrapPrinterType < + (sizeof(IsContainerTest(0)) == sizeof(IsContainer)) && + !IsRecursiveContainer::value + ? kPrintContainer + : !std::is_pointer::value + ? kPrintOther + : std::is_function::type>::value + ? kPrintFunctionPointer + : kPrintPointer > (), + value, os); +} + +// The following list of PrintTo() overloads tells +// UniversalPrinter::Print() how to print standard types (built-in +// types, strings, plain arrays, and pointers). + +// Overloads for various char types. +GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); +GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); +inline void PrintTo(char c, ::std::ostream* os) { + // When printing a plain char, we always treat it as unsigned. This + // way, the output won't be affected by whether the compiler thinks + // char is signed or not. + PrintTo(static_cast(c), os); +} + +// Overloads for other simple built-in types. +inline void PrintTo(bool x, ::std::ostream* os) { + *os << (x ? "true" : "false"); +} + +// Overload for wchar_t type. +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); + +// Overloads for C strings. +GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); +inline void PrintTo(char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// signed/unsigned char is often used for representing binary data, so +// we print pointers to it as void* to be safe. +inline void PrintTo(const signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(const unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// MSVC can be configured to define wchar_t as a typedef of unsigned +// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native +// type. When wchar_t is a typedef, defining an overload for const +// wchar_t* would cause unsigned short* be printed as a wide string, +// possibly causing invalid memory accesses. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Overloads for wide C strings +GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); +inline void PrintTo(wchar_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +#endif + +// Overload for C arrays. Multi-dimensional arrays are printed +// properly. + +// Prints the given number of elements in an array, without printing +// the curly braces. +template +void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { + UniversalPrint(a[0], os); + for (size_t i = 1; i != count; i++) { + *os << ", "; + UniversalPrint(a[i], os); + } +} + +// Overloads for ::std::string. +GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); +inline void PrintTo(const ::std::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} + +// Overloads for ::std::wstring. +#if GTEST_HAS_STD_WSTRING +GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_ABSL +// Overload for absl::string_view. +inline void PrintTo(absl::string_view sp, ::std::ostream* os) { + PrintTo(::std::string(sp), os); +} +#endif // GTEST_HAS_ABSL + +inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } + +template +void PrintTo(std::reference_wrapper ref, ::std::ostream* os) { + UniversalPrinter::Print(ref.get(), os); +} + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T&, std::integral_constant, + ::std::ostream*) {} + +template +void PrintTupleTo(const T& t, std::integral_constant, + ::std::ostream* os) { + PrintTupleTo(t, std::integral_constant(), os); + GTEST_INTENTIONAL_CONST_COND_PUSH_() + if (I > 1) { + GTEST_INTENTIONAL_CONST_COND_POP_() + *os << ", "; + } + UniversalPrinter::type>::Print( + std::get(t), os); +} + +template +void PrintTo(const ::std::tuple& t, ::std::ostream* os) { + *os << "("; + PrintTupleTo(t, std::integral_constant(), os); + *os << ")"; +} + +// Overload for std::pair. +template +void PrintTo(const ::std::pair& value, ::std::ostream* os) { + *os << '('; + // We cannot use UniversalPrint(value.first, os) here, as T1 may be + // a reference type. The same for printing value.second. + UniversalPrinter::Print(value.first, os); + *os << ", "; + UniversalPrinter::Print(value.second, os); + *os << ')'; +} + +// Implements printing a non-reference type T by letting the compiler +// pick the right overload of PrintTo() for T. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) + + // Note: we deliberately don't call this PrintTo(), as that name + // conflicts with ::testing::internal::PrintTo in the body of the + // function. + static void Print(const T& value, ::std::ostream* os) { + // By default, ::testing::internal::PrintTo() is used for printing + // the value. + // + // Thanks to Koenig look-up, if T is a class and has its own + // PrintTo() function defined in its namespace, that function will + // be visible here. Since it is more specific than the generic ones + // in ::testing::internal, it will be picked by the compiler in the + // following statement - exactly what we want. + PrintTo(value, os); + } + + GTEST_DISABLE_MSC_WARNINGS_POP_() +}; + +#if GTEST_HAS_ABSL + +// Printer for absl::optional + +template +class UniversalPrinter<::absl::optional> { + public: + static void Print(const ::absl::optional& value, ::std::ostream* os) { + *os << '('; + if (!value) { + *os << "nullopt"; + } else { + UniversalPrint(*value, os); + } + *os << ')'; + } +}; + +// Printer for absl::variant + +template +class UniversalPrinter<::absl::variant> { + public: + static void Print(const ::absl::variant& value, ::std::ostream* os) { + *os << '('; + absl::visit(Visitor{os}, value); + *os << ')'; + } + + private: + struct Visitor { + template + void operator()(const U& u) const { + *os << "'" << GetTypeName() << "' with value "; + UniversalPrint(u, os); + } + ::std::ostream* os; + }; +}; + +#endif // GTEST_HAS_ABSL + +// UniversalPrintArray(begin, len, os) prints an array of 'len' +// elements, starting at address 'begin'. +template +void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { + if (len == 0) { + *os << "{}"; + } else { + *os << "{ "; + const size_t kThreshold = 18; + const size_t kChunkSize = 8; + // If the array has more than kThreshold elements, we'll have to + // omit some details by printing only the first and the last + // kChunkSize elements. + if (len <= kThreshold) { + PrintRawArrayTo(begin, len, os); + } else { + PrintRawArrayTo(begin, kChunkSize, os); + *os << ", ..., "; + PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); + } + *os << " }"; + } +} +// This overload prints a (const) char array compactly. +GTEST_API_ void UniversalPrintArray( + const char* begin, size_t len, ::std::ostream* os); + +// This overload prints a (const) wchar_t array compactly. +GTEST_API_ void UniversalPrintArray( + const wchar_t* begin, size_t len, ::std::ostream* os); + +// Implements printing an array type T[N]. +template +class UniversalPrinter { + public: + // Prints the given array, omitting some elements when there are too + // many. + static void Print(const T (&a)[N], ::std::ostream* os) { + UniversalPrintArray(a, N, os); + } +}; + +// Implements printing a reference type T&. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) + + static void Print(const T& value, ::std::ostream* os) { + // Prints the address of the value. We use reinterpret_cast here + // as static_cast doesn't compile when T is a function type. + *os << "@" << reinterpret_cast(&value) << " "; + + // Then prints the value itself. + UniversalPrint(value, os); + } + + GTEST_DISABLE_MSC_WARNINGS_POP_() +}; + +// Prints a value tersely: for a reference type, the referenced value +// (but not the address) is printed; for a (const) char pointer, the +// NUL-terminated string (but not the pointer) is printed. + +template +class UniversalTersePrinter { + public: + static void Print(const T& value, ::std::ostream* os) { + UniversalPrint(value, os); + } +}; +template +class UniversalTersePrinter { + public: + static void Print(const T& value, ::std::ostream* os) { + UniversalPrint(value, os); + } +}; +template +class UniversalTersePrinter { + public: + static void Print(const T (&value)[N], ::std::ostream* os) { + UniversalPrinter::Print(value, os); + } +}; +template <> +class UniversalTersePrinter { + public: + static void Print(const char* str, ::std::ostream* os) { + if (str == nullptr) { + *os << "NULL"; + } else { + UniversalPrint(std::string(str), os); + } + } +}; +template <> +class UniversalTersePrinter { + public: + static void Print(char* str, ::std::ostream* os) { + UniversalTersePrinter::Print(str, os); + } +}; + +#if GTEST_HAS_STD_WSTRING +template <> +class UniversalTersePrinter { + public: + static void Print(const wchar_t* str, ::std::ostream* os) { + if (str == nullptr) { + *os << "NULL"; + } else { + UniversalPrint(::std::wstring(str), os); + } + } +}; +#endif + +template <> +class UniversalTersePrinter { + public: + static void Print(wchar_t* str, ::std::ostream* os) { + UniversalTersePrinter::Print(str, os); + } +}; + +template +void UniversalTersePrint(const T& value, ::std::ostream* os) { + UniversalTersePrinter::Print(value, os); +} + +// Prints a value using the type inferred by the compiler. The +// difference between this and UniversalTersePrint() is that for a +// (const) char pointer, this prints both the pointer and the +// NUL-terminated string. +template +void UniversalPrint(const T& value, ::std::ostream* os) { + // A workarond for the bug in VC++ 7.1 that prevents us from instantiating + // UniversalPrinter with T directly. + typedef T T1; + UniversalPrinter::Print(value, os); +} + +typedef ::std::vector< ::std::string> Strings; + + // Tersely prints the first N fields of a tuple to a string vector, + // one element for each field. +template +void TersePrintPrefixToStrings(const Tuple&, std::integral_constant, + Strings*) {} +template +void TersePrintPrefixToStrings(const Tuple& t, + std::integral_constant, + Strings* strings) { + TersePrintPrefixToStrings(t, std::integral_constant(), + strings); + ::std::stringstream ss; + UniversalTersePrint(std::get(t), &ss); + strings->push_back(ss.str()); +} + +// Prints the fields of a tuple tersely to a string vector, one +// element for each field. See the comment before +// UniversalTersePrint() for how we define "tersely". +template +Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { + Strings result; + TersePrintPrefixToStrings( + value, std::integral_constant::value>(), + &result); + return result; +} + +} // namespace internal + +#if GTEST_HAS_ABSL +namespace internal2 { +template +void TypeWithoutFormatter::PrintValue( + const T& value, ::std::ostream* os) { + internal::PrintTo(absl::string_view(value), os); +} +} // namespace internal2 +#endif + +template +::std::string PrintToString(const T& value) { + ::std::stringstream ss; + internal::UniversalTersePrinter::Print(value, &ss); + return ss.str(); +} + +} // namespace testing + +// Include any custom printer added by the local installation. +// We must include this header at the end to make sure it can use the +// declarations from this file. +#include "gtest/internal/custom/gtest-printers.h" + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-spi.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-spi.h new file mode 100644 index 0000000000000000000000000000000000000000..aa38870e8e1c91294e73cf4e8cb41d7f32764e8e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-spi.h @@ -0,0 +1,238 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Utilities for testing Google Test itself and code that uses Google Test +// (e.g. frameworks built on top of Google Test). + +// GOOGLETEST_CM0004 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + +#include "gtest/gtest.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { + +// This helper class can be used to mock out Google Test failure reporting +// so that we can test Google Test or code that builds on Google Test. +// +// An object of this class appends a TestPartResult object to the +// TestPartResultArray object given in the constructor whenever a Google Test +// failure is reported. It can either intercept only failures that are +// generated in the same thread that created this object or it can intercept +// all generated failures. The scope of this mock object can be controlled with +// the second argument to the two arguments constructor. +class GTEST_API_ ScopedFakeTestPartResultReporter + : public TestPartResultReporterInterface { + public: + // The two possible mocking modes of this object. + enum InterceptMode { + INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. + INTERCEPT_ALL_THREADS // Intercepts all failures. + }; + + // The c'tor sets this object as the test part result reporter used + // by Google Test. The 'result' parameter specifies where to report the + // results. This reporter will only catch failures generated in the current + // thread. DEPRECATED + explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); + + // Same as above, but you can choose the interception scope of this object. + ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, + TestPartResultArray* result); + + // The d'tor restores the previous test part result reporter. + ~ScopedFakeTestPartResultReporter() override; + + // Appends the TestPartResult object to the TestPartResultArray + // received in the constructor. + // + // This method is from the TestPartResultReporterInterface + // interface. + void ReportTestPartResult(const TestPartResult& result) override; + + private: + void Init(); + + const InterceptMode intercept_mode_; + TestPartResultReporterInterface* old_reporter_; + TestPartResultArray* const result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); +}; + +namespace internal { + +// A helper class for implementing EXPECT_FATAL_FAILURE() and +// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +class GTEST_API_ SingleFailureChecker { + public: + // The constructor remembers the arguments. + SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, const std::string& substr); + ~SingleFailureChecker(); + private: + const TestPartResultArray* const results_; + const TestPartResult::Type type_; + const std::string substr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); +}; + +} // namespace internal + +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +// A set of macros for testing Google Test assertions or code that's expected +// to generate Google Test fatal failures. It verifies that the given +// statement will cause exactly one fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_FATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - 'statement' cannot reference local non-static variables or +// non-static members of the current object. +// - 'statement' cannot return a value. +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. The AcceptsMacroThatExpandsToUnprotectedComma test in +// gtest_unittest.cc will fail to compile if we do that. +#define EXPECT_FATAL_FAILURE(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ALL_THREADS, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +// A macro for testing Google Test assertions or code that's expected to +// generate Google Test non-fatal failures. It asserts that the given +// statement will cause exactly one non-fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// 'statement' is allowed to reference local variables and members of +// the current object. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. If we do that, the code won't compile when the user gives +// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that +// expands to code containing an unprotected comma. The +// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc +// catches that. +// +// For the same reason, we have to write +// if (::testing::internal::AlwaysTrue()) { statement; } +// instead of +// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) +// to avoid an MSVC warning on unreachable code. +#define EXPECT_NONFATAL_FAILURE(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ + >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-test-part.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-test-part.h new file mode 100644 index 0000000000000000000000000000000000000000..05a79853586a911c49ddf910fa1f0595e338265e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-test-part.h @@ -0,0 +1,184 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ + +#include +#include +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { + +// A copyable object representing the result of a test part (i.e. an +// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). +// +// Don't inherit from TestPartResult as its destructor is not virtual. +class GTEST_API_ TestPartResult { + public: + // The possible outcomes of a test part (i.e. an assertion or an + // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). + enum Type { + kSuccess, // Succeeded. + kNonFatalFailure, // Failed but the test can continue. + kFatalFailure, // Failed and the test should be terminated. + kSkip // Skipped. + }; + + // C'tor. TestPartResult does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestPartResult object. + TestPartResult(Type a_type, const char* a_file_name, int a_line_number, + const char* a_message) + : type_(a_type), + file_name_(a_file_name == nullptr ? "" : a_file_name), + line_number_(a_line_number), + summary_(ExtractSummary(a_message)), + message_(a_message) {} + + // Gets the outcome of the test part. + Type type() const { return type_; } + + // Gets the name of the source file where the test part took place, or + // NULL if it's unknown. + const char* file_name() const { + return file_name_.empty() ? nullptr : file_name_.c_str(); + } + + // Gets the line in the source file where the test part took place, + // or -1 if it's unknown. + int line_number() const { return line_number_; } + + // Gets the summary of the failure message. + const char* summary() const { return summary_.c_str(); } + + // Gets the message associated with the test part. + const char* message() const { return message_.c_str(); } + + // Returns true if and only if the test part was skipped. + bool skipped() const { return type_ == kSkip; } + + // Returns true if and only if the test part passed. + bool passed() const { return type_ == kSuccess; } + + // Returns true if and only if the test part non-fatally failed. + bool nonfatally_failed() const { return type_ == kNonFatalFailure; } + + // Returns true if and only if the test part fatally failed. + bool fatally_failed() const { return type_ == kFatalFailure; } + + // Returns true if and only if the test part failed. + bool failed() const { return fatally_failed() || nonfatally_failed(); } + + private: + Type type_; + + // Gets the summary of the failure message by omitting the stack + // trace in it. + static std::string ExtractSummary(const char* message); + + // The name of the source file where the test part took place, or + // "" if the source file is unknown. + std::string file_name_; + // The line in the source file where the test part took place, or -1 + // if the line number is unknown. + int line_number_; + std::string summary_; // The test failure summary. + std::string message_; // The test failure message. +}; + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result); + +// An array of TestPartResult objects. +// +// Don't inherit from TestPartResultArray as its destructor is not +// virtual. +class GTEST_API_ TestPartResultArray { + public: + TestPartResultArray() {} + + // Appends the given TestPartResult to the array. + void Append(const TestPartResult& result); + + // Returns the TestPartResult at the given index (0-based). + const TestPartResult& GetTestPartResult(int index) const; + + // Returns the number of TestPartResult objects in the array. + int size() const; + + private: + std::vector array_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); +}; + +// This interface knows how to report a test part result. +class GTEST_API_ TestPartResultReporterInterface { + public: + virtual ~TestPartResultReporterInterface() {} + + virtual void ReportTestPartResult(const TestPartResult& result) = 0; +}; + +namespace internal { + +// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a +// statement generates new fatal failures. To do so it registers itself as the +// current test part result reporter. Besides checking if fatal failures were +// reported, it only delegates the reporting to the former result reporter. +// The original result reporter is restored in the destructor. +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +class GTEST_API_ HasNewFatalFailureHelper + : public TestPartResultReporterInterface { + public: + HasNewFatalFailureHelper(); + ~HasNewFatalFailureHelper() override; + void ReportTestPartResult(const TestPartResult& result) override; + bool has_new_fatal_failure() const { return has_new_fatal_failure_; } + private: + bool has_new_fatal_failure_; + TestPartResultReporterInterface* original_reporter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); +}; + +} // namespace internal + +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-typed-test.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-typed-test.h new file mode 100644 index 0000000000000000000000000000000000000000..095ce058022f892169664e29ea2bc528f960576b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest-typed-test.h @@ -0,0 +1,330 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// This header implements typed tests and type-parameterized tests. + +// Typed (aka type-driven) tests repeat the same test for types in a +// list. You must know which types you want to test with when writing +// typed tests. Here's how you do it: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + public: + ... + typedef std::list List; + static T shared_; + T value_; +}; + +// Next, associate a list of types with the test suite, which will be +// repeated for each type in the list. The typedef is necessary for +// the macro to parse correctly. +typedef testing::Types MyTypes; +TYPED_TEST_SUITE(FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// TYPED_TEST_SUITE(FooTest, int); + +// Then, use TYPED_TEST() instead of TEST_F() to define as many typed +// tests for this test suite as you want. +TYPED_TEST(FooTest, DoesBlah) { + // Inside a test, refer to the special name TypeParam to get the type + // parameter. Since we are inside a derived class template, C++ requires + // us to visit the members of FooTest via 'this'. + TypeParam n = this->value_; + + // To visit static members of the fixture, add the TestFixture:: + // prefix. + n += TestFixture::shared_; + + // To refer to typedefs in the fixture, add the "typename + // TestFixture::" prefix. + typename TestFixture::List values; + values.push_back(n); + ... +} + +TYPED_TEST(FooTest, HasPropertyA) { ... } + +// TYPED_TEST_SUITE takes an optional third argument which allows to specify a +// class that generates custom test name suffixes based on the type. This should +// be a class which has a static template function GetName(int index) returning +// a string for each type. The provided integer index equals the index of the +// type in the provided type list. In many cases the index can be ignored. +// +// For example: +// class MyTypeNames { +// public: +// template +// static std::string GetName(int) { +// if (std::is_same()) return "char"; +// if (std::is_same()) return "int"; +// if (std::is_same()) return "unsignedInt"; +// } +// }; +// TYPED_TEST_SUITE(FooTest, MyTypes, MyTypeNames); + +#endif // 0 + +// Type-parameterized tests are abstract test patterns parameterized +// by a type. Compared with typed tests, type-parameterized tests +// allow you to define the test pattern without knowing what the type +// parameters are. The defined pattern can be instantiated with +// different types any number of times, in any number of translation +// units. +// +// If you are designing an interface or concept, you can define a +// suite of type-parameterized tests to verify properties that any +// valid implementation of the interface/concept should have. Then, +// each implementation can easily instantiate the test suite to verify +// that it conforms to the requirements, without having to write +// similar tests repeatedly. Here's an example: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + ... +}; + +// Next, declare that you will define a type-parameterized test suite +// (the _P suffix is for "parameterized" or "pattern", whichever you +// prefer): +TYPED_TEST_SUITE_P(FooTest); + +// Then, use TYPED_TEST_P() to define as many type-parameterized tests +// for this type-parameterized test suite as you want. +TYPED_TEST_P(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + TypeParam n = 0; + ... +} + +TYPED_TEST_P(FooTest, HasPropertyA) { ... } + +// Now the tricky part: you need to register all test patterns before +// you can instantiate them. The first argument of the macro is the +// test suite name; the rest are the names of the tests in this test +// case. +REGISTER_TYPED_TEST_SUITE_P(FooTest, + DoesBlah, HasPropertyA); + +// Finally, you are free to instantiate the pattern with the types you +// want. If you put the above code in a header file, you can #include +// it in multiple C++ source files and instantiate it multiple times. +// +// To distinguish different instances of the pattern, the first +// argument to the INSTANTIATE_* macro is a prefix that will be added +// to the actual test suite name. Remember to pick unique prefixes for +// different instances. +typedef testing::Types MyTypes; +INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int); +// +// Similar to the optional argument of TYPED_TEST_SUITE above, +// INSTANTIATE_TEST_SUITE_P takes an optional fourth argument which allows to +// generate custom names. +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes, MyTypeNames); + +#endif // 0 + +#include "gtest/internal/gtest-port.h" +#include "gtest/internal/gtest-type-util.h" + +// Implements typed tests. + +#if GTEST_HAS_TYPED_TEST + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the typedef for the type parameters of the +// given test suite. +#define GTEST_TYPE_PARAMS_(TestSuiteName) gtest_type_params_##TestSuiteName##_ + +// Expands to the name of the typedef for the NameGenerator, responsible for +// creating the suffixes of the name. +#define GTEST_NAME_GENERATOR_(TestSuiteName) \ + gtest_type_params_##TestSuiteName##_NameGenerator + +#define TYPED_TEST_SUITE(CaseName, Types, ...) \ + typedef ::testing::internal::TypeList::type GTEST_TYPE_PARAMS_( \ + CaseName); \ + typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ + GTEST_NAME_GENERATOR_(CaseName) + +# define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##CaseName##_##TestName##_registered_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel, \ + GTEST_TYPE_PARAMS_( \ + CaseName)>::Register("", \ + ::testing::internal::CodeLocation( \ + __FILE__, __LINE__), \ + #CaseName, #TestName, 0, \ + ::testing::internal::GenerateNames< \ + GTEST_NAME_GENERATOR_(CaseName), \ + GTEST_TYPE_PARAMS_(CaseName)>()); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, \ + TestName)::TestBody() + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE \ + static_assert(::testing::internal::TypedTestCaseIsDeprecated(), ""); \ + TYPED_TEST_SUITE +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#endif // GTEST_HAS_TYPED_TEST + +// Implements type-parameterized tests. + +#if GTEST_HAS_TYPED_TEST_P + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the namespace name that the type-parameterized tests for +// the given type-parameterized test suite are defined in. The exact +// name of the namespace is subject to change without notice. +#define GTEST_SUITE_NAMESPACE_(TestSuiteName) gtest_suite_##TestSuiteName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the variable used to remember the names of +// the defined tests in the given test suite. +#define GTEST_TYPED_TEST_SUITE_P_STATE_(TestSuiteName) \ + gtest_typed_test_suite_p_state_##TestSuiteName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. +// +// Expands to the name of the variable used to remember the names of +// the registered tests in the given test suite. +#define GTEST_REGISTERED_TEST_NAMES_(TestSuiteName) \ + gtest_registered_test_names_##TestSuiteName##_ + +// The variables defined in the type-parameterized test macros are +// static as typically these macros are used in a .h file that can be +// #included in multiple translation units linked together. +#define TYPED_TEST_SUITE_P(SuiteName) \ + static ::testing::internal::TypedTestSuitePState \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE_P \ + static_assert(::testing::internal::TypedTestCase_P_IsDeprecated(), ""); \ + TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#define TYPED_TEST_P(SuiteName, TestName) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + template \ + class TestName : public SuiteName { \ + private: \ + typedef SuiteName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \ + __FILE__, __LINE__, #SuiteName, #TestName); \ + } \ + template \ + void GTEST_SUITE_NAMESPACE_( \ + SuiteName)::TestName::TestBody() + +#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_( \ + SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \ + __FILE__, __LINE__, #__VA_ARGS__) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define REGISTER_TYPED_TEST_CASE_P \ + static_assert(::testing::internal::RegisterTypedTestCase_P_IsDeprecated(), \ + ""); \ + REGISTER_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \ + static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestSuite< \ + SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \ + ::testing::internal::TypeList::type>:: \ + Register(#Prefix, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), \ + >EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), #SuiteName, \ + GTEST_REGISTERED_TEST_NAMES_(SuiteName), \ + ::testing::internal::GenerateNames< \ + ::testing::internal::NameGeneratorSelector< \ + __VA_ARGS__>::type, \ + ::testing::internal::TypeList::type>()) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TYPED_TEST_CASE_P \ + static_assert( \ + ::testing::internal::InstantiateTypedTestCase_P_IsDeprecated(), ""); \ + INSTANTIATE_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest.h new file mode 100644 index 0000000000000000000000000000000000000000..dbe5b1c2c3f647f9d707e2e4ceb1d0c0d2aac7dd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest.h @@ -0,0 +1,2478 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines the public API for Google Test. It should be +// included by any test program that uses Google Test. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! +// +// Acknowledgment: Google Test borrowed the idea of automatic test +// registration from Barthelemy Dagenais' (barthelemy@prologique.com) +// easyUnit framework. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_H_ + +#include +#include +#include +#include +#include +#include + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" +#include "gtest/gtest-death-test.h" +#include "gtest/gtest-matchers.h" +#include "gtest/gtest-message.h" +#include "gtest/gtest-param-test.h" +#include "gtest/gtest-printers.h" +#include "gtest/gtest_prod.h" +#include "gtest/gtest-test-part.h" +#include "gtest/gtest-typed-test.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { + +// Silence C4100 (unreferenced formal parameter) and 4805 +// unsafe mix of type 'const int' and type 'const bool' +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4805) +# pragma warning(disable:4100) +#endif + + +// Declares the flags. + +// This flag temporary enables the disabled tests. +GTEST_DECLARE_bool_(also_run_disabled_tests); + +// This flag brings the debugger on an assertion failure. +GTEST_DECLARE_bool_(break_on_failure); + +// This flag controls whether Google Test catches all test-thrown exceptions +// and logs them as failures. +GTEST_DECLARE_bool_(catch_exceptions); + +// This flag enables using colors in terminal output. Available values are +// "yes" to enable colors, "no" (disable colors), or "auto" (the default) +// to let Google Test decide. +GTEST_DECLARE_string_(color); + +// This flag sets up the filter to select by name using a glob pattern +// the tests to run. If the filter is not given all tests are executed. +GTEST_DECLARE_string_(filter); + +// This flag controls whether Google Test installs a signal handler that dumps +// debugging information when fatal signals are raised. +GTEST_DECLARE_bool_(install_failure_signal_handler); + +// This flag causes the Google Test to list tests. None of the tests listed +// are actually run if the flag is provided. +GTEST_DECLARE_bool_(list_tests); + +// This flag controls whether Google Test emits a detailed XML report to a file +// in addition to its normal textual output. +GTEST_DECLARE_string_(output); + +// This flags control whether Google Test prints the elapsed time for each +// test. +GTEST_DECLARE_bool_(print_time); + +// This flags control whether Google Test prints UTF8 characters as text. +GTEST_DECLARE_bool_(print_utf8); + +// This flag specifies the random number seed. +GTEST_DECLARE_int32_(random_seed); + +// This flag sets how many times the tests are repeated. The default value +// is 1. If the value is -1 the tests are repeating forever. +GTEST_DECLARE_int32_(repeat); + +// This flag controls whether Google Test includes Google Test internal +// stack frames in failure stack traces. +GTEST_DECLARE_bool_(show_internal_stack_frames); + +// When this flag is specified, tests' order is randomized on every iteration. +GTEST_DECLARE_bool_(shuffle); + +// This flag specifies the maximum number of stack frames to be +// printed in a failure message. +GTEST_DECLARE_int32_(stack_trace_depth); + +// When this flag is specified, a failed assertion will throw an +// exception if exceptions are enabled, or exit the program with a +// non-zero code otherwise. For use with an external test framework. +GTEST_DECLARE_bool_(throw_on_failure); + +// When this flag is set with a "host:port" string, on supported +// platforms test results are streamed to the specified port on +// the specified host machine. +GTEST_DECLARE_string_(stream_result_to); + +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +GTEST_DECLARE_string_(flagfile); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + +// The upper limit for valid stack trace depths. +const int kMaxStackTraceDepth = 100; + +namespace internal { + +class AssertHelper; +class DefaultGlobalTestPartResultReporter; +class ExecDeathTest; +class NoExecDeathTest; +class FinalSuccessChecker; +class GTestFlagSaver; +class StreamingListenerTest; +class TestResultAccessor; +class TestEventListenersAccessor; +class TestEventRepeater; +class UnitTestRecordPropertyTestHelper; +class WindowsDeathTest; +class FuchsiaDeathTest; +class UnitTestImpl* GetUnitTestImpl(); +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const std::string& message); + +} // namespace internal + +// The friend relationship of some of these classes is cyclic. +// If we don't forward declare them the compiler might confuse the classes +// in friendship clauses with same named classes on the scope. +class Test; +class TestSuite; + +// Old API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TestCase = TestSuite; +#endif +class TestInfo; +class UnitTest; + +// A class for indicating whether an assertion was successful. When +// the assertion wasn't successful, the AssertionResult object +// remembers a non-empty message that describes how it failed. +// +// To create an instance of this class, use one of the factory functions +// (AssertionSuccess() and AssertionFailure()). +// +// This class is useful for two purposes: +// 1. Defining predicate functions to be used with Boolean test assertions +// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts +// 2. Defining predicate-format functions to be +// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). +// +// For example, if you define IsEven predicate: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) +// will print the message +// +// Value of: IsEven(Fib(5)) +// Actual: false (5 is odd) +// Expected: true +// +// instead of a more opaque +// +// Value of: IsEven(Fib(5)) +// Actual: false +// Expected: true +// +// in case IsEven is a simple Boolean predicate. +// +// If you expect your predicate to be reused and want to support informative +// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up +// about half as often as positive ones in our tests), supply messages for +// both success and failure cases: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess() << n << " is even"; +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print +// +// Value of: IsEven(Fib(6)) +// Actual: true (8 is even) +// Expected: false +// +// NB: Predicates that support negative Boolean assertions have reduced +// performance in positive ones so be careful not to use them in tests +// that have lots (tens of thousands) of positive Boolean assertions. +// +// To use this class with EXPECT_PRED_FORMAT assertions such as: +// +// // Verifies that Foo() returns an even number. +// EXPECT_PRED_FORMAT1(IsEven, Foo()); +// +// you need to define: +// +// testing::AssertionResult IsEven(const char* expr, int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() +// << "Expected: " << expr << " is even\n Actual: it's " << n; +// } +// +// If Foo() returns 5, you will see the following message: +// +// Expected: Foo() is even +// Actual: it's 5 +// +class GTEST_API_ AssertionResult { + public: + // Copy constructor. + // Used in EXPECT_TRUE/FALSE(assertion_result). + AssertionResult(const AssertionResult& other); + +#if defined(_MSC_VER) && _MSC_VER < 1910 + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) +#endif + + // Used in the EXPECT_TRUE/FALSE(bool_expression). + // + // T must be contextually convertible to bool. + // + // The second parameter prevents this overload from being considered if + // the argument is implicitly convertible to AssertionResult. In that case + // we want AssertionResult's copy constructor to be used. + template + explicit AssertionResult( + const T& success, + typename std::enable_if< + !std::is_convertible::value>::type* + /*enabler*/ + = nullptr) + : success_(success) {} + +#if defined(_MSC_VER) && _MSC_VER < 1910 + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + + // Assignment operator. + AssertionResult& operator=(AssertionResult other) { + swap(other); + return *this; + } + + // Returns true if and only if the assertion succeeded. + operator bool() const { return success_; } // NOLINT + + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. + AssertionResult operator!() const; + + // Returns the text streamed into this AssertionResult. Test assertions + // use it when they fail (i.e., the predicate's outcome doesn't match the + // assertion's expectation). When nothing has been streamed into the + // object, returns an empty string. + const char* message() const { + return message_.get() != nullptr ? message_->c_str() : ""; + } + // Deprecated; please use message() instead. + const char* failure_message() const { return message(); } + + // Streams a custom failure message into this object. + template AssertionResult& operator<<(const T& value) { + AppendMessage(Message() << value); + return *this; + } + + // Allows streaming basic output manipulators such as endl or flush into + // this object. + AssertionResult& operator<<( + ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { + AppendMessage(Message() << basic_manipulator); + return *this; + } + + private: + // Appends the contents of message to message_. + void AppendMessage(const Message& a_message) { + if (message_.get() == nullptr) message_.reset(new ::std::string); + message_->append(a_message.GetString().c_str()); + } + + // Swap the contents of this AssertionResult with other. + void swap(AssertionResult& other); + + // Stores result of the assertion predicate. + bool success_; + // Stores the message describing the condition in case the expectation + // construct is not satisfied with the predicate's outcome. + // Referenced via a pointer to avoid taking too much stack frame space + // with test assertions. + std::unique_ptr< ::std::string> message_; +}; + +// Makes a successful assertion result. +GTEST_API_ AssertionResult AssertionSuccess(); + +// Makes a failed assertion result. +GTEST_API_ AssertionResult AssertionFailure(); + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << msg. +GTEST_API_ AssertionResult AssertionFailure(const Message& msg); + +} // namespace testing + +// Includes the auto-generated header that implements a family of generic +// predicate assertion macros. This include comes late because it relies on +// APIs declared above. +#include "gtest/gtest_pred_impl.h" + +namespace testing { + +// The abstract class that all tests inherit from. +// +// In Google Test, a unit test program contains one or many TestSuites, and +// each TestSuite contains one or many Tests. +// +// When you define a test using the TEST macro, you don't need to +// explicitly derive from Test - the TEST macro automatically does +// this for you. +// +// The only time you derive from Test is when defining a test fixture +// to be used in a TEST_F. For example: +// +// class FooTest : public testing::Test { +// protected: +// void SetUp() override { ... } +// void TearDown() override { ... } +// ... +// }; +// +// TEST_F(FooTest, Bar) { ... } +// TEST_F(FooTest, Baz) { ... } +// +// Test is not copyable. +class GTEST_API_ Test { + public: + friend class TestInfo; + + // The d'tor is virtual as we intend to inherit from Test. + virtual ~Test(); + + // Sets up the stuff shared by all tests in this test case. + // + // Google Test will call Foo::SetUpTestSuite() before running the first + // test in test case Foo. Hence a sub-class can define its own + // SetUpTestSuite() method to shadow the one defined in the super + // class. + // Failures that happen during SetUpTestSuite are logged but otherwise + // ignored. + static void SetUpTestSuite() {} + + // Tears down the stuff shared by all tests in this test suite. + // + // Google Test will call Foo::TearDownTestSuite() after running the last + // test in test case Foo. Hence a sub-class can define its own + // TearDownTestSuite() method to shadow the one defined in the super + // class. + // Failures that happen during TearDownTestSuite are logged but otherwise + // ignored. + static void TearDownTestSuite() {} + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + static void TearDownTestCase() {} + static void SetUpTestCase() {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Returns true if and only if the current test has a fatal failure. + static bool HasFatalFailure(); + + // Returns true if and only if the current test has a non-fatal failure. + static bool HasNonfatalFailure(); + + // Returns true if and only if the current test was skipped. + static bool IsSkipped(); + + // Returns true if and only if the current test has a (either fatal or + // non-fatal) failure. + static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } + + // Logs a property for the current test, test suite, or for the entire + // invocation of the test program when used outside of the context of a + // test suite. Only the last value for a given key is remembered. These + // are public static so they can be called from utility functions that are + // not members of the test fixture. Calls to RecordProperty made during + // lifespan of the test (from the moment its constructor starts to the + // moment its destructor finishes) will be output in XML as attributes of + // the element. Properties recorded from fixture's + // SetUpTestSuite or TearDownTestSuite are logged as attributes of the + // corresponding element. Calls to RecordProperty made in the + // global context (before or after invocation of RUN_ALL_TESTS and from + // SetUp/TearDown method of Environment objects registered with Google + // Test) will be output as attributes of the element. + static void RecordProperty(const std::string& key, const std::string& value); + static void RecordProperty(const std::string& key, int value); + + protected: + // Creates a Test object. + Test(); + + // Sets up the test fixture. + virtual void SetUp(); + + // Tears down the test fixture. + virtual void TearDown(); + + private: + // Returns true if and only if the current test has the same fixture class + // as the first test in the current test suite. + static bool HasSameFixtureClass(); + + // Runs the test after the test fixture has been set up. + // + // A sub-class must implement this to define the test logic. + // + // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. + // Instead, use the TEST or TEST_F macro. + virtual void TestBody() = 0; + + // Sets up, executes, and tears down the test. + void Run(); + + // Deletes self. We deliberately pick an unusual name for this + // internal method to avoid clashing with names used in user TESTs. + void DeleteSelf_() { delete this; } + + const std::unique_ptr gtest_flag_saver_; + + // Often a user misspells SetUp() as Setup() and spends a long time + // wondering why it is never called by Google Test. The declaration of + // the following method is solely for catching such an error at + // compile time: + // + // - The return type is deliberately chosen to be not void, so it + // will be a conflict if void Setup() is declared in the user's + // test fixture. + // + // - This method is private, so it will be another compiler error + // if the method is called from the user's test fixture. + // + // DO NOT OVERRIDE THIS FUNCTION. + // + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } + + // We disallow copying Tests. + GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); +}; + +typedef internal::TimeInMillis TimeInMillis; + +// A copyable object representing a user specified test property which can be +// output as a key/value string pair. +// +// Don't inherit from TestProperty as its destructor is not virtual. +class TestProperty { + public: + // C'tor. TestProperty does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestProperty object. + TestProperty(const std::string& a_key, const std::string& a_value) : + key_(a_key), value_(a_value) { + } + + // Gets the user supplied key. + const char* key() const { + return key_.c_str(); + } + + // Gets the user supplied value. + const char* value() const { + return value_.c_str(); + } + + // Sets a new value, overriding the one supplied in the constructor. + void SetValue(const std::string& new_value) { + value_ = new_value; + } + + private: + // The key supplied by the user. + std::string key_; + // The value supplied by the user. + std::string value_; +}; + +// The result of a single Test. This includes a list of +// TestPartResults, a list of TestProperties, a count of how many +// death tests there are in the Test, and how much time it took to run +// the Test. +// +// TestResult is not copyable. +class GTEST_API_ TestResult { + public: + // Creates an empty TestResult. + TestResult(); + + // D'tor. Do not inherit from TestResult. + ~TestResult(); + + // Gets the number of all test parts. This is the sum of the number + // of successful test parts and the number of failed test parts. + int total_part_count() const; + + // Returns the number of the test properties. + int test_property_count() const; + + // Returns true if and only if the test passed (i.e. no test part failed). + bool Passed() const { return !Skipped() && !Failed(); } + + // Returns true if and only if the test was skipped. + bool Skipped() const; + + // Returns true if and only if the test failed. + bool Failed() const; + + // Returns true if and only if the test fatally failed. + bool HasFatalFailure() const; + + // Returns true if and only if the test has a non-fatal failure. + bool HasNonfatalFailure() const; + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Gets the time of the test case start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + + // Returns the i-th test part result among all the results. i can range from 0 + // to total_part_count() - 1. If i is not in that range, aborts the program. + const TestPartResult& GetTestPartResult(int i) const; + + // Returns the i-th test property. i can range from 0 to + // test_property_count() - 1. If i is not in that range, aborts the + // program. + const TestProperty& GetTestProperty(int i) const; + + private: + friend class TestInfo; + friend class TestSuite; + friend class UnitTest; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::ExecDeathTest; + friend class internal::TestResultAccessor; + friend class internal::UnitTestImpl; + friend class internal::WindowsDeathTest; + friend class internal::FuchsiaDeathTest; + + // Gets the vector of TestPartResults. + const std::vector& test_part_results() const { + return test_part_results_; + } + + // Gets the vector of TestProperties. + const std::vector& test_properties() const { + return test_properties_; + } + + // Sets the start time. + void set_start_timestamp(TimeInMillis start) { start_timestamp_ = start; } + + // Sets the elapsed time. + void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } + + // Adds a test property to the list. The property is validated and may add + // a non-fatal failure if invalid (e.g., if it conflicts with reserved + // key names). If a property is already recorded for the same key, the + // value will be updated, rather than storing multiple values for the same + // key. xml_element specifies the element for which the property is being + // recorded and is used for validation. + void RecordProperty(const std::string& xml_element, + const TestProperty& test_property); + + // Adds a failure if the key is a reserved attribute of Google Test + // testsuite tags. Returns true if the property is valid. + // FIXME: Validate attribute names are legal and human readable. + static bool ValidateTestProperty(const std::string& xml_element, + const TestProperty& test_property); + + // Adds a test part result to the list. + void AddTestPartResult(const TestPartResult& test_part_result); + + // Returns the death test count. + int death_test_count() const { return death_test_count_; } + + // Increments the death test count, returning the new count. + int increment_death_test_count() { return ++death_test_count_; } + + // Clears the test part results. + void ClearTestPartResults(); + + // Clears the object. + void Clear(); + + // Protects mutable state of the property vector and of owned + // properties, whose values may be updated. + internal::Mutex test_properites_mutex_; + + // The vector of TestPartResults + std::vector test_part_results_; + // The vector of TestProperties + std::vector test_properties_; + // Running count of death tests. + int death_test_count_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; + // The elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestResult. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); +}; // class TestResult + +// A TestInfo object stores the following information about a test: +// +// Test suite name +// Test name +// Whether the test should be run +// A function pointer that creates the test object when invoked +// Test result +// +// The constructor of TestInfo registers itself with the UnitTest +// singleton such that the RUN_ALL_TESTS() macro knows which tests to +// run. +class GTEST_API_ TestInfo { + public: + // Destructs a TestInfo object. This function is not virtual, so + // don't inherit from TestInfo. + ~TestInfo(); + + // Returns the test suite name. + const char* test_suite_name() const { return test_suite_name_.c_str(); } + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const char* test_case_name() const { return test_suite_name(); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Returns the test name. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a typed + // or a type-parameterized test. + const char* type_param() const { + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; + } + + // Returns the text representation of the value parameter, or NULL if this + // is not a value-parameterized test. + const char* value_param() const { + if (value_param_.get() != nullptr) return value_param_->c_str(); + return nullptr; + } + + // Returns the file name where this test is defined. + const char* file() const { return location_.file.c_str(); } + + // Returns the line where this test is defined. + int line() const { return location_.line; } + + // Return true if this test should not be run because it's in another shard. + bool is_in_another_shard() const { return is_in_another_shard_; } + + // Returns true if this test should run, that is if the test is not + // disabled (or it is disabled but the also_run_disabled_tests flag has + // been specified) and its full name matches the user-specified filter. + // + // Google Test allows the user to filter the tests by their full names. + // The full name of a test Bar in test suite Foo is defined as + // "Foo.Bar". Only the tests that match the filter will run. + // + // A filter is a colon-separated list of glob (not regex) patterns, + // optionally followed by a '-' and a colon-separated list of + // negative patterns (tests to exclude). A test is run if it + // matches one of the positive patterns and does not match any of + // the negative patterns. + // + // For example, *A*:Foo.* is a filter that matches any string that + // contains the character 'A' or starts with "Foo.". + bool should_run() const { return should_run_; } + + // Returns true if and only if this test will appear in the XML report. + bool is_reportable() const { + // The XML report includes tests matching the filter, excluding those + // run in other shards. + return matches_filter_ && !is_in_another_shard_; + } + + // Returns the result of the test. + const TestResult* result() const { return &result_; } + + private: +#if GTEST_HAS_DEATH_TEST + friend class internal::DefaultDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + friend class Test; + friend class TestSuite; + friend class internal::UnitTestImpl; + friend class internal::StreamingListenerTest; + friend TestInfo* internal::MakeAndRegisterTestInfo( + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, internal::CodeLocation code_location, + internal::TypeId fixture_class_id, internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc, + internal::TestFactoryBase* factory); + + // Constructs a TestInfo object. The newly constructed instance assumes + // ownership of the factory object. + TestInfo(const std::string& test_suite_name, const std::string& name, + const char* a_type_param, // NULL if not a type-parameterized test + const char* a_value_param, // NULL if not a value-parameterized test + internal::CodeLocation a_code_location, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory); + + // Increments the number of death tests encountered in this test so + // far. + int increment_death_test_count() { + return result_.increment_death_test_count(); + } + + // Creates the test object, runs it, records its result, and then + // deletes it. + void Run(); + + static void ClearTestResult(TestInfo* test_info) { + test_info->result_.Clear(); + } + + // These fields are immutable properties of the test. + const std::string test_suite_name_; // test suite name + const std::string name_; // Test name + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const std::unique_ptr type_param_; + // Text representation of the value parameter, or NULL if this is not a + // value-parameterized test. + const std::unique_ptr value_param_; + internal::CodeLocation location_; + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True if and only if this test should run + bool is_disabled_; // True if and only if this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + bool is_in_another_shard_; // Will be run in another shard. + internal::TestFactoryBase* const factory_; // The factory that creates + // the test object + + // This field is mutable and needs to be reset before running the + // test for the second time. + TestResult result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); +}; + +// A test suite, which consists of a vector of TestInfos. +// +// TestSuite is not copyable. +class GTEST_API_ TestSuite { + public: + // Creates a TestSuite with the given name. + // + // TestSuite does NOT have a default constructor. Always use this + // constructor to create a TestSuite object. + // + // Arguments: + // + // name: name of the test suite + // a_type_param: the name of the test's type parameter, or NULL if + // this is not a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + TestSuite(const char* name, const char* a_type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc); + + // Destructor of TestSuite. + virtual ~TestSuite(); + + // Gets the name of the TestSuite. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a + // type-parameterized test suite. + const char* type_param() const { + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; + } + + // Returns true if any test in this test suite should run. + bool should_run() const { return should_run_; } + + // Gets the number of successful tests in this test suite. + int successful_test_count() const; + + // Gets the number of skipped tests in this test suite. + int skipped_test_count() const; + + // Gets the number of failed tests in this test suite. + int failed_test_count() const; + + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + + // Gets the number of disabled tests in this test suite. + int disabled_test_count() const; + + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + + // Get the number of tests in this test suite that should run. + int test_to_run_count() const; + + // Gets the number of all tests in this test suite. + int total_test_count() const; + + // Returns true if and only if the test suite passed. + bool Passed() const { return !Failed(); } + + // Returns true if and only if the test suite failed. + bool Failed() const { return failed_test_count() > 0; } + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Gets the time of the test suite start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + const TestInfo* GetTestInfo(int i) const; + + // Returns the TestResult that holds test properties recorded during + // execution of SetUpTestSuite and TearDownTestSuite. + const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } + + private: + friend class Test; + friend class internal::UnitTestImpl; + + // Gets the (mutable) vector of TestInfos in this TestSuite. + std::vector& test_info_list() { return test_info_list_; } + + // Gets the (immutable) vector of TestInfos in this TestSuite. + const std::vector& test_info_list() const { + return test_info_list_; + } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + TestInfo* GetMutableTestInfo(int i); + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Adds a TestInfo to this test suite. Will delete the TestInfo upon + // destruction of the TestSuite object. + void AddTestInfo(TestInfo * test_info); + + // Clears the results of all tests in this test suite. + void ClearResult(); + + // Clears the results of all tests in the given test suite. + static void ClearTestSuiteResult(TestSuite* test_suite) { + test_suite->ClearResult(); + } + + // Runs every test in this TestSuite. + void Run(); + + // Runs SetUpTestSuite() for this TestSuite. This wrapper is needed + // for catching exceptions thrown from SetUpTestSuite(). + void RunSetUpTestSuite() { + if (set_up_tc_ != nullptr) { + (*set_up_tc_)(); + } + } + + // Runs TearDownTestSuite() for this TestSuite. This wrapper is + // needed for catching exceptions thrown from TearDownTestSuite(). + void RunTearDownTestSuite() { + if (tear_down_tc_ != nullptr) { + (*tear_down_tc_)(); + } + } + + // Returns true if and only if test passed. + static bool TestPassed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Passed(); + } + + // Returns true if and only if test skipped. + static bool TestSkipped(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Skipped(); + } + + // Returns true if and only if test failed. + static bool TestFailed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Failed(); + } + + // Returns true if and only if the test is disabled and will be reported in + // the XML report. + static bool TestReportableDisabled(const TestInfo* test_info) { + return test_info->is_reportable() && test_info->is_disabled_; + } + + // Returns true if and only if test is disabled. + static bool TestDisabled(const TestInfo* test_info) { + return test_info->is_disabled_; + } + + // Returns true if and only if this test will appear in the XML report. + static bool TestReportable(const TestInfo* test_info) { + return test_info->is_reportable(); + } + + // Returns true if the given test should run. + static bool ShouldRunTest(const TestInfo* test_info) { + return test_info->should_run(); + } + + // Shuffles the tests in this test suite. + void ShuffleTests(internal::Random* random); + + // Restores the test order to before the first shuffle. + void UnshuffleTests(); + + // Name of the test suite. + std::string name_; + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const std::unique_ptr type_param_; + // The vector of TestInfos in their original order. It owns the + // elements in the vector. + std::vector test_info_list_; + // Provides a level of indirection for the test list to allow easy + // shuffling and restoring the test order. The i-th element in this + // vector is the index of the i-th test in the shuffled test list. + std::vector test_indices_; + // Pointer to the function that sets up the test suite. + internal::SetUpTestSuiteFunc set_up_tc_; + // Pointer to the function that tears down the test suite. + internal::TearDownTestSuiteFunc tear_down_tc_; + // True if and only if any test in this test suite should run. + bool should_run_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; + // Elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + // Holds test properties recorded during execution of SetUpTestSuite and + // TearDownTestSuite. + TestResult ad_hoc_test_result_; + + // We disallow copying TestSuites. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestSuite); +}; + +// An Environment object is capable of setting up and tearing down an +// environment. You should subclass this to define your own +// environment(s). +// +// An Environment object does the set-up and tear-down in virtual +// methods SetUp() and TearDown() instead of the constructor and the +// destructor, as: +// +// 1. You cannot safely throw from a destructor. This is a problem +// as in some cases Google Test is used where exceptions are enabled, and +// we may want to implement ASSERT_* using exceptions where they are +// available. +// 2. You cannot use ASSERT_* directly in a constructor or +// destructor. +class Environment { + public: + // The d'tor is virtual as we need to subclass Environment. + virtual ~Environment() {} + + // Override this to define how to set up the environment. + virtual void SetUp() {} + + // Override this to define how to tear down the environment. + virtual void TearDown() {} + private: + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } +}; + +#if GTEST_HAS_EXCEPTIONS + +// Exception which can be thrown from TestEventListener::OnTestPartResult. +class GTEST_API_ AssertionException + : public internal::GoogleTestFailureException { + public: + explicit AssertionException(const TestPartResult& result) + : GoogleTestFailureException(result) {} +}; + +#endif // GTEST_HAS_EXCEPTIONS + +// The interface for tracing execution of tests. The methods are organized in +// the order the corresponding events are fired. +class TestEventListener { + public: + virtual ~TestEventListener() {} + + // Fired before any test activity starts. + virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + + // Fired before each iteration of tests starts. There may be more than + // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration + // index, starting from 0. + virtual void OnTestIterationStart(const UnitTest& unit_test, + int iteration) = 0; + + // Fired before environment set-up for each iteration of tests starts. + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + + // Fired after environment set-up for each iteration of tests ends. + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + + // Fired before the test suite starts. + virtual void OnTestSuiteStart(const TestSuite& /*test_suite*/) {} + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Fired before the test starts. + virtual void OnTestStart(const TestInfo& test_info) = 0; + + // Fired after a failed assertion or a SUCCEED() invocation. + // If you want to throw an exception from this function to skip to the next + // TEST, it must be AssertionException defined above, or inherited from it. + virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + + // Fired after the test ends. + virtual void OnTestEnd(const TestInfo& test_info) = 0; + + // Fired after the test suite ends. + virtual void OnTestSuiteEnd(const TestSuite& /*test_suite*/) {} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Fired before environment tear-down for each iteration of tests starts. + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; + + // Fired after environment tear-down for each iteration of tests ends. + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; + + // Fired after each iteration of tests finishes. + virtual void OnTestIterationEnd(const UnitTest& unit_test, + int iteration) = 0; + + // Fired after all test activities have ended. + virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; +}; + +// The convenience class for users who need to override just one or two +// methods and are not concerned that a possible change to a signature of +// the methods they override will not be caught during the build. For +// comments about each method please see the definition of TestEventListener +// above. +class EmptyTestEventListener : public TestEventListener { + public: + void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) override {} + void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} + void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {} +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase& /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnTestStart(const TestInfo& /*test_info*/) override {} + void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {} + void OnTestEnd(const TestInfo& /*test_info*/) override {} + void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) override {} + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} +}; + +// TestEventListeners lets users add listeners to track events in Google Test. +class GTEST_API_ TestEventListeners { + public: + TestEventListeners(); + ~TestEventListeners(); + + // Appends an event listener to the end of the list. Google Test assumes + // the ownership of the listener (i.e. it will delete the listener when + // the test program finishes). + void Append(TestEventListener* listener); + + // Removes the given event listener from the list and returns it. It then + // becomes the caller's responsibility to delete the listener. Returns + // NULL if the listener is not found in the list. + TestEventListener* Release(TestEventListener* listener); + + // Returns the standard listener responsible for the default console + // output. Can be removed from the listeners list to shut down default + // console output. Note that removing this object from the listener list + // with Release transfers its ownership to the caller and makes this + // function return NULL the next time. + TestEventListener* default_result_printer() const { + return default_result_printer_; + } + + // Returns the standard listener responsible for the default XML output + // controlled by the --gtest_output=xml flag. Can be removed from the + // listeners list by users who want to shut down the default XML output + // controlled by this flag and substitute it with custom one. Note that + // removing this object from the listener list with Release transfers its + // ownership to the caller and makes this function return NULL the next + // time. + TestEventListener* default_xml_generator() const { + return default_xml_generator_; + } + + private: + friend class TestSuite; + friend class TestInfo; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::NoExecDeathTest; + friend class internal::TestEventListenersAccessor; + friend class internal::UnitTestImpl; + + // Returns repeater that broadcasts the TestEventListener events to all + // subscribers. + TestEventListener* repeater(); + + // Sets the default_result_printer attribute to the provided listener. + // The listener is also added to the listener list and previous + // default_result_printer is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultResultPrinter(TestEventListener* listener); + + // Sets the default_xml_generator attribute to the provided listener. The + // listener is also added to the listener list and previous + // default_xml_generator is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultXmlGenerator(TestEventListener* listener); + + // Controls whether events will be forwarded by the repeater to the + // listeners in the list. + bool EventForwardingEnabled() const; + void SuppressEventForwarding(); + + // The actual list of listeners. + internal::TestEventRepeater* repeater_; + // Listener responsible for the standard result output. + TestEventListener* default_result_printer_; + // Listener responsible for the creation of the XML output file. + TestEventListener* default_xml_generator_; + + // We disallow copying TestEventListeners. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); +}; + +// A UnitTest consists of a vector of TestSuites. +// +// This is a singleton class. The only instance of UnitTest is +// created when UnitTest::GetInstance() is first called. This +// instance is never deleted. +// +// UnitTest is not copyable. +// +// This class is thread-safe as long as the methods are called +// according to their specification. +class GTEST_API_ UnitTest { + public: + // Gets the singleton UnitTest object. The first time this method + // is called, a UnitTest object is constructed and returned. + // Consecutive calls will return the same object. + static UnitTest* GetInstance(); + + // Runs all tests in this UnitTest object and prints the result. + // Returns 0 if successful, or 1 otherwise. + // + // This method can only be called from the main thread. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + int Run() GTEST_MUST_USE_RESULT_; + + // Returns the working directory when the first TEST() or TEST_F() + // was executed. The UnitTest object owns the string. + const char* original_working_dir() const; + + // Returns the TestSuite object for the test that's currently running, + // or NULL if no test is running. + const TestSuite* current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_); + +// Legacy API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_); +#endif + + // Returns the TestInfo object for the test that's currently running, + // or NULL if no test is running. + const TestInfo* current_test_info() const + GTEST_LOCK_EXCLUDED_(mutex_); + + // Returns the random seed used at the start of the current test run. + int random_seed() const; + + // Returns the ParameterizedTestSuiteRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() + GTEST_LOCK_EXCLUDED_(mutex_); + + // Gets the number of successful test suites. + int successful_test_suite_count() const; + + // Gets the number of failed test suites. + int failed_test_suite_count() const; + + // Gets the number of all test suites. + int total_test_suite_count() const; + + // Gets the number of all test suites that contain at least one test + // that should run. + int test_suite_to_run_count() const; + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + int successful_test_case_count() const; + int failed_test_case_count() const; + int total_test_case_count() const; + int test_case_to_run_count() const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of skipped tests. + int skipped_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the time of the test program start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const; + + // Returns true if and only if the unit test passed (i.e. all test suites + // passed). + bool Passed() const; + + // Returns true if and only if the unit test failed (i.e. some test suite + // failed or something outside of all tests failed). + bool Failed() const; + + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + const TestSuite* GetTestSuite(int i) const; + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase* GetTestCase(int i) const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Returns the TestResult containing information on test failures and + // properties logged outside of individual test suites. + const TestResult& ad_hoc_test_result() const; + + // Returns the list of event listeners that can be used to track events + // inside Google Test. + TestEventListeners& listeners(); + + private: + // Registers and returns a global test environment. When a test + // program is run, all global test environments will be set-up in + // the order they were registered. After all tests in the program + // have finished, all global test environments will be torn-down in + // the *reverse* order they were registered. + // + // The UnitTest object takes ownership of the given environment. + // + // This method can only be called from the main thread. + Environment* AddEnvironment(Environment* env); + + // Adds a TestPartResult to the current TestResult object. All + // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) + // eventually call this to report their results. The user code + // should use the assertion macros instead of calling this directly. + void AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const std::string& message, + const std::string& os_stack_trace) + GTEST_LOCK_EXCLUDED_(mutex_); + + // Adds a TestProperty to the current TestResult object when invoked from + // inside a test, to current TestSuite's ad_hoc_test_result_ when invoked + // from SetUpTestSuite or TearDownTestSuite, or to the global property set + // when invoked elsewhere. If the result already contains a property with + // the same key, the value will be updated. + void RecordProperty(const std::string& key, const std::string& value); + + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + TestSuite* GetMutableTestSuite(int i); + + // Accessors for the implementation object. + internal::UnitTestImpl* impl() { return impl_; } + const internal::UnitTestImpl* impl() const { return impl_; } + + // These classes and functions are friends as they need to access private + // members of UnitTest. + friend class ScopedTrace; + friend class Test; + friend class internal::AssertHelper; + friend class internal::StreamingListenerTest; + friend class internal::UnitTestRecordPropertyTestHelper; + friend Environment* AddGlobalTestEnvironment(Environment* env); + friend internal::UnitTestImpl* internal::GetUnitTestImpl(); + friend void internal::ReportFailureInUnknownLocation( + TestPartResult::Type result_type, + const std::string& message); + + // Creates an empty UnitTest. + UnitTest(); + + // D'tor + virtual ~UnitTest(); + + // Pushes a trace defined by SCOPED_TRACE() on to the per-thread + // Google Test trace stack. + void PushGTestTrace(const internal::TraceInfo& trace) + GTEST_LOCK_EXCLUDED_(mutex_); + + // Pops a trace from the per-thread Google Test trace stack. + void PopGTestTrace() + GTEST_LOCK_EXCLUDED_(mutex_); + + // Protects mutable state in *impl_. This is mutable as some const + // methods need to lock it too. + mutable internal::Mutex mutex_; + + // Opaque implementation object. This field is never changed once + // the object is constructed. We don't mark it as const here, as + // doing so will cause a warning in the constructor of UnitTest. + // Mutable state in *impl_ is protected by mutex_. + internal::UnitTestImpl* impl_; + + // We disallow copying UnitTest. + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); +}; + +// A convenient wrapper for adding an environment for the test +// program. +// +// You should call this before RUN_ALL_TESTS() is called, probably in +// main(). If you use gtest_main, you need to call this before main() +// starts for it to take effect. For example, you can define a global +// variable like this: +// +// testing::Environment* const foo_env = +// testing::AddGlobalTestEnvironment(new FooEnvironment); +// +// However, we strongly recommend you to write your own main() and +// call AddGlobalTestEnvironment() there, as relying on initialization +// of global variables makes the code harder to read and may cause +// problems when you register multiple environments from different +// translation units and the environments have dependencies among them +// (remember that the compiler doesn't guarantee the order in which +// global variables from different translation units are initialized). +inline Environment* AddGlobalTestEnvironment(Environment* env) { + return UnitTest::GetInstance()->AddEnvironment(env); +} + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +GTEST_API_ void InitGoogleTest(int* argc, char** argv); + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); + +// This overloaded version can be used on Arduino/embedded platforms where +// there is no argc/argv. +GTEST_API_ void InitGoogleTest(); + +namespace internal { + +// Separate the error generating code from the code path to reduce the stack +// frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers +// when calling EXPECT_* in a tight loop. +template +AssertionResult CmpHelperEQFailure(const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, const T2& rhs) { + return EqFailure(lhs_expression, + rhs_expression, + FormatForComparisonFailureMessage(lhs, rhs), + FormatForComparisonFailureMessage(rhs, lhs), + false); +} + +// This block of code defines operator==/!= +// to block lexical scope lookup. +// It prevents using invalid operator==/!= defined at namespace scope. +struct faketype {}; +inline bool operator==(faketype, faketype) { return true; } +inline bool operator!=(faketype, faketype) { return false; } + +// The helper function for {ASSERT|EXPECT}_EQ. +template +AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, + const T2& rhs) { + if (lhs == rhs) { + return AssertionSuccess(); + } + + return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs); +} + +// With this overloaded version, we allow anonymous enums to be used +// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums +// can be implicitly cast to BiggestInt. +GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs); + +class EqHelper { + public: + // This templatized version is for the general case. + template < + typename T1, typename T2, + // Disable this overload for cases where one argument is a pointer + // and the other is the null pointer constant. + typename std::enable_if::value || + !std::is_pointer::value>::type* = nullptr> + static AssertionResult Compare(const char* lhs_expression, + const char* rhs_expression, const T1& lhs, + const T2& rhs) { + return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); + } + + // With this overloaded version, we allow anonymous enums to be used + // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous + // enums can be implicitly cast to BiggestInt. + // + // Even though its body looks the same as the above version, we + // cannot merge the two, as it will make anonymous enums unhappy. + static AssertionResult Compare(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs) { + return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); + } + + template + static AssertionResult Compare( + const char* lhs_expression, const char* rhs_expression, + // Handle cases where '0' is used as a null pointer literal. + std::nullptr_t /* lhs */, T* rhs) { + // We already know that 'lhs' is a null pointer. + return CmpHelperEQ(lhs_expression, rhs_expression, static_cast(nullptr), + rhs); + } +}; + +// Separate the error generating code from the code path to reduce the stack +// frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers +// when calling EXPECT_OP in a tight loop. +template +AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2, + const T1& val1, const T2& val2, + const char* op) { + return AssertionFailure() + << "Expected: (" << expr1 << ") " << op << " (" << expr2 + << "), actual: " << FormatForComparisonFailureMessage(val1, val2) + << " vs " << FormatForComparisonFailureMessage(val2, val1); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste +// of similar code. +// +// For each templatized helper function, we also define an overloaded +// version for BiggestInt in order to reduce code bloat and allow +// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled +// with gcc 4. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +template \ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + const T1& val1, const T2& val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\ + }\ +}\ +GTEST_API_ AssertionResult CmpHelper##op_name(\ + const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) + +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// Implements the helper function for {ASSERT|EXPECT}_NE +GTEST_IMPL_CMP_HELPER_(NE, !=); +// Implements the helper function for {ASSERT|EXPECT}_LE +GTEST_IMPL_CMP_HELPER_(LE, <=); +// Implements the helper function for {ASSERT|EXPECT}_LT +GTEST_IMPL_CMP_HELPER_(LT, <); +// Implements the helper function for {ASSERT|EXPECT}_GE +GTEST_IMPL_CMP_HELPER_(GE, >=); +// Implements the helper function for {ASSERT|EXPECT}_GT +GTEST_IMPL_CMP_HELPER_(GT, >); + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRNE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + + +// Helper function for *_STREQ on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); + +// Helper function for *_STRNE on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); + +} // namespace internal + +// IsSubstring() and IsNotSubstring() are intended to be used as the +// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by +// themselves. They check whether needle is a substring of haystack +// (NULL is considered a substring of itself only), and return an +// appropriate error message when they fail. +// +// The {needle,haystack}_expr arguments are the stringified +// expressions that generated the two real arguments. +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +// Helper template function for comparing floating-points. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, + const char* rhs_expression, + RawType lhs_value, + RawType rhs_value) { + const FloatingPoint lhs(lhs_value), rhs(rhs_value); + + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + ::std::stringstream lhs_ss; + lhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << lhs_value; + + ::std::stringstream rhs_ss; + rhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << rhs_value; + + return EqFailure(lhs_expression, + rhs_expression, + StringStreamToString(&lhs_ss), + StringStreamToString(&rhs_ss), + false); +} + +// Helper function for implementing ASSERT_NEAR. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error); + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// A class that enables one to stream messages to assertion macros +class GTEST_API_ AssertHelper { + public: + // Constructor. + AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message); + ~AssertHelper(); + + // Message assignment is a semantic trick to enable assertion + // streaming; see the GTEST_MESSAGE_ macro below. + void operator=(const Message& message) const; + + private: + // We put our data in a struct so that the size of the AssertHelper class can + // be as small as possible. This is important because gcc is incapable of + // re-using stack space even for temporary variables, so every EXPECT_EQ + // reserves stack space for another AssertHelper. + struct AssertHelperData { + AssertHelperData(TestPartResult::Type t, + const char* srcfile, + int line_num, + const char* msg) + : type(t), file(srcfile), line(line_num), message(msg) { } + + TestPartResult::Type const type; + const char* const file; + int const line; + std::string const message; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); + }; + + AssertHelperData* const data_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); +}; + +enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; + +GTEST_API_ GTEST_ATTRIBUTE_PRINTF_(2, 3) void ColoredPrintf(GTestColor color, + const char* fmt, + ...); + +} // namespace internal + +// The pure interface class that all value-parameterized tests inherit from. +// A value-parameterized class must inherit from both ::testing::Test and +// ::testing::WithParamInterface. In most cases that just means inheriting +// from ::testing::TestWithParam, but more complicated test hierarchies +// may need to inherit from Test and WithParamInterface at different levels. +// +// This interface has support for accessing the test parameter value via +// the GetParam() method. +// +// Use it with one of the parameter generator defining functions, like Range(), +// Values(), ValuesIn(), Bool(), and Combine(). +// +// class FooTest : public ::testing::TestWithParam { +// protected: +// FooTest() { +// // Can use GetParam() here. +// } +// ~FooTest() override { +// // Can use GetParam() here. +// } +// void SetUp() override { +// // Can use GetParam() here. +// } +// void TearDown override { +// // Can use GetParam() here. +// } +// }; +// TEST_P(FooTest, DoesBar) { +// // Can use GetParam() method here. +// Foo foo; +// ASSERT_TRUE(foo.DoesBar(GetParam())); +// } +// INSTANTIATE_TEST_SUITE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); + +template +class WithParamInterface { + public: + typedef T ParamType; + virtual ~WithParamInterface() {} + + // The current parameter value. Is also available in the test fixture's + // constructor. + static const ParamType& GetParam() { + GTEST_CHECK_(parameter_ != nullptr) + << "GetParam() can only be called inside a value-parameterized test " + << "-- did you intend to write TEST_P instead of TEST_F?"; + return *parameter_; + } + + private: + // Sets parameter value. The caller is responsible for making sure the value + // remains alive and unchanged throughout the current test. + static void SetParam(const ParamType* parameter) { + parameter_ = parameter; + } + + // Static value used for accessing parameter during a test lifetime. + static const ParamType* parameter_; + + // TestClass must be a subclass of WithParamInterface and Test. + template friend class internal::ParameterizedTestFactory; +}; + +template +const T* WithParamInterface::parameter_ = nullptr; + +// Most value-parameterized classes can ignore the existence of +// WithParamInterface, and can just inherit from ::testing::TestWithParam. + +template +class TestWithParam : public Test, public WithParamInterface { +}; + +// Macros for indicating success/failure in test code. + +// Skips test in runtime. +// Skipping test aborts current function. +// Skipped tests are neither successful nor failed. +#define GTEST_SKIP() GTEST_SKIP_("Skipped") + +// ADD_FAILURE unconditionally adds a failure to the current test. +// SUCCEED generates a success - it doesn't automatically make the +// current test successful, as a test is only successful when it has +// no failure. +// +// EXPECT_* verifies that a certain condition is satisfied. If not, +// it behaves like ADD_FAILURE. In particular: +// +// EXPECT_TRUE verifies that a Boolean condition is true. +// EXPECT_FALSE verifies that a Boolean condition is false. +// +// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except +// that they will also abort the current function on failure. People +// usually want the fail-fast behavior of FAIL and ASSERT_*, but those +// writing data-driven tests often find themselves using ADD_FAILURE +// and EXPECT_* more. + +// Generates a nonfatal failure with a generic message. +#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") + +// Generates a nonfatal failure at the given source file location with +// a generic message. +#define ADD_FAILURE_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kNonFatalFailure) + +// Generates a fatal failure with a generic message. +#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") + +// Like GTEST_FAIL(), but at the given source file location. +#define GTEST_FAIL_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kFatalFailure) + +// Define this macro to 1 to omit the definition of FAIL(), which is a +// generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_FAIL +# define FAIL() GTEST_FAIL() +#endif + +// Generates a success with a generic message. +#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") + +// Define this macro to 1 to omit the definition of SUCCEED(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_SUCCEED +# define SUCCEED() GTEST_SUCCEED() +#endif + +// Macros for testing exceptions. +// +// * {ASSERT|EXPECT}_THROW(statement, expected_exception): +// Tests that the statement throws the expected exception. +// * {ASSERT|EXPECT}_NO_THROW(statement): +// Tests that the statement doesn't throw any exception. +// * {ASSERT|EXPECT}_ANY_THROW(statement): +// Tests that the statement throws an exception. + +#define EXPECT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) +#define EXPECT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define EXPECT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define ASSERT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) +#define ASSERT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) +#define ASSERT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) + +// Boolean assertions. Condition can be either a Boolean expression or an +// AssertionResult. For more information on how to use AssertionResult with +// these macros see comments on that class. +#define EXPECT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_NONFATAL_FAILURE_) +#define EXPECT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_NONFATAL_FAILURE_) +#define ASSERT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_FATAL_FAILURE_) +#define ASSERT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_FATAL_FAILURE_) + +// Macros for testing equalities and inequalities. +// +// * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2 +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// +// When they are not, Google Test prints both the tested expressions and +// their actual values. The values must be compatible built-in types, +// or you will get a compiler error. By "compatible" we mean that the +// values can be compared by the respective operator. +// +// Note: +// +// 1. It is possible to make a user-defined type work with +// {ASSERT|EXPECT}_??(), but that requires overloading the +// comparison operators and is thus discouraged by the Google C++ +// Usage Guide. Therefore, you are advised to use the +// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are +// equal. +// +// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on +// pointers (in particular, C strings). Therefore, if you use it +// with two C strings, you are testing how their locations in memory +// are related, not how their content is related. To compare two C +// strings by content, use {ASSERT|EXPECT}_STR*(). +// +// 3. {ASSERT|EXPECT}_EQ(v1, v2) is preferred to +// {ASSERT|EXPECT}_TRUE(v1 == v2), as the former tells you +// what the actual value is when it fails, and similarly for the +// other comparisons. +// +// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() +// evaluate their arguments, which is undefined. +// +// 5. These macros evaluate their arguments exactly once. +// +// Examples: +// +// EXPECT_NE(Foo(), 5); +// EXPECT_EQ(a_pointer, NULL); +// ASSERT_LT(i, array_size); +// ASSERT_GT(records.size(), 0) << "There is no record left."; + +#define EXPECT_EQ(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) +#define EXPECT_NE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) +#define EXPECT_LE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define EXPECT_LT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define EXPECT_GE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define EXPECT_GT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +#define GTEST_ASSERT_EQ(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) +#define GTEST_ASSERT_NE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) +#define GTEST_ASSERT_LE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define GTEST_ASSERT_LT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define GTEST_ASSERT_GE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define GTEST_ASSERT_GT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of +// ASSERT_XY(), which clashes with some users' own code. + +#if !GTEST_DONT_DEFINE_ASSERT_EQ +# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_NE +# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LE +# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LT +# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GE +# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GT +# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) +#endif + +// C-string Comparisons. All tests treat NULL and any non-NULL string +// as different. Two NULLs are equal. +// +// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 +// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 +// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case +// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case +// +// For wide or narrow string objects, you can use the +// {ASSERT|EXPECT}_??() macros. +// +// Don't depend on the order in which the arguments are evaluated, +// which is undefined. +// +// These macros evaluate their arguments exactly once. + +#define EXPECT_STREQ(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) +#define EXPECT_STRNE(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define EXPECT_STRCASEEQ(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) +#define EXPECT_STRCASENE(s1, s2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +#define ASSERT_STREQ(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) +#define ASSERT_STRNE(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define ASSERT_STRCASEEQ(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) +#define ASSERT_STRCASENE(s1, s2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +// Macros for comparing floating-point numbers. +// +// * {ASSERT|EXPECT}_FLOAT_EQ(val1, val2): +// Tests that two float values are almost equal. +// * {ASSERT|EXPECT}_DOUBLE_EQ(val1, val2): +// Tests that two double values are almost equal. +// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): +// Tests that v1 and v2 are within the given distance to each other. +// +// Google Test uses ULP-based comparison to automatically pick a default +// error bound that is appropriate for the operands. See the +// FloatingPoint template class in gtest-internal.h if you are +// interested in the implementation details. + +#define EXPECT_FLOAT_EQ(val1, val2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + val1, val2) + +#define EXPECT_DOUBLE_EQ(val1, val2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + val1, val2) + +#define ASSERT_FLOAT_EQ(val1, val2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + val1, val2) + +#define ASSERT_DOUBLE_EQ(val1, val2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + val1, val2) + +#define EXPECT_NEAR(val1, val2, abs_error)\ + EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +#define ASSERT_NEAR(val1, val2, abs_error)\ + ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +// These predicate format functions work on floating-point values, and +// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. +// +// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2); +GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2); + + +#if GTEST_OS_WINDOWS + +// Macros that test for HRESULT failure and success, these are only useful +// on Windows, and rely on Windows SDK macros and APIs to compile. +// +// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) +// +// When expr unexpectedly fails or succeeds, Google Test prints the +// expected result and the actual result with both a human-readable +// string representation of the error, if available, as well as the +// hex result code. +# define EXPECT_HRESULT_SUCCEEDED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define ASSERT_HRESULT_SUCCEEDED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define EXPECT_HRESULT_FAILED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +# define ASSERT_HRESULT_FAILED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +#endif // GTEST_OS_WINDOWS + +// Macros that execute statement and check that it doesn't generate new fatal +// failures in the current thread. +// +// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); +// +// Examples: +// +// EXPECT_NO_FATAL_FAILURE(Process()); +// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; +// +#define ASSERT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) +#define EXPECT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) + +// Causes a trace (including the given source file path and line number, +// and the given message) to be included in every test failure message generated +// by code in the scope of the lifetime of an instance of this class. The effect +// is undone with the destruction of the instance. +// +// The message argument can be anything streamable to std::ostream. +// +// Example: +// testing::ScopedTrace trace("file.cc", 123, "message"); +// +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + + // Template version. Uses Message() to convert the values into strings. + // Slow, but flexible. + template + ScopedTrace(const char* file, int line, const T& message) { + PushTrace(file, line, (Message() << message).GetString()); + } + + // Optimize for some known types. + ScopedTrace(const char* file, int line, const char* message) { + PushTrace(file, line, message ? message : "(null)"); + } + + ScopedTrace(const char* file, int line, const std::string& message) { + PushTrace(file, line, message); + } + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + void PushTrace(const char* file, int line, std::string message); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + +// Causes a trace (including the source file path, the current line +// number, and the given message) to be included in every test failure +// message generated by code in the current scope. The effect is +// undone when the control leaves the current scope. +// +// The message argument can be anything streamable to std::ostream. +// +// In the implementation, we include the current line number as part +// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s +// to appear in the same block - as long as they are on different +// lines. +// +// Assuming that each thread maintains its own stack of traces. +// Therefore, a SCOPED_TRACE() would (correctly) only affect the +// assertions in its own thread. +#define SCOPED_TRACE(message) \ + ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, (message)) + +// Compile-time assertion for type equality. +// StaticAssertTypeEq() compiles if and only if type1 and type2 +// are the same type. The value it returns is not interesting. +// +// Instead of making StaticAssertTypeEq a class template, we make it a +// function template that invokes a helper class template. This +// prevents a user from misusing StaticAssertTypeEq by +// defining objects of that type. +// +// CAVEAT: +// +// When used inside a method of a class template, +// StaticAssertTypeEq() is effective ONLY IF the method is +// instantiated. For example, given: +// +// template class Foo { +// public: +// void Bar() { testing::StaticAssertTypeEq(); } +// }; +// +// the code: +// +// void Test1() { Foo foo; } +// +// will NOT generate a compiler error, as Foo::Bar() is never +// actually instantiated. Instead, you need: +// +// void Test2() { Foo foo; foo.Bar(); } +// +// to cause a compiler error. +template +constexpr bool StaticAssertTypeEq() noexcept { + static_assert(std::is_same::value, + "type1 and type2 are not the same type"); + return true; +} + +// Defines a test. +// +// The first parameter is the name of the test suite, and the second +// parameter is the name of the test within the test suite. +// +// The convention is to end the test suite name with "Test". For +// example, a test suite for the Foo class can be named FooTest. +// +// Test code should appear between braces after an invocation of +// this macro. Example: +// +// TEST(FooTest, InitializesCorrectly) { +// Foo foo; +// EXPECT_TRUE(foo.StatusIsOK()); +// } + +// Note that we call GetTestTypeId() instead of GetTypeId< +// ::testing::Test>() here to get the type ID of testing::Test. This +// is to work around a suspected linker bug when using Google Test as +// a framework on Mac OS X. The bug causes GetTypeId< +// ::testing::Test>() to return different values depending on whether +// the call is from the Google Test framework itself or from user test +// code. GetTestTypeId() is guaranteed to always return the same +// value, as it always calls GetTypeId<>() from the Google Test +// framework. +#define GTEST_TEST(test_suite_name, test_name) \ + GTEST_TEST_(test_suite_name, test_name, ::testing::Test, \ + ::testing::internal::GetTestTypeId()) + +// Define this macro to 1 to omit the definition of TEST(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_TEST +#define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name) +#endif + +// Defines a test that uses a test fixture. +// +// The first parameter is the name of the test fixture class, which +// also doubles as the test suite name. The second parameter is the +// name of the test within the test suite. +// +// A test fixture class must be declared earlier. The user should put +// the test code between braces after using this macro. Example: +// +// class FooTest : public testing::Test { +// protected: +// void SetUp() override { b_.AddElement(3); } +// +// Foo a_; +// Foo b_; +// }; +// +// TEST_F(FooTest, InitializesCorrectly) { +// EXPECT_TRUE(a_.StatusIsOK()); +// } +// +// TEST_F(FooTest, ReturnsElementCountCorrectly) { +// EXPECT_EQ(a_.size(), 0); +// EXPECT_EQ(b_.size(), 1); +// } +// +// GOOGLETEST_CM0011 DO NOT DELETE +#define TEST_F(test_fixture, test_name)\ + GTEST_TEST_(test_fixture, test_name, test_fixture, \ + ::testing::internal::GetTypeId()) + +// Returns a path to temporary directory. +// Tries to determine an appropriate directory for the platform. +GTEST_API_ std::string TempDir(); + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +// Dynamically registers a test with the framework. +// +// This is an advanced API only to be used when the `TEST` macros are +// insufficient. The macros should be preferred when possible, as they avoid +// most of the complexity of calling this function. +// +// The `factory` argument is a factory callable (move-constructible) object or +// function pointer that creates a new instance of the Test object. It +// handles ownership to the caller. The signature of the callable is +// `Fixture*()`, where `Fixture` is the test fixture class for the test. All +// tests registered with the same `test_suite_name` must return the same +// fixture type. This is checked at runtime. +// +// The framework will infer the fixture class from the factory and will call +// the `SetUpTestSuite` and `TearDownTestSuite` for it. +// +// Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is +// undefined. +// +// Use case example: +// +// class MyFixture : public ::testing::Test { +// public: +// // All of these optional, just like in regular macro usage. +// static void SetUpTestSuite() { ... } +// static void TearDownTestSuite() { ... } +// void SetUp() override { ... } +// void TearDown() override { ... } +// }; +// +// class MyTest : public MyFixture { +// public: +// explicit MyTest(int data) : data_(data) {} +// void TestBody() override { ... } +// +// private: +// int data_; +// }; +// +// void RegisterMyTests(const std::vector& values) { +// for (int v : values) { +// ::testing::RegisterTest( +// "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, +// std::to_string(v).c_str(), +// __FILE__, __LINE__, +// // Important to use the fixture type as the return type here. +// [=]() -> MyFixture* { return new MyTest(v); }); +// } +// } +// ... +// int main(int argc, char** argv) { +// std::vector values_to_test = LoadValuesFromConfig(); +// RegisterMyTests(values_to_test); +// ... +// return RUN_ALL_TESTS(); +// } +// +template +TestInfo* RegisterTest(const char* test_suite_name, const char* test_name, + const char* type_param, const char* value_param, + const char* file, int line, Factory factory) { + using TestT = typename std::remove_pointer::type; + + class FactoryImpl : public internal::TestFactoryBase { + public: + explicit FactoryImpl(Factory f) : factory_(std::move(f)) {} + Test* CreateTest() override { return factory_(); } + + private: + Factory factory_; + }; + + return internal::MakeAndRegisterTestInfo( + test_suite_name, test_name, type_param, value_param, + internal::CodeLocation(file, line), internal::GetTypeId(), + internal::SuiteApiResolver::GetSetUpCaseOrSuite(file, line), + internal::SuiteApiResolver::GetTearDownCaseOrSuite(file, line), + new FactoryImpl{std::move(factory)}); +} + +} // namespace testing + +// Use this function in main() to run all tests. It returns 0 if all +// tests are successful, or 1 otherwise. +// +// RUN_ALL_TESTS() should be invoked after the command line has been +// parsed by InitGoogleTest(). +// +// This function was formerly a macro; thus, it is in the global +// namespace and has an all-caps name. +int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; + +inline int RUN_ALL_TESTS() { + return ::testing::UnitTest::GetInstance()->Run(); +} + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest_pred_impl.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest_pred_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..d514255c733b76ae8c6cd01902d328f30b9a6de9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest_pred_impl.h @@ -0,0 +1,359 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on 01/02/2019 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +#include "gtest/gtest.h" + +namespace testing { + +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most 5. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. + +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. + +#define GTEST_ASSERT_(expression, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar = (expression)) \ + ; \ + else \ + on_failure(gtest_ar.failure_message()) + + +// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +template +AssertionResult AssertPred1Helper(const char* pred_text, + const char* e1, + Pred pred, + const T1& v1) { + if (pred(v1)) return AssertionSuccess(); + + return AssertionFailure() + << pred_text << "(" << e1 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. +// Don't use this in your code. +#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, v1), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +#define GTEST_PRED1_(pred, v1, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ + #v1, \ + pred, \ + v1), on_failure) + +// Unary predicate assertion macros. +#define EXPECT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +template +AssertionResult AssertPred2Helper(const char* pred_text, + const char* e1, + const char* e2, + Pred pred, + const T1& v1, + const T2& v2) { + if (pred(v1, v2)) return AssertionSuccess(); + + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. +// Don't use this in your code. +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +#define GTEST_PRED2_(pred, v1, v2, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ + #v1, \ + #v2, \ + pred, \ + v1, \ + v2), on_failure) + +// Binary predicate assertion macros. +#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +template +AssertionResult AssertPred3Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3) { + if (pred(v1, v2, v3)) return AssertionSuccess(); + + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. +// Don't use this in your code. +#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + pred, \ + v1, \ + v2, \ + v3), on_failure) + +// Ternary predicate assertion macros. +#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +template +AssertionResult AssertPred4Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (pred(v1, v2, v3, v4)) return AssertionSuccess(); + + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. +// Don't use this in your code. +#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4), on_failure) + +// 4-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +template +AssertionResult AssertPred5Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); + + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ", " << e5 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n" + << e5 << " evaluates to " << ::testing::PrintToString(v5); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. +// Don't use this in your code. +#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + #v5, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4, \ + v5), on_failure) + +// 5-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) + + + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest_prod.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest_prod.h new file mode 100644 index 0000000000000000000000000000000000000000..e651671ebde859fc731b5459bdc0661af0757cb6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/gtest_prod.h @@ -0,0 +1,61 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Google C++ Testing and Mocking Framework definitions useful in production code. +// GOOGLETEST_CM0003 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ + +// When you need to test the private or protected members of a class, +// use the FRIEND_TEST macro to declare your tests as friends of the +// class. For example: +// +// class MyClass { +// private: +// void PrivateMethod(); +// FRIEND_TEST(MyClassTest, PrivateMethodWorks); +// }; +// +// class MyClassTest : public testing::Test { +// // ... +// }; +// +// TEST_F(MyClassTest, PrivateMethodWorks) { +// // Can call MyClass::PrivateMethod() here. +// } +// +// Note: The test class must be in the same namespace as the class being tested. +// For example, putting MyClassTest in an anonymous namespace will not work. + +#define FRIEND_TEST(test_case_name, test_name)\ +friend class test_case_name##_##test_name##_Test + +#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/README.md b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ff391fb4e2b5765cac8c6943359b15bbd5f4f149 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/README.md @@ -0,0 +1,56 @@ +# Customization Points + +The custom directory is an injection point for custom user configurations. + +## Header `gtest.h` + +### The following macros can be defined: + +* `GTEST_OS_STACK_TRACE_GETTER_` - The name of an implementation of + `OsStackTraceGetterInterface`. +* `GTEST_CUSTOM_TEMPDIR_FUNCTION_` - An override for `testing::TempDir()`. See + `testing::TempDir` for semantics and signature. + +## Header `gtest-port.h` + +The following macros can be defined: + +### Flag related macros: + +* `GTEST_FLAG(flag_name)` +* `GTEST_USE_OWN_FLAGFILE_FLAG_` - Define to 0 when the system provides its + own flagfile flag parsing. +* `GTEST_DECLARE_bool_(name)` +* `GTEST_DECLARE_int32_(name)` +* `GTEST_DECLARE_string_(name)` +* `GTEST_DEFINE_bool_(name, default_val, doc)` +* `GTEST_DEFINE_int32_(name, default_val, doc)` +* `GTEST_DEFINE_string_(name, default_val, doc)` + +### Logging: + +* `GTEST_LOG_(severity)` +* `GTEST_CHECK_(condition)` +* Functions `LogToStderr()` and `FlushInfoLog()` have to be provided too. + +### Threading: + +* `GTEST_HAS_NOTIFICATION_` - Enabled if Notification is already provided. +* `GTEST_HAS_MUTEX_AND_THREAD_LOCAL_` - Enabled if `Mutex` and `ThreadLocal` + are already provided. Must also provide `GTEST_DECLARE_STATIC_MUTEX_(mutex)` + and `GTEST_DEFINE_STATIC_MUTEX_(mutex)` +* `GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)` +* `GTEST_LOCK_EXCLUDED_(locks)` + +### Underlying library support features + +* `GTEST_HAS_CXXABI_H_` + +### Exporting API symbols: + +* `GTEST_API_` - Specifier for exported symbols. + +## Header `gtest-printers.h` + +* See documentation at `gtest/gtest-printers.h` for details on how to define a + custom printer. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/gtest-port.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/gtest-port.h new file mode 100644 index 0000000000000000000000000000000000000000..cd85d956d2dc17bd537f2142340bdf58f4737118 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/gtest-port.h @@ -0,0 +1,37 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/gtest-printers.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/gtest-printers.h new file mode 100644 index 0000000000000000000000000000000000000000..eb4467abcabea7ff76f9d2d527387c9da810148b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/gtest-printers.h @@ -0,0 +1,42 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file provides an injection point for custom printers in a local +// installation of gTest. +// It will be included from gtest-printers.h and the overrides in this file +// will be visible to everyone. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/gtest.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/gtest.h new file mode 100644 index 0000000000000000000000000000000000000000..4c8e07be23f1fd6159afef2eefd7444034dd0604 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/custom/gtest.h @@ -0,0 +1,37 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-death-test-internal.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-death-test-internal.h new file mode 100644 index 0000000000000000000000000000000000000000..68bd3530618f264c44749a7796ce5ee581751e62 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-death-test-internal.h @@ -0,0 +1,304 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines internal utilities needed for implementing +// death tests. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + +#include "gtest/gtest-matchers.h" +#include "gtest/internal/gtest-internal.h" + +#include +#include + +namespace testing { +namespace internal { + +GTEST_DECLARE_string_(internal_run_death_test); + +// Names of the flags (needed for parsing Google Test flags). +const char kDeathTestStyleFlag[] = "death_test_style"; +const char kDeathTestUseFork[] = "death_test_use_fork"; +const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; + +#if GTEST_HAS_DEATH_TEST + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +// DeathTest is a class that hides much of the complexity of the +// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method +// returns a concrete class that depends on the prevailing death test +// style, as defined by the --gtest_death_test_style and/or +// --gtest_internal_run_death_test flags. + +// In describing the results of death tests, these terms are used with +// the corresponding definitions: +// +// exit status: The integer exit information in the format specified +// by wait(2) +// exit code: The integer code passed to exit(3), _exit(2), or +// returned from main() +class GTEST_API_ DeathTest { + public: + // Create returns false if there was an error determining the + // appropriate action to take for the current death test; for example, + // if the gtest_death_test_style flag is set to an invalid value. + // The LastMessage method will return a more detailed message in that + // case. Otherwise, the DeathTest pointer pointed to by the "test" + // argument is set. If the death test should be skipped, the pointer + // is set to NULL; otherwise, it is set to the address of a new concrete + // DeathTest object that controls the execution of the current test. + static bool Create(const char* statement, Matcher matcher, + const char* file, int line, DeathTest** test); + DeathTest(); + virtual ~DeathTest() { } + + // A helper class that aborts a death test when it's deleted. + class ReturnSentinel { + public: + explicit ReturnSentinel(DeathTest* test) : test_(test) { } + ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } + private: + DeathTest* const test_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); + } GTEST_ATTRIBUTE_UNUSED_; + + // An enumeration of possible roles that may be taken when a death + // test is encountered. EXECUTE means that the death test logic should + // be executed immediately. OVERSEE means that the program should prepare + // the appropriate environment for a child process to execute the death + // test, then wait for it to complete. + enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; + + // An enumeration of the three reasons that a test might be aborted. + enum AbortReason { + TEST_ENCOUNTERED_RETURN_STATEMENT, + TEST_THREW_EXCEPTION, + TEST_DID_NOT_DIE + }; + + // Assumes one of the above roles. + virtual TestRole AssumeRole() = 0; + + // Waits for the death test to finish and returns its status. + virtual int Wait() = 0; + + // Returns true if the death test passed; that is, the test process + // exited during the test, its exit status matches a user-supplied + // predicate, and its stderr output matches a user-supplied regular + // expression. + // The user-supplied predicate may be a macro expression rather + // than a function pointer or functor, or else Wait and Passed could + // be combined. + virtual bool Passed(bool exit_status_ok) = 0; + + // Signals that the death test did not die as expected. + virtual void Abort(AbortReason reason) = 0; + + // Returns a human-readable outcome message regarding the outcome of + // the last death test. + static const char* LastMessage(); + + static void set_last_death_test_message(const std::string& message); + + private: + // A string containing a description of the outcome of the last death test. + static std::string last_death_test_message_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); +}; + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +// Factory interface for death tests. May be mocked out for testing. +class DeathTestFactory { + public: + virtual ~DeathTestFactory() { } + virtual bool Create(const char* statement, + Matcher matcher, const char* file, + int line, DeathTest** test) = 0; +}; + +// A concrete DeathTestFactory implementation for normal use. +class DefaultDeathTestFactory : public DeathTestFactory { + public: + bool Create(const char* statement, Matcher matcher, + const char* file, int line, DeathTest** test) override; +}; + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +GTEST_API_ bool ExitedUnsuccessfully(int exit_status); + +// A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads +// and interpreted as a regex (rather than an Eq matcher) for legacy +// compatibility. +inline Matcher MakeDeathTestMatcher( + ::testing::internal::RE regex) { + return ContainsRegex(regex.pattern()); +} +inline Matcher MakeDeathTestMatcher(const char* regex) { + return ContainsRegex(regex); +} +inline Matcher MakeDeathTestMatcher( + const ::std::string& regex) { + return ContainsRegex(regex); +} + +// If a Matcher is passed to EXPECT_DEATH (etc.), it's +// used directly. +inline Matcher MakeDeathTestMatcher( + Matcher matcher) { + return matcher; +} + +// Traps C++ exceptions escaping statement and reports them as test +// failures. Note that trapping SEH exceptions is not implemented here. +# if GTEST_HAS_EXCEPTIONS +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (const ::std::exception& gtest_exception) { \ + fprintf(\ + stderr, \ + "\n%s: Caught std::exception-derived exception escaping the " \ + "death test statement. Exception message: %s\n", \ + ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ + gtest_exception.what()); \ + fflush(stderr); \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } catch (...) { \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } + +# else +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) + +# endif + +// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, +// ASSERT_EXIT*, and EXPECT_EXIT*. +#define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create( \ + #statement, \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != nullptr) { \ + std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \ + gtest_dt); \ + GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + default: \ + break; \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \ + : fail(::testing::internal::DeathTest::LastMessage()) +// The symbol "fail" here expands to something into which a message +// can be streamed. + +// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in +// NDEBUG mode. In this case we need the statements to be executed and the macro +// must accept a streamed message even though the message is never printed. +// The regex object is not evaluated, but it is used to prevent "unused" +// warnings and to avoid an expression that doesn't compile in debug mode. +#define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } else if (!::testing::internal::AlwaysTrue()) { \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \ + } else \ + ::testing::Message() + +// A class representing the parsed contents of the +// --gtest_internal_run_death_test flag, as it existed when +// RUN_ALL_TESTS was called. +class InternalRunDeathTestFlag { + public: + InternalRunDeathTestFlag(const std::string& a_file, + int a_line, + int an_index, + int a_write_fd) + : file_(a_file), line_(a_line), index_(an_index), + write_fd_(a_write_fd) {} + + ~InternalRunDeathTestFlag() { + if (write_fd_ >= 0) + posix::Close(write_fd_); + } + + const std::string& file() const { return file_; } + int line() const { return line_; } + int index() const { return index_; } + int write_fd() const { return write_fd_; } + + private: + std::string file_; + int line_; + int index_; + int write_fd_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); +}; + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-filepath.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-filepath.h new file mode 100644 index 0000000000000000000000000000000000000000..c11b101516e530aaa9510b65d97dd67bbc0690a6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-filepath.h @@ -0,0 +1,211 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Google Test filepath utilities +// +// This header file declares classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included in gtest/internal/gtest-internal.h. +// Do not include this header file separately! + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ + +#include "gtest/internal/gtest-string.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { +namespace internal { + +// FilePath - a class for file and directory pathname manipulation which +// handles platform-specific conventions (like the pathname separator). +// Used for helper functions for naming files in a directory for xml output. +// Except for Set methods, all methods are const or static, which provides an +// "immutable value object" -- useful for peace of mind. +// A FilePath with a value ending in a path separator ("like/this/") represents +// a directory, otherwise it is assumed to represent a file. In either case, +// it may or may not represent an actual file or directory in the file system. +// Names are NOT checked for syntax correctness -- no checking for illegal +// characters, malformed paths, etc. + +class GTEST_API_ FilePath { + public: + FilePath() : pathname_("") { } + FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } + + explicit FilePath(const std::string& pathname) : pathname_(pathname) { + Normalize(); + } + + FilePath& operator=(const FilePath& rhs) { + Set(rhs); + return *this; + } + + void Set(const FilePath& rhs) { + pathname_ = rhs.pathname_; + } + + const std::string& string() const { return pathname_; } + const char* c_str() const { return pathname_.c_str(); } + + // Returns the current working directory, or "" if unsuccessful. + static FilePath GetCurrentDir(); + + // Given directory = "dir", base_name = "test", number = 0, + // extension = "xml", returns "dir/test.xml". If number is greater + // than zero (e.g., 12), returns "dir/test_12.xml". + // On Windows platform, uses \ as the separator rather than /. + static FilePath MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension); + + // Given directory = "dir", relative_path = "test.xml", + // returns "dir/test.xml". + // On Windows, uses \ as the separator rather than /. + static FilePath ConcatPaths(const FilePath& directory, + const FilePath& relative_path); + + // Returns a pathname for a file that does not currently exist. The pathname + // will be directory/base_name.extension or + // directory/base_name_.extension if directory/base_name.extension + // already exists. The number will be incremented until a pathname is found + // that does not already exist. + // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. + // There could be a race condition if two or more processes are calling this + // function at the same time -- they could both pick the same filename. + static FilePath GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension); + + // Returns true if and only if the path is "". + bool IsEmpty() const { return pathname_.empty(); } + + // If input name has a trailing separator character, removes it and returns + // the name, otherwise return the name string unmodified. + // On Windows platform, uses \ as the separator, other platforms use /. + FilePath RemoveTrailingPathSeparator() const; + + // Returns a copy of the FilePath with the directory part removed. + // Example: FilePath("path/to/file").RemoveDirectoryName() returns + // FilePath("file"). If there is no directory part ("just_a_file"), it returns + // the FilePath unmodified. If there is no file part ("just_a_dir/") it + // returns an empty FilePath (""). + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveDirectoryName() const; + + // RemoveFileName returns the directory path with the filename removed. + // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". + // If the FilePath is "a_file" or "/a_file", RemoveFileName returns + // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does + // not have a file, like "just/a/dir/", it returns the FilePath unmodified. + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveFileName() const; + + // Returns a copy of the FilePath with the case-insensitive extension removed. + // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns + // FilePath("dir/file"). If a case-insensitive extension is not + // found, returns a copy of the original FilePath. + FilePath RemoveExtension(const char* extension) const; + + // Creates directories so that path exists. Returns true if successful or if + // the directories already exist; returns false if unable to create + // directories for any reason. Will also return false if the FilePath does + // not represent a directory (that is, it doesn't end with a path separator). + bool CreateDirectoriesRecursively() const; + + // Create the directory so that path exists. Returns true if successful or + // if the directory already exists; returns false if unable to create the + // directory for any reason, including if the parent directory does not + // exist. Not named "CreateDirectory" because that's a macro on Windows. + bool CreateFolder() const; + + // Returns true if FilePath describes something in the file-system, + // either a file, directory, or whatever, and that something exists. + bool FileOrDirectoryExists() const; + + // Returns true if pathname describes a directory in the file-system + // that exists. + bool DirectoryExists() const; + + // Returns true if FilePath ends with a path separator, which indicates that + // it is intended to represent a directory. Returns false otherwise. + // This does NOT check that a directory (or file) actually exists. + bool IsDirectory() const; + + // Returns true if pathname describes a root directory. (Windows has one + // root directory per disk drive.) + bool IsRootDirectory() const; + + // Returns true if pathname describes an absolute path. + bool IsAbsolutePath() const; + + private: + // Replaces multiple consecutive separators with a single separator. + // For example, "bar///foo" becomes "bar/foo". Does not eliminate other + // redundancies that might be in a pathname involving "." or "..". + // + // A pathname with multiple consecutive separators may occur either through + // user error or as a result of some scripts or APIs that generate a pathname + // with a trailing separator. On other platforms the same API or script + // may NOT generate a pathname with a trailing "/". Then elsewhere that + // pathname may have another "/" and pathname components added to it, + // without checking for the separator already being there. + // The script language and operating system may allow paths like "foo//bar" + // but some of the functions in FilePath will not handle that correctly. In + // particular, RemoveTrailingPathSeparator() only removes one separator, and + // it is called in CreateDirectoriesRecursively() assuming that it will change + // a pathname from directory syntax (trailing separator) to filename syntax. + // + // On Windows this method also replaces the alternate path separator '/' with + // the primary path separator '\\', so that for example "bar\\/\\foo" becomes + // "bar\\foo". + + void Normalize(); + + // Returns a pointer to the last occurence of a valid path separator in + // the FilePath. On Windows, for example, both '/' and '\' are valid path + // separators. Returns NULL if no path separator was found. + const char* FindLastPathSeparator() const; + + std::string pathname_; +}; // class FilePath + +} // namespace internal +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-internal.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-internal.h new file mode 100644 index 0000000000000000000000000000000000000000..94c816a28bdb170aec9568e02be4a448a9b4dc7f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-internal.h @@ -0,0 +1,1380 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file declares functions and macros used internally by +// Google Test. They are subject to change without notice. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + +#include "gtest/internal/gtest-port.h" + +#if GTEST_OS_LINUX +# include +# include +# include +# include +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-string.h" +#include "gtest/internal/gtest-type-util.h" + +// Due to C++ preprocessor weirdness, we need double indirection to +// concatenate two tokens when one of them is __LINE__. Writing +// +// foo ## __LINE__ +// +// will result in the token foo__LINE__, instead of foo followed by +// the current line number. For more details, see +// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 +#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) +#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar + +// Stringifies its argument. +#define GTEST_STRINGIFY_(name) #name + +namespace proto2 { class Message; } + +namespace testing { + +// Forward declarations. + +class AssertionResult; // Result of an assertion. +class Message; // Represents a failure message. +class Test; // Represents a test. +class TestInfo; // Information about a test. +class TestPartResult; // Result of a test part. +class UnitTest; // A collection of test suites. + +template +::std::string PrintToString(const T& value); + +namespace internal { + +struct TraceInfo; // Information about a trace point. +class TestInfoImpl; // Opaque implementation of TestInfo +class UnitTestImpl; // Opaque implementation of UnitTest + +// The text used in failure messages to indicate the start of the +// stack trace. +GTEST_API_ extern const char kStackTraceMarker[]; + +// An IgnoredValue object can be implicitly constructed from ANY value. +class IgnoredValue { + struct Sink {}; + public: + // This constructor template allows any value to be implicitly + // converted to IgnoredValue. The object has no data member and + // doesn't try to remember anything about the argument. We + // deliberately omit the 'explicit' keyword in order to allow the + // conversion to be implicit. + // Disable the conversion if T already has a magical conversion operator. + // Otherwise we get ambiguity. + template ::value, + int>::type = 0> + IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit) +}; + +// Appends the user-supplied message to the Google-Test-generated message. +GTEST_API_ std::string AppendUserMessage( + const std::string& gtest_msg, const Message& user_msg); + +#if GTEST_HAS_EXCEPTIONS + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4275 \ +/* an exported class was derived from a class that was not exported */) + +// This exception is thrown by (and only by) a failed Google Test +// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions +// are enabled). We derive it from std::runtime_error, which is for +// errors presumably detectable only at run time. Since +// std::runtime_error inherits from std::exception, many testing +// frameworks know how to extract and print the message inside it. +class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure); +}; + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4275 + +#endif // GTEST_HAS_EXCEPTIONS + +namespace edit_distance { +// Returns the optimal edits to go from 'left' to 'right'. +// All edits cost the same, with replace having lower priority than +// add/remove. +// Simple implementation of the Wagner-Fischer algorithm. +// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm +enum EditType { kMatch, kAdd, kRemove, kReplace }; +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, const std::vector& right); + +// Same as above, but the input is represented as strings. +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right); + +// Create a diff of the input strings in Unified diff format. +GTEST_API_ std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context = 2); + +} // namespace edit_distance + +// Calculate the diff between 'left' and 'right' and return it in unified diff +// format. +// If not null, stores in 'total_line_count' the total number of lines found +// in left + right. +GTEST_API_ std::string DiffStrings(const std::string& left, + const std::string& right, + size_t* total_line_count); + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true if and only if the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +GTEST_API_ AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const std::string& expected_value, + const std::string& actual_value, + bool ignoring_case); + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +GTEST_API_ std::string GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value); + +// This template class represents an IEEE floating-point number +// (either single-precision or double-precision, depending on the +// template parameters). +// +// The purpose of this class is to do more sophisticated number +// comparison. (Due to round-off error, etc, it's very unlikely that +// two floating-points will be equal exactly. Hence a naive +// comparison by the == operation often doesn't work.) +// +// Format of IEEE floating-point: +// +// The most-significant bit being the leftmost, an IEEE +// floating-point looks like +// +// sign_bit exponent_bits fraction_bits +// +// Here, sign_bit is a single bit that designates the sign of the +// number. +// +// For float, there are 8 exponent bits and 23 fraction bits. +// +// For double, there are 11 exponent bits and 52 fraction bits. +// +// More details can be found at +// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +template +class FloatingPoint { + public: + // Defines the unsigned integer type that has the same size as the + // floating point number. + typedef typename TypeWithSize::UInt Bits; + + // Constants. + + // # of bits in a number. + static const size_t kBitCount = 8*sizeof(RawType); + + // # of fraction bits in a number. + static const size_t kFractionBitCount = + std::numeric_limits::digits - 1; + + // # of exponent bits in a number. + static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; + + // The mask for the sign bit. + static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); + + // The mask for the fraction bits. + static const Bits kFractionBitMask = + ~static_cast(0) >> (kExponentBitCount + 1); + + // The mask for the exponent bits. + static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); + + // How many ULP's (Units in the Last Place) we want to tolerate when + // comparing two numbers. The larger the value, the more error we + // allow. A 0 value means that two numbers must be exactly the same + // to be considered equal. + // + // The maximum error of a single floating-point operation is 0.5 + // units in the last place. On Intel CPU's, all floating-point + // calculations are done with 80-bit precision, while double has 64 + // bits. Therefore, 4 should be enough for ordinary use. + // + // See the following article for more details on ULP: + // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ + static const size_t kMaxUlps = 4; + + // Constructs a FloatingPoint from a raw floating-point number. + // + // On an Intel CPU, passing a non-normalized NAN (Not a Number) + // around may change its bits, although the new value is guaranteed + // to be also a NAN. Therefore, don't expect this constructor to + // preserve the bits in x when x is a NAN. + explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + + // Static methods + + // Reinterprets a bit pattern as a floating-point number. + // + // This function is needed to test the AlmostEquals() method. + static RawType ReinterpretBits(const Bits bits) { + FloatingPoint fp(0); + fp.u_.bits_ = bits; + return fp.u_.value_; + } + + // Returns the floating-point number that represent positive infinity. + static RawType Infinity() { + return ReinterpretBits(kExponentBitMask); + } + + // Returns the maximum representable finite floating-point number. + static RawType Max(); + + // Non-static methods + + // Returns the bits that represents this number. + const Bits &bits() const { return u_.bits_; } + + // Returns the exponent bits of this number. + Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + + // Returns the fraction bits of this number. + Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + + // Returns the sign bit of this number. + Bits sign_bit() const { return kSignBitMask & u_.bits_; } + + // Returns true if and only if this is NAN (not a number). + bool is_nan() const { + // It's a NAN if the exponent bits are all ones and the fraction + // bits are not entirely zeros. + return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); + } + + // Returns true if and only if this number is at most kMaxUlps ULP's away + // from rhs. In particular, this function: + // + // - returns false if either number is (or both are) NAN. + // - treats really large numbers as almost equal to infinity. + // - thinks +0.0 and -0.0 are 0 DLP's apart. + bool AlmostEquals(const FloatingPoint& rhs) const { + // The IEEE standard says that any comparison operation involving + // a NAN must return false. + if (is_nan() || rhs.is_nan()) return false; + + return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) + <= kMaxUlps; + } + + private: + // The data type used to store the actual floating-point number. + union FloatingPointUnion { + RawType value_; // The raw floating-point number. + Bits bits_; // The bits that represent the number. + }; + + // Converts an integer from the sign-and-magnitude representation to + // the biased representation. More precisely, let N be 2 to the + // power of (kBitCount - 1), an integer x is represented by the + // unsigned number x + N. + // + // For instance, + // + // -N + 1 (the most negative number representable using + // sign-and-magnitude) is represented by 1; + // 0 is represented by N; and + // N - 1 (the biggest number representable using + // sign-and-magnitude) is represented by 2N - 1. + // + // Read http://en.wikipedia.org/wiki/Signed_number_representations + // for more details on signed number representations. + static Bits SignAndMagnitudeToBiased(const Bits &sam) { + if (kSignBitMask & sam) { + // sam represents a negative number. + return ~sam + 1; + } else { + // sam represents a positive number. + return kSignBitMask | sam; + } + } + + // Given two numbers in the sign-and-magnitude representation, + // returns the distance between them as an unsigned number. + static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, + const Bits &sam2) { + const Bits biased1 = SignAndMagnitudeToBiased(sam1); + const Bits biased2 = SignAndMagnitudeToBiased(sam2); + return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); + } + + FloatingPointUnion u_; +}; + +// We cannot use std::numeric_limits::max() as it clashes with the max() +// macro defined by . +template <> +inline float FloatingPoint::Max() { return FLT_MAX; } +template <> +inline double FloatingPoint::Max() { return DBL_MAX; } + +// Typedefs the instances of the FloatingPoint template class that we +// care to use. +typedef FloatingPoint Float; +typedef FloatingPoint Double; + +// In order to catch the mistake of putting tests that use different +// test fixture classes in the same test suite, we need to assign +// unique IDs to fixture classes and compare them. The TypeId type is +// used to hold such IDs. The user should treat TypeId as an opaque +// type: the only operation allowed on TypeId values is to compare +// them for equality using the == operator. +typedef const void* TypeId; + +template +class TypeIdHelper { + public: + // dummy_ must not have a const type. Otherwise an overly eager + // compiler (e.g. MSVC 7.1 & 8.0) may try to merge + // TypeIdHelper::dummy_ for different Ts as an "optimization". + static bool dummy_; +}; + +template +bool TypeIdHelper::dummy_ = false; + +// GetTypeId() returns the ID of type T. Different values will be +// returned for different types. Calling the function twice with the +// same type argument is guaranteed to return the same ID. +template +TypeId GetTypeId() { + // The compiler is required to allocate a different + // TypeIdHelper::dummy_ variable for each T used to instantiate + // the template. Therefore, the address of dummy_ is guaranteed to + // be unique. + return &(TypeIdHelper::dummy_); +} + +// Returns the type ID of ::testing::Test. Always call this instead +// of GetTypeId< ::testing::Test>() to get the type ID of +// ::testing::Test, as the latter may give the wrong result due to a +// suspected linker bug when compiling Google Test as a Mac OS X +// framework. +GTEST_API_ TypeId GetTestTypeId(); + +// Defines the abstract factory interface that creates instances +// of a Test object. +class TestFactoryBase { + public: + virtual ~TestFactoryBase() {} + + // Creates a test instance to run. The instance is both created and destroyed + // within TestInfoImpl::Run() + virtual Test* CreateTest() = 0; + + protected: + TestFactoryBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); +}; + +// This class provides implementation of TeastFactoryBase interface. +// It is used in TEST and TEST_F macros. +template +class TestFactoryImpl : public TestFactoryBase { + public: + Test* CreateTest() override { return new TestClass; } +}; + +#if GTEST_OS_WINDOWS + +// Predicate-formatters for implementing the HRESULT checking macros +// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} +// We pass a long instead of HRESULT to avoid causing an +// include dependency for the HRESULT type. +GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, + long hr); // NOLINT +GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, + long hr); // NOLINT + +#endif // GTEST_OS_WINDOWS + +// Types of SetUpTestSuite() and TearDownTestSuite() functions. +using SetUpTestSuiteFunc = void (*)(); +using TearDownTestSuiteFunc = void (*)(); + +struct CodeLocation { + CodeLocation(const std::string& a_file, int a_line) + : file(a_file), line(a_line) {} + + std::string file; + int line; +}; + +// Helper to identify which setup function for TestCase / TestSuite to call. +// Only one function is allowed, either TestCase or TestSute but not both. + +// Utility functions to help SuiteApiResolver +using SetUpTearDownSuiteFuncType = void (*)(); + +inline SetUpTearDownSuiteFuncType GetNotDefaultOrNull( + SetUpTearDownSuiteFuncType a, SetUpTearDownSuiteFuncType def) { + return a == def ? nullptr : a; +} + +template +// Note that SuiteApiResolver inherits from T because +// SetUpTestSuite()/TearDownTestSuite() could be protected. Ths way +// SuiteApiResolver can access them. +struct SuiteApiResolver : T { + // testing::Test is only forward declared at this point. So we make it a + // dependend class for the compiler to be OK with it. + using Test = + typename std::conditional::type; + + static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename, + int line_num) { + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::SetUpTestSuite, &Test::SetUpTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both SetUpTestSuite and SetUpTestCase, please " + "make sure there is only one present at " + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; + } + + static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename, + int line_num) { + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::TearDownTestSuite, &Test::TearDownTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both TearDownTestSuite and TearDownTestCase," + " please make sure there is only one present at" + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; + } +}; + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_suite_name: name of the test suite +// name: name of the test +// type_param the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param text representation of the test's value parameter, +// or NULL if this is not a type-parameterized test. +// code_location: code location where the test is defined +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +GTEST_API_ TestInfo* MakeAndRegisterTestInfo( + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory); + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +// State of the definition of a type-parameterized test suite. +class GTEST_API_ TypedTestSuitePState { + public: + TypedTestSuitePState() : registered_(false) {} + + // Adds the given test name to defined_test_names_ and return true + // if the test suite hasn't been registered; otherwise aborts the + // program. + bool AddTestName(const char* file, int line, const char* case_name, + const char* test_name) { + if (registered_) { + fprintf(stderr, + "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_SUITE_P(%s, ...).\n", + FormatFileLocation(file, line).c_str(), test_name, case_name); + fflush(stderr); + posix::Abort(); + } + registered_tests_.insert( + ::std::make_pair(test_name, CodeLocation(file, line))); + return true; + } + + bool TestExists(const std::string& test_name) const { + return registered_tests_.count(test_name) > 0; + } + + const CodeLocation& GetCodeLocation(const std::string& test_name) const { + RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name); + GTEST_CHECK_(it != registered_tests_.end()); + return it->second; + } + + // Verifies that registered_tests match the test names in + // defined_test_names_; returns registered_tests if successful, or + // aborts the program otherwise. + const char* VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests); + + private: + typedef ::std::map RegisteredTestsMap; + + bool registered_; + RegisteredTestsMap registered_tests_; +}; + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TypedTestCasePState = TypedTestSuitePState; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +// Skips to the first non-space char after the first comma in 'str'; +// returns NULL if no comma is found in 'str'. +inline const char* SkipComma(const char* str) { + const char* comma = strchr(str, ','); + if (comma == nullptr) { + return nullptr; + } + while (IsSpace(*(++comma))) {} + return comma; +} + +// Returns the prefix of 'str' before the first comma in it; returns +// the entire string if it contains no comma. +inline std::string GetPrefixUntilComma(const char* str) { + const char* comma = strchr(str, ','); + return comma == nullptr ? str : std::string(str, comma); +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. +void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest); + +// The default argument to the template below for the case when the user does +// not provide a name generator. +struct DefaultNameGenerator { + template + static std::string GetName(int i) { + return StreamableToString(i); + } +}; + +template +struct NameGeneratorSelector { + typedef Provided type; +}; + +template +void GenerateNamesRecursively(Types0, std::vector*, int) {} + +template +void GenerateNamesRecursively(Types, std::vector* result, int i) { + result->push_back(NameGenerator::template GetName(i)); + GenerateNamesRecursively(typename Types::Tail(), result, + i + 1); +} + +template +std::vector GenerateNames() { + std::vector result; + GenerateNamesRecursively(Types(), &result, 0); + return result; +} + +// TypeParameterizedTest::Register() +// registers a list of type-parameterized tests with Google Test. The +// return value is insignificant - we just need to return something +// such that we can call this function in a namespace scope. +// +// Implementation note: The GTEST_TEMPLATE_ macro declares a template +// template parameter. It's defined in gtest-type-util.h. +template +class TypeParameterizedTest { + public: + // 'index' is the index of the test in the type list 'Types' + // specified in INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TestSuite, + // Types). Valid values for 'index' are [0, N - 1] where N is the + // length of Types. + static bool Register(const char* prefix, const CodeLocation& code_location, + const char* case_name, const char* test_names, int index, + const std::vector& type_names = + GenerateNames()) { + typedef typename Types::Head Type; + typedef Fixture FixtureClass; + typedef typename GTEST_BIND_(TestSel, Type) TestClass; + + // First, registers the first type-parameterized test in the type + // list. + MakeAndRegisterTestInfo( + (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + + "/" + type_names[static_cast(index)]) + .c_str(), + StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), + GetTypeName().c_str(), + nullptr, // No value parameter. + code_location, GetTypeId(), + SuiteApiResolver::GetSetUpCaseOrSuite( + code_location.file.c_str(), code_location.line), + SuiteApiResolver::GetTearDownCaseOrSuite( + code_location.file.c_str(), code_location.line), + new TestFactoryImpl); + + // Next, recurses (at compile time) with the tail of the type list. + return TypeParameterizedTest::Register(prefix, + code_location, + case_name, + test_names, + index + 1, + type_names); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTest { + public: + static bool Register(const char* /*prefix*/, const CodeLocation&, + const char* /*case_name*/, const char* /*test_names*/, + int /*index*/, + const std::vector& = + std::vector() /*type_names*/) { + return true; + } +}; + +// TypeParameterizedTestSuite::Register() +// registers *all combinations* of 'Tests' and 'Types' with Google +// Test. The return value is insignificant - we just need to return +// something such that we can call this function in a namespace scope. +template +class TypeParameterizedTestSuite { + public: + static bool Register(const char* prefix, CodeLocation code_location, + const TypedTestSuitePState* state, const char* case_name, + const char* test_names, + const std::vector& type_names = + GenerateNames()) { + std::string test_name = StripTrailingSpaces( + GetPrefixUntilComma(test_names)); + if (!state->TestExists(test_name)) { + fprintf(stderr, "Failed to get code location for test %s.%s at %s.", + case_name, test_name.c_str(), + FormatFileLocation(code_location.file.c_str(), + code_location.line).c_str()); + fflush(stderr); + posix::Abort(); + } + const CodeLocation& test_location = state->GetCodeLocation(test_name); + + typedef typename Tests::Head Head; + + // First, register the first test in 'Test' for each type in 'Types'. + TypeParameterizedTest::Register( + prefix, test_location, case_name, test_names, 0, type_names); + + // Next, recurses (at compile time) with the tail of the test list. + return TypeParameterizedTestSuite::Register(prefix, code_location, + state, case_name, + SkipComma(test_names), + type_names); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTestSuite { + public: + static bool Register(const char* /*prefix*/, const CodeLocation&, + const TypedTestSuitePState* /*state*/, + const char* /*case_name*/, const char* /*test_names*/, + const std::vector& = + std::vector() /*type_names*/) { + return true; + } +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// Returns the current OS stack trace as an std::string. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( + UnitTest* unit_test, int skip_count); + +// Helpers for suppressing warnings on unreachable code or constant +// condition. + +// Always returns true. +GTEST_API_ bool AlwaysTrue(); + +// Always returns false. +inline bool AlwaysFalse() { return !AlwaysTrue(); } + +// Helper for suppressing false warning from Clang on a const char* +// variable declared in a conditional expression always being NULL in +// the else branch. +struct GTEST_API_ ConstCharPtr { + ConstCharPtr(const char* str) : value(str) {} + operator bool() const { return true; } + const char* value; +}; + +// A simple Linear Congruential Generator for generating random +// numbers with a uniform distribution. Unlike rand() and srand(), it +// doesn't use global state (and therefore can't interfere with user +// code). Unlike rand_r(), it's portable. An LCG isn't very random, +// but it's good enough for our purposes. +class GTEST_API_ Random { + public: + static const UInt32 kMaxRange = 1u << 31; + + explicit Random(UInt32 seed) : state_(seed) {} + + void Reseed(UInt32 seed) { state_ = seed; } + + // Generates a random number from [0, range). Crashes if 'range' is + // 0 or greater than kMaxRange. + UInt32 Generate(UInt32 range); + + private: + UInt32 state_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); +}; + +// Turns const U&, U&, const U, and U all into U. +#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ + typename std::remove_const::type>::type + +// IsAProtocolMessage::value is a compile-time bool constant that's +// true if and only if T is type proto2::Message or a subclass of it. +template +struct IsAProtocolMessage + : public bool_constant< + std::is_convertible::value> {}; + +// When the compiler sees expression IsContainerTest(0), if C is an +// STL-style container class, the first overload of IsContainerTest +// will be viable (since both C::iterator* and C::const_iterator* are +// valid types and NULL can be implicitly converted to them). It will +// be picked over the second overload as 'int' is a perfect match for +// the type of argument 0. If C::iterator or C::const_iterator is not +// a valid type, the first overload is not viable, and the second +// overload will be picked. Therefore, we can determine whether C is +// a container class by checking the type of IsContainerTest(0). +// The value of the expression is insignificant. +// +// In C++11 mode we check the existence of a const_iterator and that an +// iterator is properly implemented for the container. +// +// For pre-C++11 that we look for both C::iterator and C::const_iterator. +// The reason is that C++ injects the name of a class as a member of the +// class itself (e.g. you can refer to class iterator as either +// 'iterator' or 'iterator::iterator'). If we look for C::iterator +// only, for example, we would mistakenly think that a class named +// iterator is an STL container. +// +// Also note that the simpler approach of overloading +// IsContainerTest(typename C::const_iterator*) and +// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. +typedef int IsContainer; +template ().begin()), + class = decltype(::std::declval().end()), + class = decltype(++::std::declval()), + class = decltype(*::std::declval()), + class = typename C::const_iterator> +IsContainer IsContainerTest(int /* dummy */) { + return 0; +} + +typedef char IsNotContainer; +template +IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } + +// Trait to detect whether a type T is a hash table. +// The heuristic used is that the type contains an inner type `hasher` and does +// not contain an inner type `reverse_iterator`. +// If the container is iterable in reverse, then order might actually matter. +template +struct IsHashTable { + private: + template + static char test(typename U::hasher*, typename U::reverse_iterator*); + template + static int test(typename U::hasher*, ...); + template + static char test(...); + + public: + static const bool value = sizeof(test(nullptr, nullptr)) == sizeof(int); +}; + +template +const bool IsHashTable::value; + +template (0)) == sizeof(IsContainer)> +struct IsRecursiveContainerImpl; + +template +struct IsRecursiveContainerImpl : public std::false_type {}; + +// Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to +// obey the same inconsistencies as the IsContainerTest, namely check if +// something is a container is relying on only const_iterator in C++11 and +// is relying on both const_iterator and iterator otherwise +template +struct IsRecursiveContainerImpl { + using value_type = decltype(*std::declval()); + using type = + std::is_same::type>::type, + C>; +}; + +// IsRecursiveContainer is a unary compile-time predicate that +// evaluates whether C is a recursive container type. A recursive container +// type is a container type whose value_type is equal to the container type +// itself. An example for a recursive container type is +// boost::filesystem::path, whose iterator has a value_type that is equal to +// boost::filesystem::path. +template +struct IsRecursiveContainer : public IsRecursiveContainerImpl::type {}; + +// Utilities for native arrays. + +// ArrayEq() compares two k-dimensional native arrays using the +// elements' operator==, where k can be any integer >= 0. When k is +// 0, ArrayEq() degenerates into comparing a single pair of values. + +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs); + +// This generic version is used when k is 0. +template +inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } + +// This overload is used when k >= 1. +template +inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { + return internal::ArrayEq(lhs, N, rhs); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous ArrayEq() function, arrays with different sizes would +// lead to different copies of the template code. +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs) { + for (size_t i = 0; i != size; i++) { + if (!internal::ArrayEq(lhs[i], rhs[i])) + return false; + } + return true; +} + +// Finds the first element in the iterator range [begin, end) that +// equals elem. Element may be a native array type itself. +template +Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { + for (Iter it = begin; it != end; ++it) { + if (internal::ArrayEq(*it, elem)) + return it; + } + return end; +} + +// CopyArray() copies a k-dimensional native array using the elements' +// operator=, where k can be any integer >= 0. When k is 0, +// CopyArray() degenerates into copying a single value. + +template +void CopyArray(const T* from, size_t size, U* to); + +// This generic version is used when k is 0. +template +inline void CopyArray(const T& from, U* to) { *to = from; } + +// This overload is used when k >= 1. +template +inline void CopyArray(const T(&from)[N], U(*to)[N]) { + internal::CopyArray(from, N, *to); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous CopyArray() function, arrays with different sizes +// would lead to different copies of the template code. +template +void CopyArray(const T* from, size_t size, U* to) { + for (size_t i = 0; i != size; i++) { + internal::CopyArray(from[i], to + i); + } +} + +// The relation between an NativeArray object (see below) and the +// native array it represents. +// We use 2 different structs to allow non-copyable types to be used, as long +// as RelationToSourceReference() is passed. +struct RelationToSourceReference {}; +struct RelationToSourceCopy {}; + +// Adapts a native array to a read-only STL-style container. Instead +// of the complete STL container concept, this adaptor only implements +// members useful for Google Mock's container matchers. New members +// should be added as needed. To simplify the implementation, we only +// support Element being a raw type (i.e. having no top-level const or +// reference modifier). It's the client's responsibility to satisfy +// this requirement. Element can be an array type itself (hence +// multi-dimensional arrays are supported). +template +class NativeArray { + public: + // STL-style container typedefs. + typedef Element value_type; + typedef Element* iterator; + typedef const Element* const_iterator; + + // Constructs from a native array. References the source. + NativeArray(const Element* array, size_t count, RelationToSourceReference) { + InitRef(array, count); + } + + // Constructs from a native array. Copies the source. + NativeArray(const Element* array, size_t count, RelationToSourceCopy) { + InitCopy(array, count); + } + + // Copy constructor. + NativeArray(const NativeArray& rhs) { + (this->*rhs.clone_)(rhs.array_, rhs.size_); + } + + ~NativeArray() { + if (clone_ != &NativeArray::InitRef) + delete[] array_; + } + + // STL-style container methods. + size_t size() const { return size_; } + const_iterator begin() const { return array_; } + const_iterator end() const { return array_ + size_; } + bool operator==(const NativeArray& rhs) const { + return size() == rhs.size() && + ArrayEq(begin(), size(), rhs.begin()); + } + + private: + static_assert(!std::is_const::value, "Type must not be const"); + static_assert(!std::is_reference::value, + "Type must not be a reference"); + + // Initializes this object with a copy of the input. + void InitCopy(const Element* array, size_t a_size) { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; + size_ = a_size; + clone_ = &NativeArray::InitCopy; + } + + // Initializes this object with a reference of the input. + void InitRef(const Element* array, size_t a_size) { + array_ = array; + size_ = a_size; + clone_ = &NativeArray::InitRef; + } + + const Element* array_; + size_t size_; + void (NativeArray::*clone_)(const Element*, size_t); + + GTEST_DISALLOW_ASSIGN_(NativeArray); +}; + +// Backport of std::index_sequence. +template +struct IndexSequence { + using type = IndexSequence; +}; + +// Double the IndexSequence, and one if plus_one is true. +template +struct DoubleSequence; +template +struct DoubleSequence, sizeofT> { + using type = IndexSequence; +}; +template +struct DoubleSequence, sizeofT> { + using type = IndexSequence; +}; + +// Backport of std::make_index_sequence. +// It uses O(ln(N)) instantiation depth. +template +struct MakeIndexSequence + : DoubleSequence::type, + N / 2>::type {}; + +template <> +struct MakeIndexSequence<0> : IndexSequence<> {}; + +// FIXME: This implementation of ElemFromList is O(1) in instantiation depth, +// but it is O(N^2) in total instantiations. Not sure if this is the best +// tradeoff, as it will make it somewhat slow to compile. +template +struct ElemFromListImpl {}; + +template +struct ElemFromListImpl { + using type = T; +}; + +// Get the Nth element from T... +// It uses O(1) instantiation depth. +template +struct ElemFromList; + +template +struct ElemFromList, T...> + : ElemFromListImpl... {}; + +template +class FlatTuple; + +template +struct FlatTupleElemBase; + +template +struct FlatTupleElemBase, I> { + using value_type = + typename ElemFromList::type, + T...>::type; + FlatTupleElemBase() = default; + explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {} + value_type value; +}; + +template +struct FlatTupleBase; + +template +struct FlatTupleBase, IndexSequence> + : FlatTupleElemBase, Idx>... { + using Indices = IndexSequence; + FlatTupleBase() = default; + explicit FlatTupleBase(T... t) + : FlatTupleElemBase, Idx>(std::move(t))... {} +}; + +// Analog to std::tuple but with different tradeoffs. +// This class minimizes the template instantiation depth, thus allowing more +// elements that std::tuple would. std::tuple has been seen to require an +// instantiation depth of more than 10x the number of elements in some +// implementations. +// FlatTuple and ElemFromList are not recursive and have a fixed depth +// regardless of T... +// MakeIndexSequence, on the other hand, it is recursive but with an +// instantiation depth of O(ln(N)). +template +class FlatTuple + : private FlatTupleBase, + typename MakeIndexSequence::type> { + using Indices = typename FlatTuple::FlatTupleBase::Indices; + + public: + FlatTuple() = default; + explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {} + + template + const typename ElemFromList::type& Get() const { + return static_cast*>(this)->value; + } + + template + typename ElemFromList::type& Get() { + return static_cast*>(this)->value; + } +}; + +// Utility functions to be called with static_assert to induce deprecation +// warnings. +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TEST_SUITE_P") +constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE_P is deprecated, please use " + "TYPED_TEST_SUITE_P") +constexpr bool TypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE is deprecated, please use " + "TYPED_TEST_SUITE") +constexpr bool TypedTestCaseIsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "REGISTER_TYPED_TEST_CASE_P is deprecated, please use " + "REGISTER_TYPED_TEST_SUITE_P") +constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TYPED_TEST_SUITE_P") +constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } + +} // namespace internal +} // namespace testing + +#define GTEST_MESSAGE_AT_(file, line, message, result_type) \ + ::testing::internal::AssertHelper(result_type, file, line, message) \ + = ::testing::Message() + +#define GTEST_MESSAGE_(message, result_type) \ + GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) + +#define GTEST_FATAL_FAILURE_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) + +#define GTEST_NONFATAL_FAILURE_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) + +#define GTEST_SUCCESS_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) + +#define GTEST_SKIP_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSkip) + +// Suppress MSVC warning 4072 (unreachable code) for the code following +// statement if it returns or throws (or doesn't return or throw in some +// situations). +#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ + if (::testing::internal::AlwaysTrue()) { statement; } + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::ConstCharPtr gtest_msg = "") { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + catch (...) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws a different type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ + fail(gtest_msg.value) + +#define GTEST_TEST_NO_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ + fail("Expected: " #statement " doesn't throw an exception.\n" \ + " Actual: it throws.") + +#define GTEST_TEST_ANY_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + bool gtest_caught_any = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + gtest_caught_any = true; \ + } \ + if (!gtest_caught_any) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ + fail("Expected: " #statement " throws an exception.\n" \ + " Actual: it doesn't.") + + +// Implements Boolean test assertions such as EXPECT_TRUE. expression can be +// either a boolean expression or an AssertionResult. text is a textual +// represenation of expression as it was passed into the EXPECT_TRUE. +#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar_ = \ + ::testing::AssertionResult(expression)) \ + ; \ + else \ + fail(::testing::internal::GetBoolAssertionFailureMessage(\ + gtest_ar_, text, #actual, #expected).c_str()) + +#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ + fail("Expected: " #statement " doesn't generate new fatal " \ + "failures in the current thread.\n" \ + " Actual: it does.") + +// Expands to the name of the class that implements the given test. +#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + test_suite_name##_##test_name##_Test + +// Helper macro for defining tests. +#define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id) \ + static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \ + "test_suite_name must not be empty"); \ + static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1, \ + "test_name must not be empty"); \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public parent_class { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + \ + private: \ + virtual void TestBody(); \ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + }; \ + \ + ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::test_info_ = \ + ::testing::internal::MakeAndRegisterTestInfo( \ + #test_suite_name, #test_name, nullptr, nullptr, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetTearDownCaseOrSuite(__FILE__, __LINE__), \ + new ::testing::internal::TestFactoryImpl); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-param-util.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-param-util.h new file mode 100644 index 0000000000000000000000000000000000000000..97533993c0c3ce9beb489f1bfa25317b88f879a1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-param-util.h @@ -0,0 +1,883 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Type and function utilities for implementing parameterized tests. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-printers.h" + +namespace testing { +// Input to a parameterized test name generator, describing a test parameter. +// Consists of the parameter value and the integer parameter index. +template +struct TestParamInfo { + TestParamInfo(const ParamType& a_param, size_t an_index) : + param(a_param), + index(an_index) {} + ParamType param; + size_t index; +}; + +// A builtin parameterized test name generator which returns the result of +// testing::PrintToString. +struct PrintToStringParamName { + template + std::string operator()(const TestParamInfo& info) const { + return PrintToString(info.param); + } +}; + +namespace internal { + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// Utility Functions + +// Outputs a message explaining invalid registration of different +// fixture class for the same test suite. This may happen when +// TEST_P macro is used to define two tests with the same name +// but in different namespaces. +GTEST_API_ void ReportInvalidTestSuiteType(const char* test_suite_name, + CodeLocation code_location); + +template class ParamGeneratorInterface; +template class ParamGenerator; + +// Interface for iterating over elements provided by an implementation +// of ParamGeneratorInterface. +template +class ParamIteratorInterface { + public: + virtual ~ParamIteratorInterface() {} + // A pointer to the base generator instance. + // Used only for the purposes of iterator comparison + // to make sure that two iterators belong to the same generator. + virtual const ParamGeneratorInterface* BaseGenerator() const = 0; + // Advances iterator to point to the next element + // provided by the generator. The caller is responsible + // for not calling Advance() on an iterator equal to + // BaseGenerator()->End(). + virtual void Advance() = 0; + // Clones the iterator object. Used for implementing copy semantics + // of ParamIterator. + virtual ParamIteratorInterface* Clone() const = 0; + // Dereferences the current iterator and provides (read-only) access + // to the pointed value. It is the caller's responsibility not to call + // Current() on an iterator equal to BaseGenerator()->End(). + // Used for implementing ParamGenerator::operator*(). + virtual const T* Current() const = 0; + // Determines whether the given iterator and other point to the same + // element in the sequence generated by the generator. + // Used for implementing ParamGenerator::operator==(). + virtual bool Equals(const ParamIteratorInterface& other) const = 0; +}; + +// Class iterating over elements provided by an implementation of +// ParamGeneratorInterface. It wraps ParamIteratorInterface +// and implements the const forward iterator concept. +template +class ParamIterator { + public: + typedef T value_type; + typedef const T& reference; + typedef ptrdiff_t difference_type; + + // ParamIterator assumes ownership of the impl_ pointer. + ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} + ParamIterator& operator=(const ParamIterator& other) { + if (this != &other) + impl_.reset(other.impl_->Clone()); + return *this; + } + + const T& operator*() const { return *impl_->Current(); } + const T* operator->() const { return impl_->Current(); } + // Prefix version of operator++. + ParamIterator& operator++() { + impl_->Advance(); + return *this; + } + // Postfix version of operator++. + ParamIterator operator++(int /*unused*/) { + ParamIteratorInterface* clone = impl_->Clone(); + impl_->Advance(); + return ParamIterator(clone); + } + bool operator==(const ParamIterator& other) const { + return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); + } + bool operator!=(const ParamIterator& other) const { + return !(*this == other); + } + + private: + friend class ParamGenerator; + explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} + std::unique_ptr > impl_; +}; + +// ParamGeneratorInterface is the binary interface to access generators +// defined in other translation units. +template +class ParamGeneratorInterface { + public: + typedef T ParamType; + + virtual ~ParamGeneratorInterface() {} + + // Generator interface definition + virtual ParamIteratorInterface* Begin() const = 0; + virtual ParamIteratorInterface* End() const = 0; +}; + +// Wraps ParamGeneratorInterface and provides general generator syntax +// compatible with the STL Container concept. +// This class implements copy initialization semantics and the contained +// ParamGeneratorInterface instance is shared among all copies +// of the original object. This is possible because that instance is immutable. +template +class ParamGenerator { + public: + typedef ParamIterator iterator; + + explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} + ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} + + ParamGenerator& operator=(const ParamGenerator& other) { + impl_ = other.impl_; + return *this; + } + + iterator begin() const { return iterator(impl_->Begin()); } + iterator end() const { return iterator(impl_->End()); } + + private: + std::shared_ptr > impl_; +}; + +// Generates values from a range of two comparable values. Can be used to +// generate sequences of user-defined types that implement operator+() and +// operator<(). +// This class is used in the Range() function. +template +class RangeGenerator : public ParamGeneratorInterface { + public: + RangeGenerator(T begin, T end, IncrementT step) + : begin_(begin), end_(end), + step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} + ~RangeGenerator() override {} + + ParamIteratorInterface* Begin() const override { + return new Iterator(this, begin_, 0, step_); + } + ParamIteratorInterface* End() const override { + return new Iterator(this, end_, end_index_, step_); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, T value, int index, + IncrementT step) + : base_(base), value_(value), index_(index), step_(step) {} + ~Iterator() override {} + + const ParamGeneratorInterface* BaseGenerator() const override { + return base_; + } + void Advance() override { + value_ = static_cast(value_ + step_); + index_++; + } + ParamIteratorInterface* Clone() const override { + return new Iterator(*this); + } + const T* Current() const override { return &value_; } + bool Equals(const ParamIteratorInterface& other) const override { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const int other_index = + CheckedDowncastToActualType(&other)->index_; + return index_ == other_index; + } + + private: + Iterator(const Iterator& other) + : ParamIteratorInterface(), + base_(other.base_), value_(other.value_), index_(other.index_), + step_(other.step_) {} + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + T value_; + int index_; + const IncrementT step_; + }; // class RangeGenerator::Iterator + + static int CalculateEndIndex(const T& begin, + const T& end, + const IncrementT& step) { + int end_index = 0; + for (T i = begin; i < end; i = static_cast(i + step)) + end_index++; + return end_index; + } + + // No implementation - assignment is unsupported. + void operator=(const RangeGenerator& other); + + const T begin_; + const T end_; + const IncrementT step_; + // The index for the end() iterator. All the elements in the generated + // sequence are indexed (0-based) to aid iterator comparison. + const int end_index_; +}; // class RangeGenerator + + +// Generates values from a pair of STL-style iterators. Used in the +// ValuesIn() function. The elements are copied from the source range +// since the source can be located on the stack, and the generator +// is likely to persist beyond that stack frame. +template +class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { + public: + template + ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) + : container_(begin, end) {} + ~ValuesInIteratorRangeGenerator() override {} + + ParamIteratorInterface* Begin() const override { + return new Iterator(this, container_.begin()); + } + ParamIteratorInterface* End() const override { + return new Iterator(this, container_.end()); + } + + private: + typedef typename ::std::vector ContainerType; + + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + typename ContainerType::const_iterator iterator) + : base_(base), iterator_(iterator) {} + ~Iterator() override {} + + const ParamGeneratorInterface* BaseGenerator() const override { + return base_; + } + void Advance() override { + ++iterator_; + value_.reset(); + } + ParamIteratorInterface* Clone() const override { + return new Iterator(*this); + } + // We need to use cached value referenced by iterator_ because *iterator_ + // can return a temporary object (and of type other then T), so just + // having "return &*iterator_;" doesn't work. + // value_ is updated here and not in Advance() because Advance() + // can advance iterator_ beyond the end of the range, and we cannot + // detect that fact. The client code, on the other hand, is + // responsible for not calling Current() on an out-of-range iterator. + const T* Current() const override { + if (value_.get() == nullptr) value_.reset(new T(*iterator_)); + return value_.get(); + } + bool Equals(const ParamIteratorInterface& other) const override { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + return iterator_ == + CheckedDowncastToActualType(&other)->iterator_; + } + + private: + Iterator(const Iterator& other) + // The explicit constructor call suppresses a false warning + // emitted by gcc when supplied with the -Wextra option. + : ParamIteratorInterface(), + base_(other.base_), + iterator_(other.iterator_) {} + + const ParamGeneratorInterface* const base_; + typename ContainerType::const_iterator iterator_; + // A cached value of *iterator_. We keep it here to allow access by + // pointer in the wrapping iterator's operator->(). + // value_ needs to be mutable to be accessed in Current(). + // Use of std::unique_ptr helps manage cached value's lifetime, + // which is bound by the lifespan of the iterator itself. + mutable std::unique_ptr value_; + }; // class ValuesInIteratorRangeGenerator::Iterator + + // No implementation - assignment is unsupported. + void operator=(const ValuesInIteratorRangeGenerator& other); + + const ContainerType container_; +}; // class ValuesInIteratorRangeGenerator + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Default parameterized test name generator, returns a string containing the +// integer test parameter index. +template +std::string DefaultParamName(const TestParamInfo& info) { + Message name_stream; + name_stream << info.index; + return name_stream.GetString(); +} + +template +void TestNotEmpty() { + static_assert(sizeof(T) == 0, "Empty arguments are not allowed."); +} +template +void TestNotEmpty(const T&) {} + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Stores a parameter value and later creates tests parameterized with that +// value. +template +class ParameterizedTestFactory : public TestFactoryBase { + public: + typedef typename TestClass::ParamType ParamType; + explicit ParameterizedTestFactory(ParamType parameter) : + parameter_(parameter) {} + Test* CreateTest() override { + TestClass::SetParam(¶meter_); + return new TestClass(); + } + + private: + const ParamType parameter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactoryBase is a base class for meta-factories that create +// test factories for passing into MakeAndRegisterTestInfo function. +template +class TestMetaFactoryBase { + public: + virtual ~TestMetaFactoryBase() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactory creates test factories for passing into +// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives +// ownership of test factory pointer, same factory object cannot be passed +// into that method twice. But ParameterizedTestSuiteInfo is going to call +// it for each Test/Parameter value combination. Thus it needs meta factory +// creator class. +template +class TestMetaFactory + : public TestMetaFactoryBase { + public: + using ParamType = typename TestSuite::ParamType; + + TestMetaFactory() {} + + TestFactoryBase* CreateTestFactory(ParamType parameter) override { + return new ParameterizedTestFactory(parameter); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestSuiteInfoBase is a generic interface +// to ParameterizedTestSuiteInfo classes. ParameterizedTestSuiteInfoBase +// accumulates test information provided by TEST_P macro invocations +// and generators provided by INSTANTIATE_TEST_SUITE_P macro invocations +// and uses that information to register all resulting test instances +// in RegisterTests method. The ParameterizeTestSuiteRegistry class holds +// a collection of pointers to the ParameterizedTestSuiteInfo objects +// and calls RegisterTests() on each of them when asked. +class ParameterizedTestSuiteInfoBase { + public: + virtual ~ParameterizedTestSuiteInfoBase() {} + + // Base part of test suite name for display purposes. + virtual const std::string& GetTestSuiteName() const = 0; + // Test case id to verify identity. + virtual TypeId GetTestSuiteTypeId() const = 0; + // UnitTest class invokes this method to register tests in this + // test suite right before running them in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. + virtual void RegisterTests() = 0; + + protected: + ParameterizedTestSuiteInfoBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test suite and generators +// obtained from INSTANTIATE_TEST_SUITE_P macro invocations for that +// test suite. It registers tests with all values generated by all +// generators when asked. +template +class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { + public: + // ParamType and GeneratorCreationFunc are private types but are required + // for declarations of public methods AddTestPattern() and + // AddTestSuiteInstantiation(). + using ParamType = typename TestSuite::ParamType; + // A function that returns an instance of appropriate generator type. + typedef ParamGenerator(GeneratorCreationFunc)(); + using ParamNameGeneratorFunc = std::string(const TestParamInfo&); + + explicit ParameterizedTestSuiteInfo(const char* name, + CodeLocation code_location) + : test_suite_name_(name), code_location_(code_location) {} + + // Test case base name for display purposes. + const std::string& GetTestSuiteName() const override { + return test_suite_name_; + } + // Test case id to verify identity. + TypeId GetTestSuiteTypeId() const override { return GetTypeId(); } + // TEST_P macro uses AddTestPattern() to record information + // about a single test in a LocalTestInfo structure. + // test_suite_name is the base name of the test suite (without invocation + // prefix). test_base_name is the name of an individual test without + // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is + // test suite base name and DoBar is test base name. + void AddTestPattern(const char* test_suite_name, const char* test_base_name, + TestMetaFactoryBase* meta_factory) { + tests_.push_back(std::shared_ptr( + new TestInfo(test_suite_name, test_base_name, meta_factory))); + } + // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information + // about a generator. + int AddTestSuiteInstantiation(const std::string& instantiation_name, + GeneratorCreationFunc* func, + ParamNameGeneratorFunc* name_func, + const char* file, int line) { + instantiations_.push_back( + InstantiationInfo(instantiation_name, func, name_func, file, line)); + return 0; // Return value used only to run this method in namespace scope. + } + // UnitTest class invokes this method to register tests in this test suite + // test suites right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more than once. + void RegisterTests() override { + for (typename TestInfoContainer::iterator test_it = tests_.begin(); + test_it != tests_.end(); ++test_it) { + std::shared_ptr test_info = *test_it; + for (typename InstantiationContainer::iterator gen_it = + instantiations_.begin(); gen_it != instantiations_.end(); + ++gen_it) { + const std::string& instantiation_name = gen_it->name; + ParamGenerator generator((*gen_it->generator)()); + ParamNameGeneratorFunc* name_func = gen_it->name_func; + const char* file = gen_it->file; + int line = gen_it->line; + + std::string test_suite_name; + if ( !instantiation_name.empty() ) + test_suite_name = instantiation_name + "/"; + test_suite_name += test_info->test_suite_base_name; + + size_t i = 0; + std::set test_param_names; + for (typename ParamGenerator::iterator param_it = + generator.begin(); + param_it != generator.end(); ++param_it, ++i) { + Message test_name_stream; + + std::string param_name = name_func( + TestParamInfo(*param_it, i)); + + GTEST_CHECK_(IsValidParamName(param_name)) + << "Parameterized test name '" << param_name + << "' is invalid, in " << file + << " line " << line << std::endl; + + GTEST_CHECK_(test_param_names.count(param_name) == 0) + << "Duplicate parameterized test name '" << param_name + << "', in " << file << " line " << line << std::endl; + + test_param_names.insert(param_name); + + if (!test_info->test_base_name.empty()) { + test_name_stream << test_info->test_base_name << "/"; + } + test_name_stream << param_name; + MakeAndRegisterTestInfo( + test_suite_name.c_str(), test_name_stream.GetString().c_str(), + nullptr, // No type parameter. + PrintToString(*param_it).c_str(), code_location_, + GetTestSuiteTypeId(), + SuiteApiResolver::GetSetUpCaseOrSuite(file, line), + SuiteApiResolver::GetTearDownCaseOrSuite(file, line), + test_info->test_meta_factory->CreateTestFactory(*param_it)); + } // for param_it + } // for gen_it + } // for test_it + } // RegisterTests + + private: + // LocalTestInfo structure keeps information about a single test registered + // with TEST_P macro. + struct TestInfo { + TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name, + TestMetaFactoryBase* a_test_meta_factory) + : test_suite_base_name(a_test_suite_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} + + const std::string test_suite_base_name; + const std::string test_base_name; + const std::unique_ptr > test_meta_factory; + }; + using TestInfoContainer = ::std::vector >; + // Records data received from INSTANTIATE_TEST_SUITE_P macros: + // + struct InstantiationInfo { + InstantiationInfo(const std::string &name_in, + GeneratorCreationFunc* generator_in, + ParamNameGeneratorFunc* name_func_in, + const char* file_in, + int line_in) + : name(name_in), + generator(generator_in), + name_func(name_func_in), + file(file_in), + line(line_in) {} + + std::string name; + GeneratorCreationFunc* generator; + ParamNameGeneratorFunc* name_func; + const char* file; + int line; + }; + typedef ::std::vector InstantiationContainer; + + static bool IsValidParamName(const std::string& name) { + // Check for empty string + if (name.empty()) + return false; + + // Check for invalid characters + for (std::string::size_type index = 0; index < name.size(); ++index) { + if (!isalnum(name[index]) && name[index] != '_') + return false; + } + + return true; + } + + const std::string test_suite_name_; + CodeLocation code_location_; + TestInfoContainer tests_; + InstantiationContainer instantiations_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfo); +}; // class ParameterizedTestSuiteInfo + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +template +using ParameterizedTestCaseInfo = ParameterizedTestSuiteInfo; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestSuiteRegistry contains a map of +// ParameterizedTestSuiteInfoBase classes accessed by test suite names. TEST_P +// and INSTANTIATE_TEST_SUITE_P macros use it to locate their corresponding +// ParameterizedTestSuiteInfo descriptors. +class ParameterizedTestSuiteRegistry { + public: + ParameterizedTestSuiteRegistry() {} + ~ParameterizedTestSuiteRegistry() { + for (auto& test_suite_info : test_suite_infos_) { + delete test_suite_info; + } + } + + // Looks up or creates and returns a structure containing information about + // tests and instantiations of a particular test suite. + template + ParameterizedTestSuiteInfo* GetTestSuitePatternHolder( + const char* test_suite_name, CodeLocation code_location) { + ParameterizedTestSuiteInfo* typed_test_info = nullptr; + for (auto& test_suite_info : test_suite_infos_) { + if (test_suite_info->GetTestSuiteName() == test_suite_name) { + if (test_suite_info->GetTestSuiteTypeId() != GetTypeId()) { + // Complain about incorrect usage of Google Test facilities + // and terminate the program since we cannot guaranty correct + // test suite setup and tear-down in this case. + ReportInvalidTestSuiteType(test_suite_name, code_location); + posix::Abort(); + } else { + // At this point we are sure that the object we found is of the same + // type we are looking for, so we downcast it to that type + // without further checks. + typed_test_info = CheckedDowncastToActualType< + ParameterizedTestSuiteInfo >(test_suite_info); + } + break; + } + } + if (typed_test_info == nullptr) { + typed_test_info = new ParameterizedTestSuiteInfo( + test_suite_name, code_location); + test_suite_infos_.push_back(typed_test_info); + } + return typed_test_info; + } + void RegisterTests() { + for (auto& test_suite_info : test_suite_infos_) { + test_suite_info->RegisterTests(); + } + } +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + template + ParameterizedTestCaseInfo* GetTestCasePatternHolder( + const char* test_case_name, CodeLocation code_location) { + return GetTestSuitePatternHolder(test_case_name, code_location); + } + +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + private: + using TestSuiteInfoContainer = ::std::vector; + + TestSuiteInfoContainer test_suite_infos_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry); +}; + +} // namespace internal + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { +// Used in the Values() function to provide polymorphic capabilities. + +template +class ValueArray { + public: + ValueArray(Ts... v) : v_{std::move(v)...} {} + + template + operator ParamGenerator() const { // NOLINT + return ValuesIn(MakeVector(MakeIndexSequence())); + } + + private: + template + std::vector MakeVector(IndexSequence) const { + return std::vector{static_cast(v_.template Get())...}; + } + + FlatTuple v_; +}; + +template +class CartesianProductGenerator + : public ParamGeneratorInterface<::std::tuple> { + public: + typedef ::std::tuple ParamType; + + CartesianProductGenerator(const std::tuple...>& g) + : generators_(g) {} + ~CartesianProductGenerator() override {} + + ParamIteratorInterface* Begin() const override { + return new Iterator(this, generators_, false); + } + ParamIteratorInterface* End() const override { + return new Iterator(this, generators_, true); + } + + private: + template + class IteratorImpl; + template + class IteratorImpl> + : public ParamIteratorInterface { + public: + IteratorImpl(const ParamGeneratorInterface* base, + const std::tuple...>& generators, bool is_end) + : base_(base), + begin_(std::get(generators).begin()...), + end_(std::get(generators).end()...), + current_(is_end ? end_ : begin_) { + ComputeCurrentValue(); + } + ~IteratorImpl() override {} + + const ParamGeneratorInterface* BaseGenerator() const override { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + void Advance() override { + assert(!AtEnd()); + // Advance the last iterator. + ++std::get(current_); + // if that reaches end, propagate that up. + AdvanceIfEnd(); + ComputeCurrentValue(); + } + ParamIteratorInterface* Clone() const override { + return new IteratorImpl(*this); + } + + const ParamType* Current() const override { return current_value_.get(); } + + bool Equals(const ParamIteratorInterface& other) const override { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const IteratorImpl* typed_other = + CheckedDowncastToActualType(&other); + + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + if (AtEnd() && typed_other->AtEnd()) return true; + + bool same = true; + bool dummy[] = { + (same = same && std::get(current_) == + std::get(typed_other->current_))...}; + (void)dummy; + return same; + } + + private: + template + void AdvanceIfEnd() { + if (std::get(current_) != std::get(end_)) return; + + bool last = ThisI == 0; + if (last) { + // We are done. Nothing else to propagate. + return; + } + + constexpr size_t NextI = ThisI - (ThisI != 0); + std::get(current_) = std::get(begin_); + ++std::get(current_); + AdvanceIfEnd(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = std::make_shared(*std::get(current_)...); + } + bool AtEnd() const { + bool at_end = false; + bool dummy[] = { + (at_end = at_end || std::get(current_) == std::get(end_))...}; + (void)dummy; + return at_end; + } + + const ParamGeneratorInterface* const base_; + std::tuple::iterator...> begin_; + std::tuple::iterator...> end_; + std::tuple::iterator...> current_; + std::shared_ptr current_value_; + }; + + using Iterator = IteratorImpl::type>; + + std::tuple...> generators_; +}; + +template +class CartesianProductHolder { + public: + CartesianProductHolder(const Gen&... g) : generators_(g...) {} + template + operator ParamGenerator<::std::tuple>() const { + return ParamGenerator<::std::tuple>( + new CartesianProductGenerator(generators_)); + } + + private: + std::tuple generators_; +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-port-arch.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-port-arch.h new file mode 100644 index 0000000000000000000000000000000000000000..cece93dba12d4983c7ef0b3413b7964c4477abca --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-port-arch.h @@ -0,0 +1,107 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines the GTEST_OS_* macro. +// It is separate from gtest-port.h so that custom/gtest-port.h can include it. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +# define GTEST_OS_CYGWIN 1 +# elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__) +# define GTEST_OS_WINDOWS_MINGW 1 +# define GTEST_OS_WINDOWS 1 +#elif defined _WIN32 +# define GTEST_OS_WINDOWS 1 +# ifdef _WIN32_WCE +# define GTEST_OS_WINDOWS_MOBILE 1 +# elif defined(WINAPI_FAMILY) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define GTEST_OS_WINDOWS_DESKTOP 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) +# define GTEST_OS_WINDOWS_PHONE 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +# define GTEST_OS_WINDOWS_RT 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) +# define GTEST_OS_WINDOWS_PHONE 1 +# define GTEST_OS_WINDOWS_TV_TITLE 1 +# else + // WINAPI_FAMILY defined but no known partition matched. + // Default to desktop. +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif +# else +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif // _WIN32_WCE +#elif defined __OS2__ +# define GTEST_OS_OS2 1 +#elif defined __APPLE__ +# define GTEST_OS_MAC 1 +# if TARGET_OS_IPHONE +# define GTEST_OS_IOS 1 +# endif +#elif defined __DragonFly__ +# define GTEST_OS_DRAGONFLY 1 +#elif defined __FreeBSD__ +# define GTEST_OS_FREEBSD 1 +#elif defined __Fuchsia__ +# define GTEST_OS_FUCHSIA 1 +#elif defined(__GLIBC__) && defined(__FreeBSD_kernel__) +# define GTEST_OS_GNU_KFREEBSD 1 +#elif defined __linux__ +# define GTEST_OS_LINUX 1 +# if defined __ANDROID__ +# define GTEST_OS_LINUX_ANDROID 1 +# endif +#elif defined __MVS__ +# define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +# define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +# define GTEST_OS_AIX 1 +#elif defined(__hpux) +# define GTEST_OS_HPUX 1 +#elif defined __native_client__ +# define GTEST_OS_NACL 1 +#elif defined __NetBSD__ +# define GTEST_OS_NETBSD 1 +#elif defined __OpenBSD__ +# define GTEST_OS_OPENBSD 1 +#elif defined __QNX__ +# define GTEST_OS_QNX 1 +#elif defined(__HAIKU__) +#define GTEST_OS_HAIKU 1 +#endif // __CYGWIN__ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-port.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-port.h new file mode 100644 index 0000000000000000000000000000000000000000..063fcb1083babb5226ff1098339b2bac06f08250 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-port.h @@ -0,0 +1,2231 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Low-level types and utilities for porting Google Test to various +// platforms. All macros ending with _ and symbols defined in an +// internal namespace are subject to change without notice. Code +// outside Google Test MUST NOT USE THEM DIRECTLY. Macros that don't +// end with _ are part of Google Test's public API and can be used by +// code outside Google Test. +// +// This file is fundamental to Google Test. All other Google Test source +// files are expected to #include this. Therefore, it cannot #include +// any other Google Test header. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +// Environment-describing macros +// ----------------------------- +// +// Google Test can be used in many different environments. Macros in +// this section tell Google Test what kind of environment it is being +// used in, such that Google Test can provide environment-specific +// features and implementations. +// +// Google Test tries to automatically detect the properties of its +// environment, so users usually don't need to worry about these +// macros. However, the automatic detection is not perfect. +// Sometimes it's necessary for a user to define some of the following +// macros in the build script to override Google Test's decisions. +// +// If the user doesn't define a macro in the list, Google Test will +// provide a default definition. After this header is #included, all +// macros in this list will be defined to either 1 or 0. +// +// Notes to maintainers: +// - Each macro here is a user-tweakable knob; do not grow the list +// lightly. +// - Use #if to key off these macros. Don't use #ifdef or "#if +// defined(...)", which will not work as these macros are ALWAYS +// defined. +// +// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) +// is/isn't available. +// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions +// are enabled. +// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular +// expressions are/aren't available. +// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that +// is/isn't available. +// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't +// enabled. +// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that +// std::wstring does/doesn't work (Google Test can +// be used where std::wstring is unavailable). +// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the +// compiler supports Microsoft's "Structured +// Exception Handling". +// GTEST_HAS_STREAM_REDIRECTION +// - Define it to 1/0 to indicate whether the +// platform supports I/O stream redirection using +// dup() and dup2(). +// GTEST_LINKED_AS_SHARED_LIBRARY +// - Define to 1 when compiling tests that use +// Google Test as a shared library (known as +// DLL on Windows). +// GTEST_CREATE_SHARED_LIBRARY +// - Define to 1 when compiling Google Test itself +// as a shared library. +// GTEST_DEFAULT_DEATH_TEST_STYLE +// - The default value of --gtest_death_test_style. +// The legacy default has been "fast" in the open +// source version since 2008. The recommended value +// is "threadsafe", and can be set in +// custom/gtest-port.h. + +// Platform-indicating macros +// -------------------------- +// +// Macros indicating the platform on which Google Test is being used +// (a macro is defined to 1 if compiled on the given platform; +// otherwise UNDEFINED -- it's never defined to 0.). Google Test +// defines these macros automatically. Code outside Google Test MUST +// NOT define them. +// +// GTEST_OS_AIX - IBM AIX +// GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_DRAGONFLY - DragonFlyBSD +// GTEST_OS_FREEBSD - FreeBSD +// GTEST_OS_FUCHSIA - Fuchsia +// GTEST_OS_GNU_KFREEBSD - GNU/kFreeBSD +// GTEST_OS_HAIKU - Haiku +// GTEST_OS_HPUX - HP-UX +// GTEST_OS_LINUX - Linux +// GTEST_OS_LINUX_ANDROID - Google Android +// GTEST_OS_MAC - Mac OS X +// GTEST_OS_IOS - iOS +// GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_NETBSD - NetBSD +// GTEST_OS_OPENBSD - OpenBSD +// GTEST_OS_OS2 - OS/2 +// GTEST_OS_QNX - QNX +// GTEST_OS_SOLARIS - Sun Solaris +// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) +// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop +// GTEST_OS_WINDOWS_MINGW - MinGW +// GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_WINDOWS_PHONE - Windows Phone +// GTEST_OS_WINDOWS_RT - Windows Store App/WinRT +// GTEST_OS_ZOS - z/OS +// +// Among the platforms, Cygwin, Linux, Mac OS X, and Windows have the +// most stable support. Since core members of the Google Test project +// don't have access to other platforms, support for them may be less +// stable. If you notice any problems on your platform, please notify +// googletestframework@googlegroups.com (patches for fixing them are +// even more welcome!). +// +// It is possible that none of the GTEST_OS_* macros are defined. + +// Feature-indicating macros +// ------------------------- +// +// Macros indicating which Google Test features are available (a macro +// is defined to 1 if the corresponding feature is supported; +// otherwise UNDEFINED -- it's never defined to 0.). Google Test +// defines these macros automatically. Code outside Google Test MUST +// NOT define them. +// +// These macros are public so that portable tests can be written. +// Such tests typically surround code using a feature with an #if +// which controls that code. For example: +// +// #if GTEST_HAS_DEATH_TEST +// EXPECT_DEATH(DoSomethingDeadly()); +// #endif +// +// GTEST_HAS_DEATH_TEST - death tests +// GTEST_HAS_TYPED_TEST - typed tests +// GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_IS_THREADSAFE - Google Test is thread-safe. +// GOOGLETEST_CM0007 DO NOT DELETE +// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with +// GTEST_HAS_POSIX_RE (see above) which users can +// define themselves. +// GTEST_USES_SIMPLE_RE - our own simple regex is used; +// the above RE\b(s) are mutually exclusive. + +// Misc public macros +// ------------------ +// +// GTEST_FLAG(flag_name) - references the variable corresponding to +// the given Google Test flag. + +// Internal utilities +// ------------------ +// +// The following macros and utilities are for Google Test's INTERNAL +// use only. Code outside Google Test MUST NOT USE THEM DIRECTLY. +// +// Macros for basic C++ coding: +// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. +// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a +// variable don't have to be used. +// GTEST_DISALLOW_ASSIGN_ - disables operator=. +// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. +// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is +// suppressed (constant conditional). +// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 +// is suppressed. +// +// Synchronization: +// Mutex, MutexLock, ThreadLocal, GetThreadCount() +// - synchronization primitives. +// +// Regular expressions: +// RE - a simple regular expression class using the POSIX +// Extended Regular Expression syntax on UNIX-like platforms +// GOOGLETEST_CM0008 DO NOT DELETE +// or a reduced regular exception syntax on other +// platforms, including Windows. +// Logging: +// GTEST_LOG_() - logs messages at the specified severity level. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. +// +// Stdout and stderr capturing: +// CaptureStdout() - starts capturing stdout. +// GetCapturedStdout() - stops capturing stdout and returns the captured +// string. +// CaptureStderr() - starts capturing stderr. +// GetCapturedStderr() - stops capturing stderr and returns the captured +// string. +// +// Integer types: +// TypeWithSize - maps an integer to a int type. +// Int32, UInt32, Int64, UInt64, TimeInMillis +// - integers of known sizes. +// BiggestInt - the biggest signed integer type. +// +// Command-line utilities: +// GTEST_DECLARE_*() - declares a flag. +// GTEST_DEFINE_*() - defines a flag. +// GetInjectableArgvs() - returns the command line as a vector of strings. +// +// Environment variable utilities: +// GetEnv() - gets the value of an environment variable. +// BoolFromGTestEnv() - parses a bool environment variable. +// Int32FromGTestEnv() - parses an Int32 environment variable. +// StringFromGTestEnv() - parses a string environment variable. +// +// Deprecation warnings: +// GTEST_INTERNAL_DEPRECATED(message) - attribute marking a function as +// deprecated; calling a marked function +// should generate a compiler warning + +#include // for isspace, etc +#include // for ptrdiff_t +#include +#include +#include +#include +#include + +#ifndef _WIN32_WCE +# include +# include +#endif // !_WIN32_WCE + +#if defined __APPLE__ +# include +# include +#endif + +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include +#include +#include // NOLINT + +#include "gtest/internal/gtest-port-arch.h" +#include "gtest/internal/custom/gtest-port.h" + +#if !defined(GTEST_DEV_EMAIL_) +# define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +# define GTEST_FLAG_PREFIX_ "gtest_" +# define GTEST_FLAG_PREFIX_DASH_ "gtest-" +# define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +# define GTEST_NAME_ "Google Test" +# define GTEST_PROJECT_URL_ "https://github.com/google/googletest/" +#endif // !defined(GTEST_DEV_EMAIL_) + +#if !defined(GTEST_INIT_GOOGLE_TEST_NAME_) +# define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest" +#endif // !defined(GTEST_INIT_GOOGLE_TEST_NAME_) + +// Determines the version of gcc that is used to compile this. +#ifdef __GNUC__ +// 40302 means version 4.3.2. +# define GTEST_GCC_VER_ \ + (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#endif // __GNUC__ + +// Macros for disabling Microsoft Visual C++ warnings. +// +// GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) +// /* code that triggers warnings C4800 and C4385 */ +// GTEST_DISABLE_MSC_WARNINGS_POP_() +#if defined(_MSC_VER) +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ + __pragma(warning(push)) \ + __pragma(warning(disable: warnings)) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() \ + __pragma(warning(pop)) +#else +// Not all compilers are MSVC +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + +// Clang on Windows does not understand MSVC's pragma warning. +// We need clang-specific way to disable function deprecation warning. +#ifdef __clang__ +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"") +#define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + _Pragma("clang diagnostic pop") +#else +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) +# define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + +// Brings in definitions for functions used in the testing::internal::posix +// namespace (read, write, close, chdir, isatty, stat). We do not currently +// use them on Windows Mobile. +#if GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS_MOBILE +# include +# include +# endif +// In order to avoid having to include , use forward declaration +#if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR) +// MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two +// separate (equivalent) structs, instead of using typedef +typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#else +// Assume CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. +// This assumption is verified by +// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. +typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#endif +#else +// This assumes that non-Windows OSes provide unistd.h. For OSes where this +// is not the case, we need to include headers that provide the functions +// mentioned above. +# include +# include +#endif // GTEST_OS_WINDOWS + +#if GTEST_OS_LINUX_ANDROID +// Used to define __ANDROID_API__ matching the target NDK API level. +# include // NOLINT +#endif + +// Defines this to true if and only if Google Test can use POSIX regular +// expressions. +#ifndef GTEST_HAS_POSIX_RE +# if GTEST_OS_LINUX_ANDROID +// On Android, is only available starting with Gingerbread. +# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) +# else +# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) +# endif +#endif + +#if GTEST_USES_PCRE +// The appropriate headers have already been included. + +#elif GTEST_HAS_POSIX_RE + +// On some platforms, needs someone to define size_t, and +// won't compile otherwise. We can #include it here as we already +// included , which is guaranteed to define size_t through +// . +# include // NOLINT + +# define GTEST_USES_POSIX_RE 1 + +#elif GTEST_OS_WINDOWS + +// is not available on Windows. Use our own simple regex +// implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#else + +// may not be available on this platform. Use our own +// simple regex implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#endif // GTEST_USES_PCRE + +#ifndef GTEST_HAS_EXCEPTIONS +// The user didn't tell us whether exceptions are enabled, so we need +// to figure it out. +# if defined(_MSC_VER) && defined(_CPPUNWIND) +// MSVC defines _CPPUNWIND to 1 if and only if exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__BORLANDC__) +// C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS +// macro to enable exceptions, so we'll do the same. +// Assumes that exceptions are enabled by default. +# ifndef _HAS_EXCEPTIONS +# define _HAS_EXCEPTIONS 1 +# endif // _HAS_EXCEPTIONS +# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +# elif defined(__clang__) +// clang defines __EXCEPTIONS if and only if exceptions are enabled before clang +// 220714, but if and only if cleanups are enabled after that. In Obj-C++ files, +// there can be cleanups for ObjC exceptions which also need cleanups, even if +// C++ exceptions are disabled. clang has __has_feature(cxx_exceptions) which +// checks for C++ exceptions starting at clang r206352, but which checked for +// cleanups prior to that. To reliably check for C++ exception availability with +// clang, check for +// __EXCEPTIONS && __has_feature(cxx_exceptions). +# define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions)) +# elif defined(__GNUC__) && __EXCEPTIONS +// gcc defines __EXCEPTIONS to 1 if and only if exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__SUNPRO_CC) +// Sun Pro CC supports exceptions. However, there is no compile-time way of +// detecting whether they are enabled or not. Therefore, we assume that +// they are enabled unless the user tells us otherwise. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__IBMCPP__) && __EXCEPTIONS +// xlC defines __EXCEPTIONS to 1 if and only if exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__HP_aCC) +// Exception handling is in effect by default in HP aCC compiler. It has to +// be turned of by +noeh compiler option if desired. +# define GTEST_HAS_EXCEPTIONS 1 +# else +// For other compilers, we assume exceptions are disabled to be +// conservative. +# define GTEST_HAS_EXCEPTIONS 0 +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +#endif // GTEST_HAS_EXCEPTIONS + +#if !defined(GTEST_HAS_STD_STRING) +// Even though we don't use this macro any longer, we keep it in case +// some clients still depend on it. +# define GTEST_HAS_STD_STRING 1 +#elif !GTEST_HAS_STD_STRING +// The user told us that ::std::string isn't available. +# error "::std::string isn't available." +#endif // !defined(GTEST_HAS_STD_STRING) + +#ifndef GTEST_HAS_STD_WSTRING +// The user didn't tell us whether ::std::wstring is available, so we need +// to figure it out. +// Cygwin 1.7 and below doesn't support ::std::wstring. +// Solaris' libc++ doesn't support it either. Android has +// no support for it at least as recent as Froyo (2.2). +#define GTEST_HAS_STD_WSTRING \ + (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + GTEST_OS_HAIKU)) + +#endif // GTEST_HAS_STD_WSTRING + +// Determines whether RTTI is available. +#ifndef GTEST_HAS_RTTI +// The user didn't tell us whether RTTI is enabled, so we need to +// figure it out. + +# ifdef _MSC_VER + +#ifdef _CPPRTTI // MSVC defines this macro if and only if RTTI is enabled. +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +// Starting with version 4.3.2, gcc defines __GXX_RTTI if and only if RTTI is +// enabled. +# elif defined(__GNUC__) + +# ifdef __GXX_RTTI +// When building against STLport with the Android NDK and with +// -frtti -fno-exceptions, the build fails at link time with undefined +// references to __cxa_bad_typeid. Note sure if STL or toolchain bug, +// so disable RTTI when detected. +# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ + !defined(__EXCEPTIONS) +# define GTEST_HAS_RTTI 0 +# else +# define GTEST_HAS_RTTI 1 +# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS +# else +# define GTEST_HAS_RTTI 0 +# endif // __GXX_RTTI + +// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends +// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the +// first version with C++ support. +# elif defined(__clang__) + +# define GTEST_HAS_RTTI __has_feature(cxx_rtti) + +// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if +// both the typeid and dynamic_cast features are present. +# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) + +# ifdef __RTTI_ALL__ +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +# else + +// For all other compilers, we assume RTTI is enabled. +# define GTEST_HAS_RTTI 1 + +# endif // _MSC_VER + +#endif // GTEST_HAS_RTTI + +// It's this header's responsibility to #include when RTTI +// is enabled. +#if GTEST_HAS_RTTI +# include +#endif + +// Determines whether Google Test can use the pthreads library. +#ifndef GTEST_HAS_PTHREAD +// The user didn't tell us explicitly, so we make reasonable assumptions about +// which platforms have pthreads support. +// +// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 +// to your compiler flags. +#define GTEST_HAS_PTHREAD \ + (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD || \ + GTEST_OS_HAIKU) +#endif // GTEST_HAS_PTHREAD + +#if GTEST_HAS_PTHREAD +// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is +// true. +# include // NOLINT + +// For timespec and nanosleep, used below. +# include // NOLINT +#endif + +// Determines whether clone(2) is supported. +// Usually it will only be available on Linux, excluding +// Linux on the Itanium architecture. +// Also see http://linux.die.net/man/2/clone. +#ifndef GTEST_HAS_CLONE +// The user didn't tell us, so we need to figure it out. + +# if GTEST_OS_LINUX && !defined(__ia64__) +# if GTEST_OS_LINUX_ANDROID +// On Android, clone() became available at different API levels for each 32-bit +// architecture. +# if defined(__LP64__) || \ + (defined(__arm__) && __ANDROID_API__ >= 9) || \ + (defined(__mips__) && __ANDROID_API__ >= 12) || \ + (defined(__i386__) && __ANDROID_API__ >= 17) +# define GTEST_HAS_CLONE 1 +# else +# define GTEST_HAS_CLONE 0 +# endif +# else +# define GTEST_HAS_CLONE 1 +# endif +# else +# define GTEST_HAS_CLONE 0 +# endif // GTEST_OS_LINUX && !defined(__ia64__) + +#endif // GTEST_HAS_CLONE + +// Determines whether to support stream redirection. This is used to test +// output correctness and to implement death tests. +#ifndef GTEST_HAS_STREAM_REDIRECTION +// By default, we assume that stream redirection is supported on all +// platforms except known mobile ones. +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT +# define GTEST_HAS_STREAM_REDIRECTION 0 +# else +# define GTEST_HAS_STREAM_REDIRECTION 1 +# endif // !GTEST_OS_WINDOWS_MOBILE +#endif // GTEST_HAS_STREAM_REDIRECTION + +// Determines whether to support death tests. +// pops up a dialog window that cannot be suppressed programmatically. +#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_MAC && !GTEST_OS_IOS) || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) || GTEST_OS_WINDOWS_MINGW || \ + GTEST_OS_AIX || GTEST_OS_HPUX || GTEST_OS_OPENBSD || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_HAIKU) +# define GTEST_HAS_DEATH_TEST 1 +#endif + +// Determines whether to support type-driven tests. + +// Typed tests need and variadic macros, which GCC, VC++ 8.0, +// Sun Pro CC, IBM Visual Age, and HP aCC support. +#if defined(__GNUC__) || defined(_MSC_VER) || defined(__SUNPRO_CC) || \ + defined(__IBMCPP__) || defined(__HP_aCC) +# define GTEST_HAS_TYPED_TEST 1 +# define GTEST_HAS_TYPED_TEST_P 1 +#endif + +// Determines whether the system compiler uses UTF-16 for encoding wide strings. +#define GTEST_WIDE_STRING_USES_UTF16_ \ + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_AIX || GTEST_OS_OS2) + +// Determines whether test results can be streamed to a socket. +#if GTEST_OS_LINUX || GTEST_OS_GNU_KFREEBSD || GTEST_OS_DRAGONFLY || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_OPENBSD +# define GTEST_CAN_STREAM_RESULTS_ 1 +#endif + +// Defines some utility macros. + +// The GNU compiler emits a warning if nested "if" statements are followed by +// an "else" statement and braces are not used to explicitly disambiguate the +// "else" binding. This leads to problems with code like: +// +// if (gate) +// ASSERT_*(condition) << "Some message"; +// +// The "switch (0) case 0:" idiom is used to suppress this. +#ifdef __INTEL_COMPILER +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ +#else +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT +#endif + +// Use this annotation at the end of a struct/class definition to +// prevent the compiler from optimizing away instances that are never +// used. This is useful when all interesting logic happens inside the +// c'tor and / or d'tor. Example: +// +// struct Foo { +// Foo() { ... } +// } GTEST_ATTRIBUTE_UNUSED_; +// +// Also use it after a variable or parameter declaration to tell the +// compiler the variable/parameter does not have to be used. +#if defined(__GNUC__) && !defined(COMPILER_ICC) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +#elif defined(__clang__) +# if __has_attribute(unused) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +# endif +#endif +#ifndef GTEST_ATTRIBUTE_UNUSED_ +# define GTEST_ATTRIBUTE_UNUSED_ +#endif + +// Use this annotation before a function that takes a printf format string. +#if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC) +# if defined(__MINGW_PRINTF_FORMAT) +// MinGW has two different printf implementations. Ensure the format macro +// matches the selected implementation. See +// https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__MINGW_PRINTF_FORMAT, string_index, \ + first_to_check))) +# else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__printf__, string_index, first_to_check))) +# endif +#else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) +#endif + + +// A macro to disallow operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_ASSIGN_(type) \ + void operator=(type const &) = delete + +// A macro to disallow copy constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \ + type(type const &) = delete; \ + GTEST_DISALLOW_ASSIGN_(type) + +// Tell the compiler to warn about unused return values for functions declared +// with this macro. The macro should be used on function declarations +// following the argument list: +// +// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; +#if defined(__GNUC__) && !defined(COMPILER_ICC) +# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) +#else +# define GTEST_MUST_USE_RESULT_ +#endif // __GNUC__ && !COMPILER_ICC + +// MS C++ compiler emits warning when a conditional expression is compile time +// constant. In some contexts this warning is false positive and needs to be +// suppressed. Use the following two macros in such cases: +// +// GTEST_INTENTIONAL_CONST_COND_PUSH_() +// while (true) { +// GTEST_INTENTIONAL_CONST_COND_POP_() +// } +# define GTEST_INTENTIONAL_CONST_COND_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127) +# define GTEST_INTENTIONAL_CONST_COND_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() + +// Determine whether the compiler supports Microsoft's Structured Exception +// Handling. This is supported by several Windows compilers but generally +// does not exist on any other system. +#ifndef GTEST_HAS_SEH +// The user didn't tell us, so we need to figure it out. + +# if defined(_MSC_VER) || defined(__BORLANDC__) +// These two compilers are known to support SEH. +# define GTEST_HAS_SEH 1 +# else +// Assume no SEH. +# define GTEST_HAS_SEH 0 +# endif + +#endif // GTEST_HAS_SEH + +#ifndef GTEST_IS_THREADSAFE + +#define GTEST_IS_THREADSAFE \ + (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ || \ + (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) || \ + GTEST_HAS_PTHREAD) + +#endif // GTEST_IS_THREADSAFE + +// GTEST_API_ qualifies all symbols that must be exported. The definitions below +// are guarded by #ifndef to give embedders a chance to define GTEST_API_ in +// gtest/internal/custom/gtest-port.h +#ifndef GTEST_API_ + +#ifdef _MSC_VER +# if GTEST_LINKED_AS_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllimport) +# elif GTEST_CREATE_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllexport) +# endif +#elif __GNUC__ >= 4 || defined(__clang__) +# define GTEST_API_ __attribute__((visibility ("default"))) +#endif // _MSC_VER + +#endif // GTEST_API_ + +#ifndef GTEST_API_ +# define GTEST_API_ +#endif // GTEST_API_ + +#ifndef GTEST_DEFAULT_DEATH_TEST_STYLE +# define GTEST_DEFAULT_DEATH_TEST_STYLE "fast" +#endif // GTEST_DEFAULT_DEATH_TEST_STYLE + +#ifdef __GNUC__ +// Ask the compiler to never inline a given function. +# define GTEST_NO_INLINE_ __attribute__((noinline)) +#else +# define GTEST_NO_INLINE_ +#endif + +// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. +#if !defined(GTEST_HAS_CXXABI_H_) +# if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER)) +# define GTEST_HAS_CXXABI_H_ 1 +# else +# define GTEST_HAS_CXXABI_H_ 0 +# endif +#endif + +// A function level attribute to disable checking for use of uninitialized +// memory when built with MemorySanitizer. +#if defined(__clang__) +# if __has_feature(memory_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \ + __attribute__((no_sanitize_memory)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +# endif // __has_feature(memory_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +#endif // __clang__ + +// A function level attribute to disable AddressSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(address_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \ + __attribute__((no_sanitize_address)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +# endif // __has_feature(address_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +#endif // __clang__ + +// A function level attribute to disable HWAddressSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(hwaddress_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \ + __attribute__((no_sanitize("hwaddress"))) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +# endif // __has_feature(hwaddress_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +#endif // __clang__ + +// A function level attribute to disable ThreadSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(thread_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \ + __attribute__((no_sanitize_thread)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +# endif // __has_feature(thread_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +#endif // __clang__ + +namespace testing { + +class Message; + +// Legacy imports for backwards compatibility. +// New code should use std:: names directly. +using std::get; +using std::make_tuple; +using std::tuple; +using std::tuple_element; +using std::tuple_size; + +namespace internal { + +// A secret type that Google Test users don't know about. It has no +// definition on purpose. Therefore it's impossible to create a +// Secret object, which is what we want. +class Secret; + +// The GTEST_COMPILE_ASSERT_ is a legacy macro used to verify that a compile +// time expression is true (in new code, use static_assert instead). For +// example, you could use it to verify the size of a static array: +// +// GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES, +// names_incorrect_size); +// +// The second argument to the macro must be a valid C++ identifier. If the +// expression is false, compiler will issue an error containing this identifier. +#define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) + +// Evaluates to the number of elements in 'array'. +#define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) + +// A helper for suppressing warnings on constant condition. It just +// returns 'condition'. +GTEST_API_ bool IsTrue(bool condition); + +// Defines RE. + +#if GTEST_USES_PCRE +// if used, PCRE is injected by custom/gtest-port.h +#elif GTEST_USES_POSIX_RE || GTEST_USES_SIMPLE_RE + +// A simple C++ wrapper for . It uses the POSIX Extended +// Regular Expression syntax. +class GTEST_API_ RE { + public: + // A copy constructor is required by the Standard to initialize object + // references from r-values. + RE(const RE& other) { Init(other.pattern()); } + + // Constructs an RE from a string. + RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT + + RE(const char* regex) { Init(regex); } // NOLINT + ~RE(); + + // Returns the string representation of the regex. + const char* pattern() const { return pattern_; } + + // FullMatch(str, re) returns true if and only if regular expression re + // matches the entire str. + // PartialMatch(str, re) returns true if and only if regular expression re + // matches a substring of str (including str itself). + static bool FullMatch(const ::std::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::std::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + + static bool FullMatch(const char* str, const RE& re); + static bool PartialMatch(const char* str, const RE& re); + + private: + void Init(const char* regex); + const char* pattern_; + bool is_valid_; + +# if GTEST_USES_POSIX_RE + + regex_t full_regex_; // For FullMatch(). + regex_t partial_regex_; // For PartialMatch(). + +# else // GTEST_USES_SIMPLE_RE + + const char* full_pattern_; // For FullMatch(); + +# endif + + GTEST_DISALLOW_ASSIGN_(RE); +}; + +#endif // GTEST_USES_PCRE + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, + int line); + +// Defines logging utilities: +// GTEST_LOG_(severity) - logs messages at the specified severity level. The +// message itself is streamed into the macro. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. + +enum GTestLogSeverity { + GTEST_INFO, + GTEST_WARNING, + GTEST_ERROR, + GTEST_FATAL +}; + +// Formats log entry severity, provides a stream object for streaming the +// log message, and terminates the message with a newline when going out of +// scope. +class GTEST_API_ GTestLog { + public: + GTestLog(GTestLogSeverity severity, const char* file, int line); + + // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. + ~GTestLog(); + + ::std::ostream& GetStream() { return ::std::cerr; } + + private: + const GTestLogSeverity severity_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); +}; + +#if !defined(GTEST_LOG_) + +# define GTEST_LOG_(severity) \ + ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ + __FILE__, __LINE__).GetStream() + +inline void LogToStderr() {} +inline void FlushInfoLog() { fflush(nullptr); } + +#endif // !defined(GTEST_LOG_) + +#if !defined(GTEST_CHECK_) +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GTEST_CHECK_(boolean_condition); +// or +// GTEST_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. +# define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " +#endif // !defined(GTEST_CHECK_) + +// An all-mode assert to verify that the given POSIX-style function +// call returns 0 (indicating success). Known limitation: this +// doesn't expand to a balanced 'if' statement, so enclose the macro +// in {} if you need to use it as the only statement in an 'if' +// branch. +#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ + if (const int gtest_error = (posix_call)) \ + GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ + << gtest_error + +// Transforms "T" into "const T&" according to standard reference collapsing +// rules (this is only needed as a backport for C++98 compilers that do not +// support reference collapsing). Specifically, it transforms: +// +// char ==> const char& +// const char ==> const char& +// char& ==> char& +// const char& ==> const char& +// +// Note that the non-const reference will not have "const" added. This is +// standard, and necessary so that "T" can always bind to "const T&". +template +struct ConstRef { typedef const T& type; }; +template +struct ConstRef { typedef T& type; }; + +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + typename ::testing::internal::ConstRef::type + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Use ImplicitCast_ as a safe version of static_cast for upcasting in +// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a +// const Foo*). When you use ImplicitCast_, the compiler checks that +// the cast is safe. Such explicit ImplicitCast_s are necessary in +// surprisingly many situations where C++ demands an exact type match +// instead of an argument type convertable to a target type. +// +// The syntax for using ImplicitCast_ is the same as for static_cast: +// +// ImplicitCast_(expr) +// +// ImplicitCast_ would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., implicit_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template +inline To ImplicitCast_(To x) { return x; } + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., down_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template // use like this: DownCast_(foo); +inline To DownCast_(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + GTEST_INTENTIONAL_CONST_COND_PUSH_() + if (false) { + GTEST_INTENTIONAL_CONST_COND_POP_() + const To to = nullptr; + ::testing::internal::ImplicitCast_(to); + } + +#if GTEST_HAS_RTTI + // RTTI: debug mode only! + GTEST_CHECK_(f == nullptr || dynamic_cast(f) != nullptr); +#endif + return static_cast(f); +} + +// Downcasts the pointer of type Base to Derived. +// Derived must be a subclass of Base. The parameter MUST +// point to a class of type Derived, not any subclass of it. +// When RTTI is available, the function performs a runtime +// check to enforce this. +template +Derived* CheckedDowncastToActualType(Base* base) { +#if GTEST_HAS_RTTI + GTEST_CHECK_(typeid(*base) == typeid(Derived)); +#endif + +#if GTEST_HAS_DOWNCAST_ + return ::down_cast(base); +#elif GTEST_HAS_RTTI + return dynamic_cast(base); // NOLINT +#else + return static_cast(base); // Poor man's downcast. +#endif +} + +#if GTEST_HAS_STREAM_REDIRECTION + +// Defines the stderr capturer: +// CaptureStdout - starts capturing stdout. +// GetCapturedStdout - stops capturing stdout and returns the captured string. +// CaptureStderr - starts capturing stderr. +// GetCapturedStderr - stops capturing stderr and returns the captured string. +// +GTEST_API_ void CaptureStdout(); +GTEST_API_ std::string GetCapturedStdout(); +GTEST_API_ void CaptureStderr(); +GTEST_API_ std::string GetCapturedStderr(); + +#endif // GTEST_HAS_STREAM_REDIRECTION +// Returns the size (in bytes) of a file. +GTEST_API_ size_t GetFileSize(FILE* file); + +// Reads the entire content of a file as a string. +GTEST_API_ std::string ReadEntireFile(FILE* file); + +// All command line arguments. +GTEST_API_ std::vector GetArgvs(); + +#if GTEST_HAS_DEATH_TEST + +std::vector GetInjectableArgvs(); +// Deprecated: pass the args vector by value instead. +void SetInjectableArgvs(const std::vector* new_argvs); +void SetInjectableArgvs(const std::vector& new_argvs); +void ClearInjectableArgvs(); + +#endif // GTEST_HAS_DEATH_TEST + +// Defines synchronization primitives. +#if GTEST_IS_THREADSAFE +# if GTEST_HAS_PTHREAD +// Sleeps for (roughly) n milliseconds. This function is only for testing +// Google Test's own constructs. Don't use it in user tests, either +// directly or indirectly. +inline void SleepMilliseconds(int n) { + const timespec time = { + 0, // 0 seconds. + n * 1000L * 1000L, // And n ms. + }; + nanosleep(&time, nullptr); +} +# endif // GTEST_HAS_PTHREAD + +# if GTEST_HAS_NOTIFICATION_ +// Notification has already been imported into the namespace. +// Nothing to do here. + +# elif GTEST_HAS_PTHREAD +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class Notification { + public: + Notification() : notified_(false) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); + } + ~Notification() { + pthread_mutex_destroy(&mutex_); + } + + // Notifies all threads created with this notification to start. Must + // be called from the controller thread. + void Notify() { + pthread_mutex_lock(&mutex_); + notified_ = true; + pthread_mutex_unlock(&mutex_); + } + + // Blocks until the controller thread notifies. Must be called from a test + // thread. + void WaitForNotification() { + for (;;) { + pthread_mutex_lock(&mutex_); + const bool notified = notified_; + pthread_mutex_unlock(&mutex_); + if (notified) + break; + SleepMilliseconds(10); + } + } + + private: + pthread_mutex_t mutex_; + bool notified_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; + +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + +GTEST_API_ void SleepMilliseconds(int n); + +// Provides leak-safe Windows kernel handle ownership. +// Used in death tests and in threading support. +class GTEST_API_ AutoHandle { + public: + // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to + // avoid including in this header file. Including is + // undesirable because it defines a lot of symbols and macros that tend to + // conflict with client code. This assumption is verified by + // WindowsTypesTest.HANDLEIsVoidStar. + typedef void* Handle; + AutoHandle(); + explicit AutoHandle(Handle handle); + + ~AutoHandle(); + + Handle Get() const; + void Reset(); + void Reset(Handle handle); + + private: + // Returns true if and only if the handle is a valid handle object that can be + // closed. + bool IsCloseable() const; + + Handle handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class GTEST_API_ Notification { + public: + Notification(); + void Notify(); + void WaitForNotification(); + + private: + AutoHandle event_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; +# endif // GTEST_HAS_NOTIFICATION_ + +// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD +// defined, but we don't want to use MinGW's pthreads implementation, which +// has conformance problems with some versions of the POSIX standard. +# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW + +// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. +// Consequently, it cannot select a correct instantiation of ThreadWithParam +// in order to call its Run(). Introducing ThreadWithParamBase as a +// non-templated base class for ThreadWithParam allows us to bypass this +// problem. +class ThreadWithParamBase { + public: + virtual ~ThreadWithParamBase() {} + virtual void Run() = 0; +}; + +// pthread_create() accepts a pointer to a function type with the C linkage. +// According to the Standard (7.5/1), function types with different linkages +// are different even if they are otherwise identical. Some compilers (for +// example, SunStudio) treat them as different types. Since class methods +// cannot be defined with C-linkage we need to define a free C-function to +// pass into pthread_create(). +extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { + static_cast(thread)->Run(); + return nullptr; +} + +// Helper class for testing Google Test's multi-threading constructs. +// To use it, write: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// Notification thread_can_start; +// ... +// // The thread_can_start parameter is optional; you can supply NULL. +// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); +// thread_can_start.Notify(); +// +// These classes are only for testing Google Test's own constructs. Do +// not use them in user tests, either directly or indirectly. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void UserThreadFunc(T); + + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) + : func_(func), + param_(param), + thread_can_start_(thread_can_start), + finished_(false) { + ThreadWithParamBase* const base = this; + // The thread can be created only after all fields except thread_ + // have been initialized. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_create(&thread_, nullptr, &ThreadFuncWithCLinkage, base)); + } + ~ThreadWithParam() override { Join(); } + + void Join() { + if (!finished_) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, nullptr)); + finished_ = true; + } + } + + void Run() override { + if (thread_can_start_ != nullptr) thread_can_start_->WaitForNotification(); + func_(param_); + } + + private: + UserThreadFunc* const func_; // User-supplied thread function. + const T param_; // User-supplied parameter to the thread function. + // When non-NULL, used to block execution until the controller thread + // notifies. + Notification* const thread_can_start_; + bool finished_; // true if and only if we know that the thread function has + // finished. + pthread_t thread_; // The native thread object. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; +# endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD || + // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ + +# if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ +// Mutex and ThreadLocal have already been imported into the namespace. +// Nothing to do here. + +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + +// Mutex implements mutex on Windows platforms. It is used in conjunction +// with class MutexLock: +// +// Mutex mutex; +// ... +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the +// // end of the current scope. +// +// A static Mutex *must* be defined or declared using one of the following +// macros: +// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// (A non-static Mutex is defined/declared in the usual way). +class GTEST_API_ Mutex { + public: + enum MutexType { kStatic = 0, kDynamic = 1 }; + // We rely on kStaticMutex being 0 as it is to what the linker initializes + // type_ in static mutexes. critical_section_ will be initialized lazily + // in ThreadSafeLazyInit(). + enum StaticConstructorSelector { kStaticMutex = 0 }; + + // This constructor intentionally does nothing. It relies on type_ being + // statically initialized to 0 (effectively setting it to kStatic) and on + // ThreadSafeLazyInit() to lazily initialize the rest of the members. + explicit Mutex(StaticConstructorSelector /*dummy*/) {} + + Mutex(); + ~Mutex(); + + void Lock(); + + void Unlock(); + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld(); + + private: + // Initializes owner_thread_id_ and critical_section_ in static mutexes. + void ThreadSafeLazyInit(); + + // Per https://blogs.msdn.microsoft.com/oldnewthing/20040223-00/?p=40503, + // we assume that 0 is an invalid value for thread IDs. + unsigned int owner_thread_id_; + + // For static mutexes, we rely on these members being initialized to zeros + // by the linker. + MutexType type_; + long critical_section_init_phase_; // NOLINT + GTEST_CRITICAL_SECTION* critical_section_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex) + +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + Mutex* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Base class for ValueHolder. Allows a caller to hold and delete a value +// without knowing its type. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Provides a way for a thread to send notifications to a ThreadLocal +// regardless of its parameter type. +class ThreadLocalBase { + public: + // Creates a new ValueHolder object holding a default value passed to + // this ThreadLocal's constructor and returns it. It is the caller's + // responsibility not to call this when the ThreadLocal instance already + // has a value on the current thread. + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0; + + protected: + ThreadLocalBase() {} + virtual ~ThreadLocalBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase); +}; + +// Maps a thread to a set of ThreadLocals that have values instantiated on that +// thread and notifies them when the thread exits. A ThreadLocal instance is +// expected to persist until all threads it has values on have terminated. +class GTEST_API_ ThreadLocalRegistry { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance); + + // Invoked when a ThreadLocal instance is destroyed. + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance); +}; + +class GTEST_API_ ThreadWithParamBase { + public: + void Join(); + + protected: + class Runnable { + public: + virtual ~Runnable() {} + virtual void Run() = 0; + }; + + ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start); + virtual ~ThreadWithParamBase(); + + private: + AutoHandle thread_; +}; + +// Helper class for testing Google Test's multi-threading constructs. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void UserThreadFunc(T); + + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) + : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) { + } + virtual ~ThreadWithParam() {} + + private: + class RunnableImpl : public Runnable { + public: + RunnableImpl(UserThreadFunc* func, T param) + : func_(func), + param_(param) { + } + virtual ~RunnableImpl() {} + virtual void Run() { + func_(param_); + } + + private: + UserThreadFunc* const func_; + const T param_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl); + }; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// Implements thread-local storage on Windows systems. +// +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. +// +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// The users of a TheadLocal instance have to make sure that all but one +// threads (including the main one) using that instance have exited before +// destroying it. Otherwise, the per-thread objects managed for them by the +// ThreadLocal instance are not guaranteed to be destroyed on all platforms. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal : public ThreadLocalBase { + public: + ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {} + explicit ThreadLocal(const T& value) + : default_factory_(new InstanceValueHolderFactory(value)) {} + + ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of T. Can be deleted via its base class without the caller + // knowing the type of T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + ValueHolder() : value_() {} + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + + T* GetOrCreateValue() const { + return static_cast( + ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer(); + } + + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const { + return default_factory_->MakeNewHolder(); + } + + class ValueHolderFactory { + public: + ValueHolderFactory() {} + virtual ~ValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); + }; + + class DefaultValueHolderFactory : public ValueHolderFactory { + public: + DefaultValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); + }; + + class InstanceValueHolderFactory : public ValueHolderFactory { + public: + explicit InstanceValueHolderFactory(const T& value) : value_(value) {} + virtual ValueHolder* MakeNewHolder() const { + return new ValueHolder(value_); + } + + private: + const T value_; // The value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); + }; + + std::unique_ptr default_factory_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# elif GTEST_HAS_PTHREAD + +// MutexBase and Mutex implement mutex on pthreads-based platforms. +class MutexBase { + public: + // Acquires this mutex. + void Lock() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); + owner_ = pthread_self(); + has_owner_ = true; + } + + // Releases this mutex. + void Unlock() { + // Since the lock is being released the owner_ field should no longer be + // considered valid. We don't protect writing to has_owner_ here, as it's + // the caller's responsibility to ensure that the current thread holds the + // mutex when this is called. + has_owner_ = false; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); + } + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld() const { + GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) + << "The current thread is not holding the mutex @" << this; + } + + // A static mutex may be used before main() is entered. It may even + // be used before the dynamic initialization stage. Therefore we + // must be able to initialize a static mutex object at link time. + // This means MutexBase has to be a POD and its member variables + // have to be public. + public: + pthread_mutex_t mutex_; // The underlying pthread mutex. + // has_owner_ indicates whether the owner_ field below contains a valid thread + // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All + // accesses to the owner_ field should be protected by a check of this field. + // An alternative might be to memset() owner_ to all zeros, but there's no + // guarantee that a zero'd pthread_t is necessarily invalid or even different + // from pthread_self(). + bool has_owner_; + pthread_t owner_; // The thread holding the mutex. +}; + +// Forward-declares a static mutex. +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex + +// Defines and statically (i.e. at link time) initializes a static mutex. +// The initialization list here does not explicitly initialize each field, +// instead relying on default initialization for the unspecified fields. In +// particular, the owner_ field (a pthread_t) is not explicitly initialized. +// This allows initialization to work whether pthread_t is a scalar or struct. +// The flag -Wmissing-field-initializers must not be specified for this to work. +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = {PTHREAD_MUTEX_INITIALIZER, false, 0} + +// The Mutex class can only be used for mutexes created at runtime. It +// shares its API with MutexBase otherwise. +class Mutex : public MutexBase { + public: + Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); + has_owner_ = false; + } + ~Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(MutexBase* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + MutexBase* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Helpers for ThreadLocal. + +// pthread_key_create() requires DeleteThreadLocalValue() to have +// C-linkage. Therefore it cannot be templatized to access +// ThreadLocal. Hence the need for class +// ThreadLocalValueHolderBase. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Called by pthread to delete thread-local data stored by +// pthread_setspecific(). +extern "C" inline void DeleteThreadLocalValue(void* value_holder) { + delete static_cast(value_holder); +} + +// Implements thread-local storage on pthreads-based systems. +template +class GTEST_API_ ThreadLocal { + public: + ThreadLocal() + : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {} + explicit ThreadLocal(const T& value) + : key_(CreateKey()), + default_factory_(new InstanceValueHolderFactory(value)) {} + + ~ThreadLocal() { + // Destroys the managed object for the current thread, if any. + DeleteThreadLocalValue(pthread_getspecific(key_)); + + // Releases resources associated with the key. This will *not* + // delete managed objects for other threads. + GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); + } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of type T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + ValueHolder() : value_() {} + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + static pthread_key_t CreateKey() { + pthread_key_t key; + // When a thread exits, DeleteThreadLocalValue() will be called on + // the object managed for that thread. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_key_create(&key, &DeleteThreadLocalValue)); + return key; + } + + T* GetOrCreateValue() const { + ThreadLocalValueHolderBase* const holder = + static_cast(pthread_getspecific(key_)); + if (holder != nullptr) { + return CheckedDowncastToActualType(holder)->pointer(); + } + + ValueHolder* const new_holder = default_factory_->MakeNewHolder(); + ThreadLocalValueHolderBase* const holder_base = new_holder; + GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); + return new_holder->pointer(); + } + + class ValueHolderFactory { + public: + ValueHolderFactory() {} + virtual ~ValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); + }; + + class DefaultValueHolderFactory : public ValueHolderFactory { + public: + DefaultValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); + }; + + class InstanceValueHolderFactory : public ValueHolderFactory { + public: + explicit InstanceValueHolderFactory(const T& value) : value_(value) {} + virtual ValueHolder* MakeNewHolder() const { + return new ValueHolder(value_); + } + + private: + const T value_; // The value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); + }; + + // A key pthreads uses for looking up per-thread values. + const pthread_key_t key_; + std::unique_ptr default_factory_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ + +#else // GTEST_IS_THREADSAFE + +// A dummy implementation of synchronization primitives (mutex, lock, +// and thread-local variable). Necessary for compiling Google Test where +// mutex is not supported - using Google Test in multiple threads is not +// supported on such platforms. + +class Mutex { + public: + Mutex() {} + void Lock() {} + void Unlock() {} + void AssertHeld() const {} +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex + +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex*) {} // NOLINT +}; + +typedef GTestMutexLock MutexLock; + +template +class GTEST_API_ ThreadLocal { + public: + ThreadLocal() : value_() {} + explicit ThreadLocal(const T& value) : value_(value) {} + T* pointer() { return &value_; } + const T* pointer() const { return &value_; } + const T& get() const { return value_; } + void set(const T& value) { value_ = value; } + private: + T value_; +}; + +#endif // GTEST_IS_THREADSAFE + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +GTEST_API_ size_t GetThreadCount(); + +template +using bool_constant = std::integral_constant; + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_SEP_ "\\" +# define GTEST_HAS_ALT_PATH_SEP_ 1 +// The biggest signed integer type the compiler supports. +typedef __int64 BiggestInt; +#else +# define GTEST_PATH_SEP_ "/" +# define GTEST_HAS_ALT_PATH_SEP_ 0 +typedef long long BiggestInt; // NOLINT +#endif // GTEST_OS_WINDOWS + +// Utilities for char. + +// isspace(int ch) and friends accept an unsigned char or EOF. char +// may be signed, depending on the compiler (or compiler flags). +// Therefore we need to cast a char to unsigned char before calling +// isspace(), etc. + +inline bool IsAlpha(char ch) { + return isalpha(static_cast(ch)) != 0; +} +inline bool IsAlNum(char ch) { + return isalnum(static_cast(ch)) != 0; +} +inline bool IsDigit(char ch) { + return isdigit(static_cast(ch)) != 0; +} +inline bool IsLower(char ch) { + return islower(static_cast(ch)) != 0; +} +inline bool IsSpace(char ch) { + return isspace(static_cast(ch)) != 0; +} +inline bool IsUpper(char ch) { + return isupper(static_cast(ch)) != 0; +} +inline bool IsXDigit(char ch) { + return isxdigit(static_cast(ch)) != 0; +} +inline bool IsXDigit(wchar_t ch) { + const unsigned char low_byte = static_cast(ch); + return ch == low_byte && isxdigit(low_byte) != 0; +} + +inline char ToLower(char ch) { + return static_cast(tolower(static_cast(ch))); +} +inline char ToUpper(char ch) { + return static_cast(toupper(static_cast(ch))); +} + +inline std::string StripTrailingSpaces(std::string str) { + std::string::iterator it = str.end(); + while (it != str.begin() && IsSpace(*--it)) + it = str.erase(it); + return str; +} + +// The testing::internal::posix namespace holds wrappers for common +// POSIX functions. These wrappers hide the differences between +// Windows/MSVC and POSIX systems. Since some compilers define these +// standard functions as macros, the wrapper cannot have the same name +// as the wrapped function. + +namespace posix { + +// Functions with a different name on Windows. + +#if GTEST_OS_WINDOWS + +typedef struct _stat StatStruct; + +# ifdef __BORLANDC__ +inline int IsATTY(int fd) { return isatty(fd); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +# else // !__BORLANDC__ +# if GTEST_OS_WINDOWS_MOBILE +inline int IsATTY(int /* fd */) { return 0; } +# else +inline int IsATTY(int fd) { return _isatty(fd); } +# endif // GTEST_OS_WINDOWS_MOBILE +inline int StrCaseCmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return _strdup(src); } +# endif // __BORLANDC__ + +# if GTEST_OS_WINDOWS_MOBILE +inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } +// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this +// time and thus not defined there. +# else +inline int FileNo(FILE* file) { return _fileno(file); } +inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } +inline int RmDir(const char* dir) { return _rmdir(dir); } +inline bool IsDir(const StatStruct& st) { + return (_S_IFDIR & st.st_mode) != 0; +} +# endif // GTEST_OS_WINDOWS_MOBILE + +#else + +typedef struct stat StatStruct; + +inline int FileNo(FILE* file) { return fileno(file); } +inline int IsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } + +#endif // GTEST_OS_WINDOWS + +// Functions deprecated by MSVC 8.0. + +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() + +inline const char* StrNCpy(char* dest, const char* src, size_t n) { + return strncpy(dest, src, n); +} + +// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and +// StrError() aren't needed on Windows CE at this time and thus not +// defined there. + +#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT +inline int ChDir(const char* dir) { return chdir(dir); } +#endif +inline FILE* FOpen(const char* path, const char* mode) { + return fopen(path, mode); +} +#if !GTEST_OS_WINDOWS_MOBILE +inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { + return freopen(path, mode, stream); +} +inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } +#endif +inline int FClose(FILE* fp) { return fclose(fp); } +#if !GTEST_OS_WINDOWS_MOBILE +inline int Read(int fd, void* buf, unsigned int count) { + return static_cast(read(fd, buf, count)); +} +inline int Write(int fd, const void* buf, unsigned int count) { + return static_cast(write(fd, buf, count)); +} +inline int Close(int fd) { return close(fd); } +inline const char* StrError(int errnum) { return strerror(errnum); } +#endif +inline const char* GetEnv(const char* name) { +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT + // We are on Windows CE, which has no environment variables. + static_cast(name); // To prevent 'unused argument' warning. + return nullptr; +#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) + // Environment variables which we programmatically clear will be set to the + // empty string rather than unset (NULL). Handle that case. + const char* const env = getenv(name); + return (env != nullptr && env[0] != '\0') ? env : nullptr; +#else + return getenv(name); +#endif +} + +GTEST_DISABLE_MSC_DEPRECATED_POP_() + +#if GTEST_OS_WINDOWS_MOBILE +// Windows CE has no C library. The abort() function is used in +// several places in Google Test. This implementation provides a reasonable +// imitation of standard behaviour. +[[noreturn]] void Abort(); +#else +[[noreturn]] inline void Abort() { abort(); } +#endif // GTEST_OS_WINDOWS_MOBILE + +} // namespace posix + +// MSVC "deprecates" snprintf and issues warnings wherever it is used. In +// order to avoid these warnings, we need to use _snprintf or _snprintf_s on +// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate +// function in order to achieve that. We use macro definition here because +// snprintf is a variadic function. +#if _MSC_VER && !GTEST_OS_WINDOWS_MOBILE +// MSVC 2005 and above support variadic macros. +# define GTEST_SNPRINTF_(buffer, size, format, ...) \ + _snprintf_s(buffer, size, size, format, __VA_ARGS__) +#elif defined(_MSC_VER) +// Windows CE does not define _snprintf_s +# define GTEST_SNPRINTF_ _snprintf +#else +# define GTEST_SNPRINTF_ snprintf +#endif + +// The maximum number a BiggestInt can represent. This definition +// works no matter BiggestInt is represented in one's complement or +// two's complement. +// +// We cannot rely on numeric_limits in STL, as __int64 and long long +// are not part of standard C++ and numeric_limits doesn't need to be +// defined for them. +const BiggestInt kMaxBiggestInt = + ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); + +// This template class serves as a compile-time function from size to +// type. It maps a size in bytes to a primitive type with that +// size. e.g. +// +// TypeWithSize<4>::UInt +// +// is typedef-ed to be unsigned int (unsigned integer made up of 4 +// bytes). +// +// Such functionality should belong to STL, but I cannot find it +// there. +// +// Google Test uses this class in the implementation of floating-point +// comparison. +// +// For now it only handles UInt (unsigned int) as that's all Google Test +// needs. Other types can be easily added in the future if need +// arises. +template +class TypeWithSize { + public: + // This prevents the user from using TypeWithSize with incorrect + // values of N. + typedef void UInt; +}; + +// The specialization for size 4. +template <> +class TypeWithSize<4> { + public: + // unsigned int has size 4 in both gcc and MSVC. + // + // As base/basictypes.h doesn't compile on Windows, we cannot use + // uint32, uint64, and etc here. + typedef int Int; + typedef unsigned int UInt; +}; + +// The specialization for size 8. +template <> +class TypeWithSize<8> { + public: +#if GTEST_OS_WINDOWS + typedef __int64 Int; + typedef unsigned __int64 UInt; +#else + typedef long long Int; // NOLINT + typedef unsigned long long UInt; // NOLINT +#endif // GTEST_OS_WINDOWS +}; + +// Integer types of known sizes. +typedef TypeWithSize<4>::Int Int32; +typedef TypeWithSize<4>::UInt UInt32; +typedef TypeWithSize<8>::Int Int64; +typedef TypeWithSize<8>::UInt UInt64; +typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. + +// Utilities for command line flags and environment variables. + +// Macro for referencing flags. +#if !defined(GTEST_FLAG) +# define GTEST_FLAG(name) FLAGS_gtest_##name +#endif // !defined(GTEST_FLAG) + +#if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) +# define GTEST_USE_OWN_FLAGFILE_FLAG_ 1 +#endif // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) + +#if !defined(GTEST_DECLARE_bool_) +# define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver + +// Macros for declaring flags. +# define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +# define GTEST_DECLARE_int32_(name) \ + GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) +# define GTEST_DECLARE_string_(name) \ + GTEST_API_ extern ::std::string GTEST_FLAG(name) + +// Macros for defining flags. +# define GTEST_DEFINE_bool_(name, default_val, doc) \ + GTEST_API_ bool GTEST_FLAG(name) = (default_val) +# define GTEST_DEFINE_int32_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) +# define GTEST_DEFINE_string_(name, default_val, doc) \ + GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) + +#endif // !defined(GTEST_DECLARE_bool_) + +// Thread annotations +#if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) +# define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) +# define GTEST_LOCK_EXCLUDED_(locks) +#endif // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) + +// Parses 'str' for a 32-bit signed integer. If successful, writes the result +// to *value and returns true; otherwise leaves *value unchanged and returns +// false. +bool ParseInt32(const Message& src_text, const char* str, Int32* value); + +// Parses a bool/Int32/string from the environment variable +// corresponding to the given Google Test flag. +bool BoolFromGTestEnv(const char* flag, bool default_val); +GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +std::string OutputFlagAlsoCheckEnvVar(); +const char* StringFromGTestEnv(const char* flag, const char* default_val); + +} // namespace internal +} // namespace testing + +#if !defined(GTEST_INTERNAL_DEPRECATED) + +// Internal Macro to mark an API deprecated, for googletest usage only +// Usage: class GTEST_INTERNAL_DEPRECATED(message) MyClass or +// GTEST_INTERNAL_DEPRECATED(message) myFunction(); Every usage of +// a deprecated entity will trigger a warning when compiled with +// `-Wdeprecated-declarations` option (clang, gcc, any __GNUC__ compiler). +// For msvc /W3 option will need to be used +// Note that for 'other' compilers this macro evaluates to nothing to prevent +// compilations errors. +#if defined(_MSC_VER) +#define GTEST_INTERNAL_DEPRECATED(message) __declspec(deprecated(message)) +#elif defined(__GNUC__) +#define GTEST_INTERNAL_DEPRECATED(message) __attribute__((deprecated(message))) +#else +#define GTEST_INTERNAL_DEPRECATED(message) +#endif + +#endif // !defined(GTEST_INTERNAL_DEPRECATED) + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-string.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-string.h new file mode 100644 index 0000000000000000000000000000000000000000..82aaa63bf4657569772b45746c390bcf1206ab56 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-string.h @@ -0,0 +1,171 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file declares the String class and functions used internally by +// Google Test. They are subject to change without notice. They should not used +// by code external to Google Test. +// +// This header file is #included by gtest-internal.h. +// It should not be #included by other files. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ + +#ifdef __BORLANDC__ +// string.h is not guaranteed to provide strcpy on C++ Builder. +# include +#endif + +#include +#include + +#include "gtest/internal/gtest-port.h" + +namespace testing { +namespace internal { + +// String - an abstract class holding static string utilities. +class GTEST_API_ String { + public: + // Static utility methods + + // Clones a 0-terminated C string, allocating memory using new. The + // caller is responsible for deleting the return value using + // delete[]. Returns the cloned string, or NULL if the input is + // NULL. + // + // This is different from strdup() in string.h, which allocates + // memory using malloc(). + static const char* CloneCString(const char* c_str); + +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be + // able to pass strings to Win32 APIs on CE we need to convert them + // to 'Unicode', UTF-16. + + // Creates a UTF-16 wide string from the given ANSI string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the wide string, or NULL if the + // input is NULL. + // + // The wide string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static LPCWSTR AnsiToUtf16(const char* c_str); + + // Creates an ANSI string from the given wide string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the ANSI string, or NULL if the + // input is NULL. + // + // The returned string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static const char* Utf16ToAnsi(LPCWSTR utf16_str); +#endif + + // Compares two C strings. Returns true if and only if they have the same + // content. + // + // Unlike strcmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CStringEquals(const char* lhs, const char* rhs); + + // Converts a wide C string to a String using the UTF-8 encoding. + // NULL will be converted to "(null)". If an error occurred during + // the conversion, "(failed to convert from wide string)" is + // returned. + static std::string ShowWideCString(const wchar_t* wide_c_str); + + // Compares two wide C strings. Returns true if and only if they have the + // same content. + // + // Unlike wcscmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); + + // Compares two C strings, ignoring case. Returns true if and only if + // they have the same content. + // + // Unlike strcasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CaseInsensitiveCStringEquals(const char* lhs, + const char* rhs); + + // Compares two wide C strings, ignoring case. Returns true if and only if + // they have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. + static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs); + + // Returns true if and only if the given string ends with the given suffix, + // ignoring case. Any string is considered to end with an empty suffix. + static bool EndsWithCaseInsensitive( + const std::string& str, const std::string& suffix); + + // Formats an int value as "%02d". + static std::string FormatIntWidth2(int value); // "%02d" for width == 2 + + // Formats an int value as "%X". + static std::string FormatHexInt(int value); + + // Formats an int value as "%X". + static std::string FormatHexUInt32(UInt32 value); + + // Formats a byte as "%02X". + static std::string FormatByte(unsigned char value); + + private: + String(); // Not meant to be instantiated. +}; // class String + +// Gets the content of the stringstream's buffer as an std::string. Each '\0' +// character in the buffer is replaced with "\\0". +GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-type-util.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-type-util.h new file mode 100644 index 0000000000000000000000000000000000000000..3d7542d1fb3502bc22d6b844fb438be83d442aa3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-type-util.h @@ -0,0 +1,3335 @@ +// This file was GENERATED by command: +// pump.py gtest-type-util.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Type utilities needed for implementing typed and type-parameterized +// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently we support at most 50 types in a list, and at most 50 +// type-parameterized tests in one type-parameterized test suite. +// Please contact googletestframework@googlegroups.com if you need +// more. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +#include "gtest/internal/gtest-port.h" + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +# if GTEST_HAS_CXXABI_H_ +# include +# elif defined(__HP_aCC) +# include +# endif // GTEST_HASH_CXXABI_H_ + +namespace testing { +namespace internal { + +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + +// GetTypeName() returns a human-readable name of type T. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +std::string GetTypeName() { +# if GTEST_HAS_RTTI + + const char* const name = typeid(T).name(); +# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. +# if GTEST_HAS_CXXABI_H_ + using abi::__cxa_demangle; +# endif // GTEST_HAS_CXXABI_H_ + char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); + const std::string name_str(status == 0 ? readable_name : name); + free(readable_name); + return CanonicalizeForStdLibVersioning(name_str); +# else + return name; +# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC + +# else + + return ""; + +# endif // GTEST_HAS_RTTI +} + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// A unique type used as the default value for the arguments of class +// template Types. This allows us to simulate variadic templates +// (e.g. Types, Type, and etc), which C++ doesn't +// support directly. +struct None {}; + +// The following family of struct and struct templates are used to +// represent type lists. In particular, TypesN +// represents a type list with N types (T1, T2, ..., and TN) in it. +// Except for Types0, every struct in the family has two member types: +// Head for the first type in the list, and Tail for the rest of the +// list. + +// The empty type list. +struct Types0 {}; + +// Type lists of length 1, 2, 3, and so on. + +template +struct Types1 { + typedef T1 Head; + typedef Types0 Tail; +}; +template +struct Types2 { + typedef T1 Head; + typedef Types1 Tail; +}; + +template +struct Types3 { + typedef T1 Head; + typedef Types2 Tail; +}; + +template +struct Types4 { + typedef T1 Head; + typedef Types3 Tail; +}; + +template +struct Types5 { + typedef T1 Head; + typedef Types4 Tail; +}; + +template +struct Types6 { + typedef T1 Head; + typedef Types5 Tail; +}; + +template +struct Types7 { + typedef T1 Head; + typedef Types6 Tail; +}; + +template +struct Types8 { + typedef T1 Head; + typedef Types7 Tail; +}; + +template +struct Types9 { + typedef T1 Head; + typedef Types8 Tail; +}; + +template +struct Types10 { + typedef T1 Head; + typedef Types9 Tail; +}; + +template +struct Types11 { + typedef T1 Head; + typedef Types10 Tail; +}; + +template +struct Types12 { + typedef T1 Head; + typedef Types11 Tail; +}; + +template +struct Types13 { + typedef T1 Head; + typedef Types12 Tail; +}; + +template +struct Types14 { + typedef T1 Head; + typedef Types13 Tail; +}; + +template +struct Types15 { + typedef T1 Head; + typedef Types14 Tail; +}; + +template +struct Types16 { + typedef T1 Head; + typedef Types15 Tail; +}; + +template +struct Types17 { + typedef T1 Head; + typedef Types16 Tail; +}; + +template +struct Types18 { + typedef T1 Head; + typedef Types17 Tail; +}; + +template +struct Types19 { + typedef T1 Head; + typedef Types18 Tail; +}; + +template +struct Types20 { + typedef T1 Head; + typedef Types19 Tail; +}; + +template +struct Types21 { + typedef T1 Head; + typedef Types20 Tail; +}; + +template +struct Types22 { + typedef T1 Head; + typedef Types21 Tail; +}; + +template +struct Types23 { + typedef T1 Head; + typedef Types22 Tail; +}; + +template +struct Types24 { + typedef T1 Head; + typedef Types23 Tail; +}; + +template +struct Types25 { + typedef T1 Head; + typedef Types24 Tail; +}; + +template +struct Types26 { + typedef T1 Head; + typedef Types25 Tail; +}; + +template +struct Types27 { + typedef T1 Head; + typedef Types26 Tail; +}; + +template +struct Types28 { + typedef T1 Head; + typedef Types27 Tail; +}; + +template +struct Types29 { + typedef T1 Head; + typedef Types28 Tail; +}; + +template +struct Types30 { + typedef T1 Head; + typedef Types29 Tail; +}; + +template +struct Types31 { + typedef T1 Head; + typedef Types30 Tail; +}; + +template +struct Types32 { + typedef T1 Head; + typedef Types31 Tail; +}; + +template +struct Types33 { + typedef T1 Head; + typedef Types32 Tail; +}; + +template +struct Types34 { + typedef T1 Head; + typedef Types33 Tail; +}; + +template +struct Types35 { + typedef T1 Head; + typedef Types34 Tail; +}; + +template +struct Types36 { + typedef T1 Head; + typedef Types35 Tail; +}; + +template +struct Types37 { + typedef T1 Head; + typedef Types36 Tail; +}; + +template +struct Types38 { + typedef T1 Head; + typedef Types37 Tail; +}; + +template +struct Types39 { + typedef T1 Head; + typedef Types38 Tail; +}; + +template +struct Types40 { + typedef T1 Head; + typedef Types39 Tail; +}; + +template +struct Types41 { + typedef T1 Head; + typedef Types40 Tail; +}; + +template +struct Types42 { + typedef T1 Head; + typedef Types41 Tail; +}; + +template +struct Types43 { + typedef T1 Head; + typedef Types42 Tail; +}; + +template +struct Types44 { + typedef T1 Head; + typedef Types43 Tail; +}; + +template +struct Types45 { + typedef T1 Head; + typedef Types44 Tail; +}; + +template +struct Types46 { + typedef T1 Head; + typedef Types45 Tail; +}; + +template +struct Types47 { + typedef T1 Head; + typedef Types46 Tail; +}; + +template +struct Types48 { + typedef T1 Head; + typedef Types47 Tail; +}; + +template +struct Types49 { + typedef T1 Head; + typedef Types48 Tail; +}; + +template +struct Types50 { + typedef T1 Head; + typedef Types49 Tail; +}; + + +} // namespace internal + +// We don't want to require the users to write TypesN<...> directly, +// as that would require them to count the length. Types<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Types +// will appear as Types in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Types, and Google Test will translate +// that to TypesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Types template. +template +struct Types { + typedef internal::Types50 type; +}; + +template <> +struct Types { + typedef internal::Types0 type; +}; +template +struct Types { + typedef internal::Types1 type; +}; +template +struct Types { + typedef internal::Types2 type; +}; +template +struct Types { + typedef internal::Types3 type; +}; +template +struct Types { + typedef internal::Types4 type; +}; +template +struct Types { + typedef internal::Types5 type; +}; +template +struct Types { + typedef internal::Types6 type; +}; +template +struct Types { + typedef internal::Types7 type; +}; +template +struct Types { + typedef internal::Types8 type; +}; +template +struct Types { + typedef internal::Types9 type; +}; +template +struct Types { + typedef internal::Types10 type; +}; +template +struct Types { + typedef internal::Types11 type; +}; +template +struct Types { + typedef internal::Types12 type; +}; +template +struct Types { + typedef internal::Types13 type; +}; +template +struct Types { + typedef internal::Types14 type; +}; +template +struct Types { + typedef internal::Types15 type; +}; +template +struct Types { + typedef internal::Types16 type; +}; +template +struct Types { + typedef internal::Types17 type; +}; +template +struct Types { + typedef internal::Types18 type; +}; +template +struct Types { + typedef internal::Types19 type; +}; +template +struct Types { + typedef internal::Types20 type; +}; +template +struct Types { + typedef internal::Types21 type; +}; +template +struct Types { + typedef internal::Types22 type; +}; +template +struct Types { + typedef internal::Types23 type; +}; +template +struct Types { + typedef internal::Types24 type; +}; +template +struct Types { + typedef internal::Types25 type; +}; +template +struct Types { + typedef internal::Types26 type; +}; +template +struct Types { + typedef internal::Types27 type; +}; +template +struct Types { + typedef internal::Types28 type; +}; +template +struct Types { + typedef internal::Types29 type; +}; +template +struct Types { + typedef internal::Types30 type; +}; +template +struct Types { + typedef internal::Types31 type; +}; +template +struct Types { + typedef internal::Types32 type; +}; +template +struct Types { + typedef internal::Types33 type; +}; +template +struct Types { + typedef internal::Types34 type; +}; +template +struct Types { + typedef internal::Types35 type; +}; +template +struct Types { + typedef internal::Types36 type; +}; +template +struct Types { + typedef internal::Types37 type; +}; +template +struct Types { + typedef internal::Types38 type; +}; +template +struct Types { + typedef internal::Types39 type; +}; +template +struct Types { + typedef internal::Types40 type; +}; +template +struct Types { + typedef internal::Types41 type; +}; +template +struct Types { + typedef internal::Types42 type; +}; +template +struct Types { + typedef internal::Types43 type; +}; +template +struct Types { + typedef internal::Types44 type; +}; +template +struct Types { + typedef internal::Types45 type; +}; +template +struct Types { + typedef internal::Types46 type; +}; +template +struct Types { + typedef internal::Types47 type; +}; +template +struct Types { + typedef internal::Types48 type; +}; +template +struct Types { + typedef internal::Types49 type; +}; + +namespace internal { + +# define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +# define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +// A unique struct template used as the default value for the +// arguments of class template Templates. This allows us to simulate +// variadic templates (e.g. Templates, Templates, +// and etc), which C++ doesn't support directly. +template +struct NoneT {}; + +// The following family of struct and struct templates are used to +// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except +// for Templates0, every struct in the family has two member types: +// Head for the selector of the first template in the list, and Tail +// for the rest of the list. + +// The empty template list. +struct Templates0 {}; + +// Template lists of length 1, 2, 3, and so on. + +template +struct Templates1 { + typedef TemplateSel Head; + typedef Templates0 Tail; +}; +template +struct Templates2 { + typedef TemplateSel Head; + typedef Templates1 Tail; +}; + +template +struct Templates3 { + typedef TemplateSel Head; + typedef Templates2 Tail; +}; + +template +struct Templates4 { + typedef TemplateSel Head; + typedef Templates3 Tail; +}; + +template +struct Templates5 { + typedef TemplateSel Head; + typedef Templates4 Tail; +}; + +template +struct Templates6 { + typedef TemplateSel Head; + typedef Templates5 Tail; +}; + +template +struct Templates7 { + typedef TemplateSel Head; + typedef Templates6 Tail; +}; + +template +struct Templates8 { + typedef TemplateSel Head; + typedef Templates7 Tail; +}; + +template +struct Templates9 { + typedef TemplateSel Head; + typedef Templates8 Tail; +}; + +template +struct Templates10 { + typedef TemplateSel Head; + typedef Templates9 Tail; +}; + +template +struct Templates11 { + typedef TemplateSel Head; + typedef Templates10 Tail; +}; + +template +struct Templates12 { + typedef TemplateSel Head; + typedef Templates11 Tail; +}; + +template +struct Templates13 { + typedef TemplateSel Head; + typedef Templates12 Tail; +}; + +template +struct Templates14 { + typedef TemplateSel Head; + typedef Templates13 Tail; +}; + +template +struct Templates15 { + typedef TemplateSel Head; + typedef Templates14 Tail; +}; + +template +struct Templates16 { + typedef TemplateSel Head; + typedef Templates15 Tail; +}; + +template +struct Templates17 { + typedef TemplateSel Head; + typedef Templates16 Tail; +}; + +template +struct Templates18 { + typedef TemplateSel Head; + typedef Templates17 Tail; +}; + +template +struct Templates19 { + typedef TemplateSel Head; + typedef Templates18 Tail; +}; + +template +struct Templates20 { + typedef TemplateSel Head; + typedef Templates19 Tail; +}; + +template +struct Templates21 { + typedef TemplateSel Head; + typedef Templates20 Tail; +}; + +template +struct Templates22 { + typedef TemplateSel Head; + typedef Templates21 Tail; +}; + +template +struct Templates23 { + typedef TemplateSel Head; + typedef Templates22 Tail; +}; + +template +struct Templates24 { + typedef TemplateSel Head; + typedef Templates23 Tail; +}; + +template +struct Templates25 { + typedef TemplateSel Head; + typedef Templates24 Tail; +}; + +template +struct Templates26 { + typedef TemplateSel Head; + typedef Templates25 Tail; +}; + +template +struct Templates27 { + typedef TemplateSel Head; + typedef Templates26 Tail; +}; + +template +struct Templates28 { + typedef TemplateSel Head; + typedef Templates27 Tail; +}; + +template +struct Templates29 { + typedef TemplateSel Head; + typedef Templates28 Tail; +}; + +template +struct Templates30 { + typedef TemplateSel Head; + typedef Templates29 Tail; +}; + +template +struct Templates31 { + typedef TemplateSel Head; + typedef Templates30 Tail; +}; + +template +struct Templates32 { + typedef TemplateSel Head; + typedef Templates31 Tail; +}; + +template +struct Templates33 { + typedef TemplateSel Head; + typedef Templates32 Tail; +}; + +template +struct Templates34 { + typedef TemplateSel Head; + typedef Templates33 Tail; +}; + +template +struct Templates35 { + typedef TemplateSel Head; + typedef Templates34 Tail; +}; + +template +struct Templates36 { + typedef TemplateSel Head; + typedef Templates35 Tail; +}; + +template +struct Templates37 { + typedef TemplateSel Head; + typedef Templates36 Tail; +}; + +template +struct Templates38 { + typedef TemplateSel Head; + typedef Templates37 Tail; +}; + +template +struct Templates39 { + typedef TemplateSel Head; + typedef Templates38 Tail; +}; + +template +struct Templates40 { + typedef TemplateSel Head; + typedef Templates39 Tail; +}; + +template +struct Templates41 { + typedef TemplateSel Head; + typedef Templates40 Tail; +}; + +template +struct Templates42 { + typedef TemplateSel Head; + typedef Templates41 Tail; +}; + +template +struct Templates43 { + typedef TemplateSel Head; + typedef Templates42 Tail; +}; + +template +struct Templates44 { + typedef TemplateSel Head; + typedef Templates43 Tail; +}; + +template +struct Templates45 { + typedef TemplateSel Head; + typedef Templates44 Tail; +}; + +template +struct Templates46 { + typedef TemplateSel Head; + typedef Templates45 Tail; +}; + +template +struct Templates47 { + typedef TemplateSel Head; + typedef Templates46 Tail; +}; + +template +struct Templates48 { + typedef TemplateSel Head; + typedef Templates47 Tail; +}; + +template +struct Templates49 { + typedef TemplateSel Head; + typedef Templates48 Tail; +}; + +template +struct Templates50 { + typedef TemplateSel Head; + typedef Templates49 Tail; +}; + + +// We don't want to require the users to write TemplatesN<...> directly, +// as that would require them to count the length. Templates<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Templates +// will appear as Templates in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Templates, and Google Test will translate +// that to TemplatesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Templates template. +template +struct Templates { + typedef Templates50 type; +}; + +template <> +struct Templates { + typedef Templates0 type; +}; +template +struct Templates { + typedef Templates1 type; +}; +template +struct Templates { + typedef Templates2 type; +}; +template +struct Templates { + typedef Templates3 type; +}; +template +struct Templates { + typedef Templates4 type; +}; +template +struct Templates { + typedef Templates5 type; +}; +template +struct Templates { + typedef Templates6 type; +}; +template +struct Templates { + typedef Templates7 type; +}; +template +struct Templates { + typedef Templates8 type; +}; +template +struct Templates { + typedef Templates9 type; +}; +template +struct Templates { + typedef Templates10 type; +}; +template +struct Templates { + typedef Templates11 type; +}; +template +struct Templates { + typedef Templates12 type; +}; +template +struct Templates { + typedef Templates13 type; +}; +template +struct Templates { + typedef Templates14 type; +}; +template +struct Templates { + typedef Templates15 type; +}; +template +struct Templates { + typedef Templates16 type; +}; +template +struct Templates { + typedef Templates17 type; +}; +template +struct Templates { + typedef Templates18 type; +}; +template +struct Templates { + typedef Templates19 type; +}; +template +struct Templates { + typedef Templates20 type; +}; +template +struct Templates { + typedef Templates21 type; +}; +template +struct Templates { + typedef Templates22 type; +}; +template +struct Templates { + typedef Templates23 type; +}; +template +struct Templates { + typedef Templates24 type; +}; +template +struct Templates { + typedef Templates25 type; +}; +template +struct Templates { + typedef Templates26 type; +}; +template +struct Templates { + typedef Templates27 type; +}; +template +struct Templates { + typedef Templates28 type; +}; +template +struct Templates { + typedef Templates29 type; +}; +template +struct Templates { + typedef Templates30 type; +}; +template +struct Templates { + typedef Templates31 type; +}; +template +struct Templates { + typedef Templates32 type; +}; +template +struct Templates { + typedef Templates33 type; +}; +template +struct Templates { + typedef Templates34 type; +}; +template +struct Templates { + typedef Templates35 type; +}; +template +struct Templates { + typedef Templates36 type; +}; +template +struct Templates { + typedef Templates37 type; +}; +template +struct Templates { + typedef Templates38 type; +}; +template +struct Templates { + typedef Templates39 type; +}; +template +struct Templates { + typedef Templates40 type; +}; +template +struct Templates { + typedef Templates41 type; +}; +template +struct Templates { + typedef Templates42 type; +}; +template +struct Templates { + typedef Templates43 type; +}; +template +struct Templates { + typedef Templates44 type; +}; +template +struct Templates { + typedef Templates45 type; +}; +template +struct Templates { + typedef Templates46 type; +}; +template +struct Templates { + typedef Templates47 type; +}; +template +struct Templates { + typedef Templates48 type; +}; +template +struct Templates { + typedef Templates49 type; +}; + +// The TypeList template makes it possible to use either a single type +// or a Types<...> list in TYPED_TEST_SUITE() and +// INSTANTIATE_TYPED_TEST_SUITE_P(). + +template +struct TypeList { + typedef Types1 type; +}; + +template +struct TypeList > { + typedef typename Types::type type; +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-type-util.h.pump b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-type-util.h.pump new file mode 100644 index 0000000000000000000000000000000000000000..5e31b7b3206b284a3da32769faea0de185e054a8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/include/gtest/internal/gtest-type-util.h.pump @@ -0,0 +1,302 @@ +$$ -*- mode: c++; -*- +$var n = 50 $$ Maximum length of type lists we want to support. +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Type utilities needed for implementing typed and type-parameterized +// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently we support at most $n types in a list, and at most $n +// type-parameterized tests in one type-parameterized test suite. +// Please contact googletestframework@googlegroups.com if you need +// more. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +#include "gtest/internal/gtest-port.h" + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +# if GTEST_HAS_CXXABI_H_ +# include +# elif defined(__HP_aCC) +# include +# endif // GTEST_HASH_CXXABI_H_ + +namespace testing { +namespace internal { + +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + +// GetTypeName() returns a human-readable name of type T. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +std::string GetTypeName() { +# if GTEST_HAS_RTTI + + const char* const name = typeid(T).name(); +# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. +# if GTEST_HAS_CXXABI_H_ + using abi::__cxa_demangle; +# endif // GTEST_HAS_CXXABI_H_ + char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); + const std::string name_str(status == 0 ? readable_name : name); + free(readable_name); + return CanonicalizeForStdLibVersioning(name_str); +# else + return name; +# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC + +# else + + return ""; + +# endif // GTEST_HAS_RTTI +} + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// A unique type used as the default value for the arguments of class +// template Types. This allows us to simulate variadic templates +// (e.g. Types, Type, and etc), which C++ doesn't +// support directly. +struct None {}; + +// The following family of struct and struct templates are used to +// represent type lists. In particular, TypesN +// represents a type list with N types (T1, T2, ..., and TN) in it. +// Except for Types0, every struct in the family has two member types: +// Head for the first type in the list, and Tail for the rest of the +// list. + +// The empty type list. +struct Types0 {}; + +// Type lists of length 1, 2, 3, and so on. + +template +struct Types1 { + typedef T1 Head; + typedef Types0 Tail; +}; + +$range i 2..n + +$for i [[ +$range j 1..i +$range k 2..i +template <$for j, [[typename T$j]]> +struct Types$i { + typedef T1 Head; + typedef Types$(i-1)<$for k, [[T$k]]> Tail; +}; + + +]] + +} // namespace internal + +// We don't want to require the users to write TypesN<...> directly, +// as that would require them to count the length. Types<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Types +// will appear as Types in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Types, and Google Test will translate +// that to TypesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Types template. + +$range i 1..n +template <$for i, [[typename T$i = internal::None]]> +struct Types { + typedef internal::Types$n<$for i, [[T$i]]> type; +}; + +template <> +struct Types<$for i, [[internal::None]]> { + typedef internal::Types0 type; +}; + +$range i 1..n-1 +$for i [[ +$range j 1..i +$range k i+1..n +template <$for j, [[typename T$j]]> +struct Types<$for j, [[T$j]]$for k[[, internal::None]]> { + typedef internal::Types$i<$for j, [[T$j]]> type; +}; + +]] + +namespace internal { + +# define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +# define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +// A unique struct template used as the default value for the +// arguments of class template Templates. This allows us to simulate +// variadic templates (e.g. Templates, Templates, +// and etc), which C++ doesn't support directly. +template +struct NoneT {}; + +// The following family of struct and struct templates are used to +// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except +// for Templates0, every struct in the family has two member types: +// Head for the selector of the first template in the list, and Tail +// for the rest of the list. + +// The empty template list. +struct Templates0 {}; + +// Template lists of length 1, 2, 3, and so on. + +template +struct Templates1 { + typedef TemplateSel Head; + typedef Templates0 Tail; +}; + +$range i 2..n + +$for i [[ +$range j 1..i +$range k 2..i +template <$for j, [[GTEST_TEMPLATE_ T$j]]> +struct Templates$i { + typedef TemplateSel Head; + typedef Templates$(i-1)<$for k, [[T$k]]> Tail; +}; + + +]] + +// We don't want to require the users to write TemplatesN<...> directly, +// as that would require them to count the length. Templates<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Templates +// will appear as Templates in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Templates, and Google Test will translate +// that to TemplatesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Templates template. + +$range i 1..n +template <$for i, [[GTEST_TEMPLATE_ T$i = NoneT]]> +struct Templates { + typedef Templates$n<$for i, [[T$i]]> type; +}; + +template <> +struct Templates<$for i, [[NoneT]]> { + typedef Templates0 type; +}; + +$range i 1..n-1 +$for i [[ +$range j 1..i +$range k i+1..n +template <$for j, [[GTEST_TEMPLATE_ T$j]]> +struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> { + typedef Templates$i<$for j, [[T$j]]> type; +}; + +]] + +// The TypeList template makes it possible to use either a single type +// or a Types<...> list in TYPED_TEST_SUITE() and +// INSTANTIATE_TYPED_TEST_SUITE_P(). + +template +struct TypeList { + typedef Types1 type; +}; + + +$range i 1..n +template <$for i, [[typename T$i]]> +struct TypeList > { + typedef typename Types<$for i, [[T$i]]>::type type; +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/prime_tables.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/prime_tables.h new file mode 100644 index 0000000000000000000000000000000000000000..72539bf14a2314cf0044fee4d2fb8de272368cb1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/prime_tables.h @@ -0,0 +1,126 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +// This provides interface PrimeTable that determines whether a number is a +// prime and determines a next prime number. This interface is used +// in Google Test samples demonstrating use of parameterized tests. + +#ifndef GTEST_SAMPLES_PRIME_TABLES_H_ +#define GTEST_SAMPLES_PRIME_TABLES_H_ + +#include + +// The prime table interface. +class PrimeTable { + public: + virtual ~PrimeTable() {} + + // Returns true if and only if n is a prime number. + virtual bool IsPrime(int n) const = 0; + + // Returns the smallest prime number greater than p; or returns -1 + // if the next prime is beyond the capacity of the table. + virtual int GetNextPrime(int p) const = 0; +}; + +// Implementation #1 calculates the primes on-the-fly. +class OnTheFlyPrimeTable : public PrimeTable { + public: + bool IsPrime(int n) const override { + if (n <= 1) return false; + + for (int i = 2; i*i <= n; i++) { + // n is divisible by an integer other than 1 and itself. + if ((n % i) == 0) return false; + } + + return true; + } + + int GetNextPrime(int p) const override { + for (int n = p + 1; n > 0; n++) { + if (IsPrime(n)) return n; + } + + return -1; + } +}; + +// Implementation #2 pre-calculates the primes and stores the result +// in an array. +class PreCalculatedPrimeTable : public PrimeTable { + public: + // 'max' specifies the maximum number the prime table holds. + explicit PreCalculatedPrimeTable(int max) + : is_prime_size_(max + 1), is_prime_(new bool[max + 1]) { + CalculatePrimesUpTo(max); + } + ~PreCalculatedPrimeTable() override { delete[] is_prime_; } + + bool IsPrime(int n) const override { + return 0 <= n && n < is_prime_size_ && is_prime_[n]; + } + + int GetNextPrime(int p) const override { + for (int n = p + 1; n < is_prime_size_; n++) { + if (is_prime_[n]) return n; + } + + return -1; + } + + private: + void CalculatePrimesUpTo(int max) { + ::std::fill(is_prime_, is_prime_ + is_prime_size_, true); + is_prime_[0] = is_prime_[1] = false; + + // Checks every candidate for prime number (we know that 2 is the only even + // prime). + for (int i = 2; i*i <= max; i += i%2+1) { + if (!is_prime_[i]) continue; + + // Marks all multiples of i (except i itself) as non-prime. + // We are starting here from i-th multiplier, because all smaller + // complex numbers were already marked. + for (int j = i*i; j <= max; j += i) { + is_prime_[j] = false; + } + } + } + + const int is_prime_size_; + bool* const is_prime_; + + // Disables compiler warning "assignment operator could not be generated." + void operator=(const PreCalculatedPrimeTable& rhs); +}; + +#endif // GTEST_SAMPLES_PRIME_TABLES_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample1.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample1.cc new file mode 100644 index 0000000000000000000000000000000000000000..1d4275979ff61101bf1ae9c3205f41f40830c336 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample1.cc @@ -0,0 +1,66 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. + +#include "sample1.h" + +// Returns n! (the factorial of n). For negative n, n! is defined to be 1. +int Factorial(int n) { + int result = 1; + for (int i = 1; i <= n; i++) { + result *= i; + } + + return result; +} + +// Returns true if and only if n is a prime number. +bool IsPrime(int n) { + // Trivial case 1: small numbers + if (n <= 1) return false; + + // Trivial case 2: even numbers + if (n % 2 == 0) return n == 2; + + // Now, we have that n is odd and n >= 3. + + // Try to divide n by every odd number i, starting from 3 + for (int i = 3; ; i += 2) { + // We only have to try i up to the square root of n + if (i > n/i) break; + + // Now, we have i <= n/i < n. + // If n is divisible by i, n is not prime. + if (n % i == 0) return false; + } + + // n has no integer factor in the range (1, n), and thus is prime. + return true; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample1.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample1.h new file mode 100644 index 0000000000000000000000000000000000000000..12e49deafa2c9328e722e795d02f02aa9777bed0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample1.h @@ -0,0 +1,41 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. + +#ifndef GTEST_SAMPLES_SAMPLE1_H_ +#define GTEST_SAMPLES_SAMPLE1_H_ + +// Returns n! (the factorial of n). For negative n, n! is defined to be 1. +int Factorial(int n); + +// Returns true if and only if n is a prime number. +bool IsPrime(int n); + +#endif // GTEST_SAMPLES_SAMPLE1_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample10_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample10_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..36cdac2279aeea702e0d3520c77258e9273726a5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample10_unittest.cc @@ -0,0 +1,139 @@ +// Copyright 2009 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// This sample shows how to use Google Test listener API to implement +// a primitive leak checker. + +#include +#include + +#include "gtest/gtest.h" +using ::testing::EmptyTestEventListener; +using ::testing::InitGoogleTest; +using ::testing::Test; +using ::testing::TestEventListeners; +using ::testing::TestInfo; +using ::testing::TestPartResult; +using ::testing::UnitTest; + +namespace { +// We will track memory used by this class. +class Water { + public: + // Normal Water declarations go here. + + // operator new and operator delete help us control water allocation. + void* operator new(size_t allocation_size) { + allocated_++; + return malloc(allocation_size); + } + + void operator delete(void* block, size_t /* allocation_size */) { + allocated_--; + free(block); + } + + static int allocated() { return allocated_; } + + private: + static int allocated_; +}; + +int Water::allocated_ = 0; + +// This event listener monitors how many Water objects are created and +// destroyed by each test, and reports a failure if a test leaks some Water +// objects. It does this by comparing the number of live Water objects at +// the beginning of a test and at the end of a test. +class LeakChecker : public EmptyTestEventListener { + private: + // Called before a test starts. + void OnTestStart(const TestInfo& /* test_info */) override { + initially_allocated_ = Water::allocated(); + } + + // Called after a test ends. + void OnTestEnd(const TestInfo& /* test_info */) override { + int difference = Water::allocated() - initially_allocated_; + + // You can generate a failure in any event handler except + // OnTestPartResult. Just use an appropriate Google Test assertion to do + // it. + EXPECT_LE(difference, 0) << "Leaked " << difference << " unit(s) of Water!"; + } + + int initially_allocated_; +}; + +TEST(ListenersTest, DoesNotLeak) { + Water* water = new Water; + delete water; +} + +// This should fail when the --check_for_leaks command line flag is +// specified. +TEST(ListenersTest, LeaksWater) { + Water* water = new Water; + EXPECT_TRUE(water != nullptr); +} +} // namespace + +int main(int argc, char **argv) { + InitGoogleTest(&argc, argv); + + bool check_for_leaks = false; + if (argc > 1 && strcmp(argv[1], "--check_for_leaks") == 0 ) + check_for_leaks = true; + else + printf("%s\n", "Run this program with --check_for_leaks to enable " + "custom leak checking in the tests."); + + // If we are given the --check_for_leaks command line flag, installs the + // leak checker. + if (check_for_leaks) { + TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); + + // Adds the leak checker to the end of the test event listener list, + // after the default text output printer and the default XML report + // generator. + // + // The order is important - it ensures that failures generated in the + // leak checker's OnTestEnd() method are processed by the text and XML + // printers *before* their OnTestEnd() methods are called, such that + // they are attributed to the right test. Remember that a listener + // receives an OnXyzStart event *after* listeners preceding it in the + // list received that event, and receives an OnXyzEnd event *before* + // listeners preceding it. + // + // We don't need to worry about deleting the new listener later, as + // Google Test will do it. + listeners.Append(new LeakChecker); + } + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample1_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample1_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..cb08b61a59a9e16b3657861f1c9609001d2096b2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample1_unittest.cc @@ -0,0 +1,151 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. + +// This sample shows how to write a simple unit test for a function, +// using Google C++ testing framework. +// +// Writing a unit test using Google C++ testing framework is easy as 1-2-3: + + +// Step 1. Include necessary header files such that the stuff your +// test logic needs is declared. +// +// Don't forget gtest.h, which declares the testing framework. + +#include +#include "sample1.h" +#include "gtest/gtest.h" +namespace { + +// Step 2. Use the TEST macro to define your tests. +// +// TEST has two parameters: the test case name and the test name. +// After using the macro, you should define your test logic between a +// pair of braces. You can use a bunch of macros to indicate the +// success or failure of a test. EXPECT_TRUE and EXPECT_EQ are +// examples of such macros. For a complete list, see gtest.h. +// +// +// +// In Google Test, tests are grouped into test cases. This is how we +// keep test code organized. You should put logically related tests +// into the same test case. +// +// The test case name and the test name should both be valid C++ +// identifiers. And you should not use underscore (_) in the names. +// +// Google Test guarantees that each test you define is run exactly +// once, but it makes no guarantee on the order the tests are +// executed. Therefore, you should write your tests in such a way +// that their results don't depend on their order. +// +// + + +// Tests Factorial(). + +// Tests factorial of negative numbers. +TEST(FactorialTest, Negative) { + // This test is named "Negative", and belongs to the "FactorialTest" + // test case. + EXPECT_EQ(1, Factorial(-5)); + EXPECT_EQ(1, Factorial(-1)); + EXPECT_GT(Factorial(-10), 0); + + // + // + // EXPECT_EQ(expected, actual) is the same as + // + // EXPECT_TRUE((expected) == (actual)) + // + // except that it will print both the expected value and the actual + // value when the assertion fails. This is very helpful for + // debugging. Therefore in this case EXPECT_EQ is preferred. + // + // On the other hand, EXPECT_TRUE accepts any Boolean expression, + // and is thus more general. + // + // +} + +// Tests factorial of 0. +TEST(FactorialTest, Zero) { + EXPECT_EQ(1, Factorial(0)); +} + +// Tests factorial of positive numbers. +TEST(FactorialTest, Positive) { + EXPECT_EQ(1, Factorial(1)); + EXPECT_EQ(2, Factorial(2)); + EXPECT_EQ(6, Factorial(3)); + EXPECT_EQ(40320, Factorial(8)); +} + + +// Tests IsPrime() + +// Tests negative input. +TEST(IsPrimeTest, Negative) { + // This test belongs to the IsPrimeTest test case. + + EXPECT_FALSE(IsPrime(-1)); + EXPECT_FALSE(IsPrime(-2)); + EXPECT_FALSE(IsPrime(INT_MIN)); +} + +// Tests some trivial cases. +TEST(IsPrimeTest, Trivial) { + EXPECT_FALSE(IsPrime(0)); + EXPECT_FALSE(IsPrime(1)); + EXPECT_TRUE(IsPrime(2)); + EXPECT_TRUE(IsPrime(3)); +} + +// Tests positive input. +TEST(IsPrimeTest, Positive) { + EXPECT_FALSE(IsPrime(4)); + EXPECT_TRUE(IsPrime(5)); + EXPECT_FALSE(IsPrime(6)); + EXPECT_TRUE(IsPrime(23)); +} +} // namespace + +// Step 3. Call RUN_ALL_TESTS() in main(). +// +// We do this by linking in src/gtest_main.cc file, which consists of +// a main() function which calls RUN_ALL_TESTS() for us. +// +// This runs all the tests you've defined, prints the result, and +// returns 0 if successful, or 1 otherwise. +// +// Did you notice that we didn't register the tests? The +// RUN_ALL_TESTS() macro magically knows about all the tests we +// defined. Isn't this convenient? diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample2.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample2.cc new file mode 100644 index 0000000000000000000000000000000000000000..d8e8723965a1dc01ea7f656619b71fb5069849da --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample2.cc @@ -0,0 +1,54 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. + +#include "sample2.h" + +#include + +// Clones a 0-terminated C string, allocating memory using new. +const char* MyString::CloneCString(const char* a_c_string) { + if (a_c_string == nullptr) return nullptr; + + const size_t len = strlen(a_c_string); + char* const clone = new char[ len + 1 ]; + memcpy(clone, a_c_string, len + 1); + + return clone; +} + +// Sets the 0-terminated C string this MyString object +// represents. +void MyString::Set(const char* a_c_string) { + // Makes sure this works when c_string == c_string_ + const char* const temp = MyString::CloneCString(a_c_string); + delete[] c_string_; + c_string_ = temp; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample2.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample2.h new file mode 100644 index 0000000000000000000000000000000000000000..e9a5a7050b7d61c3417a962b5f6bb7c077625be1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample2.h @@ -0,0 +1,81 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. + +#ifndef GTEST_SAMPLES_SAMPLE2_H_ +#define GTEST_SAMPLES_SAMPLE2_H_ + +#include + + +// A simple string class. +class MyString { + private: + const char* c_string_; + const MyString& operator=(const MyString& rhs); + + public: + // Clones a 0-terminated C string, allocating memory using new. + static const char* CloneCString(const char* a_c_string); + + //////////////////////////////////////////////////////////// + // + // C'tors + + // The default c'tor constructs a NULL string. + MyString() : c_string_(nullptr) {} + + // Constructs a MyString by cloning a 0-terminated C string. + explicit MyString(const char* a_c_string) : c_string_(nullptr) { + Set(a_c_string); + } + + // Copy c'tor + MyString(const MyString& string) : c_string_(nullptr) { + Set(string.c_string_); + } + + //////////////////////////////////////////////////////////// + // + // D'tor. MyString is intended to be a final class, so the d'tor + // doesn't need to be virtual. + ~MyString() { delete[] c_string_; } + + // Gets the 0-terminated C string this MyString object represents. + const char* c_string() const { return c_string_; } + + size_t Length() const { return c_string_ == nullptr ? 0 : strlen(c_string_); } + + // Sets the 0-terminated C string this MyString object represents. + void Set(const char* c_string); +}; + + +#endif // GTEST_SAMPLES_SAMPLE2_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample2_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample2_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..41e31c1767dee55cc5d5c0bea2df267c5d81176d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample2_unittest.cc @@ -0,0 +1,107 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. + +// This sample shows how to write a more complex unit test for a class +// that has multiple member functions. +// +// Usually, it's a good idea to have one test for each method in your +// class. You don't have to do that exactly, but it helps to keep +// your tests organized. You may also throw in additional tests as +// needed. + +#include "sample2.h" +#include "gtest/gtest.h" +namespace { +// In this example, we test the MyString class (a simple string). + +// Tests the default c'tor. +TEST(MyString, DefaultConstructor) { + const MyString s; + + // Asserts that s.c_string() returns NULL. + // + // + // + // If we write NULL instead of + // + // static_cast(NULL) + // + // in this assertion, it will generate a warning on gcc 3.4. The + // reason is that EXPECT_EQ needs to know the types of its + // arguments in order to print them when it fails. Since NULL is + // #defined as 0, the compiler will use the formatter function for + // int to print it. However, gcc thinks that NULL should be used as + // a pointer, not an int, and therefore complains. + // + // The root of the problem is C++'s lack of distinction between the + // integer number 0 and the null pointer constant. Unfortunately, + // we have to live with this fact. + // + // + EXPECT_STREQ(nullptr, s.c_string()); + + EXPECT_EQ(0u, s.Length()); +} + +const char kHelloString[] = "Hello, world!"; + +// Tests the c'tor that accepts a C string. +TEST(MyString, ConstructorFromCString) { + const MyString s(kHelloString); + EXPECT_EQ(0, strcmp(s.c_string(), kHelloString)); + EXPECT_EQ(sizeof(kHelloString)/sizeof(kHelloString[0]) - 1, + s.Length()); +} + +// Tests the copy c'tor. +TEST(MyString, CopyConstructor) { + const MyString s1(kHelloString); + const MyString s2 = s1; + EXPECT_EQ(0, strcmp(s2.c_string(), kHelloString)); +} + +// Tests the Set method. +TEST(MyString, Set) { + MyString s; + + s.Set(kHelloString); + EXPECT_EQ(0, strcmp(s.c_string(), kHelloString)); + + // Set should work when the input pointer is the same as the one + // already in the MyString object. + s.Set(s.c_string()); + EXPECT_EQ(0, strcmp(s.c_string(), kHelloString)); + + // Can we set the MyString to NULL? + s.Set(nullptr); + EXPECT_STREQ(nullptr, s.c_string()); +} +} // namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample3-inl.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample3-inl.h new file mode 100644 index 0000000000000000000000000000000000000000..80ba6b923480da8fd9e6499821b7f24e5d1aadaf --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample3-inl.h @@ -0,0 +1,172 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. + +#ifndef GTEST_SAMPLES_SAMPLE3_INL_H_ +#define GTEST_SAMPLES_SAMPLE3_INL_H_ + +#include + + +// Queue is a simple queue implemented as a singled-linked list. +// +// The element type must support copy constructor. +template // E is the element type +class Queue; + +// QueueNode is a node in a Queue, which consists of an element of +// type E and a pointer to the next node. +template // E is the element type +class QueueNode { + friend class Queue; + + public: + // Gets the element in this node. + const E& element() const { return element_; } + + // Gets the next node in the queue. + QueueNode* next() { return next_; } + const QueueNode* next() const { return next_; } + + private: + // Creates a node with a given element value. The next pointer is + // set to NULL. + explicit QueueNode(const E& an_element) + : element_(an_element), next_(nullptr) {} + + // We disable the default assignment operator and copy c'tor. + const QueueNode& operator = (const QueueNode&); + QueueNode(const QueueNode&); + + E element_; + QueueNode* next_; +}; + +template // E is the element type. +class Queue { + public: + // Creates an empty queue. + Queue() : head_(nullptr), last_(nullptr), size_(0) {} + + // D'tor. Clears the queue. + ~Queue() { Clear(); } + + // Clears the queue. + void Clear() { + if (size_ > 0) { + // 1. Deletes every node. + QueueNode* node = head_; + QueueNode* next = node->next(); + for (; ;) { + delete node; + node = next; + if (node == nullptr) break; + next = node->next(); + } + + // 2. Resets the member variables. + head_ = last_ = nullptr; + size_ = 0; + } + } + + // Gets the number of elements. + size_t Size() const { return size_; } + + // Gets the first element of the queue, or NULL if the queue is empty. + QueueNode* Head() { return head_; } + const QueueNode* Head() const { return head_; } + + // Gets the last element of the queue, or NULL if the queue is empty. + QueueNode* Last() { return last_; } + const QueueNode* Last() const { return last_; } + + // Adds an element to the end of the queue. A copy of the element is + // created using the copy constructor, and then stored in the queue. + // Changes made to the element in the queue doesn't affect the source + // object, and vice versa. + void Enqueue(const E& element) { + QueueNode* new_node = new QueueNode(element); + + if (size_ == 0) { + head_ = last_ = new_node; + size_ = 1; + } else { + last_->next_ = new_node; + last_ = new_node; + size_++; + } + } + + // Removes the head of the queue and returns it. Returns NULL if + // the queue is empty. + E* Dequeue() { + if (size_ == 0) { + return nullptr; + } + + const QueueNode* const old_head = head_; + head_ = head_->next_; + size_--; + if (size_ == 0) { + last_ = nullptr; + } + + E* element = new E(old_head->element()); + delete old_head; + + return element; + } + + // Applies a function/functor on each element of the queue, and + // returns the result in a new queue. The original queue is not + // affected. + template + Queue* Map(F function) const { + Queue* new_queue = new Queue(); + for (const QueueNode* node = head_; node != nullptr; + node = node->next_) { + new_queue->Enqueue(function(node->element())); + } + + return new_queue; + } + + private: + QueueNode* head_; // The first node of the queue. + QueueNode* last_; // The last node of the queue. + size_t size_; // The number of elements in the queue. + + // We disallow copying a queue. + Queue(const Queue&); + const Queue& operator = (const Queue&); +}; + +#endif // GTEST_SAMPLES_SAMPLE3_INL_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample3_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample3_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..b19416d53c95f084efe51bf8ef23cc693f3c5d40 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample3_unittest.cc @@ -0,0 +1,149 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. + +// In this example, we use a more advanced feature of Google Test called +// test fixture. +// +// A test fixture is a place to hold objects and functions shared by +// all tests in a test case. Using a test fixture avoids duplicating +// the test code necessary to initialize and cleanup those common +// objects for each test. It is also useful for defining sub-routines +// that your tests need to invoke a lot. +// +// +// +// The tests share the test fixture in the sense of code sharing, not +// data sharing. Each test is given its own fresh copy of the +// fixture. You cannot expect the data modified by one test to be +// passed on to another test, which is a bad idea. +// +// The reason for this design is that tests should be independent and +// repeatable. In particular, a test should not fail as the result of +// another test's failure. If one test depends on info produced by +// another test, then the two tests should really be one big test. +// +// The macros for indicating the success/failure of a test +// (EXPECT_TRUE, FAIL, etc) need to know what the current test is +// (when Google Test prints the test result, it tells you which test +// each failure belongs to). Technically, these macros invoke a +// member function of the Test class. Therefore, you cannot use them +// in a global function. That's why you should put test sub-routines +// in a test fixture. +// +// + +#include "sample3-inl.h" +#include "gtest/gtest.h" +namespace { +// To use a test fixture, derive a class from testing::Test. +class QueueTestSmpl3 : public testing::Test { + protected: // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the variables. + // Otherwise, this can be skipped. + void SetUp() override { + q1_.Enqueue(1); + q2_.Enqueue(2); + q2_.Enqueue(3); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + // virtual void TearDown() { + // } + + // A helper function that some test uses. + static int Double(int n) { + return 2*n; + } + + // A helper function for testing Queue::Map(). + void MapTester(const Queue * q) { + // Creates a new queue, where each element is twice as big as the + // corresponding one in q. + const Queue * const new_q = q->Map(Double); + + // Verifies that the new queue has the same size as q. + ASSERT_EQ(q->Size(), new_q->Size()); + + // Verifies the relationship between the elements of the two queues. + for (const QueueNode*n1 = q->Head(), *n2 = new_q->Head(); + n1 != nullptr; n1 = n1->next(), n2 = n2->next()) { + EXPECT_EQ(2 * n1->element(), n2->element()); + } + + delete new_q; + } + + // Declares the variables your tests want to use. + Queue q0_; + Queue q1_; + Queue q2_; +}; + +// When you have a test fixture, you define a test using TEST_F +// instead of TEST. + +// Tests the default c'tor. +TEST_F(QueueTestSmpl3, DefaultConstructor) { + // You can access data in the test fixture here. + EXPECT_EQ(0u, q0_.Size()); +} + +// Tests Dequeue(). +TEST_F(QueueTestSmpl3, Dequeue) { + int * n = q0_.Dequeue(); + EXPECT_TRUE(n == nullptr); + + n = q1_.Dequeue(); + ASSERT_TRUE(n != nullptr); + EXPECT_EQ(1, *n); + EXPECT_EQ(0u, q1_.Size()); + delete n; + + n = q2_.Dequeue(); + ASSERT_TRUE(n != nullptr); + EXPECT_EQ(2, *n); + EXPECT_EQ(1u, q2_.Size()); + delete n; +} + +// Tests the Queue::Map() function. +TEST_F(QueueTestSmpl3, Map) { + MapTester(&q0_); + MapTester(&q1_); + MapTester(&q2_); +} +} // namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample4.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample4.cc new file mode 100644 index 0000000000000000000000000000000000000000..b0ee6093b4a250cf11936ccc8208a612291b8140 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample4.cc @@ -0,0 +1,54 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. + +#include + +#include "sample4.h" + +// Returns the current counter value, and increments it. +int Counter::Increment() { + return counter_++; +} + +// Returns the current counter value, and decrements it. +// counter can not be less than 0, return 0 in this case +int Counter::Decrement() { + if (counter_ == 0) { + return counter_; + } else { + return counter_--; + } +} + +// Prints the current counter value to STDOUT. +void Counter::Print() const { + printf("%d", counter_); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample4.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample4.h new file mode 100644 index 0000000000000000000000000000000000000000..e256f4064fe91a7f01a94550d32c3bb11b0a4fff --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample4.h @@ -0,0 +1,53 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A sample program demonstrating using Google C++ testing framework. +#ifndef GTEST_SAMPLES_SAMPLE4_H_ +#define GTEST_SAMPLES_SAMPLE4_H_ + +// A simple monotonic counter. +class Counter { + private: + int counter_; + + public: + // Creates a counter that starts at 0. + Counter() : counter_(0) {} + + // Returns the current counter value, and increments it. + int Increment(); + + // Returns the current counter value, and decrements it. + int Decrement(); + + // Prints the current counter value to STDOUT. + void Print() const; +}; + +#endif // GTEST_SAMPLES_SAMPLE4_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample4_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample4_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..d5144c0d00f5c7600693ea025802c0d7d5250d2e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample4_unittest.cc @@ -0,0 +1,53 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#include "sample4.h" +#include "gtest/gtest.h" + +namespace { +// Tests the Increment() method. + +TEST(Counter, Increment) { + Counter c; + + // Test that counter 0 returns 0 + EXPECT_EQ(0, c.Decrement()); + + // EXPECT_EQ() evaluates its arguments exactly once, so they + // can have side effects. + + EXPECT_EQ(0, c.Increment()); + EXPECT_EQ(1, c.Increment()); + EXPECT_EQ(2, c.Increment()); + + EXPECT_EQ(3, c.Decrement()); +} + +} // namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample5_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample5_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..0a21dd2157707fb32c459248b0c5341609ec0614 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample5_unittest.cc @@ -0,0 +1,196 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// This sample teaches how to reuse a test fixture in multiple test +// cases by deriving sub-fixtures from it. +// +// When you define a test fixture, you specify the name of the test +// case that will use this fixture. Therefore, a test fixture can +// be used by only one test case. +// +// Sometimes, more than one test cases may want to use the same or +// slightly different test fixtures. For example, you may want to +// make sure that all tests for a GUI library don't leak important +// system resources like fonts and brushes. In Google Test, you do +// this by putting the shared logic in a super (as in "super class") +// test fixture, and then have each test case use a fixture derived +// from this super fixture. + +#include +#include +#include "gtest/gtest.h" +#include "sample1.h" +#include "sample3-inl.h" +namespace { +// In this sample, we want to ensure that every test finishes within +// ~5 seconds. If a test takes longer to run, we consider it a +// failure. +// +// We put the code for timing a test in a test fixture called +// "QuickTest". QuickTest is intended to be the super fixture that +// other fixtures derive from, therefore there is no test case with +// the name "QuickTest". This is OK. +// +// Later, we will derive multiple test fixtures from QuickTest. +class QuickTest : public testing::Test { + protected: + // Remember that SetUp() is run immediately before a test starts. + // This is a good place to record the start time. + void SetUp() override { start_time_ = time(nullptr); } + + // TearDown() is invoked immediately after a test finishes. Here we + // check if the test was too slow. + void TearDown() override { + // Gets the time when the test finishes + const time_t end_time = time(nullptr); + + // Asserts that the test took no more than ~5 seconds. Did you + // know that you can use assertions in SetUp() and TearDown() as + // well? + EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long."; + } + + // The UTC time (in seconds) when the test starts + time_t start_time_; +}; + + +// We derive a fixture named IntegerFunctionTest from the QuickTest +// fixture. All tests using this fixture will be automatically +// required to be quick. +class IntegerFunctionTest : public QuickTest { + // We don't need any more logic than already in the QuickTest fixture. + // Therefore the body is empty. +}; + + +// Now we can write tests in the IntegerFunctionTest test case. + +// Tests Factorial() +TEST_F(IntegerFunctionTest, Factorial) { + // Tests factorial of negative numbers. + EXPECT_EQ(1, Factorial(-5)); + EXPECT_EQ(1, Factorial(-1)); + EXPECT_GT(Factorial(-10), 0); + + // Tests factorial of 0. + EXPECT_EQ(1, Factorial(0)); + + // Tests factorial of positive numbers. + EXPECT_EQ(1, Factorial(1)); + EXPECT_EQ(2, Factorial(2)); + EXPECT_EQ(6, Factorial(3)); + EXPECT_EQ(40320, Factorial(8)); +} + + +// Tests IsPrime() +TEST_F(IntegerFunctionTest, IsPrime) { + // Tests negative input. + EXPECT_FALSE(IsPrime(-1)); + EXPECT_FALSE(IsPrime(-2)); + EXPECT_FALSE(IsPrime(INT_MIN)); + + // Tests some trivial cases. + EXPECT_FALSE(IsPrime(0)); + EXPECT_FALSE(IsPrime(1)); + EXPECT_TRUE(IsPrime(2)); + EXPECT_TRUE(IsPrime(3)); + + // Tests positive input. + EXPECT_FALSE(IsPrime(4)); + EXPECT_TRUE(IsPrime(5)); + EXPECT_FALSE(IsPrime(6)); + EXPECT_TRUE(IsPrime(23)); +} + + +// The next test case (named "QueueTest") also needs to be quick, so +// we derive another fixture from QuickTest. +// +// The QueueTest test fixture has some logic and shared objects in +// addition to what's in QuickTest already. We define the additional +// stuff inside the body of the test fixture, as usual. +class QueueTest : public QuickTest { + protected: + void SetUp() override { + // First, we need to set up the super fixture (QuickTest). + QuickTest::SetUp(); + + // Second, some additional setup for this fixture. + q1_.Enqueue(1); + q2_.Enqueue(2); + q2_.Enqueue(3); + } + + // By default, TearDown() inherits the behavior of + // QuickTest::TearDown(). As we have no additional cleaning work + // for QueueTest, we omit it here. + // + // virtual void TearDown() { + // QuickTest::TearDown(); + // } + + Queue q0_; + Queue q1_; + Queue q2_; +}; + + +// Now, let's write tests using the QueueTest fixture. + +// Tests the default constructor. +TEST_F(QueueTest, DefaultConstructor) { + EXPECT_EQ(0u, q0_.Size()); +} + +// Tests Dequeue(). +TEST_F(QueueTest, Dequeue) { + int* n = q0_.Dequeue(); + EXPECT_TRUE(n == nullptr); + + n = q1_.Dequeue(); + EXPECT_TRUE(n != nullptr); + EXPECT_EQ(1, *n); + EXPECT_EQ(0u, q1_.Size()); + delete n; + + n = q2_.Dequeue(); + EXPECT_TRUE(n != nullptr); + EXPECT_EQ(2, *n); + EXPECT_EQ(1u, q2_.Size()); + delete n; +} +} // namespace +// If necessary, you can derive further test fixtures from a derived +// fixture itself. For example, you can derive another fixture from +// QueueTest. Google Test imposes no limit on how deep the hierarchy +// can be. In practice, however, you probably don't want it to be too +// deep as to be confusing. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample6_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample6_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..0266e27e589e069ad718c2e38cb9b4c21732f737 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample6_unittest.cc @@ -0,0 +1,224 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// This sample shows how to test common properties of multiple +// implementations of the same interface (aka interface tests). + +// The interface and its implementations are in this header. +#include "prime_tables.h" + +#include "gtest/gtest.h" +namespace { +// First, we define some factory functions for creating instances of +// the implementations. You may be able to skip this step if all your +// implementations can be constructed the same way. + +template +PrimeTable* CreatePrimeTable(); + +template <> +PrimeTable* CreatePrimeTable() { + return new OnTheFlyPrimeTable; +} + +template <> +PrimeTable* CreatePrimeTable() { + return new PreCalculatedPrimeTable(10000); +} + +// Then we define a test fixture class template. +template +class PrimeTableTest : public testing::Test { + protected: + // The ctor calls the factory function to create a prime table + // implemented by T. + PrimeTableTest() : table_(CreatePrimeTable()) {} + + ~PrimeTableTest() override { delete table_; } + + // Note that we test an implementation via the base interface + // instead of the actual implementation class. This is important + // for keeping the tests close to the real world scenario, where the + // implementation is invoked via the base interface. It avoids + // got-yas where the implementation class has a method that shadows + // a method with the same name (but slightly different argument + // types) in the base interface, for example. + PrimeTable* const table_; +}; + +#if GTEST_HAS_TYPED_TEST + +using testing::Types; + +// Google Test offers two ways for reusing tests for different types. +// The first is called "typed tests". You should use it if you +// already know *all* the types you are gonna exercise when you write +// the tests. + +// To write a typed test case, first use +// +// TYPED_TEST_SUITE(TestCaseName, TypeList); +// +// to declare it and specify the type parameters. As with TEST_F, +// TestCaseName must match the test fixture name. + +// The list of types we want to test. +typedef Types Implementations; + +TYPED_TEST_SUITE(PrimeTableTest, Implementations); + +// Then use TYPED_TEST(TestCaseName, TestName) to define a typed test, +// similar to TEST_F. +TYPED_TEST(PrimeTableTest, ReturnsFalseForNonPrimes) { + // Inside the test body, you can refer to the type parameter by + // TypeParam, and refer to the fixture class by TestFixture. We + // don't need them in this example. + + // Since we are in the template world, C++ requires explicitly + // writing 'this->' when referring to members of the fixture class. + // This is something you have to learn to live with. + EXPECT_FALSE(this->table_->IsPrime(-5)); + EXPECT_FALSE(this->table_->IsPrime(0)); + EXPECT_FALSE(this->table_->IsPrime(1)); + EXPECT_FALSE(this->table_->IsPrime(4)); + EXPECT_FALSE(this->table_->IsPrime(6)); + EXPECT_FALSE(this->table_->IsPrime(100)); +} + +TYPED_TEST(PrimeTableTest, ReturnsTrueForPrimes) { + EXPECT_TRUE(this->table_->IsPrime(2)); + EXPECT_TRUE(this->table_->IsPrime(3)); + EXPECT_TRUE(this->table_->IsPrime(5)); + EXPECT_TRUE(this->table_->IsPrime(7)); + EXPECT_TRUE(this->table_->IsPrime(11)); + EXPECT_TRUE(this->table_->IsPrime(131)); +} + +TYPED_TEST(PrimeTableTest, CanGetNextPrime) { + EXPECT_EQ(2, this->table_->GetNextPrime(0)); + EXPECT_EQ(3, this->table_->GetNextPrime(2)); + EXPECT_EQ(5, this->table_->GetNextPrime(3)); + EXPECT_EQ(7, this->table_->GetNextPrime(5)); + EXPECT_EQ(11, this->table_->GetNextPrime(7)); + EXPECT_EQ(131, this->table_->GetNextPrime(128)); +} + +// That's it! Google Test will repeat each TYPED_TEST for each type +// in the type list specified in TYPED_TEST_SUITE. Sit back and be +// happy that you don't have to define them multiple times. + +#endif // GTEST_HAS_TYPED_TEST + +#if GTEST_HAS_TYPED_TEST_P + +using testing::Types; + +// Sometimes, however, you don't yet know all the types that you want +// to test when you write the tests. For example, if you are the +// author of an interface and expect other people to implement it, you +// might want to write a set of tests to make sure each implementation +// conforms to some basic requirements, but you don't know what +// implementations will be written in the future. +// +// How can you write the tests without committing to the type +// parameters? That's what "type-parameterized tests" can do for you. +// It is a bit more involved than typed tests, but in return you get a +// test pattern that can be reused in many contexts, which is a big +// win. Here's how you do it: + +// First, define a test fixture class template. Here we just reuse +// the PrimeTableTest fixture defined earlier: + +template +class PrimeTableTest2 : public PrimeTableTest { +}; + +// Then, declare the test case. The argument is the name of the test +// fixture, and also the name of the test case (as usual). The _P +// suffix is for "parameterized" or "pattern". +TYPED_TEST_SUITE_P(PrimeTableTest2); + +// Next, use TYPED_TEST_P(TestCaseName, TestName) to define a test, +// similar to what you do with TEST_F. +TYPED_TEST_P(PrimeTableTest2, ReturnsFalseForNonPrimes) { + EXPECT_FALSE(this->table_->IsPrime(-5)); + EXPECT_FALSE(this->table_->IsPrime(0)); + EXPECT_FALSE(this->table_->IsPrime(1)); + EXPECT_FALSE(this->table_->IsPrime(4)); + EXPECT_FALSE(this->table_->IsPrime(6)); + EXPECT_FALSE(this->table_->IsPrime(100)); +} + +TYPED_TEST_P(PrimeTableTest2, ReturnsTrueForPrimes) { + EXPECT_TRUE(this->table_->IsPrime(2)); + EXPECT_TRUE(this->table_->IsPrime(3)); + EXPECT_TRUE(this->table_->IsPrime(5)); + EXPECT_TRUE(this->table_->IsPrime(7)); + EXPECT_TRUE(this->table_->IsPrime(11)); + EXPECT_TRUE(this->table_->IsPrime(131)); +} + +TYPED_TEST_P(PrimeTableTest2, CanGetNextPrime) { + EXPECT_EQ(2, this->table_->GetNextPrime(0)); + EXPECT_EQ(3, this->table_->GetNextPrime(2)); + EXPECT_EQ(5, this->table_->GetNextPrime(3)); + EXPECT_EQ(7, this->table_->GetNextPrime(5)); + EXPECT_EQ(11, this->table_->GetNextPrime(7)); + EXPECT_EQ(131, this->table_->GetNextPrime(128)); +} + +// Type-parameterized tests involve one extra step: you have to +// enumerate the tests you defined: +REGISTER_TYPED_TEST_SUITE_P( + PrimeTableTest2, // The first argument is the test case name. + // The rest of the arguments are the test names. + ReturnsFalseForNonPrimes, ReturnsTrueForPrimes, CanGetNextPrime); + +// At this point the test pattern is done. However, you don't have +// any real test yet as you haven't said which types you want to run +// the tests with. + +// To turn the abstract test pattern into real tests, you instantiate +// it with a list of types. Usually the test pattern will be defined +// in a .h file, and anyone can #include and instantiate it. You can +// even instantiate it more than once in the same program. To tell +// different instances apart, you give each of them a name, which will +// become part of the test case name and can be used in test filters. + +// The list of types we want to test. Note that it doesn't have to be +// defined at the time we write the TYPED_TEST_P()s. +typedef Types + PrimeTableImplementations; +INSTANTIATE_TYPED_TEST_SUITE_P(OnTheFlyAndPreCalculated, // Instance name + PrimeTableTest2, // Test case name + PrimeTableImplementations); // Type list + +#endif // GTEST_HAS_TYPED_TEST_P +} // namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample7_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample7_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..e0efc29e4a2a977e1a50a45bb375243c968547d7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample7_unittest.cc @@ -0,0 +1,117 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// This sample shows how to test common properties of multiple +// implementations of an interface (aka interface tests) using +// value-parameterized tests. Each test in the test case has +// a parameter that is an interface pointer to an implementation +// tested. + +// The interface and its implementations are in this header. +#include "prime_tables.h" + +#include "gtest/gtest.h" +namespace { + +using ::testing::TestWithParam; +using ::testing::Values; + +// As a general rule, to prevent a test from affecting the tests that come +// after it, you should create and destroy the tested objects for each test +// instead of reusing them. In this sample we will define a simple factory +// function for PrimeTable objects. We will instantiate objects in test's +// SetUp() method and delete them in TearDown() method. +typedef PrimeTable* CreatePrimeTableFunc(); + +PrimeTable* CreateOnTheFlyPrimeTable() { + return new OnTheFlyPrimeTable(); +} + +template +PrimeTable* CreatePreCalculatedPrimeTable() { + return new PreCalculatedPrimeTable(max_precalculated); +} + +// Inside the test body, fixture constructor, SetUp(), and TearDown() you +// can refer to the test parameter by GetParam(). In this case, the test +// parameter is a factory function which we call in fixture's SetUp() to +// create and store an instance of PrimeTable. +class PrimeTableTestSmpl7 : public TestWithParam { + public: + ~PrimeTableTestSmpl7() override { delete table_; } + void SetUp() override { table_ = (*GetParam())(); } + void TearDown() override { + delete table_; + table_ = nullptr; + } + + protected: + PrimeTable* table_; +}; + +TEST_P(PrimeTableTestSmpl7, ReturnsFalseForNonPrimes) { + EXPECT_FALSE(table_->IsPrime(-5)); + EXPECT_FALSE(table_->IsPrime(0)); + EXPECT_FALSE(table_->IsPrime(1)); + EXPECT_FALSE(table_->IsPrime(4)); + EXPECT_FALSE(table_->IsPrime(6)); + EXPECT_FALSE(table_->IsPrime(100)); +} + +TEST_P(PrimeTableTestSmpl7, ReturnsTrueForPrimes) { + EXPECT_TRUE(table_->IsPrime(2)); + EXPECT_TRUE(table_->IsPrime(3)); + EXPECT_TRUE(table_->IsPrime(5)); + EXPECT_TRUE(table_->IsPrime(7)); + EXPECT_TRUE(table_->IsPrime(11)); + EXPECT_TRUE(table_->IsPrime(131)); +} + +TEST_P(PrimeTableTestSmpl7, CanGetNextPrime) { + EXPECT_EQ(2, table_->GetNextPrime(0)); + EXPECT_EQ(3, table_->GetNextPrime(2)); + EXPECT_EQ(5, table_->GetNextPrime(3)); + EXPECT_EQ(7, table_->GetNextPrime(5)); + EXPECT_EQ(11, table_->GetNextPrime(7)); + EXPECT_EQ(131, table_->GetNextPrime(128)); +} + +// In order to run value-parameterized tests, you need to instantiate them, +// or bind them to a list of values which will be used as test parameters. +// You can instantiate them in a different translation module, or even +// instantiate them several times. +// +// Here, we instantiate our tests with a list of two PrimeTable object +// factory functions: +INSTANTIATE_TEST_SUITE_P(OnTheFlyAndPreCalculated, PrimeTableTestSmpl7, + Values(&CreateOnTheFlyPrimeTable, + &CreatePreCalculatedPrimeTable<1000>)); + +} // namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample8_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample8_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..10488b0ea4509a6591f06b05ac5ae14433b652ee --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample8_unittest.cc @@ -0,0 +1,154 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// This sample shows how to test code relying on some global flag variables. +// Combine() helps with generating all possible combinations of such flags, +// and each test is given one combination as a parameter. + +// Use class definitions to test from this header. +#include "prime_tables.h" + +#include "gtest/gtest.h" +namespace { + +// Suppose we want to introduce a new, improved implementation of PrimeTable +// which combines speed of PrecalcPrimeTable and versatility of +// OnTheFlyPrimeTable (see prime_tables.h). Inside it instantiates both +// PrecalcPrimeTable and OnTheFlyPrimeTable and uses the one that is more +// appropriate under the circumstances. But in low memory conditions, it can be +// told to instantiate without PrecalcPrimeTable instance at all and use only +// OnTheFlyPrimeTable. +class HybridPrimeTable : public PrimeTable { + public: + HybridPrimeTable(bool force_on_the_fly, int max_precalculated) + : on_the_fly_impl_(new OnTheFlyPrimeTable), + precalc_impl_(force_on_the_fly + ? nullptr + : new PreCalculatedPrimeTable(max_precalculated)), + max_precalculated_(max_precalculated) {} + ~HybridPrimeTable() override { + delete on_the_fly_impl_; + delete precalc_impl_; + } + + bool IsPrime(int n) const override { + if (precalc_impl_ != nullptr && n < max_precalculated_) + return precalc_impl_->IsPrime(n); + else + return on_the_fly_impl_->IsPrime(n); + } + + int GetNextPrime(int p) const override { + int next_prime = -1; + if (precalc_impl_ != nullptr && p < max_precalculated_) + next_prime = precalc_impl_->GetNextPrime(p); + + return next_prime != -1 ? next_prime : on_the_fly_impl_->GetNextPrime(p); + } + + private: + OnTheFlyPrimeTable* on_the_fly_impl_; + PreCalculatedPrimeTable* precalc_impl_; + int max_precalculated_; +}; + +using ::testing::TestWithParam; +using ::testing::Bool; +using ::testing::Values; +using ::testing::Combine; + +// To test all code paths for HybridPrimeTable we must test it with numbers +// both within and outside PreCalculatedPrimeTable's capacity and also with +// PreCalculatedPrimeTable disabled. We do this by defining fixture which will +// accept different combinations of parameters for instantiating a +// HybridPrimeTable instance. +class PrimeTableTest : public TestWithParam< ::std::tuple > { + protected: + void SetUp() override { + bool force_on_the_fly; + int max_precalculated; + std::tie(force_on_the_fly, max_precalculated) = GetParam(); + table_ = new HybridPrimeTable(force_on_the_fly, max_precalculated); + } + void TearDown() override { + delete table_; + table_ = nullptr; + } + HybridPrimeTable* table_; +}; + +TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) { + // Inside the test body, you can refer to the test parameter by GetParam(). + // In this case, the test parameter is a PrimeTable interface pointer which + // we can use directly. + // Please note that you can also save it in the fixture's SetUp() method + // or constructor and use saved copy in the tests. + + EXPECT_FALSE(table_->IsPrime(-5)); + EXPECT_FALSE(table_->IsPrime(0)); + EXPECT_FALSE(table_->IsPrime(1)); + EXPECT_FALSE(table_->IsPrime(4)); + EXPECT_FALSE(table_->IsPrime(6)); + EXPECT_FALSE(table_->IsPrime(100)); +} + +TEST_P(PrimeTableTest, ReturnsTrueForPrimes) { + EXPECT_TRUE(table_->IsPrime(2)); + EXPECT_TRUE(table_->IsPrime(3)); + EXPECT_TRUE(table_->IsPrime(5)); + EXPECT_TRUE(table_->IsPrime(7)); + EXPECT_TRUE(table_->IsPrime(11)); + EXPECT_TRUE(table_->IsPrime(131)); +} + +TEST_P(PrimeTableTest, CanGetNextPrime) { + EXPECT_EQ(2, table_->GetNextPrime(0)); + EXPECT_EQ(3, table_->GetNextPrime(2)); + EXPECT_EQ(5, table_->GetNextPrime(3)); + EXPECT_EQ(7, table_->GetNextPrime(5)); + EXPECT_EQ(11, table_->GetNextPrime(7)); + EXPECT_EQ(131, table_->GetNextPrime(128)); +} + +// In order to run value-parameterized tests, you need to instantiate them, +// or bind them to a list of values which will be used as test parameters. +// You can instantiate them in a different translation module, or even +// instantiate them several times. +// +// Here, we instantiate our tests with a list of parameters. We must combine +// all variations of the boolean flag suppressing PrecalcPrimeTable and some +// meaningful values for tests. We choose a small value (1), and a value that +// will put some of the tested numbers beyond the capability of the +// PrecalcPrimeTable instance and some inside it (10). Combine will produce all +// possible combinations. +INSTANTIATE_TEST_SUITE_P(MeaningfulTestParameters, PrimeTableTest, + Combine(Bool(), Values(1, 10))); + +} // namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample9_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample9_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..e502d08d73e7d70bede86cbd711754cd09de841c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/samples/sample9_unittest.cc @@ -0,0 +1,156 @@ +// Copyright 2009 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// This sample shows how to use Google Test listener API to implement +// an alternative console output and how to use the UnitTest reflection API +// to enumerate test cases and tests and to inspect their results. + +#include + +#include "gtest/gtest.h" + +using ::testing::EmptyTestEventListener; +using ::testing::InitGoogleTest; +using ::testing::Test; +using ::testing::TestCase; +using ::testing::TestEventListeners; +using ::testing::TestInfo; +using ::testing::TestPartResult; +using ::testing::UnitTest; +namespace { +// Provides alternative output mode which produces minimal amount of +// information about tests. +class TersePrinter : public EmptyTestEventListener { + private: + // Called before any test activity starts. + void OnTestProgramStart(const UnitTest& /* unit_test */) override {} + + // Called after all test activities have ended. + void OnTestProgramEnd(const UnitTest& unit_test) override { + fprintf(stdout, "TEST %s\n", unit_test.Passed() ? "PASSED" : "FAILED"); + fflush(stdout); + } + + // Called before a test starts. + void OnTestStart(const TestInfo& test_info) override { + fprintf(stdout, + "*** Test %s.%s starting.\n", + test_info.test_case_name(), + test_info.name()); + fflush(stdout); + } + + // Called after a failed assertion or a SUCCEED() invocation. + void OnTestPartResult(const TestPartResult& test_part_result) override { + fprintf(stdout, + "%s in %s:%d\n%s\n", + test_part_result.failed() ? "*** Failure" : "Success", + test_part_result.file_name(), + test_part_result.line_number(), + test_part_result.summary()); + fflush(stdout); + } + + // Called after a test ends. + void OnTestEnd(const TestInfo& test_info) override { + fprintf(stdout, + "*** Test %s.%s ending.\n", + test_info.test_case_name(), + test_info.name()); + fflush(stdout); + } +}; // class TersePrinter + +TEST(CustomOutputTest, PrintsMessage) { + printf("Printing something from the test body...\n"); +} + +TEST(CustomOutputTest, Succeeds) { + SUCCEED() << "SUCCEED() has been invoked from here"; +} + +TEST(CustomOutputTest, Fails) { + EXPECT_EQ(1, 2) + << "This test fails in order to demonstrate alternative failure messages"; +} +} // namespace + +int main(int argc, char **argv) { + InitGoogleTest(&argc, argv); + + bool terse_output = false; + if (argc > 1 && strcmp(argv[1], "--terse_output") == 0 ) + terse_output = true; + else + printf("%s\n", "Run this program with --terse_output to change the way " + "it prints its output."); + + UnitTest& unit_test = *UnitTest::GetInstance(); + + // If we are given the --terse_output command line flag, suppresses the + // standard output and attaches own result printer. + if (terse_output) { + TestEventListeners& listeners = unit_test.listeners(); + + // Removes the default console output listener from the list so it will + // not receive events from Google Test and won't print any output. Since + // this operation transfers ownership of the listener to the caller we + // have to delete it as well. + delete listeners.Release(listeners.default_result_printer()); + + // Adds the custom output listener to the list. It will now receive + // events from Google Test and print the alternative output. We don't + // have to worry about deleting it since Google Test assumes ownership + // over it after adding it to the list. + listeners.Append(new TersePrinter); + } + int ret_val = RUN_ALL_TESTS(); + + // This is an example of using the UnitTest reflection API to inspect test + // results. Here we discount failures from the tests we expected to fail. + int unexpectedly_failed_tests = 0; + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const testing::TestSuite& test_suite = *unit_test.GetTestSuite(i); + for (int j = 0; j < test_suite.total_test_count(); ++j) { + const TestInfo& test_info = *test_suite.GetTestInfo(j); + // Counts failed tests that were not meant to fail (those without + // 'Fails' in the name). + if (test_info.result()->Failed() && + strcmp(test_info.name(), "Fails") != 0) { + unexpectedly_failed_tests++; + } + } + } + + // Test that were meant to fail should not affect the test program outcome. + if (unexpectedly_failed_tests == 0) + ret_val = 0; + + return ret_val; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/common.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/common.py new file mode 100644 index 0000000000000000000000000000000000000000..3c0347a75bdff3188097745015a5803764ad741c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/common.py @@ -0,0 +1,83 @@ +# Copyright 2013 Google Inc. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Shared utilities for writing scripts for Google Test/Mock.""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + + +import os +import re + + +# Matches the line from 'svn info .' output that describes what SVN +# path the current local directory corresponds to. For example, in +# a googletest SVN workspace's trunk/test directory, the output will be: +# +# URL: https://googletest.googlecode.com/svn/trunk/test +_SVN_INFO_URL_RE = re.compile(r'^URL: https://(\w+)\.googlecode\.com/svn(.*)') + + +def GetCommandOutput(command): + """Runs the shell command and returns its stdout as a list of lines.""" + + f = os.popen(command, 'r') + lines = [line.strip() for line in f.readlines()] + f.close() + return lines + + +def GetSvnInfo(): + """Returns the project name and the current SVN workspace's root path.""" + + for line in GetCommandOutput('svn info .'): + m = _SVN_INFO_URL_RE.match(line) + if m: + project = m.group(1) # googletest or googlemock + rel_path = m.group(2) + root = os.path.realpath(rel_path.count('/') * '../') + return project, root + + return None, None + + +def GetSvnTrunk(): + """Returns the current SVN workspace's trunk root path.""" + + _, root = GetSvnInfo() + return root + '/trunk' if root else None + + +def IsInGTestSvn(): + project, _ = GetSvnInfo() + return project == 'googletest' + + +def IsInGMockSvn(): + project, _ = GetSvnInfo() + return project == 'googlemock' diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/fuse_gtest_files.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/fuse_gtest_files.py new file mode 100755 index 0000000000000000000000000000000000000000..d0dd464fe8b59c5410a3d1b85db4795bbd031d89 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/fuse_gtest_files.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python +# +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""fuse_gtest_files.py v0.2.0 +Fuses Google Test source code into a .h file and a .cc file. + +SYNOPSIS + fuse_gtest_files.py [GTEST_ROOT_DIR] OUTPUT_DIR + + Scans GTEST_ROOT_DIR for Google Test source code, and generates + two files: OUTPUT_DIR/gtest/gtest.h and OUTPUT_DIR/gtest/gtest-all.cc. + Then you can build your tests by adding OUTPUT_DIR to the include + search path and linking with OUTPUT_DIR/gtest/gtest-all.cc. These + two files contain everything you need to use Google Test. Hence + you can "install" Google Test by copying them to wherever you want. + + GTEST_ROOT_DIR can be omitted and defaults to the parent + directory of the directory holding this script. + +EXAMPLES + ./fuse_gtest_files.py fused_gtest + ./fuse_gtest_files.py path/to/unpacked/gtest fused_gtest + +This tool is experimental. In particular, it assumes that there is no +conditional inclusion of Google Test headers. Please report any +problems to googletestframework@googlegroups.com. You can read +https://github.com/google/googletest/blob/master/googletest/docs/advanced.md for +more information. +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import re +try: + from sets import Set as set # For Python 2.3 compatibility +except ImportError: + pass +import sys + +# We assume that this file is in the scripts/ directory in the Google +# Test root directory. +DEFAULT_GTEST_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..') + +# Regex for matching '#include "gtest/..."'. +INCLUDE_GTEST_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(gtest/.+)"') + +# Regex for matching '#include "src/..."'. +INCLUDE_SRC_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(src/.+)"') + +# Where to find the source seed files. +GTEST_H_SEED = 'include/gtest/gtest.h' +GTEST_SPI_H_SEED = 'include/gtest/gtest-spi.h' +GTEST_ALL_CC_SEED = 'src/gtest-all.cc' + +# Where to put the generated files. +GTEST_H_OUTPUT = 'gtest/gtest.h' +GTEST_ALL_CC_OUTPUT = 'gtest/gtest-all.cc' + + +def VerifyFileExists(directory, relative_path): + """Verifies that the given file exists; aborts on failure. + + relative_path is the file path relative to the given directory. + """ + + if not os.path.isfile(os.path.join(directory, relative_path)): + print('ERROR: Cannot find %s in directory %s.' % (relative_path, + directory)) + print('Please either specify a valid project root directory ' + 'or omit it on the command line.') + sys.exit(1) + + +def ValidateGTestRootDir(gtest_root): + """Makes sure gtest_root points to a valid gtest root directory. + + The function aborts the program on failure. + """ + + VerifyFileExists(gtest_root, GTEST_H_SEED) + VerifyFileExists(gtest_root, GTEST_ALL_CC_SEED) + + +def VerifyOutputFile(output_dir, relative_path): + """Verifies that the given output file path is valid. + + relative_path is relative to the output_dir directory. + """ + + # Makes sure the output file either doesn't exist or can be overwritten. + output_file = os.path.join(output_dir, relative_path) + if os.path.exists(output_file): + # TODO(wan@google.com): The following user-interaction doesn't + # work with automated processes. We should provide a way for the + # Makefile to force overwriting the files. + print('%s already exists in directory %s - overwrite it? (y/N) ' % + (relative_path, output_dir)) + answer = sys.stdin.readline().strip() + if answer not in ['y', 'Y']: + print('ABORTED.') + sys.exit(1) + + # Makes sure the directory holding the output file exists; creates + # it and all its ancestors if necessary. + parent_directory = os.path.dirname(output_file) + if not os.path.isdir(parent_directory): + os.makedirs(parent_directory) + + +def ValidateOutputDir(output_dir): + """Makes sure output_dir points to a valid output directory. + + The function aborts the program on failure. + """ + + VerifyOutputFile(output_dir, GTEST_H_OUTPUT) + VerifyOutputFile(output_dir, GTEST_ALL_CC_OUTPUT) + + +def FuseGTestH(gtest_root, output_dir): + """Scans folder gtest_root to generate gtest/gtest.h in output_dir.""" + + output_file = open(os.path.join(output_dir, GTEST_H_OUTPUT), 'w') + processed_files = set() # Holds all gtest headers we've processed. + + def ProcessFile(gtest_header_path): + """Processes the given gtest header file.""" + + # We don't process the same header twice. + if gtest_header_path in processed_files: + return + + processed_files.add(gtest_header_path) + + # Reads each line in the given gtest header. + for line in open(os.path.join(gtest_root, gtest_header_path), 'r'): + m = INCLUDE_GTEST_FILE_REGEX.match(line) + if m: + # It's '#include "gtest/..."' - let's process it recursively. + ProcessFile('include/' + m.group(1)) + else: + # Otherwise we copy the line unchanged to the output file. + output_file.write(line) + + ProcessFile(GTEST_H_SEED) + output_file.close() + + +def FuseGTestAllCcToFile(gtest_root, output_file): + """Scans folder gtest_root to generate gtest/gtest-all.cc in output_file.""" + + processed_files = set() + + def ProcessFile(gtest_source_file): + """Processes the given gtest source file.""" + + # We don't process the same #included file twice. + if gtest_source_file in processed_files: + return + + processed_files.add(gtest_source_file) + + # Reads each line in the given gtest source file. + for line in open(os.path.join(gtest_root, gtest_source_file), 'r'): + m = INCLUDE_GTEST_FILE_REGEX.match(line) + if m: + if 'include/' + m.group(1) == GTEST_SPI_H_SEED: + # It's '#include "gtest/gtest-spi.h"'. This file is not + # #included by "gtest/gtest.h", so we need to process it. + ProcessFile(GTEST_SPI_H_SEED) + else: + # It's '#include "gtest/foo.h"' where foo is not gtest-spi. + # We treat it as '#include "gtest/gtest.h"', as all other + # gtest headers are being fused into gtest.h and cannot be + # #included directly. + + # There is no need to #include "gtest/gtest.h" more than once. + if not GTEST_H_SEED in processed_files: + processed_files.add(GTEST_H_SEED) + output_file.write('#include "%s"\n' % (GTEST_H_OUTPUT,)) + else: + m = INCLUDE_SRC_FILE_REGEX.match(line) + if m: + # It's '#include "src/foo"' - let's process it recursively. + ProcessFile(m.group(1)) + else: + output_file.write(line) + + ProcessFile(GTEST_ALL_CC_SEED) + + +def FuseGTestAllCc(gtest_root, output_dir): + """Scans folder gtest_root to generate gtest/gtest-all.cc in output_dir.""" + + output_file = open(os.path.join(output_dir, GTEST_ALL_CC_OUTPUT), 'w') + FuseGTestAllCcToFile(gtest_root, output_file) + output_file.close() + + +def FuseGTest(gtest_root, output_dir): + """Fuses gtest.h and gtest-all.cc.""" + + ValidateGTestRootDir(gtest_root) + ValidateOutputDir(output_dir) + + FuseGTestH(gtest_root, output_dir) + FuseGTestAllCc(gtest_root, output_dir) + + +def main(): + argc = len(sys.argv) + if argc == 2: + # fuse_gtest_files.py OUTPUT_DIR + FuseGTest(DEFAULT_GTEST_ROOT_DIR, sys.argv[1]) + elif argc == 3: + # fuse_gtest_files.py GTEST_ROOT_DIR OUTPUT_DIR + FuseGTest(sys.argv[1], sys.argv[2]) + else: + print(__doc__) + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/gen_gtest_pred_impl.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/gen_gtest_pred_impl.py new file mode 100755 index 0000000000000000000000000000000000000000..b43efdf41e5c02740f72b35532be5cf049794835 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/gen_gtest_pred_impl.py @@ -0,0 +1,730 @@ +#!/usr/bin/env python +# +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""gen_gtest_pred_impl.py v0.1 + +Generates the implementation of Google Test predicate assertions and +accompanying tests. + +Usage: + + gen_gtest_pred_impl.py MAX_ARITY + +where MAX_ARITY is a positive integer. + +The command generates the implementation of up-to MAX_ARITY-ary +predicate assertions, and writes it to file gtest_pred_impl.h in the +directory where the script is. It also generates the accompanying +unit test in file gtest_pred_impl_unittest.cc. +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import sys +import time + +# Where this script is. +SCRIPT_DIR = os.path.dirname(sys.argv[0]) + +# Where to store the generated header. +HEADER = os.path.join(SCRIPT_DIR, '../include/gtest/gtest_pred_impl.h') + +# Where to store the generated unit test. +UNIT_TEST = os.path.join(SCRIPT_DIR, '../test/gtest_pred_impl_unittest.cc') + + +def HeaderPreamble(n): + """Returns the preamble for the header file. + + Args: + n: the maximum arity of the predicate macros to be generated. + """ + + # A map that defines the values used in the preamble template. + DEFS = { + 'today' : time.strftime('%m/%d/%Y'), + 'year' : time.strftime('%Y'), + 'command' : '%s %s' % (os.path.basename(sys.argv[0]), n), + 'n' : n + } + + return ( +"""// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on %(today)s by command +// '%(command)s'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +#include "gtest/gtest.h" + +namespace testing { + +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most %(n)s. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. + +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. + +#define GTEST_ASSERT_(expression, on_failure) \\ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \\ + if (const ::testing::AssertionResult gtest_ar = (expression)) \\ + ; \\ + else \\ + on_failure(gtest_ar.failure_message()) +""" % DEFS) + + +def Arity(n): + """Returns the English name of the given arity.""" + + if n < 0: + return None + elif n <= 3: + return ['nullary', 'unary', 'binary', 'ternary'][n] + else: + return '%s-ary' % n + + +def Title(word): + """Returns the given word in title case. The difference between + this and string's title() method is that Title('4-ary') is '4-ary' + while '4-ary'.title() is '4-Ary'.""" + + return word[0].upper() + word[1:] + + +def OneTo(n): + """Returns the list [1, 2, 3, ..., n].""" + + return range(1, n + 1) + + +def Iter(n, format, sep=''): + """Given a positive integer n, a format string that contains 0 or + more '%s' format specs, and optionally a separator string, returns + the join of n strings, each formatted with the format string on an + iterator ranged from 1 to n. + + Example: + + Iter(3, 'v%s', sep=', ') returns 'v1, v2, v3'. + """ + + # How many '%s' specs are in format? + spec_count = len(format.split('%s')) - 1 + return sep.join([format % (spec_count * (i,)) for i in OneTo(n)]) + + +def ImplementationForArity(n): + """Returns the implementation of n-ary predicate assertions.""" + + # A map the defines the values used in the implementation template. + DEFS = { + 'n' : str(n), + 'vs' : Iter(n, 'v%s', sep=', '), + 'vts' : Iter(n, '#v%s', sep=', '), + 'arity' : Arity(n), + 'Arity' : Title(Arity(n)) + } + + impl = """ + +// Helper function for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use +// this in your code. +template +AssertionResult AssertPred%(n)sHelper(const char* pred_text""" % DEFS + + impl += Iter(n, """, + const char* e%s""") + + impl += """, + Pred pred""" + + impl += Iter(n, """, + const T%s& v%s""") + + impl += """) { + if (pred(%(vs)s)) return AssertionSuccess(); + +""" % DEFS + + impl += ' return AssertionFailure() << pred_text << "("' + + impl += Iter(n, """ + << e%s""", sep=' << ", "') + + impl += ' << ") evaluates to false, where"' + + impl += Iter(n, """ + << "\\n" << e%s << " evaluates to " << v%s""") + + impl += """; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT%(n)s. +// Don't use this in your code. +#define GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, on_failure)\\ + GTEST_ASSERT_(pred_format(%(vts)s, %(vs)s), \\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use +// this in your code. +#define GTEST_PRED%(n)s_(pred, %(vs)s, on_failure)\\ + GTEST_ASSERT_(::testing::AssertPred%(n)sHelper(#pred""" % DEFS + + impl += Iter(n, """, \\ + #v%s""") + + impl += """, \\ + pred""" + + impl += Iter(n, """, \\ + v%s""") + + impl += """), on_failure) + +// %(Arity)s predicate assertion macros. +#define EXPECT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\ + GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED%(n)s(pred, %(vs)s) \\ + GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\ + GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED%(n)s(pred, %(vs)s) \\ + GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_FATAL_FAILURE_) + +""" % DEFS + + return impl + + +def HeaderPostamble(): + """Returns the postamble for the header file.""" + + return """ + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +""" + + +def GenerateFile(path, content): + """Given a file path and a content string + overwrites it with the given content. + """ + print 'Updating file %s . . .' % path + f = file(path, 'w+') + print >>f, content, + f.close() + + print 'File %s has been updated.' % path + + +def GenerateHeader(n): + """Given the maximum arity n, updates the header file that implements + the predicate assertions. + """ + GenerateFile(HEADER, + HeaderPreamble(n) + + ''.join([ImplementationForArity(i) for i in OneTo(n)]) + + HeaderPostamble()) + + +def UnitTestPreamble(): + """Returns the preamble for the unit test file.""" + + # A map that defines the values used in the preamble template. + DEFS = { + 'today' : time.strftime('%m/%d/%Y'), + 'year' : time.strftime('%Y'), + 'command' : '%s %s' % (os.path.basename(sys.argv[0]), sys.argv[1]), + } + + return ( +"""// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on %(today)s by command +// '%(command)s'. DO NOT EDIT BY HAND! + +// Regression test for gtest_pred_impl.h +// +// This file is generated by a script and quite long. If you intend to +// learn how Google Test works by reading its unit tests, read +// gtest_unittest.cc instead. +// +// This is intended as a regression test for the Google Test predicate +// assertions. We compile it as part of the gtest_unittest target +// only to keep the implementation tidy and compact, as it is quite +// involved to set up the stage for testing Google Test using Google +// Test itself. +// +// Currently, gtest_unittest takes ~11 seconds to run in the testing +// daemon. In the future, if it grows too large and needs much more +// time to finish, we should consider separating this file into a +// stand-alone regression test. + +#include + +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" + +// A user-defined data type. +struct Bool { + explicit Bool(int val) : value(val != 0) {} + + bool operator>(int n) const { return value > Bool(n).value; } + + Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); } + + bool operator==(const Bool& rhs) const { return value == rhs.value; } + + bool value; +}; + +// Enables Bool to be used in assertions. +std::ostream& operator<<(std::ostream& os, const Bool& x) { + return os << (x.value ? "true" : "false"); +} + +""" % DEFS) + + +def TestsForArity(n): + """Returns the tests for n-ary predicate assertions.""" + + # A map that defines the values used in the template for the tests. + DEFS = { + 'n' : n, + 'es' : Iter(n, 'e%s', sep=', '), + 'vs' : Iter(n, 'v%s', sep=', '), + 'vts' : Iter(n, '#v%s', sep=', '), + 'tvs' : Iter(n, 'T%s v%s', sep=', '), + 'int_vs' : Iter(n, 'int v%s', sep=', '), + 'Bool_vs' : Iter(n, 'Bool v%s', sep=', '), + 'types' : Iter(n, 'typename T%s', sep=', '), + 'v_sum' : Iter(n, 'v%s', sep=' + '), + 'arity' : Arity(n), + 'Arity' : Title(Arity(n)), + } + + tests = ( +"""// Sample functions/functors for testing %(arity)s predicate assertions. + +// A %(arity)s predicate function. +template <%(types)s> +bool PredFunction%(n)s(%(tvs)s) { + return %(v_sum)s > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction%(n)sInt(%(int_vs)s) { + return %(v_sum)s > 0; +} +bool PredFunction%(n)sBool(%(Bool_vs)s) { + return %(v_sum)s > 0; +} +""" % DEFS) + + tests += """ +// A %(arity)s predicate functor. +struct PredFunctor%(n)s { + template <%(types)s> + bool operator()(""" % DEFS + + tests += Iter(n, 'const T%s& v%s', sep=""", + """) + + tests += """) { + return %(v_sum)s > 0; + } +}; +""" % DEFS + + tests += """ +// A %(arity)s predicate-formatter function. +template <%(types)s> +testing::AssertionResult PredFormatFunction%(n)s(""" % DEFS + + tests += Iter(n, 'const char* e%s', sep=""", + """) + + tests += Iter(n, """, + const T%s& v%s""") + + tests += """) { + if (PredFunction%(n)s(%(vs)s)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << """ % DEFS + + tests += Iter(n, 'e%s', sep=' << " + " << ') + + tests += """ + << " is expected to be positive, but evaluates to " + << %(v_sum)s << "."; +} +""" % DEFS + + tests += """ +// A %(arity)s predicate-formatter functor. +struct PredFormatFunctor%(n)s { + template <%(types)s> + testing::AssertionResult operator()(""" % DEFS + + tests += Iter(n, 'const char* e%s', sep=""", + """) + + tests += Iter(n, """, + const T%s& v%s""") + + tests += """) const { + return PredFormatFunction%(n)s(%(es)s, %(vs)s); + } +}; +""" % DEFS + + tests += """ +// Tests for {EXPECT|ASSERT}_PRED_FORMAT%(n)s. + +class Predicate%(n)sTest : public testing::Test { + protected: + virtual void SetUp() { + expected_to_finish_ = true; + finished_ = false;""" % DEFS + + tests += """ + """ + Iter(n, 'n%s_ = ') + """0; + } +""" + + tests += """ + virtual void TearDown() { + // Verifies that each of the predicate's arguments was evaluated + // exactly once.""" + + tests += ''.join([""" + EXPECT_EQ(1, n%s_) << + "The predicate assertion didn't evaluate argument %s " + "exactly once.";""" % (i, i + 1) for i in OneTo(n)]) + + tests += """ + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true iff the test function is expected to run to finish. + static bool expected_to_finish_; + + // true iff the test function did run to finish. + static bool finished_; +""" % DEFS + + tests += Iter(n, """ + static int n%s_;""") + + tests += """ +}; + +bool Predicate%(n)sTest::expected_to_finish_; +bool Predicate%(n)sTest::finished_; +""" % DEFS + + tests += Iter(n, """int Predicate%%(n)sTest::n%s_; +""") % DEFS + + tests += """ +typedef Predicate%(n)sTest EXPECT_PRED_FORMAT%(n)sTest; +typedef Predicate%(n)sTest ASSERT_PRED_FORMAT%(n)sTest; +typedef Predicate%(n)sTest EXPECT_PRED%(n)sTest; +typedef Predicate%(n)sTest ASSERT_PRED%(n)sTest; +""" % DEFS + + def GenTest(use_format, use_assert, expect_failure, + use_functor, use_user_type): + """Returns the test for a predicate assertion macro. + + Args: + use_format: true iff the assertion is a *_PRED_FORMAT*. + use_assert: true iff the assertion is a ASSERT_*. + expect_failure: true iff the assertion is expected to fail. + use_functor: true iff the first argument of the assertion is + a functor (as opposed to a function) + use_user_type: true iff the predicate functor/function takes + argument(s) of a user-defined type. + + Example: + + GenTest(1, 0, 0, 1, 0) returns a test that tests the behavior + of a successful EXPECT_PRED_FORMATn() that takes a functor + whose arguments have built-in types.""" + + if use_assert: + assrt = 'ASSERT' # 'assert' is reserved, so we cannot use + # that identifier here. + else: + assrt = 'EXPECT' + + assertion = assrt + '_PRED' + + if use_format: + pred_format = 'PredFormat' + assertion += '_FORMAT' + else: + pred_format = 'Pred' + + assertion += '%(n)s' % DEFS + + if use_functor: + pred_format_type = 'functor' + pred_format += 'Functor%(n)s()' + else: + pred_format_type = 'function' + pred_format += 'Function%(n)s' + if not use_format: + if use_user_type: + pred_format += 'Bool' + else: + pred_format += 'Int' + + test_name = pred_format_type.title() + + if use_user_type: + arg_type = 'user-defined type (Bool)' + test_name += 'OnUserType' + if expect_failure: + arg = 'Bool(n%s_++)' + else: + arg = 'Bool(++n%s_)' + else: + arg_type = 'built-in type (int)' + test_name += 'OnBuiltInType' + if expect_failure: + arg = 'n%s_++' + else: + arg = '++n%s_' + + if expect_failure: + successful_or_failed = 'failed' + expected_or_not = 'expected.' + test_name += 'Failure' + else: + successful_or_failed = 'successful' + expected_or_not = 'UNEXPECTED!' + test_name += 'Success' + + # A map that defines the values used in the test template. + defs = DEFS.copy() + defs.update({ + 'assert' : assrt, + 'assertion' : assertion, + 'test_name' : test_name, + 'pf_type' : pred_format_type, + 'pf' : pred_format, + 'arg_type' : arg_type, + 'arg' : arg, + 'successful' : successful_or_failed, + 'expected' : expected_or_not, + }) + + test = """ +// Tests a %(successful)s %(assertion)s where the +// predicate-formatter is a %(pf_type)s on a %(arg_type)s. +TEST_F(%(assertion)sTest, %(test_name)s) {""" % defs + + indent = (len(assertion) + 3)*' ' + extra_indent = '' + + if expect_failure: + extra_indent = ' ' + if use_assert: + test += """ + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT""" + else: + test += """ + EXPECT_NONFATAL_FAILURE({ // NOLINT""" + + test += '\n' + extra_indent + """ %(assertion)s(%(pf)s""" % defs + + test = test % defs + test += Iter(n, ',\n' + indent + extra_indent + '%(arg)s' % defs) + test += ');\n' + extra_indent + ' finished_ = true;\n' + + if expect_failure: + test += ' }, "");\n' + + test += '}\n' + return test + + # Generates tests for all 2**6 = 64 combinations. + tests += ''.join([GenTest(use_format, use_assert, expect_failure, + use_functor, use_user_type) + for use_format in [0, 1] + for use_assert in [0, 1] + for expect_failure in [0, 1] + for use_functor in [0, 1] + for use_user_type in [0, 1] + ]) + + return tests + + +def UnitTestPostamble(): + """Returns the postamble for the tests.""" + + return '' + + +def GenerateUnitTest(n): + """Returns the tests for up-to n-ary predicate assertions.""" + + GenerateFile(UNIT_TEST, + UnitTestPreamble() + + ''.join([TestsForArity(i) for i in OneTo(n)]) + + UnitTestPostamble()) + + +def _Main(): + """The entry point of the script. Generates the header file and its + unit test.""" + + if len(sys.argv) != 2: + print __doc__ + print 'Author: ' + __author__ + sys.exit(1) + + n = int(sys.argv[1]) + GenerateHeader(n) + GenerateUnitTest(n) + + +if __name__ == '__main__': + _Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/gtest-config.in b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/gtest-config.in new file mode 100755 index 0000000000000000000000000000000000000000..780f8432efcc1aeeaaad0706086d3ff641285b68 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/gtest-config.in @@ -0,0 +1,274 @@ +#!/bin/sh + +# These variables are automatically filled in by the configure script. +name="@PACKAGE_TARNAME@" +version="@PACKAGE_VERSION@" + +show_usage() +{ + echo "Usage: gtest-config [OPTIONS...]" +} + +show_help() +{ + show_usage + cat <<\EOF + +The `gtest-config' script provides access to the necessary compile and linking +flags to connect with Google C++ Testing Framework, both in a build prior to +installation, and on the system proper after installation. The installation +overrides may be issued in combination with any other queries, but will only +affect installation queries if called on a built but not installed gtest. The +installation queries may not be issued with any other types of queries, and +only one installation query may be made at a time. The version queries and +compiler flag queries may be combined as desired but not mixed. Different +version queries are always combined with logical "and" semantics, and only the +last of any particular query is used while all previous ones ignored. All +versions must be specified as a sequence of numbers separated by periods. +Compiler flag queries output the union of the sets of flags when combined. + + Examples: + gtest-config --min-version=1.0 || echo "Insufficient Google Test version." + + g++ $(gtest-config --cppflags --cxxflags) -o foo.o -c foo.cpp + g++ $(gtest-config --ldflags --libs) -o foo foo.o + + # When using a built but not installed Google Test: + g++ $(../../my_gtest_build/scripts/gtest-config ...) ... + + # When using an installed Google Test, but with installation overrides: + export GTEST_PREFIX="/opt" + g++ $(gtest-config --libdir="/opt/lib64" ...) ... + + Help: + --usage brief usage information + --help display this help message + + Installation Overrides: + --prefix=
overrides the installation prefix + --exec-prefix= overrides the executable installation prefix + --libdir= overrides the library installation prefix + --includedir= overrides the header file installation prefix + + Installation Queries: + --prefix installation prefix + --exec-prefix executable installation prefix + --libdir library installation directory + --includedir header file installation directory + --version the version of the Google Test installation + + Version Queries: + --min-version=VERSION return 0 if the version is at least VERSION + --exact-version=VERSION return 0 if the version is exactly VERSION + --max-version=VERSION return 0 if the version is at most VERSION + + Compilation Flag Queries: + --cppflags compile flags specific to the C-like preprocessors + --cxxflags compile flags appropriate for C++ programs + --ldflags linker flags + --libs libraries for linking + +EOF +} + +# This function bounds our version with a min and a max. It uses some clever +# POSIX-compliant variable expansion to portably do all the work in the shell +# and avoid any dependency on a particular "sed" or "awk" implementation. +# Notable is that it will only ever compare the first 3 components of versions. +# Further components will be cleanly stripped off. All versions must be +# unadorned, so "v1.0" will *not* work. The minimum version must be in $1, and +# the max in $2. TODO(chandlerc@google.com): If this ever breaks, we should +# investigate expanding this via autom4te from AS_VERSION_COMPARE rather than +# continuing to maintain our own shell version. +check_versions() +{ + major_version=${version%%.*} + minor_version="0" + point_version="0" + if test "${version#*.}" != "${version}"; then + minor_version=${version#*.} + minor_version=${minor_version%%.*} + fi + if test "${version#*.*.}" != "${version}"; then + point_version=${version#*.*.} + point_version=${point_version%%.*} + fi + + min_version="$1" + min_major_version=${min_version%%.*} + min_minor_version="0" + min_point_version="0" + if test "${min_version#*.}" != "${min_version}"; then + min_minor_version=${min_version#*.} + min_minor_version=${min_minor_version%%.*} + fi + if test "${min_version#*.*.}" != "${min_version}"; then + min_point_version=${min_version#*.*.} + min_point_version=${min_point_version%%.*} + fi + + max_version="$2" + max_major_version=${max_version%%.*} + max_minor_version="0" + max_point_version="0" + if test "${max_version#*.}" != "${max_version}"; then + max_minor_version=${max_version#*.} + max_minor_version=${max_minor_version%%.*} + fi + if test "${max_version#*.*.}" != "${max_version}"; then + max_point_version=${max_version#*.*.} + max_point_version=${max_point_version%%.*} + fi + + test $(($major_version)) -lt $(($min_major_version)) && exit 1 + if test $(($major_version)) -eq $(($min_major_version)); then + test $(($minor_version)) -lt $(($min_minor_version)) && exit 1 + if test $(($minor_version)) -eq $(($min_minor_version)); then + test $(($point_version)) -lt $(($min_point_version)) && exit 1 + fi + fi + + test $(($major_version)) -gt $(($max_major_version)) && exit 1 + if test $(($major_version)) -eq $(($max_major_version)); then + test $(($minor_version)) -gt $(($max_minor_version)) && exit 1 + if test $(($minor_version)) -eq $(($max_minor_version)); then + test $(($point_version)) -gt $(($max_point_version)) && exit 1 + fi + fi + + exit 0 +} + +# Show the usage line when no arguments are specified. +if test $# -eq 0; then + show_usage + exit 1 +fi + +while test $# -gt 0; do + case $1 in + --usage) show_usage; exit 0;; + --help) show_help; exit 0;; + + # Installation overrides + --prefix=*) GTEST_PREFIX=${1#--prefix=};; + --exec-prefix=*) GTEST_EXEC_PREFIX=${1#--exec-prefix=};; + --libdir=*) GTEST_LIBDIR=${1#--libdir=};; + --includedir=*) GTEST_INCLUDEDIR=${1#--includedir=};; + + # Installation queries + --prefix|--exec-prefix|--libdir|--includedir|--version) + if test -n "${do_query}"; then + show_usage + exit 1 + fi + do_query=${1#--} + ;; + + # Version checking + --min-version=*) + do_check_versions=yes + min_version=${1#--min-version=} + ;; + --max-version=*) + do_check_versions=yes + max_version=${1#--max-version=} + ;; + --exact-version=*) + do_check_versions=yes + exact_version=${1#--exact-version=} + ;; + + # Compiler flag output + --cppflags) echo_cppflags=yes;; + --cxxflags) echo_cxxflags=yes;; + --ldflags) echo_ldflags=yes;; + --libs) echo_libs=yes;; + + # Everything else is an error + *) show_usage; exit 1;; + esac + shift +done + +# These have defaults filled in by the configure script but can also be +# overridden by environment variables or command line parameters. +prefix="${GTEST_PREFIX:-@prefix@}" +exec_prefix="${GTEST_EXEC_PREFIX:-@exec_prefix@}" +libdir="${GTEST_LIBDIR:-@libdir@}" +includedir="${GTEST_INCLUDEDIR:-@includedir@}" + +# We try and detect if our binary is not located at its installed location. If +# it's not, we provide variables pointing to the source and build tree rather +# than to the install tree. This allows building against a just-built gtest +# rather than an installed gtest. +bindir="@bindir@" +this_relative_bindir=`dirname $0` +this_bindir=`cd ${this_relative_bindir}; pwd -P` +if test "${this_bindir}" = "${this_bindir%${bindir}}"; then + # The path to the script doesn't end in the bindir sequence from Autoconf, + # assume that we are in a build tree. + build_dir=`dirname ${this_bindir}` + src_dir=`cd ${this_bindir}; cd @top_srcdir@; pwd -P` + + # TODO(chandlerc@google.com): This is a dangerous dependency on libtool, we + # should work to remove it, and/or remove libtool altogether, replacing it + # with direct references to the library and a link path. + gtest_libs="${build_dir}/lib/libgtest.la @PTHREAD_CFLAGS@ @PTHREAD_LIBS@" + gtest_ldflags="" + + # We provide hooks to include from either the source or build dir, where the + # build dir is always preferred. This will potentially allow us to write + # build rules for generated headers and have them automatically be preferred + # over provided versions. + gtest_cppflags="-I${build_dir}/include -I${src_dir}/include" + gtest_cxxflags="@PTHREAD_CFLAGS@" +else + # We're using an installed gtest, although it may be staged under some + # prefix. Assume (as our own libraries do) that we can resolve the prefix, + # and are present in the dynamic link paths. + gtest_ldflags="-L${libdir}" + gtest_libs="-l${name} @PTHREAD_CFLAGS@ @PTHREAD_LIBS@" + gtest_cppflags="-I${includedir}" + gtest_cxxflags="@PTHREAD_CFLAGS@" +fi + +# Do an installation query if requested. +if test -n "$do_query"; then + case $do_query in + prefix) echo $prefix; exit 0;; + exec-prefix) echo $exec_prefix; exit 0;; + libdir) echo $libdir; exit 0;; + includedir) echo $includedir; exit 0;; + version) echo $version; exit 0;; + *) show_usage; exit 1;; + esac +fi + +# Do a version check if requested. +if test "$do_check_versions" = "yes"; then + # Make sure we didn't receive a bad combination of parameters. + test "$echo_cppflags" = "yes" && show_usage && exit 1 + test "$echo_cxxflags" = "yes" && show_usage && exit 1 + test "$echo_ldflags" = "yes" && show_usage && exit 1 + test "$echo_libs" = "yes" && show_usage && exit 1 + + if test "$exact_version" != ""; then + check_versions $exact_version $exact_version + # unreachable + else + check_versions ${min_version:-0.0.0} ${max_version:-9999.9999.9999} + # unreachable + fi +fi + +# Do the output in the correct order so that these can be used in-line of +# a compiler invocation. +output="" +test "$echo_cppflags" = "yes" && output="$output $gtest_cppflags" +test "$echo_cxxflags" = "yes" && output="$output $gtest_cxxflags" +test "$echo_ldflags" = "yes" && output="$output $gtest_ldflags" +test "$echo_libs" = "yes" && output="$output $gtest_libs" +echo $output + +exit 0 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/pump.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/pump.py new file mode 100755 index 0000000000000000000000000000000000000000..5efb653c207d1f1c2aecc4d690bf732e3c1d71ab --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/pump.py @@ -0,0 +1,855 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""pump v0.2.0 - Pretty Useful for Meta Programming. + +A tool for preprocessor meta programming. Useful for generating +repetitive boilerplate code. Especially useful for writing C++ +classes, functions, macros, and templates that need to work with +various number of arguments. + +USAGE: + pump.py SOURCE_FILE + +EXAMPLES: + pump.py foo.cc.pump + Converts foo.cc.pump to foo.cc. + +GRAMMAR: + CODE ::= ATOMIC_CODE* + ATOMIC_CODE ::= $var ID = EXPRESSION + | $var ID = [[ CODE ]] + | $range ID EXPRESSION..EXPRESSION + | $for ID SEPARATOR [[ CODE ]] + | $($) + | $ID + | $(EXPRESSION) + | $if EXPRESSION [[ CODE ]] ELSE_BRANCH + | [[ CODE ]] + | RAW_CODE + SEPARATOR ::= RAW_CODE | EMPTY + ELSE_BRANCH ::= $else [[ CODE ]] + | $elif EXPRESSION [[ CODE ]] ELSE_BRANCH + | EMPTY + EXPRESSION has Python syntax. +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import re +import sys + + +TOKEN_TABLE = [ + (re.compile(r'\$var\s+'), '$var'), + (re.compile(r'\$elif\s+'), '$elif'), + (re.compile(r'\$else\s+'), '$else'), + (re.compile(r'\$for\s+'), '$for'), + (re.compile(r'\$if\s+'), '$if'), + (re.compile(r'\$range\s+'), '$range'), + (re.compile(r'\$[_A-Za-z]\w*'), '$id'), + (re.compile(r'\$\(\$\)'), '$($)'), + (re.compile(r'\$'), '$'), + (re.compile(r'\[\[\n?'), '[['), + (re.compile(r'\]\]\n?'), ']]'), + ] + + +class Cursor: + """Represents a position (line and column) in a text file.""" + + def __init__(self, line=-1, column=-1): + self.line = line + self.column = column + + def __eq__(self, rhs): + return self.line == rhs.line and self.column == rhs.column + + def __ne__(self, rhs): + return not self == rhs + + def __lt__(self, rhs): + return self.line < rhs.line or ( + self.line == rhs.line and self.column < rhs.column) + + def __le__(self, rhs): + return self < rhs or self == rhs + + def __gt__(self, rhs): + return rhs < self + + def __ge__(self, rhs): + return rhs <= self + + def __str__(self): + if self == Eof(): + return 'EOF' + else: + return '%s(%s)' % (self.line + 1, self.column) + + def __add__(self, offset): + return Cursor(self.line, self.column + offset) + + def __sub__(self, offset): + return Cursor(self.line, self.column - offset) + + def Clone(self): + """Returns a copy of self.""" + + return Cursor(self.line, self.column) + + +# Special cursor to indicate the end-of-file. +def Eof(): + """Returns the special cursor to denote the end-of-file.""" + return Cursor(-1, -1) + + +class Token: + """Represents a token in a Pump source file.""" + + def __init__(self, start=None, end=None, value=None, token_type=None): + if start is None: + self.start = Eof() + else: + self.start = start + if end is None: + self.end = Eof() + else: + self.end = end + self.value = value + self.token_type = token_type + + def __str__(self): + return 'Token @%s: \'%s\' type=%s' % ( + self.start, self.value, self.token_type) + + def Clone(self): + """Returns a copy of self.""" + + return Token(self.start.Clone(), self.end.Clone(), self.value, + self.token_type) + + +def StartsWith(lines, pos, string): + """Returns True iff the given position in lines starts with 'string'.""" + + return lines[pos.line][pos.column:].startswith(string) + + +def FindFirstInLine(line, token_table): + best_match_start = -1 + for (regex, token_type) in token_table: + m = regex.search(line) + if m: + # We found regex in lines + if best_match_start < 0 or m.start() < best_match_start: + best_match_start = m.start() + best_match_length = m.end() - m.start() + best_match_token_type = token_type + + if best_match_start < 0: + return None + + return (best_match_start, best_match_length, best_match_token_type) + + +def FindFirst(lines, token_table, cursor): + """Finds the first occurrence of any string in strings in lines.""" + + start = cursor.Clone() + cur_line_number = cursor.line + for line in lines[start.line:]: + if cur_line_number == start.line: + line = line[start.column:] + m = FindFirstInLine(line, token_table) + if m: + # We found a regex in line. + (start_column, length, token_type) = m + if cur_line_number == start.line: + start_column += start.column + found_start = Cursor(cur_line_number, start_column) + found_end = found_start + length + return MakeToken(lines, found_start, found_end, token_type) + cur_line_number += 1 + # We failed to find str in lines + return None + + +def SubString(lines, start, end): + """Returns a substring in lines.""" + + if end == Eof(): + end = Cursor(len(lines) - 1, len(lines[-1])) + + if start >= end: + return '' + + if start.line == end.line: + return lines[start.line][start.column:end.column] + + result_lines = ([lines[start.line][start.column:]] + + lines[start.line + 1:end.line] + + [lines[end.line][:end.column]]) + return ''.join(result_lines) + + +def StripMetaComments(str): + """Strip meta comments from each line in the given string.""" + + # First, completely remove lines containing nothing but a meta + # comment, including the trailing \n. + str = re.sub(r'^\s*\$\$.*\n', '', str) + + # Then, remove meta comments from contentful lines. + return re.sub(r'\s*\$\$.*', '', str) + + +def MakeToken(lines, start, end, token_type): + """Creates a new instance of Token.""" + + return Token(start, end, SubString(lines, start, end), token_type) + + +def ParseToken(lines, pos, regex, token_type): + line = lines[pos.line][pos.column:] + m = regex.search(line) + if m and not m.start(): + return MakeToken(lines, pos, pos + m.end(), token_type) + else: + print 'ERROR: %s expected at %s.' % (token_type, pos) + sys.exit(1) + + +ID_REGEX = re.compile(r'[_A-Za-z]\w*') +EQ_REGEX = re.compile(r'=') +REST_OF_LINE_REGEX = re.compile(r'.*?(?=$|\$\$)') +OPTIONAL_WHITE_SPACES_REGEX = re.compile(r'\s*') +WHITE_SPACE_REGEX = re.compile(r'\s') +DOT_DOT_REGEX = re.compile(r'\.\.') + + +def Skip(lines, pos, regex): + line = lines[pos.line][pos.column:] + m = re.search(regex, line) + if m and not m.start(): + return pos + m.end() + else: + return pos + + +def SkipUntil(lines, pos, regex, token_type): + line = lines[pos.line][pos.column:] + m = re.search(regex, line) + if m: + return pos + m.start() + else: + print ('ERROR: %s expected on line %s after column %s.' % + (token_type, pos.line + 1, pos.column)) + sys.exit(1) + + +def ParseExpTokenInParens(lines, pos): + def ParseInParens(pos): + pos = Skip(lines, pos, OPTIONAL_WHITE_SPACES_REGEX) + pos = Skip(lines, pos, r'\(') + pos = Parse(pos) + pos = Skip(lines, pos, r'\)') + return pos + + def Parse(pos): + pos = SkipUntil(lines, pos, r'\(|\)', ')') + if SubString(lines, pos, pos + 1) == '(': + pos = Parse(pos + 1) + pos = Skip(lines, pos, r'\)') + return Parse(pos) + else: + return pos + + start = pos.Clone() + pos = ParseInParens(pos) + return MakeToken(lines, start, pos, 'exp') + + +def RStripNewLineFromToken(token): + if token.value.endswith('\n'): + return Token(token.start, token.end, token.value[:-1], token.token_type) + else: + return token + + +def TokenizeLines(lines, pos): + while True: + found = FindFirst(lines, TOKEN_TABLE, pos) + if not found: + yield MakeToken(lines, pos, Eof(), 'code') + return + + if found.start == pos: + prev_token = None + prev_token_rstripped = None + else: + prev_token = MakeToken(lines, pos, found.start, 'code') + prev_token_rstripped = RStripNewLineFromToken(prev_token) + + if found.token_type == '$var': + if prev_token_rstripped: + yield prev_token_rstripped + yield found + id_token = ParseToken(lines, found.end, ID_REGEX, 'id') + yield id_token + pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX) + + eq_token = ParseToken(lines, pos, EQ_REGEX, '=') + yield eq_token + pos = Skip(lines, eq_token.end, r'\s*') + + if SubString(lines, pos, pos + 2) != '[[': + exp_token = ParseToken(lines, pos, REST_OF_LINE_REGEX, 'exp') + yield exp_token + pos = Cursor(exp_token.end.line + 1, 0) + elif found.token_type == '$for': + if prev_token_rstripped: + yield prev_token_rstripped + yield found + id_token = ParseToken(lines, found.end, ID_REGEX, 'id') + yield id_token + pos = Skip(lines, id_token.end, WHITE_SPACE_REGEX) + elif found.token_type == '$range': + if prev_token_rstripped: + yield prev_token_rstripped + yield found + id_token = ParseToken(lines, found.end, ID_REGEX, 'id') + yield id_token + pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX) + + dots_pos = SkipUntil(lines, pos, DOT_DOT_REGEX, '..') + yield MakeToken(lines, pos, dots_pos, 'exp') + yield MakeToken(lines, dots_pos, dots_pos + 2, '..') + pos = dots_pos + 2 + new_pos = Cursor(pos.line + 1, 0) + yield MakeToken(lines, pos, new_pos, 'exp') + pos = new_pos + elif found.token_type == '$': + if prev_token: + yield prev_token + yield found + exp_token = ParseExpTokenInParens(lines, found.end) + yield exp_token + pos = exp_token.end + elif (found.token_type == ']]' or found.token_type == '$if' or + found.token_type == '$elif' or found.token_type == '$else'): + if prev_token_rstripped: + yield prev_token_rstripped + yield found + pos = found.end + else: + if prev_token: + yield prev_token + yield found + pos = found.end + + +def Tokenize(s): + """A generator that yields the tokens in the given string.""" + if s != '': + lines = s.splitlines(True) + for token in TokenizeLines(lines, Cursor(0, 0)): + yield token + + +class CodeNode: + def __init__(self, atomic_code_list=None): + self.atomic_code = atomic_code_list + + +class VarNode: + def __init__(self, identifier=None, atomic_code=None): + self.identifier = identifier + self.atomic_code = atomic_code + + +class RangeNode: + def __init__(self, identifier=None, exp1=None, exp2=None): + self.identifier = identifier + self.exp1 = exp1 + self.exp2 = exp2 + + +class ForNode: + def __init__(self, identifier=None, sep=None, code=None): + self.identifier = identifier + self.sep = sep + self.code = code + + +class ElseNode: + def __init__(self, else_branch=None): + self.else_branch = else_branch + + +class IfNode: + def __init__(self, exp=None, then_branch=None, else_branch=None): + self.exp = exp + self.then_branch = then_branch + self.else_branch = else_branch + + +class RawCodeNode: + def __init__(self, token=None): + self.raw_code = token + + +class LiteralDollarNode: + def __init__(self, token): + self.token = token + + +class ExpNode: + def __init__(self, token, python_exp): + self.token = token + self.python_exp = python_exp + + +def PopFront(a_list): + head = a_list[0] + a_list[:1] = [] + return head + + +def PushFront(a_list, elem): + a_list[:0] = [elem] + + +def PopToken(a_list, token_type=None): + token = PopFront(a_list) + if token_type is not None and token.token_type != token_type: + print 'ERROR: %s expected at %s' % (token_type, token.start) + print 'ERROR: %s found instead' % (token,) + sys.exit(1) + + return token + + +def PeekToken(a_list): + if not a_list: + return None + + return a_list[0] + + +def ParseExpNode(token): + python_exp = re.sub(r'([_A-Za-z]\w*)', r'self.GetValue("\1")', token.value) + return ExpNode(token, python_exp) + + +def ParseElseNode(tokens): + def Pop(token_type=None): + return PopToken(tokens, token_type) + + next = PeekToken(tokens) + if not next: + return None + if next.token_type == '$else': + Pop('$else') + Pop('[[') + code_node = ParseCodeNode(tokens) + Pop(']]') + return code_node + elif next.token_type == '$elif': + Pop('$elif') + exp = Pop('code') + Pop('[[') + code_node = ParseCodeNode(tokens) + Pop(']]') + inner_else_node = ParseElseNode(tokens) + return CodeNode([IfNode(ParseExpNode(exp), code_node, inner_else_node)]) + elif not next.value.strip(): + Pop('code') + return ParseElseNode(tokens) + else: + return None + + +def ParseAtomicCodeNode(tokens): + def Pop(token_type=None): + return PopToken(tokens, token_type) + + head = PopFront(tokens) + t = head.token_type + if t == 'code': + return RawCodeNode(head) + elif t == '$var': + id_token = Pop('id') + Pop('=') + next = PeekToken(tokens) + if next.token_type == 'exp': + exp_token = Pop() + return VarNode(id_token, ParseExpNode(exp_token)) + Pop('[[') + code_node = ParseCodeNode(tokens) + Pop(']]') + return VarNode(id_token, code_node) + elif t == '$for': + id_token = Pop('id') + next_token = PeekToken(tokens) + if next_token.token_type == 'code': + sep_token = next_token + Pop('code') + else: + sep_token = None + Pop('[[') + code_node = ParseCodeNode(tokens) + Pop(']]') + return ForNode(id_token, sep_token, code_node) + elif t == '$if': + exp_token = Pop('code') + Pop('[[') + code_node = ParseCodeNode(tokens) + Pop(']]') + else_node = ParseElseNode(tokens) + return IfNode(ParseExpNode(exp_token), code_node, else_node) + elif t == '$range': + id_token = Pop('id') + exp1_token = Pop('exp') + Pop('..') + exp2_token = Pop('exp') + return RangeNode(id_token, ParseExpNode(exp1_token), + ParseExpNode(exp2_token)) + elif t == '$id': + return ParseExpNode(Token(head.start + 1, head.end, head.value[1:], 'id')) + elif t == '$($)': + return LiteralDollarNode(head) + elif t == '$': + exp_token = Pop('exp') + return ParseExpNode(exp_token) + elif t == '[[': + code_node = ParseCodeNode(tokens) + Pop(']]') + return code_node + else: + PushFront(tokens, head) + return None + + +def ParseCodeNode(tokens): + atomic_code_list = [] + while True: + if not tokens: + break + atomic_code_node = ParseAtomicCodeNode(tokens) + if atomic_code_node: + atomic_code_list.append(atomic_code_node) + else: + break + return CodeNode(atomic_code_list) + + +def ParseToAST(pump_src_text): + """Convert the given Pump source text into an AST.""" + tokens = list(Tokenize(pump_src_text)) + code_node = ParseCodeNode(tokens) + return code_node + + +class Env: + def __init__(self): + self.variables = [] + self.ranges = [] + + def Clone(self): + clone = Env() + clone.variables = self.variables[:] + clone.ranges = self.ranges[:] + return clone + + def PushVariable(self, var, value): + # If value looks like an int, store it as an int. + try: + int_value = int(value) + if ('%s' % int_value) == value: + value = int_value + except Exception: + pass + self.variables[:0] = [(var, value)] + + def PopVariable(self): + self.variables[:1] = [] + + def PushRange(self, var, lower, upper): + self.ranges[:0] = [(var, lower, upper)] + + def PopRange(self): + self.ranges[:1] = [] + + def GetValue(self, identifier): + for (var, value) in self.variables: + if identifier == var: + return value + + print 'ERROR: meta variable %s is undefined.' % (identifier,) + sys.exit(1) + + def EvalExp(self, exp): + try: + result = eval(exp.python_exp) + except Exception, e: + print 'ERROR: caught exception %s: %s' % (e.__class__.__name__, e) + print ('ERROR: failed to evaluate meta expression %s at %s' % + (exp.python_exp, exp.token.start)) + sys.exit(1) + return result + + def GetRange(self, identifier): + for (var, lower, upper) in self.ranges: + if identifier == var: + return (lower, upper) + + print 'ERROR: range %s is undefined.' % (identifier,) + sys.exit(1) + + +class Output: + def __init__(self): + self.string = '' + + def GetLastLine(self): + index = self.string.rfind('\n') + if index < 0: + return '' + + return self.string[index + 1:] + + def Append(self, s): + self.string += s + + +def RunAtomicCode(env, node, output): + if isinstance(node, VarNode): + identifier = node.identifier.value.strip() + result = Output() + RunAtomicCode(env.Clone(), node.atomic_code, result) + value = result.string + env.PushVariable(identifier, value) + elif isinstance(node, RangeNode): + identifier = node.identifier.value.strip() + lower = int(env.EvalExp(node.exp1)) + upper = int(env.EvalExp(node.exp2)) + env.PushRange(identifier, lower, upper) + elif isinstance(node, ForNode): + identifier = node.identifier.value.strip() + if node.sep is None: + sep = '' + else: + sep = node.sep.value + (lower, upper) = env.GetRange(identifier) + for i in range(lower, upper + 1): + new_env = env.Clone() + new_env.PushVariable(identifier, i) + RunCode(new_env, node.code, output) + if i != upper: + output.Append(sep) + elif isinstance(node, RawCodeNode): + output.Append(node.raw_code.value) + elif isinstance(node, IfNode): + cond = env.EvalExp(node.exp) + if cond: + RunCode(env.Clone(), node.then_branch, output) + elif node.else_branch is not None: + RunCode(env.Clone(), node.else_branch, output) + elif isinstance(node, ExpNode): + value = env.EvalExp(node) + output.Append('%s' % (value,)) + elif isinstance(node, LiteralDollarNode): + output.Append('$') + elif isinstance(node, CodeNode): + RunCode(env.Clone(), node, output) + else: + print 'BAD' + print node + sys.exit(1) + + +def RunCode(env, code_node, output): + for atomic_code in code_node.atomic_code: + RunAtomicCode(env, atomic_code, output) + + +def IsSingleLineComment(cur_line): + return '//' in cur_line + + +def IsInPreprocessorDirective(prev_lines, cur_line): + if cur_line.lstrip().startswith('#'): + return True + return prev_lines and prev_lines[-1].endswith('\\') + + +def WrapComment(line, output): + loc = line.find('//') + before_comment = line[:loc].rstrip() + if before_comment == '': + indent = loc + else: + output.append(before_comment) + indent = len(before_comment) - len(before_comment.lstrip()) + prefix = indent*' ' + '// ' + max_len = 80 - len(prefix) + comment = line[loc + 2:].strip() + segs = [seg for seg in re.split(r'(\w+\W*)', comment) if seg != ''] + cur_line = '' + for seg in segs: + if len((cur_line + seg).rstrip()) < max_len: + cur_line += seg + else: + if cur_line.strip() != '': + output.append(prefix + cur_line.rstrip()) + cur_line = seg.lstrip() + if cur_line.strip() != '': + output.append(prefix + cur_line.strip()) + + +def WrapCode(line, line_concat, output): + indent = len(line) - len(line.lstrip()) + prefix = indent*' ' # Prefix of the current line + max_len = 80 - indent - len(line_concat) # Maximum length of the current line + new_prefix = prefix + 4*' ' # Prefix of a continuation line + new_max_len = max_len - 4 # Maximum length of a continuation line + # Prefers to wrap a line after a ',' or ';'. + segs = [seg for seg in re.split(r'([^,;]+[,;]?)', line.strip()) if seg != ''] + cur_line = '' # The current line without leading spaces. + for seg in segs: + # If the line is still too long, wrap at a space. + while cur_line == '' and len(seg.strip()) > max_len: + seg = seg.lstrip() + split_at = seg.rfind(' ', 0, max_len) + output.append(prefix + seg[:split_at].strip() + line_concat) + seg = seg[split_at + 1:] + prefix = new_prefix + max_len = new_max_len + + if len((cur_line + seg).rstrip()) < max_len: + cur_line = (cur_line + seg).lstrip() + else: + output.append(prefix + cur_line.rstrip() + line_concat) + prefix = new_prefix + max_len = new_max_len + cur_line = seg.lstrip() + if cur_line.strip() != '': + output.append(prefix + cur_line.strip()) + + +def WrapPreprocessorDirective(line, output): + WrapCode(line, ' \\', output) + + +def WrapPlainCode(line, output): + WrapCode(line, '', output) + + +def IsMultiLineIWYUPragma(line): + return re.search(r'/\* IWYU pragma: ', line) + + +def IsHeaderGuardIncludeOrOneLineIWYUPragma(line): + return (re.match(r'^#(ifndef|define|endif\s*//)\s*[\w_]+\s*$', line) or + re.match(r'^#include\s', line) or + # Don't break IWYU pragmas, either; that causes iwyu.py problems. + re.search(r'// IWYU pragma: ', line)) + + +def WrapLongLine(line, output): + line = line.rstrip() + if len(line) <= 80: + output.append(line) + elif IsSingleLineComment(line): + if IsHeaderGuardIncludeOrOneLineIWYUPragma(line): + # The style guide made an exception to allow long header guard lines, + # includes and IWYU pragmas. + output.append(line) + else: + WrapComment(line, output) + elif IsInPreprocessorDirective(output, line): + if IsHeaderGuardIncludeOrOneLineIWYUPragma(line): + # The style guide made an exception to allow long header guard lines, + # includes and IWYU pragmas. + output.append(line) + else: + WrapPreprocessorDirective(line, output) + elif IsMultiLineIWYUPragma(line): + output.append(line) + else: + WrapPlainCode(line, output) + + +def BeautifyCode(string): + lines = string.splitlines() + output = [] + for line in lines: + WrapLongLine(line, output) + output2 = [line.rstrip() for line in output] + return '\n'.join(output2) + '\n' + + +def ConvertFromPumpSource(src_text): + """Return the text generated from the given Pump source text.""" + ast = ParseToAST(StripMetaComments(src_text)) + output = Output() + RunCode(Env(), ast, output) + return BeautifyCode(output.string) + + +def main(argv): + if len(argv) == 1: + print __doc__ + sys.exit(1) + + file_path = argv[-1] + output_str = ConvertFromPumpSource(file(file_path, 'r').read()) + if file_path.endswith('.pump'): + output_file_path = file_path[:-5] + else: + output_file_path = '-' + if output_file_path == '-': + print output_str, + else: + output_file = file(output_file_path, 'w') + output_file.write('// This file was GENERATED by command:\n') + output_file.write('// %s %s\n' % + (os.path.basename(__file__), os.path.basename(file_path))) + output_file.write('// DO NOT EDIT BY HAND!!!\n\n') + output_file.write(output_str) + output_file.close() + + +if __name__ == '__main__': + main(sys.argv) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/release_docs.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/release_docs.py new file mode 100755 index 0000000000000000000000000000000000000000..1291347f674afd7af849615a75b138d5293f9cf4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/release_docs.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# +# Copyright 2013 Google Inc. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Script for branching Google Test/Mock wiki pages for a new version. + +SYNOPSIS + release_docs.py NEW_RELEASE_VERSION + + Google Test and Google Mock's external user documentation is in + interlinked wiki files. When we release a new version of + Google Test or Google Mock, we need to branch the wiki files + such that users of a specific version of Google Test/Mock can + look up documenation relevant for that version. This script + automates that process by: + + - branching the current wiki pages (which document the + behavior of the SVN trunk head) to pages for the specified + version (e.g. branching FAQ.wiki to V2_6_FAQ.wiki when + NEW_RELEASE_VERSION is 2.6); + - updating the links in the branched files to point to the branched + version (e.g. a link in V2_6_FAQ.wiki that pointed to + Primer.wiki#Anchor will now point to V2_6_Primer.wiki#Anchor). + + NOTE: NEW_RELEASE_VERSION must be a NEW version number for + which the wiki pages don't yet exist; otherwise you'll get SVN + errors like "svn: Path 'V1_7_PumpManual.wiki' is not a + directory" when running the script. + +EXAMPLE + $ cd PATH/TO/GTEST_SVN_WORKSPACE/trunk + $ scripts/release_docs.py 2.6 # create wiki pages for v2.6 + $ svn status # verify the file list + $ svn diff # verify the file contents + $ svn commit -m "release wiki pages for v2.6" +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import re +import sys + +import common + + +# Wiki pages that shouldn't be branched for every gtest/gmock release. +GTEST_UNVERSIONED_WIKIS = ['DevGuide.wiki'] +GMOCK_UNVERSIONED_WIKIS = [ + 'DesignDoc.wiki', + 'DevGuide.wiki', + 'KnownIssues.wiki' + ] + + +def DropWikiSuffix(wiki_filename): + """Removes the .wiki suffix (if any) from the given filename.""" + + return (wiki_filename[:-len('.wiki')] if wiki_filename.endswith('.wiki') + else wiki_filename) + + +class WikiBrancher(object): + """Branches ...""" + + def __init__(self, dot_version): + self.project, svn_root_path = common.GetSvnInfo() + if self.project not in ('googletest', 'googlemock'): + sys.exit('This script must be run in a gtest or gmock SVN workspace.') + self.wiki_dir = svn_root_path + '/wiki' + # Turn '2.6' to 'V2_6_'. + self.version_prefix = 'V' + dot_version.replace('.', '_') + '_' + self.files_to_branch = self.GetFilesToBranch() + page_names = [DropWikiSuffix(f) for f in self.files_to_branch] + # A link to Foo.wiki is in one of the following forms: + # [Foo words] + # [Foo#Anchor words] + # [http://code.google.com/.../wiki/Foo words] + # [http://code.google.com/.../wiki/Foo#Anchor words] + # We want to replace 'Foo' with 'V2_6_Foo' in the above cases. + self.search_for_re = re.compile( + # This regex matches either + # [Foo + # or + # /wiki/Foo + # followed by a space or a #, where Foo is the name of an + # unversioned wiki page. + r'(\[|/wiki/)(%s)([ #])' % '|'.join(page_names)) + self.replace_with = r'\1%s\2\3' % (self.version_prefix,) + + def GetFilesToBranch(self): + """Returns a list of .wiki file names that need to be branched.""" + + unversioned_wikis = (GTEST_UNVERSIONED_WIKIS if self.project == 'googletest' + else GMOCK_UNVERSIONED_WIKIS) + return [f for f in os.listdir(self.wiki_dir) + if (f.endswith('.wiki') and + not re.match(r'^V\d', f) and # Excluded versioned .wiki files. + f not in unversioned_wikis)] + + def BranchFiles(self): + """Branches the .wiki files needed to be branched.""" + + print 'Branching %d .wiki files:' % (len(self.files_to_branch),) + os.chdir(self.wiki_dir) + for f in self.files_to_branch: + command = 'svn cp %s %s%s' % (f, self.version_prefix, f) + print command + os.system(command) + + def UpdateLinksInBranchedFiles(self): + + for f in self.files_to_branch: + source_file = os.path.join(self.wiki_dir, f) + versioned_file = os.path.join(self.wiki_dir, self.version_prefix + f) + print 'Updating links in %s.' % (versioned_file,) + text = file(source_file, 'r').read() + new_text = self.search_for_re.sub(self.replace_with, text) + file(versioned_file, 'w').write(new_text) + + +def main(): + if len(sys.argv) != 2: + sys.exit(__doc__) + + brancher = WikiBrancher(sys.argv[1]) + brancher.BranchFiles() + brancher.UpdateLinksInBranchedFiles() + + +if __name__ == '__main__': + main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/test/Makefile b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/test/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cdff584637b7a6e9df1fa43ce8f588c43815e561 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/test/Makefile @@ -0,0 +1,59 @@ +# A Makefile for fusing Google Test and building a sample test against it. +# +# SYNOPSIS: +# +# make [all] - makes everything. +# make TARGET - makes the given target. +# make check - makes everything and runs the built sample test. +# make clean - removes all files generated by make. + +# Points to the root of fused Google Test, relative to where this file is. +FUSED_GTEST_DIR = output + +# Paths to the fused gtest files. +FUSED_GTEST_H = $(FUSED_GTEST_DIR)/gtest/gtest.h +FUSED_GTEST_ALL_CC = $(FUSED_GTEST_DIR)/gtest/gtest-all.cc + +# Where to find the sample test. +SAMPLE_DIR = ../../samples + +# Where to find gtest_main.cc. +GTEST_MAIN_CC = ../../src/gtest_main.cc + +# Flags passed to the preprocessor. +# We have no idea here whether pthreads is available in the system, so +# disable its use. +CPPFLAGS += -I$(FUSED_GTEST_DIR) -DGTEST_HAS_PTHREAD=0 + +# Flags passed to the C++ compiler. +CXXFLAGS += -g + +all : sample1_unittest + +check : all + ./sample1_unittest + +clean : + rm -rf $(FUSED_GTEST_DIR) sample1_unittest *.o + +$(FUSED_GTEST_H) : + ../fuse_gtest_files.py $(FUSED_GTEST_DIR) + +$(FUSED_GTEST_ALL_CC) : + ../fuse_gtest_files.py $(FUSED_GTEST_DIR) + +gtest-all.o : $(FUSED_GTEST_H) $(FUSED_GTEST_ALL_CC) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(FUSED_GTEST_DIR)/gtest/gtest-all.cc + +gtest_main.o : $(FUSED_GTEST_H) $(GTEST_MAIN_CC) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_MAIN_CC) + +sample1.o : $(SAMPLE_DIR)/sample1.cc $(SAMPLE_DIR)/sample1.h + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1.cc + +sample1_unittest.o : $(SAMPLE_DIR)/sample1_unittest.cc \ + $(SAMPLE_DIR)/sample1.h $(FUSED_GTEST_H) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1_unittest.cc + +sample1_unittest : sample1.o sample1_unittest.o gtest-all.o gtest_main.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/upload.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/upload.py new file mode 100755 index 0000000000000000000000000000000000000000..c852e4c91e06ef7c49e038683509ffd9495c820f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/upload.py @@ -0,0 +1,1387 @@ +#!/usr/bin/env python +# +# Copyright 2007 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tool for uploading diffs from a version control system to the codereview app. + +Usage summary: upload.py [options] [-- diff_options] + +Diff options are passed to the diff command of the underlying system. + +Supported version control systems: + Git + Mercurial + Subversion + +It is important for Git/Mercurial users to specify a tree/node/branch to diff +against by using the '--rev' option. +""" +# This code is derived from appcfg.py in the App Engine SDK (open source), +# and from ASPN recipe #146306. + +import cookielib +import getpass +import logging +import md5 +import mimetypes +import optparse +import os +import re +import socket +import subprocess +import sys +import urllib +import urllib2 +import urlparse + +try: + import readline +except ImportError: + pass + +# The logging verbosity: +# 0: Errors only. +# 1: Status messages. +# 2: Info logs. +# 3: Debug logs. +verbosity = 1 + +# Max size of patch or base file. +MAX_UPLOAD_SIZE = 900 * 1024 + + +def GetEmail(prompt): + """Prompts the user for their email address and returns it. + + The last used email address is saved to a file and offered up as a suggestion + to the user. If the user presses enter without typing in anything the last + used email address is used. If the user enters a new address, it is saved + for next time we prompt. + + """ + last_email_file_name = os.path.expanduser("~/.last_codereview_email_address") + last_email = "" + if os.path.exists(last_email_file_name): + try: + last_email_file = open(last_email_file_name, "r") + last_email = last_email_file.readline().strip("\n") + last_email_file.close() + prompt += " [%s]" % last_email + except IOError, e: + pass + email = raw_input(prompt + ": ").strip() + if email: + try: + last_email_file = open(last_email_file_name, "w") + last_email_file.write(email) + last_email_file.close() + except IOError, e: + pass + else: + email = last_email + return email + + +def StatusUpdate(msg): + """Print a status message to stdout. + + If 'verbosity' is greater than 0, print the message. + + Args: + msg: The string to print. + """ + if verbosity > 0: + print msg + + +def ErrorExit(msg): + """Print an error message to stderr and exit.""" + print >>sys.stderr, msg + sys.exit(1) + + +class ClientLoginError(urllib2.HTTPError): + """Raised to indicate there was an error authenticating with ClientLogin.""" + + def __init__(self, url, code, msg, headers, args): + urllib2.HTTPError.__init__(self, url, code, msg, headers, None) + self.args = args + self.reason = args["Error"] + + +class AbstractRpcServer(object): + """Provides a common interface for a simple RPC server.""" + + def __init__(self, host, auth_function, host_override=None, extra_headers={}, + save_cookies=False): + """Creates a new HttpRpcServer. + + Args: + host: The host to send requests to. + auth_function: A function that takes no arguments and returns an + (email, password) tuple when called. Will be called if authentication + is required. + host_override: The host header to send to the server (defaults to host). + extra_headers: A dict of extra headers to append to every request. + save_cookies: If True, save the authentication cookies to local disk. + If False, use an in-memory cookiejar instead. Subclasses must + implement this functionality. Defaults to False. + """ + self.host = host + self.host_override = host_override + self.auth_function = auth_function + self.authenticated = False + self.extra_headers = extra_headers + self.save_cookies = save_cookies + self.opener = self._GetOpener() + if self.host_override: + logging.info("Server: %s; Host: %s", self.host, self.host_override) + else: + logging.info("Server: %s", self.host) + + def _GetOpener(self): + """Returns an OpenerDirector for making HTTP requests. + + Returns: + A urllib2.OpenerDirector object. + """ + raise NotImplementedError() + + def _CreateRequest(self, url, data=None): + """Creates a new urllib request.""" + logging.debug("Creating request for: '%s' with payload:\n%s", url, data) + req = urllib2.Request(url, data=data) + if self.host_override: + req.add_header("Host", self.host_override) + for key, value in self.extra_headers.iteritems(): + req.add_header(key, value) + return req + + def _GetAuthToken(self, email, password): + """Uses ClientLogin to authenticate the user, returning an auth token. + + Args: + email: The user's email address + password: The user's password + + Raises: + ClientLoginError: If there was an error authenticating with ClientLogin. + HTTPError: If there was some other form of HTTP error. + + Returns: + The authentication token returned by ClientLogin. + """ + account_type = "GOOGLE" + if self.host.endswith(".google.com"): + # Needed for use inside Google. + account_type = "HOSTED" + req = self._CreateRequest( + url="https://www.google.com/accounts/ClientLogin", + data=urllib.urlencode({ + "Email": email, + "Passwd": password, + "service": "ah", + "source": "rietveld-codereview-upload", + "accountType": account_type, + }), + ) + try: + response = self.opener.open(req) + response_body = response.read() + response_dict = dict(x.split("=") + for x in response_body.split("\n") if x) + return response_dict["Auth"] + except urllib2.HTTPError, e: + if e.code == 403: + body = e.read() + response_dict = dict(x.split("=", 1) for x in body.split("\n") if x) + raise ClientLoginError(req.get_full_url(), e.code, e.msg, + e.headers, response_dict) + else: + raise + + def _GetAuthCookie(self, auth_token): + """Fetches authentication cookies for an authentication token. + + Args: + auth_token: The authentication token returned by ClientLogin. + + Raises: + HTTPError: If there was an error fetching the authentication cookies. + """ + # This is a dummy value to allow us to identify when we're successful. + continue_location = "http://localhost/" + args = {"continue": continue_location, "auth": auth_token} + req = self._CreateRequest("http://%s/_ah/login?%s" % + (self.host, urllib.urlencode(args))) + try: + response = self.opener.open(req) + except urllib2.HTTPError, e: + response = e + if (response.code != 302 or + response.info()["location"] != continue_location): + raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg, + response.headers, response.fp) + self.authenticated = True + + def _Authenticate(self): + """Authenticates the user. + + The authentication process works as follows: + 1) We get a username and password from the user + 2) We use ClientLogin to obtain an AUTH token for the user + (see https://developers.google.com/identity/protocols/AuthForInstalledApps). + 3) We pass the auth token to /_ah/login on the server to obtain an + authentication cookie. If login was successful, it tries to redirect + us to the URL we provided. + + If we attempt to access the upload API without first obtaining an + authentication cookie, it returns a 401 response and directs us to + authenticate ourselves with ClientLogin. + """ + for i in range(3): + credentials = self.auth_function() + try: + auth_token = self._GetAuthToken(credentials[0], credentials[1]) + except ClientLoginError, e: + if e.reason == "BadAuthentication": + print >>sys.stderr, "Invalid username or password." + continue + if e.reason == "CaptchaRequired": + print >>sys.stderr, ( + "Please go to\n" + "https://www.google.com/accounts/DisplayUnlockCaptcha\n" + "and verify you are a human. Then try again.") + break + if e.reason == "NotVerified": + print >>sys.stderr, "Account not verified." + break + if e.reason == "TermsNotAgreed": + print >>sys.stderr, "User has not agreed to TOS." + break + if e.reason == "AccountDeleted": + print >>sys.stderr, "The user account has been deleted." + break + if e.reason == "AccountDisabled": + print >>sys.stderr, "The user account has been disabled." + break + if e.reason == "ServiceDisabled": + print >>sys.stderr, ("The user's access to the service has been " + "disabled.") + break + if e.reason == "ServiceUnavailable": + print >>sys.stderr, "The service is not available; try again later." + break + raise + self._GetAuthCookie(auth_token) + return + + def Send(self, request_path, payload=None, + content_type="application/octet-stream", + timeout=None, + **kwargs): + """Sends an RPC and returns the response. + + Args: + request_path: The path to send the request to, eg /api/appversion/create. + payload: The body of the request, or None to send an empty request. + content_type: The Content-Type header to use. + timeout: timeout in seconds; default None i.e. no timeout. + (Note: for large requests on OS X, the timeout doesn't work right.) + kwargs: Any keyword arguments are converted into query string parameters. + + Returns: + The response body, as a string. + """ + # TODO: Don't require authentication. Let the server say + # whether it is necessary. + if not self.authenticated: + self._Authenticate() + + old_timeout = socket.getdefaulttimeout() + socket.setdefaulttimeout(timeout) + try: + tries = 0 + while True: + tries += 1 + args = dict(kwargs) + url = "http://%s%s" % (self.host, request_path) + if args: + url += "?" + urllib.urlencode(args) + req = self._CreateRequest(url=url, data=payload) + req.add_header("Content-Type", content_type) + try: + f = self.opener.open(req) + response = f.read() + f.close() + return response + except urllib2.HTTPError, e: + if tries > 3: + raise + elif e.code == 401: + self._Authenticate() +## elif e.code >= 500 and e.code < 600: +## # Server Error - try again. +## continue + else: + raise + finally: + socket.setdefaulttimeout(old_timeout) + + +class HttpRpcServer(AbstractRpcServer): + """Provides a simplified RPC-style interface for HTTP requests.""" + + def _Authenticate(self): + """Save the cookie jar after authentication.""" + super(HttpRpcServer, self)._Authenticate() + if self.save_cookies: + StatusUpdate("Saving authentication cookies to %s" % self.cookie_file) + self.cookie_jar.save() + + def _GetOpener(self): + """Returns an OpenerDirector that supports cookies and ignores redirects. + + Returns: + A urllib2.OpenerDirector object. + """ + opener = urllib2.OpenerDirector() + opener.add_handler(urllib2.ProxyHandler()) + opener.add_handler(urllib2.UnknownHandler()) + opener.add_handler(urllib2.HTTPHandler()) + opener.add_handler(urllib2.HTTPDefaultErrorHandler()) + opener.add_handler(urllib2.HTTPSHandler()) + opener.add_handler(urllib2.HTTPErrorProcessor()) + if self.save_cookies: + self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies") + self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file) + if os.path.exists(self.cookie_file): + try: + self.cookie_jar.load() + self.authenticated = True + StatusUpdate("Loaded authentication cookies from %s" % + self.cookie_file) + except (cookielib.LoadError, IOError): + # Failed to load cookies - just ignore them. + pass + else: + # Create an empty cookie file with mode 600 + fd = os.open(self.cookie_file, os.O_CREAT, 0600) + os.close(fd) + # Always chmod the cookie file + os.chmod(self.cookie_file, 0600) + else: + # Don't save cookies across runs of update.py. + self.cookie_jar = cookielib.CookieJar() + opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar)) + return opener + + +parser = optparse.OptionParser(usage="%prog [options] [-- diff_options]") +parser.add_option("-y", "--assume_yes", action="store_true", + dest="assume_yes", default=False, + help="Assume that the answer to yes/no questions is 'yes'.") +# Logging +group = parser.add_option_group("Logging options") +group.add_option("-q", "--quiet", action="store_const", const=0, + dest="verbose", help="Print errors only.") +group.add_option("-v", "--verbose", action="store_const", const=2, + dest="verbose", default=1, + help="Print info level logs (default).") +group.add_option("--noisy", action="store_const", const=3, + dest="verbose", help="Print all logs.") +# Review server +group = parser.add_option_group("Review server options") +group.add_option("-s", "--server", action="store", dest="server", + default="codereview.appspot.com", + metavar="SERVER", + help=("The server to upload to. The format is host[:port]. " + "Defaults to 'codereview.appspot.com'.")) +group.add_option("-e", "--email", action="store", dest="email", + metavar="EMAIL", default=None, + help="The username to use. Will prompt if omitted.") +group.add_option("-H", "--host", action="store", dest="host", + metavar="HOST", default=None, + help="Overrides the Host header sent with all RPCs.") +group.add_option("--no_cookies", action="store_false", + dest="save_cookies", default=True, + help="Do not save authentication cookies to local disk.") +# Issue +group = parser.add_option_group("Issue options") +group.add_option("-d", "--description", action="store", dest="description", + metavar="DESCRIPTION", default=None, + help="Optional description when creating an issue.") +group.add_option("-f", "--description_file", action="store", + dest="description_file", metavar="DESCRIPTION_FILE", + default=None, + help="Optional path of a file that contains " + "the description when creating an issue.") +group.add_option("-r", "--reviewers", action="store", dest="reviewers", + metavar="REVIEWERS", default=None, + help="Add reviewers (comma separated email addresses).") +group.add_option("--cc", action="store", dest="cc", + metavar="CC", default=None, + help="Add CC (comma separated email addresses).") +# Upload options +group = parser.add_option_group("Patch options") +group.add_option("-m", "--message", action="store", dest="message", + metavar="MESSAGE", default=None, + help="A message to identify the patch. " + "Will prompt if omitted.") +group.add_option("-i", "--issue", type="int", action="store", + metavar="ISSUE", default=None, + help="Issue number to which to add. Defaults to new issue.") +group.add_option("--download_base", action="store_true", + dest="download_base", default=False, + help="Base files will be downloaded by the server " + "(side-by-side diffs may not work on files with CRs).") +group.add_option("--rev", action="store", dest="revision", + metavar="REV", default=None, + help="Branch/tree/revision to diff against (used by DVCS).") +group.add_option("--send_mail", action="store_true", + dest="send_mail", default=False, + help="Send notification email to reviewers.") + + +def GetRpcServer(options): + """Returns an instance of an AbstractRpcServer. + + Returns: + A new AbstractRpcServer, on which RPC calls can be made. + """ + + rpc_server_class = HttpRpcServer + + def GetUserCredentials(): + """Prompts the user for a username and password.""" + email = options.email + if email is None: + email = GetEmail("Email (login for uploading to %s)" % options.server) + password = getpass.getpass("Password for %s: " % email) + return (email, password) + + # If this is the dev_appserver, use fake authentication. + host = (options.host or options.server).lower() + if host == "localhost" or host.startswith("localhost:"): + email = options.email + if email is None: + email = "test@example.com" + logging.info("Using debug user %s. Override with --email" % email) + server = rpc_server_class( + options.server, + lambda: (email, "password"), + host_override=options.host, + extra_headers={"Cookie": + 'dev_appserver_login="%s:False"' % email}, + save_cookies=options.save_cookies) + # Don't try to talk to ClientLogin. + server.authenticated = True + return server + + return rpc_server_class(options.server, GetUserCredentials, + host_override=options.host, + save_cookies=options.save_cookies) + + +def EncodeMultipartFormData(fields, files): + """Encode form fields for multipart/form-data. + + Args: + fields: A sequence of (name, value) elements for regular form fields. + files: A sequence of (name, filename, value) elements for data to be + uploaded as files. + Returns: + (content_type, body) ready for httplib.HTTP instance. + + Source: + https://web.archive.org/web/20160116052001/code.activestate.com/recipes/146306 + """ + BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-' + CRLF = '\r\n' + lines = [] + for (key, value) in fields: + lines.append('--' + BOUNDARY) + lines.append('Content-Disposition: form-data; name="%s"' % key) + lines.append('') + lines.append(value) + for (key, filename, value) in files: + lines.append('--' + BOUNDARY) + lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' % + (key, filename)) + lines.append('Content-Type: %s' % GetContentType(filename)) + lines.append('') + lines.append(value) + lines.append('--' + BOUNDARY + '--') + lines.append('') + body = CRLF.join(lines) + content_type = 'multipart/form-data; boundary=%s' % BOUNDARY + return content_type, body + + +def GetContentType(filename): + """Helper to guess the content-type from the filename.""" + return mimetypes.guess_type(filename)[0] or 'application/octet-stream' + + +# Use a shell for subcommands on Windows to get a PATH search. +use_shell = sys.platform.startswith("win") + +def RunShellWithReturnCode(command, print_output=False, + universal_newlines=True): + """Executes a command and returns the output from stdout and the return code. + + Args: + command: Command to execute. + print_output: If True, the output is printed to stdout. + If False, both stdout and stderr are ignored. + universal_newlines: Use universal_newlines flag (default: True). + + Returns: + Tuple (output, return code) + """ + logging.info("Running %s", command) + p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + shell=use_shell, universal_newlines=universal_newlines) + if print_output: + output_array = [] + while True: + line = p.stdout.readline() + if not line: + break + print line.strip("\n") + output_array.append(line) + output = "".join(output_array) + else: + output = p.stdout.read() + p.wait() + errout = p.stderr.read() + if print_output and errout: + print >>sys.stderr, errout + p.stdout.close() + p.stderr.close() + return output, p.returncode + + +def RunShell(command, silent_ok=False, universal_newlines=True, + print_output=False): + data, retcode = RunShellWithReturnCode(command, print_output, + universal_newlines) + if retcode: + ErrorExit("Got error status from %s:\n%s" % (command, data)) + if not silent_ok and not data: + ErrorExit("No output from %s" % command) + return data + + +class VersionControlSystem(object): + """Abstract base class providing an interface to the VCS.""" + + def __init__(self, options): + """Constructor. + + Args: + options: Command line options. + """ + self.options = options + + def GenerateDiff(self, args): + """Return the current diff as a string. + + Args: + args: Extra arguments to pass to the diff command. + """ + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + def GetUnknownFiles(self): + """Return a list of files unknown to the VCS.""" + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + def CheckForUnknownFiles(self): + """Show an "are you sure?" prompt if there are unknown files.""" + unknown_files = self.GetUnknownFiles() + if unknown_files: + print "The following files are not added to version control:" + for line in unknown_files: + print line + prompt = "Are you sure to continue?(y/N) " + answer = raw_input(prompt).strip() + if answer != "y": + ErrorExit("User aborted") + + def GetBaseFile(self, filename): + """Get the content of the upstream version of a file. + + Returns: + A tuple (base_content, new_content, is_binary, status) + base_content: The contents of the base file. + new_content: For text files, this is empty. For binary files, this is + the contents of the new file, since the diff output won't contain + information to reconstruct the current file. + is_binary: True iff the file is binary. + status: The status of the file. + """ + + raise NotImplementedError( + "abstract method -- subclass %s must override" % self.__class__) + + + def GetBaseFiles(self, diff): + """Helper that calls GetBase file for each file in the patch. + + Returns: + A dictionary that maps from filename to GetBaseFile's tuple. Filenames + are retrieved based on lines that start with "Index:" or + "Property changes on:". + """ + files = {} + for line in diff.splitlines(True): + if line.startswith('Index:') or line.startswith('Property changes on:'): + unused, filename = line.split(':', 1) + # On Windows if a file has property changes its filename uses '\' + # instead of '/'. + filename = filename.strip().replace('\\', '/') + files[filename] = self.GetBaseFile(filename) + return files + + + def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options, + files): + """Uploads the base files (and if necessary, the current ones as well).""" + + def UploadFile(filename, file_id, content, is_binary, status, is_base): + """Uploads a file to the server.""" + file_too_large = False + if is_base: + type = "base" + else: + type = "current" + if len(content) > MAX_UPLOAD_SIZE: + print ("Not uploading the %s file for %s because it's too large." % + (type, filename)) + file_too_large = True + content = "" + checksum = md5.new(content).hexdigest() + if options.verbose > 0 and not file_too_large: + print "Uploading %s file for %s" % (type, filename) + url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id) + form_fields = [("filename", filename), + ("status", status), + ("checksum", checksum), + ("is_binary", str(is_binary)), + ("is_current", str(not is_base)), + ] + if file_too_large: + form_fields.append(("file_too_large", "1")) + if options.email: + form_fields.append(("user", options.email)) + ctype, body = EncodeMultipartFormData(form_fields, + [("data", filename, content)]) + response_body = rpc_server.Send(url, body, + content_type=ctype) + if not response_body.startswith("OK"): + StatusUpdate(" --> %s" % response_body) + sys.exit(1) + + patches = dict() + [patches.setdefault(v, k) for k, v in patch_list] + for filename in patches.keys(): + base_content, new_content, is_binary, status = files[filename] + file_id_str = patches.get(filename) + if file_id_str.find("nobase") != -1: + base_content = None + file_id_str = file_id_str[file_id_str.rfind("_") + 1:] + file_id = int(file_id_str) + if base_content != None: + UploadFile(filename, file_id, base_content, is_binary, status, True) + if new_content != None: + UploadFile(filename, file_id, new_content, is_binary, status, False) + + def IsImage(self, filename): + """Returns true if the filename has an image extension.""" + mimetype = mimetypes.guess_type(filename)[0] + if not mimetype: + return False + return mimetype.startswith("image/") + + +class SubversionVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Subversion.""" + + def __init__(self, options): + super(SubversionVCS, self).__init__(options) + if self.options.revision: + match = re.match(r"(\d+)(:(\d+))?", self.options.revision) + if not match: + ErrorExit("Invalid Subversion revision %s." % self.options.revision) + self.rev_start = match.group(1) + self.rev_end = match.group(3) + else: + self.rev_start = self.rev_end = None + # Cache output from "svn list -r REVNO dirname". + # Keys: dirname, Values: 2-tuple (output for start rev and end rev). + self.svnls_cache = {} + # SVN base URL is required to fetch files deleted in an older revision. + # Result is cached to not guess it over and over again in GetBaseFile(). + required = self.options.download_base or self.options.revision is not None + self.svn_base = self._GuessBase(required) + + def GuessBase(self, required): + """Wrapper for _GuessBase.""" + return self.svn_base + + def _GuessBase(self, required): + """Returns the SVN base URL. + + Args: + required: If true, exits if the url can't be guessed, otherwise None is + returned. + """ + info = RunShell(["svn", "info"]) + for line in info.splitlines(): + words = line.split() + if len(words) == 2 and words[0] == "URL:": + url = words[1] + scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) + username, netloc = urllib.splituser(netloc) + if username: + logging.info("Removed username from base URL") + if netloc.endswith("svn.python.org"): + if netloc == "svn.python.org": + if path.startswith("/projects/"): + path = path[9:] + elif netloc != "pythondev@svn.python.org": + ErrorExit("Unrecognized Python URL: %s" % url) + base = "http://svn.python.org/view/*checkout*%s/" % path + logging.info("Guessed Python base = %s", base) + elif netloc.endswith("svn.collab.net"): + if path.startswith("/repos/"): + path = path[6:] + base = "http://svn.collab.net/viewvc/*checkout*%s/" % path + logging.info("Guessed CollabNet base = %s", base) + elif netloc.endswith(".googlecode.com"): + path = path + "/" + base = urlparse.urlunparse(("http", netloc, path, params, + query, fragment)) + logging.info("Guessed Google Code base = %s", base) + else: + path = path + "/" + base = urlparse.urlunparse((scheme, netloc, path, params, + query, fragment)) + logging.info("Guessed base = %s", base) + return base + if required: + ErrorExit("Can't find URL in output from svn info") + return None + + def GenerateDiff(self, args): + cmd = ["svn", "diff"] + if self.options.revision: + cmd += ["-r", self.options.revision] + cmd.extend(args) + data = RunShell(cmd) + count = 0 + for line in data.splitlines(): + if line.startswith("Index:") or line.startswith("Property changes on:"): + count += 1 + logging.info(line) + if not count: + ErrorExit("No valid patches found in output from svn diff") + return data + + def _CollapseKeywords(self, content, keyword_str): + """Collapses SVN keywords.""" + # svn cat translates keywords but svn diff doesn't. As a result of this + # behavior patching.PatchChunks() fails with a chunk mismatch error. + # This part was originally written by the Review Board development team + # who had the same problem (https://reviews.reviewboard.org/r/276/). + # Mapping of keywords to known aliases + svn_keywords = { + # Standard keywords + 'Date': ['Date', 'LastChangedDate'], + 'Revision': ['Revision', 'LastChangedRevision', 'Rev'], + 'Author': ['Author', 'LastChangedBy'], + 'HeadURL': ['HeadURL', 'URL'], + 'Id': ['Id'], + + # Aliases + 'LastChangedDate': ['LastChangedDate', 'Date'], + 'LastChangedRevision': ['LastChangedRevision', 'Rev', 'Revision'], + 'LastChangedBy': ['LastChangedBy', 'Author'], + 'URL': ['URL', 'HeadURL'], + } + + def repl(m): + if m.group(2): + return "$%s::%s$" % (m.group(1), " " * len(m.group(3))) + return "$%s$" % m.group(1) + keywords = [keyword + for name in keyword_str.split(" ") + for keyword in svn_keywords.get(name, [])] + return re.sub(r"\$(%s):(:?)([^\$]+)\$" % '|'.join(keywords), repl, content) + + def GetUnknownFiles(self): + status = RunShell(["svn", "status", "--ignore-externals"], silent_ok=True) + unknown_files = [] + for line in status.split("\n"): + if line and line[0] == "?": + unknown_files.append(line) + return unknown_files + + def ReadFile(self, filename): + """Returns the contents of a file.""" + file = open(filename, 'rb') + result = "" + try: + result = file.read() + finally: + file.close() + return result + + def GetStatus(self, filename): + """Returns the status of a file.""" + if not self.options.revision: + status = RunShell(["svn", "status", "--ignore-externals", filename]) + if not status: + ErrorExit("svn status returned no output for %s" % filename) + status_lines = status.splitlines() + # If file is in a cl, the output will begin with + # "\n--- Changelist 'cl_name':\n". See + # https://web.archive.org/web/20090918234815/svn.collab.net/repos/svn/trunk/notes/changelist-design.txt + if (len(status_lines) == 3 and + not status_lines[0] and + status_lines[1].startswith("--- Changelist")): + status = status_lines[2] + else: + status = status_lines[0] + # If we have a revision to diff against we need to run "svn list" + # for the old and the new revision and compare the results to get + # the correct status for a file. + else: + dirname, relfilename = os.path.split(filename) + if dirname not in self.svnls_cache: + cmd = ["svn", "list", "-r", self.rev_start, dirname or "."] + out, returncode = RunShellWithReturnCode(cmd) + if returncode: + ErrorExit("Failed to get status for %s." % filename) + old_files = out.splitlines() + args = ["svn", "list"] + if self.rev_end: + args += ["-r", self.rev_end] + cmd = args + [dirname or "."] + out, returncode = RunShellWithReturnCode(cmd) + if returncode: + ErrorExit("Failed to run command %s" % cmd) + self.svnls_cache[dirname] = (old_files, out.splitlines()) + old_files, new_files = self.svnls_cache[dirname] + if relfilename in old_files and relfilename not in new_files: + status = "D " + elif relfilename in old_files and relfilename in new_files: + status = "M " + else: + status = "A " + return status + + def GetBaseFile(self, filename): + status = self.GetStatus(filename) + base_content = None + new_content = None + + # If a file is copied its status will be "A +", which signifies + # "addition-with-history". See "svn st" for more information. We need to + # upload the original file or else diff parsing will fail if the file was + # edited. + if status[0] == "A" and status[3] != "+": + # We'll need to upload the new content if we're adding a binary file + # since diff's output won't contain it. + mimetype = RunShell(["svn", "propget", "svn:mime-type", filename], + silent_ok=True) + base_content = "" + is_binary = mimetype and not mimetype.startswith("text/") + if is_binary and self.IsImage(filename): + new_content = self.ReadFile(filename) + elif (status[0] in ("M", "D", "R") or + (status[0] == "A" and status[3] == "+") or # Copied file. + (status[0] == " " and status[1] == "M")): # Property change. + args = [] + if self.options.revision: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + else: + # Don't change filename, it's needed later. + url = filename + args += ["-r", "BASE"] + cmd = ["svn"] + args + ["propget", "svn:mime-type", url] + mimetype, returncode = RunShellWithReturnCode(cmd) + if returncode: + # File does not exist in the requested revision. + # Reset mimetype, it contains an error message. + mimetype = "" + get_base = False + is_binary = mimetype and not mimetype.startswith("text/") + if status[0] == " ": + # Empty base content just to force an upload. + base_content = "" + elif is_binary: + if self.IsImage(filename): + get_base = True + if status[0] == "M": + if not self.rev_end: + new_content = self.ReadFile(filename) + else: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_end) + new_content = RunShell(["svn", "cat", url], + universal_newlines=True, silent_ok=True) + else: + base_content = "" + else: + get_base = True + + if get_base: + if is_binary: + universal_newlines = False + else: + universal_newlines = True + if self.rev_start: + # "svn cat -r REV delete_file.txt" doesn't work. cat requires + # the full URL with "@REV" appended instead of using "-r" option. + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + base_content = RunShell(["svn", "cat", url], + universal_newlines=universal_newlines, + silent_ok=True) + else: + base_content = RunShell(["svn", "cat", filename], + universal_newlines=universal_newlines, + silent_ok=True) + if not is_binary: + args = [] + if self.rev_start: + url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start) + else: + url = filename + args += ["-r", "BASE"] + cmd = ["svn"] + args + ["propget", "svn:keywords", url] + keywords, returncode = RunShellWithReturnCode(cmd) + if keywords and not returncode: + base_content = self._CollapseKeywords(base_content, keywords) + else: + StatusUpdate("svn status returned unexpected output: %s" % status) + sys.exit(1) + return base_content, new_content, is_binary, status[0:5] + + +class GitVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Git.""" + + def __init__(self, options): + super(GitVCS, self).__init__(options) + # Map of filename -> hash of base file. + self.base_hashes = {} + + def GenerateDiff(self, extra_args): + # This is more complicated than svn's GenerateDiff because we must convert + # the diff output to include an svn-style "Index:" line as well as record + # the hashes of the base files, so we can upload them along with our diff. + if self.options.revision: + extra_args = [self.options.revision] + extra_args + gitdiff = RunShell(["git", "diff", "--full-index"] + extra_args) + svndiff = [] + filecount = 0 + filename = None + for line in gitdiff.splitlines(): + match = re.match(r"diff --git a/(.*) b/.*$", line) + if match: + filecount += 1 + filename = match.group(1) + svndiff.append("Index: %s\n" % filename) + else: + # The "index" line in a git diff looks like this (long hashes elided): + # index 82c0d44..b2cee3f 100755 + # We want to save the left hash, as that identifies the base file. + match = re.match(r"index (\w+)\.\.", line) + if match: + self.base_hashes[filename] = match.group(1) + svndiff.append(line + "\n") + if not filecount: + ErrorExit("No valid patches found in output from git diff") + return "".join(svndiff) + + def GetUnknownFiles(self): + status = RunShell(["git", "ls-files", "--exclude-standard", "--others"], + silent_ok=True) + return status.splitlines() + + def GetBaseFile(self, filename): + hash = self.base_hashes[filename] + base_content = None + new_content = None + is_binary = False + if hash == "0" * 40: # All-zero hash indicates no base file. + status = "A" + base_content = "" + else: + status = "M" + base_content, returncode = RunShellWithReturnCode(["git", "show", hash]) + if returncode: + ErrorExit("Got error status from 'git show %s'" % hash) + return (base_content, new_content, is_binary, status) + + +class MercurialVCS(VersionControlSystem): + """Implementation of the VersionControlSystem interface for Mercurial.""" + + def __init__(self, options, repo_dir): + super(MercurialVCS, self).__init__(options) + # Absolute path to repository (we can be in a subdir) + self.repo_dir = os.path.normpath(repo_dir) + # Compute the subdir + cwd = os.path.normpath(os.getcwd()) + assert cwd.startswith(self.repo_dir) + self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/") + if self.options.revision: + self.base_rev = self.options.revision + else: + self.base_rev = RunShell(["hg", "parent", "-q"]).split(':')[1].strip() + + def _GetRelPath(self, filename): + """Get relative path of a file according to the current directory, + given its logical path in the repo.""" + assert filename.startswith(self.subdir), filename + return filename[len(self.subdir):].lstrip(r"\/") + + def GenerateDiff(self, extra_args): + # If no file specified, restrict to the current subdir + extra_args = extra_args or ["."] + cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args + data = RunShell(cmd, silent_ok=True) + svndiff = [] + filecount = 0 + for line in data.splitlines(): + m = re.match("diff --git a/(\S+) b/(\S+)", line) + if m: + # Modify line to make it look like as it comes from svn diff. + # With this modification no changes on the server side are required + # to make upload.py work with Mercurial repos. + # NOTE: for proper handling of moved/copied files, we have to use + # the second filename. + filename = m.group(2) + svndiff.append("Index: %s" % filename) + svndiff.append("=" * 67) + filecount += 1 + logging.info(line) + else: + svndiff.append(line) + if not filecount: + ErrorExit("No valid patches found in output from hg diff") + return "\n".join(svndiff) + "\n" + + def GetUnknownFiles(self): + """Return a list of files unknown to the VCS.""" + args = [] + status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."], + silent_ok=True) + unknown_files = [] + for line in status.splitlines(): + st, fn = line.split(" ", 1) + if st == "?": + unknown_files.append(fn) + return unknown_files + + def GetBaseFile(self, filename): + # "hg status" and "hg cat" both take a path relative to the current subdir + # rather than to the repo root, but "hg diff" has given us the full path + # to the repo root. + base_content = "" + new_content = None + is_binary = False + oldrelpath = relpath = self._GetRelPath(filename) + # "hg status -C" returns two lines for moved/copied files, one otherwise + out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath]) + out = out.splitlines() + # HACK: strip error message about missing file/directory if it isn't in + # the working copy + if out[0].startswith('%s: ' % relpath): + out = out[1:] + if len(out) > 1: + # Moved/copied => considered as modified, use old filename to + # retrieve base contents + oldrelpath = out[1].strip() + status = "M" + else: + status, _ = out[0].split(' ', 1) + if status != "A": + base_content = RunShell(["hg", "cat", "-r", self.base_rev, oldrelpath], + silent_ok=True) + is_binary = "\0" in base_content # Mercurial's heuristic + if status != "R": + new_content = open(relpath, "rb").read() + is_binary = is_binary or "\0" in new_content + if is_binary and base_content: + # Fetch again without converting newlines + base_content = RunShell(["hg", "cat", "-r", self.base_rev, oldrelpath], + silent_ok=True, universal_newlines=False) + if not is_binary or not self.IsImage(relpath): + new_content = None + return base_content, new_content, is_binary, status + + +# NOTE: The SplitPatch function is duplicated in engine.py, keep them in sync. +def SplitPatch(data): + """Splits a patch into separate pieces for each file. + + Args: + data: A string containing the output of svn diff. + + Returns: + A list of 2-tuple (filename, text) where text is the svn diff output + pertaining to filename. + """ + patches = [] + filename = None + diff = [] + for line in data.splitlines(True): + new_filename = None + if line.startswith('Index:'): + unused, new_filename = line.split(':', 1) + new_filename = new_filename.strip() + elif line.startswith('Property changes on:'): + unused, temp_filename = line.split(':', 1) + # When a file is modified, paths use '/' between directories, however + # when a property is modified '\' is used on Windows. Make them the same + # otherwise the file shows up twice. + temp_filename = temp_filename.strip().replace('\\', '/') + if temp_filename != filename: + # File has property changes but no modifications, create a new diff. + new_filename = temp_filename + if new_filename: + if filename and diff: + patches.append((filename, ''.join(diff))) + filename = new_filename + diff = [line] + continue + if diff is not None: + diff.append(line) + if filename and diff: + patches.append((filename, ''.join(diff))) + return patches + + +def UploadSeparatePatches(issue, rpc_server, patchset, data, options): + """Uploads a separate patch for each file in the diff output. + + Returns a list of [patch_key, filename] for each file. + """ + patches = SplitPatch(data) + rv = [] + for patch in patches: + if len(patch[1]) > MAX_UPLOAD_SIZE: + print ("Not uploading the patch for " + patch[0] + + " because the file is too large.") + continue + form_fields = [("filename", patch[0])] + if not options.download_base: + form_fields.append(("content_upload", "1")) + files = [("data", "data.diff", patch[1])] + ctype, body = EncodeMultipartFormData(form_fields, files) + url = "/%d/upload_patch/%d" % (int(issue), int(patchset)) + print "Uploading patch for " + patch[0] + response_body = rpc_server.Send(url, body, content_type=ctype) + lines = response_body.splitlines() + if not lines or lines[0] != "OK": + StatusUpdate(" --> %s" % response_body) + sys.exit(1) + rv.append([lines[1], patch[0]]) + return rv + + +def GuessVCS(options): + """Helper to guess the version control system. + + This examines the current directory, guesses which VersionControlSystem + we're using, and returns an instance of the appropriate class. Exit with an + error if we can't figure it out. + + Returns: + A VersionControlSystem instance. Exits if the VCS can't be guessed. + """ + # Mercurial has a command to get the base directory of a repository + # Try running it, but don't die if we don't have hg installed. + # NOTE: we try Mercurial first as it can sit on top of an SVN working copy. + try: + out, returncode = RunShellWithReturnCode(["hg", "root"]) + if returncode == 0: + return MercurialVCS(options, out.strip()) + except OSError, (errno, message): + if errno != 2: # ENOENT -- they don't have hg installed. + raise + + # Subversion has a .svn in all working directories. + if os.path.isdir('.svn'): + logging.info("Guessed VCS = Subversion") + return SubversionVCS(options) + + # Git has a command to test if you're in a git tree. + # Try running it, but don't die if we don't have git installed. + try: + out, returncode = RunShellWithReturnCode(["git", "rev-parse", + "--is-inside-work-tree"]) + if returncode == 0: + return GitVCS(options) + except OSError, (errno, message): + if errno != 2: # ENOENT -- they don't have git installed. + raise + + ErrorExit(("Could not guess version control system. " + "Are you in a working copy directory?")) + + +def RealMain(argv, data=None): + """The real main function. + + Args: + argv: Command line arguments. + data: Diff contents. If None (default) the diff is generated by + the VersionControlSystem implementation returned by GuessVCS(). + + Returns: + A 2-tuple (issue id, patchset id). + The patchset id is None if the base files are not uploaded by this + script (applies only to SVN checkouts). + """ + logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:" + "%(lineno)s %(message)s ")) + os.environ['LC_ALL'] = 'C' + options, args = parser.parse_args(argv[1:]) + global verbosity + verbosity = options.verbose + if verbosity >= 3: + logging.getLogger().setLevel(logging.DEBUG) + elif verbosity >= 2: + logging.getLogger().setLevel(logging.INFO) + vcs = GuessVCS(options) + if isinstance(vcs, SubversionVCS): + # base field is only allowed for Subversion. + # Note: Fetching base files may become deprecated in future releases. + base = vcs.GuessBase(options.download_base) + else: + base = None + if not base and options.download_base: + options.download_base = True + logging.info("Enabled upload of base file") + if not options.assume_yes: + vcs.CheckForUnknownFiles() + if data is None: + data = vcs.GenerateDiff(args) + files = vcs.GetBaseFiles(data) + if verbosity >= 1: + print "Upload server:", options.server, "(change with -s/--server)" + if options.issue: + prompt = "Message describing this patch set: " + else: + prompt = "New issue subject: " + message = options.message or raw_input(prompt).strip() + if not message: + ErrorExit("A non-empty message is required") + rpc_server = GetRpcServer(options) + form_fields = [("subject", message)] + if base: + form_fields.append(("base", base)) + if options.issue: + form_fields.append(("issue", str(options.issue))) + if options.email: + form_fields.append(("user", options.email)) + if options.reviewers: + for reviewer in options.reviewers.split(','): + if "@" in reviewer and not reviewer.split("@")[1].count(".") == 1: + ErrorExit("Invalid email address: %s" % reviewer) + form_fields.append(("reviewers", options.reviewers)) + if options.cc: + for cc in options.cc.split(','): + if "@" in cc and not cc.split("@")[1].count(".") == 1: + ErrorExit("Invalid email address: %s" % cc) + form_fields.append(("cc", options.cc)) + description = options.description + if options.description_file: + if options.description: + ErrorExit("Can't specify description and description_file") + file = open(options.description_file, 'r') + description = file.read() + file.close() + if description: + form_fields.append(("description", description)) + # Send a hash of all the base file so the server can determine if a copy + # already exists in an earlier patchset. + base_hashes = "" + for file, info in files.iteritems(): + if not info[0] is None: + checksum = md5.new(info[0]).hexdigest() + if base_hashes: + base_hashes += "|" + base_hashes += checksum + ":" + file + form_fields.append(("base_hashes", base_hashes)) + # If we're uploading base files, don't send the email before the uploads, so + # that it contains the file status. + if options.send_mail and options.download_base: + form_fields.append(("send_mail", "1")) + if not options.download_base: + form_fields.append(("content_upload", "1")) + if len(data) > MAX_UPLOAD_SIZE: + print "Patch is large, so uploading file patches separately." + uploaded_diff_file = [] + form_fields.append(("separate_patches", "1")) + else: + uploaded_diff_file = [("data", "data.diff", data)] + ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file) + response_body = rpc_server.Send("/upload", body, content_type=ctype) + patchset = None + if not options.download_base or not uploaded_diff_file: + lines = response_body.splitlines() + if len(lines) >= 2: + msg = lines[0] + patchset = lines[1].strip() + patches = [x.split(" ", 1) for x in lines[2:]] + else: + msg = response_body + else: + msg = response_body + StatusUpdate(msg) + if not response_body.startswith("Issue created.") and \ + not response_body.startswith("Issue updated."): + sys.exit(0) + issue = msg[msg.rfind("/")+1:] + + if not uploaded_diff_file: + result = UploadSeparatePatches(issue, rpc_server, patchset, data, options) + if not options.download_base: + patches = result + + if not options.download_base: + vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files) + if options.send_mail: + rpc_server.Send("/" + issue + "/mail", payload="") + return issue, patchset + + +def main(): + try: + RealMain(sys.argv) + except KeyboardInterrupt: + print + StatusUpdate("Interrupted.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/upload_gtest.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/upload_gtest.py new file mode 100755 index 0000000000000000000000000000000000000000..be19ae80911c3ad67e1273751c747cd915528f91 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/scripts/upload_gtest.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""upload_gtest.py v0.1.0 -- uploads a Google Test patch for review. + +This simple wrapper passes all command line flags and +--cc=googletestframework@googlegroups.com to upload.py. + +USAGE: upload_gtest.py [options for upload.py] +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import os +import sys + +CC_FLAG = '--cc=' +GTEST_GROUP = 'googletestframework@googlegroups.com' + + +def main(): + # Finds the path to upload.py, assuming it is in the same directory + # as this file. + my_dir = os.path.dirname(os.path.abspath(__file__)) + upload_py_path = os.path.join(my_dir, 'upload.py') + + # Adds Google Test discussion group to the cc line if it's not there + # already. + upload_py_argv = [upload_py_path] + found_cc_flag = False + for arg in sys.argv[1:]: + if arg.startswith(CC_FLAG): + found_cc_flag = True + cc_line = arg[len(CC_FLAG):] + cc_list = [addr for addr in cc_line.split(',') if addr] + if GTEST_GROUP not in cc_list: + cc_list.append(GTEST_GROUP) + upload_py_argv.append(CC_FLAG + ','.join(cc_list)) + else: + upload_py_argv.append(arg) + + if not found_cc_flag: + upload_py_argv.append(CC_FLAG + GTEST_GROUP) + + # Invokes upload.py with the modified command line flags. + os.execv(upload_py_path, upload_py_argv) + + +if __name__ == '__main__': + main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-all.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-all.cc new file mode 100644 index 0000000000000000000000000000000000000000..ad292905cf381d69eba9008f5196cf6477a56c1a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-all.cc @@ -0,0 +1,48 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Google C++ Testing and Mocking Framework (Google Test) +// +// Sometimes it's desirable to build Google Test by compiling a single file. +// This file serves this purpose. + +// This line ensures that gtest.h can be compiled on its own, even +// when it's fused. +#include "gtest/gtest.h" + +// The following lines pull in the real gtest *.cc files. +#include "src/gtest.cc" +#include "src/gtest-death-test.cc" +#include "src/gtest-filepath.cc" +#include "src/gtest-matchers.cc" +#include "src/gtest-port.cc" +#include "src/gtest-printers.cc" +#include "src/gtest-test-part.cc" +#include "src/gtest-typed-test.cc" diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-death-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-death-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..da09a1cfc23a550b14251ac0e0ba9a6a8375c535 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-death-test.cc @@ -0,0 +1,1653 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// This file implements death tests. + +#include "gtest/gtest-death-test.h" + +#include + +#include "gtest/internal/gtest-port.h" +#include "gtest/internal/custom/gtest.h" + +#if GTEST_HAS_DEATH_TEST + +# if GTEST_OS_MAC +# include +# endif // GTEST_OS_MAC + +# include +# include +# include + +# if GTEST_OS_LINUX +# include +# endif // GTEST_OS_LINUX + +# include + +# if GTEST_OS_WINDOWS +# include +# else +# include +# include +# endif // GTEST_OS_WINDOWS + +# if GTEST_OS_QNX +# include +# endif // GTEST_OS_QNX + +# if GTEST_OS_FUCHSIA +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# endif // GTEST_OS_FUCHSIA + +#endif // GTEST_HAS_DEATH_TEST + +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-string.h" +#include "src/gtest-internal-inl.h" + +namespace testing { + +// Constants. + +// The default death test style. +// +// This is defined in internal/gtest-port.h as "fast", but can be overridden by +// a definition in internal/custom/gtest-port.h. The recommended value, which is +// used internally at Google, is "threadsafe". +static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE; + +GTEST_DEFINE_string_( + death_test_style, + internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), + "Indicates how to run a death test in a forked child process: " + "\"threadsafe\" (child process re-executes the test binary " + "from the beginning, running only the specific death test) or " + "\"fast\" (child process runs the death test immediately " + "after forking)."); + +GTEST_DEFINE_bool_( + death_test_use_fork, + internal::BoolFromGTestEnv("death_test_use_fork", false), + "Instructs to use fork()/_exit() instead of clone() in death tests. " + "Ignored and always uses fork() on POSIX systems where clone() is not " + "implemented. Useful when running under valgrind or similar tools if " + "those do not support clone(). Valgrind 3.3.1 will just fail if " + "it sees an unsupported combination of clone() flags. " + "It is not recommended to use this flag w/o valgrind though it will " + "work in 99% of the cases. Once valgrind is fixed, this flag will " + "most likely be removed."); + +namespace internal { +GTEST_DEFINE_string_( + internal_run_death_test, "", + "Indicates the file, line number, temporal index of " + "the single death test to run, and a file descriptor to " + "which a success code may be sent, all separated by " + "the '|' characters. This flag is specified if and only if the " + "current process is a sub-process launched for running a thread-safe " + "death test. FOR INTERNAL USE ONLY."); +} // namespace internal + +#if GTEST_HAS_DEATH_TEST + +namespace internal { + +// Valid only for fast death tests. Indicates the code is running in the +// child process of a fast style death test. +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA +static bool g_in_fast_death_test_child = false; +# endif + +// Returns a Boolean value indicating whether the caller is currently +// executing in the context of the death test child process. Tools such as +// Valgrind heap checkers may need this to modify their behavior in death +// tests. IMPORTANT: This is an internal utility. Using it may break the +// implementation of death tests. User code MUST NOT use it. +bool InDeathTestChild() { +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA + + // On Windows and Fuchsia, death tests are thread-safe regardless of the value + // of the death_test_style flag. + return !GTEST_FLAG(internal_run_death_test).empty(); + +# else + + if (GTEST_FLAG(death_test_style) == "threadsafe") + return !GTEST_FLAG(internal_run_death_test).empty(); + else + return g_in_fast_death_test_child; +#endif +} + +} // namespace internal + +// ExitedWithCode constructor. +ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { +} + +// ExitedWithCode function-call operator. +bool ExitedWithCode::operator()(int exit_status) const { +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA + + return exit_status == exit_code_; + +# else + + return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; + +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA +} + +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA +// KilledBySignal constructor. +KilledBySignal::KilledBySignal(int signum) : signum_(signum) { +} + +// KilledBySignal function-call operator. +bool KilledBySignal::operator()(int exit_status) const { +# if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) + { + bool result; + if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) { + return result; + } + } +# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) + return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; +} +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA + +namespace internal { + +// Utilities needed for death tests. + +// Generates a textual description of a given exit code, in the format +// specified by wait(2). +static std::string ExitSummary(int exit_code) { + Message m; + +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA + + m << "Exited with exit status " << exit_code; + +# else + + if (WIFEXITED(exit_code)) { + m << "Exited with exit status " << WEXITSTATUS(exit_code); + } else if (WIFSIGNALED(exit_code)) { + m << "Terminated by signal " << WTERMSIG(exit_code); + } +# ifdef WCOREDUMP + if (WCOREDUMP(exit_code)) { + m << " (core dumped)"; + } +# endif +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA + + return m.GetString(); +} + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +bool ExitedUnsuccessfully(int exit_status) { + return !ExitedWithCode(0)(exit_status); +} + +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA +// Generates a textual failure message when a death test finds more than +// one thread running, or cannot determine the number of threads, prior +// to executing the given statement. It is the responsibility of the +// caller not to pass a thread_count of 1. +static std::string DeathTestThreadWarning(size_t thread_count) { + Message msg; + msg << "Death tests use fork(), which is unsafe particularly" + << " in a threaded context. For this test, " << GTEST_NAME_ << " "; + if (thread_count == 0) { + msg << "couldn't detect the number of threads."; + } else { + msg << "detected " << thread_count << " threads."; + } + msg << " See " + "https://github.com/google/googletest/blob/master/googletest/docs/" + "advanced.md#death-tests-and-threads" + << " for more explanation and suggested solutions, especially if" + << " this is the last message you see before your test times out."; + return msg.GetString(); +} +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA + +// Flag characters for reporting a death test that did not die. +static const char kDeathTestLived = 'L'; +static const char kDeathTestReturned = 'R'; +static const char kDeathTestThrew = 'T'; +static const char kDeathTestInternalError = 'I'; + +#if GTEST_OS_FUCHSIA + +// File descriptor used for the pipe in the child process. +static const int kFuchsiaReadPipeFd = 3; + +#endif + +// An enumeration describing all of the possible ways that a death test can +// conclude. DIED means that the process died while executing the test +// code; LIVED means that process lived beyond the end of the test code; +// RETURNED means that the test statement attempted to execute a return +// statement, which is not allowed; THREW means that the test statement +// returned control by throwing an exception. IN_PROGRESS means the test +// has not yet concluded. +enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; + +// Routine for aborting the program which is safe to call from an +// exec-style death test child process, in which case the error +// message is propagated back to the parent process. Otherwise, the +// message is simply printed to stderr. In either case, the program +// then exits with status 1. +static void DeathTestAbort(const std::string& message) { + // On a POSIX system, this function may be called from a threadsafe-style + // death test child process, which operates on a very small stack. Use + // the heap for any additional non-minuscule memory requirements. + const InternalRunDeathTestFlag* const flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + if (flag != nullptr) { + FILE* parent = posix::FDOpen(flag->write_fd(), "w"); + fputc(kDeathTestInternalError, parent); + fprintf(parent, "%s", message.c_str()); + fflush(parent); + _exit(1); + } else { + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); + posix::Abort(); + } +} + +// A replacement for CHECK that calls DeathTestAbort if the assertion +// fails. +# define GTEST_DEATH_TEST_CHECK_(expression) \ + do { \ + if (!::testing::internal::IsTrue(expression)) { \ + DeathTestAbort( \ + ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + + ::testing::internal::StreamableToString(__LINE__) + ": " \ + + #expression); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for +// evaluating any system call that fulfills two conditions: it must return +// -1 on failure, and set errno to EINTR when it is interrupted and +// should be tried again. The macro expands to a loop that repeatedly +// evaluates the expression as long as it evaluates to -1 and sets +// errno to EINTR. If the expression evaluates to -1 but errno is +// something other than EINTR, DeathTestAbort is called. +# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ + do { \ + int gtest_retval; \ + do { \ + gtest_retval = (expression); \ + } while (gtest_retval == -1 && errno == EINTR); \ + if (gtest_retval == -1) { \ + DeathTestAbort( \ + ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + + ::testing::internal::StreamableToString(__LINE__) + ": " \ + + #expression + " != -1"); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// Returns the message describing the last system error in errno. +std::string GetLastErrnoDescription() { + return errno == 0 ? "" : posix::StrError(errno); +} + +// This is called from a death test parent process to read a failure +// message from the death test child process and log it with the FATAL +// severity. On Windows, the message is read from a pipe handle. On other +// platforms, it is read from a file descriptor. +static void FailFromInternalError(int fd) { + Message error; + char buffer[256]; + int num_read; + + do { + while ((num_read = posix::Read(fd, buffer, 255)) > 0) { + buffer[num_read] = '\0'; + error << buffer; + } + } while (num_read == -1 && errno == EINTR); + + if (num_read == 0) { + GTEST_LOG_(FATAL) << error.GetString(); + } else { + const int last_error = errno; + GTEST_LOG_(FATAL) << "Error while reading death test internal: " + << GetLastErrnoDescription() << " [" << last_error << "]"; + } +} + +// Death test constructor. Increments the running death test count +// for the current test. +DeathTest::DeathTest() { + TestInfo* const info = GetUnitTestImpl()->current_test_info(); + if (info == nullptr) { + DeathTestAbort("Cannot run a death test outside of a TEST or " + "TEST_F construct"); + } +} + +// Creates and returns a death test by dispatching to the current +// death test factory. +bool DeathTest::Create(const char* statement, + Matcher matcher, const char* file, + int line, DeathTest** test) { + return GetUnitTestImpl()->death_test_factory()->Create( + statement, std::move(matcher), file, line, test); +} + +const char* DeathTest::LastMessage() { + return last_death_test_message_.c_str(); +} + +void DeathTest::set_last_death_test_message(const std::string& message) { + last_death_test_message_ = message; +} + +std::string DeathTest::last_death_test_message_; + +// Provides cross platform implementation for some death functionality. +class DeathTestImpl : public DeathTest { + protected: + DeathTestImpl(const char* a_statement, Matcher matcher) + : statement_(a_statement), + matcher_(std::move(matcher)), + spawned_(false), + status_(-1), + outcome_(IN_PROGRESS), + read_fd_(-1), + write_fd_(-1) {} + + // read_fd_ is expected to be closed and cleared by a derived class. + ~DeathTestImpl() override { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + + void Abort(AbortReason reason) override; + bool Passed(bool status_ok) override; + + const char* statement() const { return statement_; } + bool spawned() const { return spawned_; } + void set_spawned(bool is_spawned) { spawned_ = is_spawned; } + int status() const { return status_; } + void set_status(int a_status) { status_ = a_status; } + DeathTestOutcome outcome() const { return outcome_; } + void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } + int read_fd() const { return read_fd_; } + void set_read_fd(int fd) { read_fd_ = fd; } + int write_fd() const { return write_fd_; } + void set_write_fd(int fd) { write_fd_ = fd; } + + // Called in the parent process only. Reads the result code of the death + // test child process via a pipe, interprets it to set the outcome_ + // member, and closes read_fd_. Outputs diagnostics and terminates in + // case of unexpected codes. + void ReadAndInterpretStatusByte(); + + // Returns stderr output from the child process. + virtual std::string GetErrorLogs(); + + private: + // The textual content of the code this object is testing. This class + // doesn't own this string and should not attempt to delete it. + const char* const statement_; + // A matcher that's expected to match the stderr output by the child process. + Matcher matcher_; + // True if the death test child process has been successfully spawned. + bool spawned_; + // The exit status of the child process. + int status_; + // How the death test concluded. + DeathTestOutcome outcome_; + // Descriptor to the read end of the pipe to the child process. It is + // always -1 in the child process. The child keeps its write end of the + // pipe in write_fd_. + int read_fd_; + // Descriptor to the child's write end of the pipe to the parent process. + // It is always -1 in the parent process. The parent keeps its end of the + // pipe in read_fd_. + int write_fd_; +}; + +// Called in the parent process only. Reads the result code of the death +// test child process via a pipe, interprets it to set the outcome_ +// member, and closes read_fd_. Outputs diagnostics and terminates in +// case of unexpected codes. +void DeathTestImpl::ReadAndInterpretStatusByte() { + char flag; + int bytes_read; + + // The read() here blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before + // the child process has exited. + do { + bytes_read = posix::Read(read_fd(), &flag, 1); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0) { + set_outcome(DIED); + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + set_outcome(RETURNED); + break; + case kDeathTestThrew: + set_outcome(THREW); + break; + case kDeathTestLived: + set_outcome(LIVED); + break; + case kDeathTestInternalError: + FailFromInternalError(read_fd()); // Does not return. + break; + default: + GTEST_LOG_(FATAL) << "Death test child process reported " + << "unexpected status byte (" + << static_cast(flag) << ")"; + } + } else { + GTEST_LOG_(FATAL) << "Read from death test child process failed: " + << GetLastErrnoDescription(); + } + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); + set_read_fd(-1); +} + +std::string DeathTestImpl::GetErrorLogs() { + return GetCapturedStderr(); +} + +// Signals that the death test code which should have exited, didn't. +// Should be called only in a death test child process. +// Writes a status byte to the child's status file descriptor, then +// calls _exit(1). +void DeathTestImpl::Abort(AbortReason reason) { + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char status_ch = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : + reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; + + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); + // We are leaking the descriptor here because on some platforms (i.e., + // when built as Windows DLL), destructors of global objects will still + // run after calling _exit(). On such systems, write_fd_ will be + // indirectly closed from the destructor of UnitTestImpl, causing double + // close if it is also closed here. On debug configurations, double close + // may assert. As there are no in-process buffers to flush here, we are + // relying on the OS to close the descriptor after the process terminates + // when the destructors are not run. + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// Returns an indented copy of stderr output for a death test. +// This makes distinguishing death test output lines from regular log lines +// much easier. +static ::std::string FormatDeathTestOutput(const ::std::string& output) { + ::std::string ret; + for (size_t at = 0; ; ) { + const size_t line_end = output.find('\n', at); + ret += "[ DEATH ] "; + if (line_end == ::std::string::npos) { + ret += output.substr(at); + break; + } + ret += output.substr(at, line_end + 1 - at); + at = line_end + 1; + } + return ret; +} + +// Assesses the success or failure of a death test, using both private +// members which have previously been set, and one argument: +// +// Private data members: +// outcome: An enumeration describing how the death test +// concluded: DIED, LIVED, THREW, or RETURNED. The death test +// fails in the latter three cases. +// status: The exit status of the child process. On *nix, it is in the +// in the format specified by wait(2). On Windows, this is the +// value supplied to the ExitProcess() API or a numeric code +// of the exception that terminated the program. +// matcher_: A matcher that's expected to match the stderr output by the child +// process. +// +// Argument: +// status_ok: true if exit_status is acceptable in the context of +// this particular death test, which fails if it is false +// +// Returns true if and only if all of the above conditions are met. Otherwise, +// the first failing condition, in the order given above, is the one that is +// reported. Also sets the last death test message string. +bool DeathTestImpl::Passed(bool status_ok) { + if (!spawned()) + return false; + + const std::string error_message = GetErrorLogs(); + + bool success = false; + Message buffer; + + buffer << "Death test: " << statement() << "\n"; + switch (outcome()) { + case LIVED: + buffer << " Result: failed to die.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case THREW: + buffer << " Result: threw an exception.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case RETURNED: + buffer << " Result: illegal return in test statement.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case DIED: + if (status_ok) { + if (matcher_.Matches(error_message)) { + success = true; + } else { + std::ostringstream stream; + matcher_.DescribeTo(&stream); + buffer << " Result: died but not with expected error.\n" + << " Expected: " << stream.str() << "\n" + << "Actual msg:\n" + << FormatDeathTestOutput(error_message); + } + } else { + buffer << " Result: died but not with expected exit code:\n" + << " " << ExitSummary(status()) << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + break; + case IN_PROGRESS: + default: + GTEST_LOG_(FATAL) + << "DeathTest::Passed somehow called before conclusion of test"; + } + + DeathTest::set_last_death_test_message(buffer.GetString()); + return success; +} + +# if GTEST_OS_WINDOWS +// WindowsDeathTest implements death tests on Windows. Due to the +// specifics of starting new processes on Windows, death tests there are +// always threadsafe, and Google Test considers the +// --gtest_death_test_style=fast setting to be equivalent to +// --gtest_death_test_style=threadsafe there. +// +// A few implementation notes: Like the Linux version, the Windows +// implementation uses pipes for child-to-parent communication. But due to +// the specifics of pipes on Windows, some extra steps are required: +// +// 1. The parent creates a communication pipe and stores handles to both +// ends of it. +// 2. The parent starts the child and provides it with the information +// necessary to acquire the handle to the write end of the pipe. +// 3. The child acquires the write end of the pipe and signals the parent +// using a Windows event. +// 4. Now the parent can release the write end of the pipe on its side. If +// this is done before step 3, the object's reference count goes down to +// 0 and it is destroyed, preventing the child from acquiring it. The +// parent now has to release it, or read operations on the read end of +// the pipe will not return when the child terminates. +// 5. The parent reads child's output through the pipe (outcome code and +// any possible error messages) from the pipe, and its stderr and then +// determines whether to fail the test. +// +// Note: to distinguish Win32 API calls from the local method and function +// calls, the former are explicitly resolved in the global namespace. +// +class WindowsDeathTest : public DeathTestImpl { + public: + WindowsDeathTest(const char* a_statement, Matcher matcher, + const char* file, int line) + : DeathTestImpl(a_statement, std::move(matcher)), + file_(file), + line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // Handle to the write end of the pipe to the child process. + AutoHandle write_handle_; + // Child process handle. + AutoHandle child_handle_; + // Event the child process uses to signal the parent that it has + // acquired the handle to the write end of the pipe. After seeing this + // event the parent can release its own handles to make sure its + // ReadFile() calls return when the child terminates. + AutoHandle event_handle_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int WindowsDeathTest::Wait() { + if (!spawned()) + return 0; + + // Wait until the child either signals that it has acquired the write end + // of the pipe or it dies. + const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; + switch (::WaitForMultipleObjects(2, + wait_handles, + FALSE, // Waits for any of the handles. + INFINITE)) { + case WAIT_OBJECT_0: + case WAIT_OBJECT_0 + 1: + break; + default: + GTEST_DEATH_TEST_CHECK_(false); // Should not get here. + } + + // The child has acquired the write end of the pipe or exited. + // We release the handle on our side and continue. + write_handle_.Reset(); + event_handle_.Reset(); + + ReadAndInterpretStatusByte(); + + // Waits for the child process to exit if it haven't already. This + // returns immediately if the child has already exited, regardless of + // whether previous calls to WaitForMultipleObjects synchronized on this + // handle or not. + GTEST_DEATH_TEST_CHECK_( + WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), + INFINITE)); + DWORD status_code; + GTEST_DEATH_TEST_CHECK_( + ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); + child_handle_.Reset(); + set_status(static_cast(status_code)); + return status(); +} + +// The AssumeRole process for a Windows death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole WindowsDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != nullptr) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + // WindowsDeathTest uses an anonymous pipe to communicate results of + // a death test. + SECURITY_ATTRIBUTES handles_are_inheritable = {sizeof(SECURITY_ATTRIBUTES), + nullptr, TRUE}; + HANDLE read_handle, write_handle; + GTEST_DEATH_TEST_CHECK_( + ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, + 0) // Default buffer size. + != FALSE); + set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), + O_RDONLY)); + write_handle_.Reset(write_handle); + event_handle_.Reset(::CreateEvent( + &handles_are_inheritable, + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + nullptr)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr); + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + + "=" + file_ + "|" + StreamableToString(line_) + "|" + + StreamableToString(death_test_index) + "|" + + StreamableToString(static_cast(::GetCurrentProcessId())) + + // size_t has the same width as pointers on both 32-bit and 64-bit + // Windows platforms. + // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. + "|" + StreamableToString(reinterpret_cast(write_handle)) + + "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); + + char executable_path[_MAX_PATH + 1]; // NOLINT + GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr, + executable_path, + _MAX_PATH)); + + std::string command_line = + std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + + internal_flag + "\""; + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // The child process will share the standard handles with the parent. + STARTUPINFOA startup_info; + memset(&startup_info, 0, sizeof(STARTUPINFO)); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); + + PROCESS_INFORMATION process_info; + GTEST_DEATH_TEST_CHECK_( + ::CreateProcessA( + executable_path, const_cast(command_line.c_str()), + nullptr, // Retuned process handle is not inheritable. + nullptr, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + nullptr, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), &startup_info, + &process_info) != FALSE); + child_handle_.Reset(process_info.hProcess); + ::CloseHandle(process_info.hThread); + set_spawned(true); + return OVERSEE_TEST; +} + +# elif GTEST_OS_FUCHSIA + +class FuchsiaDeathTest : public DeathTestImpl { + public: + FuchsiaDeathTest(const char* a_statement, Matcher matcher, + const char* file, int line) + : DeathTestImpl(a_statement, std::move(matcher)), + file_(file), + line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + int Wait() override; + TestRole AssumeRole() override; + std::string GetErrorLogs() override; + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // The stderr data captured by the child process. + std::string captured_stderr_; + + zx::process child_process_; + zx::channel exception_channel_; + zx::socket stderr_socket_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { args_.push_back(nullptr); } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + + int size() { + return args_.size() - 1; + } + + private: + std::vector args_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int FuchsiaDeathTest::Wait() { + const int kProcessKey = 0; + const int kSocketKey = 1; + const int kExceptionKey = 2; + + if (!spawned()) + return 0; + + // Create a port to wait for socket/task/exception events. + zx_status_t status_zx; + zx::port port; + status_zx = zx::port::create(0, &port); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Register to wait for the child process to terminate. + status_zx = child_process_.wait_async( + port, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Register to wait for the socket to be readable or closed. + status_zx = stderr_socket_.wait_async( + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Register to wait for an exception. + status_zx = exception_channel_.wait_async( + port, kExceptionKey, ZX_CHANNEL_READABLE, ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + bool process_terminated = false; + bool socket_closed = false; + do { + zx_port_packet_t packet = {}; + status_zx = port.wait(zx::time::infinite(), &packet); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + if (packet.key == kExceptionKey) { + // Process encountered an exception. Kill it directly rather than + // letting other handlers process the event. We will get a kProcessKey + // event when the process actually terminates. + status_zx = child_process_.kill(); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + } else if (packet.key == kProcessKey) { + // Process terminated. + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); + process_terminated = true; + } else if (packet.key == kSocketKey) { + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + if (packet.signal.observed & ZX_SOCKET_READABLE) { + // Read data from the socket. + constexpr size_t kBufferSize = 1024; + do { + size_t old_length = captured_stderr_.length(); + size_t bytes_read = 0; + captured_stderr_.resize(old_length + kBufferSize); + status_zx = stderr_socket_.read( + 0, &captured_stderr_.front() + old_length, kBufferSize, + &bytes_read); + captured_stderr_.resize(old_length + bytes_read); + } while (status_zx == ZX_OK); + if (status_zx == ZX_ERR_PEER_CLOSED) { + socket_closed = true; + } else { + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); + status_zx = stderr_socket_.wait_async( + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + } + } else { + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED); + socket_closed = true; + } + } + } while (!process_terminated && !socket_closed); + + ReadAndInterpretStatusByte(); + + zx_info_process_t buffer; + status_zx = child_process_.get_info( + ZX_INFO_PROCESS, &buffer, sizeof(buffer), nullptr, nullptr); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + GTEST_DEATH_TEST_CHECK_(buffer.exited); + set_status(buffer.return_code); + return status(); +} + +// The AssumeRole process for a Fuchsia death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != nullptr) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(kFuchsiaReadPipeFd); + return EXECUTE_TEST; + } + + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // Build the child process command line. + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + + file_ + "|" + + StreamableToString(line_) + "|" + + StreamableToString(death_test_index); + Arguments args; + args.AddArguments(GetInjectableArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + // Build the pipe for communication with the child. + zx_status_t status; + zx_handle_t child_pipe_handle; + int child_pipe_fd; + status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + set_read_fd(child_pipe_fd); + + // Set the pipe handle for the child. + fdio_spawn_action_t spawn_actions[2] = {}; + fdio_spawn_action_t* add_handle_action = &spawn_actions[0]; + add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE; + add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd); + add_handle_action->h.handle = child_pipe_handle; + + // Create a socket pair will be used to receive the child process' stderr. + zx::socket stderr_producer_socket; + status = + zx::socket::create(0, &stderr_producer_socket, &stderr_socket_); + GTEST_DEATH_TEST_CHECK_(status >= 0); + int stderr_producer_fd = -1; + status = + fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd); + GTEST_DEATH_TEST_CHECK_(status >= 0); + + // Make the stderr socket nonblocking. + GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0); + + fdio_spawn_action_t* add_stderr_action = &spawn_actions[1]; + add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD; + add_stderr_action->fd.local_fd = stderr_producer_fd; + add_stderr_action->fd.target_fd = STDERR_FILENO; + + // Create a child job. + zx_handle_t child_job = ZX_HANDLE_INVALID; + status = zx_job_create(zx_job_default(), 0, & child_job); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + zx_policy_basic_t policy; + policy.condition = ZX_POL_NEW_ANY; + policy.policy = ZX_POL_ACTION_ALLOW; + status = zx_job_set_policy( + child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Create an exception channel attached to the |child_job|, to allow + // us to suppress the system default exception handler from firing. + status = + zx_task_create_exception_channel( + child_job, 0, exception_channel_.reset_and_get_address()); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Spawn the child process. + status = fdio_spawn_etc( + child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], args.Argv(), nullptr, + 2, spawn_actions, child_process_.reset_and_get_address(), nullptr); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + set_spawned(true); + return OVERSEE_TEST; +} + +std::string FuchsiaDeathTest::GetErrorLogs() { + return captured_stderr_; +} + +#else // We are neither on Windows, nor on Fuchsia. + +// ForkingDeathTest provides implementations for most of the abstract +// methods of the DeathTest interface. Only the AssumeRole method is +// left undefined. +class ForkingDeathTest : public DeathTestImpl { + public: + ForkingDeathTest(const char* statement, Matcher matcher); + + // All of these virtual functions are inherited from DeathTest. + int Wait() override; + + protected: + void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } + + private: + // PID of child process during death test; 0 in the child process itself. + pid_t child_pid_; +}; + +// Constructs a ForkingDeathTest. +ForkingDeathTest::ForkingDeathTest(const char* a_statement, + Matcher matcher) + : DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {} + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int ForkingDeathTest::Wait() { + if (!spawned()) + return 0; + + ReadAndInterpretStatusByte(); + + int status_value; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); + set_status(status_value); + return status_value; +} + +// A concrete death test class that forks, then immediately runs the test +// in the child process. +class NoExecDeathTest : public ForkingDeathTest { + public: + NoExecDeathTest(const char* a_statement, Matcher matcher) + : ForkingDeathTest(a_statement, std::move(matcher)) {} + TestRole AssumeRole() override; +}; + +// The AssumeRole process for a fork-and-run death test. It implements a +// straightforward fork, with a simple pipe to transmit the status byte. +DeathTest::TestRole NoExecDeathTest::AssumeRole() { + const size_t thread_count = GetThreadCount(); + if (thread_count != 1) { + GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + + DeathTest::set_last_death_test_message(""); + CaptureStderr(); + // When we fork the process below, the log file buffers are copied, but the + // file descriptors are shared. We flush all log files here so that closing + // the file descriptors in the child process doesn't throw off the + // synchronization between descriptors and buffers in the parent process. + // This is as close to the fork as possible to avoid a race condition in case + // there are multiple threads running before the death test, and another + // thread writes to the log file. + FlushInfoLog(); + + const pid_t child_pid = fork(); + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + set_child_pid(child_pid); + if (child_pid == 0) { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); + set_write_fd(pipe_fd[1]); + // Redirects all logging to stderr in the child process to prevent + // concurrent writes to the log files. We capture stderr in the parent + // process and append the child process' output to a log. + LogToStderr(); + // Event forwarding to the listeners of event listener API mush be shut + // down in death test subprocesses. + GetUnitTestImpl()->listeners()->SuppressEventForwarding(); + g_in_fast_death_test_child = true; + return EXECUTE_TEST; + } else { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; + } +} + +// A concrete death test class that forks and re-executes the main +// program from the beginning, with command-line flags set that cause +// only this specific death test to be run. +class ExecDeathTest : public ForkingDeathTest { + public: + ExecDeathTest(const char* a_statement, Matcher matcher, + const char* file, int line) + : ForkingDeathTest(a_statement, std::move(matcher)), + file_(file), + line_(line) {} + TestRole AssumeRole() override; + + private: + static ::std::vector GetArgvsForDeathTestChildProcess() { + ::std::vector args = GetInjectableArgvs(); +# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) + ::std::vector extra_args = + GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); + args.insert(args.end(), extra_args.begin(), extra_args.end()); +# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) + return args; + } + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { args_.push_back(nullptr); } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + + private: + std::vector args_; +}; + +// A struct that encompasses the arguments to the child process of a +// threadsafe-style death test process. +struct ExecDeathTestArgs { + char* const* argv; // Command-line arguments for the child's call to exec + int close_fd; // File descriptor to close; the read end of a pipe +}; + +# if GTEST_OS_MAC +inline char** GetEnviron() { + // When Google Test is built as a framework on MacOS X, the environ variable + // is unavailable. Apple's documentation (man environ) recommends using + // _NSGetEnviron() instead. + return *_NSGetEnviron(); +} +# else +// Some POSIX platforms expect you to declare environ. extern "C" makes +// it reside in the global namespace. +extern "C" char** environ; +inline char** GetEnviron() { return environ; } +# endif // GTEST_OS_MAC + +# if !GTEST_OS_QNX +// The main function for a threadsafe-style death test child process. +// This function is called in a clone()-ed process and thus must avoid +// any potentially unsafe operations like malloc or libc functions. +static int ExecDeathTestChildMain(void* child_arg) { + ExecDeathTestArgs* const args = static_cast(child_arg); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); + + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + + GetLastErrnoDescription()); + return EXIT_FAILURE; + } + + // We can safely call execve() as it's a direct system call. We + // cannot use execvp() as it's a libc function and thus potentially + // unsafe. Since execve() doesn't search the PATH, the user must + // invoke the test program via a valid path that contains at least + // one path separator. + execve(args->argv[0], args->argv, GetEnviron()); + DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + + original_dir + " failed: " + + GetLastErrnoDescription()); + return EXIT_FAILURE; +} +# endif // !GTEST_OS_QNX + +# if GTEST_HAS_CLONE +// Two utility routines that together determine the direction the stack +// grows. +// This could be accomplished more elegantly by a single recursive +// function, but we want to guard against the unlikely possibility of +// a smart compiler optimizing the recursion away. +// +// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining +// StackLowerThanAddress into StackGrowsDown, which then doesn't give +// correct answer. +static void StackLowerThanAddress(const void* ptr, + bool* result) GTEST_NO_INLINE_; +// HWAddressSanitizer add a random tag to the MSB of the local variable address, +// making comparison result unpredictable. +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +static void StackLowerThanAddress(const void* ptr, bool* result) { + int dummy; + *result = (&dummy < ptr); +} + +// Make sure AddressSanitizer does not tamper with the stack here. +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +static bool StackGrowsDown() { + int dummy; + bool result; + StackLowerThanAddress(&dummy, &result); + return result; +} +# endif // GTEST_HAS_CLONE + +// Spawns a child process with the same executable as the current process in +// a thread-safe manner and instructs it to run the death test. The +// implementation uses fork(2) + exec. On systems where clone(2) is +// available, it is used instead, being slightly more thread-safe. On QNX, +// fork supports only single-threaded environments, so this function uses +// spawn(2) there instead. The function dies with an error message if +// anything goes wrong. +static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { + ExecDeathTestArgs args = { argv, close_fd }; + pid_t child_pid = -1; + +# if GTEST_OS_QNX + // Obtains the current directory and sets it to be closed in the child + // process. + const int cwd_fd = open(".", O_RDONLY); + GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); + GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + + GetLastErrnoDescription()); + return EXIT_FAILURE; + } + + int fd_flags; + // Set close_fd to be closed after spawn. + GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, + fd_flags | FD_CLOEXEC)); + struct inheritance inherit = {0}; + // spawn is a system call. + child_pid = + spawn(args.argv[0], 0, nullptr, &inherit, args.argv, GetEnviron()); + // Restores the current working directory. + GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); + +# else // GTEST_OS_QNX +# if GTEST_OS_LINUX + // When a SIGPROF signal is received while fork() or clone() are executing, + // the process may hang. To avoid this, we ignore SIGPROF here and re-enable + // it after the call to fork()/clone() is complete. + struct sigaction saved_sigprof_action; + struct sigaction ignore_sigprof_action; + memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); + sigemptyset(&ignore_sigprof_action.sa_mask); + ignore_sigprof_action.sa_handler = SIG_IGN; + GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( + SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); +# endif // GTEST_OS_LINUX + +# if GTEST_HAS_CLONE + const bool use_fork = GTEST_FLAG(death_test_use_fork); + + if (!use_fork) { + static const bool stack_grows_down = StackGrowsDown(); + const auto stack_size = static_cast(getpagesize()); + // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. + void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); + + // Maximum stack alignment in bytes: For a downward-growing stack, this + // amount is subtracted from size of the stack space to get an address + // that is within the stack space and is aligned on all systems we care + // about. As far as I know there is no ABI with stack alignment greater + // than 64. We assume stack and stack_size already have alignment of + // kMaxStackAlignment. + const size_t kMaxStackAlignment = 64; + void* const stack_top = + static_cast(stack) + + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); + GTEST_DEATH_TEST_CHECK_( + static_cast(stack_size) > kMaxStackAlignment && + reinterpret_cast(stack_top) % kMaxStackAlignment == 0); + + child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); + + GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); + } +# else + const bool use_fork = true; +# endif // GTEST_HAS_CLONE + + if (use_fork && (child_pid = fork()) == 0) { + ExecDeathTestChildMain(&args); + _exit(0); + } +# endif // GTEST_OS_QNX +# if GTEST_OS_LINUX + GTEST_DEATH_TEST_CHECK_SYSCALL_( + sigaction(SIGPROF, &saved_sigprof_action, nullptr)); +# endif // GTEST_OS_LINUX + + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + return child_pid; +} + +// The AssumeRole process for a fork-and-exec death test. It re-executes the +// main program from the beginning, setting the --gtest_filter +// and --gtest_internal_run_death_test flags to cause only the current +// death test to be re-run. +DeathTest::TestRole ExecDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != nullptr) { + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + // Clear the close-on-exec flag on the write end of the pipe, lest + // it be closed when the child process does an exec: + GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); + + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + + file_ + "|" + StreamableToString(line_) + "|" + + StreamableToString(death_test_index) + "|" + + StreamableToString(pipe_fd[1]); + Arguments args; + args.AddArguments(GetArgvsForDeathTestChildProcess()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // See the comment in NoExecDeathTest::AssumeRole for why the next line + // is necessary. + FlushInfoLog(); + + const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_child_pid(child_pid); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; +} + +# endif // !GTEST_OS_WINDOWS + +// Creates a concrete DeathTest-derived class that depends on the +// --gtest_death_test_style flag, and sets the pointer pointed to +// by the "test" argument to its address. If the test should be +// skipped, sets that pointer to NULL. Returns true, unless the +// flag is set to an invalid value. +bool DefaultDeathTestFactory::Create(const char* statement, + Matcher matcher, + const char* file, int line, + DeathTest** test) { + UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const int death_test_index = impl->current_test_info() + ->increment_death_test_count(); + + if (flag != nullptr) { + if (death_test_index > flag->index()) { + DeathTest::set_last_death_test_message( + "Death test count (" + StreamableToString(death_test_index) + + ") somehow exceeded expected maximum (" + + StreamableToString(flag->index()) + ")"); + return false; + } + + if (!(flag->file() == file && flag->line() == line && + flag->index() == death_test_index)) { + *test = nullptr; + return true; + } + } + +# if GTEST_OS_WINDOWS + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new WindowsDeathTest(statement, std::move(matcher), file, line); + } + +# elif GTEST_OS_FUCHSIA + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new FuchsiaDeathTest(statement, std::move(matcher), file, line); + } + +# else + + if (GTEST_FLAG(death_test_style) == "threadsafe") { + *test = new ExecDeathTest(statement, std::move(matcher), file, line); + } else if (GTEST_FLAG(death_test_style) == "fast") { + *test = new NoExecDeathTest(statement, std::move(matcher)); + } + +# endif // GTEST_OS_WINDOWS + + else { // NOLINT - this is more readable than unbalanced brackets inside #if. + DeathTest::set_last_death_test_message( + "Unknown death test style \"" + GTEST_FLAG(death_test_style) + + "\" encountered"); + return false; + } + + return true; +} + +# if GTEST_OS_WINDOWS +// Recreates the pipe and event handles from the provided parameters, +// signals the event, and returns a file descriptor wrapped around the pipe +// handle. This function is called in the child process only. +static int GetStatusFileDescriptor(unsigned int parent_process_id, + size_t write_handle_as_size_t, + size_t event_handle_as_size_t) { + AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, + FALSE, // Non-inheritable. + parent_process_id)); + if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { + DeathTestAbort("Unable to open parent process " + + StreamableToString(parent_process_id)); + } + + GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); + + const HANDLE write_handle = + reinterpret_cast(write_handle_as_size_t); + HANDLE dup_write_handle; + + // The newly initialized handle is accessible only in the parent + // process. To obtain one accessible within the child, we need to use + // DuplicateHandle. + if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, + ::GetCurrentProcess(), &dup_write_handle, + 0x0, // Requested privileges ignored since + // DUPLICATE_SAME_ACCESS is used. + FALSE, // Request non-inheritable handler. + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort("Unable to duplicate the pipe handle " + + StreamableToString(write_handle_as_size_t) + + " from the parent process " + + StreamableToString(parent_process_id)); + } + + const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); + HANDLE dup_event_handle; + + if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, + ::GetCurrentProcess(), &dup_event_handle, + 0x0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort("Unable to duplicate the event handle " + + StreamableToString(event_handle_as_size_t) + + " from the parent process " + + StreamableToString(parent_process_id)); + } + + const int write_fd = + ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); + if (write_fd == -1) { + DeathTestAbort("Unable to convert pipe handle " + + StreamableToString(write_handle_as_size_t) + + " to a file descriptor"); + } + + // Signals the parent that the write end of the pipe has been acquired + // so the parent can release its own write end. + ::SetEvent(dup_event_handle); + + return write_fd; +} +# endif // GTEST_OS_WINDOWS + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { + if (GTEST_FLAG(internal_run_death_test) == "") return nullptr; + + // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we + // can use it here. + int line = -1; + int index = -1; + ::std::vector< ::std::string> fields; + SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); + int write_fd = -1; + +# if GTEST_OS_WINDOWS + + unsigned int parent_process_id = 0; + size_t write_handle_as_size_t = 0; + size_t event_handle_as_size_t = 0; + + if (fields.size() != 6 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &parent_process_id) + || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) + || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + write_fd = GetStatusFileDescriptor(parent_process_id, + write_handle_as_size_t, + event_handle_as_size_t); + +# elif GTEST_OS_FUCHSIA + + if (fields.size() != 3 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + +# else + + if (fields.size() != 4 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &write_fd)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + +# endif // GTEST_OS_WINDOWS + + return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); +} + +} // namespace internal + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-filepath.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-filepath.cc new file mode 100644 index 0000000000000000000000000000000000000000..bd7b99ff03e49616afd07ce961351dd7928ebe8f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-filepath.cc @@ -0,0 +1,379 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "gtest/internal/gtest-filepath.h" + +#include +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-message.h" + +#if GTEST_OS_WINDOWS_MOBILE +# include +#elif GTEST_OS_WINDOWS +# include +# include +#else +# include +# include // Some Linux distributions define PATH_MAX here. +#endif // GTEST_OS_WINDOWS_MOBILE + +#include "gtest/internal/gtest-string.h" + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_MAX_ _MAX_PATH +#elif defined(PATH_MAX) +# define GTEST_PATH_MAX_ PATH_MAX +#elif defined(_XOPEN_PATH_MAX) +# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +#else +# define GTEST_PATH_MAX_ _POSIX_PATH_MAX +#endif // GTEST_OS_WINDOWS + +namespace testing { +namespace internal { + +#if GTEST_OS_WINDOWS +// On Windows, '\\' is the standard path separator, but many tools and the +// Windows API also accept '/' as an alternate path separator. Unless otherwise +// noted, a file path can contain either kind of path separators, or a mixture +// of them. +const char kPathSeparator = '\\'; +const char kAlternatePathSeparator = '/'; +const char kAlternatePathSeparatorString[] = "/"; +# if GTEST_OS_WINDOWS_MOBILE +// Windows CE doesn't have a current directory. You should not use +// the current directory in tests on Windows CE, but this at least +// provides a reasonable fallback. +const char kCurrentDirectoryString[] = "\\"; +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES +const DWORD kInvalidFileAttributes = 0xffffffff; +# else +const char kCurrentDirectoryString[] = ".\\"; +# endif // GTEST_OS_WINDOWS_MOBILE +#else +const char kPathSeparator = '/'; +const char kCurrentDirectoryString[] = "./"; +#endif // GTEST_OS_WINDOWS + +// Returns whether the given character is a valid path separator. +static bool IsPathSeparator(char c) { +#if GTEST_HAS_ALT_PATH_SEP_ + return (c == kPathSeparator) || (c == kAlternatePathSeparator); +#else + return c == kPathSeparator; +#endif +} + +// Returns the current working directory, or "" if unsuccessful. +FilePath FilePath::GetCurrentDir() { +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ + GTEST_OS_WINDOWS_RT || ARDUINO || defined(ESP_PLATFORM) + // These platforms do not have a current directory, so we just return + // something reasonable. + return FilePath(kCurrentDirectoryString); +#elif GTEST_OS_WINDOWS + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(_getcwd(cwd, sizeof(cwd)) == nullptr ? "" : cwd); +#else + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + char* result = getcwd(cwd, sizeof(cwd)); +# if GTEST_OS_NACL + // getcwd will likely fail in NaCl due to the sandbox, so return something + // reasonable. The user may have provided a shim implementation for getcwd, + // however, so fallback only when failure is detected. + return FilePath(result == nullptr ? kCurrentDirectoryString : cwd); +# endif // GTEST_OS_NACL + return FilePath(result == nullptr ? "" : cwd); +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns a copy of the FilePath with the case-insensitive extension removed. +// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns +// FilePath("dir/file"). If a case-insensitive extension is not +// found, returns a copy of the original FilePath. +FilePath FilePath::RemoveExtension(const char* extension) const { + const std::string dot_extension = std::string(".") + extension; + if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) { + return FilePath(pathname_.substr( + 0, pathname_.length() - dot_extension.length())); + } + return *this; +} + +// Returns a pointer to the last occurrence of a valid path separator in +// the FilePath. On Windows, for example, both '/' and '\' are valid path +// separators. Returns NULL if no path separator was found. +const char* FilePath::FindLastPathSeparator() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); +#if GTEST_HAS_ALT_PATH_SEP_ + const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); + // Comparing two pointers of which only one is NULL is undefined. + if (last_alt_sep != nullptr && + (last_sep == nullptr || last_alt_sep > last_sep)) { + return last_alt_sep; + } +#endif + return last_sep; +} + +// Returns a copy of the FilePath with the directory part removed. +// Example: FilePath("path/to/file").RemoveDirectoryName() returns +// FilePath("file"). If there is no directory part ("just_a_file"), it returns +// the FilePath unmodified. If there is no file part ("just_a_dir/") it +// returns an empty FilePath (""). +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveDirectoryName() const { + const char* const last_sep = FindLastPathSeparator(); + return last_sep ? FilePath(last_sep + 1) : *this; +} + +// RemoveFileName returns the directory path with the filename removed. +// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". +// If the FilePath is "a_file" or "/a_file", RemoveFileName returns +// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does +// not have a file, like "just/a/dir/", it returns the FilePath unmodified. +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveFileName() const { + const char* const last_sep = FindLastPathSeparator(); + std::string dir; + if (last_sep) { + dir = std::string(c_str(), static_cast(last_sep + 1 - c_str())); + } else { + dir = kCurrentDirectoryString; + } + return FilePath(dir); +} + +// Helper functions for naming files in a directory for xml output. + +// Given directory = "dir", base_name = "test", number = 0, +// extension = "xml", returns "dir/test.xml". If number is greater +// than zero (e.g., 12), returns "dir/test_12.xml". +// On Windows platform, uses \ as the separator rather than /. +FilePath FilePath::MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension) { + std::string file; + if (number == 0) { + file = base_name.string() + "." + extension; + } else { + file = base_name.string() + "_" + StreamableToString(number) + + "." + extension; + } + return ConcatPaths(directory, FilePath(file)); +} + +// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". +// On Windows, uses \ as the separator rather than /. +FilePath FilePath::ConcatPaths(const FilePath& directory, + const FilePath& relative_path) { + if (directory.IsEmpty()) + return relative_path; + const FilePath dir(directory.RemoveTrailingPathSeparator()); + return FilePath(dir.string() + kPathSeparator + relative_path.string()); +} + +// Returns true if pathname describes something findable in the file-system, +// either a file, directory, or whatever. +bool FilePath::FileOrDirectoryExists() const { +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + return attributes != kInvalidFileAttributes; +#else + posix::StatStruct file_stat; + return posix::Stat(pathname_.c_str(), &file_stat) == 0; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns true if pathname describes a directory in the file-system +// that exists. +bool FilePath::DirectoryExists() const { + bool result = false; +#if GTEST_OS_WINDOWS + // Don't strip off trailing separator if path is a root directory on + // Windows (like "C:\\"). + const FilePath& path(IsRootDirectory() ? *this : + RemoveTrailingPathSeparator()); +#else + const FilePath& path(*this); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + if ((attributes != kInvalidFileAttributes) && + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = true; + } +#else + posix::StatStruct file_stat; + result = posix::Stat(path.c_str(), &file_stat) == 0 && + posix::IsDir(file_stat); +#endif // GTEST_OS_WINDOWS_MOBILE + + return result; +} + +// Returns true if pathname describes a root directory. (Windows has one +// root directory per disk drive.) +bool FilePath::IsRootDirectory() const { +#if GTEST_OS_WINDOWS + return pathname_.length() == 3 && IsAbsolutePath(); +#else + return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); +#endif +} + +// Returns true if pathname describes an absolute path. +bool FilePath::IsAbsolutePath() const { + const char* const name = pathname_.c_str(); +#if GTEST_OS_WINDOWS + return pathname_.length() >= 3 && + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && + IsPathSeparator(name[2]); +#else + return IsPathSeparator(name[0]); +#endif +} + +// Returns a pathname for a file that does not currently exist. The pathname +// will be directory/base_name.extension or +// directory/base_name_.extension if directory/base_name.extension +// already exists. The number will be incremented until a pathname is found +// that does not already exist. +// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. +// There could be a race condition if two or more processes are calling this +// function at the same time -- they could both pick the same filename. +FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension) { + FilePath full_pathname; + int number = 0; + do { + full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); + } while (full_pathname.FileOrDirectoryExists()); + return full_pathname; +} + +// Returns true if FilePath ends with a path separator, which indicates that +// it is intended to represent a directory. Returns false otherwise. +// This does NOT check that a directory (or file) actually exists. +bool FilePath::IsDirectory() const { + return !pathname_.empty() && + IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); +} + +// Create directories so that path exists. Returns true if successful or if +// the directories already exist; returns false if unable to create directories +// for any reason. +bool FilePath::CreateDirectoriesRecursively() const { + if (!this->IsDirectory()) { + return false; + } + + if (pathname_.length() == 0 || this->DirectoryExists()) { + return true; + } + + const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); + return parent.CreateDirectoriesRecursively() && this->CreateFolder(); +} + +// Create the directory so that path exists. Returns true if successful or +// if the directory already exists; returns false if unable to create the +// directory for any reason, including if the parent directory does not +// exist. Not named "CreateDirectory" because that's a macro on Windows. +bool FilePath::CreateFolder() const { +#if GTEST_OS_WINDOWS_MOBILE + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + int result = CreateDirectory(unicode, nullptr) ? 0 : -1; + delete [] unicode; +#elif GTEST_OS_WINDOWS + int result = _mkdir(pathname_.c_str()); +#else + int result = mkdir(pathname_.c_str(), 0777); +#endif // GTEST_OS_WINDOWS_MOBILE + + if (result == -1) { + return this->DirectoryExists(); // An error is OK if the directory exists. + } + return true; // No error. +} + +// If input name has a trailing separator character, remove it and return the +// name, otherwise return the name string unmodified. +// On Windows platform, uses \ as the separator, other platforms use /. +FilePath FilePath::RemoveTrailingPathSeparator() const { + return IsDirectory() + ? FilePath(pathname_.substr(0, pathname_.length() - 1)) + : *this; +} + +// Removes any redundant separators that might be in the pathname. +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other +// redundancies that might be in a pathname involving "." or "..". +void FilePath::Normalize() { + if (pathname_.c_str() == nullptr) { + pathname_ = ""; + return; + } + const char* src = pathname_.c_str(); + char* const dest = new char[pathname_.length() + 1]; + char* dest_ptr = dest; + memset(dest_ptr, 0, pathname_.length() + 1); + + while (*src != '\0') { + *dest_ptr = *src; + if (!IsPathSeparator(*src)) { + src++; + } else { +#if GTEST_HAS_ALT_PATH_SEP_ + if (*dest_ptr == kAlternatePathSeparator) { + *dest_ptr = kPathSeparator; + } +#endif + while (IsPathSeparator(*src)) + src++; + } + dest_ptr++; + } + *dest_ptr = '\0'; + pathname_ = dest; + delete[] dest; +} + +} // namespace internal +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-internal-inl.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-internal-inl.h new file mode 100644 index 0000000000000000000000000000000000000000..8ed70daab0943969d5a3b3b88b1196775f0b1d3a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-internal-inl.h @@ -0,0 +1,1211 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility functions and classes used by the Google C++ testing framework.// +// This file contains purely Google Test's internal implementation. Please +// DO NOT #INCLUDE IT IN A USER PROGRAM. + +#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ +#define GTEST_SRC_GTEST_INTERNAL_INL_H_ + +#ifndef _WIN32_WCE +# include +#endif // !_WIN32_WCE +#include +#include // For strtoll/_strtoul64/malloc/free. +#include // For memmove. + +#include +#include +#include +#include + +#include "gtest/internal/gtest-port.h" + +#if GTEST_CAN_STREAM_RESULTS_ +# include // NOLINT +# include // NOLINT +#endif + +#if GTEST_OS_WINDOWS +# include // NOLINT +#endif // GTEST_OS_WINDOWS + +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { + +// Declares the flags. +// +// We don't want the users to modify this flag in the code, but want +// Google Test's own unit tests to be able to access it. Therefore we +// declare it here as opposed to in gtest.h. +GTEST_DECLARE_bool_(death_test_use_fork); + +namespace internal { + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; + +// Names of the flags (needed for parsing Google Test flags). +const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; +const char kBreakOnFailureFlag[] = "break_on_failure"; +const char kCatchExceptionsFlag[] = "catch_exceptions"; +const char kColorFlag[] = "color"; +const char kFilterFlag[] = "filter"; +const char kListTestsFlag[] = "list_tests"; +const char kOutputFlag[] = "output"; +const char kPrintTimeFlag[] = "print_time"; +const char kPrintUTF8Flag[] = "print_utf8"; +const char kRandomSeedFlag[] = "random_seed"; +const char kRepeatFlag[] = "repeat"; +const char kShuffleFlag[] = "shuffle"; +const char kStackTraceDepthFlag[] = "stack_trace_depth"; +const char kStreamResultToFlag[] = "stream_result_to"; +const char kThrowOnFailureFlag[] = "throw_on_failure"; +const char kFlagfileFlag[] = "flagfile"; + +// A valid random seed must be in [1, kMaxRandomSeed]. +const int kMaxRandomSeed = 99999; + +// g_help_flag is true if and only if the --help flag or an equivalent form +// is specified on the command line. +GTEST_API_ extern bool g_help_flag; + +// Returns the current time in milliseconds. +GTEST_API_ TimeInMillis GetTimeInMillis(); + +// Returns true if and only if Google Test should use colors in the output. +GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); + +// Formats the given time in milliseconds as seconds. +GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); + +// Converts the given time in milliseconds to a date string in the ISO 8601 +// format, without the timezone information. N.B.: due to the use the +// non-reentrant localtime() function, this function is not thread safe. Do +// not use it in any code that can be called from multiple threads. +GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); + +// Parses a string for an Int32 flag, in the form of "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +GTEST_API_ bool ParseInt32Flag( + const char* str, const char* flag, Int32* value); + +// Returns a random seed in range [1, kMaxRandomSeed] based on the +// given --gtest_random_seed flag value. +inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { + const unsigned int raw_seed = (random_seed_flag == 0) ? + static_cast(GetTimeInMillis()) : + static_cast(random_seed_flag); + + // Normalizes the actual seed to range [1, kMaxRandomSeed] such that + // it's easy to type. + const int normalized_seed = + static_cast((raw_seed - 1U) % + static_cast(kMaxRandomSeed)) + 1; + return normalized_seed; +} + +// Returns the first valid random seed after 'seed'. The behavior is +// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is +// considered to be 1. +inline int GetNextRandomSeed(int seed) { + GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) + << "Invalid random seed " << seed << " - must be in [1, " + << kMaxRandomSeed << "]."; + const int next_seed = seed + 1; + return (next_seed > kMaxRandomSeed) ? 1 : next_seed; +} + +// This class saves the values of all Google Test flags in its c'tor, and +// restores them in its d'tor. +class GTestFlagSaver { + public: + // The c'tor. + GTestFlagSaver() { + also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); + break_on_failure_ = GTEST_FLAG(break_on_failure); + catch_exceptions_ = GTEST_FLAG(catch_exceptions); + color_ = GTEST_FLAG(color); + death_test_style_ = GTEST_FLAG(death_test_style); + death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); + filter_ = GTEST_FLAG(filter); + internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); + list_tests_ = GTEST_FLAG(list_tests); + output_ = GTEST_FLAG(output); + print_time_ = GTEST_FLAG(print_time); + print_utf8_ = GTEST_FLAG(print_utf8); + random_seed_ = GTEST_FLAG(random_seed); + repeat_ = GTEST_FLAG(repeat); + shuffle_ = GTEST_FLAG(shuffle); + stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); + stream_result_to_ = GTEST_FLAG(stream_result_to); + throw_on_failure_ = GTEST_FLAG(throw_on_failure); + } + + // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. + ~GTestFlagSaver() { + GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; + GTEST_FLAG(break_on_failure) = break_on_failure_; + GTEST_FLAG(catch_exceptions) = catch_exceptions_; + GTEST_FLAG(color) = color_; + GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; + GTEST_FLAG(filter) = filter_; + GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; + GTEST_FLAG(list_tests) = list_tests_; + GTEST_FLAG(output) = output_; + GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(print_utf8) = print_utf8_; + GTEST_FLAG(random_seed) = random_seed_; + GTEST_FLAG(repeat) = repeat_; + GTEST_FLAG(shuffle) = shuffle_; + GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; + GTEST_FLAG(stream_result_to) = stream_result_to_; + GTEST_FLAG(throw_on_failure) = throw_on_failure_; + } + + private: + // Fields for saving the original values of flags. + bool also_run_disabled_tests_; + bool break_on_failure_; + bool catch_exceptions_; + std::string color_; + std::string death_test_style_; + bool death_test_use_fork_; + std::string filter_; + std::string internal_run_death_test_; + bool list_tests_; + std::string output_; + bool print_time_; + bool print_utf8_; + internal::Int32 random_seed_; + internal::Int32 repeat_; + bool shuffle_; + internal::Int32 stack_trace_depth_; + std::string stream_result_to_; + bool throw_on_failure_; +} GTEST_ATTRIBUTE_UNUSED_; + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted +// to "(Invalid Unicode 0xXXXXXXXX)". +GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded(); + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (e.g., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +GTEST_API_ bool ShouldShard(const char* total_shards_str, + const char* shard_index_str, + bool in_subprocess_for_death_test); + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error and +// and aborts. +GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); + +// Given the total number of shards, the shard index, and the test id, +// returns true if and only if the test should be run on this shard. The test id +// is some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +GTEST_API_ bool ShouldRunTestOnShard( + int total_shards, int shard_index, int test_id); + +// STL container utilities. + +// Returns the number of elements in the given container that satisfy +// the given predicate. +template +inline int CountIf(const Container& c, Predicate predicate) { + // Implemented as an explicit loop since std::count_if() in libCstd on + // Solaris has a non-standard signature. + int count = 0; + for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { + if (predicate(*it)) + ++count; + } + return count; +} + +// Applies a function/functor to each element in the container. +template +void ForEach(const Container& c, Functor functor) { + std::for_each(c.begin(), c.end(), functor); +} + +// Returns the i-th element of the vector, or default_value if i is not +// in range [0, v.size()). +template +inline E GetElementOr(const std::vector& v, int i, E default_value) { + return (i < 0 || i >= static_cast(v.size())) ? default_value + : v[static_cast(i)]; +} + +// Performs an in-place shuffle of a range of the vector's elements. +// 'begin' and 'end' are element indices as an STL-style range; +// i.e. [begin, end) are shuffled, where 'end' == size() means to +// shuffle to the end of the vector. +template +void ShuffleRange(internal::Random* random, int begin, int end, + std::vector* v) { + const int size = static_cast(v->size()); + GTEST_CHECK_(0 <= begin && begin <= size) + << "Invalid shuffle range start " << begin << ": must be in range [0, " + << size << "]."; + GTEST_CHECK_(begin <= end && end <= size) + << "Invalid shuffle range finish " << end << ": must be in range [" + << begin << ", " << size << "]."; + + // Fisher-Yates shuffle, from + // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + for (int range_width = end - begin; range_width >= 2; range_width--) { + const int last_in_range = begin + range_width - 1; + const int selected = + begin + + static_cast(random->Generate(static_cast(range_width))); + std::swap((*v)[static_cast(selected)], + (*v)[static_cast(last_in_range)]); + } +} + +// Performs an in-place shuffle of the vector's elements. +template +inline void Shuffle(internal::Random* random, std::vector* v) { + ShuffleRange(random, 0, static_cast(v->size()), v); +} + +// A function for deleting an object. Handy for being used as a +// functor. +template +static void Delete(T* x) { + delete x; +} + +// A predicate that checks the key of a TestProperty against a known key. +// +// TestPropertyKeyIs is copyable. +class TestPropertyKeyIs { + public: + // Constructor. + // + // TestPropertyKeyIs has NO default constructor. + explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} + + // Returns true if and only if the test name of test property matches on key_. + bool operator()(const TestProperty& test_property) const { + return test_property.key() == key_; + } + + private: + std::string key_; +}; + +// Class UnitTestOptions. +// +// This class contains functions for processing options the user +// specifies when running the tests. It has only static members. +// +// In most cases, the user can specify an option using either an +// environment variable or a command line flag. E.g. you can set the +// test filter using either GTEST_FILTER or --gtest_filter. If both +// the variable and the flag are present, the latter overrides the +// former. +class GTEST_API_ UnitTestOptions { + public: + // Functions for processing the gtest_output flag. + + // Returns the output format, or "" for normal printed output. + static std::string GetOutputFormat(); + + // Returns the absolute path of the requested output file, or the + // default (test_detail.xml in the original working directory) if + // none was explicitly specified. + static std::string GetAbsolutePathToOutputFile(); + + // Functions for processing the gtest_filter flag. + + // Returns true if and only if the wildcard pattern matches the string. + // The first ':' or '\0' character in pattern marks the end of it. + // + // This recursive algorithm isn't very efficient, but is clear and + // works well enough for matching test names, which are short. + static bool PatternMatchesString(const char *pattern, const char *str); + + // Returns true if and only if the user-specified filter matches the test + // suite name and the test name. + static bool FilterMatchesTest(const std::string& test_suite_name, + const std::string& test_name); + +#if GTEST_OS_WINDOWS + // Function for supporting the gtest_catch_exception flag. + + // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the + // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. + // This function is useful as an __except condition. + static int GTestShouldProcessSEH(DWORD exception_code); +#endif // GTEST_OS_WINDOWS + + // Returns true if "name" matches the ':' separated list of glob-style + // filters in "filter". + static bool MatchesFilter(const std::string& name, const char* filter); +}; + +// Returns the current application's name, removing directory path if that +// is present. Used by UnitTestOptions::GetOutputFile. +GTEST_API_ FilePath GetCurrentExecutableName(); + +// The role interface for getting the OS stack trace as a string. +class OsStackTraceGetterInterface { + public: + OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface() {} + + // Returns the current OS stack trace as an std::string. Parameters: + // + // max_depth - the maximum number of stack frames to be included + // in the trace. + // skip_count - the number of top frames to be skipped; doesn't count + // against max_depth. + virtual std::string CurrentStackTrace(int max_depth, int skip_count) = 0; + + // UponLeavingGTest() should be called immediately before Google Test calls + // user code. It saves some information about the current stack that + // CurrentStackTrace() will use to find and hide Google Test stack frames. + virtual void UponLeavingGTest() = 0; + + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); +}; + +// A working implementation of the OsStackTraceGetterInterface interface. +class OsStackTraceGetter : public OsStackTraceGetterInterface { + public: + OsStackTraceGetter() {} + + std::string CurrentStackTrace(int max_depth, int skip_count) override; + void UponLeavingGTest() override; + + private: +#if GTEST_HAS_ABSL + Mutex mutex_; // Protects all internal state. + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to the stack trace code from within the user code. + void* caller_frame_ = nullptr; +#endif // GTEST_HAS_ABSL + + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); +}; + +// Information about a Google Test trace point. +struct TraceInfo { + const char* file; + int line; + std::string message; +}; + +// This is the default global test part result reporter used in UnitTestImpl. +// This class should only be used by UnitTestImpl. +class DefaultGlobalTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. Reports the test part + // result in the current test. + void ReportTestPartResult(const TestPartResult& result) override; + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); +}; + +// This is the default per thread test part result reporter used in +// UnitTestImpl. This class should only be used by UnitTestImpl. +class DefaultPerThreadTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. The implementation just + // delegates to the current global test part result reporter of *unit_test_. + void ReportTestPartResult(const TestPartResult& result) override; + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); +}; + +// The private implementation of the UnitTest class. We don't protect +// the methods under a mutex, as this class is not accessible by a +// user and the UnitTest class that delegates work to this class does +// proper locking. +class GTEST_API_ UnitTestImpl { + public: + explicit UnitTestImpl(UnitTest* parent); + virtual ~UnitTestImpl(); + + // There are two different ways to register your own TestPartResultReporter. + // You can register your own repoter to listen either only for test results + // from the current thread or for results from all threads. + // By default, each per-thread test result repoter just passes a new + // TestPartResult to the global test result reporter, which registers the + // test part result for the currently running test. + + // Returns the global test part result reporter. + TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); + + // Sets the global test part result reporter. + void SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter); + + // Returns the test part result reporter for the current thread. + TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); + + // Sets the test part result reporter for the current thread. + void SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter); + + // Gets the number of successful test suites. + int successful_test_suite_count() const; + + // Gets the number of failed test suites. + int failed_test_suite_count() const; + + // Gets the number of all test suites. + int total_test_suite_count() const; + + // Gets the number of all test suites that contain at least one test + // that should run. + int test_suite_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of skipped tests. + int skipped_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the time of the test program start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns true if and only if the unit test passed (i.e. all test suites + // passed). + bool Passed() const { return !Failed(); } + + // Returns true if and only if the unit test failed (i.e. some test suite + // failed or something outside of all tests failed). + bool Failed() const { + return failed_test_suite_count() > 0 || ad_hoc_test_result()->Failed(); + } + + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + const TestSuite* GetTestSuite(int i) const { + const int index = GetElementOr(test_suite_indices_, i, -1); + return index < 0 ? nullptr : test_suites_[static_cast(i)]; + } + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase* GetTestCase(int i) const { return GetTestSuite(i); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + TestSuite* GetMutableSuiteCase(int i) { + const int index = GetElementOr(test_suite_indices_, i, -1); + return index < 0 ? nullptr : test_suites_[static_cast(index)]; + } + + // Provides access to the event listener list. + TestEventListeners* listeners() { return &listeners_; } + + // Returns the TestResult for the test that's currently running, or + // the TestResult for the ad hoc test if no test is running. + TestResult* current_test_result(); + + // Returns the TestResult for the ad hoc test. + const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } + + // Sets the OS stack trace getter. + // + // Does nothing if the input and the current OS stack trace getter + // are the same; otherwise, deletes the old getter and makes the + // input the current getter. + void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); + + // Returns the current OS stack trace getter if it is not NULL; + // otherwise, creates an OsStackTraceGetter, makes it the current + // getter, and returns it. + OsStackTraceGetterInterface* os_stack_trace_getter(); + + // Returns the current OS stack trace as an std::string. + // + // The maximum number of stack frames to be included is specified by + // the gtest_stack_trace_depth flag. The skip_count parameter + // specifies the number of top frames to be skipped, which doesn't + // count against the number of frames to be included. + // + // For example, if Foo() calls Bar(), which in turn calls + // CurrentOsStackTraceExceptTop(1), Foo() will be included in the + // trace but Bar() and CurrentOsStackTraceExceptTop() won't. + std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; + + // Finds and returns a TestSuite with the given name. If one doesn't + // exist, creates one and returns it. + // + // Arguments: + // + // test_suite_name: name of the test suite + // type_param: the name of the test's type parameter, or NULL if + // this is not a typed or a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + TestSuite* GetTestSuite(const char* test_suite_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc); + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + TestCase* GetTestCase(const char* test_case_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) { + return GetTestSuite(test_case_name, type_param, set_up_tc, tear_down_tc); + } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Adds a TestInfo to the unit test. + // + // Arguments: + // + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + // test_info: the TestInfo object + void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc, + TestInfo* test_info) { + // In order to support thread-safe death tests, we need to + // remember the original working directory when the test program + // was first invoked. We cannot do this in RUN_ALL_TESTS(), as + // the user may have changed the current directory before calling + // RUN_ALL_TESTS(). Therefore we capture the current directory in + // AddTestInfo(), which is called to register a TEST or TEST_F + // before main() is reached. + if (original_working_dir_.IsEmpty()) { + original_working_dir_.Set(FilePath::GetCurrentDir()); + GTEST_CHECK_(!original_working_dir_.IsEmpty()) + << "Failed to get the current working directory."; + } + + GetTestSuite(test_info->test_suite_name(), test_info->type_param(), + set_up_tc, tear_down_tc) + ->AddTestInfo(test_info); + } + + // Returns ParameterizedTestSuiteRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() { + return parameterized_test_registry_; + } + + // Sets the TestSuite object for the test that's currently running. + void set_current_test_suite(TestSuite* a_current_test_suite) { + current_test_suite_ = a_current_test_suite; + } + + // Sets the TestInfo object for the test that's currently running. If + // current_test_info is NULL, the assertion results will be stored in + // ad_hoc_test_result_. + void set_current_test_info(TestInfo* a_current_test_info) { + current_test_info_ = a_current_test_info; + } + + // Registers all parameterized tests defined using TEST_P and + // INSTANTIATE_TEST_SUITE_P, creating regular tests for each test/parameter + // combination. This method can be called more then once; it has guards + // protecting from registering the tests more then once. If + // value-parameterized tests are disabled, RegisterParameterizedTests is + // present but does nothing. + void RegisterParameterizedTests(); + + // Runs all tests in this UnitTest object, prints the result, and + // returns true if all tests are successful. If any exception is + // thrown during a test, this test is considered to be failed, but + // the rest of the tests will still be run. + bool RunAllTests(); + + // Clears the results of all tests, except the ad hoc tests. + void ClearNonAdHocTestResult() { + ForEach(test_suites_, TestSuite::ClearTestSuiteResult); + } + + // Clears the results of ad-hoc test assertions. + void ClearAdHocTestResult() { + ad_hoc_test_result_.Clear(); + } + + // Adds a TestProperty to the current TestResult object when invoked in a + // context of a test or a test suite, or to the global property set. If the + // result already contains a property with the same key, the value will be + // updated. + void RecordProperty(const TestProperty& test_property); + + enum ReactionToSharding { + HONOR_SHARDING_PROTOCOL, + IGNORE_SHARDING_PROTOCOL + }; + + // Matches the full name of each test against the user-specified + // filter to decide whether the test should run, then records the + // result in each TestSuite and TestInfo object. + // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests + // based on sharding variables in the environment. + // Returns the number of tests that should run. + int FilterTests(ReactionToSharding shard_tests); + + // Prints the names of the tests matching the user-specified filter flag. + void ListTestsMatchingFilter(); + + const TestSuite* current_test_suite() const { return current_test_suite_; } + TestInfo* current_test_info() { return current_test_info_; } + const TestInfo* current_test_info() const { return current_test_info_; } + + // Returns the vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector& environments() { return environments_; } + + // Getters for the per-thread Google Test trace stack. + std::vector& gtest_trace_stack() { + return *(gtest_trace_stack_.pointer()); + } + const std::vector& gtest_trace_stack() const { + return gtest_trace_stack_.get(); + } + +#if GTEST_HAS_DEATH_TEST + void InitDeathTestSubprocessControlInfo() { + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + } + // Returns a pointer to the parsed --gtest_internal_run_death_test + // flag, or NULL if that flag was not specified. + // This information is useful only in a death test child process. + // Must not be called before a call to InitGoogleTest. + const InternalRunDeathTestFlag* internal_run_death_test_flag() const { + return internal_run_death_test_flag_.get(); + } + + // Returns a pointer to the current death test factory. + internal::DeathTestFactory* death_test_factory() { + return death_test_factory_.get(); + } + + void SuppressTestEventsIfInSubprocess(); + + friend class ReplaceDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + + // Initializes the event listener performing XML output as specified by + // UnitTestOptions. Must not be called before InitGoogleTest. + void ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Initializes the event listener for streaming test results to a socket. + // Must not be called before InitGoogleTest. + void ConfigureStreamingOutput(); +#endif + + // Performs initialization dependent upon flag values obtained in + // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to + // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest + // this function is also called from RunAllTests. Since this function can be + // called more than once, it has to be idempotent. + void PostFlagParsingInit(); + + // Gets the random seed used at the start of the current test iteration. + int random_seed() const { return random_seed_; } + + // Gets the random number generator. + internal::Random* random() { return &random_; } + + // Shuffles all test suites, and the tests within each test suite, + // making sure that death tests are still run first. + void ShuffleTests(); + + // Restores the test suites and tests to their order before the first shuffle. + void UnshuffleTests(); + + // Returns the value of GTEST_FLAG(catch_exceptions) at the moment + // UnitTest::Run() starts. + bool catch_exceptions() const { return catch_exceptions_; } + + private: + friend class ::testing::UnitTest; + + // Used by UnitTest::Run() to capture the state of + // GTEST_FLAG(catch_exceptions) at the moment it starts. + void set_catch_exceptions(bool value) { catch_exceptions_ = value; } + + // The UnitTest object that owns this implementation object. + UnitTest* const parent_; + + // The working directory when the first TEST() or TEST_F() was + // executed. + internal::FilePath original_working_dir_; + + // The default test part result reporters. + DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; + DefaultPerThreadTestPartResultReporter + default_per_thread_test_part_result_reporter_; + + // Points to (but doesn't own) the global test part result reporter. + TestPartResultReporterInterface* global_test_part_result_repoter_; + + // Protects read and write access to global_test_part_result_reporter_. + internal::Mutex global_test_part_result_reporter_mutex_; + + // Points to (but doesn't own) the per-thread test part result reporter. + internal::ThreadLocal + per_thread_test_part_result_reporter_; + + // The vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector environments_; + + // The vector of TestSuites in their original order. It owns the + // elements in the vector. + std::vector test_suites_; + + // Provides a level of indirection for the test suite list to allow + // easy shuffling and restoring the test suite order. The i-th + // element of this vector is the index of the i-th test suite in the + // shuffled order. + std::vector test_suite_indices_; + + // ParameterizedTestRegistry object used to register value-parameterized + // tests. + internal::ParameterizedTestSuiteRegistry parameterized_test_registry_; + + // Indicates whether RegisterParameterizedTests() has been called already. + bool parameterized_tests_registered_; + + // Index of the last death test suite registered. Initially -1. + int last_death_test_suite_; + + // This points to the TestSuite for the currently running test. It + // changes as Google Test goes through one test suite after another. + // When no test is running, this is set to NULL and Google Test + // stores assertion results in ad_hoc_test_result_. Initially NULL. + TestSuite* current_test_suite_; + + // This points to the TestInfo for the currently running test. It + // changes as Google Test goes through one test after another. When + // no test is running, this is set to NULL and Google Test stores + // assertion results in ad_hoc_test_result_. Initially NULL. + TestInfo* current_test_info_; + + // Normally, a user only writes assertions inside a TEST or TEST_F, + // or inside a function called by a TEST or TEST_F. Since Google + // Test keeps track of which test is current running, it can + // associate such an assertion with the test it belongs to. + // + // If an assertion is encountered when no TEST or TEST_F is running, + // Google Test attributes the assertion result to an imaginary "ad hoc" + // test, and records the result in ad_hoc_test_result_. + TestResult ad_hoc_test_result_; + + // The list of event listeners that can be used to track events inside + // Google Test. + TestEventListeners listeners_; + + // The OS stack trace getter. Will be deleted when the UnitTest + // object is destructed. By default, an OsStackTraceGetter is used, + // but the user can set this field to use a custom getter if that is + // desired. + OsStackTraceGetterInterface* os_stack_trace_getter_; + + // True if and only if PostFlagParsingInit() has been called. + bool post_flag_parse_init_performed_; + + // The random number seed used at the beginning of the test run. + int random_seed_; + + // Our random number generator. + internal::Random random_; + + // The time of the test program start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp_; + + // How long the test took to run, in milliseconds. + TimeInMillis elapsed_time_; + +#if GTEST_HAS_DEATH_TEST + // The decomposed components of the gtest_internal_run_death_test flag, + // parsed when RUN_ALL_TESTS is called. + std::unique_ptr internal_run_death_test_flag_; + std::unique_ptr death_test_factory_; +#endif // GTEST_HAS_DEATH_TEST + + // A per-thread stack of traces created by the SCOPED_TRACE() macro. + internal::ThreadLocal > gtest_trace_stack_; + + // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() + // starts. + bool catch_exceptions_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); +}; // class UnitTestImpl + +// Convenience function for accessing the global UnitTest +// implementation object. +inline UnitTestImpl* GetUnitTestImpl() { + return UnitTest::GetInstance()->impl(); +} + +#if GTEST_USES_SIMPLE_RE + +// Internal helper functions for implementing the simple regular +// expression matcher. +GTEST_API_ bool IsInSet(char ch, const char* str); +GTEST_API_ bool IsAsciiDigit(char ch); +GTEST_API_ bool IsAsciiPunct(char ch); +GTEST_API_ bool IsRepeat(char ch); +GTEST_API_ bool IsAsciiWhiteSpace(char ch); +GTEST_API_ bool IsAsciiWordChar(char ch); +GTEST_API_ bool IsValidEscape(char ch); +GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); +GTEST_API_ bool ValidateRegex(const char* regex); +GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); +GTEST_API_ bool MatchRepetitionAndRegexAtHead( + bool escaped, char ch, char repeat, const char* regex, const char* str); +GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); + +#endif // GTEST_USES_SIMPLE_RE + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); + +#if GTEST_HAS_DEATH_TEST + +// Returns the message describing the last system error, regardless of the +// platform. +GTEST_API_ std::string GetLastErrnoDescription(); + +// Attempts to parse a string into a positive integer pointed to by the +// number parameter. Returns true if that is possible. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use +// it here. +template +bool ParseNaturalNumber(const ::std::string& str, Integer* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtoXXX's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !IsDigit(str[0])) { + return false; + } + errno = 0; + + char* end; + // BiggestConvertible is the largest integer type that system-provided + // string-to-number conversion routines can return. + +# if GTEST_OS_WINDOWS && !defined(__GNUC__) + + // MSVC and C++ Builder define __int64 instead of the standard long long. + typedef unsigned __int64 BiggestConvertible; + const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); + +# else + + typedef unsigned long long BiggestConvertible; // NOLINT + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); + +# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) + + const bool parse_success = *end == '\0' && errno == 0; + + GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); + + const Integer result = static_cast(parsed); + if (parse_success && static_cast(result) == parsed) { + *number = result; + return true; + } + return false; +} +#endif // GTEST_HAS_DEATH_TEST + +// TestResult contains some private methods that should be hidden from +// Google Test user but are required for testing. This class allow our tests +// to access them. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +class TestResultAccessor { + public: + static void RecordProperty(TestResult* test_result, + const std::string& xml_element, + const TestProperty& property) { + test_result->RecordProperty(xml_element, property); + } + + static void ClearTestPartResults(TestResult* test_result) { + test_result->ClearTestPartResults(); + } + + static const std::vector& test_part_results( + const TestResult& test_result) { + return test_result.test_part_results(); + } +}; + +#if GTEST_CAN_STREAM_RESULTS_ + +// Streams test results to the given port on the given host machine. +class StreamingListener : public EmptyTestEventListener { + public: + // Abstract base class for writing strings to a socket. + class AbstractSocketWriter { + public: + virtual ~AbstractSocketWriter() {} + + // Sends a string to the socket. + virtual void Send(const std::string& message) = 0; + + // Closes the socket. + virtual void CloseConnection() {} + + // Sends a string and a newline to the socket. + void SendLn(const std::string& message) { Send(message + "\n"); } + }; + + // Concrete class for actually writing strings to a socket. + class SocketWriter : public AbstractSocketWriter { + public: + SocketWriter(const std::string& host, const std::string& port) + : sockfd_(-1), host_name_(host), port_num_(port) { + MakeConnection(); + } + + ~SocketWriter() override { + if (sockfd_ != -1) + CloseConnection(); + } + + // Sends a string to the socket. + void Send(const std::string& message) override { + GTEST_CHECK_(sockfd_ != -1) + << "Send() can be called only when there is a connection."; + + const auto len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != static_cast(len)) { + GTEST_LOG_(WARNING) + << "stream_result_to: failed to stream to " + << host_name_ << ":" << port_num_; + } + } + + private: + // Creates a client socket and connects to the server. + void MakeConnection(); + + // Closes the socket. + void CloseConnection() override { + GTEST_CHECK_(sockfd_ != -1) + << "CloseConnection() can be called only when there is a connection."; + + close(sockfd_); + sockfd_ = -1; + } + + int sockfd_; // socket file descriptor + const std::string host_name_; + const std::string port_num_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); + }; // class SocketWriter + + // Escapes '=', '&', '%', and '\n' characters in str as "%xx". + static std::string UrlEncode(const char* str); + + StreamingListener(const std::string& host, const std::string& port) + : socket_writer_(new SocketWriter(host, port)) { + Start(); + } + + explicit StreamingListener(AbstractSocketWriter* socket_writer) + : socket_writer_(socket_writer) { Start(); } + + void OnTestProgramStart(const UnitTest& /* unit_test */) override { + SendLn("event=TestProgramStart"); + } + + void OnTestProgramEnd(const UnitTest& unit_test) override { + // Note that Google Test current only report elapsed time for each + // test iteration, not for the entire test program. + SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); + + // Notify the streaming server to stop. + socket_writer_->CloseConnection(); + } + + void OnTestIterationStart(const UnitTest& /* unit_test */, + int iteration) override { + SendLn("event=TestIterationStart&iteration=" + + StreamableToString(iteration)); + } + + void OnTestIterationEnd(const UnitTest& unit_test, + int /* iteration */) override { + SendLn("event=TestIterationEnd&passed=" + + FormatBool(unit_test.Passed()) + "&elapsed_time=" + + StreamableToString(unit_test.elapsed_time()) + "ms"); + } + + // Note that "event=TestCaseStart" is a wire format and has to remain + // "case" for compatibilty + void OnTestCaseStart(const TestCase& test_case) override { + SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); + } + + // Note that "event=TestCaseEnd" is a wire format and has to remain + // "case" for compatibilty + void OnTestCaseEnd(const TestCase& test_case) override { + SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + + "ms"); + } + + void OnTestStart(const TestInfo& test_info) override { + SendLn(std::string("event=TestStart&name=") + test_info.name()); + } + + void OnTestEnd(const TestInfo& test_info) override { + SendLn("event=TestEnd&passed=" + + FormatBool((test_info.result())->Passed()) + + "&elapsed_time=" + + StreamableToString((test_info.result())->elapsed_time()) + "ms"); + } + + void OnTestPartResult(const TestPartResult& test_part_result) override { + const char* file_name = test_part_result.file_name(); + if (file_name == nullptr) file_name = ""; + SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + + "&line=" + StreamableToString(test_part_result.line_number()) + + "&message=" + UrlEncode(test_part_result.message())); + } + + private: + // Sends the given message and a newline to the socket. + void SendLn(const std::string& message) { socket_writer_->SendLn(message); } + + // Called at the start of streaming to notify the receiver what + // protocol we are using. + void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } + + std::string FormatBool(bool value) { return value ? "1" : "0"; } + + const std::unique_ptr socket_writer_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); +}; // class StreamingListener + +#endif // GTEST_CAN_STREAM_RESULTS_ + +} // namespace internal +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-matchers.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-matchers.cc new file mode 100644 index 0000000000000000000000000000000000000000..7d2fb6851ec4173af6dddc7ae0720e43e43ace52 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-matchers.cc @@ -0,0 +1,97 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file implements just enough of the matcher interface to allow +// EXPECT_DEATH and friends to accept a matcher argument. + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-matchers.h" + +#include + +namespace testing { + +// Constructs a matcher that matches a const std::string& whose value is +// equal to s. +Matcher::Matcher(const std::string& s) { *this = Eq(s); } + +// Constructs a matcher that matches a const std::string& whose value is +// equal to s. +Matcher::Matcher(const char* s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a std::string whose value is equal to +// s. +Matcher::Matcher(const std::string& s) { *this = Eq(s); } + +// Constructs a matcher that matches a std::string whose value is equal to +// s. +Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } + +#if GTEST_HAS_ABSL +// Constructs a matcher that matches a const absl::string_view& whose value is +// equal to s. +Matcher::Matcher(const std::string& s) { + *this = Eq(s); +} + +// Constructs a matcher that matches a const absl::string_view& whose value is +// equal to s. +Matcher::Matcher(const char* s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a const absl::string_view& whose value is +// equal to s. +Matcher::Matcher(absl::string_view s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a absl::string_view whose value is equal to +// s. +Matcher::Matcher(const std::string& s) { *this = Eq(s); } + +// Constructs a matcher that matches a absl::string_view whose value is equal to +// s. +Matcher::Matcher(const char* s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a absl::string_view whose value is equal to +// s. +Matcher::Matcher(absl::string_view s) { + *this = Eq(std::string(s)); +} +#endif // GTEST_HAS_ABSL + +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-port.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-port.cc new file mode 100644 index 0000000000000000000000000000000000000000..fc5ba6becc55fd2cd6bb178454a7edc56998b1ab --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-port.cc @@ -0,0 +1,1399 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#include "gtest/internal/gtest-port.h" + +#include +#include +#include +#include +#include +#include + +#if GTEST_OS_WINDOWS +# include +# include +# include +# include // Used in ThreadLocal. +# ifdef _MSC_VER +# include +# endif // _MSC_VER +#else +# include +#endif // GTEST_OS_WINDOWS + +#if GTEST_OS_MAC +# include +# include +# include +#endif // GTEST_OS_MAC + +#if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ + GTEST_OS_NETBSD || GTEST_OS_OPENBSD +# include +# if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD +# include +# endif +#endif + +#if GTEST_OS_QNX +# include +# include +# include +#endif // GTEST_OS_QNX + +#if GTEST_OS_AIX +# include +# include +#endif // GTEST_OS_AIX + +#if GTEST_OS_FUCHSIA +# include +# include +#endif // GTEST_OS_FUCHSIA + +#include "gtest/gtest-spi.h" +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" +#include "src/gtest-internal-inl.h" + +namespace testing { +namespace internal { + +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC and C++Builder do not provide a definition of STDERR_FILENO. +const int kStdOutFileno = 1; +const int kStdErrFileno = 2; +#else +const int kStdOutFileno = STDOUT_FILENO; +const int kStdErrFileno = STDERR_FILENO; +#endif // _MSC_VER + +#if GTEST_OS_LINUX + +namespace { +template +T ReadProcFileField(const std::string& filename, int field) { + std::string dummy; + std::ifstream file(filename.c_str()); + while (field-- > 0) { + file >> dummy; + } + T output = 0; + file >> output; + return output; +} +} // namespace + +// Returns the number of active threads, or 0 when there is an error. +size_t GetThreadCount() { + const std::string filename = + (Message() << "/proc/" << getpid() << "/stat").GetString(); + return ReadProcFileField(filename, 19); +} + +#elif GTEST_OS_MAC + +size_t GetThreadCount() { + const task_t task = mach_task_self(); + mach_msg_type_number_t thread_count; + thread_act_array_t thread_list; + const kern_return_t status = task_threads(task, &thread_list, &thread_count); + if (status == KERN_SUCCESS) { + // task_threads allocates resources in thread_list and we need to free them + // to avoid leaks. + vm_deallocate(task, + reinterpret_cast(thread_list), + sizeof(thread_t) * thread_count); + return static_cast(thread_count); + } else { + return 0; + } +} + +#elif GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ + GTEST_OS_NETBSD + +#if GTEST_OS_NETBSD +#undef KERN_PROC +#define KERN_PROC KERN_PROC2 +#define kinfo_proc kinfo_proc2 +#endif + +#if GTEST_OS_DRAGONFLY +#define KP_NLWP(kp) (kp.kp_nthreads) +#elif GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD +#define KP_NLWP(kp) (kp.ki_numthreads) +#elif GTEST_OS_NETBSD +#define KP_NLWP(kp) (kp.p_nlwps) +#endif + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + int mib[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID, + getpid(), +#if GTEST_OS_NETBSD + sizeof(struct kinfo_proc), + 1, +#endif + }; + u_int miblen = sizeof(mib) / sizeof(mib[0]); + struct kinfo_proc info; + size_t size = sizeof(info); + if (sysctl(mib, miblen, &info, &size, NULL, 0)) { + return 0; + } + return static_cast(KP_NLWP(info)); +} +#elif GTEST_OS_OPENBSD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + int mib[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID | KERN_PROC_SHOW_THREADS, + getpid(), + sizeof(struct kinfo_proc), + 0, + }; + u_int miblen = sizeof(mib) / sizeof(mib[0]); + + // get number of structs + size_t size; + if (sysctl(mib, miblen, NULL, &size, NULL, 0)) { + return 0; + } + mib[5] = size / mib[4]; + + // populate array of structs + struct kinfo_proc info[mib[5]]; + if (sysctl(mib, miblen, &info, &size, NULL, 0)) { + return 0; + } + + // exclude empty members + int nthreads = 0; + for (int i = 0; i < size / mib[4]; i++) { + if (info[i].p_tid != -1) + nthreads++; + } + return nthreads; +} + +#elif GTEST_OS_QNX + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const int fd = open("/proc/self/as", O_RDONLY); + if (fd < 0) { + return 0; + } + procfs_info process_info; + const int status = + devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), nullptr); + close(fd); + if (status == EOK) { + return static_cast(process_info.num_threads); + } else { + return 0; + } +} + +#elif GTEST_OS_AIX + +size_t GetThreadCount() { + struct procentry64 entry; + pid_t pid = getpid(); + int status = getprocs64(&entry, sizeof(entry), nullptr, 0, &pid, 1); + if (status == 1) { + return entry.pi_thcount; + } else { + return 0; + } +} + +#elif GTEST_OS_FUCHSIA + +size_t GetThreadCount() { + int dummy_buffer; + size_t avail; + zx_status_t status = zx_object_get_info( + zx_process_self(), + ZX_INFO_PROCESS_THREADS, + &dummy_buffer, + 0, + nullptr, + &avail); + if (status == ZX_OK) { + return avail; + } else { + return 0; + } +} + +#else + +size_t GetThreadCount() { + // There's no portable way to detect the number of threads, so we just + // return 0 to indicate that we cannot detect it. + return 0; +} + +#endif // GTEST_OS_LINUX + +#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS + +void SleepMilliseconds(int n) { + ::Sleep(static_cast(n)); +} + +AutoHandle::AutoHandle() + : handle_(INVALID_HANDLE_VALUE) {} + +AutoHandle::AutoHandle(Handle handle) + : handle_(handle) {} + +AutoHandle::~AutoHandle() { + Reset(); +} + +AutoHandle::Handle AutoHandle::Get() const { + return handle_; +} + +void AutoHandle::Reset() { + Reset(INVALID_HANDLE_VALUE); +} + +void AutoHandle::Reset(HANDLE handle) { + // Resetting with the same handle we already own is invalid. + if (handle_ != handle) { + if (IsCloseable()) { + ::CloseHandle(handle_); + } + handle_ = handle; + } else { + GTEST_CHECK_(!IsCloseable()) + << "Resetting a valid handle to itself is likely a programmer error " + "and thus not allowed."; + } +} + +bool AutoHandle::IsCloseable() const { + // Different Windows APIs may use either of these values to represent an + // invalid handle. + return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE; +} + +Notification::Notification() + : event_(::CreateEvent(nullptr, // Default security attributes. + TRUE, // Do not reset automatically. + FALSE, // Initially unset. + nullptr)) { // Anonymous event. + GTEST_CHECK_(event_.Get() != nullptr); +} + +void Notification::Notify() { + GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); +} + +void Notification::WaitForNotification() { + GTEST_CHECK_( + ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); +} + +Mutex::Mutex() + : owner_thread_id_(0), + type_(kDynamic), + critical_section_init_phase_(0), + critical_section_(new CRITICAL_SECTION) { + ::InitializeCriticalSection(critical_section_); +} + +Mutex::~Mutex() { + // Static mutexes are leaked intentionally. It is not thread-safe to try + // to clean them up. + if (type_ == kDynamic) { + ::DeleteCriticalSection(critical_section_); + delete critical_section_; + critical_section_ = nullptr; + } +} + +void Mutex::Lock() { + ThreadSafeLazyInit(); + ::EnterCriticalSection(critical_section_); + owner_thread_id_ = ::GetCurrentThreadId(); +} + +void Mutex::Unlock() { + ThreadSafeLazyInit(); + // We don't protect writing to owner_thread_id_ here, as it's the + // caller's responsibility to ensure that the current thread holds the + // mutex when this is called. + owner_thread_id_ = 0; + ::LeaveCriticalSection(critical_section_); +} + +// Does nothing if the current thread holds the mutex. Otherwise, crashes +// with high probability. +void Mutex::AssertHeld() { + ThreadSafeLazyInit(); + GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId()) + << "The current thread is not holding the mutex @" << this; +} + +namespace { + +#ifdef _MSC_VER +// Use the RAII idiom to flag mem allocs that are intentionally never +// deallocated. The motivation is to silence the false positive mem leaks +// that are reported by the debug version of MS's CRT which can only detect +// if an alloc is missing a matching deallocation. +// Example: +// MemoryIsNotDeallocated memory_is_not_deallocated; +// critical_section_ = new CRITICAL_SECTION; +// +class MemoryIsNotDeallocated +{ + public: + MemoryIsNotDeallocated() : old_crtdbg_flag_(0) { + old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT + // doesn't report mem leak if there's no matching deallocation. + _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF); + } + + ~MemoryIsNotDeallocated() { + // Restore the original _CRTDBG_ALLOC_MEM_DF flag + _CrtSetDbgFlag(old_crtdbg_flag_); + } + + private: + int old_crtdbg_flag_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated); +}; +#endif // _MSC_VER + +} // namespace + +// Initializes owner_thread_id_ and critical_section_ in static mutexes. +void Mutex::ThreadSafeLazyInit() { + // Dynamic mutexes are initialized in the constructor. + if (type_ == kStatic) { + switch ( + ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) { + case 0: + // If critical_section_init_phase_ was 0 before the exchange, we + // are the first to test it and need to perform the initialization. + owner_thread_id_ = 0; + { + // Use RAII to flag that following mem alloc is never deallocated. +#ifdef _MSC_VER + MemoryIsNotDeallocated memory_is_not_deallocated; +#endif // _MSC_VER + critical_section_ = new CRITICAL_SECTION; + } + ::InitializeCriticalSection(critical_section_); + // Updates the critical_section_init_phase_ to 2 to signal + // initialization complete. + GTEST_CHECK_(::InterlockedCompareExchange( + &critical_section_init_phase_, 2L, 1L) == + 1L); + break; + case 1: + // Somebody else is already initializing the mutex; spin until they + // are done. + while (::InterlockedCompareExchange(&critical_section_init_phase_, + 2L, + 2L) != 2L) { + // Possibly yields the rest of the thread's time slice to other + // threads. + ::Sleep(0); + } + break; + + case 2: + break; // The mutex is already initialized and ready for use. + + default: + GTEST_CHECK_(false) + << "Unexpected value of critical_section_init_phase_ " + << "while initializing a static mutex."; + } + } +} + +namespace { + +class ThreadWithParamSupport : public ThreadWithParamBase { + public: + static HANDLE CreateThread(Runnable* runnable, + Notification* thread_can_start) { + ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); + DWORD thread_id; + HANDLE thread_handle = ::CreateThread( + nullptr, // Default security. + 0, // Default stack size. + &ThreadWithParamSupport::ThreadMain, + param, // Parameter to ThreadMainStatic + 0x0, // Default creation flags. + &thread_id); // Need a valid pointer for the call to work under Win98. + GTEST_CHECK_(thread_handle != nullptr) + << "CreateThread failed with error " << ::GetLastError() << "."; + if (thread_handle == nullptr) { + delete param; + } + return thread_handle; + } + + private: + struct ThreadMainParam { + ThreadMainParam(Runnable* runnable, Notification* thread_can_start) + : runnable_(runnable), + thread_can_start_(thread_can_start) { + } + std::unique_ptr runnable_; + // Does not own. + Notification* thread_can_start_; + }; + + static DWORD WINAPI ThreadMain(void* ptr) { + // Transfers ownership. + std::unique_ptr param(static_cast(ptr)); + if (param->thread_can_start_ != nullptr) + param->thread_can_start_->WaitForNotification(); + param->runnable_->Run(); + return 0; + } + + // Prohibit instantiation. + ThreadWithParamSupport(); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport); +}; + +} // namespace + +ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable, + Notification* thread_can_start) + : thread_(ThreadWithParamSupport::CreateThread(runnable, + thread_can_start)) { +} + +ThreadWithParamBase::~ThreadWithParamBase() { + Join(); +} + +void ThreadWithParamBase::Join() { + GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0) + << "Failed to join the thread with error " << ::GetLastError() << "."; +} + +// Maps a thread to a set of ThreadIdToThreadLocals that have values +// instantiated on that thread and notifies them when the thread exits. A +// ThreadLocal instance is expected to persist until all threads it has +// values on have terminated. +class ThreadLocalRegistryImpl { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + DWORD current_thread = ::GetCurrentThreadId(); + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(current_thread); + if (thread_local_pos == thread_to_thread_locals->end()) { + thread_local_pos = thread_to_thread_locals->insert( + std::make_pair(current_thread, ThreadLocalValues())).first; + StartWatcherThreadFor(current_thread); + } + ThreadLocalValues& thread_local_values = thread_local_pos->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos == thread_local_values.end()) { + value_pos = + thread_local_values + .insert(std::make_pair( + thread_local_instance, + std::shared_ptr( + thread_local_instance->NewValueForCurrentThread()))) + .first; + } + return value_pos->second.get(); + } + + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + std::vector > value_holders; + // Clean up the ThreadLocalValues data structure while holding the lock, but + // defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + for (ThreadIdToThreadLocals::iterator it = + thread_to_thread_locals->begin(); + it != thread_to_thread_locals->end(); + ++it) { + ThreadLocalValues& thread_local_values = it->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos != thread_local_values.end()) { + value_holders.push_back(value_pos->second); + thread_local_values.erase(value_pos); + // This 'if' can only be successful at most once, so theoretically we + // could break out of the loop here, but we don't bother doing so. + } + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + static void OnThreadExit(DWORD thread_id) { + GTEST_CHECK_(thread_id != 0) << ::GetLastError(); + std::vector > value_holders; + // Clean up the ThreadIdToThreadLocals data structure while holding the + // lock, but defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(thread_id); + if (thread_local_pos != thread_to_thread_locals->end()) { + ThreadLocalValues& thread_local_values = thread_local_pos->second; + for (ThreadLocalValues::iterator value_pos = + thread_local_values.begin(); + value_pos != thread_local_values.end(); + ++value_pos) { + value_holders.push_back(value_pos->second); + } + thread_to_thread_locals->erase(thread_local_pos); + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + private: + // In a particular thread, maps a ThreadLocal object to its value. + typedef std::map > + ThreadLocalValues; + // Stores all ThreadIdToThreadLocals having values in a thread, indexed by + // thread's ID. + typedef std::map ThreadIdToThreadLocals; + + // Holds the thread id and thread handle that we pass from + // StartWatcherThreadFor to WatcherThreadFunc. + typedef std::pair ThreadIdAndHandle; + + static void StartWatcherThreadFor(DWORD thread_id) { + // The returned handle will be kept in thread_map and closed by + // watcher_thread in WatcherThreadFunc. + HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, + FALSE, + thread_id); + GTEST_CHECK_(thread != nullptr); + // We need to pass a valid thread ID pointer into CreateThread for it + // to work correctly under Win98. + DWORD watcher_thread_id; + HANDLE watcher_thread = ::CreateThread( + nullptr, // Default security. + 0, // Default stack size + &ThreadLocalRegistryImpl::WatcherThreadFunc, + reinterpret_cast(new ThreadIdAndHandle(thread_id, thread)), + CREATE_SUSPENDED, &watcher_thread_id); + GTEST_CHECK_(watcher_thread != nullptr); + // Give the watcher thread the same priority as ours to avoid being + // blocked by it. + ::SetThreadPriority(watcher_thread, + ::GetThreadPriority(::GetCurrentThread())); + ::ResumeThread(watcher_thread); + ::CloseHandle(watcher_thread); + } + + // Monitors exit from a given thread and notifies those + // ThreadIdToThreadLocals about thread termination. + static DWORD WINAPI WatcherThreadFunc(LPVOID param) { + const ThreadIdAndHandle* tah = + reinterpret_cast(param); + GTEST_CHECK_( + ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); + OnThreadExit(tah->first); + ::CloseHandle(tah->second); + delete tah; + return 0; + } + + // Returns map of thread local instances. + static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { + mutex_.AssertHeld(); +#ifdef _MSC_VER + MemoryIsNotDeallocated memory_is_not_deallocated; +#endif // _MSC_VER + static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals(); + return map; + } + + // Protects access to GetThreadLocalsMapLocked() and its return value. + static Mutex mutex_; + // Protects access to GetThreadMapLocked() and its return value. + static Mutex thread_map_mutex_; +}; + +Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); +Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); + +ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + return ThreadLocalRegistryImpl::GetValueOnCurrentThread( + thread_local_instance); +} + +void ThreadLocalRegistry::OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); +} + +#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS + +#if GTEST_USES_POSIX_RE + +// Implements RE. Currently only needed for death tests. + +RE::~RE() { + if (is_valid_) { + // regfree'ing an invalid regex might crash because the content + // of the regex is undefined. Since the regex's are essentially + // the same, one cannot be valid (or invalid) without the other + // being so too. + regfree(&partial_regex_); + regfree(&full_regex_); + } + free(const_cast(pattern_)); +} + +// Returns true if and only if regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.full_regex_, str, 1, &match, 0) == 0; +} + +// Returns true if and only if regular expression re matches a substring of +// str (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = posix::StrDup(regex); + + // Reserves enough bytes to hold the regular expression used for a + // full match. + const size_t full_regex_len = strlen(regex) + 10; + char* const full_pattern = new char[full_regex_len]; + + snprintf(full_pattern, full_regex_len, "^(%s)$", regex); + is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; + // We want to call regcomp(&partial_regex_, ...) even if the + // previous expression returns false. Otherwise partial_regex_ may + // not be properly initialized can may cause trouble when it's + // freed. + // + // Some implementation of POSIX regex (e.g. on at least some + // versions of Cygwin) doesn't accept the empty string as a valid + // regex. We change it to an equivalent form "()" to be safe. + if (is_valid_) { + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; + } + EXPECT_TRUE(is_valid_) + << "Regular expression \"" << regex + << "\" is not a valid POSIX Extended regular expression."; + + delete[] full_pattern; +} + +#elif GTEST_USES_SIMPLE_RE + +// Returns true if and only if ch appears anywhere in str (excluding the +// terminating '\0' character). +bool IsInSet(char ch, const char* str) { + return ch != '\0' && strchr(str, ch) != nullptr; +} + +// Returns true if and only if ch belongs to the given classification. +// Unlike similar functions in , these aren't affected by the +// current locale. +bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsAsciiPunct(char ch) { + return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); +} +bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } +bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsAsciiWordChar(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9') || ch == '_'; +} + +// Returns true if and only if "\\c" is a supported escape sequence. +bool IsValidEscape(char c) { + return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); +} + +// Returns true if and only if the given atom (specified by escaped and +// pattern) matches ch. The result is undefined if the atom is invalid. +bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { + if (escaped) { // "\\p" where p is pattern_char. + switch (pattern_char) { + case 'd': return IsAsciiDigit(ch); + case 'D': return !IsAsciiDigit(ch); + case 'f': return ch == '\f'; + case 'n': return ch == '\n'; + case 'r': return ch == '\r'; + case 's': return IsAsciiWhiteSpace(ch); + case 'S': return !IsAsciiWhiteSpace(ch); + case 't': return ch == '\t'; + case 'v': return ch == '\v'; + case 'w': return IsAsciiWordChar(ch); + case 'W': return !IsAsciiWordChar(ch); + } + return IsAsciiPunct(pattern_char) && pattern_char == ch; + } + + return (pattern_char == '.' && ch != '\n') || pattern_char == ch; +} + +// Helper function used by ValidateRegex() to format error messages. +static std::string FormatRegexSyntaxError(const char* regex, int index) { + return (Message() << "Syntax error at index " << index + << " in simple regular expression \"" << regex << "\": ").GetString(); +} + +// Generates non-fatal failures and returns false if regex is invalid; +// otherwise returns true. +bool ValidateRegex(const char* regex) { + if (regex == nullptr) { + ADD_FAILURE() << "NULL is not a valid simple regular expression."; + return false; + } + + bool is_valid = true; + + // True if and only if ?, *, or + can follow the previous atom. + bool prev_repeatable = false; + for (int i = 0; regex[i]; i++) { + if (regex[i] == '\\') { // An escape sequence + i++; + if (regex[i] == '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "'\\' cannot appear at the end."; + return false; + } + + if (!IsValidEscape(regex[i])) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "invalid escape sequence \"\\" << regex[i] << "\"."; + is_valid = false; + } + prev_repeatable = true; + } else { // Not an escape sequence. + const char ch = regex[i]; + + if (ch == '^' && i > 0) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'^' can only appear at the beginning."; + is_valid = false; + } else if (ch == '$' && regex[i + 1] != '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'$' can only appear at the end."; + is_valid = false; + } else if (IsInSet(ch, "()[]{}|")) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' is unsupported."; + is_valid = false; + } else if (IsRepeat(ch) && !prev_repeatable) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' can only follow a repeatable token."; + is_valid = false; + } + + prev_repeatable = !IsInSet(ch, "^$?*+"); + } + } + + return is_valid; +} + +// Matches a repeated regex atom followed by a valid simple regular +// expression. The regex atom is defined as c if escaped is false, +// or \c otherwise. repeat is the repetition meta character (?, *, +// or +). The behavior is undefined if str contains too many +// characters to be indexable by size_t, in which case the test will +// probably time out anyway. We are fine with this limitation as +// std::string has it too. +bool MatchRepetitionAndRegexAtHead( + bool escaped, char c, char repeat, const char* regex, + const char* str) { + const size_t min_count = (repeat == '+') ? 1 : 0; + const size_t max_count = (repeat == '?') ? 1 : + static_cast(-1) - 1; + // We cannot call numeric_limits::max() as it conflicts with the + // max() macro on Windows. + + for (size_t i = 0; i <= max_count; ++i) { + // We know that the atom matches each of the first i characters in str. + if (i >= min_count && MatchRegexAtHead(regex, str + i)) { + // We have enough matches at the head, and the tail matches too. + // Since we only care about *whether* the pattern matches str + // (as opposed to *how* it matches), there is no need to find a + // greedy match. + return true; + } + if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) + return false; + } + return false; +} + +// Returns true if and only if regex matches a prefix of str. regex must +// be a valid simple regular expression and not start with "^", or the +// result is undefined. +bool MatchRegexAtHead(const char* regex, const char* str) { + if (*regex == '\0') // An empty regex matches a prefix of anything. + return true; + + // "$" only matches the end of a string. Note that regex being + // valid guarantees that there's nothing after "$" in it. + if (*regex == '$') + return *str == '\0'; + + // Is the first thing in regex an escape sequence? + const bool escaped = *regex == '\\'; + if (escaped) + ++regex; + if (IsRepeat(regex[1])) { + // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so + // here's an indirect recursion. It terminates as the regex gets + // shorter in each recursion. + return MatchRepetitionAndRegexAtHead( + escaped, regex[0], regex[1], regex + 2, str); + } else { + // regex isn't empty, isn't "$", and doesn't start with a + // repetition. We match the first atom of regex with the first + // character of str and recurse. + return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && + MatchRegexAtHead(regex + 1, str + 1); + } +} + +// Returns true if and only if regex matches any substring of str. regex must +// be a valid simple regular expression, or the result is undefined. +// +// The algorithm is recursive, but the recursion depth doesn't exceed +// the regex length, so we won't need to worry about running out of +// stack space normally. In rare cases the time complexity can be +// exponential with respect to the regex length + the string length, +// but usually it's must faster (often close to linear). +bool MatchRegexAnywhere(const char* regex, const char* str) { + if (regex == nullptr || str == nullptr) return false; + + if (*regex == '^') + return MatchRegexAtHead(regex + 1, str); + + // A successful match can be anywhere in str. + do { + if (MatchRegexAtHead(regex, str)) + return true; + } while (*str++ != '\0'); + return false; +} + +// Implements the RE class. + +RE::~RE() { + free(const_cast(pattern_)); + free(const_cast(full_pattern_)); +} + +// Returns true if and only if regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); +} + +// Returns true if and only if regular expression re matches a substring of +// str (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = full_pattern_ = nullptr; + if (regex != nullptr) { + pattern_ = posix::StrDup(regex); + } + + is_valid_ = ValidateRegex(regex); + if (!is_valid_) { + // No need to calculate the full pattern when the regex is invalid. + return; + } + + const size_t len = strlen(regex); + // Reserves enough bytes to hold the regular expression used for a + // full match: we need space to prepend a '^', append a '$', and + // terminate the string with '\0'. + char* buffer = static_cast(malloc(len + 3)); + full_pattern_ = buffer; + + if (*regex != '^') + *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. + + // We don't use snprintf or strncpy, as they trigger a warning when + // compiled with VC++ 8.0. + memcpy(buffer, regex, len); + buffer += len; + + if (len == 0 || regex[len - 1] != '$') + *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. + + *buffer = '\0'; +} + +#endif // GTEST_USES_POSIX_RE + +const char kUnknownFile[] = "unknown file"; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { + const std::string file_name(file == nullptr ? kUnknownFile : file); + + if (line < 0) { + return file_name + ":"; + } +#ifdef _MSC_VER + return file_name + "(" + StreamableToString(line) + "):"; +#else + return file_name + ":" + StreamableToString(line) + ":"; +#endif // _MSC_VER +} + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +// Note that FormatCompilerIndependentFileLocation() does NOT append colon +// to the file location it produces, unlike FormatFileLocation(). +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( + const char* file, int line) { + const std::string file_name(file == nullptr ? kUnknownFile : file); + + if (line < 0) + return file_name; + else + return file_name + ":" + StreamableToString(line); +} + +GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) + : severity_(severity) { + const char* const marker = + severity == GTEST_INFO ? "[ INFO ]" : + severity == GTEST_WARNING ? "[WARNING]" : + severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; + GetStream() << ::std::endl << marker << " " + << FormatFileLocation(file, line).c_str() << ": "; +} + +// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. +GTestLog::~GTestLog() { + GetStream() << ::std::endl; + if (severity_ == GTEST_FATAL) { + fflush(stderr); + posix::Abort(); + } +} + +// Disable Microsoft deprecation warnings for POSIX functions called from +// this class (creat, dup, dup2, and close) +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() + +#if GTEST_HAS_STREAM_REDIRECTION + +// Object that captures an output stream (stdout/stderr). +class CapturedStream { + public: + // The ctor redirects the stream to a temporary file. + explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { +# if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT + char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT + + ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); + const UINT success = ::GetTempFileNameA(temp_dir_path, + "gtest_redir", + 0, // Generate unique file name. + temp_file_path); + GTEST_CHECK_(success != 0) + << "Unable to create a temporary file in " << temp_dir_path; + const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " + << temp_file_path; + filename_ = temp_file_path; +# else + // There's no guarantee that a test has write access to the current + // directory, so we create the temporary file in the /tmp directory + // instead. We use /tmp on most systems, and /sdcard on Android. + // That's because Android doesn't have /tmp. +# if GTEST_OS_LINUX_ANDROID + // Note: Android applications are expected to call the framework's + // Context.getExternalStorageDirectory() method through JNI to get + // the location of the world-writable SD Card directory. However, + // this requires a Context handle, which cannot be retrieved + // globally from native code. Doing so also precludes running the + // code as part of a regular standalone executable, which doesn't + // run in a Dalvik process (e.g. when running it through 'adb shell'). + // + // The location /data/local/tmp is directly accessible from native code. + // '/sdcard' and other variants cannot be relied on, as they are not + // guaranteed to be mounted, or may have a delay in mounting. + char name_template[] = "/data/local/tmp/gtest_captured_stream.XXXXXX"; +# else + char name_template[] = "/tmp/captured_stream.XXXXXX"; +# endif // GTEST_OS_LINUX_ANDROID + const int captured_fd = mkstemp(name_template); + if (captured_fd == -1) { + GTEST_LOG_(WARNING) + << "Failed to create tmp file " << name_template + << " for test; does the test have access to the /tmp directory?"; + } + filename_ = name_template; +# endif // GTEST_OS_WINDOWS + fflush(nullptr); + dup2(captured_fd, fd_); + close(captured_fd); + } + + ~CapturedStream() { + remove(filename_.c_str()); + } + + std::string GetCapturedString() { + if (uncaptured_fd_ != -1) { + // Restores the original stream. + fflush(nullptr); + dup2(uncaptured_fd_, fd_); + close(uncaptured_fd_); + uncaptured_fd_ = -1; + } + + FILE* const file = posix::FOpen(filename_.c_str(), "r"); + if (file == nullptr) { + GTEST_LOG_(FATAL) << "Failed to open tmp file " << filename_ + << " for capturing stream."; + } + const std::string content = ReadEntireFile(file); + posix::FClose(file); + return content; + } + + private: + const int fd_; // A stream to capture. + int uncaptured_fd_; + // Name of the temporary file holding the stderr output. + ::std::string filename_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); +}; + +GTEST_DISABLE_MSC_DEPRECATED_POP_() + +static CapturedStream* g_captured_stderr = nullptr; +static CapturedStream* g_captured_stdout = nullptr; + +// Starts capturing an output stream (stdout/stderr). +static void CaptureStream(int fd, const char* stream_name, + CapturedStream** stream) { + if (*stream != nullptr) { + GTEST_LOG_(FATAL) << "Only one " << stream_name + << " capturer can exist at a time."; + } + *stream = new CapturedStream(fd); +} + +// Stops capturing the output stream and returns the captured string. +static std::string GetCapturedStream(CapturedStream** captured_stream) { + const std::string content = (*captured_stream)->GetCapturedString(); + + delete *captured_stream; + *captured_stream = nullptr; + + return content; +} + +// Starts capturing stdout. +void CaptureStdout() { + CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); +} + +// Starts capturing stderr. +void CaptureStderr() { + CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); +} + +// Stops capturing stdout and returns the captured string. +std::string GetCapturedStdout() { + return GetCapturedStream(&g_captured_stdout); +} + +// Stops capturing stderr and returns the captured string. +std::string GetCapturedStderr() { + return GetCapturedStream(&g_captured_stderr); +} + +#endif // GTEST_HAS_STREAM_REDIRECTION + + + + + +size_t GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); +} + +std::string ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const std::string content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +#if GTEST_HAS_DEATH_TEST +static const std::vector* g_injected_test_argvs = + nullptr; // Owned. + +std::vector GetInjectableArgvs() { + if (g_injected_test_argvs != nullptr) { + return *g_injected_test_argvs; + } + return GetArgvs(); +} + +void SetInjectableArgvs(const std::vector* new_argvs) { + if (g_injected_test_argvs != new_argvs) delete g_injected_test_argvs; + g_injected_test_argvs = new_argvs; +} + +void SetInjectableArgvs(const std::vector& new_argvs) { + SetInjectableArgvs( + new std::vector(new_argvs.begin(), new_argvs.end())); +} + +void ClearInjectableArgvs() { + delete g_injected_test_argvs; + g_injected_test_argvs = nullptr; +} +#endif // GTEST_HAS_DEATH_TEST + +#if GTEST_OS_WINDOWS_MOBILE +namespace posix { +void Abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +} // namespace posix +#endif // GTEST_OS_WINDOWS_MOBILE + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GTEST_FOO" in the open-source version. +static std::string FlagToEnvVar(const char* flag) { + const std::string full_flag = + (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); + + Message env_var; + for (size_t i = 0; i != full_flag.length(); i++) { + env_var << ToUpper(full_flag.c_str()[i]); + } + + return env_var.GetString(); +} + +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const Message& src_text, const char* str, Int32* value) { + // Parses the environment variable as a decimal integer. + char* end = nullptr; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value \"" << str << "\".\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + // Is the parsed value in the range of an Int32? + const Int32 result = static_cast(long_value); + if (long_value == LONG_MAX || long_value == LONG_MIN || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value " << str << ", which overflows.\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + *value = result; + return true; +} + +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true if and only if it's not "0". +bool BoolFromGTestEnv(const char* flag, bool default_value) { +#if defined(GTEST_GET_BOOL_FROM_ENV_) + return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); +#else + const std::string env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + return string_value == nullptr ? default_value + : strcmp(string_value, "0") != 0; +#endif // defined(GTEST_GET_BOOL_FROM_ENV_) +} + +// Reads and returns a 32-bit integer stored in the environment +// variable corresponding to the given flag; if it isn't set or +// doesn't represent a valid 32-bit integer, returns default_value. +Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { +#if defined(GTEST_GET_INT32_FROM_ENV_) + return GTEST_GET_INT32_FROM_ENV_(flag, default_value); +#else + const std::string env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + if (string_value == nullptr) { + // The environment variable is not set. + return default_value; + } + + Int32 result = default_value; + if (!ParseInt32(Message() << "Environment variable " << env_var, + string_value, &result)) { + printf("The default value %s is used.\n", + (Message() << default_value).GetString().c_str()); + fflush(stdout); + return default_value; + } + + return result; +#endif // defined(GTEST_GET_INT32_FROM_ENV_) +} + +// As a special case for the 'output' flag, if GTEST_OUTPUT is not +// set, we look for XML_OUTPUT_FILE, which is set by the Bazel build +// system. The value of XML_OUTPUT_FILE is a filename without the +// "xml:" prefix of GTEST_OUTPUT. +// Note that this is meant to be called at the call site so it does +// not check that the flag is 'output' +// In essence this checks an env variable called XML_OUTPUT_FILE +// and if it is set we prepend "xml:" to its value, if it not set we return "" +std::string OutputFlagAlsoCheckEnvVar(){ + std::string default_value_for_output_flag = ""; + const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE"); + if (nullptr != xml_output_file_env) { + default_value_for_output_flag = std::string("xml:") + xml_output_file_env; + } + return default_value_for_output_flag; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromGTestEnv(const char* flag, const char* default_value) { +#if defined(GTEST_GET_STRING_FROM_ENV_) + return GTEST_GET_STRING_FROM_ENV_(flag, default_value); +#else + const std::string env_var = FlagToEnvVar(flag); + const char* const value = posix::GetEnv(env_var.c_str()); + return value == nullptr ? default_value : value; +#endif // defined(GTEST_GET_STRING_FROM_ENV_) +} + +} // namespace internal +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-printers.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-printers.cc new file mode 100644 index 0000000000000000000000000000000000000000..3337be312ea400ff78c78766ec4a5ba229b0206d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-printers.cc @@ -0,0 +1,442 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Google Test - The Google C++ Testing and Mocking Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// It uses the << operator when possible, and prints the bytes in the +// object otherwise. A user can override its behavior for a class +// type Foo by defining either operator<<(::std::ostream&, const Foo&) +// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that +// defines Foo. + +#include "gtest/gtest-printers.h" +#include +#include +#include +#include // NOLINT +#include +#include "gtest/internal/gtest-port.h" +#include "src/gtest-internal-inl.h" + +namespace testing { + +namespace { + +using ::std::ostream; + +// Prints a segment of bytes in the given object. +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, + size_t count, ostream* os) { + char text[5] = ""; + for (size_t i = 0; i != count; i++) { + const size_t j = start + i; + if (i != 0) { + // Organizes the bytes into groups of 2 for easy parsing by + // human. + if ((j % 2) == 0) + *os << ' '; + else + *os << '-'; + } + GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); + *os << text; + } +} + +// Prints the bytes in the given value to the given ostream. +void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, + ostream* os) { + // Tells the user how big the object is. + *os << count << "-byte object <"; + + const size_t kThreshold = 132; + const size_t kChunkSize = 64; + // If the object size is bigger than kThreshold, we'll have to omit + // some details by printing only the first and the last kChunkSize + // bytes. + if (count < kThreshold) { + PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); + } else { + PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); + *os << " ... "; + // Rounds up to 2-byte boundary. + const size_t resume_pos = (count - kChunkSize + 1)/2*2; + PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); + } + *os << ">"; +} + +} // namespace + +namespace internal2 { + +// Delegates to PrintBytesInObjectToImpl() to print the bytes in the +// given object. The delegation simplifies the implementation, which +// uses the << operator and thus is easier done outside of the +// ::testing::internal namespace, which contains a << operator that +// sometimes conflicts with the one in STL. +void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, + ostream* os) { + PrintBytesInObjectToImpl(obj_bytes, count, os); +} + +} // namespace internal2 + +namespace internal { + +// Depending on the value of a char (or wchar_t), we print it in one +// of three formats: +// - as is if it's a printable ASCII (e.g. 'a', '2', ' '), +// - as a hexadecimal escape sequence (e.g. '\x7F'), or +// - as a special escape sequence (e.g. '\r', '\n'). +enum CharFormat { + kAsIs, + kHexEscape, + kSpecialEscape +}; + +// Returns true if c is a printable ASCII character. We test the +// value of c directly instead of calling isprint(), which is buggy on +// Windows Mobile. +inline bool IsPrintableAscii(wchar_t c) { + return 0x20 <= c && c <= 0x7E; +} + +// Prints a wide or narrow char c as a character literal without the +// quotes, escaping it when necessary; returns how c was formatted. +// The template argument UnsignedChar is the unsigned version of Char, +// which is the type of c. +template +static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { + wchar_t w_c = static_cast(c); + switch (w_c) { + case L'\0': + *os << "\\0"; + break; + case L'\'': + *os << "\\'"; + break; + case L'\\': + *os << "\\\\"; + break; + case L'\a': + *os << "\\a"; + break; + case L'\b': + *os << "\\b"; + break; + case L'\f': + *os << "\\f"; + break; + case L'\n': + *os << "\\n"; + break; + case L'\r': + *os << "\\r"; + break; + case L'\t': + *os << "\\t"; + break; + case L'\v': + *os << "\\v"; + break; + default: + if (IsPrintableAscii(w_c)) { + *os << static_cast(c); + return kAsIs; + } else { + ostream::fmtflags flags = os->flags(); + *os << "\\x" << std::hex << std::uppercase + << static_cast(static_cast(c)); + os->flags(flags); + return kHexEscape; + } + } + return kSpecialEscape; +} + +// Prints a wchar_t c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\'': + *os << "'"; + return kAsIs; + case L'"': + *os << "\\\""; + return kSpecialEscape; + default: + return PrintAsCharLiteralTo(c, os); + } +} + +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { + return PrintAsStringLiteralTo( + static_cast(static_cast(c)), os); +} + +// Prints a wide or narrow character c and its code. '\0' is printed +// as "'\\0'", other unprintable characters are also properly escaped +// using the standard C++ escape sequence. The template argument +// UnsignedChar is the unsigned version of Char, which is the type of c. +template +void PrintCharAndCodeTo(Char c, ostream* os) { + // First, print c as a literal in the most readable form we can find. + *os << ((sizeof(c) > 1) ? "L'" : "'"); + const CharFormat format = PrintAsCharLiteralTo(c, os); + *os << "'"; + + // To aid user debugging, we also print c's code in decimal, unless + // it's 0 (in which case c was printed as '\\0', making the code + // obvious). + if (c == 0) + return; + *os << " (" << static_cast(c); + + // For more convenience, we print c's code again in hexadecimal, + // unless c was already printed in the form '\x##' or the code is in + // [1, 9]. + if (format == kHexEscape || (1 <= c && c <= 9)) { + // Do nothing. + } else { + *os << ", 0x" << String::FormatHexInt(static_cast(c)); + } + *os << ")"; +} + +void PrintTo(unsigned char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} +void PrintTo(signed char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} + +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its code. L'\0' is printed as "L'\\0'". +void PrintTo(wchar_t wc, ostream* os) { + PrintCharAndCodeTo(wc, os); +} + +// Prints the given array of characters to the ostream. CharType must be either +// char or wchar_t. +// The array starts at begin, the length is len, it may include '\0' characters +// and may not be NUL-terminated. +template +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +static CharFormat PrintCharsAsStringTo( + const CharType* begin, size_t len, ostream* os) { + const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; + *os << kQuoteBegin; + bool is_previous_hex = false; + CharFormat print_format = kAsIs; + for (size_t index = 0; index < len; ++index) { + const CharType cur = begin[index]; + if (is_previous_hex && IsXDigit(cur)) { + // Previous character is of '\x..' form and this character can be + // interpreted as another hexadecimal digit in its number. Break string to + // disambiguate. + *os << "\" " << kQuoteBegin; + } + is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; + // Remember if any characters required hex escaping. + if (is_previous_hex) { + print_format = kHexEscape; + } + } + *os << "\""; + return print_format; +} + +// Prints a (const) char/wchar_t array of 'len' elements, starting at address +// 'begin'. CharType must be either char or wchar_t. +template +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +static void UniversalPrintCharArray( + const CharType* begin, size_t len, ostream* os) { + // The code + // const char kFoo[] = "foo"; + // generates an array of 4, not 3, elements, with the last one being '\0'. + // + // Therefore when printing a char array, we don't print the last element if + // it's '\0', such that the output matches the string literal as it's + // written in the source code. + if (len > 0 && begin[len - 1] == '\0') { + PrintCharsAsStringTo(begin, len - 1, os); + return; + } + + // If, however, the last element in the array is not '\0', e.g. + // const char kFoo[] = { 'f', 'o', 'o' }; + // we must print the entire array. We also print a message to indicate + // that the array is not NUL-terminated. + PrintCharsAsStringTo(begin, len, os); + *os << " (no terminating NUL)"; +} + +// Prints a (const) char array of 'len' elements, starting at address 'begin'. +void UniversalPrintArray(const char* begin, size_t len, ostream* os) { + UniversalPrintCharArray(begin, len, os); +} + +// Prints a (const) wchar_t array of 'len' elements, starting at address +// 'begin'. +void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { + UniversalPrintCharArray(begin, len, os); +} + +// Prints the given C string to the ostream. +void PrintTo(const char* s, ostream* os) { + if (s == nullptr) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintCharsAsStringTo(s, strlen(s), os); + } +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Prints the given wide C string to the ostream. +void PrintTo(const wchar_t* s, ostream* os) { + if (s == nullptr) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintCharsAsStringTo(s, wcslen(s), os); + } +} +#endif // wchar_t is native + +namespace { + +bool ContainsUnprintableControlCodes(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast(str); + + for (size_t i = 0; i < length; i++) { + unsigned char ch = *s++; + if (std::iscntrl(ch)) { + switch (ch) { + case '\t': + case '\n': + case '\r': + break; + default: + return true; + } + } + } + return false; +} + +bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t<= 0xbf; } + +bool IsValidUTF8(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast(str); + + for (size_t i = 0; i < length;) { + unsigned char lead = s[i++]; + + if (lead <= 0x7f) { + continue; // single-byte character (ASCII) 0..7F + } + if (lead < 0xc2) { + return false; // trail byte or non-shortest form + } else if (lead <= 0xdf && (i + 1) <= length && IsUTF8TrailByte(s[i])) { + ++i; // 2-byte character + } else if (0xe0 <= lead && lead <= 0xef && (i + 2) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + // check for non-shortest form and surrogate + (lead != 0xe0 || s[i] >= 0xa0) && + (lead != 0xed || s[i] < 0xa0)) { + i += 2; // 3-byte character + } else if (0xf0 <= lead && lead <= 0xf4 && (i + 3) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + IsUTF8TrailByte(s[i + 2]) && + // check for non-shortest form + (lead != 0xf0 || s[i] >= 0x90) && + (lead != 0xf4 || s[i] < 0x90)) { + i += 3; // 4-byte character + } else { + return false; + } + } + return true; +} + +void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { + if (!ContainsUnprintableControlCodes(str, length) && + IsValidUTF8(str, length)) { + *os << "\n As Text: \"" << str << "\""; + } +} + +} // anonymous namespace + +void PrintStringTo(const ::std::string& s, ostream* os) { + if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { + if (GTEST_FLAG(print_utf8)) { + ConditionalPrintAsText(s.data(), s.size(), os); + } + } +} + +#if GTEST_HAS_STD_WSTRING +void PrintWideStringTo(const ::std::wstring& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_STD_WSTRING + +} // namespace internal + +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-test-part.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-test-part.cc new file mode 100644 index 0000000000000000000000000000000000000000..178317a6bcdbd0f60a0db2317104e90ad0678713 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-test-part.cc @@ -0,0 +1,104 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// The Google C++ Testing and Mocking Framework (Google Test) + +#include "gtest/gtest-test-part.h" +#include "src/gtest-internal-inl.h" + +namespace testing { + +using internal::GetUnitTestImpl; + +// Gets the summary of the failure message by omitting the stack trace +// in it. +std::string TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, internal::kStackTraceMarker); + return stack_trace == nullptr ? message : std::string(message, stack_trace); +} + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { + return os << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess + ? "Success" + : result.type() == TestPartResult::kSkip + ? "Skipped" + : result.type() == TestPartResult::kFatalFailure + ? "Fatal failure" + : "Non-fatal failure") + << ":\n" + << result.message() << std::endl; +} + +// Appends a TestPartResult to the array. +void TestPartResultArray::Append(const TestPartResult& result) { + array_.push_back(result); +} + +// Returns the TestPartResult at the given index (0-based). +const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { + if (index < 0 || index >= size()) { + printf("\nInvalid index (%d) into TestPartResultArray.\n", index); + internal::posix::Abort(); + } + + return array_[static_cast(index)]; +} + +// Returns the number of TestPartResult objects in the array. +int TestPartResultArray::size() const { + return static_cast(array_.size()); +} + +namespace internal { + +HasNewFatalFailureHelper::HasNewFatalFailureHelper() + : has_new_fatal_failure_(false), + original_reporter_(GetUnitTestImpl()-> + GetTestPartResultReporterForCurrentThread()) { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); +} + +HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( + original_reporter_); +} + +void HasNewFatalFailureHelper::ReportTestPartResult( + const TestPartResult& result) { + if (result.fatally_failed()) + has_new_fatal_failure_ = true; + original_reporter_->ReportTestPartResult(result); +} + +} // namespace internal + +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-typed-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-typed-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..8677caf732b4239408313ac3ef98ba0474ba3665 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest-typed-test.cc @@ -0,0 +1,118 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#include "gtest/gtest-typed-test.h" + +#include "gtest/gtest.h" + +namespace testing { +namespace internal { + +#if GTEST_HAS_TYPED_TEST_P + +// Skips to the first non-space char in str. Returns an empty string if str +// contains only whitespace characters. +static const char* SkipSpaces(const char* str) { + while (IsSpace(*str)) + str++; + return str; +} + +static std::vector SplitIntoTestNames(const char* src) { + std::vector name_vec; + src = SkipSpaces(src); + for (; src != nullptr; src = SkipComma(src)) { + name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); + } + return name_vec; +} + +// Verifies that registered_tests match the test names in +// registered_tests_; returns registered_tests if successful, or +// aborts the program otherwise. +const char* TypedTestSuitePState::VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests) { + typedef RegisteredTestsMap::const_iterator RegisteredTestIter; + registered_ = true; + + std::vector name_vec = SplitIntoTestNames(registered_tests); + + Message errors; + + std::set tests; + for (std::vector::const_iterator name_it = name_vec.begin(); + name_it != name_vec.end(); ++name_it) { + const std::string& name = *name_it; + if (tests.count(name) != 0) { + errors << "Test " << name << " is listed more than once.\n"; + continue; + } + + bool found = false; + for (RegisteredTestIter it = registered_tests_.begin(); + it != registered_tests_.end(); + ++it) { + if (name == it->first) { + found = true; + break; + } + } + + if (found) { + tests.insert(name); + } else { + errors << "No test named " << name + << " can be found in this test suite.\n"; + } + } + + for (RegisteredTestIter it = registered_tests_.begin(); + it != registered_tests_.end(); + ++it) { + if (tests.count(it->first) == 0) { + errors << "You forgot to list test " << it->first << ".\n"; + } + } + + const std::string& errors_str = errors.GetString(); + if (errors_str != "") { + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors_str.c_str()); + fflush(stderr); + posix::Abort(); + } + + return registered_tests; +} + +#endif // GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest.cc new file mode 100644 index 0000000000000000000000000000000000000000..a5b4e5ac78ca1f00259d1ec5bfa7c3feaeee55ea --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest.cc @@ -0,0 +1,6177 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// The Google C++ Testing and Mocking Framework (Google Test) + +#include "gtest/gtest.h" +#include "gtest/internal/custom/gtest.h" +#include "gtest/gtest-spi.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include // NOLINT +#include +#include + +#if GTEST_OS_LINUX + +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +# include // NOLINT +# include // NOLINT +# include // NOLINT +// Declares vsnprintf(). This header is not available on Windows. +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include + +#elif GTEST_OS_ZOS +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +// On z/OS we additionally need strings.h for strcasecmp. +# include // NOLINT + +#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. + +# include // NOLINT +# undef min + +#elif GTEST_OS_WINDOWS // We are on Windows proper. + +# include // NOLINT +# undef min + +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT + +# if GTEST_OS_WINDOWS_MINGW +// MinGW has gettimeofday() but not _ftime64(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT +# endif // GTEST_OS_WINDOWS_MINGW + +#else + +// Assume other platforms have gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT +# include // NOLINT + +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +# include +#endif + +#if GTEST_CAN_STREAM_RESULTS_ +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +#endif + +#include "src/gtest-internal-inl.h" + +#if GTEST_OS_WINDOWS +# define vsnprintf _vsnprintf +#endif // GTEST_OS_WINDOWS + +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS +#include +#endif +#endif + +#if GTEST_HAS_ABSL +#include "absl/debugging/failure_signal_handler.h" +#include "absl/debugging/stacktrace.h" +#include "absl/debugging/symbolize.h" +#include "absl/strings/str_cat.h" +#endif // GTEST_HAS_ABSL + +namespace testing { + +using internal::CountIf; +using internal::ForEach; +using internal::GetElementOr; +using internal::Shuffle; + +// Constants. + +// A test whose test suite name or test name matches this filter is +// disabled and not run. +static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; + +// A test suite whose name matches this filter is considered a death +// test suite and will be run before test suites whose name doesn't +// match this filter. +static const char kDeathTestSuiteFilter[] = "*DeathTest:*DeathTest/*"; + +// A test filter that matches everything. +static const char kUniversalFilter[] = "*"; + +// The default output format. +static const char kDefaultOutputFormat[] = "xml"; +// The default output file. +static const char kDefaultOutputFile[] = "test_detail"; + +// The environment variable name for the test shard index. +static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; +// The environment variable name for the total number of test shards. +static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; +// The environment variable name for the test shard status file. +static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; + +namespace internal { + +// The text used in failure messages to indicate the start of the +// stack trace. +const char kStackTraceMarker[] = "\nStack trace:\n"; + +// g_help_flag is true if and only if the --help flag or an equivalent form +// is specified on the command line. +bool g_help_flag = false; + +// Utilty function to Open File for Writing +static FILE* OpenFileForWriting(const std::string& output_file) { + FILE* fileout = nullptr; + FilePath output_file_path(output_file); + FilePath output_dir(output_file_path.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + fileout = posix::FOpen(output_file.c_str(), "w"); + } + if (fileout == nullptr) { + GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\""; + } + return fileout; +} + +} // namespace internal + +// Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY +// environment variable. +static const char* GetDefaultFilter() { + const char* const testbridge_test_only = + internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY"); + if (testbridge_test_only != nullptr) { + return testbridge_test_only; + } + return kUniversalFilter; +} + +GTEST_DEFINE_bool_( + also_run_disabled_tests, + internal::BoolFromGTestEnv("also_run_disabled_tests", false), + "Run disabled tests too, in addition to the tests normally being run."); + +GTEST_DEFINE_bool_( + break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), + "True if and only if a failed assertion should be a debugger " + "break-point."); + +GTEST_DEFINE_bool_(catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", true), + "True if and only if " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); + +GTEST_DEFINE_string_( + color, + internal::StringFromGTestEnv("color", "auto"), + "Whether to use colors in the output. Valid values: yes, no, " + "and auto. 'auto' means to use colors if the output is " + "being sent to a terminal and the TERM environment variable " + "is set to a terminal type that supports colors."); + +GTEST_DEFINE_string_( + filter, + internal::StringFromGTestEnv("filter", GetDefaultFilter()), + "A colon-separated list of glob (not regex) patterns " + "for filtering the tests to run, optionally followed by a " + "'-' and a : separated list of negative patterns (tests to " + "exclude). A test is run if it matches one of the positive " + "patterns and does not match any of the negative patterns."); + +GTEST_DEFINE_bool_( + install_failure_signal_handler, + internal::BoolFromGTestEnv("install_failure_signal_handler", false), + "If true and supported on the current platform, " GTEST_NAME_ " should " + "install a signal handler that dumps debugging information when fatal " + "signals are raised."); + +GTEST_DEFINE_bool_(list_tests, false, + "List all tests without running them."); + +// The net priority order after flag processing is thus: +// --gtest_output command line flag +// GTEST_OUTPUT environment variable +// XML_OUTPUT_FILE environment variable +// '' +GTEST_DEFINE_string_( + output, + internal::StringFromGTestEnv("output", + internal::OutputFlagAlsoCheckEnvVar().c_str()), + "A format (defaults to \"xml\" but can be specified to be \"json\"), " + "optionally followed by a colon and an output file name or directory. " + "A directory is indicated by a trailing pathname separator. " + "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " + "If a directory is specified, output files will be created " + "within that directory, with file-names based on the test " + "executable's name and, if necessary, made unique by adding " + "digits."); + +GTEST_DEFINE_bool_(print_time, internal::BoolFromGTestEnv("print_time", true), + "True if and only if " GTEST_NAME_ + " should display elapsed time in text output."); + +GTEST_DEFINE_bool_(print_utf8, internal::BoolFromGTestEnv("print_utf8", true), + "True if and only if " GTEST_NAME_ + " prints UTF8 characters as text."); + +GTEST_DEFINE_int32_( + random_seed, + internal::Int32FromGTestEnv("random_seed", 0), + "Random number seed to use when shuffling test orders. Must be in range " + "[1, 99999], or 0 to use a seed based on the current time."); + +GTEST_DEFINE_int32_( + repeat, + internal::Int32FromGTestEnv("repeat", 1), + "How many times to repeat each test. Specify a negative number " + "for repeating forever. Useful for shaking out flaky tests."); + +GTEST_DEFINE_bool_(show_internal_stack_frames, false, + "True if and only if " GTEST_NAME_ + " should include internal stack frames when " + "printing test failure stack traces."); + +GTEST_DEFINE_bool_(shuffle, internal::BoolFromGTestEnv("shuffle", false), + "True if and only if " GTEST_NAME_ + " should randomize tests' order on every run."); + +GTEST_DEFINE_int32_( + stack_trace_depth, + internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), + "The maximum number of stack frames to print when an " + "assertion fails. The valid range is 0 through 100, inclusive."); + +GTEST_DEFINE_string_( + stream_result_to, + internal::StringFromGTestEnv("stream_result_to", ""), + "This flag specifies the host name and the port number on which to stream " + "test results. Example: \"localhost:555\". The flag is effective only on " + "Linux."); + +GTEST_DEFINE_bool_( + throw_on_failure, + internal::BoolFromGTestEnv("throw_on_failure", false), + "When this flag is specified, a failed assertion will throw an exception " + "if exceptions are enabled or exit the program with a non-zero code " + "otherwise. For use with an external test framework."); + +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +GTEST_DEFINE_string_( + flagfile, + internal::StringFromGTestEnv("flagfile", ""), + "This flag specifies the flagfile to read command-line flags from."); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + +namespace internal { + +// Generates a random number from [0, range), using a Linear +// Congruential Generator (LCG). Crashes if 'range' is 0 or greater +// than kMaxRange. +UInt32 Random::Generate(UInt32 range) { + // These constants are the same as are used in glibc's rand(3). + // Use wider types than necessary to prevent unsigned overflow diagnostics. + state_ = static_cast(1103515245ULL*state_ + 12345U) % kMaxRange; + + GTEST_CHECK_(range > 0) + << "Cannot generate a number in the range [0, 0)."; + GTEST_CHECK_(range <= kMaxRange) + << "Generation of a number in [0, " << range << ") was requested, " + << "but this can only generate numbers in [0, " << kMaxRange << ")."; + + // Converting via modulus introduces a bit of downward bias, but + // it's simple, and a linear congruential generator isn't too good + // to begin with. + return state_ % range; +} + +// GTestIsInitialized() returns true if and only if the user has initialized +// Google Test. Useful for catching the user mistake of not initializing +// Google Test before calling RUN_ALL_TESTS(). +static bool GTestIsInitialized() { return GetArgvs().size() > 0; } + +// Iterates over a vector of TestSuites, keeping a running sum of the +// results of calling a given int-returning method on each. +// Returns the sum. +static int SumOverTestSuiteList(const std::vector& case_list, + int (TestSuite::*method)() const) { + int sum = 0; + for (size_t i = 0; i < case_list.size(); i++) { + sum += (case_list[i]->*method)(); + } + return sum; +} + +// Returns true if and only if the test suite passed. +static bool TestSuitePassed(const TestSuite* test_suite) { + return test_suite->should_run() && test_suite->Passed(); +} + +// Returns true if and only if the test suite failed. +static bool TestSuiteFailed(const TestSuite* test_suite) { + return test_suite->should_run() && test_suite->Failed(); +} + +// Returns true if and only if test_suite contains at least one test that +// should run. +static bool ShouldRunTestSuite(const TestSuite* test_suite) { + return test_suite->should_run(); +} + +// AssertHelper constructor. +AssertHelper::AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message) + : data_(new AssertHelperData(type, file, line, message)) { +} + +AssertHelper::~AssertHelper() { + delete data_; +} + +// Message assignment, for assertion streaming support. +void AssertHelper::operator=(const Message& message) const { + UnitTest::GetInstance()-> + AddTestPartResult(data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), + UnitTest::GetInstance()->impl() + ->CurrentOsStackTraceExceptTop(1) + // Skips the stack frame for this function itself. + ); // NOLINT +} + +// A copy of all command line arguments. Set by InitGoogleTest(). +static ::std::vector g_argvs; + +::std::vector GetArgvs() { +#if defined(GTEST_CUSTOM_GET_ARGVS_) + // GTEST_CUSTOM_GET_ARGVS_() may return a container of std::string or + // ::string. This code converts it to the appropriate type. + const auto& custom = GTEST_CUSTOM_GET_ARGVS_(); + return ::std::vector(custom.begin(), custom.end()); +#else // defined(GTEST_CUSTOM_GET_ARGVS_) + return g_argvs; +#endif // defined(GTEST_CUSTOM_GET_ARGVS_) +} + +// Returns the current application's name, removing directory path if that +// is present. +FilePath GetCurrentExecutableName() { + FilePath result; + +#if GTEST_OS_WINDOWS || GTEST_OS_OS2 + result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe")); +#else + result.Set(FilePath(GetArgvs()[0])); +#endif // GTEST_OS_WINDOWS + + return result.RemoveDirectoryName(); +} + +// Functions for processing the gtest_output flag. + +// Returns the output format, or "" for normal printed output. +std::string UnitTestOptions::GetOutputFormat() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + const char* const colon = strchr(gtest_output_flag, ':'); + return (colon == nullptr) + ? std::string(gtest_output_flag) + : std::string(gtest_output_flag, + static_cast(colon - gtest_output_flag)); +} + +// Returns the name of the requested output file, or the default if none +// was explicitly specified. +std::string UnitTestOptions::GetAbsolutePathToOutputFile() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + + std::string format = GetOutputFormat(); + if (format.empty()) + format = std::string(kDefaultOutputFormat); + + const char* const colon = strchr(gtest_output_flag, ':'); + if (colon == nullptr) + return internal::FilePath::MakeFileName( + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(kDefaultOutputFile), 0, + format.c_str()).string(); + + internal::FilePath output_name(colon + 1); + if (!output_name.IsAbsolutePath()) + output_name = internal::FilePath::ConcatPaths( + internal::FilePath(UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(colon + 1)); + + if (!output_name.IsDirectory()) + return output_name.string(); + + internal::FilePath result(internal::FilePath::GenerateUniqueFileName( + output_name, internal::GetCurrentExecutableName(), + GetOutputFormat().c_str())); + return result.string(); +} + +// Returns true if and only if the wildcard pattern matches the string. +// The first ':' or '\0' character in pattern marks the end of it. +// +// This recursive algorithm isn't very efficient, but is clear and +// works well enough for matching test names, which are short. +bool UnitTestOptions::PatternMatchesString(const char *pattern, + const char *str) { + switch (*pattern) { + case '\0': + case ':': // Either ':' or '\0' marks the end of the pattern. + return *str == '\0'; + case '?': // Matches any single character. + return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); + case '*': // Matches any string (possibly empty) of characters. + return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || + PatternMatchesString(pattern + 1, str); + default: // Non-special character. Matches itself. + return *pattern == *str && + PatternMatchesString(pattern + 1, str + 1); + } +} + +bool UnitTestOptions::MatchesFilter( + const std::string& name, const char* filter) { + const char *cur_pattern = filter; + for (;;) { + if (PatternMatchesString(cur_pattern, name.c_str())) { + return true; + } + + // Finds the next pattern in the filter. + cur_pattern = strchr(cur_pattern, ':'); + + // Returns if no more pattern can be found. + if (cur_pattern == nullptr) { + return false; + } + + // Skips the pattern separater (the ':' character). + cur_pattern++; + } +} + +// Returns true if and only if the user-specified filter matches the test +// suite name and the test name. +bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name, + const std::string& test_name) { + const std::string& full_name = test_suite_name + "." + test_name.c_str(); + + // Split --gtest_filter at '-', if there is one, to separate into + // positive filter and negative filter portions + const char* const p = GTEST_FLAG(filter).c_str(); + const char* const dash = strchr(p, '-'); + std::string positive; + std::string negative; + if (dash == nullptr) { + positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter + negative = ""; + } else { + positive = std::string(p, dash); // Everything up to the dash + negative = std::string(dash + 1); // Everything after the dash + if (positive.empty()) { + // Treat '-test1' as the same as '*-test1' + positive = kUniversalFilter; + } + } + + // A filter is a colon-separated list of patterns. It matches a + // test if any pattern in it matches the test. + return (MatchesFilter(full_name, positive.c_str()) && + !MatchesFilter(full_name, negative.c_str())); +} + +#if GTEST_HAS_SEH +// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the +// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. +// This function is useful as an __except condition. +int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { + // Google Test should handle a SEH exception if: + // 1. the user wants it to, AND + // 2. this is not a breakpoint exception, AND + // 3. this is not a C++ exception (VC++ implements them via SEH, + // apparently). + // + // SEH exception code for C++ exceptions. + // (see http://support.microsoft.com/kb/185294 for more information). + const DWORD kCxxExceptionCode = 0xe06d7363; + + bool should_handle = true; + + if (!GTEST_FLAG(catch_exceptions)) + should_handle = false; + else if (exception_code == EXCEPTION_BREAKPOINT) + should_handle = false; + else if (exception_code == kCxxExceptionCode) + should_handle = false; + + return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} +#endif // GTEST_HAS_SEH + +} // namespace internal + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. Intercepts only failures from the current thread. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + TestPartResultArray* result) + : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), + result_(result) { + Init(); +} + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + InterceptMode intercept_mode, TestPartResultArray* result) + : intercept_mode_(intercept_mode), + result_(result) { + Init(); +} + +void ScopedFakeTestPartResultReporter::Init() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + old_reporter_ = impl->GetGlobalTestPartResultReporter(); + impl->SetGlobalTestPartResultReporter(this); + } else { + old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); + impl->SetTestPartResultReporterForCurrentThread(this); + } +} + +// The d'tor restores the test part result reporter used by Google Test +// before. +ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + impl->SetGlobalTestPartResultReporter(old_reporter_); + } else { + impl->SetTestPartResultReporterForCurrentThread(old_reporter_); + } +} + +// Increments the test part result count and remembers the result. +// This method is from the TestPartResultReporterInterface interface. +void ScopedFakeTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + result_->Append(result); +} + +namespace internal { + +// Returns the type ID of ::testing::Test. We should always call this +// instead of GetTypeId< ::testing::Test>() to get the type ID of +// testing::Test. This is to work around a suspected linker bug when +// using Google Test as a framework on Mac OS X. The bug causes +// GetTypeId< ::testing::Test>() to return different values depending +// on whether the call is from the Google Test framework itself or +// from user test code. GetTestTypeId() is guaranteed to always +// return the same value, as it always calls GetTypeId<>() from the +// gtest.cc, which is within the Google Test framework. +TypeId GetTestTypeId() { + return GetTypeId(); +} + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); + +// This predicate-formatter checks that 'results' contains a test part +// failure of the given type and that the failure message contains the +// given substring. +static AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const std::string& substr) { + const std::string expected(type == TestPartResult::kFatalFailure ? + "1 fatal failure" : + "1 non-fatal failure"); + Message msg; + if (results.size() != 1) { + msg << "Expected: " << expected << "\n" + << " Actual: " << results.size() << " failures"; + for (int i = 0; i < results.size(); i++) { + msg << "\n" << results.GetTestPartResult(i); + } + return AssertionFailure() << msg; + } + + const TestPartResult& r = results.GetTestPartResult(0); + if (r.type() != type) { + return AssertionFailure() << "Expected: " << expected << "\n" + << " Actual:\n" + << r; + } + + if (strstr(r.message(), substr.c_str()) == nullptr) { + return AssertionFailure() << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; + } + + return AssertionSuccess(); +} + +// The constructor of SingleFailureChecker remembers where to look up +// test part results, what type of failure we expect, and what +// substring the failure message should contain. +SingleFailureChecker::SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const std::string& substr) + : results_(results), type_(type), substr_(substr) {} + +// The destructor of SingleFailureChecker verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +SingleFailureChecker::~SingleFailureChecker() { + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); +} + +DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultGlobalTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->current_test_result()->AddTestPartResult(result); + unit_test_->listeners()->repeater()->OnTestPartResult(result); +} + +DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); +} + +// Returns the global test part result reporter. +TestPartResultReporterInterface* +UnitTestImpl::GetGlobalTestPartResultReporter() { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + return global_test_part_result_repoter_; +} + +// Sets the global test part result reporter. +void UnitTestImpl::SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter) { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + global_test_part_result_repoter_ = reporter; +} + +// Returns the test part result reporter for the current thread. +TestPartResultReporterInterface* +UnitTestImpl::GetTestPartResultReporterForCurrentThread() { + return per_thread_test_part_result_reporter_.get(); +} + +// Sets the test part result reporter for the current thread. +void UnitTestImpl::SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter) { + per_thread_test_part_result_reporter_.set(reporter); +} + +// Gets the number of successful test suites. +int UnitTestImpl::successful_test_suite_count() const { + return CountIf(test_suites_, TestSuitePassed); +} + +// Gets the number of failed test suites. +int UnitTestImpl::failed_test_suite_count() const { + return CountIf(test_suites_, TestSuiteFailed); +} + +// Gets the number of all test suites. +int UnitTestImpl::total_test_suite_count() const { + return static_cast(test_suites_.size()); +} + +// Gets the number of all test suites that contain at least one test +// that should run. +int UnitTestImpl::test_suite_to_run_count() const { + return CountIf(test_suites_, ShouldRunTestSuite); +} + +// Gets the number of successful tests. +int UnitTestImpl::successful_test_count() const { + return SumOverTestSuiteList(test_suites_, &TestSuite::successful_test_count); +} + +// Gets the number of skipped tests. +int UnitTestImpl::skipped_test_count() const { + return SumOverTestSuiteList(test_suites_, &TestSuite::skipped_test_count); +} + +// Gets the number of failed tests. +int UnitTestImpl::failed_test_count() const { + return SumOverTestSuiteList(test_suites_, &TestSuite::failed_test_count); +} + +// Gets the number of disabled tests that will be reported in the XML report. +int UnitTestImpl::reportable_disabled_test_count() const { + return SumOverTestSuiteList(test_suites_, + &TestSuite::reportable_disabled_test_count); +} + +// Gets the number of disabled tests. +int UnitTestImpl::disabled_test_count() const { + return SumOverTestSuiteList(test_suites_, &TestSuite::disabled_test_count); +} + +// Gets the number of tests to be printed in the XML report. +int UnitTestImpl::reportable_test_count() const { + return SumOverTestSuiteList(test_suites_, &TestSuite::reportable_test_count); +} + +// Gets the number of all tests. +int UnitTestImpl::total_test_count() const { + return SumOverTestSuiteList(test_suites_, &TestSuite::total_test_count); +} + +// Gets the number of tests that should run. +int UnitTestImpl::test_to_run_count() const { + return SumOverTestSuiteList(test_suites_, &TestSuite::test_to_run_count); +} + +// Returns the current OS stack trace as an std::string. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// CurrentOsStackTraceExceptTop(1), Foo() will be included in the +// trace but Bar() and CurrentOsStackTraceExceptTop() won't. +std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { + return os_stack_trace_getter()->CurrentStackTrace( + static_cast(GTEST_FLAG(stack_trace_depth)), + skip_count + 1 + // Skips the user-specified number of frames plus this function + // itself. + ); // NOLINT +} + +// Returns the current time in milliseconds. +TimeInMillis GetTimeInMillis() { +#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) + // Difference between 1970-01-01 and 1601-01-01 in milliseconds. + // http://analogous.blogspot.com/2005/04/epoch.html + const TimeInMillis kJavaEpochToWinFileTimeDelta = + static_cast(116444736UL) * 100000UL; + const DWORD kTenthMicrosInMilliSecond = 10000; + + SYSTEMTIME now_systime; + FILETIME now_filetime; + ULARGE_INTEGER now_int64; + GetSystemTime(&now_systime); + if (SystemTimeToFileTime(&now_systime, &now_filetime)) { + now_int64.LowPart = now_filetime.dwLowDateTime; + now_int64.HighPart = now_filetime.dwHighDateTime; + now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - + kJavaEpochToWinFileTimeDelta; + return now_int64.QuadPart; + } + return 0; +#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ + __timeb64 now; + + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 + // (deprecated function) there. + GTEST_DISABLE_MSC_DEPRECATED_PUSH_() + _ftime64(&now); + GTEST_DISABLE_MSC_DEPRECATED_POP_() + + return static_cast(now.time) * 1000 + now.millitm; +#elif GTEST_HAS_GETTIMEOFDAY_ + struct timeval now; + gettimeofday(&now, nullptr); + return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; +#else +# error "Don't know how to get the current time on your system." +#endif +} + +// Utilities + +// class String. + +#if GTEST_OS_WINDOWS_MOBILE +// Creates a UTF-16 wide string from the given ANSI string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the wide string, or NULL if the +// input is NULL. +LPCWSTR String::AnsiToUtf16(const char* ansi) { + if (!ansi) return nullptr; + const int length = strlen(ansi); + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi, length, nullptr, 0); + WCHAR* unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, + unicode, unicode_length); + unicode[unicode_length] = 0; + return unicode; +} + +// Creates an ANSI string from the given wide string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the ANSI string, or NULL if the +// input is NULL. +const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return nullptr; + const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, nullptr, + 0, nullptr, nullptr); + char* ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, nullptr, + nullptr); + ansi[ansi_length] = 0; + return ansi; +} + +#endif // GTEST_OS_WINDOWS_MOBILE + +// Compares two C strings. Returns true if and only if they have the same +// content. +// +// Unlike strcmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CStringEquals(const char * lhs, const char * rhs) { + if (lhs == nullptr) return rhs == nullptr; + + if (rhs == nullptr) return false; + + return strcmp(lhs, rhs) == 0; +} + +#if GTEST_HAS_STD_WSTRING + +// Converts an array of wide chars to a narrow string using the UTF-8 +// encoding, and streams the result to the given Message object. +static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, + Message* msg) { + for (size_t i = 0; i != length; ) { // NOLINT + if (wstr[i] != L'\0') { + *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); + while (i != length && wstr[i] != L'\0') + i++; + } else { + *msg << '\0'; + i++; + } + } +} + +#endif // GTEST_HAS_STD_WSTRING + +void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + +} // namespace internal + +// Constructs an empty Message. +// We allocate the stringstream separately because otherwise each use of +// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's +// stack frame leading to huge stack frames in some cases; gcc does not reuse +// the stack space. +Message::Message() : ss_(new ::std::stringstream) { + // By default, we want there to be enough precision when printing + // a double to a Message. + *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); +} + +// These two overloads allow streaming a wide C string to a Message +// using the UTF-8 encoding. +Message& Message::operator <<(const wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); +} +Message& Message::operator <<(wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); +} + +#if GTEST_HAS_STD_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::std::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_STD_WSTRING + +// Gets the text streamed to this object so far as an std::string. +// Each '\0' character in the buffer is replaced with "\\0". +std::string Message::GetString() const { + return internal::StringStreamToString(ss_.get()); +} + +// AssertionResult constructors. +// Used in EXPECT_TRUE/FALSE(assertion_result). +AssertionResult::AssertionResult(const AssertionResult& other) + : success_(other.success_), + message_(other.message_.get() != nullptr + ? new ::std::string(*other.message_) + : static_cast< ::std::string*>(nullptr)) {} + +// Swaps two AssertionResults. +void AssertionResult::swap(AssertionResult& other) { + using std::swap; + swap(success_, other.success_); + swap(message_, other.message_); +} + +// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. +AssertionResult AssertionResult::operator!() const { + AssertionResult negation(!success_); + if (message_.get() != nullptr) negation << *message_; + return negation; +} + +// Makes a successful assertion result. +AssertionResult AssertionSuccess() { + return AssertionResult(true); +} + +// Makes a failed assertion result. +AssertionResult AssertionFailure() { + return AssertionResult(false); +} + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << message. +AssertionResult AssertionFailure(const Message& message) { + return AssertionFailure() << message; +} + +namespace internal { + +namespace edit_distance { +std::vector CalculateOptimalEdits(const std::vector& left, + const std::vector& right) { + std::vector > costs( + left.size() + 1, std::vector(right.size() + 1)); + std::vector > best_move( + left.size() + 1, std::vector(right.size() + 1)); + + // Populate for empty right. + for (size_t l_i = 0; l_i < costs.size(); ++l_i) { + costs[l_i][0] = static_cast(l_i); + best_move[l_i][0] = kRemove; + } + // Populate for empty left. + for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) { + costs[0][r_i] = static_cast(r_i); + best_move[0][r_i] = kAdd; + } + + for (size_t l_i = 0; l_i < left.size(); ++l_i) { + for (size_t r_i = 0; r_i < right.size(); ++r_i) { + if (left[l_i] == right[r_i]) { + // Found a match. Consume it. + costs[l_i + 1][r_i + 1] = costs[l_i][r_i]; + best_move[l_i + 1][r_i + 1] = kMatch; + continue; + } + + const double add = costs[l_i + 1][r_i]; + const double remove = costs[l_i][r_i + 1]; + const double replace = costs[l_i][r_i]; + if (add < remove && add < replace) { + costs[l_i + 1][r_i + 1] = add + 1; + best_move[l_i + 1][r_i + 1] = kAdd; + } else if (remove < add && remove < replace) { + costs[l_i + 1][r_i + 1] = remove + 1; + best_move[l_i + 1][r_i + 1] = kRemove; + } else { + // We make replace a little more expensive than add/remove to lower + // their priority. + costs[l_i + 1][r_i + 1] = replace + 1.00001; + best_move[l_i + 1][r_i + 1] = kReplace; + } + } + } + + // Reconstruct the best path. We do it in reverse order. + std::vector best_path; + for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) { + EditType move = best_move[l_i][r_i]; + best_path.push_back(move); + l_i -= move != kAdd; + r_i -= move != kRemove; + } + std::reverse(best_path.begin(), best_path.end()); + return best_path; +} + +namespace { + +// Helper class to convert string into ids with deduplication. +class InternalStrings { + public: + size_t GetId(const std::string& str) { + IdMap::iterator it = ids_.find(str); + if (it != ids_.end()) return it->second; + size_t id = ids_.size(); + return ids_[str] = id; + } + + private: + typedef std::map IdMap; + IdMap ids_; +}; + +} // namespace + +std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right) { + std::vector left_ids, right_ids; + { + InternalStrings intern_table; + for (size_t i = 0; i < left.size(); ++i) { + left_ids.push_back(intern_table.GetId(left[i])); + } + for (size_t i = 0; i < right.size(); ++i) { + right_ids.push_back(intern_table.GetId(right[i])); + } + } + return CalculateOptimalEdits(left_ids, right_ids); +} + +namespace { + +// Helper class that holds the state for one hunk and prints it out to the +// stream. +// It reorders adds/removes when possible to group all removes before all +// adds. It also adds the hunk header before printint into the stream. +class Hunk { + public: + Hunk(size_t left_start, size_t right_start) + : left_start_(left_start), + right_start_(right_start), + adds_(), + removes_(), + common_() {} + + void PushLine(char edit, const char* line) { + switch (edit) { + case ' ': + ++common_; + FlushEdits(); + hunk_.push_back(std::make_pair(' ', line)); + break; + case '-': + ++removes_; + hunk_removes_.push_back(std::make_pair('-', line)); + break; + case '+': + ++adds_; + hunk_adds_.push_back(std::make_pair('+', line)); + break; + } + } + + void PrintTo(std::ostream* os) { + PrintHeader(os); + FlushEdits(); + for (std::list >::const_iterator it = + hunk_.begin(); + it != hunk_.end(); ++it) { + *os << it->first << it->second << "\n"; + } + } + + bool has_edits() const { return adds_ || removes_; } + + private: + void FlushEdits() { + hunk_.splice(hunk_.end(), hunk_removes_); + hunk_.splice(hunk_.end(), hunk_adds_); + } + + // Print a unified diff header for one hunk. + // The format is + // "@@ -, +, @@" + // where the left/right parts are omitted if unnecessary. + void PrintHeader(std::ostream* ss) const { + *ss << "@@ "; + if (removes_) { + *ss << "-" << left_start_ << "," << (removes_ + common_); + } + if (removes_ && adds_) { + *ss << " "; + } + if (adds_) { + *ss << "+" << right_start_ << "," << (adds_ + common_); + } + *ss << " @@\n"; + } + + size_t left_start_, right_start_; + size_t adds_, removes_, common_; + std::list > hunk_, hunk_adds_, hunk_removes_; +}; + +} // namespace + +// Create a list of diff hunks in Unified diff format. +// Each hunk has a header generated by PrintHeader above plus a body with +// lines prefixed with ' ' for no change, '-' for deletion and '+' for +// addition. +// 'context' represents the desired unchanged prefix/suffix around the diff. +// If two hunks are close enough that their contexts overlap, then they are +// joined into one hunk. +std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context) { + const std::vector edits = CalculateOptimalEdits(left, right); + + size_t l_i = 0, r_i = 0, edit_i = 0; + std::stringstream ss; + while (edit_i < edits.size()) { + // Find first edit. + while (edit_i < edits.size() && edits[edit_i] == kMatch) { + ++l_i; + ++r_i; + ++edit_i; + } + + // Find the first line to include in the hunk. + const size_t prefix_context = std::min(l_i, context); + Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1); + for (size_t i = prefix_context; i > 0; --i) { + hunk.PushLine(' ', left[l_i - i].c_str()); + } + + // Iterate the edits until we found enough suffix for the hunk or the input + // is over. + size_t n_suffix = 0; + for (; edit_i < edits.size(); ++edit_i) { + if (n_suffix >= context) { + // Continue only if the next hunk is very close. + auto it = edits.begin() + static_cast(edit_i); + while (it != edits.end() && *it == kMatch) ++it; + if (it == edits.end() || + static_cast(it - edits.begin()) - edit_i >= context) { + // There is no next edit or it is too far away. + break; + } + } + + EditType edit = edits[edit_i]; + // Reset count when a non match is found. + n_suffix = edit == kMatch ? n_suffix + 1 : 0; + + if (edit == kMatch || edit == kRemove || edit == kReplace) { + hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str()); + } + if (edit == kAdd || edit == kReplace) { + hunk.PushLine('+', right[r_i].c_str()); + } + + // Advance indices, depending on edit type. + l_i += edit != kAdd; + r_i += edit != kRemove; + } + + if (!hunk.has_edits()) { + // We are done. We don't want this hunk. + break; + } + + hunk.PrintTo(&ss); + } + return ss.str(); +} + +} // namespace edit_distance + +namespace { + +// The string representation of the values received in EqFailure() are already +// escaped. Split them on escaped '\n' boundaries. Leave all other escaped +// characters the same. +std::vector SplitEscapedString(const std::string& str) { + std::vector lines; + size_t start = 0, end = str.size(); + if (end > 2 && str[0] == '"' && str[end - 1] == '"') { + ++start; + --end; + } + bool escaped = false; + for (size_t i = start; i + 1 < end; ++i) { + if (escaped) { + escaped = false; + if (str[i] == 'n') { + lines.push_back(str.substr(start, i - start - 1)); + start = i + 1; + } + } else { + escaped = str[i] == '\\'; + } + } + lines.push_back(str.substr(start, end - start)); + return lines; +} + +} // namespace + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// lhs_expression: "foo" +// rhs_expression: "bar" +// lhs_value: "5" +// rhs_value: "6" +// +// The ignoring_case parameter is true if and only if the assertion is a +// *_STRCASEEQ*. When it's true, the string "Ignoring case" will +// be inserted into the message. +AssertionResult EqFailure(const char* lhs_expression, + const char* rhs_expression, + const std::string& lhs_value, + const std::string& rhs_value, + bool ignoring_case) { + Message msg; + msg << "Expected equality of these values:"; + msg << "\n " << lhs_expression; + if (lhs_value != lhs_expression) { + msg << "\n Which is: " << lhs_value; + } + msg << "\n " << rhs_expression; + if (rhs_value != rhs_expression) { + msg << "\n Which is: " << rhs_value; + } + + if (ignoring_case) { + msg << "\nIgnoring case"; + } + + if (!lhs_value.empty() && !rhs_value.empty()) { + const std::vector lhs_lines = + SplitEscapedString(lhs_value); + const std::vector rhs_lines = + SplitEscapedString(rhs_value); + if (lhs_lines.size() > 1 || rhs_lines.size() > 1) { + msg << "\nWith diff:\n" + << edit_distance::CreateUnifiedDiff(lhs_lines, rhs_lines); + } + } + + return AssertionFailure() << msg; +} + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +std::string GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value) { + const char* actual_message = assertion_result.message(); + Message msg; + msg << "Value of: " << expression_text + << "\n Actual: " << actual_predicate_value; + if (actual_message[0] != '\0') + msg << " (" << actual_message << ")"; + msg << "\nExpected: " << expected_predicate_value; + return msg.GetString(); +} + +// Helper function for implementing ASSERT_NEAR. +AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error) { + const double diff = fabs(val1 - val2); + if (diff <= abs_error) return AssertionSuccess(); + + return AssertionFailure() + << "The difference between " << expr1 << " and " << expr2 + << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; +} + + +// Helper template for implementing FloatLE() and DoubleLE(). +template +AssertionResult FloatingPointLE(const char* expr1, + const char* expr2, + RawType val1, + RawType val2) { + // Returns success if val1 is less than val2, + if (val1 < val2) { + return AssertionSuccess(); + } + + // or if val1 is almost equal to val2. + const FloatingPoint lhs(val1), rhs(val2); + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + // Note that the above two checks will both fail if either val1 or + // val2 is NaN, as the IEEE floating-point standard requires that + // any predicate involving a NaN must return false. + + ::std::stringstream val1_ss; + val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val1; + + ::std::stringstream val2_ss; + val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val2; + + return AssertionFailure() + << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StringStreamToString(&val1_ss) << " vs " + << StringStreamToString(&val2_ss); +} + +} // namespace internal + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +namespace internal { + +// The helper function for {ASSERT|EXPECT}_EQ with int or enum +// arguments. +AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs) { + if (lhs == rhs) { + return AssertionSuccess(); + } + + return EqFailure(lhs_expression, + rhs_expression, + FormatForComparisonFailureMessage(lhs, rhs), + FormatForComparisonFailureMessage(rhs, lhs), + false); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here +// just to avoid copy-and-paste of similar code. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + BiggestInt val1, BiggestInt val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +} + +// Implements the helper function for {ASSERT|EXPECT}_NE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(NE, !=) +// Implements the helper function for {ASSERT|EXPECT}_LE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LE, <=) +// Implements the helper function for {ASSERT|EXPECT}_LT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LT, < ) +// Implements the helper function for {ASSERT|EXPECT}_GE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GE, >=) +// Implements the helper function for {ASSERT|EXPECT}_GT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GT, > ) + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +AssertionResult CmpHelperSTREQ(const char* lhs_expression, + const char* rhs_expression, + const char* lhs, + const char* rhs) { + if (String::CStringEquals(lhs, rhs)) { + return AssertionSuccess(); + } + + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), + false); +} + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +AssertionResult CmpHelperSTRCASEEQ(const char* lhs_expression, + const char* rhs_expression, + const char* lhs, + const char* rhs) { + if (String::CaseInsensitiveCStringEquals(lhs, rhs)) { + return AssertionSuccess(); + } + + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), + true); +} + +// The helper function for {ASSERT|EXPECT}_STRNE. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CaseInsensitiveCStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() + << "Expected: (" << s1_expression << ") != (" + << s2_expression << ") (ignoring case), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +} // namespace internal + +namespace { + +// Helper functions for implementing IsSubString() and IsNotSubstring(). + +// This group of overloaded functions return true if and only if needle +// is a substring of haystack. NULL is considered a substring of +// itself only. + +bool IsSubstringPred(const char* needle, const char* haystack) { + if (needle == nullptr || haystack == nullptr) return needle == haystack; + + return strstr(haystack, needle) != nullptr; +} + +bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { + if (needle == nullptr || haystack == nullptr) return needle == haystack; + + return wcsstr(haystack, needle) != nullptr; +} + +// StringType here can be either ::std::string or ::std::wstring. +template +bool IsSubstringPred(const StringType& needle, + const StringType& haystack) { + return haystack.find(needle) != StringType::npos; +} + +// This function implements either IsSubstring() or IsNotSubstring(), +// depending on the value of the expected_to_be_substring parameter. +// StringType here can be const char*, const wchar_t*, ::std::string, +// or ::std::wstring. +template +AssertionResult IsSubstringImpl( + bool expected_to_be_substring, + const char* needle_expr, const char* haystack_expr, + const StringType& needle, const StringType& haystack) { + if (IsSubstringPred(needle, haystack) == expected_to_be_substring) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(needle[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure() + << "Value of: " << needle_expr << "\n" + << " Actual: " << begin_string_quote << needle << "\"\n" + << "Expected: " << (expected_to_be_substring ? "" : "not ") + << "a substring of " << haystack_expr << "\n" + << "Which is: " << begin_string_quote << haystack << "\""; +} + +} // namespace + +// IsSubstring() and IsNotSubstring() check whether needle is a +// substring of haystack (NULL is considered a substring of itself +// only), and return an appropriate error message when they fail. + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +#if GTEST_HAS_STD_WSTRING +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +#if GTEST_OS_WINDOWS + +namespace { + +// Helper function for IsHRESULT{SuccessFailure} predicates +AssertionResult HRESULTFailureHelper(const char* expr, + const char* expected, + long hr) { // NOLINT +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_TV_TITLE + + // Windows CE doesn't support FormatMessage. + const char error_text[] = ""; + +# else + + // Looks up the human-readable system message for the HRESULT code + // and since we're not passing any params to FormatMessage, we don't + // want inserts expanded. + const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS; + const DWORD kBufSize = 4096; + // Gets the system's human readable message string for this HRESULT. + char error_text[kBufSize] = { '\0' }; + DWORD message_length = ::FormatMessageA(kFlags, + 0, // no source, we're asking system + static_cast(hr), // the error + 0, // no line width restrictions + error_text, // output buffer + kBufSize, // buf size + nullptr); // no arguments for inserts + // Trims tailing white space (FormatMessage leaves a trailing CR-LF) + for (; message_length && IsSpace(error_text[message_length - 1]); + --message_length) { + error_text[message_length - 1] = '\0'; + } + +# endif // GTEST_OS_WINDOWS_MOBILE + + const std::string error_hex("0x" + String::FormatHexInt(hr)); + return ::testing::AssertionFailure() + << "Expected: " << expr << " " << expected << ".\n" + << " Actual: " << error_hex << " " << error_text << "\n"; +} + +} // namespace + +AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT + if (SUCCEEDED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "succeeds", hr); +} + +AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT + if (FAILED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "fails", hr); +} + +#endif // GTEST_OS_WINDOWS + +// Utility functions for encoding Unicode text (wide strings) in +// UTF-8. + +// A Unicode code-point can have up to 21 bits, and is encoded in UTF-8 +// like this: +// +// Code-point length Encoding +// 0 - 7 bits 0xxxxxxx +// 8 - 11 bits 110xxxxx 10xxxxxx +// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx +// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +// The maximum code-point a one-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; + +// The maximum code-point a two-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; + +// The maximum code-point a three-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; + +// The maximum code-point a four-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; + +// Chops off the n lowest bits from a bit pattern. Returns the n +// lowest bits. As a side effect, the original bit pattern will be +// shifted to the right by n bits. +inline UInt32 ChopLowBits(UInt32* bits, int n) { + const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); + *bits >>= n; + return low_bits; +} + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted +// to "(Invalid Unicode 0xXXXXXXXX)". +std::string CodePointToUtf8(UInt32 code_point) { + if (code_point > kMaxCodePoint4) { + return "(Invalid Unicode 0x" + String::FormatHexUInt32(code_point) + ")"; + } + + char str[5]; // Big enough for the largest valid code point. + if (code_point <= kMaxCodePoint1) { + str[1] = '\0'; + str[0] = static_cast(code_point); // 0xxxxxxx + } else if (code_point <= kMaxCodePoint2) { + str[2] = '\0'; + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xC0 | code_point); // 110xxxxx + } else if (code_point <= kMaxCodePoint3) { + str[3] = '\0'; + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xE0 | code_point); // 1110xxxx + } else { // code_point <= kMaxCodePoint4 + str[4] = '\0'; + str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xF0 | code_point); // 11110xxx + } + return str; +} + +// The following two functions only make sense if the system +// uses UTF-16 for wide string encoding. All supported systems +// with 16 bit wchar_t (Windows, Cygwin) do use UTF-16. + +// Determines if the arguments constitute UTF-16 surrogate pair +// and thus should be combined into a single Unicode code point +// using CreateCodePointFromUtf16SurrogatePair. +inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { + return sizeof(wchar_t) == 2 && + (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; +} + +// Creates a Unicode code point from UTF16 surrogate pair. +inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + const auto first_u = static_cast(first); + const auto second_u = static_cast(second); + const UInt32 mask = (1 << 10) - 1; + return (sizeof(wchar_t) == 2) + ? (((first_u & mask) << 10) | (second_u & mask)) + 0x10000 + : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + first_u; +} + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +std::string WideStringToUtf8(const wchar_t* str, int num_chars) { + if (num_chars == -1) + num_chars = static_cast(wcslen(str)); + + ::std::stringstream stream; + for (int i = 0; i < num_chars; ++i) { + UInt32 unicode_code_point; + + if (str[i] == L'\0') { + break; + } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { + unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], + str[i + 1]); + i++; + } else { + unicode_code_point = static_cast(str[i]); + } + + stream << CodePointToUtf8(unicode_code_point); + } + return StringStreamToString(&stream); +} + +// Converts a wide C string to an std::string using the UTF-8 encoding. +// NULL will be converted to "(null)". +std::string String::ShowWideCString(const wchar_t * wide_c_str) { + if (wide_c_str == nullptr) return "(null)"; + + return internal::WideStringToUtf8(wide_c_str, -1); +} + +// Compares two wide C strings. Returns true if and only if they have the +// same content. +// +// Unlike wcscmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { + if (lhs == nullptr) return rhs == nullptr; + + if (rhs == nullptr) return false; + + return wcscmp(lhs, rhs) == 0; +} + +// Helper function for *_STREQ on wide strings. +AssertionResult CmpHelperSTREQ(const char* lhs_expression, + const char* rhs_expression, + const wchar_t* lhs, + const wchar_t* rhs) { + if (String::WideCStringEquals(lhs, rhs)) { + return AssertionSuccess(); + } + + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), + false); +} + +// Helper function for *_STRNE on wide strings. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2) { + if (!String::WideCStringEquals(s1, s2)) { + return AssertionSuccess(); + } + + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << PrintToString(s1) + << " vs " << PrintToString(s2); +} + +// Compares two C strings, ignoring case. Returns true if and only if they have +// the same content. +// +// Unlike strcasecmp(), this function can handle NULL argument(s). A +// NULL C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { + if (lhs == nullptr) return rhs == nullptr; + if (rhs == nullptr) return false; + return posix::StrCaseCmp(lhs, rhs) == 0; +} + +// Compares two wide C strings, ignoring case. Returns true if and only if they +// have the same content. +// +// Unlike wcscasecmp(), this function can handle NULL argument(s). +// A NULL C string is considered different to any non-NULL wide C string, +// including the empty string. +// NB: The implementations on different platforms slightly differ. +// On windows, this method uses _wcsicmp which compares according to LC_CTYPE +// environment variable. On GNU platform this method uses wcscasecmp +// which compares according to LC_CTYPE category of the current locale. +// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the +// current locale. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + if (lhs == nullptr) return rhs == nullptr; + + if (rhs == nullptr) return false; + +#if GTEST_OS_WINDOWS + return _wcsicmp(lhs, rhs) == 0; +#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID + return wcscasecmp(lhs, rhs) == 0; +#else + // Android, Mac OS X and Cygwin don't define wcscasecmp. + // Other unknown OSes may not define it either. + wint_t left, right; + do { + left = towlower(static_cast(*lhs++)); + right = towlower(static_cast(*rhs++)); + } while (left && left == right); + return left == right; +#endif // OS selector +} + +// Returns true if and only if str ends with the given suffix, ignoring case. +// Any string is considered to end with an empty suffix. +bool String::EndsWithCaseInsensitive( + const std::string& str, const std::string& suffix) { + const size_t str_len = str.length(); + const size_t suffix_len = suffix.length(); + return (str_len >= suffix_len) && + CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, + suffix.c_str()); +} + +// Formats an int value as "%02d". +std::string String::FormatIntWidth2(int value) { + std::stringstream ss; + ss << std::setfill('0') << std::setw(2) << value; + return ss.str(); +} + +// Formats an int value as "%X". +std::string String::FormatHexUInt32(UInt32 value) { + std::stringstream ss; + ss << std::hex << std::uppercase << value; + return ss.str(); +} + +// Formats an int value as "%X". +std::string String::FormatHexInt(int value) { + return FormatHexUInt32(static_cast(value)); +} + +// Formats a byte as "%02X". +std::string String::FormatByte(unsigned char value) { + std::stringstream ss; + ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase + << static_cast(value); + return ss.str(); +} + +// Converts the buffer in a stringstream to an std::string, converting NUL +// bytes to "\\0" along the way. +std::string StringStreamToString(::std::stringstream* ss) { + const ::std::string& str = ss->str(); + const char* const start = str.c_str(); + const char* const end = start + str.length(); + + std::string result; + result.reserve(static_cast(2 * (end - start))); + for (const char* ch = start; ch != end; ++ch) { + if (*ch == '\0') { + result += "\\0"; // Replaces NUL with "\\0"; + } else { + result += *ch; + } + } + + return result; +} + +// Appends the user-supplied message to the Google-Test-generated message. +std::string AppendUserMessage(const std::string& gtest_msg, + const Message& user_msg) { + // Appends the user message if it's non-empty. + const std::string user_msg_string = user_msg.GetString(); + if (user_msg_string.empty()) { + return gtest_msg; + } + + return gtest_msg + "\n" + user_msg_string; +} + +} // namespace internal + +// class TestResult + +// Creates an empty TestResult. +TestResult::TestResult() + : death_test_count_(0), start_timestamp_(0), elapsed_time_(0) {} + +// D'tor. +TestResult::~TestResult() { +} + +// Returns the i-th test part result among all the results. i can +// range from 0 to total_part_count() - 1. If i is not in that range, +// aborts the program. +const TestPartResult& TestResult::GetTestPartResult(int i) const { + if (i < 0 || i >= total_part_count()) + internal::posix::Abort(); + return test_part_results_.at(static_cast(i)); +} + +// Returns the i-th test property. i can range from 0 to +// test_property_count() - 1. If i is not in that range, aborts the +// program. +const TestProperty& TestResult::GetTestProperty(int i) const { + if (i < 0 || i >= test_property_count()) + internal::posix::Abort(); + return test_properties_.at(static_cast(i)); +} + +// Clears the test part results. +void TestResult::ClearTestPartResults() { + test_part_results_.clear(); +} + +// Adds a test part result to the list. +void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { + test_part_results_.push_back(test_part_result); +} + +// Adds a test property to the list. If a property with the same key as the +// supplied property is already represented, the value of this test_property +// replaces the old value for that key. +void TestResult::RecordProperty(const std::string& xml_element, + const TestProperty& test_property) { + if (!ValidateTestProperty(xml_element, test_property)) { + return; + } + internal::MutexLock lock(&test_properites_mutex_); + const std::vector::iterator property_with_matching_key = + std::find_if(test_properties_.begin(), test_properties_.end(), + internal::TestPropertyKeyIs(test_property.key())); + if (property_with_matching_key == test_properties_.end()) { + test_properties_.push_back(test_property); + return; + } + property_with_matching_key->SetValue(test_property.value()); +} + +// The list of reserved attributes used in the element of XML +// output. +static const char* const kReservedTestSuitesAttributes[] = { + "disabled", + "errors", + "failures", + "name", + "random_seed", + "tests", + "time", + "timestamp" +}; + +// The list of reserved attributes used in the element of XML +// output. +static const char* const kReservedTestSuiteAttributes[] = { + "disabled", "errors", "failures", "name", "tests", "time", "timestamp"}; + +// The list of reserved attributes used in the element of XML output. +static const char* const kReservedTestCaseAttributes[] = { + "classname", "name", "status", "time", "type_param", + "value_param", "file", "line"}; + +// Use a slightly different set for allowed output to ensure existing tests can +// still RecordProperty("result") or "RecordProperty(timestamp") +static const char* const kReservedOutputTestCaseAttributes[] = { + "classname", "name", "status", "time", "type_param", + "value_param", "file", "line", "result", "timestamp"}; + +template +std::vector ArrayAsVector(const char* const (&array)[kSize]) { + return std::vector(array, array + kSize); +} + +static std::vector GetReservedAttributesForElement( + const std::string& xml_element) { + if (xml_element == "testsuites") { + return ArrayAsVector(kReservedTestSuitesAttributes); + } else if (xml_element == "testsuite") { + return ArrayAsVector(kReservedTestSuiteAttributes); + } else if (xml_element == "testcase") { + return ArrayAsVector(kReservedTestCaseAttributes); + } else { + GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; + } + // This code is unreachable but some compilers may not realizes that. + return std::vector(); +} + +// TODO(jdesprez): Merge the two getReserved attributes once skip is improved +static std::vector GetReservedOutputAttributesForElement( + const std::string& xml_element) { + if (xml_element == "testsuites") { + return ArrayAsVector(kReservedTestSuitesAttributes); + } else if (xml_element == "testsuite") { + return ArrayAsVector(kReservedTestSuiteAttributes); + } else if (xml_element == "testcase") { + return ArrayAsVector(kReservedOutputTestCaseAttributes); + } else { + GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; + } + // This code is unreachable but some compilers may not realizes that. + return std::vector(); +} + +static std::string FormatWordList(const std::vector& words) { + Message word_list; + for (size_t i = 0; i < words.size(); ++i) { + if (i > 0 && words.size() > 2) { + word_list << ", "; + } + if (i == words.size() - 1) { + word_list << "and "; + } + word_list << "'" << words[i] << "'"; + } + return word_list.GetString(); +} + +static bool ValidateTestPropertyName( + const std::string& property_name, + const std::vector& reserved_names) { + if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != + reserved_names.end()) { + ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name + << " (" << FormatWordList(reserved_names) + << " are reserved by " << GTEST_NAME_ << ")"; + return false; + } + return true; +} + +// Adds a failure if the key is a reserved attribute of the element named +// xml_element. Returns true if the property is valid. +bool TestResult::ValidateTestProperty(const std::string& xml_element, + const TestProperty& test_property) { + return ValidateTestPropertyName(test_property.key(), + GetReservedAttributesForElement(xml_element)); +} + +// Clears the object. +void TestResult::Clear() { + test_part_results_.clear(); + test_properties_.clear(); + death_test_count_ = 0; + elapsed_time_ = 0; +} + +// Returns true off the test part was skipped. +static bool TestPartSkipped(const TestPartResult& result) { + return result.skipped(); +} + +// Returns true if and only if the test was skipped. +bool TestResult::Skipped() const { + return !Failed() && CountIf(test_part_results_, TestPartSkipped) > 0; +} + +// Returns true if and only if the test failed. +bool TestResult::Failed() const { + for (int i = 0; i < total_part_count(); ++i) { + if (GetTestPartResult(i).failed()) + return true; + } + return false; +} + +// Returns true if and only if the test part fatally failed. +static bool TestPartFatallyFailed(const TestPartResult& result) { + return result.fatally_failed(); +} + +// Returns true if and only if the test fatally failed. +bool TestResult::HasFatalFailure() const { + return CountIf(test_part_results_, TestPartFatallyFailed) > 0; +} + +// Returns true if and only if the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult& result) { + return result.nonfatally_failed(); +} + +// Returns true if and only if the test has a non-fatal failure. +bool TestResult::HasNonfatalFailure() const { + return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; +} + +// Gets the number of all test parts. This is the sum of the number +// of successful test parts and the number of failed test parts. +int TestResult::total_part_count() const { + return static_cast(test_part_results_.size()); +} + +// Returns the number of the test properties. +int TestResult::test_property_count() const { + return static_cast(test_properties_.size()); +} + +// class Test + +// Creates a Test object. + +// The c'tor saves the states of all flags. +Test::Test() + : gtest_flag_saver_(new GTEST_FLAG_SAVER_) { +} + +// The d'tor restores the states of all flags. The actual work is +// done by the d'tor of the gtest_flag_saver_ field, and thus not +// visible here. +Test::~Test() { +} + +// Sets up the test fixture. +// +// A sub-class may override this. +void Test::SetUp() { +} + +// Tears down the test fixture. +// +// A sub-class may override this. +void Test::TearDown() { +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const std::string& key, const std::string& value) { + UnitTest::GetInstance()->RecordProperty(key, value); +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const std::string& key, int value) { + Message value_message; + value_message << value; + RecordProperty(key, value_message.GetString().c_str()); +} + +namespace internal { + +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const std::string& message) { + // This function is a friend of UnitTest and as such has access to + // AddTestPartResult. + UnitTest::GetInstance()->AddTestPartResult( + result_type, + nullptr, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. + message, + ""); // No stack trace, either. +} + +} // namespace internal + +// Google Test requires all tests in the same test suite to use the same test +// fixture class. This function checks if the current test has the +// same fixture class as the first test in the current test suite. If +// yes, it returns true; otherwise it generates a Google Test failure and +// returns false. +bool Test::HasSameFixtureClass() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + const TestSuite* const test_suite = impl->current_test_suite(); + + // Info about the first test in the current test suite. + const TestInfo* const first_test_info = test_suite->test_info_list()[0]; + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; + const char* const first_test_name = first_test_info->name(); + + // Info about the current test. + const TestInfo* const this_test_info = impl->current_test_info(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; + const char* const this_test_name = this_test_info->name(); + + if (this_fixture_id != first_fixture_id) { + // Is the first test defined using TEST? + const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); + // Is this test defined using TEST? + const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); + + if (first_is_TEST || this_is_TEST) { + // Both TEST and TEST_F appear in same test suite, which is incorrect. + // Tell the user how to fix this. + + // Gets the name of the TEST and the name of the TEST_F. Note + // that first_is_TEST and this_is_TEST cannot both be true, as + // the fixture IDs are different for the two tests. + const char* const TEST_name = + first_is_TEST ? first_test_name : this_test_name; + const char* const TEST_F_name = + first_is_TEST ? this_test_name : first_test_name; + + ADD_FAILURE() + << "All tests in the same test suite must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test suite is\n" + << "illegal. In test suite " << this_test_info->test_suite_name() + << ",\n" + << "test " << TEST_F_name << " is defined using TEST_F but\n" + << "test " << TEST_name << " is defined using TEST. You probably\n" + << "want to change the TEST to TEST_F or move it to another test\n" + << "case."; + } else { + // Two fixture classes with the same name appear in two different + // namespaces, which is not allowed. Tell the user how to fix this. + ADD_FAILURE() + << "All tests in the same test suite must use the same test fixture\n" + << "class. However, in test suite " + << this_test_info->test_suite_name() << ",\n" + << "you defined test " << first_test_name << " and test " + << this_test_name << "\n" + << "using two different test fixture classes. This can happen if\n" + << "the two classes are from different namespaces or translation\n" + << "units and have the same name. You should probably rename one\n" + << "of the classes to put the tests into different test suites."; + } + return false; + } + + return true; +} + +#if GTEST_HAS_SEH + +// Adds an "exception thrown" fatal failure to the current test. This +// function returns its result via an output parameter pointer because VC++ +// prohibits creation of objects with destructors on stack in functions +// using __try (see error C2712). +static std::string* FormatSehExceptionMessage(DWORD exception_code, + const char* location) { + Message message; + message << "SEH exception with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " thrown in " << location << "."; + + return new std::string(message.GetString()); +} + +#endif // GTEST_HAS_SEH + +namespace internal { + +#if GTEST_HAS_EXCEPTIONS + +// Adds an "exception thrown" fatal failure to the current test. +static std::string FormatCxxExceptionMessage(const char* description, + const char* location) { + Message message; + if (description != nullptr) { + message << "C++ exception with description \"" << description << "\""; + } else { + message << "Unknown C++ exception"; + } + message << " thrown in " << location << "."; + + return message.GetString(); +} + +static std::string PrintTestPartResultToString( + const TestPartResult& test_part_result); + +GoogleTestFailureException::GoogleTestFailureException( + const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} + +#endif // GTEST_HAS_EXCEPTIONS + +// We put these helper functions in the internal namespace as IBM's xlC +// compiler rejects the code if they were declared static. + +// Runs the given method and handles SEH exceptions it throws, when +// SEH is supported; returns the 0-value for type Result in case of an +// SEH exception. (Microsoft compilers cannot handle SEH and C++ +// exceptions in the same function. Therefore, we provide a separate +// wrapper function for handling SEH exceptions.) +template +Result HandleSehExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { +#if GTEST_HAS_SEH + __try { + return (object->*method)(); + } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT + GetExceptionCode())) { + // We create the exception message on the heap because VC++ prohibits + // creation of objects with destructors on stack in functions using __try + // (see error C2712). + std::string* exception_message = FormatSehExceptionMessage( + GetExceptionCode(), location); + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, + *exception_message); + delete exception_message; + return static_cast(0); + } +#else + (void)location; + return (object->*method)(); +#endif // GTEST_HAS_SEH +} + +// Runs the given method and catches and reports C++ and/or SEH-style +// exceptions, if they are supported; returns the 0-value for type +// Result in case of an SEH exception. +template +Result HandleExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { + // NOTE: The user code can affect the way in which Google Test handles + // exceptions by setting GTEST_FLAG(catch_exceptions), but only before + // RUN_ALL_TESTS() starts. It is technically possible to check the flag + // after the exception is caught and either report or re-throw the + // exception based on the flag's value: + // + // try { + // // Perform the test method. + // } catch (...) { + // if (GTEST_FLAG(catch_exceptions)) + // // Report the exception as failure. + // else + // throw; // Re-throws the original exception. + // } + // + // However, the purpose of this flag is to allow the program to drop into + // the debugger when the exception is thrown. On most platforms, once the + // control enters the catch block, the exception origin information is + // lost and the debugger will stop the program at the point of the + // re-throw in this function -- instead of at the point of the original + // throw statement in the code under test. For this reason, we perform + // the check early, sacrificing the ability to affect Google Test's + // exception handling in the method where the exception is thrown. + if (internal::GetUnitTestImpl()->catch_exceptions()) { +#if GTEST_HAS_EXCEPTIONS + try { + return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const AssertionException&) { // NOLINT + // This failure was reported already. + } catch (const internal::GoogleTestFailureException&) { // NOLINT + // This exception type can only be thrown by a failed Google + // Test assertion with the intention of letting another testing + // framework catch it. Therefore we just re-throw it. + throw; + } catch (const std::exception& e) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(e.what(), location)); + } catch (...) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(nullptr, location)); + } + return static_cast(0); +#else + return HandleSehExceptionsInMethodIfSupported(object, method, location); +#endif // GTEST_HAS_EXCEPTIONS + } else { + return (object->*method)(); + } +} + +} // namespace internal + +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); + // We will run the test only if SetUp() was successful and didn't call + // GTEST_SKIP(). + if (!HasFatalFailure() && !IsSkipped()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TestBody, "the test body"); + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TearDown, "TearDown()"); +} + +// Returns true if and only if the current test has a fatal failure. +bool Test::HasFatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); +} + +// Returns true if and only if the current test has a non-fatal failure. +bool Test::HasNonfatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()-> + HasNonfatalFailure(); +} + +// Returns true if and only if the current test was skipped. +bool Test::IsSkipped() { + return internal::GetUnitTestImpl()->current_test_result()->Skipped(); +} + +// class TestInfo + +// Constructs a TestInfo object. It assumes ownership of the test factory +// object. +TestInfo::TestInfo(const std::string& a_test_suite_name, + const std::string& a_name, const char* a_type_param, + const char* a_value_param, + internal::CodeLocation a_code_location, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory) + : test_suite_name_(a_test_suite_name), + name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : nullptr), + value_param_(a_value_param ? new std::string(a_value_param) : nullptr), + location_(a_code_location), + fixture_class_id_(fixture_class_id), + should_run_(false), + is_disabled_(false), + matches_filter_(false), + factory_(factory), + result_() {} + +// Destructs a TestInfo object. +TestInfo::~TestInfo() { delete factory_; } + +namespace internal { + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_suite_name: name of the test suite +// name: name of the test +// type_param: the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param: text representation of the test's value parameter, +// or NULL if this is not a value-parameterized test. +// code_location: code location where the test is defined +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +TestInfo* MakeAndRegisterTestInfo( + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory) { + TestInfo* const test_info = + new TestInfo(test_suite_name, name, type_param, value_param, + code_location, fixture_class_id, factory); + GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + return test_info; +} + +void ReportInvalidTestSuiteType(const char* test_suite_name, + CodeLocation code_location) { + Message errors; + errors + << "Attempted redefinition of test suite " << test_suite_name << ".\n" + << "All tests in the same test suite must use the same test fixture\n" + << "class. However, in test suite " << test_suite_name << ", you tried\n" + << "to define a test using a fixture class different from the one\n" + << "used earlier. This can happen if the two fixture classes are\n" + << "from different namespaces and have the same name. You should\n" + << "probably rename one of the classes to put the tests into different\n" + << "test suites."; + + GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(), + code_location.line) + << " " << errors.GetString(); +} +} // namespace internal + +namespace { + +// A predicate that checks the test name of a TestInfo against a known +// value. +// +// This is used for implementation of the TestSuite class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestNameIs is copyable. +class TestNameIs { + public: + // Constructor. + // + // TestNameIs has NO default constructor. + explicit TestNameIs(const char* name) + : name_(name) {} + + // Returns true if and only if the test name of test_info matches name_. + bool operator()(const TestInfo * test_info) const { + return test_info && test_info->name() == name_; + } + + private: + std::string name_; +}; + +} // namespace + +namespace internal { + +// This method expands all parameterized tests registered with macros TEST_P +// and INSTANTIATE_TEST_SUITE_P into regular tests and registers those. +// This will be done just once during the program runtime. +void UnitTestImpl::RegisterParameterizedTests() { + if (!parameterized_tests_registered_) { + parameterized_test_registry_.RegisterTests(); + parameterized_tests_registered_ = true; + } +} + +} // namespace internal + +// Creates the test object, runs it, records its result, and then +// deletes it. +void TestInfo::Run() { + if (!should_run_) return; + + // Tells UnitTest where to store test result. + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*this); + + const TimeInMillis start = internal::GetTimeInMillis(); + + impl->os_stack_trace_getter()->UponLeavingGTest(); + + // Creates the test object. + Test* const test = internal::HandleExceptionsInMethodIfSupported( + factory_, &internal::TestFactoryBase::CreateTest, + "the test fixture's constructor"); + + // Runs the test if the constructor didn't generate a fatal failure or invoke + // GTEST_SKIP(). + // Note that the object will not be null + if (!Test::HasFatalFailure() && !Test::IsSkipped()) { + // This doesn't throw as all user code that can throw are wrapped into + // exception handling code. + test->Run(); + } + + if (test != nullptr) { + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); + } + + result_.set_start_timestamp(start); + result_.set_elapsed_time(internal::GetTimeInMillis() - start); + + // Notifies the unit test event listener that a test has just finished. + repeater->OnTestEnd(*this); + + // Tells UnitTest to stop associating assertion results to this + // test. + impl->set_current_test_info(nullptr); +} + +// class TestSuite + +// Gets the number of successful tests in this test suite. +int TestSuite::successful_test_count() const { + return CountIf(test_info_list_, TestPassed); +} + +// Gets the number of successful tests in this test suite. +int TestSuite::skipped_test_count() const { + return CountIf(test_info_list_, TestSkipped); +} + +// Gets the number of failed tests in this test suite. +int TestSuite::failed_test_count() const { + return CountIf(test_info_list_, TestFailed); +} + +// Gets the number of disabled tests that will be reported in the XML report. +int TestSuite::reportable_disabled_test_count() const { + return CountIf(test_info_list_, TestReportableDisabled); +} + +// Gets the number of disabled tests in this test suite. +int TestSuite::disabled_test_count() const { + return CountIf(test_info_list_, TestDisabled); +} + +// Gets the number of tests to be printed in the XML report. +int TestSuite::reportable_test_count() const { + return CountIf(test_info_list_, TestReportable); +} + +// Get the number of tests in this test suite that should run. +int TestSuite::test_to_run_count() const { + return CountIf(test_info_list_, ShouldRunTest); +} + +// Gets the number of all tests. +int TestSuite::total_test_count() const { + return static_cast(test_info_list_.size()); +} + +// Creates a TestSuite with the given name. +// +// Arguments: +// +// name: name of the test suite +// a_type_param: the name of the test suite's type parameter, or NULL if +// this is not a typed or a type-parameterized test suite. +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +TestSuite::TestSuite(const char* a_name, const char* a_type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) + : name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : nullptr), + set_up_tc_(set_up_tc), + tear_down_tc_(tear_down_tc), + should_run_(false), + start_timestamp_(0), + elapsed_time_(0) {} + +// Destructor of TestSuite. +TestSuite::~TestSuite() { + // Deletes every Test in the collection. + ForEach(test_info_list_, internal::Delete); +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +const TestInfo* TestSuite::GetTestInfo(int i) const { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? nullptr : test_info_list_[static_cast(index)]; +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +TestInfo* TestSuite::GetMutableTestInfo(int i) { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? nullptr : test_info_list_[static_cast(index)]; +} + +// Adds a test to this test suite. Will delete the test upon +// destruction of the TestSuite object. +void TestSuite::AddTestInfo(TestInfo* test_info) { + test_info_list_.push_back(test_info); + test_indices_.push_back(static_cast(test_indices_.size())); +} + +// Runs every test in this TestSuite. +void TestSuite::Run() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_suite(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Call both legacy and the new API + repeater->OnTestSuiteStart(*this); +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI + repeater->OnTestCaseStart(*this); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI + + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()"); + + start_timestamp_ = internal::GetTimeInMillis(); + for (int i = 0; i < total_test_count(); i++) { + GetMutableTestInfo(i)->Run(); + } + elapsed_time_ = internal::GetTimeInMillis() - start_timestamp_; + + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestSuite::RunTearDownTestSuite, "TearDownTestSuite()"); + + // Call both legacy and the new API + repeater->OnTestSuiteEnd(*this); +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI + repeater->OnTestCaseEnd(*this); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI + + impl->set_current_test_suite(nullptr); +} + +// Clears the results of all tests in this test suite. +void TestSuite::ClearResult() { + ad_hoc_test_result_.Clear(); + ForEach(test_info_list_, TestInfo::ClearTestResult); +} + +// Shuffles the tests in this test suite. +void TestSuite::ShuffleTests(internal::Random* random) { + Shuffle(random, &test_indices_); +} + +// Restores the test order to before the first shuffle. +void TestSuite::UnshuffleTests() { + for (size_t i = 0; i < test_indices_.size(); i++) { + test_indices_[i] = static_cast(i); + } +} + +// Formats a countable noun. Depending on its quantity, either the +// singular form or the plural form is used. e.g. +// +// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". +// FormatCountableNoun(5, "book", "books") returns "5 books". +static std::string FormatCountableNoun(int count, + const char * singular_form, + const char * plural_form) { + return internal::StreamableToString(count) + " " + + (count == 1 ? singular_form : plural_form); +} + +// Formats the count of tests. +static std::string FormatTestCount(int test_count) { + return FormatCountableNoun(test_count, "test", "tests"); +} + +// Formats the count of test suites. +static std::string FormatTestSuiteCount(int test_suite_count) { + return FormatCountableNoun(test_suite_count, "test suite", "test suites"); +} + +// Converts a TestPartResult::Type enum to human-friendly string +// representation. Both kNonFatalFailure and kFatalFailure are translated +// to "Failure", as the user usually doesn't care about the difference +// between the two when viewing the test result. +static const char * TestPartResultTypeToString(TestPartResult::Type type) { + switch (type) { + case TestPartResult::kSkip: + return "Skipped"; + case TestPartResult::kSuccess: + return "Success"; + + case TestPartResult::kNonFatalFailure: + case TestPartResult::kFatalFailure: +#ifdef _MSC_VER + return "error: "; +#else + return "Failure\n"; +#endif + default: + return "Unknown result type"; + } +} + +namespace internal { + +// Prints a TestPartResult to an std::string. +static std::string PrintTestPartResultToString( + const TestPartResult& test_part_result) { + return (Message() + << internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()) + << " " << TestPartResultTypeToString(test_part_result.type()) + << test_part_result.message()).GetString(); +} + +// Prints a TestPartResult. +static void PrintTestPartResult(const TestPartResult& test_part_result) { + const std::string& result = + PrintTestPartResultToString(test_part_result); + printf("%s\n", result.c_str()); + fflush(stdout); + // If the test program runs in Visual Studio or a debugger, the + // following statements add the test part result message to the Output + // window such that the user can double-click on it to jump to the + // corresponding source code location; otherwise they do nothing. +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + // We don't call OutputDebugString*() on Windows Mobile, as printing + // to stdout is done by OutputDebugString() there already - we don't + // want the same message printed twice. + ::OutputDebugStringA(result.c_str()); + ::OutputDebugStringA("\n"); +#endif +} + +// class PrettyUnitTestResultPrinter +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW + +// Returns the character attribute for the given color. +static WORD GetColorAttribute(GTestColor color) { + switch (color) { + case COLOR_RED: return FOREGROUND_RED; + case COLOR_GREEN: return FOREGROUND_GREEN; + case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + default: return 0; + } +} + +static int GetBitOffset(WORD color_mask) { + if (color_mask == 0) return 0; + + int bitOffset = 0; + while ((color_mask & 1) == 0) { + color_mask >>= 1; + ++bitOffset; + } + return bitOffset; +} + +static WORD GetNewColor(GTestColor color, WORD old_color_attrs) { + // Let's reuse the BG + static const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY; + static const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED | FOREGROUND_INTENSITY; + const WORD existing_bg = old_color_attrs & background_mask; + + WORD new_color = + GetColorAttribute(color) | existing_bg | FOREGROUND_INTENSITY; + static const int bg_bitOffset = GetBitOffset(background_mask); + static const int fg_bitOffset = GetBitOffset(foreground_mask); + + if (((new_color & background_mask) >> bg_bitOffset) == + ((new_color & foreground_mask) >> fg_bitOffset)) { + new_color ^= FOREGROUND_INTENSITY; // invert intensity + } + return new_color; +} + +#else + +// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// an invalid input. +static const char* GetAnsiColorCode(GTestColor color) { + switch (color) { + case COLOR_RED: return "1"; + case COLOR_GREEN: return "2"; + case COLOR_YELLOW: return "3"; + default: + return nullptr; + } +} + +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns true if and only if Google Test should use colors in the output. +bool ShouldUseColor(bool stdout_is_tty) { + const char* const gtest_color = GTEST_FLAG(color).c_str(); + + if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return stdout_is_tty; +#else + // On non-Windows platforms, we rely on the TERM variable. + const char* const term = posix::GetEnv("TERM"); + const bool term_supports_color = + String::CStringEquals(term, "xterm") || + String::CStringEquals(term, "xterm-color") || + String::CStringEquals(term, "xterm-256color") || + String::CStringEquals(term, "screen") || + String::CStringEquals(term, "screen-256color") || + String::CStringEquals(term, "tmux") || + String::CStringEquals(term, "tmux-256color") || + String::CStringEquals(term, "rxvt-unicode") || + String::CStringEquals(term, "rxvt-unicode-256color") || + String::CStringEquals(term, "linux") || + String::CStringEquals(term, "cygwin"); + return stdout_is_tty && term_supports_color; +#endif // GTEST_OS_WINDOWS + } + + return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || + String::CaseInsensitiveCStringEquals(gtest_color, "true") || + String::CaseInsensitiveCStringEquals(gtest_color, "t") || + String::CStringEquals(gtest_color, "1"); + // We take "yes", "true", "t", and "1" as meaning "yes". If the + // value is neither one of these nor "auto", we treat it as "no" to + // be conservative. +} + +// Helpers for printing colored strings to stdout. Note that on Windows, we +// cannot simply emit special characters and have the terminal change colors. +// This routine must actually emit the characters rather than return a string +// that would be colored when printed, as can be done on Linux. +void ColoredPrintf(GTestColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS || GTEST_OS_IOS || \ + GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT || defined(ESP_PLATFORM) + const bool use_color = AlwaysFalse(); +#else + static const bool in_color_mode = + ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); + const bool use_color = in_color_mode && (color != COLOR_DEFAULT); +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS + + if (!use_color) { + vprintf(fmt, args); + va_end(args); + return; + } + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + const WORD new_color = GetNewColor(color, old_color_attrs); + + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); + SetConsoleTextAttribute(stdout_handle, new_color); + + vprintf(fmt, args); + + fflush(stdout); + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + printf("\033[0;3%sm", GetAnsiColorCode(color)); + vprintf(fmt, args); + printf("\033[m"); // Resets the terminal to default. +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + va_end(args); +} + +// Text printed in Google Test's text output and --gtest_list_tests +// output to label the type parameter and value parameter for a test. +static const char kTypeParamLabel[] = "TypeParam"; +static const char kValueParamLabel[] = "GetParam()"; + +static void PrintFullTestCommentIfPresent(const TestInfo& test_info) { + const char* const type_param = test_info.type_param(); + const char* const value_param = test_info.value_param(); + + if (type_param != nullptr || value_param != nullptr) { + printf(", where "); + if (type_param != nullptr) { + printf("%s = %s", kTypeParamLabel, type_param); + if (value_param != nullptr) printf(" and "); + } + if (value_param != nullptr) { + printf("%s = %s", kValueParamLabel, value_param); + } + } +} + +// This class implements the TestEventListener interface. +// +// Class PrettyUnitTestResultPrinter is copyable. +class PrettyUnitTestResultPrinter : public TestEventListener { + public: + PrettyUnitTestResultPrinter() {} + static void PrintTestName(const char* test_suite, const char* test) { + printf("%s.%s", test_suite, test); + } + + // The following methods override what's in the TestEventListener class. + void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest& unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase& test_case) override; +#else + void OnTestSuiteStart(const TestSuite& test_suite) override; +#endif // OnTestCaseStart + + void OnTestStart(const TestInfo& test_info) override; + + void OnTestPartResult(const TestPartResult& result) override; + void OnTestEnd(const TestInfo& test_info) override; +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& test_case) override; +#else + void OnTestSuiteEnd(const TestSuite& test_suite) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} + + private: + static void PrintFailedTests(const UnitTest& unit_test); + static void PrintSkippedTests(const UnitTest& unit_test); +}; + + // Fired before each iteration of tests starts. +void PrettyUnitTestResultPrinter::OnTestIterationStart( + const UnitTest& unit_test, int iteration) { + if (GTEST_FLAG(repeat) != 1) + printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); + + const char* const filter = GTEST_FLAG(filter).c_str(); + + // Prints the filter if it's not *. This reminds the user that some + // tests may be skipped. + if (!String::CStringEquals(filter, kUniversalFilter)) { + ColoredPrintf(COLOR_YELLOW, + "Note: %s filter = %s\n", GTEST_NAME_, filter); + } + + if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { + const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); + ColoredPrintf(COLOR_YELLOW, + "Note: This is test shard %d of %s.\n", + static_cast(shard_index) + 1, + internal::posix::GetEnv(kTestTotalShards)); + } + + if (GTEST_FLAG(shuffle)) { + ColoredPrintf(COLOR_YELLOW, + "Note: Randomizing tests' orders with a seed of %d .\n", + unit_test.random_seed()); + } + + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("Running %s from %s.\n", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment set-up.\n"); + fflush(stdout); +} + +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { + const std::string counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_case.name()); + if (test_case.type_param() == nullptr) { + printf("\n"); + } else { + printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); + } + fflush(stdout); +} +#else +void PrettyUnitTestResultPrinter::OnTestSuiteStart( + const TestSuite& test_suite) { + const std::string counts = + FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_suite.name()); + if (test_suite.type_param() == nullptr) { + printf("\n"); + } else { + printf(", where %s = %s\n", kTypeParamLabel, test_suite.type_param()); + } + fflush(stdout); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { + ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + PrintTestName(test_info.test_suite_name(), test_info.name()); + printf("\n"); + fflush(stdout); +} + +// Called after an assertion failure. +void PrettyUnitTestResultPrinter::OnTestPartResult( + const TestPartResult& result) { + switch (result.type()) { + // If the test part succeeded, or was skipped, + // we don't need to do anything. + case TestPartResult::kSkip: + case TestPartResult::kSuccess: + return; + default: + // Print failure message from the assertion + // (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); + } +} + +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { + ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else if (test_info.result()->Skipped()) { + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + } else { + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + } + PrintTestName(test_info.test_suite_name(), test_info.name()); + if (test_info.result()->Failed()) + PrintFullTestCommentIfPresent(test_info); + + if (GTEST_FLAG(print_time)) { + printf(" (%s ms)\n", internal::StreamableToString( + test_info.result()->elapsed_time()).c_str()); + } else { + printf("\n"); + } + fflush(stdout); +} + +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { + if (!GTEST_FLAG(print_time)) return; + + const std::string counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(), + internal::StreamableToString(test_case.elapsed_time()).c_str()); + fflush(stdout); +} +#else +void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite& test_suite) { + if (!GTEST_FLAG(print_time)) return; + + const std::string counts = + FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_suite.name(), + internal::StreamableToString(test_suite.elapsed_time()).c_str()); + fflush(stdout); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment tear-down\n"); + fflush(stdout); +} + +// Internal helper for printing the list of failed tests. +void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { + const int failed_test_count = unit_test.failed_test_count(); + if (failed_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite& test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run() || (test_suite.failed_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_suite.total_test_count(); ++j) { + const TestInfo& test_info = *test_suite.GetTestInfo(j); + if (!test_info.should_run() || !test_info.result()->Failed()) { + continue; + } + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s.%s", test_suite.name(), test_info.name()); + PrintFullTestCommentIfPresent(test_info); + printf("\n"); + } + } +} + +// Internal helper for printing the list of skipped tests. +void PrettyUnitTestResultPrinter::PrintSkippedTests(const UnitTest& unit_test) { + const int skipped_test_count = unit_test.skipped_test_count(); + if (skipped_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite& test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run() || (test_suite.skipped_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_suite.total_test_count(); ++j) { + const TestInfo& test_info = *test_suite.GetTestInfo(j); + if (!test_info.should_run() || !test_info.result()->Skipped()) { + continue; + } + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + printf("%s.%s", test_suite.name(), test_info.name()); + printf("\n"); + } + } +} + +void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("%s from %s ran.", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms total)", + internal::StreamableToString(unit_test.elapsed_time()).c_str()); + } + printf("\n"); + ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + + const int skipped_test_count = unit_test.skipped_test_count(); + if (skipped_test_count > 0) { + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + printf("%s, listed below:\n", FormatTestCount(skipped_test_count).c_str()); + PrintSkippedTests(unit_test); + } + + int num_failures = unit_test.failed_test_count(); + if (!unit_test.Passed()) { + const int failed_test_count = unit_test.failed_test_count(); + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); + PrintFailedTests(unit_test); + printf("\n%2d FAILED %s\n", num_failures, + num_failures == 1 ? "TEST" : "TESTS"); + } + + int num_disabled = unit_test.reportable_disabled_test_count(); + if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { + if (!num_failures) { + printf("\n"); // Add a spacer if no FAILURE banner is displayed. + } + ColoredPrintf(COLOR_YELLOW, + " YOU HAVE %d DISABLED %s\n\n", + num_disabled, + num_disabled == 1 ? "TEST" : "TESTS"); + } + // Ensure that Google Test output is printed before, e.g., heapchecker output. + fflush(stdout); +} + +// End PrettyUnitTestResultPrinter + +// class TestEventRepeater +// +// This class forwards events to other event listeners. +class TestEventRepeater : public TestEventListener { + public: + TestEventRepeater() : forwarding_enabled_(true) {} + ~TestEventRepeater() override; + void Append(TestEventListener *listener); + TestEventListener* Release(TestEventListener* listener); + + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled() const { return forwarding_enabled_; } + void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } + + void OnTestProgramStart(const UnitTest& unit_test) override; + void OnTestIterationStart(const UnitTest& unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) override; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestSuite& parameter) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestSuiteStart(const TestSuite& parameter) override; + void OnTestStart(const TestInfo& test_info) override; + void OnTestPartResult(const TestPartResult& result) override; + void OnTestEnd(const TestInfo& test_info) override; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& parameter) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestSuiteEnd(const TestSuite& parameter) override; + void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) override; + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest& unit_test) override; + + private: + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled_; + // The list of listeners that receive events. + std::vector listeners_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); +}; + +TestEventRepeater::~TestEventRepeater() { + ForEach(listeners_, Delete); +} + +void TestEventRepeater::Append(TestEventListener *listener) { + listeners_.push_back(listener); +} + +TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { + for (size_t i = 0; i < listeners_.size(); ++i) { + if (listeners_[i] == listener) { + listeners_.erase(listeners_.begin() + static_cast(i)); + return listener; + } + } + + return nullptr; +} + +// Since most methods are very similar, use macros to reduce boilerplate. +// This defines a member that forwards the call to all listeners. +#define GTEST_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = 0; i < listeners_.size(); i++) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} +// This defines a member that forwards the call to all listeners in reverse +// order. +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ + void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = listeners_.size(); i != 0; i--) { \ + listeners_[i - 1]->Name(parameter); \ + } \ + } \ + } + +GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestSuite) +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite) +GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) +GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) +GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestSuite) +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REVERSE_REPEATER_METHOD_(OnTestSuiteEnd, TestSuite) +GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) + +#undef GTEST_REPEATER_METHOD_ +#undef GTEST_REVERSE_REPEATER_METHOD_ + +void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (size_t i = 0; i < listeners_.size(); i++) { + listeners_[i]->OnTestIterationStart(unit_test, iteration); + } + } +} + +void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (size_t i = listeners_.size(); i > 0; i--) { + listeners_[i - 1]->OnTestIterationEnd(unit_test, iteration); + } + } +} + +// End TestEventRepeater + +// This class generates an XML output file. +class XmlUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit XmlUnitTestResultPrinter(const char* output_file); + + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + void ListTestsMatchingFilter(const std::vector& test_suites); + + // Prints an XML summary of all unit tests. + static void PrintXmlTestsList(std::ostream* stream, + const std::vector& test_suites); + + private: + // Is c a whitespace character that is normalized to a space character + // when it appears in an XML attribute value? + static bool IsNormalizableWhitespace(char c) { + return c == 0x9 || c == 0xA || c == 0xD; + } + + // May c appear in a well-formed XML document? + static bool IsValidXmlCharacter(char c) { + return IsNormalizableWhitespace(c) || c >= 0x20; + } + + // Returns an XML-escaped copy of the input string str. If + // is_attribute is true, the text is meant to appear as an attribute + // value, and normalizable whitespace is preserved by replacing it + // with character references. + static std::string EscapeXml(const std::string& str, bool is_attribute); + + // Returns the given string with all characters invalid in XML removed. + static std::string RemoveInvalidXmlCharacters(const std::string& str); + + // Convenience wrapper around EscapeXml when str is an attribute value. + static std::string EscapeXmlAttribute(const std::string& str) { + return EscapeXml(str, true); + } + + // Convenience wrapper around EscapeXml when str is not an attribute value. + static std::string EscapeXmlText(const char* str) { + return EscapeXml(str, false); + } + + // Verifies that the given attribute belongs to the given element and + // streams the attribute as XML. + static void OutputXmlAttribute(std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value); + + // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. + static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + + // Streams an XML representation of a TestInfo object. + static void OutputXmlTestInfo(::std::ostream* stream, + const char* test_suite_name, + const TestInfo& test_info); + + // Prints an XML representation of a TestSuite object + static void PrintXmlTestSuite(::std::ostream* stream, + const TestSuite& test_suite); + + // Prints an XML summary of unit_test to output stream out. + static void PrintXmlUnitTest(::std::ostream* stream, + const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as space + // delimited XML attributes based on the property key="value" pairs. + // When the std::string is not empty, it includes a space at the beginning, + // to delimit this attribute from prior attributes. + static std::string TestPropertiesAsXmlAttributes(const TestResult& result); + + // Streams an XML representation of the test properties of a TestResult + // object. + static void OutputXmlTestProperties(std::ostream* stream, + const TestResult& result); + + // The output file. + const std::string output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); +}; + +// Creates a new XmlUnitTestResultPrinter. +XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "XML output file may not be null"; + } +} + +// Called after the unit test ends. +void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* xmlout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintXmlUnitTest(&stream, unit_test); + fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); + fclose(xmlout); +} + +void XmlUnitTestResultPrinter::ListTestsMatchingFilter( + const std::vector& test_suites) { + FILE* xmlout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintXmlTestsList(&stream, test_suites); + fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); + fclose(xmlout); +} + +// Returns an XML-escaped copy of the input string str. If is_attribute +// is true, the text is meant to appear as an attribute value, and +// normalizable whitespace is preserved by replacing it with character +// references. +// +// Invalid XML characters in str, if any, are stripped from the output. +// It is expected that most, if not all, of the text processed by this +// module will consist of ordinary English text. +// If this module is ever modified to produce version 1.1 XML output, +// most invalid characters can be retained using character references. +std::string XmlUnitTestResultPrinter::EscapeXml( + const std::string& str, bool is_attribute) { + Message m; + + for (size_t i = 0; i < str.size(); ++i) { + const char ch = str[i]; + switch (ch) { + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: + if (IsValidXmlCharacter(ch)) { + if (is_attribute && IsNormalizableWhitespace(ch)) + m << "&#x" << String::FormatByte(static_cast(ch)) + << ";"; + else + m << ch; + } + break; + } + } + + return m.GetString(); +} + +// Returns the given string with all characters invalid in XML removed. +// Currently invalid characters are dropped from the string. An +// alternative is to replace them with certain characters such as . or ?. +std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( + const std::string& str) { + std::string output; + output.reserve(str.size()); + for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) + if (IsValidXmlCharacter(*it)) + output.push_back(*it); + + return output; +} + +// The following routines generate an XML representation of a UnitTest +// object. +// GOOGLETEST_CM0009 DO NOT DELETE +// +// This is how Google Test concepts map to the DTD: +// +// <-- corresponds to a UnitTest object +// <-- corresponds to a TestSuite object +// <-- corresponds to a TestInfo object +// ... +// ... +// ... +// <-- individual assertion failures +// +// +// + +// Formats the given time in milliseconds as seconds. +std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { + ::std::stringstream ss; + ss << (static_cast(ms) * 1e-3); + return ss.str(); +} + +static bool PortableLocaltime(time_t seconds, struct tm* out) { +#if defined(_MSC_VER) + return localtime_s(out, &seconds) == 0; +#elif defined(__MINGW32__) || defined(__MINGW64__) + // MINGW provides neither localtime_r nor localtime_s, but uses + // Windows' localtime(), which has a thread-local tm buffer. + struct tm* tm_ptr = localtime(&seconds); // NOLINT + if (tm_ptr == nullptr) return false; + *out = *tm_ptr; + return true; +#else + return localtime_r(&seconds, out) != nullptr; +#endif +} + +// Converts the given epoch time in milliseconds to a date string in the ISO +// 8601 format, without the timezone information. +std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { + struct tm time_struct; + if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) + return ""; + // YYYY-MM-DDThh:mm:ss + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec); +} + +// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. +void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, + const char* data) { + const char* segment = data; + *stream << ""); + if (next_segment != nullptr) { + stream->write( + segment, static_cast(next_segment - segment)); + *stream << "]]>]]>"); + } else { + *stream << segment; + break; + } + } + *stream << "]]>"; +} + +void XmlUnitTestResultPrinter::OutputXmlAttribute( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value) { + const std::vector& allowed_names = + GetReservedOutputAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Attribute " << name << " is not allowed for element <" << element_name + << ">."; + + *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; +} + +// Prints an XML representation of a TestInfo object. +void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, + const char* test_suite_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + const std::string kTestsuite = "testcase"; + + if (test_info.is_in_another_shard()) { + return; + } + + *stream << " \n"; + return; + } + + OutputXmlAttribute(stream, kTestsuite, "status", + test_info.should_run() ? "run" : "notrun"); + OutputXmlAttribute(stream, kTestsuite, "result", + test_info.should_run() + ? (result.Skipped() ? "skipped" : "completed") + : "suppressed"); + OutputXmlAttribute(stream, kTestsuite, "time", + FormatTimeInMillisAsSeconds(result.elapsed_time())); + OutputXmlAttribute( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsIso8601(result.start_timestamp())); + OutputXmlAttribute(stream, kTestsuite, "classname", test_suite_name); + + int failures = 0; + for (int i = 0; i < result.total_part_count(); ++i) { + const TestPartResult& part = result.GetTestPartResult(i); + if (part.failed()) { + if (++failures == 1) { + *stream << ">\n"; + } + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string summary = location + "\n" + part.summary(); + *stream << " "; + const std::string detail = location + "\n" + part.message(); + OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); + *stream << "\n"; + } + } + + if (failures == 0 && result.test_property_count() == 0) { + *stream << " />\n"; + } else { + if (failures == 0) { + *stream << ">\n"; + } + OutputXmlTestProperties(stream, result); + *stream << " \n"; + } +} + +// Prints an XML representation of a TestSuite object +void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream, + const TestSuite& test_suite) { + const std::string kTestsuite = "testsuite"; + *stream << " <" << kTestsuite; + OutputXmlAttribute(stream, kTestsuite, "name", test_suite.name()); + OutputXmlAttribute(stream, kTestsuite, "tests", + StreamableToString(test_suite.reportable_test_count())); + if (!GTEST_FLAG(list_tests)) { + OutputXmlAttribute(stream, kTestsuite, "failures", + StreamableToString(test_suite.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuite, "disabled", + StreamableToString(test_suite.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuite, "errors", "0"); + OutputXmlAttribute(stream, kTestsuite, "time", + FormatTimeInMillisAsSeconds(test_suite.elapsed_time())); + OutputXmlAttribute( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp())); + *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result()); + } + *stream << ">\n"; + for (int i = 0; i < test_suite.total_test_count(); ++i) { + if (test_suite.GetTestInfo(i)->is_reportable()) + OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); + } + *stream << " \n"; +} + +// Prints an XML summary of unit_test to output stream out. +void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, + const UnitTest& unit_test) { + const std::string kTestsuites = "testsuites"; + + *stream << "\n"; + *stream << "<" << kTestsuites; + + OutputXmlAttribute(stream, kTestsuites, "tests", + StreamableToString(unit_test.reportable_test_count())); + OutputXmlAttribute(stream, kTestsuites, "failures", + StreamableToString(unit_test.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuites, "disabled", + StreamableToString(unit_test.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuites, "errors", "0"); + OutputXmlAttribute(stream, kTestsuites, "time", + FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); + OutputXmlAttribute( + stream, kTestsuites, "timestamp", + FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); + + if (GTEST_FLAG(shuffle)) { + OutputXmlAttribute(stream, kTestsuites, "random_seed", + StreamableToString(unit_test.random_seed())); + } + *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); + + OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); + *stream << ">\n"; + + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) + PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i)); + } + *stream << "\n"; +} + +void XmlUnitTestResultPrinter::PrintXmlTestsList( + std::ostream* stream, const std::vector& test_suites) { + const std::string kTestsuites = "testsuites"; + + *stream << "\n"; + *stream << "<" << kTestsuites; + + int total_tests = 0; + for (auto test_suite : test_suites) { + total_tests += test_suite->total_test_count(); + } + OutputXmlAttribute(stream, kTestsuites, "tests", + StreamableToString(total_tests)); + OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); + *stream << ">\n"; + + for (auto test_suite : test_suites) { + PrintXmlTestSuite(stream, *test_suite); + } + *stream << "\n"; +} + +// Produces a string representing the test properties in a result as space +// delimited XML attributes based on the property key="value" pairs. +std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( + const TestResult& result) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << " " << property.key() << "=" + << "\"" << EscapeXmlAttribute(property.value()) << "\""; + } + return attributes.GetString(); +} + +void XmlUnitTestResultPrinter::OutputXmlTestProperties( + std::ostream* stream, const TestResult& result) { + const std::string kProperties = "properties"; + const std::string kProperty = "property"; + + if (result.test_property_count() <= 0) { + return; + } + + *stream << "<" << kProperties << ">\n"; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + *stream << "<" << kProperty; + *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\""; + *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\""; + *stream << "/>\n"; + } + *stream << "\n"; +} + +// End XmlUnitTestResultPrinter + +// This class generates an JSON output file. +class JsonUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit JsonUnitTestResultPrinter(const char* output_file); + + void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; + + // Prints an JSON summary of all unit tests. + static void PrintJsonTestList(::std::ostream* stream, + const std::vector& test_suites); + + private: + // Returns an JSON-escaped copy of the input string str. + static std::string EscapeJson(const std::string& str); + + //// Verifies that the given attribute belongs to the given element and + //// streams the attribute as JSON. + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma = true); + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma = true); + + // Streams a JSON representation of a TestInfo object. + static void OutputJsonTestInfo(::std::ostream* stream, + const char* test_suite_name, + const TestInfo& test_info); + + // Prints a JSON representation of a TestSuite object + static void PrintJsonTestSuite(::std::ostream* stream, + const TestSuite& test_suite); + + // Prints a JSON summary of unit_test to output stream out. + static void PrintJsonUnitTest(::std::ostream* stream, + const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as + // a JSON dictionary. + static std::string TestPropertiesAsJson(const TestResult& result, + const std::string& indent); + + // The output file. + const std::string output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(JsonUnitTestResultPrinter); +}; + +// Creates a new JsonUnitTestResultPrinter. +JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "JSON output file may not be null"; + } +} + +void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* jsonout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintJsonUnitTest(&stream, unit_test); + fprintf(jsonout, "%s", StringStreamToString(&stream).c_str()); + fclose(jsonout); +} + +// Returns an JSON-escaped copy of the input string str. +std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) { + Message m; + + for (size_t i = 0; i < str.size(); ++i) { + const char ch = str[i]; + switch (ch) { + case '\\': + case '"': + case '/': + m << '\\' << ch; + break; + case '\b': + m << "\\b"; + break; + case '\t': + m << "\\t"; + break; + case '\n': + m << "\\n"; + break; + case '\f': + m << "\\f"; + break; + case '\r': + m << "\\r"; + break; + default: + if (ch < ' ') { + m << "\\u00" << String::FormatByte(static_cast(ch)); + } else { + m << ch; + } + break; + } + } + + return m.GetString(); +} + +// The following routines generate an JSON representation of a UnitTest +// object. + +// Formats the given time in milliseconds as seconds. +static std::string FormatTimeInMillisAsDuration(TimeInMillis ms) { + ::std::stringstream ss; + ss << (static_cast(ms) * 1e-3) << "s"; + return ss.str(); +} + +// Converts the given epoch time in milliseconds to a date string in the +// RFC3339 format, without the timezone information. +static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) { + struct tm time_struct; + if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) + return ""; + // YYYY-MM-DDThh:mm:ss + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec) + "Z"; +} + +static inline std::string Indent(size_t width) { + return std::string(width, ' '); +} + +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma) { + const std::vector& allowed_names = + GetReservedOutputAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": \"" << EscapeJson(value) << "\""; + if (comma) + *stream << ",\n"; +} + +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma) { + const std::vector& allowed_names = + GetReservedOutputAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": " << StreamableToString(value); + if (comma) + *stream << ",\n"; +} + +// Prints a JSON representation of a TestInfo object. +void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, + const char* test_suite_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + const std::string kTestsuite = "testcase"; + const std::string kIndent = Indent(10); + + *stream << Indent(8) << "{\n"; + OutputJsonKey(stream, kTestsuite, "name", test_info.name(), kIndent); + + if (test_info.value_param() != nullptr) { + OutputJsonKey(stream, kTestsuite, "value_param", test_info.value_param(), + kIndent); + } + if (test_info.type_param() != nullptr) { + OutputJsonKey(stream, kTestsuite, "type_param", test_info.type_param(), + kIndent); + } + if (GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestsuite, "file", test_info.file(), kIndent); + OutputJsonKey(stream, kTestsuite, "line", test_info.line(), kIndent, false); + *stream << "\n" << Indent(8) << "}"; + return; + } + + OutputJsonKey(stream, kTestsuite, "status", + test_info.should_run() ? "RUN" : "NOTRUN", kIndent); + OutputJsonKey(stream, kTestsuite, "result", + test_info.should_run() + ? (result.Skipped() ? "SKIPPED" : "COMPLETED") + : "SUPPRESSED", + kIndent); + OutputJsonKey(stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuite, "time", + FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent); + OutputJsonKey(stream, kTestsuite, "classname", test_suite_name, kIndent, + false); + *stream << TestPropertiesAsJson(result, kIndent); + + int failures = 0; + for (int i = 0; i < result.total_part_count(); ++i) { + const TestPartResult& part = result.GetTestPartResult(i); + if (part.failed()) { + *stream << ",\n"; + if (++failures == 1) { + *stream << kIndent << "\"" << "failures" << "\": [\n"; + } + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string message = EscapeJson(location + "\n" + part.message()); + *stream << kIndent << " {\n" + << kIndent << " \"failure\": \"" << message << "\",\n" + << kIndent << " \"type\": \"\"\n" + << kIndent << " }"; + } + } + + if (failures > 0) + *stream << "\n" << kIndent << "]"; + *stream << "\n" << Indent(8) << "}"; +} + +// Prints an JSON representation of a TestSuite object +void JsonUnitTestResultPrinter::PrintJsonTestSuite( + std::ostream* stream, const TestSuite& test_suite) { + const std::string kTestsuite = "testsuite"; + const std::string kIndent = Indent(6); + + *stream << Indent(4) << "{\n"; + OutputJsonKey(stream, kTestsuite, "name", test_suite.name(), kIndent); + OutputJsonKey(stream, kTestsuite, "tests", test_suite.reportable_test_count(), + kIndent); + if (!GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestsuite, "failures", + test_suite.failed_test_count(), kIndent); + OutputJsonKey(stream, kTestsuite, "disabled", + test_suite.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent); + OutputJsonKey( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsRFC3339(test_suite.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuite, "time", + FormatTimeInMillisAsDuration(test_suite.elapsed_time()), + kIndent, false); + *stream << TestPropertiesAsJson(test_suite.ad_hoc_test_result(), kIndent) + << ",\n"; + } + + *stream << kIndent << "\"" << kTestsuite << "\": [\n"; + + bool comma = false; + for (int i = 0; i < test_suite.total_test_count(); ++i) { + if (test_suite.GetTestInfo(i)->is_reportable()) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); + } + } + *stream << "\n" << kIndent << "]\n" << Indent(4) << "}"; +} + +// Prints a JSON summary of unit_test to output stream out. +void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, + const UnitTest& unit_test) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + + OutputJsonKey(stream, kTestsuites, "tests", unit_test.reportable_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "failures", unit_test.failed_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "disabled", + unit_test.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuites, "errors", 0, kIndent); + if (GTEST_FLAG(shuffle)) { + OutputJsonKey(stream, kTestsuites, "random_seed", unit_test.random_seed(), + kIndent); + } + OutputJsonKey(stream, kTestsuites, "timestamp", + FormatEpochTimeInMillisAsRFC3339(unit_test.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuites, "time", + FormatTimeInMillisAsDuration(unit_test.elapsed_time()), kIndent, + false); + + *stream << TestPropertiesAsJson(unit_test.ad_hoc_test_result(), kIndent) + << ",\n"; + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + bool comma = false; + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + PrintJsonTestSuite(stream, *unit_test.GetTestSuite(i)); + } + } + + *stream << "\n" << kIndent << "]\n" << "}\n"; +} + +void JsonUnitTestResultPrinter::PrintJsonTestList( + std::ostream* stream, const std::vector& test_suites) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + int total_tests = 0; + for (auto test_suite : test_suites) { + total_tests += test_suite->total_test_count(); + } + OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent); + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + for (size_t i = 0; i < test_suites.size(); ++i) { + if (i != 0) { + *stream << ",\n"; + } + PrintJsonTestSuite(stream, *test_suites[i]); + } + + *stream << "\n" + << kIndent << "]\n" + << "}\n"; +} +// Produces a string representing the test properties in a result as +// a JSON dictionary. +std::string JsonUnitTestResultPrinter::TestPropertiesAsJson( + const TestResult& result, const std::string& indent) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << ",\n" << indent << "\"" << property.key() << "\": " + << "\"" << EscapeJson(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End JsonUnitTestResultPrinter + +#if GTEST_CAN_STREAM_RESULTS_ + +// Checks if str contains '=', '&', '%' or '\n' characters. If yes, +// replaces them by "%xx" where xx is their hexadecimal value. For +// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) +// in both time and space -- important as the input str may contain an +// arbitrarily long test failure message and stack trace. +std::string StreamingListener::UrlEncode(const char* str) { + std::string result; + result.reserve(strlen(str) + 1); + for (char ch = *str; ch != '\0'; ch = *++str) { + switch (ch) { + case '%': + case '=': + case '&': + case '\n': + result.append("%" + String::FormatByte(static_cast(ch))); + break; + default: + result.push_back(ch); + break; + } + } + return result; +} + +void StreamingListener::SocketWriter::MakeConnection() { + GTEST_CHECK_(sockfd_ == -1) + << "MakeConnection() can't be called when there is already a connection."; + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. + hints.ai_socktype = SOCK_STREAM; + addrinfo* servinfo = nullptr; + + // Use the getaddrinfo() to get a linked list of IP addresses for + // the given host name. + const int error_num = getaddrinfo( + host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); + if (error_num != 0) { + GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " + << gai_strerror(error_num); + } + + // Loop through all the results and connect to the first we can. + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != nullptr; + cur_addr = cur_addr->ai_next) { + sockfd_ = socket( + cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); + if (sockfd_ != -1) { + // Connect the client socket to the server socket. + if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { + close(sockfd_); + sockfd_ = -1; + } + } + } + + freeaddrinfo(servinfo); // all done with this structure + + if (sockfd_ == -1) { + GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " + << host_name_ << ":" << port_num_; + } +} + +// End of class Streaming Listener +#endif // GTEST_CAN_STREAM_RESULTS__ + +// class OsStackTraceGetter + +const char* const OsStackTraceGetterInterface::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; + +std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) + GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + std::string result; + + if (max_depth <= 0) { + return result; + } + + max_depth = std::min(max_depth, kMaxStackTraceDepth); + + std::vector raw_stack(max_depth); + // Skips the frames requested by the caller, plus this function. + const int raw_stack_size = + absl::GetStackTrace(&raw_stack[0], max_depth, skip_count + 1); + + void* caller_frame = nullptr; + { + MutexLock lock(&mutex_); + caller_frame = caller_frame_; + } + + for (int i = 0; i < raw_stack_size; ++i) { + if (raw_stack[i] == caller_frame && + !GTEST_FLAG(show_internal_stack_frames)) { + // Add a marker to the trace and stop adding frames. + absl::StrAppend(&result, kElidedFramesMarker, "\n"); + break; + } + + char tmp[1024]; + const char* symbol = "(unknown)"; + if (absl::Symbolize(raw_stack[i], tmp, sizeof(tmp))) { + symbol = tmp; + } + + char line[1024]; + snprintf(line, sizeof(line), " %p: %s\n", raw_stack[i], symbol); + result += line; + } + + return result; + +#else // !GTEST_HAS_ABSL + static_cast(max_depth); + static_cast(skip_count); + return ""; +#endif // GTEST_HAS_ABSL +} + +void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + void* caller_frame = nullptr; + if (absl::GetStackTrace(&caller_frame, 1, 3) <= 0) { + caller_frame = nullptr; + } + + MutexLock lock(&mutex_); + caller_frame_ = caller_frame; +#endif // GTEST_HAS_ABSL +} + +// A helper class that creates the premature-exit file in its +// constructor and deletes the file in its destructor. +class ScopedPrematureExitFile { + public: + explicit ScopedPrematureExitFile(const char* premature_exit_filepath) + : premature_exit_filepath_(premature_exit_filepath ? + premature_exit_filepath : "") { + // If a path to the premature-exit file is specified... + if (!premature_exit_filepath_.empty()) { + // create the file with a single "0" character in it. I/O + // errors are ignored as there's nothing better we can do and we + // don't want to fail the test because of this. + FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); + fwrite("0", 1, 1, pfile); + fclose(pfile); + } + } + + ~ScopedPrematureExitFile() { + if (!premature_exit_filepath_.empty()) { + int retval = remove(premature_exit_filepath_.c_str()); + if (retval) { + GTEST_LOG_(ERROR) << "Failed to remove premature exit filepath \"" + << premature_exit_filepath_ << "\" with error " + << retval; + } + } + } + + private: + const std::string premature_exit_filepath_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); +}; + +} // namespace internal + +// class TestEventListeners + +TestEventListeners::TestEventListeners() + : repeater_(new internal::TestEventRepeater()), + default_result_printer_(nullptr), + default_xml_generator_(nullptr) {} + +TestEventListeners::~TestEventListeners() { delete repeater_; } + +// Returns the standard listener responsible for the default console +// output. Can be removed from the listeners list to shut down default +// console output. Note that removing this object from the listener list +// with Release transfers its ownership to the user. +void TestEventListeners::Append(TestEventListener* listener) { + repeater_->Append(listener); +} + +// Removes the given event listener from the list and returns it. It then +// becomes the caller's responsibility to delete the listener. Returns +// NULL if the listener is not found in the list. +TestEventListener* TestEventListeners::Release(TestEventListener* listener) { + if (listener == default_result_printer_) + default_result_printer_ = nullptr; + else if (listener == default_xml_generator_) + default_xml_generator_ = nullptr; + return repeater_->Release(listener); +} + +// Returns repeater that broadcasts the TestEventListener events to all +// subscribers. +TestEventListener* TestEventListeners::repeater() { return repeater_; } + +// Sets the default_result_printer attribute to the provided listener. +// The listener is also added to the listener list and previous +// default_result_printer is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { + if (default_result_printer_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_result_printer_); + default_result_printer_ = listener; + if (listener != nullptr) Append(listener); + } +} + +// Sets the default_xml_generator attribute to the provided listener. The +// listener is also added to the listener list and previous +// default_xml_generator is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { + if (default_xml_generator_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_xml_generator_); + default_xml_generator_ = listener; + if (listener != nullptr) Append(listener); + } +} + +// Controls whether events will be forwarded by the repeater to the +// listeners in the list. +bool TestEventListeners::EventForwardingEnabled() const { + return repeater_->forwarding_enabled(); +} + +void TestEventListeners::SuppressEventForwarding() { + repeater_->set_forwarding_enabled(false); +} + +// class UnitTest + +// Gets the singleton UnitTest object. The first time this method is +// called, a UnitTest object is constructed and returned. Consecutive +// calls will return the same object. +// +// We don't protect this under mutex_ as a user is not supposed to +// call this before main() starts, from which point on the return +// value will never change. +UnitTest* UnitTest::GetInstance() { + // CodeGear C++Builder insists on a public destructor for the + // default implementation. Use this implementation to keep good OO + // design with private destructor. + +#if defined(__BORLANDC__) + static UnitTest* const instance = new UnitTest; + return instance; +#else + static UnitTest instance; + return &instance; +#endif // defined(__BORLANDC__) +} + +// Gets the number of successful test suites. +int UnitTest::successful_test_suite_count() const { + return impl()->successful_test_suite_count(); +} + +// Gets the number of failed test suites. +int UnitTest::failed_test_suite_count() const { + return impl()->failed_test_suite_count(); +} + +// Gets the number of all test suites. +int UnitTest::total_test_suite_count() const { + return impl()->total_test_suite_count(); +} + +// Gets the number of all test suites that contain at least one test +// that should run. +int UnitTest::test_suite_to_run_count() const { + return impl()->test_suite_to_run_count(); +} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_suite_count(); +} +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_suite_count(); +} +int UnitTest::total_test_case_count() const { + return impl()->total_test_suite_count(); +} +int UnitTest::test_case_to_run_count() const { + return impl()->test_suite_to_run_count(); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +// Gets the number of successful tests. +int UnitTest::successful_test_count() const { + return impl()->successful_test_count(); +} + +// Gets the number of skipped tests. +int UnitTest::skipped_test_count() const { + return impl()->skipped_test_count(); +} + +// Gets the number of failed tests. +int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } + +// Gets the number of disabled tests that will be reported in the XML report. +int UnitTest::reportable_disabled_test_count() const { + return impl()->reportable_disabled_test_count(); +} + +// Gets the number of disabled tests. +int UnitTest::disabled_test_count() const { + return impl()->disabled_test_count(); +} + +// Gets the number of tests to be printed in the XML report. +int UnitTest::reportable_test_count() const { + return impl()->reportable_test_count(); +} + +// Gets the number of all tests. +int UnitTest::total_test_count() const { return impl()->total_test_count(); } + +// Gets the number of tests that should run. +int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } + +// Gets the time of the test program start, in ms from the start of the +// UNIX epoch. +internal::TimeInMillis UnitTest::start_timestamp() const { + return impl()->start_timestamp(); +} + +// Gets the elapsed time, in milliseconds. +internal::TimeInMillis UnitTest::elapsed_time() const { + return impl()->elapsed_time(); +} + +// Returns true if and only if the unit test passed (i.e. all test suites +// passed). +bool UnitTest::Passed() const { return impl()->Passed(); } + +// Returns true if and only if the unit test failed (i.e. some test suite +// failed or something outside of all tests failed). +bool UnitTest::Failed() const { return impl()->Failed(); } + +// Gets the i-th test suite among all the test suites. i can range from 0 to +// total_test_suite_count() - 1. If i is not in that range, returns NULL. +const TestSuite* UnitTest::GetTestSuite(int i) const { + return impl()->GetTestSuite(i); +} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +const TestCase* UnitTest::GetTestCase(int i) const { + return impl()->GetTestCase(i); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +// Returns the TestResult containing information on test failures and +// properties logged outside of individual test suites. +const TestResult& UnitTest::ad_hoc_test_result() const { + return *impl()->ad_hoc_test_result(); +} + +// Gets the i-th test suite among all the test suites. i can range from 0 to +// total_test_suite_count() - 1. If i is not in that range, returns NULL. +TestSuite* UnitTest::GetMutableTestSuite(int i) { + return impl()->GetMutableSuiteCase(i); +} + +// Returns the list of event listeners that can be used to track events +// inside Google Test. +TestEventListeners& UnitTest::listeners() { + return *impl()->listeners(); +} + +// Registers and returns a global test environment. When a test +// program is run, all global test environments will be set-up in the +// order they were registered. After all tests in the program have +// finished, all global test environments will be torn-down in the +// *reverse* order they were registered. +// +// The UnitTest object takes ownership of the given environment. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +Environment* UnitTest::AddEnvironment(Environment* env) { + if (env == nullptr) { + return nullptr; + } + + impl_->environments().push_back(env); + return env; +} + +// Adds a TestPartResult to the current TestResult object. All Google Test +// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call +// this to report their results. The user code should use the +// assertion macros instead of calling this directly. +void UnitTest::AddTestPartResult( + TestPartResult::Type result_type, + const char* file_name, + int line_number, + const std::string& message, + const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { + Message msg; + msg << message; + + internal::MutexLock lock(&mutex_); + if (impl_->gtest_trace_stack().size() > 0) { + msg << "\n" << GTEST_NAME_ << " trace:"; + + for (size_t i = impl_->gtest_trace_stack().size(); i > 0; --i) { + const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; + msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) + << " " << trace.message; + } + } + + if (os_stack_trace.c_str() != nullptr && !os_stack_trace.empty()) { + msg << internal::kStackTraceMarker << os_stack_trace; + } + + const TestPartResult result = TestPartResult( + result_type, file_name, line_number, msg.GetString().c_str()); + impl_->GetTestPartResultReporterForCurrentThread()-> + ReportTestPartResult(result); + + if (result_type != TestPartResult::kSuccess && + result_type != TestPartResult::kSkip) { + // gtest_break_on_failure takes precedence over + // gtest_throw_on_failure. This allows a user to set the latter + // in the code (perhaps in order to use Google Test assertions + // with another testing framework) and specify the former on the + // command line for debugging. + if (GTEST_FLAG(break_on_failure)) { +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + // Using DebugBreak on Windows allows gtest to still break into a debugger + // when a failure happens and both the --gtest_break_on_failure and + // the --gtest_catch_exceptions flags are specified. + DebugBreak(); +#elif (!defined(__native_client__)) && \ + ((defined(__clang__) || defined(__GNUC__)) && \ + (defined(__x86_64__) || defined(__i386__))) + // with clang/gcc we can achieve the same effect on x86 by invoking int3 + asm("int3"); +#else + // Dereference nullptr through a volatile pointer to prevent the compiler + // from removing. We use this rather than abort() or __builtin_trap() for + // portability: some debuggers don't correctly trap abort(). + *static_cast(nullptr) = 1; +#endif // GTEST_OS_WINDOWS + } else if (GTEST_FLAG(throw_on_failure)) { +#if GTEST_HAS_EXCEPTIONS + throw internal::GoogleTestFailureException(result); +#else + // We cannot call abort() as it generates a pop-up in debug mode + // that cannot be suppressed in VC 7.1 or below. + exit(1); +#endif + } + } +} + +// Adds a TestProperty to the current TestResult object when invoked from +// inside a test, to current TestSuite's ad_hoc_test_result_ when invoked +// from SetUpTestSuite or TearDownTestSuite, or to the global property set +// when invoked elsewhere. If the result already contains a property with +// the same key, the value will be updated. +void UnitTest::RecordProperty(const std::string& key, + const std::string& value) { + impl_->RecordProperty(TestProperty(key, value)); +} + +// Runs all tests in this UnitTest object and prints the result. +// Returns 0 if successful, or 1 otherwise. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +int UnitTest::Run() { + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).length() > 0; + + // Google Test implements this protocol for catching that a test + // program exits before returning control to Google Test: + // + // 1. Upon start, Google Test creates a file whose absolute path + // is specified by the environment variable + // TEST_PREMATURE_EXIT_FILE. + // 2. When Google Test has finished its work, it deletes the file. + // + // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before + // running a Google-Test-based test program and check the existence + // of the file at the end of the test execution to see if it has + // exited prematurely. + + // If we are in the child process of a death test, don't + // create/delete the premature exit file, as doing so is unnecessary + // and will confuse the parent process. Otherwise, create/delete + // the file upon entering/leaving this function. If the program + // somehow exits before this function has a chance to return, the + // premature-exit file will be left undeleted, causing a test runner + // that understands the premature-exit-file protocol to report the + // test as having failed. + const internal::ScopedPrematureExitFile premature_exit_file( + in_death_test_child_process + ? nullptr + : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); + + // Captures the value of GTEST_FLAG(catch_exceptions). This value will be + // used for the duration of the program. + impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); + +#if GTEST_OS_WINDOWS + // Either the user wants Google Test to catch exceptions thrown by the + // tests or this is executing in the context of death test child + // process. In either case the user does not want to see pop-up dialogs + // about crashes - they are expected. + if (impl()->catch_exceptions() || in_death_test_child_process) { +# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + // SetErrorMode doesn't exist on CE. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); +# endif // !GTEST_OS_WINDOWS_MOBILE + +# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE + // Death test children can be terminated with _abort(). On Windows, + // _abort() can show a dialog with a warning message. This forces the + // abort message to go to stderr instead. + _set_error_mode(_OUT_TO_STDERR); +# endif + +# if defined(_MSC_VER) && !GTEST_OS_WINDOWS_MOBILE + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program. We need to suppress + // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement + // executed. Google Test will notify the user of any unexpected + // failure via stderr. + if (!GTEST_FLAG(break_on_failure)) + _set_abort_behavior( + 0x0, // Clear the following flags: + _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. +# endif + + // In debug mode, the Windows CRT can crash with an assertion over invalid + // input (e.g. passing an invalid file descriptor). The default handling + // for these assertions is to pop up a dialog and wait for user input. + // Instead ask the CRT to dump such assertions to stderr non-interactively. + if (!IsDebuggerPresent()) { + (void)_CrtSetReportMode(_CRT_ASSERT, + _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + } + } +#endif // GTEST_OS_WINDOWS + + return internal::HandleExceptionsInMethodIfSupported( + impl(), + &internal::UnitTestImpl::RunAllTests, + "auxiliary test code (environments or event listeners)") ? 0 : 1; +} + +// Returns the working directory when the first TEST() or TEST_F() was +// executed. +const char* UnitTest::original_working_dir() const { + return impl_->original_working_dir_.c_str(); +} + +// Returns the TestSuite object for the test that's currently running, +// or NULL if no test is running. +const TestSuite* UnitTest::current_test_suite() const + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + return impl_->current_test_suite(); +} + +// Legacy API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +const TestCase* UnitTest::current_test_case() const + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + return impl_->current_test_suite(); +} +#endif + +// Returns the TestInfo object for the test that's currently running, +// or NULL if no test is running. +const TestInfo* UnitTest::current_test_info() const + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + return impl_->current_test_info(); +} + +// Returns the random seed used at the start of the current test run. +int UnitTest::random_seed() const { return impl_->random_seed(); } + +// Returns ParameterizedTestSuiteRegistry object used to keep track of +// value-parameterized tests and instantiate and register them. +internal::ParameterizedTestSuiteRegistry& +UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) { + return impl_->parameterized_test_registry(); +} + +// Creates an empty UnitTest. +UnitTest::UnitTest() { + impl_ = new internal::UnitTestImpl(this); +} + +// Destructor of UnitTest. +UnitTest::~UnitTest() { + delete impl_; +} + +// Pushes a trace defined by SCOPED_TRACE() on to the per-thread +// Google Test trace stack. +void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().push_back(trace); +} + +// Pops a trace from the per-thread Google Test trace stack. +void UnitTest::PopGTestTrace() + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().pop_back(); +} + +namespace internal { + +UnitTestImpl::UnitTestImpl(UnitTest* parent) + : parent_(parent), + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */) + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), + GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_( + &default_global_test_part_result_reporter_), + per_thread_test_part_result_reporter_( + &default_per_thread_test_part_result_reporter_), + parameterized_test_registry_(), + parameterized_tests_registered_(false), + last_death_test_suite_(-1), + current_test_suite_(nullptr), + current_test_info_(nullptr), + ad_hoc_test_result_(), + os_stack_trace_getter_(nullptr), + post_flag_parse_init_performed_(false), + random_seed_(0), // Will be overridden by the flag before first use. + random_(0), // Will be reseeded before first use. + start_timestamp_(0), + elapsed_time_(0), +#if GTEST_HAS_DEATH_TEST + death_test_factory_(new DefaultDeathTestFactory), +#endif + // Will be overridden by the flag before first use. + catch_exceptions_(false) { + listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); +} + +UnitTestImpl::~UnitTestImpl() { + // Deletes every TestSuite. + ForEach(test_suites_, internal::Delete); + + // Deletes every Environment. + ForEach(environments_, internal::Delete); + + delete os_stack_trace_getter_; +} + +// Adds a TestProperty to the current TestResult object when invoked in a +// context of a test, to current test suite's ad_hoc_test_result when invoke +// from SetUpTestSuite/TearDownTestSuite, or to the global property set +// otherwise. If the result already contains a property with the same key, +// the value will be updated. +void UnitTestImpl::RecordProperty(const TestProperty& test_property) { + std::string xml_element; + TestResult* test_result; // TestResult appropriate for property recording. + + if (current_test_info_ != nullptr) { + xml_element = "testcase"; + test_result = &(current_test_info_->result_); + } else if (current_test_suite_ != nullptr) { + xml_element = "testsuite"; + test_result = &(current_test_suite_->ad_hoc_test_result_); + } else { + xml_element = "testsuites"; + test_result = &ad_hoc_test_result_; + } + test_result->RecordProperty(xml_element, test_property); +} + +#if GTEST_HAS_DEATH_TEST +// Disables event forwarding if the control is currently in a death test +// subprocess. Must not be called before InitGoogleTest. +void UnitTestImpl::SuppressTestEventsIfInSubprocess() { + if (internal_run_death_test_flag_.get() != nullptr) + listeners()->SuppressEventForwarding(); +} +#endif // GTEST_HAS_DEATH_TEST + +// Initializes event listeners performing XML output as specified by +// UnitTestOptions. Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureXmlOutput() { + const std::string& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format == "json") { + listeners()->SetDefaultXmlGenerator(new JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format != "") { + GTEST_LOG_(WARNING) << "WARNING: unrecognized output format \"" + << output_format << "\" ignored."; + } +} + +#if GTEST_CAN_STREAM_RESULTS_ +// Initializes event listeners for streaming test results in string form. +// Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureStreamingOutput() { + const std::string& target = GTEST_FLAG(stream_result_to); + if (!target.empty()) { + const size_t pos = target.find(':'); + if (pos != std::string::npos) { + listeners()->Append(new StreamingListener(target.substr(0, pos), + target.substr(pos+1))); + } else { + GTEST_LOG_(WARNING) << "unrecognized streaming target \"" << target + << "\" ignored."; + } + } +} +#endif // GTEST_CAN_STREAM_RESULTS_ + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. +void UnitTestImpl::PostFlagParsingInit() { + // Ensures that this function does not execute more than once. + if (!post_flag_parse_init_performed_) { + post_flag_parse_init_performed_ = true; + +#if defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) + // Register to send notifications about key process state changes. + listeners()->Append(new GTEST_CUSTOM_TEST_EVENT_LISTENER_()); +#endif // defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) + +#if GTEST_HAS_DEATH_TEST + InitDeathTestSubprocessControlInfo(); + SuppressTestEventsIfInSubprocess(); +#endif // GTEST_HAS_DEATH_TEST + + // Registers parameterized tests. This makes parameterized tests + // available to the UnitTest reflection API without running + // RUN_ALL_TESTS. + RegisterParameterizedTests(); + + // Configures listeners for XML output. This makes it possible for users + // to shut down the default XML output before invoking RUN_ALL_TESTS. + ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Configures listeners for streaming test results to the specified server. + ConfigureStreamingOutput(); +#endif // GTEST_CAN_STREAM_RESULTS_ + +#if GTEST_HAS_ABSL + if (GTEST_FLAG(install_failure_signal_handler)) { + absl::FailureSignalHandlerOptions options; + absl::InstallFailureSignalHandler(options); + } +#endif // GTEST_HAS_ABSL + } +} + +// A predicate that checks the name of a TestSuite against a known +// value. +// +// This is used for implementation of the UnitTest class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestSuiteNameIs is copyable. +class TestSuiteNameIs { + public: + // Constructor. + explicit TestSuiteNameIs(const std::string& name) : name_(name) {} + + // Returns true if and only if the name of test_suite matches name_. + bool operator()(const TestSuite* test_suite) const { + return test_suite != nullptr && + strcmp(test_suite->name(), name_.c_str()) == 0; + } + + private: + std::string name_; +}; + +// Finds and returns a TestSuite with the given name. If one doesn't +// exist, creates one and returns it. It's the CALLER'S +// RESPONSIBILITY to ensure that this function is only called WHEN THE +// TESTS ARE NOT SHUFFLED. +// +// Arguments: +// +// test_suite_name: name of the test suite +// type_param: the name of the test suite's type parameter, or NULL if +// this is not a typed or a type-parameterized test suite. +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +TestSuite* UnitTestImpl::GetTestSuite( + const char* test_suite_name, const char* type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) { + // Can we find a TestSuite with the given name? + const auto test_suite = + std::find_if(test_suites_.rbegin(), test_suites_.rend(), + TestSuiteNameIs(test_suite_name)); + + if (test_suite != test_suites_.rend()) return *test_suite; + + // No. Let's create one. + auto* const new_test_suite = + new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc); + + // Is this a death test suite? + if (internal::UnitTestOptions::MatchesFilter(test_suite_name, + kDeathTestSuiteFilter)) { + // Yes. Inserts the test suite after the last death test suite + // defined so far. This only works when the test suites haven't + // been shuffled. Otherwise we may end up running a death test + // after a non-death test. + ++last_death_test_suite_; + test_suites_.insert(test_suites_.begin() + last_death_test_suite_, + new_test_suite); + } else { + // No. Appends to the end of the list. + test_suites_.push_back(new_test_suite); + } + + test_suite_indices_.push_back(static_cast(test_suite_indices_.size())); + return new_test_suite; +} + +// Helpers for setting up / tearing down the given environment. They +// are for use in the ForEach() function. +static void SetUpEnvironment(Environment* env) { env->SetUp(); } +static void TearDownEnvironment(Environment* env) { env->TearDown(); } + +// Runs all tests in this UnitTest object, prints the result, and +// returns true if all tests are successful. If any exception is +// thrown during a test, the test is considered to be failed, but the +// rest of the tests will still be run. +// +// When parameterized tests are enabled, it expands and registers +// parameterized tests first in RegisterParameterizedTests(). +// All other functions called from RunAllTests() may safely assume that +// parameterized tests are ready to be counted and run. +bool UnitTestImpl::RunAllTests() { + // True if and only if Google Test is initialized before RUN_ALL_TESTS() is + // called. + const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized(); + + // Do not run any test if the --help flag was specified. + if (g_help_flag) + return true; + + // Repeats the call to the post-flag parsing initialization in case the + // user didn't call InitGoogleTest. + PostFlagParsingInit(); + + // Even if sharding is not on, test runners may want to use the + // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding + // protocol. + internal::WriteToShardStatusFileIfNeeded(); + + // True if and only if we are in a subprocess for running a thread-safe-style + // death test. + bool in_subprocess_for_death_test = false; + +#if GTEST_HAS_DEATH_TEST + in_subprocess_for_death_test = + (internal_run_death_test_flag_.get() != nullptr); +# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) + if (in_subprocess_for_death_test) { + GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_(); + } +# endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) +#endif // GTEST_HAS_DEATH_TEST + + const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, + in_subprocess_for_death_test); + + // Compares the full test names with the filter to decide which + // tests to run. + const bool has_tests_to_run = FilterTests(should_shard + ? HONOR_SHARDING_PROTOCOL + : IGNORE_SHARDING_PROTOCOL) > 0; + + // Lists the tests and exits if the --gtest_list_tests flag was specified. + if (GTEST_FLAG(list_tests)) { + // This must be called *after* FilterTests() has been called. + ListTestsMatchingFilter(); + return true; + } + + random_seed_ = GTEST_FLAG(shuffle) ? + GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; + + // True if and only if at least one test has failed. + bool failed = false; + + TestEventListener* repeater = listeners()->repeater(); + + start_timestamp_ = GetTimeInMillis(); + repeater->OnTestProgramStart(*parent_); + + // How many times to repeat the tests? We don't want to repeat them + // when we are inside the subprocess of a death test. + const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); + // Repeats forever if the repeat count is negative. + const bool gtest_repeat_forever = repeat < 0; + for (int i = 0; gtest_repeat_forever || i != repeat; i++) { + // We want to preserve failures generated by ad-hoc test + // assertions executed before RUN_ALL_TESTS(). + ClearNonAdHocTestResult(); + + const TimeInMillis start = GetTimeInMillis(); + + // Shuffles test suites and tests if requested. + if (has_tests_to_run && GTEST_FLAG(shuffle)) { + random()->Reseed(static_cast(random_seed_)); + // This should be done before calling OnTestIterationStart(), + // such that a test event listener can see the actual test order + // in the event. + ShuffleTests(); + } + + // Tells the unit test event listeners that the tests are about to start. + repeater->OnTestIterationStart(*parent_, i); + + // Runs each test suite if there is at least one test to run. + if (has_tests_to_run) { + // Sets up all environments beforehand. + repeater->OnEnvironmentsSetUpStart(*parent_); + ForEach(environments_, SetUpEnvironment); + repeater->OnEnvironmentsSetUpEnd(*parent_); + + // Runs the tests only if there was no fatal failure or skip triggered + // during global set-up. + if (Test::IsSkipped()) { + // Emit diagnostics when global set-up calls skip, as it will not be + // emitted by default. + TestResult& test_result = + *internal::GetUnitTestImpl()->current_test_result(); + for (int j = 0; j < test_result.total_part_count(); ++j) { + const TestPartResult& test_part_result = + test_result.GetTestPartResult(j); + if (test_part_result.type() == TestPartResult::kSkip) { + const std::string& result = test_part_result.message(); + printf("%s\n", result.c_str()); + } + } + fflush(stdout); + } else if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_suite_count(); + test_index++) { + GetMutableSuiteCase(test_index)->Run(); + } + } + + // Tears down all environments in reverse order afterwards. + repeater->OnEnvironmentsTearDownStart(*parent_); + std::for_each(environments_.rbegin(), environments_.rend(), + TearDownEnvironment); + repeater->OnEnvironmentsTearDownEnd(*parent_); + } + + elapsed_time_ = GetTimeInMillis() - start; + + // Tells the unit test event listener that the tests have just finished. + repeater->OnTestIterationEnd(*parent_, i); + + // Gets the result and clears it. + if (!Passed()) { + failed = true; + } + + // Restores the original test order after the iteration. This + // allows the user to quickly repro a failure that happens in the + // N-th iteration without repeating the first (N - 1) iterations. + // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in + // case the user somehow changes the value of the flag somewhere + // (it's always safe to unshuffle the tests). + UnshuffleTests(); + + if (GTEST_FLAG(shuffle)) { + // Picks a new random seed for each iteration. + random_seed_ = GetNextRandomSeed(random_seed_); + } + } + + repeater->OnTestProgramEnd(*parent_); + + if (!gtest_is_initialized_before_run_all_tests) { + ColoredPrintf( + COLOR_RED, + "\nIMPORTANT NOTICE - DO NOT IGNORE:\n" + "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_ + "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_ + " will start to enforce the valid usage. " + "Please fix it ASAP, or IT WILL START TO FAIL.\n"); // NOLINT +#if GTEST_FOR_GOOGLE_ + ColoredPrintf(COLOR_RED, + "For more details, see http://wiki/Main/ValidGUnitMain.\n"); +#endif // GTEST_FOR_GOOGLE_ + } + + return !failed; +} + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded() { + const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); + if (test_shard_file != nullptr) { + FILE* const file = posix::FOpen(test_shard_file, "w"); + if (file == nullptr) { + ColoredPrintf(COLOR_RED, + "Could not write to the test shard status file \"%s\" " + "specified by the %s environment variable.\n", + test_shard_file, kTestShardStatusFile); + fflush(stdout); + exit(EXIT_FAILURE); + } + fclose(file); + } +} + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (i.e., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +bool ShouldShard(const char* total_shards_env, + const char* shard_index_env, + bool in_subprocess_for_death_test) { + if (in_subprocess_for_death_test) { + return false; + } + + const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + + if (total_shards == -1 && shard_index == -1) { + return false; + } else if (total_shards == -1 && shard_index != -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestShardIndex << " = " << shard_index + << ", but have left " << kTestTotalShards << " unset.\n"; + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (total_shards != -1 && shard_index == -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestTotalShards << " = " << total_shards + << ", but have left " << kTestShardIndex << " unset.\n"; + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (shard_index < 0 || shard_index >= total_shards) { + const Message msg = Message() + << "Invalid environment variables: we require 0 <= " + << kTestShardIndex << " < " << kTestTotalShards + << ", but you have " << kTestShardIndex << "=" << shard_index + << ", " << kTestTotalShards << "=" << total_shards << ".\n"; + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } + + return total_shards > 1; +} + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error +// and aborts. +Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { + const char* str_val = posix::GetEnv(var); + if (str_val == nullptr) { + return default_val; + } + + Int32 result; + if (!ParseInt32(Message() << "The value of environment variable " << var, + str_val, &result)) { + exit(EXIT_FAILURE); + } + return result; +} + +// Given the total number of shards, the shard index, and the test id, +// returns true if and only if the test should be run on this shard. The test id +// is some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { + return (test_id % total_shards) == shard_index; +} + +// Compares the name of each test with the user-specified filter to +// decide whether the test should be run, then records the result in +// each TestSuite and TestInfo object. +// If shard_tests == true, further filters tests based on sharding +// variables in the environment - see +// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md +// . Returns the number of tests that should run. +int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { + const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + + // num_runnable_tests are the number of tests that will + // run across all shards (i.e., match filter and are not disabled). + // num_selected_tests are the number of tests to be run on + // this shard. + int num_runnable_tests = 0; + int num_selected_tests = 0; + for (auto* test_suite : test_suites_) { + const std::string& test_suite_name = test_suite->name(); + test_suite->set_should_run(false); + + for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { + TestInfo* const test_info = test_suite->test_info_list()[j]; + const std::string test_name(test_info->name()); + // A test is disabled if test suite name or test name matches + // kDisableTestFilter. + const bool is_disabled = internal::UnitTestOptions::MatchesFilter( + test_suite_name, kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter( + test_name, kDisableTestFilter); + test_info->is_disabled_ = is_disabled; + + const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest( + test_suite_name, test_name); + test_info->matches_filter_ = matches_filter; + + const bool is_runnable = + (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && + matches_filter; + + const bool is_in_another_shard = + shard_tests != IGNORE_SHARDING_PROTOCOL && + !ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests); + test_info->is_in_another_shard_ = is_in_another_shard; + const bool is_selected = is_runnable && !is_in_another_shard; + + num_runnable_tests += is_runnable; + num_selected_tests += is_selected; + + test_info->should_run_ = is_selected; + test_suite->set_should_run(test_suite->should_run() || is_selected); + } + } + return num_selected_tests; +} + +// Prints the given C-string on a single line by replacing all '\n' +// characters with string "\\n". If the output takes more than +// max_length characters, only prints the first max_length characters +// and "...". +static void PrintOnOneLine(const char* str, int max_length) { + if (str != nullptr) { + for (int i = 0; *str != '\0'; ++str) { + if (i >= max_length) { + printf("..."); + break; + } + if (*str == '\n') { + printf("\\n"); + i += 2; + } else { + printf("%c", *str); + ++i; + } + } + } +} + +// Prints the names of the tests matching the user-specified filter flag. +void UnitTestImpl::ListTestsMatchingFilter() { + // Print at most this many characters for each type/value parameter. + const int kMaxParamLength = 250; + + for (auto* test_suite : test_suites_) { + bool printed_test_suite_name = false; + + for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { + const TestInfo* const test_info = test_suite->test_info_list()[j]; + if (test_info->matches_filter_) { + if (!printed_test_suite_name) { + printed_test_suite_name = true; + printf("%s.", test_suite->name()); + if (test_suite->type_param() != nullptr) { + printf(" # %s = ", kTypeParamLabel); + // We print the type parameter on a single line to make + // the output easy to parse by a program. + PrintOnOneLine(test_suite->type_param(), kMaxParamLength); + } + printf("\n"); + } + printf(" %s", test_info->name()); + if (test_info->value_param() != nullptr) { + printf(" # %s = ", kValueParamLabel); + // We print the value parameter on a single line to make the + // output easy to parse by a program. + PrintOnOneLine(test_info->value_param(), kMaxParamLength); + } + printf("\n"); + } + } + } + fflush(stdout); + const std::string& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml" || output_format == "json") { + FILE* fileout = OpenFileForWriting( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); + std::stringstream stream; + if (output_format == "xml") { + XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintXmlTestsList(&stream, test_suites_); + } else if (output_format == "json") { + JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintJsonTestList(&stream, test_suites_); + } + fprintf(fileout, "%s", StringStreamToString(&stream).c_str()); + fclose(fileout); + } +} + +// Sets the OS stack trace getter. +// +// Does nothing if the input and the current OS stack trace getter are +// the same; otherwise, deletes the old getter and makes the input the +// current getter. +void UnitTestImpl::set_os_stack_trace_getter( + OsStackTraceGetterInterface* getter) { + if (os_stack_trace_getter_ != getter) { + delete os_stack_trace_getter_; + os_stack_trace_getter_ = getter; + } +} + +// Returns the current OS stack trace getter if it is not NULL; +// otherwise, creates an OsStackTraceGetter, makes it the current +// getter, and returns it. +OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { + if (os_stack_trace_getter_ == nullptr) { +#ifdef GTEST_OS_STACK_TRACE_GETTER_ + os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_; +#else + os_stack_trace_getter_ = new OsStackTraceGetter; +#endif // GTEST_OS_STACK_TRACE_GETTER_ + } + + return os_stack_trace_getter_; +} + +// Returns the most specific TestResult currently running. +TestResult* UnitTestImpl::current_test_result() { + if (current_test_info_ != nullptr) { + return ¤t_test_info_->result_; + } + if (current_test_suite_ != nullptr) { + return ¤t_test_suite_->ad_hoc_test_result_; + } + return &ad_hoc_test_result_; +} + +// Shuffles all test suites, and the tests within each test suite, +// making sure that death tests are still run first. +void UnitTestImpl::ShuffleTests() { + // Shuffles the death test suites. + ShuffleRange(random(), 0, last_death_test_suite_ + 1, &test_suite_indices_); + + // Shuffles the non-death test suites. + ShuffleRange(random(), last_death_test_suite_ + 1, + static_cast(test_suites_.size()), &test_suite_indices_); + + // Shuffles the tests inside each test suite. + for (auto& test_suite : test_suites_) { + test_suite->ShuffleTests(random()); + } +} + +// Restores the test suites and tests to their order before the first shuffle. +void UnitTestImpl::UnshuffleTests() { + for (size_t i = 0; i < test_suites_.size(); i++) { + // Unshuffles the tests in each test suite. + test_suites_[i]->UnshuffleTests(); + // Resets the index of each test suite. + test_suite_indices_[i] = static_cast(i); + } +} + +// Returns the current OS stack trace as an std::string. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, + int skip_count) { + // We pass skip_count + 1 to skip this wrapper function in addition + // to what the user really wants to skip. + return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); +} + +// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to +// suppress unreachable code warnings. +namespace { +class ClassUniqueToAlwaysTrue {}; +} + +bool IsTrue(bool condition) { return condition; } + +bool AlwaysTrue() { +#if GTEST_HAS_EXCEPTIONS + // This condition is always false so AlwaysTrue() never actually throws, + // but it makes the compiler think that it may throw. + if (IsTrue(false)) + throw ClassUniqueToAlwaysTrue(); +#endif // GTEST_HAS_EXCEPTIONS + return true; +} + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr) { + const size_t prefix_len = strlen(prefix); + if (strncmp(*pstr, prefix, prefix_len) == 0) { + *pstr += prefix_len; + return true; + } + return false; +} + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or NULL if the parsing failed. +static const char* ParseFlagValue(const char* str, const char* flag, + bool def_optional) { + // str and flag must not be NULL. + if (str == nullptr || flag == nullptr) return nullptr; + + // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. + const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; + const size_t flag_len = flag_str.length(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) { + return flag_end; + } + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return nullptr; + + // Returns the string after "=". + return flag_end + 1; +} + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true as long as it does +// not start with '0', 'f', or 'F'. +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +static bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == nullptr) return false; + + // Converts the string value to a bool. + *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); + return true; +} + +// Parses a string for an Int32 flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == nullptr) return false; + + // Sets *value to the value of the flag. + return ParseInt32(Message() << "The value of flag --" << flag, + value_str, value); +} + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +template +static bool ParseStringFlag(const char* str, const char* flag, String* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == nullptr) return false; + + // Sets *value to the value of the flag. + *value = value_str; + return true; +} + +// Determines whether a string has a prefix that Google Test uses for its +// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. +// If Google Test detects that a command line flag has its prefix but is not +// recognized, it will print its help message. Flags starting with +// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test +// internal flags and do not trigger the help message. +static bool HasGoogleTestFlagPrefix(const char* str) { + return (SkipPrefix("--", &str) || + SkipPrefix("-", &str) || + SkipPrefix("/", &str)) && + !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && + (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || + SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); +} + +// Prints a string containing code-encoded text. The following escape +// sequences can be used in the string to control the text color: +// +// @@ prints a single '@' character. +// @R changes the color to red. +// @G changes the color to green. +// @Y changes the color to yellow. +// @D changes to the default terminal text color. +// +static void PrintColorEncoded(const char* str) { + GTestColor color = COLOR_DEFAULT; // The current color. + + // Conceptually, we split the string into segments divided by escape + // sequences. Then we print one segment at a time. At the end of + // each iteration, the str pointer advances to the beginning of the + // next segment. + for (;;) { + const char* p = strchr(str, '@'); + if (p == nullptr) { + ColoredPrintf(color, "%s", str); + return; + } + + ColoredPrintf(color, "%s", std::string(str, p).c_str()); + + const char ch = p[1]; + str = p + 2; + if (ch == '@') { + ColoredPrintf(color, "@"); + } else if (ch == 'D') { + color = COLOR_DEFAULT; + } else if (ch == 'R') { + color = COLOR_RED; + } else if (ch == 'G') { + color = COLOR_GREEN; + } else if (ch == 'Y') { + color = COLOR_YELLOW; + } else { + --str; + } + } +} + +static const char kColorEncodedHelpMessage[] = +"This program contains tests written using " GTEST_NAME_ ". You can use the\n" +"following command line flags to control its behavior:\n" +"\n" +"Test Selection:\n" +" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" +" List the names of all tests instead of running them. The name of\n" +" TEST(Foo, Bar) is \"Foo.Bar\".\n" +" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "[@G-@YNEGATIVE_PATTERNS]@D\n" +" Run only the tests whose name matches one of the positive patterns but\n" +" none of the negative patterns. '?' matches any single character; '*'\n" +" matches any substring; ':' separates two patterns.\n" +" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" +" Run all disabled tests too.\n" +"\n" +"Test Execution:\n" +" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" +" Run the tests repeatedly; use a negative count to repeat forever.\n" +" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" +" Randomize tests' orders on every iteration.\n" +" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" +" Random number seed to use for shuffling test orders (between 1 and\n" +" 99999, or 0 to use a seed based on the current time).\n" +"\n" +"Test Output:\n" +" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" +" Enable/disable colored output. The default is @Gauto@D.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" +" Don't print the elapsed time of each test.\n" +" @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" + GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" +" Generate a JSON or XML report in the given directory or with the given\n" +" file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n" +# if GTEST_CAN_STREAM_RESULTS_ +" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" +" Stream test results to the given server.\n" +# endif // GTEST_CAN_STREAM_RESULTS_ +"\n" +"Assertion Behavior:\n" +# if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" +" Set the default death test style.\n" +# endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" +" Turn assertion failures into debugger break-points.\n" +" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" +" Turn assertion failures into C++ exceptions for use by an external\n" +" test framework.\n" +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" +" Do not report exceptions as test failures. Instead, allow them\n" +" to crash the program or throw a pop-up (on Windows).\n" +"\n" +"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + "the corresponding\n" +"environment variable of a flag (all letters in upper-case). For example, to\n" +"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "color=no@D or set\n" +"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" +"\n" +"For more information, please read the " GTEST_NAME_ " documentation at\n" +"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" +"(not one in your own code or tests), please report it to\n" +"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + +static bool ParseGoogleTestFlag(const char* const arg) { + return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseBoolFlag(arg, kPrintUTF8Flag, >EST_FLAG(print_utf8)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)); +} + +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +static void LoadFlagsFromFile(const std::string& path) { + FILE* flagfile = posix::FOpen(path.c_str(), "r"); + if (!flagfile) { + GTEST_LOG_(FATAL) << "Unable to open file \"" << GTEST_FLAG(flagfile) + << "\""; + } + std::string contents(ReadEntireFile(flagfile)); + posix::FClose(flagfile); + std::vector lines; + SplitString(contents, '\n', &lines); + for (size_t i = 0; i < lines.size(); ++i) { + if (lines[i].empty()) + continue; + if (!ParseGoogleTestFlag(lines[i].c_str())) + g_help_flag = true; + } +} +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. The type parameter CharType can be +// instantiated to either char or wchar_t. +template +void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { + for (int i = 1; i < *argc; i++) { + const std::string arg_string = StreamableToString(argv[i]); + const char* const arg = arg_string.c_str(); + + using internal::ParseBoolFlag; + using internal::ParseInt32Flag; + using internal::ParseStringFlag; + + bool remove_flag = false; + if (ParseGoogleTestFlag(arg)) { + remove_flag = true; +#if GTEST_USE_OWN_FLAGFILE_FLAG_ + } else if (ParseStringFlag(arg, kFlagfileFlag, >EST_FLAG(flagfile))) { + LoadFlagsFromFile(GTEST_FLAG(flagfile)); + remove_flag = true; +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + + if (remove_flag) { + // Shift the remainder of the argv list left by one. Note + // that argv has (*argc + 1) elements, the last one always being + // NULL. The following loop moves the trailing NULL element as + // well. + for (int j = i; j != *argc; j++) { + argv[j] = argv[j + 1]; + } + + // Decrements the argument count. + (*argc)--; + + // We also need to decrement the iterator as we just removed + // an element. + i--; + } + } + + if (g_help_flag) { + // We print the help here instead of in RUN_ALL_TESTS(), as the + // latter may not be called at all if the user is using Google + // Test with another testing framework. + PrintColorEncoded(kColorEncodedHelpMessage); + } +} + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +void ParseGoogleTestFlagsOnly(int* argc, char** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); + + // Fix the value of *_NSGetArgc() on macOS, but if and only if + // *_NSGetArgv() == argv + // Only applicable to char** version of argv +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS + if (*_NSGetArgv() == argv) { + *_NSGetArgc() = *argc; + } +#endif +#endif +} +void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} + +// The internal implementation of InitGoogleTest(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleTestImpl(int* argc, CharType** argv) { + // We don't want to run the initialization code twice. + if (GTestIsInitialized()) return; + + if (*argc <= 0) return; + + g_argvs.clear(); + for (int i = 0; i != *argc; i++) { + g_argvs.push_back(StreamableToString(argv[i])); + } + +#if GTEST_HAS_ABSL + absl::InitializeSymbolizer(g_argvs[0].c_str()); +#endif // GTEST_HAS_ABSL + + ParseGoogleTestFlagsOnly(argc, argv); + GetUnitTestImpl()->PostFlagParsingInit(); +} + +} // namespace internal + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +void InitGoogleTest(int* argc, char** argv) { +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + internal::InitGoogleTestImpl(argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +} + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +void InitGoogleTest(int* argc, wchar_t** argv) { +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + internal::InitGoogleTestImpl(argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +} + +// This overloaded version can be used on Arduino/embedded platforms where +// there is no argc/argv. +void InitGoogleTest() { + // Since Arduino doesn't have a command line, fake out the argc/argv arguments + int argc = 1; + const auto arg0 = "dummy"; + char* argv0 = const_cast(arg0); + char** argv = &argv0; + +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(&argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + internal::InitGoogleTestImpl(&argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +} + +std::string TempDir() { +#if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_) + return GTEST_CUSTOM_TEMPDIR_FUNCTION_(); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + return "\\temp\\"; +#elif GTEST_OS_WINDOWS + const char* temp_dir = internal::posix::GetEnv("TEMP"); + if (temp_dir == nullptr || temp_dir[0] == '\0') + return "\\temp\\"; + else if (temp_dir[strlen(temp_dir) - 1] == '\\') + return temp_dir; + else + return std::string(temp_dir) + "\\"; +#elif GTEST_OS_LINUX_ANDROID + return "/sdcard/"; +#else + return "/tmp/"; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +void ScopedTrace::PushTrace(const char* file, int line, std::string message) { + internal::TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message.swap(message); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +ScopedTrace::~ScopedTrace() + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { + UnitTest::GetInstance()->PopGTestTrace(); +} + +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest_main.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest_main.cc new file mode 100644 index 0000000000000000000000000000000000000000..f6e1dd96fb3b374fa1f22be5f87c208e1bcc9ec4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/src/gtest_main.cc @@ -0,0 +1,47 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include "gtest/gtest.h" + +#ifdef ARDUINO +void setup() { + testing::InitGoogleTest(); +} + +void loop() { RUN_ALL_TESTS(); } + +#else + +GTEST_API_ int main(int argc, char **argv) { + printf("Running main() from %s\n", __FILE__); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/BUILD.bazel b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/BUILD.bazel new file mode 100644 index 0000000000000000000000000000000000000000..156d5d4b423ca79a8642a6535c8885108bf86767 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/BUILD.bazel @@ -0,0 +1,521 @@ +# Copyright 2017 Google Inc. +# All Rights Reserved. +# +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Author: misterg@google.com (Gennadiy Civil) +# +# Bazel BUILD for The Google C++ Testing Framework (Google Test) + +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_test") +load("@rules_python//python:defs.bzl", "py_library", "py_test") + +licenses(["notice"]) + +#on windows exclude gtest-tuple.h +cc_test( + name = "gtest_all_test", + size = "small", + srcs = glob( + include = [ + "gtest-*.cc", + "googletest-*.cc", + "*.h", + "googletest/include/gtest/**/*.h", + ], + exclude = [ + "gtest-unittest-api_test.cc", + "googletest/src/gtest-all.cc", + "gtest_all_test.cc", + "gtest-death-test_ex_test.cc", + "gtest-listener_test.cc", + "gtest-unittest-api_test.cc", + "googletest-param-test-test.cc", + "googletest-catch-exceptions-test_.cc", + "googletest-color-test_.cc", + "googletest-env-var-test_.cc", + "googletest-filter-unittest_.cc", + "googletest-break-on-failure-unittest_.cc", + "googletest-listener-test.cc", + "googletest-output-test_.cc", + "googletest-list-tests-unittest_.cc", + "googletest-shuffle-test_.cc", + "googletest-uninitialized-test_.cc", + "googletest-death-test_ex_test.cc", + "googletest-param-test-test", + "googletest-throw-on-failure-test_.cc", + "googletest-param-test-invalid-name1-test_.cc", + "googletest-param-test-invalid-name2-test_.cc", + ], + ) + select({ + "//:windows": [], + "//conditions:default": [], + }), + copts = select({ + "//:windows": ["-DGTEST_USE_OWN_TR1_TUPLE=0"], + "//conditions:default": ["-DGTEST_USE_OWN_TR1_TUPLE=1"], + }), + includes = [ + "googletest", + "googletest/include", + "googletest/include/internal", + "googletest/test", + ], + linkopts = select({ + "//:windows": [], + "//conditions:default": ["-pthread"], + }), + deps = ["//:gtest_main"], +) + +# Tests death tests. +cc_test( + name = "googletest-death-test-test", + size = "medium", + srcs = ["googletest-death-test-test.cc"], + deps = ["//:gtest_main"], +) + +cc_test( + name = "gtest_test_macro_stack_footprint_test", + size = "small", + srcs = ["gtest_test_macro_stack_footprint_test.cc"], + deps = ["//:gtest"], +) + +#These googletest tests have their own main() +cc_test( + name = "googletest-listener-test", + size = "small", + srcs = ["googletest-listener-test.cc"], + deps = ["//:gtest_main"], +) + +cc_test( + name = "gtest-unittest-api_test", + size = "small", + srcs = [ + "gtest-unittest-api_test.cc", + ], + deps = [ + "//:gtest", + ], +) + +cc_test( + name = "googletest-param-test-test", + size = "small", + srcs = [ + "googletest-param-test-test.cc", + "googletest-param-test-test.h", + "googletest-param-test2-test.cc", + ], + deps = ["//:gtest"], +) + +cc_test( + name = "gtest_unittest", + size = "small", + srcs = ["gtest_unittest.cc"], + args = ["--heap_check=strict"], + shard_count = 2, + deps = ["//:gtest_main"], +) + +# Py tests + +py_library( + name = "gtest_test_utils", + testonly = 1, + srcs = ["gtest_test_utils.py"], +) + +cc_binary( + name = "gtest_help_test_", + testonly = 1, + srcs = ["gtest_help_test_.cc"], + deps = ["//:gtest_main"], +) + +py_test( + name = "gtest_help_test", + size = "small", + srcs = ["gtest_help_test.py"], + data = [":gtest_help_test_"], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "googletest-output-test_", + testonly = 1, + srcs = ["googletest-output-test_.cc"], + deps = ["//:gtest"], +) + +py_test( + name = "googletest-output-test", + size = "small", + srcs = ["googletest-output-test.py"], + args = select({ + "//:has_absl": [], + "//conditions:default": ["--no_stacktrace_support"], + }), + data = [ + "googletest-output-test-golden-lin.txt", + ":googletest-output-test_", + ], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "googletest-color-test_", + testonly = 1, + srcs = ["googletest-color-test_.cc"], + deps = ["//:gtest"], +) + +py_test( + name = "googletest-color-test", + size = "small", + srcs = ["googletest-color-test.py"], + data = [":googletest-color-test_"], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "googletest-env-var-test_", + testonly = 1, + srcs = ["googletest-env-var-test_.cc"], + deps = ["//:gtest"], +) + +py_test( + name = "googletest-env-var-test", + size = "medium", + srcs = ["googletest-env-var-test.py"], + data = [":googletest-env-var-test_"], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "googletest-filter-unittest_", + testonly = 1, + srcs = ["googletest-filter-unittest_.cc"], + deps = ["//:gtest"], +) + +py_test( + name = "googletest-filter-unittest", + size = "medium", + srcs = ["googletest-filter-unittest.py"], + data = [":googletest-filter-unittest_"], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "googletest-break-on-failure-unittest_", + testonly = 1, + srcs = ["googletest-break-on-failure-unittest_.cc"], + deps = ["//:gtest"], +) + +py_test( + name = "googletest-break-on-failure-unittest", + size = "small", + srcs = ["googletest-break-on-failure-unittest.py"], + data = [":googletest-break-on-failure-unittest_"], + deps = [":gtest_test_utils"], +) + +cc_test( + name = "gtest_assert_by_exception_test", + size = "small", + srcs = ["gtest_assert_by_exception_test.cc"], + deps = ["//:gtest"], +) + +cc_binary( + name = "googletest-throw-on-failure-test_", + testonly = 1, + srcs = ["googletest-throw-on-failure-test_.cc"], + deps = ["//:gtest"], +) + +py_test( + name = "googletest-throw-on-failure-test", + size = "small", + srcs = ["googletest-throw-on-failure-test.py"], + data = [":googletest-throw-on-failure-test_"], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "googletest-list-tests-unittest_", + testonly = 1, + srcs = ["googletest-list-tests-unittest_.cc"], + deps = ["//:gtest"], +) + +cc_test( + name = "gtest_skip_test", + size = "small", + srcs = ["gtest_skip_test.cc"], + deps = ["//:gtest_main"], +) + +cc_test( + name = "gtest_skip_in_environment_setup_test", + size = "small", + srcs = ["gtest_skip_in_environment_setup_test.cc"], + deps = ["//:gtest_main"], +) + +py_test( + name = "gtest_skip_environment_check_output_test", + size = "small", + srcs = ["gtest_skip_environment_check_output_test.py"], + data = [ + ":gtest_skip_in_environment_setup_test", + ], + deps = [":gtest_test_utils"], +) + +py_test( + name = "googletest-list-tests-unittest", + size = "small", + srcs = ["googletest-list-tests-unittest.py"], + data = [":googletest-list-tests-unittest_"], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "googletest-shuffle-test_", + srcs = ["googletest-shuffle-test_.cc"], + deps = ["//:gtest"], +) + +py_test( + name = "googletest-shuffle-test", + size = "small", + srcs = ["googletest-shuffle-test.py"], + data = [":googletest-shuffle-test_"], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "googletest-catch-exceptions-no-ex-test_", + testonly = 1, + srcs = ["googletest-catch-exceptions-test_.cc"], + deps = ["//:gtest_main"], +) + +cc_binary( + name = "googletest-catch-exceptions-ex-test_", + testonly = 1, + srcs = ["googletest-catch-exceptions-test_.cc"], + copts = ["-fexceptions"], + deps = ["//:gtest_main"], +) + +py_test( + name = "googletest-catch-exceptions-test", + size = "small", + srcs = ["googletest-catch-exceptions-test.py"], + data = [ + ":googletest-catch-exceptions-ex-test_", + ":googletest-catch-exceptions-no-ex-test_", + ], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "gtest_xml_output_unittest_", + testonly = 1, + srcs = ["gtest_xml_output_unittest_.cc"], + deps = ["//:gtest"], +) + +cc_test( + name = "gtest_no_test_unittest", + size = "small", + srcs = ["gtest_no_test_unittest.cc"], + deps = ["//:gtest"], +) + +py_test( + name = "gtest_xml_output_unittest", + size = "small", + srcs = [ + "gtest_xml_output_unittest.py", + "gtest_xml_test_utils.py", + ], + args = select({ + "//:has_absl": [], + "//conditions:default": ["--no_stacktrace_support"], + }), + data = [ + # We invoke gtest_no_test_unittest to verify the XML output + # when the test program contains no test definition. + ":gtest_no_test_unittest", + ":gtest_xml_output_unittest_", + ], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "gtest_xml_outfile1_test_", + testonly = 1, + srcs = ["gtest_xml_outfile1_test_.cc"], + deps = ["//:gtest_main"], +) + +cc_binary( + name = "gtest_xml_outfile2_test_", + testonly = 1, + srcs = ["gtest_xml_outfile2_test_.cc"], + deps = ["//:gtest_main"], +) + +py_test( + name = "gtest_xml_outfiles_test", + size = "small", + srcs = [ + "gtest_xml_outfiles_test.py", + "gtest_xml_test_utils.py", + ], + data = [ + ":gtest_xml_outfile1_test_", + ":gtest_xml_outfile2_test_", + ], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "googletest-uninitialized-test_", + testonly = 1, + srcs = ["googletest-uninitialized-test_.cc"], + deps = ["//:gtest"], +) + +py_test( + name = "googletest-uninitialized-test", + size = "medium", + srcs = ["googletest-uninitialized-test.py"], + data = ["googletest-uninitialized-test_"], + deps = [":gtest_test_utils"], +) + +cc_binary( + name = "gtest_testbridge_test_", + testonly = 1, + srcs = ["gtest_testbridge_test_.cc"], + deps = ["//:gtest_main"], +) + +# Tests that filtering via testbridge works +py_test( + name = "gtest_testbridge_test", + size = "small", + srcs = ["gtest_testbridge_test.py"], + data = [":gtest_testbridge_test_"], + deps = [":gtest_test_utils"], +) + +py_test( + name = "googletest-json-outfiles-test", + size = "small", + srcs = [ + "googletest-json-outfiles-test.py", + "gtest_json_test_utils.py", + ], + data = [ + ":gtest_xml_outfile1_test_", + ":gtest_xml_outfile2_test_", + ], + deps = [":gtest_test_utils"], +) + +py_test( + name = "googletest-json-output-unittest", + size = "medium", + srcs = [ + "googletest-json-output-unittest.py", + "gtest_json_test_utils.py", + ], + args = select({ + "//:has_absl": [], + "//conditions:default": ["--no_stacktrace_support"], + }), + data = [ + # We invoke gtest_no_test_unittest to verify the JSON output + # when the test program contains no test definition. + ":gtest_no_test_unittest", + ":gtest_xml_output_unittest_", + ], + deps = [":gtest_test_utils"], +) + +# Verifies interaction of death tests and exceptions. +cc_test( + name = "googletest-death-test_ex_catch_test", + size = "medium", + srcs = ["googletest-death-test_ex_test.cc"], + copts = ["-fexceptions"], + defines = ["GTEST_ENABLE_CATCH_EXCEPTIONS_=1"], + deps = ["//:gtest"], +) + +cc_binary( + name = "googletest-param-test-invalid-name1-test_", + testonly = 1, + srcs = ["googletest-param-test-invalid-name1-test_.cc"], + deps = ["//:gtest"], +) + +cc_binary( + name = "googletest-param-test-invalid-name2-test_", + testonly = 1, + srcs = ["googletest-param-test-invalid-name2-test_.cc"], + deps = ["//:gtest"], +) + +py_test( + name = "googletest-param-test-invalid-name1-test", + size = "small", + srcs = ["googletest-param-test-invalid-name1-test.py"], + data = [":googletest-param-test-invalid-name1-test_"], + deps = [":gtest_test_utils"], +) + +py_test( + name = "googletest-param-test-invalid-name2-test", + size = "small", + srcs = ["googletest-param-test-invalid-name2-test.py"], + data = [":googletest-param-test-invalid-name2-test_"], + deps = [":gtest_test_utils"], +) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-break-on-failure-unittest.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-break-on-failure-unittest.py new file mode 100755 index 0000000000000000000000000000000000000000..a5dfbc693b43a1b19e3847dcbcab886d2f4d28e6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-break-on-failure-unittest.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +# +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for Google Test's break-on-failure mode. + +A user can ask Google Test to seg-fault when an assertion fails, using +either the GTEST_BREAK_ON_FAILURE environment variable or the +--gtest_break_on_failure flag. This script tests such functionality +by invoking googletest-break-on-failure-unittest_ (a program written with +Google Test) with different environments and command line flags. +""" + +import os +import gtest_test_utils + +# Constants. + +IS_WINDOWS = os.name == 'nt' + +# The environment variable for enabling/disabling the break-on-failure mode. +BREAK_ON_FAILURE_ENV_VAR = 'GTEST_BREAK_ON_FAILURE' + +# The command line flag for enabling/disabling the break-on-failure mode. +BREAK_ON_FAILURE_FLAG = 'gtest_break_on_failure' + +# The environment variable for enabling/disabling the throw-on-failure mode. +THROW_ON_FAILURE_ENV_VAR = 'GTEST_THROW_ON_FAILURE' + +# The environment variable for enabling/disabling the catch-exceptions mode. +CATCH_EXCEPTIONS_ENV_VAR = 'GTEST_CATCH_EXCEPTIONS' + +# Path to the googletest-break-on-failure-unittest_ program. +EXE_PATH = gtest_test_utils.GetTestExecutablePath( + 'googletest-break-on-failure-unittest_') + + +environ = gtest_test_utils.environ +SetEnvVar = gtest_test_utils.SetEnvVar + +# Tests in this file run a Google-Test-based test program and expect it +# to terminate prematurely. Therefore they are incompatible with +# the premature-exit-file protocol by design. Unset the +# premature-exit filepath to prevent Google Test from creating +# the file. +SetEnvVar(gtest_test_utils.PREMATURE_EXIT_FILE_ENV_VAR, None) + + +def Run(command): + """Runs a command; returns 1 if it was killed by a signal, or 0 otherwise.""" + + p = gtest_test_utils.Subprocess(command, env=environ) + if p.terminated_by_signal: + return 1 + else: + return 0 + + +# The tests. + + +class GTestBreakOnFailureUnitTest(gtest_test_utils.TestCase): + """Tests using the GTEST_BREAK_ON_FAILURE environment variable or + the --gtest_break_on_failure flag to turn assertion failures into + segmentation faults. + """ + + def RunAndVerify(self, env_var_value, flag_value, expect_seg_fault): + """Runs googletest-break-on-failure-unittest_ and verifies that it does + (or does not) have a seg-fault. + + Args: + env_var_value: value of the GTEST_BREAK_ON_FAILURE environment + variable; None if the variable should be unset. + flag_value: value of the --gtest_break_on_failure flag; + None if the flag should not be present. + expect_seg_fault: 1 if the program is expected to generate a seg-fault; + 0 otherwise. + """ + + SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, env_var_value) + + if env_var_value is None: + env_var_value_msg = ' is not set' + else: + env_var_value_msg = '=' + env_var_value + + if flag_value is None: + flag = '' + elif flag_value == '0': + flag = '--%s=0' % BREAK_ON_FAILURE_FLAG + else: + flag = '--%s' % BREAK_ON_FAILURE_FLAG + + command = [EXE_PATH] + if flag: + command.append(flag) + + if expect_seg_fault: + should_or_not = 'should' + else: + should_or_not = 'should not' + + has_seg_fault = Run(command) + + SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, None) + + msg = ('when %s%s, an assertion failure in "%s" %s cause a seg-fault.' % + (BREAK_ON_FAILURE_ENV_VAR, env_var_value_msg, ' '.join(command), + should_or_not)) + self.assert_(has_seg_fault == expect_seg_fault, msg) + + def testDefaultBehavior(self): + """Tests the behavior of the default mode.""" + + self.RunAndVerify(env_var_value=None, + flag_value=None, + expect_seg_fault=0) + + def testEnvVar(self): + """Tests using the GTEST_BREAK_ON_FAILURE environment variable.""" + + self.RunAndVerify(env_var_value='0', + flag_value=None, + expect_seg_fault=0) + self.RunAndVerify(env_var_value='1', + flag_value=None, + expect_seg_fault=1) + + def testFlag(self): + """Tests using the --gtest_break_on_failure flag.""" + + self.RunAndVerify(env_var_value=None, + flag_value='0', + expect_seg_fault=0) + self.RunAndVerify(env_var_value=None, + flag_value='1', + expect_seg_fault=1) + + def testFlagOverridesEnvVar(self): + """Tests that the flag overrides the environment variable.""" + + self.RunAndVerify(env_var_value='0', + flag_value='0', + expect_seg_fault=0) + self.RunAndVerify(env_var_value='0', + flag_value='1', + expect_seg_fault=1) + self.RunAndVerify(env_var_value='1', + flag_value='0', + expect_seg_fault=0) + self.RunAndVerify(env_var_value='1', + flag_value='1', + expect_seg_fault=1) + + def testBreakOnFailureOverridesThrowOnFailure(self): + """Tests that gtest_break_on_failure overrides gtest_throw_on_failure.""" + + SetEnvVar(THROW_ON_FAILURE_ENV_VAR, '1') + try: + self.RunAndVerify(env_var_value=None, + flag_value='1', + expect_seg_fault=1) + finally: + SetEnvVar(THROW_ON_FAILURE_ENV_VAR, None) + + if IS_WINDOWS: + def testCatchExceptionsDoesNotInterfere(self): + """Tests that gtest_catch_exceptions doesn't interfere.""" + + SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, '1') + try: + self.RunAndVerify(env_var_value='1', + flag_value='1', + expect_seg_fault=1) + finally: + SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, None) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-break-on-failure-unittest_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-break-on-failure-unittest_.cc new file mode 100644 index 0000000000000000000000000000000000000000..f84957a2d03b56260c8e2c0ae8f5a27beb6f6378 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-break-on-failure-unittest_.cc @@ -0,0 +1,86 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Unit test for Google Test's break-on-failure mode. +// +// A user can ask Google Test to seg-fault when an assertion fails, using +// either the GTEST_BREAK_ON_FAILURE environment variable or the +// --gtest_break_on_failure flag. This file is used for testing such +// functionality. +// +// This program will be invoked from a Python unit test. It is +// expected to fail. Don't run it directly. + +#include "gtest/gtest.h" + +#if GTEST_OS_WINDOWS +# include +# include +#endif + +namespace { + +// A test that's expected to fail. +TEST(Foo, Bar) { + EXPECT_EQ(2, 3); +} + +#if GTEST_HAS_SEH && !GTEST_OS_WINDOWS_MOBILE +// On Windows Mobile global exception handlers are not supported. +LONG WINAPI ExitWithExceptionCode( + struct _EXCEPTION_POINTERS* exception_pointers) { + exit(exception_pointers->ExceptionRecord->ExceptionCode); +} +#endif + +} // namespace + +int main(int argc, char **argv) { +#if GTEST_OS_WINDOWS + // Suppresses display of the Windows error dialog upon encountering + // a general protection fault (segment violation). + SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS); + +# if GTEST_HAS_SEH && !GTEST_OS_WINDOWS_MOBILE + + // The default unhandled exception filter does not always exit + // with the exception code as exit code - for example it exits with + // 0 for EXCEPTION_ACCESS_VIOLATION and 1 for EXCEPTION_BREAKPOINT + // if the application is compiled in debug mode. Thus we use our own + // filter which always exits with the exception code for unhandled + // exceptions. + SetUnhandledExceptionFilter(ExitWithExceptionCode); + +# endif +#endif // GTEST_OS_WINDOWS + testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-catch-exceptions-test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-catch-exceptions-test.py new file mode 100755 index 0000000000000000000000000000000000000000..94a5b33f2305092593755c3ab86aa5f6c329e2a0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-catch-exceptions-test.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python +# +# Copyright 2010 Google Inc. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests Google Test's exception catching behavior. + +This script invokes googletest-catch-exceptions-test_ and +googletest-catch-exceptions-ex-test_ (programs written with +Google Test) and verifies their output. +""" + +import gtest_test_utils + +# Constants. +FLAG_PREFIX = '--gtest_' +LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests' +NO_CATCH_EXCEPTIONS_FLAG = FLAG_PREFIX + 'catch_exceptions=0' +FILTER_FLAG = FLAG_PREFIX + 'filter' + +# Path to the googletest-catch-exceptions-ex-test_ binary, compiled with +# exceptions enabled. +EX_EXE_PATH = gtest_test_utils.GetTestExecutablePath( + 'googletest-catch-exceptions-ex-test_') + +# Path to the googletest-catch-exceptions-test_ binary, compiled with +# exceptions disabled. +EXE_PATH = gtest_test_utils.GetTestExecutablePath( + 'googletest-catch-exceptions-no-ex-test_') + +environ = gtest_test_utils.environ +SetEnvVar = gtest_test_utils.SetEnvVar + +# Tests in this file run a Google-Test-based test program and expect it +# to terminate prematurely. Therefore they are incompatible with +# the premature-exit-file protocol by design. Unset the +# premature-exit filepath to prevent Google Test from creating +# the file. +SetEnvVar(gtest_test_utils.PREMATURE_EXIT_FILE_ENV_VAR, None) + +TEST_LIST = gtest_test_utils.Subprocess( + [EXE_PATH, LIST_TESTS_FLAG], env=environ).output + +SUPPORTS_SEH_EXCEPTIONS = 'ThrowsSehException' in TEST_LIST + +if SUPPORTS_SEH_EXCEPTIONS: + BINARY_OUTPUT = gtest_test_utils.Subprocess([EXE_PATH], env=environ).output + +EX_BINARY_OUTPUT = gtest_test_utils.Subprocess( + [EX_EXE_PATH], env=environ).output + + +# The tests. +if SUPPORTS_SEH_EXCEPTIONS: + # pylint:disable-msg=C6302 + class CatchSehExceptionsTest(gtest_test_utils.TestCase): + """Tests exception-catching behavior.""" + + + def TestSehExceptions(self, test_output): + self.assert_('SEH exception with code 0x2a thrown ' + 'in the test fixture\'s constructor' + in test_output) + self.assert_('SEH exception with code 0x2a thrown ' + 'in the test fixture\'s destructor' + in test_output) + self.assert_('SEH exception with code 0x2a thrown in SetUpTestSuite()' + in test_output) + self.assert_('SEH exception with code 0x2a thrown in TearDownTestSuite()' + in test_output) + self.assert_('SEH exception with code 0x2a thrown in SetUp()' + in test_output) + self.assert_('SEH exception with code 0x2a thrown in TearDown()' + in test_output) + self.assert_('SEH exception with code 0x2a thrown in the test body' + in test_output) + + def testCatchesSehExceptionsWithCxxExceptionsEnabled(self): + self.TestSehExceptions(EX_BINARY_OUTPUT) + + def testCatchesSehExceptionsWithCxxExceptionsDisabled(self): + self.TestSehExceptions(BINARY_OUTPUT) + + +class CatchCxxExceptionsTest(gtest_test_utils.TestCase): + """Tests C++ exception-catching behavior. + + Tests in this test case verify that: + * C++ exceptions are caught and logged as C++ (not SEH) exceptions + * Exception thrown affect the remainder of the test work flow in the + expected manner. + """ + + def testCatchesCxxExceptionsInFixtureConstructor(self): + self.assertTrue( + 'C++ exception with description ' + '"Standard C++ exception" thrown ' + 'in the test fixture\'s constructor' in EX_BINARY_OUTPUT, + EX_BINARY_OUTPUT) + self.assert_('unexpected' not in EX_BINARY_OUTPUT, + 'This failure belongs in this test only if ' + '"CxxExceptionInConstructorTest" (no quotes) ' + 'appears on the same line as words "called unexpectedly"') + + if ('CxxExceptionInDestructorTest.ThrowsExceptionInDestructor' in + EX_BINARY_OUTPUT): + + def testCatchesCxxExceptionsInFixtureDestructor(self): + self.assertTrue( + 'C++ exception with description ' + '"Standard C++ exception" thrown ' + 'in the test fixture\'s destructor' in EX_BINARY_OUTPUT, + EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInDestructorTest::TearDownTestSuite() ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + + def testCatchesCxxExceptionsInSetUpTestCase(self): + self.assertTrue( + 'C++ exception with description "Standard C++ exception"' + ' thrown in SetUpTestSuite()' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInConstructorTest::TearDownTestSuite() ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInSetUpTestSuiteTest constructor ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInSetUpTestSuiteTest destructor ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInSetUpTestSuiteTest::SetUp() ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInSetUpTestSuiteTest::TearDown() ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInSetUpTestSuiteTest test body ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + + def testCatchesCxxExceptionsInTearDownTestCase(self): + self.assertTrue( + 'C++ exception with description "Standard C++ exception"' + ' thrown in TearDownTestSuite()' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + + def testCatchesCxxExceptionsInSetUp(self): + self.assertTrue( + 'C++ exception with description "Standard C++ exception"' + ' thrown in SetUp()' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInSetUpTest::TearDownTestSuite() ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInSetUpTest destructor ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInSetUpTest::TearDown() ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assert_('unexpected' not in EX_BINARY_OUTPUT, + 'This failure belongs in this test only if ' + '"CxxExceptionInSetUpTest" (no quotes) ' + 'appears on the same line as words "called unexpectedly"') + + def testCatchesCxxExceptionsInTearDown(self): + self.assertTrue( + 'C++ exception with description "Standard C++ exception"' + ' thrown in TearDown()' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInTearDownTest::TearDownTestSuite() ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInTearDownTest destructor ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + + def testCatchesCxxExceptionsInTestBody(self): + self.assertTrue( + 'C++ exception with description "Standard C++ exception"' + ' thrown in the test body' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInTestBodyTest::TearDownTestSuite() ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInTestBodyTest destructor ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + self.assertTrue( + 'CxxExceptionInTestBodyTest::TearDown() ' + 'called as expected.' in EX_BINARY_OUTPUT, EX_BINARY_OUTPUT) + + def testCatchesNonStdCxxExceptions(self): + self.assertTrue( + 'Unknown C++ exception thrown in the test body' in EX_BINARY_OUTPUT, + EX_BINARY_OUTPUT) + + def testUnhandledCxxExceptionsAbortTheProgram(self): + # Filters out SEH exception tests on Windows. Unhandled SEH exceptions + # cause tests to show pop-up windows there. + FITLER_OUT_SEH_TESTS_FLAG = FILTER_FLAG + '=-*Seh*' + # By default, Google Test doesn't catch the exceptions. + uncaught_exceptions_ex_binary_output = gtest_test_utils.Subprocess( + [EX_EXE_PATH, + NO_CATCH_EXCEPTIONS_FLAG, + FITLER_OUT_SEH_TESTS_FLAG], + env=environ).output + + self.assert_('Unhandled C++ exception terminating the program' + in uncaught_exceptions_ex_binary_output) + self.assert_('unexpected' not in uncaught_exceptions_ex_binary_output) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-catch-exceptions-test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-catch-exceptions-test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..8c127d40b11d4d72a3faae80bafbb746d1aa4128 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-catch-exceptions-test_.cc @@ -0,0 +1,293 @@ +// Copyright 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Tests for Google Test itself. Tests in this file throw C++ or SEH +// exceptions, and the output is verified by +// googletest-catch-exceptions-test.py. + +#include // NOLINT +#include // For exit(). + +#include "gtest/gtest.h" + +#if GTEST_HAS_SEH +# include +#endif + +#if GTEST_HAS_EXCEPTIONS +# include // For set_terminate(). +# include +#endif + +using testing::Test; + +#if GTEST_HAS_SEH + +class SehExceptionInConstructorTest : public Test { + public: + SehExceptionInConstructorTest() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInConstructorTest, ThrowsExceptionInConstructor) {} + +class SehExceptionInDestructorTest : public Test { + public: + ~SehExceptionInDestructorTest() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInDestructorTest, ThrowsExceptionInDestructor) {} + +class SehExceptionInSetUpTestSuiteTest : public Test { + public: + static void SetUpTestSuite() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInSetUpTestSuiteTest, ThrowsExceptionInSetUpTestSuite) {} + +class SehExceptionInTearDownTestSuiteTest : public Test { + public: + static void TearDownTestSuite() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInTearDownTestSuiteTest, + ThrowsExceptionInTearDownTestSuite) {} + +class SehExceptionInSetUpTest : public Test { + protected: + virtual void SetUp() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInSetUpTest, ThrowsExceptionInSetUp) {} + +class SehExceptionInTearDownTest : public Test { + protected: + virtual void TearDown() { RaiseException(42, 0, 0, NULL); } +}; + +TEST_F(SehExceptionInTearDownTest, ThrowsExceptionInTearDown) {} + +TEST(SehExceptionTest, ThrowsSehException) { + RaiseException(42, 0, 0, NULL); +} + +#endif // GTEST_HAS_SEH + +#if GTEST_HAS_EXCEPTIONS + +class CxxExceptionInConstructorTest : public Test { + public: + CxxExceptionInConstructorTest() { + // Without this macro VC++ complains about unreachable code at the end of + // the constructor. + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_( + throw std::runtime_error("Standard C++ exception")); + } + + static void TearDownTestSuite() { + printf("%s", + "CxxExceptionInConstructorTest::TearDownTestSuite() " + "called as expected.\n"); + } + + protected: + ~CxxExceptionInConstructorTest() override { + ADD_FAILURE() << "CxxExceptionInConstructorTest destructor " + << "called unexpectedly."; + } + + void SetUp() override { + ADD_FAILURE() << "CxxExceptionInConstructorTest::SetUp() " + << "called unexpectedly."; + } + + void TearDown() override { + ADD_FAILURE() << "CxxExceptionInConstructorTest::TearDown() " + << "called unexpectedly."; + } +}; + +TEST_F(CxxExceptionInConstructorTest, ThrowsExceptionInConstructor) { + ADD_FAILURE() << "CxxExceptionInConstructorTest test body " + << "called unexpectedly."; +} + +class CxxExceptionInSetUpTestSuiteTest : public Test { + public: + CxxExceptionInSetUpTestSuiteTest() { + printf("%s", + "CxxExceptionInSetUpTestSuiteTest constructor " + "called as expected.\n"); + } + + static void SetUpTestSuite() { + throw std::runtime_error("Standard C++ exception"); + } + + static void TearDownTestSuite() { + printf("%s", + "CxxExceptionInSetUpTestSuiteTest::TearDownTestSuite() " + "called as expected.\n"); + } + + protected: + ~CxxExceptionInSetUpTestSuiteTest() override { + printf("%s", + "CxxExceptionInSetUpTestSuiteTest destructor " + "called as expected.\n"); + } + + void SetUp() override { + printf("%s", + "CxxExceptionInSetUpTestSuiteTest::SetUp() " + "called as expected.\n"); + } + + void TearDown() override { + printf("%s", + "CxxExceptionInSetUpTestSuiteTest::TearDown() " + "called as expected.\n"); + } +}; + +TEST_F(CxxExceptionInSetUpTestSuiteTest, ThrowsExceptionInSetUpTestSuite) { + printf("%s", + "CxxExceptionInSetUpTestSuiteTest test body " + "called as expected.\n"); +} + +class CxxExceptionInTearDownTestSuiteTest : public Test { + public: + static void TearDownTestSuite() { + throw std::runtime_error("Standard C++ exception"); + } +}; + +TEST_F(CxxExceptionInTearDownTestSuiteTest, + ThrowsExceptionInTearDownTestSuite) {} + +class CxxExceptionInSetUpTest : public Test { + public: + static void TearDownTestSuite() { + printf("%s", + "CxxExceptionInSetUpTest::TearDownTestSuite() " + "called as expected.\n"); + } + + protected: + ~CxxExceptionInSetUpTest() override { + printf("%s", + "CxxExceptionInSetUpTest destructor " + "called as expected.\n"); + } + + void SetUp() override { throw std::runtime_error("Standard C++ exception"); } + + void TearDown() override { + printf("%s", + "CxxExceptionInSetUpTest::TearDown() " + "called as expected.\n"); + } +}; + +TEST_F(CxxExceptionInSetUpTest, ThrowsExceptionInSetUp) { + ADD_FAILURE() << "CxxExceptionInSetUpTest test body " + << "called unexpectedly."; +} + +class CxxExceptionInTearDownTest : public Test { + public: + static void TearDownTestSuite() { + printf("%s", + "CxxExceptionInTearDownTest::TearDownTestSuite() " + "called as expected.\n"); + } + + protected: + ~CxxExceptionInTearDownTest() override { + printf("%s", + "CxxExceptionInTearDownTest destructor " + "called as expected.\n"); + } + + void TearDown() override { + throw std::runtime_error("Standard C++ exception"); + } +}; + +TEST_F(CxxExceptionInTearDownTest, ThrowsExceptionInTearDown) {} + +class CxxExceptionInTestBodyTest : public Test { + public: + static void TearDownTestSuite() { + printf("%s", + "CxxExceptionInTestBodyTest::TearDownTestSuite() " + "called as expected.\n"); + } + + protected: + ~CxxExceptionInTestBodyTest() override { + printf("%s", + "CxxExceptionInTestBodyTest destructor " + "called as expected.\n"); + } + + void TearDown() override { + printf("%s", + "CxxExceptionInTestBodyTest::TearDown() " + "called as expected.\n"); + } +}; + +TEST_F(CxxExceptionInTestBodyTest, ThrowsStdCxxException) { + throw std::runtime_error("Standard C++ exception"); +} + +TEST(CxxExceptionTest, ThrowsNonStdCxxException) { + throw "C-string"; +} + +// This terminate handler aborts the program using exit() rather than abort(). +// This avoids showing pop-ups on Windows systems and core dumps on Unix-like +// ones. +void TerminateHandler() { + fprintf(stderr, "%s\n", "Unhandled C++ exception terminating the program."); + fflush(nullptr); + exit(3); +} + +#endif // GTEST_HAS_EXCEPTIONS + +int main(int argc, char** argv) { +#if GTEST_HAS_EXCEPTIONS + std::set_terminate(&TerminateHandler); +#endif + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-color-test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-color-test.py new file mode 100755 index 0000000000000000000000000000000000000000..f3b7c9990bcf44a65036c253e7a01845af9c3717 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-color-test.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Verifies that Google Test correctly determines whether to use colors.""" + +import os +import gtest_test_utils + +IS_WINDOWS = os.name == 'nt' + +COLOR_ENV_VAR = 'GTEST_COLOR' +COLOR_FLAG = 'gtest_color' +COMMAND = gtest_test_utils.GetTestExecutablePath('googletest-color-test_') + + +def SetEnvVar(env_var, value): + """Sets the env variable to 'value'; unsets it when 'value' is None.""" + + if value is not None: + os.environ[env_var] = value + elif env_var in os.environ: + del os.environ[env_var] + + +def UsesColor(term, color_env_var, color_flag): + """Runs googletest-color-test_ and returns its exit code.""" + + SetEnvVar('TERM', term) + SetEnvVar(COLOR_ENV_VAR, color_env_var) + + if color_flag is None: + args = [] + else: + args = ['--%s=%s' % (COLOR_FLAG, color_flag)] + p = gtest_test_utils.Subprocess([COMMAND] + args) + return not p.exited or p.exit_code + + +class GTestColorTest(gtest_test_utils.TestCase): + def testNoEnvVarNoFlag(self): + """Tests the case when there's neither GTEST_COLOR nor --gtest_color.""" + + if not IS_WINDOWS: + self.assert_(not UsesColor('dumb', None, None)) + self.assert_(not UsesColor('emacs', None, None)) + self.assert_(not UsesColor('xterm-mono', None, None)) + self.assert_(not UsesColor('unknown', None, None)) + self.assert_(not UsesColor(None, None, None)) + self.assert_(UsesColor('linux', None, None)) + self.assert_(UsesColor('cygwin', None, None)) + self.assert_(UsesColor('xterm', None, None)) + self.assert_(UsesColor('xterm-color', None, None)) + self.assert_(UsesColor('xterm-256color', None, None)) + + def testFlagOnly(self): + """Tests the case when there's --gtest_color but not GTEST_COLOR.""" + + self.assert_(not UsesColor('dumb', None, 'no')) + self.assert_(not UsesColor('xterm-color', None, 'no')) + if not IS_WINDOWS: + self.assert_(not UsesColor('emacs', None, 'auto')) + self.assert_(UsesColor('xterm', None, 'auto')) + self.assert_(UsesColor('dumb', None, 'yes')) + self.assert_(UsesColor('xterm', None, 'yes')) + + def testEnvVarOnly(self): + """Tests the case when there's GTEST_COLOR but not --gtest_color.""" + + self.assert_(not UsesColor('dumb', 'no', None)) + self.assert_(not UsesColor('xterm-color', 'no', None)) + if not IS_WINDOWS: + self.assert_(not UsesColor('dumb', 'auto', None)) + self.assert_(UsesColor('xterm-color', 'auto', None)) + self.assert_(UsesColor('dumb', 'yes', None)) + self.assert_(UsesColor('xterm-color', 'yes', None)) + + def testEnvVarAndFlag(self): + """Tests the case when there are both GTEST_COLOR and --gtest_color.""" + + self.assert_(not UsesColor('xterm-color', 'no', 'no')) + self.assert_(UsesColor('dumb', 'no', 'yes')) + self.assert_(UsesColor('xterm-color', 'no', 'auto')) + + def testAliasesOfYesAndNo(self): + """Tests using aliases in specifying --gtest_color.""" + + self.assert_(UsesColor('dumb', None, 'true')) + self.assert_(UsesColor('dumb', None, 'YES')) + self.assert_(UsesColor('dumb', None, 'T')) + self.assert_(UsesColor('dumb', None, '1')) + + self.assert_(not UsesColor('xterm', None, 'f')) + self.assert_(not UsesColor('xterm', None, 'false')) + self.assert_(not UsesColor('xterm', None, '0')) + self.assert_(not UsesColor('xterm', None, 'unknown')) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-color-test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-color-test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..220a3a00548fdb1e935a3da16df563a50e179a8a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-color-test_.cc @@ -0,0 +1,62 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// A helper program for testing how Google Test determines whether to use +// colors in the output. It prints "YES" and returns 1 if Google Test +// decides to use colors, and prints "NO" and returns 0 otherwise. + +#include + +#include "gtest/gtest.h" +#include "src/gtest-internal-inl.h" + +using testing::internal::ShouldUseColor; + +// The purpose of this is to ensure that the UnitTest singleton is +// created before main() is entered, and thus that ShouldUseColor() +// works the same way as in a real Google-Test-based test. We don't actual +// run the TEST itself. +TEST(GTestColorTest, Dummy) { +} + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + + if (ShouldUseColor(true)) { + // Google Test decides to use colors in the output (assuming it + // goes to a TTY). + printf("YES\n"); + return 1; + } else { + // Google Test decides not to use colors in the output. + printf("NO\n"); + return 0; + } +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-death-test-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-death-test-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..cba906ccd861df493ae848c814010a2249f9767e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-death-test-test.cc @@ -0,0 +1,1516 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Tests for death tests. + +#include "gtest/gtest-death-test.h" + +#include "gtest/gtest.h" +#include "gtest/internal/gtest-filepath.h" + +using testing::internal::AlwaysFalse; +using testing::internal::AlwaysTrue; + +#if GTEST_HAS_DEATH_TEST + +# if GTEST_OS_WINDOWS +# include // For O_BINARY +# include // For chdir(). +# include +# else +# include +# include // For waitpid. +# endif // GTEST_OS_WINDOWS + +# include +# include +# include + +# if GTEST_OS_LINUX +# include +# endif // GTEST_OS_LINUX + +# include "gtest/gtest-spi.h" +# include "src/gtest-internal-inl.h" + +namespace posix = ::testing::internal::posix; + +using testing::ContainsRegex; +using testing::Matcher; +using testing::Message; +using testing::internal::DeathTest; +using testing::internal::DeathTestFactory; +using testing::internal::FilePath; +using testing::internal::GetLastErrnoDescription; +using testing::internal::GetUnitTestImpl; +using testing::internal::InDeathTestChild; +using testing::internal::ParseNaturalNumber; + +namespace testing { +namespace internal { + +// A helper class whose objects replace the death test factory for a +// single UnitTest object during their lifetimes. +class ReplaceDeathTestFactory { + public: + explicit ReplaceDeathTestFactory(DeathTestFactory* new_factory) + : unit_test_impl_(GetUnitTestImpl()) { + old_factory_ = unit_test_impl_->death_test_factory_.release(); + unit_test_impl_->death_test_factory_.reset(new_factory); + } + + ~ReplaceDeathTestFactory() { + unit_test_impl_->death_test_factory_.release(); + unit_test_impl_->death_test_factory_.reset(old_factory_); + } + private: + // Prevents copying ReplaceDeathTestFactory objects. + ReplaceDeathTestFactory(const ReplaceDeathTestFactory&); + void operator=(const ReplaceDeathTestFactory&); + + UnitTestImpl* unit_test_impl_; + DeathTestFactory* old_factory_; +}; + +} // namespace internal +} // namespace testing + +namespace { + +void DieWithMessage(const ::std::string& message) { + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); // Make sure the text is printed before the process exits. + + // We call _exit() instead of exit(), as the former is a direct + // system call and thus safer in the presence of threads. exit() + // will invoke user-defined exit-hooks, which may do dangerous + // things that conflict with death tests. + // + // Some compilers can recognize that _exit() never returns and issue the + // 'unreachable code' warning for code following this function, unless + // fooled by a fake condition. + if (AlwaysTrue()) + _exit(1); +} + +void DieInside(const ::std::string& function) { + DieWithMessage("death inside " + function + "()."); +} + +// Tests that death tests work. + +class TestForDeathTest : public testing::Test { + protected: + TestForDeathTest() : original_dir_(FilePath::GetCurrentDir()) {} + + ~TestForDeathTest() override { posix::ChDir(original_dir_.c_str()); } + + // A static member function that's expected to die. + static void StaticMemberFunction() { DieInside("StaticMemberFunction"); } + + // A method of the test fixture that may die. + void MemberFunction() { + if (should_die_) + DieInside("MemberFunction"); + } + + // True if and only if MemberFunction() should die. + bool should_die_; + const FilePath original_dir_; +}; + +// A class with a member function that may die. +class MayDie { + public: + explicit MayDie(bool should_die) : should_die_(should_die) {} + + // A member function that may die. + void MemberFunction() const { + if (should_die_) + DieInside("MayDie::MemberFunction"); + } + + private: + // True if and only if MemberFunction() should die. + bool should_die_; +}; + +// A global function that's expected to die. +void GlobalFunction() { DieInside("GlobalFunction"); } + +// A non-void function that's expected to die. +int NonVoidFunction() { + DieInside("NonVoidFunction"); + return 1; +} + +// A unary function that may die. +void DieIf(bool should_die) { + if (should_die) + DieInside("DieIf"); +} + +// A binary function that may die. +bool DieIfLessThan(int x, int y) { + if (x < y) { + DieInside("DieIfLessThan"); + } + return true; +} + +// Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture. +void DeathTestSubroutine() { + EXPECT_DEATH(GlobalFunction(), "death.*GlobalFunction"); + ASSERT_DEATH(GlobalFunction(), "death.*GlobalFunction"); +} + +// Death in dbg, not opt. +int DieInDebugElse12(int* sideeffect) { + if (sideeffect) *sideeffect = 12; + +# ifndef NDEBUG + + DieInside("DieInDebugElse12"); + +# endif // NDEBUG + + return 12; +} + +# if GTEST_OS_WINDOWS + +// Death in dbg due to Windows CRT assertion failure, not opt. +int DieInCRTDebugElse12(int* sideeffect) { + if (sideeffect) *sideeffect = 12; + + // Create an invalid fd by closing a valid one + int fdpipe[2]; + EXPECT_EQ(_pipe(fdpipe, 256, O_BINARY), 0); + EXPECT_EQ(_close(fdpipe[0]), 0); + EXPECT_EQ(_close(fdpipe[1]), 0); + + // _dup() should crash in debug mode + EXPECT_EQ(_dup(fdpipe[0]), -1); + + return 12; +} + +#endif // GTEST_OS_WINDOWS + +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA + +// Tests the ExitedWithCode predicate. +TEST(ExitStatusPredicateTest, ExitedWithCode) { + // On Windows, the process's exit code is the same as its exit status, + // so the predicate just compares the its input with its parameter. + EXPECT_TRUE(testing::ExitedWithCode(0)(0)); + EXPECT_TRUE(testing::ExitedWithCode(1)(1)); + EXPECT_TRUE(testing::ExitedWithCode(42)(42)); + EXPECT_FALSE(testing::ExitedWithCode(0)(1)); + EXPECT_FALSE(testing::ExitedWithCode(1)(0)); +} + +# else + +// Returns the exit status of a process that calls _exit(2) with a +// given exit code. This is a helper function for the +// ExitStatusPredicateTest test suite. +static int NormalExitStatus(int exit_code) { + pid_t child_pid = fork(); + if (child_pid == 0) { + _exit(exit_code); + } + int status; + waitpid(child_pid, &status, 0); + return status; +} + +// Returns the exit status of a process that raises a given signal. +// If the signal does not cause the process to die, then it returns +// instead the exit status of a process that exits normally with exit +// code 1. This is a helper function for the ExitStatusPredicateTest +// test suite. +static int KilledExitStatus(int signum) { + pid_t child_pid = fork(); + if (child_pid == 0) { + raise(signum); + _exit(1); + } + int status; + waitpid(child_pid, &status, 0); + return status; +} + +// Tests the ExitedWithCode predicate. +TEST(ExitStatusPredicateTest, ExitedWithCode) { + const int status0 = NormalExitStatus(0); + const int status1 = NormalExitStatus(1); + const int status42 = NormalExitStatus(42); + const testing::ExitedWithCode pred0(0); + const testing::ExitedWithCode pred1(1); + const testing::ExitedWithCode pred42(42); + EXPECT_PRED1(pred0, status0); + EXPECT_PRED1(pred1, status1); + EXPECT_PRED1(pred42, status42); + EXPECT_FALSE(pred0(status1)); + EXPECT_FALSE(pred42(status0)); + EXPECT_FALSE(pred1(status42)); +} + +// Tests the KilledBySignal predicate. +TEST(ExitStatusPredicateTest, KilledBySignal) { + const int status_segv = KilledExitStatus(SIGSEGV); + const int status_kill = KilledExitStatus(SIGKILL); + const testing::KilledBySignal pred_segv(SIGSEGV); + const testing::KilledBySignal pred_kill(SIGKILL); + EXPECT_PRED1(pred_segv, status_segv); + EXPECT_PRED1(pred_kill, status_kill); + EXPECT_FALSE(pred_segv(status_kill)); + EXPECT_FALSE(pred_kill(status_segv)); +} + +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA + +// Tests that the death test macros expand to code which may or may not +// be followed by operator<<, and that in either case the complete text +// comprises only a single C++ statement. +TEST_F(TestForDeathTest, SingleStatement) { + if (AlwaysFalse()) + // This would fail if executed; this is a compilation test only + ASSERT_DEATH(return, ""); + + if (AlwaysTrue()) + EXPECT_DEATH(_exit(1), ""); + else + // This empty "else" branch is meant to ensure that EXPECT_DEATH + // doesn't expand into an "if" statement without an "else" + ; + + if (AlwaysFalse()) + ASSERT_DEATH(return, "") << "did not die"; + + if (AlwaysFalse()) + ; + else + EXPECT_DEATH(_exit(1), "") << 1 << 2 << 3; +} + +# if GTEST_USES_PCRE + +void DieWithEmbeddedNul() { + fprintf(stderr, "Hello%cmy null world.\n", '\0'); + fflush(stderr); + _exit(1); +} + +// Tests that EXPECT_DEATH and ASSERT_DEATH work when the error +// message has a NUL character in it. +TEST_F(TestForDeathTest, EmbeddedNulInMessage) { + EXPECT_DEATH(DieWithEmbeddedNul(), "my null world"); + ASSERT_DEATH(DieWithEmbeddedNul(), "my null world"); +} + +# endif // GTEST_USES_PCRE + +// Tests that death test macros expand to code which interacts well with switch +// statements. +TEST_F(TestForDeathTest, SwitchStatement) { + // Microsoft compiler usually complains about switch statements without + // case labels. We suppress that warning for this test. + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4065) + + switch (0) + default: + ASSERT_DEATH(_exit(1), "") << "exit in default switch handler"; + + switch (0) + case 0: + EXPECT_DEATH(_exit(1), "") << "exit in switch case"; + + GTEST_DISABLE_MSC_WARNINGS_POP_() +} + +// Tests that a static member function can be used in a "fast" style +// death test. +TEST_F(TestForDeathTest, StaticMemberFunctionFastStyle) { + testing::GTEST_FLAG(death_test_style) = "fast"; + ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember"); +} + +// Tests that a method of the test fixture can be used in a "fast" +// style death test. +TEST_F(TestForDeathTest, MemberFunctionFastStyle) { + testing::GTEST_FLAG(death_test_style) = "fast"; + should_die_ = true; + EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction"); +} + +void ChangeToRootDir() { posix::ChDir(GTEST_PATH_SEP_); } + +// Tests that death tests work even if the current directory has been +// changed. +TEST_F(TestForDeathTest, FastDeathTestInChangedDir) { + testing::GTEST_FLAG(death_test_style) = "fast"; + + ChangeToRootDir(); + EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); + + ChangeToRootDir(); + ASSERT_DEATH(_exit(1), ""); +} + +# if GTEST_OS_LINUX +void SigprofAction(int, siginfo_t*, void*) { /* no op */ } + +// Sets SIGPROF action and ITIMER_PROF timer (interval: 1ms). +void SetSigprofActionAndTimer() { + struct itimerval timer; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = 1; + timer.it_value = timer.it_interval; + ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, nullptr)); + struct sigaction signal_action; + memset(&signal_action, 0, sizeof(signal_action)); + sigemptyset(&signal_action.sa_mask); + signal_action.sa_sigaction = SigprofAction; + signal_action.sa_flags = SA_RESTART | SA_SIGINFO; + ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, nullptr)); +} + +// Disables ITIMER_PROF timer and ignores SIGPROF signal. +void DisableSigprofActionAndTimer(struct sigaction* old_signal_action) { + struct itimerval timer; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = 0; + timer.it_value = timer.it_interval; + ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, nullptr)); + struct sigaction signal_action; + memset(&signal_action, 0, sizeof(signal_action)); + sigemptyset(&signal_action.sa_mask); + signal_action.sa_handler = SIG_IGN; + ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, old_signal_action)); +} + +// Tests that death tests work when SIGPROF handler and timer are set. +TEST_F(TestForDeathTest, FastSigprofActionSet) { + testing::GTEST_FLAG(death_test_style) = "fast"; + SetSigprofActionAndTimer(); + EXPECT_DEATH(_exit(1), ""); + struct sigaction old_signal_action; + DisableSigprofActionAndTimer(&old_signal_action); + EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction); +} + +TEST_F(TestForDeathTest, ThreadSafeSigprofActionSet) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + SetSigprofActionAndTimer(); + EXPECT_DEATH(_exit(1), ""); + struct sigaction old_signal_action; + DisableSigprofActionAndTimer(&old_signal_action); + EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction); +} +# endif // GTEST_OS_LINUX + +// Repeats a representative sample of death tests in the "threadsafe" style: + +TEST_F(TestForDeathTest, StaticMemberFunctionThreadsafeStyle) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember"); +} + +TEST_F(TestForDeathTest, MemberFunctionThreadsafeStyle) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + should_die_ = true; + EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction"); +} + +TEST_F(TestForDeathTest, ThreadsafeDeathTestInLoop) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + + for (int i = 0; i < 3; ++i) + EXPECT_EXIT(_exit(i), testing::ExitedWithCode(i), "") << ": i = " << i; +} + +TEST_F(TestForDeathTest, ThreadsafeDeathTestInChangedDir) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + + ChangeToRootDir(); + EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); + + ChangeToRootDir(); + ASSERT_DEATH(_exit(1), ""); +} + +TEST_F(TestForDeathTest, MixedStyles) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + EXPECT_DEATH(_exit(1), ""); + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_DEATH(_exit(1), ""); +} + +# if GTEST_HAS_CLONE && GTEST_HAS_PTHREAD + +bool pthread_flag; + +void SetPthreadFlag() { + pthread_flag = true; +} + +TEST_F(TestForDeathTest, DoesNotExecuteAtforkHooks) { + if (!testing::GTEST_FLAG(death_test_use_fork)) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + pthread_flag = false; + ASSERT_EQ(0, pthread_atfork(&SetPthreadFlag, nullptr, nullptr)); + ASSERT_DEATH(_exit(1), ""); + ASSERT_FALSE(pthread_flag); + } +} + +# endif // GTEST_HAS_CLONE && GTEST_HAS_PTHREAD + +// Tests that a method of another class can be used in a death test. +TEST_F(TestForDeathTest, MethodOfAnotherClass) { + const MayDie x(true); + ASSERT_DEATH(x.MemberFunction(), "MayDie\\:\\:MemberFunction"); +} + +// Tests that a global function can be used in a death test. +TEST_F(TestForDeathTest, GlobalFunction) { + EXPECT_DEATH(GlobalFunction(), "GlobalFunction"); +} + +// Tests that any value convertible to an RE works as a second +// argument to EXPECT_DEATH. +TEST_F(TestForDeathTest, AcceptsAnythingConvertibleToRE) { + static const char regex_c_str[] = "GlobalFunction"; + EXPECT_DEATH(GlobalFunction(), regex_c_str); + + const testing::internal::RE regex(regex_c_str); + EXPECT_DEATH(GlobalFunction(), regex); + +# if !GTEST_USES_PCRE + + const ::std::string regex_std_str(regex_c_str); + EXPECT_DEATH(GlobalFunction(), regex_std_str); + + // This one is tricky; a temporary pointer into another temporary. Reference + // lifetime extension of the pointer is not sufficient. + EXPECT_DEATH(GlobalFunction(), ::std::string(regex_c_str).c_str()); + +# endif // !GTEST_USES_PCRE +} + +// Tests that a non-void function can be used in a death test. +TEST_F(TestForDeathTest, NonVoidFunction) { + ASSERT_DEATH(NonVoidFunction(), "NonVoidFunction"); +} + +// Tests that functions that take parameter(s) can be used in a death test. +TEST_F(TestForDeathTest, FunctionWithParameter) { + EXPECT_DEATH(DieIf(true), "DieIf\\(\\)"); + EXPECT_DEATH(DieIfLessThan(2, 3), "DieIfLessThan"); +} + +// Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture. +TEST_F(TestForDeathTest, OutsideFixture) { + DeathTestSubroutine(); +} + +// Tests that death tests can be done inside a loop. +TEST_F(TestForDeathTest, InsideLoop) { + for (int i = 0; i < 5; i++) { + EXPECT_DEATH(DieIfLessThan(-1, i), "DieIfLessThan") << "where i == " << i; + } +} + +// Tests that a compound statement can be used in a death test. +TEST_F(TestForDeathTest, CompoundStatement) { + EXPECT_DEATH({ // NOLINT + const int x = 2; + const int y = x + 1; + DieIfLessThan(x, y); + }, + "DieIfLessThan"); +} + +// Tests that code that doesn't die causes a death test to fail. +TEST_F(TestForDeathTest, DoesNotDie) { + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(DieIf(false), "DieIf"), + "failed to die"); +} + +// Tests that a death test fails when the error message isn't expected. +TEST_F(TestForDeathTest, ErrorMessageMismatch) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_DEATH(DieIf(true), "DieIfLessThan") << "End of death test message."; + }, "died but not with expected error"); +} + +// On exit, *aborted will be true if and only if the EXPECT_DEATH() +// statement aborted the function. +void ExpectDeathTestHelper(bool* aborted) { + *aborted = true; + EXPECT_DEATH(DieIf(false), "DieIf"); // This assertion should fail. + *aborted = false; +} + +// Tests that EXPECT_DEATH doesn't abort the test on failure. +TEST_F(TestForDeathTest, EXPECT_DEATH) { + bool aborted = true; + EXPECT_NONFATAL_FAILURE(ExpectDeathTestHelper(&aborted), + "failed to die"); + EXPECT_FALSE(aborted); +} + +// Tests that ASSERT_DEATH does abort the test on failure. +TEST_F(TestForDeathTest, ASSERT_DEATH) { + static bool aborted; + EXPECT_FATAL_FAILURE({ // NOLINT + aborted = true; + ASSERT_DEATH(DieIf(false), "DieIf"); // This assertion should fail. + aborted = false; + }, "failed to die"); + EXPECT_TRUE(aborted); +} + +// Tests that EXPECT_DEATH evaluates the arguments exactly once. +TEST_F(TestForDeathTest, SingleEvaluation) { + int x = 3; + EXPECT_DEATH(DieIf((++x) == 4), "DieIf"); + + const char* regex = "DieIf"; + const char* regex_save = regex; + EXPECT_DEATH(DieIfLessThan(3, 4), regex++); + EXPECT_EQ(regex_save + 1, regex); +} + +// Tests that run-away death tests are reported as failures. +TEST_F(TestForDeathTest, RunawayIsFailure) { + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(static_cast(0), "Foo"), + "failed to die."); +} + +// Tests that death tests report executing 'return' in the statement as +// failure. +TEST_F(TestForDeathTest, ReturnIsFailure) { + EXPECT_FATAL_FAILURE(ASSERT_DEATH(return, "Bar"), + "illegal return in test statement."); +} + +// Tests that EXPECT_DEBUG_DEATH works as expected, that is, you can stream a +// message to it, and in debug mode it: +// 1. Asserts on death. +// 2. Has no side effect. +// +// And in opt mode, it: +// 1. Has side effects but does not assert. +TEST_F(TestForDeathTest, TestExpectDebugDeath) { + int sideeffect = 0; + + // Put the regex in a local variable to make sure we don't get an "unused" + // warning in opt mode. + const char* regex = "death.*DieInDebugElse12"; + + EXPECT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), regex) + << "Must accept a streamed message"; + +# ifdef NDEBUG + + // Checks that the assignment occurs in opt mode (sideeffect). + EXPECT_EQ(12, sideeffect); + +# else + + // Checks that the assignment does not occur in dbg mode (no sideeffect). + EXPECT_EQ(0, sideeffect); + +# endif +} + +# if GTEST_OS_WINDOWS + +// Tests that EXPECT_DEBUG_DEATH works as expected when in debug mode +// the Windows CRT crashes the process with an assertion failure. +// 1. Asserts on death. +// 2. Has no side effect (doesn't pop up a window or wait for user input). +// +// And in opt mode, it: +// 1. Has side effects but does not assert. +TEST_F(TestForDeathTest, CRTDebugDeath) { + int sideeffect = 0; + + // Put the regex in a local variable to make sure we don't get an "unused" + // warning in opt mode. + const char* regex = "dup.* : Assertion failed"; + + EXPECT_DEBUG_DEATH(DieInCRTDebugElse12(&sideeffect), regex) + << "Must accept a streamed message"; + +# ifdef NDEBUG + + // Checks that the assignment occurs in opt mode (sideeffect). + EXPECT_EQ(12, sideeffect); + +# else + + // Checks that the assignment does not occur in dbg mode (no sideeffect). + EXPECT_EQ(0, sideeffect); + +# endif +} + +# endif // GTEST_OS_WINDOWS + +// Tests that ASSERT_DEBUG_DEATH works as expected, that is, you can stream a +// message to it, and in debug mode it: +// 1. Asserts on death. +// 2. Has no side effect. +// +// And in opt mode, it: +// 1. Has side effects but does not assert. +TEST_F(TestForDeathTest, TestAssertDebugDeath) { + int sideeffect = 0; + + ASSERT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), "death.*DieInDebugElse12") + << "Must accept a streamed message"; + +# ifdef NDEBUG + + // Checks that the assignment occurs in opt mode (sideeffect). + EXPECT_EQ(12, sideeffect); + +# else + + // Checks that the assignment does not occur in dbg mode (no sideeffect). + EXPECT_EQ(0, sideeffect); + +# endif +} + +# ifndef NDEBUG + +void ExpectDebugDeathHelper(bool* aborted) { + *aborted = true; + EXPECT_DEBUG_DEATH(return, "") << "This is expected to fail."; + *aborted = false; +} + +# if GTEST_OS_WINDOWS +TEST(PopUpDeathTest, DoesNotShowPopUpOnAbort) { + printf("This test should be considered failing if it shows " + "any pop-up dialogs.\n"); + fflush(stdout); + + EXPECT_DEATH({ + testing::GTEST_FLAG(catch_exceptions) = false; + abort(); + }, ""); +} +# endif // GTEST_OS_WINDOWS + +// Tests that EXPECT_DEBUG_DEATH in debug mode does not abort +// the function. +TEST_F(TestForDeathTest, ExpectDebugDeathDoesNotAbort) { + bool aborted = true; + EXPECT_NONFATAL_FAILURE(ExpectDebugDeathHelper(&aborted), ""); + EXPECT_FALSE(aborted); +} + +void AssertDebugDeathHelper(bool* aborted) { + *aborted = true; + GTEST_LOG_(INFO) << "Before ASSERT_DEBUG_DEATH"; + ASSERT_DEBUG_DEATH(GTEST_LOG_(INFO) << "In ASSERT_DEBUG_DEATH"; return, "") + << "This is expected to fail."; + GTEST_LOG_(INFO) << "After ASSERT_DEBUG_DEATH"; + *aborted = false; +} + +// Tests that ASSERT_DEBUG_DEATH in debug mode aborts the function on +// failure. +TEST_F(TestForDeathTest, AssertDebugDeathAborts) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts2) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts3) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts4) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts5) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts6) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts7) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts8) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts9) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts10) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +# endif // _NDEBUG + +// Tests the *_EXIT family of macros, using a variety of predicates. +static void TestExitMacros() { + EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), ""); + ASSERT_EXIT(_exit(42), testing::ExitedWithCode(42), ""); + +# if GTEST_OS_WINDOWS + + // Of all signals effects on the process exit code, only those of SIGABRT + // are documented on Windows. + // See https://msdn.microsoft.com/en-us/query-bi/m/dwwzkt4c. + EXPECT_EXIT(raise(SIGABRT), testing::ExitedWithCode(3), "") << "b_ar"; + +# elif !GTEST_OS_FUCHSIA + + // Fuchsia has no unix signals. + EXPECT_EXIT(raise(SIGKILL), testing::KilledBySignal(SIGKILL), "") << "foo"; + ASSERT_EXIT(raise(SIGUSR2), testing::KilledBySignal(SIGUSR2), "") << "bar"; + + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_EXIT(_exit(0), testing::KilledBySignal(SIGSEGV), "") + << "This failure is expected, too."; + }, "This failure is expected, too."); + +# endif // GTEST_OS_WINDOWS + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_EXIT(raise(SIGSEGV), testing::ExitedWithCode(0), "") + << "This failure is expected."; + }, "This failure is expected."); +} + +TEST_F(TestForDeathTest, ExitMacros) { + TestExitMacros(); +} + +TEST_F(TestForDeathTest, ExitMacrosUsingFork) { + testing::GTEST_FLAG(death_test_use_fork) = true; + TestExitMacros(); +} + +TEST_F(TestForDeathTest, InvalidStyle) { + testing::GTEST_FLAG(death_test_style) = "rococo"; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_DEATH(_exit(0), "") << "This failure is expected."; + }, "This failure is expected."); +} + +TEST_F(TestForDeathTest, DeathTestFailedOutput) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_NONFATAL_FAILURE( + EXPECT_DEATH(DieWithMessage("death\n"), + "expected message"), + "Actual msg:\n" + "[ DEATH ] death\n"); +} + +TEST_F(TestForDeathTest, DeathTestUnexpectedReturnOutput) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_NONFATAL_FAILURE( + EXPECT_DEATH({ + fprintf(stderr, "returning\n"); + fflush(stderr); + return; + }, ""), + " Result: illegal return in test statement.\n" + " Error msg:\n" + "[ DEATH ] returning\n"); +} + +TEST_F(TestForDeathTest, DeathTestBadExitCodeOutput) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_NONFATAL_FAILURE( + EXPECT_EXIT(DieWithMessage("exiting with rc 1\n"), + testing::ExitedWithCode(3), + "expected message"), + " Result: died but not with expected exit code:\n" + " Exited with exit status 1\n" + "Actual msg:\n" + "[ DEATH ] exiting with rc 1\n"); +} + +TEST_F(TestForDeathTest, DeathTestMultiLineMatchFail) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_NONFATAL_FAILURE( + EXPECT_DEATH(DieWithMessage("line 1\nline 2\nline 3\n"), + "line 1\nxyz\nline 3\n"), + "Actual msg:\n" + "[ DEATH ] line 1\n" + "[ DEATH ] line 2\n" + "[ DEATH ] line 3\n"); +} + +TEST_F(TestForDeathTest, DeathTestMultiLineMatchPass) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_DEATH(DieWithMessage("line 1\nline 2\nline 3\n"), + "line 1\nline 2\nline 3\n"); +} + +// A DeathTestFactory that returns MockDeathTests. +class MockDeathTestFactory : public DeathTestFactory { + public: + MockDeathTestFactory(); + bool Create(const char* statement, + testing::Matcher matcher, const char* file, + int line, DeathTest** test) override; + + // Sets the parameters for subsequent calls to Create. + void SetParameters(bool create, DeathTest::TestRole role, + int status, bool passed); + + // Accessors. + int AssumeRoleCalls() const { return assume_role_calls_; } + int WaitCalls() const { return wait_calls_; } + size_t PassedCalls() const { return passed_args_.size(); } + bool PassedArgument(int n) const { + return passed_args_[static_cast(n)]; + } + size_t AbortCalls() const { return abort_args_.size(); } + DeathTest::AbortReason AbortArgument(int n) const { + return abort_args_[static_cast(n)]; + } + bool TestDeleted() const { return test_deleted_; } + + private: + friend class MockDeathTest; + // If true, Create will return a MockDeathTest; otherwise it returns + // NULL. + bool create_; + // The value a MockDeathTest will return from its AssumeRole method. + DeathTest::TestRole role_; + // The value a MockDeathTest will return from its Wait method. + int status_; + // The value a MockDeathTest will return from its Passed method. + bool passed_; + + // Number of times AssumeRole was called. + int assume_role_calls_; + // Number of times Wait was called. + int wait_calls_; + // The arguments to the calls to Passed since the last call to + // SetParameters. + std::vector passed_args_; + // The arguments to the calls to Abort since the last call to + // SetParameters. + std::vector abort_args_; + // True if the last MockDeathTest returned by Create has been + // deleted. + bool test_deleted_; +}; + + +// A DeathTest implementation useful in testing. It returns values set +// at its creation from its various inherited DeathTest methods, and +// reports calls to those methods to its parent MockDeathTestFactory +// object. +class MockDeathTest : public DeathTest { + public: + MockDeathTest(MockDeathTestFactory *parent, + TestRole role, int status, bool passed) : + parent_(parent), role_(role), status_(status), passed_(passed) { + } + ~MockDeathTest() override { parent_->test_deleted_ = true; } + TestRole AssumeRole() override { + ++parent_->assume_role_calls_; + return role_; + } + int Wait() override { + ++parent_->wait_calls_; + return status_; + } + bool Passed(bool exit_status_ok) override { + parent_->passed_args_.push_back(exit_status_ok); + return passed_; + } + void Abort(AbortReason reason) override { + parent_->abort_args_.push_back(reason); + } + + private: + MockDeathTestFactory* const parent_; + const TestRole role_; + const int status_; + const bool passed_; +}; + + +// MockDeathTestFactory constructor. +MockDeathTestFactory::MockDeathTestFactory() + : create_(true), + role_(DeathTest::OVERSEE_TEST), + status_(0), + passed_(true), + assume_role_calls_(0), + wait_calls_(0), + passed_args_(), + abort_args_() { +} + + +// Sets the parameters for subsequent calls to Create. +void MockDeathTestFactory::SetParameters(bool create, + DeathTest::TestRole role, + int status, bool passed) { + create_ = create; + role_ = role; + status_ = status; + passed_ = passed; + + assume_role_calls_ = 0; + wait_calls_ = 0; + passed_args_.clear(); + abort_args_.clear(); +} + + +// Sets test to NULL (if create_ is false) or to the address of a new +// MockDeathTest object with parameters taken from the last call +// to SetParameters (if create_ is true). Always returns true. +bool MockDeathTestFactory::Create( + const char* /*statement*/, testing::Matcher /*matcher*/, + const char* /*file*/, int /*line*/, DeathTest** test) { + test_deleted_ = false; + if (create_) { + *test = new MockDeathTest(this, role_, status_, passed_); + } else { + *test = nullptr; + } + return true; +} + +// A test fixture for testing the logic of the GTEST_DEATH_TEST_ macro. +// It installs a MockDeathTestFactory that is used for the duration +// of the test case. +class MacroLogicDeathTest : public testing::Test { + protected: + static testing::internal::ReplaceDeathTestFactory* replacer_; + static MockDeathTestFactory* factory_; + + static void SetUpTestSuite() { + factory_ = new MockDeathTestFactory; + replacer_ = new testing::internal::ReplaceDeathTestFactory(factory_); + } + + static void TearDownTestSuite() { + delete replacer_; + replacer_ = nullptr; + delete factory_; + factory_ = nullptr; + } + + // Runs a death test that breaks the rules by returning. Such a death + // test cannot be run directly from a test routine that uses a + // MockDeathTest, or the remainder of the routine will not be executed. + static void RunReturningDeathTest(bool* flag) { + ASSERT_DEATH({ // NOLINT + *flag = true; + return; + }, ""); + } +}; + +testing::internal::ReplaceDeathTestFactory* MacroLogicDeathTest::replacer_ = + nullptr; +MockDeathTestFactory* MacroLogicDeathTest::factory_ = nullptr; + +// Test that nothing happens when the factory doesn't return a DeathTest: +TEST_F(MacroLogicDeathTest, NothingHappens) { + bool flag = false; + factory_->SetParameters(false, DeathTest::OVERSEE_TEST, 0, true); + EXPECT_DEATH(flag = true, ""); + EXPECT_FALSE(flag); + EXPECT_EQ(0, factory_->AssumeRoleCalls()); + EXPECT_EQ(0, factory_->WaitCalls()); + EXPECT_EQ(0U, factory_->PassedCalls()); + EXPECT_EQ(0U, factory_->AbortCalls()); + EXPECT_FALSE(factory_->TestDeleted()); +} + +// Test that the parent process doesn't run the death test code, +// and that the Passed method returns false when the (simulated) +// child process exits with status 0: +TEST_F(MacroLogicDeathTest, ChildExitsSuccessfully) { + bool flag = false; + factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 0, true); + EXPECT_DEATH(flag = true, ""); + EXPECT_FALSE(flag); + EXPECT_EQ(1, factory_->AssumeRoleCalls()); + EXPECT_EQ(1, factory_->WaitCalls()); + ASSERT_EQ(1U, factory_->PassedCalls()); + EXPECT_FALSE(factory_->PassedArgument(0)); + EXPECT_EQ(0U, factory_->AbortCalls()); + EXPECT_TRUE(factory_->TestDeleted()); +} + +// Tests that the Passed method was given the argument "true" when +// the (simulated) child process exits with status 1: +TEST_F(MacroLogicDeathTest, ChildExitsUnsuccessfully) { + bool flag = false; + factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 1, true); + EXPECT_DEATH(flag = true, ""); + EXPECT_FALSE(flag); + EXPECT_EQ(1, factory_->AssumeRoleCalls()); + EXPECT_EQ(1, factory_->WaitCalls()); + ASSERT_EQ(1U, factory_->PassedCalls()); + EXPECT_TRUE(factory_->PassedArgument(0)); + EXPECT_EQ(0U, factory_->AbortCalls()); + EXPECT_TRUE(factory_->TestDeleted()); +} + +// Tests that the (simulated) child process executes the death test +// code, and is aborted with the correct AbortReason if it +// executes a return statement. +TEST_F(MacroLogicDeathTest, ChildPerformsReturn) { + bool flag = false; + factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true); + RunReturningDeathTest(&flag); + EXPECT_TRUE(flag); + EXPECT_EQ(1, factory_->AssumeRoleCalls()); + EXPECT_EQ(0, factory_->WaitCalls()); + EXPECT_EQ(0U, factory_->PassedCalls()); + EXPECT_EQ(1U, factory_->AbortCalls()); + EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT, + factory_->AbortArgument(0)); + EXPECT_TRUE(factory_->TestDeleted()); +} + +// Tests that the (simulated) child process is aborted with the +// correct AbortReason if it does not die. +TEST_F(MacroLogicDeathTest, ChildDoesNotDie) { + bool flag = false; + factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true); + EXPECT_DEATH(flag = true, ""); + EXPECT_TRUE(flag); + EXPECT_EQ(1, factory_->AssumeRoleCalls()); + EXPECT_EQ(0, factory_->WaitCalls()); + EXPECT_EQ(0U, factory_->PassedCalls()); + // This time there are two calls to Abort: one since the test didn't + // die, and another from the ReturnSentinel when it's destroyed. The + // sentinel normally isn't destroyed if a test doesn't die, since + // _exit(2) is called in that case by ForkingDeathTest, but not by + // our MockDeathTest. + ASSERT_EQ(2U, factory_->AbortCalls()); + EXPECT_EQ(DeathTest::TEST_DID_NOT_DIE, + factory_->AbortArgument(0)); + EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT, + factory_->AbortArgument(1)); + EXPECT_TRUE(factory_->TestDeleted()); +} + +// Tests that a successful death test does not register a successful +// test part. +TEST(SuccessRegistrationDeathTest, NoSuccessPart) { + EXPECT_DEATH(_exit(1), ""); + EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +TEST(StreamingAssertionsDeathTest, DeathTest) { + EXPECT_DEATH(_exit(1), "") << "unexpected failure"; + ASSERT_DEATH(_exit(1), "") << "unexpected failure"; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_DEATH(_exit(0), "") << "expected failure"; + }, "expected failure"); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_DEATH(_exit(0), "") << "expected failure"; + }, "expected failure"); +} + +// Tests that GetLastErrnoDescription returns an empty string when the +// last error is 0 and non-empty string when it is non-zero. +TEST(GetLastErrnoDescription, GetLastErrnoDescriptionWorks) { + errno = ENOENT; + EXPECT_STRNE("", GetLastErrnoDescription().c_str()); + errno = 0; + EXPECT_STREQ("", GetLastErrnoDescription().c_str()); +} + +# if GTEST_OS_WINDOWS +TEST(AutoHandleTest, AutoHandleWorks) { + HANDLE handle = ::CreateEvent(NULL, FALSE, FALSE, NULL); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + + // Tests that the AutoHandle is correctly initialized with a handle. + testing::internal::AutoHandle auto_handle(handle); + EXPECT_EQ(handle, auto_handle.Get()); + + // Tests that Reset assigns INVALID_HANDLE_VALUE. + // Note that this cannot verify whether the original handle is closed. + auto_handle.Reset(); + EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle.Get()); + + // Tests that Reset assigns the new handle. + // Note that this cannot verify whether the original handle is closed. + handle = ::CreateEvent(NULL, FALSE, FALSE, NULL); + ASSERT_NE(INVALID_HANDLE_VALUE, handle); + auto_handle.Reset(handle); + EXPECT_EQ(handle, auto_handle.Get()); + + // Tests that AutoHandle contains INVALID_HANDLE_VALUE by default. + testing::internal::AutoHandle auto_handle2; + EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle2.Get()); +} +# endif // GTEST_OS_WINDOWS + +# if GTEST_OS_WINDOWS +typedef unsigned __int64 BiggestParsable; +typedef signed __int64 BiggestSignedParsable; +# else +typedef unsigned long long BiggestParsable; +typedef signed long long BiggestSignedParsable; +# endif // GTEST_OS_WINDOWS + +// We cannot use std::numeric_limits::max() as it clashes with the +// max() macro defined by . +const BiggestParsable kBiggestParsableMax = ULLONG_MAX; +const BiggestSignedParsable kBiggestSignedParsableMax = LLONG_MAX; + +TEST(ParseNaturalNumberTest, RejectsInvalidFormat) { + BiggestParsable result = 0; + + // Rejects non-numbers. + EXPECT_FALSE(ParseNaturalNumber("non-number string", &result)); + + // Rejects numbers with whitespace prefix. + EXPECT_FALSE(ParseNaturalNumber(" 123", &result)); + + // Rejects negative numbers. + EXPECT_FALSE(ParseNaturalNumber("-123", &result)); + + // Rejects numbers starting with a plus sign. + EXPECT_FALSE(ParseNaturalNumber("+123", &result)); + errno = 0; +} + +TEST(ParseNaturalNumberTest, RejectsOverflownNumbers) { + BiggestParsable result = 0; + + EXPECT_FALSE(ParseNaturalNumber("99999999999999999999999", &result)); + + signed char char_result = 0; + EXPECT_FALSE(ParseNaturalNumber("200", &char_result)); + errno = 0; +} + +TEST(ParseNaturalNumberTest, AcceptsValidNumbers) { + BiggestParsable result = 0; + + result = 0; + ASSERT_TRUE(ParseNaturalNumber("123", &result)); + EXPECT_EQ(123U, result); + + // Check 0 as an edge case. + result = 1; + ASSERT_TRUE(ParseNaturalNumber("0", &result)); + EXPECT_EQ(0U, result); + + result = 1; + ASSERT_TRUE(ParseNaturalNumber("00000", &result)); + EXPECT_EQ(0U, result); +} + +TEST(ParseNaturalNumberTest, AcceptsTypeLimits) { + Message msg; + msg << kBiggestParsableMax; + + BiggestParsable result = 0; + EXPECT_TRUE(ParseNaturalNumber(msg.GetString(), &result)); + EXPECT_EQ(kBiggestParsableMax, result); + + Message msg2; + msg2 << kBiggestSignedParsableMax; + + BiggestSignedParsable signed_result = 0; + EXPECT_TRUE(ParseNaturalNumber(msg2.GetString(), &signed_result)); + EXPECT_EQ(kBiggestSignedParsableMax, signed_result); + + Message msg3; + msg3 << INT_MAX; + + int int_result = 0; + EXPECT_TRUE(ParseNaturalNumber(msg3.GetString(), &int_result)); + EXPECT_EQ(INT_MAX, int_result); + + Message msg4; + msg4 << UINT_MAX; + + unsigned int uint_result = 0; + EXPECT_TRUE(ParseNaturalNumber(msg4.GetString(), &uint_result)); + EXPECT_EQ(UINT_MAX, uint_result); +} + +TEST(ParseNaturalNumberTest, WorksForShorterIntegers) { + short short_result = 0; + ASSERT_TRUE(ParseNaturalNumber("123", &short_result)); + EXPECT_EQ(123, short_result); + + signed char char_result = 0; + ASSERT_TRUE(ParseNaturalNumber("123", &char_result)); + EXPECT_EQ(123, char_result); +} + +# if GTEST_OS_WINDOWS +TEST(EnvironmentTest, HandleFitsIntoSizeT) { + ASSERT_TRUE(sizeof(HANDLE) <= sizeof(size_t)); +} +# endif // GTEST_OS_WINDOWS + +// Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED trigger +// failures when death tests are available on the system. +TEST(ConditionalDeathMacrosDeathTest, ExpectsDeathWhenDeathTestsAvailable) { + EXPECT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestExpectMacro"), + "death inside CondDeathTestExpectMacro"); + ASSERT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestAssertMacro"), + "death inside CondDeathTestAssertMacro"); + + // Empty statement will not crash, which must trigger a failure. + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH_IF_SUPPORTED(;, ""), ""); + EXPECT_FATAL_FAILURE(ASSERT_DEATH_IF_SUPPORTED(;, ""), ""); +} + +TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInFastStyle) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_FALSE(InDeathTestChild()); + EXPECT_DEATH({ + fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside"); + fflush(stderr); + _exit(1); + }, "Inside"); +} + +TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInThreadSafeStyle) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + EXPECT_FALSE(InDeathTestChild()); + EXPECT_DEATH({ + fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside"); + fflush(stderr); + _exit(1); + }, "Inside"); +} + +void DieWithMessage(const char* message) { + fputs(message, stderr); + fflush(stderr); // Make sure the text is printed before the process exits. + _exit(1); +} + +TEST(MatcherDeathTest, DoesNotBreakBareRegexMatching) { + // googletest tests this, of course; here we ensure that including googlemock + // has not broken it. + EXPECT_DEATH(DieWithMessage("O, I die, Horatio."), "I d[aeiou]e"); +} + +TEST(MatcherDeathTest, MonomorphicMatcherMatches) { + EXPECT_DEATH(DieWithMessage("Behind O, I am slain!"), + Matcher(ContainsRegex("I am slain"))); +} + +TEST(MatcherDeathTest, MonomorphicMatcherDoesNotMatch) { + EXPECT_NONFATAL_FAILURE( + EXPECT_DEATH( + DieWithMessage("Behind O, I am slain!"), + Matcher(ContainsRegex("Ow, I am slain"))), + "Expected: contains regular expression \"Ow, I am slain\""); +} + +TEST(MatcherDeathTest, PolymorphicMatcherMatches) { + EXPECT_DEATH(DieWithMessage("The rest is silence."), + ContainsRegex("rest is silence")); +} + +TEST(MatcherDeathTest, PolymorphicMatcherDoesNotMatch) { + EXPECT_NONFATAL_FAILURE( + EXPECT_DEATH(DieWithMessage("The rest is silence."), + ContainsRegex("rest is science")), + "Expected: contains regular expression \"rest is science\""); +} + +} // namespace + +#else // !GTEST_HAS_DEATH_TEST follows + +namespace { + +using testing::internal::CaptureStderr; +using testing::internal::GetCapturedStderr; + +// Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED are still +// defined but do not trigger failures when death tests are not available on +// the system. +TEST(ConditionalDeathMacrosTest, WarnsWhenDeathTestsNotAvailable) { + // Empty statement will not crash, but that should not trigger a failure + // when death tests are not supported. + CaptureStderr(); + EXPECT_DEATH_IF_SUPPORTED(;, ""); + std::string output = GetCapturedStderr(); + ASSERT_TRUE(NULL != strstr(output.c_str(), + "Death tests are not supported on this platform")); + ASSERT_TRUE(NULL != strstr(output.c_str(), ";")); + + // The streamed message should not be printed as there is no test failure. + CaptureStderr(); + EXPECT_DEATH_IF_SUPPORTED(;, "") << "streamed message"; + output = GetCapturedStderr(); + ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message")); + + CaptureStderr(); + ASSERT_DEATH_IF_SUPPORTED(;, ""); // NOLINT + output = GetCapturedStderr(); + ASSERT_TRUE(NULL != strstr(output.c_str(), + "Death tests are not supported on this platform")); + ASSERT_TRUE(NULL != strstr(output.c_str(), ";")); + + CaptureStderr(); + ASSERT_DEATH_IF_SUPPORTED(;, "") << "streamed message"; // NOLINT + output = GetCapturedStderr(); + ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message")); +} + +void FuncWithAssert(int* n) { + ASSERT_DEATH_IF_SUPPORTED(return;, ""); + (*n)++; +} + +// Tests that ASSERT_DEATH_IF_SUPPORTED does not return from the current +// function (as ASSERT_DEATH does) if death tests are not supported. +TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported) { + int n = 0; + FuncWithAssert(&n); + EXPECT_EQ(1, n); +} + +} // namespace + +#endif // !GTEST_HAS_DEATH_TEST + +namespace { + +// Tests that the death test macros expand to code which may or may not +// be followed by operator<<, and that in either case the complete text +// comprises only a single C++ statement. +// +// The syntax should work whether death tests are available or not. +TEST(ConditionalDeathMacrosSyntaxDeathTest, SingleStatement) { + if (AlwaysFalse()) + // This would fail if executed; this is a compilation test only + ASSERT_DEATH_IF_SUPPORTED(return, ""); + + if (AlwaysTrue()) + EXPECT_DEATH_IF_SUPPORTED(_exit(1), ""); + else + // This empty "else" branch is meant to ensure that EXPECT_DEATH + // doesn't expand into an "if" statement without an "else" + ; // NOLINT + + if (AlwaysFalse()) + ASSERT_DEATH_IF_SUPPORTED(return, "") << "did not die"; + + if (AlwaysFalse()) + ; // NOLINT + else + EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << 1 << 2 << 3; +} + +// Tests that conditional death test macros expand to code which interacts +// well with switch statements. +TEST(ConditionalDeathMacrosSyntaxDeathTest, SwitchStatement) { + // Microsoft compiler usually complains about switch statements without + // case labels. We suppress that warning for this test. + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4065) + + switch (0) + default: + ASSERT_DEATH_IF_SUPPORTED(_exit(1), "") + << "exit in default switch handler"; + + switch (0) + case 0: + EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << "exit in switch case"; + + GTEST_DISABLE_MSC_WARNINGS_POP_() +} + +// Tests that a test case whose name ends with "DeathTest" works fine +// on Windows. +TEST(NotADeathTest, Test) { + SUCCEED(); +} + +} // namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-death-test_ex_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-death-test_ex_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..7ea5b9468e3b29175fff06614d6815c4649a5ac7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-death-test_ex_test.cc @@ -0,0 +1,92 @@ +// Copyright 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Tests that verify interaction of exceptions and death tests. + +#include "gtest/gtest-death-test.h" +#include "gtest/gtest.h" + +#if GTEST_HAS_DEATH_TEST + +# if GTEST_HAS_SEH +# include // For RaiseException(). +# endif + +# include "gtest/gtest-spi.h" + +# if GTEST_HAS_EXCEPTIONS + +# include // For std::exception. + +// Tests that death tests report thrown exceptions as failures and that the +// exceptions do not escape death test macros. +TEST(CxxExceptionDeathTest, ExceptionIsFailure) { + try { + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw 1, ""), "threw an exception"); + } catch (...) { // NOLINT + FAIL() << "An exception escaped a death test macro invocation " + << "with catch_exceptions " + << (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled"); + } +} + +class TestException : public std::exception { + public: + const char* what() const throw() override { return "exceptional message"; } +}; + +TEST(CxxExceptionDeathTest, PrintsMessageForStdExceptions) { + // Verifies that the exception message is quoted in the failure text. + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""), + "exceptional message"); + // Verifies that the location is mentioned in the failure text. + EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""), + __FILE__); +} +# endif // GTEST_HAS_EXCEPTIONS + +# if GTEST_HAS_SEH +// Tests that enabling interception of SEH exceptions with the +// catch_exceptions flag does not interfere with SEH exceptions being +// treated as death by death tests. +TEST(SehExceptionDeasTest, CatchExceptionsDoesNotInterfere) { + EXPECT_DEATH(RaiseException(42, 0x0, 0, NULL), "") + << "with catch_exceptions " + << (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled"); +} +# endif + +#endif // GTEST_HAS_DEATH_TEST + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + testing::GTEST_FLAG(catch_exceptions) = GTEST_ENABLE_CATCH_EXCEPTIONS_ != 0; + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-env-var-test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-env-var-test.py new file mode 100755 index 0000000000000000000000000000000000000000..2f0e406afcfc09dc11754c5fd9dd49a8956ddc91 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-env-var-test.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Verifies that Google Test correctly parses environment variables.""" + +import os +import gtest_test_utils + + +IS_WINDOWS = os.name == 'nt' +IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux' + +COMMAND = gtest_test_utils.GetTestExecutablePath('googletest-env-var-test_') + +environ = os.environ.copy() + + +def AssertEq(expected, actual): + if expected != actual: + print('Expected: %s' % (expected,)) + print(' Actual: %s' % (actual,)) + raise AssertionError + + +def SetEnvVar(env_var, value): + """Sets the env variable to 'value'; unsets it when 'value' is None.""" + + if value is not None: + environ[env_var] = value + elif env_var in environ: + del environ[env_var] + + +def GetFlag(flag): + """Runs googletest-env-var-test_ and returns its output.""" + + args = [COMMAND] + if flag is not None: + args += [flag] + return gtest_test_utils.Subprocess(args, env=environ).output + + +def TestFlag(flag, test_val, default_val): + """Verifies that the given flag is affected by the corresponding env var.""" + + env_var = 'GTEST_' + flag.upper() + SetEnvVar(env_var, test_val) + AssertEq(test_val, GetFlag(flag)) + SetEnvVar(env_var, None) + AssertEq(default_val, GetFlag(flag)) + + +class GTestEnvVarTest(gtest_test_utils.TestCase): + + def testEnvVarAffectsFlag(self): + """Tests that environment variable should affect the corresponding flag.""" + + TestFlag('break_on_failure', '1', '0') + TestFlag('color', 'yes', 'auto') + TestFlag('filter', 'FooTest.Bar', '*') + SetEnvVar('XML_OUTPUT_FILE', None) # For 'output' test + TestFlag('output', 'xml:tmp/foo.xml', '') + TestFlag('print_time', '0', '1') + TestFlag('repeat', '999', '1') + TestFlag('throw_on_failure', '1', '0') + TestFlag('death_test_style', 'threadsafe', 'fast') + TestFlag('catch_exceptions', '0', '1') + + if IS_LINUX: + TestFlag('death_test_use_fork', '1', '0') + TestFlag('stack_trace_depth', '0', '100') + + + def testXmlOutputFile(self): + """Tests that $XML_OUTPUT_FILE affects the output flag.""" + + SetEnvVar('GTEST_OUTPUT', None) + SetEnvVar('XML_OUTPUT_FILE', 'tmp/bar.xml') + AssertEq('xml:tmp/bar.xml', GetFlag('output')) + + def testXmlOutputFileOverride(self): + """Tests that $XML_OUTPUT_FILE is overridden by $GTEST_OUTPUT.""" + + SetEnvVar('GTEST_OUTPUT', 'xml:tmp/foo.xml') + SetEnvVar('XML_OUTPUT_FILE', 'tmp/bar.xml') + AssertEq('xml:tmp/foo.xml', GetFlag('output')) + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-env-var-test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-env-var-test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..fd2aa82f74faa21201e79ae0e5c3b568553df337 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-env-var-test_.cc @@ -0,0 +1,122 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// A helper program for testing that Google Test parses the environment +// variables correctly. + +#include + +#include "gtest/gtest.h" +#include "src/gtest-internal-inl.h" + +using ::std::cout; + +namespace testing { + +// The purpose of this is to make the test more realistic by ensuring +// that the UnitTest singleton is created before main() is entered. +// We don't actual run the TEST itself. +TEST(GTestEnvVarTest, Dummy) { +} + +void PrintFlag(const char* flag) { + if (strcmp(flag, "break_on_failure") == 0) { + cout << GTEST_FLAG(break_on_failure); + return; + } + + if (strcmp(flag, "catch_exceptions") == 0) { + cout << GTEST_FLAG(catch_exceptions); + return; + } + + if (strcmp(flag, "color") == 0) { + cout << GTEST_FLAG(color); + return; + } + + if (strcmp(flag, "death_test_style") == 0) { + cout << GTEST_FLAG(death_test_style); + return; + } + + if (strcmp(flag, "death_test_use_fork") == 0) { + cout << GTEST_FLAG(death_test_use_fork); + return; + } + + if (strcmp(flag, "filter") == 0) { + cout << GTEST_FLAG(filter); + return; + } + + if (strcmp(flag, "output") == 0) { + cout << GTEST_FLAG(output); + return; + } + + if (strcmp(flag, "print_time") == 0) { + cout << GTEST_FLAG(print_time); + return; + } + + if (strcmp(flag, "repeat") == 0) { + cout << GTEST_FLAG(repeat); + return; + } + + if (strcmp(flag, "stack_trace_depth") == 0) { + cout << GTEST_FLAG(stack_trace_depth); + return; + } + + if (strcmp(flag, "throw_on_failure") == 0) { + cout << GTEST_FLAG(throw_on_failure); + return; + } + + cout << "Invalid flag name " << flag + << ". Valid names are break_on_failure, color, filter, etc.\n"; + exit(1); +} + +} // namespace testing + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + + if (argc != 2) { + cout << "Usage: googletest-env-var-test_ NAME_OF_FLAG\n"; + return 1; + } + + testing::PrintFlag(argv[1]); + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-filepath-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-filepath-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..aafad36f3fef449f46ba77db20ecc966b5720b77 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-filepath-test.cc @@ -0,0 +1,649 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Google Test filepath utilities +// +// This file tests classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included from gtest-internal.h. +// Do not #include this file anywhere else! + +#include "gtest/internal/gtest-filepath.h" +#include "gtest/gtest.h" +#include "src/gtest-internal-inl.h" + +#if GTEST_OS_WINDOWS_MOBILE +# include // NOLINT +#elif GTEST_OS_WINDOWS +# include // NOLINT +#endif // GTEST_OS_WINDOWS_MOBILE + +namespace testing { +namespace internal { +namespace { + +#if GTEST_OS_WINDOWS_MOBILE + +// Windows CE doesn't have the remove C function. +int remove(const char* path) { + LPCWSTR wpath = String::AnsiToUtf16(path); + int ret = DeleteFile(wpath) ? 0 : -1; + delete [] wpath; + return ret; +} +// Windows CE doesn't have the _rmdir C function. +int _rmdir(const char* path) { + FilePath filepath(path); + LPCWSTR wpath = String::AnsiToUtf16( + filepath.RemoveTrailingPathSeparator().c_str()); + int ret = RemoveDirectory(wpath) ? 0 : -1; + delete [] wpath; + return ret; +} + +#else + +TEST(GetCurrentDirTest, ReturnsCurrentDir) { + const FilePath original_dir = FilePath::GetCurrentDir(); + EXPECT_FALSE(original_dir.IsEmpty()); + + posix::ChDir(GTEST_PATH_SEP_); + const FilePath cwd = FilePath::GetCurrentDir(); + posix::ChDir(original_dir.c_str()); + +# if GTEST_OS_WINDOWS || GTEST_OS_OS2 + + // Skips the ":". + const char* const cwd_without_drive = strchr(cwd.c_str(), ':'); + ASSERT_TRUE(cwd_without_drive != NULL); + EXPECT_STREQ(GTEST_PATH_SEP_, cwd_without_drive + 1); + +# else + + EXPECT_EQ(GTEST_PATH_SEP_, cwd.string()); + +# endif +} + +#endif // GTEST_OS_WINDOWS_MOBILE + +TEST(IsEmptyTest, ReturnsTrueForEmptyPath) { + EXPECT_TRUE(FilePath("").IsEmpty()); +} + +TEST(IsEmptyTest, ReturnsFalseForNonEmptyPath) { + EXPECT_FALSE(FilePath("a").IsEmpty()); + EXPECT_FALSE(FilePath(".").IsEmpty()); + EXPECT_FALSE(FilePath("a/b").IsEmpty()); + EXPECT_FALSE(FilePath("a\\b\\").IsEmpty()); +} + +// RemoveDirectoryName "" -> "" +TEST(RemoveDirectoryNameTest, WhenEmptyName) { + EXPECT_EQ("", FilePath("").RemoveDirectoryName().string()); +} + +// RemoveDirectoryName "afile" -> "afile" +TEST(RemoveDirectoryNameTest, ButNoDirectory) { + EXPECT_EQ("afile", + FilePath("afile").RemoveDirectoryName().string()); +} + +// RemoveDirectoryName "/afile" -> "afile" +TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileName) { + EXPECT_EQ("afile", + FilePath(GTEST_PATH_SEP_ "afile").RemoveDirectoryName().string()); +} + +// RemoveDirectoryName "adir/" -> "" +TEST(RemoveDirectoryNameTest, WhereThereIsNoFileName) { + EXPECT_EQ("", + FilePath("adir" GTEST_PATH_SEP_).RemoveDirectoryName().string()); +} + +// RemoveDirectoryName "adir/afile" -> "afile" +TEST(RemoveDirectoryNameTest, ShouldGiveFileName) { + EXPECT_EQ("afile", + FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveDirectoryName().string()); +} + +// RemoveDirectoryName "adir/subdir/afile" -> "afile" +TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileName) { + EXPECT_EQ("afile", + FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile") + .RemoveDirectoryName().string()); +} + +#if GTEST_HAS_ALT_PATH_SEP_ + +// Tests that RemoveDirectoryName() works with the alternate separator +// on Windows. + +// RemoveDirectoryName("/afile") -> "afile" +TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileNameForAlternateSeparator) { + EXPECT_EQ("afile", FilePath("/afile").RemoveDirectoryName().string()); +} + +// RemoveDirectoryName("adir/") -> "" +TEST(RemoveDirectoryNameTest, WhereThereIsNoFileNameForAlternateSeparator) { + EXPECT_EQ("", FilePath("adir/").RemoveDirectoryName().string()); +} + +// RemoveDirectoryName("adir/afile") -> "afile" +TEST(RemoveDirectoryNameTest, ShouldGiveFileNameForAlternateSeparator) { + EXPECT_EQ("afile", FilePath("adir/afile").RemoveDirectoryName().string()); +} + +// RemoveDirectoryName("adir/subdir/afile") -> "afile" +TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileNameForAlternateSeparator) { + EXPECT_EQ("afile", + FilePath("adir/subdir/afile").RemoveDirectoryName().string()); +} + +#endif + +// RemoveFileName "" -> "./" +TEST(RemoveFileNameTest, EmptyName) { +#if GTEST_OS_WINDOWS_MOBILE + // On Windows CE, we use the root as the current directory. + EXPECT_EQ(GTEST_PATH_SEP_, FilePath("").RemoveFileName().string()); +#else + EXPECT_EQ("." GTEST_PATH_SEP_, FilePath("").RemoveFileName().string()); +#endif +} + +// RemoveFileName "adir/" -> "adir/" +TEST(RemoveFileNameTest, ButNoFile) { + EXPECT_EQ("adir" GTEST_PATH_SEP_, + FilePath("adir" GTEST_PATH_SEP_).RemoveFileName().string()); +} + +// RemoveFileName "adir/afile" -> "adir/" +TEST(RemoveFileNameTest, GivesDirName) { + EXPECT_EQ("adir" GTEST_PATH_SEP_, + FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveFileName().string()); +} + +// RemoveFileName "adir/subdir/afile" -> "adir/subdir/" +TEST(RemoveFileNameTest, GivesDirAndSubDirName) { + EXPECT_EQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_, + FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile") + .RemoveFileName().string()); +} + +// RemoveFileName "/afile" -> "/" +TEST(RemoveFileNameTest, GivesRootDir) { + EXPECT_EQ(GTEST_PATH_SEP_, + FilePath(GTEST_PATH_SEP_ "afile").RemoveFileName().string()); +} + +#if GTEST_HAS_ALT_PATH_SEP_ + +// Tests that RemoveFileName() works with the alternate separator on +// Windows. + +// RemoveFileName("adir/") -> "adir/" +TEST(RemoveFileNameTest, ButNoFileForAlternateSeparator) { + EXPECT_EQ("adir" GTEST_PATH_SEP_, + FilePath("adir/").RemoveFileName().string()); +} + +// RemoveFileName("adir/afile") -> "adir/" +TEST(RemoveFileNameTest, GivesDirNameForAlternateSeparator) { + EXPECT_EQ("adir" GTEST_PATH_SEP_, + FilePath("adir/afile").RemoveFileName().string()); +} + +// RemoveFileName("adir/subdir/afile") -> "adir/subdir/" +TEST(RemoveFileNameTest, GivesDirAndSubDirNameForAlternateSeparator) { + EXPECT_EQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_, + FilePath("adir/subdir/afile").RemoveFileName().string()); +} + +// RemoveFileName("/afile") -> "\" +TEST(RemoveFileNameTest, GivesRootDirForAlternateSeparator) { + EXPECT_EQ(GTEST_PATH_SEP_, FilePath("/afile").RemoveFileName().string()); +} + +#endif + +TEST(MakeFileNameTest, GenerateWhenNumberIsZero) { + FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"), + 0, "xml"); + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); +} + +TEST(MakeFileNameTest, GenerateFileNameNumberGtZero) { + FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"), + 12, "xml"); + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.string()); +} + +TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberIsZero) { + FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_), + FilePath("bar"), 0, "xml"); + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); +} + +TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberGtZero) { + FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_), + FilePath("bar"), 12, "xml"); + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.string()); +} + +TEST(MakeFileNameTest, GenerateWhenNumberIsZeroAndDirIsEmpty) { + FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"), + 0, "xml"); + EXPECT_EQ("bar.xml", actual.string()); +} + +TEST(MakeFileNameTest, GenerateWhenNumberIsNotZeroAndDirIsEmpty) { + FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"), + 14, "xml"); + EXPECT_EQ("bar_14.xml", actual.string()); +} + +TEST(ConcatPathsTest, WorksWhenDirDoesNotEndWithPathSep) { + FilePath actual = FilePath::ConcatPaths(FilePath("foo"), + FilePath("bar.xml")); + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); +} + +TEST(ConcatPathsTest, WorksWhenPath1EndsWithPathSep) { + FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_), + FilePath("bar.xml")); + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); +} + +TEST(ConcatPathsTest, Path1BeingEmpty) { + FilePath actual = FilePath::ConcatPaths(FilePath(""), + FilePath("bar.xml")); + EXPECT_EQ("bar.xml", actual.string()); +} + +TEST(ConcatPathsTest, Path2BeingEmpty) { + FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath("")); + EXPECT_EQ("foo" GTEST_PATH_SEP_, actual.string()); +} + +TEST(ConcatPathsTest, BothPathBeingEmpty) { + FilePath actual = FilePath::ConcatPaths(FilePath(""), + FilePath("")); + EXPECT_EQ("", actual.string()); +} + +TEST(ConcatPathsTest, Path1ContainsPathSep) { + FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_ "bar"), + FilePath("foobar.xml")); + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "foobar.xml", + actual.string()); +} + +TEST(ConcatPathsTest, Path2ContainsPathSep) { + FilePath actual = FilePath::ConcatPaths( + FilePath("foo" GTEST_PATH_SEP_), + FilePath("bar" GTEST_PATH_SEP_ "bar.xml")); + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "bar.xml", + actual.string()); +} + +TEST(ConcatPathsTest, Path2EndsWithPathSep) { + FilePath actual = FilePath::ConcatPaths(FilePath("foo"), + FilePath("bar" GTEST_PATH_SEP_)); + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_, actual.string()); +} + +// RemoveTrailingPathSeparator "" -> "" +TEST(RemoveTrailingPathSeparatorTest, EmptyString) { + EXPECT_EQ("", FilePath("").RemoveTrailingPathSeparator().string()); +} + +// RemoveTrailingPathSeparator "foo" -> "foo" +TEST(RemoveTrailingPathSeparatorTest, FileNoSlashString) { + EXPECT_EQ("foo", FilePath("foo").RemoveTrailingPathSeparator().string()); +} + +// RemoveTrailingPathSeparator "foo/" -> "foo" +TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveTrailingSeparator) { + EXPECT_EQ("foo", + FilePath("foo" GTEST_PATH_SEP_).RemoveTrailingPathSeparator().string()); +#if GTEST_HAS_ALT_PATH_SEP_ + EXPECT_EQ("foo", FilePath("foo/").RemoveTrailingPathSeparator().string()); +#endif +} + +// RemoveTrailingPathSeparator "foo/bar/" -> "foo/bar/" +TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveLastSeparator) { + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", + FilePath("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_) + .RemoveTrailingPathSeparator().string()); +} + +// RemoveTrailingPathSeparator "foo/bar" -> "foo/bar" +TEST(RemoveTrailingPathSeparatorTest, ShouldReturnUnmodified) { + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", + FilePath("foo" GTEST_PATH_SEP_ "bar") + .RemoveTrailingPathSeparator().string()); +} + +TEST(DirectoryTest, RootDirectoryExists) { +#if GTEST_OS_WINDOWS // We are on Windows. + char current_drive[_MAX_PATH]; // NOLINT + current_drive[0] = static_cast(_getdrive() + 'A' - 1); + current_drive[1] = ':'; + current_drive[2] = '\\'; + current_drive[3] = '\0'; + EXPECT_TRUE(FilePath(current_drive).DirectoryExists()); +#else + EXPECT_TRUE(FilePath("/").DirectoryExists()); +#endif // GTEST_OS_WINDOWS +} + +#if GTEST_OS_WINDOWS +TEST(DirectoryTest, RootOfWrongDriveDoesNotExists) { + const int saved_drive_ = _getdrive(); + // Find a drive that doesn't exist. Start with 'Z' to avoid common ones. + for (char drive = 'Z'; drive >= 'A'; drive--) + if (_chdrive(drive - 'A' + 1) == -1) { + char non_drive[_MAX_PATH]; // NOLINT + non_drive[0] = drive; + non_drive[1] = ':'; + non_drive[2] = '\\'; + non_drive[3] = '\0'; + EXPECT_FALSE(FilePath(non_drive).DirectoryExists()); + break; + } + _chdrive(saved_drive_); +} +#endif // GTEST_OS_WINDOWS + +#if !GTEST_OS_WINDOWS_MOBILE +// Windows CE _does_ consider an empty directory to exist. +TEST(DirectoryTest, EmptyPathDirectoryDoesNotExist) { + EXPECT_FALSE(FilePath("").DirectoryExists()); +} +#endif // !GTEST_OS_WINDOWS_MOBILE + +TEST(DirectoryTest, CurrentDirectoryExists) { +#if GTEST_OS_WINDOWS // We are on Windows. +# ifndef _WIN32_CE // Windows CE doesn't have a current directory. + + EXPECT_TRUE(FilePath(".").DirectoryExists()); + EXPECT_TRUE(FilePath(".\\").DirectoryExists()); + +# endif // _WIN32_CE +#else + EXPECT_TRUE(FilePath(".").DirectoryExists()); + EXPECT_TRUE(FilePath("./").DirectoryExists()); +#endif // GTEST_OS_WINDOWS +} + +// "foo/bar" == foo//bar" == "foo///bar" +TEST(NormalizeTest, MultipleConsecutiveSepaparatorsInMidstring) { + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", + FilePath("foo" GTEST_PATH_SEP_ "bar").string()); + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", + FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string()); + EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", + FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ + GTEST_PATH_SEP_ "bar").string()); +} + +// "/bar" == //bar" == "///bar" +TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringStart) { + EXPECT_EQ(GTEST_PATH_SEP_ "bar", + FilePath(GTEST_PATH_SEP_ "bar").string()); + EXPECT_EQ(GTEST_PATH_SEP_ "bar", + FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string()); + EXPECT_EQ(GTEST_PATH_SEP_ "bar", + FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string()); +} + +// "foo/" == foo//" == "foo///" +TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringEnd) { + EXPECT_EQ("foo" GTEST_PATH_SEP_, + FilePath("foo" GTEST_PATH_SEP_).string()); + EXPECT_EQ("foo" GTEST_PATH_SEP_, + FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_).string()); + EXPECT_EQ("foo" GTEST_PATH_SEP_, + FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_).string()); +} + +#if GTEST_HAS_ALT_PATH_SEP_ + +// Tests that separators at the end of the string are normalized +// regardless of their combination (e.g. "foo\" =="foo/\" == +// "foo\\/"). +TEST(NormalizeTest, MixAlternateSeparatorAtStringEnd) { + EXPECT_EQ("foo" GTEST_PATH_SEP_, + FilePath("foo/").string()); + EXPECT_EQ("foo" GTEST_PATH_SEP_, + FilePath("foo" GTEST_PATH_SEP_ "/").string()); + EXPECT_EQ("foo" GTEST_PATH_SEP_, + FilePath("foo//" GTEST_PATH_SEP_).string()); +} + +#endif + +TEST(AssignmentOperatorTest, DefaultAssignedToNonDefault) { + FilePath default_path; + FilePath non_default_path("path"); + non_default_path = default_path; + EXPECT_EQ("", non_default_path.string()); + EXPECT_EQ("", default_path.string()); // RHS var is unchanged. +} + +TEST(AssignmentOperatorTest, NonDefaultAssignedToDefault) { + FilePath non_default_path("path"); + FilePath default_path; + default_path = non_default_path; + EXPECT_EQ("path", default_path.string()); + EXPECT_EQ("path", non_default_path.string()); // RHS var is unchanged. +} + +TEST(AssignmentOperatorTest, ConstAssignedToNonConst) { + const FilePath const_default_path("const_path"); + FilePath non_default_path("path"); + non_default_path = const_default_path; + EXPECT_EQ("const_path", non_default_path.string()); +} + +class DirectoryCreationTest : public Test { + protected: + void SetUp() override { + testdata_path_.Set(FilePath( + TempDir() + GetCurrentExecutableName().string() + + "_directory_creation" GTEST_PATH_SEP_ "test" GTEST_PATH_SEP_)); + testdata_file_.Set(testdata_path_.RemoveTrailingPathSeparator()); + + unique_file0_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"), + 0, "txt")); + unique_file1_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"), + 1, "txt")); + + remove(testdata_file_.c_str()); + remove(unique_file0_.c_str()); + remove(unique_file1_.c_str()); + posix::RmDir(testdata_path_.c_str()); + } + + void TearDown() override { + remove(testdata_file_.c_str()); + remove(unique_file0_.c_str()); + remove(unique_file1_.c_str()); + posix::RmDir(testdata_path_.c_str()); + } + + void CreateTextFile(const char* filename) { + FILE* f = posix::FOpen(filename, "w"); + fprintf(f, "text\n"); + fclose(f); + } + + // Strings representing a directory and a file, with identical paths + // except for the trailing separator character that distinquishes + // a directory named 'test' from a file named 'test'. Example names: + FilePath testdata_path_; // "/tmp/directory_creation/test/" + FilePath testdata_file_; // "/tmp/directory_creation/test" + FilePath unique_file0_; // "/tmp/directory_creation/test/unique.txt" + FilePath unique_file1_; // "/tmp/directory_creation/test/unique_1.txt" +}; + +TEST_F(DirectoryCreationTest, CreateDirectoriesRecursively) { + EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.string(); + EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); + EXPECT_TRUE(testdata_path_.DirectoryExists()); +} + +TEST_F(DirectoryCreationTest, CreateDirectoriesForAlreadyExistingPath) { + EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.string(); + EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); + // Call 'create' again... should still succeed. + EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); +} + +TEST_F(DirectoryCreationTest, CreateDirectoriesAndUniqueFilename) { + FilePath file_path(FilePath::GenerateUniqueFileName(testdata_path_, + FilePath("unique"), "txt")); + EXPECT_EQ(unique_file0_.string(), file_path.string()); + EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file not there + + testdata_path_.CreateDirectoriesRecursively(); + EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file still not there + CreateTextFile(file_path.c_str()); + EXPECT_TRUE(file_path.FileOrDirectoryExists()); + + FilePath file_path2(FilePath::GenerateUniqueFileName(testdata_path_, + FilePath("unique"), "txt")); + EXPECT_EQ(unique_file1_.string(), file_path2.string()); + EXPECT_FALSE(file_path2.FileOrDirectoryExists()); // file not there + CreateTextFile(file_path2.c_str()); + EXPECT_TRUE(file_path2.FileOrDirectoryExists()); +} + +TEST_F(DirectoryCreationTest, CreateDirectoriesFail) { + // force a failure by putting a file where we will try to create a directory. + CreateTextFile(testdata_file_.c_str()); + EXPECT_TRUE(testdata_file_.FileOrDirectoryExists()); + EXPECT_FALSE(testdata_file_.DirectoryExists()); + EXPECT_FALSE(testdata_file_.CreateDirectoriesRecursively()); +} + +TEST(NoDirectoryCreationTest, CreateNoDirectoriesForDefaultXmlFile) { + const FilePath test_detail_xml("test_detail.xml"); + EXPECT_FALSE(test_detail_xml.CreateDirectoriesRecursively()); +} + +TEST(FilePathTest, DefaultConstructor) { + FilePath fp; + EXPECT_EQ("", fp.string()); +} + +TEST(FilePathTest, CharAndCopyConstructors) { + const FilePath fp("spicy"); + EXPECT_EQ("spicy", fp.string()); + + const FilePath fp_copy(fp); + EXPECT_EQ("spicy", fp_copy.string()); +} + +TEST(FilePathTest, StringConstructor) { + const FilePath fp(std::string("cider")); + EXPECT_EQ("cider", fp.string()); +} + +TEST(FilePathTest, Set) { + const FilePath apple("apple"); + FilePath mac("mac"); + mac.Set(apple); // Implement Set() since overloading operator= is forbidden. + EXPECT_EQ("apple", mac.string()); + EXPECT_EQ("apple", apple.string()); +} + +TEST(FilePathTest, ToString) { + const FilePath file("drink"); + EXPECT_EQ("drink", file.string()); +} + +TEST(FilePathTest, RemoveExtension) { + EXPECT_EQ("app", FilePath("app.cc").RemoveExtension("cc").string()); + EXPECT_EQ("app", FilePath("app.exe").RemoveExtension("exe").string()); + EXPECT_EQ("APP", FilePath("APP.EXE").RemoveExtension("exe").string()); +} + +TEST(FilePathTest, RemoveExtensionWhenThereIsNoExtension) { + EXPECT_EQ("app", FilePath("app").RemoveExtension("exe").string()); +} + +TEST(FilePathTest, IsDirectory) { + EXPECT_FALSE(FilePath("cola").IsDirectory()); + EXPECT_TRUE(FilePath("koala" GTEST_PATH_SEP_).IsDirectory()); +#if GTEST_HAS_ALT_PATH_SEP_ + EXPECT_TRUE(FilePath("koala/").IsDirectory()); +#endif +} + +TEST(FilePathTest, IsAbsolutePath) { + EXPECT_FALSE(FilePath("is" GTEST_PATH_SEP_ "relative").IsAbsolutePath()); + EXPECT_FALSE(FilePath("").IsAbsolutePath()); +#if GTEST_OS_WINDOWS + EXPECT_TRUE(FilePath("c:\\" GTEST_PATH_SEP_ "is_not" + GTEST_PATH_SEP_ "relative").IsAbsolutePath()); + EXPECT_FALSE(FilePath("c:foo" GTEST_PATH_SEP_ "bar").IsAbsolutePath()); + EXPECT_TRUE(FilePath("c:/" GTEST_PATH_SEP_ "is_not" + GTEST_PATH_SEP_ "relative").IsAbsolutePath()); +#else + EXPECT_TRUE(FilePath(GTEST_PATH_SEP_ "is_not" GTEST_PATH_SEP_ "relative") + .IsAbsolutePath()); +#endif // GTEST_OS_WINDOWS +} + +TEST(FilePathTest, IsRootDirectory) { +#if GTEST_OS_WINDOWS + EXPECT_TRUE(FilePath("a:\\").IsRootDirectory()); + EXPECT_TRUE(FilePath("Z:/").IsRootDirectory()); + EXPECT_TRUE(FilePath("e://").IsRootDirectory()); + EXPECT_FALSE(FilePath("").IsRootDirectory()); + EXPECT_FALSE(FilePath("b:").IsRootDirectory()); + EXPECT_FALSE(FilePath("b:a").IsRootDirectory()); + EXPECT_FALSE(FilePath("8:/").IsRootDirectory()); + EXPECT_FALSE(FilePath("c|/").IsRootDirectory()); +#else + EXPECT_TRUE(FilePath("/").IsRootDirectory()); + EXPECT_TRUE(FilePath("//").IsRootDirectory()); + EXPECT_FALSE(FilePath("").IsRootDirectory()); + EXPECT_FALSE(FilePath("\\").IsRootDirectory()); + EXPECT_FALSE(FilePath("/x").IsRootDirectory()); +#endif +} + +} // namespace +} // namespace internal +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-filter-unittest.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-filter-unittest.py new file mode 100755 index 0000000000000000000000000000000000000000..6b32f2d21997189a3cd9eaf313d470bdd84fcc11 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-filter-unittest.py @@ -0,0 +1,639 @@ +#!/usr/bin/env python +# +# Copyright 2005 Google Inc. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for Google Test test filters. + +A user can specify which test(s) in a Google Test program to run via either +the GTEST_FILTER environment variable or the --gtest_filter flag. +This script tests such functionality by invoking +googletest-filter-unittest_ (a program written with Google Test) with different +environments and command line flags. + +Note that test sharding may also influence which tests are filtered. Therefore, +we test that here also. +""" + +import os +import re +try: + from sets import Set as set # For Python 2.3 compatibility +except ImportError: + pass +import sys +import gtest_test_utils + +# Constants. + +# Checks if this platform can pass empty environment variables to child +# processes. We set an env variable to an empty string and invoke a python +# script in a subprocess to print whether the variable is STILL in +# os.environ. We then use 'eval' to parse the child's output so that an +# exception is thrown if the input is anything other than 'True' nor 'False'. +CAN_PASS_EMPTY_ENV = False +if sys.executable: + os.environ['EMPTY_VAR'] = '' + child = gtest_test_utils.Subprocess( + [sys.executable, '-c', 'import os; print(\'EMPTY_VAR\' in os.environ)']) + CAN_PASS_EMPTY_ENV = eval(child.output) + + +# Check if this platform can unset environment variables in child processes. +# We set an env variable to a non-empty string, unset it, and invoke +# a python script in a subprocess to print whether the variable +# is NO LONGER in os.environ. +# We use 'eval' to parse the child's output so that an exception +# is thrown if the input is neither 'True' nor 'False'. +CAN_UNSET_ENV = False +if sys.executable: + os.environ['UNSET_VAR'] = 'X' + del os.environ['UNSET_VAR'] + child = gtest_test_utils.Subprocess( + [sys.executable, '-c', 'import os; print(\'UNSET_VAR\' not in os.environ)' + ]) + CAN_UNSET_ENV = eval(child.output) + + +# Checks if we should test with an empty filter. This doesn't +# make sense on platforms that cannot pass empty env variables (Win32) +# and on platforms that cannot unset variables (since we cannot tell +# the difference between "" and NULL -- Borland and Solaris < 5.10) +CAN_TEST_EMPTY_FILTER = (CAN_PASS_EMPTY_ENV and CAN_UNSET_ENV) + + +# The environment variable for specifying the test filters. +FILTER_ENV_VAR = 'GTEST_FILTER' + +# The environment variables for test sharding. +TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' +SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' +SHARD_STATUS_FILE_ENV_VAR = 'GTEST_SHARD_STATUS_FILE' + +# The command line flag for specifying the test filters. +FILTER_FLAG = 'gtest_filter' + +# The command line flag for including disabled tests. +ALSO_RUN_DISABLED_TESTS_FLAG = 'gtest_also_run_disabled_tests' + +# Command to run the googletest-filter-unittest_ program. +COMMAND = gtest_test_utils.GetTestExecutablePath('googletest-filter-unittest_') + +# Regex for determining whether parameterized tests are enabled in the binary. +PARAM_TEST_REGEX = re.compile(r'/ParamTest') + +# Regex for parsing test case names from Google Test's output. +TEST_CASE_REGEX = re.compile(r'^\[\-+\] \d+ tests? from (\w+(/\w+)?)') + +# Regex for parsing test names from Google Test's output. +TEST_REGEX = re.compile(r'^\[\s*RUN\s*\].*\.(\w+(/\w+)?)') + +# The command line flag to tell Google Test to output the list of tests it +# will run. +LIST_TESTS_FLAG = '--gtest_list_tests' + +# Indicates whether Google Test supports death tests. +SUPPORTS_DEATH_TESTS = 'HasDeathTest' in gtest_test_utils.Subprocess( + [COMMAND, LIST_TESTS_FLAG]).output + +# Full names of all tests in googletest-filter-unittests_. +PARAM_TESTS = [ + 'SeqP/ParamTest.TestX/0', + 'SeqP/ParamTest.TestX/1', + 'SeqP/ParamTest.TestY/0', + 'SeqP/ParamTest.TestY/1', + 'SeqQ/ParamTest.TestX/0', + 'SeqQ/ParamTest.TestX/1', + 'SeqQ/ParamTest.TestY/0', + 'SeqQ/ParamTest.TestY/1', + ] + +DISABLED_TESTS = [ + 'BarTest.DISABLED_TestFour', + 'BarTest.DISABLED_TestFive', + 'BazTest.DISABLED_TestC', + 'DISABLED_FoobarTest.Test1', + 'DISABLED_FoobarTest.DISABLED_Test2', + 'DISABLED_FoobarbazTest.TestA', + ] + +if SUPPORTS_DEATH_TESTS: + DEATH_TESTS = [ + 'HasDeathTest.Test1', + 'HasDeathTest.Test2', + ] +else: + DEATH_TESTS = [] + +# All the non-disabled tests. +ACTIVE_TESTS = [ + 'FooTest.Abc', + 'FooTest.Xyz', + + 'BarTest.TestOne', + 'BarTest.TestTwo', + 'BarTest.TestThree', + + 'BazTest.TestOne', + 'BazTest.TestA', + 'BazTest.TestB', + ] + DEATH_TESTS + PARAM_TESTS + +param_tests_present = None + +# Utilities. + +environ = os.environ.copy() + + +def SetEnvVar(env_var, value): + """Sets the env variable to 'value'; unsets it when 'value' is None.""" + + if value is not None: + environ[env_var] = value + elif env_var in environ: + del environ[env_var] + + +def RunAndReturnOutput(args = None): + """Runs the test program and returns its output.""" + + return gtest_test_utils.Subprocess([COMMAND] + (args or []), + env=environ).output + + +def RunAndExtractTestList(args = None): + """Runs the test program and returns its exit code and a list of tests run.""" + + p = gtest_test_utils.Subprocess([COMMAND] + (args or []), env=environ) + tests_run = [] + test_case = '' + test = '' + for line in p.output.split('\n'): + match = TEST_CASE_REGEX.match(line) + if match is not None: + test_case = match.group(1) + else: + match = TEST_REGEX.match(line) + if match is not None: + test = match.group(1) + tests_run.append(test_case + '.' + test) + return (tests_run, p.exit_code) + + +def InvokeWithModifiedEnv(extra_env, function, *args, **kwargs): + """Runs the given function and arguments in a modified environment.""" + try: + original_env = environ.copy() + environ.update(extra_env) + return function(*args, **kwargs) + finally: + environ.clear() + environ.update(original_env) + + +def RunWithSharding(total_shards, shard_index, command): + """Runs a test program shard and returns exit code and a list of tests run.""" + + extra_env = {SHARD_INDEX_ENV_VAR: str(shard_index), + TOTAL_SHARDS_ENV_VAR: str(total_shards)} + return InvokeWithModifiedEnv(extra_env, RunAndExtractTestList, command) + +# The unit test. + + +class GTestFilterUnitTest(gtest_test_utils.TestCase): + """Tests the env variable or the command line flag to filter tests.""" + + # Utilities. + + def AssertSetEqual(self, lhs, rhs): + """Asserts that two sets are equal.""" + + for elem in lhs: + self.assert_(elem in rhs, '%s in %s' % (elem, rhs)) + + for elem in rhs: + self.assert_(elem in lhs, '%s in %s' % (elem, lhs)) + + def AssertPartitionIsValid(self, set_var, list_of_sets): + """Asserts that list_of_sets is a valid partition of set_var.""" + + full_partition = [] + for slice_var in list_of_sets: + full_partition.extend(slice_var) + self.assertEqual(len(set_var), len(full_partition)) + self.assertEqual(set(set_var), set(full_partition)) + + def AdjustForParameterizedTests(self, tests_to_run): + """Adjust tests_to_run in case value parameterized tests are disabled.""" + + global param_tests_present + if not param_tests_present: + return list(set(tests_to_run) - set(PARAM_TESTS)) + else: + return tests_to_run + + def RunAndVerify(self, gtest_filter, tests_to_run): + """Checks that the binary runs correct set of tests for a given filter.""" + + tests_to_run = self.AdjustForParameterizedTests(tests_to_run) + + # First, tests using the environment variable. + + # Windows removes empty variables from the environment when passing it + # to a new process. This means it is impossible to pass an empty filter + # into a process using the environment variable. However, we can still + # test the case when the variable is not supplied (i.e., gtest_filter is + # None). + # pylint: disable-msg=C6403 + if CAN_TEST_EMPTY_FILTER or gtest_filter != '': + SetEnvVar(FILTER_ENV_VAR, gtest_filter) + tests_run = RunAndExtractTestList()[0] + SetEnvVar(FILTER_ENV_VAR, None) + self.AssertSetEqual(tests_run, tests_to_run) + # pylint: enable-msg=C6403 + + # Next, tests using the command line flag. + + if gtest_filter is None: + args = [] + else: + args = ['--%s=%s' % (FILTER_FLAG, gtest_filter)] + + tests_run = RunAndExtractTestList(args)[0] + self.AssertSetEqual(tests_run, tests_to_run) + + def RunAndVerifyWithSharding(self, gtest_filter, total_shards, tests_to_run, + args=None, check_exit_0=False): + """Checks that binary runs correct tests for the given filter and shard. + + Runs all shards of googletest-filter-unittest_ with the given filter, and + verifies that the right set of tests were run. The union of tests run + on each shard should be identical to tests_to_run, without duplicates. + If check_exit_0, . + + Args: + gtest_filter: A filter to apply to the tests. + total_shards: A total number of shards to split test run into. + tests_to_run: A set of tests expected to run. + args : Arguments to pass to the to the test binary. + check_exit_0: When set to a true value, make sure that all shards + return 0. + """ + + tests_to_run = self.AdjustForParameterizedTests(tests_to_run) + + # Windows removes empty variables from the environment when passing it + # to a new process. This means it is impossible to pass an empty filter + # into a process using the environment variable. However, we can still + # test the case when the variable is not supplied (i.e., gtest_filter is + # None). + # pylint: disable-msg=C6403 + if CAN_TEST_EMPTY_FILTER or gtest_filter != '': + SetEnvVar(FILTER_ENV_VAR, gtest_filter) + partition = [] + for i in range(0, total_shards): + (tests_run, exit_code) = RunWithSharding(total_shards, i, args) + if check_exit_0: + self.assertEqual(0, exit_code) + partition.append(tests_run) + + self.AssertPartitionIsValid(tests_to_run, partition) + SetEnvVar(FILTER_ENV_VAR, None) + # pylint: enable-msg=C6403 + + def RunAndVerifyAllowingDisabled(self, gtest_filter, tests_to_run): + """Checks that the binary runs correct set of tests for the given filter. + + Runs googletest-filter-unittest_ with the given filter, and enables + disabled tests. Verifies that the right set of tests were run. + + Args: + gtest_filter: A filter to apply to the tests. + tests_to_run: A set of tests expected to run. + """ + + tests_to_run = self.AdjustForParameterizedTests(tests_to_run) + + # Construct the command line. + args = ['--%s' % ALSO_RUN_DISABLED_TESTS_FLAG] + if gtest_filter is not None: + args.append('--%s=%s' % (FILTER_FLAG, gtest_filter)) + + tests_run = RunAndExtractTestList(args)[0] + self.AssertSetEqual(tests_run, tests_to_run) + + def setUp(self): + """Sets up test case. + + Determines whether value-parameterized tests are enabled in the binary and + sets the flags accordingly. + """ + + global param_tests_present + if param_tests_present is None: + param_tests_present = PARAM_TEST_REGEX.search( + RunAndReturnOutput()) is not None + + def testDefaultBehavior(self): + """Tests the behavior of not specifying the filter.""" + + self.RunAndVerify(None, ACTIVE_TESTS) + + def testDefaultBehaviorWithShards(self): + """Tests the behavior without the filter, with sharding enabled.""" + + self.RunAndVerifyWithSharding(None, 1, ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, 2, ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) - 1, ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS), ACTIVE_TESTS) + self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) + 1, ACTIVE_TESTS) + + def testEmptyFilter(self): + """Tests an empty filter.""" + + self.RunAndVerify('', []) + self.RunAndVerifyWithSharding('', 1, []) + self.RunAndVerifyWithSharding('', 2, []) + + def testBadFilter(self): + """Tests a filter that matches nothing.""" + + self.RunAndVerify('BadFilter', []) + self.RunAndVerifyAllowingDisabled('BadFilter', []) + + def testFullName(self): + """Tests filtering by full name.""" + + self.RunAndVerify('FooTest.Xyz', ['FooTest.Xyz']) + self.RunAndVerifyAllowingDisabled('FooTest.Xyz', ['FooTest.Xyz']) + self.RunAndVerifyWithSharding('FooTest.Xyz', 5, ['FooTest.Xyz']) + + def testUniversalFilters(self): + """Tests filters that match everything.""" + + self.RunAndVerify('*', ACTIVE_TESTS) + self.RunAndVerify('*.*', ACTIVE_TESTS) + self.RunAndVerifyWithSharding('*.*', len(ACTIVE_TESTS) - 3, ACTIVE_TESTS) + self.RunAndVerifyAllowingDisabled('*', ACTIVE_TESTS + DISABLED_TESTS) + self.RunAndVerifyAllowingDisabled('*.*', ACTIVE_TESTS + DISABLED_TESTS) + + def testFilterByTestCase(self): + """Tests filtering by test case name.""" + + self.RunAndVerify('FooTest.*', ['FooTest.Abc', 'FooTest.Xyz']) + + BAZ_TESTS = ['BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB'] + self.RunAndVerify('BazTest.*', BAZ_TESTS) + self.RunAndVerifyAllowingDisabled('BazTest.*', + BAZ_TESTS + ['BazTest.DISABLED_TestC']) + + def testFilterByTest(self): + """Tests filtering by test name.""" + + self.RunAndVerify('*.TestOne', ['BarTest.TestOne', 'BazTest.TestOne']) + + def testFilterDisabledTests(self): + """Select only the disabled tests to run.""" + + self.RunAndVerify('DISABLED_FoobarTest.Test1', []) + self.RunAndVerifyAllowingDisabled('DISABLED_FoobarTest.Test1', + ['DISABLED_FoobarTest.Test1']) + + self.RunAndVerify('*DISABLED_*', []) + self.RunAndVerifyAllowingDisabled('*DISABLED_*', DISABLED_TESTS) + + self.RunAndVerify('*.DISABLED_*', []) + self.RunAndVerifyAllowingDisabled('*.DISABLED_*', [ + 'BarTest.DISABLED_TestFour', + 'BarTest.DISABLED_TestFive', + 'BazTest.DISABLED_TestC', + 'DISABLED_FoobarTest.DISABLED_Test2', + ]) + + self.RunAndVerify('DISABLED_*', []) + self.RunAndVerifyAllowingDisabled('DISABLED_*', [ + 'DISABLED_FoobarTest.Test1', + 'DISABLED_FoobarTest.DISABLED_Test2', + 'DISABLED_FoobarbazTest.TestA', + ]) + + def testWildcardInTestCaseName(self): + """Tests using wildcard in the test case name.""" + + self.RunAndVerify('*a*.*', [ + 'BarTest.TestOne', + 'BarTest.TestTwo', + 'BarTest.TestThree', + + 'BazTest.TestOne', + 'BazTest.TestA', + 'BazTest.TestB', ] + DEATH_TESTS + PARAM_TESTS) + + def testWildcardInTestName(self): + """Tests using wildcard in the test name.""" + + self.RunAndVerify('*.*A*', ['FooTest.Abc', 'BazTest.TestA']) + + def testFilterWithoutDot(self): + """Tests a filter that has no '.' in it.""" + + self.RunAndVerify('*z*', [ + 'FooTest.Xyz', + + 'BazTest.TestOne', + 'BazTest.TestA', + 'BazTest.TestB', + ]) + + def testTwoPatterns(self): + """Tests filters that consist of two patterns.""" + + self.RunAndVerify('Foo*.*:*A*', [ + 'FooTest.Abc', + 'FooTest.Xyz', + + 'BazTest.TestA', + ]) + + # An empty pattern + a non-empty one + self.RunAndVerify(':*A*', ['FooTest.Abc', 'BazTest.TestA']) + + def testThreePatterns(self): + """Tests filters that consist of three patterns.""" + + self.RunAndVerify('*oo*:*A*:*One', [ + 'FooTest.Abc', + 'FooTest.Xyz', + + 'BarTest.TestOne', + + 'BazTest.TestOne', + 'BazTest.TestA', + ]) + + # The 2nd pattern is empty. + self.RunAndVerify('*oo*::*One', [ + 'FooTest.Abc', + 'FooTest.Xyz', + + 'BarTest.TestOne', + + 'BazTest.TestOne', + ]) + + # The last 2 patterns are empty. + self.RunAndVerify('*oo*::', [ + 'FooTest.Abc', + 'FooTest.Xyz', + ]) + + def testNegativeFilters(self): + self.RunAndVerify('*-BazTest.TestOne', [ + 'FooTest.Abc', + 'FooTest.Xyz', + + 'BarTest.TestOne', + 'BarTest.TestTwo', + 'BarTest.TestThree', + + 'BazTest.TestA', + 'BazTest.TestB', + ] + DEATH_TESTS + PARAM_TESTS) + + self.RunAndVerify('*-FooTest.Abc:BazTest.*', [ + 'FooTest.Xyz', + + 'BarTest.TestOne', + 'BarTest.TestTwo', + 'BarTest.TestThree', + ] + DEATH_TESTS + PARAM_TESTS) + + self.RunAndVerify('BarTest.*-BarTest.TestOne', [ + 'BarTest.TestTwo', + 'BarTest.TestThree', + ]) + + # Tests without leading '*'. + self.RunAndVerify('-FooTest.Abc:FooTest.Xyz:BazTest.*', [ + 'BarTest.TestOne', + 'BarTest.TestTwo', + 'BarTest.TestThree', + ] + DEATH_TESTS + PARAM_TESTS) + + # Value parameterized tests. + self.RunAndVerify('*/*', PARAM_TESTS) + + # Value parameterized tests filtering by the sequence name. + self.RunAndVerify('SeqP/*', [ + 'SeqP/ParamTest.TestX/0', + 'SeqP/ParamTest.TestX/1', + 'SeqP/ParamTest.TestY/0', + 'SeqP/ParamTest.TestY/1', + ]) + + # Value parameterized tests filtering by the test name. + self.RunAndVerify('*/0', [ + 'SeqP/ParamTest.TestX/0', + 'SeqP/ParamTest.TestY/0', + 'SeqQ/ParamTest.TestX/0', + 'SeqQ/ParamTest.TestY/0', + ]) + + def testFlagOverridesEnvVar(self): + """Tests that the filter flag overrides the filtering env. variable.""" + + SetEnvVar(FILTER_ENV_VAR, 'Foo*') + args = ['--%s=%s' % (FILTER_FLAG, '*One')] + tests_run = RunAndExtractTestList(args)[0] + SetEnvVar(FILTER_ENV_VAR, None) + + self.AssertSetEqual(tests_run, ['BarTest.TestOne', 'BazTest.TestOne']) + + def testShardStatusFileIsCreated(self): + """Tests that the shard file is created if specified in the environment.""" + + shard_status_file = os.path.join(gtest_test_utils.GetTempDir(), + 'shard_status_file') + self.assert_(not os.path.exists(shard_status_file)) + + extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file} + try: + InvokeWithModifiedEnv(extra_env, RunAndReturnOutput) + finally: + self.assert_(os.path.exists(shard_status_file)) + os.remove(shard_status_file) + + def testShardStatusFileIsCreatedWithListTests(self): + """Tests that the shard file is created with the "list_tests" flag.""" + + shard_status_file = os.path.join(gtest_test_utils.GetTempDir(), + 'shard_status_file2') + self.assert_(not os.path.exists(shard_status_file)) + + extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file} + try: + output = InvokeWithModifiedEnv(extra_env, + RunAndReturnOutput, + [LIST_TESTS_FLAG]) + finally: + # This assertion ensures that Google Test enumerated the tests as + # opposed to running them. + self.assert_('[==========]' not in output, + 'Unexpected output during test enumeration.\n' + 'Please ensure that LIST_TESTS_FLAG is assigned the\n' + 'correct flag value for listing Google Test tests.') + + self.assert_(os.path.exists(shard_status_file)) + os.remove(shard_status_file) + + if SUPPORTS_DEATH_TESTS: + def testShardingWorksWithDeathTests(self): + """Tests integration with death tests and sharding.""" + + gtest_filter = 'HasDeathTest.*:SeqP/*' + expected_tests = [ + 'HasDeathTest.Test1', + 'HasDeathTest.Test2', + + 'SeqP/ParamTest.TestX/0', + 'SeqP/ParamTest.TestX/1', + 'SeqP/ParamTest.TestY/0', + 'SeqP/ParamTest.TestY/1', + ] + + for flag in ['--gtest_death_test_style=threadsafe', + '--gtest_death_test_style=fast']: + self.RunAndVerifyWithSharding(gtest_filter, 3, expected_tests, + check_exit_0=True, args=[flag]) + self.RunAndVerifyWithSharding(gtest_filter, 5, expected_tests, + check_exit_0=True, args=[flag]) + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-filter-unittest_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-filter-unittest_.cc new file mode 100644 index 0000000000000000000000000000000000000000..d30ec9c78b565d8e8180173d8fc4e8aefad88aea --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-filter-unittest_.cc @@ -0,0 +1,137 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Unit test for Google Test test filters. +// +// A user can specify which test(s) in a Google Test program to run via +// either the GTEST_FILTER environment variable or the --gtest_filter +// flag. This is used for testing such functionality. +// +// The program will be invoked from a Python unit test. Don't run it +// directly. + +#include "gtest/gtest.h" + +namespace { + +// Test case FooTest. + +class FooTest : public testing::Test { +}; + +TEST_F(FooTest, Abc) { +} + +TEST_F(FooTest, Xyz) { + FAIL() << "Expected failure."; +} + +// Test case BarTest. + +TEST(BarTest, TestOne) { +} + +TEST(BarTest, TestTwo) { +} + +TEST(BarTest, TestThree) { +} + +TEST(BarTest, DISABLED_TestFour) { + FAIL() << "Expected failure."; +} + +TEST(BarTest, DISABLED_TestFive) { + FAIL() << "Expected failure."; +} + +// Test case BazTest. + +TEST(BazTest, TestOne) { + FAIL() << "Expected failure."; +} + +TEST(BazTest, TestA) { +} + +TEST(BazTest, TestB) { +} + +TEST(BazTest, DISABLED_TestC) { + FAIL() << "Expected failure."; +} + +// Test case HasDeathTest + +TEST(HasDeathTest, Test1) { + EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*"); +} + +// We need at least two death tests to make sure that the all death tests +// aren't on the first shard. +TEST(HasDeathTest, Test2) { + EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*"); +} + +// Test case FoobarTest + +TEST(DISABLED_FoobarTest, Test1) { + FAIL() << "Expected failure."; +} + +TEST(DISABLED_FoobarTest, DISABLED_Test2) { + FAIL() << "Expected failure."; +} + +// Test case FoobarbazTest + +TEST(DISABLED_FoobarbazTest, TestA) { + FAIL() << "Expected failure."; +} + +class ParamTest : public testing::TestWithParam { +}; + +TEST_P(ParamTest, TestX) { +} + +TEST_P(ParamTest, TestY) { +} + +INSTANTIATE_TEST_SUITE_P(SeqP, ParamTest, testing::Values(1, 2)); +INSTANTIATE_TEST_SUITE_P(SeqQ, ParamTest, testing::Values(5, 6)); + +} // namespace + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-json-outfiles-test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-json-outfiles-test.py new file mode 100644 index 0000000000000000000000000000000000000000..8ef47b8f97463c2e3ad44225479d3bc06338792c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-json-outfiles-test.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python +# Copyright 2018, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for the gtest_json_output module.""" + +import json +import os +import gtest_json_test_utils +import gtest_test_utils + +GTEST_OUTPUT_SUBDIR = 'json_outfiles' +GTEST_OUTPUT_1_TEST = 'gtest_xml_outfile1_test_' +GTEST_OUTPUT_2_TEST = 'gtest_xml_outfile2_test_' + +EXPECTED_1 = { + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'name': + u'AllTests', + u'testsuites': [{ + u'name': + u'PropertyOne', + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'TestSomeProperties', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'PropertyOne', + u'SetUpProp': u'1', + u'TestSomeProperty': u'1', + u'TearDownProp': u'1', + }], + }], +} + +EXPECTED_2 = { + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'name': + u'AllTests', + u'testsuites': [{ + u'name': + u'PropertyTwo', + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'TestSomeProperties', + u'status': u'RUN', + u'result': u'COMPLETED', + u'timestamp': u'*', + u'time': u'*', + u'classname': u'PropertyTwo', + u'SetUpProp': u'2', + u'TestSomeProperty': u'2', + u'TearDownProp': u'2', + }], + }], +} + + +class GTestJsonOutFilesTest(gtest_test_utils.TestCase): + """Unit test for Google Test's JSON output functionality.""" + + def setUp(self): + # We want the trailing '/' that the last "" provides in os.path.join, for + # telling Google Test to create an output directory instead of a single file + # for xml output. + self.output_dir_ = os.path.join(gtest_test_utils.GetTempDir(), + GTEST_OUTPUT_SUBDIR, '') + self.DeleteFilesAndDir() + + def tearDown(self): + self.DeleteFilesAndDir() + + def DeleteFilesAndDir(self): + try: + os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_1_TEST + '.json')) + except os.error: + pass + try: + os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_2_TEST + '.json')) + except os.error: + pass + try: + os.rmdir(self.output_dir_) + except os.error: + pass + + def testOutfile1(self): + self._TestOutFile(GTEST_OUTPUT_1_TEST, EXPECTED_1) + + def testOutfile2(self): + self._TestOutFile(GTEST_OUTPUT_2_TEST, EXPECTED_2) + + def _TestOutFile(self, test_name, expected): + gtest_prog_path = gtest_test_utils.GetTestExecutablePath(test_name) + command = [gtest_prog_path, '--gtest_output=json:%s' % self.output_dir_] + p = gtest_test_utils.Subprocess(command, + working_dir=gtest_test_utils.GetTempDir()) + self.assert_(p.exited) + self.assertEquals(0, p.exit_code) + + output_file_name1 = test_name + '.json' + output_file1 = os.path.join(self.output_dir_, output_file_name1) + output_file_name2 = 'lt-' + output_file_name1 + output_file2 = os.path.join(self.output_dir_, output_file_name2) + self.assert_(os.path.isfile(output_file1) or os.path.isfile(output_file2), + output_file1) + + if os.path.isfile(output_file1): + with open(output_file1) as f: + actual = json.load(f) + else: + with open(output_file2) as f: + actual = json.load(f) + self.assertEqual(expected, gtest_json_test_utils.normalize(actual)) + + +if __name__ == '__main__': + os.environ['GTEST_STACK_TRACE_DEPTH'] = '0' + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-json-output-unittest.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-json-output-unittest.py new file mode 100644 index 0000000000000000000000000000000000000000..15861f75cbe83d909e25f605ec0bc12df9db0ea8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-json-output-unittest.py @@ -0,0 +1,778 @@ +#!/usr/bin/env python +# Copyright 2018, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for the gtest_json_output module.""" + +import datetime +import errno +import json +import os +import re +import sys + +import gtest_json_test_utils +import gtest_test_utils + +GTEST_FILTER_FLAG = '--gtest_filter' +GTEST_LIST_TESTS_FLAG = '--gtest_list_tests' +GTEST_OUTPUT_FLAG = '--gtest_output' +GTEST_DEFAULT_OUTPUT_FILE = 'test_detail.json' +GTEST_PROGRAM_NAME = 'gtest_xml_output_unittest_' + +# The flag indicating stacktraces are not supported +NO_STACKTRACE_SUPPORT_FLAG = '--no_stacktrace_support' + +SUPPORTS_STACK_TRACES = NO_STACKTRACE_SUPPORT_FLAG not in sys.argv + +if SUPPORTS_STACK_TRACES: + STACK_TRACE_TEMPLATE = '\nStack trace:\n*' +else: + STACK_TRACE_TEMPLATE = '' + +EXPECTED_NON_EMPTY = { + u'tests': + 24, + u'failures': + 4, + u'disabled': + 2, + u'errors': + 0, + u'timestamp': + u'*', + u'time': + u'*', + u'ad_hoc_property': + u'42', + u'name': + u'AllTests', + u'testsuites': [{ + u'name': + u'SuccessfulTest', + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'Succeeds', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'SuccessfulTest' + }] + }, { + u'name': + u'FailedTest', + u'tests': + 1, + u'failures': + 1, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': + u'Fails', + u'status': + u'RUN', + u'result': + u'COMPLETED', + u'time': + u'*', + u'timestamp': + u'*', + u'classname': + u'FailedTest', + u'failures': [{ + u'failure': u'gtest_xml_output_unittest_.cc:*\n' + u'Expected equality of these values:\n' + u' 1\n 2' + STACK_TRACE_TEMPLATE, + u'type': u'' + }] + }] + }, { + u'name': + u'DisabledTest', + u'tests': + 1, + u'failures': + 0, + u'disabled': + 1, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'DISABLED_test_not_run', + u'status': u'NOTRUN', + u'result': u'SUPPRESSED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'DisabledTest' + }] + }, { + u'name': + u'SkippedTest', + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'Skipped', + u'status': u'RUN', + u'result': u'SKIPPED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'SkippedTest' + }] + }, { + u'name': + u'MixedResultTest', + u'tests': + 3, + u'failures': + 1, + u'disabled': + 1, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'Succeeds', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'MixedResultTest' + }, { + u'name': + u'Fails', + u'status': + u'RUN', + u'result': + u'COMPLETED', + u'time': + u'*', + u'timestamp': + u'*', + u'classname': + u'MixedResultTest', + u'failures': [{ + u'failure': u'gtest_xml_output_unittest_.cc:*\n' + u'Expected equality of these values:\n' + u' 1\n 2' + STACK_TRACE_TEMPLATE, + u'type': u'' + }, { + u'failure': u'gtest_xml_output_unittest_.cc:*\n' + u'Expected equality of these values:\n' + u' 2\n 3' + STACK_TRACE_TEMPLATE, + u'type': u'' + }] + }, { + u'name': u'DISABLED_test', + u'status': u'NOTRUN', + u'result': u'SUPPRESSED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'MixedResultTest' + }] + }, { + u'name': + u'XmlQuotingTest', + u'tests': + 1, + u'failures': + 1, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': + u'OutputsCData', + u'status': + u'RUN', + u'result': + u'COMPLETED', + u'time': + u'*', + u'timestamp': + u'*', + u'classname': + u'XmlQuotingTest', + u'failures': [{ + u'failure': u'gtest_xml_output_unittest_.cc:*\n' + u'Failed\nXML output: ' + u'' + + STACK_TRACE_TEMPLATE, + u'type': u'' + }] + }] + }, { + u'name': + u'InvalidCharactersTest', + u'tests': + 1, + u'failures': + 1, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': + u'InvalidCharactersInMessage', + u'status': + u'RUN', + u'result': + u'COMPLETED', + u'time': + u'*', + u'timestamp': + u'*', + u'classname': + u'InvalidCharactersTest', + u'failures': [{ + u'failure': u'gtest_xml_output_unittest_.cc:*\n' + u'Failed\nInvalid characters in brackets' + u' [\x01\x02]' + STACK_TRACE_TEMPLATE, + u'type': u'' + }] + }] + }, { + u'name': + u'PropertyRecordingTest', + u'tests': + 4, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'SetUpTestSuite': + u'yes', + u'TearDownTestSuite': + u'aye', + u'testsuite': [{ + u'name': u'OneProperty', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'PropertyRecordingTest', + u'key_1': u'1' + }, { + u'name': u'IntValuedProperty', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'PropertyRecordingTest', + u'key_int': u'1' + }, { + u'name': u'ThreeProperties', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'PropertyRecordingTest', + u'key_1': u'1', + u'key_2': u'2', + u'key_3': u'3' + }, { + u'name': u'TwoValuesForOneKeyUsesLastValue', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'PropertyRecordingTest', + u'key_1': u'2' + }] + }, { + u'name': + u'NoFixtureTest', + u'tests': + 3, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'RecordProperty', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'NoFixtureTest', + u'key': u'1' + }, { + u'name': u'ExternalUtilityThatCallsRecordIntValuedProperty', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'NoFixtureTest', + u'key_for_utility_int': u'1' + }, { + u'name': u'ExternalUtilityThatCallsRecordStringValuedProperty', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'NoFixtureTest', + u'key_for_utility_string': u'1' + }] + }, { + u'name': + u'TypedTest/0', + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'HasTypeParamAttribute', + u'type_param': u'int', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'TypedTest/0' + }] + }, { + u'name': + u'TypedTest/1', + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'HasTypeParamAttribute', + u'type_param': u'long', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'TypedTest/1' + }] + }, { + u'name': + u'Single/TypeParameterizedTestSuite/0', + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'HasTypeParamAttribute', + u'type_param': u'int', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'Single/TypeParameterizedTestSuite/0' + }] + }, { + u'name': + u'Single/TypeParameterizedTestSuite/1', + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'HasTypeParamAttribute', + u'type_param': u'long', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'Single/TypeParameterizedTestSuite/1' + }] + }, { + u'name': + u'Single/ValueParamTest', + u'tests': + 4, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'HasValueParamAttribute/0', + u'value_param': u'33', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'Single/ValueParamTest' + }, { + u'name': u'HasValueParamAttribute/1', + u'value_param': u'42', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'Single/ValueParamTest' + }, { + u'name': u'AnotherTestThatHasValueParamAttribute/0', + u'value_param': u'33', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'Single/ValueParamTest' + }, { + u'name': u'AnotherTestThatHasValueParamAttribute/1', + u'value_param': u'42', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'Single/ValueParamTest' + }] + }] +} + +EXPECTED_FILTERED = { + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'name': + u'AllTests', + u'ad_hoc_property': + u'42', + u'testsuites': [{ + u'name': + u'SuccessfulTest', + u'tests': + 1, + u'failures': + 0, + u'disabled': + 0, + u'errors': + 0, + u'time': + u'*', + u'timestamp': + u'*', + u'testsuite': [{ + u'name': u'Succeeds', + u'status': u'RUN', + u'result': u'COMPLETED', + u'time': u'*', + u'timestamp': u'*', + u'classname': u'SuccessfulTest', + }] + }], +} + +EXPECTED_EMPTY = { + u'tests': 0, + u'failures': 0, + u'disabled': 0, + u'errors': 0, + u'time': u'*', + u'timestamp': u'*', + u'name': u'AllTests', + u'testsuites': [], +} + +GTEST_PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME) + +SUPPORTS_TYPED_TESTS = 'TypedTest' in gtest_test_utils.Subprocess( + [GTEST_PROGRAM_PATH, GTEST_LIST_TESTS_FLAG], capture_stderr=False).output + + +class GTestJsonOutputUnitTest(gtest_test_utils.TestCase): + """Unit test for Google Test's JSON output functionality. + """ + + # This test currently breaks on platforms that do not support typed and + # type-parameterized tests, so we don't run it under them. + if SUPPORTS_TYPED_TESTS: + + def testNonEmptyJsonOutput(self): + """Verifies JSON output for a Google Test binary with non-empty output. + + Runs a test program that generates a non-empty JSON output, and + tests that the JSON output is expected. + """ + self._TestJsonOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY, 1) + + def testEmptyJsonOutput(self): + """Verifies JSON output for a Google Test binary without actual tests. + + Runs a test program that generates an empty JSON output, and + tests that the JSON output is expected. + """ + + self._TestJsonOutput('gtest_no_test_unittest', EXPECTED_EMPTY, 0) + + def testTimestampValue(self): + """Checks whether the timestamp attribute in the JSON output is valid. + + Runs a test program that generates an empty JSON output, and checks if + the timestamp attribute in the testsuites tag is valid. + """ + actual = self._GetJsonOutput('gtest_no_test_unittest', [], 0) + date_time_str = actual['timestamp'] + # datetime.strptime() is only available in Python 2.5+ so we have to + # parse the expected datetime manually. + match = re.match(r'(\d+)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)', date_time_str) + self.assertTrue( + re.match, + 'JSON datettime string %s has incorrect format' % date_time_str) + date_time_from_json = datetime.datetime( + year=int(match.group(1)), month=int(match.group(2)), + day=int(match.group(3)), hour=int(match.group(4)), + minute=int(match.group(5)), second=int(match.group(6))) + + time_delta = abs(datetime.datetime.now() - date_time_from_json) + # timestamp value should be near the current local time + self.assertTrue(time_delta < datetime.timedelta(seconds=600), + 'time_delta is %s' % time_delta) + + def testDefaultOutputFile(self): + """Verifies the default output file name. + + Confirms that Google Test produces an JSON output file with the expected + default name if no name is explicitly specified. + """ + output_file = os.path.join(gtest_test_utils.GetTempDir(), + GTEST_DEFAULT_OUTPUT_FILE) + gtest_prog_path = gtest_test_utils.GetTestExecutablePath( + 'gtest_no_test_unittest') + try: + os.remove(output_file) + except OSError: + e = sys.exc_info()[1] + if e.errno != errno.ENOENT: + raise + + p = gtest_test_utils.Subprocess( + [gtest_prog_path, '%s=json' % GTEST_OUTPUT_FLAG], + working_dir=gtest_test_utils.GetTempDir()) + self.assert_(p.exited) + self.assertEquals(0, p.exit_code) + self.assert_(os.path.isfile(output_file)) + + def testSuppressedJsonOutput(self): + """Verifies that no JSON output is generated. + + Tests that no JSON file is generated if the default JSON listener is + shut down before RUN_ALL_TESTS is invoked. + """ + + json_path = os.path.join(gtest_test_utils.GetTempDir(), + GTEST_PROGRAM_NAME + 'out.json') + if os.path.isfile(json_path): + os.remove(json_path) + + command = [GTEST_PROGRAM_PATH, + '%s=json:%s' % (GTEST_OUTPUT_FLAG, json_path), + '--shut_down_xml'] + p = gtest_test_utils.Subprocess(command) + if p.terminated_by_signal: + # p.signal is available only if p.terminated_by_signal is True. + self.assertFalse( + p.terminated_by_signal, + '%s was killed by signal %d' % (GTEST_PROGRAM_NAME, p.signal)) + else: + self.assert_(p.exited) + self.assertEquals(1, p.exit_code, + "'%s' exited with code %s, which doesn't match " + 'the expected exit code %s.' + % (command, p.exit_code, 1)) + + self.assert_(not os.path.isfile(json_path)) + + def testFilteredTestJsonOutput(self): + """Verifies JSON output when a filter is applied. + + Runs a test program that executes only some tests and verifies that + non-selected tests do not show up in the JSON output. + """ + + self._TestJsonOutput(GTEST_PROGRAM_NAME, EXPECTED_FILTERED, 0, + extra_args=['%s=SuccessfulTest.*' % GTEST_FILTER_FLAG]) + + def _GetJsonOutput(self, gtest_prog_name, extra_args, expected_exit_code): + """Returns the JSON output generated by running the program gtest_prog_name. + + Furthermore, the program's exit code must be expected_exit_code. + + Args: + gtest_prog_name: Google Test binary name. + extra_args: extra arguments to binary invocation. + expected_exit_code: program's exit code. + """ + json_path = os.path.join(gtest_test_utils.GetTempDir(), + gtest_prog_name + 'out.json') + gtest_prog_path = gtest_test_utils.GetTestExecutablePath(gtest_prog_name) + + command = ( + [gtest_prog_path, '%s=json:%s' % (GTEST_OUTPUT_FLAG, json_path)] + + extra_args + ) + p = gtest_test_utils.Subprocess(command) + if p.terminated_by_signal: + self.assert_(False, + '%s was killed by signal %d' % (gtest_prog_name, p.signal)) + else: + self.assert_(p.exited) + self.assertEquals(expected_exit_code, p.exit_code, + "'%s' exited with code %s, which doesn't match " + 'the expected exit code %s.' + % (command, p.exit_code, expected_exit_code)) + with open(json_path) as f: + actual = json.load(f) + return actual + + def _TestJsonOutput(self, gtest_prog_name, expected, + expected_exit_code, extra_args=None): + """Checks the JSON output generated by the Google Test binary. + + Asserts that the JSON document generated by running the program + gtest_prog_name matches expected_json, a string containing another + JSON document. Furthermore, the program's exit code must be + expected_exit_code. + + Args: + gtest_prog_name: Google Test binary name. + expected: expected output. + expected_exit_code: program's exit code. + extra_args: extra arguments to binary invocation. + """ + + actual = self._GetJsonOutput(gtest_prog_name, extra_args or [], + expected_exit_code) + self.assertEqual(expected, gtest_json_test_utils.normalize(actual)) + + +if __name__ == '__main__': + if NO_STACKTRACE_SUPPORT_FLAG in sys.argv: + # unittest.main() can't handle unknown flags + sys.argv.remove(NO_STACKTRACE_SUPPORT_FLAG) + + os.environ['GTEST_STACK_TRACE_DEPTH'] = '1' + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-list-tests-unittest.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-list-tests-unittest.py new file mode 100755 index 0000000000000000000000000000000000000000..81423a339e8fd28aa2b4253013b3c23ce3533749 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-list-tests-unittest.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python +# +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for Google Test's --gtest_list_tests flag. + +A user can ask Google Test to list all tests by specifying the +--gtest_list_tests flag. This script tests such functionality +by invoking googletest-list-tests-unittest_ (a program written with +Google Test) the command line flags. +""" + +import re +import gtest_test_utils + +# Constants. + +# The command line flag for enabling/disabling listing all tests. +LIST_TESTS_FLAG = 'gtest_list_tests' + +# Path to the googletest-list-tests-unittest_ program. +EXE_PATH = gtest_test_utils.GetTestExecutablePath('googletest-list-tests-unittest_') + +# The expected output when running googletest-list-tests-unittest_ with +# --gtest_list_tests +EXPECTED_OUTPUT_NO_FILTER_RE = re.compile(r"""FooDeathTest\. + Test1 +Foo\. + Bar1 + Bar2 + DISABLED_Bar3 +Abc\. + Xyz + Def +FooBar\. + Baz +FooTest\. + Test1 + DISABLED_Test2 + Test3 +TypedTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\. + TestA + TestB +TypedTest/1\. # TypeParam = int\s*\*( __ptr64)? + TestA + TestB +TypedTest/2\. # TypeParam = .*MyArray + TestA + TestB +My/TypeParamTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\. + TestA + TestB +My/TypeParamTest/1\. # TypeParam = int\s*\*( __ptr64)? + TestA + TestB +My/TypeParamTest/2\. # TypeParam = .*MyArray + TestA + TestB +MyInstantiation/ValueParamTest\. + TestA/0 # GetParam\(\) = one line + TestA/1 # GetParam\(\) = two\\nlines + TestA/2 # GetParam\(\) = a very\\nlo{241}\.\.\. + TestB/0 # GetParam\(\) = one line + TestB/1 # GetParam\(\) = two\\nlines + TestB/2 # GetParam\(\) = a very\\nlo{241}\.\.\. +""") + +# The expected output when running googletest-list-tests-unittest_ with +# --gtest_list_tests and --gtest_filter=Foo*. +EXPECTED_OUTPUT_FILTER_FOO_RE = re.compile(r"""FooDeathTest\. + Test1 +Foo\. + Bar1 + Bar2 + DISABLED_Bar3 +FooBar\. + Baz +FooTest\. + Test1 + DISABLED_Test2 + Test3 +""") + +# Utilities. + + +def Run(args): + """Runs googletest-list-tests-unittest_ and returns the list of tests printed.""" + + return gtest_test_utils.Subprocess([EXE_PATH] + args, + capture_stderr=False).output + + +# The unit test. + + +class GTestListTestsUnitTest(gtest_test_utils.TestCase): + """Tests using the --gtest_list_tests flag to list all tests.""" + + def RunAndVerify(self, flag_value, expected_output_re, other_flag): + """Runs googletest-list-tests-unittest_ and verifies that it prints + the correct tests. + + Args: + flag_value: value of the --gtest_list_tests flag; + None if the flag should not be present. + expected_output_re: regular expression that matches the expected + output after running command; + other_flag: a different flag to be passed to command + along with gtest_list_tests; + None if the flag should not be present. + """ + + if flag_value is None: + flag = '' + flag_expression = 'not set' + elif flag_value == '0': + flag = '--%s=0' % LIST_TESTS_FLAG + flag_expression = '0' + else: + flag = '--%s' % LIST_TESTS_FLAG + flag_expression = '1' + + args = [flag] + + if other_flag is not None: + args += [other_flag] + + output = Run(args) + + if expected_output_re: + self.assert_( + expected_output_re.match(output), + ('when %s is %s, the output of "%s" is "%s",\n' + 'which does not match regex "%s"' % + (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output, + expected_output_re.pattern))) + else: + self.assert_( + not EXPECTED_OUTPUT_NO_FILTER_RE.match(output), + ('when %s is %s, the output of "%s" is "%s"'% + (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output))) + + def testDefaultBehavior(self): + """Tests the behavior of the default mode.""" + + self.RunAndVerify(flag_value=None, + expected_output_re=None, + other_flag=None) + + def testFlag(self): + """Tests using the --gtest_list_tests flag.""" + + self.RunAndVerify(flag_value='0', + expected_output_re=None, + other_flag=None) + self.RunAndVerify(flag_value='1', + expected_output_re=EXPECTED_OUTPUT_NO_FILTER_RE, + other_flag=None) + + def testOverrideNonFilterFlags(self): + """Tests that --gtest_list_tests overrides the non-filter flags.""" + + self.RunAndVerify(flag_value='1', + expected_output_re=EXPECTED_OUTPUT_NO_FILTER_RE, + other_flag='--gtest_break_on_failure') + + def testWithFilterFlags(self): + """Tests that --gtest_list_tests takes into account the + --gtest_filter flag.""" + + self.RunAndVerify(flag_value='1', + expected_output_re=EXPECTED_OUTPUT_FILTER_FOO_RE, + other_flag='--gtest_filter=Foo*') + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-list-tests-unittest_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-list-tests-unittest_.cc new file mode 100644 index 0000000000000000000000000000000000000000..493c6f00464a90d635d8df096bffec5173e6e44d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-list-tests-unittest_.cc @@ -0,0 +1,156 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Unit test for Google Test's --gtest_list_tests flag. +// +// A user can ask Google Test to list all tests that will run +// so that when using a filter, a user will know what +// tests to look for. The tests will not be run after listing. +// +// This program will be invoked from a Python unit test. +// Don't run it directly. + +#include "gtest/gtest.h" + +// Several different test cases and tests that will be listed. +TEST(Foo, Bar1) { +} + +TEST(Foo, Bar2) { +} + +TEST(Foo, DISABLED_Bar3) { +} + +TEST(Abc, Xyz) { +} + +TEST(Abc, Def) { +} + +TEST(FooBar, Baz) { +} + +class FooTest : public testing::Test { +}; + +TEST_F(FooTest, Test1) { +} + +TEST_F(FooTest, DISABLED_Test2) { +} + +TEST_F(FooTest, Test3) { +} + +TEST(FooDeathTest, Test1) { +} + +// A group of value-parameterized tests. + +class MyType { + public: + explicit MyType(const std::string& a_value) : value_(a_value) {} + + const std::string& value() const { return value_; } + + private: + std::string value_; +}; + +// Teaches Google Test how to print a MyType. +void PrintTo(const MyType& x, std::ostream* os) { + *os << x.value(); +} + +class ValueParamTest : public testing::TestWithParam { +}; + +TEST_P(ValueParamTest, TestA) { +} + +TEST_P(ValueParamTest, TestB) { +} + +INSTANTIATE_TEST_SUITE_P( + MyInstantiation, ValueParamTest, + testing::Values(MyType("one line"), + MyType("two\nlines"), + MyType("a very\nloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line"))); // NOLINT + +// A group of typed tests. + +// A deliberately long type name for testing the line-truncating +// behavior when printing a type parameter. +class VeryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooogName { // NOLINT +}; + +template +class TypedTest : public testing::Test { +}; + +template +class MyArray { +}; + +typedef testing::Types > MyTypes; + +TYPED_TEST_SUITE(TypedTest, MyTypes); + +TYPED_TEST(TypedTest, TestA) { +} + +TYPED_TEST(TypedTest, TestB) { +} + +// A group of type-parameterized tests. + +template +class TypeParamTest : public testing::Test { +}; + +TYPED_TEST_SUITE_P(TypeParamTest); + +TYPED_TEST_P(TypeParamTest, TestA) { +} + +TYPED_TEST_P(TypeParamTest, TestB) { +} + +REGISTER_TYPED_TEST_SUITE_P(TypeParamTest, TestA, TestB); + +INSTANTIATE_TYPED_TEST_SUITE_P(My, TypeParamTest, MyTypes); + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-listener-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-listener-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..10457afe39a7dbd1fa0f733928678728dcd1b955 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-listener-test.cc @@ -0,0 +1,518 @@ +// Copyright 2009 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file verifies Google Test event listeners receive events at the +// right times. + +#include + +#include "gtest/gtest.h" +#include "gtest/internal/custom/gtest.h" + +using ::testing::AddGlobalTestEnvironment; +using ::testing::Environment; +using ::testing::InitGoogleTest; +using ::testing::Test; +using ::testing::TestSuite; +using ::testing::TestEventListener; +using ::testing::TestInfo; +using ::testing::TestPartResult; +using ::testing::UnitTest; + +// Used by tests to register their events. +std::vector* g_events = nullptr; + +namespace testing { +namespace internal { + +class EventRecordingListener : public TestEventListener { + public: + explicit EventRecordingListener(const char* name) : name_(name) {} + + protected: + void OnTestProgramStart(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnTestProgramStart")); + } + + void OnTestIterationStart(const UnitTest& /*unit_test*/, + int iteration) override { + Message message; + message << GetFullMethodName("OnTestIterationStart") + << "(" << iteration << ")"; + g_events->push_back(message.GetString()); + } + + void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpStart")); + } + + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpEnd")); + } +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase& /*test_case*/) override { + g_events->push_back(GetFullMethodName("OnTestCaseStart")); + } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnTestStart(const TestInfo& /*test_info*/) override { + g_events->push_back(GetFullMethodName("OnTestStart")); + } + + void OnTestPartResult(const TestPartResult& /*test_part_result*/) override { + g_events->push_back(GetFullMethodName("OnTestPartResult")); + } + + void OnTestEnd(const TestInfo& /*test_info*/) override { + g_events->push_back(GetFullMethodName("OnTestEnd")); + } + +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& /*test_case*/) override { + g_events->push_back(GetFullMethodName("OnTestCaseEnd")); + } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownStart")); + } + + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownEnd")); + } + + void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int iteration) override { + Message message; + message << GetFullMethodName("OnTestIterationEnd") + << "(" << iteration << ")"; + g_events->push_back(message.GetString()); + } + + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnTestProgramEnd")); + } + + private: + std::string GetFullMethodName(const char* name) { + return name_ + "." + name; + } + + std::string name_; +}; + +// This listener is using OnTestSuiteStart, OnTestSuiteEnd API +class EventRecordingListener2 : public TestEventListener { + public: + explicit EventRecordingListener2(const char* name) : name_(name) {} + + protected: + void OnTestProgramStart(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnTestProgramStart")); + } + + void OnTestIterationStart(const UnitTest& /*unit_test*/, + int iteration) override { + Message message; + message << GetFullMethodName("OnTestIterationStart") << "(" << iteration + << ")"; + g_events->push_back(message.GetString()); + } + + void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpStart")); + } + + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpEnd")); + } + + void OnTestSuiteStart(const TestSuite& /*test_suite*/) override { + g_events->push_back(GetFullMethodName("OnTestSuiteStart")); + } + + void OnTestStart(const TestInfo& /*test_info*/) override { + g_events->push_back(GetFullMethodName("OnTestStart")); + } + + void OnTestPartResult(const TestPartResult& /*test_part_result*/) override { + g_events->push_back(GetFullMethodName("OnTestPartResult")); + } + + void OnTestEnd(const TestInfo& /*test_info*/) override { + g_events->push_back(GetFullMethodName("OnTestEnd")); + } + + void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override { + g_events->push_back(GetFullMethodName("OnTestSuiteEnd")); + } + + void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownStart")); + } + + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownEnd")); + } + + void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int iteration) override { + Message message; + message << GetFullMethodName("OnTestIterationEnd") << "(" << iteration + << ")"; + g_events->push_back(message.GetString()); + } + + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override { + g_events->push_back(GetFullMethodName("OnTestProgramEnd")); + } + + private: + std::string GetFullMethodName(const char* name) { return name_ + "." + name; } + + std::string name_; +}; + +class EnvironmentInvocationCatcher : public Environment { + protected: + void SetUp() override { g_events->push_back("Environment::SetUp"); } + + void TearDown() override { g_events->push_back("Environment::TearDown"); } +}; + +class ListenerTest : public Test { + protected: + static void SetUpTestSuite() { + g_events->push_back("ListenerTest::SetUpTestSuite"); + } + + static void TearDownTestSuite() { + g_events->push_back("ListenerTest::TearDownTestSuite"); + } + + void SetUp() override { g_events->push_back("ListenerTest::SetUp"); } + + void TearDown() override { g_events->push_back("ListenerTest::TearDown"); } +}; + +TEST_F(ListenerTest, DoesFoo) { + // Test execution order within a test case is not guaranteed so we are not + // recording the test name. + g_events->push_back("ListenerTest::* Test Body"); + SUCCEED(); // Triggers OnTestPartResult. +} + +TEST_F(ListenerTest, DoesBar) { + g_events->push_back("ListenerTest::* Test Body"); + SUCCEED(); // Triggers OnTestPartResult. +} + +} // namespace internal + +} // namespace testing + +using ::testing::internal::EnvironmentInvocationCatcher; +using ::testing::internal::EventRecordingListener; +using ::testing::internal::EventRecordingListener2; + +void VerifyResults(const std::vector& data, + const char* const* expected_data, + size_t expected_data_size) { + const size_t actual_size = data.size(); + // If the following assertion fails, a new entry will be appended to + // data. Hence we save data.size() first. + EXPECT_EQ(expected_data_size, actual_size); + + // Compares the common prefix. + const size_t shorter_size = expected_data_size <= actual_size ? + expected_data_size : actual_size; + size_t i = 0; + for (; i < shorter_size; ++i) { + ASSERT_STREQ(expected_data[i], data[i].c_str()) + << "at position " << i; + } + + // Prints extra elements in the actual data. + for (; i < actual_size; ++i) { + printf(" Actual event #%lu: %s\n", + static_cast(i), data[i].c_str()); + } +} + +int main(int argc, char **argv) { + std::vector events; + g_events = &events; + InitGoogleTest(&argc, argv); + + UnitTest::GetInstance()->listeners().Append( + new EventRecordingListener("1st")); + UnitTest::GetInstance()->listeners().Append( + new EventRecordingListener("2nd")); + UnitTest::GetInstance()->listeners().Append( + new EventRecordingListener2("3rd")); + + AddGlobalTestEnvironment(new EnvironmentInvocationCatcher); + + GTEST_CHECK_(events.size() == 0) + << "AddGlobalTestEnvironment should not generate any events itself."; + + ::testing::GTEST_FLAG(repeat) = 2; + int ret_val = RUN_ALL_TESTS(); + +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // The deprecated OnTestSuiteStart/OnTestCaseStart events are included + const char* const expected_events[] = {"1st.OnTestProgramStart", + "2nd.OnTestProgramStart", + "3rd.OnTestProgramStart", + "1st.OnTestIterationStart(0)", + "2nd.OnTestIterationStart(0)", + "3rd.OnTestIterationStart(0)", + "1st.OnEnvironmentsSetUpStart", + "2nd.OnEnvironmentsSetUpStart", + "3rd.OnEnvironmentsSetUpStart", + "Environment::SetUp", + "3rd.OnEnvironmentsSetUpEnd", + "2nd.OnEnvironmentsSetUpEnd", + "1st.OnEnvironmentsSetUpEnd", + "3rd.OnTestSuiteStart", + "1st.OnTestCaseStart", + "2nd.OnTestCaseStart", + "ListenerTest::SetUpTestSuite", + "1st.OnTestStart", + "2nd.OnTestStart", + "3rd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "3rd.OnTestPartResult", + "ListenerTest::TearDown", + "3rd.OnTestEnd", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "1st.OnTestStart", + "2nd.OnTestStart", + "3rd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "3rd.OnTestPartResult", + "ListenerTest::TearDown", + "3rd.OnTestEnd", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "ListenerTest::TearDownTestSuite", + "3rd.OnTestSuiteEnd", + "2nd.OnTestCaseEnd", + "1st.OnTestCaseEnd", + "1st.OnEnvironmentsTearDownStart", + "2nd.OnEnvironmentsTearDownStart", + "3rd.OnEnvironmentsTearDownStart", + "Environment::TearDown", + "3rd.OnEnvironmentsTearDownEnd", + "2nd.OnEnvironmentsTearDownEnd", + "1st.OnEnvironmentsTearDownEnd", + "3rd.OnTestIterationEnd(0)", + "2nd.OnTestIterationEnd(0)", + "1st.OnTestIterationEnd(0)", + "1st.OnTestIterationStart(1)", + "2nd.OnTestIterationStart(1)", + "3rd.OnTestIterationStart(1)", + "1st.OnEnvironmentsSetUpStart", + "2nd.OnEnvironmentsSetUpStart", + "3rd.OnEnvironmentsSetUpStart", + "Environment::SetUp", + "3rd.OnEnvironmentsSetUpEnd", + "2nd.OnEnvironmentsSetUpEnd", + "1st.OnEnvironmentsSetUpEnd", + "3rd.OnTestSuiteStart", + "1st.OnTestCaseStart", + "2nd.OnTestCaseStart", + "ListenerTest::SetUpTestSuite", + "1st.OnTestStart", + "2nd.OnTestStart", + "3rd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "3rd.OnTestPartResult", + "ListenerTest::TearDown", + "3rd.OnTestEnd", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "1st.OnTestStart", + "2nd.OnTestStart", + "3rd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "3rd.OnTestPartResult", + "ListenerTest::TearDown", + "3rd.OnTestEnd", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "ListenerTest::TearDownTestSuite", + "3rd.OnTestSuiteEnd", + "2nd.OnTestCaseEnd", + "1st.OnTestCaseEnd", + "1st.OnEnvironmentsTearDownStart", + "2nd.OnEnvironmentsTearDownStart", + "3rd.OnEnvironmentsTearDownStart", + "Environment::TearDown", + "3rd.OnEnvironmentsTearDownEnd", + "2nd.OnEnvironmentsTearDownEnd", + "1st.OnEnvironmentsTearDownEnd", + "3rd.OnTestIterationEnd(1)", + "2nd.OnTestIterationEnd(1)", + "1st.OnTestIterationEnd(1)", + "3rd.OnTestProgramEnd", + "2nd.OnTestProgramEnd", + "1st.OnTestProgramEnd"}; +#else + const char* const expected_events[] = {"1st.OnTestProgramStart", + "2nd.OnTestProgramStart", + "3rd.OnTestProgramStart", + "1st.OnTestIterationStart(0)", + "2nd.OnTestIterationStart(0)", + "3rd.OnTestIterationStart(0)", + "1st.OnEnvironmentsSetUpStart", + "2nd.OnEnvironmentsSetUpStart", + "3rd.OnEnvironmentsSetUpStart", + "Environment::SetUp", + "3rd.OnEnvironmentsSetUpEnd", + "2nd.OnEnvironmentsSetUpEnd", + "1st.OnEnvironmentsSetUpEnd", + "3rd.OnTestSuiteStart", + "ListenerTest::SetUpTestSuite", + "1st.OnTestStart", + "2nd.OnTestStart", + "3rd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "3rd.OnTestPartResult", + "ListenerTest::TearDown", + "3rd.OnTestEnd", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "1st.OnTestStart", + "2nd.OnTestStart", + "3rd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "3rd.OnTestPartResult", + "ListenerTest::TearDown", + "3rd.OnTestEnd", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "ListenerTest::TearDownTestSuite", + "3rd.OnTestSuiteEnd", + "1st.OnEnvironmentsTearDownStart", + "2nd.OnEnvironmentsTearDownStart", + "3rd.OnEnvironmentsTearDownStart", + "Environment::TearDown", + "3rd.OnEnvironmentsTearDownEnd", + "2nd.OnEnvironmentsTearDownEnd", + "1st.OnEnvironmentsTearDownEnd", + "3rd.OnTestIterationEnd(0)", + "2nd.OnTestIterationEnd(0)", + "1st.OnTestIterationEnd(0)", + "1st.OnTestIterationStart(1)", + "2nd.OnTestIterationStart(1)", + "3rd.OnTestIterationStart(1)", + "1st.OnEnvironmentsSetUpStart", + "2nd.OnEnvironmentsSetUpStart", + "3rd.OnEnvironmentsSetUpStart", + "Environment::SetUp", + "3rd.OnEnvironmentsSetUpEnd", + "2nd.OnEnvironmentsSetUpEnd", + "1st.OnEnvironmentsSetUpEnd", + "3rd.OnTestSuiteStart", + "ListenerTest::SetUpTestSuite", + "1st.OnTestStart", + "2nd.OnTestStart", + "3rd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "3rd.OnTestPartResult", + "ListenerTest::TearDown", + "3rd.OnTestEnd", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "1st.OnTestStart", + "2nd.OnTestStart", + "3rd.OnTestStart", + "ListenerTest::SetUp", + "ListenerTest::* Test Body", + "1st.OnTestPartResult", + "2nd.OnTestPartResult", + "3rd.OnTestPartResult", + "ListenerTest::TearDown", + "3rd.OnTestEnd", + "2nd.OnTestEnd", + "1st.OnTestEnd", + "ListenerTest::TearDownTestSuite", + "3rd.OnTestSuiteEnd", + "1st.OnEnvironmentsTearDownStart", + "2nd.OnEnvironmentsTearDownStart", + "3rd.OnEnvironmentsTearDownStart", + "Environment::TearDown", + "3rd.OnEnvironmentsTearDownEnd", + "2nd.OnEnvironmentsTearDownEnd", + "1st.OnEnvironmentsTearDownEnd", + "3rd.OnTestIterationEnd(1)", + "2nd.OnTestIterationEnd(1)", + "1st.OnTestIterationEnd(1)", + "3rd.OnTestProgramEnd", + "2nd.OnTestProgramEnd", + "1st.OnTestProgramEnd"}; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + VerifyResults(events, + expected_events, + sizeof(expected_events)/sizeof(expected_events[0])); + + // We need to check manually for ad hoc test failures that happen after + // RUN_ALL_TESTS finishes. + if (UnitTest::GetInstance()->Failed()) + ret_val = 1; + + return ret_val; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-message-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-message-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..962d519114e6e4e3dc3df19fde7545571bc031bc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-message-test.cc @@ -0,0 +1,158 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Tests for the Message class. + +#include "gtest/gtest-message.h" + +#include "gtest/gtest.h" + +namespace { + +using ::testing::Message; + +// Tests the testing::Message class + +// Tests the default constructor. +TEST(MessageTest, DefaultConstructor) { + const Message msg; + EXPECT_EQ("", msg.GetString()); +} + +// Tests the copy constructor. +TEST(MessageTest, CopyConstructor) { + const Message msg1("Hello"); + const Message msg2(msg1); + EXPECT_EQ("Hello", msg2.GetString()); +} + +// Tests constructing a Message from a C-string. +TEST(MessageTest, ConstructsFromCString) { + Message msg("Hello"); + EXPECT_EQ("Hello", msg.GetString()); +} + +// Tests streaming a float. +TEST(MessageTest, StreamsFloat) { + const std::string s = (Message() << 1.23456F << " " << 2.34567F).GetString(); + // Both numbers should be printed with enough precision. + EXPECT_PRED_FORMAT2(testing::IsSubstring, "1.234560", s.c_str()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, " 2.345669", s.c_str()); +} + +// Tests streaming a double. +TEST(MessageTest, StreamsDouble) { + const std::string s = (Message() << 1260570880.4555497 << " " + << 1260572265.1954534).GetString(); + // Both numbers should be printed with enough precision. + EXPECT_PRED_FORMAT2(testing::IsSubstring, "1260570880.45", s.c_str()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, " 1260572265.19", s.c_str()); +} + +// Tests streaming a non-char pointer. +TEST(MessageTest, StreamsPointer) { + int n = 0; + int* p = &n; + EXPECT_NE("(null)", (Message() << p).GetString()); +} + +// Tests streaming a NULL non-char pointer. +TEST(MessageTest, StreamsNullPointer) { + int* p = nullptr; + EXPECT_EQ("(null)", (Message() << p).GetString()); +} + +// Tests streaming a C string. +TEST(MessageTest, StreamsCString) { + EXPECT_EQ("Foo", (Message() << "Foo").GetString()); +} + +// Tests streaming a NULL C string. +TEST(MessageTest, StreamsNullCString) { + char* p = nullptr; + EXPECT_EQ("(null)", (Message() << p).GetString()); +} + +// Tests streaming std::string. +TEST(MessageTest, StreamsString) { + const ::std::string str("Hello"); + EXPECT_EQ("Hello", (Message() << str).GetString()); +} + +// Tests that we can output strings containing embedded NULs. +TEST(MessageTest, StreamsStringWithEmbeddedNUL) { + const char char_array_with_nul[] = + "Here's a NUL\0 and some more string"; + const ::std::string string_with_nul(char_array_with_nul, + sizeof(char_array_with_nul) - 1); + EXPECT_EQ("Here's a NUL\\0 and some more string", + (Message() << string_with_nul).GetString()); +} + +// Tests streaming a NUL char. +TEST(MessageTest, StreamsNULChar) { + EXPECT_EQ("\\0", (Message() << '\0').GetString()); +} + +// Tests streaming int. +TEST(MessageTest, StreamsInt) { + EXPECT_EQ("123", (Message() << 123).GetString()); +} + +// Tests that basic IO manipulators (endl, ends, and flush) can be +// streamed to Message. +TEST(MessageTest, StreamsBasicIoManip) { + EXPECT_EQ("Line 1.\nA NUL char \\0 in line 2.", + (Message() << "Line 1." << std::endl + << "A NUL char " << std::ends << std::flush + << " in line 2.").GetString()); +} + +// Tests Message::GetString() +TEST(MessageTest, GetString) { + Message msg; + msg << 1 << " lamb"; + EXPECT_EQ("1 lamb", msg.GetString()); +} + +// Tests streaming a Message object to an ostream. +TEST(MessageTest, StreamsToOStream) { + Message msg("Hello"); + ::std::stringstream ss; + ss << msg; + EXPECT_EQ("Hello", testing::internal::StringStreamToString(&ss)); +} + +// Tests that a Message object doesn't take up too much stack space. +TEST(MessageTest, DoesNotTakeUpMuchStackSpace) { + EXPECT_LE(sizeof(Message), 16U); +} + +} // namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-options-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-options-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..f07b316db3b94105303b2275eb3f9dc6d111908c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-options-test.cc @@ -0,0 +1,216 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Google Test UnitTestOptions tests +// +// This file tests classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included from gtest.cc, to avoid changing build or +// make-files on Windows and other platforms. Do not #include this file +// anywhere else! + +#include "gtest/gtest.h" + +#if GTEST_OS_WINDOWS_MOBILE +# include +#elif GTEST_OS_WINDOWS +# include +#endif // GTEST_OS_WINDOWS_MOBILE + +#include "src/gtest-internal-inl.h" + +namespace testing { +namespace internal { +namespace { + +// Turns the given relative path into an absolute path. +FilePath GetAbsolutePathOf(const FilePath& relative_path) { + return FilePath::ConcatPaths(FilePath::GetCurrentDir(), relative_path); +} + +// Testing UnitTestOptions::GetOutputFormat/GetOutputFile. + +TEST(XmlOutputTest, GetOutputFormatDefault) { + GTEST_FLAG(output) = ""; + EXPECT_STREQ("", UnitTestOptions::GetOutputFormat().c_str()); +} + +TEST(XmlOutputTest, GetOutputFormat) { + GTEST_FLAG(output) = "xml:filename"; + EXPECT_STREQ("xml", UnitTestOptions::GetOutputFormat().c_str()); +} + +TEST(XmlOutputTest, GetOutputFileDefault) { + GTEST_FLAG(output) = ""; + EXPECT_EQ(GetAbsolutePathOf(FilePath("test_detail.xml")).string(), + UnitTestOptions::GetAbsolutePathToOutputFile()); +} + +TEST(XmlOutputTest, GetOutputFileSingleFile) { + GTEST_FLAG(output) = "xml:filename.abc"; + EXPECT_EQ(GetAbsolutePathOf(FilePath("filename.abc")).string(), + UnitTestOptions::GetAbsolutePathToOutputFile()); +} + +TEST(XmlOutputTest, GetOutputFileFromDirectoryPath) { + GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_; + const std::string expected_output_file = + GetAbsolutePathOf( + FilePath(std::string("path") + GTEST_PATH_SEP_ + + GetCurrentExecutableName().string() + ".xml")).string(); + const std::string& output_file = + UnitTestOptions::GetAbsolutePathToOutputFile(); +#if GTEST_OS_WINDOWS + EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); +#else + EXPECT_EQ(expected_output_file, output_file.c_str()); +#endif +} + +TEST(OutputFileHelpersTest, GetCurrentExecutableName) { + const std::string exe_str = GetCurrentExecutableName().string(); +#if GTEST_OS_WINDOWS + const bool success = + _strcmpi("googletest-options-test", exe_str.c_str()) == 0 || + _strcmpi("gtest-options-ex_test", exe_str.c_str()) == 0 || + _strcmpi("gtest_all_test", exe_str.c_str()) == 0 || + _strcmpi("gtest_dll_test", exe_str.c_str()) == 0; +#elif GTEST_OS_OS2 + const bool success = + strcasecmp("googletest-options-test", exe_str.c_str()) == 0 || + strcasecmp("gtest-options-ex_test", exe_str.c_str()) == 0 || + strcasecmp("gtest_all_test", exe_str.c_str()) == 0 || + strcasecmp("gtest_dll_test", exe_str.c_str()) == 0; +#elif GTEST_OS_FUCHSIA + const bool success = exe_str == "app"; +#else + const bool success = + exe_str == "googletest-options-test" || + exe_str == "gtest_all_test" || + exe_str == "lt-gtest_all_test" || + exe_str == "gtest_dll_test"; +#endif // GTEST_OS_WINDOWS + if (!success) + FAIL() << "GetCurrentExecutableName() returns " << exe_str; +} + +#if !GTEST_OS_FUCHSIA + +class XmlOutputChangeDirTest : public Test { + protected: + void SetUp() override { + original_working_dir_ = FilePath::GetCurrentDir(); + posix::ChDir(".."); + // This will make the test fail if run from the root directory. + EXPECT_NE(original_working_dir_.string(), + FilePath::GetCurrentDir().string()); + } + + void TearDown() override { + posix::ChDir(original_working_dir_.string().c_str()); + } + + FilePath original_working_dir_; +}; + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefault) { + GTEST_FLAG(output) = ""; + EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_, + FilePath("test_detail.xml")).string(), + UnitTestOptions::GetAbsolutePathToOutputFile()); +} + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefaultXML) { + GTEST_FLAG(output) = "xml"; + EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_, + FilePath("test_detail.xml")).string(), + UnitTestOptions::GetAbsolutePathToOutputFile()); +} + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativeFile) { + GTEST_FLAG(output) = "xml:filename.abc"; + EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_, + FilePath("filename.abc")).string(), + UnitTestOptions::GetAbsolutePathToOutputFile()); +} + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativePath) { + GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_; + const std::string expected_output_file = + FilePath::ConcatPaths( + original_working_dir_, + FilePath(std::string("path") + GTEST_PATH_SEP_ + + GetCurrentExecutableName().string() + ".xml")).string(); + const std::string& output_file = + UnitTestOptions::GetAbsolutePathToOutputFile(); +#if GTEST_OS_WINDOWS + EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); +#else + EXPECT_EQ(expected_output_file, output_file.c_str()); +#endif +} + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsoluteFile) { +#if GTEST_OS_WINDOWS + GTEST_FLAG(output) = "xml:c:\\tmp\\filename.abc"; + EXPECT_EQ(FilePath("c:\\tmp\\filename.abc").string(), + UnitTestOptions::GetAbsolutePathToOutputFile()); +#else + GTEST_FLAG(output) ="xml:/tmp/filename.abc"; + EXPECT_EQ(FilePath("/tmp/filename.abc").string(), + UnitTestOptions::GetAbsolutePathToOutputFile()); +#endif +} + +TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsolutePath) { +#if GTEST_OS_WINDOWS + const std::string path = "c:\\tmp\\"; +#else + const std::string path = "/tmp/"; +#endif + + GTEST_FLAG(output) = "xml:" + path; + const std::string expected_output_file = + path + GetCurrentExecutableName().string() + ".xml"; + const std::string& output_file = + UnitTestOptions::GetAbsolutePathToOutputFile(); + +#if GTEST_OS_WINDOWS + EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str()); +#else + EXPECT_EQ(expected_output_file, output_file.c_str()); +#endif +} + +#endif // !GTEST_OS_FUCHSIA + +} // namespace +} // namespace internal +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-output-test-golden-lin.txt b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-output-test-golden-lin.txt new file mode 100644 index 0000000000000000000000000000000000000000..038de921baba594bf7c001b89d3eb6d6b111b880 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-output-test-golden-lin.txt @@ -0,0 +1,1140 @@ +The non-test part of the code is expected to have 2 failures. + +googletest-output-test_.cc:#: Failure +Value of: false + Actual: false +Expected: true +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 2 + 3 +Stack trace: (omitted) + +[==========] Running 85 tests from 40 test suites. +[----------] Global test environment set-up. +FooEnvironment::SetUp() called. +BarEnvironment::SetUp() called. +[----------] 1 test from ADeathTest +[ RUN ] ADeathTest.ShouldRunFirst +[ OK ] ADeathTest.ShouldRunFirst +[----------] 1 test from ATypedDeathTest/0, where TypeParam = int +[ RUN ] ATypedDeathTest/0.ShouldRunFirst +[ OK ] ATypedDeathTest/0.ShouldRunFirst +[----------] 1 test from ATypedDeathTest/1, where TypeParam = double +[ RUN ] ATypedDeathTest/1.ShouldRunFirst +[ OK ] ATypedDeathTest/1.ShouldRunFirst +[----------] 1 test from My/ATypeParamDeathTest/0, where TypeParam = int +[ RUN ] My/ATypeParamDeathTest/0.ShouldRunFirst +[ OK ] My/ATypeParamDeathTest/0.ShouldRunFirst +[----------] 1 test from My/ATypeParamDeathTest/1, where TypeParam = double +[ RUN ] My/ATypeParamDeathTest/1.ShouldRunFirst +[ OK ] My/ATypeParamDeathTest/1.ShouldRunFirst +[----------] 2 tests from PassingTest +[ RUN ] PassingTest.PassingTest1 +[ OK ] PassingTest.PassingTest1 +[ RUN ] PassingTest.PassingTest2 +[ OK ] PassingTest.PassingTest2 +[----------] 2 tests from NonfatalFailureTest +[ RUN ] NonfatalFailureTest.EscapesStringOperands +googletest-output-test_.cc:#: Failure +Expected equality of these values: + kGoldenString + Which is: "\"Line" + actual + Which is: "actual \"string\"" +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Expected equality of these values: + golden + Which is: "\"Line" + actual + Which is: "actual \"string\"" +Stack trace: (omitted) + +[ FAILED ] NonfatalFailureTest.EscapesStringOperands +[ RUN ] NonfatalFailureTest.DiffForLongStrings +googletest-output-test_.cc:#: Failure +Expected equality of these values: + golden_str + Which is: "\"Line\0 1\"\nLine 2" + "Line 2" +With diff: +@@ -1,2 @@ +-\"Line\0 1\" + Line 2 + +Stack trace: (omitted) + +[ FAILED ] NonfatalFailureTest.DiffForLongStrings +[----------] 3 tests from FatalFailureTest +[ RUN ] FatalFailureTest.FatalFailureInSubroutine +(expecting a failure that x should be 1) +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1 + x + Which is: 2 +Stack trace: (omitted) + +[ FAILED ] FatalFailureTest.FatalFailureInSubroutine +[ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine +(expecting a failure that x should be 1) +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1 + x + Which is: 2 +Stack trace: (omitted) + +[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine +[ RUN ] FatalFailureTest.NonfatalFailureInSubroutine +(expecting a failure on false) +googletest-output-test_.cc:#: Failure +Value of: false + Actual: false +Expected: true +Stack trace: (omitted) + +[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine +[----------] 1 test from LoggingTest +[ RUN ] LoggingTest.InterleavingLoggingAndAssertions +(expecting 2 failures on (3) >= (a[i])) +i == 0 +i == 1 +googletest-output-test_.cc:#: Failure +Expected: (3) >= (a[i]), actual: 3 vs 9 +Stack trace: (omitted) + +i == 2 +i == 3 +googletest-output-test_.cc:#: Failure +Expected: (3) >= (a[i]), actual: 3 vs 6 +Stack trace: (omitted) + +[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions +[----------] 7 tests from SCOPED_TRACETest +[ RUN ] SCOPED_TRACETest.AcceptedValues +googletest-output-test_.cc:#: Failure +Failed +Just checking that all these values work fine. +Google Test trace: +googletest-output-test_.cc:#: (null) +googletest-output-test_.cc:#: 1337 +googletest-output-test_.cc:#: std::string +googletest-output-test_.cc:#: literal string +Stack trace: (omitted) + +[ FAILED ] SCOPED_TRACETest.AcceptedValues +[ RUN ] SCOPED_TRACETest.ObeysScopes +(expected to fail) +googletest-output-test_.cc:#: Failure +Failed +This failure is expected, and shouldn't have a trace. +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +This failure is expected, and should have a trace. +Google Test trace: +googletest-output-test_.cc:#: Expected trace +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +This failure is expected, and shouldn't have a trace. +Stack trace: (omitted) + +[ FAILED ] SCOPED_TRACETest.ObeysScopes +[ RUN ] SCOPED_TRACETest.WorksInLoop +(expected to fail) +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 2 + n + Which is: 1 +Google Test trace: +googletest-output-test_.cc:#: i = 1 +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1 + n + Which is: 2 +Google Test trace: +googletest-output-test_.cc:#: i = 2 +Stack trace: (omitted) + +[ FAILED ] SCOPED_TRACETest.WorksInLoop +[ RUN ] SCOPED_TRACETest.WorksInSubroutine +(expected to fail) +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 2 + n + Which is: 1 +Google Test trace: +googletest-output-test_.cc:#: n = 1 +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1 + n + Which is: 2 +Google Test trace: +googletest-output-test_.cc:#: n = 2 +Stack trace: (omitted) + +[ FAILED ] SCOPED_TRACETest.WorksInSubroutine +[ RUN ] SCOPED_TRACETest.CanBeNested +(expected to fail) +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1 + n + Which is: 2 +Google Test trace: +googletest-output-test_.cc:#: n = 2 +googletest-output-test_.cc:#: +Stack trace: (omitted) + +[ FAILED ] SCOPED_TRACETest.CanBeNested +[ RUN ] SCOPED_TRACETest.CanBeRepeated +(expected to fail) +googletest-output-test_.cc:#: Failure +Failed +This failure is expected, and should contain trace point A. +Google Test trace: +googletest-output-test_.cc:#: A +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +This failure is expected, and should contain trace point A and B. +Google Test trace: +googletest-output-test_.cc:#: B +googletest-output-test_.cc:#: A +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +This failure is expected, and should contain trace point A, B, and C. +Google Test trace: +googletest-output-test_.cc:#: C +googletest-output-test_.cc:#: B +googletest-output-test_.cc:#: A +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +This failure is expected, and should contain trace point A, B, and D. +Google Test trace: +googletest-output-test_.cc:#: D +googletest-output-test_.cc:#: B +googletest-output-test_.cc:#: A +Stack trace: (omitted) + +[ FAILED ] SCOPED_TRACETest.CanBeRepeated +[ RUN ] SCOPED_TRACETest.WorksConcurrently +(expecting 6 failures) +googletest-output-test_.cc:#: Failure +Failed +Expected failure #1 (in thread B, only trace B alive). +Google Test trace: +googletest-output-test_.cc:#: Trace B +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #2 (in thread A, trace A & B both alive). +Google Test trace: +googletest-output-test_.cc:#: Trace A +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #3 (in thread B, trace A & B both alive). +Google Test trace: +googletest-output-test_.cc:#: Trace B +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #4 (in thread B, only trace A alive). +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #5 (in thread A, only trace A alive). +Google Test trace: +googletest-output-test_.cc:#: Trace A +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #6 (in thread A, no trace alive). +Stack trace: (omitted) + +[ FAILED ] SCOPED_TRACETest.WorksConcurrently +[----------] 1 test from ScopedTraceTest +[ RUN ] ScopedTraceTest.WithExplicitFileAndLine +googletest-output-test_.cc:#: Failure +Failed +Check that the trace is attached to a particular location. +Google Test trace: +explicit_file.cc:123: expected trace message +Stack trace: (omitted) + +[ FAILED ] ScopedTraceTest.WithExplicitFileAndLine +[----------] 1 test from NonFatalFailureInFixtureConstructorTest +[ RUN ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor +(expecting 5 failures) +googletest-output-test_.cc:#: Failure +Failed +Expected failure #1, in the test fixture c'tor. +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #2, in SetUp(). +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #3, in the test body. +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #4, in TearDown. +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #5, in the test fixture d'tor. +Stack trace: (omitted) + +[ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor +[----------] 1 test from FatalFailureInFixtureConstructorTest +[ RUN ] FatalFailureInFixtureConstructorTest.FailureInConstructor +(expecting 2 failures) +googletest-output-test_.cc:#: Failure +Failed +Expected failure #1, in the test fixture c'tor. +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #2, in the test fixture d'tor. +Stack trace: (omitted) + +[ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor +[----------] 1 test from NonFatalFailureInSetUpTest +[ RUN ] NonFatalFailureInSetUpTest.FailureInSetUp +(expecting 4 failures) +googletest-output-test_.cc:#: Failure +Failed +Expected failure #1, in SetUp(). +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #2, in the test function. +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #3, in TearDown(). +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #4, in the test fixture d'tor. +Stack trace: (omitted) + +[ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp +[----------] 1 test from FatalFailureInSetUpTest +[ RUN ] FatalFailureInSetUpTest.FailureInSetUp +(expecting 3 failures) +googletest-output-test_.cc:#: Failure +Failed +Expected failure #1, in SetUp(). +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #2, in TearDown(). +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected failure #3, in the test fixture d'tor. +Stack trace: (omitted) + +[ FAILED ] FatalFailureInSetUpTest.FailureInSetUp +[----------] 1 test from AddFailureAtTest +[ RUN ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber +foo.cc:42: Failure +Failed +Expected nonfatal failure in foo.cc +Stack trace: (omitted) + +[ FAILED ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber +[----------] 1 test from GtestFailAtTest +[ RUN ] GtestFailAtTest.MessageContainsSpecifiedFileAndLineNumber +foo.cc:42: Failure +Failed +Expected fatal failure in foo.cc +Stack trace: (omitted) + +[ FAILED ] GtestFailAtTest.MessageContainsSpecifiedFileAndLineNumber +[----------] 4 tests from MixedUpTestSuiteTest +[ RUN ] MixedUpTestSuiteTest.FirstTestFromNamespaceFoo +[ OK ] MixedUpTestSuiteTest.FirstTestFromNamespaceFoo +[ RUN ] MixedUpTestSuiteTest.SecondTestFromNamespaceFoo +[ OK ] MixedUpTestSuiteTest.SecondTestFromNamespaceFoo +[ RUN ] MixedUpTestSuiteTest.ThisShouldFail +gtest.cc:#: Failure +Failed +All tests in the same test suite must use the same test fixture +class. However, in test suite MixedUpTestSuiteTest, +you defined test FirstTestFromNamespaceFoo and test ThisShouldFail +using two different test fixture classes. This can happen if +the two classes are from different namespaces or translation +units and have the same name. You should probably rename one +of the classes to put the tests into different test suites. +Stack trace: (omitted) + +[ FAILED ] MixedUpTestSuiteTest.ThisShouldFail +[ RUN ] MixedUpTestSuiteTest.ThisShouldFailToo +gtest.cc:#: Failure +Failed +All tests in the same test suite must use the same test fixture +class. However, in test suite MixedUpTestSuiteTest, +you defined test FirstTestFromNamespaceFoo and test ThisShouldFailToo +using two different test fixture classes. This can happen if +the two classes are from different namespaces or translation +units and have the same name. You should probably rename one +of the classes to put the tests into different test suites. +Stack trace: (omitted) + +[ FAILED ] MixedUpTestSuiteTest.ThisShouldFailToo +[----------] 2 tests from MixedUpTestSuiteWithSameTestNameTest +[ RUN ] MixedUpTestSuiteWithSameTestNameTest.TheSecondTestWithThisNameShouldFail +[ OK ] MixedUpTestSuiteWithSameTestNameTest.TheSecondTestWithThisNameShouldFail +[ RUN ] MixedUpTestSuiteWithSameTestNameTest.TheSecondTestWithThisNameShouldFail +gtest.cc:#: Failure +Failed +All tests in the same test suite must use the same test fixture +class. However, in test suite MixedUpTestSuiteWithSameTestNameTest, +you defined test TheSecondTestWithThisNameShouldFail and test TheSecondTestWithThisNameShouldFail +using two different test fixture classes. This can happen if +the two classes are from different namespaces or translation +units and have the same name. You should probably rename one +of the classes to put the tests into different test suites. +Stack trace: (omitted) + +[ FAILED ] MixedUpTestSuiteWithSameTestNameTest.TheSecondTestWithThisNameShouldFail +[----------] 2 tests from TEST_F_before_TEST_in_same_test_case +[ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F +[ OK ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F +[ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail +gtest.cc:#: Failure +Failed +All tests in the same test suite must use the same test fixture +class, so mixing TEST_F and TEST in the same test suite is +illegal. In test suite TEST_F_before_TEST_in_same_test_case, +test DefinedUsingTEST_F is defined using TEST_F but +test DefinedUsingTESTAndShouldFail is defined using TEST. You probably +want to change the TEST to TEST_F or move it to another test +case. +Stack trace: (omitted) + +[ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail +[----------] 2 tests from TEST_before_TEST_F_in_same_test_case +[ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST +[ OK ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST +[ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail +gtest.cc:#: Failure +Failed +All tests in the same test suite must use the same test fixture +class, so mixing TEST_F and TEST in the same test suite is +illegal. In test suite TEST_before_TEST_F_in_same_test_case, +test DefinedUsingTEST_FAndShouldFail is defined using TEST_F but +test DefinedUsingTEST is defined using TEST. You probably +want to change the TEST to TEST_F or move it to another test +case. +Stack trace: (omitted) + +[ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail +[----------] 8 tests from ExpectNonfatalFailureTest +[ RUN ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables +[ OK ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables +[ RUN ] ExpectNonfatalFailureTest.CanReferenceLocalVariables +[ OK ] ExpectNonfatalFailureTest.CanReferenceLocalVariables +[ RUN ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure +[ OK ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure +[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: 0 failures +Stack trace: (omitted) + +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure +[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: 2 failures +googletest-output-test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure 1. +Stack trace: (omitted) + + +googletest-output-test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure 2. +Stack trace: (omitted) + + +Stack trace: (omitted) + +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures +[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: +googletest-output-test_.cc:#: Fatal failure: +Failed +Expected fatal failure. +Stack trace: (omitted) + + +Stack trace: (omitted) + +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure +[ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementReturns +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: 0 failures +Stack trace: (omitted) + +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns +[ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementThrows +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: 0 failures +Stack trace: (omitted) + +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows +[----------] 8 tests from ExpectFatalFailureTest +[ RUN ] ExpectFatalFailureTest.CanReferenceGlobalVariables +[ OK ] ExpectFatalFailureTest.CanReferenceGlobalVariables +[ RUN ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables +[ OK ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables +[ RUN ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure +[ OK ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure +[ RUN ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: 0 failures +Stack trace: (omitted) + +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure +[ RUN ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: 2 failures +googletest-output-test_.cc:#: Fatal failure: +Failed +Expected fatal failure. +Stack trace: (omitted) + + +googletest-output-test_.cc:#: Fatal failure: +Failed +Expected fatal failure. +Stack trace: (omitted) + + +Stack trace: (omitted) + +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures +[ RUN ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: +googletest-output-test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure. +Stack trace: (omitted) + + +Stack trace: (omitted) + +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure +[ RUN ] ExpectFatalFailureTest.FailsWhenStatementReturns +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: 0 failures +Stack trace: (omitted) + +[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns +[ RUN ] ExpectFatalFailureTest.FailsWhenStatementThrows +(expecting a failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: 0 failures +Stack trace: (omitted) + +[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows +[----------] 2 tests from TypedTest/0, where TypeParam = int +[ RUN ] TypedTest/0.Success +[ OK ] TypedTest/0.Success +[ RUN ] TypedTest/0.Failure +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1 + TypeParam() + Which is: 0 +Expected failure +Stack trace: (omitted) + +[ FAILED ] TypedTest/0.Failure, where TypeParam = int +[----------] 2 tests from TypedTestWithNames/char0, where TypeParam = char +[ RUN ] TypedTestWithNames/char0.Success +[ OK ] TypedTestWithNames/char0.Success +[ RUN ] TypedTestWithNames/char0.Failure +googletest-output-test_.cc:#: Failure +Failed +Stack trace: (omitted) + +[ FAILED ] TypedTestWithNames/char0.Failure, where TypeParam = char +[----------] 2 tests from TypedTestWithNames/int1, where TypeParam = int +[ RUN ] TypedTestWithNames/int1.Success +[ OK ] TypedTestWithNames/int1.Success +[ RUN ] TypedTestWithNames/int1.Failure +googletest-output-test_.cc:#: Failure +Failed +Stack trace: (omitted) + +[ FAILED ] TypedTestWithNames/int1.Failure, where TypeParam = int +[----------] 2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char +[ RUN ] Unsigned/TypedTestP/0.Success +[ OK ] Unsigned/TypedTestP/0.Success +[ RUN ] Unsigned/TypedTestP/0.Failure +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1U + Which is: 1 + TypeParam() + Which is: '\0' +Expected failure +Stack trace: (omitted) + +[ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char +[----------] 2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int +[ RUN ] Unsigned/TypedTestP/1.Success +[ OK ] Unsigned/TypedTestP/1.Success +[ RUN ] Unsigned/TypedTestP/1.Failure +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1U + Which is: 1 + TypeParam() + Which is: 0 +Expected failure +Stack trace: (omitted) + +[ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int +[----------] 2 tests from UnsignedCustomName/TypedTestP/unsignedChar0, where TypeParam = unsigned char +[ RUN ] UnsignedCustomName/TypedTestP/unsignedChar0.Success +[ OK ] UnsignedCustomName/TypedTestP/unsignedChar0.Success +[ RUN ] UnsignedCustomName/TypedTestP/unsignedChar0.Failure +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1U + Which is: 1 + TypeParam() + Which is: '\0' +Expected failure +Stack trace: (omitted) + +[ FAILED ] UnsignedCustomName/TypedTestP/unsignedChar0.Failure, where TypeParam = unsigned char +[----------] 2 tests from UnsignedCustomName/TypedTestP/unsignedInt1, where TypeParam = unsigned int +[ RUN ] UnsignedCustomName/TypedTestP/unsignedInt1.Success +[ OK ] UnsignedCustomName/TypedTestP/unsignedInt1.Success +[ RUN ] UnsignedCustomName/TypedTestP/unsignedInt1.Failure +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1U + Which is: 1 + TypeParam() + Which is: 0 +Expected failure +Stack trace: (omitted) + +[ FAILED ] UnsignedCustomName/TypedTestP/unsignedInt1.Failure, where TypeParam = unsigned int +[----------] 4 tests from ExpectFailureTest +[ RUN ] ExpectFailureTest.ExpectFatalFailure +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: +googletest-output-test_.cc:#: Success: +Succeeded +Stack trace: (omitted) + + +Stack trace: (omitted) + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: +googletest-output-test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure. +Stack trace: (omitted) + + +Stack trace: (omitted) + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure containing "Some other fatal failure expected." + Actual: +googletest-output-test_.cc:#: Fatal failure: +Failed +Expected fatal failure. +Stack trace: (omitted) + + +Stack trace: (omitted) + +[ FAILED ] ExpectFailureTest.ExpectFatalFailure +[ RUN ] ExpectFailureTest.ExpectNonFatalFailure +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: +googletest-output-test_.cc:#: Success: +Succeeded +Stack trace: (omitted) + + +Stack trace: (omitted) + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: +googletest-output-test_.cc:#: Fatal failure: +Failed +Expected fatal failure. +Stack trace: (omitted) + + +Stack trace: (omitted) + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure containing "Some other non-fatal failure." + Actual: +googletest-output-test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure. +Stack trace: (omitted) + + +Stack trace: (omitted) + +[ FAILED ] ExpectFailureTest.ExpectNonFatalFailure +[ RUN ] ExpectFailureTest.ExpectFatalFailureOnAllThreads +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: +googletest-output-test_.cc:#: Success: +Succeeded +Stack trace: (omitted) + + +Stack trace: (omitted) + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: +googletest-output-test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure. +Stack trace: (omitted) + + +Stack trace: (omitted) + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 fatal failure containing "Some other fatal failure expected." + Actual: +googletest-output-test_.cc:#: Fatal failure: +Failed +Expected fatal failure. +Stack trace: (omitted) + + +Stack trace: (omitted) + +[ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads +[ RUN ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: +googletest-output-test_.cc:#: Success: +Succeeded +Stack trace: (omitted) + + +Stack trace: (omitted) + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: +googletest-output-test_.cc:#: Fatal failure: +Failed +Expected fatal failure. +Stack trace: (omitted) + + +Stack trace: (omitted) + +(expecting 1 failure) +gtest.cc:#: Failure +Expected: 1 non-fatal failure containing "Some other non-fatal failure." + Actual: +googletest-output-test_.cc:#: Non-fatal failure: +Failed +Expected non-fatal failure. +Stack trace: (omitted) + + +Stack trace: (omitted) + +[ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads +[----------] 2 tests from ExpectFailureWithThreadsTest +[ RUN ] ExpectFailureWithThreadsTest.ExpectFatalFailure +(expecting 2 failures) +googletest-output-test_.cc:#: Failure +Failed +Expected fatal failure. +Stack trace: (omitted) + +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: 0 failures +Stack trace: (omitted) + +[ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure +[ RUN ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure +(expecting 2 failures) +googletest-output-test_.cc:#: Failure +Failed +Expected non-fatal failure. +Stack trace: (omitted) + +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: 0 failures +Stack trace: (omitted) + +[ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure +[----------] 1 test from ScopedFakeTestPartResultReporterTest +[ RUN ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread +(expecting 2 failures) +googletest-output-test_.cc:#: Failure +Failed +Expected fatal failure. +Stack trace: (omitted) + +googletest-output-test_.cc:#: Failure +Failed +Expected non-fatal failure. +Stack trace: (omitted) + +[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread +[----------] 2 tests from DynamicFixture +DynamicFixture::SetUpTestSuite +[ RUN ] DynamicFixture.DynamicTestPass +DynamicFixture() +DynamicFixture::SetUp +DynamicFixture::TearDown +~DynamicFixture() +[ OK ] DynamicFixture.DynamicTestPass +[ RUN ] DynamicFixture.DynamicTestFail +DynamicFixture() +DynamicFixture::SetUp +googletest-output-test_.cc:#: Failure +Value of: Pass + Actual: false +Expected: true +Stack trace: (omitted) + +DynamicFixture::TearDown +~DynamicFixture() +[ FAILED ] DynamicFixture.DynamicTestFail +DynamicFixture::TearDownTestSuite +[----------] 1 test from DynamicFixtureAnotherName +DynamicFixture::SetUpTestSuite +[ RUN ] DynamicFixtureAnotherName.DynamicTestPass +DynamicFixture() +DynamicFixture::SetUp +DynamicFixture::TearDown +~DynamicFixture() +[ OK ] DynamicFixtureAnotherName.DynamicTestPass +DynamicFixture::TearDownTestSuite +[----------] 2 tests from BadDynamicFixture1 +DynamicFixture::SetUpTestSuite +[ RUN ] BadDynamicFixture1.FixtureBase +DynamicFixture() +DynamicFixture::SetUp +DynamicFixture::TearDown +~DynamicFixture() +[ OK ] BadDynamicFixture1.FixtureBase +[ RUN ] BadDynamicFixture1.TestBase +DynamicFixture() +gtest.cc:#: Failure +Failed +All tests in the same test suite must use the same test fixture +class, so mixing TEST_F and TEST in the same test suite is +illegal. In test suite BadDynamicFixture1, +test FixtureBase is defined using TEST_F but +test TestBase is defined using TEST. You probably +want to change the TEST to TEST_F or move it to another test +case. +Stack trace: (omitted) + +~DynamicFixture() +[ FAILED ] BadDynamicFixture1.TestBase +DynamicFixture::TearDownTestSuite +[----------] 2 tests from BadDynamicFixture2 +DynamicFixture::SetUpTestSuite +[ RUN ] BadDynamicFixture2.FixtureBase +DynamicFixture() +DynamicFixture::SetUp +DynamicFixture::TearDown +~DynamicFixture() +[ OK ] BadDynamicFixture2.FixtureBase +[ RUN ] BadDynamicFixture2.Derived +DynamicFixture() +gtest.cc:#: Failure +Failed +All tests in the same test suite must use the same test fixture +class. However, in test suite BadDynamicFixture2, +you defined test FixtureBase and test Derived +using two different test fixture classes. This can happen if +the two classes are from different namespaces or translation +units and have the same name. You should probably rename one +of the classes to put the tests into different test suites. +Stack trace: (omitted) + +~DynamicFixture() +[ FAILED ] BadDynamicFixture2.Derived +DynamicFixture::TearDownTestSuite +[----------] 1 test from PrintingFailingParams/FailingParamTest +[ RUN ] PrintingFailingParams/FailingParamTest.Fails/0 +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1 + GetParam() + Which is: 2 +Stack trace: (omitted) + +[ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2 +[----------] 1 test from EmptyBasenameParamInst +[ RUN ] EmptyBasenameParamInst.Passes/0 +[ OK ] EmptyBasenameParamInst.Passes/0 +[----------] 2 tests from PrintingStrings/ParamTest +[ RUN ] PrintingStrings/ParamTest.Success/a +[ OK ] PrintingStrings/ParamTest.Success/a +[ RUN ] PrintingStrings/ParamTest.Failure/a +googletest-output-test_.cc:#: Failure +Expected equality of these values: + "b" + GetParam() + Which is: "a" +Expected failure +Stack trace: (omitted) + +[ FAILED ] PrintingStrings/ParamTest.Failure/a, where GetParam() = "a" +[----------] Global test environment tear-down +BarEnvironment::TearDown() called. +googletest-output-test_.cc:#: Failure +Failed +Expected non-fatal failure. +Stack trace: (omitted) + +FooEnvironment::TearDown() called. +googletest-output-test_.cc:#: Failure +Failed +Expected fatal failure. +Stack trace: (omitted) + +[==========] 85 tests from 40 test suites ran. +[ PASSED ] 31 tests. +[ FAILED ] 54 tests, listed below: +[ FAILED ] NonfatalFailureTest.EscapesStringOperands +[ FAILED ] NonfatalFailureTest.DiffForLongStrings +[ FAILED ] FatalFailureTest.FatalFailureInSubroutine +[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine +[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine +[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions +[ FAILED ] SCOPED_TRACETest.AcceptedValues +[ FAILED ] SCOPED_TRACETest.ObeysScopes +[ FAILED ] SCOPED_TRACETest.WorksInLoop +[ FAILED ] SCOPED_TRACETest.WorksInSubroutine +[ FAILED ] SCOPED_TRACETest.CanBeNested +[ FAILED ] SCOPED_TRACETest.CanBeRepeated +[ FAILED ] SCOPED_TRACETest.WorksConcurrently +[ FAILED ] ScopedTraceTest.WithExplicitFileAndLine +[ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor +[ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor +[ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp +[ FAILED ] FatalFailureInSetUpTest.FailureInSetUp +[ FAILED ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber +[ FAILED ] GtestFailAtTest.MessageContainsSpecifiedFileAndLineNumber +[ FAILED ] MixedUpTestSuiteTest.ThisShouldFail +[ FAILED ] MixedUpTestSuiteTest.ThisShouldFailToo +[ FAILED ] MixedUpTestSuiteWithSameTestNameTest.TheSecondTestWithThisNameShouldFail +[ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail +[ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns +[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures +[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure +[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns +[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows +[ FAILED ] TypedTest/0.Failure, where TypeParam = int +[ FAILED ] TypedTestWithNames/char0.Failure, where TypeParam = char +[ FAILED ] TypedTestWithNames/int1.Failure, where TypeParam = int +[ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char +[ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int +[ FAILED ] UnsignedCustomName/TypedTestP/unsignedChar0.Failure, where TypeParam = unsigned char +[ FAILED ] UnsignedCustomName/TypedTestP/unsignedInt1.Failure, where TypeParam = unsigned int +[ FAILED ] ExpectFailureTest.ExpectFatalFailure +[ FAILED ] ExpectFailureTest.ExpectNonFatalFailure +[ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads +[ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads +[ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure +[ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure +[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread +[ FAILED ] DynamicFixture.DynamicTestFail +[ FAILED ] BadDynamicFixture1.TestBase +[ FAILED ] BadDynamicFixture2.Derived +[ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2 +[ FAILED ] PrintingStrings/ParamTest.Failure/a, where GetParam() = "a" + +54 FAILED TESTS + YOU HAVE 1 DISABLED TEST + +Note: Google Test filter = FatalFailureTest.*:LoggingTest.* +[==========] Running 4 tests from 2 test suites. +[----------] Global test environment set-up. +[----------] 3 tests from FatalFailureTest +[ RUN ] FatalFailureTest.FatalFailureInSubroutine +(expecting a failure that x should be 1) +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1 + x + Which is: 2 +Stack trace: (omitted) + +[ FAILED ] FatalFailureTest.FatalFailureInSubroutine (? ms) +[ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine +(expecting a failure that x should be 1) +googletest-output-test_.cc:#: Failure +Expected equality of these values: + 1 + x + Which is: 2 +Stack trace: (omitted) + +[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine (? ms) +[ RUN ] FatalFailureTest.NonfatalFailureInSubroutine +(expecting a failure on false) +googletest-output-test_.cc:#: Failure +Value of: false + Actual: false +Expected: true +Stack trace: (omitted) + +[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine (? ms) +[----------] 3 tests from FatalFailureTest (? ms total) + +[----------] 1 test from LoggingTest +[ RUN ] LoggingTest.InterleavingLoggingAndAssertions +(expecting 2 failures on (3) >= (a[i])) +i == 0 +i == 1 +googletest-output-test_.cc:#: Failure +Expected: (3) >= (a[i]), actual: 3 vs 9 +Stack trace: (omitted) + +i == 2 +i == 3 +googletest-output-test_.cc:#: Failure +Expected: (3) >= (a[i]), actual: 3 vs 6 +Stack trace: (omitted) + +[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions (? ms) +[----------] 1 test from LoggingTest (? ms total) + +[----------] Global test environment tear-down +[==========] 4 tests from 2 test suites ran. (? ms total) +[ PASSED ] 0 tests. +[ FAILED ] 4 tests, listed below: +[ FAILED ] FatalFailureTest.FatalFailureInSubroutine +[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine +[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine +[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions + + 4 FAILED TESTS +Note: Google Test filter = *DISABLED_* +[==========] Running 1 test from 1 test suite. +[----------] Global test environment set-up. +[----------] 1 test from DisabledTestsWarningTest +[ RUN ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning +[ OK ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning +[----------] Global test environment tear-down +[==========] 1 test from 1 test suite ran. +[ PASSED ] 1 test. +Note: Google Test filter = PassingTest.* +Note: This is test shard 2 of 2. +[==========] Running 1 test from 1 test suite. +[----------] Global test environment set-up. +[----------] 1 test from PassingTest +[ RUN ] PassingTest.PassingTest2 +[ OK ] PassingTest.PassingTest2 +[----------] Global test environment tear-down +[==========] 1 test from 1 test suite ran. +[ PASSED ] 1 test. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-output-test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-output-test.py new file mode 100755 index 0000000000000000000000000000000000000000..c727f17a4963a96995e5c75335e1c3c4a09d4d84 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-output-test.py @@ -0,0 +1,346 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests the text output of Google C++ Testing and Mocking Framework. + +To update the golden file: +googletest_output_test.py --build_dir=BUILD/DIR --gengolden +where BUILD/DIR contains the built googletest-output-test_ file. +googletest_output_test.py --gengolden +googletest_output_test.py +""" + +import difflib +import os +import re +import sys +import gtest_test_utils + + +# The flag for generating the golden file +GENGOLDEN_FLAG = '--gengolden' +CATCH_EXCEPTIONS_ENV_VAR_NAME = 'GTEST_CATCH_EXCEPTIONS' + +# The flag indicating stacktraces are not supported +NO_STACKTRACE_SUPPORT_FLAG = '--no_stacktrace_support' + +IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux' +IS_WINDOWS = os.name == 'nt' + +GOLDEN_NAME = 'googletest-output-test-golden-lin.txt' + +PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('googletest-output-test_') + +# At least one command we exercise must not have the +# 'internal_skip_environment_and_ad_hoc_tests' argument. +COMMAND_LIST_TESTS = ({}, [PROGRAM_PATH, '--gtest_list_tests']) +COMMAND_WITH_COLOR = ({}, [PROGRAM_PATH, '--gtest_color=yes']) +COMMAND_WITH_TIME = ({}, [PROGRAM_PATH, + '--gtest_print_time', + 'internal_skip_environment_and_ad_hoc_tests', + '--gtest_filter=FatalFailureTest.*:LoggingTest.*']) +COMMAND_WITH_DISABLED = ( + {}, [PROGRAM_PATH, + '--gtest_also_run_disabled_tests', + 'internal_skip_environment_and_ad_hoc_tests', + '--gtest_filter=*DISABLED_*']) +COMMAND_WITH_SHARDING = ( + {'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'}, + [PROGRAM_PATH, + 'internal_skip_environment_and_ad_hoc_tests', + '--gtest_filter=PassingTest.*']) + +GOLDEN_PATH = os.path.join(gtest_test_utils.GetSourceDir(), GOLDEN_NAME) + + +def ToUnixLineEnding(s): + """Changes all Windows/Mac line endings in s to UNIX line endings.""" + + return s.replace('\r\n', '\n').replace('\r', '\n') + + +def RemoveLocations(test_output): + """Removes all file location info from a Google Test program's output. + + Args: + test_output: the output of a Google Test program. + + Returns: + output with all file location info (in the form of + 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or + 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by + 'FILE_NAME:#: '. + """ + + return re.sub(r'.*[/\\]((googletest-output-test_|gtest).cc)(\:\d+|\(\d+\))\: ', + r'\1:#: ', test_output) + + +def RemoveStackTraceDetails(output): + """Removes all stack traces from a Google Test program's output.""" + + # *? means "find the shortest string that matches". + return re.sub(r'Stack trace:(.|\n)*?\n\n', + 'Stack trace: (omitted)\n\n', output) + + +def RemoveStackTraces(output): + """Removes all traces of stack traces from a Google Test program's output.""" + + # *? means "find the shortest string that matches". + return re.sub(r'Stack trace:(.|\n)*?\n\n', '', output) + + +def RemoveTime(output): + """Removes all time information from a Google Test program's output.""" + + return re.sub(r'\(\d+ ms', '(? ms', output) + + +def RemoveTypeInfoDetails(test_output): + """Removes compiler-specific type info from Google Test program's output. + + Args: + test_output: the output of a Google Test program. + + Returns: + output with type information normalized to canonical form. + """ + + # some compilers output the name of type 'unsigned int' as 'unsigned' + return re.sub(r'unsigned int', 'unsigned', test_output) + + +def NormalizeToCurrentPlatform(test_output): + """Normalizes platform specific output details for easier comparison.""" + + if IS_WINDOWS: + # Removes the color information that is not present on Windows. + test_output = re.sub('\x1b\\[(0;3\d)?m', '', test_output) + # Changes failure message headers into the Windows format. + test_output = re.sub(r': Failure\n', r': error: ', test_output) + # Changes file(line_number) to file:line_number. + test_output = re.sub(r'((\w|\.)+)\((\d+)\):', r'\1:\3:', test_output) + + return test_output + + +def RemoveTestCounts(output): + """Removes test counts from a Google Test program's output.""" + + output = re.sub(r'\d+ tests?, listed below', + '? tests, listed below', output) + output = re.sub(r'\d+ FAILED TESTS', + '? FAILED TESTS', output) + output = re.sub(r'\d+ tests? from \d+ test cases?', + '? tests from ? test cases', output) + output = re.sub(r'\d+ tests? from ([a-zA-Z_])', + r'? tests from \1', output) + return re.sub(r'\d+ tests?\.', '? tests.', output) + + +def RemoveMatchingTests(test_output, pattern): + """Removes output of specified tests from a Google Test program's output. + + This function strips not only the beginning and the end of a test but also + all output in between. + + Args: + test_output: A string containing the test output. + pattern: A regex string that matches names of test cases or + tests to remove. + + Returns: + Contents of test_output with tests whose names match pattern removed. + """ + + test_output = re.sub( + r'.*\[ RUN \] .*%s(.|\n)*?\[( FAILED | OK )\] .*%s.*\n' % ( + pattern, pattern), + '', + test_output) + return re.sub(r'.*%s.*\n' % pattern, '', test_output) + + +def NormalizeOutput(output): + """Normalizes output (the output of googletest-output-test_.exe).""" + + output = ToUnixLineEnding(output) + output = RemoveLocations(output) + output = RemoveStackTraceDetails(output) + output = RemoveTime(output) + return output + + +def GetShellCommandOutput(env_cmd): + """Runs a command in a sub-process, and returns its output in a string. + + Args: + env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra + environment variables to set, and element 1 is a string with + the command and any flags. + + Returns: + A string with the command's combined standard and diagnostic output. + """ + + # Spawns cmd in a sub-process, and gets its standard I/O file objects. + # Set and save the environment properly. + environ = os.environ.copy() + environ.update(env_cmd[0]) + p = gtest_test_utils.Subprocess(env_cmd[1], env=environ) + + return p.output + + +def GetCommandOutput(env_cmd): + """Runs a command and returns its output with all file location + info stripped off. + + Args: + env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra + environment variables to set, and element 1 is a string with + the command and any flags. + """ + + # Disables exception pop-ups on Windows. + environ, cmdline = env_cmd + environ = dict(environ) # Ensures we are modifying a copy. + environ[CATCH_EXCEPTIONS_ENV_VAR_NAME] = '1' + return NormalizeOutput(GetShellCommandOutput((environ, cmdline))) + + +def GetOutputOfAllCommands(): + """Returns concatenated output from several representative commands.""" + + return (GetCommandOutput(COMMAND_WITH_COLOR) + + GetCommandOutput(COMMAND_WITH_TIME) + + GetCommandOutput(COMMAND_WITH_DISABLED) + + GetCommandOutput(COMMAND_WITH_SHARDING)) + + +test_list = GetShellCommandOutput(COMMAND_LIST_TESTS) +SUPPORTS_DEATH_TESTS = 'DeathTest' in test_list +SUPPORTS_TYPED_TESTS = 'TypedTest' in test_list +SUPPORTS_THREADS = 'ExpectFailureWithThreadsTest' in test_list +SUPPORTS_STACK_TRACES = NO_STACKTRACE_SUPPORT_FLAG not in sys.argv + +CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and + SUPPORTS_TYPED_TESTS and + SUPPORTS_THREADS and + SUPPORTS_STACK_TRACES) + +class GTestOutputTest(gtest_test_utils.TestCase): + def RemoveUnsupportedTests(self, test_output): + if not SUPPORTS_DEATH_TESTS: + test_output = RemoveMatchingTests(test_output, 'DeathTest') + if not SUPPORTS_TYPED_TESTS: + test_output = RemoveMatchingTests(test_output, 'TypedTest') + test_output = RemoveMatchingTests(test_output, 'TypedDeathTest') + test_output = RemoveMatchingTests(test_output, 'TypeParamDeathTest') + if not SUPPORTS_THREADS: + test_output = RemoveMatchingTests(test_output, + 'ExpectFailureWithThreadsTest') + test_output = RemoveMatchingTests(test_output, + 'ScopedFakeTestPartResultReporterTest') + test_output = RemoveMatchingTests(test_output, + 'WorksConcurrently') + if not SUPPORTS_STACK_TRACES: + test_output = RemoveStackTraces(test_output) + + return test_output + + def testOutput(self): + output = GetOutputOfAllCommands() + + golden_file = open(GOLDEN_PATH, 'rb') + # A mis-configured source control system can cause \r appear in EOL + # sequences when we read the golden file irrespective of an operating + # system used. Therefore, we need to strip those \r's from newlines + # unconditionally. + golden = ToUnixLineEnding(golden_file.read().decode()) + golden_file.close() + + # We want the test to pass regardless of certain features being + # supported or not. + + # We still have to remove type name specifics in all cases. + normalized_actual = RemoveTypeInfoDetails(output) + normalized_golden = RemoveTypeInfoDetails(golden) + + if CAN_GENERATE_GOLDEN_FILE: + self.assertEqual(normalized_golden, normalized_actual, + '\n'.join(difflib.unified_diff( + normalized_golden.split('\n'), + normalized_actual.split('\n'), + 'golden', 'actual'))) + else: + normalized_actual = NormalizeToCurrentPlatform( + RemoveTestCounts(normalized_actual)) + normalized_golden = NormalizeToCurrentPlatform( + RemoveTestCounts(self.RemoveUnsupportedTests(normalized_golden))) + + # This code is very handy when debugging golden file differences: + if os.getenv('DEBUG_GTEST_OUTPUT_TEST'): + open(os.path.join( + gtest_test_utils.GetSourceDir(), + '_googletest-output-test_normalized_actual.txt'), 'wb').write( + normalized_actual) + open(os.path.join( + gtest_test_utils.GetSourceDir(), + '_googletest-output-test_normalized_golden.txt'), 'wb').write( + normalized_golden) + + self.assertEqual(normalized_golden, normalized_actual) + + +if __name__ == '__main__': + if NO_STACKTRACE_SUPPORT_FLAG in sys.argv: + # unittest.main() can't handle unknown flags + sys.argv.remove(NO_STACKTRACE_SUPPORT_FLAG) + + if GENGOLDEN_FLAG in sys.argv: + if CAN_GENERATE_GOLDEN_FILE: + output = GetOutputOfAllCommands() + golden_file = open(GOLDEN_PATH, 'wb') + golden_file.write(output) + golden_file.close() + else: + message = ( + """Unable to write a golden file when compiled in an environment +that does not support all the required features (death tests, +typed tests, stack traces, and multiple threads). +Please build this test and generate the golden file using Blaze on Linux.""") + + sys.stderr.write(message) + sys.exit(1) + else: + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-output-test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-output-test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..4f716d843b125cbf6f93d1a9592077a058fff1c4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-output-test_.cc @@ -0,0 +1,1157 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The purpose of this file is to generate Google Test output under +// various conditions. The output will then be verified by +// googletest-output-test.py to ensure that Google Test generates the +// desired messages. Therefore, most tests in this file are MEANT TO +// FAIL. + +#include "gtest/gtest-spi.h" +#include "gtest/gtest.h" +#include "src/gtest-internal-inl.h" + +#include + +#if _MSC_VER +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127 /* conditional expression is constant */) +#endif // _MSC_VER + +#if GTEST_IS_THREADSAFE +using testing::ScopedFakeTestPartResultReporter; +using testing::TestPartResultArray; + +using testing::internal::Notification; +using testing::internal::ThreadWithParam; +#endif + +namespace posix = ::testing::internal::posix; + +// Tests catching fatal failures. + +// A subroutine used by the following test. +void TestEq1(int x) { + ASSERT_EQ(1, x); +} + +// This function calls a test subroutine, catches the fatal failure it +// generates, and then returns early. +void TryTestSubroutine() { + // Calls a subrountine that yields a fatal failure. + TestEq1(2); + + // Catches the fatal failure and aborts the test. + // + // The testing::Test:: prefix is necessary when calling + // HasFatalFailure() outside of a TEST, TEST_F, or test fixture. + if (testing::Test::HasFatalFailure()) return; + + // If we get here, something is wrong. + FAIL() << "This should never be reached."; +} + +TEST(PassingTest, PassingTest1) { +} + +TEST(PassingTest, PassingTest2) { +} + +// Tests that parameters of failing parameterized tests are printed in the +// failing test summary. +class FailingParamTest : public testing::TestWithParam {}; + +TEST_P(FailingParamTest, Fails) { + EXPECT_EQ(1, GetParam()); +} + +// This generates a test which will fail. Google Test is expected to print +// its parameter when it outputs the list of all failed tests. +INSTANTIATE_TEST_SUITE_P(PrintingFailingParams, + FailingParamTest, + testing::Values(2)); + +// Tests that an empty value for the test suite basename yields just +// the test name without any prior / +class EmptyBasenameParamInst : public testing::TestWithParam {}; + +TEST_P(EmptyBasenameParamInst, Passes) { EXPECT_EQ(1, GetParam()); } + +INSTANTIATE_TEST_SUITE_P(, EmptyBasenameParamInst, testing::Values(1)); + +static const char kGoldenString[] = "\"Line\0 1\"\nLine 2"; + +TEST(NonfatalFailureTest, EscapesStringOperands) { + std::string actual = "actual \"string\""; + EXPECT_EQ(kGoldenString, actual); + + const char* golden = kGoldenString; + EXPECT_EQ(golden, actual); +} + +TEST(NonfatalFailureTest, DiffForLongStrings) { + std::string golden_str(kGoldenString, sizeof(kGoldenString) - 1); + EXPECT_EQ(golden_str, "Line 2"); +} + +// Tests catching a fatal failure in a subroutine. +TEST(FatalFailureTest, FatalFailureInSubroutine) { + printf("(expecting a failure that x should be 1)\n"); + + TryTestSubroutine(); +} + +// Tests catching a fatal failure in a nested subroutine. +TEST(FatalFailureTest, FatalFailureInNestedSubroutine) { + printf("(expecting a failure that x should be 1)\n"); + + // Calls a subrountine that yields a fatal failure. + TryTestSubroutine(); + + // Catches the fatal failure and aborts the test. + // + // When calling HasFatalFailure() inside a TEST, TEST_F, or test + // fixture, the testing::Test:: prefix is not needed. + if (HasFatalFailure()) return; + + // If we get here, something is wrong. + FAIL() << "This should never be reached."; +} + +// Tests HasFatalFailure() after a failed EXPECT check. +TEST(FatalFailureTest, NonfatalFailureInSubroutine) { + printf("(expecting a failure on false)\n"); + EXPECT_TRUE(false); // Generates a nonfatal failure + ASSERT_FALSE(HasFatalFailure()); // This should succeed. +} + +// Tests interleaving user logging and Google Test assertions. +TEST(LoggingTest, InterleavingLoggingAndAssertions) { + static const int a[4] = { + 3, 9, 2, 6 + }; + + printf("(expecting 2 failures on (3) >= (a[i]))\n"); + for (int i = 0; i < static_cast(sizeof(a)/sizeof(*a)); i++) { + printf("i == %d\n", i); + EXPECT_GE(3, a[i]); + } +} + +// Tests the SCOPED_TRACE macro. + +// A helper function for testing SCOPED_TRACE. +void SubWithoutTrace(int n) { + EXPECT_EQ(1, n); + ASSERT_EQ(2, n); +} + +// Another helper function for testing SCOPED_TRACE. +void SubWithTrace(int n) { + SCOPED_TRACE(testing::Message() << "n = " << n); + + SubWithoutTrace(n); +} + +TEST(SCOPED_TRACETest, AcceptedValues) { + SCOPED_TRACE("literal string"); + SCOPED_TRACE(std::string("std::string")); + SCOPED_TRACE(1337); // streamable type + const char* null_value = nullptr; + SCOPED_TRACE(null_value); + + ADD_FAILURE() << "Just checking that all these values work fine."; +} + +// Tests that SCOPED_TRACE() obeys lexical scopes. +TEST(SCOPED_TRACETest, ObeysScopes) { + printf("(expected to fail)\n"); + + // There should be no trace before SCOPED_TRACE() is invoked. + ADD_FAILURE() << "This failure is expected, and shouldn't have a trace."; + + { + SCOPED_TRACE("Expected trace"); + // After SCOPED_TRACE(), a failure in the current scope should contain + // the trace. + ADD_FAILURE() << "This failure is expected, and should have a trace."; + } + + // Once the control leaves the scope of the SCOPED_TRACE(), there + // should be no trace again. + ADD_FAILURE() << "This failure is expected, and shouldn't have a trace."; +} + +// Tests that SCOPED_TRACE works inside a loop. +TEST(SCOPED_TRACETest, WorksInLoop) { + printf("(expected to fail)\n"); + + for (int i = 1; i <= 2; i++) { + SCOPED_TRACE(testing::Message() << "i = " << i); + + SubWithoutTrace(i); + } +} + +// Tests that SCOPED_TRACE works in a subroutine. +TEST(SCOPED_TRACETest, WorksInSubroutine) { + printf("(expected to fail)\n"); + + SubWithTrace(1); + SubWithTrace(2); +} + +// Tests that SCOPED_TRACE can be nested. +TEST(SCOPED_TRACETest, CanBeNested) { + printf("(expected to fail)\n"); + + SCOPED_TRACE(""); // A trace without a message. + + SubWithTrace(2); +} + +// Tests that multiple SCOPED_TRACEs can be used in the same scope. +TEST(SCOPED_TRACETest, CanBeRepeated) { + printf("(expected to fail)\n"); + + SCOPED_TRACE("A"); + ADD_FAILURE() + << "This failure is expected, and should contain trace point A."; + + SCOPED_TRACE("B"); + ADD_FAILURE() + << "This failure is expected, and should contain trace point A and B."; + + { + SCOPED_TRACE("C"); + ADD_FAILURE() << "This failure is expected, and should " + << "contain trace point A, B, and C."; + } + + SCOPED_TRACE("D"); + ADD_FAILURE() << "This failure is expected, and should " + << "contain trace point A, B, and D."; +} + +#if GTEST_IS_THREADSAFE +// Tests that SCOPED_TRACE()s can be used concurrently from multiple +// threads. Namely, an assertion should be affected by +// SCOPED_TRACE()s in its own thread only. + +// Here's the sequence of actions that happen in the test: +// +// Thread A (main) | Thread B (spawned) +// ===============================|================================ +// spawns thread B | +// -------------------------------+-------------------------------- +// waits for n1 | SCOPED_TRACE("Trace B"); +// | generates failure #1 +// | notifies n1 +// -------------------------------+-------------------------------- +// SCOPED_TRACE("Trace A"); | waits for n2 +// generates failure #2 | +// notifies n2 | +// -------------------------------|-------------------------------- +// waits for n3 | generates failure #3 +// | trace B dies +// | generates failure #4 +// | notifies n3 +// -------------------------------|-------------------------------- +// generates failure #5 | finishes +// trace A dies | +// generates failure #6 | +// -------------------------------|-------------------------------- +// waits for thread B to finish | + +struct CheckPoints { + Notification n1; + Notification n2; + Notification n3; +}; + +static void ThreadWithScopedTrace(CheckPoints* check_points) { + { + SCOPED_TRACE("Trace B"); + ADD_FAILURE() + << "Expected failure #1 (in thread B, only trace B alive)."; + check_points->n1.Notify(); + check_points->n2.WaitForNotification(); + + ADD_FAILURE() + << "Expected failure #3 (in thread B, trace A & B both alive)."; + } // Trace B dies here. + ADD_FAILURE() + << "Expected failure #4 (in thread B, only trace A alive)."; + check_points->n3.Notify(); +} + +TEST(SCOPED_TRACETest, WorksConcurrently) { + printf("(expecting 6 failures)\n"); + + CheckPoints check_points; + ThreadWithParam thread(&ThreadWithScopedTrace, &check_points, + nullptr); + check_points.n1.WaitForNotification(); + + { + SCOPED_TRACE("Trace A"); + ADD_FAILURE() + << "Expected failure #2 (in thread A, trace A & B both alive)."; + check_points.n2.Notify(); + check_points.n3.WaitForNotification(); + + ADD_FAILURE() + << "Expected failure #5 (in thread A, only trace A alive)."; + } // Trace A dies here. + ADD_FAILURE() + << "Expected failure #6 (in thread A, no trace alive)."; + thread.Join(); +} +#endif // GTEST_IS_THREADSAFE + +// Tests basic functionality of the ScopedTrace utility (most of its features +// are already tested in SCOPED_TRACETest). +TEST(ScopedTraceTest, WithExplicitFileAndLine) { + testing::ScopedTrace trace("explicit_file.cc", 123, "expected trace message"); + ADD_FAILURE() << "Check that the trace is attached to a particular location."; +} + +TEST(DisabledTestsWarningTest, + DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning) { + // This test body is intentionally empty. Its sole purpose is for + // verifying that the --gtest_also_run_disabled_tests flag + // suppresses the "YOU HAVE 12 DISABLED TESTS" warning at the end of + // the test output. +} + +// Tests using assertions outside of TEST and TEST_F. +// +// This function creates two failures intentionally. +void AdHocTest() { + printf("The non-test part of the code is expected to have 2 failures.\n\n"); + EXPECT_TRUE(false); + EXPECT_EQ(2, 3); +} + +// Runs all TESTs, all TEST_Fs, and the ad hoc test. +int RunAllTests() { + AdHocTest(); + return RUN_ALL_TESTS(); +} + +// Tests non-fatal failures in the fixture constructor. +class NonFatalFailureInFixtureConstructorTest : public testing::Test { + protected: + NonFatalFailureInFixtureConstructorTest() { + printf("(expecting 5 failures)\n"); + ADD_FAILURE() << "Expected failure #1, in the test fixture c'tor."; + } + + ~NonFatalFailureInFixtureConstructorTest() override { + ADD_FAILURE() << "Expected failure #5, in the test fixture d'tor."; + } + + void SetUp() override { ADD_FAILURE() << "Expected failure #2, in SetUp()."; } + + void TearDown() override { + ADD_FAILURE() << "Expected failure #4, in TearDown."; + } +}; + +TEST_F(NonFatalFailureInFixtureConstructorTest, FailureInConstructor) { + ADD_FAILURE() << "Expected failure #3, in the test body."; +} + +// Tests fatal failures in the fixture constructor. +class FatalFailureInFixtureConstructorTest : public testing::Test { + protected: + FatalFailureInFixtureConstructorTest() { + printf("(expecting 2 failures)\n"); + Init(); + } + + ~FatalFailureInFixtureConstructorTest() override { + ADD_FAILURE() << "Expected failure #2, in the test fixture d'tor."; + } + + void SetUp() override { + ADD_FAILURE() << "UNEXPECTED failure in SetUp(). " + << "We should never get here, as the test fixture c'tor " + << "had a fatal failure."; + } + + void TearDown() override { + ADD_FAILURE() << "UNEXPECTED failure in TearDown(). " + << "We should never get here, as the test fixture c'tor " + << "had a fatal failure."; + } + + private: + void Init() { + FAIL() << "Expected failure #1, in the test fixture c'tor."; + } +}; + +TEST_F(FatalFailureInFixtureConstructorTest, FailureInConstructor) { + ADD_FAILURE() << "UNEXPECTED failure in the test body. " + << "We should never get here, as the test fixture c'tor " + << "had a fatal failure."; +} + +// Tests non-fatal failures in SetUp(). +class NonFatalFailureInSetUpTest : public testing::Test { + protected: + ~NonFatalFailureInSetUpTest() override { Deinit(); } + + void SetUp() override { + printf("(expecting 4 failures)\n"); + ADD_FAILURE() << "Expected failure #1, in SetUp()."; + } + + void TearDown() override { FAIL() << "Expected failure #3, in TearDown()."; } + + private: + void Deinit() { + FAIL() << "Expected failure #4, in the test fixture d'tor."; + } +}; + +TEST_F(NonFatalFailureInSetUpTest, FailureInSetUp) { + FAIL() << "Expected failure #2, in the test function."; +} + +// Tests fatal failures in SetUp(). +class FatalFailureInSetUpTest : public testing::Test { + protected: + ~FatalFailureInSetUpTest() override { Deinit(); } + + void SetUp() override { + printf("(expecting 3 failures)\n"); + FAIL() << "Expected failure #1, in SetUp()."; + } + + void TearDown() override { FAIL() << "Expected failure #2, in TearDown()."; } + + private: + void Deinit() { + FAIL() << "Expected failure #3, in the test fixture d'tor."; + } +}; + +TEST_F(FatalFailureInSetUpTest, FailureInSetUp) { + FAIL() << "UNEXPECTED failure in the test function. " + << "We should never get here, as SetUp() failed."; +} + +TEST(AddFailureAtTest, MessageContainsSpecifiedFileAndLineNumber) { + ADD_FAILURE_AT("foo.cc", 42) << "Expected nonfatal failure in foo.cc"; +} + +TEST(GtestFailAtTest, MessageContainsSpecifiedFileAndLineNumber) { + GTEST_FAIL_AT("foo.cc", 42) << "Expected fatal failure in foo.cc"; +} + +#if GTEST_IS_THREADSAFE + +// A unary function that may die. +void DieIf(bool should_die) { + GTEST_CHECK_(!should_die) << " - death inside DieIf()."; +} + +// Tests running death tests in a multi-threaded context. + +// Used for coordination between the main and the spawn thread. +struct SpawnThreadNotifications { + SpawnThreadNotifications() {} + + Notification spawn_thread_started; + Notification spawn_thread_ok_to_terminate; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(SpawnThreadNotifications); +}; + +// The function to be executed in the thread spawn by the +// MultipleThreads test (below). +static void ThreadRoutine(SpawnThreadNotifications* notifications) { + // Signals the main thread that this thread has started. + notifications->spawn_thread_started.Notify(); + + // Waits for permission to finish from the main thread. + notifications->spawn_thread_ok_to_terminate.WaitForNotification(); +} + +// This is a death-test test, but it's not named with a DeathTest +// suffix. It starts threads which might interfere with later +// death tests, so it must run after all other death tests. +class DeathTestAndMultiThreadsTest : public testing::Test { + protected: + // Starts a thread and waits for it to begin. + void SetUp() override { + thread_.reset(new ThreadWithParam( + &ThreadRoutine, ¬ifications_, nullptr)); + notifications_.spawn_thread_started.WaitForNotification(); + } + // Tells the thread to finish, and reaps it. + // Depending on the version of the thread library in use, + // a manager thread might still be left running that will interfere + // with later death tests. This is unfortunate, but this class + // cleans up after itself as best it can. + void TearDown() override { + notifications_.spawn_thread_ok_to_terminate.Notify(); + } + + private: + SpawnThreadNotifications notifications_; + std::unique_ptr > thread_; +}; + +#endif // GTEST_IS_THREADSAFE + +// The MixedUpTestSuiteTest test case verifies that Google Test will fail a +// test if it uses a different fixture class than what other tests in +// the same test case use. It deliberately contains two fixture +// classes with the same name but defined in different namespaces. + +// The MixedUpTestSuiteWithSameTestNameTest test case verifies that +// when the user defines two tests with the same test case name AND +// same test name (but in different namespaces), the second test will +// fail. + +namespace foo { + +class MixedUpTestSuiteTest : public testing::Test { +}; + +TEST_F(MixedUpTestSuiteTest, FirstTestFromNamespaceFoo) {} +TEST_F(MixedUpTestSuiteTest, SecondTestFromNamespaceFoo) {} + +class MixedUpTestSuiteWithSameTestNameTest : public testing::Test { +}; + +TEST_F(MixedUpTestSuiteWithSameTestNameTest, + TheSecondTestWithThisNameShouldFail) {} + +} // namespace foo + +namespace bar { + +class MixedUpTestSuiteTest : public testing::Test { +}; + +// The following two tests are expected to fail. We rely on the +// golden file to check that Google Test generates the right error message. +TEST_F(MixedUpTestSuiteTest, ThisShouldFail) {} +TEST_F(MixedUpTestSuiteTest, ThisShouldFailToo) {} + +class MixedUpTestSuiteWithSameTestNameTest : public testing::Test { +}; + +// Expected to fail. We rely on the golden file to check that Google Test +// generates the right error message. +TEST_F(MixedUpTestSuiteWithSameTestNameTest, + TheSecondTestWithThisNameShouldFail) {} + +} // namespace bar + +// The following two test cases verify that Google Test catches the user +// error of mixing TEST and TEST_F in the same test case. The first +// test case checks the scenario where TEST_F appears before TEST, and +// the second one checks where TEST appears before TEST_F. + +class TEST_F_before_TEST_in_same_test_case : public testing::Test { +}; + +TEST_F(TEST_F_before_TEST_in_same_test_case, DefinedUsingTEST_F) {} + +// Expected to fail. We rely on the golden file to check that Google Test +// generates the right error message. +TEST(TEST_F_before_TEST_in_same_test_case, DefinedUsingTESTAndShouldFail) {} + +class TEST_before_TEST_F_in_same_test_case : public testing::Test { +}; + +TEST(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST) {} + +// Expected to fail. We rely on the golden file to check that Google Test +// generates the right error message. +TEST_F(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST_FAndShouldFail) { +} + +// Used for testing EXPECT_NONFATAL_FAILURE() and EXPECT_FATAL_FAILURE(). +int global_integer = 0; + +// Tests that EXPECT_NONFATAL_FAILURE() can reference global variables. +TEST(ExpectNonfatalFailureTest, CanReferenceGlobalVariables) { + global_integer = 0; + EXPECT_NONFATAL_FAILURE({ + EXPECT_EQ(1, global_integer) << "Expected non-fatal failure."; + }, "Expected non-fatal failure."); +} + +// Tests that EXPECT_NONFATAL_FAILURE() can reference local variables +// (static or not). +TEST(ExpectNonfatalFailureTest, CanReferenceLocalVariables) { + int m = 0; + static int n; + n = 1; + EXPECT_NONFATAL_FAILURE({ + EXPECT_EQ(m, n) << "Expected non-fatal failure."; + }, "Expected non-fatal failure."); +} + +// Tests that EXPECT_NONFATAL_FAILURE() succeeds when there is exactly +// one non-fatal failure and no fatal failure. +TEST(ExpectNonfatalFailureTest, SucceedsWhenThereIsOneNonfatalFailure) { + EXPECT_NONFATAL_FAILURE({ + ADD_FAILURE() << "Expected non-fatal failure."; + }, "Expected non-fatal failure."); +} + +// Tests that EXPECT_NONFATAL_FAILURE() fails when there is no +// non-fatal failure. +TEST(ExpectNonfatalFailureTest, FailsWhenThereIsNoNonfatalFailure) { + printf("(expecting a failure)\n"); + EXPECT_NONFATAL_FAILURE({ + }, ""); +} + +// Tests that EXPECT_NONFATAL_FAILURE() fails when there are two +// non-fatal failures. +TEST(ExpectNonfatalFailureTest, FailsWhenThereAreTwoNonfatalFailures) { + printf("(expecting a failure)\n"); + EXPECT_NONFATAL_FAILURE({ + ADD_FAILURE() << "Expected non-fatal failure 1."; + ADD_FAILURE() << "Expected non-fatal failure 2."; + }, ""); +} + +// Tests that EXPECT_NONFATAL_FAILURE() fails when there is one fatal +// failure. +TEST(ExpectNonfatalFailureTest, FailsWhenThereIsOneFatalFailure) { + printf("(expecting a failure)\n"); + EXPECT_NONFATAL_FAILURE({ + FAIL() << "Expected fatal failure."; + }, ""); +} + +// Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being +// tested returns. +TEST(ExpectNonfatalFailureTest, FailsWhenStatementReturns) { + printf("(expecting a failure)\n"); + EXPECT_NONFATAL_FAILURE({ + return; + }, ""); +} + +#if GTEST_HAS_EXCEPTIONS + +// Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being +// tested throws. +TEST(ExpectNonfatalFailureTest, FailsWhenStatementThrows) { + printf("(expecting a failure)\n"); + try { + EXPECT_NONFATAL_FAILURE({ + throw 0; + }, ""); + } catch(int) { // NOLINT + } +} + +#endif // GTEST_HAS_EXCEPTIONS + +// Tests that EXPECT_FATAL_FAILURE() can reference global variables. +TEST(ExpectFatalFailureTest, CanReferenceGlobalVariables) { + global_integer = 0; + EXPECT_FATAL_FAILURE({ + ASSERT_EQ(1, global_integer) << "Expected fatal failure."; + }, "Expected fatal failure."); +} + +// Tests that EXPECT_FATAL_FAILURE() can reference local static +// variables. +TEST(ExpectFatalFailureTest, CanReferenceLocalStaticVariables) { + static int n; + n = 1; + EXPECT_FATAL_FAILURE({ + ASSERT_EQ(0, n) << "Expected fatal failure."; + }, "Expected fatal failure."); +} + +// Tests that EXPECT_FATAL_FAILURE() succeeds when there is exactly +// one fatal failure and no non-fatal failure. +TEST(ExpectFatalFailureTest, SucceedsWhenThereIsOneFatalFailure) { + EXPECT_FATAL_FAILURE({ + FAIL() << "Expected fatal failure."; + }, "Expected fatal failure."); +} + +// Tests that EXPECT_FATAL_FAILURE() fails when there is no fatal +// failure. +TEST(ExpectFatalFailureTest, FailsWhenThereIsNoFatalFailure) { + printf("(expecting a failure)\n"); + EXPECT_FATAL_FAILURE({ + }, ""); +} + +// A helper for generating a fatal failure. +void FatalFailure() { + FAIL() << "Expected fatal failure."; +} + +// Tests that EXPECT_FATAL_FAILURE() fails when there are two +// fatal failures. +TEST(ExpectFatalFailureTest, FailsWhenThereAreTwoFatalFailures) { + printf("(expecting a failure)\n"); + EXPECT_FATAL_FAILURE({ + FatalFailure(); + FatalFailure(); + }, ""); +} + +// Tests that EXPECT_FATAL_FAILURE() fails when there is one non-fatal +// failure. +TEST(ExpectFatalFailureTest, FailsWhenThereIsOneNonfatalFailure) { + printf("(expecting a failure)\n"); + EXPECT_FATAL_FAILURE({ + ADD_FAILURE() << "Expected non-fatal failure."; + }, ""); +} + +// Tests that EXPECT_FATAL_FAILURE() fails when the statement being +// tested returns. +TEST(ExpectFatalFailureTest, FailsWhenStatementReturns) { + printf("(expecting a failure)\n"); + EXPECT_FATAL_FAILURE({ + return; + }, ""); +} + +#if GTEST_HAS_EXCEPTIONS + +// Tests that EXPECT_FATAL_FAILURE() fails when the statement being +// tested throws. +TEST(ExpectFatalFailureTest, FailsWhenStatementThrows) { + printf("(expecting a failure)\n"); + try { + EXPECT_FATAL_FAILURE({ + throw 0; + }, ""); + } catch(int) { // NOLINT + } +} + +#endif // GTEST_HAS_EXCEPTIONS + +// This #ifdef block tests the output of value-parameterized tests. + +std::string ParamNameFunc(const testing::TestParamInfo& info) { + return info.param; +} + +class ParamTest : public testing::TestWithParam { +}; + +TEST_P(ParamTest, Success) { + EXPECT_EQ("a", GetParam()); +} + +TEST_P(ParamTest, Failure) { + EXPECT_EQ("b", GetParam()) << "Expected failure"; +} + +INSTANTIATE_TEST_SUITE_P(PrintingStrings, + ParamTest, + testing::Values(std::string("a")), + ParamNameFunc); + +// This #ifdef block tests the output of typed tests. +#if GTEST_HAS_TYPED_TEST + +template +class TypedTest : public testing::Test { +}; + +TYPED_TEST_SUITE(TypedTest, testing::Types); + +TYPED_TEST(TypedTest, Success) { + EXPECT_EQ(0, TypeParam()); +} + +TYPED_TEST(TypedTest, Failure) { + EXPECT_EQ(1, TypeParam()) << "Expected failure"; +} + +typedef testing::Types TypesForTestWithNames; + +template +class TypedTestWithNames : public testing::Test {}; + +class TypedTestNames { + public: + template + static std::string GetName(int i) { + if (std::is_same::value) + return std::string("char") + ::testing::PrintToString(i); + if (std::is_same::value) + return std::string("int") + ::testing::PrintToString(i); + } +}; + +TYPED_TEST_SUITE(TypedTestWithNames, TypesForTestWithNames, TypedTestNames); + +TYPED_TEST(TypedTestWithNames, Success) {} + +TYPED_TEST(TypedTestWithNames, Failure) { FAIL(); } + +#endif // GTEST_HAS_TYPED_TEST + +// This #ifdef block tests the output of type-parameterized tests. +#if GTEST_HAS_TYPED_TEST_P + +template +class TypedTestP : public testing::Test { +}; + +TYPED_TEST_SUITE_P(TypedTestP); + +TYPED_TEST_P(TypedTestP, Success) { + EXPECT_EQ(0U, TypeParam()); +} + +TYPED_TEST_P(TypedTestP, Failure) { + EXPECT_EQ(1U, TypeParam()) << "Expected failure"; +} + +REGISTER_TYPED_TEST_SUITE_P(TypedTestP, Success, Failure); + +typedef testing::Types UnsignedTypes; +INSTANTIATE_TYPED_TEST_SUITE_P(Unsigned, TypedTestP, UnsignedTypes); + +class TypedTestPNames { + public: + template + static std::string GetName(int i) { + if (std::is_same::value) { + return std::string("unsignedChar") + ::testing::PrintToString(i); + } + if (std::is_same::value) { + return std::string("unsignedInt") + ::testing::PrintToString(i); + } + } +}; + +INSTANTIATE_TYPED_TEST_SUITE_P(UnsignedCustomName, TypedTestP, UnsignedTypes, + TypedTestPNames); + +#endif // GTEST_HAS_TYPED_TEST_P + +#if GTEST_HAS_DEATH_TEST + +// We rely on the golden file to verify that tests whose test case +// name ends with DeathTest are run first. + +TEST(ADeathTest, ShouldRunFirst) { +} + +# if GTEST_HAS_TYPED_TEST + +// We rely on the golden file to verify that typed tests whose test +// case name ends with DeathTest are run first. + +template +class ATypedDeathTest : public testing::Test { +}; + +typedef testing::Types NumericTypes; +TYPED_TEST_SUITE(ATypedDeathTest, NumericTypes); + +TYPED_TEST(ATypedDeathTest, ShouldRunFirst) { +} + +# endif // GTEST_HAS_TYPED_TEST + +# if GTEST_HAS_TYPED_TEST_P + + +// We rely on the golden file to verify that type-parameterized tests +// whose test case name ends with DeathTest are run first. + +template +class ATypeParamDeathTest : public testing::Test { +}; + +TYPED_TEST_SUITE_P(ATypeParamDeathTest); + +TYPED_TEST_P(ATypeParamDeathTest, ShouldRunFirst) { +} + +REGISTER_TYPED_TEST_SUITE_P(ATypeParamDeathTest, ShouldRunFirst); + +INSTANTIATE_TYPED_TEST_SUITE_P(My, ATypeParamDeathTest, NumericTypes); + +# endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_HAS_DEATH_TEST + +// Tests various failure conditions of +// EXPECT_{,NON}FATAL_FAILURE{,_ON_ALL_THREADS}. +class ExpectFailureTest : public testing::Test { + public: // Must be public and not protected due to a bug in g++ 3.4.2. + enum FailureMode { + FATAL_FAILURE, + NONFATAL_FAILURE + }; + static void AddFailure(FailureMode failure) { + if (failure == FATAL_FAILURE) { + FAIL() << "Expected fatal failure."; + } else { + ADD_FAILURE() << "Expected non-fatal failure."; + } + } +}; + +TEST_F(ExpectFailureTest, ExpectFatalFailure) { + // Expected fatal failure, but succeeds. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE(SUCCEED(), "Expected fatal failure."); + // Expected fatal failure, but got a non-fatal failure. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Expected non-fatal " + "failure."); + // Wrong message. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE(AddFailure(FATAL_FAILURE), "Some other fatal failure " + "expected."); +} + +TEST_F(ExpectFailureTest, ExpectNonFatalFailure) { + // Expected non-fatal failure, but succeeds. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE(SUCCEED(), "Expected non-fatal failure."); + // Expected non-fatal failure, but got a fatal failure. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE(AddFailure(FATAL_FAILURE), "Expected fatal failure."); + // Wrong message. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Some other non-fatal " + "failure."); +} + +#if GTEST_IS_THREADSAFE + +class ExpectFailureWithThreadsTest : public ExpectFailureTest { + protected: + static void AddFailureInOtherThread(FailureMode failure) { + ThreadWithParam thread(&AddFailure, failure, nullptr); + thread.Join(); + } +}; + +TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailure) { + // We only intercept the current thread. + printf("(expecting 2 failures)\n"); + EXPECT_FATAL_FAILURE(AddFailureInOtherThread(FATAL_FAILURE), + "Expected fatal failure."); +} + +TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailure) { + // We only intercept the current thread. + printf("(expecting 2 failures)\n"); + EXPECT_NONFATAL_FAILURE(AddFailureInOtherThread(NONFATAL_FAILURE), + "Expected non-fatal failure."); +} + +typedef ExpectFailureWithThreadsTest ScopedFakeTestPartResultReporterTest; + +// Tests that the ScopedFakeTestPartResultReporter only catches failures from +// the current thread if it is instantiated with INTERCEPT_ONLY_CURRENT_THREAD. +TEST_F(ScopedFakeTestPartResultReporterTest, InterceptOnlyCurrentThread) { + printf("(expecting 2 failures)\n"); + TestPartResultArray results; + { + ScopedFakeTestPartResultReporter reporter( + ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD, + &results); + AddFailureInOtherThread(FATAL_FAILURE); + AddFailureInOtherThread(NONFATAL_FAILURE); + } + // The two failures should not have been intercepted. + EXPECT_EQ(0, results.size()) << "This shouldn't fail."; +} + +#endif // GTEST_IS_THREADSAFE + +TEST_F(ExpectFailureTest, ExpectFatalFailureOnAllThreads) { + // Expected fatal failure, but succeeds. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected fatal failure."); + // Expected fatal failure, but got a non-fatal failure. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE), + "Expected non-fatal failure."); + // Wrong message. + printf("(expecting 1 failure)\n"); + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE), + "Some other fatal failure expected."); +} + +TEST_F(ExpectFailureTest, ExpectNonFatalFailureOnAllThreads) { + // Expected non-fatal failure, but succeeds. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected non-fatal " + "failure."); + // Expected non-fatal failure, but got a fatal failure. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE), + "Expected fatal failure."); + // Wrong message. + printf("(expecting 1 failure)\n"); + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE), + "Some other non-fatal failure."); +} + +class DynamicFixture : public testing::Test { + protected: + DynamicFixture() { printf("DynamicFixture()\n"); } + ~DynamicFixture() override { printf("~DynamicFixture()\n"); } + void SetUp() override { printf("DynamicFixture::SetUp\n"); } + void TearDown() override { printf("DynamicFixture::TearDown\n"); } + + static void SetUpTestSuite() { printf("DynamicFixture::SetUpTestSuite\n"); } + static void TearDownTestSuite() { + printf("DynamicFixture::TearDownTestSuite\n"); + } +}; + +template +class DynamicTest : public DynamicFixture { + public: + void TestBody() override { EXPECT_TRUE(Pass); } +}; + +auto dynamic_test = ( + // Register two tests with the same fixture correctly. + testing::RegisterTest( + "DynamicFixture", "DynamicTestPass", nullptr, nullptr, __FILE__, + __LINE__, []() -> DynamicFixture* { return new DynamicTest; }), + testing::RegisterTest( + "DynamicFixture", "DynamicTestFail", nullptr, nullptr, __FILE__, + __LINE__, []() -> DynamicFixture* { return new DynamicTest; }), + + // Register the same fixture with another name. That's fine. + testing::RegisterTest( + "DynamicFixtureAnotherName", "DynamicTestPass", nullptr, nullptr, + __FILE__, __LINE__, + []() -> DynamicFixture* { return new DynamicTest; }), + + // Register two tests with the same fixture incorrectly. + testing::RegisterTest( + "BadDynamicFixture1", "FixtureBase", nullptr, nullptr, __FILE__, + __LINE__, []() -> DynamicFixture* { return new DynamicTest; }), + testing::RegisterTest( + "BadDynamicFixture1", "TestBase", nullptr, nullptr, __FILE__, __LINE__, + []() -> testing::Test* { return new DynamicTest; }), + + // Register two tests with the same fixture incorrectly by ommiting the + // return type. + testing::RegisterTest( + "BadDynamicFixture2", "FixtureBase", nullptr, nullptr, __FILE__, + __LINE__, []() -> DynamicFixture* { return new DynamicTest; }), + testing::RegisterTest("BadDynamicFixture2", "Derived", nullptr, nullptr, + __FILE__, __LINE__, + []() { return new DynamicTest; })); + +// Two test environments for testing testing::AddGlobalTestEnvironment(). + +class FooEnvironment : public testing::Environment { + public: + void SetUp() override { printf("%s", "FooEnvironment::SetUp() called.\n"); } + + void TearDown() override { + printf("%s", "FooEnvironment::TearDown() called.\n"); + FAIL() << "Expected fatal failure."; + } +}; + +class BarEnvironment : public testing::Environment { + public: + void SetUp() override { printf("%s", "BarEnvironment::SetUp() called.\n"); } + + void TearDown() override { + printf("%s", "BarEnvironment::TearDown() called.\n"); + ADD_FAILURE() << "Expected non-fatal failure."; + } +}; + +// The main function. +// +// The idea is to use Google Test to run all the tests we have defined (some +// of them are intended to fail), and then compare the test results +// with the "golden" file. +int main(int argc, char **argv) { + testing::GTEST_FLAG(print_time) = false; + + // We just run the tests, knowing some of them are intended to fail. + // We will use a separate Python script to compare the output of + // this program with the golden file. + + // It's hard to test InitGoogleTest() directly, as it has many + // global side effects. The following line serves as a sanity test + // for it. + testing::InitGoogleTest(&argc, argv); + bool internal_skip_environment_and_ad_hoc_tests = + std::count(argv, argv + argc, + std::string("internal_skip_environment_and_ad_hoc_tests")) > 0; + +#if GTEST_HAS_DEATH_TEST + if (testing::internal::GTEST_FLAG(internal_run_death_test) != "") { + // Skip the usual output capturing if we're running as the child + // process of an threadsafe-style death test. +# if GTEST_OS_WINDOWS + posix::FReopen("nul:", "w", stdout); +# else + posix::FReopen("/dev/null", "w", stdout); +# endif // GTEST_OS_WINDOWS + return RUN_ALL_TESTS(); + } +#endif // GTEST_HAS_DEATH_TEST + + if (internal_skip_environment_and_ad_hoc_tests) + return RUN_ALL_TESTS(); + + // Registers two global test environments. + // The golden file verifies that they are set up in the order they + // are registered, and torn down in the reverse order. + testing::AddGlobalTestEnvironment(new FooEnvironment); + testing::AddGlobalTestEnvironment(new BarEnvironment); +#if _MSC_VER +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4127 +#endif // _MSC_VER + return RunAllTests(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name1-test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name1-test.py new file mode 100644 index 0000000000000000000000000000000000000000..2a08477a77ebdf0aa55f23444abd6b839d90ba43 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name1-test.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# +# Copyright 2015 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Verifies that Google Test warns the user when not initialized properly.""" + +import gtest_test_utils + +binary_name = 'googletest-param-test-invalid-name1-test_' +COMMAND = gtest_test_utils.GetTestExecutablePath(binary_name) + + +def Assert(condition): + if not condition: + raise AssertionError + + +def TestExitCodeAndOutput(command): + """Runs the given command and verifies its exit code and output.""" + + err = ('Parameterized test name \'"InvalidWithQuotes"\' is invalid') + + p = gtest_test_utils.Subprocess(command) + Assert(p.terminated_by_signal) + + # Verify the output message contains appropriate output + Assert(err in p.output) + + +class GTestParamTestInvalidName1Test(gtest_test_utils.TestCase): + + def testExitCodeAndOutput(self): + TestExitCodeAndOutput(COMMAND) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name1-test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name1-test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..955d699900d8cd8eb19b251d35d6d5f7ee82e604 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name1-test_.cc @@ -0,0 +1,50 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#include "gtest/gtest.h" + +namespace { +class DummyTest : public ::testing::TestWithParam {}; + +TEST_P(DummyTest, Dummy) { +} + +INSTANTIATE_TEST_SUITE_P(InvalidTestName, + DummyTest, + ::testing::Values("InvalidWithQuotes"), + ::testing::PrintToStringParamName()); + +} // namespace + +int main(int argc, char *argv[]) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name2-test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name2-test.py new file mode 100644 index 0000000000000000000000000000000000000000..ab838f4632291d1cb78e4a11ec3ab0c773b94d5c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name2-test.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# +# Copyright 2015 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Verifies that Google Test warns the user when not initialized properly.""" + +import gtest_test_utils + +binary_name = 'googletest-param-test-invalid-name2-test_' +COMMAND = gtest_test_utils.GetTestExecutablePath(binary_name) + + +def Assert(condition): + if not condition: + raise AssertionError + + +def TestExitCodeAndOutput(command): + """Runs the given command and verifies its exit code and output.""" + + err = ('Duplicate parameterized test name \'a\'') + + p = gtest_test_utils.Subprocess(command) + Assert(p.terminated_by_signal) + + # Check for appropriate output + Assert(err in p.output) + + +class GTestParamTestInvalidName2Test(gtest_test_utils.TestCase): + + def testExitCodeAndOutput(self): + TestExitCodeAndOutput(COMMAND) + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name2-test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name2-test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..76371df54f0b3e2f277364dd8a22d02823c2eecc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-invalid-name2-test_.cc @@ -0,0 +1,55 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#include "gtest/gtest.h" + +namespace { +class DummyTest : public ::testing::TestWithParam {}; + +std::string StringParamTestSuffix( + const testing::TestParamInfo& info) { + return std::string(info.param); +} + +TEST_P(DummyTest, Dummy) { +} + +INSTANTIATE_TEST_SUITE_P(DuplicateTestNames, + DummyTest, + ::testing::Values("a", "b", "a", "c"), + StringParamTestSuffix); +} // namespace + +int main(int argc, char *argv[]) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..6c187dfff0c1239cf02c09f284d087376cbfb22d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-test.cc @@ -0,0 +1,1055 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Tests for Google Test itself. This file verifies that the parameter +// generators objects produce correct parameter sequences and that +// Google Test runtime instantiates correct tests from those sequences. + +#include "gtest/gtest.h" + +# include +# include +# include +# include +# include +# include + +# include "src/gtest-internal-inl.h" // for UnitTestOptions +# include "test/googletest-param-test-test.h" + +using ::std::vector; +using ::std::sort; + +using ::testing::AddGlobalTestEnvironment; +using ::testing::Bool; +using ::testing::Combine; +using ::testing::Message; +using ::testing::Range; +using ::testing::TestWithParam; +using ::testing::Values; +using ::testing::ValuesIn; + +using ::testing::internal::ParamGenerator; +using ::testing::internal::UnitTestOptions; + +// Prints a value to a string. +// +// FIXME: remove PrintValue() when we move matchers and +// EXPECT_THAT() from Google Mock to Google Test. At that time, we +// can write EXPECT_THAT(x, Eq(y)) to compare two tuples x and y, as +// EXPECT_THAT() and the matchers know how to print tuples. +template +::std::string PrintValue(const T& value) { + return testing::PrintToString(value); +} + +// Verifies that a sequence generated by the generator and accessed +// via the iterator object matches the expected one using Google Test +// assertions. +template +void VerifyGenerator(const ParamGenerator& generator, + const T (&expected_values)[N]) { + typename ParamGenerator::iterator it = generator.begin(); + for (size_t i = 0; i < N; ++i) { + ASSERT_FALSE(it == generator.end()) + << "At element " << i << " when accessing via an iterator " + << "created with the copy constructor.\n"; + // We cannot use EXPECT_EQ() here as the values may be tuples, + // which don't support <<. + EXPECT_TRUE(expected_values[i] == *it) + << "where i is " << i + << ", expected_values[i] is " << PrintValue(expected_values[i]) + << ", *it is " << PrintValue(*it) + << ", and 'it' is an iterator created with the copy constructor.\n"; + ++it; + } + EXPECT_TRUE(it == generator.end()) + << "At the presumed end of sequence when accessing via an iterator " + << "created with the copy constructor.\n"; + + // Test the iterator assignment. The following lines verify that + // the sequence accessed via an iterator initialized via the + // assignment operator (as opposed to a copy constructor) matches + // just the same. + it = generator.begin(); + for (size_t i = 0; i < N; ++i) { + ASSERT_FALSE(it == generator.end()) + << "At element " << i << " when accessing via an iterator " + << "created with the assignment operator.\n"; + EXPECT_TRUE(expected_values[i] == *it) + << "where i is " << i + << ", expected_values[i] is " << PrintValue(expected_values[i]) + << ", *it is " << PrintValue(*it) + << ", and 'it' is an iterator created with the copy constructor.\n"; + ++it; + } + EXPECT_TRUE(it == generator.end()) + << "At the presumed end of sequence when accessing via an iterator " + << "created with the assignment operator.\n"; +} + +template +void VerifyGeneratorIsEmpty(const ParamGenerator& generator) { + typename ParamGenerator::iterator it = generator.begin(); + EXPECT_TRUE(it == generator.end()); + + it = generator.begin(); + EXPECT_TRUE(it == generator.end()); +} + +// Generator tests. They test that each of the provided generator functions +// generates an expected sequence of values. The general test pattern +// instantiates a generator using one of the generator functions, +// checks the sequence produced by the generator using its iterator API, +// and then resets the iterator back to the beginning of the sequence +// and checks the sequence again. + +// Tests that iterators produced by generator functions conform to the +// ForwardIterator concept. +TEST(IteratorTest, ParamIteratorConformsToForwardIteratorConcept) { + const ParamGenerator gen = Range(0, 10); + ParamGenerator::iterator it = gen.begin(); + + // Verifies that iterator initialization works as expected. + ParamGenerator::iterator it2 = it; + EXPECT_TRUE(*it == *it2) << "Initialized iterators must point to the " + << "element same as its source points to"; + + // Verifies that iterator assignment works as expected. + ++it; + EXPECT_FALSE(*it == *it2); + it2 = it; + EXPECT_TRUE(*it == *it2) << "Assigned iterators must point to the " + << "element same as its source points to"; + + // Verifies that prefix operator++() returns *this. + EXPECT_EQ(&it, &(++it)) << "Result of the prefix operator++ must be " + << "refer to the original object"; + + // Verifies that the result of the postfix operator++ points to the value + // pointed to by the original iterator. + int original_value = *it; // Have to compute it outside of macro call to be + // unaffected by the parameter evaluation order. + EXPECT_EQ(original_value, *(it++)); + + // Verifies that prefix and postfix operator++() advance an iterator + // all the same. + it2 = it; + ++it; + ++it2; + EXPECT_TRUE(*it == *it2); +} + +// Tests that Range() generates the expected sequence. +TEST(RangeTest, IntRangeWithDefaultStep) { + const ParamGenerator gen = Range(0, 3); + const int expected_values[] = {0, 1, 2}; + VerifyGenerator(gen, expected_values); +} + +// Edge case. Tests that Range() generates the single element sequence +// as expected when provided with range limits that are equal. +TEST(RangeTest, IntRangeSingleValue) { + const ParamGenerator gen = Range(0, 1); + const int expected_values[] = {0}; + VerifyGenerator(gen, expected_values); +} + +// Edge case. Tests that Range() with generates empty sequence when +// supplied with an empty range. +TEST(RangeTest, IntRangeEmpty) { + const ParamGenerator gen = Range(0, 0); + VerifyGeneratorIsEmpty(gen); +} + +// Tests that Range() with custom step (greater then one) generates +// the expected sequence. +TEST(RangeTest, IntRangeWithCustomStep) { + const ParamGenerator gen = Range(0, 9, 3); + const int expected_values[] = {0, 3, 6}; + VerifyGenerator(gen, expected_values); +} + +// Tests that Range() with custom step (greater then one) generates +// the expected sequence when the last element does not fall on the +// upper range limit. Sequences generated by Range() must not have +// elements beyond the range limits. +TEST(RangeTest, IntRangeWithCustomStepOverUpperBound) { + const ParamGenerator gen = Range(0, 4, 3); + const int expected_values[] = {0, 3}; + VerifyGenerator(gen, expected_values); +} + +// Verifies that Range works with user-defined types that define +// copy constructor, operator=(), operator+(), and operator<(). +class DogAdder { + public: + explicit DogAdder(const char* a_value) : value_(a_value) {} + DogAdder(const DogAdder& other) : value_(other.value_.c_str()) {} + + DogAdder operator=(const DogAdder& other) { + if (this != &other) + value_ = other.value_; + return *this; + } + DogAdder operator+(const DogAdder& other) const { + Message msg; + msg << value_.c_str() << other.value_.c_str(); + return DogAdder(msg.GetString().c_str()); + } + bool operator<(const DogAdder& other) const { + return value_ < other.value_; + } + const std::string& value() const { return value_; } + + private: + std::string value_; +}; + +TEST(RangeTest, WorksWithACustomType) { + const ParamGenerator gen = + Range(DogAdder("cat"), DogAdder("catdogdog"), DogAdder("dog")); + ParamGenerator::iterator it = gen.begin(); + + ASSERT_FALSE(it == gen.end()); + EXPECT_STREQ("cat", it->value().c_str()); + + ASSERT_FALSE(++it == gen.end()); + EXPECT_STREQ("catdog", it->value().c_str()); + + EXPECT_TRUE(++it == gen.end()); +} + +class IntWrapper { + public: + explicit IntWrapper(int a_value) : value_(a_value) {} + IntWrapper(const IntWrapper& other) : value_(other.value_) {} + + IntWrapper operator=(const IntWrapper& other) { + value_ = other.value_; + return *this; + } + // operator+() adds a different type. + IntWrapper operator+(int other) const { return IntWrapper(value_ + other); } + bool operator<(const IntWrapper& other) const { + return value_ < other.value_; + } + int value() const { return value_; } + + private: + int value_; +}; + +TEST(RangeTest, WorksWithACustomTypeWithDifferentIncrementType) { + const ParamGenerator gen = Range(IntWrapper(0), IntWrapper(2)); + ParamGenerator::iterator it = gen.begin(); + + ASSERT_FALSE(it == gen.end()); + EXPECT_EQ(0, it->value()); + + ASSERT_FALSE(++it == gen.end()); + EXPECT_EQ(1, it->value()); + + EXPECT_TRUE(++it == gen.end()); +} + +// Tests that ValuesIn() with an array parameter generates +// the expected sequence. +TEST(ValuesInTest, ValuesInArray) { + int array[] = {3, 5, 8}; + const ParamGenerator gen = ValuesIn(array); + VerifyGenerator(gen, array); +} + +// Tests that ValuesIn() with a const array parameter generates +// the expected sequence. +TEST(ValuesInTest, ValuesInConstArray) { + const int array[] = {3, 5, 8}; + const ParamGenerator gen = ValuesIn(array); + VerifyGenerator(gen, array); +} + +// Edge case. Tests that ValuesIn() with an array parameter containing a +// single element generates the single element sequence. +TEST(ValuesInTest, ValuesInSingleElementArray) { + int array[] = {42}; + const ParamGenerator gen = ValuesIn(array); + VerifyGenerator(gen, array); +} + +// Tests that ValuesIn() generates the expected sequence for an STL +// container (vector). +TEST(ValuesInTest, ValuesInVector) { + typedef ::std::vector ContainerType; + ContainerType values; + values.push_back(3); + values.push_back(5); + values.push_back(8); + const ParamGenerator gen = ValuesIn(values); + + const int expected_values[] = {3, 5, 8}; + VerifyGenerator(gen, expected_values); +} + +// Tests that ValuesIn() generates the expected sequence. +TEST(ValuesInTest, ValuesInIteratorRange) { + typedef ::std::vector ContainerType; + ContainerType values; + values.push_back(3); + values.push_back(5); + values.push_back(8); + const ParamGenerator gen = ValuesIn(values.begin(), values.end()); + + const int expected_values[] = {3, 5, 8}; + VerifyGenerator(gen, expected_values); +} + +// Edge case. Tests that ValuesIn() provided with an iterator range specifying a +// single value generates a single-element sequence. +TEST(ValuesInTest, ValuesInSingleElementIteratorRange) { + typedef ::std::vector ContainerType; + ContainerType values; + values.push_back(42); + const ParamGenerator gen = ValuesIn(values.begin(), values.end()); + + const int expected_values[] = {42}; + VerifyGenerator(gen, expected_values); +} + +// Edge case. Tests that ValuesIn() provided with an empty iterator range +// generates an empty sequence. +TEST(ValuesInTest, ValuesInEmptyIteratorRange) { + typedef ::std::vector ContainerType; + ContainerType values; + const ParamGenerator gen = ValuesIn(values.begin(), values.end()); + + VerifyGeneratorIsEmpty(gen); +} + +// Tests that the Values() generates the expected sequence. +TEST(ValuesTest, ValuesWorks) { + const ParamGenerator gen = Values(3, 5, 8); + + const int expected_values[] = {3, 5, 8}; + VerifyGenerator(gen, expected_values); +} + +// Tests that Values() generates the expected sequences from elements of +// different types convertible to ParamGenerator's parameter type. +TEST(ValuesTest, ValuesWorksForValuesOfCompatibleTypes) { + const ParamGenerator gen = Values(3, 5.0f, 8.0); + + const double expected_values[] = {3.0, 5.0, 8.0}; + VerifyGenerator(gen, expected_values); +} + +TEST(ValuesTest, ValuesWorksForMaxLengthList) { + const ParamGenerator gen = Values( + 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, + 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, + 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, + 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, + 410, 420, 430, 440, 450, 460, 470, 480, 490, 500); + + const int expected_values[] = { + 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, + 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, + 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, + 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, + 410, 420, 430, 440, 450, 460, 470, 480, 490, 500}; + VerifyGenerator(gen, expected_values); +} + +// Edge case test. Tests that single-parameter Values() generates the sequence +// with the single value. +TEST(ValuesTest, ValuesWithSingleParameter) { + const ParamGenerator gen = Values(42); + + const int expected_values[] = {42}; + VerifyGenerator(gen, expected_values); +} + +// Tests that Bool() generates sequence (false, true). +TEST(BoolTest, BoolWorks) { + const ParamGenerator gen = Bool(); + + const bool expected_values[] = {false, true}; + VerifyGenerator(gen, expected_values); +} + +// Tests that Combine() with two parameters generates the expected sequence. +TEST(CombineTest, CombineWithTwoParameters) { + const char* foo = "foo"; + const char* bar = "bar"; + const ParamGenerator > gen = + Combine(Values(foo, bar), Values(3, 4)); + + std::tuple expected_values[] = { + std::make_tuple(foo, 3), std::make_tuple(foo, 4), std::make_tuple(bar, 3), + std::make_tuple(bar, 4)}; + VerifyGenerator(gen, expected_values); +} + +// Tests that Combine() with three parameters generates the expected sequence. +TEST(CombineTest, CombineWithThreeParameters) { + const ParamGenerator > gen = + Combine(Values(0, 1), Values(3, 4), Values(5, 6)); + std::tuple expected_values[] = { + std::make_tuple(0, 3, 5), std::make_tuple(0, 3, 6), + std::make_tuple(0, 4, 5), std::make_tuple(0, 4, 6), + std::make_tuple(1, 3, 5), std::make_tuple(1, 3, 6), + std::make_tuple(1, 4, 5), std::make_tuple(1, 4, 6)}; + VerifyGenerator(gen, expected_values); +} + +// Tests that the Combine() with the first parameter generating a single value +// sequence generates a sequence with the number of elements equal to the +// number of elements in the sequence generated by the second parameter. +TEST(CombineTest, CombineWithFirstParameterSingleValue) { + const ParamGenerator > gen = + Combine(Values(42), Values(0, 1)); + + std::tuple expected_values[] = {std::make_tuple(42, 0), + std::make_tuple(42, 1)}; + VerifyGenerator(gen, expected_values); +} + +// Tests that the Combine() with the second parameter generating a single value +// sequence generates a sequence with the number of elements equal to the +// number of elements in the sequence generated by the first parameter. +TEST(CombineTest, CombineWithSecondParameterSingleValue) { + const ParamGenerator > gen = + Combine(Values(0, 1), Values(42)); + + std::tuple expected_values[] = {std::make_tuple(0, 42), + std::make_tuple(1, 42)}; + VerifyGenerator(gen, expected_values); +} + +// Tests that when the first parameter produces an empty sequence, +// Combine() produces an empty sequence, too. +TEST(CombineTest, CombineWithFirstParameterEmptyRange) { + const ParamGenerator > gen = + Combine(Range(0, 0), Values(0, 1)); + VerifyGeneratorIsEmpty(gen); +} + +// Tests that when the second parameter produces an empty sequence, +// Combine() produces an empty sequence, too. +TEST(CombineTest, CombineWithSecondParameterEmptyRange) { + const ParamGenerator > gen = + Combine(Values(0, 1), Range(1, 1)); + VerifyGeneratorIsEmpty(gen); +} + +// Edge case. Tests that combine works with the maximum number +// of parameters supported by Google Test (currently 10). +TEST(CombineTest, CombineWithMaxNumberOfParameters) { + const char* foo = "foo"; + const char* bar = "bar"; + const ParamGenerator< + std::tuple > + gen = + Combine(Values(foo, bar), Values(1), Values(2), Values(3), Values(4), + Values(5), Values(6), Values(7), Values(8), Values(9)); + + std::tuple + expected_values[] = {std::make_tuple(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9), + std::make_tuple(bar, 1, 2, 3, 4, 5, 6, 7, 8, 9)}; + VerifyGenerator(gen, expected_values); +} + +class NonDefaultConstructAssignString { + public: + NonDefaultConstructAssignString(const std::string& s) : str_(s) {} + + const std::string& str() const { return str_; } + + private: + std::string str_; + + // Not default constructible + NonDefaultConstructAssignString(); + // Not assignable + void operator=(const NonDefaultConstructAssignString&); +}; + +TEST(CombineTest, NonDefaultConstructAssign) { + const ParamGenerator > gen = + Combine(Values(0, 1), Values(NonDefaultConstructAssignString("A"), + NonDefaultConstructAssignString("B"))); + + ParamGenerator >::iterator + it = gen.begin(); + + EXPECT_EQ(0, std::get<0>(*it)); + EXPECT_EQ("A", std::get<1>(*it).str()); + ++it; + + EXPECT_EQ(0, std::get<0>(*it)); + EXPECT_EQ("B", std::get<1>(*it).str()); + ++it; + + EXPECT_EQ(1, std::get<0>(*it)); + EXPECT_EQ("A", std::get<1>(*it).str()); + ++it; + + EXPECT_EQ(1, std::get<0>(*it)); + EXPECT_EQ("B", std::get<1>(*it).str()); + ++it; + + EXPECT_TRUE(it == gen.end()); +} + + +// Tests that an generator produces correct sequence after being +// assigned from another generator. +TEST(ParamGeneratorTest, AssignmentWorks) { + ParamGenerator gen = Values(1, 2); + const ParamGenerator gen2 = Values(3, 4); + gen = gen2; + + const int expected_values[] = {3, 4}; + VerifyGenerator(gen, expected_values); +} + +// This test verifies that the tests are expanded and run as specified: +// one test per element from the sequence produced by the generator +// specified in INSTANTIATE_TEST_SUITE_P. It also verifies that the test's +// fixture constructor, SetUp(), and TearDown() have run and have been +// supplied with the correct parameters. + +// The use of environment object allows detection of the case where no test +// case functionality is run at all. In this case TearDownTestSuite will not +// be able to detect missing tests, naturally. +template +class TestGenerationEnvironment : public ::testing::Environment { + public: + static TestGenerationEnvironment* Instance() { + static TestGenerationEnvironment* instance = new TestGenerationEnvironment; + return instance; + } + + void FixtureConstructorExecuted() { fixture_constructor_count_++; } + void SetUpExecuted() { set_up_count_++; } + void TearDownExecuted() { tear_down_count_++; } + void TestBodyExecuted() { test_body_count_++; } + + void TearDown() override { + // If all MultipleTestGenerationTest tests have been de-selected + // by the filter flag, the following checks make no sense. + bool perform_check = false; + + for (int i = 0; i < kExpectedCalls; ++i) { + Message msg; + msg << "TestsExpandedAndRun/" << i; + if (UnitTestOptions::FilterMatchesTest( + "TestExpansionModule/MultipleTestGenerationTest", + msg.GetString().c_str())) { + perform_check = true; + } + } + if (perform_check) { + EXPECT_EQ(kExpectedCalls, fixture_constructor_count_) + << "Fixture constructor of ParamTestGenerationTest test case " + << "has not been run as expected."; + EXPECT_EQ(kExpectedCalls, set_up_count_) + << "Fixture SetUp method of ParamTestGenerationTest test case " + << "has not been run as expected."; + EXPECT_EQ(kExpectedCalls, tear_down_count_) + << "Fixture TearDown method of ParamTestGenerationTest test case " + << "has not been run as expected."; + EXPECT_EQ(kExpectedCalls, test_body_count_) + << "Test in ParamTestGenerationTest test case " + << "has not been run as expected."; + } + } + + private: + TestGenerationEnvironment() : fixture_constructor_count_(0), set_up_count_(0), + tear_down_count_(0), test_body_count_(0) {} + + int fixture_constructor_count_; + int set_up_count_; + int tear_down_count_; + int test_body_count_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationEnvironment); +}; + +const int test_generation_params[] = {36, 42, 72}; + +class TestGenerationTest : public TestWithParam { + public: + enum { + PARAMETER_COUNT = + sizeof(test_generation_params)/sizeof(test_generation_params[0]) + }; + + typedef TestGenerationEnvironment Environment; + + TestGenerationTest() { + Environment::Instance()->FixtureConstructorExecuted(); + current_parameter_ = GetParam(); + } + void SetUp() override { + Environment::Instance()->SetUpExecuted(); + EXPECT_EQ(current_parameter_, GetParam()); + } + void TearDown() override { + Environment::Instance()->TearDownExecuted(); + EXPECT_EQ(current_parameter_, GetParam()); + } + + static void SetUpTestSuite() { + bool all_tests_in_test_case_selected = true; + + for (int i = 0; i < PARAMETER_COUNT; ++i) { + Message test_name; + test_name << "TestsExpandedAndRun/" << i; + if ( !UnitTestOptions::FilterMatchesTest( + "TestExpansionModule/MultipleTestGenerationTest", + test_name.GetString())) { + all_tests_in_test_case_selected = false; + } + } + EXPECT_TRUE(all_tests_in_test_case_selected) + << "When running the TestGenerationTest test case all of its tests\n" + << "must be selected by the filter flag for the test case to pass.\n" + << "If not all of them are enabled, we can't reliably conclude\n" + << "that the correct number of tests have been generated."; + + collected_parameters_.clear(); + } + + static void TearDownTestSuite() { + vector expected_values(test_generation_params, + test_generation_params + PARAMETER_COUNT); + // Test execution order is not guaranteed by Google Test, + // so the order of values in collected_parameters_ can be + // different and we have to sort to compare. + sort(expected_values.begin(), expected_values.end()); + sort(collected_parameters_.begin(), collected_parameters_.end()); + + EXPECT_TRUE(collected_parameters_ == expected_values); + } + + protected: + int current_parameter_; + static vector collected_parameters_; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationTest); +}; +vector TestGenerationTest::collected_parameters_; + +TEST_P(TestGenerationTest, TestsExpandedAndRun) { + Environment::Instance()->TestBodyExecuted(); + EXPECT_EQ(current_parameter_, GetParam()); + collected_parameters_.push_back(GetParam()); +} +INSTANTIATE_TEST_SUITE_P(TestExpansionModule, TestGenerationTest, + ValuesIn(test_generation_params)); + +// This test verifies that the element sequence (third parameter of +// INSTANTIATE_TEST_SUITE_P) is evaluated in InitGoogleTest() and neither at +// the call site of INSTANTIATE_TEST_SUITE_P nor in RUN_ALL_TESTS(). For +// that, we declare param_value_ to be a static member of +// GeneratorEvaluationTest and initialize it to 0. We set it to 1 in +// main(), just before invocation of InitGoogleTest(). After calling +// InitGoogleTest(), we set the value to 2. If the sequence is evaluated +// before or after InitGoogleTest, INSTANTIATE_TEST_SUITE_P will create a +// test with parameter other than 1, and the test body will fail the +// assertion. +class GeneratorEvaluationTest : public TestWithParam { + public: + static int param_value() { return param_value_; } + static void set_param_value(int param_value) { param_value_ = param_value; } + + private: + static int param_value_; +}; +int GeneratorEvaluationTest::param_value_ = 0; + +TEST_P(GeneratorEvaluationTest, GeneratorsEvaluatedInMain) { + EXPECT_EQ(1, GetParam()); +} +INSTANTIATE_TEST_SUITE_P(GenEvalModule, GeneratorEvaluationTest, + Values(GeneratorEvaluationTest::param_value())); + +// Tests that generators defined in a different translation unit are +// functional. Generator extern_gen is defined in gtest-param-test_test2.cc. +extern ParamGenerator extern_gen; +class ExternalGeneratorTest : public TestWithParam {}; +TEST_P(ExternalGeneratorTest, ExternalGenerator) { + // Sequence produced by extern_gen contains only a single value + // which we verify here. + EXPECT_EQ(GetParam(), 33); +} +INSTANTIATE_TEST_SUITE_P(ExternalGeneratorModule, ExternalGeneratorTest, + extern_gen); + +// Tests that a parameterized test case can be defined in one translation +// unit and instantiated in another. This test will be instantiated in +// gtest-param-test_test2.cc. ExternalInstantiationTest fixture class is +// defined in gtest-param-test_test.h. +TEST_P(ExternalInstantiationTest, IsMultipleOf33) { + EXPECT_EQ(0, GetParam() % 33); +} + +// Tests that a parameterized test case can be instantiated with multiple +// generators. +class MultipleInstantiationTest : public TestWithParam {}; +TEST_P(MultipleInstantiationTest, AllowsMultipleInstances) { +} +INSTANTIATE_TEST_SUITE_P(Sequence1, MultipleInstantiationTest, Values(1, 2)); +INSTANTIATE_TEST_SUITE_P(Sequence2, MultipleInstantiationTest, Range(3, 5)); + +// Tests that a parameterized test case can be instantiated +// in multiple translation units. This test will be instantiated +// here and in gtest-param-test_test2.cc. +// InstantiationInMultipleTranslationUnitsTest fixture class +// is defined in gtest-param-test_test.h. +TEST_P(InstantiationInMultipleTranslationUnitsTest, IsMultipleOf42) { + EXPECT_EQ(0, GetParam() % 42); +} +INSTANTIATE_TEST_SUITE_P(Sequence1, InstantiationInMultipleTranslationUnitsTest, + Values(42, 42 * 2)); + +// Tests that each iteration of parameterized test runs in a separate test +// object. +class SeparateInstanceTest : public TestWithParam { + public: + SeparateInstanceTest() : count_(0) {} + + static void TearDownTestSuite() { + EXPECT_GE(global_count_, 2) + << "If some (but not all) SeparateInstanceTest tests have been " + << "filtered out this test will fail. Make sure that all " + << "GeneratorEvaluationTest are selected or de-selected together " + << "by the test filter."; + } + + protected: + int count_; + static int global_count_; +}; +int SeparateInstanceTest::global_count_ = 0; + +TEST_P(SeparateInstanceTest, TestsRunInSeparateInstances) { + EXPECT_EQ(0, count_++); + global_count_++; +} +INSTANTIATE_TEST_SUITE_P(FourElemSequence, SeparateInstanceTest, Range(1, 4)); + +// Tests that all instantiations of a test have named appropriately. Test +// defined with TEST_P(TestSuiteName, TestName) and instantiated with +// INSTANTIATE_TEST_SUITE_P(SequenceName, TestSuiteName, generator) must be +// named SequenceName/TestSuiteName.TestName/i, where i is the 0-based index of +// the sequence element used to instantiate the test. +class NamingTest : public TestWithParam {}; + +TEST_P(NamingTest, TestsReportCorrectNamesAndParameters) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + EXPECT_STREQ("ZeroToFiveSequence/NamingTest", test_info->test_suite_name()); + + Message index_stream; + index_stream << "TestsReportCorrectNamesAndParameters/" << GetParam(); + EXPECT_STREQ(index_stream.GetString().c_str(), test_info->name()); + + EXPECT_EQ(::testing::PrintToString(GetParam()), test_info->value_param()); +} + +INSTANTIATE_TEST_SUITE_P(ZeroToFiveSequence, NamingTest, Range(0, 5)); + +// Tests that macros in test names are expanded correctly. +class MacroNamingTest : public TestWithParam {}; + +#define PREFIX_WITH_FOO(test_name) Foo##test_name +#define PREFIX_WITH_MACRO(test_name) Macro##test_name + +TEST_P(PREFIX_WITH_MACRO(NamingTest), PREFIX_WITH_FOO(SomeTestName)) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + EXPECT_STREQ("FortyTwo/MacroNamingTest", test_info->test_suite_name()); + EXPECT_STREQ("FooSomeTestName", test_info->name()); +} + +INSTANTIATE_TEST_SUITE_P(FortyTwo, MacroNamingTest, Values(42)); + +// Tests the same thing for non-parametrized tests. +class MacroNamingTestNonParametrized : public ::testing::Test {}; + +TEST_F(PREFIX_WITH_MACRO(NamingTestNonParametrized), + PREFIX_WITH_FOO(SomeTestName)) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + EXPECT_STREQ("MacroNamingTestNonParametrized", test_info->test_suite_name()); + EXPECT_STREQ("FooSomeTestName", test_info->name()); +} + +// Tests that user supplied custom parameter names are working correctly. +// Runs the test with a builtin helper method which uses PrintToString, +// as well as a custom function and custom functor to ensure all possible +// uses work correctly. +class CustomFunctorNamingTest : public TestWithParam {}; +TEST_P(CustomFunctorNamingTest, CustomTestNames) {} + +struct CustomParamNameFunctor { + std::string operator()(const ::testing::TestParamInfo& inf) { + return inf.param; + } +}; + +INSTANTIATE_TEST_SUITE_P(CustomParamNameFunctor, CustomFunctorNamingTest, + Values(std::string("FunctorName")), + CustomParamNameFunctor()); + +INSTANTIATE_TEST_SUITE_P(AllAllowedCharacters, CustomFunctorNamingTest, + Values("abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "01234567890_"), + CustomParamNameFunctor()); + +inline std::string CustomParamNameFunction( + const ::testing::TestParamInfo& inf) { + return inf.param; +} + +class CustomFunctionNamingTest : public TestWithParam {}; +TEST_P(CustomFunctionNamingTest, CustomTestNames) {} + +INSTANTIATE_TEST_SUITE_P(CustomParamNameFunction, CustomFunctionNamingTest, + Values(std::string("FunctionName")), + CustomParamNameFunction); + +INSTANTIATE_TEST_SUITE_P(CustomParamNameFunctionP, CustomFunctionNamingTest, + Values(std::string("FunctionNameP")), + &CustomParamNameFunction); + +// Test custom naming with a lambda + +class CustomLambdaNamingTest : public TestWithParam {}; +TEST_P(CustomLambdaNamingTest, CustomTestNames) {} + +INSTANTIATE_TEST_SUITE_P(CustomParamNameLambda, CustomLambdaNamingTest, + Values(std::string("LambdaName")), + [](const ::testing::TestParamInfo& inf) { + return inf.param; + }); + +TEST(CustomNamingTest, CheckNameRegistry) { + ::testing::UnitTest* unit_test = ::testing::UnitTest::GetInstance(); + std::set test_names; + for (int suite_num = 0; suite_num < unit_test->total_test_suite_count(); + ++suite_num) { + const ::testing::TestSuite* test_suite = unit_test->GetTestSuite(suite_num); + for (int test_num = 0; test_num < test_suite->total_test_count(); + ++test_num) { + const ::testing::TestInfo* test_info = test_suite->GetTestInfo(test_num); + test_names.insert(std::string(test_info->name())); + } + } + EXPECT_EQ(1u, test_names.count("CustomTestNames/FunctorName")); + EXPECT_EQ(1u, test_names.count("CustomTestNames/FunctionName")); + EXPECT_EQ(1u, test_names.count("CustomTestNames/FunctionNameP")); + EXPECT_EQ(1u, test_names.count("CustomTestNames/LambdaName")); +} + +// Test a numeric name to ensure PrintToStringParamName works correctly. + +class CustomIntegerNamingTest : public TestWithParam {}; + +TEST_P(CustomIntegerNamingTest, TestsReportCorrectNames) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + Message test_name_stream; + test_name_stream << "TestsReportCorrectNames/" << GetParam(); + EXPECT_STREQ(test_name_stream.GetString().c_str(), test_info->name()); +} + +INSTANTIATE_TEST_SUITE_P(PrintToString, CustomIntegerNamingTest, Range(0, 5), + ::testing::PrintToStringParamName()); + +// Test a custom struct with PrintToString. + +struct CustomStruct { + explicit CustomStruct(int value) : x(value) {} + int x; +}; + +std::ostream& operator<<(std::ostream& stream, const CustomStruct& val) { + stream << val.x; + return stream; +} + +class CustomStructNamingTest : public TestWithParam {}; + +TEST_P(CustomStructNamingTest, TestsReportCorrectNames) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + Message test_name_stream; + test_name_stream << "TestsReportCorrectNames/" << GetParam(); + EXPECT_STREQ(test_name_stream.GetString().c_str(), test_info->name()); +} + +INSTANTIATE_TEST_SUITE_P(PrintToString, CustomStructNamingTest, + Values(CustomStruct(0), CustomStruct(1)), + ::testing::PrintToStringParamName()); + +// Test that using a stateful parameter naming function works as expected. + +struct StatefulNamingFunctor { + StatefulNamingFunctor() : sum(0) {} + std::string operator()(const ::testing::TestParamInfo& info) { + int value = info.param + sum; + sum += info.param; + return ::testing::PrintToString(value); + } + int sum; +}; + +class StatefulNamingTest : public ::testing::TestWithParam { + protected: + StatefulNamingTest() : sum_(0) {} + int sum_; +}; + +TEST_P(StatefulNamingTest, TestsReportCorrectNames) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + sum_ += GetParam(); + Message test_name_stream; + test_name_stream << "TestsReportCorrectNames/" << sum_; + EXPECT_STREQ(test_name_stream.GetString().c_str(), test_info->name()); +} + +INSTANTIATE_TEST_SUITE_P(StatefulNamingFunctor, StatefulNamingTest, Range(0, 5), + StatefulNamingFunctor()); + +// Class that cannot be streamed into an ostream. It needs to be copyable +// (and, in case of MSVC, also assignable) in order to be a test parameter +// type. Its default copy constructor and assignment operator do exactly +// what we need. +class Unstreamable { + public: + explicit Unstreamable(int value) : value_(value) {} + // -Wunused-private-field: dummy accessor for `value_`. + const int& dummy_value() const { return value_; } + + private: + int value_; +}; + +class CommentTest : public TestWithParam {}; + +TEST_P(CommentTest, TestsCorrectlyReportUnstreamableParams) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + EXPECT_EQ(::testing::PrintToString(GetParam()), test_info->value_param()); +} + +INSTANTIATE_TEST_SUITE_P(InstantiationWithComments, CommentTest, + Values(Unstreamable(1))); + +// Verify that we can create a hierarchy of test fixtures, where the base +// class fixture is not parameterized and the derived class is. In this case +// ParameterizedDerivedTest inherits from NonParameterizedBaseTest. We +// perform simple tests on both. +class NonParameterizedBaseTest : public ::testing::Test { + public: + NonParameterizedBaseTest() : n_(17) { } + protected: + int n_; +}; + +class ParameterizedDerivedTest : public NonParameterizedBaseTest, + public ::testing::WithParamInterface { + protected: + ParameterizedDerivedTest() : count_(0) { } + int count_; + static int global_count_; +}; + +int ParameterizedDerivedTest::global_count_ = 0; + +TEST_F(NonParameterizedBaseTest, FixtureIsInitialized) { + EXPECT_EQ(17, n_); +} + +TEST_P(ParameterizedDerivedTest, SeesSequence) { + EXPECT_EQ(17, n_); + EXPECT_EQ(0, count_++); + EXPECT_EQ(GetParam(), global_count_++); +} + +class ParameterizedDeathTest : public ::testing::TestWithParam { }; + +TEST_F(ParameterizedDeathTest, GetParamDiesFromTestF) { + EXPECT_DEATH_IF_SUPPORTED(GetParam(), + ".* value-parameterized test .*"); +} + +INSTANTIATE_TEST_SUITE_P(RangeZeroToFive, ParameterizedDerivedTest, + Range(0, 5)); + +// Tests param generator working with Enums +enum MyEnums { + ENUM1 = 1, + ENUM2 = 3, + ENUM3 = 8, +}; + +class MyEnumTest : public testing::TestWithParam {}; + +TEST_P(MyEnumTest, ChecksParamMoreThanZero) { EXPECT_GE(10, GetParam()); } +INSTANTIATE_TEST_SUITE_P(MyEnumTests, MyEnumTest, + ::testing::Values(ENUM1, ENUM2, 0)); + +int main(int argc, char **argv) { + // Used in TestGenerationTest test suite. + AddGlobalTestEnvironment(TestGenerationTest::Environment::Instance()); + // Used in GeneratorEvaluationTest test suite. Tests that the updated value + // will be picked up for instantiating tests in GeneratorEvaluationTest. + GeneratorEvaluationTest::set_param_value(1); + + ::testing::InitGoogleTest(&argc, argv); + + // Used in GeneratorEvaluationTest test suite. Tests that value updated + // here will NOT be used for instantiating tests in + // GeneratorEvaluationTest. + GeneratorEvaluationTest::set_param_value(2); + + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-test.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-test.h new file mode 100644 index 0000000000000000000000000000000000000000..648057017e840ddc07080e0cf937c51e74429981 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test-test.h @@ -0,0 +1,51 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file provides classes and functions used internally +// for testing Google Test itself. + +#ifndef GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ +#define GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ + +#include "gtest/gtest.h" + +// Test fixture for testing definition and instantiation of a test +// in separate translation units. +class ExternalInstantiationTest : public ::testing::TestWithParam { +}; + +// Test fixture for testing instantiation of a test in multiple +// translation units. +class InstantiationInMultipleTranslationUnitsTest + : public ::testing::TestWithParam { +}; + +#endif // GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test2-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test2-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..2a29fb1d0686e2a4ec7c67c8912ff6a38f89ccd0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-param-test2-test.cc @@ -0,0 +1,61 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Tests for Google Test itself. This verifies that the basic constructs of +// Google Test work. + +#include "gtest/gtest.h" +#include "test/googletest-param-test-test.h" + +using ::testing::Values; +using ::testing::internal::ParamGenerator; + +// Tests that generators defined in a different translation unit +// are functional. The test using extern_gen is defined +// in googletest-param-test-test.cc. +ParamGenerator extern_gen = Values(33); + +// Tests that a parameterized test case can be defined in one translation unit +// and instantiated in another. The test is defined in +// googletest-param-test-test.cc and ExternalInstantiationTest fixture class is +// defined in gtest-param-test_test.h. +INSTANTIATE_TEST_SUITE_P(MultiplesOf33, + ExternalInstantiationTest, + Values(33, 66)); + +// Tests that a parameterized test case can be instantiated +// in multiple translation units. Another instantiation is defined +// in googletest-param-test-test.cc and +// InstantiationInMultipleTranslationUnitsTest fixture is defined in +// gtest-param-test_test.h +INSTANTIATE_TEST_SUITE_P(Sequence2, + InstantiationInMultipleTranslationUnitsTest, + Values(42*3, 42*4, 42*5)); + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-port-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-port-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..60d637c32f63369ff7c6eb9d25e12b11504193f3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-port-test.cc @@ -0,0 +1,1272 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file tests the internal cross-platform support utilities. +#include + +#include "gtest/internal/gtest-port.h" + +#if GTEST_OS_MAC +# include +#endif // GTEST_OS_MAC + +#include +#include +#include // For std::pair and std::make_pair. +#include + +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" +#include "src/gtest-internal-inl.h" + +using std::make_pair; +using std::pair; + +namespace testing { +namespace internal { + +TEST(IsXDigitTest, WorksForNarrowAscii) { + EXPECT_TRUE(IsXDigit('0')); + EXPECT_TRUE(IsXDigit('9')); + EXPECT_TRUE(IsXDigit('A')); + EXPECT_TRUE(IsXDigit('F')); + EXPECT_TRUE(IsXDigit('a')); + EXPECT_TRUE(IsXDigit('f')); + + EXPECT_FALSE(IsXDigit('-')); + EXPECT_FALSE(IsXDigit('g')); + EXPECT_FALSE(IsXDigit('G')); +} + +TEST(IsXDigitTest, ReturnsFalseForNarrowNonAscii) { + EXPECT_FALSE(IsXDigit(static_cast('\x80'))); + EXPECT_FALSE(IsXDigit(static_cast('0' | '\x80'))); +} + +TEST(IsXDigitTest, WorksForWideAscii) { + EXPECT_TRUE(IsXDigit(L'0')); + EXPECT_TRUE(IsXDigit(L'9')); + EXPECT_TRUE(IsXDigit(L'A')); + EXPECT_TRUE(IsXDigit(L'F')); + EXPECT_TRUE(IsXDigit(L'a')); + EXPECT_TRUE(IsXDigit(L'f')); + + EXPECT_FALSE(IsXDigit(L'-')); + EXPECT_FALSE(IsXDigit(L'g')); + EXPECT_FALSE(IsXDigit(L'G')); +} + +TEST(IsXDigitTest, ReturnsFalseForWideNonAscii) { + EXPECT_FALSE(IsXDigit(static_cast(0x80))); + EXPECT_FALSE(IsXDigit(static_cast(L'0' | 0x80))); + EXPECT_FALSE(IsXDigit(static_cast(L'0' | 0x100))); +} + +class Base { + public: + // Copy constructor and assignment operator do exactly what we need, so we + // use them. + Base() : member_(0) {} + explicit Base(int n) : member_(n) {} + virtual ~Base() {} + int member() { return member_; } + + private: + int member_; +}; + +class Derived : public Base { + public: + explicit Derived(int n) : Base(n) {} +}; + +TEST(ImplicitCastTest, ConvertsPointers) { + Derived derived(0); + EXPECT_TRUE(&derived == ::testing::internal::ImplicitCast_(&derived)); +} + +TEST(ImplicitCastTest, CanUseInheritance) { + Derived derived(1); + Base base = ::testing::internal::ImplicitCast_(derived); + EXPECT_EQ(derived.member(), base.member()); +} + +class Castable { + public: + explicit Castable(bool* converted) : converted_(converted) {} + operator Base() { + *converted_ = true; + return Base(); + } + + private: + bool* converted_; +}; + +TEST(ImplicitCastTest, CanUseNonConstCastOperator) { + bool converted = false; + Castable castable(&converted); + Base base = ::testing::internal::ImplicitCast_(castable); + EXPECT_TRUE(converted); +} + +class ConstCastable { + public: + explicit ConstCastable(bool* converted) : converted_(converted) {} + operator Base() const { + *converted_ = true; + return Base(); + } + + private: + bool* converted_; +}; + +TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) { + bool converted = false; + const ConstCastable const_castable(&converted); + Base base = ::testing::internal::ImplicitCast_(const_castable); + EXPECT_TRUE(converted); +} + +class ConstAndNonConstCastable { + public: + ConstAndNonConstCastable(bool* converted, bool* const_converted) + : converted_(converted), const_converted_(const_converted) {} + operator Base() { + *converted_ = true; + return Base(); + } + operator Base() const { + *const_converted_ = true; + return Base(); + } + + private: + bool* converted_; + bool* const_converted_; +}; + +TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) { + bool converted = false; + bool const_converted = false; + ConstAndNonConstCastable castable(&converted, &const_converted); + Base base = ::testing::internal::ImplicitCast_(castable); + EXPECT_TRUE(converted); + EXPECT_FALSE(const_converted); + + converted = false; + const_converted = false; + const ConstAndNonConstCastable const_castable(&converted, &const_converted); + base = ::testing::internal::ImplicitCast_(const_castable); + EXPECT_FALSE(converted); + EXPECT_TRUE(const_converted); +} + +class To { + public: + To(bool* converted) { *converted = true; } // NOLINT +}; + +TEST(ImplicitCastTest, CanUseImplicitConstructor) { + bool converted = false; + To to = ::testing::internal::ImplicitCast_(&converted); + (void)to; + EXPECT_TRUE(converted); +} + +TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement) { + if (AlwaysFalse()) + GTEST_CHECK_(false) << "This should never be executed; " + "It's a compilation test only."; + + if (AlwaysTrue()) + GTEST_CHECK_(true); + else + ; // NOLINT + + if (AlwaysFalse()) + ; // NOLINT + else + GTEST_CHECK_(true) << ""; +} + +TEST(GtestCheckSyntaxTest, WorksWithSwitch) { + switch (0) { + case 1: + break; + default: + GTEST_CHECK_(true); + } + + switch (0) + case 0: + GTEST_CHECK_(true) << "Check failed in switch case"; +} + +// Verifies behavior of FormatFileLocation. +TEST(FormatFileLocationTest, FormatsFileLocation) { + EXPECT_PRED_FORMAT2(IsSubstring, "foo.cc", FormatFileLocation("foo.cc", 42)); + EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation("foo.cc", 42)); +} + +TEST(FormatFileLocationTest, FormatsUnknownFile) { + EXPECT_PRED_FORMAT2(IsSubstring, "unknown file", + FormatFileLocation(nullptr, 42)); + EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation(nullptr, 42)); +} + +TEST(FormatFileLocationTest, FormatsUknownLine) { + EXPECT_EQ("foo.cc:", FormatFileLocation("foo.cc", -1)); +} + +TEST(FormatFileLocationTest, FormatsUknownFileAndLine) { + EXPECT_EQ("unknown file:", FormatFileLocation(nullptr, -1)); +} + +// Verifies behavior of FormatCompilerIndependentFileLocation. +TEST(FormatCompilerIndependentFileLocationTest, FormatsFileLocation) { + EXPECT_EQ("foo.cc:42", FormatCompilerIndependentFileLocation("foo.cc", 42)); +} + +TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFile) { + EXPECT_EQ("unknown file:42", + FormatCompilerIndependentFileLocation(nullptr, 42)); +} + +TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownLine) { + EXPECT_EQ("foo.cc", FormatCompilerIndependentFileLocation("foo.cc", -1)); +} + +TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFileAndLine) { + EXPECT_EQ("unknown file", FormatCompilerIndependentFileLocation(nullptr, -1)); +} + +#if GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ + GTEST_OS_NETBSD || GTEST_OS_OPENBSD +void* ThreadFunc(void* data) { + internal::Mutex* mutex = static_cast(data); + mutex->Lock(); + mutex->Unlock(); + return nullptr; +} + +TEST(GetThreadCountTest, ReturnsCorrectValue) { + const size_t starting_count = GetThreadCount(); + pthread_t thread_id; + + internal::Mutex mutex; + { + internal::MutexLock lock(&mutex); + pthread_attr_t attr; + ASSERT_EQ(0, pthread_attr_init(&attr)); + ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); + + const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex); + ASSERT_EQ(0, pthread_attr_destroy(&attr)); + ASSERT_EQ(0, status); + EXPECT_EQ(starting_count + 1, GetThreadCount()); + } + + void* dummy; + ASSERT_EQ(0, pthread_join(thread_id, &dummy)); + + // The OS may not immediately report the updated thread count after + // joining a thread, causing flakiness in this test. To counter that, we + // wait for up to .5 seconds for the OS to report the correct value. + for (int i = 0; i < 5; ++i) { + if (GetThreadCount() == starting_count) + break; + + SleepMilliseconds(100); + } + + EXPECT_EQ(starting_count, GetThreadCount()); +} +#else +TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) { + EXPECT_EQ(0U, GetThreadCount()); +} +#endif // GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX || GTEST_OS_FUCHSIA + +TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { + const bool a_false_condition = false; + const char regex[] = +#ifdef _MSC_VER + "googletest-port-test\\.cc\\(\\d+\\):" +#elif GTEST_USES_POSIX_RE + "googletest-port-test\\.cc:[0-9]+" +#else + "googletest-port-test\\.cc:\\d+" +#endif // _MSC_VER + ".*a_false_condition.*Extra info.*"; + + EXPECT_DEATH_IF_SUPPORTED(GTEST_CHECK_(a_false_condition) << "Extra info", + regex); +} + +#if GTEST_HAS_DEATH_TEST + +TEST(GtestCheckDeathTest, LivesSilentlyOnSuccess) { + EXPECT_EXIT({ + GTEST_CHECK_(true) << "Extra info"; + ::std::cerr << "Success\n"; + exit(0); }, + ::testing::ExitedWithCode(0), "Success"); +} + +#endif // GTEST_HAS_DEATH_TEST + +// Verifies that Google Test choose regular expression engine appropriate to +// the platform. The test will produce compiler errors in case of failure. +// For simplicity, we only cover the most important platforms here. +TEST(RegexEngineSelectionTest, SelectsCorrectRegexEngine) { +#if !GTEST_USES_PCRE +# if GTEST_HAS_POSIX_RE + + EXPECT_TRUE(GTEST_USES_POSIX_RE); + +# else + + EXPECT_TRUE(GTEST_USES_SIMPLE_RE); + +# endif +#endif // !GTEST_USES_PCRE +} + +#if GTEST_USES_POSIX_RE + +# if GTEST_HAS_TYPED_TEST + +template +class RETest : public ::testing::Test {}; + +// Defines StringTypes as the list of all string types that class RE +// supports. +typedef testing::Types< ::std::string, const char*> StringTypes; + +TYPED_TEST_SUITE(RETest, StringTypes); + +// Tests RE's implicit constructors. +TYPED_TEST(RETest, ImplicitConstructorWorks) { + const RE empty(TypeParam("")); + EXPECT_STREQ("", empty.pattern()); + + const RE simple(TypeParam("hello")); + EXPECT_STREQ("hello", simple.pattern()); + + const RE normal(TypeParam(".*(\\w+)")); + EXPECT_STREQ(".*(\\w+)", normal.pattern()); +} + +// Tests that RE's constructors reject invalid regular expressions. +TYPED_TEST(RETest, RejectsInvalidRegex) { + EXPECT_NONFATAL_FAILURE({ + const RE invalid(TypeParam("?")); + }, "\"?\" is not a valid POSIX Extended regular expression."); +} + +// Tests RE::FullMatch(). +TYPED_TEST(RETest, FullMatchWorks) { + const RE empty(TypeParam("")); + EXPECT_TRUE(RE::FullMatch(TypeParam(""), empty)); + EXPECT_FALSE(RE::FullMatch(TypeParam("a"), empty)); + + const RE re(TypeParam("a.*z")); + EXPECT_TRUE(RE::FullMatch(TypeParam("az"), re)); + EXPECT_TRUE(RE::FullMatch(TypeParam("axyz"), re)); + EXPECT_FALSE(RE::FullMatch(TypeParam("baz"), re)); + EXPECT_FALSE(RE::FullMatch(TypeParam("azy"), re)); +} + +// Tests RE::PartialMatch(). +TYPED_TEST(RETest, PartialMatchWorks) { + const RE empty(TypeParam("")); + EXPECT_TRUE(RE::PartialMatch(TypeParam(""), empty)); + EXPECT_TRUE(RE::PartialMatch(TypeParam("a"), empty)); + + const RE re(TypeParam("a.*z")); + EXPECT_TRUE(RE::PartialMatch(TypeParam("az"), re)); + EXPECT_TRUE(RE::PartialMatch(TypeParam("axyz"), re)); + EXPECT_TRUE(RE::PartialMatch(TypeParam("baz"), re)); + EXPECT_TRUE(RE::PartialMatch(TypeParam("azy"), re)); + EXPECT_FALSE(RE::PartialMatch(TypeParam("zza"), re)); +} + +# endif // GTEST_HAS_TYPED_TEST + +#elif GTEST_USES_SIMPLE_RE + +TEST(IsInSetTest, NulCharIsNotInAnySet) { + EXPECT_FALSE(IsInSet('\0', "")); + EXPECT_FALSE(IsInSet('\0', "\0")); + EXPECT_FALSE(IsInSet('\0', "a")); +} + +TEST(IsInSetTest, WorksForNonNulChars) { + EXPECT_FALSE(IsInSet('a', "Ab")); + EXPECT_FALSE(IsInSet('c', "")); + + EXPECT_TRUE(IsInSet('b', "bcd")); + EXPECT_TRUE(IsInSet('b', "ab")); +} + +TEST(IsAsciiDigitTest, IsFalseForNonDigit) { + EXPECT_FALSE(IsAsciiDigit('\0')); + EXPECT_FALSE(IsAsciiDigit(' ')); + EXPECT_FALSE(IsAsciiDigit('+')); + EXPECT_FALSE(IsAsciiDigit('-')); + EXPECT_FALSE(IsAsciiDigit('.')); + EXPECT_FALSE(IsAsciiDigit('a')); +} + +TEST(IsAsciiDigitTest, IsTrueForDigit) { + EXPECT_TRUE(IsAsciiDigit('0')); + EXPECT_TRUE(IsAsciiDigit('1')); + EXPECT_TRUE(IsAsciiDigit('5')); + EXPECT_TRUE(IsAsciiDigit('9')); +} + +TEST(IsAsciiPunctTest, IsFalseForNonPunct) { + EXPECT_FALSE(IsAsciiPunct('\0')); + EXPECT_FALSE(IsAsciiPunct(' ')); + EXPECT_FALSE(IsAsciiPunct('\n')); + EXPECT_FALSE(IsAsciiPunct('a')); + EXPECT_FALSE(IsAsciiPunct('0')); +} + +TEST(IsAsciiPunctTest, IsTrueForPunct) { + for (const char* p = "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"; *p; p++) { + EXPECT_PRED1(IsAsciiPunct, *p); + } +} + +TEST(IsRepeatTest, IsFalseForNonRepeatChar) { + EXPECT_FALSE(IsRepeat('\0')); + EXPECT_FALSE(IsRepeat(' ')); + EXPECT_FALSE(IsRepeat('a')); + EXPECT_FALSE(IsRepeat('1')); + EXPECT_FALSE(IsRepeat('-')); +} + +TEST(IsRepeatTest, IsTrueForRepeatChar) { + EXPECT_TRUE(IsRepeat('?')); + EXPECT_TRUE(IsRepeat('*')); + EXPECT_TRUE(IsRepeat('+')); +} + +TEST(IsAsciiWhiteSpaceTest, IsFalseForNonWhiteSpace) { + EXPECT_FALSE(IsAsciiWhiteSpace('\0')); + EXPECT_FALSE(IsAsciiWhiteSpace('a')); + EXPECT_FALSE(IsAsciiWhiteSpace('1')); + EXPECT_FALSE(IsAsciiWhiteSpace('+')); + EXPECT_FALSE(IsAsciiWhiteSpace('_')); +} + +TEST(IsAsciiWhiteSpaceTest, IsTrueForWhiteSpace) { + EXPECT_TRUE(IsAsciiWhiteSpace(' ')); + EXPECT_TRUE(IsAsciiWhiteSpace('\n')); + EXPECT_TRUE(IsAsciiWhiteSpace('\r')); + EXPECT_TRUE(IsAsciiWhiteSpace('\t')); + EXPECT_TRUE(IsAsciiWhiteSpace('\v')); + EXPECT_TRUE(IsAsciiWhiteSpace('\f')); +} + +TEST(IsAsciiWordCharTest, IsFalseForNonWordChar) { + EXPECT_FALSE(IsAsciiWordChar('\0')); + EXPECT_FALSE(IsAsciiWordChar('+')); + EXPECT_FALSE(IsAsciiWordChar('.')); + EXPECT_FALSE(IsAsciiWordChar(' ')); + EXPECT_FALSE(IsAsciiWordChar('\n')); +} + +TEST(IsAsciiWordCharTest, IsTrueForLetter) { + EXPECT_TRUE(IsAsciiWordChar('a')); + EXPECT_TRUE(IsAsciiWordChar('b')); + EXPECT_TRUE(IsAsciiWordChar('A')); + EXPECT_TRUE(IsAsciiWordChar('Z')); +} + +TEST(IsAsciiWordCharTest, IsTrueForDigit) { + EXPECT_TRUE(IsAsciiWordChar('0')); + EXPECT_TRUE(IsAsciiWordChar('1')); + EXPECT_TRUE(IsAsciiWordChar('7')); + EXPECT_TRUE(IsAsciiWordChar('9')); +} + +TEST(IsAsciiWordCharTest, IsTrueForUnderscore) { + EXPECT_TRUE(IsAsciiWordChar('_')); +} + +TEST(IsValidEscapeTest, IsFalseForNonPrintable) { + EXPECT_FALSE(IsValidEscape('\0')); + EXPECT_FALSE(IsValidEscape('\007')); +} + +TEST(IsValidEscapeTest, IsFalseForDigit) { + EXPECT_FALSE(IsValidEscape('0')); + EXPECT_FALSE(IsValidEscape('9')); +} + +TEST(IsValidEscapeTest, IsFalseForWhiteSpace) { + EXPECT_FALSE(IsValidEscape(' ')); + EXPECT_FALSE(IsValidEscape('\n')); +} + +TEST(IsValidEscapeTest, IsFalseForSomeLetter) { + EXPECT_FALSE(IsValidEscape('a')); + EXPECT_FALSE(IsValidEscape('Z')); +} + +TEST(IsValidEscapeTest, IsTrueForPunct) { + EXPECT_TRUE(IsValidEscape('.')); + EXPECT_TRUE(IsValidEscape('-')); + EXPECT_TRUE(IsValidEscape('^')); + EXPECT_TRUE(IsValidEscape('$')); + EXPECT_TRUE(IsValidEscape('(')); + EXPECT_TRUE(IsValidEscape(']')); + EXPECT_TRUE(IsValidEscape('{')); + EXPECT_TRUE(IsValidEscape('|')); +} + +TEST(IsValidEscapeTest, IsTrueForSomeLetter) { + EXPECT_TRUE(IsValidEscape('d')); + EXPECT_TRUE(IsValidEscape('D')); + EXPECT_TRUE(IsValidEscape('s')); + EXPECT_TRUE(IsValidEscape('S')); + EXPECT_TRUE(IsValidEscape('w')); + EXPECT_TRUE(IsValidEscape('W')); +} + +TEST(AtomMatchesCharTest, EscapedPunct) { + EXPECT_FALSE(AtomMatchesChar(true, '\\', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, '\\', ' ')); + EXPECT_FALSE(AtomMatchesChar(true, '_', '.')); + EXPECT_FALSE(AtomMatchesChar(true, '.', 'a')); + + EXPECT_TRUE(AtomMatchesChar(true, '\\', '\\')); + EXPECT_TRUE(AtomMatchesChar(true, '_', '_')); + EXPECT_TRUE(AtomMatchesChar(true, '+', '+')); + EXPECT_TRUE(AtomMatchesChar(true, '.', '.')); +} + +TEST(AtomMatchesCharTest, Escaped_d) { + EXPECT_FALSE(AtomMatchesChar(true, 'd', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'd', 'a')); + EXPECT_FALSE(AtomMatchesChar(true, 'd', '.')); + + EXPECT_TRUE(AtomMatchesChar(true, 'd', '0')); + EXPECT_TRUE(AtomMatchesChar(true, 'd', '9')); +} + +TEST(AtomMatchesCharTest, Escaped_D) { + EXPECT_FALSE(AtomMatchesChar(true, 'D', '0')); + EXPECT_FALSE(AtomMatchesChar(true, 'D', '9')); + + EXPECT_TRUE(AtomMatchesChar(true, 'D', '\0')); + EXPECT_TRUE(AtomMatchesChar(true, 'D', 'a')); + EXPECT_TRUE(AtomMatchesChar(true, 'D', '-')); +} + +TEST(AtomMatchesCharTest, Escaped_s) { + EXPECT_FALSE(AtomMatchesChar(true, 's', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 's', 'a')); + EXPECT_FALSE(AtomMatchesChar(true, 's', '.')); + EXPECT_FALSE(AtomMatchesChar(true, 's', '9')); + + EXPECT_TRUE(AtomMatchesChar(true, 's', ' ')); + EXPECT_TRUE(AtomMatchesChar(true, 's', '\n')); + EXPECT_TRUE(AtomMatchesChar(true, 's', '\t')); +} + +TEST(AtomMatchesCharTest, Escaped_S) { + EXPECT_FALSE(AtomMatchesChar(true, 'S', ' ')); + EXPECT_FALSE(AtomMatchesChar(true, 'S', '\r')); + + EXPECT_TRUE(AtomMatchesChar(true, 'S', '\0')); + EXPECT_TRUE(AtomMatchesChar(true, 'S', 'a')); + EXPECT_TRUE(AtomMatchesChar(true, 'S', '9')); +} + +TEST(AtomMatchesCharTest, Escaped_w) { + EXPECT_FALSE(AtomMatchesChar(true, 'w', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'w', '+')); + EXPECT_FALSE(AtomMatchesChar(true, 'w', ' ')); + EXPECT_FALSE(AtomMatchesChar(true, 'w', '\n')); + + EXPECT_TRUE(AtomMatchesChar(true, 'w', '0')); + EXPECT_TRUE(AtomMatchesChar(true, 'w', 'b')); + EXPECT_TRUE(AtomMatchesChar(true, 'w', 'C')); + EXPECT_TRUE(AtomMatchesChar(true, 'w', '_')); +} + +TEST(AtomMatchesCharTest, Escaped_W) { + EXPECT_FALSE(AtomMatchesChar(true, 'W', 'A')); + EXPECT_FALSE(AtomMatchesChar(true, 'W', 'b')); + EXPECT_FALSE(AtomMatchesChar(true, 'W', '9')); + EXPECT_FALSE(AtomMatchesChar(true, 'W', '_')); + + EXPECT_TRUE(AtomMatchesChar(true, 'W', '\0')); + EXPECT_TRUE(AtomMatchesChar(true, 'W', '*')); + EXPECT_TRUE(AtomMatchesChar(true, 'W', '\n')); +} + +TEST(AtomMatchesCharTest, EscapedWhiteSpace) { + EXPECT_FALSE(AtomMatchesChar(true, 'f', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'f', '\n')); + EXPECT_FALSE(AtomMatchesChar(true, 'n', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'n', '\r')); + EXPECT_FALSE(AtomMatchesChar(true, 'r', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'r', 'a')); + EXPECT_FALSE(AtomMatchesChar(true, 't', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 't', 't')); + EXPECT_FALSE(AtomMatchesChar(true, 'v', '\0')); + EXPECT_FALSE(AtomMatchesChar(true, 'v', '\f')); + + EXPECT_TRUE(AtomMatchesChar(true, 'f', '\f')); + EXPECT_TRUE(AtomMatchesChar(true, 'n', '\n')); + EXPECT_TRUE(AtomMatchesChar(true, 'r', '\r')); + EXPECT_TRUE(AtomMatchesChar(true, 't', '\t')); + EXPECT_TRUE(AtomMatchesChar(true, 'v', '\v')); +} + +TEST(AtomMatchesCharTest, UnescapedDot) { + EXPECT_FALSE(AtomMatchesChar(false, '.', '\n')); + + EXPECT_TRUE(AtomMatchesChar(false, '.', '\0')); + EXPECT_TRUE(AtomMatchesChar(false, '.', '.')); + EXPECT_TRUE(AtomMatchesChar(false, '.', 'a')); + EXPECT_TRUE(AtomMatchesChar(false, '.', ' ')); +} + +TEST(AtomMatchesCharTest, UnescapedChar) { + EXPECT_FALSE(AtomMatchesChar(false, 'a', '\0')); + EXPECT_FALSE(AtomMatchesChar(false, 'a', 'b')); + EXPECT_FALSE(AtomMatchesChar(false, '$', 'a')); + + EXPECT_TRUE(AtomMatchesChar(false, '$', '$')); + EXPECT_TRUE(AtomMatchesChar(false, '5', '5')); + EXPECT_TRUE(AtomMatchesChar(false, 'Z', 'Z')); +} + +TEST(ValidateRegexTest, GeneratesFailureAndReturnsFalseForInvalid) { + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(NULL)), + "NULL is not a valid simple regular expression"); + EXPECT_NONFATAL_FAILURE( + ASSERT_FALSE(ValidateRegex("a\\")), + "Syntax error at index 1 in simple regular expression \"a\\\": "); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a\\")), + "'\\' cannot appear at the end"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\n\\")), + "'\\' cannot appear at the end"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\s\\hb")), + "invalid escape sequence \"\\h\""); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^^")), + "'^' can only appear at the beginning"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(".*^b")), + "'^' can only appear at the beginning"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("$$")), + "'$' can only appear at the end"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^$a")), + "'$' can only appear at the end"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a(b")), + "'(' is unsupported"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("ab)")), + "')' is unsupported"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("[ab")), + "'[' is unsupported"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a{2")), + "'{' is unsupported"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("?")), + "'?' can only follow a repeatable token"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^*")), + "'*' can only follow a repeatable token"); + EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("5*+")), + "'+' can only follow a repeatable token"); +} + +TEST(ValidateRegexTest, ReturnsTrueForValid) { + EXPECT_TRUE(ValidateRegex("")); + EXPECT_TRUE(ValidateRegex("a")); + EXPECT_TRUE(ValidateRegex(".*")); + EXPECT_TRUE(ValidateRegex("^a_+")); + EXPECT_TRUE(ValidateRegex("^a\\t\\&?")); + EXPECT_TRUE(ValidateRegex("09*$")); + EXPECT_TRUE(ValidateRegex("^Z$")); + EXPECT_TRUE(ValidateRegex("a\\^Z\\$\\(\\)\\|\\[\\]\\{\\}")); +} + +TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrOne) { + EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "a", "ba")); + // Repeating more than once. + EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "aab")); + + // Repeating zero times. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ba")); + // Repeating once. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ab")); + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '#', '?', ".", "##")); +} + +TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrMany) { + EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '*', "a$", "baab")); + + // Repeating zero times. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "bc")); + // Repeating once. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "abc")); + // Repeating more than once. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '*', "-", "ab_1-g")); +} + +TEST(MatchRepetitionAndRegexAtHeadTest, WorksForOneOrMany) { + EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "a$", "baab")); + // Repeating zero times. + EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "bc")); + + // Repeating once. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "abc")); + // Repeating more than once. + EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '+', "-", "ab_1-g")); +} + +TEST(MatchRegexAtHeadTest, ReturnsTrueForEmptyRegex) { + EXPECT_TRUE(MatchRegexAtHead("", "")); + EXPECT_TRUE(MatchRegexAtHead("", "ab")); +} + +TEST(MatchRegexAtHeadTest, WorksWhenDollarIsInRegex) { + EXPECT_FALSE(MatchRegexAtHead("$", "a")); + + EXPECT_TRUE(MatchRegexAtHead("$", "")); + EXPECT_TRUE(MatchRegexAtHead("a$", "a")); +} + +TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithEscapeSequence) { + EXPECT_FALSE(MatchRegexAtHead("\\w", "+")); + EXPECT_FALSE(MatchRegexAtHead("\\W", "ab")); + + EXPECT_TRUE(MatchRegexAtHead("\\sa", "\nab")); + EXPECT_TRUE(MatchRegexAtHead("\\d", "1a")); +} + +TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetition) { + EXPECT_FALSE(MatchRegexAtHead(".+a", "abc")); + EXPECT_FALSE(MatchRegexAtHead("a?b", "aab")); + + EXPECT_TRUE(MatchRegexAtHead(".*a", "bc12-ab")); + EXPECT_TRUE(MatchRegexAtHead("a?b", "b")); + EXPECT_TRUE(MatchRegexAtHead("a?b", "ab")); +} + +TEST(MatchRegexAtHeadTest, + WorksWhenRegexStartsWithRepetionOfEscapeSequence) { + EXPECT_FALSE(MatchRegexAtHead("\\.+a", "abc")); + EXPECT_FALSE(MatchRegexAtHead("\\s?b", " b")); + + EXPECT_TRUE(MatchRegexAtHead("\\(*a", "((((ab")); + EXPECT_TRUE(MatchRegexAtHead("\\^?b", "^b")); + EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "b")); + EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "\\b")); +} + +TEST(MatchRegexAtHeadTest, MatchesSequentially) { + EXPECT_FALSE(MatchRegexAtHead("ab.*c", "acabc")); + + EXPECT_TRUE(MatchRegexAtHead("ab.*c", "ab-fsc")); +} + +TEST(MatchRegexAnywhereTest, ReturnsFalseWhenStringIsNull) { + EXPECT_FALSE(MatchRegexAnywhere("", NULL)); +} + +TEST(MatchRegexAnywhereTest, WorksWhenRegexStartsWithCaret) { + EXPECT_FALSE(MatchRegexAnywhere("^a", "ba")); + EXPECT_FALSE(MatchRegexAnywhere("^$", "a")); + + EXPECT_TRUE(MatchRegexAnywhere("^a", "ab")); + EXPECT_TRUE(MatchRegexAnywhere("^", "ab")); + EXPECT_TRUE(MatchRegexAnywhere("^$", "")); +} + +TEST(MatchRegexAnywhereTest, ReturnsFalseWhenNoMatch) { + EXPECT_FALSE(MatchRegexAnywhere("a", "bcde123")); + EXPECT_FALSE(MatchRegexAnywhere("a.+a", "--aa88888888")); +} + +TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingPrefix) { + EXPECT_TRUE(MatchRegexAnywhere("\\w+", "ab1_ - 5")); + EXPECT_TRUE(MatchRegexAnywhere(".*=", "=")); + EXPECT_TRUE(MatchRegexAnywhere("x.*ab?.*bc", "xaaabc")); +} + +TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingNonPrefix) { + EXPECT_TRUE(MatchRegexAnywhere("\\w+", "$$$ ab1_ - 5")); + EXPECT_TRUE(MatchRegexAnywhere("\\.+=", "= ...=")); +} + +// Tests RE's implicit constructors. +TEST(RETest, ImplicitConstructorWorks) { + const RE empty(""); + EXPECT_STREQ("", empty.pattern()); + + const RE simple("hello"); + EXPECT_STREQ("hello", simple.pattern()); +} + +// Tests that RE's constructors reject invalid regular expressions. +TEST(RETest, RejectsInvalidRegex) { + EXPECT_NONFATAL_FAILURE({ + const RE normal(NULL); + }, "NULL is not a valid simple regular expression"); + + EXPECT_NONFATAL_FAILURE({ + const RE normal(".*(\\w+"); + }, "'(' is unsupported"); + + EXPECT_NONFATAL_FAILURE({ + const RE invalid("^?"); + }, "'?' can only follow a repeatable token"); +} + +// Tests RE::FullMatch(). +TEST(RETest, FullMatchWorks) { + const RE empty(""); + EXPECT_TRUE(RE::FullMatch("", empty)); + EXPECT_FALSE(RE::FullMatch("a", empty)); + + const RE re1("a"); + EXPECT_TRUE(RE::FullMatch("a", re1)); + + const RE re("a.*z"); + EXPECT_TRUE(RE::FullMatch("az", re)); + EXPECT_TRUE(RE::FullMatch("axyz", re)); + EXPECT_FALSE(RE::FullMatch("baz", re)); + EXPECT_FALSE(RE::FullMatch("azy", re)); +} + +// Tests RE::PartialMatch(). +TEST(RETest, PartialMatchWorks) { + const RE empty(""); + EXPECT_TRUE(RE::PartialMatch("", empty)); + EXPECT_TRUE(RE::PartialMatch("a", empty)); + + const RE re("a.*z"); + EXPECT_TRUE(RE::PartialMatch("az", re)); + EXPECT_TRUE(RE::PartialMatch("axyz", re)); + EXPECT_TRUE(RE::PartialMatch("baz", re)); + EXPECT_TRUE(RE::PartialMatch("azy", re)); + EXPECT_FALSE(RE::PartialMatch("zza", re)); +} + +#endif // GTEST_USES_POSIX_RE + +#if !GTEST_OS_WINDOWS_MOBILE + +TEST(CaptureTest, CapturesStdout) { + CaptureStdout(); + fprintf(stdout, "abc"); + EXPECT_STREQ("abc", GetCapturedStdout().c_str()); + + CaptureStdout(); + fprintf(stdout, "def%cghi", '\0'); + EXPECT_EQ(::std::string("def\0ghi", 7), ::std::string(GetCapturedStdout())); +} + +TEST(CaptureTest, CapturesStderr) { + CaptureStderr(); + fprintf(stderr, "jkl"); + EXPECT_STREQ("jkl", GetCapturedStderr().c_str()); + + CaptureStderr(); + fprintf(stderr, "jkl%cmno", '\0'); + EXPECT_EQ(::std::string("jkl\0mno", 7), ::std::string(GetCapturedStderr())); +} + +// Tests that stdout and stderr capture don't interfere with each other. +TEST(CaptureTest, CapturesStdoutAndStderr) { + CaptureStdout(); + CaptureStderr(); + fprintf(stdout, "pqr"); + fprintf(stderr, "stu"); + EXPECT_STREQ("pqr", GetCapturedStdout().c_str()); + EXPECT_STREQ("stu", GetCapturedStderr().c_str()); +} + +TEST(CaptureDeathTest, CannotReenterStdoutCapture) { + CaptureStdout(); + EXPECT_DEATH_IF_SUPPORTED(CaptureStdout(), + "Only one stdout capturer can exist at a time"); + GetCapturedStdout(); + + // We cannot test stderr capturing using death tests as they use it + // themselves. +} + +#endif // !GTEST_OS_WINDOWS_MOBILE + +TEST(ThreadLocalTest, DefaultConstructorInitializesToDefaultValues) { + ThreadLocal t1; + EXPECT_EQ(0, t1.get()); + + ThreadLocal t2; + EXPECT_TRUE(t2.get() == nullptr); +} + +TEST(ThreadLocalTest, SingleParamConstructorInitializesToParam) { + ThreadLocal t1(123); + EXPECT_EQ(123, t1.get()); + + int i = 0; + ThreadLocal t2(&i); + EXPECT_EQ(&i, t2.get()); +} + +class NoDefaultContructor { + public: + explicit NoDefaultContructor(const char*) {} + NoDefaultContructor(const NoDefaultContructor&) {} +}; + +TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion) { + ThreadLocal bar(NoDefaultContructor("foo")); + bar.pointer(); +} + +TEST(ThreadLocalTest, GetAndPointerReturnSameValue) { + ThreadLocal thread_local_string; + + EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get())); + + // Verifies the condition still holds after calling set. + thread_local_string.set("foo"); + EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get())); +} + +TEST(ThreadLocalTest, PointerAndConstPointerReturnSameValue) { + ThreadLocal thread_local_string; + const ThreadLocal& const_thread_local_string = + thread_local_string; + + EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer()); + + thread_local_string.set("foo"); + EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer()); +} + +#if GTEST_IS_THREADSAFE + +void AddTwo(int* param) { *param += 2; } + +TEST(ThreadWithParamTest, ConstructorExecutesThreadFunc) { + int i = 40; + ThreadWithParam thread(&AddTwo, &i, nullptr); + thread.Join(); + EXPECT_EQ(42, i); +} + +TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) { + // AssertHeld() is flaky only in the presence of multiple threads accessing + // the lock. In this case, the test is robust. + EXPECT_DEATH_IF_SUPPORTED({ + Mutex m; + { MutexLock lock(&m); } + m.AssertHeld(); + }, + "thread .*hold"); +} + +TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) { + Mutex m; + MutexLock lock(&m); + m.AssertHeld(); +} + +class AtomicCounterWithMutex { + public: + explicit AtomicCounterWithMutex(Mutex* mutex) : + value_(0), mutex_(mutex), random_(42) {} + + void Increment() { + MutexLock lock(mutex_); + int temp = value_; + { + // We need to put up a memory barrier to prevent reads and writes to + // value_ rearranged with the call to SleepMilliseconds when observed + // from other threads. +#if GTEST_HAS_PTHREAD + // On POSIX, locking a mutex puts up a memory barrier. We cannot use + // Mutex and MutexLock here or rely on their memory barrier + // functionality as we are testing them here. + pthread_mutex_t memory_barrier_mutex; + GTEST_CHECK_POSIX_SUCCESS_( + pthread_mutex_init(&memory_barrier_mutex, nullptr)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex)); + + SleepMilliseconds(static_cast(random_.Generate(30))); + + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&memory_barrier_mutex)); +#elif GTEST_OS_WINDOWS + // On Windows, performing an interlocked access puts up a memory barrier. + volatile LONG dummy = 0; + ::InterlockedIncrement(&dummy); + SleepMilliseconds(static_cast(random_.Generate(30))); + ::InterlockedIncrement(&dummy); +#else +# error "Memory barrier not implemented on this platform." +#endif // GTEST_HAS_PTHREAD + } + value_ = temp + 1; + } + int value() const { return value_; } + + private: + volatile int value_; + Mutex* const mutex_; // Protects value_. + Random random_; +}; + +void CountingThreadFunc(pair param) { + for (int i = 0; i < param.second; ++i) + param.first->Increment(); +} + +// Tests that the mutex only lets one thread at a time to lock it. +TEST(MutexTest, OnlyOneThreadCanLockAtATime) { + Mutex mutex; + AtomicCounterWithMutex locked_counter(&mutex); + + typedef ThreadWithParam > ThreadType; + const int kCycleCount = 20; + const int kThreadCount = 7; + std::unique_ptr counting_threads[kThreadCount]; + Notification threads_can_start; + // Creates and runs kThreadCount threads that increment locked_counter + // kCycleCount times each. + for (int i = 0; i < kThreadCount; ++i) { + counting_threads[i].reset(new ThreadType(&CountingThreadFunc, + make_pair(&locked_counter, + kCycleCount), + &threads_can_start)); + } + threads_can_start.Notify(); + for (int i = 0; i < kThreadCount; ++i) + counting_threads[i]->Join(); + + // If the mutex lets more than one thread to increment the counter at a + // time, they are likely to encounter a race condition and have some + // increments overwritten, resulting in the lower then expected counter + // value. + EXPECT_EQ(kCycleCount * kThreadCount, locked_counter.value()); +} + +template +void RunFromThread(void (func)(T), T param) { + ThreadWithParam thread(func, param, nullptr); + thread.Join(); +} + +void RetrieveThreadLocalValue( + pair*, std::string*> param) { + *param.second = param.first->get(); +} + +TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) { + ThreadLocal thread_local_string("foo"); + EXPECT_STREQ("foo", thread_local_string.get().c_str()); + + thread_local_string.set("bar"); + EXPECT_STREQ("bar", thread_local_string.get().c_str()); + + std::string result; + RunFromThread(&RetrieveThreadLocalValue, + make_pair(&thread_local_string, &result)); + EXPECT_STREQ("foo", result.c_str()); +} + +// Keeps track of whether of destructors being called on instances of +// DestructorTracker. On Windows, waits for the destructor call reports. +class DestructorCall { + public: + DestructorCall() { + invoked_ = false; +#if GTEST_OS_WINDOWS + wait_event_.Reset(::CreateEvent(NULL, TRUE, FALSE, NULL)); + GTEST_CHECK_(wait_event_.Get() != NULL); +#endif + } + + bool CheckDestroyed() const { +#if GTEST_OS_WINDOWS + if (::WaitForSingleObject(wait_event_.Get(), 1000) != WAIT_OBJECT_0) + return false; +#endif + return invoked_; + } + + void ReportDestroyed() { + invoked_ = true; +#if GTEST_OS_WINDOWS + ::SetEvent(wait_event_.Get()); +#endif + } + + static std::vector& List() { return *list_; } + + static void ResetList() { + for (size_t i = 0; i < list_->size(); ++i) { + delete list_->at(i); + } + list_->clear(); + } + + private: + bool invoked_; +#if GTEST_OS_WINDOWS + AutoHandle wait_event_; +#endif + static std::vector* const list_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DestructorCall); +}; + +std::vector* const DestructorCall::list_ = + new std::vector; + +// DestructorTracker keeps track of whether its instances have been +// destroyed. +class DestructorTracker { + public: + DestructorTracker() : index_(GetNewIndex()) {} + DestructorTracker(const DestructorTracker& /* rhs */) + : index_(GetNewIndex()) {} + ~DestructorTracker() { + // We never access DestructorCall::List() concurrently, so we don't need + // to protect this access with a mutex. + DestructorCall::List()[index_]->ReportDestroyed(); + } + + private: + static size_t GetNewIndex() { + DestructorCall::List().push_back(new DestructorCall); + return DestructorCall::List().size() - 1; + } + const size_t index_; + + GTEST_DISALLOW_ASSIGN_(DestructorTracker); +}; + +typedef ThreadLocal* ThreadParam; + +void CallThreadLocalGet(ThreadParam thread_local_param) { + thread_local_param->get(); +} + +// Tests that when a ThreadLocal object dies in a thread, it destroys +// the managed object for that thread. +TEST(ThreadLocalTest, DestroysManagedObjectForOwnThreadWhenDying) { + DestructorCall::ResetList(); + + { + ThreadLocal thread_local_tracker; + ASSERT_EQ(0U, DestructorCall::List().size()); + + // This creates another DestructorTracker object for the main thread. + thread_local_tracker.get(); + ASSERT_EQ(1U, DestructorCall::List().size()); + ASSERT_FALSE(DestructorCall::List()[0]->CheckDestroyed()); + } + + // Now thread_local_tracker has died. + ASSERT_EQ(1U, DestructorCall::List().size()); + EXPECT_TRUE(DestructorCall::List()[0]->CheckDestroyed()); + + DestructorCall::ResetList(); +} + +// Tests that when a thread exits, the thread-local object for that +// thread is destroyed. +TEST(ThreadLocalTest, DestroysManagedObjectAtThreadExit) { + DestructorCall::ResetList(); + + { + ThreadLocal thread_local_tracker; + ASSERT_EQ(0U, DestructorCall::List().size()); + + // This creates another DestructorTracker object in the new thread. + ThreadWithParam thread(&CallThreadLocalGet, + &thread_local_tracker, nullptr); + thread.Join(); + + // The thread has exited, and we should have a DestroyedTracker + // instance created for it. But it may not have been destroyed yet. + ASSERT_EQ(1U, DestructorCall::List().size()); + } + + // The thread has exited and thread_local_tracker has died. + ASSERT_EQ(1U, DestructorCall::List().size()); + EXPECT_TRUE(DestructorCall::List()[0]->CheckDestroyed()); + + DestructorCall::ResetList(); +} + +TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) { + ThreadLocal thread_local_string; + thread_local_string.set("Foo"); + EXPECT_STREQ("Foo", thread_local_string.get().c_str()); + + std::string result; + RunFromThread(&RetrieveThreadLocalValue, + make_pair(&thread_local_string, &result)); + EXPECT_TRUE(result.empty()); +} + +#endif // GTEST_IS_THREADSAFE + +#if GTEST_OS_WINDOWS +TEST(WindowsTypesTest, HANDLEIsVoidStar) { + StaticAssertTypeEq(); +} + +#if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR) +TEST(WindowsTypesTest, _CRITICAL_SECTIONIs_CRITICAL_SECTION) { + StaticAssertTypeEq(); +} +#else +TEST(WindowsTypesTest, CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION) { + StaticAssertTypeEq(); +} +#endif + +#endif // GTEST_OS_WINDOWS + +} // namespace internal +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-printers-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-printers-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..4bdc9adde9e0ea42653ae13c2b1f462cd3c86988 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-printers-test.cc @@ -0,0 +1,1620 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Google Test - The Google C++ Testing and Mocking Framework +// +// This file tests the universal value printer. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest-printers.h" +#include "gtest/gtest.h" + +// Some user-defined types for testing the universal value printer. + +// An anonymous enum type. +enum AnonymousEnum { + kAE1 = -1, + kAE2 = 1 +}; + +// An enum without a user-defined printer. +enum EnumWithoutPrinter { + kEWP1 = -2, + kEWP2 = 42 +}; + +// An enum with a << operator. +enum EnumWithStreaming { + kEWS1 = 10 +}; + +std::ostream& operator<<(std::ostream& os, EnumWithStreaming e) { + return os << (e == kEWS1 ? "kEWS1" : "invalid"); +} + +// An enum with a PrintTo() function. +enum EnumWithPrintTo { + kEWPT1 = 1 +}; + +void PrintTo(EnumWithPrintTo e, std::ostream* os) { + *os << (e == kEWPT1 ? "kEWPT1" : "invalid"); +} + +// A class implicitly convertible to BiggestInt. +class BiggestIntConvertible { + public: + operator ::testing::internal::BiggestInt() const { return 42; } +}; + +// A user-defined unprintable class template in the global namespace. +template +class UnprintableTemplateInGlobal { + public: + UnprintableTemplateInGlobal() : value_() {} + private: + T value_; +}; + +// A user-defined streamable type in the global namespace. +class StreamableInGlobal { + public: + virtual ~StreamableInGlobal() {} +}; + +inline void operator<<(::std::ostream& os, const StreamableInGlobal& /* x */) { + os << "StreamableInGlobal"; +} + +void operator<<(::std::ostream& os, const StreamableInGlobal* /* x */) { + os << "StreamableInGlobal*"; +} + +namespace foo { + +// A user-defined unprintable type in a user namespace. +class UnprintableInFoo { + public: + UnprintableInFoo() : z_(0) { memcpy(xy_, "\xEF\x12\x0\x0\x34\xAB\x0\x0", 8); } + double z() const { return z_; } + private: + char xy_[8]; + double z_; +}; + +// A user-defined printable type in a user-chosen namespace. +struct PrintableViaPrintTo { + PrintableViaPrintTo() : value() {} + int value; +}; + +void PrintTo(const PrintableViaPrintTo& x, ::std::ostream* os) { + *os << "PrintableViaPrintTo: " << x.value; +} + +// A type with a user-defined << for printing its pointer. +struct PointerPrintable { +}; + +::std::ostream& operator<<(::std::ostream& os, + const PointerPrintable* /* x */) { + return os << "PointerPrintable*"; +} + +// A user-defined printable class template in a user-chosen namespace. +template +class PrintableViaPrintToTemplate { + public: + explicit PrintableViaPrintToTemplate(const T& a_value) : value_(a_value) {} + + const T& value() const { return value_; } + private: + T value_; +}; + +template +void PrintTo(const PrintableViaPrintToTemplate& x, ::std::ostream* os) { + *os << "PrintableViaPrintToTemplate: " << x.value(); +} + +// A user-defined streamable class template in a user namespace. +template +class StreamableTemplateInFoo { + public: + StreamableTemplateInFoo() : value_() {} + + const T& value() const { return value_; } + private: + T value_; +}; + +template +inline ::std::ostream& operator<<(::std::ostream& os, + const StreamableTemplateInFoo& x) { + return os << "StreamableTemplateInFoo: " << x.value(); +} + +// A user-defined streamable but recursivly-defined container type in +// a user namespace, it mimics therefore std::filesystem::path or +// boost::filesystem::path. +class PathLike { + public: + struct iterator { + typedef PathLike value_type; + + iterator& operator++(); + PathLike& operator*(); + }; + + using value_type = char; + using const_iterator = iterator; + + PathLike() {} + + iterator begin() const { return iterator(); } + iterator end() const { return iterator(); } + + friend ::std::ostream& operator<<(::std::ostream& os, const PathLike&) { + return os << "Streamable-PathLike"; + } +}; + +} // namespace foo + +namespace testing { +namespace gtest_printers_test { + +using ::std::deque; +using ::std::list; +using ::std::make_pair; +using ::std::map; +using ::std::multimap; +using ::std::multiset; +using ::std::pair; +using ::std::set; +using ::std::vector; +using ::testing::PrintToString; +using ::testing::internal::FormatForComparisonFailureMessage; +using ::testing::internal::ImplicitCast_; +using ::testing::internal::NativeArray; +using ::testing::internal::RE; +using ::testing::internal::RelationToSourceReference; +using ::testing::internal::Strings; +using ::testing::internal::UniversalPrint; +using ::testing::internal::UniversalPrinter; +using ::testing::internal::UniversalTersePrint; +using ::testing::internal::UniversalTersePrintTupleFieldsToStrings; + +// Prints a value to a string using the universal value printer. This +// is a helper for testing UniversalPrinter::Print() for various types. +template +std::string Print(const T& value) { + ::std::stringstream ss; + UniversalPrinter::Print(value, &ss); + return ss.str(); +} + +// Prints a value passed by reference to a string, using the universal +// value printer. This is a helper for testing +// UniversalPrinter::Print() for various types. +template +std::string PrintByRef(const T& value) { + ::std::stringstream ss; + UniversalPrinter::Print(value, &ss); + return ss.str(); +} + +// Tests printing various enum types. + +TEST(PrintEnumTest, AnonymousEnum) { + EXPECT_EQ("-1", Print(kAE1)); + EXPECT_EQ("1", Print(kAE2)); +} + +TEST(PrintEnumTest, EnumWithoutPrinter) { + EXPECT_EQ("-2", Print(kEWP1)); + EXPECT_EQ("42", Print(kEWP2)); +} + +TEST(PrintEnumTest, EnumWithStreaming) { + EXPECT_EQ("kEWS1", Print(kEWS1)); + EXPECT_EQ("invalid", Print(static_cast(0))); +} + +TEST(PrintEnumTest, EnumWithPrintTo) { + EXPECT_EQ("kEWPT1", Print(kEWPT1)); + EXPECT_EQ("invalid", Print(static_cast(0))); +} + +// Tests printing a class implicitly convertible to BiggestInt. + +TEST(PrintClassTest, BiggestIntConvertible) { + EXPECT_EQ("42", Print(BiggestIntConvertible())); +} + +// Tests printing various char types. + +// char. +TEST(PrintCharTest, PlainChar) { + EXPECT_EQ("'\\0'", Print('\0')); + EXPECT_EQ("'\\'' (39, 0x27)", Print('\'')); + EXPECT_EQ("'\"' (34, 0x22)", Print('"')); + EXPECT_EQ("'?' (63, 0x3F)", Print('?')); + EXPECT_EQ("'\\\\' (92, 0x5C)", Print('\\')); + EXPECT_EQ("'\\a' (7)", Print('\a')); + EXPECT_EQ("'\\b' (8)", Print('\b')); + EXPECT_EQ("'\\f' (12, 0xC)", Print('\f')); + EXPECT_EQ("'\\n' (10, 0xA)", Print('\n')); + EXPECT_EQ("'\\r' (13, 0xD)", Print('\r')); + EXPECT_EQ("'\\t' (9)", Print('\t')); + EXPECT_EQ("'\\v' (11, 0xB)", Print('\v')); + EXPECT_EQ("'\\x7F' (127)", Print('\x7F')); + EXPECT_EQ("'\\xFF' (255)", Print('\xFF')); + EXPECT_EQ("' ' (32, 0x20)", Print(' ')); + EXPECT_EQ("'a' (97, 0x61)", Print('a')); +} + +// signed char. +TEST(PrintCharTest, SignedChar) { + EXPECT_EQ("'\\0'", Print(static_cast('\0'))); + EXPECT_EQ("'\\xCE' (-50)", + Print(static_cast(-50))); +} + +// unsigned char. +TEST(PrintCharTest, UnsignedChar) { + EXPECT_EQ("'\\0'", Print(static_cast('\0'))); + EXPECT_EQ("'b' (98, 0x62)", + Print(static_cast('b'))); +} + +// Tests printing other simple, built-in types. + +// bool. +TEST(PrintBuiltInTypeTest, Bool) { + EXPECT_EQ("false", Print(false)); + EXPECT_EQ("true", Print(true)); +} + +// wchar_t. +TEST(PrintBuiltInTypeTest, Wchar_t) { + EXPECT_EQ("L'\\0'", Print(L'\0')); + EXPECT_EQ("L'\\'' (39, 0x27)", Print(L'\'')); + EXPECT_EQ("L'\"' (34, 0x22)", Print(L'"')); + EXPECT_EQ("L'?' (63, 0x3F)", Print(L'?')); + EXPECT_EQ("L'\\\\' (92, 0x5C)", Print(L'\\')); + EXPECT_EQ("L'\\a' (7)", Print(L'\a')); + EXPECT_EQ("L'\\b' (8)", Print(L'\b')); + EXPECT_EQ("L'\\f' (12, 0xC)", Print(L'\f')); + EXPECT_EQ("L'\\n' (10, 0xA)", Print(L'\n')); + EXPECT_EQ("L'\\r' (13, 0xD)", Print(L'\r')); + EXPECT_EQ("L'\\t' (9)", Print(L'\t')); + EXPECT_EQ("L'\\v' (11, 0xB)", Print(L'\v')); + EXPECT_EQ("L'\\x7F' (127)", Print(L'\x7F')); + EXPECT_EQ("L'\\xFF' (255)", Print(L'\xFF')); + EXPECT_EQ("L' ' (32, 0x20)", Print(L' ')); + EXPECT_EQ("L'a' (97, 0x61)", Print(L'a')); + EXPECT_EQ("L'\\x576' (1398)", Print(static_cast(0x576))); + EXPECT_EQ("L'\\xC74D' (51021)", Print(static_cast(0xC74D))); +} + +// Test that Int64 provides more storage than wchar_t. +TEST(PrintTypeSizeTest, Wchar_t) { + EXPECT_LT(sizeof(wchar_t), sizeof(testing::internal::Int64)); +} + +// Various integer types. +TEST(PrintBuiltInTypeTest, Integer) { + EXPECT_EQ("'\\xFF' (255)", Print(static_cast(255))); // uint8 + EXPECT_EQ("'\\x80' (-128)", Print(static_cast(-128))); // int8 + EXPECT_EQ("65535", Print(USHRT_MAX)); // uint16 + EXPECT_EQ("-32768", Print(SHRT_MIN)); // int16 + EXPECT_EQ("4294967295", Print(UINT_MAX)); // uint32 + EXPECT_EQ("-2147483648", Print(INT_MIN)); // int32 + EXPECT_EQ("18446744073709551615", + Print(static_cast(-1))); // uint64 + EXPECT_EQ("-9223372036854775808", + Print(static_cast(1) << 63)); // int64 +} + +// Size types. +TEST(PrintBuiltInTypeTest, Size_t) { + EXPECT_EQ("1", Print(sizeof('a'))); // size_t. +#if !GTEST_OS_WINDOWS + // Windows has no ssize_t type. + EXPECT_EQ("-2", Print(static_cast(-2))); // ssize_t. +#endif // !GTEST_OS_WINDOWS +} + +// Floating-points. +TEST(PrintBuiltInTypeTest, FloatingPoints) { + EXPECT_EQ("1.5", Print(1.5f)); // float + EXPECT_EQ("-2.5", Print(-2.5)); // double +} + +// Since ::std::stringstream::operator<<(const void *) formats the pointer +// output differently with different compilers, we have to create the expected +// output first and use it as our expectation. +static std::string PrintPointer(const void* p) { + ::std::stringstream expected_result_stream; + expected_result_stream << p; + return expected_result_stream.str(); +} + +// Tests printing C strings. + +// const char*. +TEST(PrintCStringTest, Const) { + const char* p = "World"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"World\"", Print(p)); +} + +// char*. +TEST(PrintCStringTest, NonConst) { + char p[] = "Hi"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"Hi\"", + Print(static_cast(p))); +} + +// NULL C string. +TEST(PrintCStringTest, Null) { + const char* p = nullptr; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests that C strings are escaped properly. +TEST(PrintCStringTest, EscapesProperly) { + const char* p = "'\"?\\\a\b\f\n\r\t\v\x7F\xFF a"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"'\\\"?\\\\\\a\\b\\f" + "\\n\\r\\t\\v\\x7F\\xFF a\"", + Print(p)); +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) + +// const wchar_t*. +TEST(PrintWideCStringTest, Const) { + const wchar_t* p = L"World"; + EXPECT_EQ(PrintPointer(p) + " pointing to L\"World\"", Print(p)); +} + +// wchar_t*. +TEST(PrintWideCStringTest, NonConst) { + wchar_t p[] = L"Hi"; + EXPECT_EQ(PrintPointer(p) + " pointing to L\"Hi\"", + Print(static_cast(p))); +} + +// NULL wide C string. +TEST(PrintWideCStringTest, Null) { + const wchar_t* p = nullptr; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests that wide C strings are escaped properly. +TEST(PrintWideCStringTest, EscapesProperly) { + const wchar_t s[] = {'\'', '"', '?', '\\', '\a', '\b', '\f', '\n', '\r', + '\t', '\v', 0xD3, 0x576, 0x8D3, 0xC74D, ' ', 'a', '\0'}; + EXPECT_EQ(PrintPointer(s) + " pointing to L\"'\\\"?\\\\\\a\\b\\f" + "\\n\\r\\t\\v\\xD3\\x576\\x8D3\\xC74D a\"", + Print(static_cast(s))); +} +#endif // native wchar_t + +// Tests printing pointers to other char types. + +// signed char*. +TEST(PrintCharPointerTest, SignedChar) { + signed char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = nullptr; + EXPECT_EQ("NULL", Print(p)); +} + +// const signed char*. +TEST(PrintCharPointerTest, ConstSignedChar) { + signed char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = nullptr; + EXPECT_EQ("NULL", Print(p)); +} + +// unsigned char*. +TEST(PrintCharPointerTest, UnsignedChar) { + unsigned char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = nullptr; + EXPECT_EQ("NULL", Print(p)); +} + +// const unsigned char*. +TEST(PrintCharPointerTest, ConstUnsignedChar) { + const unsigned char* p = reinterpret_cast(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = nullptr; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing pointers to simple, built-in types. + +// bool*. +TEST(PrintPointerToBuiltInTypeTest, Bool) { + bool* p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = nullptr; + EXPECT_EQ("NULL", Print(p)); +} + +// void*. +TEST(PrintPointerToBuiltInTypeTest, Void) { + void* p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = nullptr; + EXPECT_EQ("NULL", Print(p)); +} + +// const void*. +TEST(PrintPointerToBuiltInTypeTest, ConstVoid) { + const void* p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = nullptr; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing pointers to pointers. +TEST(PrintPointerToPointerTest, IntPointerPointer) { + int** p = reinterpret_cast(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = nullptr; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing (non-member) function pointers. + +void MyFunction(int /* n */) {} + +TEST(PrintPointerTest, NonMemberFunctionPointer) { + // We cannot directly cast &MyFunction to const void* because the + // standard disallows casting between pointers to functions and + // pointers to objects, and some compilers (e.g. GCC 3.4) enforce + // this limitation. + EXPECT_EQ( + PrintPointer(reinterpret_cast( + reinterpret_cast(&MyFunction))), + Print(&MyFunction)); + int (*p)(bool) = NULL; // NOLINT + EXPECT_EQ("NULL", Print(p)); +} + +// An assertion predicate determining whether a one string is a prefix for +// another. +template +AssertionResult HasPrefix(const StringType& str, const StringType& prefix) { + if (str.find(prefix, 0) == 0) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(prefix[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure() + << begin_string_quote << prefix << "\" is not a prefix of " + << begin_string_quote << str << "\"\n"; +} + +// Tests printing member variable pointers. Although they are called +// pointers, they don't point to a location in the address space. +// Their representation is implementation-defined. Thus they will be +// printed as raw bytes. + +struct Foo { + public: + virtual ~Foo() {} + int MyMethod(char x) { return x + 1; } + virtual char MyVirtualMethod(int /* n */) { return 'a'; } + + int value; +}; + +TEST(PrintPointerTest, MemberVariablePointer) { + EXPECT_TRUE(HasPrefix(Print(&Foo::value), + Print(sizeof(&Foo::value)) + "-byte object ")); + int Foo::*p = NULL; // NOLINT + EXPECT_TRUE(HasPrefix(Print(p), + Print(sizeof(p)) + "-byte object ")); +} + +// Tests printing member function pointers. Although they are called +// pointers, they don't point to a location in the address space. +// Their representation is implementation-defined. Thus they will be +// printed as raw bytes. +TEST(PrintPointerTest, MemberFunctionPointer) { + EXPECT_TRUE(HasPrefix(Print(&Foo::MyMethod), + Print(sizeof(&Foo::MyMethod)) + "-byte object ")); + EXPECT_TRUE( + HasPrefix(Print(&Foo::MyVirtualMethod), + Print(sizeof((&Foo::MyVirtualMethod))) + "-byte object ")); + int (Foo::*p)(char) = NULL; // NOLINT + EXPECT_TRUE(HasPrefix(Print(p), + Print(sizeof(p)) + "-byte object ")); +} + +// Tests printing C arrays. + +// The difference between this and Print() is that it ensures that the +// argument is a reference to an array. +template +std::string PrintArrayHelper(T (&a)[N]) { + return Print(a); +} + +// One-dimensional array. +TEST(PrintArrayTest, OneDimensionalArray) { + int a[5] = { 1, 2, 3, 4, 5 }; + EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a)); +} + +// Two-dimensional array. +TEST(PrintArrayTest, TwoDimensionalArray) { + int a[2][5] = { + { 1, 2, 3, 4, 5 }, + { 6, 7, 8, 9, 0 } + }; + EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", PrintArrayHelper(a)); +} + +// Array of const elements. +TEST(PrintArrayTest, ConstArray) { + const bool a[1] = { false }; + EXPECT_EQ("{ false }", PrintArrayHelper(a)); +} + +// char array without terminating NUL. +TEST(PrintArrayTest, CharArrayWithNoTerminatingNul) { + // Array a contains '\0' in the middle and doesn't end with '\0'. + char a[] = { 'H', '\0', 'i' }; + EXPECT_EQ("\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a)); +} + +// const char array with terminating NUL. +TEST(PrintArrayTest, ConstCharArrayWithTerminatingNul) { + const char a[] = "\0Hi"; + EXPECT_EQ("\"\\0Hi\"", PrintArrayHelper(a)); +} + +// const wchar_t array without terminating NUL. +TEST(PrintArrayTest, WCharArrayWithNoTerminatingNul) { + // Array a contains '\0' in the middle and doesn't end with '\0'. + const wchar_t a[] = { L'H', L'\0', L'i' }; + EXPECT_EQ("L\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a)); +} + +// wchar_t array with terminating NUL. +TEST(PrintArrayTest, WConstCharArrayWithTerminatingNul) { + const wchar_t a[] = L"\0Hi"; + EXPECT_EQ("L\"\\0Hi\"", PrintArrayHelper(a)); +} + +// Array of objects. +TEST(PrintArrayTest, ObjectArray) { + std::string a[3] = {"Hi", "Hello", "Ni hao"}; + EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", PrintArrayHelper(a)); +} + +// Array with many elements. +TEST(PrintArrayTest, BigArray) { + int a[100] = { 1, 2, 3 }; + EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }", + PrintArrayHelper(a)); +} + +// Tests printing ::string and ::std::string. + +// ::std::string. +TEST(PrintStringTest, StringInStdNamespace) { + const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; + const ::std::string str(s, sizeof(s)); + EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", + Print(str)); +} + +TEST(PrintStringTest, StringAmbiguousHex) { + // "\x6BANANA" is ambiguous, it can be interpreted as starting with either of: + // '\x6', '\x6B', or '\x6BA'. + + // a hex escaping sequence following by a decimal digit + EXPECT_EQ("\"0\\x12\" \"3\"", Print(::std::string("0\x12" "3"))); + // a hex escaping sequence following by a hex digit (lower-case) + EXPECT_EQ("\"mm\\x6\" \"bananas\"", Print(::std::string("mm\x6" "bananas"))); + // a hex escaping sequence following by a hex digit (upper-case) + EXPECT_EQ("\"NOM\\x6\" \"BANANA\"", Print(::std::string("NOM\x6" "BANANA"))); + // a hex escaping sequence following by a non-xdigit + EXPECT_EQ("\"!\\x5-!\"", Print(::std::string("!\x5-!"))); +} + +// Tests printing ::std::wstring. +#if GTEST_HAS_STD_WSTRING +// ::std::wstring. +TEST(PrintWideStringTest, StringInStdNamespace) { + const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; + const ::std::wstring str(s, sizeof(s)/sizeof(wchar_t)); + EXPECT_EQ("L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" + "\\xD3\\x576\\x8D3\\xC74D a\\0\"", + Print(str)); +} + +TEST(PrintWideStringTest, StringAmbiguousHex) { + // same for wide strings. + EXPECT_EQ("L\"0\\x12\" L\"3\"", Print(::std::wstring(L"0\x12" L"3"))); + EXPECT_EQ("L\"mm\\x6\" L\"bananas\"", + Print(::std::wstring(L"mm\x6" L"bananas"))); + EXPECT_EQ("L\"NOM\\x6\" L\"BANANA\"", + Print(::std::wstring(L"NOM\x6" L"BANANA"))); + EXPECT_EQ("L\"!\\x5-!\"", Print(::std::wstring(L"!\x5-!"))); +} +#endif // GTEST_HAS_STD_WSTRING + +// Tests printing types that support generic streaming (i.e. streaming +// to std::basic_ostream for any valid Char and +// CharTraits types). + +// Tests printing a non-template type that supports generic streaming. + +class AllowsGenericStreaming {}; + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const AllowsGenericStreaming& /* a */) { + return os << "AllowsGenericStreaming"; +} + +TEST(PrintTypeWithGenericStreamingTest, NonTemplateType) { + AllowsGenericStreaming a; + EXPECT_EQ("AllowsGenericStreaming", Print(a)); +} + +// Tests printing a template type that supports generic streaming. + +template +class AllowsGenericStreamingTemplate {}; + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const AllowsGenericStreamingTemplate& /* a */) { + return os << "AllowsGenericStreamingTemplate"; +} + +TEST(PrintTypeWithGenericStreamingTest, TemplateType) { + AllowsGenericStreamingTemplate a; + EXPECT_EQ("AllowsGenericStreamingTemplate", Print(a)); +} + +// Tests printing a type that supports generic streaming and can be +// implicitly converted to another printable type. + +template +class AllowsGenericStreamingAndImplicitConversionTemplate { + public: + operator bool() const { return false; } +}; + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const AllowsGenericStreamingAndImplicitConversionTemplate& /* a */) { + return os << "AllowsGenericStreamingAndImplicitConversionTemplate"; +} + +TEST(PrintTypeWithGenericStreamingTest, TypeImplicitlyConvertible) { + AllowsGenericStreamingAndImplicitConversionTemplate a; + EXPECT_EQ("AllowsGenericStreamingAndImplicitConversionTemplate", Print(a)); +} + +#if GTEST_HAS_ABSL + +// Tests printing ::absl::string_view. + +TEST(PrintStringViewTest, SimpleStringView) { + const ::absl::string_view sp = "Hello"; + EXPECT_EQ("\"Hello\"", Print(sp)); +} + +TEST(PrintStringViewTest, UnprintableCharacters) { + const char str[] = "NUL (\0) and \r\t"; + const ::absl::string_view sp(str, sizeof(str) - 1); + EXPECT_EQ("\"NUL (\\0) and \\r\\t\"", Print(sp)); +} + +#endif // GTEST_HAS_ABSL + +// Tests printing STL containers. + +TEST(PrintStlContainerTest, EmptyDeque) { + deque empty; + EXPECT_EQ("{}", Print(empty)); +} + +TEST(PrintStlContainerTest, NonEmptyDeque) { + deque non_empty; + non_empty.push_back(1); + non_empty.push_back(3); + EXPECT_EQ("{ 1, 3 }", Print(non_empty)); +} + + +TEST(PrintStlContainerTest, OneElementHashMap) { + ::std::unordered_map map1; + map1[1] = 'a'; + EXPECT_EQ("{ (1, 'a' (97, 0x61)) }", Print(map1)); +} + +TEST(PrintStlContainerTest, HashMultiMap) { + ::std::unordered_multimap map1; + map1.insert(make_pair(5, true)); + map1.insert(make_pair(5, false)); + + // Elements of hash_multimap can be printed in any order. + const std::string result = Print(map1); + EXPECT_TRUE(result == "{ (5, true), (5, false) }" || + result == "{ (5, false), (5, true) }") + << " where Print(map1) returns \"" << result << "\"."; +} + + + +TEST(PrintStlContainerTest, HashSet) { + ::std::unordered_set set1; + set1.insert(1); + EXPECT_EQ("{ 1 }", Print(set1)); +} + +TEST(PrintStlContainerTest, HashMultiSet) { + const int kSize = 5; + int a[kSize] = { 1, 1, 2, 5, 1 }; + ::std::unordered_multiset set1(a, a + kSize); + + // Elements of hash_multiset can be printed in any order. + const std::string result = Print(set1); + const std::string expected_pattern = "{ d, d, d, d, d }"; // d means a digit. + + // Verifies the result matches the expected pattern; also extracts + // the numbers in the result. + ASSERT_EQ(expected_pattern.length(), result.length()); + std::vector numbers; + for (size_t i = 0; i != result.length(); i++) { + if (expected_pattern[i] == 'd') { + ASSERT_NE(isdigit(static_cast(result[i])), 0); + numbers.push_back(result[i] - '0'); + } else { + EXPECT_EQ(expected_pattern[i], result[i]) << " where result is " + << result; + } + } + + // Makes sure the result contains the right numbers. + std::sort(numbers.begin(), numbers.end()); + std::sort(a, a + kSize); + EXPECT_TRUE(std::equal(a, a + kSize, numbers.begin())); +} + + +TEST(PrintStlContainerTest, List) { + const std::string a[] = {"hello", "world"}; + const list strings(a, a + 2); + EXPECT_EQ("{ \"hello\", \"world\" }", Print(strings)); +} + +TEST(PrintStlContainerTest, Map) { + map map1; + map1[1] = true; + map1[5] = false; + map1[3] = true; + EXPECT_EQ("{ (1, true), (3, true), (5, false) }", Print(map1)); +} + +TEST(PrintStlContainerTest, MultiMap) { + multimap map1; + // The make_pair template function would deduce the type as + // pair here, and since the key part in a multimap has to + // be constant, without a templated ctor in the pair class (as in + // libCstd on Solaris), make_pair call would fail to compile as no + // implicit conversion is found. Thus explicit typename is used + // here instead. + map1.insert(pair(true, 0)); + map1.insert(pair(true, 1)); + map1.insert(pair(false, 2)); + EXPECT_EQ("{ (false, 2), (true, 0), (true, 1) }", Print(map1)); +} + +TEST(PrintStlContainerTest, Set) { + const unsigned int a[] = { 3, 0, 5 }; + set set1(a, a + 3); + EXPECT_EQ("{ 0, 3, 5 }", Print(set1)); +} + +TEST(PrintStlContainerTest, MultiSet) { + const int a[] = { 1, 1, 2, 5, 1 }; + multiset set1(a, a + 5); + EXPECT_EQ("{ 1, 1, 1, 2, 5 }", Print(set1)); +} + + +TEST(PrintStlContainerTest, SinglyLinkedList) { + int a[] = { 9, 2, 8 }; + const std::forward_list ints(a, a + 3); + EXPECT_EQ("{ 9, 2, 8 }", Print(ints)); +} + +TEST(PrintStlContainerTest, Pair) { + pair p(true, 5); + EXPECT_EQ("(true, 5)", Print(p)); +} + +TEST(PrintStlContainerTest, Vector) { + vector v; + v.push_back(1); + v.push_back(2); + EXPECT_EQ("{ 1, 2 }", Print(v)); +} + +TEST(PrintStlContainerTest, LongSequence) { + const int a[100] = { 1, 2, 3 }; + const vector v(a, a + 100); + EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, " + "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... }", Print(v)); +} + +TEST(PrintStlContainerTest, NestedContainer) { + const int a1[] = { 1, 2 }; + const int a2[] = { 3, 4, 5 }; + const list l1(a1, a1 + 2); + const list l2(a2, a2 + 3); + + vector > v; + v.push_back(l1); + v.push_back(l2); + EXPECT_EQ("{ { 1, 2 }, { 3, 4, 5 } }", Print(v)); +} + +TEST(PrintStlContainerTest, OneDimensionalNativeArray) { + const int a[3] = { 1, 2, 3 }; + NativeArray b(a, 3, RelationToSourceReference()); + EXPECT_EQ("{ 1, 2, 3 }", Print(b)); +} + +TEST(PrintStlContainerTest, TwoDimensionalNativeArray) { + const int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; + NativeArray b(a, 2, RelationToSourceReference()); + EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b)); +} + +// Tests that a class named iterator isn't treated as a container. + +struct iterator { + char x; +}; + +TEST(PrintStlContainerTest, Iterator) { + iterator it = {}; + EXPECT_EQ("1-byte object <00>", Print(it)); +} + +// Tests that a class named const_iterator isn't treated as a container. + +struct const_iterator { + char x; +}; + +TEST(PrintStlContainerTest, ConstIterator) { + const_iterator it = {}; + EXPECT_EQ("1-byte object <00>", Print(it)); +} + +// Tests printing ::std::tuples. + +// Tuples of various arities. +TEST(PrintStdTupleTest, VariousSizes) { + ::std::tuple<> t0; + EXPECT_EQ("()", Print(t0)); + + ::std::tuple t1(5); + EXPECT_EQ("(5)", Print(t1)); + + ::std::tuple t2('a', true); + EXPECT_EQ("('a' (97, 0x61), true)", Print(t2)); + + ::std::tuple t3(false, 2, 3); + EXPECT_EQ("(false, 2, 3)", Print(t3)); + + ::std::tuple t4(false, 2, 3, 4); + EXPECT_EQ("(false, 2, 3, 4)", Print(t4)); + + const char* const str = "8"; + ::std::tuple + t10(false, 'a', static_cast(3), 4, 5, 1.5F, -2.5, str, // NOLINT + nullptr, "10"); + EXPECT_EQ("(false, 'a' (97, 0x61), 3, 4, 5, 1.5, -2.5, " + PrintPointer(str) + + " pointing to \"8\", NULL, \"10\")", + Print(t10)); +} + +// Nested tuples. +TEST(PrintStdTupleTest, NestedTuple) { + ::std::tuple< ::std::tuple, char> nested( + ::std::make_tuple(5, true), 'a'); + EXPECT_EQ("((5, true), 'a' (97, 0x61))", Print(nested)); +} + +TEST(PrintNullptrT, Basic) { + EXPECT_EQ("(nullptr)", Print(nullptr)); +} + +TEST(PrintReferenceWrapper, Printable) { + int x = 5; + EXPECT_EQ("@" + PrintPointer(&x) + " 5", Print(std::ref(x))); + EXPECT_EQ("@" + PrintPointer(&x) + " 5", Print(std::cref(x))); +} + +TEST(PrintReferenceWrapper, Unprintable) { + ::foo::UnprintableInFoo up; + EXPECT_EQ( + "@" + PrintPointer(&up) + + " 16-byte object ", + Print(std::ref(up))); + EXPECT_EQ( + "@" + PrintPointer(&up) + + " 16-byte object ", + Print(std::cref(up))); +} + +// Tests printing user-defined unprintable types. + +// Unprintable types in the global namespace. +TEST(PrintUnprintableTypeTest, InGlobalNamespace) { + EXPECT_EQ("1-byte object <00>", + Print(UnprintableTemplateInGlobal())); +} + +// Unprintable types in a user namespace. +TEST(PrintUnprintableTypeTest, InUserNamespace) { + EXPECT_EQ("16-byte object ", + Print(::foo::UnprintableInFoo())); +} + +// Unprintable types are that too big to be printed completely. + +struct Big { + Big() { memset(array, 0, sizeof(array)); } + char array[257]; +}; + +TEST(PrintUnpritableTypeTest, BigObject) { + EXPECT_EQ("257-byte object <00-00 00-00 00-00 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 ... 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " + "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00>", + Print(Big())); +} + +// Tests printing user-defined streamable types. + +// Streamable types in the global namespace. +TEST(PrintStreamableTypeTest, InGlobalNamespace) { + StreamableInGlobal x; + EXPECT_EQ("StreamableInGlobal", Print(x)); + EXPECT_EQ("StreamableInGlobal*", Print(&x)); +} + +// Printable template types in a user namespace. +TEST(PrintStreamableTypeTest, TemplateTypeInUserNamespace) { + EXPECT_EQ("StreamableTemplateInFoo: 0", + Print(::foo::StreamableTemplateInFoo())); +} + +// Tests printing a user-defined recursive container type that has a << +// operator. +TEST(PrintStreamableTypeTest, PathLikeInUserNamespace) { + ::foo::PathLike x; + EXPECT_EQ("Streamable-PathLike", Print(x)); + const ::foo::PathLike cx; + EXPECT_EQ("Streamable-PathLike", Print(cx)); +} + +// Tests printing user-defined types that have a PrintTo() function. +TEST(PrintPrintableTypeTest, InUserNamespace) { + EXPECT_EQ("PrintableViaPrintTo: 0", + Print(::foo::PrintableViaPrintTo())); +} + +// Tests printing a pointer to a user-defined type that has a << +// operator for its pointer. +TEST(PrintPrintableTypeTest, PointerInUserNamespace) { + ::foo::PointerPrintable x; + EXPECT_EQ("PointerPrintable*", Print(&x)); +} + +// Tests printing user-defined class template that have a PrintTo() function. +TEST(PrintPrintableTypeTest, TemplateInUserNamespace) { + EXPECT_EQ("PrintableViaPrintToTemplate: 5", + Print(::foo::PrintableViaPrintToTemplate(5))); +} + +// Tests that the universal printer prints both the address and the +// value of a reference. +TEST(PrintReferenceTest, PrintsAddressAndValue) { + int n = 5; + EXPECT_EQ("@" + PrintPointer(&n) + " 5", PrintByRef(n)); + + int a[2][3] = { + { 0, 1, 2 }, + { 3, 4, 5 } + }; + EXPECT_EQ("@" + PrintPointer(a) + " { { 0, 1, 2 }, { 3, 4, 5 } }", + PrintByRef(a)); + + const ::foo::UnprintableInFoo x; + EXPECT_EQ("@" + PrintPointer(&x) + " 16-byte object " + "", + PrintByRef(x)); +} + +// Tests that the universal printer prints a function pointer passed by +// reference. +TEST(PrintReferenceTest, HandlesFunctionPointer) { + void (*fp)(int n) = &MyFunction; + const std::string fp_pointer_string = + PrintPointer(reinterpret_cast(&fp)); + // We cannot directly cast &MyFunction to const void* because the + // standard disallows casting between pointers to functions and + // pointers to objects, and some compilers (e.g. GCC 3.4) enforce + // this limitation. + const std::string fp_string = PrintPointer(reinterpret_cast( + reinterpret_cast(fp))); + EXPECT_EQ("@" + fp_pointer_string + " " + fp_string, + PrintByRef(fp)); +} + +// Tests that the universal printer prints a member function pointer +// passed by reference. +TEST(PrintReferenceTest, HandlesMemberFunctionPointer) { + int (Foo::*p)(char ch) = &Foo::MyMethod; + EXPECT_TRUE(HasPrefix( + PrintByRef(p), + "@" + PrintPointer(reinterpret_cast(&p)) + " " + + Print(sizeof(p)) + "-byte object ")); + + char (Foo::*p2)(int n) = &Foo::MyVirtualMethod; + EXPECT_TRUE(HasPrefix( + PrintByRef(p2), + "@" + PrintPointer(reinterpret_cast(&p2)) + " " + + Print(sizeof(p2)) + "-byte object ")); +} + +// Tests that the universal printer prints a member variable pointer +// passed by reference. +TEST(PrintReferenceTest, HandlesMemberVariablePointer) { + int Foo::*p = &Foo::value; // NOLINT + EXPECT_TRUE(HasPrefix( + PrintByRef(p), + "@" + PrintPointer(&p) + " " + Print(sizeof(p)) + "-byte object ")); +} + +// Tests that FormatForComparisonFailureMessage(), which is used to print +// an operand in a comparison assertion (e.g. ASSERT_EQ) when the assertion +// fails, formats the operand in the desired way. + +// scalar +TEST(FormatForComparisonFailureMessageTest, WorksForScalar) { + EXPECT_STREQ("123", + FormatForComparisonFailureMessage(123, 124).c_str()); +} + +// non-char pointer +TEST(FormatForComparisonFailureMessageTest, WorksForNonCharPointer) { + int n = 0; + EXPECT_EQ(PrintPointer(&n), + FormatForComparisonFailureMessage(&n, &n).c_str()); +} + +// non-char array +TEST(FormatForComparisonFailureMessageTest, FormatsNonCharArrayAsPointer) { + // In expression 'array == x', 'array' is compared by pointer. + // Therefore we want to print an array operand as a pointer. + int n[] = { 1, 2, 3 }; + EXPECT_EQ(PrintPointer(n), + FormatForComparisonFailureMessage(n, n).c_str()); +} + +// Tests formatting a char pointer when it's compared with another pointer. +// In this case we want to print it as a raw pointer, as the comparison is by +// pointer. + +// char pointer vs pointer +TEST(FormatForComparisonFailureMessageTest, WorksForCharPointerVsPointer) { + // In expression 'p == x', where 'p' and 'x' are (const or not) char + // pointers, the operands are compared by pointer. Therefore we + // want to print 'p' as a pointer instead of a C string (we don't + // even know if it's supposed to point to a valid C string). + + // const char* + const char* s = "hello"; + EXPECT_EQ(PrintPointer(s), + FormatForComparisonFailureMessage(s, s).c_str()); + + // char* + char ch = 'a'; + EXPECT_EQ(PrintPointer(&ch), + FormatForComparisonFailureMessage(&ch, &ch).c_str()); +} + +// wchar_t pointer vs pointer +TEST(FormatForComparisonFailureMessageTest, WorksForWCharPointerVsPointer) { + // In expression 'p == x', where 'p' and 'x' are (const or not) char + // pointers, the operands are compared by pointer. Therefore we + // want to print 'p' as a pointer instead of a wide C string (we don't + // even know if it's supposed to point to a valid wide C string). + + // const wchar_t* + const wchar_t* s = L"hello"; + EXPECT_EQ(PrintPointer(s), + FormatForComparisonFailureMessage(s, s).c_str()); + + // wchar_t* + wchar_t ch = L'a'; + EXPECT_EQ(PrintPointer(&ch), + FormatForComparisonFailureMessage(&ch, &ch).c_str()); +} + +// Tests formatting a char pointer when it's compared to a string object. +// In this case we want to print the char pointer as a C string. + +// char pointer vs std::string +TEST(FormatForComparisonFailureMessageTest, WorksForCharPointerVsStdString) { + const char* s = "hello \"world"; + EXPECT_STREQ("\"hello \\\"world\"", // The string content should be escaped. + FormatForComparisonFailureMessage(s, ::std::string()).c_str()); + + // char* + char str[] = "hi\1"; + char* p = str; + EXPECT_STREQ("\"hi\\x1\"", // The string content should be escaped. + FormatForComparisonFailureMessage(p, ::std::string()).c_str()); +} + +#if GTEST_HAS_STD_WSTRING +// wchar_t pointer vs std::wstring +TEST(FormatForComparisonFailureMessageTest, WorksForWCharPointerVsStdWString) { + const wchar_t* s = L"hi \"world"; + EXPECT_STREQ("L\"hi \\\"world\"", // The string content should be escaped. + FormatForComparisonFailureMessage(s, ::std::wstring()).c_str()); + + // wchar_t* + wchar_t str[] = L"hi\1"; + wchar_t* p = str; + EXPECT_STREQ("L\"hi\\x1\"", // The string content should be escaped. + FormatForComparisonFailureMessage(p, ::std::wstring()).c_str()); +} +#endif + +// Tests formatting a char array when it's compared with a pointer or array. +// In this case we want to print the array as a row pointer, as the comparison +// is by pointer. + +// char array vs pointer +TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsPointer) { + char str[] = "hi \"world\""; + char* p = nullptr; + EXPECT_EQ(PrintPointer(str), + FormatForComparisonFailureMessage(str, p).c_str()); +} + +// char array vs char array +TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsCharArray) { + const char str[] = "hi \"world\""; + EXPECT_EQ(PrintPointer(str), + FormatForComparisonFailureMessage(str, str).c_str()); +} + +// wchar_t array vs pointer +TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsPointer) { + wchar_t str[] = L"hi \"world\""; + wchar_t* p = nullptr; + EXPECT_EQ(PrintPointer(str), + FormatForComparisonFailureMessage(str, p).c_str()); +} + +// wchar_t array vs wchar_t array +TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsWCharArray) { + const wchar_t str[] = L"hi \"world\""; + EXPECT_EQ(PrintPointer(str), + FormatForComparisonFailureMessage(str, str).c_str()); +} + +// Tests formatting a char array when it's compared with a string object. +// In this case we want to print the array as a C string. + +// char array vs std::string +TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsStdString) { + const char str[] = "hi \"world\""; + EXPECT_STREQ("\"hi \\\"world\\\"\"", // The content should be escaped. + FormatForComparisonFailureMessage(str, ::std::string()).c_str()); +} + +#if GTEST_HAS_STD_WSTRING +// wchar_t array vs std::wstring +TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsStdWString) { + const wchar_t str[] = L"hi \"w\0rld\""; + EXPECT_STREQ( + "L\"hi \\\"w\"", // The content should be escaped. + // Embedded NUL terminates the string. + FormatForComparisonFailureMessage(str, ::std::wstring()).c_str()); +} +#endif + +// Useful for testing PrintToString(). We cannot use EXPECT_EQ() +// there as its implementation uses PrintToString(). The caller must +// ensure that 'value' has no side effect. +#define EXPECT_PRINT_TO_STRING_(value, expected_string) \ + EXPECT_TRUE(PrintToString(value) == (expected_string)) \ + << " where " #value " prints as " << (PrintToString(value)) + +TEST(PrintToStringTest, WorksForScalar) { + EXPECT_PRINT_TO_STRING_(123, "123"); +} + +TEST(PrintToStringTest, WorksForPointerToConstChar) { + const char* p = "hello"; + EXPECT_PRINT_TO_STRING_(p, "\"hello\""); +} + +TEST(PrintToStringTest, WorksForPointerToNonConstChar) { + char s[] = "hello"; + char* p = s; + EXPECT_PRINT_TO_STRING_(p, "\"hello\""); +} + +TEST(PrintToStringTest, EscapesForPointerToConstChar) { + const char* p = "hello\n"; + EXPECT_PRINT_TO_STRING_(p, "\"hello\\n\""); +} + +TEST(PrintToStringTest, EscapesForPointerToNonConstChar) { + char s[] = "hello\1"; + char* p = s; + EXPECT_PRINT_TO_STRING_(p, "\"hello\\x1\""); +} + +TEST(PrintToStringTest, WorksForArray) { + int n[3] = { 1, 2, 3 }; + EXPECT_PRINT_TO_STRING_(n, "{ 1, 2, 3 }"); +} + +TEST(PrintToStringTest, WorksForCharArray) { + char s[] = "hello"; + EXPECT_PRINT_TO_STRING_(s, "\"hello\""); +} + +TEST(PrintToStringTest, WorksForCharArrayWithEmbeddedNul) { + const char str_with_nul[] = "hello\0 world"; + EXPECT_PRINT_TO_STRING_(str_with_nul, "\"hello\\0 world\""); + + char mutable_str_with_nul[] = "hello\0 world"; + EXPECT_PRINT_TO_STRING_(mutable_str_with_nul, "\"hello\\0 world\""); +} + + TEST(PrintToStringTest, ContainsNonLatin) { + // Sanity test with valid UTF-8. Prints both in hex and as text. + std::string non_ascii_str = ::std::string("오전 4:30"); + EXPECT_PRINT_TO_STRING_(non_ascii_str, + "\"\\xEC\\x98\\xA4\\xEC\\xA0\\x84 4:30\"\n" + " As Text: \"오전 4:30\""); + non_ascii_str = ::std::string("From ä — ẑ"); + EXPECT_PRINT_TO_STRING_(non_ascii_str, + "\"From \\xC3\\xA4 \\xE2\\x80\\x94 \\xE1\\xBA\\x91\"" + "\n As Text: \"From ä — ẑ\""); +} + +TEST(IsValidUTF8Test, IllFormedUTF8) { + // The following test strings are ill-formed UTF-8 and are printed + // as hex only (or ASCII, in case of ASCII bytes) because IsValidUTF8() is + // expected to fail, thus output does not contain "As Text:". + + static const char *const kTestdata[][2] = { + // 2-byte lead byte followed by a single-byte character. + {"\xC3\x74", "\"\\xC3t\""}, + // Valid 2-byte character followed by an orphan trail byte. + {"\xC3\x84\xA4", "\"\\xC3\\x84\\xA4\""}, + // Lead byte without trail byte. + {"abc\xC3", "\"abc\\xC3\""}, + // 3-byte lead byte, single-byte character, orphan trail byte. + {"x\xE2\x70\x94", "\"x\\xE2p\\x94\""}, + // Truncated 3-byte character. + {"\xE2\x80", "\"\\xE2\\x80\""}, + // Truncated 3-byte character followed by valid 2-byte char. + {"\xE2\x80\xC3\x84", "\"\\xE2\\x80\\xC3\\x84\""}, + // Truncated 3-byte character followed by a single-byte character. + {"\xE2\x80\x7A", "\"\\xE2\\x80z\""}, + // 3-byte lead byte followed by valid 3-byte character. + {"\xE2\xE2\x80\x94", "\"\\xE2\\xE2\\x80\\x94\""}, + // 4-byte lead byte followed by valid 3-byte character. + {"\xF0\xE2\x80\x94", "\"\\xF0\\xE2\\x80\\x94\""}, + // Truncated 4-byte character. + {"\xF0\xE2\x80", "\"\\xF0\\xE2\\x80\""}, + // Invalid UTF-8 byte sequences embedded in other chars. + {"abc\xE2\x80\x94\xC3\x74xyc", "\"abc\\xE2\\x80\\x94\\xC3txyc\""}, + {"abc\xC3\x84\xE2\x80\xC3\x84xyz", + "\"abc\\xC3\\x84\\xE2\\x80\\xC3\\x84xyz\""}, + // Non-shortest UTF-8 byte sequences are also ill-formed. + // The classics: xC0, xC1 lead byte. + {"\xC0\x80", "\"\\xC0\\x80\""}, + {"\xC1\x81", "\"\\xC1\\x81\""}, + // Non-shortest sequences. + {"\xE0\x80\x80", "\"\\xE0\\x80\\x80\""}, + {"\xf0\x80\x80\x80", "\"\\xF0\\x80\\x80\\x80\""}, + // Last valid code point before surrogate range, should be printed as text, + // too. + {"\xED\x9F\xBF", "\"\\xED\\x9F\\xBF\"\n As Text: \"퟿\""}, + // Start of surrogate lead. Surrogates are not printed as text. + {"\xED\xA0\x80", "\"\\xED\\xA0\\x80\""}, + // Last non-private surrogate lead. + {"\xED\xAD\xBF", "\"\\xED\\xAD\\xBF\""}, + // First private-use surrogate lead. + {"\xED\xAE\x80", "\"\\xED\\xAE\\x80\""}, + // Last private-use surrogate lead. + {"\xED\xAF\xBF", "\"\\xED\\xAF\\xBF\""}, + // Mid-point of surrogate trail. + {"\xED\xB3\xBF", "\"\\xED\\xB3\\xBF\""}, + // First valid code point after surrogate range, should be printed as text, + // too. + {"\xEE\x80\x80", "\"\\xEE\\x80\\x80\"\n As Text: \"\""} + }; + + for (int i = 0; i < int(sizeof(kTestdata)/sizeof(kTestdata[0])); ++i) { + EXPECT_PRINT_TO_STRING_(kTestdata[i][0], kTestdata[i][1]); + } +} + +#undef EXPECT_PRINT_TO_STRING_ + +TEST(UniversalTersePrintTest, WorksForNonReference) { + ::std::stringstream ss; + UniversalTersePrint(123, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalTersePrintTest, WorksForReference) { + const int& n = 123; + ::std::stringstream ss; + UniversalTersePrint(n, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalTersePrintTest, WorksForCString) { + const char* s1 = "abc"; + ::std::stringstream ss1; + UniversalTersePrint(s1, &ss1); + EXPECT_EQ("\"abc\"", ss1.str()); + + char* s2 = const_cast(s1); + ::std::stringstream ss2; + UniversalTersePrint(s2, &ss2); + EXPECT_EQ("\"abc\"", ss2.str()); + + const char* s3 = nullptr; + ::std::stringstream ss3; + UniversalTersePrint(s3, &ss3); + EXPECT_EQ("NULL", ss3.str()); +} + +TEST(UniversalPrintTest, WorksForNonReference) { + ::std::stringstream ss; + UniversalPrint(123, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalPrintTest, WorksForReference) { + const int& n = 123; + ::std::stringstream ss; + UniversalPrint(n, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalPrintTest, WorksForCString) { + const char* s1 = "abc"; + ::std::stringstream ss1; + UniversalPrint(s1, &ss1); + EXPECT_EQ(PrintPointer(s1) + " pointing to \"abc\"", std::string(ss1.str())); + + char* s2 = const_cast(s1); + ::std::stringstream ss2; + UniversalPrint(s2, &ss2); + EXPECT_EQ(PrintPointer(s2) + " pointing to \"abc\"", std::string(ss2.str())); + + const char* s3 = nullptr; + ::std::stringstream ss3; + UniversalPrint(s3, &ss3); + EXPECT_EQ("NULL", ss3.str()); +} + +TEST(UniversalPrintTest, WorksForCharArray) { + const char str[] = "\"Line\0 1\"\nLine 2"; + ::std::stringstream ss1; + UniversalPrint(str, &ss1); + EXPECT_EQ("\"\\\"Line\\0 1\\\"\\nLine 2\"", ss1.str()); + + const char mutable_str[] = "\"Line\0 1\"\nLine 2"; + ::std::stringstream ss2; + UniversalPrint(mutable_str, &ss2); + EXPECT_EQ("\"\\\"Line\\0 1\\\"\\nLine 2\"", ss2.str()); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsEmptyTuple) { + Strings result = UniversalTersePrintTupleFieldsToStrings(::std::make_tuple()); + EXPECT_EQ(0u, result.size()); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsOneTuple) { + Strings result = UniversalTersePrintTupleFieldsToStrings( + ::std::make_tuple(1)); + ASSERT_EQ(1u, result.size()); + EXPECT_EQ("1", result[0]); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsTwoTuple) { + Strings result = UniversalTersePrintTupleFieldsToStrings( + ::std::make_tuple(1, 'a')); + ASSERT_EQ(2u, result.size()); + EXPECT_EQ("1", result[0]); + EXPECT_EQ("'a' (97, 0x61)", result[1]); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsTersely) { + const int n = 1; + Strings result = UniversalTersePrintTupleFieldsToStrings( + ::std::tuple(n, "a")); + ASSERT_EQ(2u, result.size()); + EXPECT_EQ("1", result[0]); + EXPECT_EQ("\"a\"", result[1]); +} + +#if GTEST_HAS_ABSL + +TEST(PrintOptionalTest, Basic) { + absl::optional value; + EXPECT_EQ("(nullopt)", PrintToString(value)); + value = {7}; + EXPECT_EQ("(7)", PrintToString(value)); + EXPECT_EQ("(1.1)", PrintToString(absl::optional{1.1})); + EXPECT_EQ("(\"A\")", PrintToString(absl::optional{"A"})); +} + +struct NonPrintable { + unsigned char contents = 17; +}; + +TEST(PrintOneofTest, Basic) { + using Type = absl::variant; + EXPECT_EQ("('int' with value 7)", PrintToString(Type(7))); + EXPECT_EQ("('StreamableInGlobal' with value StreamableInGlobal)", + PrintToString(Type(StreamableInGlobal{}))); + EXPECT_EQ( + "('testing::gtest_printers_test::NonPrintable' with value 1-byte object " + "<11>)", + PrintToString(Type(NonPrintable{}))); +} +#endif // GTEST_HAS_ABSL +namespace { +class string_ref; + +/** + * This is a synthetic pointer to a fixed size string. + */ +class string_ptr { + public: + string_ptr(const char* data, size_t size) : data_(data), size_(size) {} + + string_ptr& operator++() noexcept { + data_ += size_; + return *this; + } + + string_ref operator*() const noexcept; + + private: + const char* data_; + size_t size_; +}; + +/** + * This is a synthetic reference of a fixed size string. + */ +class string_ref { + public: + string_ref(const char* data, size_t size) : data_(data), size_(size) {} + + string_ptr operator&() const noexcept { return {data_, size_}; } // NOLINT + + bool operator==(const char* s) const noexcept { + if (size_ > 0 && data_[size_ - 1] != 0) { + return std::string(data_, size_) == std::string(s); + } else { + return std::string(data_) == std::string(s); + } + } + + private: + const char* data_; + size_t size_; +}; + +string_ref string_ptr::operator*() const noexcept { return {data_, size_}; } + +TEST(string_ref, compare) { + const char* s = "alex\0davidjohn\0"; + string_ptr ptr(s, 5); + EXPECT_EQ(*ptr, "alex"); + EXPECT_TRUE(*ptr == "alex"); + ++ptr; + EXPECT_EQ(*ptr, "david"); + EXPECT_TRUE(*ptr == "david"); + ++ptr; + EXPECT_EQ(*ptr, "john"); +} + +} // namespace + +} // namespace gtest_printers_test +} // namespace testing diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-shuffle-test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-shuffle-test.py new file mode 100755 index 0000000000000000000000000000000000000000..573cc5eca3fce458aa3ac3e39850f47bb382e55b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-shuffle-test.py @@ -0,0 +1,323 @@ +#!/usr/bin/env python +# +# Copyright 2009 Google Inc. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Verifies that test shuffling works.""" + +import os +import gtest_test_utils + +# Command to run the googletest-shuffle-test_ program. +COMMAND = gtest_test_utils.GetTestExecutablePath('googletest-shuffle-test_') + +# The environment variables for test sharding. +TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' +SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' + +TEST_FILTER = 'A*.A:A*.B:C*' + +ALL_TESTS = [] +ACTIVE_TESTS = [] +FILTERED_TESTS = [] +SHARDED_TESTS = [] + +SHUFFLED_ALL_TESTS = [] +SHUFFLED_ACTIVE_TESTS = [] +SHUFFLED_FILTERED_TESTS = [] +SHUFFLED_SHARDED_TESTS = [] + + +def AlsoRunDisabledTestsFlag(): + return '--gtest_also_run_disabled_tests' + + +def FilterFlag(test_filter): + return '--gtest_filter=%s' % (test_filter,) + + +def RepeatFlag(n): + return '--gtest_repeat=%s' % (n,) + + +def ShuffleFlag(): + return '--gtest_shuffle' + + +def RandomSeedFlag(n): + return '--gtest_random_seed=%s' % (n,) + + +def RunAndReturnOutput(extra_env, args): + """Runs the test program and returns its output.""" + + environ_copy = os.environ.copy() + environ_copy.update(extra_env) + + return gtest_test_utils.Subprocess([COMMAND] + args, env=environ_copy).output + + +def GetTestsForAllIterations(extra_env, args): + """Runs the test program and returns a list of test lists. + + Args: + extra_env: a map from environment variables to their values + args: command line flags to pass to googletest-shuffle-test_ + + Returns: + A list where the i-th element is the list of tests run in the i-th + test iteration. + """ + + test_iterations = [] + for line in RunAndReturnOutput(extra_env, args).split('\n'): + if line.startswith('----'): + tests = [] + test_iterations.append(tests) + elif line.strip(): + tests.append(line.strip()) # 'TestCaseName.TestName' + + return test_iterations + + +def GetTestCases(tests): + """Returns a list of test cases in the given full test names. + + Args: + tests: a list of full test names + + Returns: + A list of test cases from 'tests', in their original order. + Consecutive duplicates are removed. + """ + + test_cases = [] + for test in tests: + test_case = test.split('.')[0] + if not test_case in test_cases: + test_cases.append(test_case) + + return test_cases + + +def CalculateTestLists(): + """Calculates the list of tests run under different flags.""" + + if not ALL_TESTS: + ALL_TESTS.extend( + GetTestsForAllIterations({}, [AlsoRunDisabledTestsFlag()])[0]) + + if not ACTIVE_TESTS: + ACTIVE_TESTS.extend(GetTestsForAllIterations({}, [])[0]) + + if not FILTERED_TESTS: + FILTERED_TESTS.extend( + GetTestsForAllIterations({}, [FilterFlag(TEST_FILTER)])[0]) + + if not SHARDED_TESTS: + SHARDED_TESTS.extend( + GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '1'}, + [])[0]) + + if not SHUFFLED_ALL_TESTS: + SHUFFLED_ALL_TESTS.extend(GetTestsForAllIterations( + {}, [AlsoRunDisabledTestsFlag(), ShuffleFlag(), RandomSeedFlag(1)])[0]) + + if not SHUFFLED_ACTIVE_TESTS: + SHUFFLED_ACTIVE_TESTS.extend(GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1)])[0]) + + if not SHUFFLED_FILTERED_TESTS: + SHUFFLED_FILTERED_TESTS.extend(GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1), FilterFlag(TEST_FILTER)])[0]) + + if not SHUFFLED_SHARDED_TESTS: + SHUFFLED_SHARDED_TESTS.extend( + GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '1'}, + [ShuffleFlag(), RandomSeedFlag(1)])[0]) + + +class GTestShuffleUnitTest(gtest_test_utils.TestCase): + """Tests test shuffling.""" + + def setUp(self): + CalculateTestLists() + + def testShufflePreservesNumberOfTests(self): + self.assertEqual(len(ALL_TESTS), len(SHUFFLED_ALL_TESTS)) + self.assertEqual(len(ACTIVE_TESTS), len(SHUFFLED_ACTIVE_TESTS)) + self.assertEqual(len(FILTERED_TESTS), len(SHUFFLED_FILTERED_TESTS)) + self.assertEqual(len(SHARDED_TESTS), len(SHUFFLED_SHARDED_TESTS)) + + def testShuffleChangesTestOrder(self): + self.assert_(SHUFFLED_ALL_TESTS != ALL_TESTS, SHUFFLED_ALL_TESTS) + self.assert_(SHUFFLED_ACTIVE_TESTS != ACTIVE_TESTS, SHUFFLED_ACTIVE_TESTS) + self.assert_(SHUFFLED_FILTERED_TESTS != FILTERED_TESTS, + SHUFFLED_FILTERED_TESTS) + self.assert_(SHUFFLED_SHARDED_TESTS != SHARDED_TESTS, + SHUFFLED_SHARDED_TESTS) + + def testShuffleChangesTestCaseOrder(self): + self.assert_(GetTestCases(SHUFFLED_ALL_TESTS) != GetTestCases(ALL_TESTS), + GetTestCases(SHUFFLED_ALL_TESTS)) + self.assert_( + GetTestCases(SHUFFLED_ACTIVE_TESTS) != GetTestCases(ACTIVE_TESTS), + GetTestCases(SHUFFLED_ACTIVE_TESTS)) + self.assert_( + GetTestCases(SHUFFLED_FILTERED_TESTS) != GetTestCases(FILTERED_TESTS), + GetTestCases(SHUFFLED_FILTERED_TESTS)) + self.assert_( + GetTestCases(SHUFFLED_SHARDED_TESTS) != GetTestCases(SHARDED_TESTS), + GetTestCases(SHUFFLED_SHARDED_TESTS)) + + def testShuffleDoesNotRepeatTest(self): + for test in SHUFFLED_ALL_TESTS: + self.assertEqual(1, SHUFFLED_ALL_TESTS.count(test), + '%s appears more than once' % (test,)) + for test in SHUFFLED_ACTIVE_TESTS: + self.assertEqual(1, SHUFFLED_ACTIVE_TESTS.count(test), + '%s appears more than once' % (test,)) + for test in SHUFFLED_FILTERED_TESTS: + self.assertEqual(1, SHUFFLED_FILTERED_TESTS.count(test), + '%s appears more than once' % (test,)) + for test in SHUFFLED_SHARDED_TESTS: + self.assertEqual(1, SHUFFLED_SHARDED_TESTS.count(test), + '%s appears more than once' % (test,)) + + def testShuffleDoesNotCreateNewTest(self): + for test in SHUFFLED_ALL_TESTS: + self.assert_(test in ALL_TESTS, '%s is an invalid test' % (test,)) + for test in SHUFFLED_ACTIVE_TESTS: + self.assert_(test in ACTIVE_TESTS, '%s is an invalid test' % (test,)) + for test in SHUFFLED_FILTERED_TESTS: + self.assert_(test in FILTERED_TESTS, '%s is an invalid test' % (test,)) + for test in SHUFFLED_SHARDED_TESTS: + self.assert_(test in SHARDED_TESTS, '%s is an invalid test' % (test,)) + + def testShuffleIncludesAllTests(self): + for test in ALL_TESTS: + self.assert_(test in SHUFFLED_ALL_TESTS, '%s is missing' % (test,)) + for test in ACTIVE_TESTS: + self.assert_(test in SHUFFLED_ACTIVE_TESTS, '%s is missing' % (test,)) + for test in FILTERED_TESTS: + self.assert_(test in SHUFFLED_FILTERED_TESTS, '%s is missing' % (test,)) + for test in SHARDED_TESTS: + self.assert_(test in SHUFFLED_SHARDED_TESTS, '%s is missing' % (test,)) + + def testShuffleLeavesDeathTestsAtFront(self): + non_death_test_found = False + for test in SHUFFLED_ACTIVE_TESTS: + if 'DeathTest.' in test: + self.assert_(not non_death_test_found, + '%s appears after a non-death test' % (test,)) + else: + non_death_test_found = True + + def _VerifyTestCasesDoNotInterleave(self, tests): + test_cases = [] + for test in tests: + [test_case, _] = test.split('.') + if test_cases and test_cases[-1] != test_case: + test_cases.append(test_case) + self.assertEqual(1, test_cases.count(test_case), + 'Test case %s is not grouped together in %s' % + (test_case, tests)) + + def testShuffleDoesNotInterleaveTestCases(self): + self._VerifyTestCasesDoNotInterleave(SHUFFLED_ALL_TESTS) + self._VerifyTestCasesDoNotInterleave(SHUFFLED_ACTIVE_TESTS) + self._VerifyTestCasesDoNotInterleave(SHUFFLED_FILTERED_TESTS) + self._VerifyTestCasesDoNotInterleave(SHUFFLED_SHARDED_TESTS) + + def testShuffleRestoresOrderAfterEachIteration(self): + # Get the test lists in all 3 iterations, using random seed 1, 2, + # and 3 respectively. Google Test picks a different seed in each + # iteration, and this test depends on the current implementation + # picking successive numbers. This dependency is not ideal, but + # makes the test much easier to write. + [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = ( + GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)])) + + # Make sure running the tests with random seed 1 gets the same + # order as in iteration 1 above. + [tests_with_seed1] = GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1)]) + self.assertEqual(tests_in_iteration1, tests_with_seed1) + + # Make sure running the tests with random seed 2 gets the same + # order as in iteration 2 above. Success means that Google Test + # correctly restores the test order before re-shuffling at the + # beginning of iteration 2. + [tests_with_seed2] = GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(2)]) + self.assertEqual(tests_in_iteration2, tests_with_seed2) + + # Make sure running the tests with random seed 3 gets the same + # order as in iteration 3 above. Success means that Google Test + # correctly restores the test order before re-shuffling at the + # beginning of iteration 3. + [tests_with_seed3] = GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(3)]) + self.assertEqual(tests_in_iteration3, tests_with_seed3) + + def testShuffleGeneratesNewOrderInEachIteration(self): + [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = ( + GetTestsForAllIterations( + {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)])) + + self.assert_(tests_in_iteration1 != tests_in_iteration2, + tests_in_iteration1) + self.assert_(tests_in_iteration1 != tests_in_iteration3, + tests_in_iteration1) + self.assert_(tests_in_iteration2 != tests_in_iteration3, + tests_in_iteration2) + + def testShuffleShardedTestsPreservesPartition(self): + # If we run M tests on N shards, the same M tests should be run in + # total, regardless of the random seeds used by the shards. + [tests1] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '0'}, + [ShuffleFlag(), RandomSeedFlag(1)]) + [tests2] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '1'}, + [ShuffleFlag(), RandomSeedFlag(20)]) + [tests3] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3', + SHARD_INDEX_ENV_VAR: '2'}, + [ShuffleFlag(), RandomSeedFlag(25)]) + sorted_sharded_tests = tests1 + tests2 + tests3 + sorted_sharded_tests.sort() + sorted_active_tests = [] + sorted_active_tests.extend(ACTIVE_TESTS) + sorted_active_tests.sort() + self.assertEqual(sorted_active_tests, sorted_sharded_tests) + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-shuffle-test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-shuffle-test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..c1fc106686e242d233f1090606c22a60823c2507 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-shuffle-test_.cc @@ -0,0 +1,101 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Verifies that test shuffling works. + +#include "gtest/gtest.h" + +namespace { + +using ::testing::EmptyTestEventListener; +using ::testing::InitGoogleTest; +using ::testing::Message; +using ::testing::Test; +using ::testing::TestEventListeners; +using ::testing::TestInfo; +using ::testing::UnitTest; + +// The test methods are empty, as the sole purpose of this program is +// to print the test names before/after shuffling. + +class A : public Test {}; +TEST_F(A, A) {} +TEST_F(A, B) {} + +TEST(ADeathTest, A) {} +TEST(ADeathTest, B) {} +TEST(ADeathTest, C) {} + +TEST(B, A) {} +TEST(B, B) {} +TEST(B, C) {} +TEST(B, DISABLED_D) {} +TEST(B, DISABLED_E) {} + +TEST(BDeathTest, A) {} +TEST(BDeathTest, B) {} + +TEST(C, A) {} +TEST(C, B) {} +TEST(C, C) {} +TEST(C, DISABLED_D) {} + +TEST(CDeathTest, A) {} + +TEST(DISABLED_D, A) {} +TEST(DISABLED_D, DISABLED_B) {} + +// This printer prints the full test names only, starting each test +// iteration with a "----" marker. +class TestNamePrinter : public EmptyTestEventListener { + public: + void OnTestIterationStart(const UnitTest& /* unit_test */, + int /* iteration */) override { + printf("----\n"); + } + + void OnTestStart(const TestInfo& test_info) override { + printf("%s.%s\n", test_info.test_case_name(), test_info.name()); + } +}; + +} // namespace + +int main(int argc, char **argv) { + InitGoogleTest(&argc, argv); + + // Replaces the default printer with TestNamePrinter, which prints + // the test name only. + TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); + delete listeners.Release(listeners.default_result_printer()); + listeners.Append(new TestNamePrinter); + + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-test-part-test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-test-part-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..44cf7ca044b850dadc0df89628225c07dea27c91 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-test-part-test.cc @@ -0,0 +1,230 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "gtest/gtest-test-part.h" + +#include "gtest/gtest.h" + +using testing::Message; +using testing::Test; +using testing::TestPartResult; +using testing::TestPartResultArray; + +namespace { + +// Tests the TestPartResult class. + +// The test fixture for testing TestPartResult. +class TestPartResultTest : public Test { + protected: + TestPartResultTest() + : r1_(TestPartResult::kSuccess, "foo/bar.cc", 10, "Success!"), + r2_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure!"), + r3_(TestPartResult::kFatalFailure, nullptr, -1, "Failure!"), + r4_(TestPartResult::kSkip, "foo/bar.cc", 2, "Skipped!") {} + + TestPartResult r1_, r2_, r3_, r4_; +}; + + +TEST_F(TestPartResultTest, ConstructorWorks) { + Message message; + message << "something is terribly wrong"; + message << static_cast(testing::internal::kStackTraceMarker); + message << "some unimportant stack trace"; + + const TestPartResult result(TestPartResult::kNonFatalFailure, + "some_file.cc", + 42, + message.GetString().c_str()); + + EXPECT_EQ(TestPartResult::kNonFatalFailure, result.type()); + EXPECT_STREQ("some_file.cc", result.file_name()); + EXPECT_EQ(42, result.line_number()); + EXPECT_STREQ(message.GetString().c_str(), result.message()); + EXPECT_STREQ("something is terribly wrong", result.summary()); +} + +TEST_F(TestPartResultTest, ResultAccessorsWork) { + const TestPartResult success(TestPartResult::kSuccess, + "file.cc", + 42, + "message"); + EXPECT_TRUE(success.passed()); + EXPECT_FALSE(success.failed()); + EXPECT_FALSE(success.nonfatally_failed()); + EXPECT_FALSE(success.fatally_failed()); + EXPECT_FALSE(success.skipped()); + + const TestPartResult nonfatal_failure(TestPartResult::kNonFatalFailure, + "file.cc", + 42, + "message"); + EXPECT_FALSE(nonfatal_failure.passed()); + EXPECT_TRUE(nonfatal_failure.failed()); + EXPECT_TRUE(nonfatal_failure.nonfatally_failed()); + EXPECT_FALSE(nonfatal_failure.fatally_failed()); + EXPECT_FALSE(nonfatal_failure.skipped()); + + const TestPartResult fatal_failure(TestPartResult::kFatalFailure, + "file.cc", + 42, + "message"); + EXPECT_FALSE(fatal_failure.passed()); + EXPECT_TRUE(fatal_failure.failed()); + EXPECT_FALSE(fatal_failure.nonfatally_failed()); + EXPECT_TRUE(fatal_failure.fatally_failed()); + EXPECT_FALSE(fatal_failure.skipped()); + + const TestPartResult skip(TestPartResult::kSkip, "file.cc", 42, "message"); + EXPECT_FALSE(skip.passed()); + EXPECT_FALSE(skip.failed()); + EXPECT_FALSE(skip.nonfatally_failed()); + EXPECT_FALSE(skip.fatally_failed()); + EXPECT_TRUE(skip.skipped()); +} + +// Tests TestPartResult::type(). +TEST_F(TestPartResultTest, type) { + EXPECT_EQ(TestPartResult::kSuccess, r1_.type()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, r2_.type()); + EXPECT_EQ(TestPartResult::kFatalFailure, r3_.type()); + EXPECT_EQ(TestPartResult::kSkip, r4_.type()); +} + +// Tests TestPartResult::file_name(). +TEST_F(TestPartResultTest, file_name) { + EXPECT_STREQ("foo/bar.cc", r1_.file_name()); + EXPECT_STREQ(nullptr, r3_.file_name()); + EXPECT_STREQ("foo/bar.cc", r4_.file_name()); +} + +// Tests TestPartResult::line_number(). +TEST_F(TestPartResultTest, line_number) { + EXPECT_EQ(10, r1_.line_number()); + EXPECT_EQ(-1, r2_.line_number()); + EXPECT_EQ(2, r4_.line_number()); +} + +// Tests TestPartResult::message(). +TEST_F(TestPartResultTest, message) { + EXPECT_STREQ("Success!", r1_.message()); + EXPECT_STREQ("Skipped!", r4_.message()); +} + +// Tests TestPartResult::passed(). +TEST_F(TestPartResultTest, Passed) { + EXPECT_TRUE(r1_.passed()); + EXPECT_FALSE(r2_.passed()); + EXPECT_FALSE(r3_.passed()); + EXPECT_FALSE(r4_.passed()); +} + +// Tests TestPartResult::failed(). +TEST_F(TestPartResultTest, Failed) { + EXPECT_FALSE(r1_.failed()); + EXPECT_TRUE(r2_.failed()); + EXPECT_TRUE(r3_.failed()); + EXPECT_FALSE(r4_.failed()); +} + +// Tests TestPartResult::failed(). +TEST_F(TestPartResultTest, Skipped) { + EXPECT_FALSE(r1_.skipped()); + EXPECT_FALSE(r2_.skipped()); + EXPECT_FALSE(r3_.skipped()); + EXPECT_TRUE(r4_.skipped()); +} + +// Tests TestPartResult::fatally_failed(). +TEST_F(TestPartResultTest, FatallyFailed) { + EXPECT_FALSE(r1_.fatally_failed()); + EXPECT_FALSE(r2_.fatally_failed()); + EXPECT_TRUE(r3_.fatally_failed()); + EXPECT_FALSE(r4_.fatally_failed()); +} + +// Tests TestPartResult::nonfatally_failed(). +TEST_F(TestPartResultTest, NonfatallyFailed) { + EXPECT_FALSE(r1_.nonfatally_failed()); + EXPECT_TRUE(r2_.nonfatally_failed()); + EXPECT_FALSE(r3_.nonfatally_failed()); + EXPECT_FALSE(r4_.nonfatally_failed()); +} + +// Tests the TestPartResultArray class. + +class TestPartResultArrayTest : public Test { + protected: + TestPartResultArrayTest() + : r1_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure 1"), + r2_(TestPartResult::kFatalFailure, "foo/bar.cc", -1, "Failure 2") {} + + const TestPartResult r1_, r2_; +}; + +// Tests that TestPartResultArray initially has size 0. +TEST_F(TestPartResultArrayTest, InitialSizeIsZero) { + TestPartResultArray results; + EXPECT_EQ(0, results.size()); +} + +// Tests that TestPartResultArray contains the given TestPartResult +// after one Append() operation. +TEST_F(TestPartResultArrayTest, ContainsGivenResultAfterAppend) { + TestPartResultArray results; + results.Append(r1_); + EXPECT_EQ(1, results.size()); + EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message()); +} + +// Tests that TestPartResultArray contains the given TestPartResults +// after two Append() operations. +TEST_F(TestPartResultArrayTest, ContainsGivenResultsAfterTwoAppends) { + TestPartResultArray results; + results.Append(r1_); + results.Append(r2_); + EXPECT_EQ(2, results.size()); + EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message()); + EXPECT_STREQ("Failure 2", results.GetTestPartResult(1).message()); +} + +typedef TestPartResultArrayTest TestPartResultArrayDeathTest; + +// Tests that the program dies when GetTestPartResult() is called with +// an invalid index. +TEST_F(TestPartResultArrayDeathTest, DiesWhenIndexIsOutOfBound) { + TestPartResultArray results; + results.Append(r1_); + + EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(-1), ""); + EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(1), ""); +} + +} // namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-test2_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-test2_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..2e425daebab637aaaf0ca8a374fab0d6149ab2ce --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-test2_test.cc @@ -0,0 +1,61 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Tests for Google Test itself. This verifies that the basic constructs of +// Google Test work. + +#include "gtest/gtest.h" +#include "googletest-param-test-test.h" + +using ::testing::Values; +using ::testing::internal::ParamGenerator; + +// Tests that generators defined in a different translation unit +// are functional. The test using extern_gen_2 is defined +// in googletest-param-test-test.cc. +ParamGenerator extern_gen_2 = Values(33); + +// Tests that a parameterized test case can be defined in one translation unit +// and instantiated in another. The test is defined in +// googletest-param-test-test.cc and ExternalInstantiationTest fixture class is +// defined in gtest-param-test_test.h. +INSTANTIATE_TEST_SUITE_P(MultiplesOf33, + ExternalInstantiationTest, + Values(33, 66)); + +// Tests that a parameterized test case can be instantiated +// in multiple translation units. Another instantiation is defined +// in googletest-param-test-test.cc and +// InstantiationInMultipleTranslationUnitsTest fixture is defined in +// gtest-param-test_test.h +INSTANTIATE_TEST_SUITE_P(Sequence2, + InstantiationInMultipleTranslationUnitsTest, + Values(42*3, 42*4, 42*5)); + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-throw-on-failure-test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-throw-on-failure-test.py new file mode 100755 index 0000000000000000000000000000000000000000..ea627c479d5b19824ca67b98089cf400c33c279a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-throw-on-failure-test.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python +# +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests Google Test's throw-on-failure mode with exceptions disabled. + +This script invokes googletest-throw-on-failure-test_ (a program written with +Google Test) with different environments and command line flags. +""" + +import os +import gtest_test_utils + + +# Constants. + +# The command line flag for enabling/disabling the throw-on-failure mode. +THROW_ON_FAILURE = 'gtest_throw_on_failure' + +# Path to the googletest-throw-on-failure-test_ program, compiled with +# exceptions disabled. +EXE_PATH = gtest_test_utils.GetTestExecutablePath( + 'googletest-throw-on-failure-test_') + + +# Utilities. + + +def SetEnvVar(env_var, value): + """Sets an environment variable to a given value; unsets it when the + given value is None. + """ + + env_var = env_var.upper() + if value is not None: + os.environ[env_var] = value + elif env_var in os.environ: + del os.environ[env_var] + + +def Run(command): + """Runs a command; returns True/False if its exit code is/isn't 0.""" + + print('Running "%s". . .' % ' '.join(command)) + p = gtest_test_utils.Subprocess(command) + return p.exited and p.exit_code == 0 + + +# The tests. +class ThrowOnFailureTest(gtest_test_utils.TestCase): + """Tests the throw-on-failure mode.""" + + def RunAndVerify(self, env_var_value, flag_value, should_fail): + """Runs googletest-throw-on-failure-test_ and verifies that it does + (or does not) exit with a non-zero code. + + Args: + env_var_value: value of the GTEST_BREAK_ON_FAILURE environment + variable; None if the variable should be unset. + flag_value: value of the --gtest_break_on_failure flag; + None if the flag should not be present. + should_fail: True if and only if the program is expected to fail. + """ + + SetEnvVar(THROW_ON_FAILURE, env_var_value) + + if env_var_value is None: + env_var_value_msg = ' is not set' + else: + env_var_value_msg = '=' + env_var_value + + if flag_value is None: + flag = '' + elif flag_value == '0': + flag = '--%s=0' % THROW_ON_FAILURE + else: + flag = '--%s' % THROW_ON_FAILURE + + command = [EXE_PATH] + if flag: + command.append(flag) + + if should_fail: + should_or_not = 'should' + else: + should_or_not = 'should not' + + failed = not Run(command) + + SetEnvVar(THROW_ON_FAILURE, None) + + msg = ('when %s%s, an assertion failure in "%s" %s cause a non-zero ' + 'exit code.' % + (THROW_ON_FAILURE, env_var_value_msg, ' '.join(command), + should_or_not)) + self.assert_(failed == should_fail, msg) + + def testDefaultBehavior(self): + """Tests the behavior of the default mode.""" + + self.RunAndVerify(env_var_value=None, flag_value=None, should_fail=False) + + def testThrowOnFailureEnvVar(self): + """Tests using the GTEST_THROW_ON_FAILURE environment variable.""" + + self.RunAndVerify(env_var_value='0', + flag_value=None, + should_fail=False) + self.RunAndVerify(env_var_value='1', + flag_value=None, + should_fail=True) + + def testThrowOnFailureFlag(self): + """Tests using the --gtest_throw_on_failure flag.""" + + self.RunAndVerify(env_var_value=None, + flag_value='0', + should_fail=False) + self.RunAndVerify(env_var_value=None, + flag_value='1', + should_fail=True) + + def testThrowOnFailureFlagOverridesEnvVar(self): + """Tests that --gtest_throw_on_failure overrides GTEST_THROW_ON_FAILURE.""" + + self.RunAndVerify(env_var_value='0', + flag_value='0', + should_fail=False) + self.RunAndVerify(env_var_value='0', + flag_value='1', + should_fail=True) + self.RunAndVerify(env_var_value='1', + flag_value='0', + should_fail=False) + self.RunAndVerify(env_var_value='1', + flag_value='1', + should_fail=True) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-throw-on-failure-test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-throw-on-failure-test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..83bb914c7e474a812d5745a3ec50b95b38a658e4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-throw-on-failure-test_.cc @@ -0,0 +1,71 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Tests Google Test's throw-on-failure mode with exceptions disabled. +// +// This program must be compiled with exceptions disabled. It will be +// invoked by googletest-throw-on-failure-test.py, and is expected to exit +// with non-zero in the throw-on-failure mode or 0 otherwise. + +#include "gtest/gtest.h" + +#include // for fflush, fprintf, NULL, etc. +#include // for exit +#include // for set_terminate + +// This terminate handler aborts the program using exit() rather than abort(). +// This avoids showing pop-ups on Windows systems and core dumps on Unix-like +// ones. +void TerminateHandler() { + fprintf(stderr, "%s\n", "Unhandled C++ exception terminating the program."); + fflush(nullptr); + exit(1); +} + +int main(int argc, char** argv) { +#if GTEST_HAS_EXCEPTIONS + std::set_terminate(&TerminateHandler); +#endif + testing::InitGoogleTest(&argc, argv); + + // We want to ensure that people can use Google Test assertions in + // other testing frameworks, as long as they initialize Google Test + // properly and set the throw-on-failure mode. Therefore, we don't + // use Google Test's constructs for defining and running tests + // (e.g. TEST and RUN_ALL_TESTS) here. + + // In the throw-on-failure mode with exceptions disabled, this + // assertion will cause the program to exit with a non-zero code. + EXPECT_EQ(2, 3); + + // When not in the throw-on-failure mode, the control will reach + // here. + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-uninitialized-test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-uninitialized-test.py new file mode 100755 index 0000000000000000000000000000000000000000..69595a0ddede807ae3711e9ef5f7b0ae92207563 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-uninitialized-test.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Verifies that Google Test warns the user when not initialized properly.""" + +import gtest_test_utils + +COMMAND = gtest_test_utils.GetTestExecutablePath('googletest-uninitialized-test_') + + +def Assert(condition): + if not condition: + raise AssertionError + + +def AssertEq(expected, actual): + if expected != actual: + print('Expected: %s' % (expected,)) + print(' Actual: %s' % (actual,)) + raise AssertionError + + +def TestExitCodeAndOutput(command): + """Runs the given command and verifies its exit code and output.""" + + # Verifies that 'command' exits with code 1. + p = gtest_test_utils.Subprocess(command) + if p.exited and p.exit_code == 0: + Assert('IMPORTANT NOTICE' in p.output); + Assert('InitGoogleTest' in p.output) + + +class GTestUninitializedTest(gtest_test_utils.TestCase): + def testExitCodeAndOutput(self): + TestExitCodeAndOutput(COMMAND) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-uninitialized-test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-uninitialized-test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..b4434d51eebfd8726bd3f04c2d0426bba960298c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/googletest-uninitialized-test_.cc @@ -0,0 +1,42 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#include "gtest/gtest.h" + +TEST(DummyTest, Dummy) { + // This test doesn't verify anything. We just need it to create a + // realistic stage for testing the behavior of Google Test when + // RUN_ALL_TESTS() is called without + // testing::InitGoogleTest() being called first. +} + +int main() { + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-typed-test2_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-typed-test2_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..70001604ca06f1361cb6287da1d61067b3b42d76 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-typed-test2_test.cc @@ -0,0 +1,44 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#include + +#include "test/gtest-typed-test_test.h" +#include "gtest/gtest.h" + +#if GTEST_HAS_TYPED_TEST_P + +// Tests that the same type-parameterized test case can be +// instantiated in different translation units linked together. +// (ContainerTest is also instantiated in gtest-typed-test_test.cc.) +INSTANTIATE_TYPED_TEST_SUITE_P(Vector, ContainerTest, + testing::Types >); + +#endif // GTEST_HAS_TYPED_TEST_P diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-typed-test_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-typed-test_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..5411832ab2696d827abf2fe9c1416b97458e5c36 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-typed-test_test.cc @@ -0,0 +1,462 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#include "test/gtest-typed-test_test.h" + +#include +#include +#include + +#include "gtest/gtest.h" + +#if _MSC_VER +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127 /* conditional expression is constant */) +#endif // _MSC_VER + +using testing::Test; + +// Used for testing that SetUpTestSuite()/TearDownTestSuite(), fixture +// ctor/dtor, and SetUp()/TearDown() work correctly in typed tests and +// type-parameterized test. +template +class CommonTest : public Test { + // For some technical reason, SetUpTestSuite() and TearDownTestSuite() + // must be public. + public: + static void SetUpTestSuite() { + shared_ = new T(5); + } + + static void TearDownTestSuite() { + delete shared_; + shared_ = nullptr; + } + + // This 'protected:' is optional. There's no harm in making all + // members of this fixture class template public. + protected: + // We used to use std::list here, but switched to std::vector since + // MSVC's doesn't compile cleanly with /W4. + typedef std::vector Vector; + typedef std::set IntSet; + + CommonTest() : value_(1) {} + + ~CommonTest() override { EXPECT_EQ(3, value_); } + + void SetUp() override { + EXPECT_EQ(1, value_); + value_++; + } + + void TearDown() override { + EXPECT_EQ(2, value_); + value_++; + } + + T value_; + static T* shared_; +}; + +template +T* CommonTest::shared_ = nullptr; + +// This #ifdef block tests typed tests. +#if GTEST_HAS_TYPED_TEST + +using testing::Types; + +// Tests that SetUpTestSuite()/TearDownTestSuite(), fixture ctor/dtor, +// and SetUp()/TearDown() work correctly in typed tests + +typedef Types TwoTypes; +TYPED_TEST_SUITE(CommonTest, TwoTypes); + +TYPED_TEST(CommonTest, ValuesAreCorrect) { + // Static members of the fixture class template can be visited via + // the TestFixture:: prefix. + EXPECT_EQ(5, *TestFixture::shared_); + + // Typedefs in the fixture class template can be visited via the + // "typename TestFixture::" prefix. + typename TestFixture::Vector empty; + EXPECT_EQ(0U, empty.size()); + + typename TestFixture::IntSet empty2; + EXPECT_EQ(0U, empty2.size()); + + // Non-static members of the fixture class must be visited via + // 'this', as required by C++ for class templates. + EXPECT_EQ(2, this->value_); +} + +// The second test makes sure shared_ is not deleted after the first +// test. +TYPED_TEST(CommonTest, ValuesAreStillCorrect) { + // Static members of the fixture class template can also be visited + // via 'this'. + ASSERT_TRUE(this->shared_ != nullptr); + EXPECT_EQ(5, *this->shared_); + + // TypeParam can be used to refer to the type parameter. + EXPECT_EQ(static_cast(2), this->value_); +} + +// Tests that multiple TYPED_TEST_SUITE's can be defined in the same +// translation unit. + +template +class TypedTest1 : public Test { +}; + +// Verifies that the second argument of TYPED_TEST_SUITE can be a +// single type. +TYPED_TEST_SUITE(TypedTest1, int); +TYPED_TEST(TypedTest1, A) {} + +template +class TypedTest2 : public Test { +}; + +// Verifies that the second argument of TYPED_TEST_SUITE can be a +// Types<...> type list. +TYPED_TEST_SUITE(TypedTest2, Types); + +// This also verifies that tests from different typed test cases can +// share the same name. +TYPED_TEST(TypedTest2, A) {} + +// Tests that a typed test case can be defined in a namespace. + +namespace library1 { + +template +class NumericTest : public Test { +}; + +typedef Types NumericTypes; +TYPED_TEST_SUITE(NumericTest, NumericTypes); + +TYPED_TEST(NumericTest, DefaultIsZero) { + EXPECT_EQ(0, TypeParam()); +} + +} // namespace library1 + +// Tests that custom names work. +template +class TypedTestWithNames : public Test {}; + +class TypedTestNames { + public: + template + static std::string GetName(int i) { + if (std::is_same::value) { + return std::string("char") + ::testing::PrintToString(i); + } + if (std::is_same::value) { + return std::string("int") + ::testing::PrintToString(i); + } + } +}; + +TYPED_TEST_SUITE(TypedTestWithNames, TwoTypes, TypedTestNames); + +TYPED_TEST(TypedTestWithNames, TestSuiteName) { + if (std::is_same::value) { + EXPECT_STREQ(::testing::UnitTest::GetInstance() + ->current_test_info() + ->test_case_name(), + "TypedTestWithNames/char0"); + } + if (std::is_same::value) { + EXPECT_STREQ(::testing::UnitTest::GetInstance() + ->current_test_info() + ->test_case_name(), + "TypedTestWithNames/int1"); + } +} + +#endif // GTEST_HAS_TYPED_TEST + +// This #ifdef block tests type-parameterized tests. +#if GTEST_HAS_TYPED_TEST_P + +using testing::Types; +using testing::internal::TypedTestSuitePState; + +// Tests TypedTestSuitePState. + +class TypedTestSuitePStateTest : public Test { + protected: + void SetUp() override { + state_.AddTestName("foo.cc", 0, "FooTest", "A"); + state_.AddTestName("foo.cc", 0, "FooTest", "B"); + state_.AddTestName("foo.cc", 0, "FooTest", "C"); + } + + TypedTestSuitePState state_; +}; + +TEST_F(TypedTestSuitePStateTest, SucceedsForMatchingList) { + const char* tests = "A, B, C"; + EXPECT_EQ(tests, + state_.VerifyRegisteredTestNames("foo.cc", 1, tests)); +} + +// Makes sure that the order of the tests and spaces around the names +// don't matter. +TEST_F(TypedTestSuitePStateTest, IgnoresOrderAndSpaces) { + const char* tests = "A,C, B"; + EXPECT_EQ(tests, + state_.VerifyRegisteredTestNames("foo.cc", 1, tests)); +} + +using TypedTestSuitePStateDeathTest = TypedTestSuitePStateTest; + +TEST_F(TypedTestSuitePStateDeathTest, DetectsDuplicates) { + EXPECT_DEATH_IF_SUPPORTED( + state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, A, C"), + "foo\\.cc.1.?: Test A is listed more than once\\."); +} + +TEST_F(TypedTestSuitePStateDeathTest, DetectsExtraTest) { + EXPECT_DEATH_IF_SUPPORTED( + state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C, D"), + "foo\\.cc.1.?: No test named D can be found in this test suite\\."); +} + +TEST_F(TypedTestSuitePStateDeathTest, DetectsMissedTest) { + EXPECT_DEATH_IF_SUPPORTED( + state_.VerifyRegisteredTestNames("foo.cc", 1, "A, C"), + "foo\\.cc.1.?: You forgot to list test B\\."); +} + +// Tests that defining a test for a parameterized test case generates +// a run-time error if the test case has been registered. +TEST_F(TypedTestSuitePStateDeathTest, DetectsTestAfterRegistration) { + state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C"); + EXPECT_DEATH_IF_SUPPORTED( + state_.AddTestName("foo.cc", 2, "FooTest", "D"), + "foo\\.cc.2.?: Test D must be defined before REGISTER_TYPED_TEST_SUITE_P" + "\\(FooTest, \\.\\.\\.\\)\\."); +} + +// Tests that SetUpTestSuite()/TearDownTestSuite(), fixture ctor/dtor, +// and SetUp()/TearDown() work correctly in type-parameterized tests. + +template +class DerivedTest : public CommonTest { +}; + +TYPED_TEST_SUITE_P(DerivedTest); + +TYPED_TEST_P(DerivedTest, ValuesAreCorrect) { + // Static members of the fixture class template can be visited via + // the TestFixture:: prefix. + EXPECT_EQ(5, *TestFixture::shared_); + + // Non-static members of the fixture class must be visited via + // 'this', as required by C++ for class templates. + EXPECT_EQ(2, this->value_); +} + +// The second test makes sure shared_ is not deleted after the first +// test. +TYPED_TEST_P(DerivedTest, ValuesAreStillCorrect) { + // Static members of the fixture class template can also be visited + // via 'this'. + ASSERT_TRUE(this->shared_ != nullptr); + EXPECT_EQ(5, *this->shared_); + EXPECT_EQ(2, this->value_); +} + +REGISTER_TYPED_TEST_SUITE_P(DerivedTest, + ValuesAreCorrect, ValuesAreStillCorrect); + +typedef Types MyTwoTypes; +INSTANTIATE_TYPED_TEST_SUITE_P(My, DerivedTest, MyTwoTypes); + +// Tests that custom names work with type parametrized tests. We reuse the +// TwoTypes from above here. +template +class TypeParametrizedTestWithNames : public Test {}; + +TYPED_TEST_SUITE_P(TypeParametrizedTestWithNames); + +TYPED_TEST_P(TypeParametrizedTestWithNames, TestSuiteName) { + if (std::is_same::value) { + EXPECT_STREQ(::testing::UnitTest::GetInstance() + ->current_test_info() + ->test_case_name(), + "CustomName/TypeParametrizedTestWithNames/parChar0"); + } + if (std::is_same::value) { + EXPECT_STREQ(::testing::UnitTest::GetInstance() + ->current_test_info() + ->test_case_name(), + "CustomName/TypeParametrizedTestWithNames/parInt1"); + } +} + +REGISTER_TYPED_TEST_SUITE_P(TypeParametrizedTestWithNames, TestSuiteName); + +class TypeParametrizedTestNames { + public: + template + static std::string GetName(int i) { + if (std::is_same::value) { + return std::string("parChar") + ::testing::PrintToString(i); + } + if (std::is_same::value) { + return std::string("parInt") + ::testing::PrintToString(i); + } + } +}; + +INSTANTIATE_TYPED_TEST_SUITE_P(CustomName, TypeParametrizedTestWithNames, + TwoTypes, TypeParametrizedTestNames); + +// Tests that multiple TYPED_TEST_SUITE_P's can be defined in the same +// translation unit. + +template +class TypedTestP1 : public Test { +}; + +TYPED_TEST_SUITE_P(TypedTestP1); + +// For testing that the code between TYPED_TEST_SUITE_P() and +// TYPED_TEST_P() is not enclosed in a namespace. +using IntAfterTypedTestSuiteP = int; + +TYPED_TEST_P(TypedTestP1, A) {} +TYPED_TEST_P(TypedTestP1, B) {} + +// For testing that the code between TYPED_TEST_P() and +// REGISTER_TYPED_TEST_SUITE_P() is not enclosed in a namespace. +using IntBeforeRegisterTypedTestSuiteP = int; + +REGISTER_TYPED_TEST_SUITE_P(TypedTestP1, A, B); + +template +class TypedTestP2 : public Test { +}; + +TYPED_TEST_SUITE_P(TypedTestP2); + +// This also verifies that tests from different type-parameterized +// test cases can share the same name. +TYPED_TEST_P(TypedTestP2, A) {} + +REGISTER_TYPED_TEST_SUITE_P(TypedTestP2, A); + +// Verifies that the code between TYPED_TEST_SUITE_P() and +// REGISTER_TYPED_TEST_SUITE_P() is not enclosed in a namespace. +IntAfterTypedTestSuiteP after = 0; +IntBeforeRegisterTypedTestSuiteP before = 0; + +// Verifies that the last argument of INSTANTIATE_TYPED_TEST_SUITE_P() +// can be either a single type or a Types<...> type list. +INSTANTIATE_TYPED_TEST_SUITE_P(Int, TypedTestP1, int); +INSTANTIATE_TYPED_TEST_SUITE_P(Int, TypedTestP2, Types); + +// Tests that the same type-parameterized test case can be +// instantiated more than once in the same translation unit. +INSTANTIATE_TYPED_TEST_SUITE_P(Double, TypedTestP2, Types); + +// Tests that the same type-parameterized test case can be +// instantiated in different translation units linked together. +// (ContainerTest is also instantiated in gtest-typed-test_test.cc.) +typedef Types, std::set > MyContainers; +INSTANTIATE_TYPED_TEST_SUITE_P(My, ContainerTest, MyContainers); + +// Tests that a type-parameterized test case can be defined and +// instantiated in a namespace. + +namespace library2 { + +template +class NumericTest : public Test { +}; + +TYPED_TEST_SUITE_P(NumericTest); + +TYPED_TEST_P(NumericTest, DefaultIsZero) { + EXPECT_EQ(0, TypeParam()); +} + +TYPED_TEST_P(NumericTest, ZeroIsLessThanOne) { + EXPECT_LT(TypeParam(0), TypeParam(1)); +} + +REGISTER_TYPED_TEST_SUITE_P(NumericTest, + DefaultIsZero, ZeroIsLessThanOne); +typedef Types NumericTypes; +INSTANTIATE_TYPED_TEST_SUITE_P(My, NumericTest, NumericTypes); + +static const char* GetTestName() { + return testing::UnitTest::GetInstance()->current_test_info()->name(); +} +// Test the stripping of space from test names +template class TrimmedTest : public Test { }; +TYPED_TEST_SUITE_P(TrimmedTest); +TYPED_TEST_P(TrimmedTest, Test1) { EXPECT_STREQ("Test1", GetTestName()); } +TYPED_TEST_P(TrimmedTest, Test2) { EXPECT_STREQ("Test2", GetTestName()); } +TYPED_TEST_P(TrimmedTest, Test3) { EXPECT_STREQ("Test3", GetTestName()); } +TYPED_TEST_P(TrimmedTest, Test4) { EXPECT_STREQ("Test4", GetTestName()); } +TYPED_TEST_P(TrimmedTest, Test5) { EXPECT_STREQ("Test5", GetTestName()); } +REGISTER_TYPED_TEST_SUITE_P( + TrimmedTest, + Test1, Test2,Test3 , Test4 ,Test5 ); // NOLINT +template struct MyPair {}; +// Be sure to try a type with a comma in its name just in case it matters. +typedef Types > TrimTypes; +INSTANTIATE_TYPED_TEST_SUITE_P(My, TrimmedTest, TrimTypes); + +} // namespace library2 + +#endif // GTEST_HAS_TYPED_TEST_P + +#if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) + +// Google Test may not support type-parameterized tests with some +// compilers. If we use conditional compilation to compile out all +// code referring to the gtest_main library, MSVC linker will not link +// that library at all and consequently complain about missing entry +// point defined in that library (fatal error LNK1561: entry point +// must be defined). This dummy test keeps gtest_main linked in. +TEST(DummyTest, TypedTestsAreNotSupportedOnThisPlatform) {} + +#if _MSC_VER +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4127 +#endif // _MSC_VER + +#endif // #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-typed-test_test.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-typed-test_test.h new file mode 100644 index 0000000000000000000000000000000000000000..23137b7ef79898755320c31113b51e80b9af120d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-typed-test_test.h @@ -0,0 +1,65 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#ifndef GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ +#define GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ + +#include "gtest/gtest.h" + +#if GTEST_HAS_TYPED_TEST_P + +using testing::Test; + +// For testing that the same type-parameterized test case can be +// instantiated in different translation units linked together. +// ContainerTest will be instantiated in both gtest-typed-test_test.cc +// and gtest-typed-test2_test.cc. + +template +class ContainerTest : public Test { +}; + +TYPED_TEST_SUITE_P(ContainerTest); + +TYPED_TEST_P(ContainerTest, CanBeDefaultConstructed) { + TypeParam container; +} + +TYPED_TEST_P(ContainerTest, InitialSizeIsZero) { + TypeParam container; + EXPECT_EQ(0U, container.size()); +} + +REGISTER_TYPED_TEST_SUITE_P(ContainerTest, + CanBeDefaultConstructed, InitialSizeIsZero); + +#endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_TEST_GTEST_TYPED_TEST_TEST_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-unittest-api_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-unittest-api_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..480a41fb42eeeefa8b624e4fb124d8e7f6234efb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest-unittest-api_test.cc @@ -0,0 +1,340 @@ +// Copyright 2009 Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file contains tests verifying correctness of data provided via +// UnitTest's public methods. + +#include "gtest/gtest.h" + +#include // For strcmp. +#include + +using ::testing::InitGoogleTest; + +namespace testing { +namespace internal { + +template +struct LessByName { + bool operator()(const T* a, const T* b) { + return strcmp(a->name(), b->name()) < 0; + } +}; + +class UnitTestHelper { + public: + // Returns the array of pointers to all test suites sorted by the test suite + // name. The caller is responsible for deleting the array. + static TestSuite const** GetSortedTestSuites() { + UnitTest& unit_test = *UnitTest::GetInstance(); + auto const** const test_suites = + new const TestSuite*[unit_test.total_test_suite_count()]; + + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) + test_suites[i] = unit_test.GetTestSuite(i); + + std::sort(test_suites, + test_suites + unit_test.total_test_suite_count(), + LessByName()); + return test_suites; + } + + // Returns the test suite by its name. The caller doesn't own the returned + // pointer. + static const TestSuite* FindTestSuite(const char* name) { + UnitTest& unit_test = *UnitTest::GetInstance(); + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite* test_suite = unit_test.GetTestSuite(i); + if (0 == strcmp(test_suite->name(), name)) + return test_suite; + } + return nullptr; + } + + // Returns the array of pointers to all tests in a particular test suite + // sorted by the test name. The caller is responsible for deleting the + // array. + static TestInfo const** GetSortedTests(const TestSuite* test_suite) { + TestInfo const** const tests = + new const TestInfo*[test_suite->total_test_count()]; + + for (int i = 0; i < test_suite->total_test_count(); ++i) + tests[i] = test_suite->GetTestInfo(i); + + std::sort(tests, tests + test_suite->total_test_count(), + LessByName()); + return tests; + } +}; + +#if GTEST_HAS_TYPED_TEST +template class TestSuiteWithCommentTest : public Test {}; +TYPED_TEST_SUITE(TestSuiteWithCommentTest, Types); +TYPED_TEST(TestSuiteWithCommentTest, Dummy) {} + +const int kTypedTestSuites = 1; +const int kTypedTests = 1; +#else +const int kTypedTestSuites = 0; +const int kTypedTests = 0; +#endif // GTEST_HAS_TYPED_TEST + +// We can only test the accessors that do not change value while tests run. +// Since tests can be run in any order, the values the accessors that track +// test execution (such as failed_test_count) can not be predicted. +TEST(ApiTest, UnitTestImmutableAccessorsWork) { + UnitTest* unit_test = UnitTest::GetInstance(); + + ASSERT_EQ(2 + kTypedTestSuites, unit_test->total_test_suite_count()); + EXPECT_EQ(1 + kTypedTestSuites, unit_test->test_suite_to_run_count()); + EXPECT_EQ(2, unit_test->disabled_test_count()); + EXPECT_EQ(5 + kTypedTests, unit_test->total_test_count()); + EXPECT_EQ(3 + kTypedTests, unit_test->test_to_run_count()); + + const TestSuite** const test_suites = UnitTestHelper::GetSortedTestSuites(); + + EXPECT_STREQ("ApiTest", test_suites[0]->name()); + EXPECT_STREQ("DISABLED_Test", test_suites[1]->name()); +#if GTEST_HAS_TYPED_TEST + EXPECT_STREQ("TestSuiteWithCommentTest/0", test_suites[2]->name()); +#endif // GTEST_HAS_TYPED_TEST + + delete[] test_suites; + + // The following lines initiate actions to verify certain methods in + // FinalSuccessChecker::TearDown. + + // Records a test property to verify TestResult::GetTestProperty(). + RecordProperty("key", "value"); +} + +AssertionResult IsNull(const char* str) { + if (str != nullptr) { + return testing::AssertionFailure() << "argument is " << str; + } + return AssertionSuccess(); +} + +TEST(ApiTest, TestSuiteImmutableAccessorsWork) { + const TestSuite* test_suite = UnitTestHelper::FindTestSuite("ApiTest"); + ASSERT_TRUE(test_suite != nullptr); + + EXPECT_STREQ("ApiTest", test_suite->name()); + EXPECT_TRUE(IsNull(test_suite->type_param())); + EXPECT_TRUE(test_suite->should_run()); + EXPECT_EQ(1, test_suite->disabled_test_count()); + EXPECT_EQ(3, test_suite->test_to_run_count()); + ASSERT_EQ(4, test_suite->total_test_count()); + + const TestInfo** tests = UnitTestHelper::GetSortedTests(test_suite); + + EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name()); + EXPECT_STREQ("ApiTest", tests[0]->test_suite_name()); + EXPECT_TRUE(IsNull(tests[0]->value_param())); + EXPECT_TRUE(IsNull(tests[0]->type_param())); + EXPECT_FALSE(tests[0]->should_run()); + + EXPECT_STREQ("TestSuiteDisabledAccessorsWork", tests[1]->name()); + EXPECT_STREQ("ApiTest", tests[1]->test_suite_name()); + EXPECT_TRUE(IsNull(tests[1]->value_param())); + EXPECT_TRUE(IsNull(tests[1]->type_param())); + EXPECT_TRUE(tests[1]->should_run()); + + EXPECT_STREQ("TestSuiteImmutableAccessorsWork", tests[2]->name()); + EXPECT_STREQ("ApiTest", tests[2]->test_suite_name()); + EXPECT_TRUE(IsNull(tests[2]->value_param())); + EXPECT_TRUE(IsNull(tests[2]->type_param())); + EXPECT_TRUE(tests[2]->should_run()); + + EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name()); + EXPECT_STREQ("ApiTest", tests[3]->test_suite_name()); + EXPECT_TRUE(IsNull(tests[3]->value_param())); + EXPECT_TRUE(IsNull(tests[3]->type_param())); + EXPECT_TRUE(tests[3]->should_run()); + + delete[] tests; + tests = nullptr; + +#if GTEST_HAS_TYPED_TEST + test_suite = UnitTestHelper::FindTestSuite("TestSuiteWithCommentTest/0"); + ASSERT_TRUE(test_suite != nullptr); + + EXPECT_STREQ("TestSuiteWithCommentTest/0", test_suite->name()); + EXPECT_STREQ(GetTypeName().c_str(), test_suite->type_param()); + EXPECT_TRUE(test_suite->should_run()); + EXPECT_EQ(0, test_suite->disabled_test_count()); + EXPECT_EQ(1, test_suite->test_to_run_count()); + ASSERT_EQ(1, test_suite->total_test_count()); + + tests = UnitTestHelper::GetSortedTests(test_suite); + + EXPECT_STREQ("Dummy", tests[0]->name()); + EXPECT_STREQ("TestSuiteWithCommentTest/0", tests[0]->test_suite_name()); + EXPECT_TRUE(IsNull(tests[0]->value_param())); + EXPECT_STREQ(GetTypeName().c_str(), tests[0]->type_param()); + EXPECT_TRUE(tests[0]->should_run()); + + delete[] tests; +#endif // GTEST_HAS_TYPED_TEST +} + +TEST(ApiTest, TestSuiteDisabledAccessorsWork) { + const TestSuite* test_suite = UnitTestHelper::FindTestSuite("DISABLED_Test"); + ASSERT_TRUE(test_suite != nullptr); + + EXPECT_STREQ("DISABLED_Test", test_suite->name()); + EXPECT_TRUE(IsNull(test_suite->type_param())); + EXPECT_FALSE(test_suite->should_run()); + EXPECT_EQ(1, test_suite->disabled_test_count()); + EXPECT_EQ(0, test_suite->test_to_run_count()); + ASSERT_EQ(1, test_suite->total_test_count()); + + const TestInfo* const test_info = test_suite->GetTestInfo(0); + EXPECT_STREQ("Dummy2", test_info->name()); + EXPECT_STREQ("DISABLED_Test", test_info->test_suite_name()); + EXPECT_TRUE(IsNull(test_info->value_param())); + EXPECT_TRUE(IsNull(test_info->type_param())); + EXPECT_FALSE(test_info->should_run()); +} + +// These two tests are here to provide support for testing +// test_suite_to_run_count, disabled_test_count, and test_to_run_count. +TEST(ApiTest, DISABLED_Dummy1) {} +TEST(DISABLED_Test, Dummy2) {} + +class FinalSuccessChecker : public Environment { + protected: + void TearDown() override { + UnitTest* unit_test = UnitTest::GetInstance(); + + EXPECT_EQ(1 + kTypedTestSuites, unit_test->successful_test_suite_count()); + EXPECT_EQ(3 + kTypedTests, unit_test->successful_test_count()); + EXPECT_EQ(0, unit_test->failed_test_suite_count()); + EXPECT_EQ(0, unit_test->failed_test_count()); + EXPECT_TRUE(unit_test->Passed()); + EXPECT_FALSE(unit_test->Failed()); + ASSERT_EQ(2 + kTypedTestSuites, unit_test->total_test_suite_count()); + + const TestSuite** const test_suites = UnitTestHelper::GetSortedTestSuites(); + + EXPECT_STREQ("ApiTest", test_suites[0]->name()); + EXPECT_TRUE(IsNull(test_suites[0]->type_param())); + EXPECT_TRUE(test_suites[0]->should_run()); + EXPECT_EQ(1, test_suites[0]->disabled_test_count()); + ASSERT_EQ(4, test_suites[0]->total_test_count()); + EXPECT_EQ(3, test_suites[0]->successful_test_count()); + EXPECT_EQ(0, test_suites[0]->failed_test_count()); + EXPECT_TRUE(test_suites[0]->Passed()); + EXPECT_FALSE(test_suites[0]->Failed()); + + EXPECT_STREQ("DISABLED_Test", test_suites[1]->name()); + EXPECT_TRUE(IsNull(test_suites[1]->type_param())); + EXPECT_FALSE(test_suites[1]->should_run()); + EXPECT_EQ(1, test_suites[1]->disabled_test_count()); + ASSERT_EQ(1, test_suites[1]->total_test_count()); + EXPECT_EQ(0, test_suites[1]->successful_test_count()); + EXPECT_EQ(0, test_suites[1]->failed_test_count()); + +#if GTEST_HAS_TYPED_TEST + EXPECT_STREQ("TestSuiteWithCommentTest/0", test_suites[2]->name()); + EXPECT_STREQ(GetTypeName().c_str(), test_suites[2]->type_param()); + EXPECT_TRUE(test_suites[2]->should_run()); + EXPECT_EQ(0, test_suites[2]->disabled_test_count()); + ASSERT_EQ(1, test_suites[2]->total_test_count()); + EXPECT_EQ(1, test_suites[2]->successful_test_count()); + EXPECT_EQ(0, test_suites[2]->failed_test_count()); + EXPECT_TRUE(test_suites[2]->Passed()); + EXPECT_FALSE(test_suites[2]->Failed()); +#endif // GTEST_HAS_TYPED_TEST + + const TestSuite* test_suite = UnitTestHelper::FindTestSuite("ApiTest"); + const TestInfo** tests = UnitTestHelper::GetSortedTests(test_suite); + EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name()); + EXPECT_STREQ("ApiTest", tests[0]->test_suite_name()); + EXPECT_FALSE(tests[0]->should_run()); + + EXPECT_STREQ("TestSuiteDisabledAccessorsWork", tests[1]->name()); + EXPECT_STREQ("ApiTest", tests[1]->test_suite_name()); + EXPECT_TRUE(IsNull(tests[1]->value_param())); + EXPECT_TRUE(IsNull(tests[1]->type_param())); + EXPECT_TRUE(tests[1]->should_run()); + EXPECT_TRUE(tests[1]->result()->Passed()); + EXPECT_EQ(0, tests[1]->result()->test_property_count()); + + EXPECT_STREQ("TestSuiteImmutableAccessorsWork", tests[2]->name()); + EXPECT_STREQ("ApiTest", tests[2]->test_suite_name()); + EXPECT_TRUE(IsNull(tests[2]->value_param())); + EXPECT_TRUE(IsNull(tests[2]->type_param())); + EXPECT_TRUE(tests[2]->should_run()); + EXPECT_TRUE(tests[2]->result()->Passed()); + EXPECT_EQ(0, tests[2]->result()->test_property_count()); + + EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name()); + EXPECT_STREQ("ApiTest", tests[3]->test_suite_name()); + EXPECT_TRUE(IsNull(tests[3]->value_param())); + EXPECT_TRUE(IsNull(tests[3]->type_param())); + EXPECT_TRUE(tests[3]->should_run()); + EXPECT_TRUE(tests[3]->result()->Passed()); + EXPECT_EQ(1, tests[3]->result()->test_property_count()); + const TestProperty& property = tests[3]->result()->GetTestProperty(0); + EXPECT_STREQ("key", property.key()); + EXPECT_STREQ("value", property.value()); + + delete[] tests; + +#if GTEST_HAS_TYPED_TEST + test_suite = UnitTestHelper::FindTestSuite("TestSuiteWithCommentTest/0"); + tests = UnitTestHelper::GetSortedTests(test_suite); + + EXPECT_STREQ("Dummy", tests[0]->name()); + EXPECT_STREQ("TestSuiteWithCommentTest/0", tests[0]->test_suite_name()); + EXPECT_TRUE(IsNull(tests[0]->value_param())); + EXPECT_STREQ(GetTypeName().c_str(), tests[0]->type_param()); + EXPECT_TRUE(tests[0]->should_run()); + EXPECT_TRUE(tests[0]->result()->Passed()); + EXPECT_EQ(0, tests[0]->result()->test_property_count()); + + delete[] tests; +#endif // GTEST_HAS_TYPED_TEST + delete[] test_suites; + } +}; + +} // namespace internal +} // namespace testing + +int main(int argc, char **argv) { + InitGoogleTest(&argc, argv); + + AddGlobalTestEnvironment(new testing::internal::FinalSuccessChecker()); + + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_all_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_all_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..615b29b706516b15ffb6d1ae515ae9a56600b815 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_all_test.cc @@ -0,0 +1,46 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Tests for Google C++ Testing and Mocking Framework (Google Test) +// +// Sometimes it's desirable to build most of Google Test's own tests +// by compiling a single file. This file serves this purpose. +#include "test/googletest-filepath-test.cc" +#include "test/googletest-message-test.cc" +#include "test/googletest-options-test.cc" +#include "test/googletest-port-test.cc" +#include "test/googletest-test-part-test.cc" +#include "test/gtest-typed-test2_test.cc" +#include "test/gtest-typed-test_test.cc" +#include "test/gtest_pred_impl_unittest.cc" +#include "test/gtest_prod_test.cc" +#include "test/gtest_skip_test.cc" +#include "test/gtest_unittest.cc" +#include "test/production.cc" diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_assert_by_exception_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_assert_by_exception_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..ada4cb30ef68c55db81356529186834e25c1ac24 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_assert_by_exception_test.cc @@ -0,0 +1,116 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Tests Google Test's assert-by-exception mode with exceptions enabled. + +#include "gtest/gtest.h" + +#include +#include +#include +#include + +class ThrowListener : public testing::EmptyTestEventListener { + void OnTestPartResult(const testing::TestPartResult& result) override { + if (result.type() == testing::TestPartResult::kFatalFailure) { + throw testing::AssertionException(result); + } + } +}; + +// Prints the given failure message and exits the program with +// non-zero. We use this instead of a Google Test assertion to +// indicate a failure, as the latter is been tested and cannot be +// relied on. +void Fail(const char* msg) { + printf("FAILURE: %s\n", msg); + fflush(stdout); + exit(1); +} + +static void AssertFalse() { + ASSERT_EQ(2, 3) << "Expected failure"; +} + +// Tests that an assertion failure throws a subclass of +// std::runtime_error. +TEST(Test, Test) { + // A successful assertion shouldn't throw. + try { + EXPECT_EQ(3, 3); + } catch(...) { + Fail("A successful assertion wrongfully threw."); + } + + // A successful assertion shouldn't throw. + try { + EXPECT_EQ(3, 4); + } catch(...) { + Fail("A failed non-fatal assertion wrongfully threw."); + } + + // A failed assertion should throw. + try { + AssertFalse(); + } catch(const testing::AssertionException& e) { + if (strstr(e.what(), "Expected failure") != nullptr) throw; + + printf("%s", + "A failed assertion did throw an exception of the right type, " + "but the message is incorrect. Instead of containing \"Expected " + "failure\", it is:\n"); + Fail(e.what()); + } catch(...) { + Fail("A failed assertion threw the wrong type of exception."); + } + Fail("A failed assertion should've thrown but didn't."); +} + +int kTestForContinuingTest = 0; + +TEST(Test, Test2) { + kTestForContinuingTest = 1; +} + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + testing::UnitTest::GetInstance()->listeners().Append(new ThrowListener); + + int result = RUN_ALL_TESTS(); + if (result == 0) { + printf("RUN_ALL_TESTS returned %d\n", result); + Fail("Expected failure instead."); + } + + if (kTestForContinuingTest == 0) { + Fail("Should have continued with other tests, but did not."); + } + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_environment_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_environment_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..064bfc50b918451e2907bd5856673ddcd2701941 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_environment_test.cc @@ -0,0 +1,188 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Tests using global test environments. + +#include +#include +#include "gtest/gtest.h" +#include "src/gtest-internal-inl.h" + +namespace testing { +GTEST_DECLARE_string_(filter); +} + +namespace { + +enum FailureType { + NO_FAILURE, NON_FATAL_FAILURE, FATAL_FAILURE +}; + +// For testing using global test environments. +class MyEnvironment : public testing::Environment { + public: + MyEnvironment() { Reset(); } + + // Depending on the value of failure_in_set_up_, SetUp() will + // generate a non-fatal failure, generate a fatal failure, or + // succeed. + void SetUp() override { + set_up_was_run_ = true; + + switch (failure_in_set_up_) { + case NON_FATAL_FAILURE: + ADD_FAILURE() << "Expected non-fatal failure in global set-up."; + break; + case FATAL_FAILURE: + FAIL() << "Expected fatal failure in global set-up."; + break; + default: + break; + } + } + + // Generates a non-fatal failure. + void TearDown() override { + tear_down_was_run_ = true; + ADD_FAILURE() << "Expected non-fatal failure in global tear-down."; + } + + // Resets the state of the environment s.t. it can be reused. + void Reset() { + failure_in_set_up_ = NO_FAILURE; + set_up_was_run_ = false; + tear_down_was_run_ = false; + } + + // We call this function to set the type of failure SetUp() should + // generate. + void set_failure_in_set_up(FailureType type) { + failure_in_set_up_ = type; + } + + // Was SetUp() run? + bool set_up_was_run() const { return set_up_was_run_; } + + // Was TearDown() run? + bool tear_down_was_run() const { return tear_down_was_run_; } + + private: + FailureType failure_in_set_up_; + bool set_up_was_run_; + bool tear_down_was_run_; +}; + +// Was the TEST run? +bool test_was_run; + +// The sole purpose of this TEST is to enable us to check whether it +// was run. +TEST(FooTest, Bar) { + test_was_run = true; +} + +// Prints the message and aborts the program if condition is false. +void Check(bool condition, const char* msg) { + if (!condition) { + printf("FAILED: %s\n", msg); + testing::internal::posix::Abort(); + } +} + +// Runs the tests. Return true if and only if successful. +// +// The 'failure' parameter specifies the type of failure that should +// be generated by the global set-up. +int RunAllTests(MyEnvironment* env, FailureType failure) { + env->Reset(); + env->set_failure_in_set_up(failure); + test_was_run = false; + testing::internal::GetUnitTestImpl()->ClearAdHocTestResult(); + return RUN_ALL_TESTS(); +} + +} // namespace + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + + // Registers a global test environment, and verifies that the + // registration function returns its argument. + MyEnvironment* const env = new MyEnvironment; + Check(testing::AddGlobalTestEnvironment(env) == env, + "AddGlobalTestEnvironment() should return its argument."); + + // Verifies that RUN_ALL_TESTS() runs the tests when the global + // set-up is successful. + Check(RunAllTests(env, NO_FAILURE) != 0, + "RUN_ALL_TESTS() should return non-zero, as the global tear-down " + "should generate a failure."); + Check(test_was_run, + "The tests should run, as the global set-up should generate no " + "failure"); + Check(env->tear_down_was_run(), + "The global tear-down should run, as the global set-up was run."); + + // Verifies that RUN_ALL_TESTS() runs the tests when the global + // set-up generates no fatal failure. + Check(RunAllTests(env, NON_FATAL_FAILURE) != 0, + "RUN_ALL_TESTS() should return non-zero, as both the global set-up " + "and the global tear-down should generate a non-fatal failure."); + Check(test_was_run, + "The tests should run, as the global set-up should generate no " + "fatal failure."); + Check(env->tear_down_was_run(), + "The global tear-down should run, as the global set-up was run."); + + // Verifies that RUN_ALL_TESTS() runs no test when the global set-up + // generates a fatal failure. + Check(RunAllTests(env, FATAL_FAILURE) != 0, + "RUN_ALL_TESTS() should return non-zero, as the global set-up " + "should generate a fatal failure."); + Check(!test_was_run, + "The tests should not run, as the global set-up should generate " + "a fatal failure."); + Check(env->tear_down_was_run(), + "The global tear-down should run, as the global set-up was run."); + + // Verifies that RUN_ALL_TESTS() doesn't do global set-up or + // tear-down when there is no test to run. + testing::GTEST_FLAG(filter) = "-*"; + Check(RunAllTests(env, NO_FAILURE) == 0, + "RUN_ALL_TESTS() should return zero, as there is no test to run."); + Check(!env->set_up_was_run(), + "The global set-up should not run, as there is no test to run."); + Check(!env->tear_down_was_run(), + "The global tear-down should not run, " + "as the global set-up was not run."); + + printf("PASS\n"); + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_help_test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_help_test.py new file mode 100755 index 0000000000000000000000000000000000000000..582d24c2dcce894538aa63ccbd6120bdd4b350a0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_help_test.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python +# +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests the --help flag of Google C++ Testing and Mocking Framework. + +SYNOPSIS + gtest_help_test.py --build_dir=BUILD/DIR + # where BUILD/DIR contains the built gtest_help_test_ file. + gtest_help_test.py +""" + +import os +import re +import gtest_test_utils + + +IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux' +IS_WINDOWS = os.name == 'nt' + +PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_help_test_') +FLAG_PREFIX = '--gtest_' +DEATH_TEST_STYLE_FLAG = FLAG_PREFIX + 'death_test_style' +STREAM_RESULT_TO_FLAG = FLAG_PREFIX + 'stream_result_to' +UNKNOWN_FLAG = FLAG_PREFIX + 'unknown_flag_for_testing' +LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests' +INCORRECT_FLAG_VARIANTS = [re.sub('^--', '-', LIST_TESTS_FLAG), + re.sub('^--', '/', LIST_TESTS_FLAG), + re.sub('_', '-', LIST_TESTS_FLAG)] +INTERNAL_FLAG_FOR_TESTING = FLAG_PREFIX + 'internal_flag_for_testing' + +SUPPORTS_DEATH_TESTS = "DeathTest" in gtest_test_utils.Subprocess( + [PROGRAM_PATH, LIST_TESTS_FLAG]).output + +# The help message must match this regex. +HELP_REGEX = re.compile( + FLAG_PREFIX + r'list_tests.*' + + FLAG_PREFIX + r'filter=.*' + + FLAG_PREFIX + r'also_run_disabled_tests.*' + + FLAG_PREFIX + r'repeat=.*' + + FLAG_PREFIX + r'shuffle.*' + + FLAG_PREFIX + r'random_seed=.*' + + FLAG_PREFIX + r'color=.*' + + FLAG_PREFIX + r'print_time.*' + + FLAG_PREFIX + r'output=.*' + + FLAG_PREFIX + r'break_on_failure.*' + + FLAG_PREFIX + r'throw_on_failure.*' + + FLAG_PREFIX + r'catch_exceptions=0.*', + re.DOTALL) + + +def RunWithFlag(flag): + """Runs gtest_help_test_ with the given flag. + + Returns: + the exit code and the text output as a tuple. + Args: + flag: the command-line flag to pass to gtest_help_test_, or None. + """ + + if flag is None: + command = [PROGRAM_PATH] + else: + command = [PROGRAM_PATH, flag] + child = gtest_test_utils.Subprocess(command) + return child.exit_code, child.output + + +class GTestHelpTest(gtest_test_utils.TestCase): + """Tests the --help flag and its equivalent forms.""" + + def TestHelpFlag(self, flag): + """Verifies correct behavior when help flag is specified. + + The right message must be printed and the tests must + skipped when the given flag is specified. + + Args: + flag: A flag to pass to the binary or None. + """ + + exit_code, output = RunWithFlag(flag) + self.assertEquals(0, exit_code) + self.assert_(HELP_REGEX.search(output), output) + + if IS_LINUX: + self.assert_(STREAM_RESULT_TO_FLAG in output, output) + else: + self.assert_(STREAM_RESULT_TO_FLAG not in output, output) + + if SUPPORTS_DEATH_TESTS and not IS_WINDOWS: + self.assert_(DEATH_TEST_STYLE_FLAG in output, output) + else: + self.assert_(DEATH_TEST_STYLE_FLAG not in output, output) + + def TestNonHelpFlag(self, flag): + """Verifies correct behavior when no help flag is specified. + + Verifies that when no help flag is specified, the tests are run + and the help message is not printed. + + Args: + flag: A flag to pass to the binary or None. + """ + + exit_code, output = RunWithFlag(flag) + self.assert_(exit_code != 0) + self.assert_(not HELP_REGEX.search(output), output) + + def testPrintsHelpWithFullFlag(self): + self.TestHelpFlag('--help') + + def testPrintsHelpWithShortFlag(self): + self.TestHelpFlag('-h') + + def testPrintsHelpWithQuestionFlag(self): + self.TestHelpFlag('-?') + + def testPrintsHelpWithWindowsStyleQuestionFlag(self): + self.TestHelpFlag('/?') + + def testPrintsHelpWithUnrecognizedGoogleTestFlag(self): + self.TestHelpFlag(UNKNOWN_FLAG) + + def testPrintsHelpWithIncorrectFlagStyle(self): + for incorrect_flag in INCORRECT_FLAG_VARIANTS: + self.TestHelpFlag(incorrect_flag) + + def testRunsTestsWithoutHelpFlag(self): + """Verifies that when no help flag is specified, the tests are run + and the help message is not printed.""" + + self.TestNonHelpFlag(None) + + def testRunsTestsWithGtestInternalFlag(self): + """Verifies that the tests are run and no help message is printed when + a flag starting with Google Test prefix and 'internal_' is supplied.""" + + self.TestNonHelpFlag(INTERNAL_FLAG_FOR_TESTING) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_help_test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_help_test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..750ae6ce95fcbcb338ed5db2b588f15cdd5c2f9e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_help_test_.cc @@ -0,0 +1,45 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// This program is meant to be run by gtest_help_test.py. Do not run +// it directly. + +#include "gtest/gtest.h" + +// When a help flag is specified, this program should skip the tests +// and exit with 0; otherwise the following test will be executed, +// causing this program to exit with a non-zero code. +TEST(HelpFlagTest, ShouldNotBeRun) { + ASSERT_TRUE(false) << "Tests shouldn't be run when --help is specified."; +} + +#if GTEST_HAS_DEATH_TEST +TEST(DeathTest, UsedByPythonScriptToDetectSupportForDeathTestsInThisBinary) {} +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_json_test_utils.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_json_test_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..62bbfc288f82b387cd83446c0a05ba167b1aa754 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_json_test_utils.py @@ -0,0 +1,60 @@ +# Copyright 2018, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test utilities for gtest_json_output.""" + +import re + + +def normalize(obj): + """Normalize output object. + + Args: + obj: Google Test's JSON output object to normalize. + + Returns: + Normalized output without any references to transient information that may + change from run to run. + """ + def _normalize(key, value): + if key == 'time': + return re.sub(r'^\d+(\.\d+)?s$', '*', value) + elif key == 'timestamp': + return re.sub(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ$', '*', value) + elif key == 'failure': + value = re.sub(r'^.*[/\\](.*:)\d+\n', '\\1*\n', value) + return re.sub(r'Stack trace:\n(.|\n)*', 'Stack trace:\n*', value) + else: + return normalize(value) + if isinstance(obj, dict): + return {k: _normalize(k, v) for k, v in obj.items()} + if isinstance(obj, list): + return [normalize(x) for x in obj] + else: + return obj diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_list_output_unittest.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_list_output_unittest.py new file mode 100644 index 0000000000000000000000000000000000000000..3bba7ea2cfd37cad5509f40f8e8b0022706be784 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_list_output_unittest.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +"""Unit test for Google Test's --gtest_list_tests flag. + +A user can ask Google Test to list all tests by specifying the +--gtest_list_tests flag. If output is requested, via --gtest_output=xml +or --gtest_output=json, the tests are listed, with extra information in the +output file. +This script tests such functionality by invoking gtest_list_output_unittest_ + (a program written with Google Test) the command line flags. +""" + +import os +import re +import gtest_test_utils + +GTEST_LIST_TESTS_FLAG = '--gtest_list_tests' +GTEST_OUTPUT_FLAG = '--gtest_output' + +EXPECTED_XML = """<\?xml version="1.0" encoding="UTF-8"\?> + + + + + + +""" + +EXPECTED_JSON = """{ + "tests": 2, + "name": "AllTests", + "testsuites": \[ + { + "name": "FooTest", + "tests": 2, + "testsuite": \[ + { + "name": "Test1", + "file": ".*gtest_list_output_unittest_.cc", + "line": 43 + }, + { + "name": "Test2", + "file": ".*gtest_list_output_unittest_.cc", + "line": 45 + } + \] + } + \] +} +""" + + +class GTestListTestsOutputUnitTest(gtest_test_utils.TestCase): + """Unit test for Google Test's list tests with output to file functionality. + """ + + def testXml(self): + """Verifies XML output for listing tests in a Google Test binary. + + Runs a test program that generates an empty XML output, and + tests that the XML output is expected. + """ + self._TestOutput('xml', EXPECTED_XML) + + def testJSON(self): + """Verifies XML output for listing tests in a Google Test binary. + + Runs a test program that generates an empty XML output, and + tests that the XML output is expected. + """ + self._TestOutput('json', EXPECTED_JSON) + + def _GetOutput(self, out_format): + file_path = os.path.join(gtest_test_utils.GetTempDir(), + 'test_out.' + out_format) + gtest_prog_path = gtest_test_utils.GetTestExecutablePath( + 'gtest_list_output_unittest_') + + command = ([ + gtest_prog_path, + '%s=%s:%s' % (GTEST_OUTPUT_FLAG, out_format, file_path), + '--gtest_list_tests' + ]) + environ_copy = os.environ.copy() + p = gtest_test_utils.Subprocess( + command, env=environ_copy, working_dir=gtest_test_utils.GetTempDir()) + + self.assert_(p.exited) + self.assertEquals(0, p.exit_code) + with open(file_path) as f: + result = f.read() + return result + + def _TestOutput(self, test_format, expected_output): + actual = self._GetOutput(test_format) + actual_lines = actual.splitlines() + expected_lines = expected_output.splitlines() + line_count = 0 + for actual_line in actual_lines: + expected_line = expected_lines[line_count] + expected_line_re = re.compile(expected_line.strip()) + self.assert_( + expected_line_re.match(actual_line.strip()), + ('actual output of "%s",\n' + 'which does not match expected regex of "%s"\n' + 'on line %d' % (actual, expected_output, line_count))) + line_count = line_count + 1 + + +if __name__ == '__main__': + os.environ['GTEST_STACK_TRACE_DEPTH'] = '1' + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_list_output_unittest_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_list_output_unittest_.cc new file mode 100644 index 0000000000000000000000000000000000000000..b1c7b4de3461fc1645f411b71f9e37f8224fd8a6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_list_output_unittest_.cc @@ -0,0 +1,51 @@ +// Copyright 2018, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: david.schuldenfrei@gmail.com (David Schuldenfrei) + +// Unit test for Google Test's --gtest_list_tests and --gtest_output flag. +// +// A user can ask Google Test to list all tests that will run, +// and have the output saved in a Json/Xml file. +// The tests will not be run after listing. +// +// This program will be invoked from a Python unit test. +// Don't run it directly. + +#include "gtest/gtest.h" + +TEST(FooTest, Test1) {} + +TEST(FooTest, Test2) {} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_main_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_main_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..eddedeabe8f3bb083dabca600e72f451b8d94cdb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_main_unittest.cc @@ -0,0 +1,44 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#include "gtest/gtest.h" + +// Tests that we don't have to define main() when we link to +// gtest_main instead of gtest. + +namespace { + +TEST(GTestMainTest, ShouldSucceed) { +} + +} // namespace + +// We are using the main() function defined in gtest_main.cc, so we +// don't define it here. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_no_test_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_no_test_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..d4f88dbfdfa68e6a0c40bb99fac6e4dbccff8f3b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_no_test_unittest.cc @@ -0,0 +1,54 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Tests that a Google Test program that has no test defined can run +// successfully. + +#include "gtest/gtest.h" + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + + // An ad-hoc assertion outside of all tests. + // + // This serves three purposes: + // + // 1. It verifies that an ad-hoc assertion can be executed even if + // no test is defined. + // 2. It verifies that a failed ad-hoc assertion causes the test + // program to fail. + // 3. We had a bug where the XML output won't be generated if an + // assertion is executed before RUN_ALL_TESTS() is called, even + // though --gtest_output=xml is specified. This makes sure the + // bug is fixed and doesn't regress. + EXPECT_EQ(1, 2); + + // The above EXPECT_EQ() should cause RUN_ALL_TESTS() to return non-zero. + return RUN_ALL_TESTS() ? 0 : 1; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_pred_impl_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_pred_impl_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..1afe5e2da7fe552e5ff4ca797e9b7c289f45e335 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_pred_impl_unittest.cc @@ -0,0 +1,2427 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on 01/02/2019 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! + +// Regression test for gtest_pred_impl.h +// +// This file is generated by a script and quite long. If you intend to +// learn how Google Test works by reading its unit tests, read +// gtest_unittest.cc instead. +// +// This is intended as a regression test for the Google Test predicate +// assertions. We compile it as part of the gtest_unittest target +// only to keep the implementation tidy and compact, as it is quite +// involved to set up the stage for testing Google Test using Google +// Test itself. +// +// Currently, gtest_unittest takes ~11 seconds to run in the testing +// daemon. In the future, if it grows too large and needs much more +// time to finish, we should consider separating this file into a +// stand-alone regression test. + +#include + +#include "gtest/gtest.h" +#include "gtest/gtest-spi.h" + +// A user-defined data type. +struct Bool { + explicit Bool(int val) : value(val != 0) {} + + bool operator>(int n) const { return value > Bool(n).value; } + + Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); } + + bool operator==(const Bool& rhs) const { return value == rhs.value; } + + bool value; +}; + +// Enables Bool to be used in assertions. +std::ostream& operator<<(std::ostream& os, const Bool& x) { + return os << (x.value ? "true" : "false"); +} + +// Sample functions/functors for testing unary predicate assertions. + +// A unary predicate function. +template +bool PredFunction1(T1 v1) { + return v1 > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction1Int(int v1) { + return v1 > 0; +} +bool PredFunction1Bool(Bool v1) { + return v1 > 0; +} + +// A unary predicate functor. +struct PredFunctor1 { + template + bool operator()(const T1& v1) { + return v1 > 0; + } +}; + +// A unary predicate-formatter function. +template +testing::AssertionResult PredFormatFunction1(const char* e1, + const T1& v1) { + if (PredFunction1(v1)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << e1 + << " is expected to be positive, but evaluates to " + << v1 << "."; +} + +// A unary predicate-formatter functor. +struct PredFormatFunctor1 { + template + testing::AssertionResult operator()(const char* e1, + const T1& v1) const { + return PredFormatFunction1(e1, v1); + } +}; + +// Tests for {EXPECT|ASSERT}_PRED_FORMAT1. + +class Predicate1Test : public testing::Test { + protected: + void SetUp() override { + expected_to_finish_ = true; + finished_ = false; + n1_ = 0; + } + + void TearDown() override { + // Verifies that each of the predicate's arguments was evaluated + // exactly once. + EXPECT_EQ(1, n1_) << + "The predicate assertion didn't evaluate argument 2 " + "exactly once."; + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true if and only if the test function is expected to run to finish. + static bool expected_to_finish_; + + // true if and only if the test function did run to finish. + static bool finished_; + + static int n1_; +}; + +bool Predicate1Test::expected_to_finish_; +bool Predicate1Test::finished_; +int Predicate1Test::n1_; + +typedef Predicate1Test EXPECT_PRED_FORMAT1Test; +typedef Predicate1Test ASSERT_PRED_FORMAT1Test; +typedef Predicate1Test EXPECT_PRED1Test; +typedef Predicate1Test ASSERT_PRED1Test; + +// Tests a successful EXPECT_PRED1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED1(PredFunction1Int, + ++n1_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED1(PredFunction1Bool, + Bool(++n1_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED1(PredFunctor1(), + ++n1_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED1(PredFunctor1(), + Bool(++n1_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED1(PredFunction1Int, + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED1(PredFunction1Bool, + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED1(PredFunctor1(), + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED1(PredFunctor1(), + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED1(PredFunction1Int, + ++n1_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED1(PredFunction1Bool, + Bool(++n1_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED1(PredFunctor1(), + ++n1_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED1(PredFunctor1(), + Bool(++n1_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED1(PredFunction1Int, + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED1(PredFunction1Bool, + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED1(PredFunctor1(), + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED1(PredFunctor1(), + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a successful EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT1(PredFormatFunction1, + ++n1_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED_FORMAT1(PredFormatFunction1, + Bool(++n1_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT1(PredFormatFunctor1(), + ++n1_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED_FORMAT1(PredFormatFunctor1(), + Bool(++n1_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT1(PredFormatFunction1, + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT1(PredFormatFunction1, + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT1(PredFormatFunctor1(), + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT1(PredFormatFunctor1(), + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT1(PredFormatFunction1, + ++n1_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED_FORMAT1(PredFormatFunction1, + Bool(++n1_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT1(PredFormatFunctor1(), + ++n1_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED_FORMAT1(PredFormatFunctor1(), + Bool(++n1_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(PredFormatFunction1, + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(PredFormatFunction1, + Bool(n1_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(PredFormatFunctor1(), + n1_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT1 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(PredFormatFunctor1(), + Bool(n1_++)); + finished_ = true; + }, ""); +} +// Sample functions/functors for testing binary predicate assertions. + +// A binary predicate function. +template +bool PredFunction2(T1 v1, T2 v2) { + return v1 + v2 > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction2Int(int v1, int v2) { + return v1 + v2 > 0; +} +bool PredFunction2Bool(Bool v1, Bool v2) { + return v1 + v2 > 0; +} + +// A binary predicate functor. +struct PredFunctor2 { + template + bool operator()(const T1& v1, + const T2& v2) { + return v1 + v2 > 0; + } +}; + +// A binary predicate-formatter function. +template +testing::AssertionResult PredFormatFunction2(const char* e1, + const char* e2, + const T1& v1, + const T2& v2) { + if (PredFunction2(v1, v2)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << e1 << " + " << e2 + << " is expected to be positive, but evaluates to " + << v1 + v2 << "."; +} + +// A binary predicate-formatter functor. +struct PredFormatFunctor2 { + template + testing::AssertionResult operator()(const char* e1, + const char* e2, + const T1& v1, + const T2& v2) const { + return PredFormatFunction2(e1, e2, v1, v2); + } +}; + +// Tests for {EXPECT|ASSERT}_PRED_FORMAT2. + +class Predicate2Test : public testing::Test { + protected: + void SetUp() override { + expected_to_finish_ = true; + finished_ = false; + n1_ = n2_ = 0; + } + + void TearDown() override { + // Verifies that each of the predicate's arguments was evaluated + // exactly once. + EXPECT_EQ(1, n1_) << + "The predicate assertion didn't evaluate argument 2 " + "exactly once."; + EXPECT_EQ(1, n2_) << + "The predicate assertion didn't evaluate argument 3 " + "exactly once."; + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true if and only if the test function is expected to run to finish. + static bool expected_to_finish_; + + // true if and only if the test function did run to finish. + static bool finished_; + + static int n1_; + static int n2_; +}; + +bool Predicate2Test::expected_to_finish_; +bool Predicate2Test::finished_; +int Predicate2Test::n1_; +int Predicate2Test::n2_; + +typedef Predicate2Test EXPECT_PRED_FORMAT2Test; +typedef Predicate2Test ASSERT_PRED_FORMAT2Test; +typedef Predicate2Test EXPECT_PRED2Test; +typedef Predicate2Test ASSERT_PRED2Test; + +// Tests a successful EXPECT_PRED2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED2(PredFunction2Int, + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED2(PredFunction2Bool, + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED2(PredFunctor2(), + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED2(PredFunctor2(), + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED2(PredFunction2Int, + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED2(PredFunction2Bool, + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED2(PredFunctor2(), + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED2(PredFunctor2(), + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED2(PredFunction2Int, + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED2(PredFunction2Bool, + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED2(PredFunctor2(), + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED2(PredFunctor2(), + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED2(PredFunction2Int, + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED2(PredFunction2Bool, + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED2(PredFunctor2(), + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED2(PredFunctor2(), + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a successful EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT2(PredFormatFunction2, + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED_FORMAT2(PredFormatFunction2, + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT2(PredFormatFunctor2(), + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED_FORMAT2(PredFormatFunctor2(), + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(PredFormatFunction2, + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(PredFormatFunction2, + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(PredFormatFunctor2(), + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(PredFormatFunctor2(), + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT2(PredFormatFunction2, + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED_FORMAT2(PredFormatFunction2, + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT2(PredFormatFunctor2(), + ++n1_, + ++n2_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED_FORMAT2(PredFormatFunctor2(), + Bool(++n1_), + Bool(++n2_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(PredFormatFunction2, + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(PredFormatFunction2, + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(PredFormatFunctor2(), + n1_++, + n2_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT2 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(PredFormatFunctor2(), + Bool(n1_++), + Bool(n2_++)); + finished_ = true; + }, ""); +} +// Sample functions/functors for testing ternary predicate assertions. + +// A ternary predicate function. +template +bool PredFunction3(T1 v1, T2 v2, T3 v3) { + return v1 + v2 + v3 > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction3Int(int v1, int v2, int v3) { + return v1 + v2 + v3 > 0; +} +bool PredFunction3Bool(Bool v1, Bool v2, Bool v3) { + return v1 + v2 + v3 > 0; +} + +// A ternary predicate functor. +struct PredFunctor3 { + template + bool operator()(const T1& v1, + const T2& v2, + const T3& v3) { + return v1 + v2 + v3 > 0; + } +}; + +// A ternary predicate-formatter function. +template +testing::AssertionResult PredFormatFunction3(const char* e1, + const char* e2, + const char* e3, + const T1& v1, + const T2& v2, + const T3& v3) { + if (PredFunction3(v1, v2, v3)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << e1 << " + " << e2 << " + " << e3 + << " is expected to be positive, but evaluates to " + << v1 + v2 + v3 << "."; +} + +// A ternary predicate-formatter functor. +struct PredFormatFunctor3 { + template + testing::AssertionResult operator()(const char* e1, + const char* e2, + const char* e3, + const T1& v1, + const T2& v2, + const T3& v3) const { + return PredFormatFunction3(e1, e2, e3, v1, v2, v3); + } +}; + +// Tests for {EXPECT|ASSERT}_PRED_FORMAT3. + +class Predicate3Test : public testing::Test { + protected: + void SetUp() override { + expected_to_finish_ = true; + finished_ = false; + n1_ = n2_ = n3_ = 0; + } + + void TearDown() override { + // Verifies that each of the predicate's arguments was evaluated + // exactly once. + EXPECT_EQ(1, n1_) << + "The predicate assertion didn't evaluate argument 2 " + "exactly once."; + EXPECT_EQ(1, n2_) << + "The predicate assertion didn't evaluate argument 3 " + "exactly once."; + EXPECT_EQ(1, n3_) << + "The predicate assertion didn't evaluate argument 4 " + "exactly once."; + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true if and only if the test function is expected to run to finish. + static bool expected_to_finish_; + + // true if and only if the test function did run to finish. + static bool finished_; + + static int n1_; + static int n2_; + static int n3_; +}; + +bool Predicate3Test::expected_to_finish_; +bool Predicate3Test::finished_; +int Predicate3Test::n1_; +int Predicate3Test::n2_; +int Predicate3Test::n3_; + +typedef Predicate3Test EXPECT_PRED_FORMAT3Test; +typedef Predicate3Test ASSERT_PRED_FORMAT3Test; +typedef Predicate3Test EXPECT_PRED3Test; +typedef Predicate3Test ASSERT_PRED3Test; + +// Tests a successful EXPECT_PRED3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED3(PredFunction3Int, + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED3(PredFunction3Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED3(PredFunctor3(), + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED3(PredFunctor3(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED3(PredFunction3Int, + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED3(PredFunction3Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED3(PredFunctor3(), + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED3(PredFunctor3(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED3(PredFunction3Int, + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED3(PredFunction3Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED3(PredFunctor3(), + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED3(PredFunctor3(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED3(PredFunction3Int, + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED3(PredFunction3Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED3(PredFunctor3(), + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED3(PredFunctor3(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a successful EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT3(PredFormatFunction3, + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED_FORMAT3(PredFormatFunction3, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT3(PredFormatFunctor3(), + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED_FORMAT3(PredFormatFunctor3(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT3(PredFormatFunction3, + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT3(PredFormatFunction3, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT3(PredFormatFunctor3(), + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT3(PredFormatFunctor3(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT3(PredFormatFunction3, + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED_FORMAT3(PredFormatFunction3, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT3(PredFormatFunctor3(), + ++n1_, + ++n2_, + ++n3_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED_FORMAT3(PredFormatFunctor3(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT3(PredFormatFunction3, + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT3(PredFormatFunction3, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT3(PredFormatFunctor3(), + n1_++, + n2_++, + n3_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT3 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT3(PredFormatFunctor3(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++)); + finished_ = true; + }, ""); +} +// Sample functions/functors for testing 4-ary predicate assertions. + +// A 4-ary predicate function. +template +bool PredFunction4(T1 v1, T2 v2, T3 v3, T4 v4) { + return v1 + v2 + v3 + v4 > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction4Int(int v1, int v2, int v3, int v4) { + return v1 + v2 + v3 + v4 > 0; +} +bool PredFunction4Bool(Bool v1, Bool v2, Bool v3, Bool v4) { + return v1 + v2 + v3 + v4 > 0; +} + +// A 4-ary predicate functor. +struct PredFunctor4 { + template + bool operator()(const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + return v1 + v2 + v3 + v4 > 0; + } +}; + +// A 4-ary predicate-formatter function. +template +testing::AssertionResult PredFormatFunction4(const char* e1, + const char* e2, + const char* e3, + const char* e4, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (PredFunction4(v1, v2, v3, v4)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << e1 << " + " << e2 << " + " << e3 << " + " << e4 + << " is expected to be positive, but evaluates to " + << v1 + v2 + v3 + v4 << "."; +} + +// A 4-ary predicate-formatter functor. +struct PredFormatFunctor4 { + template + testing::AssertionResult operator()(const char* e1, + const char* e2, + const char* e3, + const char* e4, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) const { + return PredFormatFunction4(e1, e2, e3, e4, v1, v2, v3, v4); + } +}; + +// Tests for {EXPECT|ASSERT}_PRED_FORMAT4. + +class Predicate4Test : public testing::Test { + protected: + void SetUp() override { + expected_to_finish_ = true; + finished_ = false; + n1_ = n2_ = n3_ = n4_ = 0; + } + + void TearDown() override { + // Verifies that each of the predicate's arguments was evaluated + // exactly once. + EXPECT_EQ(1, n1_) << + "The predicate assertion didn't evaluate argument 2 " + "exactly once."; + EXPECT_EQ(1, n2_) << + "The predicate assertion didn't evaluate argument 3 " + "exactly once."; + EXPECT_EQ(1, n3_) << + "The predicate assertion didn't evaluate argument 4 " + "exactly once."; + EXPECT_EQ(1, n4_) << + "The predicate assertion didn't evaluate argument 5 " + "exactly once."; + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true if and only if the test function is expected to run to finish. + static bool expected_to_finish_; + + // true if and only if the test function did run to finish. + static bool finished_; + + static int n1_; + static int n2_; + static int n3_; + static int n4_; +}; + +bool Predicate4Test::expected_to_finish_; +bool Predicate4Test::finished_; +int Predicate4Test::n1_; +int Predicate4Test::n2_; +int Predicate4Test::n3_; +int Predicate4Test::n4_; + +typedef Predicate4Test EXPECT_PRED_FORMAT4Test; +typedef Predicate4Test ASSERT_PRED_FORMAT4Test; +typedef Predicate4Test EXPECT_PRED4Test; +typedef Predicate4Test ASSERT_PRED4Test; + +// Tests a successful EXPECT_PRED4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED4(PredFunction4Int, + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED4(PredFunction4Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED4(PredFunctor4(), + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED4(PredFunctor4(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED4(PredFunction4Int, + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED4(PredFunction4Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED4(PredFunctor4(), + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED4(PredFunctor4(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED4(PredFunction4Int, + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED4(PredFunction4Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED4(PredFunctor4(), + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED4(PredFunctor4(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED4(PredFunction4Int, + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED4(PredFunction4Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED4(PredFunctor4(), + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED4(PredFunctor4(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a successful EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT4(PredFormatFunction4, + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED_FORMAT4(PredFormatFunction4, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT4(PredFormatFunctor4(), + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED_FORMAT4(PredFormatFunctor4(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(PredFormatFunction4, + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(PredFormatFunction4, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(PredFormatFunctor4(), + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(PredFormatFunctor4(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT4(PredFormatFunction4, + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED_FORMAT4(PredFormatFunction4, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT4(PredFormatFunctor4(), + ++n1_, + ++n2_, + ++n3_, + ++n4_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED_FORMAT4(PredFormatFunctor4(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT4(PredFormatFunction4, + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT4(PredFormatFunction4, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT4(PredFormatFunctor4(), + n1_++, + n2_++, + n3_++, + n4_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT4 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT4(PredFormatFunctor4(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++)); + finished_ = true; + }, ""); +} +// Sample functions/functors for testing 5-ary predicate assertions. + +// A 5-ary predicate function. +template +bool PredFunction5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { + return v1 + v2 + v3 + v4 + v5 > 0; +} + +// The following two functions are needed to circumvent a bug in +// gcc 2.95.3, which sometimes has problem with the above template +// function. +bool PredFunction5Int(int v1, int v2, int v3, int v4, int v5) { + return v1 + v2 + v3 + v4 + v5 > 0; +} +bool PredFunction5Bool(Bool v1, Bool v2, Bool v3, Bool v4, Bool v5) { + return v1 + v2 + v3 + v4 + v5 > 0; +} + +// A 5-ary predicate functor. +struct PredFunctor5 { + template + bool operator()(const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + return v1 + v2 + v3 + v4 + v5 > 0; + } +}; + +// A 5-ary predicate-formatter function. +template +testing::AssertionResult PredFormatFunction5(const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (PredFunction5(v1, v2, v3, v4, v5)) + return testing::AssertionSuccess(); + + return testing::AssertionFailure() + << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5 + << " is expected to be positive, but evaluates to " + << v1 + v2 + v3 + v4 + v5 << "."; +} + +// A 5-ary predicate-formatter functor. +struct PredFormatFunctor5 { + template + testing::AssertionResult operator()(const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) const { + return PredFormatFunction5(e1, e2, e3, e4, e5, v1, v2, v3, v4, v5); + } +}; + +// Tests for {EXPECT|ASSERT}_PRED_FORMAT5. + +class Predicate5Test : public testing::Test { + protected: + void SetUp() override { + expected_to_finish_ = true; + finished_ = false; + n1_ = n2_ = n3_ = n4_ = n5_ = 0; + } + + void TearDown() override { + // Verifies that each of the predicate's arguments was evaluated + // exactly once. + EXPECT_EQ(1, n1_) << + "The predicate assertion didn't evaluate argument 2 " + "exactly once."; + EXPECT_EQ(1, n2_) << + "The predicate assertion didn't evaluate argument 3 " + "exactly once."; + EXPECT_EQ(1, n3_) << + "The predicate assertion didn't evaluate argument 4 " + "exactly once."; + EXPECT_EQ(1, n4_) << + "The predicate assertion didn't evaluate argument 5 " + "exactly once."; + EXPECT_EQ(1, n5_) << + "The predicate assertion didn't evaluate argument 6 " + "exactly once."; + + // Verifies that the control flow in the test function is expected. + if (expected_to_finish_ && !finished_) { + FAIL() << "The predicate assertion unexpactedly aborted the test."; + } else if (!expected_to_finish_ && finished_) { + FAIL() << "The failed predicate assertion didn't abort the test " + "as expected."; + } + } + + // true if and only if the test function is expected to run to finish. + static bool expected_to_finish_; + + // true if and only if the test function did run to finish. + static bool finished_; + + static int n1_; + static int n2_; + static int n3_; + static int n4_; + static int n5_; +}; + +bool Predicate5Test::expected_to_finish_; +bool Predicate5Test::finished_; +int Predicate5Test::n1_; +int Predicate5Test::n2_; +int Predicate5Test::n3_; +int Predicate5Test::n4_; +int Predicate5Test::n5_; + +typedef Predicate5Test EXPECT_PRED_FORMAT5Test; +typedef Predicate5Test ASSERT_PRED_FORMAT5Test; +typedef Predicate5Test EXPECT_PRED5Test; +typedef Predicate5Test ASSERT_PRED5Test; + +// Tests a successful EXPECT_PRED5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED5(PredFunction5Int, + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED5(PredFunction5Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED5(PredFunctor5(), + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED5(PredFunctor5(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED5(PredFunction5Int, + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED5(PredFunction5Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED5(PredFunctor5(), + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED5(PredFunctor5(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED5(PredFunction5Int, + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED5(PredFunction5Bool, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED5(PredFunctor5(), + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED5(PredFunctor5(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED5(PredFunction5Int, + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED5(PredFunction5Bool, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED5(PredFunctor5(), + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED5(PredFunctor5(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a successful EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT5(PredFormatFunction5, + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess) { + EXPECT_PRED_FORMAT5(PredFormatFunction5, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess) { + EXPECT_PRED_FORMAT5(PredFormatFunctor5(), + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess) { + EXPECT_PRED_FORMAT5(PredFormatFunctor5(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a failed EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT5(PredFormatFunction5, + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT5(PredFormatFunction5, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT5(PredFormatFunctor5(), + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed EXPECT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeFailure) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT5(PredFormatFunctor5(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a successful ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT5(PredFormatFunction5, + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess) { + ASSERT_PRED_FORMAT5(PredFormatFunction5, + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess) { + ASSERT_PRED_FORMAT5(PredFormatFunctor5(), + ++n1_, + ++n2_, + ++n3_, + ++n4_, + ++n5_); + finished_ = true; +} + +// Tests a successful ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess) { + ASSERT_PRED_FORMAT5(PredFormatFunctor5(), + Bool(++n1_), + Bool(++n2_), + Bool(++n3_), + Bool(++n4_), + Bool(++n5_)); + finished_ = true; +} + +// Tests a failed ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a function on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT5(PredFormatFunction5, + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a function on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT5(PredFormatFunction5, + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a built-in type (int). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT5(PredFormatFunctor5(), + n1_++, + n2_++, + n3_++, + n4_++, + n5_++); + finished_ = true; + }, ""); +} + +// Tests a failed ASSERT_PRED_FORMAT5 where the +// predicate-formatter is a functor on a user-defined type (Bool). +TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeFailure) { + expected_to_finish_ = false; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT5(PredFormatFunctor5(), + Bool(n1_++), + Bool(n2_++), + Bool(n3_++), + Bool(n4_++), + Bool(n5_++)); + finished_ = true; + }, ""); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_premature_exit_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_premature_exit_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..1d1187eff006cc88750ef957829d580ac690350b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_premature_exit_test.cc @@ -0,0 +1,126 @@ +// Copyright 2013, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Tests that Google Test manipulates the premature-exit-detection +// file correctly. + +#include + +#include "gtest/gtest.h" + +using ::testing::InitGoogleTest; +using ::testing::Test; +using ::testing::internal::posix::GetEnv; +using ::testing::internal::posix::Stat; +using ::testing::internal::posix::StatStruct; + +namespace { + +class PrematureExitTest : public Test { + public: + // Returns true if and only if the given file exists. + static bool FileExists(const char* filepath) { + StatStruct stat; + return Stat(filepath, &stat) == 0; + } + + protected: + PrematureExitTest() { + premature_exit_file_path_ = GetEnv("TEST_PREMATURE_EXIT_FILE"); + + // Normalize NULL to "" for ease of handling. + if (premature_exit_file_path_ == nullptr) { + premature_exit_file_path_ = ""; + } + } + + // Returns true if and only if the premature-exit file exists. + bool PrematureExitFileExists() const { + return FileExists(premature_exit_file_path_); + } + + const char* premature_exit_file_path_; +}; + +typedef PrematureExitTest PrematureExitDeathTest; + +// Tests that: +// - the premature-exit file exists during the execution of a +// death test (EXPECT_DEATH*), and +// - a death test doesn't interfere with the main test process's +// handling of the premature-exit file. +TEST_F(PrematureExitDeathTest, FileExistsDuringExecutionOfDeathTest) { + if (*premature_exit_file_path_ == '\0') { + return; + } + + EXPECT_DEATH_IF_SUPPORTED({ + // If the file exists, crash the process such that the main test + // process will catch the (expected) crash and report a success; + // otherwise don't crash, which will cause the main test process + // to report that the death test has failed. + if (PrematureExitFileExists()) { + exit(1); + } + }, ""); +} + +// Tests that the premature-exit file exists during the execution of a +// normal (non-death) test. +TEST_F(PrematureExitTest, PrematureExitFileExistsDuringTestExecution) { + if (*premature_exit_file_path_ == '\0') { + return; + } + + EXPECT_TRUE(PrematureExitFileExists()) + << " file " << premature_exit_file_path_ + << " should exist during test execution, but doesn't."; +} + +} // namespace + +int main(int argc, char **argv) { + InitGoogleTest(&argc, argv); + const int exit_code = RUN_ALL_TESTS(); + + // Test that the premature-exit file is deleted upon return from + // RUN_ALL_TESTS(). + const char* const filepath = GetEnv("TEST_PREMATURE_EXIT_FILE"); + if (filepath != nullptr && *filepath != '\0') { + if (PrematureExitTest::FileExists(filepath)) { + printf( + "File %s shouldn't exist after the test program finishes, but does.", + filepath); + return 1; + } + } + + return exit_code; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_prod_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_prod_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..ede81a0d17a02c853ed2234ec88fe8277180a37e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_prod_test.cc @@ -0,0 +1,56 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Unit test for gtest_prod.h. + +#include "production.h" +#include "gtest/gtest.h" + +// Tests that private members can be accessed from a TEST declared as +// a friend of the class. +TEST(PrivateCodeTest, CanAccessPrivateMembers) { + PrivateCode a; + EXPECT_EQ(0, a.x_); + + a.set_x(1); + EXPECT_EQ(1, a.x_); +} + +typedef testing::Test PrivateCodeFixtureTest; + +// Tests that private members can be accessed from a TEST_F declared +// as a friend of the class. +TEST_F(PrivateCodeFixtureTest, CanAccessPrivateMembers) { + PrivateCode a; + EXPECT_EQ(0, a.x_); + + a.set_x(2); + EXPECT_EQ(2, a.x_); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_repeat_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_repeat_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..7da4a15ea141989f86426a572bac0a58b33f76ba --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_repeat_test.cc @@ -0,0 +1,233 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Tests the --gtest_repeat=number flag. + +#include +#include +#include "gtest/gtest.h" +#include "src/gtest-internal-inl.h" + +namespace testing { + +GTEST_DECLARE_string_(death_test_style); +GTEST_DECLARE_string_(filter); +GTEST_DECLARE_int32_(repeat); + +} // namespace testing + +using testing::GTEST_FLAG(death_test_style); +using testing::GTEST_FLAG(filter); +using testing::GTEST_FLAG(repeat); + +namespace { + +// We need this when we are testing Google Test itself and therefore +// cannot use Google Test assertions. +#define GTEST_CHECK_INT_EQ_(expected, actual) \ + do {\ + const int expected_val = (expected);\ + const int actual_val = (actual);\ + if (::testing::internal::IsTrue(expected_val != actual_val)) {\ + ::std::cout << "Value of: " #actual "\n"\ + << " Actual: " << actual_val << "\n"\ + << "Expected: " #expected "\n"\ + << "Which is: " << expected_val << "\n";\ + ::testing::internal::posix::Abort();\ + }\ + } while (::testing::internal::AlwaysFalse()) + + +// Used for verifying that global environment set-up and tear-down are +// inside the --gtest_repeat loop. + +int g_environment_set_up_count = 0; +int g_environment_tear_down_count = 0; + +class MyEnvironment : public testing::Environment { + public: + MyEnvironment() {} + void SetUp() override { g_environment_set_up_count++; } + void TearDown() override { g_environment_tear_down_count++; } +}; + +// A test that should fail. + +int g_should_fail_count = 0; + +TEST(FooTest, ShouldFail) { + g_should_fail_count++; + EXPECT_EQ(0, 1) << "Expected failure."; +} + +// A test that should pass. + +int g_should_pass_count = 0; + +TEST(FooTest, ShouldPass) { + g_should_pass_count++; +} + +// A test that contains a thread-safe death test and a fast death +// test. It should pass. + +int g_death_test_count = 0; + +TEST(BarDeathTest, ThreadSafeAndFast) { + g_death_test_count++; + + GTEST_FLAG(death_test_style) = "threadsafe"; + EXPECT_DEATH_IF_SUPPORTED(::testing::internal::posix::Abort(), ""); + + GTEST_FLAG(death_test_style) = "fast"; + EXPECT_DEATH_IF_SUPPORTED(::testing::internal::posix::Abort(), ""); +} + +int g_param_test_count = 0; + +const int kNumberOfParamTests = 10; + +class MyParamTest : public testing::TestWithParam {}; + +TEST_P(MyParamTest, ShouldPass) { + GTEST_CHECK_INT_EQ_(g_param_test_count % kNumberOfParamTests, GetParam()); + g_param_test_count++; +} +INSTANTIATE_TEST_SUITE_P(MyParamSequence, + MyParamTest, + testing::Range(0, kNumberOfParamTests)); + +// Resets the count for each test. +void ResetCounts() { + g_environment_set_up_count = 0; + g_environment_tear_down_count = 0; + g_should_fail_count = 0; + g_should_pass_count = 0; + g_death_test_count = 0; + g_param_test_count = 0; +} + +// Checks that the count for each test is expected. +void CheckCounts(int expected) { + GTEST_CHECK_INT_EQ_(expected, g_environment_set_up_count); + GTEST_CHECK_INT_EQ_(expected, g_environment_tear_down_count); + GTEST_CHECK_INT_EQ_(expected, g_should_fail_count); + GTEST_CHECK_INT_EQ_(expected, g_should_pass_count); + GTEST_CHECK_INT_EQ_(expected, g_death_test_count); + GTEST_CHECK_INT_EQ_(expected * kNumberOfParamTests, g_param_test_count); +} + +// Tests the behavior of Google Test when --gtest_repeat is not specified. +void TestRepeatUnspecified() { + ResetCounts(); + GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS()); + CheckCounts(1); +} + +// Tests the behavior of Google Test when --gtest_repeat has the given value. +void TestRepeat(int repeat) { + GTEST_FLAG(repeat) = repeat; + + ResetCounts(); + GTEST_CHECK_INT_EQ_(repeat > 0 ? 1 : 0, RUN_ALL_TESTS()); + CheckCounts(repeat); +} + +// Tests using --gtest_repeat when --gtest_filter specifies an empty +// set of tests. +void TestRepeatWithEmptyFilter(int repeat) { + GTEST_FLAG(repeat) = repeat; + GTEST_FLAG(filter) = "None"; + + ResetCounts(); + GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS()); + CheckCounts(0); +} + +// Tests using --gtest_repeat when --gtest_filter specifies a set of +// successful tests. +void TestRepeatWithFilterForSuccessfulTests(int repeat) { + GTEST_FLAG(repeat) = repeat; + GTEST_FLAG(filter) = "*-*ShouldFail"; + + ResetCounts(); + GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS()); + GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count); + GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count); + GTEST_CHECK_INT_EQ_(0, g_should_fail_count); + GTEST_CHECK_INT_EQ_(repeat, g_should_pass_count); + GTEST_CHECK_INT_EQ_(repeat, g_death_test_count); + GTEST_CHECK_INT_EQ_(repeat * kNumberOfParamTests, g_param_test_count); +} + +// Tests using --gtest_repeat when --gtest_filter specifies a set of +// failed tests. +void TestRepeatWithFilterForFailedTests(int repeat) { + GTEST_FLAG(repeat) = repeat; + GTEST_FLAG(filter) = "*ShouldFail"; + + ResetCounts(); + GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS()); + GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count); + GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count); + GTEST_CHECK_INT_EQ_(repeat, g_should_fail_count); + GTEST_CHECK_INT_EQ_(0, g_should_pass_count); + GTEST_CHECK_INT_EQ_(0, g_death_test_count); + GTEST_CHECK_INT_EQ_(0, g_param_test_count); +} + +} // namespace + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + + testing::AddGlobalTestEnvironment(new MyEnvironment); + + TestRepeatUnspecified(); + TestRepeat(0); + TestRepeat(1); + TestRepeat(5); + + TestRepeatWithEmptyFilter(2); + TestRepeatWithEmptyFilter(3); + + TestRepeatWithFilterForSuccessfulTests(3); + + TestRepeatWithFilterForFailedTests(4); + + // It would be nice to verify that the tests indeed loop forever + // when GTEST_FLAG(repeat) is negative, but this test will be quite + // complicated to write. Since this flag is for interactive + // debugging only and doesn't affect the normal test result, such a + // test would be an overkill. + + printf("PASS\n"); + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_skip_environment_check_output_test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_skip_environment_check_output_test.py new file mode 100755 index 0000000000000000000000000000000000000000..6e791556aa71e5623a357af822713b4df2176403 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_skip_environment_check_output_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# +# Copyright 2019 Google LLC. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +"""Tests Google Test's gtest skip in environment setup behavior. + +This script invokes gtest_skip_in_environment_setup_test_ and verifies its +output. +""" + +import gtest_test_utils + +# Path to the gtest_skip_in_environment_setup_test binary +EXE_PATH = gtest_test_utils.GetTestExecutablePath( + 'gtest_skip_in_environment_setup_test') + +OUTPUT = gtest_test_utils.Subprocess([EXE_PATH]).output + + +# Test. +class SkipEntireEnvironmentTest(gtest_test_utils.TestCase): + + def testSkipEntireEnvironmentTest(self): + self.assertIn('Skipping the entire environment', OUTPUT) + self.assertNotIn('FAILED', OUTPUT) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_skip_in_environment_setup_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_skip_in_environment_setup_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..937231063816e047acdd2fb416da80e4986438be --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_skip_in_environment_setup_test.cc @@ -0,0 +1,49 @@ +// Copyright 2019, Google LLC. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This test verifies that skipping in the environment results in the +// testcases being skipped. + +#include +#include "gtest/gtest.h" + +class SetupEnvironment : public testing::Environment { + public: + void SetUp() override { GTEST_SKIP() << "Skipping the entire environment"; } +}; + +TEST(Test, AlwaysFails) { EXPECT_EQ(true, false); } + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + + testing::AddGlobalTestEnvironment(new SetupEnvironment()); + + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_skip_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_skip_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..717e105e2e073e4b11cd3c17bc21018001861406 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_skip_test.cc @@ -0,0 +1,55 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: arseny.aprelev@gmail.com (Arseny Aprelev) +// + +#include "gtest/gtest.h" + +using ::testing::Test; + +TEST(SkipTest, DoesSkip) { + GTEST_SKIP(); + EXPECT_EQ(0, 1); +} + +class Fixture : public Test { + protected: + void SetUp() override { + GTEST_SKIP() << "skipping all tests for this fixture"; + } +}; + +TEST_F(Fixture, SkipsOneTest) { + EXPECT_EQ(5, 7); +} + +TEST_F(Fixture, SkipsAnotherTest) { + EXPECT_EQ(99, 100); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_sole_header_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_sole_header_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..1d94ac6b3ad9f9f7dbadbfb2bf749b8271560dac --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_sole_header_test.cc @@ -0,0 +1,56 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// This test verifies that it's possible to use Google Test by including +// the gtest.h header file alone. + +#include "gtest/gtest.h" + +namespace { + +void Subroutine() { + EXPECT_EQ(42, 42); +} + +TEST(NoFatalFailureTest, ExpectNoFatalFailure) { + EXPECT_NO_FATAL_FAILURE(;); + EXPECT_NO_FATAL_FAILURE(SUCCEED()); + EXPECT_NO_FATAL_FAILURE(Subroutine()); + EXPECT_NO_FATAL_FAILURE({ SUCCEED(); }); +} + +TEST(NoFatalFailureTest, AssertNoFatalFailure) { + ASSERT_NO_FATAL_FAILURE(;); + ASSERT_NO_FATAL_FAILURE(SUCCEED()); + ASSERT_NO_FATAL_FAILURE(Subroutine()); + ASSERT_NO_FATAL_FAILURE({ SUCCEED(); }); +} + +} // namespace diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_stress_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_stress_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..843481910f03f6989773c586b8e11eddbd6034cb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_stress_test.cc @@ -0,0 +1,248 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Tests that SCOPED_TRACE() and various Google Test assertions can be +// used in a large number of threads concurrently. + +#include "gtest/gtest.h" + +#include + +#include "src/gtest-internal-inl.h" + +#if GTEST_IS_THREADSAFE + +namespace testing { +namespace { + +using internal::Notification; +using internal::TestPropertyKeyIs; +using internal::ThreadWithParam; + +// In order to run tests in this file, for platforms where Google Test is +// thread safe, implement ThreadWithParam. See the description of its API +// in gtest-port.h, where it is defined for already supported platforms. + +// How many threads to create? +const int kThreadCount = 50; + +std::string IdToKey(int id, const char* suffix) { + Message key; + key << "key_" << id << "_" << suffix; + return key.GetString(); +} + +std::string IdToString(int id) { + Message id_message; + id_message << id; + return id_message.GetString(); +} + +void ExpectKeyAndValueWereRecordedForId( + const std::vector& properties, + int id, const char* suffix) { + TestPropertyKeyIs matches_key(IdToKey(id, suffix).c_str()); + const std::vector::const_iterator property = + std::find_if(properties.begin(), properties.end(), matches_key); + ASSERT_TRUE(property != properties.end()) + << "expecting " << suffix << " value for id " << id; + EXPECT_STREQ(IdToString(id).c_str(), property->value()); +} + +// Calls a large number of Google Test assertions, where exactly one of them +// will fail. +void ManyAsserts(int id) { + GTEST_LOG_(INFO) << "Thread #" << id << " running..."; + + SCOPED_TRACE(Message() << "Thread #" << id); + + for (int i = 0; i < kThreadCount; i++) { + SCOPED_TRACE(Message() << "Iteration #" << i); + + // A bunch of assertions that should succeed. + EXPECT_TRUE(true); + ASSERT_FALSE(false) << "This shouldn't fail."; + EXPECT_STREQ("a", "a"); + ASSERT_LE(5, 6); + EXPECT_EQ(i, i) << "This shouldn't fail."; + + // RecordProperty() should interact safely with other threads as well. + // The shared_key forces property updates. + Test::RecordProperty(IdToKey(id, "string").c_str(), IdToString(id).c_str()); + Test::RecordProperty(IdToKey(id, "int").c_str(), id); + Test::RecordProperty("shared_key", IdToString(id).c_str()); + + // This assertion should fail kThreadCount times per thread. It + // is for testing whether Google Test can handle failed assertions in a + // multi-threaded context. + EXPECT_LT(i, 0) << "This should always fail."; + } +} + +void CheckTestFailureCount(int expected_failures) { + const TestInfo* const info = UnitTest::GetInstance()->current_test_info(); + const TestResult* const result = info->result(); + GTEST_CHECK_(expected_failures == result->total_part_count()) + << "Logged " << result->total_part_count() << " failures " + << " vs. " << expected_failures << " expected"; +} + +// Tests using SCOPED_TRACE() and Google Test assertions in many threads +// concurrently. +TEST(StressTest, CanUseScopedTraceAndAssertionsInManyThreads) { + { + std::unique_ptr > threads[kThreadCount]; + Notification threads_can_start; + for (int i = 0; i != kThreadCount; i++) + threads[i].reset(new ThreadWithParam(&ManyAsserts, + i, + &threads_can_start)); + + threads_can_start.Notify(); + + // Blocks until all the threads are done. + for (int i = 0; i != kThreadCount; i++) + threads[i]->Join(); + } + + // Ensures that kThreadCount*kThreadCount failures have been reported. + const TestInfo* const info = UnitTest::GetInstance()->current_test_info(); + const TestResult* const result = info->result(); + + std::vector properties; + // We have no access to the TestResult's list of properties but we can + // copy them one by one. + for (int i = 0; i < result->test_property_count(); ++i) + properties.push_back(result->GetTestProperty(i)); + + EXPECT_EQ(kThreadCount * 2 + 1, result->test_property_count()) + << "String and int values recorded on each thread, " + << "as well as one shared_key"; + for (int i = 0; i < kThreadCount; ++i) { + ExpectKeyAndValueWereRecordedForId(properties, i, "string"); + ExpectKeyAndValueWereRecordedForId(properties, i, "int"); + } + CheckTestFailureCount(kThreadCount*kThreadCount); +} + +void FailingThread(bool is_fatal) { + if (is_fatal) + FAIL() << "Fatal failure in some other thread. " + << "(This failure is expected.)"; + else + ADD_FAILURE() << "Non-fatal failure in some other thread. " + << "(This failure is expected.)"; +} + +void GenerateFatalFailureInAnotherThread(bool is_fatal) { + ThreadWithParam thread(&FailingThread, is_fatal, nullptr); + thread.Join(); +} + +TEST(NoFatalFailureTest, ExpectNoFatalFailureIgnoresFailuresInOtherThreads) { + EXPECT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true)); + // We should only have one failure (the one from + // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE + // should succeed. + CheckTestFailureCount(1); +} + +void AssertNoFatalFailureIgnoresFailuresInOtherThreads() { + ASSERT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true)); +} +TEST(NoFatalFailureTest, AssertNoFatalFailureIgnoresFailuresInOtherThreads) { + // Using a subroutine, to make sure, that the test continues. + AssertNoFatalFailureIgnoresFailuresInOtherThreads(); + // We should only have one failure (the one from + // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE + // should succeed. + CheckTestFailureCount(1); +} + +TEST(FatalFailureTest, ExpectFatalFailureIgnoresFailuresInOtherThreads) { + // This statement should fail, since the current thread doesn't generate a + // fatal failure, only another one does. + EXPECT_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true), "expected"); + CheckTestFailureCount(2); +} + +TEST(FatalFailureOnAllThreadsTest, ExpectFatalFailureOnAllThreads) { + // This statement should succeed, because failures in all threads are + // considered. + EXPECT_FATAL_FAILURE_ON_ALL_THREADS( + GenerateFatalFailureInAnotherThread(true), "expected"); + CheckTestFailureCount(0); + // We need to add a failure, because main() checks that there are failures. + // But when only this test is run, we shouldn't have any failures. + ADD_FAILURE() << "This is an expected non-fatal failure."; +} + +TEST(NonFatalFailureTest, ExpectNonFatalFailureIgnoresFailuresInOtherThreads) { + // This statement should fail, since the current thread doesn't generate a + // fatal failure, only another one does. + EXPECT_NONFATAL_FAILURE(GenerateFatalFailureInAnotherThread(false), + "expected"); + CheckTestFailureCount(2); +} + +TEST(NonFatalFailureOnAllThreadsTest, ExpectNonFatalFailureOnAllThreads) { + // This statement should succeed, because failures in all threads are + // considered. + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS( + GenerateFatalFailureInAnotherThread(false), "expected"); + CheckTestFailureCount(0); + // We need to add a failure, because main() checks that there are failures, + // But when only this test is run, we shouldn't have any failures. + ADD_FAILURE() << "This is an expected non-fatal failure."; +} + +} // namespace +} // namespace testing + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + + const int result = RUN_ALL_TESTS(); // Expected to fail. + GTEST_CHECK_(result == 1) << "RUN_ALL_TESTS() did not fail as expected"; + + printf("\nPASS\n"); + return 0; +} + +#else +TEST(StressTest, + DISABLED_ThreadSafetyTestsAreSkippedWhenGoogleTestIsNotThreadSafe) { +} + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#endif // GTEST_IS_THREADSAFE diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_test_macro_stack_footprint_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_test_macro_stack_footprint_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..a48db05012cc30e0edf4a1354ff392c92d000bf0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_test_macro_stack_footprint_test.cc @@ -0,0 +1,89 @@ +// Copyright 2013, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Each TEST() expands to some static registration logic. GCC puts all +// such static initialization logic for a translation unit in a common, +// internal function. Since Google's build system restricts how much +// stack space a function can use, there's a limit on how many TEST()s +// one can put in a single C++ test file. This test ensures that a large +// number of TEST()s can be defined in the same translation unit. + +#include "gtest/gtest.h" + +// This macro defines 10 dummy tests. +#define TEN_TESTS_(test_case_name) \ + TEST(test_case_name, T0) {} \ + TEST(test_case_name, T1) {} \ + TEST(test_case_name, T2) {} \ + TEST(test_case_name, T3) {} \ + TEST(test_case_name, T4) {} \ + TEST(test_case_name, T5) {} \ + TEST(test_case_name, T6) {} \ + TEST(test_case_name, T7) {} \ + TEST(test_case_name, T8) {} \ + TEST(test_case_name, T9) {} + +// This macro defines 100 dummy tests. +#define HUNDRED_TESTS_(test_case_name_prefix) \ + TEN_TESTS_(test_case_name_prefix ## 0) \ + TEN_TESTS_(test_case_name_prefix ## 1) \ + TEN_TESTS_(test_case_name_prefix ## 2) \ + TEN_TESTS_(test_case_name_prefix ## 3) \ + TEN_TESTS_(test_case_name_prefix ## 4) \ + TEN_TESTS_(test_case_name_prefix ## 5) \ + TEN_TESTS_(test_case_name_prefix ## 6) \ + TEN_TESTS_(test_case_name_prefix ## 7) \ + TEN_TESTS_(test_case_name_prefix ## 8) \ + TEN_TESTS_(test_case_name_prefix ## 9) + +// This macro defines 1000 dummy tests. +#define THOUSAND_TESTS_(test_case_name_prefix) \ + HUNDRED_TESTS_(test_case_name_prefix ## 0) \ + HUNDRED_TESTS_(test_case_name_prefix ## 1) \ + HUNDRED_TESTS_(test_case_name_prefix ## 2) \ + HUNDRED_TESTS_(test_case_name_prefix ## 3) \ + HUNDRED_TESTS_(test_case_name_prefix ## 4) \ + HUNDRED_TESTS_(test_case_name_prefix ## 5) \ + HUNDRED_TESTS_(test_case_name_prefix ## 6) \ + HUNDRED_TESTS_(test_case_name_prefix ## 7) \ + HUNDRED_TESTS_(test_case_name_prefix ## 8) \ + HUNDRED_TESTS_(test_case_name_prefix ## 9) + +// Ensures that we can define 1000 TEST()s in the same translation +// unit. +THOUSAND_TESTS_(T) + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + + // We don't actually need to run the dummy tests - the purpose is to + // ensure that they compile. + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_test_utils.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_test_utils.py new file mode 100755 index 0000000000000000000000000000000000000000..ef9363c3694539833826ecf670cdcd159a28a585 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_test_utils.py @@ -0,0 +1,314 @@ +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test utilities for Google C++ Testing and Mocking Framework.""" +# Suppresses the 'Import not at the top of the file' lint complaint. +# pylint: disable-msg=C6204 + +import os +import sys + +IS_WINDOWS = os.name == 'nt' +IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0] +IS_OS2 = os.name == 'os2' + +import atexit +import shutil +import tempfile +import unittest as _test_module + +try: + import subprocess + _SUBPROCESS_MODULE_AVAILABLE = True +except: + import popen2 + _SUBPROCESS_MODULE_AVAILABLE = False +# pylint: enable-msg=C6204 + +GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT' + +# The environment variable for specifying the path to the premature-exit file. +PREMATURE_EXIT_FILE_ENV_VAR = 'TEST_PREMATURE_EXIT_FILE' + +environ = os.environ.copy() + + +def SetEnvVar(env_var, value): + """Sets/unsets an environment variable to a given value.""" + + if value is not None: + environ[env_var] = value + elif env_var in environ: + del environ[env_var] + + +# Here we expose a class from a particular module, depending on the +# environment. The comment suppresses the 'Invalid variable name' lint +# complaint. +TestCase = _test_module.TestCase # pylint: disable=C6409 + +# Initially maps a flag to its default value. After +# _ParseAndStripGTestFlags() is called, maps a flag to its actual value. +_flag_map = {'source_dir': os.path.dirname(sys.argv[0]), + 'build_dir': os.path.dirname(sys.argv[0])} +_gtest_flags_are_parsed = False + + +def _ParseAndStripGTestFlags(argv): + """Parses and strips Google Test flags from argv. This is idempotent.""" + + # Suppresses the lint complaint about a global variable since we need it + # here to maintain module-wide state. + global _gtest_flags_are_parsed # pylint: disable=W0603 + if _gtest_flags_are_parsed: + return + + _gtest_flags_are_parsed = True + for flag in _flag_map: + # The environment variable overrides the default value. + if flag.upper() in os.environ: + _flag_map[flag] = os.environ[flag.upper()] + + # The command line flag overrides the environment variable. + i = 1 # Skips the program name. + while i < len(argv): + prefix = '--' + flag + '=' + if argv[i].startswith(prefix): + _flag_map[flag] = argv[i][len(prefix):] + del argv[i] + break + else: + # We don't increment i in case we just found a --gtest_* flag + # and removed it from argv. + i += 1 + + +def GetFlag(flag): + """Returns the value of the given flag.""" + + # In case GetFlag() is called before Main(), we always call + # _ParseAndStripGTestFlags() here to make sure the --gtest_* flags + # are parsed. + _ParseAndStripGTestFlags(sys.argv) + + return _flag_map[flag] + + +def GetSourceDir(): + """Returns the absolute path of the directory where the .py files are.""" + + return os.path.abspath(GetFlag('source_dir')) + + +def GetBuildDir(): + """Returns the absolute path of the directory where the test binaries are.""" + + return os.path.abspath(GetFlag('build_dir')) + + +_temp_dir = None + +def _RemoveTempDir(): + if _temp_dir: + shutil.rmtree(_temp_dir, ignore_errors=True) + +atexit.register(_RemoveTempDir) + + +def GetTempDir(): + global _temp_dir + if not _temp_dir: + _temp_dir = tempfile.mkdtemp() + return _temp_dir + + +def GetTestExecutablePath(executable_name, build_dir=None): + """Returns the absolute path of the test binary given its name. + + The function will print a message and abort the program if the resulting file + doesn't exist. + + Args: + executable_name: name of the test binary that the test script runs. + build_dir: directory where to look for executables, by default + the result of GetBuildDir(). + + Returns: + The absolute path of the test binary. + """ + + path = os.path.abspath(os.path.join(build_dir or GetBuildDir(), + executable_name)) + if (IS_WINDOWS or IS_CYGWIN or IS_OS2) and not path.endswith('.exe'): + path += '.exe' + + if not os.path.exists(path): + message = ( + 'Unable to find the test binary "%s". Please make sure to provide\n' + 'a path to the binary via the --build_dir flag or the BUILD_DIR\n' + 'environment variable.' % path) + print >> sys.stderr, message + sys.exit(1) + + return path + + +def GetExitStatus(exit_code): + """Returns the argument to exit(), or -1 if exit() wasn't called. + + Args: + exit_code: the result value of os.system(command). + """ + + if os.name == 'nt': + # On Windows, os.WEXITSTATUS() doesn't work and os.system() returns + # the argument to exit() directly. + return exit_code + else: + # On Unix, os.WEXITSTATUS() must be used to extract the exit status + # from the result of os.system(). + if os.WIFEXITED(exit_code): + return os.WEXITSTATUS(exit_code) + else: + return -1 + + +class Subprocess: + def __init__(self, command, working_dir=None, capture_stderr=True, env=None): + """Changes into a specified directory, if provided, and executes a command. + + Restores the old directory afterwards. + + Args: + command: The command to run, in the form of sys.argv. + working_dir: The directory to change into. + capture_stderr: Determines whether to capture stderr in the output member + or to discard it. + env: Dictionary with environment to pass to the subprocess. + + Returns: + An object that represents outcome of the executed process. It has the + following attributes: + terminated_by_signal True if and only if the child process has been + terminated by a signal. + signal Sygnal that terminated the child process. + exited True if and only if the child process exited + normally. + exit_code The code with which the child process exited. + output Child process's stdout and stderr output + combined in a string. + """ + + # The subprocess module is the preferrable way of running programs + # since it is available and behaves consistently on all platforms, + # including Windows. But it is only available starting in python 2.4. + # In earlier python versions, we revert to the popen2 module, which is + # available in python 2.0 and later but doesn't provide required + # functionality (Popen4) under Windows. This allows us to support Mac + # OS X 10.4 Tiger, which has python 2.3 installed. + if _SUBPROCESS_MODULE_AVAILABLE: + if capture_stderr: + stderr = subprocess.STDOUT + else: + stderr = subprocess.PIPE + + p = subprocess.Popen(command, + stdout=subprocess.PIPE, stderr=stderr, + cwd=working_dir, universal_newlines=True, env=env) + # communicate returns a tuple with the file object for the child's + # output. + self.output = p.communicate()[0] + self._return_code = p.returncode + else: + old_dir = os.getcwd() + + def _ReplaceEnvDict(dest, src): + # Changes made by os.environ.clear are not inheritable by child + # processes until Python 2.6. To produce inheritable changes we have + # to delete environment items with the del statement. + for key in dest.keys(): + del dest[key] + dest.update(src) + + # When 'env' is not None, backup the environment variables and replace + # them with the passed 'env'. When 'env' is None, we simply use the + # current 'os.environ' for compatibility with the subprocess.Popen + # semantics used above. + if env is not None: + old_environ = os.environ.copy() + _ReplaceEnvDict(os.environ, env) + + try: + if working_dir is not None: + os.chdir(working_dir) + if capture_stderr: + p = popen2.Popen4(command) + else: + p = popen2.Popen3(command) + p.tochild.close() + self.output = p.fromchild.read() + ret_code = p.wait() + finally: + os.chdir(old_dir) + + # Restore the old environment variables + # if they were replaced. + if env is not None: + _ReplaceEnvDict(os.environ, old_environ) + + # Converts ret_code to match the semantics of + # subprocess.Popen.returncode. + if os.WIFSIGNALED(ret_code): + self._return_code = -os.WTERMSIG(ret_code) + else: # os.WIFEXITED(ret_code) should return True here. + self._return_code = os.WEXITSTATUS(ret_code) + + if self._return_code < 0: + self.terminated_by_signal = True + self.exited = False + self.signal = -self._return_code + else: + self.terminated_by_signal = False + self.exited = True + self.exit_code = self._return_code + + +def Main(): + """Runs the unit test.""" + + # We must call _ParseAndStripGTestFlags() before calling + # unittest.main(). Otherwise the latter will be confused by the + # --gtest_* flags. + _ParseAndStripGTestFlags(sys.argv) + # The tested binaries should not be writing XML output files unless the + # script explicitly instructs them to. + if GTEST_OUTPUT_VAR_NAME in os.environ: + del os.environ[GTEST_OUTPUT_VAR_NAME] + + _test_module.main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_testbridge_test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_testbridge_test.py new file mode 100755 index 0000000000000000000000000000000000000000..87ffad73d40065298f30500de824d808b6571d8d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_testbridge_test.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# +# Copyright 2018 Google LLC. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +"""Verifies that Google Test uses filter provided via testbridge.""" + +import os + +import gtest_test_utils + +binary_name = 'gtest_testbridge_test_' +COMMAND = gtest_test_utils.GetTestExecutablePath(binary_name) +TESTBRIDGE_NAME = 'TESTBRIDGE_TEST_ONLY' + + +def Assert(condition): + if not condition: + raise AssertionError + + +class GTestTestFilterTest(gtest_test_utils.TestCase): + + def testTestExecutionIsFiltered(self): + """Tests that the test filter is picked up from the testbridge env var.""" + subprocess_env = os.environ.copy() + + subprocess_env[TESTBRIDGE_NAME] = '*.TestThatSucceeds' + p = gtest_test_utils.Subprocess(COMMAND, env=subprocess_env) + + self.assertEquals(0, p.exit_code) + + Assert('filter = *.TestThatSucceeds' in p.output) + Assert('[ OK ] TestFilterTest.TestThatSucceeds' in p.output) + Assert('[ PASSED ] 1 test.' in p.output) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_testbridge_test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_testbridge_test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..24617b209e10a9d1798368e26465aaa62715f0ee --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_testbridge_test_.cc @@ -0,0 +1,43 @@ +// Copyright 2018, Google LLC. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// This program is meant to be run by gtest_test_filter_test.py. Do not run +// it directly. + +#include "gtest/gtest.h" + +// These tests are used to detect if filtering is working. Only +// 'TestThatSucceeds' should ever run. + +TEST(TestFilterTest, TestThatSucceeds) {} + +TEST(TestFilterTest, TestThatFails) { + ASSERT_TRUE(false) << "This test should never be run."; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_throw_on_failure_ex_test.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_throw_on_failure_ex_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..1d95adbf537ba9178163987c0d3e0c8aa03ab5ee --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_throw_on_failure_ex_test.cc @@ -0,0 +1,90 @@ +// Copyright 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Tests Google Test's throw-on-failure mode with exceptions enabled. + +#include "gtest/gtest.h" + +#include +#include +#include +#include + +// Prints the given failure message and exits the program with +// non-zero. We use this instead of a Google Test assertion to +// indicate a failure, as the latter is been tested and cannot be +// relied on. +void Fail(const char* msg) { + printf("FAILURE: %s\n", msg); + fflush(stdout); + exit(1); +} + +// Tests that an assertion failure throws a subclass of +// std::runtime_error. +void TestFailureThrowsRuntimeError() { + testing::GTEST_FLAG(throw_on_failure) = true; + + // A successful assertion shouldn't throw. + try { + EXPECT_EQ(3, 3); + } catch(...) { + Fail("A successful assertion wrongfully threw."); + } + + // A failed assertion should throw a subclass of std::runtime_error. + try { + EXPECT_EQ(2, 3) << "Expected failure"; + } catch(const std::runtime_error& e) { + if (strstr(e.what(), "Expected failure") != nullptr) return; + + printf("%s", + "A failed assertion did throw an exception of the right type, " + "but the message is incorrect. Instead of containing \"Expected " + "failure\", it is:\n"); + Fail(e.what()); + } catch(...) { + Fail("A failed assertion threw the wrong type of exception."); + } + Fail("A failed assertion should've thrown but didn't."); +} + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + + // We want to ensure that people can use Google Test assertions in + // other testing frameworks, as long as they initialize Google Test + // properly and set the thrown-on-failure mode. Therefore, we don't + // use Google Test's constructs for defining and running tests + // (e.g. TEST and RUN_ALL_TESTS) here. + + TestFailureThrowsRuntimeError(); + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_unittest.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..39749b7b19f86203f21726a6419a2f7a3d149dbb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_unittest.cc @@ -0,0 +1,7488 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Tests for Google Test itself. This verifies that the basic constructs of +// Google Test work. + +#include "gtest/gtest.h" + +// Verifies that the command line flag variables can be accessed in +// code once "gtest.h" has been #included. +// Do not move it after other gtest #includes. +TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) { + bool dummy = testing::GTEST_FLAG(also_run_disabled_tests) + || testing::GTEST_FLAG(break_on_failure) + || testing::GTEST_FLAG(catch_exceptions) + || testing::GTEST_FLAG(color) != "unknown" + || testing::GTEST_FLAG(filter) != "unknown" + || testing::GTEST_FLAG(list_tests) + || testing::GTEST_FLAG(output) != "unknown" + || testing::GTEST_FLAG(print_time) + || testing::GTEST_FLAG(random_seed) + || testing::GTEST_FLAG(repeat) > 0 + || testing::GTEST_FLAG(show_internal_stack_frames) + || testing::GTEST_FLAG(shuffle) + || testing::GTEST_FLAG(stack_trace_depth) > 0 + || testing::GTEST_FLAG(stream_result_to) != "unknown" + || testing::GTEST_FLAG(throw_on_failure); + EXPECT_TRUE(dummy || !dummy); // Suppresses warning that dummy is unused. +} + +#include // For INT_MAX. +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "gtest/gtest-spi.h" +#include "src/gtest-internal-inl.h" + +namespace testing { +namespace internal { + +#if GTEST_CAN_STREAM_RESULTS_ + +class StreamingListenerTest : public Test { + public: + class FakeSocketWriter : public StreamingListener::AbstractSocketWriter { + public: + // Sends a string to the socket. + void Send(const std::string& message) override { output_ += message; } + + std::string output_; + }; + + StreamingListenerTest() + : fake_sock_writer_(new FakeSocketWriter), + streamer_(fake_sock_writer_), + test_info_obj_("FooTest", "Bar", nullptr, nullptr, + CodeLocation(__FILE__, __LINE__), nullptr, nullptr) {} + + protected: + std::string* output() { return &(fake_sock_writer_->output_); } + + FakeSocketWriter* const fake_sock_writer_; + StreamingListener streamer_; + UnitTest unit_test_; + TestInfo test_info_obj_; // The name test_info_ was taken by testing::Test. +}; + +TEST_F(StreamingListenerTest, OnTestProgramEnd) { + *output() = ""; + streamer_.OnTestProgramEnd(unit_test_); + EXPECT_EQ("event=TestProgramEnd&passed=1\n", *output()); +} + +TEST_F(StreamingListenerTest, OnTestIterationEnd) { + *output() = ""; + streamer_.OnTestIterationEnd(unit_test_, 42); + EXPECT_EQ("event=TestIterationEnd&passed=1&elapsed_time=0ms\n", *output()); +} + +TEST_F(StreamingListenerTest, OnTestCaseStart) { + *output() = ""; + streamer_.OnTestCaseStart(TestCase("FooTest", "Bar", nullptr, nullptr)); + EXPECT_EQ("event=TestCaseStart&name=FooTest\n", *output()); +} + +TEST_F(StreamingListenerTest, OnTestCaseEnd) { + *output() = ""; + streamer_.OnTestCaseEnd(TestCase("FooTest", "Bar", nullptr, nullptr)); + EXPECT_EQ("event=TestCaseEnd&passed=1&elapsed_time=0ms\n", *output()); +} + +TEST_F(StreamingListenerTest, OnTestStart) { + *output() = ""; + streamer_.OnTestStart(test_info_obj_); + EXPECT_EQ("event=TestStart&name=Bar\n", *output()); +} + +TEST_F(StreamingListenerTest, OnTestEnd) { + *output() = ""; + streamer_.OnTestEnd(test_info_obj_); + EXPECT_EQ("event=TestEnd&passed=1&elapsed_time=0ms\n", *output()); +} + +TEST_F(StreamingListenerTest, OnTestPartResult) { + *output() = ""; + streamer_.OnTestPartResult(TestPartResult( + TestPartResult::kFatalFailure, "foo.cc", 42, "failed=\n&%")); + + // Meta characters in the failure message should be properly escaped. + EXPECT_EQ( + "event=TestPartResult&file=foo.cc&line=42&message=failed%3D%0A%26%25\n", + *output()); +} + +#endif // GTEST_CAN_STREAM_RESULTS_ + +// Provides access to otherwise private parts of the TestEventListeners class +// that are needed to test it. +class TestEventListenersAccessor { + public: + static TestEventListener* GetRepeater(TestEventListeners* listeners) { + return listeners->repeater(); + } + + static void SetDefaultResultPrinter(TestEventListeners* listeners, + TestEventListener* listener) { + listeners->SetDefaultResultPrinter(listener); + } + static void SetDefaultXmlGenerator(TestEventListeners* listeners, + TestEventListener* listener) { + listeners->SetDefaultXmlGenerator(listener); + } + + static bool EventForwardingEnabled(const TestEventListeners& listeners) { + return listeners.EventForwardingEnabled(); + } + + static void SuppressEventForwarding(TestEventListeners* listeners) { + listeners->SuppressEventForwarding(); + } +}; + +class UnitTestRecordPropertyTestHelper : public Test { + protected: + UnitTestRecordPropertyTestHelper() {} + + // Forwards to UnitTest::RecordProperty() to bypass access controls. + void UnitTestRecordProperty(const char* key, const std::string& value) { + unit_test_.RecordProperty(key, value); + } + + UnitTest unit_test_; +}; + +} // namespace internal +} // namespace testing + +using testing::AssertionFailure; +using testing::AssertionResult; +using testing::AssertionSuccess; +using testing::DoubleLE; +using testing::EmptyTestEventListener; +using testing::Environment; +using testing::FloatLE; +using testing::GTEST_FLAG(also_run_disabled_tests); +using testing::GTEST_FLAG(break_on_failure); +using testing::GTEST_FLAG(catch_exceptions); +using testing::GTEST_FLAG(color); +using testing::GTEST_FLAG(death_test_use_fork); +using testing::GTEST_FLAG(filter); +using testing::GTEST_FLAG(list_tests); +using testing::GTEST_FLAG(output); +using testing::GTEST_FLAG(print_time); +using testing::GTEST_FLAG(random_seed); +using testing::GTEST_FLAG(repeat); +using testing::GTEST_FLAG(show_internal_stack_frames); +using testing::GTEST_FLAG(shuffle); +using testing::GTEST_FLAG(stack_trace_depth); +using testing::GTEST_FLAG(stream_result_to); +using testing::GTEST_FLAG(throw_on_failure); +using testing::IsNotSubstring; +using testing::IsSubstring; +using testing::Message; +using testing::ScopedFakeTestPartResultReporter; +using testing::StaticAssertTypeEq; +using testing::Test; +using testing::TestCase; +using testing::TestEventListeners; +using testing::TestInfo; +using testing::TestPartResult; +using testing::TestPartResultArray; +using testing::TestProperty; +using testing::TestResult; +using testing::TimeInMillis; +using testing::UnitTest; +using testing::internal::AlwaysFalse; +using testing::internal::AlwaysTrue; +using testing::internal::AppendUserMessage; +using testing::internal::ArrayAwareFind; +using testing::internal::ArrayEq; +using testing::internal::CodePointToUtf8; +using testing::internal::CopyArray; +using testing::internal::CountIf; +using testing::internal::EqFailure; +using testing::internal::FloatingPoint; +using testing::internal::ForEach; +using testing::internal::FormatEpochTimeInMillisAsIso8601; +using testing::internal::FormatTimeInMillisAsSeconds; +using testing::internal::GTestFlagSaver; +using testing::internal::GetCurrentOsStackTraceExceptTop; +using testing::internal::GetElementOr; +using testing::internal::GetNextRandomSeed; +using testing::internal::GetRandomSeedFromFlag; +using testing::internal::GetTestTypeId; +using testing::internal::GetTimeInMillis; +using testing::internal::GetTypeId; +using testing::internal::GetUnitTestImpl; +using testing::internal::Int32; +using testing::internal::Int32FromEnvOrDie; +using testing::internal::IsAProtocolMessage; +using testing::internal::IsContainer; +using testing::internal::IsContainerTest; +using testing::internal::IsNotContainer; +using testing::internal::NativeArray; +using testing::internal::OsStackTraceGetter; +using testing::internal::OsStackTraceGetterInterface; +using testing::internal::ParseInt32Flag; +using testing::internal::RelationToSourceCopy; +using testing::internal::RelationToSourceReference; +using testing::internal::ShouldRunTestOnShard; +using testing::internal::ShouldShard; +using testing::internal::ShouldUseColor; +using testing::internal::Shuffle; +using testing::internal::ShuffleRange; +using testing::internal::SkipPrefix; +using testing::internal::StreamableToString; +using testing::internal::String; +using testing::internal::TestEventListenersAccessor; +using testing::internal::TestResultAccessor; +using testing::internal::UInt32; +using testing::internal::UnitTestImpl; +using testing::internal::WideStringToUtf8; +using testing::internal::edit_distance::CalculateOptimalEdits; +using testing::internal::edit_distance::CreateUnifiedDiff; +using testing::internal::edit_distance::EditType; +using testing::internal::kMaxRandomSeed; +using testing::internal::kTestTypeIdInGoogleTest; +using testing::kMaxStackTraceDepth; + +#if GTEST_HAS_STREAM_REDIRECTION +using testing::internal::CaptureStdout; +using testing::internal::GetCapturedStdout; +#endif + +#if GTEST_IS_THREADSAFE +using testing::internal::ThreadWithParam; +#endif + +class TestingVector : public std::vector { +}; + +::std::ostream& operator<<(::std::ostream& os, + const TestingVector& vector) { + os << "{ "; + for (size_t i = 0; i < vector.size(); i++) { + os << vector[i] << " "; + } + os << "}"; + return os; +} + +// This line tests that we can define tests in an unnamed namespace. +namespace { + +TEST(GetRandomSeedFromFlagTest, HandlesZero) { + const int seed = GetRandomSeedFromFlag(0); + EXPECT_LE(1, seed); + EXPECT_LE(seed, static_cast(kMaxRandomSeed)); +} + +TEST(GetRandomSeedFromFlagTest, PreservesValidSeed) { + EXPECT_EQ(1, GetRandomSeedFromFlag(1)); + EXPECT_EQ(2, GetRandomSeedFromFlag(2)); + EXPECT_EQ(kMaxRandomSeed - 1, GetRandomSeedFromFlag(kMaxRandomSeed - 1)); + EXPECT_EQ(static_cast(kMaxRandomSeed), + GetRandomSeedFromFlag(kMaxRandomSeed)); +} + +TEST(GetRandomSeedFromFlagTest, NormalizesInvalidSeed) { + const int seed1 = GetRandomSeedFromFlag(-1); + EXPECT_LE(1, seed1); + EXPECT_LE(seed1, static_cast(kMaxRandomSeed)); + + const int seed2 = GetRandomSeedFromFlag(kMaxRandomSeed + 1); + EXPECT_LE(1, seed2); + EXPECT_LE(seed2, static_cast(kMaxRandomSeed)); +} + +TEST(GetNextRandomSeedTest, WorksForValidInput) { + EXPECT_EQ(2, GetNextRandomSeed(1)); + EXPECT_EQ(3, GetNextRandomSeed(2)); + EXPECT_EQ(static_cast(kMaxRandomSeed), + GetNextRandomSeed(kMaxRandomSeed - 1)); + EXPECT_EQ(1, GetNextRandomSeed(kMaxRandomSeed)); + + // We deliberately don't test GetNextRandomSeed() with invalid + // inputs, as that requires death tests, which are expensive. This + // is fine as GetNextRandomSeed() is internal and has a + // straightforward definition. +} + +static void ClearCurrentTestPartResults() { + TestResultAccessor::ClearTestPartResults( + GetUnitTestImpl()->current_test_result()); +} + +// Tests GetTypeId. + +TEST(GetTypeIdTest, ReturnsSameValueForSameType) { + EXPECT_EQ(GetTypeId(), GetTypeId()); + EXPECT_EQ(GetTypeId(), GetTypeId()); +} + +class SubClassOfTest : public Test {}; +class AnotherSubClassOfTest : public Test {}; + +TEST(GetTypeIdTest, ReturnsDifferentValuesForDifferentTypes) { + EXPECT_NE(GetTypeId(), GetTypeId()); + EXPECT_NE(GetTypeId(), GetTypeId()); + EXPECT_NE(GetTypeId(), GetTestTypeId()); + EXPECT_NE(GetTypeId(), GetTestTypeId()); + EXPECT_NE(GetTypeId(), GetTestTypeId()); + EXPECT_NE(GetTypeId(), GetTypeId()); +} + +// Verifies that GetTestTypeId() returns the same value, no matter it +// is called from inside Google Test or outside of it. +TEST(GetTestTypeIdTest, ReturnsTheSameValueInsideOrOutsideOfGoogleTest) { + EXPECT_EQ(kTestTypeIdInGoogleTest, GetTestTypeId()); +} + +// Tests CanonicalizeForStdLibVersioning. + +using ::testing::internal::CanonicalizeForStdLibVersioning; + +TEST(CanonicalizeForStdLibVersioning, LeavesUnversionedNamesUnchanged) { + EXPECT_EQ("std::bind", CanonicalizeForStdLibVersioning("std::bind")); + EXPECT_EQ("std::_", CanonicalizeForStdLibVersioning("std::_")); + EXPECT_EQ("std::__foo", CanonicalizeForStdLibVersioning("std::__foo")); + EXPECT_EQ("gtl::__1::x", CanonicalizeForStdLibVersioning("gtl::__1::x")); + EXPECT_EQ("__1::x", CanonicalizeForStdLibVersioning("__1::x")); + EXPECT_EQ("::__1::x", CanonicalizeForStdLibVersioning("::__1::x")); +} + +TEST(CanonicalizeForStdLibVersioning, ElidesDoubleUnderNames) { + EXPECT_EQ("std::bind", CanonicalizeForStdLibVersioning("std::__1::bind")); + EXPECT_EQ("std::_", CanonicalizeForStdLibVersioning("std::__1::_")); + + EXPECT_EQ("std::bind", CanonicalizeForStdLibVersioning("std::__g::bind")); + EXPECT_EQ("std::_", CanonicalizeForStdLibVersioning("std::__g::_")); + + EXPECT_EQ("std::bind", + CanonicalizeForStdLibVersioning("std::__google::bind")); + EXPECT_EQ("std::_", CanonicalizeForStdLibVersioning("std::__google::_")); +} + +// Tests FormatTimeInMillisAsSeconds(). + +TEST(FormatTimeInMillisAsSecondsTest, FormatsZero) { + EXPECT_EQ("0", FormatTimeInMillisAsSeconds(0)); +} + +TEST(FormatTimeInMillisAsSecondsTest, FormatsPositiveNumber) { + EXPECT_EQ("0.003", FormatTimeInMillisAsSeconds(3)); + EXPECT_EQ("0.01", FormatTimeInMillisAsSeconds(10)); + EXPECT_EQ("0.2", FormatTimeInMillisAsSeconds(200)); + EXPECT_EQ("1.2", FormatTimeInMillisAsSeconds(1200)); + EXPECT_EQ("3", FormatTimeInMillisAsSeconds(3000)); +} + +TEST(FormatTimeInMillisAsSecondsTest, FormatsNegativeNumber) { + EXPECT_EQ("-0.003", FormatTimeInMillisAsSeconds(-3)); + EXPECT_EQ("-0.01", FormatTimeInMillisAsSeconds(-10)); + EXPECT_EQ("-0.2", FormatTimeInMillisAsSeconds(-200)); + EXPECT_EQ("-1.2", FormatTimeInMillisAsSeconds(-1200)); + EXPECT_EQ("-3", FormatTimeInMillisAsSeconds(-3000)); +} + +// Tests FormatEpochTimeInMillisAsIso8601(). The correctness of conversion +// for particular dates below was verified in Python using +// datetime.datetime.fromutctimestamp(/1000). + +// FormatEpochTimeInMillisAsIso8601 depends on the current timezone, so we +// have to set up a particular timezone to obtain predictable results. +class FormatEpochTimeInMillisAsIso8601Test : public Test { + public: + // On Cygwin, GCC doesn't allow unqualified integer literals to exceed + // 32 bits, even when 64-bit integer types are available. We have to + // force the constants to have a 64-bit type here. + static const TimeInMillis kMillisPerSec = 1000; + + private: + void SetUp() override { + saved_tz_ = nullptr; + + GTEST_DISABLE_MSC_DEPRECATED_PUSH_(/* getenv, strdup: deprecated */) + if (getenv("TZ")) + saved_tz_ = strdup(getenv("TZ")); + GTEST_DISABLE_MSC_DEPRECATED_POP_() + + // Set up the time zone for FormatEpochTimeInMillisAsIso8601 to use. We + // cannot use the local time zone because the function's output depends + // on the time zone. + SetTimeZone("UTC+00"); + } + + void TearDown() override { + SetTimeZone(saved_tz_); + free(const_cast(saved_tz_)); + saved_tz_ = nullptr; + } + + static void SetTimeZone(const char* time_zone) { + // tzset() distinguishes between the TZ variable being present and empty + // and not being present, so we have to consider the case of time_zone + // being NULL. +#if _MSC_VER || GTEST_OS_WINDOWS_MINGW + // ...Unless it's MSVC, whose standard library's _putenv doesn't + // distinguish between an empty and a missing variable. + const std::string env_var = + std::string("TZ=") + (time_zone ? time_zone : ""); + _putenv(env_var.c_str()); + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */) + tzset(); + GTEST_DISABLE_MSC_WARNINGS_POP_() +#else + if (time_zone) { + setenv(("TZ"), time_zone, 1); + } else { + unsetenv("TZ"); + } + tzset(); +#endif + } + + const char* saved_tz_; +}; + +const TimeInMillis FormatEpochTimeInMillisAsIso8601Test::kMillisPerSec; + +TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsTwoDigitSegments) { + EXPECT_EQ("2011-10-31T18:52:42", + FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec)); +} + +TEST_F(FormatEpochTimeInMillisAsIso8601Test, MillisecondsDoNotAffectResult) { + EXPECT_EQ( + "2011-10-31T18:52:42", + FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec + 234)); +} + +TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsLeadingZeroes) { + EXPECT_EQ("2011-09-03T05:07:02", + FormatEpochTimeInMillisAsIso8601(1315026422 * kMillisPerSec)); +} + +TEST_F(FormatEpochTimeInMillisAsIso8601Test, Prints24HourTime) { + EXPECT_EQ("2011-09-28T17:08:22", + FormatEpochTimeInMillisAsIso8601(1317229702 * kMillisPerSec)); +} + +TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsEpochStart) { + EXPECT_EQ("1970-01-01T00:00:00", FormatEpochTimeInMillisAsIso8601(0)); +} + +# ifdef __BORLANDC__ +// Silences warnings: "Condition is always true", "Unreachable code" +# pragma option push -w-ccc -w-rch +# endif + +// Tests that the LHS of EXPECT_EQ or ASSERT_EQ can be used as a null literal +// when the RHS is a pointer type. +TEST(NullLiteralTest, LHSAllowsNullLiterals) { + EXPECT_EQ(0, static_cast(nullptr)); // NOLINT + ASSERT_EQ(0, static_cast(nullptr)); // NOLINT + EXPECT_EQ(NULL, static_cast(nullptr)); // NOLINT + ASSERT_EQ(NULL, static_cast(nullptr)); // NOLINT + EXPECT_EQ(nullptr, static_cast(nullptr)); + ASSERT_EQ(nullptr, static_cast(nullptr)); + + const int* const p = nullptr; + EXPECT_EQ(0, p); // NOLINT + ASSERT_EQ(0, p); // NOLINT + EXPECT_EQ(NULL, p); // NOLINT + ASSERT_EQ(NULL, p); // NOLINT + EXPECT_EQ(nullptr, p); + ASSERT_EQ(nullptr, p); +} + +struct ConvertToAll { + template + operator T() const { // NOLINT + return T(); + } +}; + +struct ConvertToPointer { + template + operator T*() const { // NOLINT + return nullptr; + } +}; + +struct ConvertToAllButNoPointers { + template ::value, int>::type = 0> + operator T() const { // NOLINT + return T(); + } +}; + +struct MyType {}; +inline bool operator==(MyType const&, MyType const&) { return true; } + +TEST(NullLiteralTest, ImplicitConversion) { + EXPECT_EQ(ConvertToPointer{}, static_cast(nullptr)); +#if !defined(__GNUC__) || defined(__clang__) + // Disabled due to GCC bug gcc.gnu.org/PR89580 + EXPECT_EQ(ConvertToAll{}, static_cast(nullptr)); +#endif + EXPECT_EQ(ConvertToAll{}, MyType{}); + EXPECT_EQ(ConvertToAllButNoPointers{}, MyType{}); +} + +#ifdef __clang__ +#pragma clang diagnostic push +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic error "-Wzero-as-null-pointer-constant" +#endif +#endif + +TEST(NullLiteralTest, NoConversionNoWarning) { + // Test that gtests detection and handling of null pointer constants + // doesn't trigger a warning when '0' isn't actually used as null. + EXPECT_EQ(0, 0); + ASSERT_EQ(0, 0); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +# ifdef __BORLANDC__ +// Restores warnings after previous "#pragma option push" suppressed them. +# pragma option pop +# endif + +// +// Tests CodePointToUtf8(). + +// Tests that the NUL character L'\0' is encoded correctly. +TEST(CodePointToUtf8Test, CanEncodeNul) { + EXPECT_EQ("", CodePointToUtf8(L'\0')); +} + +// Tests that ASCII characters are encoded correctly. +TEST(CodePointToUtf8Test, CanEncodeAscii) { + EXPECT_EQ("a", CodePointToUtf8(L'a')); + EXPECT_EQ("Z", CodePointToUtf8(L'Z')); + EXPECT_EQ("&", CodePointToUtf8(L'&')); + EXPECT_EQ("\x7F", CodePointToUtf8(L'\x7F')); +} + +// Tests that Unicode code-points that have 8 to 11 bits are encoded +// as 110xxxxx 10xxxxxx. +TEST(CodePointToUtf8Test, CanEncode8To11Bits) { + // 000 1101 0011 => 110-00011 10-010011 + EXPECT_EQ("\xC3\x93", CodePointToUtf8(L'\xD3')); + + // 101 0111 0110 => 110-10101 10-110110 + // Some compilers (e.g., GCC on MinGW) cannot handle non-ASCII codepoints + // in wide strings and wide chars. In order to accommodate them, we have to + // introduce such character constants as integers. + EXPECT_EQ("\xD5\xB6", + CodePointToUtf8(static_cast(0x576))); +} + +// Tests that Unicode code-points that have 12 to 16 bits are encoded +// as 1110xxxx 10xxxxxx 10xxxxxx. +TEST(CodePointToUtf8Test, CanEncode12To16Bits) { + // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011 + EXPECT_EQ("\xE0\xA3\x93", + CodePointToUtf8(static_cast(0x8D3))); + + // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101 + EXPECT_EQ("\xEC\x9D\x8D", + CodePointToUtf8(static_cast(0xC74D))); +} + +#if !GTEST_WIDE_STRING_USES_UTF16_ +// Tests in this group require a wchar_t to hold > 16 bits, and thus +// are skipped on Windows, and Cygwin, where a wchar_t is +// 16-bit wide. This code may not compile on those systems. + +// Tests that Unicode code-points that have 17 to 21 bits are encoded +// as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx. +TEST(CodePointToUtf8Test, CanEncode17To21Bits) { + // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011 + EXPECT_EQ("\xF0\x90\xA3\x93", CodePointToUtf8(L'\x108D3')); + + // 0 0001 0000 0100 0000 0000 => 11110-000 10-010000 10-010000 10-000000 + EXPECT_EQ("\xF0\x90\x90\x80", CodePointToUtf8(L'\x10400')); + + // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100 + EXPECT_EQ("\xF4\x88\x98\xB4", CodePointToUtf8(L'\x108634')); +} + +// Tests that encoding an invalid code-point generates the expected result. +TEST(CodePointToUtf8Test, CanEncodeInvalidCodePoint) { + EXPECT_EQ("(Invalid Unicode 0x1234ABCD)", CodePointToUtf8(L'\x1234ABCD')); +} + +#endif // !GTEST_WIDE_STRING_USES_UTF16_ + +// Tests WideStringToUtf8(). + +// Tests that the NUL character L'\0' is encoded correctly. +TEST(WideStringToUtf8Test, CanEncodeNul) { + EXPECT_STREQ("", WideStringToUtf8(L"", 0).c_str()); + EXPECT_STREQ("", WideStringToUtf8(L"", -1).c_str()); +} + +// Tests that ASCII strings are encoded correctly. +TEST(WideStringToUtf8Test, CanEncodeAscii) { + EXPECT_STREQ("a", WideStringToUtf8(L"a", 1).c_str()); + EXPECT_STREQ("ab", WideStringToUtf8(L"ab", 2).c_str()); + EXPECT_STREQ("a", WideStringToUtf8(L"a", -1).c_str()); + EXPECT_STREQ("ab", WideStringToUtf8(L"ab", -1).c_str()); +} + +// Tests that Unicode code-points that have 8 to 11 bits are encoded +// as 110xxxxx 10xxxxxx. +TEST(WideStringToUtf8Test, CanEncode8To11Bits) { + // 000 1101 0011 => 110-00011 10-010011 + EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", 1).c_str()); + EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", -1).c_str()); + + // 101 0111 0110 => 110-10101 10-110110 + const wchar_t s[] = { 0x576, '\0' }; + EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(s, 1).c_str()); + EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(s, -1).c_str()); +} + +// Tests that Unicode code-points that have 12 to 16 bits are encoded +// as 1110xxxx 10xxxxxx 10xxxxxx. +TEST(WideStringToUtf8Test, CanEncode12To16Bits) { + // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011 + const wchar_t s1[] = { 0x8D3, '\0' }; + EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(s1, 1).c_str()); + EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(s1, -1).c_str()); + + // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101 + const wchar_t s2[] = { 0xC74D, '\0' }; + EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(s2, 1).c_str()); + EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(s2, -1).c_str()); +} + +// Tests that the conversion stops when the function encounters \0 character. +TEST(WideStringToUtf8Test, StopsOnNulCharacter) { + EXPECT_STREQ("ABC", WideStringToUtf8(L"ABC\0XYZ", 100).c_str()); +} + +// Tests that the conversion stops when the function reaches the limit +// specified by the 'length' parameter. +TEST(WideStringToUtf8Test, StopsWhenLengthLimitReached) { + EXPECT_STREQ("ABC", WideStringToUtf8(L"ABCDEF", 3).c_str()); +} + +#if !GTEST_WIDE_STRING_USES_UTF16_ +// Tests that Unicode code-points that have 17 to 21 bits are encoded +// as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx. This code may not compile +// on the systems using UTF-16 encoding. +TEST(WideStringToUtf8Test, CanEncode17To21Bits) { + // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011 + EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", 1).c_str()); + EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", -1).c_str()); + + // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100 + EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", 1).c_str()); + EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", -1).c_str()); +} + +// Tests that encoding an invalid code-point generates the expected result. +TEST(WideStringToUtf8Test, CanEncodeInvalidCodePoint) { + EXPECT_STREQ("(Invalid Unicode 0xABCDFF)", + WideStringToUtf8(L"\xABCDFF", -1).c_str()); +} +#else // !GTEST_WIDE_STRING_USES_UTF16_ +// Tests that surrogate pairs are encoded correctly on the systems using +// UTF-16 encoding in the wide strings. +TEST(WideStringToUtf8Test, CanEncodeValidUtf16SUrrogatePairs) { + const wchar_t s[] = { 0xD801, 0xDC00, '\0' }; + EXPECT_STREQ("\xF0\x90\x90\x80", WideStringToUtf8(s, -1).c_str()); +} + +// Tests that encoding an invalid UTF-16 surrogate pair +// generates the expected result. +TEST(WideStringToUtf8Test, CanEncodeInvalidUtf16SurrogatePair) { + // Leading surrogate is at the end of the string. + const wchar_t s1[] = { 0xD800, '\0' }; + EXPECT_STREQ("\xED\xA0\x80", WideStringToUtf8(s1, -1).c_str()); + // Leading surrogate is not followed by the trailing surrogate. + const wchar_t s2[] = { 0xD800, 'M', '\0' }; + EXPECT_STREQ("\xED\xA0\x80M", WideStringToUtf8(s2, -1).c_str()); + // Trailing surrogate appearas without a leading surrogate. + const wchar_t s3[] = { 0xDC00, 'P', 'Q', 'R', '\0' }; + EXPECT_STREQ("\xED\xB0\x80PQR", WideStringToUtf8(s3, -1).c_str()); +} +#endif // !GTEST_WIDE_STRING_USES_UTF16_ + +// Tests that codepoint concatenation works correctly. +#if !GTEST_WIDE_STRING_USES_UTF16_ +TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { + const wchar_t s[] = { 0x108634, 0xC74D, '\n', 0x576, 0x8D3, 0x108634, '\0'}; + EXPECT_STREQ( + "\xF4\x88\x98\xB4" + "\xEC\x9D\x8D" + "\n" + "\xD5\xB6" + "\xE0\xA3\x93" + "\xF4\x88\x98\xB4", + WideStringToUtf8(s, -1).c_str()); +} +#else +TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { + const wchar_t s[] = { 0xC74D, '\n', 0x576, 0x8D3, '\0'}; + EXPECT_STREQ( + "\xEC\x9D\x8D" "\n" "\xD5\xB6" "\xE0\xA3\x93", + WideStringToUtf8(s, -1).c_str()); +} +#endif // !GTEST_WIDE_STRING_USES_UTF16_ + +// Tests the Random class. + +TEST(RandomDeathTest, GeneratesCrashesOnInvalidRange) { + testing::internal::Random random(42); + EXPECT_DEATH_IF_SUPPORTED( + random.Generate(0), + "Cannot generate a number in the range \\[0, 0\\)"); + EXPECT_DEATH_IF_SUPPORTED( + random.Generate(testing::internal::Random::kMaxRange + 1), + "Generation of a number in \\[0, 2147483649\\) was requested, " + "but this can only generate numbers in \\[0, 2147483648\\)"); +} + +TEST(RandomTest, GeneratesNumbersWithinRange) { + const UInt32 kRange = 10000; + testing::internal::Random random(12345); + for (int i = 0; i < 10; i++) { + EXPECT_LT(random.Generate(kRange), kRange) << " for iteration " << i; + } + + testing::internal::Random random2(testing::internal::Random::kMaxRange); + for (int i = 0; i < 10; i++) { + EXPECT_LT(random2.Generate(kRange), kRange) << " for iteration " << i; + } +} + +TEST(RandomTest, RepeatsWhenReseeded) { + const int kSeed = 123; + const int kArraySize = 10; + const UInt32 kRange = 10000; + UInt32 values[kArraySize]; + + testing::internal::Random random(kSeed); + for (int i = 0; i < kArraySize; i++) { + values[i] = random.Generate(kRange); + } + + random.Reseed(kSeed); + for (int i = 0; i < kArraySize; i++) { + EXPECT_EQ(values[i], random.Generate(kRange)) << " for iteration " << i; + } +} + +// Tests STL container utilities. + +// Tests CountIf(). + +static bool IsPositive(int n) { return n > 0; } + +TEST(ContainerUtilityTest, CountIf) { + std::vector v; + EXPECT_EQ(0, CountIf(v, IsPositive)); // Works for an empty container. + + v.push_back(-1); + v.push_back(0); + EXPECT_EQ(0, CountIf(v, IsPositive)); // Works when no value satisfies. + + v.push_back(2); + v.push_back(-10); + v.push_back(10); + EXPECT_EQ(2, CountIf(v, IsPositive)); +} + +// Tests ForEach(). + +static int g_sum = 0; +static void Accumulate(int n) { g_sum += n; } + +TEST(ContainerUtilityTest, ForEach) { + std::vector v; + g_sum = 0; + ForEach(v, Accumulate); + EXPECT_EQ(0, g_sum); // Works for an empty container; + + g_sum = 0; + v.push_back(1); + ForEach(v, Accumulate); + EXPECT_EQ(1, g_sum); // Works for a container with one element. + + g_sum = 0; + v.push_back(20); + v.push_back(300); + ForEach(v, Accumulate); + EXPECT_EQ(321, g_sum); +} + +// Tests GetElementOr(). +TEST(ContainerUtilityTest, GetElementOr) { + std::vector a; + EXPECT_EQ('x', GetElementOr(a, 0, 'x')); + + a.push_back('a'); + a.push_back('b'); + EXPECT_EQ('a', GetElementOr(a, 0, 'x')); + EXPECT_EQ('b', GetElementOr(a, 1, 'x')); + EXPECT_EQ('x', GetElementOr(a, -2, 'x')); + EXPECT_EQ('x', GetElementOr(a, 2, 'x')); +} + +TEST(ContainerUtilityDeathTest, ShuffleRange) { + std::vector a; + a.push_back(0); + a.push_back(1); + a.push_back(2); + testing::internal::Random random(1); + + EXPECT_DEATH_IF_SUPPORTED( + ShuffleRange(&random, -1, 1, &a), + "Invalid shuffle range start -1: must be in range \\[0, 3\\]"); + EXPECT_DEATH_IF_SUPPORTED( + ShuffleRange(&random, 4, 4, &a), + "Invalid shuffle range start 4: must be in range \\[0, 3\\]"); + EXPECT_DEATH_IF_SUPPORTED( + ShuffleRange(&random, 3, 2, &a), + "Invalid shuffle range finish 2: must be in range \\[3, 3\\]"); + EXPECT_DEATH_IF_SUPPORTED( + ShuffleRange(&random, 3, 4, &a), + "Invalid shuffle range finish 4: must be in range \\[3, 3\\]"); +} + +class VectorShuffleTest : public Test { + protected: + static const size_t kVectorSize = 20; + + VectorShuffleTest() : random_(1) { + for (int i = 0; i < static_cast(kVectorSize); i++) { + vector_.push_back(i); + } + } + + static bool VectorIsCorrupt(const TestingVector& vector) { + if (kVectorSize != vector.size()) { + return true; + } + + bool found_in_vector[kVectorSize] = { false }; + for (size_t i = 0; i < vector.size(); i++) { + const int e = vector[i]; + if (e < 0 || e >= static_cast(kVectorSize) || found_in_vector[e]) { + return true; + } + found_in_vector[e] = true; + } + + // Vector size is correct, elements' range is correct, no + // duplicate elements. Therefore no corruption has occurred. + return false; + } + + static bool VectorIsNotCorrupt(const TestingVector& vector) { + return !VectorIsCorrupt(vector); + } + + static bool RangeIsShuffled(const TestingVector& vector, int begin, int end) { + for (int i = begin; i < end; i++) { + if (i != vector[static_cast(i)]) { + return true; + } + } + return false; + } + + static bool RangeIsUnshuffled( + const TestingVector& vector, int begin, int end) { + return !RangeIsShuffled(vector, begin, end); + } + + static bool VectorIsShuffled(const TestingVector& vector) { + return RangeIsShuffled(vector, 0, static_cast(vector.size())); + } + + static bool VectorIsUnshuffled(const TestingVector& vector) { + return !VectorIsShuffled(vector); + } + + testing::internal::Random random_; + TestingVector vector_; +}; // class VectorShuffleTest + +const size_t VectorShuffleTest::kVectorSize; + +TEST_F(VectorShuffleTest, HandlesEmptyRange) { + // Tests an empty range at the beginning... + ShuffleRange(&random_, 0, 0, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...in the middle... + ShuffleRange(&random_, kVectorSize/2, kVectorSize/2, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...at the end... + ShuffleRange(&random_, kVectorSize - 1, kVectorSize - 1, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...and past the end. + ShuffleRange(&random_, kVectorSize, kVectorSize, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); +} + +TEST_F(VectorShuffleTest, HandlesRangeOfSizeOne) { + // Tests a size one range at the beginning... + ShuffleRange(&random_, 0, 1, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...in the middle... + ShuffleRange(&random_, kVectorSize/2, kVectorSize/2 + 1, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); + + // ...and at the end. + ShuffleRange(&random_, kVectorSize - 1, kVectorSize, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsUnshuffled, vector_); +} + +// Because we use our own random number generator and a fixed seed, +// we can guarantee that the following "random" tests will succeed. + +TEST_F(VectorShuffleTest, ShufflesEntireVector) { + Shuffle(&random_, &vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_FALSE(VectorIsUnshuffled(vector_)) << vector_; + + // Tests the first and last elements in particular to ensure that + // there are no off-by-one problems in our shuffle algorithm. + EXPECT_NE(0, vector_[0]); + EXPECT_NE(static_cast(kVectorSize - 1), vector_[kVectorSize - 1]); +} + +TEST_F(VectorShuffleTest, ShufflesStartOfVector) { + const int kRangeSize = kVectorSize/2; + + ShuffleRange(&random_, 0, kRangeSize, &vector_); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_PRED3(RangeIsShuffled, vector_, 0, kRangeSize); + EXPECT_PRED3(RangeIsUnshuffled, vector_, kRangeSize, + static_cast(kVectorSize)); +} + +TEST_F(VectorShuffleTest, ShufflesEndOfVector) { + const int kRangeSize = kVectorSize / 2; + ShuffleRange(&random_, kRangeSize, kVectorSize, &vector_); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize); + EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, + static_cast(kVectorSize)); +} + +TEST_F(VectorShuffleTest, ShufflesMiddleOfVector) { + const int kRangeSize = static_cast(kVectorSize) / 3; + ShuffleRange(&random_, kRangeSize, 2*kRangeSize, &vector_); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize); + EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, 2*kRangeSize); + EXPECT_PRED3(RangeIsUnshuffled, vector_, 2 * kRangeSize, + static_cast(kVectorSize)); +} + +TEST_F(VectorShuffleTest, ShufflesRepeatably) { + TestingVector vector2; + for (size_t i = 0; i < kVectorSize; i++) { + vector2.push_back(static_cast(i)); + } + + random_.Reseed(1234); + Shuffle(&random_, &vector_); + random_.Reseed(1234); + Shuffle(&random_, &vector2); + + ASSERT_PRED1(VectorIsNotCorrupt, vector_); + ASSERT_PRED1(VectorIsNotCorrupt, vector2); + + for (size_t i = 0; i < kVectorSize; i++) { + EXPECT_EQ(vector_[i], vector2[i]) << " where i is " << i; + } +} + +// Tests the size of the AssertHelper class. + +TEST(AssertHelperTest, AssertHelperIsSmall) { + // To avoid breaking clients that use lots of assertions in one + // function, we cannot grow the size of AssertHelper. + EXPECT_LE(sizeof(testing::internal::AssertHelper), sizeof(void*)); +} + +// Tests String::EndsWithCaseInsensitive(). +TEST(StringTest, EndsWithCaseInsensitive) { + EXPECT_TRUE(String::EndsWithCaseInsensitive("foobar", "BAR")); + EXPECT_TRUE(String::EndsWithCaseInsensitive("foobaR", "bar")); + EXPECT_TRUE(String::EndsWithCaseInsensitive("foobar", "")); + EXPECT_TRUE(String::EndsWithCaseInsensitive("", "")); + + EXPECT_FALSE(String::EndsWithCaseInsensitive("Foobar", "foo")); + EXPECT_FALSE(String::EndsWithCaseInsensitive("foobar", "Foo")); + EXPECT_FALSE(String::EndsWithCaseInsensitive("", "foo")); +} + +// C++Builder's preprocessor is buggy; it fails to expand macros that +// appear in macro parameters after wide char literals. Provide an alias +// for NULL as a workaround. +static const wchar_t* const kNull = nullptr; + +// Tests String::CaseInsensitiveWideCStringEquals +TEST(StringTest, CaseInsensitiveWideCStringEquals) { + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(nullptr, nullptr)); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L"")); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"", kNull)); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L"foobar")); + EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"foobar", kNull)); + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"foobar")); + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"FOOBAR")); + EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"FOOBAR", L"foobar")); +} + +#if GTEST_OS_WINDOWS + +// Tests String::ShowWideCString(). +TEST(StringTest, ShowWideCString) { + EXPECT_STREQ("(null)", + String::ShowWideCString(NULL).c_str()); + EXPECT_STREQ("", String::ShowWideCString(L"").c_str()); + EXPECT_STREQ("foo", String::ShowWideCString(L"foo").c_str()); +} + +# if GTEST_OS_WINDOWS_MOBILE +TEST(StringTest, AnsiAndUtf16Null) { + EXPECT_EQ(NULL, String::AnsiToUtf16(NULL)); + EXPECT_EQ(NULL, String::Utf16ToAnsi(NULL)); +} + +TEST(StringTest, AnsiAndUtf16ConvertBasic) { + const char* ansi = String::Utf16ToAnsi(L"str"); + EXPECT_STREQ("str", ansi); + delete [] ansi; + const WCHAR* utf16 = String::AnsiToUtf16("str"); + EXPECT_EQ(0, wcsncmp(L"str", utf16, 3)); + delete [] utf16; +} + +TEST(StringTest, AnsiAndUtf16ConvertPathChars) { + const char* ansi = String::Utf16ToAnsi(L".:\\ \"*?"); + EXPECT_STREQ(".:\\ \"*?", ansi); + delete [] ansi; + const WCHAR* utf16 = String::AnsiToUtf16(".:\\ \"*?"); + EXPECT_EQ(0, wcsncmp(L".:\\ \"*?", utf16, 3)); + delete [] utf16; +} +# endif // GTEST_OS_WINDOWS_MOBILE + +#endif // GTEST_OS_WINDOWS + +// Tests TestProperty construction. +TEST(TestPropertyTest, StringValue) { + TestProperty property("key", "1"); + EXPECT_STREQ("key", property.key()); + EXPECT_STREQ("1", property.value()); +} + +// Tests TestProperty replacing a value. +TEST(TestPropertyTest, ReplaceStringValue) { + TestProperty property("key", "1"); + EXPECT_STREQ("1", property.value()); + property.SetValue("2"); + EXPECT_STREQ("2", property.value()); +} + +// AddFatalFailure() and AddNonfatalFailure() must be stand-alone +// functions (i.e. their definitions cannot be inlined at the call +// sites), or C++Builder won't compile the code. +static void AddFatalFailure() { + FAIL() << "Expected fatal failure."; +} + +static void AddNonfatalFailure() { + ADD_FAILURE() << "Expected non-fatal failure."; +} + +class ScopedFakeTestPartResultReporterTest : public Test { + public: // Must be public and not protected due to a bug in g++ 3.4.2. + enum FailureMode { + FATAL_FAILURE, + NONFATAL_FAILURE + }; + static void AddFailure(FailureMode failure) { + if (failure == FATAL_FAILURE) { + AddFatalFailure(); + } else { + AddNonfatalFailure(); + } + } +}; + +// Tests that ScopedFakeTestPartResultReporter intercepts test +// failures. +TEST_F(ScopedFakeTestPartResultReporterTest, InterceptsTestFailures) { + TestPartResultArray results; + { + ScopedFakeTestPartResultReporter reporter( + ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD, + &results); + AddFailure(NONFATAL_FAILURE); + AddFailure(FATAL_FAILURE); + } + + EXPECT_EQ(2, results.size()); + EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed()); + EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed()); +} + +TEST_F(ScopedFakeTestPartResultReporterTest, DeprecatedConstructor) { + TestPartResultArray results; + { + // Tests, that the deprecated constructor still works. + ScopedFakeTestPartResultReporter reporter(&results); + AddFailure(NONFATAL_FAILURE); + } + EXPECT_EQ(1, results.size()); +} + +#if GTEST_IS_THREADSAFE + +class ScopedFakeTestPartResultReporterWithThreadsTest + : public ScopedFakeTestPartResultReporterTest { + protected: + static void AddFailureInOtherThread(FailureMode failure) { + ThreadWithParam thread(&AddFailure, failure, nullptr); + thread.Join(); + } +}; + +TEST_F(ScopedFakeTestPartResultReporterWithThreadsTest, + InterceptsTestFailuresInAllThreads) { + TestPartResultArray results; + { + ScopedFakeTestPartResultReporter reporter( + ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, &results); + AddFailure(NONFATAL_FAILURE); + AddFailure(FATAL_FAILURE); + AddFailureInOtherThread(NONFATAL_FAILURE); + AddFailureInOtherThread(FATAL_FAILURE); + } + + EXPECT_EQ(4, results.size()); + EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed()); + EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed()); + EXPECT_TRUE(results.GetTestPartResult(2).nonfatally_failed()); + EXPECT_TRUE(results.GetTestPartResult(3).fatally_failed()); +} + +#endif // GTEST_IS_THREADSAFE + +// Tests EXPECT_FATAL_FAILURE{,ON_ALL_THREADS}. Makes sure that they +// work even if the failure is generated in a called function rather than +// the current context. + +typedef ScopedFakeTestPartResultReporterTest ExpectFatalFailureTest; + +TEST_F(ExpectFatalFailureTest, CatchesFatalFaliure) { + EXPECT_FATAL_FAILURE(AddFatalFailure(), "Expected fatal failure."); +} + +TEST_F(ExpectFatalFailureTest, AcceptsStdStringObject) { + EXPECT_FATAL_FAILURE(AddFatalFailure(), + ::std::string("Expected fatal failure.")); +} + +TEST_F(ExpectFatalFailureTest, CatchesFatalFailureOnAllThreads) { + // We have another test below to verify that the macro catches fatal + // failures generated on another thread. + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFatalFailure(), + "Expected fatal failure."); +} + +#ifdef __BORLANDC__ +// Silences warnings: "Condition is always true" +# pragma option push -w-ccc +#endif + +// Tests that EXPECT_FATAL_FAILURE() can be used in a non-void +// function even when the statement in it contains ASSERT_*. + +int NonVoidFunction() { + EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), ""); + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), ""); + return 0; +} + +TEST_F(ExpectFatalFailureTest, CanBeUsedInNonVoidFunction) { + NonVoidFunction(); +} + +// Tests that EXPECT_FATAL_FAILURE(statement, ...) doesn't abort the +// current function even though 'statement' generates a fatal failure. + +void DoesNotAbortHelper(bool* aborted) { + EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), ""); + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), ""); + + *aborted = false; +} + +#ifdef __BORLANDC__ +// Restores warnings after previous "#pragma option push" suppressed them. +# pragma option pop +#endif + +TEST_F(ExpectFatalFailureTest, DoesNotAbort) { + bool aborted = true; + DoesNotAbortHelper(&aborted); + EXPECT_FALSE(aborted); +} + +// Tests that the EXPECT_FATAL_FAILURE{,_ON_ALL_THREADS} accepts a +// statement that contains a macro which expands to code containing an +// unprotected comma. + +static int global_var = 0; +#define GTEST_USE_UNPROTECTED_COMMA_ global_var++, global_var++ + +TEST_F(ExpectFatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) { +#ifndef __BORLANDC__ + // ICE's in C++Builder. + EXPECT_FATAL_FAILURE({ + GTEST_USE_UNPROTECTED_COMMA_; + AddFatalFailure(); + }, ""); +#endif + + EXPECT_FATAL_FAILURE_ON_ALL_THREADS({ + GTEST_USE_UNPROTECTED_COMMA_; + AddFatalFailure(); + }, ""); +} + +// Tests EXPECT_NONFATAL_FAILURE{,ON_ALL_THREADS}. + +typedef ScopedFakeTestPartResultReporterTest ExpectNonfatalFailureTest; + +TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailure) { + EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(), + "Expected non-fatal failure."); +} + +TEST_F(ExpectNonfatalFailureTest, AcceptsStdStringObject) { + EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(), + ::std::string("Expected non-fatal failure.")); +} + +TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailureOnAllThreads) { + // We have another test below to verify that the macro catches + // non-fatal failures generated on another thread. + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddNonfatalFailure(), + "Expected non-fatal failure."); +} + +// Tests that the EXPECT_NONFATAL_FAILURE{,_ON_ALL_THREADS} accepts a +// statement that contains a macro which expands to code containing an +// unprotected comma. +TEST_F(ExpectNonfatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) { + EXPECT_NONFATAL_FAILURE({ + GTEST_USE_UNPROTECTED_COMMA_; + AddNonfatalFailure(); + }, ""); + + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS({ + GTEST_USE_UNPROTECTED_COMMA_; + AddNonfatalFailure(); + }, ""); +} + +#if GTEST_IS_THREADSAFE + +typedef ScopedFakeTestPartResultReporterWithThreadsTest + ExpectFailureWithThreadsTest; + +TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailureOnAllThreads) { + EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailureInOtherThread(FATAL_FAILURE), + "Expected fatal failure."); +} + +TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailureOnAllThreads) { + EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS( + AddFailureInOtherThread(NONFATAL_FAILURE), "Expected non-fatal failure."); +} + +#endif // GTEST_IS_THREADSAFE + +// Tests the TestProperty class. + +TEST(TestPropertyTest, ConstructorWorks) { + const TestProperty property("key", "value"); + EXPECT_STREQ("key", property.key()); + EXPECT_STREQ("value", property.value()); +} + +TEST(TestPropertyTest, SetValue) { + TestProperty property("key", "value_1"); + EXPECT_STREQ("key", property.key()); + property.SetValue("value_2"); + EXPECT_STREQ("key", property.key()); + EXPECT_STREQ("value_2", property.value()); +} + +// Tests the TestResult class + +// The test fixture for testing TestResult. +class TestResultTest : public Test { + protected: + typedef std::vector TPRVector; + + // We make use of 2 TestPartResult objects, + TestPartResult * pr1, * pr2; + + // ... and 3 TestResult objects. + TestResult * r0, * r1, * r2; + + void SetUp() override { + // pr1 is for success. + pr1 = new TestPartResult(TestPartResult::kSuccess, + "foo/bar.cc", + 10, + "Success!"); + + // pr2 is for fatal failure. + pr2 = new TestPartResult(TestPartResult::kFatalFailure, + "foo/bar.cc", + -1, // This line number means "unknown" + "Failure!"); + + // Creates the TestResult objects. + r0 = new TestResult(); + r1 = new TestResult(); + r2 = new TestResult(); + + // In order to test TestResult, we need to modify its internal + // state, in particular the TestPartResult vector it holds. + // test_part_results() returns a const reference to this vector. + // We cast it to a non-const object s.t. it can be modified + TPRVector* results1 = const_cast( + &TestResultAccessor::test_part_results(*r1)); + TPRVector* results2 = const_cast( + &TestResultAccessor::test_part_results(*r2)); + + // r0 is an empty TestResult. + + // r1 contains a single SUCCESS TestPartResult. + results1->push_back(*pr1); + + // r2 contains a SUCCESS, and a FAILURE. + results2->push_back(*pr1); + results2->push_back(*pr2); + } + + void TearDown() override { + delete pr1; + delete pr2; + + delete r0; + delete r1; + delete r2; + } + + // Helper that compares two TestPartResults. + static void CompareTestPartResult(const TestPartResult& expected, + const TestPartResult& actual) { + EXPECT_EQ(expected.type(), actual.type()); + EXPECT_STREQ(expected.file_name(), actual.file_name()); + EXPECT_EQ(expected.line_number(), actual.line_number()); + EXPECT_STREQ(expected.summary(), actual.summary()); + EXPECT_STREQ(expected.message(), actual.message()); + EXPECT_EQ(expected.passed(), actual.passed()); + EXPECT_EQ(expected.failed(), actual.failed()); + EXPECT_EQ(expected.nonfatally_failed(), actual.nonfatally_failed()); + EXPECT_EQ(expected.fatally_failed(), actual.fatally_failed()); + } +}; + +// Tests TestResult::total_part_count(). +TEST_F(TestResultTest, total_part_count) { + ASSERT_EQ(0, r0->total_part_count()); + ASSERT_EQ(1, r1->total_part_count()); + ASSERT_EQ(2, r2->total_part_count()); +} + +// Tests TestResult::Passed(). +TEST_F(TestResultTest, Passed) { + ASSERT_TRUE(r0->Passed()); + ASSERT_TRUE(r1->Passed()); + ASSERT_FALSE(r2->Passed()); +} + +// Tests TestResult::Failed(). +TEST_F(TestResultTest, Failed) { + ASSERT_FALSE(r0->Failed()); + ASSERT_FALSE(r1->Failed()); + ASSERT_TRUE(r2->Failed()); +} + +// Tests TestResult::GetTestPartResult(). + +typedef TestResultTest TestResultDeathTest; + +TEST_F(TestResultDeathTest, GetTestPartResult) { + CompareTestPartResult(*pr1, r2->GetTestPartResult(0)); + CompareTestPartResult(*pr2, r2->GetTestPartResult(1)); + EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(2), ""); + EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(-1), ""); +} + +// Tests TestResult has no properties when none are added. +TEST(TestResultPropertyTest, NoPropertiesFoundWhenNoneAreAdded) { + TestResult test_result; + ASSERT_EQ(0, test_result.test_property_count()); +} + +// Tests TestResult has the expected property when added. +TEST(TestResultPropertyTest, OnePropertyFoundWhenAdded) { + TestResult test_result; + TestProperty property("key_1", "1"); + TestResultAccessor::RecordProperty(&test_result, "testcase", property); + ASSERT_EQ(1, test_result.test_property_count()); + const TestProperty& actual_property = test_result.GetTestProperty(0); + EXPECT_STREQ("key_1", actual_property.key()); + EXPECT_STREQ("1", actual_property.value()); +} + +// Tests TestResult has multiple properties when added. +TEST(TestResultPropertyTest, MultiplePropertiesFoundWhenAdded) { + TestResult test_result; + TestProperty property_1("key_1", "1"); + TestProperty property_2("key_2", "2"); + TestResultAccessor::RecordProperty(&test_result, "testcase", property_1); + TestResultAccessor::RecordProperty(&test_result, "testcase", property_2); + ASSERT_EQ(2, test_result.test_property_count()); + const TestProperty& actual_property_1 = test_result.GetTestProperty(0); + EXPECT_STREQ("key_1", actual_property_1.key()); + EXPECT_STREQ("1", actual_property_1.value()); + + const TestProperty& actual_property_2 = test_result.GetTestProperty(1); + EXPECT_STREQ("key_2", actual_property_2.key()); + EXPECT_STREQ("2", actual_property_2.value()); +} + +// Tests TestResult::RecordProperty() overrides values for duplicate keys. +TEST(TestResultPropertyTest, OverridesValuesForDuplicateKeys) { + TestResult test_result; + TestProperty property_1_1("key_1", "1"); + TestProperty property_2_1("key_2", "2"); + TestProperty property_1_2("key_1", "12"); + TestProperty property_2_2("key_2", "22"); + TestResultAccessor::RecordProperty(&test_result, "testcase", property_1_1); + TestResultAccessor::RecordProperty(&test_result, "testcase", property_2_1); + TestResultAccessor::RecordProperty(&test_result, "testcase", property_1_2); + TestResultAccessor::RecordProperty(&test_result, "testcase", property_2_2); + + ASSERT_EQ(2, test_result.test_property_count()); + const TestProperty& actual_property_1 = test_result.GetTestProperty(0); + EXPECT_STREQ("key_1", actual_property_1.key()); + EXPECT_STREQ("12", actual_property_1.value()); + + const TestProperty& actual_property_2 = test_result.GetTestProperty(1); + EXPECT_STREQ("key_2", actual_property_2.key()); + EXPECT_STREQ("22", actual_property_2.value()); +} + +// Tests TestResult::GetTestProperty(). +TEST(TestResultPropertyTest, GetTestProperty) { + TestResult test_result; + TestProperty property_1("key_1", "1"); + TestProperty property_2("key_2", "2"); + TestProperty property_3("key_3", "3"); + TestResultAccessor::RecordProperty(&test_result, "testcase", property_1); + TestResultAccessor::RecordProperty(&test_result, "testcase", property_2); + TestResultAccessor::RecordProperty(&test_result, "testcase", property_3); + + const TestProperty& fetched_property_1 = test_result.GetTestProperty(0); + const TestProperty& fetched_property_2 = test_result.GetTestProperty(1); + const TestProperty& fetched_property_3 = test_result.GetTestProperty(2); + + EXPECT_STREQ("key_1", fetched_property_1.key()); + EXPECT_STREQ("1", fetched_property_1.value()); + + EXPECT_STREQ("key_2", fetched_property_2.key()); + EXPECT_STREQ("2", fetched_property_2.value()); + + EXPECT_STREQ("key_3", fetched_property_3.key()); + EXPECT_STREQ("3", fetched_property_3.value()); + + EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(3), ""); + EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(-1), ""); +} + +// Tests the Test class. +// +// It's difficult to test every public method of this class (we are +// already stretching the limit of Google Test by using it to test itself!). +// Fortunately, we don't have to do that, as we are already testing +// the functionalities of the Test class extensively by using Google Test +// alone. +// +// Therefore, this section only contains one test. + +// Tests that GTestFlagSaver works on Windows and Mac. + +class GTestFlagSaverTest : public Test { + protected: + // Saves the Google Test flags such that we can restore them later, and + // then sets them to their default values. This will be called + // before the first test in this test case is run. + static void SetUpTestSuite() { + saver_ = new GTestFlagSaver; + + GTEST_FLAG(also_run_disabled_tests) = false; + GTEST_FLAG(break_on_failure) = false; + GTEST_FLAG(catch_exceptions) = false; + GTEST_FLAG(death_test_use_fork) = false; + GTEST_FLAG(color) = "auto"; + GTEST_FLAG(filter) = ""; + GTEST_FLAG(list_tests) = false; + GTEST_FLAG(output) = ""; + GTEST_FLAG(print_time) = true; + GTEST_FLAG(random_seed) = 0; + GTEST_FLAG(repeat) = 1; + GTEST_FLAG(shuffle) = false; + GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth; + GTEST_FLAG(stream_result_to) = ""; + GTEST_FLAG(throw_on_failure) = false; + } + + // Restores the Google Test flags that the tests have modified. This will + // be called after the last test in this test case is run. + static void TearDownTestSuite() { + delete saver_; + saver_ = nullptr; + } + + // Verifies that the Google Test flags have their default values, and then + // modifies each of them. + void VerifyAndModifyFlags() { + EXPECT_FALSE(GTEST_FLAG(also_run_disabled_tests)); + EXPECT_FALSE(GTEST_FLAG(break_on_failure)); + EXPECT_FALSE(GTEST_FLAG(catch_exceptions)); + EXPECT_STREQ("auto", GTEST_FLAG(color).c_str()); + EXPECT_FALSE(GTEST_FLAG(death_test_use_fork)); + EXPECT_STREQ("", GTEST_FLAG(filter).c_str()); + EXPECT_FALSE(GTEST_FLAG(list_tests)); + EXPECT_STREQ("", GTEST_FLAG(output).c_str()); + EXPECT_TRUE(GTEST_FLAG(print_time)); + EXPECT_EQ(0, GTEST_FLAG(random_seed)); + EXPECT_EQ(1, GTEST_FLAG(repeat)); + EXPECT_FALSE(GTEST_FLAG(shuffle)); + EXPECT_EQ(kMaxStackTraceDepth, GTEST_FLAG(stack_trace_depth)); + EXPECT_STREQ("", GTEST_FLAG(stream_result_to).c_str()); + EXPECT_FALSE(GTEST_FLAG(throw_on_failure)); + + GTEST_FLAG(also_run_disabled_tests) = true; + GTEST_FLAG(break_on_failure) = true; + GTEST_FLAG(catch_exceptions) = true; + GTEST_FLAG(color) = "no"; + GTEST_FLAG(death_test_use_fork) = true; + GTEST_FLAG(filter) = "abc"; + GTEST_FLAG(list_tests) = true; + GTEST_FLAG(output) = "xml:foo.xml"; + GTEST_FLAG(print_time) = false; + GTEST_FLAG(random_seed) = 1; + GTEST_FLAG(repeat) = 100; + GTEST_FLAG(shuffle) = true; + GTEST_FLAG(stack_trace_depth) = 1; + GTEST_FLAG(stream_result_to) = "localhost:1234"; + GTEST_FLAG(throw_on_failure) = true; + } + + private: + // For saving Google Test flags during this test case. + static GTestFlagSaver* saver_; +}; + +GTestFlagSaver* GTestFlagSaverTest::saver_ = nullptr; + +// Google Test doesn't guarantee the order of tests. The following two +// tests are designed to work regardless of their order. + +// Modifies the Google Test flags in the test body. +TEST_F(GTestFlagSaverTest, ModifyGTestFlags) { + VerifyAndModifyFlags(); +} + +// Verifies that the Google Test flags in the body of the previous test were +// restored to their original values. +TEST_F(GTestFlagSaverTest, VerifyGTestFlags) { + VerifyAndModifyFlags(); +} + +// Sets an environment variable with the given name to the given +// value. If the value argument is "", unsets the environment +// variable. The caller must ensure that both arguments are not NULL. +static void SetEnv(const char* name, const char* value) { +#if GTEST_OS_WINDOWS_MOBILE + // Environment variables are not supported on Windows CE. + return; +#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) + // C++Builder's putenv only stores a pointer to its parameter; we have to + // ensure that the string remains valid as long as it might be needed. + // We use an std::map to do so. + static std::map added_env; + + // Because putenv stores a pointer to the string buffer, we can't delete the + // previous string (if present) until after it's replaced. + std::string *prev_env = NULL; + if (added_env.find(name) != added_env.end()) { + prev_env = added_env[name]; + } + added_env[name] = new std::string( + (Message() << name << "=" << value).GetString()); + + // The standard signature of putenv accepts a 'char*' argument. Other + // implementations, like C++Builder's, accept a 'const char*'. + // We cast away the 'const' since that would work for both variants. + putenv(const_cast(added_env[name]->c_str())); + delete prev_env; +#elif GTEST_OS_WINDOWS // If we are on Windows proper. + _putenv((Message() << name << "=" << value).GetString().c_str()); +#else + if (*value == '\0') { + unsetenv(name); + } else { + setenv(name, value, 1); + } +#endif // GTEST_OS_WINDOWS_MOBILE +} + +#if !GTEST_OS_WINDOWS_MOBILE +// Environment variables are not supported on Windows CE. + +using testing::internal::Int32FromGTestEnv; + +// Tests Int32FromGTestEnv(). + +// Tests that Int32FromGTestEnv() returns the default value when the +// environment variable is not set. +TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenVariableIsNotSet) { + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", ""); + EXPECT_EQ(10, Int32FromGTestEnv("temp", 10)); +} + +# if !defined(GTEST_GET_INT32_FROM_ENV_) + +// Tests that Int32FromGTestEnv() returns the default value when the +// environment variable overflows as an Int32. +TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueOverflows) { + printf("(expecting 2 warnings)\n"); + + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12345678987654321"); + EXPECT_EQ(20, Int32FromGTestEnv("temp", 20)); + + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-12345678987654321"); + EXPECT_EQ(30, Int32FromGTestEnv("temp", 30)); +} + +// Tests that Int32FromGTestEnv() returns the default value when the +// environment variable does not represent a valid decimal integer. +TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueIsInvalid) { + printf("(expecting 2 warnings)\n"); + + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "A1"); + EXPECT_EQ(40, Int32FromGTestEnv("temp", 40)); + + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12X"); + EXPECT_EQ(50, Int32FromGTestEnv("temp", 50)); +} + +# endif // !defined(GTEST_GET_INT32_FROM_ENV_) + +// Tests that Int32FromGTestEnv() parses and returns the value of the +// environment variable when it represents a valid decimal integer in +// the range of an Int32. +TEST(Int32FromGTestEnvTest, ParsesAndReturnsValidValue) { + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "123"); + EXPECT_EQ(123, Int32FromGTestEnv("temp", 0)); + + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-321"); + EXPECT_EQ(-321, Int32FromGTestEnv("temp", 0)); +} +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Tests ParseInt32Flag(). + +// Tests that ParseInt32Flag() returns false and doesn't change the +// output value when the flag has wrong format +TEST(ParseInt32FlagTest, ReturnsFalseForInvalidFlag) { + Int32 value = 123; + EXPECT_FALSE(ParseInt32Flag("--a=100", "b", &value)); + EXPECT_EQ(123, value); + + EXPECT_FALSE(ParseInt32Flag("a=100", "a", &value)); + EXPECT_EQ(123, value); +} + +// Tests that ParseInt32Flag() returns false and doesn't change the +// output value when the flag overflows as an Int32. +TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueOverflows) { + printf("(expecting 2 warnings)\n"); + + Int32 value = 123; + EXPECT_FALSE(ParseInt32Flag("--abc=12345678987654321", "abc", &value)); + EXPECT_EQ(123, value); + + EXPECT_FALSE(ParseInt32Flag("--abc=-12345678987654321", "abc", &value)); + EXPECT_EQ(123, value); +} + +// Tests that ParseInt32Flag() returns false and doesn't change the +// output value when the flag does not represent a valid decimal +// integer. +TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueIsInvalid) { + printf("(expecting 2 warnings)\n"); + + Int32 value = 123; + EXPECT_FALSE(ParseInt32Flag("--abc=A1", "abc", &value)); + EXPECT_EQ(123, value); + + EXPECT_FALSE(ParseInt32Flag("--abc=12X", "abc", &value)); + EXPECT_EQ(123, value); +} + +// Tests that ParseInt32Flag() parses the value of the flag and +// returns true when the flag represents a valid decimal integer in +// the range of an Int32. +TEST(ParseInt32FlagTest, ParsesAndReturnsValidValue) { + Int32 value = 123; + EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=456", "abc", &value)); + EXPECT_EQ(456, value); + + EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=-789", + "abc", &value)); + EXPECT_EQ(-789, value); +} + +// Tests that Int32FromEnvOrDie() parses the value of the var or +// returns the correct default. +// Environment variables are not supported on Windows CE. +#if !GTEST_OS_WINDOWS_MOBILE +TEST(Int32FromEnvOrDieTest, ParsesAndReturnsValidValue) { + EXPECT_EQ(333, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "123"); + EXPECT_EQ(123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "-123"); + EXPECT_EQ(-123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); +} +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Tests that Int32FromEnvOrDie() aborts with an error message +// if the variable is not an Int32. +TEST(Int32FromEnvOrDieDeathTest, AbortsOnFailure) { + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "xxx"); + EXPECT_DEATH_IF_SUPPORTED( + Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123), + ".*"); +} + +// Tests that Int32FromEnvOrDie() aborts with an error message +// if the variable cannot be represented by an Int32. +TEST(Int32FromEnvOrDieDeathTest, AbortsOnInt32Overflow) { + SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "1234567891234567891234"); + EXPECT_DEATH_IF_SUPPORTED( + Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123), + ".*"); +} + +// Tests that ShouldRunTestOnShard() selects all tests +// where there is 1 shard. +TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereIsOneShard) { + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 0)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 1)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 2)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 3)); + EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 4)); +} + +class ShouldShardTest : public testing::Test { + protected: + void SetUp() override { + index_var_ = GTEST_FLAG_PREFIX_UPPER_ "INDEX"; + total_var_ = GTEST_FLAG_PREFIX_UPPER_ "TOTAL"; + } + + void TearDown() override { + SetEnv(index_var_, ""); + SetEnv(total_var_, ""); + } + + const char* index_var_; + const char* total_var_; +}; + +// Tests that sharding is disabled if neither of the environment variables +// are set. +TEST_F(ShouldShardTest, ReturnsFalseWhenNeitherEnvVarIsSet) { + SetEnv(index_var_, ""); + SetEnv(total_var_, ""); + + EXPECT_FALSE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); +} + +// Tests that sharding is not enabled if total_shards == 1. +TEST_F(ShouldShardTest, ReturnsFalseWhenTotalShardIsOne) { + SetEnv(index_var_, "0"); + SetEnv(total_var_, "1"); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); +} + +// Tests that sharding is enabled if total_shards > 1 and +// we are not in a death test subprocess. +// Environment variables are not supported on Windows CE. +#if !GTEST_OS_WINDOWS_MOBILE +TEST_F(ShouldShardTest, WorksWhenShardEnvVarsAreValid) { + SetEnv(index_var_, "4"); + SetEnv(total_var_, "22"); + EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); + + SetEnv(index_var_, "8"); + SetEnv(total_var_, "9"); + EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); + + SetEnv(index_var_, "0"); + SetEnv(total_var_, "9"); + EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); + EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); +} +#endif // !GTEST_OS_WINDOWS_MOBILE + +// Tests that we exit in error if the sharding values are not valid. + +typedef ShouldShardTest ShouldShardDeathTest; + +TEST_F(ShouldShardDeathTest, AbortsWhenShardingEnvVarsAreInvalid) { + SetEnv(index_var_, "4"); + SetEnv(total_var_, "4"); + EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); + + SetEnv(index_var_, "4"); + SetEnv(total_var_, "-2"); + EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); + + SetEnv(index_var_, "5"); + SetEnv(total_var_, ""); + EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); + + SetEnv(index_var_, ""); + SetEnv(total_var_, "5"); + EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*"); +} + +// Tests that ShouldRunTestOnShard is a partition when 5 +// shards are used. +TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereAreFiveShards) { + // Choose an arbitrary number of tests and shards. + const int num_tests = 17; + const int num_shards = 5; + + // Check partitioning: each test should be on exactly 1 shard. + for (int test_id = 0; test_id < num_tests; test_id++) { + int prev_selected_shard_index = -1; + for (int shard_index = 0; shard_index < num_shards; shard_index++) { + if (ShouldRunTestOnShard(num_shards, shard_index, test_id)) { + if (prev_selected_shard_index < 0) { + prev_selected_shard_index = shard_index; + } else { + ADD_FAILURE() << "Shard " << prev_selected_shard_index << " and " + << shard_index << " are both selected to run test " << test_id; + } + } + } + } + + // Check balance: This is not required by the sharding protocol, but is a + // desirable property for performance. + for (int shard_index = 0; shard_index < num_shards; shard_index++) { + int num_tests_on_shard = 0; + for (int test_id = 0; test_id < num_tests; test_id++) { + num_tests_on_shard += + ShouldRunTestOnShard(num_shards, shard_index, test_id); + } + EXPECT_GE(num_tests_on_shard, num_tests / num_shards); + } +} + +// For the same reason we are not explicitly testing everything in the +// Test class, there are no separate tests for the following classes +// (except for some trivial cases): +// +// TestSuite, UnitTest, UnitTestResultPrinter. +// +// Similarly, there are no separate tests for the following macros: +// +// TEST, TEST_F, RUN_ALL_TESTS + +TEST(UnitTestTest, CanGetOriginalWorkingDir) { + ASSERT_TRUE(UnitTest::GetInstance()->original_working_dir() != nullptr); + EXPECT_STRNE(UnitTest::GetInstance()->original_working_dir(), ""); +} + +TEST(UnitTestTest, ReturnsPlausibleTimestamp) { + EXPECT_LT(0, UnitTest::GetInstance()->start_timestamp()); + EXPECT_LE(UnitTest::GetInstance()->start_timestamp(), GetTimeInMillis()); +} + +// When a property using a reserved key is supplied to this function, it +// tests that a non-fatal failure is added, a fatal failure is not added, +// and that the property is not recorded. +void ExpectNonFatalFailureRecordingPropertyWithReservedKey( + const TestResult& test_result, const char* key) { + EXPECT_NONFATAL_FAILURE(Test::RecordProperty(key, "1"), "Reserved key"); + ASSERT_EQ(0, test_result.test_property_count()) << "Property for key '" << key + << "' recorded unexpectedly."; +} + +void ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( + const char* key) { + const TestInfo* test_info = UnitTest::GetInstance()->current_test_info(); + ASSERT_TRUE(test_info != nullptr); + ExpectNonFatalFailureRecordingPropertyWithReservedKey(*test_info->result(), + key); +} + +void ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestSuite( + const char* key) { + const testing::TestSuite* test_suite = + UnitTest::GetInstance()->current_test_suite(); + ASSERT_TRUE(test_suite != nullptr); + ExpectNonFatalFailureRecordingPropertyWithReservedKey( + test_suite->ad_hoc_test_result(), key); +} + +void ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestSuite( + const char* key) { + ExpectNonFatalFailureRecordingPropertyWithReservedKey( + UnitTest::GetInstance()->ad_hoc_test_result(), key); +} + +// Tests that property recording functions in UnitTest outside of tests +// functions correcly. Creating a separate instance of UnitTest ensures it +// is in a state similar to the UnitTest's singleton's between tests. +class UnitTestRecordPropertyTest : + public testing::internal::UnitTestRecordPropertyTestHelper { + public: + static void SetUpTestSuite() { + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestSuite( + "disabled"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestSuite( + "errors"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestSuite( + "failures"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestSuite( + "name"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestSuite( + "tests"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestSuite( + "time"); + + Test::RecordProperty("test_case_key_1", "1"); + + const testing::TestSuite* test_suite = + UnitTest::GetInstance()->current_test_suite(); + + ASSERT_TRUE(test_suite != nullptr); + + ASSERT_EQ(1, test_suite->ad_hoc_test_result().test_property_count()); + EXPECT_STREQ("test_case_key_1", + test_suite->ad_hoc_test_result().GetTestProperty(0).key()); + EXPECT_STREQ("1", + test_suite->ad_hoc_test_result().GetTestProperty(0).value()); + } +}; + +// Tests TestResult has the expected property when added. +TEST_F(UnitTestRecordPropertyTest, OnePropertyFoundWhenAdded) { + UnitTestRecordProperty("key_1", "1"); + + ASSERT_EQ(1, unit_test_.ad_hoc_test_result().test_property_count()); + + EXPECT_STREQ("key_1", + unit_test_.ad_hoc_test_result().GetTestProperty(0).key()); + EXPECT_STREQ("1", + unit_test_.ad_hoc_test_result().GetTestProperty(0).value()); +} + +// Tests TestResult has multiple properties when added. +TEST_F(UnitTestRecordPropertyTest, MultiplePropertiesFoundWhenAdded) { + UnitTestRecordProperty("key_1", "1"); + UnitTestRecordProperty("key_2", "2"); + + ASSERT_EQ(2, unit_test_.ad_hoc_test_result().test_property_count()); + + EXPECT_STREQ("key_1", + unit_test_.ad_hoc_test_result().GetTestProperty(0).key()); + EXPECT_STREQ("1", unit_test_.ad_hoc_test_result().GetTestProperty(0).value()); + + EXPECT_STREQ("key_2", + unit_test_.ad_hoc_test_result().GetTestProperty(1).key()); + EXPECT_STREQ("2", unit_test_.ad_hoc_test_result().GetTestProperty(1).value()); +} + +// Tests TestResult::RecordProperty() overrides values for duplicate keys. +TEST_F(UnitTestRecordPropertyTest, OverridesValuesForDuplicateKeys) { + UnitTestRecordProperty("key_1", "1"); + UnitTestRecordProperty("key_2", "2"); + UnitTestRecordProperty("key_1", "12"); + UnitTestRecordProperty("key_2", "22"); + + ASSERT_EQ(2, unit_test_.ad_hoc_test_result().test_property_count()); + + EXPECT_STREQ("key_1", + unit_test_.ad_hoc_test_result().GetTestProperty(0).key()); + EXPECT_STREQ("12", + unit_test_.ad_hoc_test_result().GetTestProperty(0).value()); + + EXPECT_STREQ("key_2", + unit_test_.ad_hoc_test_result().GetTestProperty(1).key()); + EXPECT_STREQ("22", + unit_test_.ad_hoc_test_result().GetTestProperty(1).value()); +} + +TEST_F(UnitTestRecordPropertyTest, + AddFailureInsideTestsWhenUsingTestSuiteReservedKeys) { + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( + "name"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( + "value_param"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( + "type_param"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( + "status"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( + "time"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( + "classname"); +} + +TEST_F(UnitTestRecordPropertyTest, + AddRecordWithReservedKeysGeneratesCorrectPropertyList) { + EXPECT_NONFATAL_FAILURE( + Test::RecordProperty("name", "1"), + "'classname', 'name', 'status', 'time', 'type_param', 'value_param'," + " 'file', and 'line' are reserved"); +} + +class UnitTestRecordPropertyTestEnvironment : public Environment { + public: + void TearDown() override { + ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestSuite( + "tests"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestSuite( + "failures"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestSuite( + "disabled"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestSuite( + "errors"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestSuite( + "name"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestSuite( + "timestamp"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestSuite( + "time"); + ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestSuite( + "random_seed"); + } +}; + +// This will test property recording outside of any test or test case. +static Environment* record_property_env GTEST_ATTRIBUTE_UNUSED_ = + AddGlobalTestEnvironment(new UnitTestRecordPropertyTestEnvironment); + +// This group of tests is for predicate assertions (ASSERT_PRED*, etc) +// of various arities. They do not attempt to be exhaustive. Rather, +// view them as smoke tests that can be easily reviewed and verified. +// A more complete set of tests for predicate assertions can be found +// in gtest_pred_impl_unittest.cc. + +// First, some predicates and predicate-formatters needed by the tests. + +// Returns true if and only if the argument is an even number. +bool IsEven(int n) { + return (n % 2) == 0; +} + +// A functor that returns true if and only if the argument is an even number. +struct IsEvenFunctor { + bool operator()(int n) { return IsEven(n); } +}; + +// A predicate-formatter function that asserts the argument is an even +// number. +AssertionResult AssertIsEven(const char* expr, int n) { + if (IsEven(n)) { + return AssertionSuccess(); + } + + Message msg; + msg << expr << " evaluates to " << n << ", which is not even."; + return AssertionFailure(msg); +} + +// A predicate function that returns AssertionResult for use in +// EXPECT/ASSERT_TRUE/FALSE. +AssertionResult ResultIsEven(int n) { + if (IsEven(n)) + return AssertionSuccess() << n << " is even"; + else + return AssertionFailure() << n << " is odd"; +} + +// A predicate function that returns AssertionResult but gives no +// explanation why it succeeds. Needed for testing that +// EXPECT/ASSERT_FALSE handles such functions correctly. +AssertionResult ResultIsEvenNoExplanation(int n) { + if (IsEven(n)) + return AssertionSuccess(); + else + return AssertionFailure() << n << " is odd"; +} + +// A predicate-formatter functor that asserts the argument is an even +// number. +struct AssertIsEvenFunctor { + AssertionResult operator()(const char* expr, int n) { + return AssertIsEven(expr, n); + } +}; + +// Returns true if and only if the sum of the arguments is an even number. +bool SumIsEven2(int n1, int n2) { + return IsEven(n1 + n2); +} + +// A functor that returns true if and only if the sum of the arguments is an +// even number. +struct SumIsEven3Functor { + bool operator()(int n1, int n2, int n3) { + return IsEven(n1 + n2 + n3); + } +}; + +// A predicate-formatter function that asserts the sum of the +// arguments is an even number. +AssertionResult AssertSumIsEven4( + const char* e1, const char* e2, const char* e3, const char* e4, + int n1, int n2, int n3, int n4) { + const int sum = n1 + n2 + n3 + n4; + if (IsEven(sum)) { + return AssertionSuccess(); + } + + Message msg; + msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 + << " (" << n1 << " + " << n2 << " + " << n3 << " + " << n4 + << ") evaluates to " << sum << ", which is not even."; + return AssertionFailure(msg); +} + +// A predicate-formatter functor that asserts the sum of the arguments +// is an even number. +struct AssertSumIsEven5Functor { + AssertionResult operator()( + const char* e1, const char* e2, const char* e3, const char* e4, + const char* e5, int n1, int n2, int n3, int n4, int n5) { + const int sum = n1 + n2 + n3 + n4 + n5; + if (IsEven(sum)) { + return AssertionSuccess(); + } + + Message msg; + msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5 + << " (" + << n1 << " + " << n2 << " + " << n3 << " + " << n4 << " + " << n5 + << ") evaluates to " << sum << ", which is not even."; + return AssertionFailure(msg); + } +}; + + +// Tests unary predicate assertions. + +// Tests unary predicate assertions that don't use a custom formatter. +TEST(Pred1Test, WithoutFormat) { + // Success cases. + EXPECT_PRED1(IsEvenFunctor(), 2) << "This failure is UNEXPECTED!"; + ASSERT_PRED1(IsEven, 4); + + // Failure cases. + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED1(IsEven, 5) << "This failure is expected."; + }, "This failure is expected."); + EXPECT_FATAL_FAILURE(ASSERT_PRED1(IsEvenFunctor(), 5), + "evaluates to false"); +} + +// Tests unary predicate assertions that use a custom formatter. +TEST(Pred1Test, WithFormat) { + // Success cases. + EXPECT_PRED_FORMAT1(AssertIsEven, 2); + ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), 4) + << "This failure is UNEXPECTED!"; + + // Failure cases. + const int n = 5; + EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT1(AssertIsEvenFunctor(), n), + "n evaluates to 5, which is not even."); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(AssertIsEven, 5) << "This failure is expected."; + }, "This failure is expected."); +} + +// Tests that unary predicate assertions evaluates their arguments +// exactly once. +TEST(Pred1Test, SingleEvaluationOnFailure) { + // A success case. + static int n = 0; + EXPECT_PRED1(IsEven, n++); + EXPECT_EQ(1, n) << "The argument is not evaluated exactly once."; + + // A failure case. + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), n++) + << "This failure is expected."; + }, "This failure is expected."); + EXPECT_EQ(2, n) << "The argument is not evaluated exactly once."; +} + + +// Tests predicate assertions whose arity is >= 2. + +// Tests predicate assertions that don't use a custom formatter. +TEST(PredTest, WithoutFormat) { + // Success cases. + ASSERT_PRED2(SumIsEven2, 2, 4) << "This failure is UNEXPECTED!"; + EXPECT_PRED3(SumIsEven3Functor(), 4, 6, 8); + + // Failure cases. + const int n1 = 1; + const int n2 = 2; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED2(SumIsEven2, n1, n2) << "This failure is expected."; + }, "This failure is expected."); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED3(SumIsEven3Functor(), 1, 2, 4); + }, "evaluates to false"); +} + +// Tests predicate assertions that use a custom formatter. +TEST(PredTest, WithFormat) { + // Success cases. + ASSERT_PRED_FORMAT4(AssertSumIsEven4, 4, 6, 8, 10) << + "This failure is UNEXPECTED!"; + EXPECT_PRED_FORMAT5(AssertSumIsEven5Functor(), 2, 4, 6, 8, 10); + + // Failure cases. + const int n1 = 1; + const int n2 = 2; + const int n3 = 4; + const int n4 = 6; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(AssertSumIsEven4, n1, n2, n3, n4); + }, "evaluates to 13, which is not even."); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(), 1, 2, 4, 6, 8) + << "This failure is expected."; + }, "This failure is expected."); +} + +// Tests that predicate assertions evaluates their arguments +// exactly once. +TEST(PredTest, SingleEvaluationOnFailure) { + // A success case. + int n1 = 0; + int n2 = 0; + EXPECT_PRED2(SumIsEven2, n1++, n2++); + EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; + EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; + + // Another success case. + n1 = n2 = 0; + int n3 = 0; + int n4 = 0; + int n5 = 0; + ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(), + n1++, n2++, n3++, n4++, n5++) + << "This failure is UNEXPECTED!"; + EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; + EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; + EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; + EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once."; + EXPECT_EQ(1, n5) << "Argument 5 is not evaluated exactly once."; + + // A failure case. + n1 = n2 = n3 = 0; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED3(SumIsEven3Functor(), ++n1, n2++, n3++) + << "This failure is expected."; + }, "This failure is expected."); + EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; + EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; + EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; + + // Another failure case. + n1 = n2 = n3 = n4 = 0; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT4(AssertSumIsEven4, ++n1, n2++, n3++, n4++); + }, "evaluates to 1, which is not even."); + EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once."; + EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once."; + EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once."; + EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once."; +} + +// Test predicate assertions for sets +TEST(PredTest, ExpectPredEvalFailure) { + std::set set_a = {2, 1, 3, 4, 5}; + std::set set_b = {0, 4, 8}; + const auto compare_sets = [] (std::set, std::set) { return false; }; + EXPECT_NONFATAL_FAILURE( + EXPECT_PRED2(compare_sets, set_a, set_b), + "compare_sets(set_a, set_b) evaluates to false, where\nset_a evaluates " + "to { 1, 2, 3, 4, 5 }\nset_b evaluates to { 0, 4, 8 }"); +} + +// Some helper functions for testing using overloaded/template +// functions with ASSERT_PREDn and EXPECT_PREDn. + +bool IsPositive(double x) { + return x > 0; +} + +template +bool IsNegative(T x) { + return x < 0; +} + +template +bool GreaterThan(T1 x1, T2 x2) { + return x1 > x2; +} + +// Tests that overloaded functions can be used in *_PRED* as long as +// their types are explicitly specified. +TEST(PredicateAssertionTest, AcceptsOverloadedFunction) { + // C++Builder requires C-style casts rather than static_cast. + EXPECT_PRED1((bool (*)(int))(IsPositive), 5); // NOLINT + ASSERT_PRED1((bool (*)(double))(IsPositive), 6.0); // NOLINT +} + +// Tests that template functions can be used in *_PRED* as long as +// their types are explicitly specified. +TEST(PredicateAssertionTest, AcceptsTemplateFunction) { + EXPECT_PRED1(IsNegative, -5); + // Makes sure that we can handle templates with more than one + // parameter. + ASSERT_PRED2((GreaterThan), 5, 0); +} + + +// Some helper functions for testing using overloaded/template +// functions with ASSERT_PRED_FORMATn and EXPECT_PRED_FORMATn. + +AssertionResult IsPositiveFormat(const char* /* expr */, int n) { + return n > 0 ? AssertionSuccess() : + AssertionFailure(Message() << "Failure"); +} + +AssertionResult IsPositiveFormat(const char* /* expr */, double x) { + return x > 0 ? AssertionSuccess() : + AssertionFailure(Message() << "Failure"); +} + +template +AssertionResult IsNegativeFormat(const char* /* expr */, T x) { + return x < 0 ? AssertionSuccess() : + AssertionFailure(Message() << "Failure"); +} + +template +AssertionResult EqualsFormat(const char* /* expr1 */, const char* /* expr2 */, + const T1& x1, const T2& x2) { + return x1 == x2 ? AssertionSuccess() : + AssertionFailure(Message() << "Failure"); +} + +// Tests that overloaded functions can be used in *_PRED_FORMAT* +// without explicitly specifying their types. +TEST(PredicateFormatAssertionTest, AcceptsOverloadedFunction) { + EXPECT_PRED_FORMAT1(IsPositiveFormat, 5); + ASSERT_PRED_FORMAT1(IsPositiveFormat, 6.0); +} + +// Tests that template functions can be used in *_PRED_FORMAT* without +// explicitly specifying their types. +TEST(PredicateFormatAssertionTest, AcceptsTemplateFunction) { + EXPECT_PRED_FORMAT1(IsNegativeFormat, -5); + ASSERT_PRED_FORMAT2(EqualsFormat, 3, 3); +} + + +// Tests string assertions. + +// Tests ASSERT_STREQ with non-NULL arguments. +TEST(StringAssertionTest, ASSERT_STREQ) { + const char * const p1 = "good"; + ASSERT_STREQ(p1, p1); + + // Let p2 have the same content as p1, but be at a different address. + const char p2[] = "good"; + ASSERT_STREQ(p1, p2); + + EXPECT_FATAL_FAILURE(ASSERT_STREQ("bad", "good"), + " \"bad\"\n \"good\""); +} + +// Tests ASSERT_STREQ with NULL arguments. +TEST(StringAssertionTest, ASSERT_STREQ_Null) { + ASSERT_STREQ(static_cast(nullptr), nullptr); + EXPECT_FATAL_FAILURE(ASSERT_STREQ(nullptr, "non-null"), "non-null"); +} + +// Tests ASSERT_STREQ with NULL arguments. +TEST(StringAssertionTest, ASSERT_STREQ_Null2) { + EXPECT_FATAL_FAILURE(ASSERT_STREQ("non-null", nullptr), "non-null"); +} + +// Tests ASSERT_STRNE. +TEST(StringAssertionTest, ASSERT_STRNE) { + ASSERT_STRNE("hi", "Hi"); + ASSERT_STRNE("Hi", nullptr); + ASSERT_STRNE(nullptr, "Hi"); + ASSERT_STRNE("", nullptr); + ASSERT_STRNE(nullptr, ""); + ASSERT_STRNE("", "Hi"); + ASSERT_STRNE("Hi", ""); + EXPECT_FATAL_FAILURE(ASSERT_STRNE("Hi", "Hi"), + "\"Hi\" vs \"Hi\""); +} + +// Tests ASSERT_STRCASEEQ. +TEST(StringAssertionTest, ASSERT_STRCASEEQ) { + ASSERT_STRCASEEQ("hi", "Hi"); + ASSERT_STRCASEEQ(static_cast(nullptr), nullptr); + + ASSERT_STRCASEEQ("", ""); + EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("Hi", "hi2"), + "Ignoring case"); +} + +// Tests ASSERT_STRCASENE. +TEST(StringAssertionTest, ASSERT_STRCASENE) { + ASSERT_STRCASENE("hi1", "Hi2"); + ASSERT_STRCASENE("Hi", nullptr); + ASSERT_STRCASENE(nullptr, "Hi"); + ASSERT_STRCASENE("", nullptr); + ASSERT_STRCASENE(nullptr, ""); + ASSERT_STRCASENE("", "Hi"); + ASSERT_STRCASENE("Hi", ""); + EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("Hi", "hi"), + "(ignoring case)"); +} + +// Tests *_STREQ on wide strings. +TEST(StringAssertionTest, STREQ_Wide) { + // NULL strings. + ASSERT_STREQ(static_cast(nullptr), nullptr); + + // Empty strings. + ASSERT_STREQ(L"", L""); + + // Non-null vs NULL. + EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"non-null", nullptr), "non-null"); + + // Equal strings. + EXPECT_STREQ(L"Hi", L"Hi"); + + // Unequal strings. + EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc", L"Abc"), + "Abc"); + + // Strings containing wide characters. + EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc\x8119", L"abc\x8120"), + "abc"); + + // The streaming variation. + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_STREQ(L"abc\x8119", L"abc\x8121") << "Expected failure"; + }, "Expected failure"); +} + +// Tests *_STRNE on wide strings. +TEST(StringAssertionTest, STRNE_Wide) { + // NULL strings. + EXPECT_NONFATAL_FAILURE( + { // NOLINT + EXPECT_STRNE(static_cast(nullptr), nullptr); + }, + ""); + + // Empty strings. + EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"", L""), + "L\"\""); + + // Non-null vs NULL. + ASSERT_STRNE(L"non-null", nullptr); + + // Equal strings. + EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"Hi", L"Hi"), + "L\"Hi\""); + + // Unequal strings. + EXPECT_STRNE(L"abc", L"Abc"); + + // Strings containing wide characters. + EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"abc\x8119", L"abc\x8119"), + "abc"); + + // The streaming variation. + ASSERT_STRNE(L"abc\x8119", L"abc\x8120") << "This shouldn't happen"; +} + +// Tests for ::testing::IsSubstring(). + +// Tests that IsSubstring() returns the correct result when the input +// argument type is const char*. +TEST(IsSubstringTest, ReturnsCorrectResultForCString) { + EXPECT_FALSE(IsSubstring("", "", nullptr, "a")); + EXPECT_FALSE(IsSubstring("", "", "b", nullptr)); + EXPECT_FALSE(IsSubstring("", "", "needle", "haystack")); + + EXPECT_TRUE(IsSubstring("", "", static_cast(nullptr), nullptr)); + EXPECT_TRUE(IsSubstring("", "", "needle", "two needles")); +} + +// Tests that IsSubstring() returns the correct result when the input +// argument type is const wchar_t*. +TEST(IsSubstringTest, ReturnsCorrectResultForWideCString) { + EXPECT_FALSE(IsSubstring("", "", kNull, L"a")); + EXPECT_FALSE(IsSubstring("", "", L"b", kNull)); + EXPECT_FALSE(IsSubstring("", "", L"needle", L"haystack")); + + EXPECT_TRUE( + IsSubstring("", "", static_cast(nullptr), nullptr)); + EXPECT_TRUE(IsSubstring("", "", L"needle", L"two needles")); +} + +// Tests that IsSubstring() generates the correct message when the input +// argument type is const char*. +TEST(IsSubstringTest, GeneratesCorrectMessageForCString) { + EXPECT_STREQ("Value of: needle_expr\n" + " Actual: \"needle\"\n" + "Expected: a substring of haystack_expr\n" + "Which is: \"haystack\"", + IsSubstring("needle_expr", "haystack_expr", + "needle", "haystack").failure_message()); +} + +// Tests that IsSubstring returns the correct result when the input +// argument type is ::std::string. +TEST(IsSubstringTest, ReturnsCorrectResultsForStdString) { + EXPECT_TRUE(IsSubstring("", "", std::string("hello"), "ahellob")); + EXPECT_FALSE(IsSubstring("", "", "hello", std::string("world"))); +} + +#if GTEST_HAS_STD_WSTRING +// Tests that IsSubstring returns the correct result when the input +// argument type is ::std::wstring. +TEST(IsSubstringTest, ReturnsCorrectResultForStdWstring) { + EXPECT_TRUE(IsSubstring("", "", ::std::wstring(L"needle"), L"two needles")); + EXPECT_FALSE(IsSubstring("", "", L"needle", ::std::wstring(L"haystack"))); +} + +// Tests that IsSubstring() generates the correct message when the input +// argument type is ::std::wstring. +TEST(IsSubstringTest, GeneratesCorrectMessageForWstring) { + EXPECT_STREQ("Value of: needle_expr\n" + " Actual: L\"needle\"\n" + "Expected: a substring of haystack_expr\n" + "Which is: L\"haystack\"", + IsSubstring( + "needle_expr", "haystack_expr", + ::std::wstring(L"needle"), L"haystack").failure_message()); +} + +#endif // GTEST_HAS_STD_WSTRING + +// Tests for ::testing::IsNotSubstring(). + +// Tests that IsNotSubstring() returns the correct result when the input +// argument type is const char*. +TEST(IsNotSubstringTest, ReturnsCorrectResultForCString) { + EXPECT_TRUE(IsNotSubstring("", "", "needle", "haystack")); + EXPECT_FALSE(IsNotSubstring("", "", "needle", "two needles")); +} + +// Tests that IsNotSubstring() returns the correct result when the input +// argument type is const wchar_t*. +TEST(IsNotSubstringTest, ReturnsCorrectResultForWideCString) { + EXPECT_TRUE(IsNotSubstring("", "", L"needle", L"haystack")); + EXPECT_FALSE(IsNotSubstring("", "", L"needle", L"two needles")); +} + +// Tests that IsNotSubstring() generates the correct message when the input +// argument type is const wchar_t*. +TEST(IsNotSubstringTest, GeneratesCorrectMessageForWideCString) { + EXPECT_STREQ("Value of: needle_expr\n" + " Actual: L\"needle\"\n" + "Expected: not a substring of haystack_expr\n" + "Which is: L\"two needles\"", + IsNotSubstring( + "needle_expr", "haystack_expr", + L"needle", L"two needles").failure_message()); +} + +// Tests that IsNotSubstring returns the correct result when the input +// argument type is ::std::string. +TEST(IsNotSubstringTest, ReturnsCorrectResultsForStdString) { + EXPECT_FALSE(IsNotSubstring("", "", std::string("hello"), "ahellob")); + EXPECT_TRUE(IsNotSubstring("", "", "hello", std::string("world"))); +} + +// Tests that IsNotSubstring() generates the correct message when the input +// argument type is ::std::string. +TEST(IsNotSubstringTest, GeneratesCorrectMessageForStdString) { + EXPECT_STREQ("Value of: needle_expr\n" + " Actual: \"needle\"\n" + "Expected: not a substring of haystack_expr\n" + "Which is: \"two needles\"", + IsNotSubstring( + "needle_expr", "haystack_expr", + ::std::string("needle"), "two needles").failure_message()); +} + +#if GTEST_HAS_STD_WSTRING + +// Tests that IsNotSubstring returns the correct result when the input +// argument type is ::std::wstring. +TEST(IsNotSubstringTest, ReturnsCorrectResultForStdWstring) { + EXPECT_FALSE( + IsNotSubstring("", "", ::std::wstring(L"needle"), L"two needles")); + EXPECT_TRUE(IsNotSubstring("", "", L"needle", ::std::wstring(L"haystack"))); +} + +#endif // GTEST_HAS_STD_WSTRING + +// Tests floating-point assertions. + +template +class FloatingPointTest : public Test { + protected: + // Pre-calculated numbers to be used by the tests. + struct TestValues { + RawType close_to_positive_zero; + RawType close_to_negative_zero; + RawType further_from_negative_zero; + + RawType close_to_one; + RawType further_from_one; + + RawType infinity; + RawType close_to_infinity; + RawType further_from_infinity; + + RawType nan1; + RawType nan2; + }; + + typedef typename testing::internal::FloatingPoint Floating; + typedef typename Floating::Bits Bits; + + void SetUp() override { + const size_t max_ulps = Floating::kMaxUlps; + + // The bits that represent 0.0. + const Bits zero_bits = Floating(0).bits(); + + // Makes some numbers close to 0.0. + values_.close_to_positive_zero = Floating::ReinterpretBits( + zero_bits + max_ulps/2); + values_.close_to_negative_zero = -Floating::ReinterpretBits( + zero_bits + max_ulps - max_ulps/2); + values_.further_from_negative_zero = -Floating::ReinterpretBits( + zero_bits + max_ulps + 1 - max_ulps/2); + + // The bits that represent 1.0. + const Bits one_bits = Floating(1).bits(); + + // Makes some numbers close to 1.0. + values_.close_to_one = Floating::ReinterpretBits(one_bits + max_ulps); + values_.further_from_one = Floating::ReinterpretBits( + one_bits + max_ulps + 1); + + // +infinity. + values_.infinity = Floating::Infinity(); + + // The bits that represent +infinity. + const Bits infinity_bits = Floating(values_.infinity).bits(); + + // Makes some numbers close to infinity. + values_.close_to_infinity = Floating::ReinterpretBits( + infinity_bits - max_ulps); + values_.further_from_infinity = Floating::ReinterpretBits( + infinity_bits - max_ulps - 1); + + // Makes some NAN's. Sets the most significant bit of the fraction so that + // our NaN's are quiet; trying to process a signaling NaN would raise an + // exception if our environment enables floating point exceptions. + values_.nan1 = Floating::ReinterpretBits(Floating::kExponentBitMask + | (static_cast(1) << (Floating::kFractionBitCount - 1)) | 1); + values_.nan2 = Floating::ReinterpretBits(Floating::kExponentBitMask + | (static_cast(1) << (Floating::kFractionBitCount - 1)) | 200); + } + + void TestSize() { + EXPECT_EQ(sizeof(RawType), sizeof(Bits)); + } + + static TestValues values_; +}; + +template +typename FloatingPointTest::TestValues + FloatingPointTest::values_; + +// Instantiates FloatingPointTest for testing *_FLOAT_EQ. +typedef FloatingPointTest FloatTest; + +// Tests that the size of Float::Bits matches the size of float. +TEST_F(FloatTest, Size) { + TestSize(); +} + +// Tests comparing with +0 and -0. +TEST_F(FloatTest, Zeros) { + EXPECT_FLOAT_EQ(0.0, -0.0); + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(-0.0, 1.0), + "1.0"); + EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.5), + "1.5"); +} + +// Tests comparing numbers close to 0. +// +// This ensures that *_FLOAT_EQ handles the sign correctly and no +// overflow occurs when comparing numbers whose absolute value is very +// small. +TEST_F(FloatTest, AlmostZeros) { + // In C++Builder, names within local classes (such as used by + // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the + // scoping class. Use a static local alias as a workaround. + // We use the assignment syntax since some compilers, like Sun Studio, + // don't allow initializing references using construction syntax + // (parentheses). + static const FloatTest::TestValues& v = this->values_; + + EXPECT_FLOAT_EQ(0.0, v.close_to_positive_zero); + EXPECT_FLOAT_EQ(-0.0, v.close_to_negative_zero); + EXPECT_FLOAT_EQ(v.close_to_positive_zero, v.close_to_negative_zero); + + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_FLOAT_EQ(v.close_to_positive_zero, + v.further_from_negative_zero); + }, "v.further_from_negative_zero"); +} + +// Tests comparing numbers close to each other. +TEST_F(FloatTest, SmallDiff) { + EXPECT_FLOAT_EQ(1.0, values_.close_to_one); + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, values_.further_from_one), + "values_.further_from_one"); +} + +// Tests comparing numbers far apart. +TEST_F(FloatTest, LargeDiff) { + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(2.5, 3.0), + "3.0"); +} + +// Tests comparing with infinity. +// +// This ensures that no overflow occurs when comparing numbers whose +// absolute value is very large. +TEST_F(FloatTest, Infinity) { + EXPECT_FLOAT_EQ(values_.infinity, values_.close_to_infinity); + EXPECT_FLOAT_EQ(-values_.infinity, -values_.close_to_infinity); + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, -values_.infinity), + "-values_.infinity"); + + // This is interesting as the representations of infinity and nan1 + // are only 1 DLP apart. + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, values_.nan1), + "values_.nan1"); +} + +// Tests that comparing with NAN always returns false. +TEST_F(FloatTest, NaN) { + // In C++Builder, names within local classes (such as used by + // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the + // scoping class. Use a static local alias as a workaround. + // We use the assignment syntax since some compilers, like Sun Studio, + // don't allow initializing references using construction syntax + // (parentheses). + static const FloatTest::TestValues& v = this->values_; + + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan1), + "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan2), + "v.nan2"); + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, v.nan1), + "v.nan1"); + + EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(v.nan1, v.infinity), + "v.infinity"); +} + +// Tests that *_FLOAT_EQ are reflexive. +TEST_F(FloatTest, Reflexive) { + EXPECT_FLOAT_EQ(0.0, 0.0); + EXPECT_FLOAT_EQ(1.0, 1.0); + ASSERT_FLOAT_EQ(values_.infinity, values_.infinity); +} + +// Tests that *_FLOAT_EQ are commutative. +TEST_F(FloatTest, Commutative) { + // We already tested EXPECT_FLOAT_EQ(1.0, values_.close_to_one). + EXPECT_FLOAT_EQ(values_.close_to_one, 1.0); + + // We already tested EXPECT_FLOAT_EQ(1.0, values_.further_from_one). + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.further_from_one, 1.0), + "1.0"); +} + +// Tests EXPECT_NEAR. +TEST_F(FloatTest, EXPECT_NEAR) { + EXPECT_NEAR(-1.0f, -1.1f, 0.2f); + EXPECT_NEAR(2.0f, 3.0f, 1.0f); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0f,1.5f, 0.25f), // NOLINT + "The difference between 1.0f and 1.5f is 0.5, " + "which exceeds 0.25f"); + // To work around a bug in gcc 2.95.0, there is intentionally no + // space after the first comma in the previous line. +} + +// Tests ASSERT_NEAR. +TEST_F(FloatTest, ASSERT_NEAR) { + ASSERT_NEAR(-1.0f, -1.1f, 0.2f); + ASSERT_NEAR(2.0f, 3.0f, 1.0f); + EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0f,1.5f, 0.25f), // NOLINT + "The difference between 1.0f and 1.5f is 0.5, " + "which exceeds 0.25f"); + // To work around a bug in gcc 2.95.0, there is intentionally no + // space after the first comma in the previous line. +} + +// Tests the cases where FloatLE() should succeed. +TEST_F(FloatTest, FloatLESucceeds) { + EXPECT_PRED_FORMAT2(FloatLE, 1.0f, 2.0f); // When val1 < val2, + ASSERT_PRED_FORMAT2(FloatLE, 1.0f, 1.0f); // val1 == val2, + + // or when val1 is greater than, but almost equals to, val2. + EXPECT_PRED_FORMAT2(FloatLE, values_.close_to_positive_zero, 0.0f); +} + +// Tests the cases where FloatLE() should fail. +TEST_F(FloatTest, FloatLEFails) { + // When val1 is greater than val2 by a large margin, + EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(FloatLE, 2.0f, 1.0f), + "(2.0f) <= (1.0f)"); + + // or by a small yet non-negligible margin, + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(FloatLE, values_.further_from_one, 1.0f); + }, "(values_.further_from_one) <= (1.0f)"); + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(FloatLE, values_.nan1, values_.infinity); + }, "(values_.nan1) <= (values_.infinity)"); + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(FloatLE, -values_.infinity, values_.nan1); + }, "(-values_.infinity) <= (values_.nan1)"); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(FloatLE, values_.nan1, values_.nan1); + }, "(values_.nan1) <= (values_.nan1)"); +} + +// Instantiates FloatingPointTest for testing *_DOUBLE_EQ. +typedef FloatingPointTest DoubleTest; + +// Tests that the size of Double::Bits matches the size of double. +TEST_F(DoubleTest, Size) { + TestSize(); +} + +// Tests comparing with +0 and -0. +TEST_F(DoubleTest, Zeros) { + EXPECT_DOUBLE_EQ(0.0, -0.0); + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(-0.0, 1.0), + "1.0"); + EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(0.0, 1.0), + "1.0"); +} + +// Tests comparing numbers close to 0. +// +// This ensures that *_DOUBLE_EQ handles the sign correctly and no +// overflow occurs when comparing numbers whose absolute value is very +// small. +TEST_F(DoubleTest, AlmostZeros) { + // In C++Builder, names within local classes (such as used by + // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the + // scoping class. Use a static local alias as a workaround. + // We use the assignment syntax since some compilers, like Sun Studio, + // don't allow initializing references using construction syntax + // (parentheses). + static const DoubleTest::TestValues& v = this->values_; + + EXPECT_DOUBLE_EQ(0.0, v.close_to_positive_zero); + EXPECT_DOUBLE_EQ(-0.0, v.close_to_negative_zero); + EXPECT_DOUBLE_EQ(v.close_to_positive_zero, v.close_to_negative_zero); + + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_DOUBLE_EQ(v.close_to_positive_zero, + v.further_from_negative_zero); + }, "v.further_from_negative_zero"); +} + +// Tests comparing numbers close to each other. +TEST_F(DoubleTest, SmallDiff) { + EXPECT_DOUBLE_EQ(1.0, values_.close_to_one); + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, values_.further_from_one), + "values_.further_from_one"); +} + +// Tests comparing numbers far apart. +TEST_F(DoubleTest, LargeDiff) { + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(2.0, 3.0), + "3.0"); +} + +// Tests comparing with infinity. +// +// This ensures that no overflow occurs when comparing numbers whose +// absolute value is very large. +TEST_F(DoubleTest, Infinity) { + EXPECT_DOUBLE_EQ(values_.infinity, values_.close_to_infinity); + EXPECT_DOUBLE_EQ(-values_.infinity, -values_.close_to_infinity); + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, -values_.infinity), + "-values_.infinity"); + + // This is interesting as the representations of infinity_ and nan1_ + // are only 1 DLP apart. + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, values_.nan1), + "values_.nan1"); +} + +// Tests that comparing with NAN always returns false. +TEST_F(DoubleTest, NaN) { + static const DoubleTest::TestValues& v = this->values_; + + // Nokia's STLport crashes if we try to output infinity or NaN. + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan1), + "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan2), "v.nan2"); + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, v.nan1), "v.nan1"); + EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(v.nan1, v.infinity), + "v.infinity"); +} + +// Tests that *_DOUBLE_EQ are reflexive. +TEST_F(DoubleTest, Reflexive) { + EXPECT_DOUBLE_EQ(0.0, 0.0); + EXPECT_DOUBLE_EQ(1.0, 1.0); + ASSERT_DOUBLE_EQ(values_.infinity, values_.infinity); +} + +// Tests that *_DOUBLE_EQ are commutative. +TEST_F(DoubleTest, Commutative) { + // We already tested EXPECT_DOUBLE_EQ(1.0, values_.close_to_one). + EXPECT_DOUBLE_EQ(values_.close_to_one, 1.0); + + // We already tested EXPECT_DOUBLE_EQ(1.0, values_.further_from_one). + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.further_from_one, 1.0), + "1.0"); +} + +// Tests EXPECT_NEAR. +TEST_F(DoubleTest, EXPECT_NEAR) { + EXPECT_NEAR(-1.0, -1.1, 0.2); + EXPECT_NEAR(2.0, 3.0, 1.0); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0, 1.5, 0.25), // NOLINT + "The difference between 1.0 and 1.5 is 0.5, " + "which exceeds 0.25"); + // To work around a bug in gcc 2.95.0, there is intentionally no + // space after the first comma in the previous statement. +} + +// Tests ASSERT_NEAR. +TEST_F(DoubleTest, ASSERT_NEAR) { + ASSERT_NEAR(-1.0, -1.1, 0.2); + ASSERT_NEAR(2.0, 3.0, 1.0); + EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0, 1.5, 0.25), // NOLINT + "The difference between 1.0 and 1.5 is 0.5, " + "which exceeds 0.25"); + // To work around a bug in gcc 2.95.0, there is intentionally no + // space after the first comma in the previous statement. +} + +// Tests the cases where DoubleLE() should succeed. +TEST_F(DoubleTest, DoubleLESucceeds) { + EXPECT_PRED_FORMAT2(DoubleLE, 1.0, 2.0); // When val1 < val2, + ASSERT_PRED_FORMAT2(DoubleLE, 1.0, 1.0); // val1 == val2, + + // or when val1 is greater than, but almost equals to, val2. + EXPECT_PRED_FORMAT2(DoubleLE, values_.close_to_positive_zero, 0.0); +} + +// Tests the cases where DoubleLE() should fail. +TEST_F(DoubleTest, DoubleLEFails) { + // When val1 is greater than val2 by a large margin, + EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(DoubleLE, 2.0, 1.0), + "(2.0) <= (1.0)"); + + // or by a small yet non-negligible margin, + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(DoubleLE, values_.further_from_one, 1.0); + }, "(values_.further_from_one) <= (1.0)"); + + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.infinity); + }, "(values_.nan1) <= (values_.infinity)"); + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_PRED_FORMAT2(DoubleLE, -values_.infinity, values_.nan1); + }, " (-values_.infinity) <= (values_.nan1)"); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.nan1); + }, "(values_.nan1) <= (values_.nan1)"); +} + + +// Verifies that a test or test case whose name starts with DISABLED_ is +// not run. + +// A test whose name starts with DISABLED_. +// Should not run. +TEST(DisabledTest, DISABLED_TestShouldNotRun) { + FAIL() << "Unexpected failure: Disabled test should not be run."; +} + +// A test whose name does not start with DISABLED_. +// Should run. +TEST(DisabledTest, NotDISABLED_TestShouldRun) { + EXPECT_EQ(1, 1); +} + +// A test case whose name starts with DISABLED_. +// Should not run. +TEST(DISABLED_TestSuite, TestShouldNotRun) { + FAIL() << "Unexpected failure: Test in disabled test case should not be run."; +} + +// A test case and test whose names start with DISABLED_. +// Should not run. +TEST(DISABLED_TestSuite, DISABLED_TestShouldNotRun) { + FAIL() << "Unexpected failure: Test in disabled test case should not be run."; +} + +// Check that when all tests in a test case are disabled, SetUpTestSuite() and +// TearDownTestSuite() are not called. +class DisabledTestsTest : public Test { + protected: + static void SetUpTestSuite() { + FAIL() << "Unexpected failure: All tests disabled in test case. " + "SetUpTestSuite() should not be called."; + } + + static void TearDownTestSuite() { + FAIL() << "Unexpected failure: All tests disabled in test case. " + "TearDownTestSuite() should not be called."; + } +}; + +TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_1) { + FAIL() << "Unexpected failure: Disabled test should not be run."; +} + +TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_2) { + FAIL() << "Unexpected failure: Disabled test should not be run."; +} + +// Tests that disabled typed tests aren't run. + +#if GTEST_HAS_TYPED_TEST + +template +class TypedTest : public Test { +}; + +typedef testing::Types NumericTypes; +TYPED_TEST_SUITE(TypedTest, NumericTypes); + +TYPED_TEST(TypedTest, DISABLED_ShouldNotRun) { + FAIL() << "Unexpected failure: Disabled typed test should not run."; +} + +template +class DISABLED_TypedTest : public Test { +}; + +TYPED_TEST_SUITE(DISABLED_TypedTest, NumericTypes); + +TYPED_TEST(DISABLED_TypedTest, ShouldNotRun) { + FAIL() << "Unexpected failure: Disabled typed test should not run."; +} + +#endif // GTEST_HAS_TYPED_TEST + +// Tests that disabled type-parameterized tests aren't run. + +#if GTEST_HAS_TYPED_TEST_P + +template +class TypedTestP : public Test { +}; + +TYPED_TEST_SUITE_P(TypedTestP); + +TYPED_TEST_P(TypedTestP, DISABLED_ShouldNotRun) { + FAIL() << "Unexpected failure: " + << "Disabled type-parameterized test should not run."; +} + +REGISTER_TYPED_TEST_SUITE_P(TypedTestP, DISABLED_ShouldNotRun); + +INSTANTIATE_TYPED_TEST_SUITE_P(My, TypedTestP, NumericTypes); + +template +class DISABLED_TypedTestP : public Test { +}; + +TYPED_TEST_SUITE_P(DISABLED_TypedTestP); + +TYPED_TEST_P(DISABLED_TypedTestP, ShouldNotRun) { + FAIL() << "Unexpected failure: " + << "Disabled type-parameterized test should not run."; +} + +REGISTER_TYPED_TEST_SUITE_P(DISABLED_TypedTestP, ShouldNotRun); + +INSTANTIATE_TYPED_TEST_SUITE_P(My, DISABLED_TypedTestP, NumericTypes); + +#endif // GTEST_HAS_TYPED_TEST_P + +// Tests that assertion macros evaluate their arguments exactly once. + +class SingleEvaluationTest : public Test { + public: // Must be public and not protected due to a bug in g++ 3.4.2. + // This helper function is needed by the FailedASSERT_STREQ test + // below. It's public to work around C++Builder's bug with scoping local + // classes. + static void CompareAndIncrementCharPtrs() { + ASSERT_STREQ(p1_++, p2_++); + } + + // This helper function is needed by the FailedASSERT_NE test below. It's + // public to work around C++Builder's bug with scoping local classes. + static void CompareAndIncrementInts() { + ASSERT_NE(a_++, b_++); + } + + protected: + SingleEvaluationTest() { + p1_ = s1_; + p2_ = s2_; + a_ = 0; + b_ = 0; + } + + static const char* const s1_; + static const char* const s2_; + static const char* p1_; + static const char* p2_; + + static int a_; + static int b_; +}; + +const char* const SingleEvaluationTest::s1_ = "01234"; +const char* const SingleEvaluationTest::s2_ = "abcde"; +const char* SingleEvaluationTest::p1_; +const char* SingleEvaluationTest::p2_; +int SingleEvaluationTest::a_; +int SingleEvaluationTest::b_; + +// Tests that when ASSERT_STREQ fails, it evaluates its arguments +// exactly once. +TEST_F(SingleEvaluationTest, FailedASSERT_STREQ) { + EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementCharPtrs(), + "p2_++"); + EXPECT_EQ(s1_ + 1, p1_); + EXPECT_EQ(s2_ + 1, p2_); +} + +// Tests that string assertion arguments are evaluated exactly once. +TEST_F(SingleEvaluationTest, ASSERT_STR) { + // successful EXPECT_STRNE + EXPECT_STRNE(p1_++, p2_++); + EXPECT_EQ(s1_ + 1, p1_); + EXPECT_EQ(s2_ + 1, p2_); + + // failed EXPECT_STRCASEEQ + EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ(p1_++, p2_++), + "Ignoring case"); + EXPECT_EQ(s1_ + 2, p1_); + EXPECT_EQ(s2_ + 2, p2_); +} + +// Tests that when ASSERT_NE fails, it evaluates its arguments exactly +// once. +TEST_F(SingleEvaluationTest, FailedASSERT_NE) { + EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementInts(), + "(a_++) != (b_++)"); + EXPECT_EQ(1, a_); + EXPECT_EQ(1, b_); +} + +// Tests that assertion arguments are evaluated exactly once. +TEST_F(SingleEvaluationTest, OtherCases) { + // successful EXPECT_TRUE + EXPECT_TRUE(0 == a_++); // NOLINT + EXPECT_EQ(1, a_); + + // failed EXPECT_TRUE + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(-1 == a_++), "-1 == a_++"); + EXPECT_EQ(2, a_); + + // successful EXPECT_GT + EXPECT_GT(a_++, b_++); + EXPECT_EQ(3, a_); + EXPECT_EQ(1, b_); + + // failed EXPECT_LT + EXPECT_NONFATAL_FAILURE(EXPECT_LT(a_++, b_++), "(a_++) < (b_++)"); + EXPECT_EQ(4, a_); + EXPECT_EQ(2, b_); + + // successful ASSERT_TRUE + ASSERT_TRUE(0 < a_++); // NOLINT + EXPECT_EQ(5, a_); + + // successful ASSERT_GT + ASSERT_GT(a_++, b_++); + EXPECT_EQ(6, a_); + EXPECT_EQ(3, b_); +} + +#if GTEST_HAS_EXCEPTIONS + +void ThrowAnInteger() { + throw 1; +} + +// Tests that assertion arguments are evaluated exactly once. +TEST_F(SingleEvaluationTest, ExceptionTests) { + // successful EXPECT_THROW + EXPECT_THROW({ // NOLINT + a_++; + ThrowAnInteger(); + }, int); + EXPECT_EQ(1, a_); + + // failed EXPECT_THROW, throws different + EXPECT_NONFATAL_FAILURE(EXPECT_THROW({ // NOLINT + a_++; + ThrowAnInteger(); + }, bool), "throws a different type"); + EXPECT_EQ(2, a_); + + // failed EXPECT_THROW, throws nothing + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(a_++, bool), "throws nothing"); + EXPECT_EQ(3, a_); + + // successful EXPECT_NO_THROW + EXPECT_NO_THROW(a_++); + EXPECT_EQ(4, a_); + + // failed EXPECT_NO_THROW + EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW({ // NOLINT + a_++; + ThrowAnInteger(); + }), "it throws"); + EXPECT_EQ(5, a_); + + // successful EXPECT_ANY_THROW + EXPECT_ANY_THROW({ // NOLINT + a_++; + ThrowAnInteger(); + }); + EXPECT_EQ(6, a_); + + // failed EXPECT_ANY_THROW + EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(a_++), "it doesn't"); + EXPECT_EQ(7, a_); +} + +#endif // GTEST_HAS_EXCEPTIONS + +// Tests {ASSERT|EXPECT}_NO_FATAL_FAILURE. +class NoFatalFailureTest : public Test { + protected: + void Succeeds() {} + void FailsNonFatal() { + ADD_FAILURE() << "some non-fatal failure"; + } + void Fails() { + FAIL() << "some fatal failure"; + } + + void DoAssertNoFatalFailureOnFails() { + ASSERT_NO_FATAL_FAILURE(Fails()); + ADD_FAILURE() << "should not reach here."; + } + + void DoExpectNoFatalFailureOnFails() { + EXPECT_NO_FATAL_FAILURE(Fails()); + ADD_FAILURE() << "other failure"; + } +}; + +TEST_F(NoFatalFailureTest, NoFailure) { + EXPECT_NO_FATAL_FAILURE(Succeeds()); + ASSERT_NO_FATAL_FAILURE(Succeeds()); +} + +TEST_F(NoFatalFailureTest, NonFatalIsNoFailure) { + EXPECT_NONFATAL_FAILURE( + EXPECT_NO_FATAL_FAILURE(FailsNonFatal()), + "some non-fatal failure"); + EXPECT_NONFATAL_FAILURE( + ASSERT_NO_FATAL_FAILURE(FailsNonFatal()), + "some non-fatal failure"); +} + +TEST_F(NoFatalFailureTest, AssertNoFatalFailureOnFatalFailure) { + TestPartResultArray gtest_failures; + { + ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); + DoAssertNoFatalFailureOnFails(); + } + ASSERT_EQ(2, gtest_failures.size()); + EXPECT_EQ(TestPartResult::kFatalFailure, + gtest_failures.GetTestPartResult(0).type()); + EXPECT_EQ(TestPartResult::kFatalFailure, + gtest_failures.GetTestPartResult(1).type()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure", + gtest_failures.GetTestPartResult(0).message()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does", + gtest_failures.GetTestPartResult(1).message()); +} + +TEST_F(NoFatalFailureTest, ExpectNoFatalFailureOnFatalFailure) { + TestPartResultArray gtest_failures; + { + ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); + DoExpectNoFatalFailureOnFails(); + } + ASSERT_EQ(3, gtest_failures.size()); + EXPECT_EQ(TestPartResult::kFatalFailure, + gtest_failures.GetTestPartResult(0).type()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, + gtest_failures.GetTestPartResult(1).type()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, + gtest_failures.GetTestPartResult(2).type()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure", + gtest_failures.GetTestPartResult(0).message()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does", + gtest_failures.GetTestPartResult(1).message()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "other failure", + gtest_failures.GetTestPartResult(2).message()); +} + +TEST_F(NoFatalFailureTest, MessageIsStreamable) { + TestPartResultArray gtest_failures; + { + ScopedFakeTestPartResultReporter gtest_reporter(>est_failures); + EXPECT_NO_FATAL_FAILURE(FAIL() << "foo") << "my message"; + } + ASSERT_EQ(2, gtest_failures.size()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, + gtest_failures.GetTestPartResult(0).type()); + EXPECT_EQ(TestPartResult::kNonFatalFailure, + gtest_failures.GetTestPartResult(1).type()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "foo", + gtest_failures.GetTestPartResult(0).message()); + EXPECT_PRED_FORMAT2(testing::IsSubstring, "my message", + gtest_failures.GetTestPartResult(1).message()); +} + +// Tests non-string assertions. + +std::string EditsToString(const std::vector& edits) { + std::string out; + for (size_t i = 0; i < edits.size(); ++i) { + static const char kEdits[] = " +-/"; + out.append(1, kEdits[edits[i]]); + } + return out; +} + +std::vector CharsToIndices(const std::string& str) { + std::vector out; + for (size_t i = 0; i < str.size(); ++i) { + out.push_back(static_cast(str[i])); + } + return out; +} + +std::vector CharsToLines(const std::string& str) { + std::vector out; + for (size_t i = 0; i < str.size(); ++i) { + out.push_back(str.substr(i, 1)); + } + return out; +} + +TEST(EditDistance, TestSuites) { + struct Case { + int line; + const char* left; + const char* right; + const char* expected_edits; + const char* expected_diff; + }; + static const Case kCases[] = { + // No change. + {__LINE__, "A", "A", " ", ""}, + {__LINE__, "ABCDE", "ABCDE", " ", ""}, + // Simple adds. + {__LINE__, "X", "XA", " +", "@@ +1,2 @@\n X\n+A\n"}, + {__LINE__, "X", "XABCD", " ++++", "@@ +1,5 @@\n X\n+A\n+B\n+C\n+D\n"}, + // Simple removes. + {__LINE__, "XA", "X", " -", "@@ -1,2 @@\n X\n-A\n"}, + {__LINE__, "XABCD", "X", " ----", "@@ -1,5 @@\n X\n-A\n-B\n-C\n-D\n"}, + // Simple replaces. + {__LINE__, "A", "a", "/", "@@ -1,1 +1,1 @@\n-A\n+a\n"}, + {__LINE__, "ABCD", "abcd", "////", + "@@ -1,4 +1,4 @@\n-A\n-B\n-C\n-D\n+a\n+b\n+c\n+d\n"}, + // Path finding. + {__LINE__, "ABCDEFGH", "ABXEGH1", " -/ - +", + "@@ -1,8 +1,7 @@\n A\n B\n-C\n-D\n+X\n E\n-F\n G\n H\n+1\n"}, + {__LINE__, "AAAABCCCC", "ABABCDCDC", "- / + / ", + "@@ -1,9 +1,9 @@\n-A\n A\n-A\n+B\n A\n B\n C\n+D\n C\n-C\n+D\n C\n"}, + {__LINE__, "ABCDE", "BCDCD", "- +/", + "@@ -1,5 +1,5 @@\n-A\n B\n C\n D\n-E\n+C\n+D\n"}, + {__LINE__, "ABCDEFGHIJKL", "BCDCDEFGJKLJK", "- ++ -- ++", + "@@ -1,4 +1,5 @@\n-A\n B\n+C\n+D\n C\n D\n" + "@@ -6,7 +7,7 @@\n F\n G\n-H\n-I\n J\n K\n L\n+J\n+K\n"}, + {}}; + for (const Case* c = kCases; c->left; ++c) { + EXPECT_TRUE(c->expected_edits == + EditsToString(CalculateOptimalEdits(CharsToIndices(c->left), + CharsToIndices(c->right)))) + << "Left <" << c->left << "> Right <" << c->right << "> Edits <" + << EditsToString(CalculateOptimalEdits( + CharsToIndices(c->left), CharsToIndices(c->right))) << ">"; + EXPECT_TRUE(c->expected_diff == CreateUnifiedDiff(CharsToLines(c->left), + CharsToLines(c->right))) + << "Left <" << c->left << "> Right <" << c->right << "> Diff <" + << CreateUnifiedDiff(CharsToLines(c->left), CharsToLines(c->right)) + << ">"; + } +} + +// Tests EqFailure(), used for implementing *EQ* assertions. +TEST(AssertionTest, EqFailure) { + const std::string foo_val("5"), bar_val("6"); + const std::string msg1( + EqFailure("foo", "bar", foo_val, bar_val, false) + .failure_message()); + EXPECT_STREQ( + "Expected equality of these values:\n" + " foo\n" + " Which is: 5\n" + " bar\n" + " Which is: 6", + msg1.c_str()); + + const std::string msg2( + EqFailure("foo", "6", foo_val, bar_val, false) + .failure_message()); + EXPECT_STREQ( + "Expected equality of these values:\n" + " foo\n" + " Which is: 5\n" + " 6", + msg2.c_str()); + + const std::string msg3( + EqFailure("5", "bar", foo_val, bar_val, false) + .failure_message()); + EXPECT_STREQ( + "Expected equality of these values:\n" + " 5\n" + " bar\n" + " Which is: 6", + msg3.c_str()); + + const std::string msg4( + EqFailure("5", "6", foo_val, bar_val, false).failure_message()); + EXPECT_STREQ( + "Expected equality of these values:\n" + " 5\n" + " 6", + msg4.c_str()); + + const std::string msg5( + EqFailure("foo", "bar", + std::string("\"x\""), std::string("\"y\""), + true).failure_message()); + EXPECT_STREQ( + "Expected equality of these values:\n" + " foo\n" + " Which is: \"x\"\n" + " bar\n" + " Which is: \"y\"\n" + "Ignoring case", + msg5.c_str()); +} + +TEST(AssertionTest, EqFailureWithDiff) { + const std::string left( + "1\\n2XXX\\n3\\n5\\n6\\n7\\n8\\n9\\n10\\n11\\n12XXX\\n13\\n14\\n15"); + const std::string right( + "1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\\n11\\n12\\n13\\n14"); + const std::string msg1( + EqFailure("left", "right", left, right, false).failure_message()); + EXPECT_STREQ( + "Expected equality of these values:\n" + " left\n" + " Which is: " + "1\\n2XXX\\n3\\n5\\n6\\n7\\n8\\n9\\n10\\n11\\n12XXX\\n13\\n14\\n15\n" + " right\n" + " Which is: 1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\\n11\\n12\\n13\\n14\n" + "With diff:\n@@ -1,5 +1,6 @@\n 1\n-2XXX\n+2\n 3\n+4\n 5\n 6\n" + "@@ -7,8 +8,6 @@\n 8\n 9\n-10\n 11\n-12XXX\n+12\n 13\n 14\n-15\n", + msg1.c_str()); +} + +// Tests AppendUserMessage(), used for implementing the *EQ* macros. +TEST(AssertionTest, AppendUserMessage) { + const std::string foo("foo"); + + Message msg; + EXPECT_STREQ("foo", + AppendUserMessage(foo, msg).c_str()); + + msg << "bar"; + EXPECT_STREQ("foo\nbar", + AppendUserMessage(foo, msg).c_str()); +} + +#ifdef __BORLANDC__ +// Silences warnings: "Condition is always true", "Unreachable code" +# pragma option push -w-ccc -w-rch +#endif + +// Tests ASSERT_TRUE. +TEST(AssertionTest, ASSERT_TRUE) { + ASSERT_TRUE(2 > 1); // NOLINT + EXPECT_FATAL_FAILURE(ASSERT_TRUE(2 < 1), + "2 < 1"); +} + +// Tests ASSERT_TRUE(predicate) for predicates returning AssertionResult. +TEST(AssertionTest, AssertTrueWithAssertionResult) { + ASSERT_TRUE(ResultIsEven(2)); +#ifndef __BORLANDC__ + // ICE's in C++Builder. + EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEven(3)), + "Value of: ResultIsEven(3)\n" + " Actual: false (3 is odd)\n" + "Expected: true"); +#endif + ASSERT_TRUE(ResultIsEvenNoExplanation(2)); + EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEvenNoExplanation(3)), + "Value of: ResultIsEvenNoExplanation(3)\n" + " Actual: false (3 is odd)\n" + "Expected: true"); +} + +// Tests ASSERT_FALSE. +TEST(AssertionTest, ASSERT_FALSE) { + ASSERT_FALSE(2 < 1); // NOLINT + EXPECT_FATAL_FAILURE(ASSERT_FALSE(2 > 1), + "Value of: 2 > 1\n" + " Actual: true\n" + "Expected: false"); +} + +// Tests ASSERT_FALSE(predicate) for predicates returning AssertionResult. +TEST(AssertionTest, AssertFalseWithAssertionResult) { + ASSERT_FALSE(ResultIsEven(3)); +#ifndef __BORLANDC__ + // ICE's in C++Builder. + EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEven(2)), + "Value of: ResultIsEven(2)\n" + " Actual: true (2 is even)\n" + "Expected: false"); +#endif + ASSERT_FALSE(ResultIsEvenNoExplanation(3)); + EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEvenNoExplanation(2)), + "Value of: ResultIsEvenNoExplanation(2)\n" + " Actual: true\n" + "Expected: false"); +} + +#ifdef __BORLANDC__ +// Restores warnings after previous "#pragma option push" suppressed them +# pragma option pop +#endif + +// Tests using ASSERT_EQ on double values. The purpose is to make +// sure that the specialization we did for integer and anonymous enums +// isn't used for double arguments. +TEST(ExpectTest, ASSERT_EQ_Double) { + // A success. + ASSERT_EQ(5.6, 5.6); + + // A failure. + EXPECT_FATAL_FAILURE(ASSERT_EQ(5.1, 5.2), + "5.1"); +} + +// Tests ASSERT_EQ. +TEST(AssertionTest, ASSERT_EQ) { + ASSERT_EQ(5, 2 + 3); + EXPECT_FATAL_FAILURE(ASSERT_EQ(5, 2*3), + "Expected equality of these values:\n" + " 5\n" + " 2*3\n" + " Which is: 6"); +} + +// Tests ASSERT_EQ(NULL, pointer). +TEST(AssertionTest, ASSERT_EQ_NULL) { + // A success. + const char* p = nullptr; + // Some older GCC versions may issue a spurious warning in this or the next + // assertion statement. This warning should not be suppressed with + // static_cast since the test verifies the ability to use bare NULL as the + // expected parameter to the macro. + ASSERT_EQ(nullptr, p); + + // A failure. + static int n = 0; + EXPECT_FATAL_FAILURE(ASSERT_EQ(nullptr, &n), " &n\n Which is:"); +} + +// Tests ASSERT_EQ(0, non_pointer). Since the literal 0 can be +// treated as a null pointer by the compiler, we need to make sure +// that ASSERT_EQ(0, non_pointer) isn't interpreted by Google Test as +// ASSERT_EQ(static_cast(NULL), non_pointer). +TEST(ExpectTest, ASSERT_EQ_0) { + int n = 0; + + // A success. + ASSERT_EQ(0, n); + + // A failure. + EXPECT_FATAL_FAILURE(ASSERT_EQ(0, 5.6), + " 0\n 5.6"); +} + +// Tests ASSERT_NE. +TEST(AssertionTest, ASSERT_NE) { + ASSERT_NE(6, 7); + EXPECT_FATAL_FAILURE(ASSERT_NE('a', 'a'), + "Expected: ('a') != ('a'), " + "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)"); +} + +// Tests ASSERT_LE. +TEST(AssertionTest, ASSERT_LE) { + ASSERT_LE(2, 3); + ASSERT_LE(2, 2); + EXPECT_FATAL_FAILURE(ASSERT_LE(2, 0), + "Expected: (2) <= (0), actual: 2 vs 0"); +} + +// Tests ASSERT_LT. +TEST(AssertionTest, ASSERT_LT) { + ASSERT_LT(2, 3); + EXPECT_FATAL_FAILURE(ASSERT_LT(2, 2), + "Expected: (2) < (2), actual: 2 vs 2"); +} + +// Tests ASSERT_GE. +TEST(AssertionTest, ASSERT_GE) { + ASSERT_GE(2, 1); + ASSERT_GE(2, 2); + EXPECT_FATAL_FAILURE(ASSERT_GE(2, 3), + "Expected: (2) >= (3), actual: 2 vs 3"); +} + +// Tests ASSERT_GT. +TEST(AssertionTest, ASSERT_GT) { + ASSERT_GT(2, 1); + EXPECT_FATAL_FAILURE(ASSERT_GT(2, 2), + "Expected: (2) > (2), actual: 2 vs 2"); +} + +#if GTEST_HAS_EXCEPTIONS + +void ThrowNothing() {} + +// Tests ASSERT_THROW. +TEST(AssertionTest, ASSERT_THROW) { + ASSERT_THROW(ThrowAnInteger(), int); + +# ifndef __BORLANDC__ + + // ICE's in C++Builder 2007 and 2009. + EXPECT_FATAL_FAILURE( + ASSERT_THROW(ThrowAnInteger(), bool), + "Expected: ThrowAnInteger() throws an exception of type bool.\n" + " Actual: it throws a different type."); +# endif + + EXPECT_FATAL_FAILURE( + ASSERT_THROW(ThrowNothing(), bool), + "Expected: ThrowNothing() throws an exception of type bool.\n" + " Actual: it throws nothing."); +} + +// Tests ASSERT_NO_THROW. +TEST(AssertionTest, ASSERT_NO_THROW) { + ASSERT_NO_THROW(ThrowNothing()); + EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()), + "Expected: ThrowAnInteger() doesn't throw an exception." + "\n Actual: it throws."); +} + +// Tests ASSERT_ANY_THROW. +TEST(AssertionTest, ASSERT_ANY_THROW) { + ASSERT_ANY_THROW(ThrowAnInteger()); + EXPECT_FATAL_FAILURE( + ASSERT_ANY_THROW(ThrowNothing()), + "Expected: ThrowNothing() throws an exception.\n" + " Actual: it doesn't."); +} + +#endif // GTEST_HAS_EXCEPTIONS + +// Makes sure we deal with the precedence of <<. This test should +// compile. +TEST(AssertionTest, AssertPrecedence) { + ASSERT_EQ(1 < 2, true); + bool false_value = false; + ASSERT_EQ(true && false_value, false); +} + +// A subroutine used by the following test. +void TestEq1(int x) { + ASSERT_EQ(1, x); +} + +// Tests calling a test subroutine that's not part of a fixture. +TEST(AssertionTest, NonFixtureSubroutine) { + EXPECT_FATAL_FAILURE(TestEq1(2), + " x\n Which is: 2"); +} + +// An uncopyable class. +class Uncopyable { + public: + explicit Uncopyable(int a_value) : value_(a_value) {} + + int value() const { return value_; } + bool operator==(const Uncopyable& rhs) const { + return value() == rhs.value(); + } + private: + // This constructor deliberately has no implementation, as we don't + // want this class to be copyable. + Uncopyable(const Uncopyable&); // NOLINT + + int value_; +}; + +::std::ostream& operator<<(::std::ostream& os, const Uncopyable& value) { + return os << value.value(); +} + + +bool IsPositiveUncopyable(const Uncopyable& x) { + return x.value() > 0; +} + +// A subroutine used by the following test. +void TestAssertNonPositive() { + Uncopyable y(-1); + ASSERT_PRED1(IsPositiveUncopyable, y); +} +// A subroutine used by the following test. +void TestAssertEqualsUncopyable() { + Uncopyable x(5); + Uncopyable y(-1); + ASSERT_EQ(x, y); +} + +// Tests that uncopyable objects can be used in assertions. +TEST(AssertionTest, AssertWorksWithUncopyableObject) { + Uncopyable x(5); + ASSERT_PRED1(IsPositiveUncopyable, x); + ASSERT_EQ(x, x); + EXPECT_FATAL_FAILURE(TestAssertNonPositive(), + "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1"); + EXPECT_FATAL_FAILURE(TestAssertEqualsUncopyable(), + "Expected equality of these values:\n" + " x\n Which is: 5\n y\n Which is: -1"); +} + +// Tests that uncopyable objects can be used in expects. +TEST(AssertionTest, ExpectWorksWithUncopyableObject) { + Uncopyable x(5); + EXPECT_PRED1(IsPositiveUncopyable, x); + Uncopyable y(-1); + EXPECT_NONFATAL_FAILURE(EXPECT_PRED1(IsPositiveUncopyable, y), + "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1"); + EXPECT_EQ(x, x); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), + "Expected equality of these values:\n" + " x\n Which is: 5\n y\n Which is: -1"); +} + +enum NamedEnum { + kE1 = 0, + kE2 = 1 +}; + +TEST(AssertionTest, NamedEnum) { + EXPECT_EQ(kE1, kE1); + EXPECT_LT(kE1, kE2); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Which is: 0"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Which is: 1"); +} + +// Sun Studio and HP aCC2reject this code. +#if !defined(__SUNPRO_CC) && !defined(__HP_aCC) + +// Tests using assertions with anonymous enums. +enum { + kCaseA = -1, + +# if GTEST_OS_LINUX + + // We want to test the case where the size of the anonymous enum is + // larger than sizeof(int), to make sure our implementation of the + // assertions doesn't truncate the enums. However, MSVC + // (incorrectly) doesn't allow an enum value to exceed the range of + // an int, so this has to be conditionally compiled. + // + // On Linux, kCaseB and kCaseA have the same value when truncated to + // int size. We want to test whether this will confuse the + // assertions. + kCaseB = testing::internal::kMaxBiggestInt, + +# else + + kCaseB = INT_MAX, + +# endif // GTEST_OS_LINUX + + kCaseC = 42 +}; + +TEST(AssertionTest, AnonymousEnum) { +# if GTEST_OS_LINUX + + EXPECT_EQ(static_cast(kCaseA), static_cast(kCaseB)); + +# endif // GTEST_OS_LINUX + + EXPECT_EQ(kCaseA, kCaseA); + EXPECT_NE(kCaseA, kCaseB); + EXPECT_LT(kCaseA, kCaseB); + EXPECT_LE(kCaseA, kCaseB); + EXPECT_GT(kCaseB, kCaseA); + EXPECT_GE(kCaseA, kCaseA); + EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseB), + "(kCaseA) >= (kCaseB)"); + EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseC), + "-1 vs 42"); + + ASSERT_EQ(kCaseA, kCaseA); + ASSERT_NE(kCaseA, kCaseB); + ASSERT_LT(kCaseA, kCaseB); + ASSERT_LE(kCaseA, kCaseB); + ASSERT_GT(kCaseB, kCaseA); + ASSERT_GE(kCaseA, kCaseA); + +# ifndef __BORLANDC__ + + // ICE's in C++Builder. + EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseB), + " kCaseB\n Which is: "); + EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC), + "\n Which is: 42"); +# endif + + EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC), + "\n Which is: -1"); +} + +#endif // !GTEST_OS_MAC && !defined(__SUNPRO_CC) + +#if GTEST_OS_WINDOWS + +static HRESULT UnexpectedHRESULTFailure() { + return E_UNEXPECTED; +} + +static HRESULT OkHRESULTSuccess() { + return S_OK; +} + +static HRESULT FalseHRESULTSuccess() { + return S_FALSE; +} + +// HRESULT assertion tests test both zero and non-zero +// success codes as well as failure message for each. +// +// Windows CE doesn't support message texts. +TEST(HRESULTAssertionTest, EXPECT_HRESULT_SUCCEEDED) { + EXPECT_HRESULT_SUCCEEDED(S_OK); + EXPECT_HRESULT_SUCCEEDED(S_FALSE); + + EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()), + "Expected: (UnexpectedHRESULTFailure()) succeeds.\n" + " Actual: 0x8000FFFF"); +} + +TEST(HRESULTAssertionTest, ASSERT_HRESULT_SUCCEEDED) { + ASSERT_HRESULT_SUCCEEDED(S_OK); + ASSERT_HRESULT_SUCCEEDED(S_FALSE); + + EXPECT_FATAL_FAILURE(ASSERT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()), + "Expected: (UnexpectedHRESULTFailure()) succeeds.\n" + " Actual: 0x8000FFFF"); +} + +TEST(HRESULTAssertionTest, EXPECT_HRESULT_FAILED) { + EXPECT_HRESULT_FAILED(E_UNEXPECTED); + + EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(OkHRESULTSuccess()), + "Expected: (OkHRESULTSuccess()) fails.\n" + " Actual: 0x0"); + EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(FalseHRESULTSuccess()), + "Expected: (FalseHRESULTSuccess()) fails.\n" + " Actual: 0x1"); +} + +TEST(HRESULTAssertionTest, ASSERT_HRESULT_FAILED) { + ASSERT_HRESULT_FAILED(E_UNEXPECTED); + +# ifndef __BORLANDC__ + + // ICE's in C++Builder 2007 and 2009. + EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(OkHRESULTSuccess()), + "Expected: (OkHRESULTSuccess()) fails.\n" + " Actual: 0x0"); +# endif + + EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(FalseHRESULTSuccess()), + "Expected: (FalseHRESULTSuccess()) fails.\n" + " Actual: 0x1"); +} + +// Tests that streaming to the HRESULT macros works. +TEST(HRESULTAssertionTest, Streaming) { + EXPECT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure"; + ASSERT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure"; + EXPECT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure"; + ASSERT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure"; + + EXPECT_NONFATAL_FAILURE( + EXPECT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure", + "expected failure"); + +# ifndef __BORLANDC__ + + // ICE's in C++Builder 2007 and 2009. + EXPECT_FATAL_FAILURE( + ASSERT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure", + "expected failure"); +# endif + + EXPECT_NONFATAL_FAILURE( + EXPECT_HRESULT_FAILED(S_OK) << "expected failure", + "expected failure"); + + EXPECT_FATAL_FAILURE( + ASSERT_HRESULT_FAILED(S_OK) << "expected failure", + "expected failure"); +} + +#endif // GTEST_OS_WINDOWS + +#ifdef __BORLANDC__ +// Silences warnings: "Condition is always true", "Unreachable code" +# pragma option push -w-ccc -w-rch +#endif + +// Tests that the assertion macros behave like single statements. +TEST(AssertionSyntaxTest, BasicAssertionsBehavesLikeSingleStatement) { + if (AlwaysFalse()) + ASSERT_TRUE(false) << "This should never be executed; " + "It's a compilation test only."; + + if (AlwaysTrue()) + EXPECT_FALSE(false); + else + ; // NOLINT + + if (AlwaysFalse()) + ASSERT_LT(1, 3); + + if (AlwaysFalse()) + ; // NOLINT + else + EXPECT_GT(3, 2) << ""; +} + +#if GTEST_HAS_EXCEPTIONS +// Tests that the compiler will not complain about unreachable code in the +// EXPECT_THROW/EXPECT_ANY_THROW/EXPECT_NO_THROW macros. +TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) { + int n = 0; + + EXPECT_THROW(throw 1, int); + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(n++, int), ""); + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(throw 1, const char*), ""); + EXPECT_NO_THROW(n++); + EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(throw 1), ""); + EXPECT_ANY_THROW(throw 1); + EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(n++), ""); +} + +TEST(AssertionSyntaxTest, ExceptionAssertionsBehavesLikeSingleStatement) { + if (AlwaysFalse()) + EXPECT_THROW(ThrowNothing(), bool); + + if (AlwaysTrue()) + EXPECT_THROW(ThrowAnInteger(), int); + else + ; // NOLINT + + if (AlwaysFalse()) + EXPECT_NO_THROW(ThrowAnInteger()); + + if (AlwaysTrue()) + EXPECT_NO_THROW(ThrowNothing()); + else + ; // NOLINT + + if (AlwaysFalse()) + EXPECT_ANY_THROW(ThrowNothing()); + + if (AlwaysTrue()) + EXPECT_ANY_THROW(ThrowAnInteger()); + else + ; // NOLINT +} +#endif // GTEST_HAS_EXCEPTIONS + +TEST(AssertionSyntaxTest, NoFatalFailureAssertionsBehavesLikeSingleStatement) { + if (AlwaysFalse()) + EXPECT_NO_FATAL_FAILURE(FAIL()) << "This should never be executed. " + << "It's a compilation test only."; + else + ; // NOLINT + + if (AlwaysFalse()) + ASSERT_NO_FATAL_FAILURE(FAIL()) << ""; + else + ; // NOLINT + + if (AlwaysTrue()) + EXPECT_NO_FATAL_FAILURE(SUCCEED()); + else + ; // NOLINT + + if (AlwaysFalse()) + ; // NOLINT + else + ASSERT_NO_FATAL_FAILURE(SUCCEED()); +} + +// Tests that the assertion macros work well with switch statements. +TEST(AssertionSyntaxTest, WorksWithSwitch) { + switch (0) { + case 1: + break; + default: + ASSERT_TRUE(true); + } + + switch (0) + case 0: + EXPECT_FALSE(false) << "EXPECT_FALSE failed in switch case"; + + // Binary assertions are implemented using a different code path + // than the Boolean assertions. Hence we test them separately. + switch (0) { + case 1: + default: + ASSERT_EQ(1, 1) << "ASSERT_EQ failed in default switch handler"; + } + + switch (0) + case 0: + EXPECT_NE(1, 2); +} + +#if GTEST_HAS_EXCEPTIONS + +void ThrowAString() { + throw "std::string"; +} + +// Test that the exception assertion macros compile and work with const +// type qualifier. +TEST(AssertionSyntaxTest, WorksWithConst) { + ASSERT_THROW(ThrowAString(), const char*); + + EXPECT_THROW(ThrowAString(), const char*); +} + +#endif // GTEST_HAS_EXCEPTIONS + +} // namespace + +namespace testing { + +// Tests that Google Test tracks SUCCEED*. +TEST(SuccessfulAssertionTest, SUCCEED) { + SUCCEED(); + SUCCEED() << "OK"; + EXPECT_EQ(2, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +// Tests that Google Test doesn't track successful EXPECT_*. +TEST(SuccessfulAssertionTest, EXPECT) { + EXPECT_TRUE(true); + EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +// Tests that Google Test doesn't track successful EXPECT_STR*. +TEST(SuccessfulAssertionTest, EXPECT_STR) { + EXPECT_STREQ("", ""); + EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +// Tests that Google Test doesn't track successful ASSERT_*. +TEST(SuccessfulAssertionTest, ASSERT) { + ASSERT_TRUE(true); + EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +// Tests that Google Test doesn't track successful ASSERT_STR*. +TEST(SuccessfulAssertionTest, ASSERT_STR) { + ASSERT_STREQ("", ""); + EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count()); +} + +} // namespace testing + +namespace { + +// Tests the message streaming variation of assertions. + +TEST(AssertionWithMessageTest, EXPECT) { + EXPECT_EQ(1, 1) << "This should succeed."; + EXPECT_NONFATAL_FAILURE(EXPECT_NE(1, 1) << "Expected failure #1.", + "Expected failure #1"); + EXPECT_LE(1, 2) << "This should succeed."; + EXPECT_NONFATAL_FAILURE(EXPECT_LT(1, 0) << "Expected failure #2.", + "Expected failure #2."); + EXPECT_GE(1, 0) << "This should succeed."; + EXPECT_NONFATAL_FAILURE(EXPECT_GT(1, 2) << "Expected failure #3.", + "Expected failure #3."); + + EXPECT_STREQ("1", "1") << "This should succeed."; + EXPECT_NONFATAL_FAILURE(EXPECT_STRNE("1", "1") << "Expected failure #4.", + "Expected failure #4."); + EXPECT_STRCASEEQ("a", "A") << "This should succeed."; + EXPECT_NONFATAL_FAILURE(EXPECT_STRCASENE("a", "A") << "Expected failure #5.", + "Expected failure #5."); + + EXPECT_FLOAT_EQ(1, 1) << "This should succeed."; + EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1, 1.2) << "Expected failure #6.", + "Expected failure #6."); + EXPECT_NEAR(1, 1.1, 0.2) << "This should succeed."; +} + +TEST(AssertionWithMessageTest, ASSERT) { + ASSERT_EQ(1, 1) << "This should succeed."; + ASSERT_NE(1, 2) << "This should succeed."; + ASSERT_LE(1, 2) << "This should succeed."; + ASSERT_LT(1, 2) << "This should succeed."; + ASSERT_GE(1, 0) << "This should succeed."; + EXPECT_FATAL_FAILURE(ASSERT_GT(1, 2) << "Expected failure.", + "Expected failure."); +} + +TEST(AssertionWithMessageTest, ASSERT_STR) { + ASSERT_STREQ("1", "1") << "This should succeed."; + ASSERT_STRNE("1", "2") << "This should succeed."; + ASSERT_STRCASEEQ("a", "A") << "This should succeed."; + EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("a", "A") << "Expected failure.", + "Expected failure."); +} + +TEST(AssertionWithMessageTest, ASSERT_FLOATING) { + ASSERT_FLOAT_EQ(1, 1) << "This should succeed."; + ASSERT_DOUBLE_EQ(1, 1) << "This should succeed."; + EXPECT_FATAL_FAILURE(ASSERT_NEAR(1,1.2, 0.1) << "Expect failure.", // NOLINT + "Expect failure."); + // To work around a bug in gcc 2.95.0, there is intentionally no + // space after the first comma in the previous statement. +} + +// Tests using ASSERT_FALSE with a streamed message. +TEST(AssertionWithMessageTest, ASSERT_FALSE) { + ASSERT_FALSE(false) << "This shouldn't fail."; + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_FALSE(true) << "Expected failure: " << 2 << " > " << 1 + << " evaluates to " << true; + }, "Expected failure"); +} + +// Tests using FAIL with a streamed message. +TEST(AssertionWithMessageTest, FAIL) { + EXPECT_FATAL_FAILURE(FAIL() << 0, + "0"); +} + +// Tests using SUCCEED with a streamed message. +TEST(AssertionWithMessageTest, SUCCEED) { + SUCCEED() << "Success == " << 1; +} + +// Tests using ASSERT_TRUE with a streamed message. +TEST(AssertionWithMessageTest, ASSERT_TRUE) { + ASSERT_TRUE(true) << "This should succeed."; + ASSERT_TRUE(true) << true; + EXPECT_FATAL_FAILURE( + { // NOLINT + ASSERT_TRUE(false) << static_cast(nullptr) + << static_cast(nullptr); + }, + "(null)(null)"); +} + +#if GTEST_OS_WINDOWS +// Tests using wide strings in assertion messages. +TEST(AssertionWithMessageTest, WideStringMessage) { + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_TRUE(false) << L"This failure is expected.\x8119"; + }, "This failure is expected."); + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_EQ(1, 2) << "This failure is " + << L"expected too.\x8120"; + }, "This failure is expected too."); +} +#endif // GTEST_OS_WINDOWS + +// Tests EXPECT_TRUE. +TEST(ExpectTest, EXPECT_TRUE) { + EXPECT_TRUE(true) << "Intentional success"; + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "Intentional failure #1.", + "Intentional failure #1."); + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "Intentional failure #2.", + "Intentional failure #2."); + EXPECT_TRUE(2 > 1); // NOLINT + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 < 1), + "Value of: 2 < 1\n" + " Actual: false\n" + "Expected: true"); + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 > 3), + "2 > 3"); +} + +// Tests EXPECT_TRUE(predicate) for predicates returning AssertionResult. +TEST(ExpectTest, ExpectTrueWithAssertionResult) { + EXPECT_TRUE(ResultIsEven(2)); + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEven(3)), + "Value of: ResultIsEven(3)\n" + " Actual: false (3 is odd)\n" + "Expected: true"); + EXPECT_TRUE(ResultIsEvenNoExplanation(2)); + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEvenNoExplanation(3)), + "Value of: ResultIsEvenNoExplanation(3)\n" + " Actual: false (3 is odd)\n" + "Expected: true"); +} + +// Tests EXPECT_FALSE with a streamed message. +TEST(ExpectTest, EXPECT_FALSE) { + EXPECT_FALSE(2 < 1); // NOLINT + EXPECT_FALSE(false) << "Intentional success"; + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "Intentional failure #1.", + "Intentional failure #1."); + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "Intentional failure #2.", + "Intentional failure #2."); + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 > 1), + "Value of: 2 > 1\n" + " Actual: true\n" + "Expected: false"); + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 < 3), + "2 < 3"); +} + +// Tests EXPECT_FALSE(predicate) for predicates returning AssertionResult. +TEST(ExpectTest, ExpectFalseWithAssertionResult) { + EXPECT_FALSE(ResultIsEven(3)); + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEven(2)), + "Value of: ResultIsEven(2)\n" + " Actual: true (2 is even)\n" + "Expected: false"); + EXPECT_FALSE(ResultIsEvenNoExplanation(3)); + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEvenNoExplanation(2)), + "Value of: ResultIsEvenNoExplanation(2)\n" + " Actual: true\n" + "Expected: false"); +} + +#ifdef __BORLANDC__ +// Restores warnings after previous "#pragma option push" suppressed them +# pragma option pop +#endif + +// Tests EXPECT_EQ. +TEST(ExpectTest, EXPECT_EQ) { + EXPECT_EQ(5, 2 + 3); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2*3), + "Expected equality of these values:\n" + " 5\n" + " 2*3\n" + " Which is: 6"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2 - 3), + "2 - 3"); +} + +// Tests using EXPECT_EQ on double values. The purpose is to make +// sure that the specialization we did for integer and anonymous enums +// isn't used for double arguments. +TEST(ExpectTest, EXPECT_EQ_Double) { + // A success. + EXPECT_EQ(5.6, 5.6); + + // A failure. + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5.1, 5.2), + "5.1"); +} + +// Tests EXPECT_EQ(NULL, pointer). +TEST(ExpectTest, EXPECT_EQ_NULL) { + // A success. + const char* p = nullptr; + // Some older GCC versions may issue a spurious warning in this or the next + // assertion statement. This warning should not be suppressed with + // static_cast since the test verifies the ability to use bare NULL as the + // expected parameter to the macro. + EXPECT_EQ(nullptr, p); + + // A failure. + int n = 0; + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(nullptr, &n), " &n\n Which is:"); +} + +// Tests EXPECT_EQ(0, non_pointer). Since the literal 0 can be +// treated as a null pointer by the compiler, we need to make sure +// that EXPECT_EQ(0, non_pointer) isn't interpreted by Google Test as +// EXPECT_EQ(static_cast(NULL), non_pointer). +TEST(ExpectTest, EXPECT_EQ_0) { + int n = 0; + + // A success. + EXPECT_EQ(0, n); + + // A failure. + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(0, 5.6), + " 0\n 5.6"); +} + +// Tests EXPECT_NE. +TEST(ExpectTest, EXPECT_NE) { + EXPECT_NE(6, 7); + + EXPECT_NONFATAL_FAILURE(EXPECT_NE('a', 'a'), + "Expected: ('a') != ('a'), " + "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)"); + EXPECT_NONFATAL_FAILURE(EXPECT_NE(2, 2), + "2"); + char* const p0 = nullptr; + EXPECT_NONFATAL_FAILURE(EXPECT_NE(p0, p0), + "p0"); + // Only way to get the Nokia compiler to compile the cast + // is to have a separate void* variable first. Putting + // the two casts on the same line doesn't work, neither does + // a direct C-style to char*. + void* pv1 = (void*)0x1234; // NOLINT + char* const p1 = reinterpret_cast(pv1); + EXPECT_NONFATAL_FAILURE(EXPECT_NE(p1, p1), + "p1"); +} + +// Tests EXPECT_LE. +TEST(ExpectTest, EXPECT_LE) { + EXPECT_LE(2, 3); + EXPECT_LE(2, 2); + EXPECT_NONFATAL_FAILURE(EXPECT_LE(2, 0), + "Expected: (2) <= (0), actual: 2 vs 0"); + EXPECT_NONFATAL_FAILURE(EXPECT_LE(1.1, 0.9), + "(1.1) <= (0.9)"); +} + +// Tests EXPECT_LT. +TEST(ExpectTest, EXPECT_LT) { + EXPECT_LT(2, 3); + EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 2), + "Expected: (2) < (2), actual: 2 vs 2"); + EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1), + "(2) < (1)"); +} + +// Tests EXPECT_GE. +TEST(ExpectTest, EXPECT_GE) { + EXPECT_GE(2, 1); + EXPECT_GE(2, 2); + EXPECT_NONFATAL_FAILURE(EXPECT_GE(2, 3), + "Expected: (2) >= (3), actual: 2 vs 3"); + EXPECT_NONFATAL_FAILURE(EXPECT_GE(0.9, 1.1), + "(0.9) >= (1.1)"); +} + +// Tests EXPECT_GT. +TEST(ExpectTest, EXPECT_GT) { + EXPECT_GT(2, 1); + EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 2), + "Expected: (2) > (2), actual: 2 vs 2"); + EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 3), + "(2) > (3)"); +} + +#if GTEST_HAS_EXCEPTIONS + +// Tests EXPECT_THROW. +TEST(ExpectTest, EXPECT_THROW) { + EXPECT_THROW(ThrowAnInteger(), int); + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool), + "Expected: ThrowAnInteger() throws an exception of " + "type bool.\n Actual: it throws a different type."); + EXPECT_NONFATAL_FAILURE( + EXPECT_THROW(ThrowNothing(), bool), + "Expected: ThrowNothing() throws an exception of type bool.\n" + " Actual: it throws nothing."); +} + +// Tests EXPECT_NO_THROW. +TEST(ExpectTest, EXPECT_NO_THROW) { + EXPECT_NO_THROW(ThrowNothing()); + EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()), + "Expected: ThrowAnInteger() doesn't throw an " + "exception.\n Actual: it throws."); +} + +// Tests EXPECT_ANY_THROW. +TEST(ExpectTest, EXPECT_ANY_THROW) { + EXPECT_ANY_THROW(ThrowAnInteger()); + EXPECT_NONFATAL_FAILURE( + EXPECT_ANY_THROW(ThrowNothing()), + "Expected: ThrowNothing() throws an exception.\n" + " Actual: it doesn't."); +} + +#endif // GTEST_HAS_EXCEPTIONS + +// Make sure we deal with the precedence of <<. +TEST(ExpectTest, ExpectPrecedence) { + EXPECT_EQ(1 < 2, true); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(true, true && false), + " true && false\n Which is: false"); +} + + +// Tests the StreamableToString() function. + +// Tests using StreamableToString() on a scalar. +TEST(StreamableToStringTest, Scalar) { + EXPECT_STREQ("5", StreamableToString(5).c_str()); +} + +// Tests using StreamableToString() on a non-char pointer. +TEST(StreamableToStringTest, Pointer) { + int n = 0; + int* p = &n; + EXPECT_STRNE("(null)", StreamableToString(p).c_str()); +} + +// Tests using StreamableToString() on a NULL non-char pointer. +TEST(StreamableToStringTest, NullPointer) { + int* p = nullptr; + EXPECT_STREQ("(null)", StreamableToString(p).c_str()); +} + +// Tests using StreamableToString() on a C string. +TEST(StreamableToStringTest, CString) { + EXPECT_STREQ("Foo", StreamableToString("Foo").c_str()); +} + +// Tests using StreamableToString() on a NULL C string. +TEST(StreamableToStringTest, NullCString) { + char* p = nullptr; + EXPECT_STREQ("(null)", StreamableToString(p).c_str()); +} + +// Tests using streamable values as assertion messages. + +// Tests using std::string as an assertion message. +TEST(StreamableTest, string) { + static const std::string str( + "This failure message is a std::string, and is expected."); + EXPECT_FATAL_FAILURE(FAIL() << str, + str.c_str()); +} + +// Tests that we can output strings containing embedded NULs. +// Limited to Linux because we can only do this with std::string's. +TEST(StreamableTest, stringWithEmbeddedNUL) { + static const char char_array_with_nul[] = + "Here's a NUL\0 and some more string"; + static const std::string string_with_nul(char_array_with_nul, + sizeof(char_array_with_nul) + - 1); // drops the trailing NUL + EXPECT_FATAL_FAILURE(FAIL() << string_with_nul, + "Here's a NUL\\0 and some more string"); +} + +// Tests that we can output a NUL char. +TEST(StreamableTest, NULChar) { + EXPECT_FATAL_FAILURE({ // NOLINT + FAIL() << "A NUL" << '\0' << " and some more string"; + }, "A NUL\\0 and some more string"); +} + +// Tests using int as an assertion message. +TEST(StreamableTest, int) { + EXPECT_FATAL_FAILURE(FAIL() << 900913, + "900913"); +} + +// Tests using NULL char pointer as an assertion message. +// +// In MSVC, streaming a NULL char * causes access violation. Google Test +// implemented a workaround (substituting "(null)" for NULL). This +// tests whether the workaround works. +TEST(StreamableTest, NullCharPtr) { + EXPECT_FATAL_FAILURE(FAIL() << static_cast(nullptr), "(null)"); +} + +// Tests that basic IO manipulators (endl, ends, and flush) can be +// streamed to testing::Message. +TEST(StreamableTest, BasicIoManip) { + EXPECT_FATAL_FAILURE({ // NOLINT + FAIL() << "Line 1." << std::endl + << "A NUL char " << std::ends << std::flush << " in line 2."; + }, "Line 1.\nA NUL char \\0 in line 2."); +} + +// Tests the macros that haven't been covered so far. + +void AddFailureHelper(bool* aborted) { + *aborted = true; + ADD_FAILURE() << "Intentional failure."; + *aborted = false; +} + +// Tests ADD_FAILURE. +TEST(MacroTest, ADD_FAILURE) { + bool aborted = true; + EXPECT_NONFATAL_FAILURE(AddFailureHelper(&aborted), + "Intentional failure."); + EXPECT_FALSE(aborted); +} + +// Tests ADD_FAILURE_AT. +TEST(MacroTest, ADD_FAILURE_AT) { + // Verifies that ADD_FAILURE_AT does generate a nonfatal failure and + // the failure message contains the user-streamed part. + EXPECT_NONFATAL_FAILURE(ADD_FAILURE_AT("foo.cc", 42) << "Wrong!", "Wrong!"); + + // Verifies that the user-streamed part is optional. + EXPECT_NONFATAL_FAILURE(ADD_FAILURE_AT("foo.cc", 42), "Failed"); + + // Unfortunately, we cannot verify that the failure message contains + // the right file path and line number the same way, as + // EXPECT_NONFATAL_FAILURE() doesn't get to see the file path and + // line number. Instead, we do that in googletest-output-test_.cc. +} + +// Tests FAIL. +TEST(MacroTest, FAIL) { + EXPECT_FATAL_FAILURE(FAIL(), + "Failed"); + EXPECT_FATAL_FAILURE(FAIL() << "Intentional failure.", + "Intentional failure."); +} + +// Tests GTEST_FAIL_AT. +TEST(MacroTest, GTEST_FAIL_AT) { + // Verifies that GTEST_FAIL_AT does generate a fatal failure and + // the failure message contains the user-streamed part. + EXPECT_FATAL_FAILURE(GTEST_FAIL_AT("foo.cc", 42) << "Wrong!", "Wrong!"); + + // Verifies that the user-streamed part is optional. + EXPECT_FATAL_FAILURE(GTEST_FAIL_AT("foo.cc", 42), "Failed"); + + // See the ADD_FAIL_AT test above to see how we test that the failure message + // contains the right filename and line number -- the same applies here. +} + +// Tests SUCCEED +TEST(MacroTest, SUCCEED) { + SUCCEED(); + SUCCEED() << "Explicit success."; +} + +// Tests for EXPECT_EQ() and ASSERT_EQ(). +// +// These tests fail *intentionally*, s.t. the failure messages can be +// generated and tested. +// +// We have different tests for different argument types. + +// Tests using bool values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, Bool) { + EXPECT_EQ(true, true); + EXPECT_FATAL_FAILURE({ + bool false_value = false; + ASSERT_EQ(false_value, true); + }, " false_value\n Which is: false\n true"); +} + +// Tests using int values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, Int) { + ASSERT_EQ(32, 32); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(32, 33), + " 32\n 33"); +} + +// Tests using time_t values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, Time_T) { + EXPECT_EQ(static_cast(0), + static_cast(0)); + EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(0), + static_cast(1234)), + "1234"); +} + +// Tests using char values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, Char) { + ASSERT_EQ('z', 'z'); + const char ch = 'b'; + EXPECT_NONFATAL_FAILURE(EXPECT_EQ('\0', ch), + " ch\n Which is: 'b'"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ('a', ch), + " ch\n Which is: 'b'"); +} + +// Tests using wchar_t values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, WideChar) { + EXPECT_EQ(L'b', L'b'); + + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'\0', L'x'), + "Expected equality of these values:\n" + " L'\0'\n" + " Which is: L'\0' (0, 0x0)\n" + " L'x'\n" + " Which is: L'x' (120, 0x78)"); + + static wchar_t wchar; + wchar = L'b'; + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'a', wchar), + "wchar"); + wchar = 0x8119; + EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(0x8120), wchar), + " wchar\n Which is: L'"); +} + +// Tests using ::std::string values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, StdString) { + // Compares a const char* to an std::string that has identical + // content. + ASSERT_EQ("Test", ::std::string("Test")); + + // Compares two identical std::strings. + static const ::std::string str1("A * in the middle"); + static const ::std::string str2(str1); + EXPECT_EQ(str1, str2); + + // Compares a const char* to an std::string that has different + // content + EXPECT_NONFATAL_FAILURE(EXPECT_EQ("Test", ::std::string("test")), + "\"test\""); + + // Compares an std::string to a char* that has different content. + char* const p1 = const_cast("foo"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(::std::string("bar"), p1), + "p1"); + + // Compares two std::strings that have different contents, one of + // which having a NUL character in the middle. This should fail. + static ::std::string str3(str1); + str3.at(2) = '\0'; + EXPECT_FATAL_FAILURE(ASSERT_EQ(str1, str3), + " str3\n Which is: \"A \\0 in the middle\""); +} + +#if GTEST_HAS_STD_WSTRING + +// Tests using ::std::wstring values in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, StdWideString) { + // Compares two identical std::wstrings. + const ::std::wstring wstr1(L"A * in the middle"); + const ::std::wstring wstr2(wstr1); + ASSERT_EQ(wstr1, wstr2); + + // Compares an std::wstring to a const wchar_t* that has identical + // content. + const wchar_t kTestX8119[] = { 'T', 'e', 's', 't', 0x8119, '\0' }; + EXPECT_EQ(::std::wstring(kTestX8119), kTestX8119); + + // Compares an std::wstring to a const wchar_t* that has different + // content. + const wchar_t kTestX8120[] = { 'T', 'e', 's', 't', 0x8120, '\0' }; + EXPECT_NONFATAL_FAILURE({ // NOLINT + EXPECT_EQ(::std::wstring(kTestX8119), kTestX8120); + }, "kTestX8120"); + + // Compares two std::wstrings that have different contents, one of + // which having a NUL character in the middle. + ::std::wstring wstr3(wstr1); + wstr3.at(2) = L'\0'; + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(wstr1, wstr3), + "wstr3"); + + // Compares a wchar_t* to an std::wstring that has different + // content. + EXPECT_FATAL_FAILURE({ // NOLINT + ASSERT_EQ(const_cast(L"foo"), ::std::wstring(L"bar")); + }, ""); +} + +#endif // GTEST_HAS_STD_WSTRING + +// Tests using char pointers in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, CharPointer) { + char* const p0 = nullptr; + // Only way to get the Nokia compiler to compile the cast + // is to have a separate void* variable first. Putting + // the two casts on the same line doesn't work, neither does + // a direct C-style to char*. + void* pv1 = (void*)0x1234; // NOLINT + void* pv2 = (void*)0xABC0; // NOLINT + char* const p1 = reinterpret_cast(pv1); + char* const p2 = reinterpret_cast(pv2); + ASSERT_EQ(p1, p1); + + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2), + " p2\n Which is:"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2), + " p2\n Which is:"); + EXPECT_FATAL_FAILURE(ASSERT_EQ(reinterpret_cast(0x1234), + reinterpret_cast(0xABC0)), + "ABC0"); +} + +// Tests using wchar_t pointers in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, WideCharPointer) { + wchar_t* const p0 = nullptr; + // Only way to get the Nokia compiler to compile the cast + // is to have a separate void* variable first. Putting + // the two casts on the same line doesn't work, neither does + // a direct C-style to char*. + void* pv1 = (void*)0x1234; // NOLINT + void* pv2 = (void*)0xABC0; // NOLINT + wchar_t* const p1 = reinterpret_cast(pv1); + wchar_t* const p2 = reinterpret_cast(pv2); + EXPECT_EQ(p0, p0); + + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2), + " p2\n Which is:"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2), + " p2\n Which is:"); + void* pv3 = (void*)0x1234; // NOLINT + void* pv4 = (void*)0xABC0; // NOLINT + const wchar_t* p3 = reinterpret_cast(pv3); + const wchar_t* p4 = reinterpret_cast(pv4); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p3, p4), + "p4"); +} + +// Tests using other types of pointers in {EXPECT|ASSERT}_EQ. +TEST(EqAssertionTest, OtherPointer) { + ASSERT_EQ(static_cast(nullptr), static_cast(nullptr)); + EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(nullptr), + reinterpret_cast(0x1234)), + "0x1234"); +} + +// A class that supports binary comparison operators but not streaming. +class UnprintableChar { + public: + explicit UnprintableChar(char ch) : char_(ch) {} + + bool operator==(const UnprintableChar& rhs) const { + return char_ == rhs.char_; + } + bool operator!=(const UnprintableChar& rhs) const { + return char_ != rhs.char_; + } + bool operator<(const UnprintableChar& rhs) const { + return char_ < rhs.char_; + } + bool operator<=(const UnprintableChar& rhs) const { + return char_ <= rhs.char_; + } + bool operator>(const UnprintableChar& rhs) const { + return char_ > rhs.char_; + } + bool operator>=(const UnprintableChar& rhs) const { + return char_ >= rhs.char_; + } + + private: + char char_; +}; + +// Tests that ASSERT_EQ() and friends don't require the arguments to +// be printable. +TEST(ComparisonAssertionTest, AcceptsUnprintableArgs) { + const UnprintableChar x('x'), y('y'); + ASSERT_EQ(x, x); + EXPECT_NE(x, y); + ASSERT_LT(x, y); + EXPECT_LE(x, y); + ASSERT_GT(y, x); + EXPECT_GE(x, x); + + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "1-byte object <78>"); + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "1-byte object <79>"); + EXPECT_NONFATAL_FAILURE(EXPECT_LT(y, y), "1-byte object <79>"); + EXPECT_NONFATAL_FAILURE(EXPECT_GT(x, y), "1-byte object <78>"); + EXPECT_NONFATAL_FAILURE(EXPECT_GT(x, y), "1-byte object <79>"); + + // Code tested by EXPECT_FATAL_FAILURE cannot reference local + // variables, so we have to write UnprintableChar('x') instead of x. +#ifndef __BORLANDC__ + // ICE's in C++Builder. + EXPECT_FATAL_FAILURE(ASSERT_NE(UnprintableChar('x'), UnprintableChar('x')), + "1-byte object <78>"); + EXPECT_FATAL_FAILURE(ASSERT_LE(UnprintableChar('y'), UnprintableChar('x')), + "1-byte object <78>"); +#endif + EXPECT_FATAL_FAILURE(ASSERT_LE(UnprintableChar('y'), UnprintableChar('x')), + "1-byte object <79>"); + EXPECT_FATAL_FAILURE(ASSERT_GE(UnprintableChar('x'), UnprintableChar('y')), + "1-byte object <78>"); + EXPECT_FATAL_FAILURE(ASSERT_GE(UnprintableChar('x'), UnprintableChar('y')), + "1-byte object <79>"); +} + +// Tests the FRIEND_TEST macro. + +// This class has a private member we want to test. We will test it +// both in a TEST and in a TEST_F. +class Foo { + public: + Foo() {} + + private: + int Bar() const { return 1; } + + // Declares the friend tests that can access the private member + // Bar(). + FRIEND_TEST(FRIEND_TEST_Test, TEST); + FRIEND_TEST(FRIEND_TEST_Test2, TEST_F); +}; + +// Tests that the FRIEND_TEST declaration allows a TEST to access a +// class's private members. This should compile. +TEST(FRIEND_TEST_Test, TEST) { + ASSERT_EQ(1, Foo().Bar()); +} + +// The fixture needed to test using FRIEND_TEST with TEST_F. +class FRIEND_TEST_Test2 : public Test { + protected: + Foo foo; +}; + +// Tests that the FRIEND_TEST declaration allows a TEST_F to access a +// class's private members. This should compile. +TEST_F(FRIEND_TEST_Test2, TEST_F) { + ASSERT_EQ(1, foo.Bar()); +} + +// Tests the life cycle of Test objects. + +// The test fixture for testing the life cycle of Test objects. +// +// This class counts the number of live test objects that uses this +// fixture. +class TestLifeCycleTest : public Test { + protected: + // Constructor. Increments the number of test objects that uses + // this fixture. + TestLifeCycleTest() { count_++; } + + // Destructor. Decrements the number of test objects that uses this + // fixture. + ~TestLifeCycleTest() override { count_--; } + + // Returns the number of live test objects that uses this fixture. + int count() const { return count_; } + + private: + static int count_; +}; + +int TestLifeCycleTest::count_ = 0; + +// Tests the life cycle of test objects. +TEST_F(TestLifeCycleTest, Test1) { + // There should be only one test object in this test case that's + // currently alive. + ASSERT_EQ(1, count()); +} + +// Tests the life cycle of test objects. +TEST_F(TestLifeCycleTest, Test2) { + // After Test1 is done and Test2 is started, there should still be + // only one live test object, as the object for Test1 should've been + // deleted. + ASSERT_EQ(1, count()); +} + +} // namespace + +// Tests that the copy constructor works when it is NOT optimized away by +// the compiler. +TEST(AssertionResultTest, CopyConstructorWorksWhenNotOptimied) { + // Checks that the copy constructor doesn't try to dereference NULL pointers + // in the source object. + AssertionResult r1 = AssertionSuccess(); + AssertionResult r2 = r1; + // The following line is added to prevent the compiler from optimizing + // away the constructor call. + r1 << "abc"; + + AssertionResult r3 = r1; + EXPECT_EQ(static_cast(r3), static_cast(r1)); + EXPECT_STREQ("abc", r1.message()); +} + +// Tests that AssertionSuccess and AssertionFailure construct +// AssertionResult objects as expected. +TEST(AssertionResultTest, ConstructionWorks) { + AssertionResult r1 = AssertionSuccess(); + EXPECT_TRUE(r1); + EXPECT_STREQ("", r1.message()); + + AssertionResult r2 = AssertionSuccess() << "abc"; + EXPECT_TRUE(r2); + EXPECT_STREQ("abc", r2.message()); + + AssertionResult r3 = AssertionFailure(); + EXPECT_FALSE(r3); + EXPECT_STREQ("", r3.message()); + + AssertionResult r4 = AssertionFailure() << "def"; + EXPECT_FALSE(r4); + EXPECT_STREQ("def", r4.message()); + + AssertionResult r5 = AssertionFailure(Message() << "ghi"); + EXPECT_FALSE(r5); + EXPECT_STREQ("ghi", r5.message()); +} + +// Tests that the negation flips the predicate result but keeps the message. +TEST(AssertionResultTest, NegationWorks) { + AssertionResult r1 = AssertionSuccess() << "abc"; + EXPECT_FALSE(!r1); + EXPECT_STREQ("abc", (!r1).message()); + + AssertionResult r2 = AssertionFailure() << "def"; + EXPECT_TRUE(!r2); + EXPECT_STREQ("def", (!r2).message()); +} + +TEST(AssertionResultTest, StreamingWorks) { + AssertionResult r = AssertionSuccess(); + r << "abc" << 'd' << 0 << true; + EXPECT_STREQ("abcd0true", r.message()); +} + +TEST(AssertionResultTest, CanStreamOstreamManipulators) { + AssertionResult r = AssertionSuccess(); + r << "Data" << std::endl << std::flush << std::ends << "Will be visible"; + EXPECT_STREQ("Data\n\\0Will be visible", r.message()); +} + +// The next test uses explicit conversion operators + +TEST(AssertionResultTest, ConstructibleFromContextuallyConvertibleToBool) { + struct ExplicitlyConvertibleToBool { + explicit operator bool() const { return value; } + bool value; + }; + ExplicitlyConvertibleToBool v1 = {false}; + ExplicitlyConvertibleToBool v2 = {true}; + EXPECT_FALSE(v1); + EXPECT_TRUE(v2); +} + +struct ConvertibleToAssertionResult { + operator AssertionResult() const { return AssertionResult(true); } +}; + +TEST(AssertionResultTest, ConstructibleFromImplicitlyConvertible) { + ConvertibleToAssertionResult obj; + EXPECT_TRUE(obj); +} + +// Tests streaming a user type whose definition and operator << are +// both in the global namespace. +class Base { + public: + explicit Base(int an_x) : x_(an_x) {} + int x() const { return x_; } + private: + int x_; +}; +std::ostream& operator<<(std::ostream& os, + const Base& val) { + return os << val.x(); +} +std::ostream& operator<<(std::ostream& os, + const Base* pointer) { + return os << "(" << pointer->x() << ")"; +} + +TEST(MessageTest, CanStreamUserTypeInGlobalNameSpace) { + Message msg; + Base a(1); + + msg << a << &a; // Uses ::operator<<. + EXPECT_STREQ("1(1)", msg.GetString().c_str()); +} + +// Tests streaming a user type whose definition and operator<< are +// both in an unnamed namespace. +namespace { +class MyTypeInUnnamedNameSpace : public Base { + public: + explicit MyTypeInUnnamedNameSpace(int an_x): Base(an_x) {} +}; +std::ostream& operator<<(std::ostream& os, + const MyTypeInUnnamedNameSpace& val) { + return os << val.x(); +} +std::ostream& operator<<(std::ostream& os, + const MyTypeInUnnamedNameSpace* pointer) { + return os << "(" << pointer->x() << ")"; +} +} // namespace + +TEST(MessageTest, CanStreamUserTypeInUnnamedNameSpace) { + Message msg; + MyTypeInUnnamedNameSpace a(1); + + msg << a << &a; // Uses ::operator<<. + EXPECT_STREQ("1(1)", msg.GetString().c_str()); +} + +// Tests streaming a user type whose definition and operator<< are +// both in a user namespace. +namespace namespace1 { +class MyTypeInNameSpace1 : public Base { + public: + explicit MyTypeInNameSpace1(int an_x): Base(an_x) {} +}; +std::ostream& operator<<(std::ostream& os, + const MyTypeInNameSpace1& val) { + return os << val.x(); +} +std::ostream& operator<<(std::ostream& os, + const MyTypeInNameSpace1* pointer) { + return os << "(" << pointer->x() << ")"; +} +} // namespace namespace1 + +TEST(MessageTest, CanStreamUserTypeInUserNameSpace) { + Message msg; + namespace1::MyTypeInNameSpace1 a(1); + + msg << a << &a; // Uses namespace1::operator<<. + EXPECT_STREQ("1(1)", msg.GetString().c_str()); +} + +// Tests streaming a user type whose definition is in a user namespace +// but whose operator<< is in the global namespace. +namespace namespace2 { +class MyTypeInNameSpace2 : public ::Base { + public: + explicit MyTypeInNameSpace2(int an_x): Base(an_x) {} +}; +} // namespace namespace2 +std::ostream& operator<<(std::ostream& os, + const namespace2::MyTypeInNameSpace2& val) { + return os << val.x(); +} +std::ostream& operator<<(std::ostream& os, + const namespace2::MyTypeInNameSpace2* pointer) { + return os << "(" << pointer->x() << ")"; +} + +TEST(MessageTest, CanStreamUserTypeInUserNameSpaceWithStreamOperatorInGlobal) { + Message msg; + namespace2::MyTypeInNameSpace2 a(1); + + msg << a << &a; // Uses ::operator<<. + EXPECT_STREQ("1(1)", msg.GetString().c_str()); +} + +// Tests streaming NULL pointers to testing::Message. +TEST(MessageTest, NullPointers) { + Message msg; + char* const p1 = nullptr; + unsigned char* const p2 = nullptr; + int* p3 = nullptr; + double* p4 = nullptr; + bool* p5 = nullptr; + Message* p6 = nullptr; + + msg << p1 << p2 << p3 << p4 << p5 << p6; + ASSERT_STREQ("(null)(null)(null)(null)(null)(null)", + msg.GetString().c_str()); +} + +// Tests streaming wide strings to testing::Message. +TEST(MessageTest, WideStrings) { + // Streams a NULL of type const wchar_t*. + const wchar_t* const_wstr = nullptr; + EXPECT_STREQ("(null)", + (Message() << const_wstr).GetString().c_str()); + + // Streams a NULL of type wchar_t*. + wchar_t* wstr = nullptr; + EXPECT_STREQ("(null)", + (Message() << wstr).GetString().c_str()); + + // Streams a non-NULL of type const wchar_t*. + const_wstr = L"abc\x8119"; + EXPECT_STREQ("abc\xe8\x84\x99", + (Message() << const_wstr).GetString().c_str()); + + // Streams a non-NULL of type wchar_t*. + wstr = const_cast(const_wstr); + EXPECT_STREQ("abc\xe8\x84\x99", + (Message() << wstr).GetString().c_str()); +} + + +// This line tests that we can define tests in the testing namespace. +namespace testing { + +// Tests the TestInfo class. + +class TestInfoTest : public Test { + protected: + static const TestInfo* GetTestInfo(const char* test_name) { + const TestSuite* const test_suite = + GetUnitTestImpl()->GetTestSuite("TestInfoTest", "", nullptr, nullptr); + + for (int i = 0; i < test_suite->total_test_count(); ++i) { + const TestInfo* const test_info = test_suite->GetTestInfo(i); + if (strcmp(test_name, test_info->name()) == 0) + return test_info; + } + return nullptr; + } + + static const TestResult* GetTestResult( + const TestInfo* test_info) { + return test_info->result(); + } +}; + +// Tests TestInfo::test_case_name() and TestInfo::name(). +TEST_F(TestInfoTest, Names) { + const TestInfo* const test_info = GetTestInfo("Names"); + + ASSERT_STREQ("TestInfoTest", test_info->test_case_name()); + ASSERT_STREQ("Names", test_info->name()); +} + +// Tests TestInfo::result(). +TEST_F(TestInfoTest, result) { + const TestInfo* const test_info = GetTestInfo("result"); + + // Initially, there is no TestPartResult for this test. + ASSERT_EQ(0, GetTestResult(test_info)->total_part_count()); + + // After the previous assertion, there is still none. + ASSERT_EQ(0, GetTestResult(test_info)->total_part_count()); +} + +#define VERIFY_CODE_LOCATION \ + const int expected_line = __LINE__ - 1; \ + const TestInfo* const test_info = GetUnitTestImpl()->current_test_info(); \ + ASSERT_TRUE(test_info); \ + EXPECT_STREQ(__FILE__, test_info->file()); \ + EXPECT_EQ(expected_line, test_info->line()) + +TEST(CodeLocationForTEST, Verify) { + VERIFY_CODE_LOCATION; +} + +class CodeLocationForTESTF : public Test { +}; + +TEST_F(CodeLocationForTESTF, Verify) { + VERIFY_CODE_LOCATION; +} + +class CodeLocationForTESTP : public TestWithParam { +}; + +TEST_P(CodeLocationForTESTP, Verify) { + VERIFY_CODE_LOCATION; +} + +INSTANTIATE_TEST_SUITE_P(, CodeLocationForTESTP, Values(0)); + +template +class CodeLocationForTYPEDTEST : public Test { +}; + +TYPED_TEST_SUITE(CodeLocationForTYPEDTEST, int); + +TYPED_TEST(CodeLocationForTYPEDTEST, Verify) { + VERIFY_CODE_LOCATION; +} + +template +class CodeLocationForTYPEDTESTP : public Test { +}; + +TYPED_TEST_SUITE_P(CodeLocationForTYPEDTESTP); + +TYPED_TEST_P(CodeLocationForTYPEDTESTP, Verify) { + VERIFY_CODE_LOCATION; +} + +REGISTER_TYPED_TEST_SUITE_P(CodeLocationForTYPEDTESTP, Verify); + +INSTANTIATE_TYPED_TEST_SUITE_P(My, CodeLocationForTYPEDTESTP, int); + +#undef VERIFY_CODE_LOCATION + +// Tests setting up and tearing down a test case. +// Legacy API is deprecated but still available +#ifndef REMOVE_LEGACY_TEST_CASEAPI +class SetUpTestCaseTest : public Test { + protected: + // This will be called once before the first test in this test case + // is run. + static void SetUpTestCase() { + printf("Setting up the test case . . .\n"); + + // Initializes some shared resource. In this simple example, we + // just create a C string. More complex stuff can be done if + // desired. + shared_resource_ = "123"; + + // Increments the number of test cases that have been set up. + counter_++; + + // SetUpTestCase() should be called only once. + EXPECT_EQ(1, counter_); + } + + // This will be called once after the last test in this test case is + // run. + static void TearDownTestCase() { + printf("Tearing down the test case . . .\n"); + + // Decrements the number of test cases that have been set up. + counter_--; + + // TearDownTestCase() should be called only once. + EXPECT_EQ(0, counter_); + + // Cleans up the shared resource. + shared_resource_ = nullptr; + } + + // This will be called before each test in this test case. + void SetUp() override { + // SetUpTestCase() should be called only once, so counter_ should + // always be 1. + EXPECT_EQ(1, counter_); + } + + // Number of test cases that have been set up. + static int counter_; + + // Some resource to be shared by all tests in this test case. + static const char* shared_resource_; +}; + +int SetUpTestCaseTest::counter_ = 0; +const char* SetUpTestCaseTest::shared_resource_ = nullptr; + +// A test that uses the shared resource. +TEST_F(SetUpTestCaseTest, Test1) { EXPECT_STRNE(nullptr, shared_resource_); } + +// Another test that uses the shared resource. +TEST_F(SetUpTestCaseTest, Test2) { + EXPECT_STREQ("123", shared_resource_); +} +#endif // REMOVE_LEGACY_TEST_CASEAPI + +// Tests SetupTestSuite/TearDown TestSuite +class SetUpTestSuiteTest : public Test { + protected: + // This will be called once before the first test in this test case + // is run. + static void SetUpTestSuite() { + printf("Setting up the test suite . . .\n"); + + // Initializes some shared resource. In this simple example, we + // just create a C string. More complex stuff can be done if + // desired. + shared_resource_ = "123"; + + // Increments the number of test cases that have been set up. + counter_++; + + // SetUpTestSuite() should be called only once. + EXPECT_EQ(1, counter_); + } + + // This will be called once after the last test in this test case is + // run. + static void TearDownTestSuite() { + printf("Tearing down the test suite . . .\n"); + + // Decrements the number of test suites that have been set up. + counter_--; + + // TearDownTestSuite() should be called only once. + EXPECT_EQ(0, counter_); + + // Cleans up the shared resource. + shared_resource_ = nullptr; + } + + // This will be called before each test in this test case. + void SetUp() override { + // SetUpTestSuite() should be called only once, so counter_ should + // always be 1. + EXPECT_EQ(1, counter_); + } + + // Number of test suites that have been set up. + static int counter_; + + // Some resource to be shared by all tests in this test case. + static const char* shared_resource_; +}; + +int SetUpTestSuiteTest::counter_ = 0; +const char* SetUpTestSuiteTest::shared_resource_ = nullptr; + +// A test that uses the shared resource. +TEST_F(SetUpTestSuiteTest, TestSetupTestSuite1) { + EXPECT_STRNE(nullptr, shared_resource_); +} + +// Another test that uses the shared resource. +TEST_F(SetUpTestSuiteTest, TestSetupTestSuite2) { + EXPECT_STREQ("123", shared_resource_); +} + +// The ParseFlagsTest test case tests ParseGoogleTestFlagsOnly. + +// The Flags struct stores a copy of all Google Test flags. +struct Flags { + // Constructs a Flags struct where each flag has its default value. + Flags() : also_run_disabled_tests(false), + break_on_failure(false), + catch_exceptions(false), + death_test_use_fork(false), + filter(""), + list_tests(false), + output(""), + print_time(true), + random_seed(0), + repeat(1), + shuffle(false), + stack_trace_depth(kMaxStackTraceDepth), + stream_result_to(""), + throw_on_failure(false) {} + + // Factory methods. + + // Creates a Flags struct where the gtest_also_run_disabled_tests flag has + // the given value. + static Flags AlsoRunDisabledTests(bool also_run_disabled_tests) { + Flags flags; + flags.also_run_disabled_tests = also_run_disabled_tests; + return flags; + } + + // Creates a Flags struct where the gtest_break_on_failure flag has + // the given value. + static Flags BreakOnFailure(bool break_on_failure) { + Flags flags; + flags.break_on_failure = break_on_failure; + return flags; + } + + // Creates a Flags struct where the gtest_catch_exceptions flag has + // the given value. + static Flags CatchExceptions(bool catch_exceptions) { + Flags flags; + flags.catch_exceptions = catch_exceptions; + return flags; + } + + // Creates a Flags struct where the gtest_death_test_use_fork flag has + // the given value. + static Flags DeathTestUseFork(bool death_test_use_fork) { + Flags flags; + flags.death_test_use_fork = death_test_use_fork; + return flags; + } + + // Creates a Flags struct where the gtest_filter flag has the given + // value. + static Flags Filter(const char* filter) { + Flags flags; + flags.filter = filter; + return flags; + } + + // Creates a Flags struct where the gtest_list_tests flag has the + // given value. + static Flags ListTests(bool list_tests) { + Flags flags; + flags.list_tests = list_tests; + return flags; + } + + // Creates a Flags struct where the gtest_output flag has the given + // value. + static Flags Output(const char* output) { + Flags flags; + flags.output = output; + return flags; + } + + // Creates a Flags struct where the gtest_print_time flag has the given + // value. + static Flags PrintTime(bool print_time) { + Flags flags; + flags.print_time = print_time; + return flags; + } + + // Creates a Flags struct where the gtest_random_seed flag has the given + // value. + static Flags RandomSeed(Int32 random_seed) { + Flags flags; + flags.random_seed = random_seed; + return flags; + } + + // Creates a Flags struct where the gtest_repeat flag has the given + // value. + static Flags Repeat(Int32 repeat) { + Flags flags; + flags.repeat = repeat; + return flags; + } + + // Creates a Flags struct where the gtest_shuffle flag has the given + // value. + static Flags Shuffle(bool shuffle) { + Flags flags; + flags.shuffle = shuffle; + return flags; + } + + // Creates a Flags struct where the GTEST_FLAG(stack_trace_depth) flag has + // the given value. + static Flags StackTraceDepth(Int32 stack_trace_depth) { + Flags flags; + flags.stack_trace_depth = stack_trace_depth; + return flags; + } + + // Creates a Flags struct where the GTEST_FLAG(stream_result_to) flag has + // the given value. + static Flags StreamResultTo(const char* stream_result_to) { + Flags flags; + flags.stream_result_to = stream_result_to; + return flags; + } + + // Creates a Flags struct where the gtest_throw_on_failure flag has + // the given value. + static Flags ThrowOnFailure(bool throw_on_failure) { + Flags flags; + flags.throw_on_failure = throw_on_failure; + return flags; + } + + // These fields store the flag values. + bool also_run_disabled_tests; + bool break_on_failure; + bool catch_exceptions; + bool death_test_use_fork; + const char* filter; + bool list_tests; + const char* output; + bool print_time; + Int32 random_seed; + Int32 repeat; + bool shuffle; + Int32 stack_trace_depth; + const char* stream_result_to; + bool throw_on_failure; +}; + +// Fixture for testing ParseGoogleTestFlagsOnly(). +class ParseFlagsTest : public Test { + protected: + // Clears the flags before each test. + void SetUp() override { + GTEST_FLAG(also_run_disabled_tests) = false; + GTEST_FLAG(break_on_failure) = false; + GTEST_FLAG(catch_exceptions) = false; + GTEST_FLAG(death_test_use_fork) = false; + GTEST_FLAG(filter) = ""; + GTEST_FLAG(list_tests) = false; + GTEST_FLAG(output) = ""; + GTEST_FLAG(print_time) = true; + GTEST_FLAG(random_seed) = 0; + GTEST_FLAG(repeat) = 1; + GTEST_FLAG(shuffle) = false; + GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth; + GTEST_FLAG(stream_result_to) = ""; + GTEST_FLAG(throw_on_failure) = false; + } + + // Asserts that two narrow or wide string arrays are equal. + template + static void AssertStringArrayEq(int size1, CharType** array1, int size2, + CharType** array2) { + ASSERT_EQ(size1, size2) << " Array sizes different."; + + for (int i = 0; i != size1; i++) { + ASSERT_STREQ(array1[i], array2[i]) << " where i == " << i; + } + } + + // Verifies that the flag values match the expected values. + static void CheckFlags(const Flags& expected) { + EXPECT_EQ(expected.also_run_disabled_tests, + GTEST_FLAG(also_run_disabled_tests)); + EXPECT_EQ(expected.break_on_failure, GTEST_FLAG(break_on_failure)); + EXPECT_EQ(expected.catch_exceptions, GTEST_FLAG(catch_exceptions)); + EXPECT_EQ(expected.death_test_use_fork, GTEST_FLAG(death_test_use_fork)); + EXPECT_STREQ(expected.filter, GTEST_FLAG(filter).c_str()); + EXPECT_EQ(expected.list_tests, GTEST_FLAG(list_tests)); + EXPECT_STREQ(expected.output, GTEST_FLAG(output).c_str()); + EXPECT_EQ(expected.print_time, GTEST_FLAG(print_time)); + EXPECT_EQ(expected.random_seed, GTEST_FLAG(random_seed)); + EXPECT_EQ(expected.repeat, GTEST_FLAG(repeat)); + EXPECT_EQ(expected.shuffle, GTEST_FLAG(shuffle)); + EXPECT_EQ(expected.stack_trace_depth, GTEST_FLAG(stack_trace_depth)); + EXPECT_STREQ(expected.stream_result_to, + GTEST_FLAG(stream_result_to).c_str()); + EXPECT_EQ(expected.throw_on_failure, GTEST_FLAG(throw_on_failure)); + } + + // Parses a command line (specified by argc1 and argv1), then + // verifies that the flag values are expected and that the + // recognized flags are removed from the command line. + template + static void TestParsingFlags(int argc1, const CharType** argv1, + int argc2, const CharType** argv2, + const Flags& expected, bool should_print_help) { + const bool saved_help_flag = ::testing::internal::g_help_flag; + ::testing::internal::g_help_flag = false; + +# if GTEST_HAS_STREAM_REDIRECTION + CaptureStdout(); +# endif + + // Parses the command line. + internal::ParseGoogleTestFlagsOnly(&argc1, const_cast(argv1)); + +# if GTEST_HAS_STREAM_REDIRECTION + const std::string captured_stdout = GetCapturedStdout(); +# endif + + // Verifies the flag values. + CheckFlags(expected); + + // Verifies that the recognized flags are removed from the command + // line. + AssertStringArrayEq(argc1 + 1, argv1, argc2 + 1, argv2); + + // ParseGoogleTestFlagsOnly should neither set g_help_flag nor print the + // help message for the flags it recognizes. + EXPECT_EQ(should_print_help, ::testing::internal::g_help_flag); + +# if GTEST_HAS_STREAM_REDIRECTION + const char* const expected_help_fragment = + "This program contains tests written using"; + if (should_print_help) { + EXPECT_PRED_FORMAT2(IsSubstring, expected_help_fragment, captured_stdout); + } else { + EXPECT_PRED_FORMAT2(IsNotSubstring, + expected_help_fragment, captured_stdout); + } +# endif // GTEST_HAS_STREAM_REDIRECTION + + ::testing::internal::g_help_flag = saved_help_flag; + } + + // This macro wraps TestParsingFlags s.t. the user doesn't need + // to specify the array sizes. + +# define GTEST_TEST_PARSING_FLAGS_(argv1, argv2, expected, should_print_help) \ + TestParsingFlags(sizeof(argv1)/sizeof(*argv1) - 1, argv1, \ + sizeof(argv2)/sizeof(*argv2) - 1, argv2, \ + expected, should_print_help) +}; + +// Tests parsing an empty command line. +TEST_F(ParseFlagsTest, Empty) { + const char* argv[] = {nullptr}; + + const char* argv2[] = {nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false); +} + +// Tests parsing a command line that has no flag. +TEST_F(ParseFlagsTest, NoFlag) { + const char* argv[] = {"foo.exe", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false); +} + +// Tests parsing a bad --gtest_filter flag. +TEST_F(ParseFlagsTest, FilterBad) { + const char* argv[] = {"foo.exe", "--gtest_filter", nullptr}; + + const char* argv2[] = {"foo.exe", "--gtest_filter", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), true); +} + +// Tests parsing an empty --gtest_filter flag. +TEST_F(ParseFlagsTest, FilterEmpty) { + const char* argv[] = {"foo.exe", "--gtest_filter=", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), false); +} + +// Tests parsing a non-empty --gtest_filter flag. +TEST_F(ParseFlagsTest, FilterNonEmpty) { + const char* argv[] = {"foo.exe", "--gtest_filter=abc", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("abc"), false); +} + +// Tests parsing --gtest_break_on_failure. +TEST_F(ParseFlagsTest, BreakOnFailureWithoutValue) { + const char* argv[] = {"foo.exe", "--gtest_break_on_failure", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false); +} + +// Tests parsing --gtest_break_on_failure=0. +TEST_F(ParseFlagsTest, BreakOnFailureFalse_0) { + const char* argv[] = {"foo.exe", "--gtest_break_on_failure=0", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); +} + +// Tests parsing --gtest_break_on_failure=f. +TEST_F(ParseFlagsTest, BreakOnFailureFalse_f) { + const char* argv[] = {"foo.exe", "--gtest_break_on_failure=f", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); +} + +// Tests parsing --gtest_break_on_failure=F. +TEST_F(ParseFlagsTest, BreakOnFailureFalse_F) { + const char* argv[] = {"foo.exe", "--gtest_break_on_failure=F", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false); +} + +// Tests parsing a --gtest_break_on_failure flag that has a "true" +// definition. +TEST_F(ParseFlagsTest, BreakOnFailureTrue) { + const char* argv[] = {"foo.exe", "--gtest_break_on_failure=1", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false); +} + +// Tests parsing --gtest_catch_exceptions. +TEST_F(ParseFlagsTest, CatchExceptions) { + const char* argv[] = {"foo.exe", "--gtest_catch_exceptions", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::CatchExceptions(true), false); +} + +// Tests parsing --gtest_death_test_use_fork. +TEST_F(ParseFlagsTest, DeathTestUseFork) { + const char* argv[] = {"foo.exe", "--gtest_death_test_use_fork", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::DeathTestUseFork(true), false); +} + +// Tests having the same flag twice with different values. The +// expected behavior is that the one coming last takes precedence. +TEST_F(ParseFlagsTest, DuplicatedFlags) { + const char* argv[] = {"foo.exe", "--gtest_filter=a", "--gtest_filter=b", + nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("b"), false); +} + +// Tests having an unrecognized flag on the command line. +TEST_F(ParseFlagsTest, UnrecognizedFlag) { + const char* argv[] = {"foo.exe", "--gtest_break_on_failure", + "bar", // Unrecognized by Google Test. + "--gtest_filter=b", nullptr}; + + const char* argv2[] = {"foo.exe", "bar", nullptr}; + + Flags flags; + flags.break_on_failure = true; + flags.filter = "b"; + GTEST_TEST_PARSING_FLAGS_(argv, argv2, flags, false); +} + +// Tests having a --gtest_list_tests flag +TEST_F(ParseFlagsTest, ListTestsFlag) { + const char* argv[] = {"foo.exe", "--gtest_list_tests", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false); +} + +// Tests having a --gtest_list_tests flag with a "true" value +TEST_F(ParseFlagsTest, ListTestsTrue) { + const char* argv[] = {"foo.exe", "--gtest_list_tests=1", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false); +} + +// Tests having a --gtest_list_tests flag with a "false" value +TEST_F(ParseFlagsTest, ListTestsFalse) { + const char* argv[] = {"foo.exe", "--gtest_list_tests=0", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); +} + +// Tests parsing --gtest_list_tests=f. +TEST_F(ParseFlagsTest, ListTestsFalse_f) { + const char* argv[] = {"foo.exe", "--gtest_list_tests=f", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); +} + +// Tests parsing --gtest_list_tests=F. +TEST_F(ParseFlagsTest, ListTestsFalse_F) { + const char* argv[] = {"foo.exe", "--gtest_list_tests=F", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); +} + +// Tests parsing --gtest_output (invalid). +TEST_F(ParseFlagsTest, OutputEmpty) { + const char* argv[] = {"foo.exe", "--gtest_output", nullptr}; + + const char* argv2[] = {"foo.exe", "--gtest_output", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), true); +} + +// Tests parsing --gtest_output=xml +TEST_F(ParseFlagsTest, OutputXml) { + const char* argv[] = {"foo.exe", "--gtest_output=xml", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml"), false); +} + +// Tests parsing --gtest_output=xml:file +TEST_F(ParseFlagsTest, OutputXmlFile) { + const char* argv[] = {"foo.exe", "--gtest_output=xml:file", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml:file"), false); +} + +// Tests parsing --gtest_output=xml:directory/path/ +TEST_F(ParseFlagsTest, OutputXmlDirectory) { + const char* argv[] = {"foo.exe", "--gtest_output=xml:directory/path/", + nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, + Flags::Output("xml:directory/path/"), false); +} + +// Tests having a --gtest_print_time flag +TEST_F(ParseFlagsTest, PrintTimeFlag) { + const char* argv[] = {"foo.exe", "--gtest_print_time", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false); +} + +// Tests having a --gtest_print_time flag with a "true" value +TEST_F(ParseFlagsTest, PrintTimeTrue) { + const char* argv[] = {"foo.exe", "--gtest_print_time=1", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false); +} + +// Tests having a --gtest_print_time flag with a "false" value +TEST_F(ParseFlagsTest, PrintTimeFalse) { + const char* argv[] = {"foo.exe", "--gtest_print_time=0", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); +} + +// Tests parsing --gtest_print_time=f. +TEST_F(ParseFlagsTest, PrintTimeFalse_f) { + const char* argv[] = {"foo.exe", "--gtest_print_time=f", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); +} + +// Tests parsing --gtest_print_time=F. +TEST_F(ParseFlagsTest, PrintTimeFalse_F) { + const char* argv[] = {"foo.exe", "--gtest_print_time=F", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false); +} + +// Tests parsing --gtest_random_seed=number +TEST_F(ParseFlagsTest, RandomSeed) { + const char* argv[] = {"foo.exe", "--gtest_random_seed=1000", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::RandomSeed(1000), false); +} + +// Tests parsing --gtest_repeat=number +TEST_F(ParseFlagsTest, Repeat) { + const char* argv[] = {"foo.exe", "--gtest_repeat=1000", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Repeat(1000), false); +} + +// Tests having a --gtest_also_run_disabled_tests flag +TEST_F(ParseFlagsTest, AlsoRunDisabledTestsFlag) { + const char* argv[] = {"foo.exe", "--gtest_also_run_disabled_tests", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::AlsoRunDisabledTests(true), + false); +} + +// Tests having a --gtest_also_run_disabled_tests flag with a "true" value +TEST_F(ParseFlagsTest, AlsoRunDisabledTestsTrue) { + const char* argv[] = {"foo.exe", "--gtest_also_run_disabled_tests=1", + nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::AlsoRunDisabledTests(true), + false); +} + +// Tests having a --gtest_also_run_disabled_tests flag with a "false" value +TEST_F(ParseFlagsTest, AlsoRunDisabledTestsFalse) { + const char* argv[] = {"foo.exe", "--gtest_also_run_disabled_tests=0", + nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::AlsoRunDisabledTests(false), + false); +} + +// Tests parsing --gtest_shuffle. +TEST_F(ParseFlagsTest, ShuffleWithoutValue) { + const char* argv[] = {"foo.exe", "--gtest_shuffle", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false); +} + +// Tests parsing --gtest_shuffle=0. +TEST_F(ParseFlagsTest, ShuffleFalse_0) { + const char* argv[] = {"foo.exe", "--gtest_shuffle=0", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(false), false); +} + +// Tests parsing a --gtest_shuffle flag that has a "true" definition. +TEST_F(ParseFlagsTest, ShuffleTrue) { + const char* argv[] = {"foo.exe", "--gtest_shuffle=1", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false); +} + +// Tests parsing --gtest_stack_trace_depth=number. +TEST_F(ParseFlagsTest, StackTraceDepth) { + const char* argv[] = {"foo.exe", "--gtest_stack_trace_depth=5", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::StackTraceDepth(5), false); +} + +TEST_F(ParseFlagsTest, StreamResultTo) { + const char* argv[] = {"foo.exe", "--gtest_stream_result_to=localhost:1234", + nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_( + argv, argv2, Flags::StreamResultTo("localhost:1234"), false); +} + +// Tests parsing --gtest_throw_on_failure. +TEST_F(ParseFlagsTest, ThrowOnFailureWithoutValue) { + const char* argv[] = {"foo.exe", "--gtest_throw_on_failure", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false); +} + +// Tests parsing --gtest_throw_on_failure=0. +TEST_F(ParseFlagsTest, ThrowOnFailureFalse_0) { + const char* argv[] = {"foo.exe", "--gtest_throw_on_failure=0", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(false), false); +} + +// Tests parsing a --gtest_throw_on_failure flag that has a "true" +// definition. +TEST_F(ParseFlagsTest, ThrowOnFailureTrue) { + const char* argv[] = {"foo.exe", "--gtest_throw_on_failure=1", nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false); +} + +# if GTEST_OS_WINDOWS +// Tests parsing wide strings. +TEST_F(ParseFlagsTest, WideStrings) { + const wchar_t* argv[] = { + L"foo.exe", + L"--gtest_filter=Foo*", + L"--gtest_list_tests=1", + L"--gtest_break_on_failure", + L"--non_gtest_flag", + NULL + }; + + const wchar_t* argv2[] = { + L"foo.exe", + L"--non_gtest_flag", + NULL + }; + + Flags expected_flags; + expected_flags.break_on_failure = true; + expected_flags.filter = "Foo*"; + expected_flags.list_tests = true; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, expected_flags, false); +} +# endif // GTEST_OS_WINDOWS + +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +class FlagfileTest : public ParseFlagsTest { + public: + virtual void SetUp() { + ParseFlagsTest::SetUp(); + + testdata_path_.Set(internal::FilePath( + testing::TempDir() + internal::GetCurrentExecutableName().string() + + "_flagfile_test")); + testing::internal::posix::RmDir(testdata_path_.c_str()); + EXPECT_TRUE(testdata_path_.CreateFolder()); + } + + virtual void TearDown() { + testing::internal::posix::RmDir(testdata_path_.c_str()); + ParseFlagsTest::TearDown(); + } + + internal::FilePath CreateFlagfile(const char* contents) { + internal::FilePath file_path(internal::FilePath::GenerateUniqueFileName( + testdata_path_, internal::FilePath("unique"), "txt")); + FILE* f = testing::internal::posix::FOpen(file_path.c_str(), "w"); + fprintf(f, "%s", contents); + fclose(f); + return file_path; + } + + private: + internal::FilePath testdata_path_; +}; + +// Tests an empty flagfile. +TEST_F(FlagfileTest, Empty) { + internal::FilePath flagfile_path(CreateFlagfile("")); + std::string flagfile_flag = + std::string("--" GTEST_FLAG_PREFIX_ "flagfile=") + flagfile_path.c_str(); + + const char* argv[] = {"foo.exe", flagfile_flag.c_str(), nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false); +} + +// Tests passing a non-empty --gtest_filter flag via --gtest_flagfile. +TEST_F(FlagfileTest, FilterNonEmpty) { + internal::FilePath flagfile_path(CreateFlagfile( + "--" GTEST_FLAG_PREFIX_ "filter=abc")); + std::string flagfile_flag = + std::string("--" GTEST_FLAG_PREFIX_ "flagfile=") + flagfile_path.c_str(); + + const char* argv[] = {"foo.exe", flagfile_flag.c_str(), nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("abc"), false); +} + +// Tests passing several flags via --gtest_flagfile. +TEST_F(FlagfileTest, SeveralFlags) { + internal::FilePath flagfile_path(CreateFlagfile( + "--" GTEST_FLAG_PREFIX_ "filter=abc\n" + "--" GTEST_FLAG_PREFIX_ "break_on_failure\n" + "--" GTEST_FLAG_PREFIX_ "list_tests")); + std::string flagfile_flag = + std::string("--" GTEST_FLAG_PREFIX_ "flagfile=") + flagfile_path.c_str(); + + const char* argv[] = {"foo.exe", flagfile_flag.c_str(), nullptr}; + + const char* argv2[] = {"foo.exe", nullptr}; + + Flags expected_flags; + expected_flags.break_on_failure = true; + expected_flags.filter = "abc"; + expected_flags.list_tests = true; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, expected_flags, false); +} +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + +// Tests current_test_info() in UnitTest. +class CurrentTestInfoTest : public Test { + protected: + // Tests that current_test_info() returns NULL before the first test in + // the test case is run. + static void SetUpTestSuite() { + // There should be no tests running at this point. + const TestInfo* test_info = + UnitTest::GetInstance()->current_test_info(); + EXPECT_TRUE(test_info == nullptr) + << "There should be no tests running at this point."; + } + + // Tests that current_test_info() returns NULL after the last test in + // the test case has run. + static void TearDownTestSuite() { + const TestInfo* test_info = + UnitTest::GetInstance()->current_test_info(); + EXPECT_TRUE(test_info == nullptr) + << "There should be no tests running at this point."; + } +}; + +// Tests that current_test_info() returns TestInfo for currently running +// test by checking the expected test name against the actual one. +TEST_F(CurrentTestInfoTest, WorksForFirstTestInATestSuite) { + const TestInfo* test_info = + UnitTest::GetInstance()->current_test_info(); + ASSERT_TRUE(nullptr != test_info) + << "There is a test running so we should have a valid TestInfo."; + EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name()) + << "Expected the name of the currently running test case."; + EXPECT_STREQ("WorksForFirstTestInATestSuite", test_info->name()) + << "Expected the name of the currently running test."; +} + +// Tests that current_test_info() returns TestInfo for currently running +// test by checking the expected test name against the actual one. We +// use this test to see that the TestInfo object actually changed from +// the previous invocation. +TEST_F(CurrentTestInfoTest, WorksForSecondTestInATestSuite) { + const TestInfo* test_info = + UnitTest::GetInstance()->current_test_info(); + ASSERT_TRUE(nullptr != test_info) + << "There is a test running so we should have a valid TestInfo."; + EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name()) + << "Expected the name of the currently running test case."; + EXPECT_STREQ("WorksForSecondTestInATestSuite", test_info->name()) + << "Expected the name of the currently running test."; +} + +} // namespace testing + + +// These two lines test that we can define tests in a namespace that +// has the name "testing" and is nested in another namespace. +namespace my_namespace { +namespace testing { + +// Makes sure that TEST knows to use ::testing::Test instead of +// ::my_namespace::testing::Test. +class Test {}; + +// Makes sure that an assertion knows to use ::testing::Message instead of +// ::my_namespace::testing::Message. +class Message {}; + +// Makes sure that an assertion knows to use +// ::testing::AssertionResult instead of +// ::my_namespace::testing::AssertionResult. +class AssertionResult {}; + +// Tests that an assertion that should succeed works as expected. +TEST(NestedTestingNamespaceTest, Success) { + EXPECT_EQ(1, 1) << "This shouldn't fail."; +} + +// Tests that an assertion that should fail works as expected. +TEST(NestedTestingNamespaceTest, Failure) { + EXPECT_FATAL_FAILURE(FAIL() << "This failure is expected.", + "This failure is expected."); +} + +} // namespace testing +} // namespace my_namespace + +// Tests that one can call superclass SetUp and TearDown methods-- +// that is, that they are not private. +// No tests are based on this fixture; the test "passes" if it compiles +// successfully. +class ProtectedFixtureMethodsTest : public Test { + protected: + void SetUp() override { Test::SetUp(); } + void TearDown() override { Test::TearDown(); } +}; + +// StreamingAssertionsTest tests the streaming versions of a representative +// sample of assertions. +TEST(StreamingAssertionsTest, Unconditional) { + SUCCEED() << "expected success"; + EXPECT_NONFATAL_FAILURE(ADD_FAILURE() << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(FAIL() << "expected failure", + "expected failure"); +} + +#ifdef __BORLANDC__ +// Silences warnings: "Condition is always true", "Unreachable code" +# pragma option push -w-ccc -w-rch +#endif + +TEST(StreamingAssertionsTest, Truth) { + EXPECT_TRUE(true) << "unexpected failure"; + ASSERT_TRUE(true) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_TRUE(false) << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, Truth2) { + EXPECT_FALSE(false) << "unexpected failure"; + ASSERT_FALSE(false) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_FALSE(true) << "expected failure", + "expected failure"); +} + +#ifdef __BORLANDC__ +// Restores warnings after previous "#pragma option push" suppressed them +# pragma option pop +#endif + +TEST(StreamingAssertionsTest, IntegerEquals) { + EXPECT_EQ(1, 1) << "unexpected failure"; + ASSERT_EQ(1, 1) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_EQ(1, 2) << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_EQ(1, 2) << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, IntegerLessThan) { + EXPECT_LT(1, 2) << "unexpected failure"; + ASSERT_LT(1, 2) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1) << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_LT(2, 1) << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, StringsEqual) { + EXPECT_STREQ("foo", "foo") << "unexpected failure"; + ASSERT_STREQ("foo", "foo") << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_STREQ("foo", "bar") << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_STREQ("foo", "bar") << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, StringsNotEqual) { + EXPECT_STRNE("foo", "bar") << "unexpected failure"; + ASSERT_STRNE("foo", "bar") << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_STRNE("foo", "foo") << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_STRNE("foo", "foo") << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, StringsEqualIgnoringCase) { + EXPECT_STRCASEEQ("foo", "FOO") << "unexpected failure"; + ASSERT_STRCASEEQ("foo", "FOO") << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ("foo", "bar") << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("foo", "bar") << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, StringNotEqualIgnoringCase) { + EXPECT_STRCASENE("foo", "bar") << "unexpected failure"; + ASSERT_STRCASENE("foo", "bar") << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_STRCASENE("foo", "FOO") << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("bar", "BAR") << "expected failure", + "expected failure"); +} + +TEST(StreamingAssertionsTest, FloatingPointEquals) { + EXPECT_FLOAT_EQ(1.0, 1.0) << "unexpected failure"; + ASSERT_FLOAT_EQ(1.0, 1.0) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(0.0, 1.0) << "expected failure", + "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.0) << "expected failure", + "expected failure"); +} + +#if GTEST_HAS_EXCEPTIONS + +TEST(StreamingAssertionsTest, Throw) { + EXPECT_THROW(ThrowAnInteger(), int) << "unexpected failure"; + ASSERT_THROW(ThrowAnInteger(), int) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool) << + "expected failure", "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_THROW(ThrowAnInteger(), bool) << + "expected failure", "expected failure"); +} + +TEST(StreamingAssertionsTest, NoThrow) { + EXPECT_NO_THROW(ThrowNothing()) << "unexpected failure"; + ASSERT_NO_THROW(ThrowNothing()) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()) << + "expected failure", "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()) << + "expected failure", "expected failure"); +} + +TEST(StreamingAssertionsTest, AnyThrow) { + EXPECT_ANY_THROW(ThrowAnInteger()) << "unexpected failure"; + ASSERT_ANY_THROW(ThrowAnInteger()) << "unexpected failure"; + EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(ThrowNothing()) << + "expected failure", "expected failure"); + EXPECT_FATAL_FAILURE(ASSERT_ANY_THROW(ThrowNothing()) << + "expected failure", "expected failure"); +} + +#endif // GTEST_HAS_EXCEPTIONS + +// Tests that Google Test correctly decides whether to use colors in the output. + +TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsYes) { + GTEST_FLAG(color) = "yes"; + + SetEnv("TERM", "xterm"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. + + SetEnv("TERM", "dumb"); // TERM doesn't support colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. +} + +TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsAliasOfYes) { + SetEnv("TERM", "dumb"); // TERM doesn't support colors. + + GTEST_FLAG(color) = "True"; + EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. + + GTEST_FLAG(color) = "t"; + EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. + + GTEST_FLAG(color) = "1"; + EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY. +} + +TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsNo) { + GTEST_FLAG(color) = "no"; + + SetEnv("TERM", "xterm"); // TERM supports colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. + + SetEnv("TERM", "dumb"); // TERM doesn't support colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. +} + +TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsInvalid) { + SetEnv("TERM", "xterm"); // TERM supports colors. + + GTEST_FLAG(color) = "F"; + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + GTEST_FLAG(color) = "0"; + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + GTEST_FLAG(color) = "unknown"; + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. +} + +TEST(ColoredOutputTest, UsesColorsWhenStdoutIsTty) { + GTEST_FLAG(color) = "auto"; + + SetEnv("TERM", "xterm"); // TERM supports colors. + EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. +} + +TEST(ColoredOutputTest, UsesColorsWhenTermSupportsColors) { + GTEST_FLAG(color) = "auto"; + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW + // On Windows, we ignore the TERM variable as it's usually not set. + + SetEnv("TERM", "dumb"); + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", ""); + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "xterm"); + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. +#else + // On non-Windows platforms, we rely on TERM to determine if the + // terminal supports colors. + + SetEnv("TERM", "dumb"); // TERM doesn't support colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "emacs"); // TERM doesn't support colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "vt100"); // TERM doesn't support colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "xterm-mono"); // TERM doesn't support colors. + EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "xterm"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "xterm-color"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "xterm-256color"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "screen"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "screen-256color"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "tmux"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "tmux-256color"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "rxvt-unicode"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "rxvt-unicode-256color"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "linux"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. + + SetEnv("TERM", "cygwin"); // TERM supports colors. + EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. +#endif // GTEST_OS_WINDOWS +} + +// Verifies that StaticAssertTypeEq works in a namespace scope. + +static bool dummy1 GTEST_ATTRIBUTE_UNUSED_ = StaticAssertTypeEq(); +static bool dummy2 GTEST_ATTRIBUTE_UNUSED_ = + StaticAssertTypeEq(); + +// Verifies that StaticAssertTypeEq works in a class. + +template +class StaticAssertTypeEqTestHelper { + public: + StaticAssertTypeEqTestHelper() { StaticAssertTypeEq(); } +}; + +TEST(StaticAssertTypeEqTest, WorksInClass) { + StaticAssertTypeEqTestHelper(); +} + +// Verifies that StaticAssertTypeEq works inside a function. + +typedef int IntAlias; + +TEST(StaticAssertTypeEqTest, CompilesForEqualTypes) { + StaticAssertTypeEq(); + StaticAssertTypeEq(); +} + +TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsNoFailure) { + EXPECT_FALSE(HasNonfatalFailure()); +} + +static void FailFatally() { FAIL(); } + +TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsOnlyFatalFailure) { + FailFatally(); + const bool has_nonfatal_failure = HasNonfatalFailure(); + ClearCurrentTestPartResults(); + EXPECT_FALSE(has_nonfatal_failure); +} + +TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) { + ADD_FAILURE(); + const bool has_nonfatal_failure = HasNonfatalFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_nonfatal_failure); +} + +TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) { + FailFatally(); + ADD_FAILURE(); + const bool has_nonfatal_failure = HasNonfatalFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_nonfatal_failure); +} + +// A wrapper for calling HasNonfatalFailure outside of a test body. +static bool HasNonfatalFailureHelper() { + return testing::Test::HasNonfatalFailure(); +} + +TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody) { + EXPECT_FALSE(HasNonfatalFailureHelper()); +} + +TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody2) { + ADD_FAILURE(); + const bool has_nonfatal_failure = HasNonfatalFailureHelper(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_nonfatal_failure); +} + +TEST(HasFailureTest, ReturnsFalseWhenThereIsNoFailure) { + EXPECT_FALSE(HasFailure()); +} + +TEST(HasFailureTest, ReturnsTrueWhenThereIsFatalFailure) { + FailFatally(); + const bool has_failure = HasFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +} + +TEST(HasFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) { + ADD_FAILURE(); + const bool has_failure = HasFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +} + +TEST(HasFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) { + FailFatally(); + ADD_FAILURE(); + const bool has_failure = HasFailure(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +} + +// A wrapper for calling HasFailure outside of a test body. +static bool HasFailureHelper() { return testing::Test::HasFailure(); } + +TEST(HasFailureTest, WorksOutsideOfTestBody) { + EXPECT_FALSE(HasFailureHelper()); +} + +TEST(HasFailureTest, WorksOutsideOfTestBody2) { + ADD_FAILURE(); + const bool has_failure = HasFailureHelper(); + ClearCurrentTestPartResults(); + EXPECT_TRUE(has_failure); +} + +class TestListener : public EmptyTestEventListener { + public: + TestListener() : on_start_counter_(nullptr), is_destroyed_(nullptr) {} + TestListener(int* on_start_counter, bool* is_destroyed) + : on_start_counter_(on_start_counter), + is_destroyed_(is_destroyed) {} + + ~TestListener() override { + if (is_destroyed_) + *is_destroyed_ = true; + } + + protected: + void OnTestProgramStart(const UnitTest& /*unit_test*/) override { + if (on_start_counter_ != nullptr) (*on_start_counter_)++; + } + + private: + int* on_start_counter_; + bool* is_destroyed_; +}; + +// Tests the constructor. +TEST(TestEventListenersTest, ConstructionWorks) { + TestEventListeners listeners; + + EXPECT_TRUE(TestEventListenersAccessor::GetRepeater(&listeners) != nullptr); + EXPECT_TRUE(listeners.default_result_printer() == nullptr); + EXPECT_TRUE(listeners.default_xml_generator() == nullptr); +} + +// Tests that the TestEventListeners destructor deletes all the listeners it +// owns. +TEST(TestEventListenersTest, DestructionWorks) { + bool default_result_printer_is_destroyed = false; + bool default_xml_printer_is_destroyed = false; + bool extra_listener_is_destroyed = false; + TestListener* default_result_printer = + new TestListener(nullptr, &default_result_printer_is_destroyed); + TestListener* default_xml_printer = + new TestListener(nullptr, &default_xml_printer_is_destroyed); + TestListener* extra_listener = + new TestListener(nullptr, &extra_listener_is_destroyed); + + { + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, + default_result_printer); + TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, + default_xml_printer); + listeners.Append(extra_listener); + } + EXPECT_TRUE(default_result_printer_is_destroyed); + EXPECT_TRUE(default_xml_printer_is_destroyed); + EXPECT_TRUE(extra_listener_is_destroyed); +} + +// Tests that a listener Append'ed to a TestEventListeners list starts +// receiving events. +TEST(TestEventListenersTest, Append) { + int on_start_counter = 0; + bool is_destroyed = false; + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + TestEventListeners listeners; + listeners.Append(listener); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(1, on_start_counter); + } + EXPECT_TRUE(is_destroyed); +} + +// Tests that listeners receive events in the order they were appended to +// the list, except for *End requests, which must be received in the reverse +// order. +class SequenceTestingListener : public EmptyTestEventListener { + public: + SequenceTestingListener(std::vector* vector, const char* id) + : vector_(vector), id_(id) {} + + protected: + void OnTestProgramStart(const UnitTest& /*unit_test*/) override { + vector_->push_back(GetEventDescription("OnTestProgramStart")); + } + + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override { + vector_->push_back(GetEventDescription("OnTestProgramEnd")); + } + + void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) override { + vector_->push_back(GetEventDescription("OnTestIterationStart")); + } + + void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) override { + vector_->push_back(GetEventDescription("OnTestIterationEnd")); + } + + private: + std::string GetEventDescription(const char* method) { + Message message; + message << id_ << "." << method; + return message.GetString(); + } + + std::vector* vector_; + const char* const id_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SequenceTestingListener); +}; + +TEST(EventListenerTest, AppendKeepsOrder) { + std::vector vec; + TestEventListeners listeners; + listeners.Append(new SequenceTestingListener(&vec, "1st")); + listeners.Append(new SequenceTestingListener(&vec, "2nd")); + listeners.Append(new SequenceTestingListener(&vec, "3rd")); + + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + ASSERT_EQ(3U, vec.size()); + EXPECT_STREQ("1st.OnTestProgramStart", vec[0].c_str()); + EXPECT_STREQ("2nd.OnTestProgramStart", vec[1].c_str()); + EXPECT_STREQ("3rd.OnTestProgramStart", vec[2].c_str()); + + vec.clear(); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramEnd( + *UnitTest::GetInstance()); + ASSERT_EQ(3U, vec.size()); + EXPECT_STREQ("3rd.OnTestProgramEnd", vec[0].c_str()); + EXPECT_STREQ("2nd.OnTestProgramEnd", vec[1].c_str()); + EXPECT_STREQ("1st.OnTestProgramEnd", vec[2].c_str()); + + vec.clear(); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationStart( + *UnitTest::GetInstance(), 0); + ASSERT_EQ(3U, vec.size()); + EXPECT_STREQ("1st.OnTestIterationStart", vec[0].c_str()); + EXPECT_STREQ("2nd.OnTestIterationStart", vec[1].c_str()); + EXPECT_STREQ("3rd.OnTestIterationStart", vec[2].c_str()); + + vec.clear(); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationEnd( + *UnitTest::GetInstance(), 0); + ASSERT_EQ(3U, vec.size()); + EXPECT_STREQ("3rd.OnTestIterationEnd", vec[0].c_str()); + EXPECT_STREQ("2nd.OnTestIterationEnd", vec[1].c_str()); + EXPECT_STREQ("1st.OnTestIterationEnd", vec[2].c_str()); +} + +// Tests that a listener removed from a TestEventListeners list stops receiving +// events and is not deleted when the list is destroyed. +TEST(TestEventListenersTest, Release) { + int on_start_counter = 0; + bool is_destroyed = false; + // Although Append passes the ownership of this object to the list, + // the following calls release it, and we need to delete it before the + // test ends. + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + TestEventListeners listeners; + listeners.Append(listener); + EXPECT_EQ(listener, listeners.Release(listener)); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_TRUE(listeners.Release(listener) == nullptr); + } + EXPECT_EQ(0, on_start_counter); + EXPECT_FALSE(is_destroyed); + delete listener; +} + +// Tests that no events are forwarded when event forwarding is disabled. +TEST(EventListenerTest, SuppressEventForwarding) { + int on_start_counter = 0; + TestListener* listener = new TestListener(&on_start_counter, nullptr); + + TestEventListeners listeners; + listeners.Append(listener); + ASSERT_TRUE(TestEventListenersAccessor::EventForwardingEnabled(listeners)); + TestEventListenersAccessor::SuppressEventForwarding(&listeners); + ASSERT_FALSE(TestEventListenersAccessor::EventForwardingEnabled(listeners)); + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(0, on_start_counter); +} + +// Tests that events generated by Google Test are not forwarded in +// death test subprocesses. +TEST(EventListenerDeathTest, EventsNotForwardedInDeathTestSubprecesses) { + EXPECT_DEATH_IF_SUPPORTED({ + GTEST_CHECK_(TestEventListenersAccessor::EventForwardingEnabled( + *GetUnitTestImpl()->listeners())) << "expected failure";}, + "expected failure"); +} + +// Tests that a listener installed via SetDefaultResultPrinter() starts +// receiving events and is returned via default_result_printer() and that +// the previous default_result_printer is removed from the list and deleted. +TEST(EventListenerTest, default_result_printer) { + int on_start_counter = 0; + bool is_destroyed = false; + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener); + + EXPECT_EQ(listener, listeners.default_result_printer()); + + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + + EXPECT_EQ(1, on_start_counter); + + // Replacing default_result_printer with something else should remove it + // from the list and destroy it. + TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, nullptr); + + EXPECT_TRUE(listeners.default_result_printer() == nullptr); + EXPECT_TRUE(is_destroyed); + + // After broadcasting an event the counter is still the same, indicating + // the listener is not in the list anymore. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(1, on_start_counter); +} + +// Tests that the default_result_printer listener stops receiving events +// when removed via Release and that is not owned by the list anymore. +TEST(EventListenerTest, RemovingDefaultResultPrinterWorks) { + int on_start_counter = 0; + bool is_destroyed = false; + // Although Append passes the ownership of this object to the list, + // the following calls release it, and we need to delete it before the + // test ends. + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener); + + EXPECT_EQ(listener, listeners.Release(listener)); + EXPECT_TRUE(listeners.default_result_printer() == nullptr); + EXPECT_FALSE(is_destroyed); + + // Broadcasting events now should not affect default_result_printer. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(0, on_start_counter); + } + // Destroying the list should not affect the listener now, too. + EXPECT_FALSE(is_destroyed); + delete listener; +} + +// Tests that a listener installed via SetDefaultXmlGenerator() starts +// receiving events and is returned via default_xml_generator() and that +// the previous default_xml_generator is removed from the list and deleted. +TEST(EventListenerTest, default_xml_generator) { + int on_start_counter = 0; + bool is_destroyed = false; + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener); + + EXPECT_EQ(listener, listeners.default_xml_generator()); + + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + + EXPECT_EQ(1, on_start_counter); + + // Replacing default_xml_generator with something else should remove it + // from the list and destroy it. + TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, nullptr); + + EXPECT_TRUE(listeners.default_xml_generator() == nullptr); + EXPECT_TRUE(is_destroyed); + + // After broadcasting an event the counter is still the same, indicating + // the listener is not in the list anymore. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(1, on_start_counter); +} + +// Tests that the default_xml_generator listener stops receiving events +// when removed via Release and that is not owned by the list anymore. +TEST(EventListenerTest, RemovingDefaultXmlGeneratorWorks) { + int on_start_counter = 0; + bool is_destroyed = false; + // Although Append passes the ownership of this object to the list, + // the following calls release it, and we need to delete it before the + // test ends. + TestListener* listener = new TestListener(&on_start_counter, &is_destroyed); + { + TestEventListeners listeners; + TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener); + + EXPECT_EQ(listener, listeners.Release(listener)); + EXPECT_TRUE(listeners.default_xml_generator() == nullptr); + EXPECT_FALSE(is_destroyed); + + // Broadcasting events now should not affect default_xml_generator. + TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart( + *UnitTest::GetInstance()); + EXPECT_EQ(0, on_start_counter); + } + // Destroying the list should not affect the listener now, too. + EXPECT_FALSE(is_destroyed); + delete listener; +} + +// Sanity tests to ensure that the alternative, verbose spellings of +// some of the macros work. We don't test them thoroughly as that +// would be quite involved. Since their implementations are +// straightforward, and they are rarely used, we'll just rely on the +// users to tell us when they are broken. +GTEST_TEST(AlternativeNameTest, Works) { // GTEST_TEST is the same as TEST. + GTEST_SUCCEED() << "OK"; // GTEST_SUCCEED is the same as SUCCEED. + + // GTEST_FAIL is the same as FAIL. + EXPECT_FATAL_FAILURE(GTEST_FAIL() << "An expected failure", + "An expected failure"); + + // GTEST_ASSERT_XY is the same as ASSERT_XY. + + GTEST_ASSERT_EQ(0, 0); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_EQ(0, 1) << "An expected failure", + "An expected failure"); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_EQ(1, 0) << "An expected failure", + "An expected failure"); + + GTEST_ASSERT_NE(0, 1); + GTEST_ASSERT_NE(1, 0); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_NE(0, 0) << "An expected failure", + "An expected failure"); + + GTEST_ASSERT_LE(0, 0); + GTEST_ASSERT_LE(0, 1); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_LE(1, 0) << "An expected failure", + "An expected failure"); + + GTEST_ASSERT_LT(0, 1); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_LT(0, 0) << "An expected failure", + "An expected failure"); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_LT(1, 0) << "An expected failure", + "An expected failure"); + + GTEST_ASSERT_GE(0, 0); + GTEST_ASSERT_GE(1, 0); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_GE(0, 1) << "An expected failure", + "An expected failure"); + + GTEST_ASSERT_GT(1, 0); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_GT(0, 1) << "An expected failure", + "An expected failure"); + EXPECT_FATAL_FAILURE(GTEST_ASSERT_GT(1, 1) << "An expected failure", + "An expected failure"); +} + +// Tests for internal utilities necessary for implementation of the universal +// printing. + +class ConversionHelperBase {}; +class ConversionHelperDerived : public ConversionHelperBase {}; + +// Tests that IsAProtocolMessage::value is a compile-time constant. +TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { + GTEST_COMPILE_ASSERT_(IsAProtocolMessage<::proto2::Message>::value, + const_true); + GTEST_COMPILE_ASSERT_(!IsAProtocolMessage::value, const_false); +} + +// Tests that IsAProtocolMessage::value is true when T is +// proto2::Message or a sub-class of it. +TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) { + EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value); +} + +// Tests that IsAProtocolMessage::value is false when T is neither +// ::proto2::Message nor a sub-class of it. +TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage) { + EXPECT_FALSE(IsAProtocolMessage::value); + EXPECT_FALSE(IsAProtocolMessage::value); +} + +// Tests GTEST_REMOVE_REFERENCE_AND_CONST_. + +template +void TestGTestRemoveReferenceAndConst() { + static_assert(std::is_same::value, + "GTEST_REMOVE_REFERENCE_AND_CONST_ failed."); +} + +TEST(RemoveReferenceToConstTest, Works) { + TestGTestRemoveReferenceAndConst(); + TestGTestRemoveReferenceAndConst(); + TestGTestRemoveReferenceAndConst(); + TestGTestRemoveReferenceAndConst(); + TestGTestRemoveReferenceAndConst(); +} + +// Tests GTEST_REFERENCE_TO_CONST_. + +template +void TestGTestReferenceToConst() { + static_assert(std::is_same::value, + "GTEST_REFERENCE_TO_CONST_ failed."); +} + +TEST(GTestReferenceToConstTest, Works) { + TestGTestReferenceToConst(); + TestGTestReferenceToConst(); + TestGTestReferenceToConst(); + TestGTestReferenceToConst(); +} + + +// Tests IsContainerTest. + +class NonContainer {}; + +TEST(IsContainerTestTest, WorksForNonContainer) { + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); +} + +TEST(IsContainerTestTest, WorksForContainer) { + EXPECT_EQ(sizeof(IsContainer), + sizeof(IsContainerTest >(0))); + EXPECT_EQ(sizeof(IsContainer), + sizeof(IsContainerTest >(0))); +} + +struct ConstOnlyContainerWithPointerIterator { + using const_iterator = int*; + const_iterator begin() const; + const_iterator end() const; +}; + +struct ConstOnlyContainerWithClassIterator { + struct const_iterator { + const int& operator*() const; + const_iterator& operator++(/* pre-increment */); + }; + const_iterator begin() const; + const_iterator end() const; +}; + +TEST(IsContainerTestTest, ConstOnlyContainer) { + EXPECT_EQ(sizeof(IsContainer), + sizeof(IsContainerTest(0))); + EXPECT_EQ(sizeof(IsContainer), + sizeof(IsContainerTest(0))); +} + +// Tests IsHashTable. +struct AHashTable { + typedef void hasher; +}; +struct NotReallyAHashTable { + typedef void hasher; + typedef void reverse_iterator; +}; +TEST(IsHashTable, Basic) { + EXPECT_TRUE(testing::internal::IsHashTable::value); + EXPECT_FALSE(testing::internal::IsHashTable::value); + EXPECT_FALSE(testing::internal::IsHashTable>::value); + EXPECT_TRUE(testing::internal::IsHashTable>::value); +} + +// Tests ArrayEq(). + +TEST(ArrayEqTest, WorksForDegeneratedArrays) { + EXPECT_TRUE(ArrayEq(5, 5L)); + EXPECT_FALSE(ArrayEq('a', 0)); +} + +TEST(ArrayEqTest, WorksForOneDimensionalArrays) { + // Note that a and b are distinct but compatible types. + const int a[] = { 0, 1 }; + long b[] = { 0, 1 }; + EXPECT_TRUE(ArrayEq(a, b)); + EXPECT_TRUE(ArrayEq(a, 2, b)); + + b[0] = 2; + EXPECT_FALSE(ArrayEq(a, b)); + EXPECT_FALSE(ArrayEq(a, 1, b)); +} + +TEST(ArrayEqTest, WorksForTwoDimensionalArrays) { + const char a[][3] = { "hi", "lo" }; + const char b[][3] = { "hi", "lo" }; + const char c[][3] = { "hi", "li" }; + + EXPECT_TRUE(ArrayEq(a, b)); + EXPECT_TRUE(ArrayEq(a, 2, b)); + + EXPECT_FALSE(ArrayEq(a, c)); + EXPECT_FALSE(ArrayEq(a, 2, c)); +} + +// Tests ArrayAwareFind(). + +TEST(ArrayAwareFindTest, WorksForOneDimensionalArray) { + const char a[] = "hello"; + EXPECT_EQ(a + 4, ArrayAwareFind(a, a + 5, 'o')); + EXPECT_EQ(a + 5, ArrayAwareFind(a, a + 5, 'x')); +} + +TEST(ArrayAwareFindTest, WorksForTwoDimensionalArray) { + int a[][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } }; + const int b[2] = { 2, 3 }; + EXPECT_EQ(a + 1, ArrayAwareFind(a, a + 3, b)); + + const int c[2] = { 6, 7 }; + EXPECT_EQ(a + 3, ArrayAwareFind(a, a + 3, c)); +} + +// Tests CopyArray(). + +TEST(CopyArrayTest, WorksForDegeneratedArrays) { + int n = 0; + CopyArray('a', &n); + EXPECT_EQ('a', n); +} + +TEST(CopyArrayTest, WorksForOneDimensionalArrays) { + const char a[3] = "hi"; + int b[3]; +#ifndef __BORLANDC__ // C++Builder cannot compile some array size deductions. + CopyArray(a, &b); + EXPECT_TRUE(ArrayEq(a, b)); +#endif + + int c[3]; + CopyArray(a, 3, c); + EXPECT_TRUE(ArrayEq(a, c)); +} + +TEST(CopyArrayTest, WorksForTwoDimensionalArrays) { + const int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } }; + int b[2][3]; +#ifndef __BORLANDC__ // C++Builder cannot compile some array size deductions. + CopyArray(a, &b); + EXPECT_TRUE(ArrayEq(a, b)); +#endif + + int c[2][3]; + CopyArray(a, 2, c); + EXPECT_TRUE(ArrayEq(a, c)); +} + +// Tests NativeArray. + +TEST(NativeArrayTest, ConstructorFromArrayWorks) { + const int a[3] = { 0, 1, 2 }; + NativeArray na(a, 3, RelationToSourceReference()); + EXPECT_EQ(3U, na.size()); + EXPECT_EQ(a, na.begin()); +} + +TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo) { + typedef int Array[2]; + Array* a = new Array[1]; + (*a)[0] = 0; + (*a)[1] = 1; + NativeArray na(*a, 2, RelationToSourceCopy()); + EXPECT_NE(*a, na.begin()); + delete[] a; + EXPECT_EQ(0, na.begin()[0]); + EXPECT_EQ(1, na.begin()[1]); + + // We rely on the heap checker to verify that na deletes the copy of + // array. +} + +TEST(NativeArrayTest, TypeMembersAreCorrect) { + StaticAssertTypeEq::value_type>(); + StaticAssertTypeEq::value_type>(); + + StaticAssertTypeEq::const_iterator>(); + StaticAssertTypeEq::const_iterator>(); +} + +TEST(NativeArrayTest, MethodsWork) { + const int a[3] = { 0, 1, 2 }; + NativeArray na(a, 3, RelationToSourceCopy()); + ASSERT_EQ(3U, na.size()); + EXPECT_EQ(3, na.end() - na.begin()); + + NativeArray::const_iterator it = na.begin(); + EXPECT_EQ(0, *it); + ++it; + EXPECT_EQ(1, *it); + it++; + EXPECT_EQ(2, *it); + ++it; + EXPECT_EQ(na.end(), it); + + EXPECT_TRUE(na == na); + + NativeArray na2(a, 3, RelationToSourceReference()); + EXPECT_TRUE(na == na2); + + const int b1[3] = { 0, 1, 1 }; + const int b2[4] = { 0, 1, 2, 3 }; + EXPECT_FALSE(na == NativeArray(b1, 3, RelationToSourceReference())); + EXPECT_FALSE(na == NativeArray(b2, 4, RelationToSourceCopy())); +} + +TEST(NativeArrayTest, WorksForTwoDimensionalArray) { + const char a[2][3] = { "hi", "lo" }; + NativeArray na(a, 2, RelationToSourceReference()); + ASSERT_EQ(2U, na.size()); + EXPECT_EQ(a, na.begin()); +} + +// IndexSequence +TEST(IndexSequence, MakeIndexSequence) { + using testing::internal::IndexSequence; + using testing::internal::MakeIndexSequence; + EXPECT_TRUE( + (std::is_same, MakeIndexSequence<0>::type>::value)); + EXPECT_TRUE( + (std::is_same, MakeIndexSequence<1>::type>::value)); + EXPECT_TRUE( + (std::is_same, MakeIndexSequence<2>::type>::value)); + EXPECT_TRUE(( + std::is_same, MakeIndexSequence<3>::type>::value)); + EXPECT_TRUE( + (std::is_base_of, MakeIndexSequence<3>>::value)); +} + +// ElemFromList +TEST(ElemFromList, Basic) { + using testing::internal::ElemFromList; + using Idx = testing::internal::MakeIndexSequence<3>::type; + EXPECT_TRUE(( + std::is_same::type>::value)); + EXPECT_TRUE( + (std::is_same::type>::value)); + EXPECT_TRUE( + (std::is_same::type>::value)); + EXPECT_TRUE( + (std::is_same< + char, ElemFromList<7, testing::internal::MakeIndexSequence<12>::type, + int, int, int, int, int, int, int, char, int, int, + int, int>::type>::value)); +} + +// FlatTuple +TEST(FlatTuple, Basic) { + using testing::internal::FlatTuple; + + FlatTuple tuple = {}; + EXPECT_EQ(0, tuple.Get<0>()); + EXPECT_EQ(0.0, tuple.Get<1>()); + EXPECT_EQ(nullptr, tuple.Get<2>()); + + tuple = FlatTuple(7, 3.2, "Foo"); + EXPECT_EQ(7, tuple.Get<0>()); + EXPECT_EQ(3.2, tuple.Get<1>()); + EXPECT_EQ(std::string("Foo"), tuple.Get<2>()); + + tuple.Get<1>() = 5.1; + EXPECT_EQ(5.1, tuple.Get<1>()); +} + +TEST(FlatTuple, ManyTypes) { + using testing::internal::FlatTuple; + + // Instantiate FlatTuple with 257 ints. + // Tests show that we can do it with thousands of elements, but very long + // compile times makes it unusuitable for this test. +#define GTEST_FLAT_TUPLE_INT8 int, int, int, int, int, int, int, int, +#define GTEST_FLAT_TUPLE_INT16 GTEST_FLAT_TUPLE_INT8 GTEST_FLAT_TUPLE_INT8 +#define GTEST_FLAT_TUPLE_INT32 GTEST_FLAT_TUPLE_INT16 GTEST_FLAT_TUPLE_INT16 +#define GTEST_FLAT_TUPLE_INT64 GTEST_FLAT_TUPLE_INT32 GTEST_FLAT_TUPLE_INT32 +#define GTEST_FLAT_TUPLE_INT128 GTEST_FLAT_TUPLE_INT64 GTEST_FLAT_TUPLE_INT64 +#define GTEST_FLAT_TUPLE_INT256 GTEST_FLAT_TUPLE_INT128 GTEST_FLAT_TUPLE_INT128 + + // Let's make sure that we can have a very long list of types without blowing + // up the template instantiation depth. + FlatTuple tuple; + + tuple.Get<0>() = 7; + tuple.Get<99>() = 17; + tuple.Get<256>() = 1000; + EXPECT_EQ(7, tuple.Get<0>()); + EXPECT_EQ(17, tuple.Get<99>()); + EXPECT_EQ(1000, tuple.Get<256>()); +} + +// Tests SkipPrefix(). + +TEST(SkipPrefixTest, SkipsWhenPrefixMatches) { + const char* const str = "hello"; + + const char* p = str; + EXPECT_TRUE(SkipPrefix("", &p)); + EXPECT_EQ(str, p); + + p = str; + EXPECT_TRUE(SkipPrefix("hell", &p)); + EXPECT_EQ(str + 4, p); +} + +TEST(SkipPrefixTest, DoesNotSkipWhenPrefixDoesNotMatch) { + const char* const str = "world"; + + const char* p = str; + EXPECT_FALSE(SkipPrefix("W", &p)); + EXPECT_EQ(str, p); + + p = str; + EXPECT_FALSE(SkipPrefix("world!", &p)); + EXPECT_EQ(str, p); +} + +// Tests ad_hoc_test_result(). + +class AdHocTestResultTest : public testing::Test { + protected: + static void SetUpTestSuite() { + FAIL() << "A failure happened inside SetUpTestSuite()."; + } +}; + +TEST_F(AdHocTestResultTest, AdHocTestResultForTestSuiteShowsFailure) { + const testing::TestResult& test_result = testing::UnitTest::GetInstance() + ->current_test_suite() + ->ad_hoc_test_result(); + EXPECT_TRUE(test_result.Failed()); +} + +TEST_F(AdHocTestResultTest, AdHocTestResultTestForUnitTestDoesNotShowFailure) { + const testing::TestResult& test_result = + testing::UnitTest::GetInstance()->ad_hoc_test_result(); + EXPECT_FALSE(test_result.Failed()); +} + +class DynamicUnitTestFixture : public testing::Test {}; + +class DynamicTest : public DynamicUnitTestFixture { + void TestBody() override { EXPECT_TRUE(true); } +}; + +auto* dynamic_test = testing::RegisterTest( + "DynamicUnitTestFixture", "DynamicTest", "TYPE", "VALUE", __FILE__, + __LINE__, []() -> DynamicUnitTestFixture* { return new DynamicTest; }); + +TEST(RegisterTest, WasRegistered) { + auto* unittest = testing::UnitTest::GetInstance(); + for (int i = 0; i < unittest->total_test_suite_count(); ++i) { + auto* tests = unittest->GetTestSuite(i); + if (tests->name() != std::string("DynamicUnitTestFixture")) continue; + for (int j = 0; j < tests->total_test_count(); ++j) { + if (tests->GetTestInfo(j)->name() != std::string("DynamicTest")) continue; + // Found it. + EXPECT_STREQ(tests->GetTestInfo(j)->value_param(), "VALUE"); + EXPECT_STREQ(tests->GetTestInfo(j)->type_param(), "TYPE"); + return; + } + } + + FAIL() << "Didn't find the test!"; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_outfile1_test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_outfile1_test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..19aa252a3010fd56eabe3768308a80d2dc6dbd5a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_outfile1_test_.cc @@ -0,0 +1,43 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// gtest_xml_outfile1_test_ writes some xml via TestProperty used by +// gtest_xml_outfiles_test.py + +#include "gtest/gtest.h" + +class PropertyOne : public testing::Test { + protected: + void SetUp() override { RecordProperty("SetUpProp", 1); } + void TearDown() override { RecordProperty("TearDownProp", 1); } +}; + +TEST_F(PropertyOne, TestSomeProperties) { + RecordProperty("TestSomeProperty", 1); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_outfile2_test_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_outfile2_test_.cc new file mode 100644 index 0000000000000000000000000000000000000000..f9a2a6e9846ddcd95dbdb88d8c74d07c4bc9dffb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_outfile2_test_.cc @@ -0,0 +1,43 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// gtest_xml_outfile2_test_ writes some xml via TestProperty used by +// gtest_xml_outfiles_test.py + +#include "gtest/gtest.h" + +class PropertyTwo : public testing::Test { + protected: + void SetUp() override { RecordProperty("SetUpProp", 2); } + void TearDown() override { RecordProperty("TearDownProp", 2); } +}; + +TEST_F(PropertyTwo, TestSomeProperties) { + RecordProperty("TestSomeProperty", 2); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_outfiles_test.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_outfiles_test.py new file mode 100755 index 0000000000000000000000000000000000000000..e093f6f05e3e3ad747df47cca9db51cb9ba5f258 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_outfiles_test.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for the gtest_xml_output module.""" + +import os +from xml.dom import minidom, Node +import gtest_test_utils +import gtest_xml_test_utils + +GTEST_OUTPUT_SUBDIR = "xml_outfiles" +GTEST_OUTPUT_1_TEST = "gtest_xml_outfile1_test_" +GTEST_OUTPUT_2_TEST = "gtest_xml_outfile2_test_" + +EXPECTED_XML_1 = """ + + + + + + + + + + + +""" + +EXPECTED_XML_2 = """ + + + + + + + + + + + +""" + + +class GTestXMLOutFilesTest(gtest_xml_test_utils.GTestXMLTestCase): + """Unit test for Google Test's XML output functionality.""" + + def setUp(self): + # We want the trailing '/' that the last "" provides in os.path.join, for + # telling Google Test to create an output directory instead of a single file + # for xml output. + self.output_dir_ = os.path.join(gtest_test_utils.GetTempDir(), + GTEST_OUTPUT_SUBDIR, "") + self.DeleteFilesAndDir() + + def tearDown(self): + self.DeleteFilesAndDir() + + def DeleteFilesAndDir(self): + try: + os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_1_TEST + ".xml")) + except os.error: + pass + try: + os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_2_TEST + ".xml")) + except os.error: + pass + try: + os.rmdir(self.output_dir_) + except os.error: + pass + + def testOutfile1(self): + self._TestOutFile(GTEST_OUTPUT_1_TEST, EXPECTED_XML_1) + + def testOutfile2(self): + self._TestOutFile(GTEST_OUTPUT_2_TEST, EXPECTED_XML_2) + + def _TestOutFile(self, test_name, expected_xml): + gtest_prog_path = gtest_test_utils.GetTestExecutablePath(test_name) + command = [gtest_prog_path, "--gtest_output=xml:%s" % self.output_dir_] + p = gtest_test_utils.Subprocess(command, + working_dir=gtest_test_utils.GetTempDir()) + self.assert_(p.exited) + self.assertEquals(0, p.exit_code) + + output_file_name1 = test_name + ".xml" + output_file1 = os.path.join(self.output_dir_, output_file_name1) + output_file_name2 = 'lt-' + output_file_name1 + output_file2 = os.path.join(self.output_dir_, output_file_name2) + self.assert_(os.path.isfile(output_file1) or os.path.isfile(output_file2), + output_file1) + + expected = minidom.parseString(expected_xml) + if os.path.isfile(output_file1): + actual = minidom.parse(output_file1) + else: + actual = minidom.parse(output_file2) + self.NormalizeXml(actual.documentElement) + self.AssertEquivalentNodes(expected.documentElement, + actual.documentElement) + expected.unlink() + actual.unlink() + + +if __name__ == "__main__": + os.environ["GTEST_STACK_TRACE_DEPTH"] = "0" + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_output_unittest.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_output_unittest.py new file mode 100755 index 0000000000000000000000000000000000000000..63b1af0b6c10161eca2c9eaf9731cb29b08b1827 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_output_unittest.py @@ -0,0 +1,389 @@ +#!/usr/bin/env python +# +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for the gtest_xml_output module""" + +import datetime +import errno +import os +import re +import sys +from xml.dom import minidom, Node + +import gtest_test_utils +import gtest_xml_test_utils + +GTEST_FILTER_FLAG = '--gtest_filter' +GTEST_LIST_TESTS_FLAG = '--gtest_list_tests' +GTEST_OUTPUT_FLAG = '--gtest_output' +GTEST_DEFAULT_OUTPUT_FILE = 'test_detail.xml' +GTEST_PROGRAM_NAME = 'gtest_xml_output_unittest_' + +# The flag indicating stacktraces are not supported +NO_STACKTRACE_SUPPORT_FLAG = '--no_stacktrace_support' + +# The environment variables for test sharding. +TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' +SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' +SHARD_STATUS_FILE_ENV_VAR = 'GTEST_SHARD_STATUS_FILE' + +SUPPORTS_STACK_TRACES = NO_STACKTRACE_SUPPORT_FLAG not in sys.argv + +if SUPPORTS_STACK_TRACES: + STACK_TRACE_TEMPLATE = '\nStack trace:\n*' +else: + STACK_TRACE_TEMPLATE = '' + # unittest.main() can't handle unknown flags + sys.argv.remove(NO_STACKTRACE_SUPPORT_FLAG) + +EXPECTED_NON_EMPTY_XML = """ + + + + + + + + + + + + + + + + + + + + ]]>%(stack)s]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +""" % { + 'stack': STACK_TRACE_TEMPLATE +} + +EXPECTED_FILTERED_TEST_XML = """ + + + + +""" + +EXPECTED_SHARDED_TEST_XML = """ + + + + + + + + + + + + + + +""" + +EXPECTED_EMPTY_XML = """ + +""" + +GTEST_PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME) + +SUPPORTS_TYPED_TESTS = 'TypedTest' in gtest_test_utils.Subprocess( + [GTEST_PROGRAM_PATH, GTEST_LIST_TESTS_FLAG], capture_stderr=False).output + + +class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase): + """ + Unit test for Google Test's XML output functionality. + """ + + # This test currently breaks on platforms that do not support typed and + # type-parameterized tests, so we don't run it under them. + if SUPPORTS_TYPED_TESTS: + def testNonEmptyXmlOutput(self): + """ + Runs a test program that generates a non-empty XML output, and + tests that the XML output is expected. + """ + self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY_XML, 1) + + def testEmptyXmlOutput(self): + """Verifies XML output for a Google Test binary without actual tests. + + Runs a test program that generates an empty XML output, and + tests that the XML output is expected. + """ + + self._TestXmlOutput('gtest_no_test_unittest', EXPECTED_EMPTY_XML, 0) + + def testTimestampValue(self): + """Checks whether the timestamp attribute in the XML output is valid. + + Runs a test program that generates an empty XML output, and checks if + the timestamp attribute in the testsuites tag is valid. + """ + actual = self._GetXmlOutput('gtest_no_test_unittest', [], {}, 0) + date_time_str = actual.documentElement.getAttributeNode('timestamp').value + # datetime.strptime() is only available in Python 2.5+ so we have to + # parse the expected datetime manually. + match = re.match(r'(\d+)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)', date_time_str) + self.assertTrue( + re.match, + 'XML datettime string %s has incorrect format' % date_time_str) + date_time_from_xml = datetime.datetime( + year=int(match.group(1)), month=int(match.group(2)), + day=int(match.group(3)), hour=int(match.group(4)), + minute=int(match.group(5)), second=int(match.group(6))) + + time_delta = abs(datetime.datetime.now() - date_time_from_xml) + # timestamp value should be near the current local time + self.assertTrue(time_delta < datetime.timedelta(seconds=600), + 'time_delta is %s' % time_delta) + actual.unlink() + + def testDefaultOutputFile(self): + """ + Confirms that Google Test produces an XML output file with the expected + default name if no name is explicitly specified. + """ + output_file = os.path.join(gtest_test_utils.GetTempDir(), + GTEST_DEFAULT_OUTPUT_FILE) + gtest_prog_path = gtest_test_utils.GetTestExecutablePath( + 'gtest_no_test_unittest') + try: + os.remove(output_file) + except OSError: + e = sys.exc_info()[1] + if e.errno != errno.ENOENT: + raise + + p = gtest_test_utils.Subprocess( + [gtest_prog_path, '%s=xml' % GTEST_OUTPUT_FLAG], + working_dir=gtest_test_utils.GetTempDir()) + self.assert_(p.exited) + self.assertEquals(0, p.exit_code) + self.assert_(os.path.isfile(output_file)) + + def testSuppressedXmlOutput(self): + """ + Tests that no XML file is generated if the default XML listener is + shut down before RUN_ALL_TESTS is invoked. + """ + + xml_path = os.path.join(gtest_test_utils.GetTempDir(), + GTEST_PROGRAM_NAME + 'out.xml') + if os.path.isfile(xml_path): + os.remove(xml_path) + + command = [GTEST_PROGRAM_PATH, + '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path), + '--shut_down_xml'] + p = gtest_test_utils.Subprocess(command) + if p.terminated_by_signal: + # p.signal is available only if p.terminated_by_signal is True. + self.assertFalse( + p.terminated_by_signal, + '%s was killed by signal %d' % (GTEST_PROGRAM_NAME, p.signal)) + else: + self.assert_(p.exited) + self.assertEquals(1, p.exit_code, + "'%s' exited with code %s, which doesn't match " + 'the expected exit code %s.' + % (command, p.exit_code, 1)) + + self.assert_(not os.path.isfile(xml_path)) + + def testFilteredTestXmlOutput(self): + """Verifies XML output when a filter is applied. + + Runs a test program that executes only some tests and verifies that + non-selected tests do not show up in the XML output. + """ + + self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_FILTERED_TEST_XML, 0, + extra_args=['%s=SuccessfulTest.*' % GTEST_FILTER_FLAG]) + + def testShardedTestXmlOutput(self): + """Verifies XML output when run using multiple shards. + + Runs a test program that executes only one shard and verifies that tests + from other shards do not show up in the XML output. + """ + + self._TestXmlOutput( + GTEST_PROGRAM_NAME, + EXPECTED_SHARDED_TEST_XML, + 0, + extra_env={SHARD_INDEX_ENV_VAR: '0', + TOTAL_SHARDS_ENV_VAR: '10'}) + + def _GetXmlOutput(self, gtest_prog_name, extra_args, extra_env, + expected_exit_code): + """ + Returns the xml output generated by running the program gtest_prog_name. + Furthermore, the program's exit code must be expected_exit_code. + """ + xml_path = os.path.join(gtest_test_utils.GetTempDir(), + gtest_prog_name + 'out.xml') + gtest_prog_path = gtest_test_utils.GetTestExecutablePath(gtest_prog_name) + + command = ([gtest_prog_path, '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path)] + + extra_args) + environ_copy = os.environ.copy() + if extra_env: + environ_copy.update(extra_env) + p = gtest_test_utils.Subprocess(command, env=environ_copy) + + if p.terminated_by_signal: + self.assert_(False, + '%s was killed by signal %d' % (gtest_prog_name, p.signal)) + else: + self.assert_(p.exited) + self.assertEquals(expected_exit_code, p.exit_code, + "'%s' exited with code %s, which doesn't match " + 'the expected exit code %s.' + % (command, p.exit_code, expected_exit_code)) + actual = minidom.parse(xml_path) + return actual + + def _TestXmlOutput(self, gtest_prog_name, expected_xml, + expected_exit_code, extra_args=None, extra_env=None): + """ + Asserts that the XML document generated by running the program + gtest_prog_name matches expected_xml, a string containing another + XML document. Furthermore, the program's exit code must be + expected_exit_code. + """ + + actual = self._GetXmlOutput(gtest_prog_name, extra_args or [], + extra_env or {}, expected_exit_code) + expected = minidom.parseString(expected_xml) + self.NormalizeXml(actual.documentElement) + self.AssertEquivalentNodes(expected.documentElement, + actual.documentElement) + expected.unlink() + actual.unlink() + + +if __name__ == '__main__': + os.environ['GTEST_STACK_TRACE_DEPTH'] = '1' + gtest_test_utils.Main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_output_unittest_.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_output_unittest_.cc new file mode 100644 index 0000000000000000000000000000000000000000..c95fd66cfaef24d07d350f649970f5aa7b0884e2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_output_unittest_.cc @@ -0,0 +1,188 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Unit test for Google Test XML output. +// +// A user can specify XML output in a Google Test program to run via +// either the GTEST_OUTPUT environment variable or the --gtest_output +// flag. This is used for testing such functionality. +// +// This program will be invoked from a Python unit test. Don't run it +// directly. + +#include "gtest/gtest.h" + +using ::testing::InitGoogleTest; +using ::testing::TestEventListeners; +using ::testing::TestWithParam; +using ::testing::UnitTest; +using ::testing::Test; +using ::testing::Values; + +class SuccessfulTest : public Test { +}; + +TEST_F(SuccessfulTest, Succeeds) { + SUCCEED() << "This is a success."; + ASSERT_EQ(1, 1); +} + +class FailedTest : public Test { +}; + +TEST_F(FailedTest, Fails) { + ASSERT_EQ(1, 2); +} + +class DisabledTest : public Test { +}; + +TEST_F(DisabledTest, DISABLED_test_not_run) { + FAIL() << "Unexpected failure: Disabled test should not be run"; +} + +class SkippedTest : public Test { +}; + +TEST_F(SkippedTest, Skipped) { + GTEST_SKIP(); +} + +TEST(MixedResultTest, Succeeds) { + EXPECT_EQ(1, 1); + ASSERT_EQ(1, 1); +} + +TEST(MixedResultTest, Fails) { + EXPECT_EQ(1, 2); + ASSERT_EQ(2, 3); +} + +TEST(MixedResultTest, DISABLED_test) { + FAIL() << "Unexpected failure: Disabled test should not be run"; +} + +TEST(XmlQuotingTest, OutputsCData) { + FAIL() << "XML output: " + ""; +} + +// Helps to test that invalid characters produced by test code do not make +// it into the XML file. +TEST(InvalidCharactersTest, InvalidCharactersInMessage) { + FAIL() << "Invalid characters in brackets [\x1\x2]"; +} + +class PropertyRecordingTest : public Test { + public: + static void SetUpTestSuite() { RecordProperty("SetUpTestSuite", "yes"); } + static void TearDownTestSuite() { + RecordProperty("TearDownTestSuite", "aye"); + } +}; + +TEST_F(PropertyRecordingTest, OneProperty) { + RecordProperty("key_1", "1"); +} + +TEST_F(PropertyRecordingTest, IntValuedProperty) { + RecordProperty("key_int", 1); +} + +TEST_F(PropertyRecordingTest, ThreeProperties) { + RecordProperty("key_1", "1"); + RecordProperty("key_2", "2"); + RecordProperty("key_3", "3"); +} + +TEST_F(PropertyRecordingTest, TwoValuesForOneKeyUsesLastValue) { + RecordProperty("key_1", "1"); + RecordProperty("key_1", "2"); +} + +TEST(NoFixtureTest, RecordProperty) { + RecordProperty("key", "1"); +} + +void ExternalUtilityThatCallsRecordProperty(const std::string& key, int value) { + testing::Test::RecordProperty(key, value); +} + +void ExternalUtilityThatCallsRecordProperty(const std::string& key, + const std::string& value) { + testing::Test::RecordProperty(key, value); +} + +TEST(NoFixtureTest, ExternalUtilityThatCallsRecordIntValuedProperty) { + ExternalUtilityThatCallsRecordProperty("key_for_utility_int", 1); +} + +TEST(NoFixtureTest, ExternalUtilityThatCallsRecordStringValuedProperty) { + ExternalUtilityThatCallsRecordProperty("key_for_utility_string", "1"); +} + +// Verifies that the test parameter value is output in the 'value_param' +// XML attribute for value-parameterized tests. +class ValueParamTest : public TestWithParam {}; +TEST_P(ValueParamTest, HasValueParamAttribute) {} +TEST_P(ValueParamTest, AnotherTestThatHasValueParamAttribute) {} +INSTANTIATE_TEST_SUITE_P(Single, ValueParamTest, Values(33, 42)); + +#if GTEST_HAS_TYPED_TEST +// Verifies that the type parameter name is output in the 'type_param' +// XML attribute for typed tests. +template class TypedTest : public Test {}; +typedef testing::Types TypedTestTypes; +TYPED_TEST_SUITE(TypedTest, TypedTestTypes); +TYPED_TEST(TypedTest, HasTypeParamAttribute) {} +#endif + +#if GTEST_HAS_TYPED_TEST_P +// Verifies that the type parameter name is output in the 'type_param' +// XML attribute for type-parameterized tests. +template +class TypeParameterizedTestSuite : public Test {}; +TYPED_TEST_SUITE_P(TypeParameterizedTestSuite); +TYPED_TEST_P(TypeParameterizedTestSuite, HasTypeParamAttribute) {} +REGISTER_TYPED_TEST_SUITE_P(TypeParameterizedTestSuite, HasTypeParamAttribute); +typedef testing::Types TypeParameterizedTestSuiteTypes; // NOLINT +INSTANTIATE_TYPED_TEST_SUITE_P(Single, TypeParameterizedTestSuite, + TypeParameterizedTestSuiteTypes); +#endif + +int main(int argc, char** argv) { + InitGoogleTest(&argc, argv); + + if (argc > 1 && strcmp(argv[1], "--shut_down_xml") == 0) { + TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); + delete listeners.Release(listeners.default_xml_generator()); + } + testing::Test::RecordProperty("ad_hoc_property", "42"); + return RUN_ALL_TESTS(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_test_utils.py b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_test_utils.py new file mode 100755 index 0000000000000000000000000000000000000000..9914a49ec188b7ceaaf23718b8f73236bac2251f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/gtest_xml_test_utils.py @@ -0,0 +1,196 @@ +# Copyright 2006, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test utilities for gtest_xml_output""" + +import re +from xml.dom import minidom, Node +import gtest_test_utils + +GTEST_DEFAULT_OUTPUT_FILE = 'test_detail.xml' + +class GTestXMLTestCase(gtest_test_utils.TestCase): + """ + Base class for tests of Google Test's XML output functionality. + """ + + + def AssertEquivalentNodes(self, expected_node, actual_node): + """ + Asserts that actual_node (a DOM node object) is equivalent to + expected_node (another DOM node object), in that either both of + them are CDATA nodes and have the same value, or both are DOM + elements and actual_node meets all of the following conditions: + + * It has the same tag name as expected_node. + * It has the same set of attributes as expected_node, each with + the same value as the corresponding attribute of expected_node. + Exceptions are any attribute named "time", which needs only be + convertible to a floating-point number and any attribute named + "type_param" which only has to be non-empty. + * It has an equivalent set of child nodes (including elements and + CDATA sections) as expected_node. Note that we ignore the + order of the children as they are not guaranteed to be in any + particular order. + """ + + if expected_node.nodeType == Node.CDATA_SECTION_NODE: + self.assertEquals(Node.CDATA_SECTION_NODE, actual_node.nodeType) + self.assertEquals(expected_node.nodeValue, actual_node.nodeValue) + return + + self.assertEquals(Node.ELEMENT_NODE, actual_node.nodeType) + self.assertEquals(Node.ELEMENT_NODE, expected_node.nodeType) + self.assertEquals(expected_node.tagName, actual_node.tagName) + + expected_attributes = expected_node.attributes + actual_attributes = actual_node .attributes + self.assertEquals( + expected_attributes.length, actual_attributes.length, + 'attribute numbers differ in element %s:\nExpected: %r\nActual: %r' % ( + actual_node.tagName, expected_attributes.keys(), + actual_attributes.keys())) + for i in range(expected_attributes.length): + expected_attr = expected_attributes.item(i) + actual_attr = actual_attributes.get(expected_attr.name) + self.assert_( + actual_attr is not None, + 'expected attribute %s not found in element %s' % + (expected_attr.name, actual_node.tagName)) + self.assertEquals( + expected_attr.value, actual_attr.value, + ' values of attribute %s in element %s differ: %s vs %s' % + (expected_attr.name, actual_node.tagName, + expected_attr.value, actual_attr.value)) + + expected_children = self._GetChildren(expected_node) + actual_children = self._GetChildren(actual_node) + self.assertEquals( + len(expected_children), len(actual_children), + 'number of child elements differ in element ' + actual_node.tagName) + for child_id, child in expected_children.items(): + self.assert_(child_id in actual_children, + '<%s> is not in <%s> (in element %s)' % + (child_id, actual_children, actual_node.tagName)) + self.AssertEquivalentNodes(child, actual_children[child_id]) + + identifying_attribute = { + 'testsuites': 'name', + 'testsuite': 'name', + 'testcase': 'name', + 'failure': 'message', + 'property': 'name', + } + + def _GetChildren(self, element): + """ + Fetches all of the child nodes of element, a DOM Element object. + Returns them as the values of a dictionary keyed by the IDs of the + children. For , , , and + elements, the ID is the value of their "name" attribute; for + elements, it is the value of the "message" attribute; for + elements, it is the value of their parent's "name" attribute plus the + literal string "properties"; CDATA sections and non-whitespace + text nodes are concatenated into a single CDATA section with ID + "detail". An exception is raised if any element other than the above + four is encountered, if two child elements with the same identifying + attributes are encountered, or if any other type of node is encountered. + """ + + children = {} + for child in element.childNodes: + if child.nodeType == Node.ELEMENT_NODE: + if child.tagName == 'properties': + self.assert_(child.parentNode is not None, + 'Encountered element without a parent') + child_id = child.parentNode.getAttribute('name') + '-properties' + else: + self.assert_(child.tagName in self.identifying_attribute, + 'Encountered unknown element <%s>' % child.tagName) + child_id = child.getAttribute( + self.identifying_attribute[child.tagName]) + self.assert_(child_id not in children) + children[child_id] = child + elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]: + if 'detail' not in children: + if (child.nodeType == Node.CDATA_SECTION_NODE or + not child.nodeValue.isspace()): + children['detail'] = child.ownerDocument.createCDATASection( + child.nodeValue) + else: + children['detail'].nodeValue += child.nodeValue + else: + self.fail('Encountered unexpected node type %d' % child.nodeType) + return children + + def NormalizeXml(self, element): + """ + Normalizes Google Test's XML output to eliminate references to transient + information that may change from run to run. + + * The "time" attribute of , and + elements is replaced with a single asterisk, if it contains + only digit characters. + * The "timestamp" attribute of elements is replaced with a + single asterisk, if it contains a valid ISO8601 datetime value. + * The "type_param" attribute of elements is replaced with a + single asterisk (if it sn non-empty) as it is the type name returned + by the compiler and is platform dependent. + * The line info reported in the first line of the "message" + attribute and CDATA section of elements is replaced with the + file's basename and a single asterisk for the line number. + * The directory names in file paths are removed. + * The stack traces are removed. + """ + + if element.tagName in ('testsuites', 'testsuite', 'testcase'): + timestamp = element.getAttributeNode('timestamp') + timestamp.value = re.sub(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d$', + '*', timestamp.value) + if element.tagName in ('testsuites', 'testsuite', 'testcase'): + time = element.getAttributeNode('time') + time.value = re.sub(r'^\d+(\.\d+)?$', '*', time.value) + type_param = element.getAttributeNode('type_param') + if type_param and type_param.value: + type_param.value = '*' + elif element.tagName == 'failure': + source_line_pat = r'^.*[/\\](.*:)\d+\n' + # Replaces the source line information with a normalized form. + message = element.getAttributeNode('message') + message.value = re.sub(source_line_pat, '\\1*\n', message.value) + for child in element.childNodes: + if child.nodeType == Node.CDATA_SECTION_NODE: + # Replaces the source line information with a normalized form. + cdata = re.sub(source_line_pat, '\\1*\n', child.nodeValue) + # Removes the actual stack trace. + child.nodeValue = re.sub(r'Stack trace:\n(.|\n)*', + 'Stack trace:\n*', cdata) + for child in element.childNodes: + if child.nodeType == Node.ELEMENT_NODE: + self.NormalizeXml(child) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/production.cc b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/production.cc new file mode 100644 index 0000000000000000000000000000000000000000..0f69f6dbd2e26a3a9bdf756b480737a4ef4218d4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/production.cc @@ -0,0 +1,35 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// This is part of the unit test for gtest_prod.h. + +#include "production.h" + +PrivateCode::PrivateCode() : x_(0) {} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/production.h b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/production.h new file mode 100644 index 0000000000000000000000000000000000000000..542723b7087387d4fb529fc07a688bc1c8d78b1e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/gtest-1.11.0/test/production.h @@ -0,0 +1,54 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// This is part of the unit test for gtest_prod.h. + +#ifndef GTEST_TEST_PRODUCTION_H_ +#define GTEST_TEST_PRODUCTION_H_ + +#include "gtest/gtest_prod.h" + +class PrivateCode { + public: + // Declares a friend test that does not use a fixture. + FRIEND_TEST(PrivateCodeTest, CanAccessPrivateMembers); + + // Declares a friend test that uses a fixture. + FRIEND_TEST(PrivateCodeFixtureTest, CanAccessPrivateMembers); + + PrivateCode(); + + int x() const { return x_; } + private: + void set_x(int an_x) { x_ = an_x; } + int x_; +}; + +#endif // GTEST_TEST_PRODUCTION_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/AUTHORS b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/AUTHORS new file mode 100644 index 0000000000000000000000000000000000000000..4ee985a7ba723e8826a1b9f9e4f767611b160276 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/AUTHORS @@ -0,0 +1 @@ +Susumu Yata diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..305f273149f3fb0e13f7844566e1950bf6eba8cd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/CMakeLists.txt @@ -0,0 +1,19 @@ +include_directories(include) +include_directories(lib) + +set( + LIBMARISA_SOURCES + lib/marisa/trie.cc + lib/marisa/agent.cc + lib/marisa/grimoire/io/reader.cc + lib/marisa/grimoire/io/writer.cc + lib/marisa/grimoire/io/mapper.cc + lib/marisa/grimoire/trie/louds-trie.cc + lib/marisa/grimoire/trie/tail.cc + lib/marisa/grimoire/vector/bit-vector.cc + lib/marisa/keyset.cc +) + +add_library(marisa STATIC ${LIBMARISA_SOURCES}) +set_target_properties(marisa PROPERTIES POSITION_INDEPENDENT_CODE ON) +source_group(marisa FILES ${LIBMARISA_SOURCES}) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/COPYING.md b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/COPYING.md new file mode 100644 index 0000000000000000000000000000000000000000..8b63336f3c9c20f33231c657bf3a215c568a72b2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/COPYING.md @@ -0,0 +1,34 @@ +### COPYING + +libmarisa and its command line tools are dual-licensed under the BSD 2-clause license and the LGPL. + +#### The BSD 2-clause license + +Copyright (c) 2010-2019, Susumu Yata +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#### The LGPL 2.1 or any later version + +marisa-trie - A static and space-efficient trie data structure. +Copyright (C) 2010-2019 Susumu Yata + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/README.md b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b2f04520d8a2ce85dfb0079787d266abdf704a96 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/README.md @@ -0,0 +1,61 @@ +### README + +#### Project name + +marisa-trie + +#### Project summary + +MARISA: Matching Algorithm with Recursively Implemented StorAge + +#### Latest version + +0.2.6 + +#### Description + +Matching Algorithm with Recursively Implemented StorAge (MARISA) is a static and space-efficient trie data structure. And libmarisa is a C++ library to provide an implementation of MARISA. Also, the package of libmarisa contains a set of command line tools for building and operating a MARISA-based dictionary. + +A MARISA-based dictionary supports not only lookup but also reverse lookup, common prefix search and predictive search. + +* Lookup is to check whether or not a given string exists in a dictionary. +* Reverse lookup is to restore a key from its ID. +* Common prefix search is to find keys from prefixes of a given string. +* Predictive search is to find keys starting with a given string. + +The biggest advantage of libmarisa is that its dictionary size is considerably more compact than others. See below for the dictionary size of other implementations. + +* Input + * Source: enwiki-20121101-all-titles-in-ns0.gz + * Contents: all page titles of English Wikipedia (Nov. 2012) + * Number of keys: 9,805,576 + * Total size: 200,435,403 bytes (plain) / 54,933,690 bytes (gzipped) + +|Implementation|Size (bytes)|Remarks | +|:-------------|-----------:|--------------------------:| +|darts-clone | 376,613,888|Compacted double-array trie| +|tx-trie | 127,727,058|LOUDS-based trie | +|marisa-trie | 50,753,560|MARISA trie | + +#### Documentation + +* README (English): https://s-yata.github.io/marisa-trie/docs/readme.en.html +* README (Japanese): https://s-yata.github.io/marisa-trie/docs/readme.ja.html + +#### Build instructions + +You can get the latest version via `git clone`. Then, you can generate a `configure` script via `autoreconf -i`. After that, you can build and install libmarisa and its command line tools via `configure` and `make`. For details, see also documentation in `docs`. + +``` +$ git clone https://github.com/s-yata/marisa-trie.git +$ cd marisa-trie +$ autoreconf -i +$ ./configure --enable-native-code +$ make +$ make install +``` + +#### Source code license + +* The BSD 2-clause License +* The LGPL 2.1 or any later version diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa.h new file mode 100644 index 0000000000000000000000000000000000000000..52e1ef06359e5566940d14a9add16aaaa4b55a15 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa.h @@ -0,0 +1,14 @@ +#ifndef MARISA_H_ +#define MARISA_H_ + +// "marisa/stdio.h" includes for I/O using std::FILE. +#include "marisa/stdio.h" + +// "marisa/iostream.h" includes for I/O using std::iostream. +#include "marisa/iostream.h" + +// You can use instead of if you don't need the +// above I/O interfaces and don't want to include the above I/O headers. +#include "marisa/trie.h" + +#endif // MARISA_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/agent.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/agent.h new file mode 100644 index 0000000000000000000000000000000000000000..c72dea755d476a2ab90c42d843f469e12a71591b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/agent.h @@ -0,0 +1,73 @@ +#ifndef MARISA_AGENT_H_ +#define MARISA_AGENT_H_ + +#include "marisa/key.h" +#include "marisa/query.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +class State; + +} // namespace trie +} // namespace grimoire + +class Agent { + public: + Agent(); + ~Agent(); + + const Query &query() const { + return query_; + } + const Key &key() const { + return key_; + } + + void set_query(const char *str); + void set_query(const char *ptr, std::size_t length); + void set_query(std::size_t key_id); + + const grimoire::trie::State &state() const { + return *state_; + } + grimoire::trie::State &state() { + return *state_; + } + + void set_key(const char *str) { + MARISA_DEBUG_IF(str == NULL, MARISA_NULL_ERROR); + key_.set_str(str); + } + void set_key(const char *ptr, std::size_t length) { + MARISA_DEBUG_IF((ptr == NULL) && (length != 0), MARISA_NULL_ERROR); + MARISA_DEBUG_IF(length > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + key_.set_str(ptr, length); + } + void set_key(std::size_t id) { + MARISA_DEBUG_IF(id > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + key_.set_id(id); + } + + bool has_state() const { + return state_.get() != NULL; + } + void init_state(); + + void clear(); + void swap(Agent &rhs); + + private: + Query query_; + Key key_; + scoped_ptr state_; + + // Disallows copy and assignment. + Agent(const Agent &); + Agent &operator=(const Agent &); +}; + +} // namespace marisa + +#endif // MARISA_AGENT_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/base.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/base.h new file mode 100644 index 0000000000000000000000000000000000000000..ffcdc5bd8ccc05314ec0e029c72fe7ecbbaedffe --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/base.h @@ -0,0 +1,196 @@ +#ifndef MARISA_BASE_H_ +#define MARISA_BASE_H_ + +// Old Visual C++ does not provide stdint.h. +#ifndef _MSC_VER + #include +#endif // _MSC_VER + +#ifdef __cplusplus + #include +#else // __cplusplus + #include +#endif // __cplusplus + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#ifdef _MSC_VER +typedef unsigned __int8 marisa_uint8; +typedef unsigned __int16 marisa_uint16; +typedef unsigned __int32 marisa_uint32; +typedef unsigned __int64 marisa_uint64; +#else // _MSC_VER +typedef uint8_t marisa_uint8; +typedef uint16_t marisa_uint16; +typedef uint32_t marisa_uint32; +typedef uint64_t marisa_uint64; +#endif // _MSC_VER + +#if defined(_WIN64) || defined(__amd64__) || defined(__x86_64__) || \ + defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__sparc64__) || defined(__mips64__) || defined(__aarch64__) || \ + defined(__s390x__) + #define MARISA_WORD_SIZE 64 +#else // defined(_WIN64), etc. + #define MARISA_WORD_SIZE 32 +#endif // defined(_WIN64), etc. + +//#define MARISA_WORD_SIZE (sizeof(void *) * 8) + +#define MARISA_UINT8_MAX ((marisa_uint8)~(marisa_uint8)0) +#define MARISA_UINT16_MAX ((marisa_uint16)~(marisa_uint16)0) +#define MARISA_UINT32_MAX ((marisa_uint32)~(marisa_uint32)0) +#define MARISA_UINT64_MAX ((marisa_uint64)~(marisa_uint64)0) +#define MARISA_SIZE_MAX ((size_t)~(size_t)0) + +#define MARISA_INVALID_LINK_ID MARISA_UINT32_MAX +#define MARISA_INVALID_KEY_ID MARISA_UINT32_MAX +#define MARISA_INVALID_EXTRA (MARISA_UINT32_MAX >> 8) + +// Error codes are defined as members of marisa_error_code. This library throws +// an exception with one of the error codes when an error occurs. +typedef enum marisa_error_code_ { + // MARISA_OK means that a requested operation has succeeded. In practice, an + // exception never has MARISA_OK because it is not an error. + MARISA_OK = 0, + + // MARISA_STATE_ERROR means that an object was not ready for a requested + // operation. For example, an operation to modify a fixed vector throws an + // exception with MARISA_STATE_ERROR. + MARISA_STATE_ERROR = 1, + + // MARISA_NULL_ERROR means that an invalid NULL pointer has been given. + MARISA_NULL_ERROR = 2, + + // MARISA_BOUND_ERROR means that an operation has tried to access an out of + // range address. + MARISA_BOUND_ERROR = 3, + + // MARISA_RANGE_ERROR means that an out of range value has appeared in + // operation. + MARISA_RANGE_ERROR = 4, + + // MARISA_CODE_ERROR means that an undefined code has appeared in operation. + MARISA_CODE_ERROR = 5, + + // MARISA_RESET_ERROR means that a smart pointer has tried to reset itself. + MARISA_RESET_ERROR = 6, + + // MARISA_SIZE_ERROR means that a size has exceeded a library limitation. + MARISA_SIZE_ERROR = 7, + + // MARISA_MEMORY_ERROR means that a memory allocation has failed. + MARISA_MEMORY_ERROR = 8, + + // MARISA_IO_ERROR means that an I/O operation has failed. + MARISA_IO_ERROR = 9, + + // MARISA_FORMAT_ERROR means that input was in invalid format. + MARISA_FORMAT_ERROR = 10, +} marisa_error_code; + +// Min/max values, flags and masks for dictionary settings are defined below. +// Please note that unspecified settings will be replaced with the default +// settings. For example, 0 is equivalent to (MARISA_DEFAULT_NUM_TRIES | +// MARISA_DEFAULT_TRIE | MARISA_DEFAULT_TAIL | MARISA_DEFAULT_ORDER). + +// A dictionary consists of 3 tries in default. Usually more tries make a +// dictionary space-efficient but time-inefficient. +typedef enum marisa_num_tries_ { + MARISA_MIN_NUM_TRIES = 0x00001, + MARISA_MAX_NUM_TRIES = 0x0007F, + MARISA_DEFAULT_NUM_TRIES = 0x00003, +} marisa_num_tries; + +// This library uses a cache technique to accelerate search functions. The +// following enumerated type marisa_cache_level gives a list of available cache +// size options. A larger cache enables faster search but takes a more space. +typedef enum marisa_cache_level_ { + MARISA_HUGE_CACHE = 0x00080, + MARISA_LARGE_CACHE = 0x00100, + MARISA_NORMAL_CACHE = 0x00200, + MARISA_SMALL_CACHE = 0x00400, + MARISA_TINY_CACHE = 0x00800, + MARISA_DEFAULT_CACHE = MARISA_NORMAL_CACHE +} marisa_cache_level; + +// This library provides 2 kinds of TAIL implementations. +typedef enum marisa_tail_mode_ { + // MARISA_TEXT_TAIL merges last labels as zero-terminated strings. So, it is + // available if and only if the last labels do not contain a NULL character. + // If MARISA_TEXT_TAIL is specified and a NULL character exists in the last + // labels, the setting is automatically switched to MARISA_BINARY_TAIL. + MARISA_TEXT_TAIL = 0x01000, + + // MARISA_BINARY_TAIL also merges last labels but as byte sequences. It uses + // a bit vector to detect the end of a sequence, instead of NULL characters. + // So, MARISA_BINARY_TAIL requires a larger space if the average length of + // labels is greater than 8. + MARISA_BINARY_TAIL = 0x02000, + + MARISA_DEFAULT_TAIL = MARISA_TEXT_TAIL, +} marisa_tail_mode; + +// The arrangement of nodes affects the time cost of matching and the order of +// predictive search. +typedef enum marisa_node_order_ { + // MARISA_LABEL_ORDER arranges nodes in ascending label order. + // MARISA_LABEL_ORDER is useful if an application needs to predict keys in + // label order. + MARISA_LABEL_ORDER = 0x10000, + + // MARISA_WEIGHT_ORDER arranges nodes in descending weight order. + // MARISA_WEIGHT_ORDER is generally a better choice because it enables faster + // matching. + MARISA_WEIGHT_ORDER = 0x20000, + + MARISA_DEFAULT_ORDER = MARISA_WEIGHT_ORDER, +} marisa_node_order; + +typedef enum marisa_config_mask_ { + MARISA_NUM_TRIES_MASK = 0x0007F, + MARISA_CACHE_LEVEL_MASK = 0x00F80, + MARISA_TAIL_MODE_MASK = 0x0F000, + MARISA_NODE_ORDER_MASK = 0xF0000, + MARISA_CONFIG_MASK = 0xFFFFF +} marisa_config_mask; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#ifdef __cplusplus + +// `std::swap` is in since C++ 11 but in in C++ 98: +#if __cplusplus >= 201103L + #include +#else + #include +#endif +namespace marisa { + +typedef ::marisa_uint8 UInt8; +typedef ::marisa_uint16 UInt16; +typedef ::marisa_uint32 UInt32; +typedef ::marisa_uint64 UInt64; + +typedef ::marisa_error_code ErrorCode; + +typedef ::marisa_cache_level CacheLevel; +typedef ::marisa_tail_mode TailMode; +typedef ::marisa_node_order NodeOrder; + +using std::swap; + +} // namespace marisa +#endif // __cplusplus + +#ifdef __cplusplus + #include "marisa/exception.h" + #include "marisa/scoped-ptr.h" + #include "marisa/scoped-array.h" +#endif // __cplusplus + +#endif // MARISA_BASE_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/exception.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/exception.h new file mode 100644 index 0000000000000000000000000000000000000000..508c6b826922306cfd5dbe11bb6d8a516a40ce5c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/exception.h @@ -0,0 +1,82 @@ +#ifndef MARISA_EXCEPTION_H_ +#define MARISA_EXCEPTION_H_ + +#include + +#include "marisa/base.h" + +namespace marisa { + +// An exception object keeps a filename, a line number, an error code and an +// error message. The message format is as follows: +// "__FILE__:__LINE__: error_code: error_message" +class Exception : public std::exception { + public: + Exception(const char *filename, int line, + ErrorCode error_code, const char *error_message) + : std::exception(), filename_(filename), line_(line), + error_code_(error_code), error_message_(error_message) {} + Exception(const Exception &ex) + : std::exception(), filename_(ex.filename_), line_(ex.line_), + error_code_(ex.error_code_), error_message_(ex.error_message_) {} + virtual ~Exception() throw() {} + + Exception &operator=(const Exception &rhs) { + filename_ = rhs.filename_; + line_ = rhs.line_; + error_code_ = rhs.error_code_; + error_message_ = rhs.error_message_; + return *this; + } + + const char *filename() const { + return filename_; + } + int line() const { + return line_; + } + ErrorCode error_code() const { + return error_code_; + } + const char *error_message() const { + return error_message_; + } + + virtual const char *what() const throw() { + return error_message_; + } + + private: + const char *filename_; + int line_; + ErrorCode error_code_; + const char *error_message_; +}; + +// These macros are used to convert a line number to a string constant. +#define MARISA_INT_TO_STR(value) #value +#define MARISA_LINE_TO_STR(line) MARISA_INT_TO_STR(line) +#define MARISA_LINE_STR MARISA_LINE_TO_STR(__LINE__) + +// MARISA_THROW throws an exception with a filename, a line number, an error +// code and an error message. The message format is as follows: +// "__FILE__:__LINE__: error_code: error_message" +#define MARISA_THROW(error_code, error_message) \ + (throw marisa::Exception(__FILE__, __LINE__, error_code, \ + __FILE__ ":" MARISA_LINE_STR ": " #error_code ": " error_message)) + +// MARISA_THROW_IF throws an exception if `condition' is true. +#define MARISA_THROW_IF(condition, error_code) \ + (void)((!(condition)) || (MARISA_THROW(error_code, #condition), 0)) + +// MARISA_DEBUG_IF is ignored if _DEBUG is undefined. So, it is useful for +// debugging time-critical codes. +#ifdef _DEBUG + #define MARISA_DEBUG_IF(cond, error_code) MARISA_THROW_IF(cond, error_code) +#else + #define MARISA_DEBUG_IF(cond, error_code) +#endif + +} // namespace marisa + +#endif // MARISA_EXCEPTION_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/iostream.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/iostream.h new file mode 100644 index 0000000000000000000000000000000000000000..05d139a23b89d2e4ab0e0e75e660aeba72d196af --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/iostream.h @@ -0,0 +1,18 @@ +#ifndef MARISA_IOSTREAM_H_ +#define MARISA_IOSTREAM_H_ + +#include + +namespace marisa { + +class Trie; + +std::istream &read(std::istream &stream, Trie *trie); +std::ostream &write(std::ostream &stream, const Trie &trie); + +std::istream &operator>>(std::istream &stream, Trie &trie); +std::ostream &operator<<(std::ostream &stream, const Trie &trie); + +} // namespace marisa + +#endif // MARISA_IOSTREAM_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/key.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/key.h new file mode 100644 index 0000000000000000000000000000000000000000..8b2cf8fcf8a5caf541146f698650e95b25df910c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/key.h @@ -0,0 +1,85 @@ +#ifndef MARISA_KEY_H_ +#define MARISA_KEY_H_ + +#include "marisa/base.h" + +namespace marisa { + +class Key { + public: + Key() : ptr_(NULL), length_(0), union_() { + union_.id = 0; + } + Key(const Key &key) + : ptr_(key.ptr_), length_(key.length_), union_(key.union_) {} + + Key &operator=(const Key &key) { + ptr_ = key.ptr_; + length_ = key.length_; + union_ = key.union_; + return *this; + } + + char operator[](std::size_t i) const { + MARISA_DEBUG_IF(i >= length_, MARISA_BOUND_ERROR); + return ptr_[i]; + } + + void set_str(const char *str) { + MARISA_DEBUG_IF(str == NULL, MARISA_NULL_ERROR); + std::size_t length = 0; + while (str[length] != '\0') { + ++length; + } + MARISA_DEBUG_IF(length > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + ptr_ = str; + length_ = (UInt32)length; + } + void set_str(const char *ptr, std::size_t length) { + MARISA_DEBUG_IF((ptr == NULL) && (length != 0), MARISA_NULL_ERROR); + MARISA_DEBUG_IF(length > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + ptr_ = ptr; + length_ = (UInt32)length; + } + void set_id(std::size_t id) { + MARISA_DEBUG_IF(id > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + union_.id = (UInt32)id; + } + void set_weight(float weight) { + union_.weight = weight; + } + + const char *ptr() const { + return ptr_; + } + std::size_t length() const { + return length_; + } + std::size_t id() const { + return union_.id; + } + float weight() const { + return union_.weight; + } + + void clear() { + Key().swap(*this); + } + void swap(Key &rhs) { + marisa::swap(ptr_, rhs.ptr_); + marisa::swap(length_, rhs.length_); + marisa::swap(union_.id, rhs.union_.id); + } + + private: + const char *ptr_; + UInt32 length_; + union Union { + UInt32 id; + float weight; + } union_; +}; + +} // namespace marisa + +#endif // MARISA_KEY_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/keyset.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/keyset.h new file mode 100644 index 0000000000000000000000000000000000000000..e575015c0c37247032c133c99e2772b5273e494a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/keyset.h @@ -0,0 +1,80 @@ +#ifndef MARISA_KEYSET_H_ +#define MARISA_KEYSET_H_ + +#include "marisa/key.h" + +namespace marisa { + +class Keyset { + public: + enum { + BASE_BLOCK_SIZE = 4096, + EXTRA_BLOCK_SIZE = 1024, + KEY_BLOCK_SIZE = 256 + }; + + Keyset(); + + void push_back(const Key &key); + void push_back(const Key &key, char end_marker); + + void push_back(const char *str); + void push_back(const char *ptr, std::size_t length, float weight = 1.0); + + const Key &operator[](std::size_t i) const { + MARISA_DEBUG_IF(i >= size_, MARISA_BOUND_ERROR); + return key_blocks_[i / KEY_BLOCK_SIZE][i % KEY_BLOCK_SIZE]; + } + Key &operator[](std::size_t i) { + MARISA_DEBUG_IF(i >= size_, MARISA_BOUND_ERROR); + return key_blocks_[i / KEY_BLOCK_SIZE][i % KEY_BLOCK_SIZE]; + } + + std::size_t num_keys() const { + return size_; + } + + bool empty() const { + return size_ == 0; + } + std::size_t size() const { + return size_; + } + std::size_t total_length() const { + return total_length_; + } + + void reset(); + + void clear(); + void swap(Keyset &rhs); + + private: + scoped_array > base_blocks_; + std::size_t base_blocks_size_; + std::size_t base_blocks_capacity_; + scoped_array > extra_blocks_; + std::size_t extra_blocks_size_; + std::size_t extra_blocks_capacity_; + scoped_array > key_blocks_; + std::size_t key_blocks_size_; + std::size_t key_blocks_capacity_; + char *ptr_; + std::size_t avail_; + std::size_t size_; + std::size_t total_length_; + + char *reserve(std::size_t size); + + void append_base_block(); + void append_extra_block(std::size_t size); + void append_key_block(); + + // Disallows copy and assignment. + Keyset(const Keyset &); + Keyset &operator=(const Keyset &); +}; + +} // namespace marisa + +#endif // MARISA_KEYSET_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/query.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/query.h new file mode 100644 index 0000000000000000000000000000000000000000..316e741a8fa98f3743b5ed6e194742d1edb906a2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/query.h @@ -0,0 +1,71 @@ +#ifndef MARISA_QUERY_H_ +#define MARISA_QUERY_H_ + +#include "marisa/base.h" + +namespace marisa { + +class Query { + public: + Query() : ptr_(NULL), length_(0), id_(0) {} + Query(const Query &query) + : ptr_(query.ptr_), length_(query.length_), id_(query.id_) {} + + Query &operator=(const Query &query) { + ptr_ = query.ptr_; + length_ = query.length_; + id_ = query.id_; + return *this; + } + + char operator[](std::size_t i) const { + MARISA_DEBUG_IF(i >= length_, MARISA_BOUND_ERROR); + return ptr_[i]; + } + + void set_str(const char *str) { + MARISA_DEBUG_IF(str == NULL, MARISA_NULL_ERROR); + std::size_t length = 0; + while (str[length] != '\0') { + ++length; + } + ptr_ = str; + length_ = length; + } + void set_str(const char *ptr, std::size_t length) { + MARISA_DEBUG_IF((ptr == NULL) && (length != 0), MARISA_NULL_ERROR); + ptr_ = ptr; + length_ = length; + } + void set_id(std::size_t id) { + id_ = id; + } + + const char *ptr() const { + return ptr_; + } + std::size_t length() const { + return length_; + } + std::size_t id() const { + return id_; + } + + void clear() { + Query().swap(*this); + } + void swap(Query &rhs) { + marisa::swap(ptr_, rhs.ptr_); + marisa::swap(length_, rhs.length_); + marisa::swap(id_, rhs.id_); + } + + private: + const char *ptr_; + std::size_t length_; + std::size_t id_; +}; + +} // namespace marisa + +#endif // MARISA_QUERY_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/scoped-array.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/scoped-array.h new file mode 100644 index 0000000000000000000000000000000000000000..12b5b9e7f8360a4b850da20c8b87596c6be918b3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/scoped-array.h @@ -0,0 +1,48 @@ +#ifndef MARISA_SCOPED_ARRAY_H_ +#define MARISA_SCOPED_ARRAY_H_ + +#include "marisa/base.h" + +namespace marisa { + +template +class scoped_array { + public: + scoped_array() : array_(NULL) {} + explicit scoped_array(T *array) : array_(array) {} + + ~scoped_array() { + delete [] array_; + } + + void reset(T *array = NULL) { + MARISA_THROW_IF((array != NULL) && (array == array_), MARISA_RESET_ERROR); + scoped_array(array).swap(*this); + } + + T &operator[](std::size_t i) const { + MARISA_DEBUG_IF(array_ == NULL, MARISA_STATE_ERROR); + return array_[i]; + } + T *get() const { + return array_; + } + + void clear() { + scoped_array().swap(*this); + } + void swap(scoped_array &rhs) { + marisa::swap(array_, rhs.array_); + } + + private: + T *array_; + + // Disallows copy and assignment. + scoped_array(const scoped_array &); + scoped_array &operator=(const scoped_array &); +}; + +} // namespace marisa + +#endif // MARISA_SCOPED_ARRAY_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/scoped-ptr.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/scoped-ptr.h new file mode 100644 index 0000000000000000000000000000000000000000..63d7a3dcc92f16f6e7867655f5b9b9a6c5f15684 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/scoped-ptr.h @@ -0,0 +1,52 @@ +#ifndef MARISA_SCOPED_PTR_H_ +#define MARISA_SCOPED_PTR_H_ + +#include "marisa/base.h" + +namespace marisa { + +template +class scoped_ptr { + public: + scoped_ptr() : ptr_(NULL) {} + explicit scoped_ptr(T *ptr) : ptr_(ptr) {} + + ~scoped_ptr() { + delete ptr_; + } + + void reset(T *ptr = NULL) { + MARISA_THROW_IF((ptr != NULL) && (ptr == ptr_), MARISA_RESET_ERROR); + scoped_ptr(ptr).swap(*this); + } + + T &operator*() const { + MARISA_DEBUG_IF(ptr_ == NULL, MARISA_STATE_ERROR); + return *ptr_; + } + T *operator->() const { + MARISA_DEBUG_IF(ptr_ == NULL, MARISA_STATE_ERROR); + return ptr_; + } + T *get() const { + return ptr_; + } + + void clear() { + scoped_ptr().swap(*this); + } + void swap(scoped_ptr &rhs) { + marisa::swap(ptr_, rhs.ptr_); + } + + private: + T *ptr_; + + // Disallows copy and assignment. + scoped_ptr(const scoped_ptr &); + scoped_ptr &operator=(const scoped_ptr &); +}; + +} // namespace marisa + +#endif // MARISA_SCOPED_PTR_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/stdio.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/stdio.h new file mode 100644 index 0000000000000000000000000000000000000000..ee9a7b7795ff8b6ad74cdf85a8b93d7f16192e6b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/stdio.h @@ -0,0 +1,15 @@ +#ifndef MARISA_MYSTDIO_H_ +#define MARISA_MYSTDIO_H_ + +#include + +namespace marisa { + +class Trie; + +void fread(std::FILE *file, Trie *trie); +void fwrite(std::FILE *file, const Trie &trie); + +} // namespace marisa + +#endif // MARISA_MYSTDIO_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/trie.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/trie.h new file mode 100644 index 0000000000000000000000000000000000000000..30f3c686b261819f14b2cbcbf9747b5d2bb04398 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/include/marisa/trie.h @@ -0,0 +1,64 @@ +#ifndef MARISA_TRIE_H_ +#define MARISA_TRIE_H_ + +#include "marisa/keyset.h" +#include "marisa/agent.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +class LoudsTrie; + +} // namespace trie +} // namespace grimoire + +class Trie { + friend class TrieIO; + + public: + Trie(); + ~Trie(); + + void build(Keyset &keyset, int config_flags = 0); + + void mmap(const char *filename); + void map(const void *ptr, std::size_t size); + + void load(const char *filename); + void read(int fd); + + void save(const char *filename) const; + void write(int fd) const; + + bool lookup(Agent &agent) const; + void reverse_lookup(Agent &agent) const; + bool common_prefix_search(Agent &agent) const; + bool predictive_search(Agent &agent) const; + + std::size_t num_tries() const; + std::size_t num_keys() const; + std::size_t num_nodes() const; + + TailMode tail_mode() const; + NodeOrder node_order() const; + + bool empty() const; + std::size_t size() const; + std::size_t total_size() const; + std::size_t io_size() const; + + void clear(); + void swap(Trie &rhs); + + private: + scoped_ptr trie_; + + // Disallows copy and assignment. + Trie(const Trie &); + Trie &operator=(const Trie &); +}; + +} // namespace marisa + +#endif // MARISA_TRIE_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/agent.cc b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/agent.cc new file mode 100644 index 0000000000000000000000000000000000000000..7fa7cb1df9138d98276ec7f830195bac4fd9111a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/agent.cc @@ -0,0 +1,51 @@ +#include + +#include "marisa/agent.h" +#include "marisa/grimoire/trie.h" + +namespace marisa { + +Agent::Agent() : query_(), key_(), state_() {} + +Agent::~Agent() {} + +void Agent::set_query(const char *str) { + MARISA_THROW_IF(str == NULL, MARISA_NULL_ERROR); + if (state_.get() != NULL) { + state_->reset(); + } + query_.set_str(str); +} + +void Agent::set_query(const char *ptr, std::size_t length) { + MARISA_THROW_IF((ptr == NULL) && (length != 0), MARISA_NULL_ERROR); + if (state_.get() != NULL) { + state_->reset(); + } + query_.set_str(ptr, length); +} + +void Agent::set_query(std::size_t key_id) { + if (state_.get() != NULL) { + state_->reset(); + } + query_.set_id(key_id); +} + +void Agent::init_state() { + MARISA_THROW_IF(state_.get() != NULL, MARISA_STATE_ERROR); + state_.reset(new (std::nothrow) grimoire::State); + MARISA_THROW_IF(state_.get() == NULL, MARISA_MEMORY_ERROR); +} + +void Agent::clear() { + Agent().swap(*this); +} + +void Agent::swap(Agent &rhs) { + query_.swap(rhs.query_); + key_.swap(rhs.key_); + state_.swap(rhs.state_); +} + +} // namespace marisa diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/algorithm.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/algorithm.h new file mode 100644 index 0000000000000000000000000000000000000000..970c09f0eafac57ae7f12f5dd5ceee22db2f3bb2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/algorithm.h @@ -0,0 +1,26 @@ +#ifndef MARISA_GRIMOIRE_ALGORITHM_H_ +#define MARISA_GRIMOIRE_ALGORITHM_H_ + +#include "marisa/grimoire/algorithm/sort.h" + +namespace marisa { +namespace grimoire { + +class Algorithm { + public: + Algorithm() {} + + template + std::size_t sort(Iterator begin, Iterator end) const { + return algorithm::sort(begin, end); + } + + private: + Algorithm(const Algorithm &); + Algorithm &operator=(const Algorithm &); +}; + +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_ALGORITHM_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/algorithm/sort.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/algorithm/sort.h new file mode 100644 index 0000000000000000000000000000000000000000..5f3b6526bda8a11841f50ea996009a1b6247938f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/algorithm/sort.h @@ -0,0 +1,196 @@ +#ifndef MARISA_GRIMOIRE_ALGORITHM_SORT_H_ +#define MARISA_GRIMOIRE_ALGORITHM_SORT_H_ + +#include "marisa/base.h" + +namespace marisa { +namespace grimoire { +namespace algorithm { +namespace details { + +enum { + MARISA_INSERTION_SORT_THRESHOLD = 10 +}; + +template +int get_label(const T &unit, std::size_t depth) { + MARISA_DEBUG_IF(depth > unit.length(), MARISA_BOUND_ERROR); + + return (depth < unit.length()) ? (int)(UInt8)unit[depth] : -1; +} + +template +int median(const T &a, const T &b, const T &c, std::size_t depth) { + const int x = get_label(a, depth); + const int y = get_label(b, depth); + const int z = get_label(c, depth); + if (x < y) { + if (y < z) { + return y; + } else if (x < z) { + return z; + } + return x; + } else if (x < z) { + return x; + } else if (y < z) { + return z; + } + return y; +} + +template +int compare(const T &lhs, const T &rhs, std::size_t depth) { + for (std::size_t i = depth; i < lhs.length(); ++i) { + if (i == rhs.length()) { + return 1; + } + if (lhs[i] != rhs[i]) { + return (UInt8)lhs[i] - (UInt8)rhs[i]; + } + } + if (lhs.length() == rhs.length()) { + return 0; + } + return (lhs.length() < rhs.length()) ? -1 : 1; +} + +template +std::size_t insertion_sort(Iterator l, Iterator r, std::size_t depth) { + MARISA_DEBUG_IF(l > r, MARISA_BOUND_ERROR); + + std::size_t count = 1; + for (Iterator i = l + 1; i < r; ++i) { + int result = 0; + for (Iterator j = i; j > l; --j) { + result = compare(*(j - 1), *j, depth); + if (result <= 0) { + break; + } + marisa::swap(*(j - 1), *j); + } + if (result != 0) { + ++count; + } + } + return count; +} + +template +std::size_t sort(Iterator l, Iterator r, std::size_t depth) { + MARISA_DEBUG_IF(l > r, MARISA_BOUND_ERROR); + + std::size_t count = 0; + while ((r - l) > MARISA_INSERTION_SORT_THRESHOLD) { + Iterator pl = l; + Iterator pr = r; + Iterator pivot_l = l; + Iterator pivot_r = r; + + const int pivot = median(*l, *(l + (r - l) / 2), *(r - 1), depth); + for ( ; ; ) { + while (pl < pr) { + const int label = get_label(*pl, depth); + if (label > pivot) { + break; + } else if (label == pivot) { + marisa::swap(*pl, *pivot_l); + ++pivot_l; + } + ++pl; + } + while (pl < pr) { + const int label = get_label(*--pr, depth); + if (label < pivot) { + break; + } else if (label == pivot) { + marisa::swap(*pr, *--pivot_r); + } + } + if (pl >= pr) { + break; + } + marisa::swap(*pl, *pr); + ++pl; + } + while (pivot_l > l) { + marisa::swap(*--pivot_l, *--pl); + } + while (pivot_r < r) { + marisa::swap(*pivot_r, *pr); + ++pivot_r; + ++pr; + } + + if (((pl - l) > (pr - pl)) || ((r - pr) > (pr - pl))) { + if ((pr - pl) == 1) { + ++count; + } else if ((pr - pl) > 1) { + if (pivot == -1) { + ++count; + } else { + count += sort(pl, pr, depth + 1); + } + } + + if ((pl - l) < (r - pr)) { + if ((pl - l) == 1) { + ++count; + } else if ((pl - l) > 1) { + count += sort(l, pl, depth); + } + l = pr; + } else { + if ((r - pr) == 1) { + ++count; + } else if ((r - pr) > 1) { + count += sort(pr, r, depth); + } + r = pl; + } + } else { + if ((pl - l) == 1) { + ++count; + } else if ((pl - l) > 1) { + count += sort(l, pl, depth); + } + + if ((r - pr) == 1) { + ++count; + } else if ((r - pr) > 1) { + count += sort(pr, r, depth); + } + + l = pl, r = pr; + if ((pr - pl) == 1) { + ++count; + } else if ((pr - pl) > 1) { + if (pivot == -1) { + l = r; + ++count; + } else { + ++depth; + } + } + } + } + + if ((r - l) > 1) { + count += insertion_sort(l, r, depth); + } + return count; +} + +} // namespace details + +template +std::size_t sort(Iterator begin, Iterator end) { + MARISA_DEBUG_IF(begin > end, MARISA_BOUND_ERROR); + return details::sort(begin, end, 0); +}; + +} // namespace algorithm +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_ALGORITHM_SORT_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/intrin.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/intrin.h new file mode 100644 index 0000000000000000000000000000000000000000..77b4e9980f5b51d9a69156ae2e964f328318f241 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/intrin.h @@ -0,0 +1,138 @@ +#ifndef MARISA_GRIMOIRE_INTRIN_H_ +#define MARISA_GRIMOIRE_INTRIN_H_ + +#include "marisa/base.h" + +#if defined(__x86_64__) || defined(_M_X64) + #define MARISA_X64 +#elif defined(__i386__) || defined(_M_IX86) + #define MARISA_X86 +#else // defined(__i386__) || defined(_M_IX86) + #ifdef MARISA_USE_BMI2 + #undef MARISA_USE_BMI2 + #endif // MARISA_USE_BMI2 + #ifdef MARISA_USE_BMI + #undef MARISA_USE_BMI + #endif // MARISA_USE_BMI + #ifdef MARISA_USE_POPCNT + #undef MARISA_USE_POPCNT + #endif // MARISA_USE_POPCNT + #ifdef MARISA_USE_SSE4A + #undef MARISA_USE_SSE4A + #endif // MARISA_USE_SSE4A + #ifdef MARISA_USE_SSE4 + #undef MARISA_USE_SSE4 + #endif // MARISA_USE_SSE4 + #ifdef MARISA_USE_SSE4_2 + #undef MARISA_USE_SSE4_2 + #endif // MARISA_USE_SSE4_2 + #ifdef MARISA_USE_SSE4_1 + #undef MARISA_USE_SSE4_1 + #endif // MARISA_USE_SSE4_1 + #ifdef MARISA_USE_SSSE3 + #undef MARISA_USE_SSSE3 + #endif // MARISA_USE_SSSE3 + #ifdef MARISA_USE_SSE3 + #undef MARISA_USE_SSE3 + #endif // MARISA_USE_SSE3 + #ifdef MARISA_USE_SSE2 + #undef MARISA_USE_SSE2 + #endif // MARISA_USE_SSE2 +#endif // defined(__i386__) || defined(_M_IX86) + +#ifdef MARISA_USE_BMI2 + #ifndef MARISA_USE_BMI + #define MARISA_USE_BMI + #endif // MARISA_USE_BMI + #ifdef _MSC_VER + #include + #else // _MSC_VER + #include + #endif // _MSC_VER +#endif // MARISA_USE_BMI2 + +#ifdef MARISA_USE_BMI + #ifndef MARISA_USE_SSE4 + #define MARISA_USE_SSE4 + #endif // MARISA_USE_SSE4 +#endif // MARISA_USE_BMI + +#ifdef MARISA_USE_SSE4A + #ifndef MARISA_USE_SSE3 + #define MARISA_USE_SSE3 + #endif // MARISA_USE_SSE3 + #ifndef MARISA_USE_POPCNT + #define MARISA_USE_POPCNT + #endif // MARISA_USE_POPCNT +#endif // MARISA_USE_SSE4A + +#ifdef MARISA_USE_SSE4 + #ifndef MARISA_USE_SSE4_2 + #define MARISA_USE_SSE4_2 + #endif // MARISA_USE_SSE4_2 +#endif // MARISA_USE_SSE4 + +#ifdef MARISA_USE_SSE4_2 + #ifndef MARISA_USE_SSE4_1 + #define MARISA_USE_SSE4_1 + #endif // MARISA_USE_SSE4_1 + #ifndef MARISA_USE_POPCNT + #define MARISA_USE_POPCNT + #endif // MARISA_USE_POPCNT +#endif // MARISA_USE_SSE4_2 + +#ifdef MARISA_USE_SSE4_1 + #ifndef MARISA_USE_SSSE3 + #define MARISA_USE_SSSE3 + #endif // MARISA_USE_SSSE3 +#endif // MARISA_USE_SSE4_1 + +#ifdef MARISA_USE_POPCNT + #ifndef MARISA_USE_SSE3 + #define MARISA_USE_SSE3 + #endif // MARISA_USE_SSE3 + #ifdef _MSC_VER + #include + #else // _MSC_VER + #include + #endif // _MSC_VER +#endif // MARISA_USE_POPCNT + +#ifdef MARISA_USE_SSSE3 + #ifndef MARISA_USE_SSE3 + #define MARISA_USE_SSE3 + #endif // MARISA_USE_SSE3 + #ifdef MARISA_X64 + #define MARISA_X64_SSSE3 + #else // MARISA_X64 + #define MARISA_X86_SSSE3 + #endif // MAIRSA_X64 + #include +#endif // MARISA_USE_SSSE3 + +#ifdef MARISA_USE_SSE3 + #ifndef MARISA_USE_SSE2 + #define MARISA_USE_SSE2 + #endif // MARISA_USE_SSE2 +#endif // MARISA_USE_SSE3 + +#ifdef MARISA_USE_SSE2 + #ifdef MARISA_X64 + #define MARISA_X64_SSE2 + #else // MARISA_X64 + #define MARISA_X86_SSE2 + #endif // MAIRSA_X64 + #include +#endif // MARISA_USE_SSE2 + +#ifdef _MSC_VER + #if MARISA_WORD_SIZE == 64 + #include + #pragma intrinsic(_BitScanForward64) + #else // MARISA_WORD_SIZE == 64 + #include + #pragma intrinsic(_BitScanForward) + #endif // MARISA_WORD_SIZE == 64 +#endif // _MSC_VER + +#endif // MARISA_GRIMOIRE_INTRIN_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io.h new file mode 100644 index 0000000000000000000000000000000000000000..43ff8c91cf27c2f5830f07ea2c1f41baf88f75f1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io.h @@ -0,0 +1,18 @@ +#ifndef MARISA_GRIMOIRE_IO_H_ +#define MARISA_GRIMOIRE_IO_H_ + +#include "marisa/grimoire/io/mapper.h" +#include "marisa/grimoire/io/reader.h" +#include "marisa/grimoire/io/writer.h" + +namespace marisa { +namespace grimoire { + +using io::Mapper; +using io::Reader; +using io::Writer; + +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_IO_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/mapper.cc b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/mapper.cc new file mode 100644 index 0000000000000000000000000000000000000000..6ae0ee37f39cd04ac4884745413a60a84c039e75 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/mapper.cc @@ -0,0 +1,163 @@ +#if (defined _WIN32) || (defined _WIN64) + #include + #include + #include +#else // (defined _WIN32) || (defined _WIN64) + #include + #include + #include + #include + #include +#endif // (defined _WIN32) || (defined _WIN64) + +#include "marisa/grimoire/io/mapper.h" + +namespace marisa { +namespace grimoire { +namespace io { + +#if (defined _WIN32) || (defined _WIN64) +Mapper::Mapper() + : ptr_(NULL), origin_(NULL), avail_(0), size_(0), + file_(NULL), map_(NULL) {} +#else // (defined _WIN32) || (defined _WIN64) +Mapper::Mapper() + : ptr_(NULL), origin_(MAP_FAILED), avail_(0), size_(0), fd_(-1) {} +#endif // (defined _WIN32) || (defined _WIN64) + +#if (defined _WIN32) || (defined _WIN64) +Mapper::~Mapper() { + if (origin_ != NULL) { + ::UnmapViewOfFile(origin_); + } + + if (map_ != NULL) { + ::CloseHandle(map_); + } + + if (file_ != NULL) { + ::CloseHandle(file_); + } +} +#else // (defined _WIN32) || (defined _WIN64) +Mapper::~Mapper() { + if (origin_ != MAP_FAILED) { + ::munmap(origin_, size_); + } + + if (fd_ != -1) { + ::close(fd_); + } +} +#endif // (defined _WIN32) || (defined _WIN64) + +void Mapper::open(const char *filename) { + MARISA_THROW_IF(filename == NULL, MARISA_NULL_ERROR); + + Mapper temp; + temp.open_(filename); + swap(temp); +} + +void Mapper::open(const void *ptr, std::size_t size) { + MARISA_THROW_IF((ptr == NULL) && (size != 0), MARISA_NULL_ERROR); + + Mapper temp; + temp.open_(ptr, size); + swap(temp); +} + +void Mapper::seek(std::size_t size) { + MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR); + MARISA_THROW_IF(size > avail_, MARISA_IO_ERROR); + + map_data(size); +} + +bool Mapper::is_open() const { + return ptr_ != NULL; +} + +void Mapper::clear() { + Mapper().swap(*this); +} + +void Mapper::swap(Mapper &rhs) { + marisa::swap(ptr_, rhs.ptr_); + marisa::swap(avail_, rhs.avail_); + marisa::swap(origin_, rhs.origin_); + marisa::swap(size_, rhs.size_); +#if (defined _WIN32) || (defined _WIN64) + marisa::swap(file_, rhs.file_); + marisa::swap(map_, rhs.map_); +#else // (defined _WIN32) || (defined _WIN64) + marisa::swap(fd_, rhs.fd_); +#endif // (defined _WIN32) || (defined _WIN64) +} + +const void *Mapper::map_data(std::size_t size) { + MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR); + MARISA_THROW_IF(size > avail_, MARISA_IO_ERROR); + + const char * const data = static_cast(ptr_); + ptr_ = data + size; + avail_ -= size; + return data; +} + +#if (defined _WIN32) || (defined _WIN64) + #ifdef __MSVCRT_VERSION__ + #if __MSVCRT_VERSION__ >= 0x0601 + #define MARISA_HAS_STAT64 + #endif // __MSVCRT_VERSION__ >= 0x0601 + #endif // __MSVCRT_VERSION__ +void Mapper::open_(const char *filename) { + #ifdef MARISA_HAS_STAT64 + struct __stat64 st; + MARISA_THROW_IF(::_stat64(filename, &st) != 0, MARISA_IO_ERROR); + #else // MARISA_HAS_STAT64 + struct _stat st; + MARISA_THROW_IF(::_stat(filename, &st) != 0, MARISA_IO_ERROR); + #endif // MARISA_HAS_STAT64 + MARISA_THROW_IF((UInt64)st.st_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + size_ = (std::size_t)st.st_size; + + file_ = ::CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + MARISA_THROW_IF(file_ == INVALID_HANDLE_VALUE, MARISA_IO_ERROR); + + map_ = ::CreateFileMapping(file_, NULL, PAGE_READONLY, 0, 0, NULL); + MARISA_THROW_IF(map_ == NULL, MARISA_IO_ERROR); + + origin_ = ::MapViewOfFile(map_, FILE_MAP_READ, 0, 0, 0); + MARISA_THROW_IF(origin_ == NULL, MARISA_IO_ERROR); + + ptr_ = static_cast(origin_); + avail_ = size_; +} +#else // (defined _WIN32) || (defined _WIN64) +void Mapper::open_(const char *filename) { + struct stat st; + MARISA_THROW_IF(::stat(filename, &st) != 0, MARISA_IO_ERROR); + MARISA_THROW_IF((UInt64)st.st_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + size_ = (std::size_t)st.st_size; + + fd_ = ::open(filename, O_RDONLY); + MARISA_THROW_IF(fd_ == -1, MARISA_IO_ERROR); + + origin_ = ::mmap(NULL, size_, PROT_READ, MAP_SHARED, fd_, 0); + MARISA_THROW_IF(origin_ == MAP_FAILED, MARISA_IO_ERROR); + + ptr_ = static_cast(origin_); + avail_ = size_; +} +#endif // (defined _WIN32) || (defined _WIN64) + +void Mapper::open_(const void *ptr, std::size_t size) { + ptr_ = ptr; + avail_ = size; +} + +} // namespace io +} // namespace grimoire +} // namespace marisa diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/mapper.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/mapper.h new file mode 100644 index 0000000000000000000000000000000000000000..f701c9477a63cfdb831ddcb1836a371307d1b8f3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/mapper.h @@ -0,0 +1,67 @@ +#ifndef MARISA_GRIMOIRE_IO_MAPPER_H_ +#define MARISA_GRIMOIRE_IO_MAPPER_H_ + +#include + +#include "marisa/base.h" + +namespace marisa { +namespace grimoire { +namespace io { + +class Mapper { + public: + Mapper(); + ~Mapper(); + + void open(const char *filename); + void open(const void *ptr, std::size_t size); + + template + void map(T *obj) { + MARISA_THROW_IF(obj == NULL, MARISA_NULL_ERROR); + *obj = *static_cast(map_data(sizeof(T))); + } + + template + void map(const T **objs, std::size_t num_objs) { + MARISA_THROW_IF((objs == NULL) && (num_objs != 0), MARISA_NULL_ERROR); + MARISA_THROW_IF(num_objs > (MARISA_SIZE_MAX / sizeof(T)), + MARISA_SIZE_ERROR); + *objs = static_cast(map_data(sizeof(T) * num_objs)); + } + + void seek(std::size_t size); + + bool is_open() const; + + void clear(); + void swap(Mapper &rhs); + + private: + const void *ptr_; + void *origin_; + std::size_t avail_; + std::size_t size_; +#if (defined _WIN32) || (defined _WIN64) + void *file_; + void *map_; +#else // (defined _WIN32) || (defined _WIN64) + int fd_; +#endif // (defined _WIN32) || (defined _WIN64) + + void open_(const char *filename); + void open_(const void *ptr, std::size_t size); + + const void *map_data(std::size_t size); + + // Disallows copy and assignment. + Mapper(const Mapper &); + Mapper &operator=(const Mapper &); +}; + +} // namespace io +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_IO_MAPPER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/reader.cc b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/reader.cc new file mode 100644 index 0000000000000000000000000000000000000000..b9c0809886afdcd730b32f50bbbbe6a8cb55af86 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/reader.cc @@ -0,0 +1,147 @@ +#include + +#ifdef _WIN32 + #include +#else // _WIN32 + #include +#endif // _WIN32 + +#include + +#include "marisa/grimoire/io/reader.h" + +namespace marisa { +namespace grimoire { +namespace io { + +Reader::Reader() + : file_(NULL), fd_(-1), stream_(NULL), needs_fclose_(false) {} + +Reader::~Reader() { + if (needs_fclose_) { + ::fclose(file_); + } +} + +void Reader::open(const char *filename) { + MARISA_THROW_IF(filename == NULL, MARISA_NULL_ERROR); + + Reader temp; + temp.open_(filename); + swap(temp); +} + +void Reader::open(std::FILE *file) { + MARISA_THROW_IF(file == NULL, MARISA_NULL_ERROR); + + Reader temp; + temp.open_(file); + swap(temp); +} + +void Reader::open(int fd) { + MARISA_THROW_IF(fd == -1, MARISA_CODE_ERROR); + + Reader temp; + temp.open_(fd); + swap(temp); +} + +void Reader::open(std::istream &stream) { + Reader temp; + temp.open_(stream); + swap(temp); +} + +void Reader::clear() { + Reader().swap(*this); +} + +void Reader::swap(Reader &rhs) { + marisa::swap(file_, rhs.file_); + marisa::swap(fd_, rhs.fd_); + marisa::swap(stream_, rhs.stream_); + marisa::swap(needs_fclose_, rhs.needs_fclose_); +} + +void Reader::seek(std::size_t size) { + MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR); + if (size == 0) { + return; + } else if (size <= 16) { + char buf[16]; + read_data(buf, size); + } else { + char buf[1024]; + while (size != 0) { + const std::size_t count = (size < sizeof(buf)) ? size : sizeof(buf); + read_data(buf, count); + size -= count; + } + } +} + +bool Reader::is_open() const { + return (file_ != NULL) || (fd_ != -1) || (stream_ != NULL); +} + +void Reader::open_(const char *filename) { + std::FILE *file = NULL; +#ifdef _MSC_VER + MARISA_THROW_IF(::fopen_s(&file, filename, "rb") != 0, MARISA_IO_ERROR); +#else // _MSC_VER + file = ::fopen(filename, "rb"); + MARISA_THROW_IF(file == NULL, MARISA_IO_ERROR); +#endif // _MSC_VER + file_ = file; + needs_fclose_ = true; +} + +void Reader::open_(std::FILE *file) { + file_ = file; +} + +void Reader::open_(int fd) { + fd_ = fd; +} + +void Reader::open_(std::istream &stream) { + stream_ = &stream; +} + +void Reader::read_data(void *buf, std::size_t size) { + MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR); + if (size == 0) { + return; + } else if (fd_ != -1) { + while (size != 0) { +#ifdef _WIN32 + static const std::size_t CHUNK_SIZE = + std::numeric_limits::max(); + const unsigned int count = (size < CHUNK_SIZE) ? size : CHUNK_SIZE; + const int size_read = ::_read(fd_, buf, count); +#else // _WIN32 + static const std::size_t CHUNK_SIZE = + std::numeric_limits< ::ssize_t>::max(); + const ::size_t count = (size < CHUNK_SIZE) ? size : CHUNK_SIZE; + const ::ssize_t size_read = ::read(fd_, buf, count); +#endif // _WIN32 + MARISA_THROW_IF(size_read <= 0, MARISA_IO_ERROR); + buf = static_cast(buf) + size_read; + size -= static_cast(size_read); + } + } else if (file_ != NULL) { + MARISA_THROW_IF(::fread(buf, 1, size, file_) != size, MARISA_IO_ERROR); + } else if (stream_ != NULL) { + try { + MARISA_THROW_IF(!stream_->read(static_cast(buf), + static_cast(size)), MARISA_IO_ERROR); + } catch (const std::ios_base::failure &) { + MARISA_THROW(MARISA_IO_ERROR, "std::ios_base::failure"); + } + } +} + +} // namespace io +} // namespace grimoire +} // namespace marisa diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/reader.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/reader.h new file mode 100644 index 0000000000000000000000000000000000000000..fa4ce362782bfa3e48289eb7ac8826fb1e62db77 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/reader.h @@ -0,0 +1,66 @@ +#ifndef MARISA_GRIMOIRE_IO_READER_H_ +#define MARISA_GRIMOIRE_IO_READER_H_ + +#include +#include + +#include "marisa/base.h" + +namespace marisa { +namespace grimoire { +namespace io { + +class Reader { + public: + Reader(); + ~Reader(); + + void open(const char *filename); + void open(std::FILE *file); + void open(int fd); + void open(std::istream &stream); + + template + void read(T *obj) { + MARISA_THROW_IF(obj == NULL, MARISA_NULL_ERROR); + read_data(obj, sizeof(T)); + } + + template + void read(T *objs, std::size_t num_objs) { + MARISA_THROW_IF((objs == NULL) && (num_objs != 0), MARISA_NULL_ERROR); + MARISA_THROW_IF(num_objs > (MARISA_SIZE_MAX / sizeof(T)), + MARISA_SIZE_ERROR); + read_data(objs, sizeof(T) * num_objs); + } + + void seek(std::size_t size); + + bool is_open() const; + + void clear(); + void swap(Reader &rhs); + + private: + std::FILE *file_; + int fd_; + std::istream *stream_; + bool needs_fclose_; + + void open_(const char *filename); + void open_(std::FILE *file); + void open_(int fd); + void open_(std::istream &stream); + + void read_data(void *buf, std::size_t size); + + // Disallows copy and assignment. + Reader(const Reader &); + Reader &operator=(const Reader &); +}; + +} // namespace io +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_IO_READER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/writer.cc b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/writer.cc new file mode 100644 index 0000000000000000000000000000000000000000..fb3d2d08ff9bcabd78fcb44c35e7eed1da044225 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/writer.cc @@ -0,0 +1,148 @@ +#include + +#ifdef _WIN32 + #include +#else // _WIN32 + #include +#endif // _WIN32 + +#include + +#include "marisa/grimoire/io/writer.h" + +namespace marisa { +namespace grimoire { +namespace io { + +Writer::Writer() + : file_(NULL), fd_(-1), stream_(NULL), needs_fclose_(false) {} + +Writer::~Writer() { + if (needs_fclose_) { + ::fclose(file_); + } +} + +void Writer::open(const char *filename) { + MARISA_THROW_IF(filename == NULL, MARISA_NULL_ERROR); + + Writer temp; + temp.open_(filename); + swap(temp); +} + +void Writer::open(std::FILE *file) { + MARISA_THROW_IF(file == NULL, MARISA_NULL_ERROR); + + Writer temp; + temp.open_(file); + swap(temp); +} + +void Writer::open(int fd) { + MARISA_THROW_IF(fd == -1, MARISA_CODE_ERROR); + + Writer temp; + temp.open_(fd); + swap(temp); +} + +void Writer::open(std::ostream &stream) { + Writer temp; + temp.open_(stream); + swap(temp); +} + +void Writer::clear() { + Writer().swap(*this); +} + +void Writer::swap(Writer &rhs) { + marisa::swap(file_, rhs.file_); + marisa::swap(fd_, rhs.fd_); + marisa::swap(stream_, rhs.stream_); + marisa::swap(needs_fclose_, rhs.needs_fclose_); +} + +void Writer::seek(std::size_t size) { + MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR); + if (size == 0) { + return; + } else if (size <= 16) { + const char buf[16] = {}; + write_data(buf, size); + } else { + const char buf[1024] = {}; + do { + const std::size_t count = (size < sizeof(buf)) ? size : sizeof(buf); + write_data(buf, count); + size -= count; + } while (size != 0); + } +} + +bool Writer::is_open() const { + return (file_ != NULL) || (fd_ != -1) || (stream_ != NULL); +} + +void Writer::open_(const char *filename) { + std::FILE *file = NULL; +#ifdef _MSC_VER + MARISA_THROW_IF(::fopen_s(&file, filename, "wb") != 0, MARISA_IO_ERROR); +#else // _MSC_VER + file = ::fopen(filename, "wb"); + MARISA_THROW_IF(file == NULL, MARISA_IO_ERROR); +#endif // _MSC_VER + file_ = file; + needs_fclose_ = true; +} + +void Writer::open_(std::FILE *file) { + file_ = file; +} + +void Writer::open_(int fd) { + fd_ = fd; +} + +void Writer::open_(std::ostream &stream) { + stream_ = &stream; +} + +void Writer::write_data(const void *data, std::size_t size) { + MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR); + if (size == 0) { + return; + } else if (fd_ != -1) { + while (size != 0) { +#ifdef _WIN32 + static const std::size_t CHUNK_SIZE = + std::numeric_limits::max(); + const unsigned int count = (size < CHUNK_SIZE) ? size : CHUNK_SIZE; + const int size_written = ::_write(fd_, data, count); +#else // _WIN32 + static const std::size_t CHUNK_SIZE = + std::numeric_limits< ::ssize_t>::max(); + const ::size_t count = (size < CHUNK_SIZE) ? size : CHUNK_SIZE; + const ::ssize_t size_written = ::write(fd_, data, count); +#endif // _WIN32 + MARISA_THROW_IF(size_written <= 0, MARISA_IO_ERROR); + data = static_cast(data) + size_written; + size -= static_cast(size_written); + } + } else if (file_ != NULL) { + MARISA_THROW_IF(::fwrite(data, 1, size, file_) != size, MARISA_IO_ERROR); + MARISA_THROW_IF(::fflush(file_) != 0, MARISA_IO_ERROR); + } else if (stream_ != NULL) { + try { + MARISA_THROW_IF(!stream_->write(static_cast(data), + static_cast(size)), MARISA_IO_ERROR); + } catch (const std::ios_base::failure &) { + MARISA_THROW(MARISA_IO_ERROR, "std::ios_base::failure"); + } + } +} + +} // namespace io +} // namespace grimoire +} // namespace marisa diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/writer.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/writer.h new file mode 100644 index 0000000000000000000000000000000000000000..d49761b02274e1301d6987093b8c9cd6feccaf65 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/io/writer.h @@ -0,0 +1,65 @@ +#ifndef MARISA_GRIMOIRE_IO_WRITER_H_ +#define MARISA_GRIMOIRE_IO_WRITER_H_ + +#include +#include + +#include "marisa/base.h" + +namespace marisa { +namespace grimoire { +namespace io { + +class Writer { + public: + Writer(); + ~Writer(); + + void open(const char *filename); + void open(std::FILE *file); + void open(int fd); + void open(std::ostream &stream); + + template + void write(const T &obj) { + write_data(&obj, sizeof(T)); + } + + template + void write(const T *objs, std::size_t num_objs) { + MARISA_THROW_IF((objs == NULL) && (num_objs != 0), MARISA_NULL_ERROR); + MARISA_THROW_IF(num_objs > (MARISA_SIZE_MAX / sizeof(T)), + MARISA_SIZE_ERROR); + write_data(objs, sizeof(T) * num_objs); + } + + void seek(std::size_t size); + + bool is_open() const; + + void clear(); + void swap(Writer &rhs); + + private: + std::FILE *file_; + int fd_; + std::ostream *stream_; + bool needs_fclose_; + + void open_(const char *filename); + void open_(std::FILE *file); + void open_(int fd); + void open_(std::ostream &stream); + + void write_data(const void *data, std::size_t size); + + // Disallows copy and assignment. + Writer(const Writer &); + Writer &operator=(const Writer &); +}; + +} // namespace io +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_IO_WRITER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie.h new file mode 100644 index 0000000000000000000000000000000000000000..73a0c2bf7aab6e52c7647926b4a5e93657c5dd0b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie.h @@ -0,0 +1,16 @@ +#ifndef MARISA_GRIMOIRE_TRIE_H_ +#define MARISA_GRIMOIRE_TRIE_H_ + +#include "marisa/grimoire/trie/state.h" +#include "marisa/grimoire/trie/louds-trie.h" + +namespace marisa { +namespace grimoire { + +using trie::State; +using trie::LoudsTrie; + +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_TRIE_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/cache.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/cache.h new file mode 100644 index 0000000000000000000000000000000000000000..19ce021c32d3b2c3f270512df0c9b820926404e6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/cache.h @@ -0,0 +1,81 @@ +#ifndef MARISA_GRIMOIRE_TRIE_CACHE_H_ +#define MARISA_GRIMOIRE_TRIE_CACHE_H_ + +#include + +#include "marisa/base.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +class Cache { + public: + Cache() : parent_(0), child_(0), union_() { + union_.weight = FLT_MIN; + } + Cache(const Cache &cache) + : parent_(cache.parent_), child_(cache.child_), union_(cache.union_) {} + + Cache &operator=(const Cache &cache) { + parent_ = cache.parent_; + child_ = cache.child_; + union_ = cache.union_; + return *this; + } + + void set_parent(std::size_t parent) { + MARISA_DEBUG_IF(parent > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + parent_ = (UInt32)parent; + } + void set_child(std::size_t child) { + MARISA_DEBUG_IF(child > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + child_ = (UInt32)child; + } + void set_base(UInt8 base) { + union_.link = (union_.link & ~0xFFU) | base; + } + void set_extra(std::size_t extra) { + MARISA_DEBUG_IF(extra > (MARISA_UINT32_MAX >> 8), MARISA_SIZE_ERROR); + union_.link = (UInt32)((union_.link & 0xFFU) | (extra << 8)); + } + void set_weight(float weight) { + union_.weight = weight; + } + + std::size_t parent() const { + return parent_; + } + std::size_t child() const { + return child_; + } + UInt8 base() const { + return (UInt8)(union_.link & 0xFFU); + } + std::size_t extra() const { + return union_.link >> 8; + } + char label() const { + return (char)base(); + } + std::size_t link() const { + return union_.link; + } + float weight() const { + return union_.weight; + } + + private: + UInt32 parent_; + UInt32 child_; + union Union { + UInt32 link; + float weight; + } union_; +}; + +} // namespace trie +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_TRIE_CACHE_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/config.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/config.h new file mode 100644 index 0000000000000000000000000000000000000000..2f1e17a0643580d40460cc92add03652810efe37 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/config.h @@ -0,0 +1,155 @@ +#ifndef MARISA_GRIMOIRE_TRIE_CONFIG_H_ +#define MARISA_GRIMOIRE_TRIE_CONFIG_H_ + +#include "marisa/base.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +class Config { + public: + Config() + : num_tries_(MARISA_DEFAULT_NUM_TRIES), + cache_level_(MARISA_DEFAULT_CACHE), + tail_mode_(MARISA_DEFAULT_TAIL), + node_order_(MARISA_DEFAULT_ORDER) {} + + void parse(int config_flags) { + Config temp; + temp.parse_(config_flags); + swap(temp); + } + + int flags() const { + return (int)num_tries_ | tail_mode_ | node_order_; + } + + std::size_t num_tries() const { + return num_tries_; + } + CacheLevel cache_level() const { + return cache_level_; + } + TailMode tail_mode() const { + return tail_mode_; + } + NodeOrder node_order() const { + return node_order_; + } + + void clear() { + Config().swap(*this); + } + void swap(Config &rhs) { + marisa::swap(num_tries_, rhs.num_tries_); + marisa::swap(cache_level_, rhs.cache_level_); + marisa::swap(tail_mode_, rhs.tail_mode_); + marisa::swap(node_order_, rhs.node_order_); + } + + private: + std::size_t num_tries_; + CacheLevel cache_level_; + TailMode tail_mode_; + NodeOrder node_order_; + + void parse_(int config_flags) { + MARISA_THROW_IF((config_flags & ~MARISA_CONFIG_MASK) != 0, + MARISA_CODE_ERROR); + + parse_num_tries(config_flags); + parse_cache_level(config_flags); + parse_tail_mode(config_flags); + parse_node_order(config_flags); + } + + void parse_num_tries(int config_flags) { + const int num_tries = config_flags & MARISA_NUM_TRIES_MASK; + if (num_tries != 0) { + num_tries_ = static_cast(num_tries); + } + } + + void parse_cache_level(int config_flags) { + switch (config_flags & MARISA_CACHE_LEVEL_MASK) { + case 0: { + cache_level_ = MARISA_DEFAULT_CACHE; + break; + } + case MARISA_HUGE_CACHE: { + cache_level_ = MARISA_HUGE_CACHE; + break; + } + case MARISA_LARGE_CACHE: { + cache_level_ = MARISA_LARGE_CACHE; + break; + } + case MARISA_NORMAL_CACHE: { + cache_level_ = MARISA_NORMAL_CACHE; + break; + } + case MARISA_SMALL_CACHE: { + cache_level_ = MARISA_SMALL_CACHE; + break; + } + case MARISA_TINY_CACHE: { + cache_level_ = MARISA_TINY_CACHE; + break; + } + default: { + MARISA_THROW(MARISA_CODE_ERROR, "undefined cache level"); + } + } + } + + void parse_tail_mode(int config_flags) { + switch (config_flags & MARISA_TAIL_MODE_MASK) { + case 0: { + tail_mode_ = MARISA_DEFAULT_TAIL; + break; + } + case MARISA_TEXT_TAIL: { + tail_mode_ = MARISA_TEXT_TAIL; + break; + } + case MARISA_BINARY_TAIL: { + tail_mode_ = MARISA_BINARY_TAIL; + break; + } + default: { + MARISA_THROW(MARISA_CODE_ERROR, "undefined tail mode"); + } + } + } + + void parse_node_order(int config_flags) { + switch (config_flags & MARISA_NODE_ORDER_MASK) { + case 0: { + node_order_ = MARISA_DEFAULT_ORDER; + break; + } + case MARISA_LABEL_ORDER: { + node_order_ = MARISA_LABEL_ORDER; + break; + } + case MARISA_WEIGHT_ORDER: { + node_order_ = MARISA_WEIGHT_ORDER; + break; + } + default: { + MARISA_THROW(MARISA_CODE_ERROR, "undefined node order"); + } + } + } + + // Disallows copy and assignment. + Config(const Config &); + Config &operator=(const Config &); +}; + +} // namespace trie +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_TRIE_CONFIG_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/entry.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/entry.h new file mode 100644 index 0000000000000000000000000000000000000000..2c754a8533570e102d7b4a03cdd2c369658ce8d6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/entry.h @@ -0,0 +1,81 @@ +#ifndef MARISA_GRIMOIRE_TRIE_ENTRY_H_ +#define MARISA_GRIMOIRE_TRIE_ENTRY_H_ + +#include "marisa/base.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +class Entry { + public: + Entry() : ptr_(NULL), length_(0), id_(0) {} + Entry(const Entry &entry) + : ptr_(entry.ptr_), length_(entry.length_), id_(entry.id_) {} + + Entry &operator=(const Entry &entry) { + ptr_ = entry.ptr_; + length_ = entry.length_; + id_ = entry.id_; + return *this; + } + + char operator[](std::size_t i) const { + MARISA_DEBUG_IF(i >= length_, MARISA_BOUND_ERROR); + return *(ptr_ - i); + } + + void set_str(const char *ptr, std::size_t length) { + MARISA_DEBUG_IF((ptr == NULL) && (length != 0), MARISA_NULL_ERROR); + MARISA_DEBUG_IF(length > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + ptr_ = ptr + length - 1; + length_ = (UInt32)length; + } + void set_id(std::size_t id) { + MARISA_DEBUG_IF(id > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + id_ = (UInt32)id; + } + + const char *ptr() const { + return ptr_ - length_ + 1; + } + std::size_t length() const { + return length_; + } + std::size_t id() const { + return id_; + } + + class StringComparer { + public: + bool operator()(const Entry &lhs, const Entry &rhs) const { + for (std::size_t i = 0; i < lhs.length(); ++i) { + if (i == rhs.length()) { + return true; + } + if (lhs[i] != rhs[i]) { + return (UInt8)lhs[i] > (UInt8)rhs[i]; + } + } + return lhs.length() > rhs.length(); + } + }; + + class IDComparer { + public: + bool operator()(const Entry &lhs, const Entry &rhs) const { + return lhs.id_ < rhs.id_; + } + }; + + private: + const char *ptr_; + UInt32 length_; + UInt32 id_; +}; + +} // namespace trie +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_TRIE_ENTRY_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/header.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/header.h new file mode 100644 index 0000000000000000000000000000000000000000..e13220c6a99892f2f65a7af37df87da4e7c9bfb6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/header.h @@ -0,0 +1,61 @@ +#ifndef MARISA_GRIMOIRE_TRIE_HEADER_H_ +#define MARISA_GRIMOIRE_TRIE_HEADER_H_ + +#include "marisa/grimoire/io.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +class Header { + public: + enum { + HEADER_SIZE = 16 + }; + + Header() {} + + void map(Mapper &mapper) { + const char *ptr; + mapper.map(&ptr, HEADER_SIZE); + MARISA_THROW_IF(!test_header(ptr), MARISA_FORMAT_ERROR); + } + void read(Reader &reader) { + char buf[HEADER_SIZE]; + reader.read(buf, HEADER_SIZE); + MARISA_THROW_IF(!test_header(buf), MARISA_FORMAT_ERROR); + } + void write(Writer &writer) const { + writer.write(get_header(), HEADER_SIZE); + } + + std::size_t io_size() const { + return HEADER_SIZE; + } + + private: + + static const char *get_header() { + static const char buf[HEADER_SIZE] = "We love Marisa."; + return buf; + } + + static bool test_header(const char *ptr) { + for (std::size_t i = 0; i < HEADER_SIZE; ++i) { + if (ptr[i] != get_header()[i]) { + return false; + } + } + return true; + } + + // Disallows copy and assignment. + Header(const Header &); + Header &operator=(const Header &); +}; + +} // namespace trie +} // namespace marisa +} // namespace grimoire + +#endif // MARISA_GRIMOIRE_TRIE_HEADER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/history.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/history.h new file mode 100644 index 0000000000000000000000000000000000000000..84d10df1f19feb68ea324e2bedbd89005d3715dd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/history.h @@ -0,0 +1,65 @@ +#ifndef MARISA_GRIMOIRE_TRIE_STATE_HISTORY_H_ +#define MARISA_GRIMOIRE_TRIE_STATE_HISTORY_H_ + +#include "marisa/base.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +class History { + public: + History() + : node_id_(0), louds_pos_(0), key_pos_(0), + link_id_(MARISA_INVALID_LINK_ID), key_id_(MARISA_INVALID_KEY_ID) {} + + void set_node_id(std::size_t node_id) { + MARISA_DEBUG_IF(node_id > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + node_id_ = (UInt32)node_id; + } + void set_louds_pos(std::size_t louds_pos) { + MARISA_DEBUG_IF(louds_pos > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + louds_pos_ = (UInt32)louds_pos; + } + void set_key_pos(std::size_t key_pos) { + MARISA_DEBUG_IF(key_pos > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + key_pos_ = (UInt32)key_pos; + } + void set_link_id(std::size_t link_id) { + MARISA_DEBUG_IF(link_id > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + link_id_ = (UInt32)link_id; + } + void set_key_id(std::size_t key_id) { + MARISA_DEBUG_IF(key_id > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + key_id_ = (UInt32)key_id; + } + + std::size_t node_id() const { + return node_id_; + } + std::size_t louds_pos() const { + return louds_pos_; + } + std::size_t key_pos() const { + return key_pos_; + } + std::size_t link_id() const { + return link_id_; + } + std::size_t key_id() const { + return key_id_; + } + + private: + UInt32 node_id_; + UInt32 louds_pos_; + UInt32 key_pos_; + UInt32 link_id_; + UInt32 key_id_; +}; + +} // namespace trie +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_TRIE_STATE_HISTORY_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/key.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/key.h new file mode 100644 index 0000000000000000000000000000000000000000..8555cc72d2c8bad6338da5b1a8ecf9feb9373269 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/key.h @@ -0,0 +1,226 @@ +#ifndef MARISA_GRIMOIRE_TRIE_KEY_H_ +#define MARISA_GRIMOIRE_TRIE_KEY_H_ + +#include "marisa/base.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +class Key { + public: + Key() : ptr_(NULL), length_(0), union_(), id_(0) { + union_.terminal = 0; + } + Key(const Key &entry) + : ptr_(entry.ptr_), length_(entry.length_), + union_(entry.union_), id_(entry.id_) {} + + Key &operator=(const Key &entry) { + ptr_ = entry.ptr_; + length_ = entry.length_; + union_ = entry.union_; + id_ = entry.id_; + return *this; + } + + char operator[](std::size_t i) const { + MARISA_DEBUG_IF(i >= length_, MARISA_BOUND_ERROR); + return ptr_[i]; + } + + void substr(std::size_t pos, std::size_t length) { + MARISA_DEBUG_IF(pos > length_, MARISA_BOUND_ERROR); + MARISA_DEBUG_IF(length > length_, MARISA_BOUND_ERROR); + MARISA_DEBUG_IF(pos > (length_ - length), MARISA_BOUND_ERROR); + ptr_ += pos; + length_ = (UInt32)length; + } + + void set_str(const char *ptr, std::size_t length) { + MARISA_DEBUG_IF((ptr == NULL) && (length != 0), MARISA_NULL_ERROR); + MARISA_DEBUG_IF(length > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + ptr_ = ptr; + length_ = (UInt32)length; + } + void set_weight(float weight) { + union_.weight = weight; + } + void set_terminal(std::size_t terminal) { + MARISA_DEBUG_IF(terminal > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + union_.terminal = (UInt32)terminal; + } + void set_id(std::size_t id) { + MARISA_DEBUG_IF(id > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + id_ = (UInt32)id; + } + + const char *ptr() const { + return ptr_; + } + std::size_t length() const { + return length_; + } + float weight() const { + return union_.weight; + } + std::size_t terminal() const { + return union_.terminal; + } + std::size_t id() const { + return id_; + } + + private: + const char *ptr_; + UInt32 length_; + union Union { + float weight; + UInt32 terminal; + } union_; + UInt32 id_; +}; + +inline bool operator==(const Key &lhs, const Key &rhs) { + if (lhs.length() != rhs.length()) { + return false; + } + for (std::size_t i = 0; i < lhs.length(); ++i) { + if (lhs[i] != rhs[i]) { + return false; + } + } + return true; +} + +inline bool operator!=(const Key &lhs, const Key &rhs) { + return !(lhs == rhs); +} + +inline bool operator<(const Key &lhs, const Key &rhs) { + for (std::size_t i = 0; i < lhs.length(); ++i) { + if (i == rhs.length()) { + return false; + } + if (lhs[i] != rhs[i]) { + return (UInt8)lhs[i] < (UInt8)rhs[i]; + } + } + return lhs.length() < rhs.length(); +} + +inline bool operator>(const Key &lhs, const Key &rhs) { + return rhs < lhs; +} + +class ReverseKey { + public: + ReverseKey() : ptr_(NULL), length_(0), union_(), id_(0) { + union_.terminal = 0; + } + ReverseKey(const ReverseKey &entry) + : ptr_(entry.ptr_), length_(entry.length_), + union_(entry.union_), id_(entry.id_) {} + + ReverseKey &operator=(const ReverseKey &entry) { + ptr_ = entry.ptr_; + length_ = entry.length_; + union_ = entry.union_; + id_ = entry.id_; + return *this; + } + + char operator[](std::size_t i) const { + MARISA_DEBUG_IF(i >= length_, MARISA_BOUND_ERROR); + return *(ptr_ - i - 1); + } + + void substr(std::size_t pos, std::size_t length) { + MARISA_DEBUG_IF(pos > length_, MARISA_BOUND_ERROR); + MARISA_DEBUG_IF(length > length_, MARISA_BOUND_ERROR); + MARISA_DEBUG_IF(pos > (length_ - length), MARISA_BOUND_ERROR); + ptr_ -= pos; + length_ = (UInt32)length; + } + + void set_str(const char *ptr, std::size_t length) { + MARISA_DEBUG_IF((ptr == NULL) && (length != 0), MARISA_NULL_ERROR); + MARISA_DEBUG_IF(length > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + ptr_ = ptr + length; + length_ = (UInt32)length; + } + void set_weight(float weight) { + union_.weight = weight; + } + void set_terminal(std::size_t terminal) { + MARISA_DEBUG_IF(terminal > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + union_.terminal = (UInt32)terminal; + } + void set_id(std::size_t id) { + MARISA_DEBUG_IF(id > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + id_ = (UInt32)id; + } + + const char *ptr() const { + return ptr_ - length_; + } + std::size_t length() const { + return length_; + } + float weight() const { + return union_.weight; + } + std::size_t terminal() const { + return union_.terminal; + } + std::size_t id() const { + return id_; + } + + private: + const char *ptr_; + UInt32 length_; + union Union { + float weight; + UInt32 terminal; + } union_; + UInt32 id_; +}; + +inline bool operator==(const ReverseKey &lhs, const ReverseKey &rhs) { + if (lhs.length() != rhs.length()) { + return false; + } + for (std::size_t i = 0; i < lhs.length(); ++i) { + if (lhs[i] != rhs[i]) { + return false; + } + } + return true; +} + +inline bool operator!=(const ReverseKey &lhs, const ReverseKey &rhs) { + return !(lhs == rhs); +} + +inline bool operator<(const ReverseKey &lhs, const ReverseKey &rhs) { + for (std::size_t i = 0; i < lhs.length(); ++i) { + if (i == rhs.length()) { + return false; + } + if (lhs[i] != rhs[i]) { + return (UInt8)lhs[i] < (UInt8)rhs[i]; + } + } + return lhs.length() < rhs.length(); +} + +inline bool operator>(const ReverseKey &lhs, const ReverseKey &rhs) { + return rhs < lhs; +} + +} // namespace trie +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_TRIE_KEY_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/louds-trie.cc b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/louds-trie.cc new file mode 100644 index 0000000000000000000000000000000000000000..df191f5191e622b678519a634ab266cf236093a0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/louds-trie.cc @@ -0,0 +1,878 @@ +#include +#include +#include + +#include "marisa/grimoire/algorithm.h" +#include "marisa/grimoire/trie/header.h" +#include "marisa/grimoire/trie/range.h" +#include "marisa/grimoire/trie/state.h" +#include "marisa/grimoire/trie/louds-trie.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +LoudsTrie::LoudsTrie() + : louds_(), terminal_flags_(), link_flags_(), bases_(), extras_(), + tail_(), next_trie_(), cache_(), cache_mask_(0), num_l1_nodes_(0), + config_(), mapper_() {} + +LoudsTrie::~LoudsTrie() {} + +void LoudsTrie::build(Keyset &keyset, int flags) { + Config config; + config.parse(flags); + + LoudsTrie temp; + temp.build_(keyset, config); + swap(temp); +} + +void LoudsTrie::map(Mapper &mapper) { + Header().map(mapper); + + LoudsTrie temp; + temp.map_(mapper); + temp.mapper_.swap(mapper); + swap(temp); +} + +void LoudsTrie::read(Reader &reader) { + Header().read(reader); + + LoudsTrie temp; + temp.read_(reader); + swap(temp); +} + +void LoudsTrie::write(Writer &writer) const { + Header().write(writer); + + write_(writer); +} + +bool LoudsTrie::lookup(Agent &agent) const { + MARISA_DEBUG_IF(!agent.has_state(), MARISA_STATE_ERROR); + + State &state = agent.state(); + state.lookup_init(); + while (state.query_pos() < agent.query().length()) { + if (!find_child(agent)) { + return false; + } + } + if (!terminal_flags_[state.node_id()]) { + return false; + } + agent.set_key(agent.query().ptr(), agent.query().length()); + agent.set_key(terminal_flags_.rank1(state.node_id())); + return true; +} + +void LoudsTrie::reverse_lookup(Agent &agent) const { + MARISA_DEBUG_IF(!agent.has_state(), MARISA_STATE_ERROR); + MARISA_THROW_IF(agent.query().id() >= size(), MARISA_BOUND_ERROR); + + State &state = agent.state(); + state.reverse_lookup_init(); + + state.set_node_id(terminal_flags_.select1(agent.query().id())); + if (state.node_id() == 0) { + agent.set_key(state.key_buf().begin(), state.key_buf().size()); + agent.set_key(agent.query().id()); + return; + } + for ( ; ; ) { + if (link_flags_[state.node_id()]) { + const std::size_t prev_key_pos = state.key_buf().size(); + restore(agent, get_link(state.node_id())); + std::reverse(state.key_buf().begin() + prev_key_pos, + state.key_buf().end()); + } else { + state.key_buf().push_back((char)bases_[state.node_id()]); + } + + if (state.node_id() <= num_l1_nodes_) { + std::reverse(state.key_buf().begin(), state.key_buf().end()); + agent.set_key(state.key_buf().begin(), state.key_buf().size()); + agent.set_key(agent.query().id()); + return; + } + state.set_node_id(louds_.select1(state.node_id()) - state.node_id() - 1); + } +} + +bool LoudsTrie::common_prefix_search(Agent &agent) const { + MARISA_DEBUG_IF(!agent.has_state(), MARISA_STATE_ERROR); + + State &state = agent.state(); + if (state.status_code() == MARISA_END_OF_COMMON_PREFIX_SEARCH) { + return false; + } + + if (state.status_code() != MARISA_READY_TO_COMMON_PREFIX_SEARCH) { + state.common_prefix_search_init(); + if (terminal_flags_[state.node_id()]) { + agent.set_key(agent.query().ptr(), state.query_pos()); + agent.set_key(terminal_flags_.rank1(state.node_id())); + return true; + } + } + + while (state.query_pos() < agent.query().length()) { + if (!find_child(agent)) { + state.set_status_code(MARISA_END_OF_COMMON_PREFIX_SEARCH); + return false; + } else if (terminal_flags_[state.node_id()]) { + agent.set_key(agent.query().ptr(), state.query_pos()); + agent.set_key(terminal_flags_.rank1(state.node_id())); + return true; + } + } + state.set_status_code(MARISA_END_OF_COMMON_PREFIX_SEARCH); + return false; +} + +bool LoudsTrie::predictive_search(Agent &agent) const { + MARISA_DEBUG_IF(!agent.has_state(), MARISA_STATE_ERROR); + + State &state = agent.state(); + if (state.status_code() == MARISA_END_OF_PREDICTIVE_SEARCH) { + return false; + } + + if (state.status_code() != MARISA_READY_TO_PREDICTIVE_SEARCH) { + state.predictive_search_init(); + while (state.query_pos() < agent.query().length()) { + if (!predictive_find_child(agent)) { + state.set_status_code(MARISA_END_OF_PREDICTIVE_SEARCH); + return false; + } + } + + History history; + history.set_node_id(state.node_id()); + history.set_key_pos(state.key_buf().size()); + state.history().push_back(history); + state.set_history_pos(1); + + if (terminal_flags_[state.node_id()]) { + agent.set_key(state.key_buf().begin(), state.key_buf().size()); + agent.set_key(terminal_flags_.rank1(state.node_id())); + return true; + } + } + + for ( ; ; ) { + if (state.history_pos() == state.history().size()) { + const History ¤t = state.history().back(); + History next; + next.set_louds_pos(louds_.select0(current.node_id()) + 1); + next.set_node_id(next.louds_pos() - current.node_id() - 1); + state.history().push_back(next); + } + + History &next = state.history()[state.history_pos()]; + const bool link_flag = louds_[next.louds_pos()]; + next.set_louds_pos(next.louds_pos() + 1); + if (link_flag) { + state.set_history_pos(state.history_pos() + 1); + if (link_flags_[next.node_id()]) { + next.set_link_id(update_link_id(next.link_id(), next.node_id())); + restore(agent, get_link(next.node_id(), next.link_id())); + } else { + state.key_buf().push_back((char)bases_[next.node_id()]); + } + next.set_key_pos(state.key_buf().size()); + + if (terminal_flags_[next.node_id()]) { + if (next.key_id() == MARISA_INVALID_KEY_ID) { + next.set_key_id(terminal_flags_.rank1(next.node_id())); + } else { + next.set_key_id(next.key_id() + 1); + } + agent.set_key(state.key_buf().begin(), state.key_buf().size()); + agent.set_key(next.key_id()); + return true; + } + } else if (state.history_pos() != 1) { + History ¤t = state.history()[state.history_pos() - 1]; + current.set_node_id(current.node_id() + 1); + const History &prev = + state.history()[state.history_pos() - 2]; + state.key_buf().resize(prev.key_pos()); + state.set_history_pos(state.history_pos() - 1); + } else { + state.set_status_code(MARISA_END_OF_PREDICTIVE_SEARCH); + return false; + } + } +} + +std::size_t LoudsTrie::total_size() const { + return louds_.total_size() + terminal_flags_.total_size() + + link_flags_.total_size() + bases_.total_size() + + extras_.total_size() + tail_.total_size() + + ((next_trie_.get() != NULL) ? next_trie_->total_size() : 0) + + cache_.total_size(); +} + +std::size_t LoudsTrie::io_size() const { + return Header().io_size() + louds_.io_size() + + terminal_flags_.io_size() + link_flags_.io_size() + + bases_.io_size() + extras_.io_size() + tail_.io_size() + + ((next_trie_.get() != NULL) ? + (next_trie_->io_size() - Header().io_size()) : 0) + + cache_.io_size() + (sizeof(UInt32) * 2); +} + +void LoudsTrie::clear() { + LoudsTrie().swap(*this); +} + +void LoudsTrie::swap(LoudsTrie &rhs) { + louds_.swap(rhs.louds_); + terminal_flags_.swap(rhs.terminal_flags_); + link_flags_.swap(rhs.link_flags_); + bases_.swap(rhs.bases_); + extras_.swap(rhs.extras_); + tail_.swap(rhs.tail_); + next_trie_.swap(rhs.next_trie_); + cache_.swap(rhs.cache_); + marisa::swap(cache_mask_, rhs.cache_mask_); + marisa::swap(num_l1_nodes_, rhs.num_l1_nodes_); + config_.swap(rhs.config_); + mapper_.swap(rhs.mapper_); +} + +void LoudsTrie::build_(Keyset &keyset, const Config &config) { + Vector keys; + keys.resize(keyset.size()); + for (std::size_t i = 0; i < keyset.size(); ++i) { + keys[i].set_str(keyset[i].ptr(), keyset[i].length()); + keys[i].set_weight(keyset[i].weight()); + } + + Vector terminals; + build_trie(keys, &terminals, config, 1); + + typedef std::pair TerminalIdPair; + + Vector pairs; + pairs.resize(terminals.size()); + for (std::size_t i = 0; i < pairs.size(); ++i) { + pairs[i].first = terminals[i]; + pairs[i].second = (UInt32)i; + } + terminals.clear(); + std::sort(pairs.begin(), pairs.end()); + + std::size_t node_id = 0; + for (std::size_t i = 0; i < pairs.size(); ++i) { + while (node_id < pairs[i].first) { + terminal_flags_.push_back(false); + ++node_id; + } + if (node_id == pairs[i].first) { + terminal_flags_.push_back(true); + ++node_id; + } + } + while (node_id < bases_.size()) { + terminal_flags_.push_back(false); + ++node_id; + } + terminal_flags_.push_back(false); + terminal_flags_.build(false, true); + + for (std::size_t i = 0; i < keyset.size(); ++i) { + keyset[pairs[i].second].set_id(terminal_flags_.rank1(pairs[i].first)); + } +} + +template +void LoudsTrie::build_trie(Vector &keys, + Vector *terminals, const Config &config, std::size_t trie_id) { + build_current_trie(keys, terminals, config, trie_id); + + Vector next_terminals; + if (!keys.empty()) { + build_next_trie(keys, &next_terminals, config, trie_id); + } + + if (next_trie_.get() != NULL) { + config_.parse(static_cast((next_trie_->num_tries() + 1)) | + next_trie_->tail_mode() | next_trie_->node_order()); + } else { + config_.parse(1 | tail_.mode() | config.node_order() | + config.cache_level()); + } + + link_flags_.build(false, false); + std::size_t node_id = 0; + for (std::size_t i = 0; i < next_terminals.size(); ++i) { + while (!link_flags_[node_id]) { + ++node_id; + } + bases_[node_id] = (UInt8)(next_terminals[i] % 256); + next_terminals[i] /= 256; + ++node_id; + } + extras_.build(next_terminals); + fill_cache(); +} + +template +void LoudsTrie::build_current_trie(Vector &keys, + Vector *terminals, const Config &config, + std::size_t trie_id) try { + for (std::size_t i = 0; i < keys.size(); ++i) { + keys[i].set_id(i); + } + const std::size_t num_keys = Algorithm().sort(keys.begin(), keys.end()); + reserve_cache(config, trie_id, num_keys); + + louds_.push_back(true); + louds_.push_back(false); + bases_.push_back('\0'); + link_flags_.push_back(false); + + Vector next_keys; + std::queue queue; + Vector w_ranges; + + queue.push(make_range(0, keys.size(), 0)); + while (!queue.empty()) { + const std::size_t node_id = link_flags_.size() - queue.size(); + + Range range = queue.front(); + queue.pop(); + + while ((range.begin() < range.end()) && + (keys[range.begin()].length() == range.key_pos())) { + keys[range.begin()].set_terminal(node_id); + range.set_begin(range.begin() + 1); + } + + if (range.begin() == range.end()) { + louds_.push_back(false); + continue; + } + + w_ranges.clear(); + double weight = keys[range.begin()].weight(); + for (std::size_t i = range.begin() + 1; i < range.end(); ++i) { + if (keys[i - 1][range.key_pos()] != keys[i][range.key_pos()]) { + w_ranges.push_back(make_weighted_range( + range.begin(), i, range.key_pos(), (float)weight)); + range.set_begin(i); + weight = 0.0; + } + weight += keys[i].weight(); + } + w_ranges.push_back(make_weighted_range( + range.begin(), range.end(), range.key_pos(), (float)weight)); + if (config.node_order() == MARISA_WEIGHT_ORDER) { + std::stable_sort(w_ranges.begin(), w_ranges.end(), + std::greater()); + } + + if (node_id == 0) { + num_l1_nodes_ = w_ranges.size(); + } + + for (std::size_t i = 0; i < w_ranges.size(); ++i) { + WeightedRange &w_range = w_ranges[i]; + std::size_t key_pos = w_range.key_pos() + 1; + while (key_pos < keys[w_range.begin()].length()) { + std::size_t j; + for (j = w_range.begin() + 1; j < w_range.end(); ++j) { + if (keys[j - 1][key_pos] != keys[j][key_pos]) { + break; + } + } + if (j < w_range.end()) { + break; + } + ++key_pos; + } + cache(node_id, bases_.size(), w_range.weight(), + keys[w_range.begin()][w_range.key_pos()]); + + if (key_pos == w_range.key_pos() + 1) { + bases_.push_back(static_cast( + keys[w_range.begin()][w_range.key_pos()])); + link_flags_.push_back(false); + } else { + bases_.push_back('\0'); + link_flags_.push_back(true); + T next_key; + next_key.set_str(keys[w_range.begin()].ptr(), + keys[w_range.begin()].length()); + next_key.substr(w_range.key_pos(), key_pos - w_range.key_pos()); + next_key.set_weight(w_range.weight()); + next_keys.push_back(next_key); + } + w_range.set_key_pos(key_pos); + queue.push(w_range.range()); + louds_.push_back(true); + } + louds_.push_back(false); + } + + louds_.push_back(false); + louds_.build(trie_id == 1, true); + bases_.shrink(); + + build_terminals(keys, terminals); + keys.swap(next_keys); +} catch (const std::bad_alloc &) { + MARISA_THROW(MARISA_MEMORY_ERROR, "std::bad_alloc"); +} + +template <> +void LoudsTrie::build_next_trie(Vector &keys, + Vector *terminals, const Config &config, std::size_t trie_id) { + if (trie_id == config.num_tries()) { + Vector entries; + entries.resize(keys.size()); + for (std::size_t i = 0; i < keys.size(); ++i) { + entries[i].set_str(keys[i].ptr(), keys[i].length()); + } + tail_.build(entries, terminals, config.tail_mode()); + return; + } + Vector reverse_keys; + reverse_keys.resize(keys.size()); + for (std::size_t i = 0; i < keys.size(); ++i) { + reverse_keys[i].set_str(keys[i].ptr(), keys[i].length()); + reverse_keys[i].set_weight(keys[i].weight()); + } + keys.clear(); + next_trie_.reset(new (std::nothrow) LoudsTrie); + MARISA_THROW_IF(next_trie_.get() == NULL, MARISA_MEMORY_ERROR); + next_trie_->build_trie(reverse_keys, terminals, config, trie_id + 1); +} + +template <> +void LoudsTrie::build_next_trie(Vector &keys, + Vector *terminals, const Config &config, std::size_t trie_id) { + if (trie_id == config.num_tries()) { + Vector entries; + entries.resize(keys.size()); + for (std::size_t i = 0; i < keys.size(); ++i) { + entries[i].set_str(keys[i].ptr(), keys[i].length()); + } + tail_.build(entries, terminals, config.tail_mode()); + return; + } + next_trie_.reset(new (std::nothrow) LoudsTrie); + MARISA_THROW_IF(next_trie_.get() == NULL, MARISA_MEMORY_ERROR); + next_trie_->build_trie(keys, terminals, config, trie_id + 1); +} + +template +void LoudsTrie::build_terminals(const Vector &keys, + Vector *terminals) const { + Vector temp; + temp.resize(keys.size()); + for (std::size_t i = 0; i < keys.size(); ++i) { + temp[keys[i].id()] = (UInt32)keys[i].terminal(); + } + terminals->swap(temp); +} + +template <> +void LoudsTrie::cache(std::size_t parent, std::size_t child, + float weight, char label) { + MARISA_DEBUG_IF(parent >= child, MARISA_RANGE_ERROR); + + const std::size_t cache_id = get_cache_id(parent, label); + if (weight > cache_[cache_id].weight()) { + cache_[cache_id].set_parent(parent); + cache_[cache_id].set_child(child); + cache_[cache_id].set_weight(weight); + } +} + +void LoudsTrie::reserve_cache(const Config &config, std::size_t trie_id, + std::size_t num_keys) { + std::size_t cache_size = (trie_id == 1) ? 256 : 1; + while (cache_size < (num_keys / config.cache_level())) { + cache_size *= 2; + } + cache_.resize(cache_size); + cache_mask_ = cache_size - 1; +} + +template <> +void LoudsTrie::cache(std::size_t parent, std::size_t child, + float weight, char) { + MARISA_DEBUG_IF(parent >= child, MARISA_RANGE_ERROR); + + const std::size_t cache_id = get_cache_id(child); + if (weight > cache_[cache_id].weight()) { + cache_[cache_id].set_parent(parent); + cache_[cache_id].set_child(child); + cache_[cache_id].set_weight(weight); + } +} + +void LoudsTrie::fill_cache() { + for (std::size_t i = 0; i < cache_.size(); ++i) { + const std::size_t node_id = cache_[i].child(); + if (node_id != 0) { + cache_[i].set_base(bases_[node_id]); + cache_[i].set_extra(!link_flags_[node_id] ? + MARISA_INVALID_EXTRA : extras_[link_flags_.rank1(node_id)]); + } else { + cache_[i].set_parent(MARISA_UINT32_MAX); + cache_[i].set_child(MARISA_UINT32_MAX); + } + } +} + +void LoudsTrie::map_(Mapper &mapper) { + louds_.map(mapper); + terminal_flags_.map(mapper); + link_flags_.map(mapper); + bases_.map(mapper); + extras_.map(mapper); + tail_.map(mapper); + if ((link_flags_.num_1s() != 0) && tail_.empty()) { + next_trie_.reset(new (std::nothrow) LoudsTrie); + MARISA_THROW_IF(next_trie_.get() == NULL, MARISA_MEMORY_ERROR); + next_trie_->map_(mapper); + } + cache_.map(mapper); + cache_mask_ = cache_.size() - 1; + { + UInt32 temp_num_l1_nodes; + mapper.map(&temp_num_l1_nodes); + num_l1_nodes_ = temp_num_l1_nodes; + } + { + UInt32 temp_config_flags; + mapper.map(&temp_config_flags); + config_.parse((int)temp_config_flags); + } +} + +void LoudsTrie::read_(Reader &reader) { + louds_.read(reader); + terminal_flags_.read(reader); + link_flags_.read(reader); + bases_.read(reader); + extras_.read(reader); + tail_.read(reader); + if ((link_flags_.num_1s() != 0) && tail_.empty()) { + next_trie_.reset(new (std::nothrow) LoudsTrie); + MARISA_THROW_IF(next_trie_.get() == NULL, MARISA_MEMORY_ERROR); + next_trie_->read_(reader); + } + cache_.read(reader); + cache_mask_ = cache_.size() - 1; + { + UInt32 temp_num_l1_nodes; + reader.read(&temp_num_l1_nodes); + num_l1_nodes_ = temp_num_l1_nodes; + } + { + UInt32 temp_config_flags; + reader.read(&temp_config_flags); + config_.parse((int)temp_config_flags); + } +} + +void LoudsTrie::write_(Writer &writer) const { + louds_.write(writer); + terminal_flags_.write(writer); + link_flags_.write(writer); + bases_.write(writer); + extras_.write(writer); + tail_.write(writer); + if (next_trie_.get() != NULL) { + next_trie_->write_(writer); + } + cache_.write(writer); + writer.write((UInt32)num_l1_nodes_); + writer.write((UInt32)config_.flags()); +} + +bool LoudsTrie::find_child(Agent &agent) const { + MARISA_DEBUG_IF(agent.state().query_pos() >= agent.query().length(), + MARISA_BOUND_ERROR); + + State &state = agent.state(); + const std::size_t cache_id = get_cache_id(state.node_id(), + agent.query()[state.query_pos()]); + if (state.node_id() == cache_[cache_id].parent()) { + if (cache_[cache_id].extra() != MARISA_INVALID_EXTRA) { + if (!match(agent, cache_[cache_id].link())) { + return false; + } + } else { + state.set_query_pos(state.query_pos() + 1); + } + state.set_node_id(cache_[cache_id].child()); + return true; + } + + std::size_t louds_pos = louds_.select0(state.node_id()) + 1; + if (!louds_[louds_pos]) { + return false; + } + state.set_node_id(louds_pos - state.node_id() - 1); + std::size_t link_id = MARISA_INVALID_LINK_ID; + do { + if (link_flags_[state.node_id()]) { + link_id = update_link_id(link_id, state.node_id()); + const std::size_t prev_query_pos = state.query_pos(); + if (match(agent, get_link(state.node_id(), link_id))) { + return true; + } else if (state.query_pos() != prev_query_pos) { + return false; + } + } else if (bases_[state.node_id()] == + (UInt8)agent.query()[state.query_pos()]) { + state.set_query_pos(state.query_pos() + 1); + return true; + } + state.set_node_id(state.node_id() + 1); + ++louds_pos; + } while (louds_[louds_pos]); + return false; +} + +bool LoudsTrie::predictive_find_child(Agent &agent) const { + MARISA_DEBUG_IF(agent.state().query_pos() >= agent.query().length(), + MARISA_BOUND_ERROR); + + State &state = agent.state(); + const std::size_t cache_id = get_cache_id(state.node_id(), + agent.query()[state.query_pos()]); + if (state.node_id() == cache_[cache_id].parent()) { + if (cache_[cache_id].extra() != MARISA_INVALID_EXTRA) { + if (!prefix_match(agent, cache_[cache_id].link())) { + return false; + } + } else { + state.key_buf().push_back(cache_[cache_id].label()); + state.set_query_pos(state.query_pos() + 1); + } + state.set_node_id(cache_[cache_id].child()); + return true; + } + + std::size_t louds_pos = louds_.select0(state.node_id()) + 1; + if (!louds_[louds_pos]) { + return false; + } + state.set_node_id(louds_pos - state.node_id() - 1); + std::size_t link_id = MARISA_INVALID_LINK_ID; + do { + if (link_flags_[state.node_id()]) { + link_id = update_link_id(link_id, state.node_id()); + const std::size_t prev_query_pos = state.query_pos(); + if (prefix_match(agent, get_link(state.node_id(), link_id))) { + return true; + } else if (state.query_pos() != prev_query_pos) { + return false; + } + } else if (bases_[state.node_id()] == + (UInt8)agent.query()[state.query_pos()]) { + state.key_buf().push_back((char)bases_[state.node_id()]); + state.set_query_pos(state.query_pos() + 1); + return true; + } + state.set_node_id(state.node_id() + 1); + ++louds_pos; + } while (louds_[louds_pos]); + return false; +} + +void LoudsTrie::restore(Agent &agent, std::size_t link) const { + if (next_trie_.get() != NULL) { + next_trie_->restore_(agent, link); + } else { + tail_.restore(agent, link); + } +} + +bool LoudsTrie::match(Agent &agent, std::size_t link) const { + if (next_trie_.get() != NULL) { + return next_trie_->match_(agent, link); + } else { + return tail_.match(agent, link); + } +} + +bool LoudsTrie::prefix_match(Agent &agent, std::size_t link) const { + if (next_trie_.get() != NULL) { + return next_trie_->prefix_match_(agent, link); + } else { + return tail_.prefix_match(agent, link); + } +} + +void LoudsTrie::restore_(Agent &agent, std::size_t node_id) const { + MARISA_DEBUG_IF(node_id == 0, MARISA_RANGE_ERROR); + + State &state = agent.state(); + for ( ; ; ) { + const std::size_t cache_id = get_cache_id(node_id); + if (node_id == cache_[cache_id].child()) { + if (cache_[cache_id].extra() != MARISA_INVALID_EXTRA) { + restore(agent, cache_[cache_id].link()); + } else { + state.key_buf().push_back(cache_[cache_id].label()); + } + + node_id = cache_[cache_id].parent(); + if (node_id == 0) { + return; + } + continue; + } + + if (link_flags_[node_id]) { + restore(agent, get_link(node_id)); + } else { + state.key_buf().push_back((char)bases_[node_id]); + } + + if (node_id <= num_l1_nodes_) { + return; + } + node_id = louds_.select1(node_id) - node_id - 1; + } +} + +bool LoudsTrie::match_(Agent &agent, std::size_t node_id) const { + MARISA_DEBUG_IF(agent.state().query_pos() >= agent.query().length(), + MARISA_BOUND_ERROR); + MARISA_DEBUG_IF(node_id == 0, MARISA_RANGE_ERROR); + + State &state = agent.state(); + for ( ; ; ) { + const std::size_t cache_id = get_cache_id(node_id); + if (node_id == cache_[cache_id].child()) { + if (cache_[cache_id].extra() != MARISA_INVALID_EXTRA) { + if (!match(agent, cache_[cache_id].link())) { + return false; + } + } else if (cache_[cache_id].label() == + agent.query()[state.query_pos()]) { + state.set_query_pos(state.query_pos() + 1); + } else { + return false; + } + + node_id = cache_[cache_id].parent(); + if (node_id == 0) { + return true; + } else if (state.query_pos() >= agent.query().length()) { + return false; + } + continue; + } + + if (link_flags_[node_id]) { + if (next_trie_.get() != NULL) { + if (!match(agent, get_link(node_id))) { + return false; + } + } else if (!tail_.match(agent, get_link(node_id))) { + return false; + } + } else if (bases_[node_id] == (UInt8)agent.query()[state.query_pos()]) { + state.set_query_pos(state.query_pos() + 1); + } else { + return false; + } + + if (node_id <= num_l1_nodes_) { + return true; + } else if (state.query_pos() >= agent.query().length()) { + return false; + } + node_id = louds_.select1(node_id) - node_id - 1; + } +} + +bool LoudsTrie::prefix_match_(Agent &agent, std::size_t node_id) const { + MARISA_DEBUG_IF(agent.state().query_pos() >= agent.query().length(), + MARISA_BOUND_ERROR); + MARISA_DEBUG_IF(node_id == 0, MARISA_RANGE_ERROR); + + State &state = agent.state(); + for ( ; ; ) { + const std::size_t cache_id = get_cache_id(node_id); + if (node_id == cache_[cache_id].child()) { + if (cache_[cache_id].extra() != MARISA_INVALID_EXTRA) { + if (!prefix_match(agent, cache_[cache_id].link())) { + return false; + } + } else if (cache_[cache_id].label() == + agent.query()[state.query_pos()]) { + state.key_buf().push_back(cache_[cache_id].label()); + state.set_query_pos(state.query_pos() + 1); + } else { + return false; + } + + node_id = cache_[cache_id].parent(); + if (node_id == 0) { + return true; + } + } else { + if (link_flags_[node_id]) { + if (!prefix_match(agent, get_link(node_id))) { + return false; + } + } else if (bases_[node_id] == (UInt8)agent.query()[state.query_pos()]) { + state.key_buf().push_back((char)bases_[node_id]); + state.set_query_pos(state.query_pos() + 1); + } else { + return false; + } + + if (node_id <= num_l1_nodes_) { + return true; + } + node_id = louds_.select1(node_id) - node_id - 1; + } + + if (state.query_pos() >= agent.query().length()) { + restore_(agent, node_id); + return true; + } + } +} + +std::size_t LoudsTrie::get_cache_id(std::size_t node_id, char label) const { + return (node_id ^ (node_id << 5) ^ (UInt8)label) & cache_mask_; +} + +std::size_t LoudsTrie::get_cache_id(std::size_t node_id) const { + return node_id & cache_mask_; +} + +std::size_t LoudsTrie::get_link(std::size_t node_id) const { + return bases_[node_id] | (extras_[link_flags_.rank1(node_id)] * 256); +} + +std::size_t LoudsTrie::get_link(std::size_t node_id, + std::size_t link_id) const { + return bases_[node_id] | (extras_[link_id] * 256); +} + +std::size_t LoudsTrie::update_link_id(std::size_t link_id, + std::size_t node_id) const { + return (link_id == MARISA_INVALID_LINK_ID) ? + link_flags_.rank1(node_id) : (link_id + 1); +} + +} // namespace trie +} // namespace grimoire +} // namespace marisa diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/louds-trie.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/louds-trie.h new file mode 100644 index 0000000000000000000000000000000000000000..24ae013b25b6277a38692d5376528afaedfa2d9b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/louds-trie.h @@ -0,0 +1,134 @@ +#ifndef MARISA_GRIMOIRE_TRIE_LOUDS_TRIE_H_ +#define MARISA_GRIMOIRE_TRIE_LOUDS_TRIE_H_ + +#include "marisa/keyset.h" +#include "marisa/agent.h" +#include "marisa/grimoire/vector.h" +#include "marisa/grimoire/trie/config.h" +#include "marisa/grimoire/trie/key.h" +#include "marisa/grimoire/trie/tail.h" +#include "marisa/grimoire/trie/cache.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +class LoudsTrie { + public: + LoudsTrie(); + ~LoudsTrie(); + + void build(Keyset &keyset, int flags); + + void map(Mapper &mapper); + void read(Reader &reader); + void write(Writer &writer) const; + + bool lookup(Agent &agent) const; + void reverse_lookup(Agent &agent) const; + bool common_prefix_search(Agent &agent) const; + bool predictive_search(Agent &agent) const; + + std::size_t num_tries() const { + return config_.num_tries(); + } + std::size_t num_keys() const { + return size(); + } + std::size_t num_nodes() const { + return (louds_.size() / 2) - 1; + } + + CacheLevel cache_level() const { + return config_.cache_level(); + } + TailMode tail_mode() const { + return config_.tail_mode(); + } + NodeOrder node_order() const { + return config_.node_order(); + } + + bool empty() const { + return size() == 0; + } + std::size_t size() const { + return terminal_flags_.num_1s(); + } + std::size_t total_size() const; + std::size_t io_size() const; + + void clear(); + void swap(LoudsTrie &rhs); + + private: + BitVector louds_; + BitVector terminal_flags_; + BitVector link_flags_; + Vector bases_; + FlatVector extras_; + Tail tail_; + scoped_ptr next_trie_; + Vector cache_; + std::size_t cache_mask_; + std::size_t num_l1_nodes_; + Config config_; + Mapper mapper_; + + void build_(Keyset &keyset, const Config &config); + + template + void build_trie(Vector &keys, + Vector *terminals, const Config &config, std::size_t trie_id); + template + void build_current_trie(Vector &keys, + Vector *terminals, const Config &config, std::size_t trie_id); + template + void build_next_trie(Vector &keys, + Vector *terminals, const Config &config, std::size_t trie_id); + template + void build_terminals(const Vector &keys, + Vector *terminals) const; + + void reserve_cache(const Config &config, std::size_t trie_id, + std::size_t num_keys); + template + void cache(std::size_t parent, std::size_t child, + float weight, char label); + void fill_cache(); + + void map_(Mapper &mapper); + void read_(Reader &reader); + void write_(Writer &writer) const; + + inline bool find_child(Agent &agent) const; + inline bool predictive_find_child(Agent &agent) const; + + inline void restore(Agent &agent, std::size_t node_id) const; + inline bool match(Agent &agent, std::size_t node_id) const; + inline bool prefix_match(Agent &agent, std::size_t node_id) const; + + void restore_(Agent &agent, std::size_t node_id) const; + bool match_(Agent &agent, std::size_t node_id) const; + bool prefix_match_(Agent &agent, std::size_t node_id) const; + + inline std::size_t get_cache_id(std::size_t node_id, char label) const; + inline std::size_t get_cache_id(std::size_t node_id) const; + + inline std::size_t get_link(std::size_t node_id) const; + inline std::size_t get_link(std::size_t node_id, + std::size_t link_id) const; + + inline std::size_t update_link_id(std::size_t link_id, + std::size_t node_id) const; + + // Disallows copy and assignment. + LoudsTrie(const LoudsTrie &); + LoudsTrie &operator=(const LoudsTrie &); +}; + +} // namespace trie +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_TRIE_LOUDS_TRIE_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/range.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/range.h new file mode 100644 index 0000000000000000000000000000000000000000..6c78ddbd11e2811c755d46cb1d656dd9feba2579 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/range.h @@ -0,0 +1,115 @@ +#ifndef MARISA_GRIMOIRE_TRIE_RANGE_H_ +#define MARISA_GRIMOIRE_TRIE_RANGE_H_ + +#include "marisa/base.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +class Range { + public: + Range() : begin_(0), end_(0), key_pos_(0) {} + + void set_begin(std::size_t begin) { + MARISA_DEBUG_IF(begin > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + begin_ = static_cast(begin); + } + void set_end(std::size_t end) { + MARISA_DEBUG_IF(end > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + end_ = static_cast(end); + } + void set_key_pos(std::size_t key_pos) { + MARISA_DEBUG_IF(key_pos > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + key_pos_ = static_cast(key_pos); + } + + std::size_t begin() const { + return begin_; + } + std::size_t end() const { + return end_; + } + std::size_t key_pos() const { + return key_pos_; + } + + private: + UInt32 begin_; + UInt32 end_; + UInt32 key_pos_; +}; + +inline Range make_range(std::size_t begin, std::size_t end, + std::size_t key_pos) { + Range range; + range.set_begin(begin); + range.set_end(end); + range.set_key_pos(key_pos); + return range; +} + +class WeightedRange { + public: + WeightedRange() : range_(), weight_(0.0F) {} + + void set_range(const Range &range) { + range_ = range; + } + void set_begin(std::size_t begin) { + range_.set_begin(begin); + } + void set_end(std::size_t end) { + range_.set_end(end); + } + void set_key_pos(std::size_t key_pos) { + range_.set_key_pos(key_pos); + } + void set_weight(float weight) { + weight_ = weight; + } + + const Range &range() const { + return range_; + } + std::size_t begin() const { + return range_.begin(); + } + std::size_t end() const { + return range_.end(); + } + std::size_t key_pos() const { + return range_.key_pos(); + } + float weight() const { + return weight_; + } + + private: + Range range_; + float weight_; +}; + +inline bool operator<(const WeightedRange &lhs, const WeightedRange &rhs) { + return lhs.weight() < rhs.weight(); +} + +inline bool operator>(const WeightedRange &lhs, const WeightedRange &rhs) { + return lhs.weight() > rhs.weight(); +} + +inline WeightedRange make_weighted_range(std::size_t begin, std::size_t end, + std::size_t key_pos, float weight) { + WeightedRange range; + range.set_begin(begin); + range.set_end(end); + range.set_key_pos(key_pos); + range.set_weight(weight); + return range; +} + +} // namespace trie +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_TRIE_RANGE_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/state.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/state.h new file mode 100644 index 0000000000000000000000000000000000000000..df605a6a3e50fb2da2eef76d8c6263312e851a0f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/state.h @@ -0,0 +1,117 @@ +#ifndef MARISA_GRIMOIRE_TRIE_STATE_H_ +#define MARISA_GRIMOIRE_TRIE_STATE_H_ + +#include "marisa/grimoire/vector.h" +#include "marisa/grimoire/trie/history.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +// A search agent has its internal state and the status codes are defined +// below. +typedef enum StatusCode { + MARISA_READY_TO_ALL, + MARISA_READY_TO_COMMON_PREFIX_SEARCH, + MARISA_READY_TO_PREDICTIVE_SEARCH, + MARISA_END_OF_COMMON_PREFIX_SEARCH, + MARISA_END_OF_PREDICTIVE_SEARCH, +} StatusCode; + +class State { + public: + State() + : key_buf_(), history_(), node_id_(0), query_pos_(0), + history_pos_(0), status_code_(MARISA_READY_TO_ALL) {} + + void set_node_id(std::size_t node_id) { + MARISA_DEBUG_IF(node_id > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + node_id_ = (UInt32)node_id; + } + void set_query_pos(std::size_t query_pos) { + MARISA_DEBUG_IF(query_pos > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + query_pos_ = (UInt32)query_pos; + } + void set_history_pos(std::size_t history_pos) { + MARISA_DEBUG_IF(history_pos > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + history_pos_ = (UInt32)history_pos; + } + void set_status_code(StatusCode status_code) { + status_code_ = status_code; + } + + std::size_t node_id() const { + return node_id_; + } + std::size_t query_pos() const { + return query_pos_; + } + std::size_t history_pos() const { + return history_pos_; + } + StatusCode status_code() const { + return status_code_; + } + + const Vector &key_buf() const { + return key_buf_; + } + const Vector &history() const { + return history_; + } + + Vector &key_buf() { + return key_buf_; + } + Vector &history() { + return history_; + } + + void reset() { + status_code_ = MARISA_READY_TO_ALL; + } + + void lookup_init() { + node_id_ = 0; + query_pos_ = 0; + status_code_ = MARISA_READY_TO_ALL; + } + void reverse_lookup_init() { + key_buf_.resize(0); + key_buf_.reserve(32); + status_code_ = MARISA_READY_TO_ALL; + } + void common_prefix_search_init() { + node_id_ = 0; + query_pos_ = 0; + status_code_ = MARISA_READY_TO_COMMON_PREFIX_SEARCH; + } + void predictive_search_init() { + key_buf_.resize(0); + key_buf_.reserve(64); + history_.resize(0); + history_.reserve(4); + node_id_ = 0; + query_pos_ = 0; + history_pos_ = 0; + status_code_ = MARISA_READY_TO_PREDICTIVE_SEARCH; + } + + private: + Vector key_buf_; + Vector history_; + UInt32 node_id_; + UInt32 query_pos_; + UInt32 history_pos_; + StatusCode status_code_; + + // Disallows copy and assignment. + State(const State &); + State &operator=(const State &); +}; + +} // namespace trie +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_TRIE_STATE_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/tail.cc b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/tail.cc new file mode 100644 index 0000000000000000000000000000000000000000..bd9bd01d56e2941ad596852332e5631a6777ca27 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/tail.cc @@ -0,0 +1,218 @@ +#include "marisa/grimoire/algorithm.h" +#include "marisa/grimoire/trie/state.h" +#include "marisa/grimoire/trie/tail.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +Tail::Tail() : buf_(), end_flags_() {} + +void Tail::build(Vector &entries, Vector *offsets, + TailMode mode) { + MARISA_THROW_IF(offsets == NULL, MARISA_NULL_ERROR); + + switch (mode) { + case MARISA_TEXT_TAIL: { + for (std::size_t i = 0; i < entries.size(); ++i) { + const char * const ptr = entries[i].ptr(); + const std::size_t length = entries[i].length(); + for (std::size_t j = 0; j < length; ++j) { + if (ptr[j] == '\0') { + mode = MARISA_BINARY_TAIL; + break; + } + } + if (mode == MARISA_BINARY_TAIL) { + break; + } + } + break; + } + case MARISA_BINARY_TAIL: { + break; + } + default: { + MARISA_THROW(MARISA_CODE_ERROR, "undefined tail mode"); + } + } + + Tail temp; + temp.build_(entries, offsets, mode); + swap(temp); +} + +void Tail::map(Mapper &mapper) { + Tail temp; + temp.map_(mapper); + swap(temp); +} + +void Tail::read(Reader &reader) { + Tail temp; + temp.read_(reader); + swap(temp); +} + +void Tail::write(Writer &writer) const { + write_(writer); +} + +void Tail::restore(Agent &agent, std::size_t offset) const { + MARISA_DEBUG_IF(buf_.empty(), MARISA_STATE_ERROR); + + State &state = agent.state(); + if (end_flags_.empty()) { + for (const char *ptr = &buf_[offset]; *ptr != '\0'; ++ptr) { + state.key_buf().push_back(*ptr); + } + } else { + do { + state.key_buf().push_back(buf_[offset]); + } while (!end_flags_[offset++]); + } +} + +bool Tail::match(Agent &agent, std::size_t offset) const { + MARISA_DEBUG_IF(buf_.empty(), MARISA_STATE_ERROR); + MARISA_DEBUG_IF(agent.state().query_pos() >= agent.query().length(), + MARISA_BOUND_ERROR); + + State &state = agent.state(); + if (end_flags_.empty()) { + const char * const ptr = &buf_[offset] - state.query_pos(); + do { + if (ptr[state.query_pos()] != agent.query()[state.query_pos()]) { + return false; + } + state.set_query_pos(state.query_pos() + 1); + if (ptr[state.query_pos()] == '\0') { + return true; + } + } while (state.query_pos() < agent.query().length()); + return false; + } else { + do { + if (buf_[offset] != agent.query()[state.query_pos()]) { + return false; + } + state.set_query_pos(state.query_pos() + 1); + if (end_flags_[offset++]) { + return true; + } + } while (state.query_pos() < agent.query().length()); + return false; + } +} + +bool Tail::prefix_match(Agent &agent, std::size_t offset) const { + MARISA_DEBUG_IF(buf_.empty(), MARISA_STATE_ERROR); + + State &state = agent.state(); + if (end_flags_.empty()) { + const char *ptr = &buf_[offset] - state.query_pos(); + do { + if (ptr[state.query_pos()] != agent.query()[state.query_pos()]) { + return false; + } + state.key_buf().push_back(ptr[state.query_pos()]); + state.set_query_pos(state.query_pos() + 1); + if (ptr[state.query_pos()] == '\0') { + return true; + } + } while (state.query_pos() < agent.query().length()); + ptr += state.query_pos(); + do { + state.key_buf().push_back(*ptr); + } while (*++ptr != '\0'); + return true; + } else { + do { + if (buf_[offset] != agent.query()[state.query_pos()]) { + return false; + } + state.key_buf().push_back(buf_[offset]); + state.set_query_pos(state.query_pos() + 1); + if (end_flags_[offset++]) { + return true; + } + } while (state.query_pos() < agent.query().length()); + do { + state.key_buf().push_back(buf_[offset]); + } while (!end_flags_[offset++]); + return true; + } +} + +void Tail::clear() { + Tail().swap(*this); +} + +void Tail::swap(Tail &rhs) { + buf_.swap(rhs.buf_); + end_flags_.swap(rhs.end_flags_); +} + +void Tail::build_(Vector &entries, Vector *offsets, + TailMode mode) { + for (std::size_t i = 0; i < entries.size(); ++i) { + entries[i].set_id(i); + } + Algorithm().sort(entries.begin(), entries.end()); + + Vector temp_offsets; + temp_offsets.resize(entries.size(), 0); + + const Entry dummy; + const Entry *last = &dummy; + for (std::size_t i = entries.size(); i > 0; --i) { + const Entry ¤t = entries[i - 1]; + MARISA_THROW_IF(current.length() == 0, MARISA_RANGE_ERROR); + std::size_t match = 0; + while ((match < current.length()) && (match < last->length()) && + ((*last)[match] == current[match])) { + ++match; + } + if ((match == current.length()) && (last->length() != 0)) { + temp_offsets[current.id()] = (UInt32)( + temp_offsets[last->id()] + (last->length() - match)); + } else { + temp_offsets[current.id()] = (UInt32)buf_.size(); + for (std::size_t j = 1; j <= current.length(); ++j) { + buf_.push_back(current[current.length() - j]); + } + if (mode == MARISA_TEXT_TAIL) { + buf_.push_back('\0'); + } else { + for (std::size_t j = 1; j < current.length(); ++j) { + end_flags_.push_back(false); + } + end_flags_.push_back(true); + } + MARISA_THROW_IF(buf_.size() > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + } + last = ¤t; + } + buf_.shrink(); + + offsets->swap(temp_offsets); +} + +void Tail::map_(Mapper &mapper) { + buf_.map(mapper); + end_flags_.map(mapper); +} + +void Tail::read_(Reader &reader) { + buf_.read(reader); + end_flags_.read(reader); +} + +void Tail::write_(Writer &writer) const { + buf_.write(writer); + end_flags_.write(writer); +} + +} // namespace trie +} // namespace grimoire +} // namespace marisa diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/tail.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/tail.h new file mode 100644 index 0000000000000000000000000000000000000000..dd24f3ef81f25b47afd4a2566b0899ec1b42710e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/trie/tail.h @@ -0,0 +1,72 @@ +#ifndef MARISA_GRIMOIRE_TRIE_TAIL_H_ +#define MARISA_GRIMOIRE_TRIE_TAIL_H_ + +#include "marisa/agent.h" +#include "marisa/grimoire/vector.h" +#include "marisa/grimoire/trie/entry.h" + +namespace marisa { +namespace grimoire { +namespace trie { + +class Tail { + public: + Tail(); + + void build(Vector &entries, Vector *offsets, + TailMode mode); + + void map(Mapper &mapper); + void read(Reader &reader); + void write(Writer &writer) const; + + void restore(Agent &agent, std::size_t offset) const; + bool match(Agent &agent, std::size_t offset) const; + bool prefix_match(Agent &agent, std::size_t offset) const; + + const char &operator[](std::size_t offset) const { + MARISA_DEBUG_IF(offset >= buf_.size(), MARISA_BOUND_ERROR); + return buf_[offset]; + } + + TailMode mode() const { + return end_flags_.empty() ? MARISA_TEXT_TAIL : MARISA_BINARY_TAIL; + } + + bool empty() const { + return buf_.empty(); + } + std::size_t size() const { + return buf_.size(); + } + std::size_t total_size() const { + return buf_.total_size() + end_flags_.total_size(); + } + std::size_t io_size() const { + return buf_.io_size() + end_flags_.io_size(); + } + + void clear(); + void swap(Tail &rhs); + + private: + Vector buf_; + BitVector end_flags_; + + void build_(Vector &entries, Vector *offsets, + TailMode mode); + + void map_(Mapper &mapper); + void read_(Reader &reader); + void write_(Writer &writer) const; + + // Disallows copy and assignment. + Tail(const Tail &); + Tail &operator=(const Tail &); +}; + +} // namespace trie +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_TRIE_TAIL_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector.h new file mode 100644 index 0000000000000000000000000000000000000000..582160baf996887ceaacfaa8fc7228bd5ccde790 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector.h @@ -0,0 +1,18 @@ +#ifndef MARISA_GRIMOIRE_VECTOR_H_ +#define MARISA_GRIMOIRE_VECTOR_H_ + +#include "marisa/grimoire/vector/vector.h" +#include "marisa/grimoire/vector/flat-vector.h" +#include "marisa/grimoire/vector/bit-vector.h" + +namespace marisa { +namespace grimoire { + +using vector::Vector; +typedef vector::FlatVector FlatVector; +typedef vector::BitVector BitVector; + +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_VECTOR_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/bit-vector.cc b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/bit-vector.cc new file mode 100644 index 0000000000000000000000000000000000000000..60ded67fe637d857d3b5506c66526f567043b76f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/bit-vector.cc @@ -0,0 +1,844 @@ +#include "marisa/grimoire/vector/pop-count.h" +#include "marisa/grimoire/vector/bit-vector.h" + +namespace marisa { +namespace grimoire { +namespace vector { +namespace { + +#ifdef MARISA_USE_BMI2 +std::size_t select_bit(std::size_t i, std::size_t bit_id, UInt64 unit) { + #ifdef _MSC_VER + unsigned long pos; + ::_BitScanForward64(&pos, _pdep_u64(1ULL << i, unit)); + return bit_id + pos; + #else // _MSC_VER + return bit_id + ::__builtin_ctzll(_pdep_u64(1ULL << i, unit)); + #endif // _MSC_VER +} +#else // MARISA_USE_BMI2 +const UInt8 SELECT_TABLE[8][256] = { + { + 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 + }, + { + 7, 7, 7, 1, 7, 2, 2, 1, 7, 3, 3, 1, 3, 2, 2, 1, + 7, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 7, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, + 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 7, 6, 6, 1, 6, 2, 2, 1, 6, 3, 3, 1, 3, 2, 2, 1, + 6, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 6, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, + 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 7, 7, 7, 1, 7, 2, 2, 1, 7, 3, 3, 1, 3, 2, 2, 1, + 7, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 7, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, + 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 7, 6, 6, 1, 6, 2, 2, 1, 6, 3, 3, 1, 3, 2, 2, 1, + 6, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 6, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, + 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1 + }, + { + 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 3, 7, 3, 3, 2, + 7, 7, 7, 4, 7, 4, 4, 2, 7, 4, 4, 3, 4, 3, 3, 2, + 7, 7, 7, 5, 7, 5, 5, 2, 7, 5, 5, 3, 5, 3, 3, 2, + 7, 5, 5, 4, 5, 4, 4, 2, 5, 4, 4, 3, 4, 3, 3, 2, + 7, 7, 7, 6, 7, 6, 6, 2, 7, 6, 6, 3, 6, 3, 3, 2, + 7, 6, 6, 4, 6, 4, 4, 2, 6, 4, 4, 3, 4, 3, 3, 2, + 7, 6, 6, 5, 6, 5, 5, 2, 6, 5, 5, 3, 5, 3, 3, 2, + 6, 5, 5, 4, 5, 4, 4, 2, 5, 4, 4, 3, 4, 3, 3, 2, + 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 3, 7, 3, 3, 2, + 7, 7, 7, 4, 7, 4, 4, 2, 7, 4, 4, 3, 4, 3, 3, 2, + 7, 7, 7, 5, 7, 5, 5, 2, 7, 5, 5, 3, 5, 3, 3, 2, + 7, 5, 5, 4, 5, 4, 4, 2, 5, 4, 4, 3, 4, 3, 3, 2, + 7, 7, 7, 6, 7, 6, 6, 2, 7, 6, 6, 3, 6, 3, 3, 2, + 7, 6, 6, 4, 6, 4, 4, 2, 6, 4, 4, 3, 4, 3, 3, 2, + 7, 6, 6, 5, 6, 5, 5, 2, 6, 5, 5, 3, 5, 3, 3, 2, + 6, 5, 5, 4, 5, 4, 4, 2, 5, 4, 4, 3, 4, 3, 3, 2 + }, + { + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, + 7, 7, 7, 7, 7, 7, 7, 4, 7, 7, 7, 4, 7, 4, 4, 3, + 7, 7, 7, 7, 7, 7, 7, 5, 7, 7, 7, 5, 7, 5, 5, 3, + 7, 7, 7, 5, 7, 5, 5, 4, 7, 5, 5, 4, 5, 4, 4, 3, + 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 7, 7, 7, 6, 7, 6, 6, 4, 7, 6, 6, 4, 6, 4, 4, 3, + 7, 7, 7, 6, 7, 6, 6, 5, 7, 6, 6, 5, 6, 5, 5, 3, + 7, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, + 7, 7, 7, 7, 7, 7, 7, 4, 7, 7, 7, 4, 7, 4, 4, 3, + 7, 7, 7, 7, 7, 7, 7, 5, 7, 7, 7, 5, 7, 5, 5, 3, + 7, 7, 7, 5, 7, 5, 5, 4, 7, 5, 5, 4, 5, 4, 4, 3, + 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 3, + 7, 7, 7, 6, 7, 6, 6, 4, 7, 6, 6, 4, 6, 4, 4, 3, + 7, 7, 7, 6, 7, 6, 6, 5, 7, 6, 6, 5, 6, 5, 5, 3, + 7, 6, 6, 5, 6, 5, 5, 4, 6, 5, 5, 4, 5, 4, 4, 3 + }, + { + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, + 7, 7, 7, 7, 7, 7, 7, 5, 7, 7, 7, 5, 7, 5, 5, 4, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 4, + 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 5, + 7, 7, 7, 6, 7, 6, 6, 5, 7, 6, 6, 5, 6, 5, 5, 4, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, + 7, 7, 7, 7, 7, 7, 7, 5, 7, 7, 7, 5, 7, 5, 5, 4, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 4, + 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 5, + 7, 7, 7, 6, 7, 6, 6, 5, 7, 6, 6, 5, 6, 5, 5, 4 + }, + { + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 5, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 6, 7, 6, 6, 5 + }, + { + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6 + }, + { + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + } +}; + + #if MARISA_WORD_SIZE == 64 +const UInt64 MASK_01 = 0x0101010101010101ULL; + #if !defined(MARISA_X64) || !defined(MARISA_USE_SSSE3) +const UInt64 MASK_0F = 0x0F0F0F0F0F0F0F0FULL; +const UInt64 MASK_33 = 0x3333333333333333ULL; +const UInt64 MASK_55 = 0x5555555555555555ULL; + #endif // !defined(MARISA_X64) || !defined(MARISA_USE_SSSE3) + #if !defined(MARISA_X64) || !defined(MARISA_USE_POPCNT) +const UInt64 MASK_80 = 0x8080808080808080ULL; + #endif // !defined(MARISA_X64) || !defined(MARISA_USE_POPCNT) + +std::size_t select_bit(std::size_t i, std::size_t bit_id, UInt64 unit) { + UInt64 counts; + { + #if defined(MARISA_X64) && defined(MARISA_USE_SSSE3) + __m128i lower_nibbles = _mm_cvtsi64_si128( + static_cast(unit & 0x0F0F0F0F0F0F0F0FULL)); + __m128i upper_nibbles = _mm_cvtsi64_si128( + static_cast(unit & 0xF0F0F0F0F0F0F0F0ULL)); + upper_nibbles = _mm_srli_epi32(upper_nibbles, 4); + + __m128i lower_counts = + _mm_set_epi8(4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0); + lower_counts = _mm_shuffle_epi8(lower_counts, lower_nibbles); + __m128i upper_counts = + _mm_set_epi8(4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0); + upper_counts = _mm_shuffle_epi8(upper_counts, upper_nibbles); + + counts = static_cast(_mm_cvtsi128_si64( + _mm_add_epi8(lower_counts, upper_counts))); + #else // defined(MARISA_X64) && defined(MARISA_USE_SSSE3) + counts = unit - ((unit >> 1) & MASK_55); + counts = (counts & MASK_33) + ((counts >> 2) & MASK_33); + counts = (counts + (counts >> 4)) & MASK_0F; + #endif // defined(MARISA_X64) && defined(MARISA_USE_SSSE3) + counts *= MASK_01; + } + + #if defined(MARISA_X64) && defined(MARISA_USE_POPCNT) + UInt8 skip; + { + __m128i x = _mm_cvtsi64_si128(static_cast((i + 1) * MASK_01)); + __m128i y = _mm_cvtsi64_si128(static_cast(counts)); + x = _mm_cmpgt_epi8(x, y); + skip = (UInt8)PopCount::count(static_cast(_mm_cvtsi128_si64(x))); + } + #else // defined(MARISA_X64) && defined(MARISA_USE_POPCNT) + const UInt64 x = (counts | MASK_80) - ((i + 1) * MASK_01); + #ifdef _MSC_VER + unsigned long skip; + ::_BitScanForward64(&skip, (x & MASK_80) >> 7); + #else // _MSC_VER + const int skip = ::__builtin_ctzll((x & MASK_80) >> 7); + #endif // _MSC_VER + #endif // defined(MARISA_X64) && defined(MARISA_USE_POPCNT) + + bit_id += static_cast(skip); + unit >>= skip; + i -= ((counts << 8) >> skip) & 0xFF; + + return bit_id + SELECT_TABLE[i][unit & 0xFF]; +} + #else // MARISA_WORD_SIZE == 64 + #ifdef MARISA_USE_SSE2 +const UInt8 POPCNT_TABLE[256] = { + 0, 8, 8, 16, 8, 16, 16, 24, 8, 16, 16, 24, 16, 24, 24, 32, + 8, 16, 16, 24, 16, 24, 24, 32, 16, 24, 24, 32, 24, 32, 32, 40, + 8, 16, 16, 24, 16, 24, 24, 32, 16, 24, 24, 32, 24, 32, 32, 40, + 16, 24, 24, 32, 24, 32, 32, 40, 24, 32, 32, 40, 32, 40, 40, 48, + 8, 16, 16, 24, 16, 24, 24, 32, 16, 24, 24, 32, 24, 32, 32, 40, + 16, 24, 24, 32, 24, 32, 32, 40, 24, 32, 32, 40, 32, 40, 40, 48, + 16, 24, 24, 32, 24, 32, 32, 40, 24, 32, 32, 40, 32, 40, 40, 48, + 24, 32, 32, 40, 32, 40, 40, 48, 32, 40, 40, 48, 40, 48, 48, 56, + 8, 16, 16, 24, 16, 24, 24, 32, 16, 24, 24, 32, 24, 32, 32, 40, + 16, 24, 24, 32, 24, 32, 32, 40, 24, 32, 32, 40, 32, 40, 40, 48, + 16, 24, 24, 32, 24, 32, 32, 40, 24, 32, 32, 40, 32, 40, 40, 48, + 24, 32, 32, 40, 32, 40, 40, 48, 32, 40, 40, 48, 40, 48, 48, 56, + 16, 24, 24, 32, 24, 32, 32, 40, 24, 32, 32, 40, 32, 40, 40, 48, + 24, 32, 32, 40, 32, 40, 40, 48, 32, 40, 40, 48, 40, 48, 48, 56, + 24, 32, 32, 40, 32, 40, 40, 48, 32, 40, 40, 48, 40, 48, 48, 56, + 32, 40, 40, 48, 40, 48, 48, 56, 40, 48, 48, 56, 48, 56, 56, 64 +}; + +std::size_t select_bit(std::size_t i, std::size_t bit_id, + UInt32 unit_lo, UInt32 unit_hi) { + __m128i unit; + { + __m128i lower_dword = _mm_cvtsi32_si128(unit_lo); + __m128i upper_dword = _mm_cvtsi32_si128(unit_hi); + upper_dword = _mm_slli_si128(upper_dword, 4); + unit = _mm_or_si128(lower_dword, upper_dword); + } + + __m128i counts; + { + #ifdef MARISA_USE_SSSE3 + __m128i lower_nibbles = _mm_set1_epi8(0x0F); + lower_nibbles = _mm_and_si128(lower_nibbles, unit); + __m128i upper_nibbles = _mm_set1_epi8((UInt8)0xF0); + upper_nibbles = _mm_and_si128(upper_nibbles, unit); + upper_nibbles = _mm_srli_epi32(upper_nibbles, 4); + + __m128i lower_counts = + _mm_set_epi8(4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0); + lower_counts = _mm_shuffle_epi8(lower_counts, lower_nibbles); + __m128i upper_counts = + _mm_set_epi8(4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0); + upper_counts = _mm_shuffle_epi8(upper_counts, upper_nibbles); + + counts = _mm_add_epi8(lower_counts, upper_counts); + #else // MARISA_USE_SSSE3 + __m128i x = _mm_srli_epi32(unit, 1); + x = _mm_and_si128(x, _mm_set1_epi8(0x55)); + x = _mm_sub_epi8(unit, x); + + __m128i y = _mm_srli_epi32(x, 2); + y = _mm_and_si128(y, _mm_set1_epi8(0x33)); + x = _mm_and_si128(x, _mm_set1_epi8(0x33)); + x = _mm_add_epi8(x, y); + + y = _mm_srli_epi32(x, 4); + x = _mm_add_epi8(x, y); + counts = _mm_and_si128(x, _mm_set1_epi8(0x0F)); + #endif // MARISA_USE_SSSE3 + } + + __m128i accumulated_counts; + { + __m128i x = counts; + x = _mm_slli_si128(x, 1); + __m128i y = counts; + y = _mm_add_epi32(y, x); + + x = y; + y = _mm_slli_si128(y, 2); + x = _mm_add_epi32(x, y); + + y = x; + x = _mm_slli_si128(x, 4); + y = _mm_add_epi32(y, x); + + accumulated_counts = _mm_set_epi32(0x7F7F7F7FU, 0x7F7F7F7FU, 0, 0); + accumulated_counts = _mm_or_si128(accumulated_counts, y); + } + + UInt8 skip; + { + __m128i x = _mm_set1_epi8((UInt8)(i + 1)); + x = _mm_cmpgt_epi8(x, accumulated_counts); + skip = POPCNT_TABLE[_mm_movemask_epi8(x)]; + } + + UInt8 byte; + { + #ifdef _MSC_VER + __declspec(align(16)) UInt8 unit_bytes[16]; + __declspec(align(16)) UInt8 accumulated_counts_bytes[16]; + #else // _MSC_VER + UInt8 unit_bytes[16] __attribute__ ((aligned (16))); + UInt8 accumulated_counts_bytes[16] __attribute__ ((aligned (16))); + #endif // _MSC_VER + accumulated_counts = _mm_slli_si128(accumulated_counts, 1); + _mm_store_si128(reinterpret_cast<__m128i *>(unit_bytes), unit); + _mm_store_si128(reinterpret_cast<__m128i *>(accumulated_counts_bytes), + accumulated_counts); + + bit_id += skip; + byte = unit_bytes[skip / 8]; + i -= accumulated_counts_bytes[skip / 8]; + } + + return bit_id + SELECT_TABLE[i][byte]; +} + #endif // MARISA_USE_SSE2 + #endif // MARISA_WORD_SIZE == 64 +#endif // MARISA_USE_BMI2 + +} // namespace + +#if MARISA_WORD_SIZE == 64 + +std::size_t BitVector::rank1(std::size_t i) const { + MARISA_DEBUG_IF(ranks_.empty(), MARISA_STATE_ERROR); + MARISA_DEBUG_IF(i > size_, MARISA_BOUND_ERROR); + + const RankIndex &rank = ranks_[i / 512]; + std::size_t offset = rank.abs(); + switch ((i / 64) % 8) { + case 1: { + offset += rank.rel1(); + break; + } + case 2: { + offset += rank.rel2(); + break; + } + case 3: { + offset += rank.rel3(); + break; + } + case 4: { + offset += rank.rel4(); + break; + } + case 5: { + offset += rank.rel5(); + break; + } + case 6: { + offset += rank.rel6(); + break; + } + case 7: { + offset += rank.rel7(); + break; + } + } + offset += PopCount::count(units_[i / 64] & ((1ULL << (i % 64)) - 1)); + return offset; +} + +std::size_t BitVector::select0(std::size_t i) const { + MARISA_DEBUG_IF(select0s_.empty(), MARISA_STATE_ERROR); + MARISA_DEBUG_IF(i >= num_0s(), MARISA_BOUND_ERROR); + + const std::size_t select_id = i / 512; + MARISA_DEBUG_IF((select_id + 1) >= select0s_.size(), MARISA_BOUND_ERROR); + if ((i % 512) == 0) { + return select0s_[select_id]; + } + std::size_t begin = select0s_[select_id] / 512; + std::size_t end = (select0s_[select_id + 1] + 511) / 512; + if (begin + 10 >= end) { + while (i >= ((begin + 1) * 512) - ranks_[begin + 1].abs()) { + ++begin; + } + } else { + while (begin + 1 < end) { + const std::size_t middle = (begin + end) / 2; + if (i < (middle * 512) - ranks_[middle].abs()) { + end = middle; + } else { + begin = middle; + } + } + } + const std::size_t rank_id = begin; + i -= (rank_id * 512) - ranks_[rank_id].abs(); + + const RankIndex &rank = ranks_[rank_id]; + std::size_t unit_id = rank_id * 8; + if (i < (256U - rank.rel4())) { + if (i < (128U - rank.rel2())) { + if (i >= (64U - rank.rel1())) { + unit_id += 1; + i -= 64 - rank.rel1(); + } + } else if (i < (192U - rank.rel3())) { + unit_id += 2; + i -= 128 - rank.rel2(); + } else { + unit_id += 3; + i -= 192 - rank.rel3(); + } + } else if (i < (384U - rank.rel6())) { + if (i < (320U - rank.rel5())) { + unit_id += 4; + i -= 256 - rank.rel4(); + } else { + unit_id += 5; + i -= 320 - rank.rel5(); + } + } else if (i < (448U - rank.rel7())) { + unit_id += 6; + i -= 384 - rank.rel6(); + } else { + unit_id += 7; + i -= 448 - rank.rel7(); + } + + return select_bit(i, unit_id * 64, ~units_[unit_id]); +} + +std::size_t BitVector::select1(std::size_t i) const { + MARISA_DEBUG_IF(select1s_.empty(), MARISA_STATE_ERROR); + MARISA_DEBUG_IF(i >= num_1s(), MARISA_BOUND_ERROR); + + const std::size_t select_id = i / 512; + MARISA_DEBUG_IF((select_id + 1) >= select1s_.size(), MARISA_BOUND_ERROR); + if ((i % 512) == 0) { + return select1s_[select_id]; + } + std::size_t begin = select1s_[select_id] / 512; + std::size_t end = (select1s_[select_id + 1] + 511) / 512; + if (begin + 10 >= end) { + while (i >= ranks_[begin + 1].abs()) { + ++begin; + } + } else { + while (begin + 1 < end) { + const std::size_t middle = (begin + end) / 2; + if (i < ranks_[middle].abs()) { + end = middle; + } else { + begin = middle; + } + } + } + const std::size_t rank_id = begin; + i -= ranks_[rank_id].abs(); + + const RankIndex &rank = ranks_[rank_id]; + std::size_t unit_id = rank_id * 8; + if (i < rank.rel4()) { + if (i < rank.rel2()) { + if (i >= rank.rel1()) { + unit_id += 1; + i -= rank.rel1(); + } + } else if (i < rank.rel3()) { + unit_id += 2; + i -= rank.rel2(); + } else { + unit_id += 3; + i -= rank.rel3(); + } + } else if (i < rank.rel6()) { + if (i < rank.rel5()) { + unit_id += 4; + i -= rank.rel4(); + } else { + unit_id += 5; + i -= rank.rel5(); + } + } else if (i < rank.rel7()) { + unit_id += 6; + i -= rank.rel6(); + } else { + unit_id += 7; + i -= rank.rel7(); + } + + return select_bit(i, unit_id * 64, units_[unit_id]); +} + +#else // MARISA_WORD_SIZE == 64 + +std::size_t BitVector::rank1(std::size_t i) const { + MARISA_DEBUG_IF(ranks_.empty(), MARISA_STATE_ERROR); + MARISA_DEBUG_IF(i > size_, MARISA_BOUND_ERROR); + + const RankIndex &rank = ranks_[i / 512]; + std::size_t offset = rank.abs(); + switch ((i / 64) % 8) { + case 1: { + offset += rank.rel1(); + break; + } + case 2: { + offset += rank.rel2(); + break; + } + case 3: { + offset += rank.rel3(); + break; + } + case 4: { + offset += rank.rel4(); + break; + } + case 5: { + offset += rank.rel5(); + break; + } + case 6: { + offset += rank.rel6(); + break; + } + case 7: { + offset += rank.rel7(); + break; + } + } + if (((i / 32) & 1) == 1) { + offset += PopCount::count(units_[(i / 32) - 1]); + } + offset += PopCount::count(units_[i / 32] & ((1U << (i % 32)) - 1)); + return offset; +} + +std::size_t BitVector::select0(std::size_t i) const { + MARISA_DEBUG_IF(select0s_.empty(), MARISA_STATE_ERROR); + MARISA_DEBUG_IF(i >= num_0s(), MARISA_BOUND_ERROR); + + const std::size_t select_id = i / 512; + MARISA_DEBUG_IF((select_id + 1) >= select0s_.size(), MARISA_BOUND_ERROR); + if ((i % 512) == 0) { + return select0s_[select_id]; + } + std::size_t begin = select0s_[select_id] / 512; + std::size_t end = (select0s_[select_id + 1] + 511) / 512; + if (begin + 10 >= end) { + while (i >= ((begin + 1) * 512) - ranks_[begin + 1].abs()) { + ++begin; + } + } else { + while (begin + 1 < end) { + const std::size_t middle = (begin + end) / 2; + if (i < (middle * 512) - ranks_[middle].abs()) { + end = middle; + } else { + begin = middle; + } + } + } + const std::size_t rank_id = begin; + i -= (rank_id * 512) - ranks_[rank_id].abs(); + + const RankIndex &rank = ranks_[rank_id]; + std::size_t unit_id = rank_id * 16; + if (i < (256U - rank.rel4())) { + if (i < (128U - rank.rel2())) { + if (i >= (64U - rank.rel1())) { + unit_id += 2; + i -= 64 - rank.rel1(); + } + } else if (i < (192U - rank.rel3())) { + unit_id += 4; + i -= 128 - rank.rel2(); + } else { + unit_id += 6; + i -= 192 - rank.rel3(); + } + } else if (i < (384U - rank.rel6())) { + if (i < (320U - rank.rel5())) { + unit_id += 8; + i -= 256 - rank.rel4(); + } else { + unit_id += 10; + i -= 320 - rank.rel5(); + } + } else if (i < (448U - rank.rel7())) { + unit_id += 12; + i -= 384 - rank.rel6(); + } else { + unit_id += 14; + i -= 448 - rank.rel7(); + } + +#ifdef MARISA_USE_SSE2 + return select_bit(i, unit_id * 32, ~units_[unit_id], ~units_[unit_id + 1]); +#else // MARISA_USE_SSE2 + UInt32 unit = ~units_[unit_id]; + PopCount count(unit); + if (i >= count.lo32()) { + ++unit_id; + i -= count.lo32(); + unit = ~units_[unit_id]; + count = PopCount(unit); + } + + std::size_t bit_id = unit_id * 32; + if (i < count.lo16()) { + if (i >= count.lo8()) { + bit_id += 8; + unit >>= 8; + i -= count.lo8(); + } + } else if (i < count.lo24()) { + bit_id += 16; + unit >>= 16; + i -= count.lo16(); + } else { + bit_id += 24; + unit >>= 24; + i -= count.lo24(); + } + return bit_id + SELECT_TABLE[i][unit & 0xFF]; +#endif // MARISA_USE_SSE2 +} + +std::size_t BitVector::select1(std::size_t i) const { + MARISA_DEBUG_IF(select1s_.empty(), MARISA_STATE_ERROR); + MARISA_DEBUG_IF(i >= num_1s(), MARISA_BOUND_ERROR); + + const std::size_t select_id = i / 512; + MARISA_DEBUG_IF((select_id + 1) >= select1s_.size(), MARISA_BOUND_ERROR); + if ((i % 512) == 0) { + return select1s_[select_id]; + } + std::size_t begin = select1s_[select_id] / 512; + std::size_t end = (select1s_[select_id + 1] + 511) / 512; + if (begin + 10 >= end) { + while (i >= ranks_[begin + 1].abs()) { + ++begin; + } + } else { + while (begin + 1 < end) { + const std::size_t middle = (begin + end) / 2; + if (i < ranks_[middle].abs()) { + end = middle; + } else { + begin = middle; + } + } + } + const std::size_t rank_id = begin; + i -= ranks_[rank_id].abs(); + + const RankIndex &rank = ranks_[rank_id]; + std::size_t unit_id = rank_id * 16; + if (i < rank.rel4()) { + if (i < rank.rel2()) { + if (i >= rank.rel1()) { + unit_id += 2; + i -= rank.rel1(); + } + } else if (i < rank.rel3()) { + unit_id += 4; + i -= rank.rel2(); + } else { + unit_id += 6; + i -= rank.rel3(); + } + } else if (i < rank.rel6()) { + if (i < rank.rel5()) { + unit_id += 8; + i -= rank.rel4(); + } else { + unit_id += 10; + i -= rank.rel5(); + } + } else if (i < rank.rel7()) { + unit_id += 12; + i -= rank.rel6(); + } else { + unit_id += 14; + i -= rank.rel7(); + } + +#ifdef MARISA_USE_SSE2 + return select_bit(i, unit_id * 32, units_[unit_id], units_[unit_id + 1]); +#else // MARISA_USE_SSE2 + UInt32 unit = units_[unit_id]; + PopCount count(unit); + if (i >= count.lo32()) { + ++unit_id; + i -= count.lo32(); + unit = units_[unit_id]; + count = PopCount(unit); + } + + std::size_t bit_id = unit_id * 32; + if (i < count.lo16()) { + if (i >= count.lo8()) { + bit_id += 8; + unit >>= 8; + i -= count.lo8(); + } + } else if (i < count.lo24()) { + bit_id += 16; + unit >>= 16; + i -= count.lo16(); + } else { + bit_id += 24; + unit >>= 24; + i -= count.lo24(); + } + return bit_id + SELECT_TABLE[i][unit & 0xFF]; +#endif // MARISA_USE_SSE2 +} + +#endif // MARISA_WORD_SIZE == 64 + +void BitVector::build_index(const BitVector &bv, + bool enables_select0, bool enables_select1) { + ranks_.resize((bv.size() / 512) + (((bv.size() % 512) != 0) ? 1 : 0) + 1); + + std::size_t num_0s = 0; + std::size_t num_1s = 0; + + for (std::size_t i = 0; i < bv.size(); ++i) { + if ((i % 64) == 0) { + const std::size_t rank_id = i / 512; + switch ((i / 64) % 8) { + case 0: { + ranks_[rank_id].set_abs(num_1s); + break; + } + case 1: { + ranks_[rank_id].set_rel1(num_1s - ranks_[rank_id].abs()); + break; + } + case 2: { + ranks_[rank_id].set_rel2(num_1s - ranks_[rank_id].abs()); + break; + } + case 3: { + ranks_[rank_id].set_rel3(num_1s - ranks_[rank_id].abs()); + break; + } + case 4: { + ranks_[rank_id].set_rel4(num_1s - ranks_[rank_id].abs()); + break; + } + case 5: { + ranks_[rank_id].set_rel5(num_1s - ranks_[rank_id].abs()); + break; + } + case 6: { + ranks_[rank_id].set_rel6(num_1s - ranks_[rank_id].abs()); + break; + } + case 7: { + ranks_[rank_id].set_rel7(num_1s - ranks_[rank_id].abs()); + break; + } + } + } + + if (bv[i]) { + if (enables_select1 && ((num_1s % 512) == 0)) { + select1s_.push_back(static_cast(i)); + } + ++num_1s; + } else { + if (enables_select0 && ((num_0s % 512) == 0)) { + select0s_.push_back(static_cast(i)); + } + ++num_0s; + } + } + + if ((bv.size() % 512) != 0) { + const std::size_t rank_id = (bv.size() - 1) / 512; + switch (((bv.size() - 1) / 64) % 8) { + case 0: { + ranks_[rank_id].set_rel1(num_1s - ranks_[rank_id].abs()); + } // fall through + case 1: { + ranks_[rank_id].set_rel2(num_1s - ranks_[rank_id].abs()); + } // fall through + case 2: { + ranks_[rank_id].set_rel3(num_1s - ranks_[rank_id].abs()); + } // fall through + case 3: { + ranks_[rank_id].set_rel4(num_1s - ranks_[rank_id].abs()); + } // fall through + case 4: { + ranks_[rank_id].set_rel5(num_1s - ranks_[rank_id].abs()); + } // fall through + case 5: { + ranks_[rank_id].set_rel6(num_1s - ranks_[rank_id].abs()); + } // fall through + case 6: { + ranks_[rank_id].set_rel7(num_1s - ranks_[rank_id].abs()); + break; + } + } + } + + size_ = bv.size(); + num_1s_ = bv.num_1s(); + + ranks_.back().set_abs(num_1s); + if (enables_select0) { + select0s_.push_back(static_cast(bv.size())); + select0s_.shrink(); + } + if (enables_select1) { + select1s_.push_back(static_cast(bv.size())); + select1s_.shrink(); + } +} + +} // namespace vector +} // namespace grimoire +} // namespace marisa diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/bit-vector.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/bit-vector.h new file mode 100644 index 0000000000000000000000000000000000000000..ea698f133111d6492b18031071478f9e8dc46dc4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/bit-vector.h @@ -0,0 +1,179 @@ +#ifndef MARISA_GRIMOIRE_VECTOR_BIT_VECTOR_H_ +#define MARISA_GRIMOIRE_VECTOR_BIT_VECTOR_H_ + +#include "marisa/grimoire/vector/rank-index.h" +#include "marisa/grimoire/vector/vector.h" + +namespace marisa { +namespace grimoire { +namespace vector { + +class BitVector { + public: +#if MARISA_WORD_SIZE == 64 + typedef UInt64 Unit; +#else // MARISA_WORD_SIZE == 64 + typedef UInt32 Unit; +#endif // MARISA_WORD_SIZE == 64 + + BitVector() + : units_(), size_(0), num_1s_(0), ranks_(), select0s_(), select1s_() {} + + void build(bool enables_select0, bool enables_select1) { + BitVector temp; + temp.build_index(*this, enables_select0, enables_select1); + units_.shrink(); + temp.units_.swap(units_); + swap(temp); + } + + void map(Mapper &mapper) { + BitVector temp; + temp.map_(mapper); + swap(temp); + } + void read(Reader &reader) { + BitVector temp; + temp.read_(reader); + swap(temp); + } + void write(Writer &writer) const { + write_(writer); + } + + void disable_select0() { + select0s_.clear(); + } + void disable_select1() { + select1s_.clear(); + } + + void push_back(bool bit) { + MARISA_THROW_IF(size_ == MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + if (size_ == (MARISA_WORD_SIZE * units_.size())) { + units_.resize(units_.size() + (64 / MARISA_WORD_SIZE), 0); + } + if (bit) { + units_[size_ / MARISA_WORD_SIZE] |= + (Unit)1 << (size_ % MARISA_WORD_SIZE); + ++num_1s_; + } + ++size_; + } + + bool operator[](std::size_t i) const { + MARISA_DEBUG_IF(i >= size_, MARISA_BOUND_ERROR); + return (units_[i / MARISA_WORD_SIZE] + & ((Unit)1 << (i % MARISA_WORD_SIZE))) != 0; + } + + std::size_t rank0(std::size_t i) const { + MARISA_DEBUG_IF(ranks_.empty(), MARISA_STATE_ERROR); + MARISA_DEBUG_IF(i > size_, MARISA_BOUND_ERROR); + return i - rank1(i); + } + std::size_t rank1(std::size_t i) const; + + std::size_t select0(std::size_t i) const; + std::size_t select1(std::size_t i) const; + + std::size_t num_0s() const { + return size_ - num_1s_; + } + std::size_t num_1s() const { + return num_1s_; + } + + bool empty() const { + return size_ == 0; + } + std::size_t size() const { + return size_; + } + std::size_t total_size() const { + return units_.total_size() + ranks_.total_size() + + select0s_.total_size() + select1s_.total_size(); + } + std::size_t io_size() const { + return units_.io_size() + (sizeof(UInt32) * 2) + ranks_.io_size() + + select0s_.io_size() + select1s_.io_size(); + } + + void clear() { + BitVector().swap(*this); + } + void swap(BitVector &rhs) { + units_.swap(rhs.units_); + marisa::swap(size_, rhs.size_); + marisa::swap(num_1s_, rhs.num_1s_); + ranks_.swap(rhs.ranks_); + select0s_.swap(rhs.select0s_); + select1s_.swap(rhs.select1s_); + } + + private: + Vector units_; + std::size_t size_; + std::size_t num_1s_; + Vector ranks_; + Vector select0s_; + Vector select1s_; + + void build_index(const BitVector &bv, + bool enables_select0, bool enables_select1); + + void map_(Mapper &mapper) { + units_.map(mapper); + { + UInt32 temp_size; + mapper.map(&temp_size); + size_ = temp_size; + } + { + UInt32 temp_num_1s; + mapper.map(&temp_num_1s); + MARISA_THROW_IF(temp_num_1s > size_, MARISA_FORMAT_ERROR); + num_1s_ = temp_num_1s; + } + ranks_.map(mapper); + select0s_.map(mapper); + select1s_.map(mapper); + } + + void read_(Reader &reader) { + units_.read(reader); + { + UInt32 temp_size; + reader.read(&temp_size); + size_ = temp_size; + } + { + UInt32 temp_num_1s; + reader.read(&temp_num_1s); + MARISA_THROW_IF(temp_num_1s > size_, MARISA_FORMAT_ERROR); + num_1s_ = temp_num_1s; + } + ranks_.read(reader); + select0s_.read(reader); + select1s_.read(reader); + } + + void write_(Writer &writer) const { + units_.write(writer); + writer.write((UInt32)size_); + writer.write((UInt32)num_1s_); + ranks_.write(writer); + select0s_.write(writer); + select1s_.write(writer); + } + + // Disallows copy and assignment. + BitVector(const BitVector &); + BitVector &operator=(const BitVector &); +}; + +} // namespace vector +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_VECTOR_BIT_VECTOR_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/flat-vector.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/flat-vector.h new file mode 100644 index 0000000000000000000000000000000000000000..eeae719e27c093e74d5b2224e80ed03cf8b63ca4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/flat-vector.h @@ -0,0 +1,205 @@ +#ifndef MARISA_GRIMOIRE_VECTOR_FLAT_VECTOR_H_ +#define MARISA_GRIMOIRE_VECTOR_FLAT_VECTOR_H_ + +#include "marisa/grimoire/vector/vector.h" + +namespace marisa { +namespace grimoire { +namespace vector { + +class FlatVector { + public: +#if MARISA_WORD_SIZE == 64 + typedef UInt64 Unit; +#else // MARISA_WORD_SIZE == 64 + typedef UInt32 Unit; +#endif // MARISA_WORD_SIZE == 64 + + FlatVector() : units_(), value_size_(0), mask_(0), size_(0) {} + + void build(const Vector &values) { + FlatVector temp; + temp.build_(values); + swap(temp); + } + + void map(Mapper &mapper) { + FlatVector temp; + temp.map_(mapper); + swap(temp); + } + void read(Reader &reader) { + FlatVector temp; + temp.read_(reader); + swap(temp); + } + void write(Writer &writer) const { + write_(writer); + } + + UInt32 operator[](std::size_t i) const { + MARISA_DEBUG_IF(i >= size_, MARISA_BOUND_ERROR); + + const std::size_t pos = i * value_size_; + const std::size_t unit_id = pos / MARISA_WORD_SIZE; + const std::size_t unit_offset = pos % MARISA_WORD_SIZE; + + if ((unit_offset + value_size_) <= MARISA_WORD_SIZE) { + return (UInt32)(units_[unit_id] >> unit_offset) & mask_; + } else { + return (UInt32)((units_[unit_id] >> unit_offset) + | (units_[unit_id + 1] << (MARISA_WORD_SIZE - unit_offset))) & mask_; + } + } + + std::size_t value_size() const { + return value_size_; + } + UInt32 mask() const { + return mask_; + } + + bool empty() const { + return size_ == 0; + } + std::size_t size() const { + return size_; + } + std::size_t total_size() const { + return units_.total_size(); + } + std::size_t io_size() const { + return units_.io_size() + (sizeof(UInt32) * 2) + sizeof(UInt64); + } + + void clear() { + FlatVector().swap(*this); + } + void swap(FlatVector &rhs) { + units_.swap(rhs.units_); + marisa::swap(value_size_, rhs.value_size_); + marisa::swap(mask_, rhs.mask_); + marisa::swap(size_, rhs.size_); + } + + private: + Vector units_; + std::size_t value_size_; + UInt32 mask_; + std::size_t size_; + + void build_(const Vector &values) { + UInt32 max_value = 0; + for (std::size_t i = 0; i < values.size(); ++i) { + if (values[i] > max_value) { + max_value = values[i]; + } + } + + std::size_t value_size = 0; + while (max_value != 0) { + ++value_size; + max_value >>= 1; + } + + std::size_t num_units = values.empty() ? 0 : (64 / MARISA_WORD_SIZE); + if (value_size != 0) { + num_units = (std::size_t)( + (((UInt64)value_size * values.size()) + (MARISA_WORD_SIZE - 1)) + / MARISA_WORD_SIZE); + num_units += num_units % (64 / MARISA_WORD_SIZE); + } + + units_.resize(num_units); + if (num_units > 0) { + units_.back() = 0; + } + + value_size_ = value_size; + if (value_size != 0) { + mask_ = MARISA_UINT32_MAX >> (32 - value_size); + } + size_ = values.size(); + + for (std::size_t i = 0; i < values.size(); ++i) { + set(i, values[i]); + } + } + + void map_(Mapper &mapper) { + units_.map(mapper); + { + UInt32 temp_value_size; + mapper.map(&temp_value_size); + MARISA_THROW_IF(temp_value_size > 32, MARISA_FORMAT_ERROR); + value_size_ = temp_value_size; + } + { + UInt32 temp_mask; + mapper.map(&temp_mask); + mask_ = temp_mask; + } + { + UInt64 temp_size; + mapper.map(&temp_size); + MARISA_THROW_IF(temp_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + size_ = (std::size_t)temp_size; + } + } + + void read_(Reader &reader) { + units_.read(reader); + { + UInt32 temp_value_size; + reader.read(&temp_value_size); + MARISA_THROW_IF(temp_value_size > 32, MARISA_FORMAT_ERROR); + value_size_ = temp_value_size; + } + { + UInt32 temp_mask; + reader.read(&temp_mask); + mask_ = temp_mask; + } + { + UInt64 temp_size; + reader.read(&temp_size); + MARISA_THROW_IF(temp_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + size_ = (std::size_t)temp_size; + } + } + + void write_(Writer &writer) const { + units_.write(writer); + writer.write((UInt32)value_size_); + writer.write((UInt32)mask_); + writer.write((UInt64)size_); + } + + void set(std::size_t i, UInt32 value) { + MARISA_DEBUG_IF(i >= size_, MARISA_BOUND_ERROR); + MARISA_DEBUG_IF(value > mask_, MARISA_RANGE_ERROR); + + const std::size_t pos = i * value_size_; + const std::size_t unit_id = pos / MARISA_WORD_SIZE; + const std::size_t unit_offset = pos % MARISA_WORD_SIZE; + + units_[unit_id] &= ~((Unit)mask_ << unit_offset); + units_[unit_id] |= (Unit)(value & mask_) << unit_offset; + if ((unit_offset + value_size_) > MARISA_WORD_SIZE) { + units_[unit_id + 1] &= + ~((Unit)mask_ >> (MARISA_WORD_SIZE - unit_offset)); + units_[unit_id + 1] |= + (Unit)(value & mask_) >> (MARISA_WORD_SIZE - unit_offset); + } + } + + // Disallows copy and assignment. + FlatVector(const FlatVector &); + FlatVector &operator=(const FlatVector &); +}; + +} // namespace vector +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_VECTOR_FLAT_VECTOR_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/pop-count.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/pop-count.h new file mode 100644 index 0000000000000000000000000000000000000000..47f4b5db30699fb94691783c1fdac91cb02d70f9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/pop-count.h @@ -0,0 +1,110 @@ +#ifndef MARISA_GRIMOIRE_VECTOR_POP_COUNT_H_ +#define MARISA_GRIMOIRE_VECTOR_POP_COUNT_H_ + +#include "marisa/grimoire/intrin.h" + +namespace marisa { +namespace grimoire { +namespace vector { + +#if MARISA_WORD_SIZE == 64 + +class PopCount { + public: + explicit PopCount(UInt64 x) : value_() { + x = (x & 0x5555555555555555ULL) + ((x & 0xAAAAAAAAAAAAAAAAULL) >> 1); + x = (x & 0x3333333333333333ULL) + ((x & 0xCCCCCCCCCCCCCCCCULL) >> 2); + x = (x & 0x0F0F0F0F0F0F0F0FULL) + ((x & 0xF0F0F0F0F0F0F0F0ULL) >> 4); + x *= 0x0101010101010101ULL; + value_ = x; + } + + std::size_t lo8() const { + return (std::size_t)(value_ & 0xFFU); + } + std::size_t lo16() const { + return (std::size_t)((value_ >> 8) & 0xFFU); + } + std::size_t lo24() const { + return (std::size_t)((value_ >> 16) & 0xFFU); + } + std::size_t lo32() const { + return (std::size_t)((value_ >> 24) & 0xFFU); + } + std::size_t lo40() const { + return (std::size_t)((value_ >> 32) & 0xFFU); + } + std::size_t lo48() const { + return (std::size_t)((value_ >> 40) & 0xFFU); + } + std::size_t lo56() const { + return (std::size_t)((value_ >> 48) & 0xFFU); + } + std::size_t lo64() const { + return (std::size_t)((value_ >> 56) & 0xFFU); + } + + static std::size_t count(UInt64 x) { +#if defined(MARISA_X64) && defined(MARISA_USE_POPCNT) + #ifdef _MSC_VER + return __popcnt64(x); + #else // _MSC_VER + return static_cast(_mm_popcnt_u64(x)); + #endif // _MSC_VER +#else // defined(MARISA_X64) && defined(MARISA_USE_POPCNT) + return PopCount(x).lo64(); +#endif // defined(MARISA_X64) && defined(MARISA_USE_POPCNT) + } + + private: + UInt64 value_; +}; + +#else // MARISA_WORD_SIZE == 64 + +class PopCount { + public: + explicit PopCount(UInt32 x) : value_() { + x = (x & 0x55555555U) + ((x & 0xAAAAAAAAU) >> 1); + x = (x & 0x33333333U) + ((x & 0xCCCCCCCCU) >> 2); + x = (x & 0x0F0F0F0FU) + ((x & 0xF0F0F0F0U) >> 4); + x *= 0x01010101U; + value_ = x; + } + + std::size_t lo8() const { + return value_ & 0xFFU; + } + std::size_t lo16() const { + return (value_ >> 8) & 0xFFU; + } + std::size_t lo24() const { + return (value_ >> 16) & 0xFFU; + } + std::size_t lo32() const { + return (value_ >> 24) & 0xFFU; + } + + static std::size_t count(UInt32 x) { +#ifdef MARISA_USE_POPCNT + #ifdef _MSC_VER + return __popcnt(x); + #else // _MSC_VER + return _mm_popcnt_u32(x); + #endif // _MSC_VER +#else // MARISA_USE_POPCNT + return PopCount(x).lo32(); +#endif // MARISA_USE_POPCNT + } + + private: + UInt32 value_; +}; + +#endif // MARISA_WORD_SIZE == 64 + +} // namespace vector +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_VECTOR_POP_COUNT_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/rank-index.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/rank-index.h new file mode 100644 index 0000000000000000000000000000000000000000..c1ce476be2fd0c9239eea4bfe3303558397a2d0e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/rank-index.h @@ -0,0 +1,82 @@ +#ifndef MARISA_GRIMOIRE_VECTOR_RANK_INDEX_H_ +#define MARISA_GRIMOIRE_VECTOR_RANK_INDEX_H_ + +#include "marisa/base.h" + +namespace marisa { +namespace grimoire { +namespace vector { + +class RankIndex { + public: + RankIndex() : abs_(0), rel_lo_(0), rel_hi_(0) {} + + void set_abs(std::size_t value) { + MARISA_DEBUG_IF(value > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + abs_ = (UInt32)value; + } + void set_rel1(std::size_t value) { + MARISA_DEBUG_IF(value > 64, MARISA_RANGE_ERROR); + rel_lo_ = (UInt32)((rel_lo_ & ~0x7FU) | (value & 0x7FU)); + } + void set_rel2(std::size_t value) { + MARISA_DEBUG_IF(value > 128, MARISA_RANGE_ERROR); + rel_lo_ = (UInt32)((rel_lo_ & ~(0xFFU << 7)) | ((value & 0xFFU) << 7)); + } + void set_rel3(std::size_t value) { + MARISA_DEBUG_IF(value > 192, MARISA_RANGE_ERROR); + rel_lo_ = (UInt32)((rel_lo_ & ~(0xFFU << 15)) | ((value & 0xFFU) << 15)); + } + void set_rel4(std::size_t value) { + MARISA_DEBUG_IF(value > 256, MARISA_RANGE_ERROR); + rel_lo_ = (UInt32)((rel_lo_ & ~(0x1FFU << 23)) | ((value & 0x1FFU) << 23)); + } + void set_rel5(std::size_t value) { + MARISA_DEBUG_IF(value > 320, MARISA_RANGE_ERROR); + rel_hi_ = (UInt32)((rel_hi_ & ~0x1FFU) | (value & 0x1FFU)); + } + void set_rel6(std::size_t value) { + MARISA_DEBUG_IF(value > 384, MARISA_RANGE_ERROR); + rel_hi_ = (UInt32)((rel_hi_ & ~(0x1FFU << 9)) | ((value & 0x1FFU) << 9)); + } + void set_rel7(std::size_t value) { + MARISA_DEBUG_IF(value > 448, MARISA_RANGE_ERROR); + rel_hi_ = (UInt32)((rel_hi_ & ~(0x1FFU << 18)) | ((value & 0x1FFU) << 18)); + } + + std::size_t abs() const { + return abs_; + } + std::size_t rel1() const { + return rel_lo_ & 0x7FU; + } + std::size_t rel2() const { + return (rel_lo_ >> 7) & 0xFFU; + } + std::size_t rel3() const { + return (rel_lo_ >> 15) & 0xFFU; + } + std::size_t rel4() const { + return (rel_lo_ >> 23) & 0x1FFU; + } + std::size_t rel5() const { + return rel_hi_ & 0x1FFU; + } + std::size_t rel6() const { + return (rel_hi_ >> 9) & 0x1FFU; + } + std::size_t rel7() const { + return (rel_hi_ >> 18) & 0x1FFU; + } + + private: + UInt32 abs_; + UInt32 rel_lo_; + UInt32 rel_hi_; +}; + +} // namespace vector +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_VECTOR_RANK_INDEX_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/vector.h b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/vector.h new file mode 100644 index 0000000000000000000000000000000000000000..2bfccdbd173a5b0019518f1d106daf41a8649be1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/grimoire/vector/vector.h @@ -0,0 +1,256 @@ +#ifndef MARISA_GRIMOIRE_VECTOR_VECTOR_H_ +#define MARISA_GRIMOIRE_VECTOR_VECTOR_H_ + +#include + +#include "marisa/grimoire/io.h" + +namespace marisa { +namespace grimoire { +namespace vector { + +template +class Vector { + public: + Vector() + : buf_(), objs_(NULL), const_objs_(NULL), + size_(0), capacity_(0), fixed_(false) {} + ~Vector() { + if (objs_ != NULL) { + for (std::size_t i = 0; i < size_; ++i) { + objs_[i].~T(); + } + } + } + + void map(Mapper &mapper) { + Vector temp; + temp.map_(mapper); + swap(temp); + } + + void read(Reader &reader) { + Vector temp; + temp.read_(reader); + swap(temp); + } + + void write(Writer &writer) const { + write_(writer); + } + + void push_back(const T &x) { + MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR); + MARISA_DEBUG_IF(size_ == max_size(), MARISA_SIZE_ERROR); + reserve(size_ + 1); + new (&objs_[size_]) T(x); + ++size_; + } + + void pop_back() { + MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR); + MARISA_DEBUG_IF(size_ == 0, MARISA_STATE_ERROR); + objs_[--size_].~T(); + } + + // resize() assumes that T's placement new does not throw an exception. + void resize(std::size_t size) { + MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR); + reserve(size); + for (std::size_t i = size_; i < size; ++i) { + new (&objs_[i]) T; + } + for (std::size_t i = size; i < size_; ++i) { + objs_[i].~T(); + } + size_ = size; + } + + // resize() assumes that T's placement new does not throw an exception. + void resize(std::size_t size, const T &x) { + MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR); + reserve(size); + for (std::size_t i = size_; i < size; ++i) { + new (&objs_[i]) T(x); + } + for (std::size_t i = size; i < size_; ++i) { + objs_[i].~T(); + } + size_ = size; + } + + void reserve(std::size_t capacity) { + MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR); + if (capacity <= capacity_) { + return; + } + MARISA_DEBUG_IF(capacity > max_size(), MARISA_SIZE_ERROR); + std::size_t new_capacity = capacity; + if (capacity_ > (capacity / 2)) { + if (capacity_ > (max_size() / 2)) { + new_capacity = max_size(); + } else { + new_capacity = capacity_ * 2; + } + } + realloc(new_capacity); + } + + void shrink() { + MARISA_THROW_IF(fixed_, MARISA_STATE_ERROR); + if (size_ != capacity_) { + realloc(size_); + } + } + + void fix() { + MARISA_THROW_IF(fixed_, MARISA_STATE_ERROR); + fixed_ = true; + } + + const T *begin() const { + return const_objs_; + } + const T *end() const { + return const_objs_ + size_; + } + const T &operator[](std::size_t i) const { + MARISA_DEBUG_IF(i >= size_, MARISA_BOUND_ERROR); + return const_objs_[i]; + } + const T &front() const { + MARISA_DEBUG_IF(size_ == 0, MARISA_STATE_ERROR); + return const_objs_[0]; + } + const T &back() const { + MARISA_DEBUG_IF(size_ == 0, MARISA_STATE_ERROR); + return const_objs_[size_ - 1]; + } + + T *begin() { + MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR); + return objs_; + } + T *end() { + MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR); + return objs_ + size_; + } + T &operator[](std::size_t i) { + MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR); + MARISA_DEBUG_IF(i >= size_, MARISA_BOUND_ERROR); + return objs_[i]; + } + T &front() { + MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR); + MARISA_DEBUG_IF(size_ == 0, MARISA_STATE_ERROR); + return objs_[0]; + } + T &back() { + MARISA_DEBUG_IF(fixed_, MARISA_STATE_ERROR); + MARISA_DEBUG_IF(size_ == 0, MARISA_STATE_ERROR); + return objs_[size_ - 1]; + } + + std::size_t size() const { + return size_; + } + std::size_t capacity() const { + return capacity_; + } + bool fixed() const { + return fixed_; + } + + bool empty() const { + return size_ == 0; + } + std::size_t total_size() const { + return sizeof(T) * size_; + } + std::size_t io_size() const { + return sizeof(UInt64) + ((total_size() + 7) & ~(std::size_t)0x07); + } + + void clear() { + Vector().swap(*this); + } + void swap(Vector &rhs) { + buf_.swap(rhs.buf_); + marisa::swap(objs_, rhs.objs_); + marisa::swap(const_objs_, rhs.const_objs_); + marisa::swap(size_, rhs.size_); + marisa::swap(capacity_, rhs.capacity_); + marisa::swap(fixed_, rhs.fixed_); + } + + static std::size_t max_size() { + return MARISA_SIZE_MAX / sizeof(T); + } + + private: + scoped_array buf_; + T *objs_; + const T *const_objs_; + std::size_t size_; + std::size_t capacity_; + bool fixed_; + + void map_(Mapper &mapper) { + UInt64 total_size; + mapper.map(&total_size); + MARISA_THROW_IF(total_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + MARISA_THROW_IF((total_size % sizeof(T)) != 0, MARISA_FORMAT_ERROR); + const std::size_t size = (std::size_t)(total_size / sizeof(T)); + mapper.map(&const_objs_, size); + mapper.seek((std::size_t)((8 - (total_size % 8)) % 8)); + size_ = size; + fix(); + } + void read_(Reader &reader) { + UInt64 total_size; + reader.read(&total_size); + MARISA_THROW_IF(total_size > MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + MARISA_THROW_IF((total_size % sizeof(T)) != 0, MARISA_FORMAT_ERROR); + const std::size_t size = (std::size_t)(total_size / sizeof(T)); + resize(size); + reader.read(objs_, size); + reader.seek((std::size_t)((8 - (total_size % 8)) % 8)); + } + void write_(Writer &writer) const { + writer.write((UInt64)total_size()); + writer.write(const_objs_, size_); + writer.seek((8 - (total_size() % 8)) % 8); + } + + // realloc() assumes that T's placement new does not throw an exception. + void realloc(std::size_t new_capacity) { + MARISA_DEBUG_IF(new_capacity > max_size(), MARISA_SIZE_ERROR); + + scoped_array new_buf( + new (std::nothrow) char[sizeof(T) * new_capacity]); + MARISA_DEBUG_IF(new_buf.get() == NULL, MARISA_MEMORY_ERROR); + T *new_objs = reinterpret_cast(new_buf.get()); + + for (std::size_t i = 0; i < size_; ++i) { + new (&new_objs[i]) T(objs_[i]); + } + for (std::size_t i = 0; i < size_; ++i) { + objs_[i].~T(); + } + + buf_.swap(new_buf); + objs_ = new_objs; + const_objs_ = new_objs; + capacity_ = new_capacity; + } + + // Disallows copy and assignment. + Vector(const Vector &); + Vector &operator=(const Vector &); +}; + +} // namespace vector +} // namespace grimoire +} // namespace marisa + +#endif // MARISA_GRIMOIRE_VECTOR_VECTOR_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/keyset.cc b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/keyset.cc new file mode 100644 index 0000000000000000000000000000000000000000..41354f7144d237a673cd4017ce8995c0eebb2ff3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/keyset.cc @@ -0,0 +1,181 @@ +#include + +#include "marisa/keyset.h" + +namespace marisa { + +Keyset::Keyset() + : base_blocks_(), base_blocks_size_(0), base_blocks_capacity_(0), + extra_blocks_(), extra_blocks_size_(0), extra_blocks_capacity_(0), + key_blocks_(), key_blocks_size_(0), key_blocks_capacity_(0), + ptr_(NULL), avail_(0), size_(0), total_length_(0) {} + +void Keyset::push_back(const Key &key) { + MARISA_DEBUG_IF(size_ == MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + + char * const key_ptr = reserve(key.length()); + for (std::size_t i = 0; i < key.length(); ++i) { + key_ptr[i] = key[i]; + } + + Key &new_key = key_blocks_[size_ / KEY_BLOCK_SIZE][size_ % KEY_BLOCK_SIZE]; + new_key.set_str(key_ptr, key.length()); + new_key.set_id(key.id()); + ++size_; + total_length_ += new_key.length(); +} + +void Keyset::push_back(const Key &key, char end_marker) { + MARISA_DEBUG_IF(size_ == MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + + if ((size_ / KEY_BLOCK_SIZE) == key_blocks_size_) { + append_key_block(); + } + + char * const key_ptr = reserve(key.length() + 1); + for (std::size_t i = 0; i < key.length(); ++i) { + key_ptr[i] = key[i]; + } + key_ptr[key.length()] = end_marker; + + Key &new_key = key_blocks_[size_ / KEY_BLOCK_SIZE][size_ % KEY_BLOCK_SIZE]; + new_key.set_str(key_ptr, key.length()); + new_key.set_id(key.id()); + ++size_; + total_length_ += new_key.length(); +} + +void Keyset::push_back(const char *str) { + MARISA_DEBUG_IF(size_ == MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + MARISA_THROW_IF(str == NULL, MARISA_NULL_ERROR); + + std::size_t length = 0; + while (str[length] != '\0') { + ++length; + } + push_back(str, length); +} + +void Keyset::push_back(const char *ptr, std::size_t length, float weight) { + MARISA_DEBUG_IF(size_ == MARISA_SIZE_MAX, MARISA_SIZE_ERROR); + MARISA_THROW_IF((ptr == NULL) && (length != 0), MARISA_NULL_ERROR); + MARISA_THROW_IF(length > MARISA_UINT32_MAX, MARISA_SIZE_ERROR); + + char * const key_ptr = reserve(length); + for (std::size_t i = 0; i < length; ++i) { + key_ptr[i] = ptr[i]; + } + + Key &key = key_blocks_[size_ / KEY_BLOCK_SIZE][size_ % KEY_BLOCK_SIZE]; + key.set_str(key_ptr, length); + key.set_weight(weight); + ++size_; + total_length_ += length; +} + +void Keyset::reset() { + base_blocks_size_ = 0; + extra_blocks_size_ = 0; + ptr_ = NULL; + avail_ = 0; + size_ = 0; + total_length_ = 0; +} + +void Keyset::clear() { + Keyset().swap(*this); +} + +void Keyset::swap(Keyset &rhs) { + base_blocks_.swap(rhs.base_blocks_); + marisa::swap(base_blocks_size_, rhs.base_blocks_size_); + marisa::swap(base_blocks_capacity_, rhs.base_blocks_capacity_); + extra_blocks_.swap(rhs.extra_blocks_); + marisa::swap(extra_blocks_size_, rhs.extra_blocks_size_); + marisa::swap(extra_blocks_capacity_, rhs.extra_blocks_capacity_); + key_blocks_.swap(rhs.key_blocks_); + marisa::swap(key_blocks_size_, rhs.key_blocks_size_); + marisa::swap(key_blocks_capacity_, rhs.key_blocks_capacity_); + marisa::swap(ptr_, rhs.ptr_); + marisa::swap(avail_, rhs.avail_); + marisa::swap(size_, rhs.size_); + marisa::swap(total_length_, rhs.total_length_); +} + +char *Keyset::reserve(std::size_t size) { + if ((size_ / KEY_BLOCK_SIZE) == key_blocks_size_) { + append_key_block(); + } + + if (size > EXTRA_BLOCK_SIZE) { + append_extra_block(size); + return extra_blocks_[extra_blocks_size_ - 1].get(); + } else { + if (size > avail_) { + append_base_block(); + } + ptr_ += size; + avail_ -= size; + return ptr_ - size; + } +} + +void Keyset::append_base_block() { + if (base_blocks_size_ == base_blocks_capacity_) { + const std::size_t new_capacity = + (base_blocks_size_ != 0) ? (base_blocks_size_ * 2) : 1; + scoped_array > new_blocks( + new (std::nothrow) scoped_array[new_capacity]); + MARISA_THROW_IF(new_blocks.get() == NULL, MARISA_MEMORY_ERROR); + for (std::size_t i = 0; i < base_blocks_size_; ++i) { + base_blocks_[i].swap(new_blocks[i]); + } + base_blocks_.swap(new_blocks); + base_blocks_capacity_ = new_capacity; + } + if (base_blocks_[base_blocks_size_].get() == NULL) { + scoped_array new_block(new (std::nothrow) char[BASE_BLOCK_SIZE]); + MARISA_THROW_IF(new_block.get() == NULL, MARISA_MEMORY_ERROR); + base_blocks_[base_blocks_size_].swap(new_block); + } + ptr_ = base_blocks_[base_blocks_size_++].get(); + avail_ = BASE_BLOCK_SIZE; +} + +void Keyset::append_extra_block(std::size_t size) { + if (extra_blocks_size_ == extra_blocks_capacity_) { + const std::size_t new_capacity = + (extra_blocks_size_ != 0) ? (extra_blocks_size_ * 2) : 1; + scoped_array > new_blocks( + new (std::nothrow) scoped_array[new_capacity]); + MARISA_THROW_IF(new_blocks.get() == NULL, MARISA_MEMORY_ERROR); + for (std::size_t i = 0; i < extra_blocks_size_; ++i) { + extra_blocks_[i].swap(new_blocks[i]); + } + extra_blocks_.swap(new_blocks); + extra_blocks_capacity_ = new_capacity; + } + scoped_array new_block(new (std::nothrow) char[size]); + MARISA_THROW_IF(new_block.get() == NULL, MARISA_MEMORY_ERROR); + extra_blocks_[extra_blocks_size_++].swap(new_block); +} + +void Keyset::append_key_block() { + if (key_blocks_size_ == key_blocks_capacity_) { + const std::size_t new_capacity = + (key_blocks_size_ != 0) ? (key_blocks_size_ * 2) : 1; + scoped_array > new_blocks( + new (std::nothrow) scoped_array[new_capacity]); + MARISA_THROW_IF(new_blocks.get() == NULL, MARISA_MEMORY_ERROR); + for (std::size_t i = 0; i < key_blocks_size_; ++i) { + key_blocks_[i].swap(new_blocks[i]); + } + key_blocks_.swap(new_blocks); + key_blocks_capacity_ = new_capacity; + } + scoped_array new_block(new (std::nothrow) Key[KEY_BLOCK_SIZE]); + MARISA_THROW_IF(new_block.get() == NULL, MARISA_MEMORY_ERROR); + key_blocks_[key_blocks_size_++].swap(new_block); +} + +} // namespace marisa diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/trie.cc b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/trie.cc new file mode 100644 index 0000000000000000000000000000000000000000..68050011cc175f8d683bcd93e7f04f9b53004d17 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/marisa-0.2.6/lib/marisa/trie.cc @@ -0,0 +1,249 @@ +#include "marisa/stdio.h" +#include "marisa/iostream.h" +#include "marisa/trie.h" +#include "marisa/grimoire/trie.h" + +namespace marisa { + +Trie::Trie() : trie_() {} + +Trie::~Trie() {} + +void Trie::build(Keyset &keyset, int config_flags) { + scoped_ptr temp(new (std::nothrow) grimoire::LoudsTrie); + MARISA_THROW_IF(temp.get() == NULL, MARISA_MEMORY_ERROR); + + temp->build(keyset, config_flags); + trie_.swap(temp); +} + +void Trie::mmap(const char *filename) { + MARISA_THROW_IF(filename == NULL, MARISA_NULL_ERROR); + + scoped_ptr temp(new (std::nothrow) grimoire::LoudsTrie); + MARISA_THROW_IF(temp.get() == NULL, MARISA_MEMORY_ERROR); + + grimoire::Mapper mapper; + mapper.open(filename); + temp->map(mapper); + trie_.swap(temp); +} + +void Trie::map(const void *ptr, std::size_t size) { + MARISA_THROW_IF((ptr == NULL) && (size != 0), MARISA_NULL_ERROR); + + scoped_ptr temp(new (std::nothrow) grimoire::LoudsTrie); + MARISA_THROW_IF(temp.get() == NULL, MARISA_MEMORY_ERROR); + + grimoire::Mapper mapper; + mapper.open(ptr, size); + temp->map(mapper); + trie_.swap(temp); +} + +void Trie::load(const char *filename) { + MARISA_THROW_IF(filename == NULL, MARISA_NULL_ERROR); + + scoped_ptr temp(new (std::nothrow) grimoire::LoudsTrie); + MARISA_THROW_IF(temp.get() == NULL, MARISA_MEMORY_ERROR); + + grimoire::Reader reader; + reader.open(filename); + temp->read(reader); + trie_.swap(temp); +} + +void Trie::read(int fd) { + MARISA_THROW_IF(fd == -1, MARISA_CODE_ERROR); + + scoped_ptr temp(new (std::nothrow) grimoire::LoudsTrie); + MARISA_THROW_IF(temp.get() == NULL, MARISA_MEMORY_ERROR); + + grimoire::Reader reader; + reader.open(fd); + temp->read(reader); + trie_.swap(temp); +} + +void Trie::save(const char *filename) const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + MARISA_THROW_IF(filename == NULL, MARISA_NULL_ERROR); + + grimoire::Writer writer; + writer.open(filename); + trie_->write(writer); +} + +void Trie::write(int fd) const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + MARISA_THROW_IF(fd == -1, MARISA_CODE_ERROR); + + grimoire::Writer writer; + writer.open(fd); + trie_->write(writer); +} + +bool Trie::lookup(Agent &agent) const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + if (!agent.has_state()) { + agent.init_state(); + } + return trie_->lookup(agent); +} + +void Trie::reverse_lookup(Agent &agent) const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + if (!agent.has_state()) { + agent.init_state(); + } + trie_->reverse_lookup(agent); +} + +bool Trie::common_prefix_search(Agent &agent) const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + if (!agent.has_state()) { + agent.init_state(); + } + return trie_->common_prefix_search(agent); +} + +bool Trie::predictive_search(Agent &agent) const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + if (!agent.has_state()) { + agent.init_state(); + } + return trie_->predictive_search(agent); +} + +std::size_t Trie::num_tries() const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + return trie_->num_tries(); +} + +std::size_t Trie::num_keys() const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + return trie_->num_keys(); +} + +std::size_t Trie::num_nodes() const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + return trie_->num_nodes(); +} + +TailMode Trie::tail_mode() const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + return trie_->tail_mode(); +} + +NodeOrder Trie::node_order() const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + return trie_->node_order(); +} + +bool Trie::empty() const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + return trie_->empty(); +} + +std::size_t Trie::size() const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + return trie_->size(); +} + +std::size_t Trie::total_size() const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + return trie_->total_size(); +} + +std::size_t Trie::io_size() const { + MARISA_THROW_IF(trie_.get() == NULL, MARISA_STATE_ERROR); + return trie_->io_size(); +} + +void Trie::clear() { + Trie().swap(*this); +} + +void Trie::swap(Trie &rhs) { + trie_.swap(rhs.trie_); +} + +} // namespace marisa + +#include + +namespace marisa { + +class TrieIO { + public: + static void fread(std::FILE *file, Trie *trie) { + MARISA_THROW_IF(trie == NULL, MARISA_NULL_ERROR); + + scoped_ptr temp( + new (std::nothrow) grimoire::LoudsTrie); + MARISA_THROW_IF(temp.get() == NULL, MARISA_MEMORY_ERROR); + + grimoire::Reader reader; + reader.open(file); + temp->read(reader); + trie->trie_.swap(temp); + } + static void fwrite(std::FILE *file, const Trie &trie) { + MARISA_THROW_IF(file == NULL, MARISA_NULL_ERROR); + MARISA_THROW_IF(trie.trie_.get() == NULL, MARISA_STATE_ERROR); + grimoire::Writer writer; + writer.open(file); + trie.trie_->write(writer); + } + + static std::istream &read(std::istream &stream, Trie *trie) { + MARISA_THROW_IF(trie == NULL, MARISA_NULL_ERROR); + + scoped_ptr temp( + new (std::nothrow) grimoire::LoudsTrie); + MARISA_THROW_IF(temp.get() == NULL, MARISA_MEMORY_ERROR); + + grimoire::Reader reader; + reader.open(stream); + temp->read(reader); + trie->trie_.swap(temp); + return stream; + } + static std::ostream &write(std::ostream &stream, const Trie &trie) { + MARISA_THROW_IF(trie.trie_.get() == NULL, MARISA_STATE_ERROR); + grimoire::Writer writer; + writer.open(stream); + trie.trie_->write(writer); + return stream; + } +}; + +void fread(std::FILE *file, Trie *trie) { + MARISA_THROW_IF(file == NULL, MARISA_NULL_ERROR); + MARISA_THROW_IF(trie == NULL, MARISA_NULL_ERROR); + TrieIO::fread(file, trie); +} + +void fwrite(std::FILE *file, const Trie &trie) { + MARISA_THROW_IF(file == NULL, MARISA_NULL_ERROR); + TrieIO::fwrite(file, trie); +} + +std::istream &read(std::istream &stream, Trie *trie) { + MARISA_THROW_IF(trie == NULL, MARISA_NULL_ERROR); + return TrieIO::read(stream, trie); +} + +std::ostream &write(std::ostream &stream, const Trie &trie) { + return TrieIO::write(stream, trie); +} + +std::istream &operator>>(std::istream &stream, Trie &trie) { + return read(stream, &trie); +} + +std::ostream &operator<<(std::ostream &stream, const Trie &trie) { + return write(stream, trie); +} + +} // namespace marisa diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.appveyor.yml b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.appveyor.yml new file mode 100644 index 0000000000000000000000000000000000000000..8fbb726108f2a3e7c24075d17c49beb1110474d6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.appveyor.yml @@ -0,0 +1,70 @@ +version: 1.0.{build} +image: +- Visual Studio 2017 +- Visual Studio 2015 +test: off +skip_branch_with_pr: true +build: + parallel: true +platform: +- x64 +- x86 +environment: + matrix: + - PYTHON: 36 + CPP: 14 + CONFIG: Debug + - PYTHON: 27 + CPP: 14 + CONFIG: Debug + - CONDA: 36 + CPP: latest + CONFIG: Release +matrix: + exclude: + - image: Visual Studio 2015 + platform: x86 + - image: Visual Studio 2015 + CPP: latest + - image: Visual Studio 2017 + CPP: latest + platform: x86 +install: +- ps: | + if ($env:PLATFORM -eq "x64") { $env:CMAKE_ARCH = "x64" } + if ($env:APPVEYOR_JOB_NAME -like "*Visual Studio 2017*") { + $env:CMAKE_GENERATOR = "Visual Studio 15 2017" + $env:CMAKE_INCLUDE_PATH = "C:\Libraries\boost_1_64_0" + $env:CXXFLAGS = "-permissive-" + } else { + $env:CMAKE_GENERATOR = "Visual Studio 14 2015" + } + if ($env:PYTHON) { + if ($env:PLATFORM -eq "x64") { $env:PYTHON = "$env:PYTHON-x64" } + $env:PATH = "C:\Python$env:PYTHON\;C:\Python$env:PYTHON\Scripts\;$env:PATH" + python -W ignore -m pip install --upgrade pip wheel + python -W ignore -m pip install pytest numpy --no-warn-script-location + } elseif ($env:CONDA) { + if ($env:CONDA -eq "27") { $env:CONDA = "" } + if ($env:PLATFORM -eq "x64") { $env:CONDA = "$env:CONDA-x64" } + $env:PATH = "C:\Miniconda$env:CONDA\;C:\Miniconda$env:CONDA\Scripts\;$env:PATH" + $env:PYTHONHOME = "C:\Miniconda$env:CONDA" + conda --version + conda install -y -q pytest numpy scipy + } +- ps: | + Start-FileDownload 'http://bitbucket.org/eigen/eigen/get/3.3.3.zip' + 7z x 3.3.3.zip -y > $null + $env:CMAKE_INCLUDE_PATH = "eigen-eigen-67e894c6cd8f;$env:CMAKE_INCLUDE_PATH" +build_script: +- cmake -G "%CMAKE_GENERATOR%" -A "%CMAKE_ARCH%" + -DPYBIND11_CPP_STANDARD=/std:c++%CPP% + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DCMAKE_SUPPRESS_REGENERATION=1 + . +- set MSBuildLogger="C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" +- cmake --build . --config %CONFIG% --target pytest -- /m /v:m /logger:%MSBuildLogger% +- cmake --build . --config %CONFIG% --target cpptest -- /m /v:m /logger:%MSBuildLogger% +- if "%CPP%"=="latest" (cmake --build . --config %CONFIG% --target test_cmake_build -- /m /v:m /logger:%MSBuildLogger%) +on_failure: if exist "tests\test_cmake_build" type tests\test_cmake_build\*.log* diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.gitignore b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..979fd4431bfa1f5f36bc245d0805867f76495a2d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.gitignore @@ -0,0 +1,38 @@ +CMakeCache.txt +CMakeFiles +Makefile +cmake_install.cmake +.DS_Store +*.so +*.pyd +*.dll +*.sln +*.sdf +*.opensdf +*.vcxproj +*.filters +example.dir +Win32 +x64 +Release +Debug +.vs +CTestTestfile.cmake +Testing +autogen +MANIFEST +/.ninja_* +/*.ninja +/docs/.build +*.py[co] +*.egg-info +*~ +.*.swp +.DS_Store +/dist +/build +/cmake/ +.cache/ +sosize-*.txt +pybind11Config*.cmake +pybind11Targets.cmake diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.gitmodules b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..d063a8e89ddf5b923112a97fa09bf171636c2bd4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tools/clang"] + path = tools/clang + url = ../../wjakob/clang-cindex-python3 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.readthedocs.yml b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.readthedocs.yml new file mode 100644 index 0000000000000000000000000000000000000000..c9c61617ca9b13a3e31d33226c52ba9529872a0d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.readthedocs.yml @@ -0,0 +1,3 @@ +python: + version: 3 +requirements_file: docs/requirements.txt diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.travis.yml b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..d81cd8c7b812387ede562636269ce6d07e25d795 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/.travis.yml @@ -0,0 +1,306 @@ +language: cpp +matrix: + include: + # This config does a few things: + # - Checks C++ and Python code styles (check-style.sh and flake8). + # - Makes sure sphinx can build the docs without any errors or warnings. + # - Tests setup.py sdist and install (all header files should be present). + # - Makes sure that everything still works without optional deps (numpy/scipy/eigen) and + # also tests the automatic discovery functions in CMake (Python version, C++ standard). + - os: linux + dist: xenial # Necessary to run doxygen 1.8.15 + name: Style, docs, and pip + cache: false + before_install: + - pyenv global $(pyenv whence 2to3) # activate all python versions + - PY_CMD=python3 + - $PY_CMD -m pip install --user --upgrade pip wheel setuptools + install: + # breathe 4.14 doesn't work with bit fields. See https://github.com/michaeljones/breathe/issues/462 + - $PY_CMD -m pip install --user --upgrade sphinx sphinx_rtd_theme breathe==4.13.1 flake8 pep8-naming pytest + - curl -fsSL https://sourceforge.net/projects/doxygen/files/rel-1.8.15/doxygen-1.8.15.linux.bin.tar.gz/download | tar xz + - export PATH="$PWD/doxygen-1.8.15/bin:$PATH" + script: + - tools/check-style.sh + - flake8 + - $PY_CMD -m sphinx -W -b html docs docs/.build + - | + # Make sure setup.py distributes and installs all the headers + $PY_CMD setup.py sdist + $PY_CMD -m pip install --user -U ./dist/* + installed=$($PY_CMD -c "import pybind11; print(pybind11.get_include(True) + '/pybind11')") + diff -rq $installed ./include/pybind11 + - | + # Barebones build + cmake -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(which $PY_CMD) . + make pytest -j 2 && make cpptest -j 2 + # The following are regular test configurations, including optional dependencies. + # With regard to each other they differ in Python version, C++ standard and compiler. + - os: linux + dist: trusty + name: Python 2.7, c++11, gcc 4.8 + env: PYTHON=2.7 CPP=11 GCC=4.8 + addons: + apt: + packages: + - cmake=2.\* + - cmake-data=2.\* + - os: linux + dist: trusty + name: Python 3.6, c++11, gcc 4.8 + env: PYTHON=3.6 CPP=11 GCC=4.8 + addons: + apt: + sources: + - deadsnakes + packages: + - python3.6-dev + - python3.6-venv + - cmake=2.\* + - cmake-data=2.\* + - os: linux + dist: trusty + env: PYTHON=2.7 CPP=14 GCC=6 CMAKE=1 + name: Python 2.7, c++14, gcc 6, CMake test + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + - os: linux + dist: trusty + name: Python 3.5, c++14, gcc 6, Debug build + # N.B. `ensurepip` could be installed transitively by `python3.5-venv`, but + # seems to have apt conflicts (at least for Trusty). Use Docker instead. + services: docker + env: DOCKER=debian:stretch PYTHON=3.5 CPP=14 GCC=6 DEBUG=1 + - os: linux + dist: xenial + env: PYTHON=3.6 CPP=17 GCC=7 + name: Python 3.6, c++17, gcc 7 + addons: + apt: + sources: + - deadsnakes + - ubuntu-toolchain-r-test + packages: + - g++-7 + - python3.6-dev + - python3.6-venv + - os: linux + dist: xenial + env: PYTHON=3.6 CPP=17 CLANG=7 + name: Python 3.6, c++17, Clang 7 + addons: + apt: + sources: + - deadsnakes + - llvm-toolchain-xenial-7 + packages: + - python3.6-dev + - python3.6-venv + - clang-7 + - libclang-7-dev + - llvm-7-dev + - lld-7 + - libc++-7-dev + - libc++abi-7-dev # Why is this necessary??? + - os: linux + dist: xenial + env: PYTHON=3.8 CPP=17 GCC=7 + name: Python 3.8, c++17, gcc 7 (w/o numpy/scipy) # TODO: update build name when the numpy/scipy wheels become available + addons: + apt: + sources: + - deadsnakes + - ubuntu-toolchain-r-test + packages: + - g++-7 + - python3.8-dev + - python3.8-venv + # Currently there is no numpy/scipy wheels available for python3.8 + # TODO: remove next before_install, install and script clause when the wheels become available + before_install: + - pyenv global $(pyenv whence 2to3) # activate all python versions + - PY_CMD=python3 + - $PY_CMD -m pip install --user --upgrade pip wheel setuptools + install: + - $PY_CMD -m pip install --user --upgrade pytest + script: + - | + # Barebones build + cmake -DCMAKE_BUILD_TYPE=Debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(which $PY_CMD) . + make pytest -j 2 && make cpptest -j 2 + - os: osx + name: Python 2.7, c++14, AppleClang 7.3, CMake test + osx_image: xcode7.3 + env: PYTHON=2.7 CPP=14 CLANG CMAKE=1 + - os: osx + name: Python 3.7, c++14, AppleClang 9, Debug build + osx_image: xcode9.4 + env: PYTHON=3.7 CPP=14 CLANG DEBUG=1 + # Test a PyPy 2.7 build + - os: linux + dist: trusty + env: PYPY=5.8 PYTHON=2.7 CPP=11 GCC=4.8 + name: PyPy 5.8, Python 2.7, c++11, gcc 4.8 + addons: + apt: + packages: + - libblas-dev + - liblapack-dev + - gfortran + # Build in 32-bit mode and tests against the CMake-installed version + - os: linux + dist: trusty + services: docker + env: DOCKER=i386/debian:stretch PYTHON=3.5 CPP=14 GCC=6 INSTALL=1 + name: Python 3.5, c++14, gcc 6, 32-bit + script: + - | + # Consolidated 32-bit Docker Build + Install + set -ex + $SCRIPT_RUN_PREFIX sh -c " + set -ex + cmake ${CMAKE_EXTRA_ARGS} -DPYBIND11_INSTALL=1 -DPYBIND11_TEST=0 . + make install + cp -a tests /pybind11-tests + mkdir /build-tests && cd /build-tests + cmake ../pybind11-tests ${CMAKE_EXTRA_ARGS} -DPYBIND11_WERROR=ON + make pytest -j 2" + set +ex +cache: + directories: + - $HOME/.local/bin + - $HOME/.local/lib + - $HOME/.local/include + - $HOME/Library/Python +before_install: +- | + # Configure build variables + set -ex + if [ "$TRAVIS_OS_NAME" = "linux" ]; then + if [ -n "$CLANG" ]; then + export CXX=clang++-$CLANG CC=clang-$CLANG + EXTRA_PACKAGES+=" clang-$CLANG llvm-$CLANG-dev" + else + if [ -z "$GCC" ]; then GCC=4.8 + else EXTRA_PACKAGES+=" g++-$GCC" + fi + export CXX=g++-$GCC CC=gcc-$GCC + fi + elif [ "$TRAVIS_OS_NAME" = "osx" ]; then + export CXX=clang++ CC=clang; + fi + if [ -n "$CPP" ]; then CPP=-std=c++$CPP; fi + if [ "${PYTHON:0:1}" = "3" ]; then PY=3; fi + if [ -n "$DEBUG" ]; then CMAKE_EXTRA_ARGS+=" -DCMAKE_BUILD_TYPE=Debug"; fi + set +ex +- | + # Initialize environment + set -ex + if [ -n "$DOCKER" ]; then + docker pull $DOCKER + + containerid=$(docker run --detach --tty \ + --volume="$PWD":/pybind11 --workdir=/pybind11 \ + --env="CC=$CC" --env="CXX=$CXX" --env="DEBIAN_FRONTEND=$DEBIAN_FRONTEND" \ + --env=GCC_COLORS=\ \ + $DOCKER) + SCRIPT_RUN_PREFIX="docker exec --tty $containerid" + $SCRIPT_RUN_PREFIX sh -c 'for s in 0 15; do sleep $s; apt-get update && apt-get -qy dist-upgrade && break; done' + else + if [ "$PYPY" = "5.8" ]; then + curl -fSL https://bitbucket.org/pypy/pypy/downloads/pypy2-v5.8.0-linux64.tar.bz2 | tar xj + PY_CMD=$(echo `pwd`/pypy2-v5.8.0-linux64/bin/pypy) + CMAKE_EXTRA_ARGS+=" -DPYTHON_EXECUTABLE:FILEPATH=$PY_CMD" + else + PY_CMD=python$PYTHON + if [ "$TRAVIS_OS_NAME" = "osx" ]; then + if [ "$PY" = "3" ]; then + brew update && brew unlink python@2 && brew upgrade python + else + curl -fsSL https://bootstrap.pypa.io/get-pip.py | $PY_CMD - --user + fi + fi + fi + if [ "$PY" = 3 ] || [ -n "$PYPY" ]; then + $PY_CMD -m ensurepip --user + fi + $PY_CMD --version + $PY_CMD -m pip install --user --upgrade pip wheel + fi + set +ex +install: +- | + # Install dependencies + set -ex + cmake --version + if [ -n "$DOCKER" ]; then + if [ -n "$DEBUG" ]; then + PY_DEBUG="python$PYTHON-dbg python$PY-scipy-dbg" + CMAKE_EXTRA_ARGS+=" -DPYTHON_EXECUTABLE=/usr/bin/python${PYTHON}dm" + fi + $SCRIPT_RUN_PREFIX sh -c "for s in 0 15; do sleep \$s; \ + apt-get -qy --no-install-recommends install \ + $PY_DEBUG python$PYTHON-dev python$PY-pytest python$PY-scipy \ + libeigen3-dev libboost-dev cmake make ${EXTRA_PACKAGES} && break; done" + else + + if [ "$CLANG" = "7" ]; then + export CXXFLAGS="-stdlib=libc++" + fi + + export NPY_NUM_BUILD_JOBS=2 + echo "Installing pytest, numpy, scipy..." + local PIP_CMD="" + if [ -n $PYPY ]; then + # For expediency, install only versions that are available on the extra index. + travis_wait 30 \ + $PY_CMD -m pip install --user --upgrade --extra-index-url https://imaginary.ca/trusty-pypi \ + pytest numpy==1.15.4 scipy==1.2.0 + else + $PY_CMD -m pip install --user --upgrade pytest numpy scipy + fi + echo "done." + + mkdir eigen + curl -fsSL https://bitbucket.org/eigen/eigen/get/3.3.4.tar.bz2 | \ + tar --extract -j --directory=eigen --strip-components=1 + export CMAKE_INCLUDE_PATH="${CMAKE_INCLUDE_PATH:+$CMAKE_INCLUDE_PATH:}$PWD/eigen" + fi + set +ex +script: +- | + # CMake Configuration + set -ex + $SCRIPT_RUN_PREFIX cmake ${CMAKE_EXTRA_ARGS} \ + -DPYBIND11_PYTHON_VERSION=$PYTHON \ + -DPYBIND11_CPP_STANDARD=$CPP \ + -DPYBIND11_WERROR=${WERROR:-ON} \ + -DDOWNLOAD_CATCH=${DOWNLOAD_CATCH:-ON} \ + . + set +ex +- | + # pytest + set -ex + $SCRIPT_RUN_PREFIX make pytest -j 2 VERBOSE=1 + set +ex +- | + # cpptest + set -ex + $SCRIPT_RUN_PREFIX make cpptest -j 2 + set +ex +- | + # CMake Build Interface + set -ex + if [ -n "$CMAKE" ]; then $SCRIPT_RUN_PREFIX make test_cmake_build; fi + set +ex +after_failure: cat tests/test_cmake_build/*.log* +after_script: +- | + # Cleanup (Docker) + set -ex + if [ -n "$DOCKER" ]; then docker stop "$containerid"; docker rm "$containerid"; fi + set +ex diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..85ecd9028f31fa45ecb28bf32fe4ebce97aa8aa1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/CMakeLists.txt @@ -0,0 +1,157 @@ +# CMakeLists.txt -- Build system for the pybind11 modules +# +# Copyright (c) 2015 Wenzel Jakob +# +# All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +cmake_minimum_required(VERSION 2.8.12) + +if (POLICY CMP0048) + # cmake warns if loaded from a min-3.0-required parent dir, so silence the warning: + cmake_policy(SET CMP0048 NEW) +endif() + +# CMake versions < 3.4.0 do not support try_compile/pthread checks without C as active language. +if(CMAKE_VERSION VERSION_LESS 3.4.0) + project(pybind11) +else() + project(pybind11 CXX) +endif() + +# Check if pybind11 is being used directly or via add_subdirectory +set(PYBIND11_MASTER_PROJECT OFF) +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(PYBIND11_MASTER_PROJECT ON) +endif() + +option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT}) +option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT}) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/tools") + +include(pybind11Tools) + +# Cache variables so pybind11_add_module can be used in parent projects +set(PYBIND11_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/include" CACHE INTERNAL "") +set(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS} CACHE INTERNAL "") +set(PYTHON_LIBRARIES ${PYTHON_LIBRARIES} CACHE INTERNAL "") +set(PYTHON_MODULE_PREFIX ${PYTHON_MODULE_PREFIX} CACHE INTERNAL "") +set(PYTHON_MODULE_EXTENSION ${PYTHON_MODULE_EXTENSION} CACHE INTERNAL "") +set(PYTHON_VERSION_MAJOR ${PYTHON_VERSION_MAJOR} CACHE INTERNAL "") +set(PYTHON_VERSION_MINOR ${PYTHON_VERSION_MINOR} CACHE INTERNAL "") + +# NB: when adding a header don't forget to also add it to setup.py +set(PYBIND11_HEADERS + include/pybind11/detail/class.h + include/pybind11/detail/common.h + include/pybind11/detail/descr.h + include/pybind11/detail/init.h + include/pybind11/detail/internals.h + include/pybind11/detail/typeid.h + include/pybind11/attr.h + include/pybind11/buffer_info.h + include/pybind11/cast.h + include/pybind11/chrono.h + include/pybind11/common.h + include/pybind11/complex.h + include/pybind11/options.h + include/pybind11/eigen.h + include/pybind11/embed.h + include/pybind11/eval.h + include/pybind11/functional.h + include/pybind11/numpy.h + include/pybind11/operators.h + include/pybind11/pybind11.h + include/pybind11/pytypes.h + include/pybind11/stl.h + include/pybind11/stl_bind.h +) +string(REPLACE "include/" "${CMAKE_CURRENT_SOURCE_DIR}/include/" + PYBIND11_HEADERS "${PYBIND11_HEADERS}") + +if (PYBIND11_TEST) + add_subdirectory(tests) +endif() + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +# extract project version from source +file(STRINGS "${PYBIND11_INCLUDE_DIR}/pybind11/detail/common.h" pybind11_version_defines + REGEX "#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) ") +foreach(ver ${pybind11_version_defines}) + if (ver MATCHES "#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$") + set(PYBIND11_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "") + endif() +endforeach() +set(${PROJECT_NAME}_VERSION ${PYBIND11_VERSION_MAJOR}.${PYBIND11_VERSION_MINOR}.${PYBIND11_VERSION_PATCH}) +message(STATUS "pybind11 v${${PROJECT_NAME}_VERSION}") + +option (USE_PYTHON_INCLUDE_DIR "Install pybind11 headers in Python include directory instead of default installation prefix" OFF) +if (USE_PYTHON_INCLUDE_DIR) + file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${PYTHON_INCLUDE_DIRS}) +endif() + +if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) # CMake >= 3.0 + # Build an interface library target: + add_library(pybind11 INTERFACE) + add_library(pybind11::pybind11 ALIAS pybind11) # to match exported target + target_include_directories(pybind11 INTERFACE $ + $ + $) + target_compile_options(pybind11 INTERFACE $) + + add_library(module INTERFACE) + add_library(pybind11::module ALIAS module) + if(NOT MSVC) + target_compile_options(module INTERFACE -fvisibility=hidden) + endif() + target_link_libraries(module INTERFACE pybind11::pybind11) + if(WIN32 OR CYGWIN) + target_link_libraries(module INTERFACE $) + elseif(APPLE) + target_link_libraries(module INTERFACE "-undefined dynamic_lookup") + endif() + + add_library(embed INTERFACE) + add_library(pybind11::embed ALIAS embed) + target_link_libraries(embed INTERFACE pybind11::pybind11 $) +endif() + +if (PYBIND11_INSTALL) + install(DIRECTORY ${PYBIND11_INCLUDE_DIR}/pybind11 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + # GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share". + set(PYBIND11_CMAKECONFIG_INSTALL_DIR "share/cmake/${PROJECT_NAME}" CACHE STRING "install path for pybind11Config.cmake") + + configure_package_config_file(tools/${PROJECT_NAME}Config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) + # Remove CMAKE_SIZEOF_VOID_P from ConfigVersion.cmake since the library does + # not depend on architecture specific settings or libraries. + set(_PYBIND11_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) + unset(CMAKE_SIZEOF_VOID_P) + write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + VERSION ${${PROJECT_NAME}_VERSION} + COMPATIBILITY AnyNewerVersion) + set(CMAKE_SIZEOF_VOID_P ${_PYBIND11_CMAKE_SIZEOF_VOID_P}) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + tools/FindPythonLibsNew.cmake + tools/pybind11Tools.cmake + DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) + + if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) + if(NOT PYBIND11_EXPORT_NAME) + set(PYBIND11_EXPORT_NAME "${PROJECT_NAME}Targets") + endif() + + install(TARGETS pybind11 module embed + EXPORT "${PYBIND11_EXPORT_NAME}") + if(PYBIND11_MASTER_PROJECT) + install(EXPORT "${PYBIND11_EXPORT_NAME}" + NAMESPACE "${PROJECT_NAME}::" + DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) + endif() + endif() +endif() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/CONTRIBUTING.md b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..01596d94f3aba5b125a4d5a9f029f3d0086654aa --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/CONTRIBUTING.md @@ -0,0 +1,49 @@ +Thank you for your interest in this project! Please refer to the following +sections on how to contribute code and bug reports. + +### Reporting bugs + +At the moment, this project is run in the spare time of a single person +([Wenzel Jakob](http://rgl.epfl.ch/people/wjakob)) with very limited resources +for issue tracker tickets. Thus, before submitting a question or bug report, +please take a moment of your time and ensure that your issue isn't already +discussed in the project documentation provided at +[http://pybind11.readthedocs.org/en/latest](http://pybind11.readthedocs.org/en/latest). + +Assuming that you have identified a previously unknown problem or an important +question, it's essential that you submit a self-contained and minimal piece of +code that reproduces the problem. In other words: no external dependencies, +isolate the function(s) that cause breakage, submit matched and complete C++ +and Python snippets that can be easily compiled and run on my end. + +## Pull requests +Contributions are submitted, reviewed, and accepted using Github pull requests. +Please refer to [this +article](https://help.github.com/articles/using-pull-requests) for details and +adhere to the following rules to make the process as smooth as possible: + +* Make a new branch for every feature you're working on. +* Make small and clean pull requests that are easy to review but make sure they + do add value by themselves. +* Add tests for any new functionality and run the test suite (``make pytest``) + to ensure that no existing features break. +* Please run ``flake8`` and ``tools/check-style.sh`` to check your code matches + the project style. (Note that ``check-style.sh`` requires ``gawk``.) +* This project has a strong focus on providing general solutions using a + minimal amount of code, thus small pull requests are greatly preferred. + +### Licensing of contributions + +pybind11 is provided under a BSD-style license that can be found in the +``LICENSE`` file. By using, distributing, or contributing to this project, you +agree to the terms and conditions of this license. + +You are under no obligation whatsoever to provide any bug fixes, patches, or +upgrades to the features, functionality or performance of the source code +("Enhancements") to anyone; however, if you choose to make your Enhancements +available either publicly, or directly to the author of this software, without +imposing a separate written license agreement for such Enhancements, then you +hereby grant the following license: a non-exclusive, royalty-free perpetual +license to install, use, modify, prepare derivative works, incorporate into +other computer software, distribute, and sublicense such enhancements or +derivative works thereof, in binary and source code form. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/ISSUE_TEMPLATE.md b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000000000000000000000000000000000..75df39981ad2dc14ba50d00a078d7161f2bb2349 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/ISSUE_TEMPLATE.md @@ -0,0 +1,17 @@ +Make sure you've completed the following steps before submitting your issue -- thank you! + +1. Check if your question has already been answered in the [FAQ](http://pybind11.readthedocs.io/en/latest/faq.html) section. +2. Make sure you've read the [documentation](http://pybind11.readthedocs.io/en/latest/). Your issue may be addressed there. +3. If those resources didn't help and you only have a short question (not a bug report), consider asking in the [Gitter chat room](https://gitter.im/pybind/Lobby). +4. If you have a genuine bug report or a more complex question which is not answered in the previous items (or not suitable for chat), please fill in the details below. +5. Include a self-contained and minimal piece of code that reproduces the problem. If that's not possible, try to make the description as clear as possible. + +*After reading, remove this checklist and the template text in parentheses below.* + +## Issue description + +(Provide a short description, state the expected behavior and what actually happens.) + +## Reproducible example code + +(The code should be minimal, have no external dependencies, isolate the function(s) that cause breakage. Submit matched and complete C++ and Python snippets that can be easily compiled and run to diagnose the issue.) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/LICENSE b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..6f15578cc4044061e01305227eaefb3dc49f4e11 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2016 Wenzel Jakob , All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Please also refer to the file CONTRIBUTING.md, which clarifies licensing of +external contributions to this project including patches, pull requests, etc. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/MANIFEST.in b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/MANIFEST.in new file mode 100644 index 0000000000000000000000000000000000000000..6e57baeeef3e935b40f0f2ad5e638b58fd98db0b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/MANIFEST.in @@ -0,0 +1,2 @@ +recursive-include include/pybind11 *.h +include LICENSE README.md CONTRIBUTING.md diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/README.md b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/README.md new file mode 100644 index 0000000000000000000000000000000000000000..35d2d76ff98d7b9a9df7e74be3b583581da4182a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/README.md @@ -0,0 +1,129 @@ +![pybind11 logo](https://github.com/pybind/pybind11/raw/master/docs/pybind11-logo.png) + +# pybind11 — Seamless operability between C++11 and Python + +[![Documentation Status](https://readthedocs.org/projects/pybind11/badge/?version=master)](http://pybind11.readthedocs.org/en/master/?badge=master) +[![Documentation Status](https://readthedocs.org/projects/pybind11/badge/?version=stable)](http://pybind11.readthedocs.org/en/stable/?badge=stable) +[![Gitter chat](https://img.shields.io/gitter/room/gitterHQ/gitter.svg)](https://gitter.im/pybind/Lobby) +[![Build Status](https://travis-ci.org/pybind/pybind11.svg?branch=master)](https://travis-ci.org/pybind/pybind11) +[![Build status](https://ci.appveyor.com/api/projects/status/riaj54pn4h08xy40?svg=true)](https://ci.appveyor.com/project/wjakob/pybind11) + +**pybind11** is a lightweight header-only library that exposes C++ types in Python +and vice versa, mainly to create Python bindings of existing C++ code. Its +goals and syntax are similar to the excellent +[Boost.Python](http://www.boost.org/doc/libs/1_58_0/libs/python/doc/) library +by David Abrahams: to minimize boilerplate code in traditional extension +modules by inferring type information using compile-time introspection. + +The main issue with Boost.Python—and the reason for creating such a similar +project—is Boost. Boost is an enormously large and complex suite of utility +libraries that works with almost every C++ compiler in existence. This +compatibility has its cost: arcane template tricks and workarounds are +necessary to support the oldest and buggiest of compiler specimens. Now that +C++11-compatible compilers are widely available, this heavy machinery has +become an excessively large and unnecessary dependency. + +Think of this library as a tiny self-contained version of Boost.Python with +everything stripped away that isn't relevant for binding generation. Without +comments, the core header files only require ~4K lines of code and depend on +Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This +compact implementation was possible thanks to some of the new C++11 language +features (specifically: tuples, lambda functions and variadic templates). Since +its creation, this library has grown beyond Boost.Python in many ways, leading +to dramatically simpler binding code in many common situations. + +Tutorial and reference documentation is provided at +[http://pybind11.readthedocs.org/en/master](http://pybind11.readthedocs.org/en/master). +A PDF version of the manual is available +[here](https://media.readthedocs.org/pdf/pybind11/master/pybind11.pdf). + +## Core features +pybind11 can map the following core C++ features to Python + +- Functions accepting and returning custom data structures per value, reference, or pointer +- Instance methods and static methods +- Overloaded functions +- Instance attributes and static attributes +- Arbitrary exception types +- Enumerations +- Callbacks +- Iterators and ranges +- Custom operators +- Single and multiple inheritance +- STL data structures +- Smart pointers with reference counting like ``std::shared_ptr`` +- Internal references with correct reference counting +- C++ classes with virtual (and pure virtual) methods can be extended in Python + +## Goodies +In addition to the core functionality, pybind11 provides some extra goodies: + +- Python 2.7, 3.x, and PyPy (PyPy2.7 >= 5.7) are supported with an + implementation-agnostic interface. + +- It is possible to bind C++11 lambda functions with captured variables. The + lambda capture data is stored inside the resulting Python function object. + +- pybind11 uses C++11 move constructors and move assignment operators whenever + possible to efficiently transfer custom data types. + +- It's easy to expose the internal storage of custom data types through + Pythons' buffer protocols. This is handy e.g. for fast conversion between + C++ matrix classes like Eigen and NumPy without expensive copy operations. + +- pybind11 can automatically vectorize functions so that they are transparently + applied to all entries of one or more NumPy array arguments. + +- Python's slice-based access and assignment operations can be supported with + just a few lines of code. + +- Everything is contained in just a few header files; there is no need to link + against any additional libraries. + +- Binaries are generally smaller by a factor of at least 2 compared to + equivalent bindings generated by Boost.Python. A recent pybind11 conversion + of PyRosetta, an enormous Boost.Python binding project, + [reported](http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf) a binary + size reduction of **5.4x** and compile time reduction by **5.8x**. + +- Function signatures are precomputed at compile time (using ``constexpr``), + leading to smaller binaries. + +- With little extra effort, C++ types can be pickled and unpickled similar to + regular Python objects. + +## Supported compilers + +1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or newer) +2. GCC 4.8 or newer +3. Microsoft Visual Studio 2015 Update 3 or newer +4. Intel C++ compiler 17 or newer (16 with pybind11 v2.0 and 15 with pybind11 v2.0 and a [workaround](https://github.com/pybind/pybind11/issues/276)) +5. Cygwin/GCC (tested on 2.5.1) + +## About + +This project was created by [Wenzel Jakob](http://rgl.epfl.ch/people/wjakob). +Significant features and/or improvements to the code were contributed by +Jonas Adler, +Lori A. Burns, +Sylvain Corlay, +Trent Houliston, +Axel Huebl, +@hulucc, +Sergey Lyskov +Johan Mabille, +Tomasz Miąsko, +Dean Moldovan, +Ben Pritchard, +Jason Rhinelander, +Boris Schäling, +Pim Schellart, +Henry Schreiner, +Ivan Smirnov, and +Patrick Stewart. + +### License + +pybind11 is provided under a BSD-style license that can be found in the +``LICENSE`` file. By using, distributing, or contributing to this project, +you agree to the terms and conditions of this license. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/Doxyfile b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/Doxyfile new file mode 100644 index 0000000000000000000000000000000000000000..1b9d1297c513ab44d834a5a880def48f62cf524b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/Doxyfile @@ -0,0 +1,20 @@ +PROJECT_NAME = pybind11 +INPUT = ../include/pybind11/ +RECURSIVE = YES + +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES +XML_OUTPUT = .build/doxygenxml +XML_PROGRAMLISTING = YES + +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +EXPAND_AS_DEFINED = PYBIND11_RUNTIME_EXCEPTION + +ALIASES = "rst=\verbatim embed:rst" +ALIASES += "endrst=\endverbatim" + +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = NO diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/_static/theme_overrides.css b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/_static/theme_overrides.css new file mode 100644 index 0000000000000000000000000000000000000000..1071809fa0fecf7c28d3356f37363266e9128b81 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/_static/theme_overrides.css @@ -0,0 +1,11 @@ +.wy-table-responsive table td, +.wy-table-responsive table th { + white-space: initial !important; +} +.rst-content table.docutils td { + vertical-align: top !important; +} +div[class^='highlight'] pre { + white-space: pre; + white-space: pre-wrap; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/chrono.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/chrono.rst new file mode 100644 index 0000000000000000000000000000000000000000..fbd46057aa392c86ae3747c2b21768367205ea49 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/chrono.rst @@ -0,0 +1,81 @@ +Chrono +====== + +When including the additional header file :file:`pybind11/chrono.h` conversions +from C++11 chrono datatypes to python datetime objects are automatically enabled. +This header also enables conversions of python floats (often from sources such +as ``time.monotonic()``, ``time.perf_counter()`` and ``time.process_time()``) +into durations. + +An overview of clocks in C++11 +------------------------------ + +A point of confusion when using these conversions is the differences between +clocks provided in C++11. There are three clock types defined by the C++11 +standard and users can define their own if needed. Each of these clocks have +different properties and when converting to and from python will give different +results. + +The first clock defined by the standard is ``std::chrono::system_clock``. This +clock measures the current date and time. However, this clock changes with to +updates to the operating system time. For example, if your time is synchronised +with a time server this clock will change. This makes this clock a poor choice +for timing purposes but good for measuring the wall time. + +The second clock defined in the standard is ``std::chrono::steady_clock``. +This clock ticks at a steady rate and is never adjusted. This makes it excellent +for timing purposes, however the value in this clock does not correspond to the +current date and time. Often this clock will be the amount of time your system +has been on, although it does not have to be. This clock will never be the same +clock as the system clock as the system clock can change but steady clocks +cannot. + +The third clock defined in the standard is ``std::chrono::high_resolution_clock``. +This clock is the clock that has the highest resolution out of the clocks in the +system. It is normally a typedef to either the system clock or the steady clock +but can be its own independent clock. This is important as when using these +conversions as the types you get in python for this clock might be different +depending on the system. +If it is a typedef of the system clock, python will get datetime objects, but if +it is a different clock they will be timedelta objects. + +Provided conversions +-------------------- + +.. rubric:: C++ to Python + +- ``std::chrono::system_clock::time_point`` → ``datetime.datetime`` + System clock times are converted to python datetime instances. They are + in the local timezone, but do not have any timezone information attached + to them (they are naive datetime objects). + +- ``std::chrono::duration`` → ``datetime.timedelta`` + Durations are converted to timedeltas, any precision in the duration + greater than microseconds is lost by rounding towards zero. + +- ``std::chrono::[other_clocks]::time_point`` → ``datetime.timedelta`` + Any clock time that is not the system clock is converted to a time delta. + This timedelta measures the time from the clocks epoch to now. + +.. rubric:: Python to C++ + +- ``datetime.datetime`` or ``datetime.date`` or ``datetime.time`` → ``std::chrono::system_clock::time_point`` + Date/time objects are converted into system clock timepoints. Any + timezone information is ignored and the type is treated as a naive + object. + +- ``datetime.timedelta`` → ``std::chrono::duration`` + Time delta are converted into durations with microsecond precision. + +- ``datetime.timedelta`` → ``std::chrono::[other_clocks]::time_point`` + Time deltas that are converted into clock timepoints are treated as + the amount of time from the start of the clocks epoch. + +- ``float`` → ``std::chrono::duration`` + Floats that are passed to C++ as durations be interpreted as a number of + seconds. These will be converted to the duration using ``duration_cast`` + from the float. + +- ``float`` → ``std::chrono::[other_clocks]::time_point`` + Floats that are passed to C++ as time points will be interpreted as the + number of seconds from the start of the clocks epoch. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/custom.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/custom.rst new file mode 100644 index 0000000000000000000000000000000000000000..e4f99ac5b086355ff8e691a22ad5e16ea84dfed7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/custom.rst @@ -0,0 +1,91 @@ +Custom type casters +=================== + +In very rare cases, applications may require custom type casters that cannot be +expressed using the abstractions provided by pybind11, thus requiring raw +Python C API calls. This is fairly advanced usage and should only be pursued by +experts who are familiar with the intricacies of Python reference counting. + +The following snippets demonstrate how this works for a very simple ``inty`` +type that that should be convertible from Python types that provide a +``__int__(self)`` method. + +.. code-block:: cpp + + struct inty { long long_value; }; + + void print(inty s) { + std::cout << s.long_value << std::endl; + } + +The following Python snippet demonstrates the intended usage from the Python side: + +.. code-block:: python + + class A: + def __int__(self): + return 123 + + from example import print + print(A()) + +To register the necessary conversion routines, it is necessary to add +a partial overload to the ``pybind11::detail::type_caster`` template. +Although this is an implementation detail, adding partial overloads to this +type is explicitly allowed. + +.. code-block:: cpp + + namespace pybind11 { namespace detail { + template <> struct type_caster { + public: + /** + * This macro establishes the name 'inty' in + * function signatures and declares a local variable + * 'value' of type inty + */ + PYBIND11_TYPE_CASTER(inty, _("inty")); + + /** + * Conversion part 1 (Python->C++): convert a PyObject into a inty + * instance or return false upon failure. The second argument + * indicates whether implicit conversions should be applied. + */ + bool load(handle src, bool) { + /* Extract PyObject from handle */ + PyObject *source = src.ptr(); + /* Try converting into a Python integer value */ + PyObject *tmp = PyNumber_Long(source); + if (!tmp) + return false; + /* Now try to convert into a C++ int */ + value.long_value = PyLong_AsLong(tmp); + Py_DECREF(tmp); + /* Ensure return code was OK (to avoid out-of-range errors etc) */ + return !(value.long_value == -1 && !PyErr_Occurred()); + } + + /** + * Conversion part 2 (C++ -> Python): convert an inty instance into + * a Python object. The second and third arguments are used to + * indicate the return value policy and parent object (for + * ``return_value_policy::reference_internal``) and are generally + * ignored by implicit casters. + */ + static handle cast(inty src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromLong(src.long_value); + } + }; + }} // namespace pybind11::detail + +.. note:: + + A ``type_caster`` defined with ``PYBIND11_TYPE_CASTER(T, ...)`` requires + that ``T`` is default-constructible (``value`` is first default constructed + and then ``load()`` assigns to it). + +.. warning:: + + When using custom type casters, it's important to declare them consistently + in every compilation unit of the Python extension module. Otherwise, + undefined behavior can ensue. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/eigen.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/eigen.rst new file mode 100644 index 0000000000000000000000000000000000000000..59ba08c3c4297556f6aaa2e0c8db328eb1490e40 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/eigen.rst @@ -0,0 +1,310 @@ +Eigen +##### + +`Eigen `_ is C++ header-based library for dense and +sparse linear algebra. Due to its popularity and widespread adoption, pybind11 +provides transparent conversion and limited mapping support between Eigen and +Scientific Python linear algebra data types. + +To enable the built-in Eigen support you must include the optional header file +:file:`pybind11/eigen.h`. + +Pass-by-value +============= + +When binding a function with ordinary Eigen dense object arguments (for +example, ``Eigen::MatrixXd``), pybind11 will accept any input value that is +already (or convertible to) a ``numpy.ndarray`` with dimensions compatible with +the Eigen type, copy its values into a temporary Eigen variable of the +appropriate type, then call the function with this temporary variable. + +Sparse matrices are similarly copied to or from +``scipy.sparse.csr_matrix``/``scipy.sparse.csc_matrix`` objects. + +Pass-by-reference +================= + +One major limitation of the above is that every data conversion implicitly +involves a copy, which can be both expensive (for large matrices) and disallows +binding functions that change their (Matrix) arguments. Pybind11 allows you to +work around this by using Eigen's ``Eigen::Ref`` class much as you +would when writing a function taking a generic type in Eigen itself (subject to +some limitations discussed below). + +When calling a bound function accepting a ``Eigen::Ref`` +type, pybind11 will attempt to avoid copying by using an ``Eigen::Map`` object +that maps into the source ``numpy.ndarray`` data: this requires both that the +data types are the same (e.g. ``dtype='float64'`` and ``MatrixType::Scalar`` is +``double``); and that the storage is layout compatible. The latter limitation +is discussed in detail in the section below, and requires careful +consideration: by default, numpy matrices and Eigen matrices are *not* storage +compatible. + +If the numpy matrix cannot be used as is (either because its types differ, e.g. +passing an array of integers to an Eigen parameter requiring doubles, or +because the storage is incompatible), pybind11 makes a temporary copy and +passes the copy instead. + +When a bound function parameter is instead ``Eigen::Ref`` (note the +lack of ``const``), pybind11 will only allow the function to be called if it +can be mapped *and* if the numpy array is writeable (that is +``a.flags.writeable`` is true). Any access (including modification) made to +the passed variable will be transparently carried out directly on the +``numpy.ndarray``. + +This means you can can write code such as the following and have it work as +expected: + +.. code-block:: cpp + + void scale_by_2(Eigen::Ref v) { + v *= 2; + } + +Note, however, that you will likely run into limitations due to numpy and +Eigen's difference default storage order for data; see the below section on +:ref:`storage_orders` for details on how to bind code that won't run into such +limitations. + +.. note:: + + Passing by reference is not supported for sparse types. + +Returning values to Python +========================== + +When returning an ordinary dense Eigen matrix type to numpy (e.g. +``Eigen::MatrixXd`` or ``Eigen::RowVectorXf``) pybind11 keeps the matrix and +returns a numpy array that directly references the Eigen matrix: no copy of the +data is performed. The numpy array will have ``array.flags.owndata`` set to +``False`` to indicate that it does not own the data, and the lifetime of the +stored Eigen matrix will be tied to the returned ``array``. + +If you bind a function with a non-reference, ``const`` return type (e.g. +``const Eigen::MatrixXd``), the same thing happens except that pybind11 also +sets the numpy array's ``writeable`` flag to false. + +If you return an lvalue reference or pointer, the usual pybind11 rules apply, +as dictated by the binding function's return value policy (see the +documentation on :ref:`return_value_policies` for full details). That means, +without an explicit return value policy, lvalue references will be copied and +pointers will be managed by pybind11. In order to avoid copying, you should +explicitly specify an appropriate return value policy, as in the following +example: + +.. code-block:: cpp + + class MyClass { + Eigen::MatrixXd big_mat = Eigen::MatrixXd::Zero(10000, 10000); + public: + Eigen::MatrixXd &getMatrix() { return big_mat; } + const Eigen::MatrixXd &viewMatrix() { return big_mat; } + }; + + // Later, in binding code: + py::class_(m, "MyClass") + .def(py::init<>()) + .def("copy_matrix", &MyClass::getMatrix) // Makes a copy! + .def("get_matrix", &MyClass::getMatrix, py::return_value_policy::reference_internal) + .def("view_matrix", &MyClass::viewMatrix, py::return_value_policy::reference_internal) + ; + +.. code-block:: python + + a = MyClass() + m = a.get_matrix() # flags.writeable = True, flags.owndata = False + v = a.view_matrix() # flags.writeable = False, flags.owndata = False + c = a.copy_matrix() # flags.writeable = True, flags.owndata = True + # m[5,6] and v[5,6] refer to the same element, c[5,6] does not. + +Note in this example that ``py::return_value_policy::reference_internal`` is +used to tie the life of the MyClass object to the life of the returned arrays. + +You may also return an ``Eigen::Ref``, ``Eigen::Map`` or other map-like Eigen +object (for example, the return value of ``matrix.block()`` and related +methods) that map into a dense Eigen type. When doing so, the default +behaviour of pybind11 is to simply reference the returned data: you must take +care to ensure that this data remains valid! You may ask pybind11 to +explicitly *copy* such a return value by using the +``py::return_value_policy::copy`` policy when binding the function. You may +also use ``py::return_value_policy::reference_internal`` or a +``py::keep_alive`` to ensure the data stays valid as long as the returned numpy +array does. + +When returning such a reference of map, pybind11 additionally respects the +readonly-status of the returned value, marking the numpy array as non-writeable +if the reference or map was itself read-only. + +.. note:: + + Sparse types are always copied when returned. + +.. _storage_orders: + +Storage orders +============== + +Passing arguments via ``Eigen::Ref`` has some limitations that you must be +aware of in order to effectively pass matrices by reference. First and +foremost is that the default ``Eigen::Ref`` class requires +contiguous storage along columns (for column-major types, the default in Eigen) +or rows if ``MatrixType`` is specifically an ``Eigen::RowMajor`` storage type. +The former, Eigen's default, is incompatible with ``numpy``'s default row-major +storage, and so you will not be able to pass numpy arrays to Eigen by reference +without making one of two changes. + +(Note that this does not apply to vectors (or column or row matrices): for such +types the "row-major" and "column-major" distinction is meaningless). + +The first approach is to change the use of ``Eigen::Ref`` to the +more general ``Eigen::Ref>`` (or similar type with a fully dynamic stride type in the +third template argument). Since this is a rather cumbersome type, pybind11 +provides a ``py::EigenDRef`` type alias for your convenience (along +with EigenDMap for the equivalent Map, and EigenDStride for just the stride +type). + +This type allows Eigen to map into any arbitrary storage order. This is not +the default in Eigen for performance reasons: contiguous storage allows +vectorization that cannot be done when storage is not known to be contiguous at +compile time. The default ``Eigen::Ref`` stride type allows non-contiguous +storage along the outer dimension (that is, the rows of a column-major matrix +or columns of a row-major matrix), but not along the inner dimension. + +This type, however, has the added benefit of also being able to map numpy array +slices. For example, the following (contrived) example uses Eigen with a numpy +slice to multiply by 2 all coefficients that are both on even rows (0, 2, 4, +...) and in columns 2, 5, or 8: + +.. code-block:: cpp + + m.def("scale", [](py::EigenDRef m, double c) { m *= c; }); + +.. code-block:: python + + # a = np.array(...) + scale_by_2(myarray[0::2, 2:9:3]) + +The second approach to avoid copying is more intrusive: rearranging the +underlying data types to not run into the non-contiguous storage problem in the +first place. In particular, that means using matrices with ``Eigen::RowMajor`` +storage, where appropriate, such as: + +.. code-block:: cpp + + using RowMatrixXd = Eigen::Matrix; + // Use RowMatrixXd instead of MatrixXd + +Now bound functions accepting ``Eigen::Ref`` arguments will be +callable with numpy's (default) arrays without involving a copying. + +You can, alternatively, change the storage order that numpy arrays use by +adding the ``order='F'`` option when creating an array: + +.. code-block:: python + + myarray = np.array(source, order='F') + +Such an object will be passable to a bound function accepting an +``Eigen::Ref`` (or similar column-major Eigen type). + +One major caveat with this approach, however, is that it is not entirely as +easy as simply flipping all Eigen or numpy usage from one to the other: some +operations may alter the storage order of a numpy array. For example, ``a2 = +array.transpose()`` results in ``a2`` being a view of ``array`` that references +the same data, but in the opposite storage order! + +While this approach allows fully optimized vectorized calculations in Eigen, it +cannot be used with array slices, unlike the first approach. + +When *returning* a matrix to Python (either a regular matrix, a reference via +``Eigen::Ref<>``, or a map/block into a matrix), no special storage +consideration is required: the created numpy array will have the required +stride that allows numpy to properly interpret the array, whatever its storage +order. + +Failing rather than copying +=========================== + +The default behaviour when binding ``Eigen::Ref`` Eigen +references is to copy matrix values when passed a numpy array that does not +conform to the element type of ``MatrixType`` or does not have a compatible +stride layout. If you want to explicitly avoid copying in such a case, you +should bind arguments using the ``py::arg().noconvert()`` annotation (as +described in the :ref:`nonconverting_arguments` documentation). + +The following example shows an example of arguments that don't allow data +copying to take place: + +.. code-block:: cpp + + // The method and function to be bound: + class MyClass { + // ... + double some_method(const Eigen::Ref &matrix) { /* ... */ } + }; + float some_function(const Eigen::Ref &big, + const Eigen::Ref &small) { + // ... + } + + // The associated binding code: + using namespace pybind11::literals; // for "arg"_a + py::class_(m, "MyClass") + // ... other class definitions + .def("some_method", &MyClass::some_method, py::arg().noconvert()); + + m.def("some_function", &some_function, + "big"_a.noconvert(), // <- Don't allow copying for this arg + "small"_a // <- This one can be copied if needed + ); + +With the above binding code, attempting to call the the ``some_method(m)`` +method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)`` +will raise a ``RuntimeError`` rather than making a temporary copy of the array. +It will, however, allow the ``m2`` argument to be copied into a temporary if +necessary. + +Note that explicitly specifying ``.noconvert()`` is not required for *mutable* +Eigen references (e.g. ``Eigen::Ref`` without ``const`` on the +``MatrixXd``): mutable references will never be called with a temporary copy. + +Vectors versus column/row matrices +================================== + +Eigen and numpy have fundamentally different notions of a vector. In Eigen, a +vector is simply a matrix with the number of columns or rows set to 1 at +compile time (for a column vector or row vector, respectively). Numpy, in +contrast, has comparable 2-dimensional 1xN and Nx1 arrays, but *also* has +1-dimensional arrays of size N. + +When passing a 2-dimensional 1xN or Nx1 array to Eigen, the Eigen type must +have matching dimensions: That is, you cannot pass a 2-dimensional Nx1 numpy +array to an Eigen value expecting a row vector, or a 1xN numpy array as a +column vector argument. + +On the other hand, pybind11 allows you to pass 1-dimensional arrays of length N +as Eigen parameters. If the Eigen type can hold a column vector of length N it +will be passed as such a column vector. If not, but the Eigen type constraints +will accept a row vector, it will be passed as a row vector. (The column +vector takes precedence when both are supported, for example, when passing a +1D numpy array to a MatrixXd argument). Note that the type need not be +explicitly a vector: it is permitted to pass a 1D numpy array of size 5 to an +Eigen ``Matrix``: you would end up with a 1x5 Eigen matrix. +Passing the same to an ``Eigen::MatrixXd`` would result in a 5x1 Eigen matrix. + +When returning an Eigen vector to numpy, the conversion is ambiguous: a row +vector of length 4 could be returned as either a 1D array of length 4, or as a +2D array of size 1x4. When encountering such a situation, pybind11 compromises +by considering the returned Eigen type: if it is a compile-time vector--that +is, the type has either the number of rows or columns set to 1 at compile +time--pybind11 converts to a 1D numpy array when returning the value. For +instances that are a vector only at run-time (e.g. ``MatrixXd``, +``Matrix``), pybind11 returns the vector as a 2D array to +numpy. If this isn't want you want, you can use ``array.reshape(...)`` to get +a view of the same data in the desired dimensions. + +.. seealso:: + + The file :file:`tests/test_eigen.cpp` contains a complete example that + shows how to pass Eigen sparse and dense data types in more detail. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/functional.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/functional.rst new file mode 100644 index 0000000000000000000000000000000000000000..d9b46057598f0d182422accd088fbff9785b0b53 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/functional.rst @@ -0,0 +1,109 @@ +Functional +########## + +The following features must be enabled by including :file:`pybind11/functional.h`. + + +Callbacks and passing anonymous functions +========================================= + +The C++11 standard brought lambda functions and the generic polymorphic +function wrapper ``std::function<>`` to the C++ programming language, which +enable powerful new ways of working with functions. Lambda functions come in +two flavors: stateless lambda function resemble classic function pointers that +link to an anonymous piece of code, while stateful lambda functions +additionally depend on captured variables that are stored in an anonymous +*lambda closure object*. + +Here is a simple example of a C++ function that takes an arbitrary function +(stateful or stateless) with signature ``int -> int`` as an argument and runs +it with the value 10. + +.. code-block:: cpp + + int func_arg(const std::function &f) { + return f(10); + } + +The example below is more involved: it takes a function of signature ``int -> int`` +and returns another function of the same kind. The return value is a stateful +lambda function, which stores the value ``f`` in the capture object and adds 1 to +its return value upon execution. + +.. code-block:: cpp + + std::function func_ret(const std::function &f) { + return [f](int i) { + return f(i) + 1; + }; + } + +This example demonstrates using python named parameters in C++ callbacks which +requires using ``py::cpp_function`` as a wrapper. Usage is similar to defining +methods of classes: + +.. code-block:: cpp + + py::cpp_function func_cpp() { + return py::cpp_function([](int i) { return i+1; }, + py::arg("number")); + } + +After including the extra header file :file:`pybind11/functional.h`, it is almost +trivial to generate binding code for all of these functions. + +.. code-block:: cpp + + #include + + PYBIND11_MODULE(example, m) { + m.def("func_arg", &func_arg); + m.def("func_ret", &func_ret); + m.def("func_cpp", &func_cpp); + } + +The following interactive session shows how to call them from Python. + +.. code-block:: pycon + + $ python + >>> import example + >>> def square(i): + ... return i * i + ... + >>> example.func_arg(square) + 100L + >>> square_plus_1 = example.func_ret(square) + >>> square_plus_1(4) + 17L + >>> plus_1 = func_cpp() + >>> plus_1(number=43) + 44L + +.. warning:: + + Keep in mind that passing a function from C++ to Python (or vice versa) + will instantiate a piece of wrapper code that translates function + invocations between the two languages. Naturally, this translation + increases the computational cost of each function call somewhat. A + problematic situation can arise when a function is copied back and forth + between Python and C++ many times in a row, in which case the underlying + wrappers will accumulate correspondingly. The resulting long sequence of + C++ -> Python -> C++ -> ... roundtrips can significantly decrease + performance. + + There is one exception: pybind11 detects case where a stateless function + (i.e. a function pointer or a lambda function without captured variables) + is passed as an argument to another C++ function exposed in Python. In this + case, there is no overhead. Pybind11 will extract the underlying C++ + function pointer from the wrapped function to sidestep a potential C++ -> + Python -> C++ roundtrip. This is demonstrated in :file:`tests/test_callbacks.cpp`. + +.. note:: + + This functionality is very useful when generating bindings for callbacks in + C++ libraries (e.g. GUI libraries, asynchronous networking libraries, etc.). + + The file :file:`tests/test_callbacks.cpp` contains a complete example + that demonstrates how to work with callbacks and anonymous functions in + more detail. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/index.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..54c10570b1ccd106ee98c92ead8c28fde5134d5d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/index.rst @@ -0,0 +1,42 @@ +Type conversions +################ + +Apart from enabling cross-language function calls, a fundamental problem +that a binding tool like pybind11 must address is to provide access to +native Python types in C++ and vice versa. There are three fundamentally +different ways to do this—which approach is preferable for a particular type +depends on the situation at hand. + +1. Use a native C++ type everywhere. In this case, the type must be wrapped + using pybind11-generated bindings so that Python can interact with it. + +2. Use a native Python type everywhere. It will need to be wrapped so that + C++ functions can interact with it. + +3. Use a native C++ type on the C++ side and a native Python type on the + Python side. pybind11 refers to this as a *type conversion*. + + Type conversions are the most "natural" option in the sense that native + (non-wrapped) types are used everywhere. The main downside is that a copy + of the data must be made on every Python ↔ C++ transition: this is + needed since the C++ and Python versions of the same type generally won't + have the same memory layout. + + pybind11 can perform many kinds of conversions automatically. An overview + is provided in the table ":ref:`conversion_table`". + +The following subsections discuss the differences between these options in more +detail. The main focus in this section is on type conversions, which represent +the last case of the above list. + +.. toctree:: + :maxdepth: 1 + + overview + strings + stl + functional + chrono + eigen + custom + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/overview.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/overview.rst new file mode 100644 index 0000000000000000000000000000000000000000..b0e32a52f9c8bb2945e230416216c38e3c3a4a9b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/overview.rst @@ -0,0 +1,165 @@ +Overview +######## + +.. rubric:: 1. Native type in C++, wrapper in Python + +Exposing a custom C++ type using :class:`py::class_` was covered in detail +in the :doc:`/classes` section. There, the underlying data structure is +always the original C++ class while the :class:`py::class_` wrapper provides +a Python interface. Internally, when an object like this is sent from C++ to +Python, pybind11 will just add the outer wrapper layer over the native C++ +object. Getting it back from Python is just a matter of peeling off the +wrapper. + +.. rubric:: 2. Wrapper in C++, native type in Python + +This is the exact opposite situation. Now, we have a type which is native to +Python, like a ``tuple`` or a ``list``. One way to get this data into C++ is +with the :class:`py::object` family of wrappers. These are explained in more +detail in the :doc:`/advanced/pycpp/object` section. We'll just give a quick +example here: + +.. code-block:: cpp + + void print_list(py::list my_list) { + for (auto item : my_list) + std::cout << item << " "; + } + +.. code-block:: pycon + + >>> print_list([1, 2, 3]) + 1 2 3 + +The Python ``list`` is not converted in any way -- it's just wrapped in a C++ +:class:`py::list` class. At its core it's still a Python object. Copying a +:class:`py::list` will do the usual reference-counting like in Python. +Returning the object to Python will just remove the thin wrapper. + +.. rubric:: 3. Converting between native C++ and Python types + +In the previous two cases we had a native type in one language and a wrapper in +the other. Now, we have native types on both sides and we convert between them. + +.. code-block:: cpp + + void print_vector(const std::vector &v) { + for (auto item : v) + std::cout << item << "\n"; + } + +.. code-block:: pycon + + >>> print_vector([1, 2, 3]) + 1 2 3 + +In this case, pybind11 will construct a new ``std::vector`` and copy each +element from the Python ``list``. The newly constructed object will be passed +to ``print_vector``. The same thing happens in the other direction: a new +``list`` is made to match the value returned from C++. + +Lots of these conversions are supported out of the box, as shown in the table +below. They are very convenient, but keep in mind that these conversions are +fundamentally based on copying data. This is perfectly fine for small immutable +types but it may become quite expensive for large data structures. This can be +avoided by overriding the automatic conversion with a custom wrapper (i.e. the +above-mentioned approach 1). This requires some manual effort and more details +are available in the :ref:`opaque` section. + +.. _conversion_table: + +List of all builtin conversions +------------------------------- + +The following basic data types are supported out of the box (some may require +an additional extension header to be included). To pass other data structures +as arguments and return values, refer to the section on binding :ref:`classes`. + ++------------------------------------+---------------------------+-------------------------------+ +| Data type | Description | Header file | ++====================================+===========================+===============================+ +| ``int8_t``, ``uint8_t`` | 8-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``int16_t``, ``uint16_t`` | 16-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``int32_t``, ``uint32_t`` | 32-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``int64_t``, ``uint64_t`` | 64-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``ssize_t``, ``size_t`` | Platform-dependent size | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``float``, ``double`` | Floating point types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``bool`` | Two-state Boolean type | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``char`` | Character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``char16_t`` | UTF-16 character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``char32_t`` | UTF-32 character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``wchar_t`` | Wide character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``const char *`` | UTF-8 string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``const char16_t *`` | UTF-16 string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``const char32_t *`` | UTF-32 string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``const wchar_t *`` | Wide string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::string`` | STL dynamic UTF-8 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::u16string`` | STL dynamic UTF-16 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::u32string`` | STL dynamic UTF-32 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` | +| ``std::u16string_view``, etc. | | | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::pair`` | Pair of two custom types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::reference_wrapper<...>`` | Reference type wrapper | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::complex`` | Complex numbers | :file:`pybind11/complex.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::array`` | STL static array | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::vector`` | STL dynamic array | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::deque`` | STL double-ended queue | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::valarray`` | STL value array | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::list`` | STL linked list | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::map`` | STL ordered map | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::unordered_map`` | STL unordered map | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::set`` | STL ordered set | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::unordered_set`` | STL unordered set | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::optional`` | STL optional type (C++17) | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::experimental::optional`` | STL optional type (exp.) | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::chrono::duration<...>`` | STL time duration | :file:`pybind11/chrono.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::chrono::time_point<...>`` | STL date/time | :file:`pybind11/chrono.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``Eigen::Matrix<...>`` | Eigen: dense matrix | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``Eigen::Map<...>`` | Eigen: mapped memory | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``Eigen::SparseMatrix<...>`` | Eigen: sparse matrix | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-------------------------------+ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/stl.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/stl.rst new file mode 100644 index 0000000000000000000000000000000000000000..e48409f025d021b35e4e26f4fee754b2d858daa4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/stl.rst @@ -0,0 +1,240 @@ +STL containers +############## + +Automatic conversion +==================== + +When including the additional header file :file:`pybind11/stl.h`, conversions +between ``std::vector<>``/``std::deque<>``/``std::list<>``/``std::array<>``, +``std::set<>``/``std::unordered_set<>``, and +``std::map<>``/``std::unordered_map<>`` and the Python ``list``, ``set`` and +``dict`` data structures are automatically enabled. The types ``std::pair<>`` +and ``std::tuple<>`` are already supported out of the box with just the core +:file:`pybind11/pybind11.h` header. + +The major downside of these implicit conversions is that containers must be +converted (i.e. copied) on every Python->C++ and C++->Python transition, which +can have implications on the program semantics and performance. Please read the +next sections for more details and alternative approaches that avoid this. + +.. note:: + + Arbitrary nesting of any of these types is possible. + +.. seealso:: + + The file :file:`tests/test_stl.cpp` contains a complete + example that demonstrates how to pass STL data types in more detail. + +.. _cpp17_container_casters: + +C++17 library containers +======================== + +The :file:`pybind11/stl.h` header also includes support for ``std::optional<>`` +and ``std::variant<>``. These require a C++17 compiler and standard library. +In C++14 mode, ``std::experimental::optional<>`` is supported if available. + +Various versions of these containers also exist for C++11 (e.g. in Boost). +pybind11 provides an easy way to specialize the ``type_caster`` for such +types: + +.. code-block:: cpp + + // `boost::optional` as an example -- can be any `std::optional`-like container + namespace pybind11 { namespace detail { + template + struct type_caster> : optional_caster> {}; + }} + +The above should be placed in a header file and included in all translation units +where automatic conversion is needed. Similarly, a specialization can be provided +for custom variant types: + +.. code-block:: cpp + + // `boost::variant` as an example -- can be any `std::variant`-like container + namespace pybind11 { namespace detail { + template + struct type_caster> : variant_caster> {}; + + // Specifies the function used to visit the variant -- `apply_visitor` instead of `visit` + template <> + struct visit_helper { + template + static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) { + return boost::apply_visitor(args...); + } + }; + }} // namespace pybind11::detail + +The ``visit_helper`` specialization is not required if your ``name::variant`` provides +a ``name::visit()`` function. For any other function name, the specialization must be +included to tell pybind11 how to visit the variant. + +.. note:: + + pybind11 only supports the modern implementation of ``boost::variant`` + which makes use of variadic templates. This requires Boost 1.56 or newer. + Additionally, on Windows, MSVC 2017 is required because ``boost::variant`` + falls back to the old non-variadic implementation on MSVC 2015. + +.. _opaque: + +Making opaque types +=================== + +pybind11 heavily relies on a template matching mechanism to convert parameters +and return values that are constructed from STL data types such as vectors, +linked lists, hash tables, etc. This even works in a recursive manner, for +instance to deal with lists of hash maps of pairs of elementary and custom +types, etc. + +However, a fundamental limitation of this approach is that internal conversions +between Python and C++ types involve a copy operation that prevents +pass-by-reference semantics. What does this mean? + +Suppose we bind the following function + +.. code-block:: cpp + + void append_1(std::vector &v) { + v.push_back(1); + } + +and call it from Python, the following happens: + +.. code-block:: pycon + + >>> v = [5, 6] + >>> append_1(v) + >>> print(v) + [5, 6] + +As you can see, when passing STL data structures by reference, modifications +are not propagated back the Python side. A similar situation arises when +exposing STL data structures using the ``def_readwrite`` or ``def_readonly`` +functions: + +.. code-block:: cpp + + /* ... definition ... */ + + class MyClass { + std::vector contents; + }; + + /* ... binding code ... */ + + py::class_(m, "MyClass") + .def(py::init<>()) + .def_readwrite("contents", &MyClass::contents); + +In this case, properties can be read and written in their entirety. However, an +``append`` operation involving such a list type has no effect: + +.. code-block:: pycon + + >>> m = MyClass() + >>> m.contents = [5, 6] + >>> print(m.contents) + [5, 6] + >>> m.contents.append(7) + >>> print(m.contents) + [5, 6] + +Finally, the involved copy operations can be costly when dealing with very +large lists. To deal with all of the above situations, pybind11 provides a +macro named ``PYBIND11_MAKE_OPAQUE(T)`` that disables the template-based +conversion machinery of types, thus rendering them *opaque*. The contents of +opaque objects are never inspected or extracted, hence they *can* be passed by +reference. For instance, to turn ``std::vector`` into an opaque type, add +the declaration + +.. code-block:: cpp + + PYBIND11_MAKE_OPAQUE(std::vector); + +before any binding code (e.g. invocations to ``class_::def()``, etc.). This +macro must be specified at the top level (and outside of any namespaces), since +it instantiates a partial template overload. If your binding code consists of +multiple compilation units, it must be present in every file (typically via a +common header) preceding any usage of ``std::vector``. Opaque types must +also have a corresponding ``class_`` declaration to associate them with a name +in Python, and to define a set of available operations, e.g.: + +.. code-block:: cpp + + py::class_>(m, "IntVector") + .def(py::init<>()) + .def("clear", &std::vector::clear) + .def("pop_back", &std::vector::pop_back) + .def("__len__", [](const std::vector &v) { return v.size(); }) + .def("__iter__", [](std::vector &v) { + return py::make_iterator(v.begin(), v.end()); + }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */ + // .... + +.. seealso:: + + The file :file:`tests/test_opaque_types.cpp` contains a complete + example that demonstrates how to create and expose opaque types using + pybind11 in more detail. + +.. _stl_bind: + +Binding STL containers +====================== + +The ability to expose STL containers as native Python objects is a fairly +common request, hence pybind11 also provides an optional header file named +:file:`pybind11/stl_bind.h` that does exactly this. The mapped containers try +to match the behavior of their native Python counterparts as much as possible. + +The following example showcases usage of :file:`pybind11/stl_bind.h`: + +.. code-block:: cpp + + // Don't forget this + #include + + PYBIND11_MAKE_OPAQUE(std::vector); + PYBIND11_MAKE_OPAQUE(std::map); + + // ... + + // later in binding code: + py::bind_vector>(m, "VectorInt"); + py::bind_map>(m, "MapStringDouble"); + +When binding STL containers pybind11 considers the types of the container's +elements to decide whether the container should be confined to the local module +(via the :ref:`module_local` feature). If the container element types are +anything other than already-bound custom types bound without +``py::module_local()`` the container binding will have ``py::module_local()`` +applied. This includes converting types such as numeric types, strings, Eigen +types; and types that have not yet been bound at the time of the stl container +binding. This module-local binding is designed to avoid potential conflicts +between module bindings (for example, from two separate modules each attempting +to bind ``std::vector`` as a python type). + +It is possible to override this behavior to force a definition to be either +module-local or global. To do so, you can pass the attributes +``py::module_local()`` (to make the binding module-local) or +``py::module_local(false)`` (to make the binding global) into the +``py::bind_vector`` or ``py::bind_map`` arguments: + +.. code-block:: cpp + + py::bind_vector>(m, "VectorInt", py::module_local(false)); + +Note, however, that such a global binding would make it impossible to load this +module at the same time as any other pybind module that also attempts to bind +the same container type (``std::vector`` in the above example). + +See :ref:`module_local` for more details on module-local bindings. + +.. seealso:: + + The file :file:`tests/test_stl_binders.cpp` shows how to use the + convenience STL container wrappers. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/strings.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/strings.rst new file mode 100644 index 0000000000000000000000000000000000000000..e25701ecabd80142f4fd705f5419ef7c10cc6c56 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/cast/strings.rst @@ -0,0 +1,305 @@ +Strings, bytes and Unicode conversions +###################################### + +.. note:: + + This section discusses string handling in terms of Python 3 strings. For + Python 2.7, replace all occurrences of ``str`` with ``unicode`` and + ``bytes`` with ``str``. Python 2.7 users may find it best to use ``from + __future__ import unicode_literals`` to avoid unintentionally using ``str`` + instead of ``unicode``. + +Passing Python strings to C++ +============================= + +When a Python ``str`` is passed from Python to a C++ function that accepts +``std::string`` or ``char *`` as arguments, pybind11 will encode the Python +string to UTF-8. All Python ``str`` can be encoded in UTF-8, so this operation +does not fail. + +The C++ language is encoding agnostic. It is the responsibility of the +programmer to track encodings. It's often easiest to simply `use UTF-8 +everywhere `_. + +.. code-block:: c++ + + m.def("utf8_test", + [](const std::string &s) { + cout << "utf-8 is icing on the cake.\n"; + cout << s; + } + ); + m.def("utf8_charptr", + [](const char *s) { + cout << "My favorite food is\n"; + cout << s; + } + ); + +.. code-block:: python + + >>> utf8_test('🎂') + utf-8 is icing on the cake. + 🎂 + + >>> utf8_charptr('🍕') + My favorite food is + 🍕 + +.. note:: + + Some terminal emulators do not support UTF-8 or emoji fonts and may not + display the example above correctly. + +The results are the same whether the C++ function accepts arguments by value or +reference, and whether or not ``const`` is used. + +Passing bytes to C++ +-------------------- + +A Python ``bytes`` object will be passed to C++ functions that accept +``std::string`` or ``char*`` *without* conversion. On Python 3, in order to +make a function *only* accept ``bytes`` (and not ``str``), declare it as taking +a ``py::bytes`` argument. + + +Returning C++ strings to Python +=============================== + +When a C++ function returns a ``std::string`` or ``char*`` to a Python caller, +**pybind11 will assume that the string is valid UTF-8** and will decode it to a +native Python ``str``, using the same API as Python uses to perform +``bytes.decode('utf-8')``. If this implicit conversion fails, pybind11 will +raise a ``UnicodeDecodeError``. + +.. code-block:: c++ + + m.def("std_string_return", + []() { + return std::string("This string needs to be UTF-8 encoded"); + } + ); + +.. code-block:: python + + >>> isinstance(example.std_string_return(), str) + True + + +Because UTF-8 is inclusive of pure ASCII, there is never any issue with +returning a pure ASCII string to Python. If there is any possibility that the +string is not pure ASCII, it is necessary to ensure the encoding is valid +UTF-8. + +.. warning:: + + Implicit conversion assumes that a returned ``char *`` is null-terminated. + If there is no null terminator a buffer overrun will occur. + +Explicit conversions +-------------------- + +If some C++ code constructs a ``std::string`` that is not a UTF-8 string, one +can perform a explicit conversion and return a ``py::str`` object. Explicit +conversion has the same overhead as implicit conversion. + +.. code-block:: c++ + + // This uses the Python C API to convert Latin-1 to Unicode + m.def("str_output", + []() { + std::string s = "Send your r\xe9sum\xe9 to Alice in HR"; // Latin-1 + py::str py_s = PyUnicode_DecodeLatin1(s.data(), s.length()); + return py_s; + } + ); + +.. code-block:: python + + >>> str_output() + 'Send your résumé to Alice in HR' + +The `Python C API +`_ provides +several built-in codecs. + + +One could also use a third party encoding library such as libiconv to transcode +to UTF-8. + +Return C++ strings without conversion +------------------------------------- + +If the data in a C++ ``std::string`` does not represent text and should be +returned to Python as ``bytes``, then one can return the data as a +``py::bytes`` object. + +.. code-block:: c++ + + m.def("return_bytes", + []() { + std::string s("\xba\xd0\xba\xd0"); // Not valid UTF-8 + return py::bytes(s); // Return the data without transcoding + } + ); + +.. code-block:: python + + >>> example.return_bytes() + b'\xba\xd0\xba\xd0' + + +Note the asymmetry: pybind11 will convert ``bytes`` to ``std::string`` without +encoding, but cannot convert ``std::string`` back to ``bytes`` implicitly. + +.. code-block:: c++ + + m.def("asymmetry", + [](std::string s) { // Accepts str or bytes from Python + return s; // Looks harmless, but implicitly converts to str + } + ); + +.. code-block:: python + + >>> isinstance(example.asymmetry(b"have some bytes"), str) + True + + >>> example.asymmetry(b"\xba\xd0\xba\xd0") # invalid utf-8 as bytes + UnicodeDecodeError: 'utf-8' codec can't decode byte 0xba in position 0: invalid start byte + + +Wide character strings +====================== + +When a Python ``str`` is passed to a C++ function expecting ``std::wstring``, +``wchar_t*``, ``std::u16string`` or ``std::u32string``, the ``str`` will be +encoded to UTF-16 or UTF-32 depending on how the C++ compiler implements each +type, in the platform's native endianness. When strings of these types are +returned, they are assumed to contain valid UTF-16 or UTF-32, and will be +decoded to Python ``str``. + +.. code-block:: c++ + + #define UNICODE + #include + + m.def("set_window_text", + [](HWND hwnd, std::wstring s) { + // Call SetWindowText with null-terminated UTF-16 string + ::SetWindowText(hwnd, s.c_str()); + } + ); + m.def("get_window_text", + [](HWND hwnd) { + const int buffer_size = ::GetWindowTextLength(hwnd) + 1; + auto buffer = std::make_unique< wchar_t[] >(buffer_size); + + ::GetWindowText(hwnd, buffer.data(), buffer_size); + + std::wstring text(buffer.get()); + + // wstring will be converted to Python str + return text; + } + ); + +.. warning:: + + Wide character strings may not work as described on Python 2.7 or Python + 3.3 compiled with ``--enable-unicode=ucs2``. + +Strings in multibyte encodings such as Shift-JIS must transcoded to a +UTF-8/16/32 before being returned to Python. + + +Character literals +================== + +C++ functions that accept character literals as input will receive the first +character of a Python ``str`` as their input. If the string is longer than one +Unicode character, trailing characters will be ignored. + +When a character literal is returned from C++ (such as a ``char`` or a +``wchar_t``), it will be converted to a ``str`` that represents the single +character. + +.. code-block:: c++ + + m.def("pass_char", [](char c) { return c; }); + m.def("pass_wchar", [](wchar_t w) { return w; }); + +.. code-block:: python + + >>> example.pass_char('A') + 'A' + +While C++ will cast integers to character types (``char c = 0x65;``), pybind11 +does not convert Python integers to characters implicitly. The Python function +``chr()`` can be used to convert integers to characters. + +.. code-block:: python + + >>> example.pass_char(0x65) + TypeError + + >>> example.pass_char(chr(0x65)) + 'A' + +If the desire is to work with an 8-bit integer, use ``int8_t`` or ``uint8_t`` +as the argument type. + +Grapheme clusters +----------------- + +A single grapheme may be represented by two or more Unicode characters. For +example 'é' is usually represented as U+00E9 but can also be expressed as the +combining character sequence U+0065 U+0301 (that is, the letter 'e' followed by +a combining acute accent). The combining character will be lost if the +two-character sequence is passed as an argument, even though it renders as a +single grapheme. + +.. code-block:: python + + >>> example.pass_wchar('é') + 'é' + + >>> combining_e_acute = 'e' + '\u0301' + + >>> combining_e_acute + 'é' + + >>> combining_e_acute == 'é' + False + + >>> example.pass_wchar(combining_e_acute) + 'e' + +Normalizing combining characters before passing the character literal to C++ +may resolve *some* of these issues: + +.. code-block:: python + + >>> example.pass_wchar(unicodedata.normalize('NFC', combining_e_acute)) + 'é' + +In some languages (Thai for example), there are `graphemes that cannot be +expressed as a single Unicode code point +`_, so there is +no way to capture them in a C++ character type. + + +C++17 string views +================== + +C++17 string views are automatically supported when compiling in C++17 mode. +They follow the same rules for encoding and decoding as the corresponding STL +string type (for example, a ``std::u16string_view`` argument will be passed +UTF-16-encoded data, and a returned ``std::string_view`` will be decoded as +UTF-8). + +References +========== + +* `The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) `_ +* `C++ - Using STL Strings at Win32 API Boundaries `_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/classes.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/classes.rst new file mode 100644 index 0000000000000000000000000000000000000000..ae5907deed8a78d1a13c78c24959c0852a2662f2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/classes.rst @@ -0,0 +1,1126 @@ +Classes +####### + +This section presents advanced binding code for classes and it is assumed +that you are already familiar with the basics from :doc:`/classes`. + +.. _overriding_virtuals: + +Overriding virtual functions in Python +====================================== + +Suppose that a C++ class or interface has a virtual function that we'd like to +to override from within Python (we'll focus on the class ``Animal``; ``Dog`` is +given as a specific example of how one would do this with traditional C++ +code). + +.. code-block:: cpp + + class Animal { + public: + virtual ~Animal() { } + virtual std::string go(int n_times) = 0; + }; + + class Dog : public Animal { + public: + std::string go(int n_times) override { + std::string result; + for (int i=0; igo(3); + } + +Normally, the binding code for these classes would look as follows: + +.. code-block:: cpp + + PYBIND11_MODULE(example, m) { + py::class_(m, "Animal") + .def("go", &Animal::go); + + py::class_(m, "Dog") + .def(py::init<>()); + + m.def("call_go", &call_go); + } + +However, these bindings are impossible to extend: ``Animal`` is not +constructible, and we clearly require some kind of "trampoline" that +redirects virtual calls back to Python. + +Defining a new type of ``Animal`` from within Python is possible but requires a +helper class that is defined as follows: + +.. code-block:: cpp + + class PyAnimal : public Animal { + public: + /* Inherit the constructors */ + using Animal::Animal; + + /* Trampoline (need one for each virtual function) */ + std::string go(int n_times) override { + PYBIND11_OVERLOAD_PURE( + std::string, /* Return type */ + Animal, /* Parent class */ + go, /* Name of function in C++ (must match Python name) */ + n_times /* Argument(s) */ + ); + } + }; + +The macro :c:macro:`PYBIND11_OVERLOAD_PURE` should be used for pure virtual +functions, and :c:macro:`PYBIND11_OVERLOAD` should be used for functions which have +a default implementation. There are also two alternate macros +:c:macro:`PYBIND11_OVERLOAD_PURE_NAME` and :c:macro:`PYBIND11_OVERLOAD_NAME` which +take a string-valued name argument between the *Parent class* and *Name of the +function* slots, which defines the name of function in Python. This is required +when the C++ and Python versions of the +function have different names, e.g. ``operator()`` vs ``__call__``. + +The binding code also needs a few minor adaptations (highlighted): + +.. code-block:: cpp + :emphasize-lines: 2,3 + + PYBIND11_MODULE(example, m) { + py::class_(m, "Animal") + .def(py::init<>()) + .def("go", &Animal::go); + + py::class_(m, "Dog") + .def(py::init<>()); + + m.def("call_go", &call_go); + } + +Importantly, pybind11 is made aware of the trampoline helper class by +specifying it as an extra template argument to :class:`class_`. (This can also +be combined with other template arguments such as a custom holder type; the +order of template types does not matter). Following this, we are able to +define a constructor as usual. + +Bindings should be made against the actual class, not the trampoline helper class. + +.. code-block:: cpp + :emphasize-lines: 3 + + py::class_(m, "Animal"); + .def(py::init<>()) + .def("go", &PyAnimal::go); /* <--- THIS IS WRONG, use &Animal::go */ + +Note, however, that the above is sufficient for allowing python classes to +extend ``Animal``, but not ``Dog``: see :ref:`virtual_and_inheritance` for the +necessary steps required to providing proper overload support for inherited +classes. + +The Python session below shows how to override ``Animal::go`` and invoke it via +a virtual method call. + +.. code-block:: pycon + + >>> from example import * + >>> d = Dog() + >>> call_go(d) + u'woof! woof! woof! ' + >>> class Cat(Animal): + ... def go(self, n_times): + ... return "meow! " * n_times + ... + >>> c = Cat() + >>> call_go(c) + u'meow! meow! meow! ' + +If you are defining a custom constructor in a derived Python class, you *must* +ensure that you explicitly call the bound C++ constructor using ``__init__``, +*regardless* of whether it is a default constructor or not. Otherwise, the +memory for the C++ portion of the instance will be left uninitialized, which +will generally leave the C++ instance in an invalid state and cause undefined +behavior if the C++ instance is subsequently used. + +Here is an example: + +.. code-block:: python + + class Dachshund(Dog): + def __init__(self, name): + Dog.__init__(self) # Without this, undefined behavior may occur if the C++ portions are referenced. + self.name = name + def bark(self): + return "yap!" + +Note that a direct ``__init__`` constructor *should be called*, and ``super()`` +should not be used. For simple cases of linear inheritance, ``super()`` +may work, but once you begin mixing Python and C++ multiple inheritance, +things will fall apart due to differences between Python's MRO and C++'s +mechanisms. + +Please take a look at the :ref:`macro_notes` before using this feature. + +.. note:: + + When the overridden type returns a reference or pointer to a type that + pybind11 converts from Python (for example, numeric values, std::string, + and other built-in value-converting types), there are some limitations to + be aware of: + + - because in these cases there is no C++ variable to reference (the value + is stored in the referenced Python variable), pybind11 provides one in + the PYBIND11_OVERLOAD macros (when needed) with static storage duration. + Note that this means that invoking the overloaded method on *any* + instance will change the referenced value stored in *all* instances of + that type. + + - Attempts to modify a non-const reference will not have the desired + effect: it will change only the static cache variable, but this change + will not propagate to underlying Python instance, and the change will be + replaced the next time the overload is invoked. + +.. seealso:: + + The file :file:`tests/test_virtual_functions.cpp` contains a complete + example that demonstrates how to override virtual functions using pybind11 + in more detail. + +.. _virtual_and_inheritance: + +Combining virtual functions and inheritance +=========================================== + +When combining virtual methods with inheritance, you need to be sure to provide +an override for each method for which you want to allow overrides from derived +python classes. For example, suppose we extend the above ``Animal``/``Dog`` +example as follows: + +.. code-block:: cpp + + class Animal { + public: + virtual std::string go(int n_times) = 0; + virtual std::string name() { return "unknown"; } + }; + class Dog : public Animal { + public: + std::string go(int n_times) override { + std::string result; + for (int i=0; i class PyAnimal : public AnimalBase { + public: + using AnimalBase::AnimalBase; // Inherit constructors + std::string go(int n_times) override { PYBIND11_OVERLOAD_PURE(std::string, AnimalBase, go, n_times); } + std::string name() override { PYBIND11_OVERLOAD(std::string, AnimalBase, name, ); } + }; + template class PyDog : public PyAnimal { + public: + using PyAnimal::PyAnimal; // Inherit constructors + // Override PyAnimal's pure virtual go() with a non-pure one: + std::string go(int n_times) override { PYBIND11_OVERLOAD(std::string, DogBase, go, n_times); } + std::string bark() override { PYBIND11_OVERLOAD(std::string, DogBase, bark, ); } + }; + +This technique has the advantage of requiring just one trampoline method to be +declared per virtual method and pure virtual method override. It does, +however, require the compiler to generate at least as many methods (and +possibly more, if both pure virtual and overridden pure virtual methods are +exposed, as above). + +The classes are then registered with pybind11 using: + +.. code-block:: cpp + + py::class_> animal(m, "Animal"); + py::class_> dog(m, "Dog"); + py::class_> husky(m, "Husky"); + // ... add animal, dog, husky definitions + +Note that ``Husky`` did not require a dedicated trampoline template class at +all, since it neither declares any new virtual methods nor provides any pure +virtual method implementations. + +With either the repeated-virtuals or templated trampoline methods in place, you +can now create a python class that inherits from ``Dog``: + +.. code-block:: python + + class ShihTzu(Dog): + def bark(self): + return "yip!" + +.. seealso:: + + See the file :file:`tests/test_virtual_functions.cpp` for complete examples + using both the duplication and templated trampoline approaches. + +.. _extended_aliases: + +Extended trampoline class functionality +======================================= + +.. _extended_class_functionality_forced_trampoline: + +Forced trampoline class initialisation +-------------------------------------- +The trampoline classes described in the previous sections are, by default, only +initialized when needed. More specifically, they are initialized when a python +class actually inherits from a registered type (instead of merely creating an +instance of the registered type), or when a registered constructor is only +valid for the trampoline class but not the registered class. This is primarily +for performance reasons: when the trampoline class is not needed for anything +except virtual method dispatching, not initializing the trampoline class +improves performance by avoiding needing to do a run-time check to see if the +inheriting python instance has an overloaded method. + +Sometimes, however, it is useful to always initialize a trampoline class as an +intermediate class that does more than just handle virtual method dispatching. +For example, such a class might perform extra class initialization, extra +destruction operations, and might define new members and methods to enable a +more python-like interface to a class. + +In order to tell pybind11 that it should *always* initialize the trampoline +class when creating new instances of a type, the class constructors should be +declared using ``py::init_alias()`` instead of the usual +``py::init()``. This forces construction via the trampoline class, +ensuring member initialization and (eventual) destruction. + +.. seealso:: + + See the file :file:`tests/test_virtual_functions.cpp` for complete examples + showing both normal and forced trampoline instantiation. + +Different method signatures +--------------------------- +The macro's introduced in :ref:`overriding_virtuals` cover most of the standard +use cases when exposing C++ classes to Python. Sometimes it is hard or unwieldy +to create a direct one-on-one mapping between the arguments and method return +type. + +An example would be when the C++ signature contains output arguments using +references (See also :ref:`faq_reference_arguments`). Another way of solving +this is to use the method body of the trampoline class to do conversions to the +input and return of the Python method. + +The main building block to do so is the :func:`get_overload`, this function +allows retrieving a method implemented in Python from within the trampoline's +methods. Consider for example a C++ method which has the signature +``bool myMethod(int32_t& value)``, where the return indicates whether +something should be done with the ``value``. This can be made convenient on the +Python side by allowing the Python function to return ``None`` or an ``int``: + +.. code-block:: cpp + + bool MyClass::myMethod(int32_t& value) + { + pybind11::gil_scoped_acquire gil; // Acquire the GIL while in this scope. + // Try to look up the overloaded method on the Python side. + pybind11::function overload = pybind11::get_overload(this, "myMethod"); + if (overload) { // method is found + auto obj = overload(value); // Call the Python function. + if (py::isinstance(obj)) { // check if it returned a Python integer type + value = obj.cast(); // Cast it and assign it to the value. + return true; // Return true; value should be used. + } else { + return false; // Python returned none, return false. + } + } + return false; // Alternatively return MyClass::myMethod(value); + } + + +.. _custom_constructors: + +Custom constructors +=================== + +The syntax for binding constructors was previously introduced, but it only +works when a constructor of the appropriate arguments actually exists on the +C++ side. To extend this to more general cases, pybind11 makes it possible +to bind factory functions as constructors. For example, suppose you have a +class like this: + +.. code-block:: cpp + + class Example { + private: + Example(int); // private constructor + public: + // Factory function: + static Example create(int a) { return Example(a); } + }; + + py::class_(m, "Example") + .def(py::init(&Example::create)); + +While it is possible to create a straightforward binding of the static +``create`` method, it may sometimes be preferable to expose it as a constructor +on the Python side. This can be accomplished by calling ``.def(py::init(...))`` +with the function reference returning the new instance passed as an argument. +It is also possible to use this approach to bind a function returning a new +instance by raw pointer or by the holder (e.g. ``std::unique_ptr``). + +The following example shows the different approaches: + +.. code-block:: cpp + + class Example { + private: + Example(int); // private constructor + public: + // Factory function - returned by value: + static Example create(int a) { return Example(a); } + + // These constructors are publicly callable: + Example(double); + Example(int, int); + Example(std::string); + }; + + py::class_(m, "Example") + // Bind the factory function as a constructor: + .def(py::init(&Example::create)) + // Bind a lambda function returning a pointer wrapped in a holder: + .def(py::init([](std::string arg) { + return std::unique_ptr(new Example(arg)); + })) + // Return a raw pointer: + .def(py::init([](int a, int b) { return new Example(a, b); })) + // You can mix the above with regular C++ constructor bindings as well: + .def(py::init()) + ; + +When the constructor is invoked from Python, pybind11 will call the factory +function and store the resulting C++ instance in the Python instance. + +When combining factory functions constructors with :ref:`virtual function +trampolines ` there are two approaches. The first is to +add a constructor to the alias class that takes a base value by +rvalue-reference. If such a constructor is available, it will be used to +construct an alias instance from the value returned by the factory function. +The second option is to provide two factory functions to ``py::init()``: the +first will be invoked when no alias class is required (i.e. when the class is +being used but not inherited from in Python), and the second will be invoked +when an alias is required. + +You can also specify a single factory function that always returns an alias +instance: this will result in behaviour similar to ``py::init_alias<...>()``, +as described in the :ref:`extended trampoline class documentation +`. + +The following example shows the different factory approaches for a class with +an alias: + +.. code-block:: cpp + + #include + class Example { + public: + // ... + virtual ~Example() = default; + }; + class PyExample : public Example { + public: + using Example::Example; + PyExample(Example &&base) : Example(std::move(base)) {} + }; + py::class_(m, "Example") + // Returns an Example pointer. If a PyExample is needed, the Example + // instance will be moved via the extra constructor in PyExample, above. + .def(py::init([]() { return new Example(); })) + // Two callbacks: + .def(py::init([]() { return new Example(); } /* no alias needed */, + []() { return new PyExample(); } /* alias needed */)) + // *Always* returns an alias instance (like py::init_alias<>()) + .def(py::init([]() { return new PyExample(); })) + ; + +Brace initialization +-------------------- + +``pybind11::init<>`` internally uses C++11 brace initialization to call the +constructor of the target class. This means that it can be used to bind +*implicit* constructors as well: + +.. code-block:: cpp + + struct Aggregate { + int a; + std::string b; + }; + + py::class_(m, "Aggregate") + .def(py::init()); + +.. note:: + + Note that brace initialization preferentially invokes constructor overloads + taking a ``std::initializer_list``. In the rare event that this causes an + issue, you can work around it by using ``py::init(...)`` with a lambda + function that constructs the new object as desired. + +.. _classes_with_non_public_destructors: + +Non-public destructors +====================== + +If a class has a private or protected destructor (as might e.g. be the case in +a singleton pattern), a compile error will occur when creating bindings via +pybind11. The underlying issue is that the ``std::unique_ptr`` holder type that +is responsible for managing the lifetime of instances will reference the +destructor even if no deallocations ever take place. In order to expose classes +with private or protected destructors, it is possible to override the holder +type via a holder type argument to ``class_``. Pybind11 provides a helper class +``py::nodelete`` that disables any destructor invocations. In this case, it is +crucial that instances are deallocated on the C++ side to avoid memory leaks. + +.. code-block:: cpp + + /* ... definition ... */ + + class MyClass { + private: + ~MyClass() { } + }; + + /* ... binding code ... */ + + py::class_>(m, "MyClass") + .def(py::init<>()) + +.. _implicit_conversions: + +Implicit conversions +==================== + +Suppose that instances of two types ``A`` and ``B`` are used in a project, and +that an ``A`` can easily be converted into an instance of type ``B`` (examples of this +could be a fixed and an arbitrary precision number type). + +.. code-block:: cpp + + py::class_(m, "A") + /// ... members ... + + py::class_(m, "B") + .def(py::init()) + /// ... members ... + + m.def("func", + [](const B &) { /* .... */ } + ); + +To invoke the function ``func`` using a variable ``a`` containing an ``A`` +instance, we'd have to write ``func(B(a))`` in Python. On the other hand, C++ +will automatically apply an implicit type conversion, which makes it possible +to directly write ``func(a)``. + +In this situation (i.e. where ``B`` has a constructor that converts from +``A``), the following statement enables similar implicit conversions on the +Python side: + +.. code-block:: cpp + + py::implicitly_convertible(); + +.. note:: + + Implicit conversions from ``A`` to ``B`` only work when ``B`` is a custom + data type that is exposed to Python via pybind11. + + To prevent runaway recursion, implicit conversions are non-reentrant: an + implicit conversion invoked as part of another implicit conversion of the + same type (i.e. from ``A`` to ``B``) will fail. + +.. _static_properties: + +Static properties +================= + +The section on :ref:`properties` discussed the creation of instance properties +that are implemented in terms of C++ getters and setters. + +Static properties can also be created in a similar way to expose getters and +setters of static class attributes. Note that the implicit ``self`` argument +also exists in this case and is used to pass the Python ``type`` subclass +instance. This parameter will often not be needed by the C++ side, and the +following example illustrates how to instantiate a lambda getter function +that ignores it: + +.. code-block:: cpp + + py::class_(m, "Foo") + .def_property_readonly_static("foo", [](py::object /* self */) { return Foo(); }); + +Operator overloading +==================== + +Suppose that we're given the following ``Vector2`` class with a vector addition +and scalar multiplication operation, all implemented using overloaded operators +in C++. + +.. code-block:: cpp + + class Vector2 { + public: + Vector2(float x, float y) : x(x), y(y) { } + + Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } + Vector2 operator*(float value) const { return Vector2(x * value, y * value); } + Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; } + Vector2& operator*=(float v) { x *= v; y *= v; return *this; } + + friend Vector2 operator*(float f, const Vector2 &v) { + return Vector2(f * v.x, f * v.y); + } + + std::string toString() const { + return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; + } + private: + float x, y; + }; + +The following snippet shows how the above operators can be conveniently exposed +to Python. + +.. code-block:: cpp + + #include + + PYBIND11_MODULE(example, m) { + py::class_(m, "Vector2") + .def(py::init()) + .def(py::self + py::self) + .def(py::self += py::self) + .def(py::self *= float()) + .def(float() * py::self) + .def(py::self * float()) + .def(-py::self) + .def("__repr__", &Vector2::toString); + } + +Note that a line like + +.. code-block:: cpp + + .def(py::self * float()) + +is really just short hand notation for + +.. code-block:: cpp + + .def("__mul__", [](const Vector2 &a, float b) { + return a * b; + }, py::is_operator()) + +This can be useful for exposing additional operators that don't exist on the +C++ side, or to perform other types of customization. The ``py::is_operator`` +flag marker is needed to inform pybind11 that this is an operator, which +returns ``NotImplemented`` when invoked with incompatible arguments rather than +throwing a type error. + +.. note:: + + To use the more convenient ``py::self`` notation, the additional + header file :file:`pybind11/operators.h` must be included. + +.. seealso:: + + The file :file:`tests/test_operator_overloading.cpp` contains a + complete example that demonstrates how to work with overloaded operators in + more detail. + +.. _pickling: + +Pickling support +================ + +Python's ``pickle`` module provides a powerful facility to serialize and +de-serialize a Python object graph into a binary data stream. To pickle and +unpickle C++ classes using pybind11, a ``py::pickle()`` definition must be +provided. Suppose the class in question has the following signature: + +.. code-block:: cpp + + class Pickleable { + public: + Pickleable(const std::string &value) : m_value(value) { } + const std::string &value() const { return m_value; } + + void setExtra(int extra) { m_extra = extra; } + int extra() const { return m_extra; } + private: + std::string m_value; + int m_extra = 0; + }; + +Pickling support in Python is enabled by defining the ``__setstate__`` and +``__getstate__`` methods [#f3]_. For pybind11 classes, use ``py::pickle()`` +to bind these two functions: + +.. code-block:: cpp + + py::class_(m, "Pickleable") + .def(py::init()) + .def("value", &Pickleable::value) + .def("extra", &Pickleable::extra) + .def("setExtra", &Pickleable::setExtra) + .def(py::pickle( + [](const Pickleable &p) { // __getstate__ + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(p.value(), p.extra()); + }, + [](py::tuple t) { // __setstate__ + if (t.size() != 2) + throw std::runtime_error("Invalid state!"); + + /* Create a new C++ instance */ + Pickleable p(t[0].cast()); + + /* Assign any additional state */ + p.setExtra(t[1].cast()); + + return p; + } + )); + +The ``__setstate__`` part of the ``py::picke()`` definition follows the same +rules as the single-argument version of ``py::init()``. The return type can be +a value, pointer or holder type. See :ref:`custom_constructors` for details. + +An instance can now be pickled as follows: + +.. code-block:: python + + try: + import cPickle as pickle # Use cPickle on Python 2.7 + except ImportError: + import pickle + + p = Pickleable("test_value") + p.setExtra(15) + data = pickle.dumps(p, 2) + +Note that only the cPickle module is supported on Python 2.7. The second +argument to ``dumps`` is also crucial: it selects the pickle protocol version +2, since the older version 1 is not supported. Newer versions are also fine—for +instance, specify ``-1`` to always use the latest available version. Beware: +failure to follow these instructions will cause important pybind11 memory +allocation routines to be skipped during unpickling, which will likely lead to +memory corruption and/or segmentation faults. + +.. seealso:: + + The file :file:`tests/test_pickling.cpp` contains a complete example + that demonstrates how to pickle and unpickle types using pybind11 in more + detail. + +.. [#f3] http://docs.python.org/3/library/pickle.html#pickling-class-instances + +Multiple Inheritance +==================== + +pybind11 can create bindings for types that derive from multiple base types +(aka. *multiple inheritance*). To do so, specify all bases in the template +arguments of the ``class_`` declaration: + +.. code-block:: cpp + + py::class_(m, "MyType") + ... + +The base types can be specified in arbitrary order, and they can even be +interspersed with alias types and holder types (discussed earlier in this +document)---pybind11 will automatically find out which is which. The only +requirement is that the first template argument is the type to be declared. + +It is also permitted to inherit multiply from exported C++ classes in Python, +as well as inheriting from multiple Python and/or pybind11-exported classes. + +There is one caveat regarding the implementation of this feature: + +When only one base type is specified for a C++ type that actually has multiple +bases, pybind11 will assume that it does not participate in multiple +inheritance, which can lead to undefined behavior. In such cases, add the tag +``multiple_inheritance`` to the class constructor: + +.. code-block:: cpp + + py::class_(m, "MyType", py::multiple_inheritance()); + +The tag is redundant and does not need to be specified when multiple base types +are listed. + +.. _module_local: + +Module-local class bindings +=========================== + +When creating a binding for a class, pybind11 by default makes that binding +"global" across modules. What this means is that a type defined in one module +can be returned from any module resulting in the same Python type. For +example, this allows the following: + +.. code-block:: cpp + + // In the module1.cpp binding code for module1: + py::class_(m, "Pet") + .def(py::init()) + .def_readonly("name", &Pet::name); + +.. code-block:: cpp + + // In the module2.cpp binding code for module2: + m.def("create_pet", [](std::string name) { return new Pet(name); }); + +.. code-block:: pycon + + >>> from module1 import Pet + >>> from module2 import create_pet + >>> pet1 = Pet("Kitty") + >>> pet2 = create_pet("Doggy") + >>> pet2.name() + 'Doggy' + +When writing binding code for a library, this is usually desirable: this +allows, for example, splitting up a complex library into multiple Python +modules. + +In some cases, however, this can cause conflicts. For example, suppose two +unrelated modules make use of an external C++ library and each provide custom +bindings for one of that library's classes. This will result in an error when +a Python program attempts to import both modules (directly or indirectly) +because of conflicting definitions on the external type: + +.. code-block:: cpp + + // dogs.cpp + + // Binding for external library class: + py::class(m, "Pet") + .def("name", &pets::Pet::name); + + // Binding for local extension class: + py::class(m, "Dog") + .def(py::init()); + +.. code-block:: cpp + + // cats.cpp, in a completely separate project from the above dogs.cpp. + + // Binding for external library class: + py::class(m, "Pet") + .def("get_name", &pets::Pet::name); + + // Binding for local extending class: + py::class(m, "Cat") + .def(py::init()); + +.. code-block:: pycon + + >>> import cats + >>> import dogs + Traceback (most recent call last): + File "", line 1, in + ImportError: generic_type: type "Pet" is already registered! + +To get around this, you can tell pybind11 to keep the external class binding +localized to the module by passing the ``py::module_local()`` attribute into +the ``py::class_`` constructor: + +.. code-block:: cpp + + // Pet binding in dogs.cpp: + py::class(m, "Pet", py::module_local()) + .def("name", &pets::Pet::name); + +.. code-block:: cpp + + // Pet binding in cats.cpp: + py::class(m, "Pet", py::module_local()) + .def("get_name", &pets::Pet::name); + +This makes the Python-side ``dogs.Pet`` and ``cats.Pet`` into distinct classes, +avoiding the conflict and allowing both modules to be loaded. C++ code in the +``dogs`` module that casts or returns a ``Pet`` instance will result in a +``dogs.Pet`` Python instance, while C++ code in the ``cats`` module will result +in a ``cats.Pet`` Python instance. + +This does come with two caveats, however: First, external modules cannot return +or cast a ``Pet`` instance to Python (unless they also provide their own local +bindings). Second, from the Python point of view they are two distinct classes. + +Note that the locality only applies in the C++ -> Python direction. When +passing such a ``py::module_local`` type into a C++ function, the module-local +classes are still considered. This means that if the following function is +added to any module (including but not limited to the ``cats`` and ``dogs`` +modules above) it will be callable with either a ``dogs.Pet`` or ``cats.Pet`` +argument: + +.. code-block:: cpp + + m.def("pet_name", [](const pets::Pet &pet) { return pet.name(); }); + +For example, suppose the above function is added to each of ``cats.cpp``, +``dogs.cpp`` and ``frogs.cpp`` (where ``frogs.cpp`` is some other module that +does *not* bind ``Pets`` at all). + +.. code-block:: pycon + + >>> import cats, dogs, frogs # No error because of the added py::module_local() + >>> mycat, mydog = cats.Cat("Fluffy"), dogs.Dog("Rover") + >>> (cats.pet_name(mycat), dogs.pet_name(mydog)) + ('Fluffy', 'Rover') + >>> (cats.pet_name(mydog), dogs.pet_name(mycat), frogs.pet_name(mycat)) + ('Rover', 'Fluffy', 'Fluffy') + +It is possible to use ``py::module_local()`` registrations in one module even +if another module registers the same type globally: within the module with the +module-local definition, all C++ instances will be cast to the associated bound +Python type. In other modules any such values are converted to the global +Python type created elsewhere. + +.. note:: + + STL bindings (as provided via the optional :file:`pybind11/stl_bind.h` + header) apply ``py::module_local`` by default when the bound type might + conflict with other modules; see :ref:`stl_bind` for details. + +.. note:: + + The localization of the bound types is actually tied to the shared object + or binary generated by the compiler/linker. For typical modules created + with ``PYBIND11_MODULE()``, this distinction is not significant. It is + possible, however, when :ref:`embedding` to embed multiple modules in the + same binary (see :ref:`embedding_modules`). In such a case, the + localization will apply across all embedded modules within the same binary. + +.. seealso:: + + The file :file:`tests/test_local_bindings.cpp` contains additional examples + that demonstrate how ``py::module_local()`` works. + +Binding protected member functions +================================== + +It's normally not possible to expose ``protected`` member functions to Python: + +.. code-block:: cpp + + class A { + protected: + int foo() const { return 42; } + }; + + py::class_(m, "A") + .def("foo", &A::foo); // error: 'foo' is a protected member of 'A' + +On one hand, this is good because non-``public`` members aren't meant to be +accessed from the outside. But we may want to make use of ``protected`` +functions in derived Python classes. + +The following pattern makes this possible: + +.. code-block:: cpp + + class A { + protected: + int foo() const { return 42; } + }; + + class Publicist : public A { // helper type for exposing protected functions + public: + using A::foo; // inherited with different access modifier + }; + + py::class_(m, "A") // bind the primary class + .def("foo", &Publicist::foo); // expose protected methods via the publicist + +This works because ``&Publicist::foo`` is exactly the same function as +``&A::foo`` (same signature and address), just with a different access +modifier. The only purpose of the ``Publicist`` helper class is to make +the function name ``public``. + +If the intent is to expose ``protected`` ``virtual`` functions which can be +overridden in Python, the publicist pattern can be combined with the previously +described trampoline: + +.. code-block:: cpp + + class A { + public: + virtual ~A() = default; + + protected: + virtual int foo() const { return 42; } + }; + + class Trampoline : public A { + public: + int foo() const override { PYBIND11_OVERLOAD(int, A, foo, ); } + }; + + class Publicist : public A { + public: + using A::foo; + }; + + py::class_(m, "A") // <-- `Trampoline` here + .def("foo", &Publicist::foo); // <-- `Publicist` here, not `Trampoline`! + +.. note:: + + MSVC 2015 has a compiler bug (fixed in version 2017) which + requires a more explicit function binding in the form of + ``.def("foo", static_cast(&Publicist::foo));`` + where ``int (A::*)() const`` is the type of ``A::foo``. + +Custom automatic downcasters +============================ + +As explained in :ref:`inheritance`, pybind11 comes with built-in +understanding of the dynamic type of polymorphic objects in C++; that +is, returning a Pet to Python produces a Python object that knows it's +wrapping a Dog, if Pet has virtual methods and pybind11 knows about +Dog and this Pet is in fact a Dog. Sometimes, you might want to +provide this automatic downcasting behavior when creating bindings for +a class hierarchy that does not use standard C++ polymorphism, such as +LLVM [#f4]_. As long as there's some way to determine at runtime +whether a downcast is safe, you can proceed by specializing the +``pybind11::polymorphic_type_hook`` template: + +.. code-block:: cpp + + enum class PetKind { Cat, Dog, Zebra }; + struct Pet { // Not polymorphic: has no virtual methods + const PetKind kind; + int age = 0; + protected: + Pet(PetKind _kind) : kind(_kind) {} + }; + struct Dog : Pet { + Dog() : Pet(PetKind::Dog) {} + std::string sound = "woof!"; + std::string bark() const { return sound; } + }; + + namespace pybind11 { + template<> struct polymorphic_type_hook { + static const void *get(const Pet *src, const std::type_info*& type) { + // note that src may be nullptr + if (src && src->kind == PetKind::Dog) { + type = &typeid(Dog); + return static_cast(src); + } + return src; + } + }; + } // namespace pybind11 + +When pybind11 wants to convert a C++ pointer of type ``Base*`` to a +Python object, it calls ``polymorphic_type_hook::get()`` to +determine if a downcast is possible. The ``get()`` function should use +whatever runtime information is available to determine if its ``src`` +parameter is in fact an instance of some class ``Derived`` that +inherits from ``Base``. If it finds such a ``Derived``, it sets ``type += &typeid(Derived)`` and returns a pointer to the ``Derived`` object +that contains ``src``. Otherwise, it just returns ``src``, leaving +``type`` at its default value of nullptr. If you set ``type`` to a +type that pybind11 doesn't know about, no downcasting will occur, and +the original ``src`` pointer will be used with its static type +``Base*``. + +It is critical that the returned pointer and ``type`` argument of +``get()`` agree with each other: if ``type`` is set to something +non-null, the returned pointer must point to the start of an object +whose type is ``type``. If the hierarchy being exposed uses only +single inheritance, a simple ``return src;`` will achieve this just +fine, but in the general case, you must cast ``src`` to the +appropriate derived-class pointer (e.g. using +``static_cast(src)``) before allowing it to be returned as a +``void*``. + +.. [#f4] https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html + +.. note:: + + pybind11's standard support for downcasting objects whose types + have virtual methods is implemented using + ``polymorphic_type_hook`` too, using the standard C++ ability to + determine the most-derived type of a polymorphic object using + ``typeid()`` and to cast a base pointer to that most-derived type + (even if you don't know what it is) using ``dynamic_cast``. + +.. seealso:: + + The file :file:`tests/test_tagbased_polymorphic.cpp` contains a + more complete example, including a demonstration of how to provide + automatic downcasting for an entire class hierarchy without + writing one get() function for each class. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/embedding.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/embedding.rst new file mode 100644 index 0000000000000000000000000000000000000000..3930316032b047021ee41b9d8928509a1b55f0ce --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/embedding.rst @@ -0,0 +1,261 @@ +.. _embedding: + +Embedding the interpreter +######################### + +While pybind11 is mainly focused on extending Python using C++, it's also +possible to do the reverse: embed the Python interpreter into a C++ program. +All of the other documentation pages still apply here, so refer to them for +general pybind11 usage. This section will cover a few extra things required +for embedding. + +Getting started +=============== + +A basic executable with an embedded interpreter can be created with just a few +lines of CMake and the ``pybind11::embed`` target, as shown below. For more +information, see :doc:`/compiling`. + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.0) + project(example) + + find_package(pybind11 REQUIRED) # or `add_subdirectory(pybind11)` + + add_executable(example main.cpp) + target_link_libraries(example PRIVATE pybind11::embed) + +The essential structure of the ``main.cpp`` file looks like this: + +.. code-block:: cpp + + #include // everything needed for embedding + namespace py = pybind11; + + int main() { + py::scoped_interpreter guard{}; // start the interpreter and keep it alive + + py::print("Hello, World!"); // use the Python API + } + +The interpreter must be initialized before using any Python API, which includes +all the functions and classes in pybind11. The RAII guard class `scoped_interpreter` +takes care of the interpreter lifetime. After the guard is destroyed, the interpreter +shuts down and clears its memory. No Python functions can be called after this. + +Executing Python code +===================== + +There are a few different ways to run Python code. One option is to use `eval`, +`exec` or `eval_file`, as explained in :ref:`eval`. Here is a quick example in +the context of an executable with an embedded interpreter: + +.. code-block:: cpp + + #include + namespace py = pybind11; + + int main() { + py::scoped_interpreter guard{}; + + py::exec(R"( + kwargs = dict(name="World", number=42) + message = "Hello, {name}! The answer is {number}".format(**kwargs) + print(message) + )"); + } + +Alternatively, similar results can be achieved using pybind11's API (see +:doc:`/advanced/pycpp/index` for more details). + +.. code-block:: cpp + + #include + namespace py = pybind11; + using namespace py::literals; + + int main() { + py::scoped_interpreter guard{}; + + auto kwargs = py::dict("name"_a="World", "number"_a=42); + auto message = "Hello, {name}! The answer is {number}"_s.format(**kwargs); + py::print(message); + } + +The two approaches can also be combined: + +.. code-block:: cpp + + #include + #include + + namespace py = pybind11; + using namespace py::literals; + + int main() { + py::scoped_interpreter guard{}; + + auto locals = py::dict("name"_a="World", "number"_a=42); + py::exec(R"( + message = "Hello, {name}! The answer is {number}".format(**locals()) + )", py::globals(), locals); + + auto message = locals["message"].cast(); + std::cout << message; + } + +Importing modules +================= + +Python modules can be imported using `module::import()`: + +.. code-block:: cpp + + py::module sys = py::module::import("sys"); + py::print(sys.attr("path")); + +For convenience, the current working directory is included in ``sys.path`` when +embedding the interpreter. This makes it easy to import local Python files: + +.. code-block:: python + + """calc.py located in the working directory""" + + def add(i, j): + return i + j + + +.. code-block:: cpp + + py::module calc = py::module::import("calc"); + py::object result = calc.attr("add")(1, 2); + int n = result.cast(); + assert(n == 3); + +Modules can be reloaded using `module::reload()` if the source is modified e.g. +by an external process. This can be useful in scenarios where the application +imports a user defined data processing script which needs to be updated after +changes by the user. Note that this function does not reload modules recursively. + +.. _embedding_modules: + +Adding embedded modules +======================= + +Embedded binary modules can be added using the `PYBIND11_EMBEDDED_MODULE` macro. +Note that the definition must be placed at global scope. They can be imported +like any other module. + +.. code-block:: cpp + + #include + namespace py = pybind11; + + PYBIND11_EMBEDDED_MODULE(fast_calc, m) { + // `m` is a `py::module` which is used to bind functions and classes + m.def("add", [](int i, int j) { + return i + j; + }); + } + + int main() { + py::scoped_interpreter guard{}; + + auto fast_calc = py::module::import("fast_calc"); + auto result = fast_calc.attr("add")(1, 2).cast(); + assert(result == 3); + } + +Unlike extension modules where only a single binary module can be created, on +the embedded side an unlimited number of modules can be added using multiple +`PYBIND11_EMBEDDED_MODULE` definitions (as long as they have unique names). + +These modules are added to Python's list of builtins, so they can also be +imported in pure Python files loaded by the interpreter. Everything interacts +naturally: + +.. code-block:: python + + """py_module.py located in the working directory""" + import cpp_module + + a = cpp_module.a + b = a + 1 + + +.. code-block:: cpp + + #include + namespace py = pybind11; + + PYBIND11_EMBEDDED_MODULE(cpp_module, m) { + m.attr("a") = 1; + } + + int main() { + py::scoped_interpreter guard{}; + + auto py_module = py::module::import("py_module"); + + auto locals = py::dict("fmt"_a="{} + {} = {}", **py_module.attr("__dict__")); + assert(locals["a"].cast() == 1); + assert(locals["b"].cast() == 2); + + py::exec(R"( + c = a + b + message = fmt.format(a, b, c) + )", py::globals(), locals); + + assert(locals["c"].cast() == 3); + assert(locals["message"].cast() == "1 + 2 = 3"); + } + + +Interpreter lifetime +==================== + +The Python interpreter shuts down when `scoped_interpreter` is destroyed. After +this, creating a new instance will restart the interpreter. Alternatively, the +`initialize_interpreter` / `finalize_interpreter` pair of functions can be used +to directly set the state at any time. + +Modules created with pybind11 can be safely re-initialized after the interpreter +has been restarted. However, this may not apply to third-party extension modules. +The issue is that Python itself cannot completely unload extension modules and +there are several caveats with regard to interpreter restarting. In short, not +all memory may be freed, either due to Python reference cycles or user-created +global data. All the details can be found in the CPython documentation. + +.. warning:: + + Creating two concurrent `scoped_interpreter` guards is a fatal error. So is + calling `initialize_interpreter` for a second time after the interpreter + has already been initialized. + + Do not use the raw CPython API functions ``Py_Initialize`` and + ``Py_Finalize`` as these do not properly handle the lifetime of + pybind11's internal data. + + +Sub-interpreter support +======================= + +Creating multiple copies of `scoped_interpreter` is not possible because it +represents the main Python interpreter. Sub-interpreters are something different +and they do permit the existence of multiple interpreters. This is an advanced +feature of the CPython API and should be handled with care. pybind11 does not +currently offer a C++ interface for sub-interpreters, so refer to the CPython +documentation for all the details regarding this feature. + +We'll just mention a couple of caveats the sub-interpreters support in pybind11: + + 1. Sub-interpreters will not receive independent copies of embedded modules. + Instead, these are shared and modifications in one interpreter may be + reflected in another. + + 2. Managing multiple threads, multiple interpreters and the GIL can be + challenging and there are several caveats here, even within the pure + CPython API (please refer to the Python docs for details). As for + pybind11, keep in mind that `gil_scoped_release` and `gil_scoped_acquire` + do not take sub-interpreters into account. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/exceptions.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/exceptions.rst new file mode 100644 index 0000000000000000000000000000000000000000..75ad7f7f4a527a93a41eb0785e2beb8419208014 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/exceptions.rst @@ -0,0 +1,144 @@ +Exceptions +########## + +Built-in exception translation +============================== + +When C++ code invoked from Python throws an ``std::exception``, it is +automatically converted into a Python ``Exception``. pybind11 defines multiple +special exception classes that will map to different types of Python +exceptions: + +.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}| + ++--------------------------------------+--------------------------------------+ +| C++ exception type | Python exception type | ++======================================+======================================+ +| :class:`std::exception` | ``RuntimeError`` | ++--------------------------------------+--------------------------------------+ +| :class:`std::bad_alloc` | ``MemoryError`` | ++--------------------------------------+--------------------------------------+ +| :class:`std::domain_error` | ``ValueError`` | ++--------------------------------------+--------------------------------------+ +| :class:`std::invalid_argument` | ``ValueError`` | ++--------------------------------------+--------------------------------------+ +| :class:`std::length_error` | ``ValueError`` | ++--------------------------------------+--------------------------------------+ +| :class:`std::out_of_range` | ``IndexError`` | ++--------------------------------------+--------------------------------------+ +| :class:`std::range_error` | ``ValueError`` | ++--------------------------------------+--------------------------------------+ +| :class:`std::overflow_error` | ``OverflowError`` | ++--------------------------------------+--------------------------------------+ +| :class:`pybind11::stop_iteration` | ``StopIteration`` (used to implement | +| | custom iterators) | ++--------------------------------------+--------------------------------------+ +| :class:`pybind11::index_error` | ``IndexError`` (used to indicate out | +| | of bounds access in ``__getitem__``, | +| | ``__setitem__``, etc.) | ++--------------------------------------+--------------------------------------+ +| :class:`pybind11::value_error` | ``ValueError`` (used to indicate | +| | wrong value passed in | +| | ``container.remove(...)``) | ++--------------------------------------+--------------------------------------+ +| :class:`pybind11::key_error` | ``KeyError`` (used to indicate out | +| | of bounds access in ``__getitem__``, | +| | ``__setitem__`` in dict-like | +| | objects, etc.) | ++--------------------------------------+--------------------------------------+ +| :class:`pybind11::error_already_set` | Indicates that the Python exception | +| | flag has already been set via Python | +| | API calls from C++ code; this C++ | +| | exception is used to propagate such | +| | a Python exception back to Python. | ++--------------------------------------+--------------------------------------+ + +When a Python function invoked from C++ throws an exception, it is converted +into a C++ exception of type :class:`error_already_set` whose string payload +contains a textual summary. + +There is also a special exception :class:`cast_error` that is thrown by +:func:`handle::call` when the input arguments cannot be converted to Python +objects. + +Registering custom translators +============================== + +If the default exception conversion policy described above is insufficient, +pybind11 also provides support for registering custom exception translators. +To register a simple exception conversion that translates a C++ exception into +a new Python exception using the C++ exception's ``what()`` method, a helper +function is available: + +.. code-block:: cpp + + py::register_exception(module, "PyExp"); + +This call creates a Python exception class with the name ``PyExp`` in the given +module and automatically converts any encountered exceptions of type ``CppExp`` +into Python exceptions of type ``PyExp``. + +When more advanced exception translation is needed, the function +``py::register_exception_translator(translator)`` can be used to register +functions that can translate arbitrary exception types (and which may include +additional logic to do so). The function takes a stateless callable (e.g. a +function pointer or a lambda function without captured variables) with the call +signature ``void(std::exception_ptr)``. + +When a C++ exception is thrown, the registered exception translators are tried +in reverse order of registration (i.e. the last registered translator gets the +first shot at handling the exception). + +Inside the translator, ``std::rethrow_exception`` should be used within +a try block to re-throw the exception. One or more catch clauses to catch +the appropriate exceptions should then be used with each clause using +``PyErr_SetString`` to set a Python exception or ``ex(string)`` to set +the python exception to a custom exception type (see below). + +To declare a custom Python exception type, declare a ``py::exception`` variable +and use this in the associated exception translator (note: it is often useful +to make this a static declaration when using it inside a lambda expression +without requiring capturing). + + +The following example demonstrates this for a hypothetical exception classes +``MyCustomException`` and ``OtherException``: the first is translated to a +custom python exception ``MyCustomError``, while the second is translated to a +standard python RuntimeError: + +.. code-block:: cpp + + static py::exception exc(m, "MyCustomError"); + py::register_exception_translator([](std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (const MyCustomException &e) { + exc(e.what()); + } catch (const OtherException &e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + } + }); + +Multiple exceptions can be handled by a single translator, as shown in the +example above. If the exception is not caught by the current translator, the +previously registered one gets a chance. + +If none of the registered exception translators is able to handle the +exception, it is handled by the default converter as described in the previous +section. + +.. seealso:: + + The file :file:`tests/test_exceptions.cpp` contains examples + of various custom exception translators and custom exception types. + +.. note:: + + You must call either ``PyErr_SetString`` or a custom exception's call + operator (``exc(string)``) for every exception caught in a custom exception + translator. Failure to do so will cause Python to crash with ``SystemError: + error return without exception set``. + + Exceptions that you do not plan to handle should simply not be caught, or + may be explicitly (re-)thrown to delegate it to the other, + previously-declared existing exception translators. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/functions.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/functions.rst new file mode 100644 index 0000000000000000000000000000000000000000..3e1a3ff0e8ea89c18b1a80f97e9b03aa54771560 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/functions.rst @@ -0,0 +1,507 @@ +Functions +######### + +Before proceeding with this section, make sure that you are already familiar +with the basics of binding functions and classes, as explained in :doc:`/basics` +and :doc:`/classes`. The following guide is applicable to both free and member +functions, i.e. *methods* in Python. + +.. _return_value_policies: + +Return value policies +===================== + +Python and C++ use fundamentally different ways of managing the memory and +lifetime of objects managed by them. This can lead to issues when creating +bindings for functions that return a non-trivial type. Just by looking at the +type information, it is not clear whether Python should take charge of the +returned value and eventually free its resources, or if this is handled on the +C++ side. For this reason, pybind11 provides a several *return value policy* +annotations that can be passed to the :func:`module::def` and +:func:`class_::def` functions. The default policy is +:enum:`return_value_policy::automatic`. + +Return value policies are tricky, and it's very important to get them right. +Just to illustrate what can go wrong, consider the following simple example: + +.. code-block:: cpp + + /* Function declaration */ + Data *get_data() { return _data; /* (pointer to a static data structure) */ } + ... + + /* Binding code */ + m.def("get_data", &get_data); // <-- KABOOM, will cause crash when called from Python + +What's going on here? When ``get_data()`` is called from Python, the return +value (a native C++ type) must be wrapped to turn it into a usable Python type. +In this case, the default return value policy (:enum:`return_value_policy::automatic`) +causes pybind11 to assume ownership of the static ``_data`` instance. + +When Python's garbage collector eventually deletes the Python +wrapper, pybind11 will also attempt to delete the C++ instance (via ``operator +delete()``) due to the implied ownership. At this point, the entire application +will come crashing down, though errors could also be more subtle and involve +silent data corruption. + +In the above example, the policy :enum:`return_value_policy::reference` should have +been specified so that the global data instance is only *referenced* without any +implied transfer of ownership, i.e.: + +.. code-block:: cpp + + m.def("get_data", &get_data, return_value_policy::reference); + +On the other hand, this is not the right policy for many other situations, +where ignoring ownership could lead to resource leaks. +As a developer using pybind11, it's important to be familiar with the different +return value policies, including which situation calls for which one of them. +The following table provides an overview of available policies: + +.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}| + ++--------------------------------------------------+----------------------------------------------------------------------------+ +| Return value policy | Description | ++==================================================+============================================================================+ +| :enum:`return_value_policy::take_ownership` | Reference an existing object (i.e. do not create a new copy) and take | +| | ownership. Python will call the destructor and delete operator when the | +| | object's reference count reaches zero. Undefined behavior ensues when the | +| | C++ side does the same, or when the data was not dynamically allocated. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::copy` | Create a new copy of the returned object, which will be owned by Python. | +| | This policy is comparably safe because the lifetimes of the two instances | +| | are decoupled. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::move` | Use ``std::move`` to move the return value contents into a new instance | +| | that will be owned by Python. This policy is comparably safe because the | +| | lifetimes of the two instances (move source and destination) are decoupled.| ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::reference` | Reference an existing object, but do not take ownership. The C++ side is | +| | responsible for managing the object's lifetime and deallocating it when | +| | it is no longer used. Warning: undefined behavior will ensue when the C++ | +| | side deletes an object that is still referenced and used by Python. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::reference_internal` | Indicates that the lifetime of the return value is tied to the lifetime | +| | of a parent object, namely the implicit ``this``, or ``self`` argument of | +| | the called method or property. Internally, this policy works just like | +| | :enum:`return_value_policy::reference` but additionally applies a | +| | ``keep_alive<0, 1>`` *call policy* (described in the next section) that | +| | prevents the parent object from being garbage collected as long as the | +| | return value is referenced by Python. This is the default policy for | +| | property getters created via ``def_property``, ``def_readwrite``, etc. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::automatic` | **Default policy.** This policy falls back to the policy | +| | :enum:`return_value_policy::take_ownership` when the return value is a | +| | pointer. Otherwise, it uses :enum:`return_value_policy::move` or | +| | :enum:`return_value_policy::copy` for rvalue and lvalue references, | +| | respectively. See above for a description of what all of these different | +| | policies do. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::automatic_reference` | As above, but use policy :enum:`return_value_policy::reference` when the | +| | return value is a pointer. This is the default conversion policy for | +| | function arguments when calling Python functions manually from C++ code | +| | (i.e. via handle::operator()). You probably won't need to use this. | ++--------------------------------------------------+----------------------------------------------------------------------------+ + +Return value policies can also be applied to properties: + +.. code-block:: cpp + + class_(m, "MyClass") + .def_property("data", &MyClass::getData, &MyClass::setData, + py::return_value_policy::copy); + +Technically, the code above applies the policy to both the getter and the +setter function, however, the setter doesn't really care about *return* +value policies which makes this a convenient terse syntax. Alternatively, +targeted arguments can be passed through the :class:`cpp_function` constructor: + +.. code-block:: cpp + + class_(m, "MyClass") + .def_property("data" + py::cpp_function(&MyClass::getData, py::return_value_policy::copy), + py::cpp_function(&MyClass::setData) + ); + +.. warning:: + + Code with invalid return value policies might access uninitialized memory or + free data structures multiple times, which can lead to hard-to-debug + non-determinism and segmentation faults, hence it is worth spending the + time to understand all the different options in the table above. + +.. note:: + + One important aspect of the above policies is that they only apply to + instances which pybind11 has *not* seen before, in which case the policy + clarifies essential questions about the return value's lifetime and + ownership. When pybind11 knows the instance already (as identified by its + type and address in memory), it will return the existing Python object + wrapper rather than creating a new copy. + +.. note:: + + The next section on :ref:`call_policies` discusses *call policies* that can be + specified *in addition* to a return value policy from the list above. Call + policies indicate reference relationships that can involve both return values + and parameters of functions. + +.. note:: + + As an alternative to elaborate call policies and lifetime management logic, + consider using smart pointers (see the section on :ref:`smart_pointers` for + details). Smart pointers can tell whether an object is still referenced from + C++ or Python, which generally eliminates the kinds of inconsistencies that + can lead to crashes or undefined behavior. For functions returning smart + pointers, it is not necessary to specify a return value policy. + +.. _call_policies: + +Additional call policies +======================== + +In addition to the above return value policies, further *call policies* can be +specified to indicate dependencies between parameters or ensure a certain state +for the function call. + +Keep alive +---------- + +In general, this policy is required when the C++ object is any kind of container +and another object is being added to the container. ``keep_alive`` +indicates that the argument with index ``Patient`` should be kept alive at least +until the argument with index ``Nurse`` is freed by the garbage collector. Argument +indices start at one, while zero refers to the return value. For methods, index +``1`` refers to the implicit ``this`` pointer, while regular arguments begin at +index ``2``. Arbitrarily many call policies can be specified. When a ``Nurse`` +with value ``None`` is detected at runtime, the call policy does nothing. + +When the nurse is not a pybind11-registered type, the implementation internally +relies on the ability to create a *weak reference* to the nurse object. When +the nurse object is not a pybind11-registered type and does not support weak +references, an exception will be thrown. + +Consider the following example: here, the binding code for a list append +operation ties the lifetime of the newly added element to the underlying +container: + +.. code-block:: cpp + + py::class_(m, "List") + .def("append", &List::append, py::keep_alive<1, 2>()); + +For consistency, the argument indexing is identical for constructors. Index +``1`` still refers to the implicit ``this`` pointer, i.e. the object which is +being constructed. Index ``0`` refers to the return type which is presumed to +be ``void`` when a constructor is viewed like a function. The following example +ties the lifetime of the constructor element to the constructed object: + +.. code-block:: cpp + + py::class_(m, "Nurse") + .def(py::init(), py::keep_alive<1, 2>()); + +.. note:: + + ``keep_alive`` is analogous to the ``with_custodian_and_ward`` (if Nurse, + Patient != 0) and ``with_custodian_and_ward_postcall`` (if Nurse/Patient == + 0) policies from Boost.Python. + +Call guard +---------- + +The ``call_guard`` policy allows any scope guard type ``T`` to be placed +around the function call. For example, this definition: + +.. code-block:: cpp + + m.def("foo", foo, py::call_guard()); + +is equivalent to the following pseudocode: + +.. code-block:: cpp + + m.def("foo", [](args...) { + T scope_guard; + return foo(args...); // forwarded arguments + }); + +The only requirement is that ``T`` is default-constructible, but otherwise any +scope guard will work. This is very useful in combination with `gil_scoped_release`. +See :ref:`gil`. + +Multiple guards can also be specified as ``py::call_guard``. The +constructor order is left to right and destruction happens in reverse. + +.. seealso:: + + The file :file:`tests/test_call_policies.cpp` contains a complete example + that demonstrates using `keep_alive` and `call_guard` in more detail. + +.. _python_objects_as_args: + +Python objects as arguments +=========================== + +pybind11 exposes all major Python types using thin C++ wrapper classes. These +wrapper classes can also be used as parameters of functions in bindings, which +makes it possible to directly work with native Python types on the C++ side. +For instance, the following statement iterates over a Python ``dict``: + +.. code-block:: cpp + + void print_dict(py::dict dict) { + /* Easily interact with Python types */ + for (auto item : dict) + std::cout << "key=" << std::string(py::str(item.first)) << ", " + << "value=" << std::string(py::str(item.second)) << std::endl; + } + +It can be exported: + +.. code-block:: cpp + + m.def("print_dict", &print_dict); + +And used in Python as usual: + +.. code-block:: pycon + + >>> print_dict({'foo': 123, 'bar': 'hello'}) + key=foo, value=123 + key=bar, value=hello + +For more information on using Python objects in C++, see :doc:`/advanced/pycpp/index`. + +Accepting \*args and \*\*kwargs +=============================== + +Python provides a useful mechanism to define functions that accept arbitrary +numbers of arguments and keyword arguments: + +.. code-block:: python + + def generic(*args, **kwargs): + ... # do something with args and kwargs + +Such functions can also be created using pybind11: + +.. code-block:: cpp + + void generic(py::args args, py::kwargs kwargs) { + /// .. do something with args + if (kwargs) + /// .. do something with kwargs + } + + /// Binding code + m.def("generic", &generic); + +The class ``py::args`` derives from ``py::tuple`` and ``py::kwargs`` derives +from ``py::dict``. + +You may also use just one or the other, and may combine these with other +arguments as long as the ``py::args`` and ``py::kwargs`` arguments are the last +arguments accepted by the function. + +Please refer to the other examples for details on how to iterate over these, +and on how to cast their entries into C++ objects. A demonstration is also +available in ``tests/test_kwargs_and_defaults.cpp``. + +.. note:: + + When combining \*args or \*\*kwargs with :ref:`keyword_args` you should + *not* include ``py::arg`` tags for the ``py::args`` and ``py::kwargs`` + arguments. + +Default arguments revisited +=========================== + +The section on :ref:`default_args` previously discussed basic usage of default +arguments using pybind11. One noteworthy aspect of their implementation is that +default arguments are converted to Python objects right at declaration time. +Consider the following example: + +.. code-block:: cpp + + py::class_("MyClass") + .def("myFunction", py::arg("arg") = SomeType(123)); + +In this case, pybind11 must already be set up to deal with values of the type +``SomeType`` (via a prior instantiation of ``py::class_``), or an +exception will be thrown. + +Another aspect worth highlighting is that the "preview" of the default argument +in the function signature is generated using the object's ``__repr__`` method. +If not available, the signature may not be very helpful, e.g.: + +.. code-block:: pycon + + FUNCTIONS + ... + | myFunction(...) + | Signature : (MyClass, arg : SomeType = ) -> NoneType + ... + +The first way of addressing this is by defining ``SomeType.__repr__``. +Alternatively, it is possible to specify the human-readable preview of the +default argument manually using the ``arg_v`` notation: + +.. code-block:: cpp + + py::class_("MyClass") + .def("myFunction", py::arg_v("arg", SomeType(123), "SomeType(123)")); + +Sometimes it may be necessary to pass a null pointer value as a default +argument. In this case, remember to cast it to the underlying type in question, +like so: + +.. code-block:: cpp + + py::class_("MyClass") + .def("myFunction", py::arg("arg") = (SomeType *) nullptr); + +.. _nonconverting_arguments: + +Non-converting arguments +======================== + +Certain argument types may support conversion from one type to another. Some +examples of conversions are: + +* :ref:`implicit_conversions` declared using ``py::implicitly_convertible()`` +* Calling a method accepting a double with an integer argument +* Calling a ``std::complex`` argument with a non-complex python type + (for example, with a float). (Requires the optional ``pybind11/complex.h`` + header). +* Calling a function taking an Eigen matrix reference with a numpy array of the + wrong type or of an incompatible data layout. (Requires the optional + ``pybind11/eigen.h`` header). + +This behaviour is sometimes undesirable: the binding code may prefer to raise +an error rather than convert the argument. This behaviour can be obtained +through ``py::arg`` by calling the ``.noconvert()`` method of the ``py::arg`` +object, such as: + +.. code-block:: cpp + + m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert()); + m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f")); + +Attempting the call the second function (the one without ``.noconvert()``) with +an integer will succeed, but attempting to call the ``.noconvert()`` version +will fail with a ``TypeError``: + +.. code-block:: pycon + + >>> floats_preferred(4) + 2.0 + >>> floats_only(4) + Traceback (most recent call last): + File "", line 1, in + TypeError: floats_only(): incompatible function arguments. The following argument types are supported: + 1. (f: float) -> float + + Invoked with: 4 + +You may, of course, combine this with the :var:`_a` shorthand notation (see +:ref:`keyword_args`) and/or :ref:`default_args`. It is also permitted to omit +the argument name by using the ``py::arg()`` constructor without an argument +name, i.e. by specifying ``py::arg().noconvert()``. + +.. note:: + + When specifying ``py::arg`` options it is necessary to provide the same + number of options as the bound function has arguments. Thus if you want to + enable no-convert behaviour for just one of several arguments, you will + need to specify a ``py::arg()`` annotation for each argument with the + no-convert argument modified to ``py::arg().noconvert()``. + +.. _none_arguments: + +Allow/Prohibiting None arguments +================================ + +When a C++ type registered with :class:`py::class_` is passed as an argument to +a function taking the instance as pointer or shared holder (e.g. ``shared_ptr`` +or a custom, copyable holder as described in :ref:`smart_pointers`), pybind +allows ``None`` to be passed from Python which results in calling the C++ +function with ``nullptr`` (or an empty holder) for the argument. + +To explicitly enable or disable this behaviour, using the +``.none`` method of the :class:`py::arg` object: + +.. code-block:: cpp + + py::class_(m, "Dog").def(py::init<>()); + py::class_(m, "Cat").def(py::init<>()); + m.def("bark", [](Dog *dog) -> std::string { + if (dog) return "woof!"; /* Called with a Dog instance */ + else return "(no dog)"; /* Called with None, dog == nullptr */ + }, py::arg("dog").none(true)); + m.def("meow", [](Cat *cat) -> std::string { + // Can't be called with None argument + return "meow"; + }, py::arg("cat").none(false)); + +With the above, the Python call ``bark(None)`` will return the string ``"(no +dog)"``, while attempting to call ``meow(None)`` will raise a ``TypeError``: + +.. code-block:: pycon + + >>> from animals import Dog, Cat, bark, meow + >>> bark(Dog()) + 'woof!' + >>> meow(Cat()) + 'meow' + >>> bark(None) + '(no dog)' + >>> meow(None) + Traceback (most recent call last): + File "", line 1, in + TypeError: meow(): incompatible function arguments. The following argument types are supported: + 1. (cat: animals.Cat) -> str + + Invoked with: None + +The default behaviour when the tag is unspecified is to allow ``None``. + +.. note:: + + Even when ``.none(true)`` is specified for an argument, ``None`` will be converted to a + ``nullptr`` *only* for custom and :ref:`opaque ` types. Pointers to built-in types + (``double *``, ``int *``, ...) and STL types (``std::vector *``, ...; if ``pybind11/stl.h`` + is included) are copied when converted to C++ (see :doc:`/advanced/cast/overview`) and will + not allow ``None`` as argument. To pass optional argument of these copied types consider + using ``std::optional`` + +Overload resolution order +========================= + +When a function or method with multiple overloads is called from Python, +pybind11 determines which overload to call in two passes. The first pass +attempts to call each overload without allowing argument conversion (as if +every argument had been specified as ``py::arg().noconvert()`` as described +above). + +If no overload succeeds in the no-conversion first pass, a second pass is +attempted in which argument conversion is allowed (except where prohibited via +an explicit ``py::arg().noconvert()`` attribute in the function definition). + +If the second pass also fails a ``TypeError`` is raised. + +Within each pass, overloads are tried in the order they were registered with +pybind11. + +What this means in practice is that pybind11 will prefer any overload that does +not require conversion of arguments to an overload that does, but otherwise prefers +earlier-defined overloads to later-defined ones. + +.. note:: + + pybind11 does *not* further prioritize based on the number/pattern of + overloaded arguments. That is, pybind11 does not prioritize a function + requiring one conversion over one requiring three, but only prioritizes + overloads requiring no conversion at all to overloads that require + conversion of at least one argument. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/misc.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/misc.rst new file mode 100644 index 0000000000000000000000000000000000000000..5b38ec7598703b5a29663dedfc92c183d66c1b70 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/misc.rst @@ -0,0 +1,306 @@ +Miscellaneous +############# + +.. _macro_notes: + +General notes regarding convenience macros +========================================== + +pybind11 provides a few convenience macros such as +:func:`PYBIND11_DECLARE_HOLDER_TYPE` and ``PYBIND11_OVERLOAD_*``. Since these +are "just" macros that are evaluated in the preprocessor (which has no concept +of types), they *will* get confused by commas in a template argument; for +example, consider: + +.. code-block:: cpp + + PYBIND11_OVERLOAD(MyReturnType, Class, func) + +The limitation of the C preprocessor interprets this as five arguments (with new +arguments beginning after each comma) rather than three. To get around this, +there are two alternatives: you can use a type alias, or you can wrap the type +using the ``PYBIND11_TYPE`` macro: + +.. code-block:: cpp + + // Version 1: using a type alias + using ReturnType = MyReturnType; + using ClassType = Class; + PYBIND11_OVERLOAD(ReturnType, ClassType, func); + + // Version 2: using the PYBIND11_TYPE macro: + PYBIND11_OVERLOAD(PYBIND11_TYPE(MyReturnType), + PYBIND11_TYPE(Class), func) + +The ``PYBIND11_MAKE_OPAQUE`` macro does *not* require the above workarounds. + +.. _gil: + +Global Interpreter Lock (GIL) +============================= + +When calling a C++ function from Python, the GIL is always held. +The classes :class:`gil_scoped_release` and :class:`gil_scoped_acquire` can be +used to acquire and release the global interpreter lock in the body of a C++ +function call. In this way, long-running C++ code can be parallelized using +multiple Python threads. Taking :ref:`overriding_virtuals` as an example, this +could be realized as follows (important changes highlighted): + +.. code-block:: cpp + :emphasize-lines: 8,9,31,32 + + class PyAnimal : public Animal { + public: + /* Inherit the constructors */ + using Animal::Animal; + + /* Trampoline (need one for each virtual function) */ + std::string go(int n_times) { + /* Acquire GIL before calling Python code */ + py::gil_scoped_acquire acquire; + + PYBIND11_OVERLOAD_PURE( + std::string, /* Return type */ + Animal, /* Parent class */ + go, /* Name of function */ + n_times /* Argument(s) */ + ); + } + }; + + PYBIND11_MODULE(example, m) { + py::class_ animal(m, "Animal"); + animal + .def(py::init<>()) + .def("go", &Animal::go); + + py::class_(m, "Dog", animal) + .def(py::init<>()); + + m.def("call_go", [](Animal *animal) -> std::string { + /* Release GIL before calling into (potentially long-running) C++ code */ + py::gil_scoped_release release; + return call_go(animal); + }); + } + +The ``call_go`` wrapper can also be simplified using the `call_guard` policy +(see :ref:`call_policies`) which yields the same result: + +.. code-block:: cpp + + m.def("call_go", &call_go, py::call_guard()); + + +Binding sequence data types, iterators, the slicing protocol, etc. +================================================================== + +Please refer to the supplemental example for details. + +.. seealso:: + + The file :file:`tests/test_sequences_and_iterators.cpp` contains a + complete example that shows how to bind a sequence data type, including + length queries (``__len__``), iterators (``__iter__``), the slicing + protocol and other kinds of useful operations. + + +Partitioning code over multiple extension modules +================================================= + +It's straightforward to split binding code over multiple extension modules, +while referencing types that are declared elsewhere. Everything "just" works +without any special precautions. One exception to this rule occurs when +extending a type declared in another extension module. Recall the basic example +from Section :ref:`inheritance`. + +.. code-block:: cpp + + py::class_ pet(m, "Pet"); + pet.def(py::init()) + .def_readwrite("name", &Pet::name); + + py::class_(m, "Dog", pet /* <- specify parent */) + .def(py::init()) + .def("bark", &Dog::bark); + +Suppose now that ``Pet`` bindings are defined in a module named ``basic``, +whereas the ``Dog`` bindings are defined somewhere else. The challenge is of +course that the variable ``pet`` is not available anymore though it is needed +to indicate the inheritance relationship to the constructor of ``class_``. +However, it can be acquired as follows: + +.. code-block:: cpp + + py::object pet = (py::object) py::module::import("basic").attr("Pet"); + + py::class_(m, "Dog", pet) + .def(py::init()) + .def("bark", &Dog::bark); + +Alternatively, you can specify the base class as a template parameter option to +``class_``, which performs an automated lookup of the corresponding Python +type. Like the above code, however, this also requires invoking the ``import`` +function once to ensure that the pybind11 binding code of the module ``basic`` +has been executed: + +.. code-block:: cpp + + py::module::import("basic"); + + py::class_(m, "Dog") + .def(py::init()) + .def("bark", &Dog::bark); + +Naturally, both methods will fail when there are cyclic dependencies. + +Note that pybind11 code compiled with hidden-by-default symbol visibility (e.g. +via the command line flag ``-fvisibility=hidden`` on GCC/Clang), which is +required for proper pybind11 functionality, can interfere with the ability to +access types defined in another extension module. Working around this requires +manually exporting types that are accessed by multiple extension modules; +pybind11 provides a macro to do just this: + +.. code-block:: cpp + + class PYBIND11_EXPORT Dog : public Animal { + ... + }; + +Note also that it is possible (although would rarely be required) to share arbitrary +C++ objects between extension modules at runtime. Internal library data is shared +between modules using capsule machinery [#f6]_ which can be also utilized for +storing, modifying and accessing user-defined data. Note that an extension module +will "see" other extensions' data if and only if they were built with the same +pybind11 version. Consider the following example: + +.. code-block:: cpp + + auto data = (MyData *) py::get_shared_data("mydata"); + if (!data) + data = (MyData *) py::set_shared_data("mydata", new MyData(42)); + +If the above snippet was used in several separately compiled extension modules, +the first one to be imported would create a ``MyData`` instance and associate +a ``"mydata"`` key with a pointer to it. Extensions that are imported later +would be then able to access the data behind the same pointer. + +.. [#f6] https://docs.python.org/3/extending/extending.html#using-capsules + +Module Destructors +================== + +pybind11 does not provide an explicit mechanism to invoke cleanup code at +module destruction time. In rare cases where such functionality is required, it +is possible to emulate it using Python capsules or weak references with a +destruction callback. + +.. code-block:: cpp + + auto cleanup_callback = []() { + // perform cleanup here -- this function is called with the GIL held + }; + + m.add_object("_cleanup", py::capsule(cleanup_callback)); + +This approach has the potential downside that instances of classes exposed +within the module may still be alive when the cleanup callback is invoked +(whether this is acceptable will generally depend on the application). + +Alternatively, the capsule may also be stashed within a type object, which +ensures that it not called before all instances of that type have been +collected: + +.. code-block:: cpp + + auto cleanup_callback = []() { /* ... */ }; + m.attr("BaseClass").attr("_cleanup") = py::capsule(cleanup_callback); + +Both approaches also expose a potentially dangerous ``_cleanup`` attribute in +Python, which may be undesirable from an API standpoint (a premature explicit +call from Python might lead to undefined behavior). Yet another approach that +avoids this issue involves weak reference with a cleanup callback: + +.. code-block:: cpp + + // Register a callback function that is invoked when the BaseClass object is colelcted + py::cpp_function cleanup_callback( + [](py::handle weakref) { + // perform cleanup here -- this function is called with the GIL held + + weakref.dec_ref(); // release weak reference + } + ); + + // Create a weak reference with a cleanup callback and initially leak it + (void) py::weakref(m.attr("BaseClass"), cleanup_callback).release(); + +.. note:: + + PyPy (at least version 5.9) does not garbage collect objects when the + interpreter exits. An alternative approach (which also works on CPython) is to use + the :py:mod:`atexit` module [#f7]_, for example: + + .. code-block:: cpp + + auto atexit = py::module::import("atexit"); + atexit.attr("register")(py::cpp_function([]() { + // perform cleanup here -- this function is called with the GIL held + })); + + .. [#f7] https://docs.python.org/3/library/atexit.html + + +Generating documentation using Sphinx +===================================== + +Sphinx [#f4]_ has the ability to inspect the signatures and documentation +strings in pybind11-based extension modules to automatically generate beautiful +documentation in a variety formats. The python_example repository [#f5]_ contains a +simple example repository which uses this approach. + +There are two potential gotchas when using this approach: first, make sure that +the resulting strings do not contain any :kbd:`TAB` characters, which break the +docstring parsing routines. You may want to use C++11 raw string literals, +which are convenient for multi-line comments. Conveniently, any excess +indentation will be automatically be removed by Sphinx. However, for this to +work, it is important that all lines are indented consistently, i.e.: + +.. code-block:: cpp + + // ok + m.def("foo", &foo, R"mydelimiter( + The foo function + + Parameters + ---------- + )mydelimiter"); + + // *not ok* + m.def("foo", &foo, R"mydelimiter(The foo function + + Parameters + ---------- + )mydelimiter"); + +By default, pybind11 automatically generates and prepends a signature to the docstring of a function +registered with ``module::def()`` and ``class_::def()``. Sometimes this +behavior is not desirable, because you want to provide your own signature or remove +the docstring completely to exclude the function from the Sphinx documentation. +The class ``options`` allows you to selectively suppress auto-generated signatures: + +.. code-block:: cpp + + PYBIND11_MODULE(example, m) { + py::options options; + options.disable_function_signatures(); + + m.def("add", [](int a, int b) { return a + b; }, "A function which adds two numbers"); + } + +Note that changes to the settings affect only function bindings created during the +lifetime of the ``options`` instance. When it goes out of scope at the end of the module's init function, +the default settings are restored to prevent unwanted side effects. + +.. [#f4] http://www.sphinx-doc.org +.. [#f5] http://github.com/pybind/python_example diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/index.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..6885bdcff1b56bbab5605873ccb1e0676864bb03 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/index.rst @@ -0,0 +1,13 @@ +Python C++ interface +#################### + +pybind11 exposes Python types and functions using thin C++ wrappers, which +makes it possible to conveniently call Python code from C++ without resorting +to Python's C API. + +.. toctree:: + :maxdepth: 2 + + object + numpy + utilities diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/numpy.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/numpy.rst new file mode 100644 index 0000000000000000000000000000000000000000..458f99e9787ec1a7469afa05099abe25c685103d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/numpy.rst @@ -0,0 +1,386 @@ +.. _numpy: + +NumPy +##### + +Buffer protocol +=============== + +Python supports an extremely general and convenient approach for exchanging +data between plugin libraries. Types can expose a buffer view [#f2]_, which +provides fast direct access to the raw internal data representation. Suppose we +want to bind the following simplistic Matrix class: + +.. code-block:: cpp + + class Matrix { + public: + Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) { + m_data = new float[rows*cols]; + } + float *data() { return m_data; } + size_t rows() const { return m_rows; } + size_t cols() const { return m_cols; } + private: + size_t m_rows, m_cols; + float *m_data; + }; + +The following binding code exposes the ``Matrix`` contents as a buffer object, +making it possible to cast Matrices into NumPy arrays. It is even possible to +completely avoid copy operations with Python expressions like +``np.array(matrix_instance, copy = False)``. + +.. code-block:: cpp + + py::class_(m, "Matrix", py::buffer_protocol()) + .def_buffer([](Matrix &m) -> py::buffer_info { + return py::buffer_info( + m.data(), /* Pointer to buffer */ + sizeof(float), /* Size of one scalar */ + py::format_descriptor::format(), /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(float) * m.cols(), /* Strides (in bytes) for each index */ + sizeof(float) } + ); + }); + +Supporting the buffer protocol in a new type involves specifying the special +``py::buffer_protocol()`` tag in the ``py::class_`` constructor and calling the +``def_buffer()`` method with a lambda function that creates a +``py::buffer_info`` description record on demand describing a given matrix +instance. The contents of ``py::buffer_info`` mirror the Python buffer protocol +specification. + +.. code-block:: cpp + + struct buffer_info { + void *ptr; + ssize_t itemsize; + std::string format; + ssize_t ndim; + std::vector shape; + std::vector strides; + }; + +To create a C++ function that can take a Python buffer object as an argument, +simply use the type ``py::buffer`` as one of its arguments. Buffers can exist +in a great variety of configurations, hence some safety checks are usually +necessary in the function body. Below, you can see an basic example on how to +define a custom constructor for the Eigen double precision matrix +(``Eigen::MatrixXd``) type, which supports initialization from compatible +buffer objects (e.g. a NumPy matrix). + +.. code-block:: cpp + + /* Bind MatrixXd (or some other Eigen type) to Python */ + typedef Eigen::MatrixXd Matrix; + + typedef Matrix::Scalar Scalar; + constexpr bool rowMajor = Matrix::Flags & Eigen::RowMajorBit; + + py::class_(m, "Matrix", py::buffer_protocol()) + .def("__init__", [](Matrix &m, py::buffer b) { + typedef Eigen::Stride Strides; + + /* Request a buffer descriptor from Python */ + py::buffer_info info = b.request(); + + /* Some sanity checks ... */ + if (info.format != py::format_descriptor::format()) + throw std::runtime_error("Incompatible format: expected a double array!"); + + if (info.ndim != 2) + throw std::runtime_error("Incompatible buffer dimension!"); + + auto strides = Strides( + info.strides[rowMajor ? 0 : 1] / (py::ssize_t)sizeof(Scalar), + info.strides[rowMajor ? 1 : 0] / (py::ssize_t)sizeof(Scalar)); + + auto map = Eigen::Map( + static_cast(info.ptr), info.shape[0], info.shape[1], strides); + + new (&m) Matrix(map); + }); + +For reference, the ``def_buffer()`` call for this Eigen data type should look +as follows: + +.. code-block:: cpp + + .def_buffer([](Matrix &m) -> py::buffer_info { + return py::buffer_info( + m.data(), /* Pointer to buffer */ + sizeof(Scalar), /* Size of one scalar */ + py::format_descriptor::format(), /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(Scalar) * (rowMajor ? m.cols() : 1), + sizeof(Scalar) * (rowMajor ? 1 : m.rows()) } + /* Strides (in bytes) for each index */ + ); + }) + +For a much easier approach of binding Eigen types (although with some +limitations), refer to the section on :doc:`/advanced/cast/eigen`. + +.. seealso:: + + The file :file:`tests/test_buffers.cpp` contains a complete example + that demonstrates using the buffer protocol with pybind11 in more detail. + +.. [#f2] http://docs.python.org/3/c-api/buffer.html + +Arrays +====== + +By exchanging ``py::buffer`` with ``py::array`` in the above snippet, we can +restrict the function so that it only accepts NumPy arrays (rather than any +type of Python object satisfying the buffer protocol). + +In many situations, we want to define a function which only accepts a NumPy +array of a certain data type. This is possible via the ``py::array_t`` +template. For instance, the following function requires the argument to be a +NumPy array containing double precision values. + +.. code-block:: cpp + + void f(py::array_t array); + +When it is invoked with a different type (e.g. an integer or a list of +integers), the binding code will attempt to cast the input into a NumPy array +of the requested type. Note that this feature requires the +:file:`pybind11/numpy.h` header to be included. + +Data in NumPy arrays is not guaranteed to packed in a dense manner; +furthermore, entries can be separated by arbitrary column and row strides. +Sometimes, it can be useful to require a function to only accept dense arrays +using either the C (row-major) or Fortran (column-major) ordering. This can be +accomplished via a second template argument with values ``py::array::c_style`` +or ``py::array::f_style``. + +.. code-block:: cpp + + void f(py::array_t array); + +The ``py::array::forcecast`` argument is the default value of the second +template parameter, and it ensures that non-conforming arguments are converted +into an array satisfying the specified requirements instead of trying the next +function overload. + +Structured types +================ + +In order for ``py::array_t`` to work with structured (record) types, we first +need to register the memory layout of the type. This can be done via +``PYBIND11_NUMPY_DTYPE`` macro, called in the plugin definition code, which +expects the type followed by field names: + +.. code-block:: cpp + + struct A { + int x; + double y; + }; + + struct B { + int z; + A a; + }; + + // ... + PYBIND11_MODULE(test, m) { + // ... + + PYBIND11_NUMPY_DTYPE(A, x, y); + PYBIND11_NUMPY_DTYPE(B, z, a); + /* now both A and B can be used as template arguments to py::array_t */ + } + +The structure should consist of fundamental arithmetic types, ``std::complex``, +previously registered substructures, and arrays of any of the above. Both C++ +arrays and ``std::array`` are supported. While there is a static assertion to +prevent many types of unsupported structures, it is still the user's +responsibility to use only "plain" structures that can be safely manipulated as +raw memory without violating invariants. + +Vectorizing functions +===================== + +Suppose we want to bind a function with the following signature to Python so +that it can process arbitrary NumPy array arguments (vectors, matrices, general +N-D arrays) in addition to its normal arguments: + +.. code-block:: cpp + + double my_func(int x, float y, double z); + +After including the ``pybind11/numpy.h`` header, this is extremely simple: + +.. code-block:: cpp + + m.def("vectorized_func", py::vectorize(my_func)); + +Invoking the function like below causes 4 calls to be made to ``my_func`` with +each of the array elements. The significant advantage of this compared to +solutions like ``numpy.vectorize()`` is that the loop over the elements runs +entirely on the C++ side and can be crunched down into a tight, optimized loop +by the compiler. The result is returned as a NumPy array of type +``numpy.dtype.float64``. + +.. code-block:: pycon + + >>> x = np.array([[1, 3],[5, 7]]) + >>> y = np.array([[2, 4],[6, 8]]) + >>> z = 3 + >>> result = vectorized_func(x, y, z) + +The scalar argument ``z`` is transparently replicated 4 times. The input +arrays ``x`` and ``y`` are automatically converted into the right types (they +are of type ``numpy.dtype.int64`` but need to be ``numpy.dtype.int32`` and +``numpy.dtype.float32``, respectively). + +.. note:: + + Only arithmetic, complex, and POD types passed by value or by ``const &`` + reference are vectorized; all other arguments are passed through as-is. + Functions taking rvalue reference arguments cannot be vectorized. + +In cases where the computation is too complicated to be reduced to +``vectorize``, it will be necessary to create and access the buffer contents +manually. The following snippet contains a complete example that shows how this +works (the code is somewhat contrived, since it could have been done more +simply using ``vectorize``). + +.. code-block:: cpp + + #include + #include + + namespace py = pybind11; + + py::array_t add_arrays(py::array_t input1, py::array_t input2) { + py::buffer_info buf1 = input1.request(), buf2 = input2.request(); + + if (buf1.ndim != 1 || buf2.ndim != 1) + throw std::runtime_error("Number of dimensions must be one"); + + if (buf1.size != buf2.size) + throw std::runtime_error("Input shapes must match"); + + /* No pointer is passed, so NumPy will allocate the buffer */ + auto result = py::array_t(buf1.size); + + py::buffer_info buf3 = result.request(); + + double *ptr1 = (double *) buf1.ptr, + *ptr2 = (double *) buf2.ptr, + *ptr3 = (double *) buf3.ptr; + + for (size_t idx = 0; idx < buf1.shape[0]; idx++) + ptr3[idx] = ptr1[idx] + ptr2[idx]; + + return result; + } + + PYBIND11_MODULE(test, m) { + m.def("add_arrays", &add_arrays, "Add two NumPy arrays"); + } + +.. seealso:: + + The file :file:`tests/test_numpy_vectorize.cpp` contains a complete + example that demonstrates using :func:`vectorize` in more detail. + +Direct access +============= + +For performance reasons, particularly when dealing with very large arrays, it +is often desirable to directly access array elements without internal checking +of dimensions and bounds on every access when indices are known to be already +valid. To avoid such checks, the ``array`` class and ``array_t`` template +class offer an unchecked proxy object that can be used for this unchecked +access through the ``unchecked`` and ``mutable_unchecked`` methods, +where ``N`` gives the required dimensionality of the array: + +.. code-block:: cpp + + m.def("sum_3d", [](py::array_t x) { + auto r = x.unchecked<3>(); // x must have ndim = 3; can be non-writeable + double sum = 0; + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) + sum += r(i, j, k); + return sum; + }); + m.def("increment_3d", [](py::array_t x) { + auto r = x.mutable_unchecked<3>(); // Will throw if ndim != 3 or flags.writeable is false + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) + r(i, j, k) += 1.0; + }, py::arg().noconvert()); + +To obtain the proxy from an ``array`` object, you must specify both the data +type and number of dimensions as template arguments, such as ``auto r = +myarray.mutable_unchecked()``. + +If the number of dimensions is not known at compile time, you can omit the +dimensions template parameter (i.e. calling ``arr_t.unchecked()`` or +``arr.unchecked()``. This will give you a proxy object that works in the +same way, but results in less optimizable code and thus a small efficiency +loss in tight loops. + +Note that the returned proxy object directly references the array's data, and +only reads its shape, strides, and writeable flag when constructed. You must +take care to ensure that the referenced array is not destroyed or reshaped for +the duration of the returned object, typically by limiting the scope of the +returned instance. + +The returned proxy object supports some of the same methods as ``py::array`` so +that it can be used as a drop-in replacement for some existing, index-checked +uses of ``py::array``: + +- ``r.ndim()`` returns the number of dimensions + +- ``r.data(1, 2, ...)`` and ``r.mutable_data(1, 2, ...)``` returns a pointer to + the ``const T`` or ``T`` data, respectively, at the given indices. The + latter is only available to proxies obtained via ``a.mutable_unchecked()``. + +- ``itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``. + +- ``ndim()`` returns the number of dimensions. + +- ``shape(n)`` returns the size of dimension ``n`` + +- ``size()`` returns the total number of elements (i.e. the product of the shapes). + +- ``nbytes()`` returns the number of bytes used by the referenced elements + (i.e. ``itemsize()`` times ``size()``). + +.. seealso:: + + The file :file:`tests/test_numpy_array.cpp` contains additional examples + demonstrating the use of this feature. + +Ellipsis +======== + +Python 3 provides a convenient ``...`` ellipsis notation that is often used to +slice multidimensional arrays. For instance, the following snippet extracts the +middle dimensions of a tensor with the first and last index set to zero. + +.. code-block:: python + + a = # a NumPy array + b = a[0, ..., 0] + +The function ``py::ellipsis()`` function can be used to perform the same +operation on the C++ side: + +.. code-block:: cpp + + py::array a = /* A NumPy array */; + py::array b = a[py::make_tuple(0, py::ellipsis(), 0)]; diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/object.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/object.rst new file mode 100644 index 0000000000000000000000000000000000000000..117131edcb3665563442e5402338f0e33d77d0e0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/object.rst @@ -0,0 +1,170 @@ +Python types +############ + +Available wrappers +================== + +All major Python types are available as thin C++ wrapper classes. These +can also be used as function parameters -- see :ref:`python_objects_as_args`. + +Available types include :class:`handle`, :class:`object`, :class:`bool_`, +:class:`int_`, :class:`float_`, :class:`str`, :class:`bytes`, :class:`tuple`, +:class:`list`, :class:`dict`, :class:`slice`, :class:`none`, :class:`capsule`, +:class:`iterable`, :class:`iterator`, :class:`function`, :class:`buffer`, +:class:`array`, and :class:`array_t`. + +Casting back and forth +====================== + +In this kind of mixed code, it is often necessary to convert arbitrary C++ +types to Python, which can be done using :func:`py::cast`: + +.. code-block:: cpp + + MyClass *cls = ..; + py::object obj = py::cast(cls); + +The reverse direction uses the following syntax: + +.. code-block:: cpp + + py::object obj = ...; + MyClass *cls = obj.cast(); + +When conversion fails, both directions throw the exception :class:`cast_error`. + +.. _python_libs: + +Accessing Python libraries from C++ +=================================== + +It is also possible to import objects defined in the Python standard +library or available in the current Python environment (``sys.path``) and work +with these in C++. + +This example obtains a reference to the Python ``Decimal`` class. + +.. code-block:: cpp + + // Equivalent to "from decimal import Decimal" + py::object Decimal = py::module::import("decimal").attr("Decimal"); + +.. code-block:: cpp + + // Try to import scipy + py::object scipy = py::module::import("scipy"); + return scipy.attr("__version__"); + +.. _calling_python_functions: + +Calling Python functions +======================== + +It is also possible to call Python classes, functions and methods +via ``operator()``. + +.. code-block:: cpp + + // Construct a Python object of class Decimal + py::object pi = Decimal("3.14159"); + +.. code-block:: cpp + + // Use Python to make our directories + py::object os = py::module::import("os"); + py::object makedirs = os.attr("makedirs"); + makedirs("/tmp/path/to/somewhere"); + +One can convert the result obtained from Python to a pure C++ version +if a ``py::class_`` or type conversion is defined. + +.. code-block:: cpp + + py::function f = <...>; + py::object result_py = f(1234, "hello", some_instance); + MyClass &result = result_py.cast(); + +.. _calling_python_methods: + +Calling Python methods +======================== + +To call an object's method, one can again use ``.attr`` to obtain access to the +Python method. + +.. code-block:: cpp + + // Calculate e^π in decimal + py::object exp_pi = pi.attr("exp")(); + py::print(py::str(exp_pi)); + +In the example above ``pi.attr("exp")`` is a *bound method*: it will always call +the method for that same instance of the class. Alternately one can create an +*unbound method* via the Python class (instead of instance) and pass the ``self`` +object explicitly, followed by other arguments. + +.. code-block:: cpp + + py::object decimal_exp = Decimal.attr("exp"); + + // Compute the e^n for n=0..4 + for (int n = 0; n < 5; n++) { + py::print(decimal_exp(Decimal(n)); + } + +Keyword arguments +================= + +Keyword arguments are also supported. In Python, there is the usual call syntax: + +.. code-block:: python + + def f(number, say, to): + ... # function code + + f(1234, say="hello", to=some_instance) # keyword call in Python + +In C++, the same call can be made using: + +.. code-block:: cpp + + using namespace pybind11::literals; // to bring in the `_a` literal + f(1234, "say"_a="hello", "to"_a=some_instance); // keyword call in C++ + +Unpacking arguments +=================== + +Unpacking of ``*args`` and ``**kwargs`` is also possible and can be mixed with +other arguments: + +.. code-block:: cpp + + // * unpacking + py::tuple args = py::make_tuple(1234, "hello", some_instance); + f(*args); + + // ** unpacking + py::dict kwargs = py::dict("number"_a=1234, "say"_a="hello", "to"_a=some_instance); + f(**kwargs); + + // mixed keywords, * and ** unpacking + py::tuple args = py::make_tuple(1234); + py::dict kwargs = py::dict("to"_a=some_instance); + f(*args, "say"_a="hello", **kwargs); + +Generalized unpacking according to PEP448_ is also supported: + +.. code-block:: cpp + + py::dict kwargs1 = py::dict("number"_a=1234); + py::dict kwargs2 = py::dict("to"_a=some_instance); + f(**kwargs1, "say"_a="hello", **kwargs2); + +.. seealso:: + + The file :file:`tests/test_pytypes.cpp` contains a complete + example that demonstrates passing native Python types in more detail. The + file :file:`tests/test_callbacks.cpp` presents a few examples of calling + Python functions from C++, including keywords arguments and unpacking. + +.. _PEP448: https://www.python.org/dev/peps/pep-0448/ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/utilities.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/utilities.rst new file mode 100644 index 0000000000000000000000000000000000000000..369e7c94dbd69f3ce7bb2d837a53ea2853a04efc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/pycpp/utilities.rst @@ -0,0 +1,144 @@ +Utilities +######### + +Using Python's print function in C++ +==================================== + +The usual way to write output in C++ is using ``std::cout`` while in Python one +would use ``print``. Since these methods use different buffers, mixing them can +lead to output order issues. To resolve this, pybind11 modules can use the +:func:`py::print` function which writes to Python's ``sys.stdout`` for consistency. + +Python's ``print`` function is replicated in the C++ API including optional +keyword arguments ``sep``, ``end``, ``file``, ``flush``. Everything works as +expected in Python: + +.. code-block:: cpp + + py::print(1, 2.0, "three"); // 1 2.0 three + py::print(1, 2.0, "three", "sep"_a="-"); // 1-2.0-three + + auto args = py::make_tuple("unpacked", true); + py::print("->", *args, "end"_a="<-"); // -> unpacked True <- + +.. _ostream_redirect: + +Capturing standard output from ostream +====================================== + +Often, a library will use the streams ``std::cout`` and ``std::cerr`` to print, +but this does not play well with Python's standard ``sys.stdout`` and ``sys.stderr`` +redirection. Replacing a library's printing with `py::print ` may not +be feasible. This can be fixed using a guard around the library function that +redirects output to the corresponding Python streams: + +.. code-block:: cpp + + #include + + ... + + // Add a scoped redirect for your noisy code + m.def("noisy_func", []() { + py::scoped_ostream_redirect stream( + std::cout, // std::ostream& + py::module::import("sys").attr("stdout") // Python output + ); + call_noisy_func(); + }); + +This method respects flushes on the output streams and will flush if needed +when the scoped guard is destroyed. This allows the output to be redirected in +real time, such as to a Jupyter notebook. The two arguments, the C++ stream and +the Python output, are optional, and default to standard output if not given. An +extra type, `py::scoped_estream_redirect `, is identical +except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful with +`py::call_guard`, which allows multiple items, but uses the default constructor: + +.. code-block:: py + + // Alternative: Call single function using call guard + m.def("noisy_func", &call_noisy_function, + py::call_guard()); + +The redirection can also be done in Python with the addition of a context +manager, using the `py::add_ostream_redirect() ` function: + +.. code-block:: cpp + + py::add_ostream_redirect(m, "ostream_redirect"); + +The name in Python defaults to ``ostream_redirect`` if no name is passed. This +creates the following context manager in Python: + +.. code-block:: python + + with ostream_redirect(stdout=True, stderr=True): + noisy_function() + +It defaults to redirecting both streams, though you can use the keyword +arguments to disable one of the streams if needed. + +.. note:: + + The above methods will not redirect C-level output to file descriptors, such + as ``fprintf``. For those cases, you'll need to redirect the file + descriptors either directly in C or with Python's ``os.dup2`` function + in an operating-system dependent way. + +.. _eval: + +Evaluating Python expressions from strings and files +==================================================== + +pybind11 provides the `eval`, `exec` and `eval_file` functions to evaluate +Python expressions and statements. The following example illustrates how they +can be used. + +.. code-block:: cpp + + // At beginning of file + #include + + ... + + // Evaluate in scope of main module + py::object scope = py::module::import("__main__").attr("__dict__"); + + // Evaluate an isolated expression + int result = py::eval("my_variable + 10", scope).cast(); + + // Evaluate a sequence of statements + py::exec( + "print('Hello')\n" + "print('world!');", + scope); + + // Evaluate the statements in an separate Python file on disk + py::eval_file("script.py", scope); + +C++11 raw string literals are also supported and quite handy for this purpose. +The only requirement is that the first statement must be on a new line following +the raw string delimiter ``R"(``, ensuring all lines have common leading indent: + +.. code-block:: cpp + + py::exec(R"( + x = get_answer() + if x == 42: + print('Hello World!') + else: + print('Bye!') + )", scope + ); + +.. note:: + + `eval` and `eval_file` accept a template parameter that describes how the + string/file should be interpreted. Possible choices include ``eval_expr`` + (isolated expression), ``eval_single_statement`` (a single statement, return + value is always ``none``), and ``eval_statements`` (sequence of statements, + return value is always ``none``). `eval` defaults to ``eval_expr``, + `eval_file` defaults to ``eval_statements`` and `exec` is just a shortcut + for ``eval``. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/smart_ptrs.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/smart_ptrs.rst new file mode 100644 index 0000000000000000000000000000000000000000..da57748ca585a92000198a6c607a087704b1f07c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/advanced/smart_ptrs.rst @@ -0,0 +1,173 @@ +Smart pointers +############## + +std::unique_ptr +=============== + +Given a class ``Example`` with Python bindings, it's possible to return +instances wrapped in C++11 unique pointers, like so + +.. code-block:: cpp + + std::unique_ptr create_example() { return std::unique_ptr(new Example()); } + +.. code-block:: cpp + + m.def("create_example", &create_example); + +In other words, there is nothing special that needs to be done. While returning +unique pointers in this way is allowed, it is *illegal* to use them as function +arguments. For instance, the following function signature cannot be processed +by pybind11. + +.. code-block:: cpp + + void do_something_with_example(std::unique_ptr ex) { ... } + +The above signature would imply that Python needs to give up ownership of an +object that is passed to this function, which is generally not possible (for +instance, the object might be referenced elsewhere). + +std::shared_ptr +=============== + +The binding generator for classes, :class:`class_`, can be passed a template +type that denotes a special *holder* type that is used to manage references to +the object. If no such holder type template argument is given, the default for +a type named ``Type`` is ``std::unique_ptr``, which means that the object +is deallocated when Python's reference count goes to zero. + +It is possible to switch to other types of reference counting wrappers or smart +pointers, which is useful in codebases that rely on them. For instance, the +following snippet causes ``std::shared_ptr`` to be used instead. + +.. code-block:: cpp + + py::class_ /* <- holder type */> obj(m, "Example"); + +Note that any particular class can only be associated with a single holder type. + +One potential stumbling block when using holder types is that they need to be +applied consistently. Can you guess what's broken about the following binding +code? + +.. code-block:: cpp + + class Child { }; + + class Parent { + public: + Parent() : child(std::make_shared()) { } + Child *get_child() { return child.get(); } /* Hint: ** DON'T DO THIS ** */ + private: + std::shared_ptr child; + }; + + PYBIND11_MODULE(example, m) { + py::class_>(m, "Child"); + + py::class_>(m, "Parent") + .def(py::init<>()) + .def("get_child", &Parent::get_child); + } + +The following Python code will cause undefined behavior (and likely a +segmentation fault). + +.. code-block:: python + + from example import Parent + print(Parent().get_child()) + +The problem is that ``Parent::get_child()`` returns a pointer to an instance of +``Child``, but the fact that this instance is already managed by +``std::shared_ptr<...>`` is lost when passing raw pointers. In this case, +pybind11 will create a second independent ``std::shared_ptr<...>`` that also +claims ownership of the pointer. In the end, the object will be freed **twice** +since these shared pointers have no way of knowing about each other. + +There are two ways to resolve this issue: + +1. For types that are managed by a smart pointer class, never use raw pointers + in function arguments or return values. In other words: always consistently + wrap pointers into their designated holder types (such as + ``std::shared_ptr<...>``). In this case, the signature of ``get_child()`` + should be modified as follows: + +.. code-block:: cpp + + std::shared_ptr get_child() { return child; } + +2. Adjust the definition of ``Child`` by specifying + ``std::enable_shared_from_this`` (see cppreference_ for details) as a + base class. This adds a small bit of information to ``Child`` that allows + pybind11 to realize that there is already an existing + ``std::shared_ptr<...>`` and communicate with it. In this case, the + declaration of ``Child`` should look as follows: + +.. _cppreference: http://en.cppreference.com/w/cpp/memory/enable_shared_from_this + +.. code-block:: cpp + + class Child : public std::enable_shared_from_this { }; + +.. _smart_pointers: + +Custom smart pointers +===================== + +pybind11 supports ``std::unique_ptr`` and ``std::shared_ptr`` right out of the +box. For any other custom smart pointer, transparent conversions can be enabled +using a macro invocation similar to the following. It must be declared at the +top namespace level before any binding code: + +.. code-block:: cpp + + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr); + +The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a +placeholder name that is used as a template parameter of the second argument. +Thus, feel free to use any identifier, but use it consistently on both sides; +also, don't use the name of a type that already exists in your codebase. + +The macro also accepts a third optional boolean parameter that is set to false +by default. Specify + +.. code-block:: cpp + + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr, true); + +if ``SmartPtr`` can always be initialized from a ``T*`` pointer without the +risk of inconsistencies (such as multiple independent ``SmartPtr`` instances +believing that they are the sole owner of the ``T*`` pointer). A common +situation where ``true`` should be passed is when the ``T`` instances use +*intrusive* reference counting. + +Please take a look at the :ref:`macro_notes` before using this feature. + +By default, pybind11 assumes that your custom smart pointer has a standard +interface, i.e. provides a ``.get()`` member function to access the underlying +raw pointer. If this is not the case, pybind11's ``holder_helper`` must be +specialized: + +.. code-block:: cpp + + // Always needed for custom holder types + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr); + + // Only needed if the type's `.get()` goes by another name + namespace pybind11 { namespace detail { + template + struct holder_helper> { // <-- specialization + static const T *get(const SmartPtr &p) { return p.getPointer(); } + }; + }} + +The above specialization informs pybind11 that the custom ``SmartPtr`` class +provides ``.get()`` functionality via ``.getPointer()``. + +.. seealso:: + + The file :file:`tests/test_smart_ptr.cpp` contains a complete example + that demonstrates how to work with custom reference-counting holder types + in more detail. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/basics.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/basics.rst new file mode 100644 index 0000000000000000000000000000000000000000..7bf4d426d39db811a10f0cdfcda950d5e5fcbbf8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/basics.rst @@ -0,0 +1,293 @@ +.. _basics: + +First steps +########### + +This sections demonstrates the basic features of pybind11. Before getting +started, make sure that development environment is set up to compile the +included set of test cases. + + +Compiling the test cases +======================== + +Linux/MacOS +----------- + +On Linux you'll need to install the **python-dev** or **python3-dev** packages as +well as **cmake**. On Mac OS, the included python version works out of the box, +but **cmake** must still be installed. + +After installing the prerequisites, run + +.. code-block:: bash + + mkdir build + cd build + cmake .. + make check -j 4 + +The last line will both compile and run the tests. + +Windows +------- + +On Windows, only **Visual Studio 2015** and newer are supported since pybind11 relies +on various C++11 language features that break older versions of Visual Studio. + +To compile and run the tests: + +.. code-block:: batch + + mkdir build + cd build + cmake .. + cmake --build . --config Release --target check + +This will create a Visual Studio project, compile and run the target, all from the +command line. + +.. Note:: + + If all tests fail, make sure that the Python binary and the testcases are compiled + for the same processor type and bitness (i.e. either **i386** or **x86_64**). You + can specify **x86_64** as the target architecture for the generated Visual Studio + project using ``cmake -A x64 ..``. + +.. seealso:: + + Advanced users who are already familiar with Boost.Python may want to skip + the tutorial and look at the test cases in the :file:`tests` directory, + which exercise all features of pybind11. + +Header and namespace conventions +================================ + +For brevity, all code examples assume that the following two lines are present: + +.. code-block:: cpp + + #include + + namespace py = pybind11; + +Some features may require additional headers, but those will be specified as needed. + +.. _simple_example: + +Creating bindings for a simple function +======================================= + +Let's start by creating Python bindings for an extremely simple function, which +adds two numbers and returns their result: + +.. code-block:: cpp + + int add(int i, int j) { + return i + j; + } + +For simplicity [#f1]_, we'll put both this function and the binding code into +a file named :file:`example.cpp` with the following contents: + +.. code-block:: cpp + + #include + + int add(int i, int j) { + return i + j; + } + + PYBIND11_MODULE(example, m) { + m.doc() = "pybind11 example plugin"; // optional module docstring + + m.def("add", &add, "A function which adds two numbers"); + } + +.. [#f1] In practice, implementation and binding code will generally be located + in separate files. + +The :func:`PYBIND11_MODULE` macro creates a function that will be called when an +``import`` statement is issued from within Python. The module name (``example``) +is given as the first macro argument (it should not be in quotes). The second +argument (``m``) defines a variable of type :class:`py::module ` which +is the main interface for creating bindings. The method :func:`module::def` +generates binding code that exposes the ``add()`` function to Python. + +.. note:: + + Notice how little code was needed to expose our function to Python: all + details regarding the function's parameters and return value were + automatically inferred using template metaprogramming. This overall + approach and the used syntax are borrowed from Boost.Python, though the + underlying implementation is very different. + +pybind11 is a header-only library, hence it is not necessary to link against +any special libraries and there are no intermediate (magic) translation steps. +On Linux, the above example can be compiled using the following command: + +.. code-block:: bash + + $ c++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix` + +For more details on the required compiler flags on Linux and MacOS, see +:ref:`building_manually`. For complete cross-platform compilation instructions, +refer to the :ref:`compiling` page. + +The `python_example`_ and `cmake_example`_ repositories are also a good place +to start. They are both complete project examples with cross-platform build +systems. The only difference between the two is that `python_example`_ uses +Python's ``setuptools`` to build the module, while `cmake_example`_ uses CMake +(which may be preferable for existing C++ projects). + +.. _python_example: https://github.com/pybind/python_example +.. _cmake_example: https://github.com/pybind/cmake_example + +Building the above C++ code will produce a binary module file that can be +imported to Python. Assuming that the compiled module is located in the +current directory, the following interactive Python session shows how to +load and execute the example: + +.. code-block:: pycon + + $ python + Python 2.7.10 (default, Aug 22 2015, 20:33:39) + [GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.1)] on darwin + Type "help", "copyright", "credits" or "license" for more information. + >>> import example + >>> example.add(1, 2) + 3L + >>> + +.. _keyword_args: + +Keyword arguments +================= + +With a simple code modification, it is possible to inform Python about the +names of the arguments ("i" and "j" in this case). + +.. code-block:: cpp + + m.def("add", &add, "A function which adds two numbers", + py::arg("i"), py::arg("j")); + +:class:`arg` is one of several special tag classes which can be used to pass +metadata into :func:`module::def`. With this modified binding code, we can now +call the function using keyword arguments, which is a more readable alternative +particularly for functions taking many parameters: + +.. code-block:: pycon + + >>> import example + >>> example.add(i=1, j=2) + 3L + +The keyword names also appear in the function signatures within the documentation. + +.. code-block:: pycon + + >>> help(example) + + .... + + FUNCTIONS + add(...) + Signature : (i: int, j: int) -> int + + A function which adds two numbers + +A shorter notation for named arguments is also available: + +.. code-block:: cpp + + // regular notation + m.def("add1", &add, py::arg("i"), py::arg("j")); + // shorthand + using namespace pybind11::literals; + m.def("add2", &add, "i"_a, "j"_a); + +The :var:`_a` suffix forms a C++11 literal which is equivalent to :class:`arg`. +Note that the literal operator must first be made visible with the directive +``using namespace pybind11::literals``. This does not bring in anything else +from the ``pybind11`` namespace except for literals. + +.. _default_args: + +Default arguments +================= + +Suppose now that the function to be bound has default arguments, e.g.: + +.. code-block:: cpp + + int add(int i = 1, int j = 2) { + return i + j; + } + +Unfortunately, pybind11 cannot automatically extract these parameters, since they +are not part of the function's type information. However, they are simple to specify +using an extension of :class:`arg`: + +.. code-block:: cpp + + m.def("add", &add, "A function which adds two numbers", + py::arg("i") = 1, py::arg("j") = 2); + +The default values also appear within the documentation. + +.. code-block:: pycon + + >>> help(example) + + .... + + FUNCTIONS + add(...) + Signature : (i: int = 1, j: int = 2) -> int + + A function which adds two numbers + +The shorthand notation is also available for default arguments: + +.. code-block:: cpp + + // regular notation + m.def("add1", &add, py::arg("i") = 1, py::arg("j") = 2); + // shorthand + m.def("add2", &add, "i"_a=1, "j"_a=2); + +Exporting variables +=================== + +To expose a value from C++, use the ``attr`` function to register it in a +module as shown below. Built-in types and general objects (more on that later) +are automatically converted when assigned as attributes, and can be explicitly +converted using the function ``py::cast``. + +.. code-block:: cpp + + PYBIND11_MODULE(example, m) { + m.attr("the_answer") = 42; + py::object world = py::cast("World"); + m.attr("what") = world; + } + +These are then accessible from Python: + +.. code-block:: pycon + + >>> import example + >>> example.the_answer + 42 + >>> example.what + 'World' + +.. _supported_types: + +Supported data types +==================== + +A large number of data types are supported out of the box and can be used +seamlessly as functions arguments, return values or with ``py::cast`` in general. +For a full overview, see the :doc:`advanced/cast/index` section. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/benchmark.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/benchmark.py new file mode 100644 index 0000000000000000000000000000000000000000..6dc0604ea9909ae455872fc61670f9f8dc7194c4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/benchmark.py @@ -0,0 +1,88 @@ +import random +import os +import time +import datetime as dt + +nfns = 4 # Functions per class +nargs = 4 # Arguments per function + + +def generate_dummy_code_pybind11(nclasses=10): + decl = "" + bindings = "" + + for cl in range(nclasses): + decl += "class cl%03i;\n" % cl + decl += '\n' + + for cl in range(nclasses): + decl += "class cl%03i {\n" % cl + decl += "public:\n" + bindings += ' py::class_(m, "cl%03i")\n' % (cl, cl) + for fn in range(nfns): + ret = random.randint(0, nclasses - 1) + params = [random.randint(0, nclasses - 1) for i in range(nargs)] + decl += " cl%03i *fn_%03i(" % (ret, fn) + decl += ", ".join("cl%03i *" % p for p in params) + decl += ");\n" + bindings += ' .def("fn_%03i", &cl%03i::fn_%03i)\n' % \ + (fn, cl, fn) + decl += "};\n\n" + bindings += ' ;\n' + + result = "#include \n\n" + result += "namespace py = pybind11;\n\n" + result += decl + '\n' + result += "PYBIND11_MODULE(example, m) {\n" + result += bindings + result += "}" + return result + + +def generate_dummy_code_boost(nclasses=10): + decl = "" + bindings = "" + + for cl in range(nclasses): + decl += "class cl%03i;\n" % cl + decl += '\n' + + for cl in range(nclasses): + decl += "class cl%03i {\n" % cl + decl += "public:\n" + bindings += ' py::class_("cl%03i")\n' % (cl, cl) + for fn in range(nfns): + ret = random.randint(0, nclasses - 1) + params = [random.randint(0, nclasses - 1) for i in range(nargs)] + decl += " cl%03i *fn_%03i(" % (ret, fn) + decl += ", ".join("cl%03i *" % p for p in params) + decl += ");\n" + bindings += ' .def("fn_%03i", &cl%03i::fn_%03i, py::return_value_policy())\n' % \ + (fn, cl, fn) + decl += "};\n\n" + bindings += ' ;\n' + + result = "#include \n\n" + result += "namespace py = boost::python;\n\n" + result += decl + '\n' + result += "BOOST_PYTHON_MODULE(example) {\n" + result += bindings + result += "}" + return result + + +for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]: + print ("{") + for i in range(0, 10): + nclasses = 2 ** i + with open("test.cpp", "w") as f: + f.write(codegen(nclasses)) + n1 = dt.datetime.now() + os.system("g++ -Os -shared -rdynamic -undefined dynamic_lookup " + "-fvisibility=hidden -std=c++14 test.cpp -I include " + "-I /System/Library/Frameworks/Python.framework/Headers -o test.so") + n2 = dt.datetime.now() + elapsed = (n2 - n1).total_seconds() + size = os.stat('test.so').st_size + print(" {%i, %f, %i}," % (nclasses * nfns, elapsed, size)) + print ("}") diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/benchmark.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/benchmark.rst new file mode 100644 index 0000000000000000000000000000000000000000..59d533df9480c541b8fa9d6ba1e57b4c14a371aa --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/benchmark.rst @@ -0,0 +1,97 @@ +Benchmark +========= + +The following is the result of a synthetic benchmark comparing both compilation +time and module size of pybind11 against Boost.Python. A detailed report about a +Boost.Python to pybind11 conversion of a real project is available here: [#f1]_. + +.. [#f1] http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf + +Setup +----- + +A python script (see the ``docs/benchmark.py`` file) was used to generate a set +of files with dummy classes whose count increases for each successive benchmark +(between 1 and 2048 classes in powers of two). Each class has four methods with +a randomly generated signature with a return value and four arguments. (There +was no particular reason for this setup other than the desire to generate many +unique function signatures whose count could be controlled in a simple way.) + +Here is an example of the binding code for one class: + +.. code-block:: cpp + + ... + class cl034 { + public: + cl279 *fn_000(cl084 *, cl057 *, cl065 *, cl042 *); + cl025 *fn_001(cl098 *, cl262 *, cl414 *, cl121 *); + cl085 *fn_002(cl445 *, cl297 *, cl145 *, cl421 *); + cl470 *fn_003(cl200 *, cl323 *, cl332 *, cl492 *); + }; + ... + + PYBIND11_MODULE(example, m) { + ... + py::class_(m, "cl034") + .def("fn_000", &cl034::fn_000) + .def("fn_001", &cl034::fn_001) + .def("fn_002", &cl034::fn_002) + .def("fn_003", &cl034::fn_003) + ... + } + +The Boost.Python version looks almost identical except that a return value +policy had to be specified as an argument to ``def()``. For both libraries, +compilation was done with + +.. code-block:: bash + + Apple LLVM version 7.0.2 (clang-700.1.81) + +and the following compilation flags + +.. code-block:: bash + + g++ -Os -shared -rdynamic -undefined dynamic_lookup -fvisibility=hidden -std=c++14 + +Compilation time +---------------- + +The following log-log plot shows how the compilation time grows for an +increasing number of class and function declarations. pybind11 includes many +fewer headers, which initially leads to shorter compilation times, but the +performance is ultimately fairly similar (pybind11 is 19.8 seconds faster for +the largest largest file with 2048 classes and a total of 8192 methods -- a +modest **1.2x** speedup relative to Boost.Python, which required 116.35 +seconds). + +.. only:: not latex + + .. image:: pybind11_vs_boost_python1.svg + +.. only:: latex + + .. image:: pybind11_vs_boost_python1.png + +Module size +----------- + +Differences between the two libraries become much more pronounced when +considering the file size of the generated Python plugin: for the largest file, +the binary generated by Boost.Python required 16.8 MiB, which was **2.17 +times** / **9.1 megabytes** larger than the output generated by pybind11. For +very small inputs, Boost.Python has an edge in the plot below -- however, note +that it stores many definitions in an external library, whose size was not +included here, hence the comparison is slightly shifted in Boost.Python's +favor. + +.. only:: not latex + + .. image:: pybind11_vs_boost_python2.svg + +.. only:: latex + + .. image:: pybind11_vs_boost_python2.png + + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/changelog.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/changelog.rst new file mode 100644 index 0000000000000000000000000000000000000000..2def2b071933d7abe76d2154cf60c15c1df4fd9d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/changelog.rst @@ -0,0 +1,1277 @@ +.. _changelog: + +Changelog +######### + +Starting with version 1.8.0, pybind11 releases use a `semantic versioning +`_ policy. + +v2.5.0 (Mar 31, 2020) +----------------------------------------------------- + +* Use C++17 fold expressions in type casters, if available. This can + improve performance during overload resolution when functions have + multiple arguments. + `#2043 `_. + +* Changed include directory resolution in ``pybind11/__init__.py`` + and installation in ``setup.py``. This fixes a number of open issues + where pybind11 headers could not be found in certain environments. + `#1995 `_. + +* C++20 ``char8_t`` and ``u8string`` support. `#2026 + `_. + +* CMake: search for Python 3.9. `bb9c91 + `_. + +* Fixes for MSYS-based build environments. + `#2087 `_, + `#2053 `_. + +* STL bindings for ``std::vector<...>::clear``. `#2074 + `_. + +* Read-only flag for ``py::buffer``. `#1466 + `_. + +* Exception handling during module initialization. + `bf2b031 `_. + +* Support linking against a CPython debug build. + `#2025 `_. + +* Fixed issues involving the availability and use of aligned ``new`` and + ``delete``. `#1988 `_, + `759221 `_. + +* Fixed a resource leak upon interpreter shutdown. + `#2020 `_. + +* Fixed error handling in the boolean caster. + `#1976 `_. + +v2.4.3 (Oct 15, 2019) +----------------------------------------------------- + +* Adapt pybind11 to a C API convention change in Python 3.8. `#1950 + `_. + +v2.4.2 (Sep 21, 2019) +----------------------------------------------------- + +* Replaced usage of a C++14 only construct. `#1929 + `_. + +* Made an ifdef future-proof for Python >= 4. `f3109d + `_. + +v2.4.1 (Sep 20, 2019) +----------------------------------------------------- + +* Fixed a problem involving implicit conversion from enumerations to integers + on Python 3.8. `#1780 `_. + +v2.4.0 (Sep 19, 2019) +----------------------------------------------------- + +* Try harder to keep pybind11-internal data structures separate when there + are potential ABI incompatibilities. Fixes crashes that occurred when loading + multiple pybind11 extensions that were e.g. compiled by GCC (libstdc++) + and Clang (libc++). + `#1588 `_ and + `c9f5a `_. + +* Added support for ``__await__``, ``__aiter__``, and ``__anext__`` protocols. + `#1842 `_. + +* ``pybind11_add_module()``: don't strip symbols when compiling in + ``RelWithDebInfo`` mode. `#1980 + `_. + +* ``enum_``: Reproduce Python behavior when comparing against invalid values + (e.g. ``None``, strings, etc.). Add back support for ``__invert__()``. + `#1912 `_, + `#1907 `_. + +* List insertion operation for ``py::list``. + Added ``.empty()`` to all collection types. + Added ``py::set::contains()`` and ``py::dict::contains()``. + `#1887 `_, + `#1884 `_, + `#1888 `_. + +* ``py::details::overload_cast_impl`` is available in C++11 mode, can be used + like ``overload_cast`` with an additional set of parantheses. + `#1581 `_. + +* Fixed ``get_include()`` on Conda. + `#1877 `_. + +* ``stl_bind.h``: negative indexing support. + `#1882 `_. + +* Minor CMake fix to add MinGW compatibility. + `#1851 `_. + +* GIL-related fixes. + `#1836 `_, + `8b90b `_. + +* Other very minor/subtle fixes and improvements. + `#1329 `_, + `#1910 `_, + `#1863 `_, + `#1847 `_, + `#1890 `_, + `#1860 `_, + `#1848 `_, + `#1821 `_, + `#1837 `_, + `#1833 `_, + `#1748 `_, + `#1852 `_. + +v2.3.0 (June 11, 2019) +----------------------------------------------------- + +* Significantly reduced module binary size (10-20%) when compiled in C++11 mode + with GCC/Clang, or in any mode with MSVC. Function signatures are now always + precomputed at compile time (this was previously only available in C++14 mode + for non-MSVC compilers). + `#934 `_. + +* Add basic support for tag-based static polymorphism, where classes + provide a method to returns the desired type of an instance. + `#1326 `_. + +* Python type wrappers (``py::handle``, ``py::object``, etc.) + now support map Python's number protocol onto C++ arithmetic + operators such as ``operator+``, ``operator/=``, etc. + `#1511 `_. + +* A number of improvements related to enumerations: + + 1. The ``enum_`` implementation was rewritten from scratch to reduce + code bloat. Rather than instantiating a full implementation for each + enumeration, most code is now contained in a generic base class. + `#1511 `_. + + 2. The ``value()`` method of ``py::enum_`` now accepts an optional + docstring that will be shown in the documentation of the associated + enumeration. `#1160 `_. + + 3. check for already existing enum value and throw an error if present. + `#1453 `_. + +* Support for over-aligned type allocation via C++17's aligned ``new`` + statement. `#1582 `_. + +* Added ``py::ellipsis()`` method for slicing of multidimensional NumPy arrays + `#1502 `_. + +* Numerous Improvements to the ``mkdoc.py`` script for extracting documentation + from C++ header files. + `#1788 `_. + +* ``pybind11_add_module()``: allow including Python as a ``SYSTEM`` include path. + `#1416 `_. + +* ``pybind11/stl.h`` does not convert strings to ``vector`` anymore. + `#1258 `_. + +* Mark static methods as such to fix auto-generated Sphinx documentation. + `#1732 `_. + +* Re-throw forced unwind exceptions (e.g. during pthread termination). + `#1208 `_. + +* Added ``__contains__`` method to the bindings of maps (``std::map``, + ``std::unordered_map``). + `#1767 `_. + +* Improvements to ``gil_scoped_acquire``. + `#1211 `_. + +* Type caster support for ``std::deque``. + `#1609 `_. + +* Support for ``std::unique_ptr`` holders, whose deleters differ between a base and derived + class. `#1353 `_. + +* Construction of STL array/vector-like data structures from + iterators. Added an ``extend()`` operation. + `#1709 `_, + +* CMake build system improvements for projects that include non-C++ + files (e.g. plain C, CUDA) in ``pybind11_add_module`` et al. + `#1678 `_. + +* Fixed asynchronous invocation and deallocation of Python functions + wrapped in ``std::function``. + `#1595 `_. + +* Fixes regarding return value policy propagation in STL type casters. + `#1603 `_. + +* Fixed scoped enum comparisons. + `#1571 `_. + +* Fixed iostream redirection for code that releases the GIL. + `#1368 `_, + +* A number of CI-related fixes. + `#1757 `_, + `#1744 `_, + `#1670 `_. + +v2.2.4 (September 11, 2018) +----------------------------------------------------- + +* Use new Python 3.7 Thread Specific Storage (TSS) implementation if available. + `#1454 `_, + `#1517 `_. + +* Fixes for newer MSVC versions and C++17 mode. + `#1347 `_, + `#1462 `_. + +* Propagate return value policies to type-specific casters + when casting STL containers. + `#1455 `_. + +* Allow ostream-redirection of more than 1024 characters. + `#1479 `_. + +* Set ``Py_DEBUG`` define when compiling against a debug Python build. + `#1438 `_. + +* Untangle integer logic in number type caster to work for custom + types that may only be castable to a restricted set of builtin types. + `#1442 `_. + +* CMake build system: Remember Python version in cache file. + `#1434 `_. + +* Fix for custom smart pointers: use ``std::addressof`` to obtain holder + address instead of ``operator&``. + `#1435 `_. + +* Properly report exceptions thrown during module initialization. + `#1362 `_. + +* Fixed a segmentation fault when creating empty-shaped NumPy array. + `#1371 `_. + +* The version of Intel C++ compiler must be >= 2017, and this is now checked by + the header files. `#1363 `_. + +* A few minor typo fixes and improvements to the test suite, and + patches that silence compiler warnings. + +* Vectors now support construction from generators, as well as ``extend()`` from a + list or generator. + `#1496 `_. + + +v2.2.3 (April 29, 2018) +----------------------------------------------------- + +* The pybind11 header location detection was replaced by a new implementation + that no longer depends on ``pip`` internals (the recently released ``pip`` + 10 has restricted access to this API). + `#1190 `_. + +* Small adjustment to an implementation detail to work around a compiler segmentation fault in Clang 3.3/3.4. + `#1350 `_. + +* The minimal supported version of the Intel compiler was >= 17.0 since + pybind11 v2.1. This check is now explicit, and a compile-time error is raised + if the compiler meet the requirement. + `#1363 `_. + +* Fixed an endianness-related fault in the test suite. + `#1287 `_. + +v2.2.2 (February 7, 2018) +----------------------------------------------------- + +* Fixed a segfault when combining embedded interpreter + shutdown/reinitialization with external loaded pybind11 modules. + `#1092 `_. + +* Eigen support: fixed a bug where Nx1/1xN numpy inputs couldn't be passed as + arguments to Eigen vectors (which for Eigen are simply compile-time fixed + Nx1/1xN matrices). + `#1106 `_. + +* Clarified to license by moving the licensing of contributions from + ``LICENSE`` into ``CONTRIBUTING.md``: the licensing of contributions is not + actually part of the software license as distributed. This isn't meant to be + a substantial change in the licensing of the project, but addresses concerns + that the clause made the license non-standard. + `#1109 `_. + +* Fixed a regression introduced in 2.1 that broke binding functions with lvalue + character literal arguments. + `#1128 `_. + +* MSVC: fix for compilation failures under /permissive-, and added the flag to + the appveyor test suite. + `#1155 `_. + +* Fixed ``__qualname__`` generation, and in turn, fixes how class names + (especially nested class names) are shown in generated docstrings. + `#1171 `_. + +* Updated the FAQ with a suggested project citation reference. + `#1189 `_. + +* Added fixes for deprecation warnings when compiled under C++17 with + ``-Wdeprecated`` turned on, and add ``-Wdeprecated`` to the test suite + compilation flags. + `#1191 `_. + +* Fixed outdated PyPI URLs in ``setup.py``. + `#1213 `_. + +* Fixed a refcount leak for arguments that end up in a ``py::args`` argument + for functions with both fixed positional and ``py::args`` arguments. + `#1216 `_. + +* Fixed a potential segfault resulting from possible premature destruction of + ``py::args``/``py::kwargs`` arguments with overloaded functions. + `#1223 `_. + +* Fixed ``del map[item]`` for a ``stl_bind.h`` bound stl map. + `#1229 `_. + +* Fixed a regression from v2.1.x where the aggregate initialization could + unintentionally end up at a constructor taking a templated + ``std::initializer_list`` argument. + `#1249 `_. + +* Fixed an issue where calling a function with a keep_alive policy on the same + nurse/patient pair would cause the internal patient storage to needlessly + grow (unboundedly, if the nurse is long-lived). + `#1251 `_. + +* Various other minor fixes. + +v2.2.1 (September 14, 2017) +----------------------------------------------------- + +* Added ``py::module::reload()`` member function for reloading a module. + `#1040 `_. + +* Fixed a reference leak in the number converter. + `#1078 `_. + +* Fixed compilation with Clang on host GCC < 5 (old libstdc++ which isn't fully + C++11 compliant). `#1062 `_. + +* Fixed a regression where the automatic ``std::vector`` caster would + fail to compile. The same fix also applies to any container which returns + element proxies instead of references. + `#1053 `_. + +* Fixed a regression where the ``py::keep_alive`` policy could not be applied + to constructors. `#1065 `_. + +* Fixed a nullptr dereference when loading a ``py::module_local`` type + that's only registered in an external module. + `#1058 `_. + +* Fixed implicit conversion of accessors to types derived from ``py::object``. + `#1076 `_. + +* The ``name`` in ``PYBIND11_MODULE(name, variable)`` can now be a macro. + `#1082 `_. + +* Relaxed overly strict ``py::pickle()`` check for matching get and set types. + `#1064 `_. + +* Conversion errors now try to be more informative when it's likely that + a missing header is the cause (e.g. forgetting ````). + `#1077 `_. + +v2.2.0 (August 31, 2017) +----------------------------------------------------- + +* Support for embedding the Python interpreter. See the + :doc:`documentation page ` for a + full overview of the new features. + `#774 `_, + `#889 `_, + `#892 `_, + `#920 `_. + + .. code-block:: cpp + + #include + namespace py = pybind11; + + int main() { + py::scoped_interpreter guard{}; // start the interpreter and keep it alive + + py::print("Hello, World!"); // use the Python API + } + +* Support for inheriting from multiple C++ bases in Python. + `#693 `_. + + .. code-block:: python + + from cpp_module import CppBase1, CppBase2 + + class PyDerived(CppBase1, CppBase2): + def __init__(self): + CppBase1.__init__(self) # C++ bases must be initialized explicitly + CppBase2.__init__(self) + +* ``PYBIND11_MODULE`` is now the preferred way to create module entry points. + ``PYBIND11_PLUGIN`` is deprecated. See :ref:`macros` for details. + `#879 `_. + + .. code-block:: cpp + + // new + PYBIND11_MODULE(example, m) { + m.def("add", [](int a, int b) { return a + b; }); + } + + // old + PYBIND11_PLUGIN(example) { + py::module m("example"); + m.def("add", [](int a, int b) { return a + b; }); + return m.ptr(); + } + +* pybind11's headers and build system now more strictly enforce hidden symbol + visibility for extension modules. This should be seamless for most users, + but see the :doc:`upgrade` if you use a custom build system. + `#995 `_. + +* Support for ``py::module_local`` types which allow multiple modules to + export the same C++ types without conflicts. This is useful for opaque + types like ``std::vector``. ``py::bind_vector`` and ``py::bind_map`` + now default to ``py::module_local`` if their elements are builtins or + local types. See :ref:`module_local` for details. + `#949 `_, + `#981 `_, + `#995 `_, + `#997 `_. + +* Custom constructors can now be added very easily using lambdas or factory + functions which return a class instance by value, pointer or holder. This + supersedes the old placement-new ``__init__`` technique. + See :ref:`custom_constructors` for details. + `#805 `_, + `#1014 `_. + + .. code-block:: cpp + + struct Example { + Example(std::string); + }; + + py::class_(m, "Example") + .def(py::init()) // existing constructor + .def(py::init([](int n) { // custom constructor + return std::make_unique(std::to_string(n)); + })); + +* Similarly to custom constructors, pickling support functions are now bound + using the ``py::pickle()`` adaptor which improves type safety. See the + :doc:`upgrade` and :ref:`pickling` for details. + `#1038 `_. + +* Builtin support for converting C++17 standard library types and general + conversion improvements: + + 1. C++17 ``std::variant`` is supported right out of the box. C++11/14 + equivalents (e.g. ``boost::variant``) can also be added with a simple + user-defined specialization. See :ref:`cpp17_container_casters` for details. + `#811 `_, + `#845 `_, + `#989 `_. + + 2. Out-of-the-box support for C++17 ``std::string_view``. + `#906 `_. + + 3. Improved compatibility of the builtin ``optional`` converter. + `#874 `_. + + 4. The ``bool`` converter now accepts ``numpy.bool_`` and types which + define ``__bool__`` (Python 3.x) or ``__nonzero__`` (Python 2.7). + `#925 `_. + + 5. C++-to-Python casters are now more efficient and move elements out + of rvalue containers whenever possible. + `#851 `_, + `#936 `_, + `#938 `_. + + 6. Fixed ``bytes`` to ``std::string/char*`` conversion on Python 3. + `#817 `_. + + 7. Fixed lifetime of temporary C++ objects created in Python-to-C++ conversions. + `#924 `_. + +* Scope guard call policy for RAII types, e.g. ``py::call_guard()``, + ``py::call_guard()``. See :ref:`call_policies` for details. + `#740 `_. + +* Utility for redirecting C++ streams to Python (e.g. ``std::cout`` -> + ``sys.stdout``). Scope guard ``py::scoped_ostream_redirect`` in C++ and + a context manager in Python. See :ref:`ostream_redirect`. + `#1009 `_. + +* Improved handling of types and exceptions across module boundaries. + `#915 `_, + `#951 `_, + `#995 `_. + +* Fixed destruction order of ``py::keep_alive`` nurse/patient objects + in reference cycles. + `#856 `_. + +* Numpy and buffer protocol related improvements: + + 1. Support for negative strides in Python buffer objects/numpy arrays. This + required changing integers from unsigned to signed for the related C++ APIs. + Note: If you have compiler warnings enabled, you may notice some new conversion + warnings after upgrading. These can be resolved with ``static_cast``. + `#782 `_. + + 2. Support ``std::complex`` and arrays inside ``PYBIND11_NUMPY_DTYPE``. + `#831 `_, + `#832 `_. + + 3. Support for constructing ``py::buffer_info`` and ``py::arrays`` using + arbitrary containers or iterators instead of requiring a ``std::vector``. + `#788 `_, + `#822 `_, + `#860 `_. + + 4. Explicitly check numpy version and require >= 1.7.0. + `#819 `_. + +* Support for allowing/prohibiting ``None`` for specific arguments and improved + ``None`` overload resolution order. See :ref:`none_arguments` for details. + `#843 `_. + `#859 `_. + +* Added ``py::exec()`` as a shortcut for ``py::eval()`` + and support for C++11 raw string literals as input. See :ref:`eval`. + `#766 `_, + `#827 `_. + +* ``py::vectorize()`` ignores non-vectorizable arguments and supports + member functions. + `#762 `_. + +* Support for bound methods as callbacks (``pybind11/functional.h``). + `#815 `_. + +* Allow aliasing pybind11 methods: ``cls.attr("foo") = cls.attr("bar")``. + `#802 `_. + +* Don't allow mixed static/non-static overloads. + `#804 `_. + +* Fixed overriding static properties in derived classes. + `#784 `_. + +* Added support for write only properties. + `#1144 `_. + +* Improved deduction of member functions of a derived class when its bases + aren't registered with pybind11. + `#855 `_. + + .. code-block:: cpp + + struct Base { + int foo() { return 42; } + } + + struct Derived : Base {} + + // Now works, but previously required also binding `Base` + py::class_(m, "Derived") + .def("foo", &Derived::foo); // function is actually from `Base` + +* The implementation of ``py::init<>`` now uses C++11 brace initialization + syntax to construct instances, which permits binding implicit constructors of + aggregate types. `#1015 `_. + + .. code-block:: cpp + + struct Aggregate { + int a; + std::string b; + }; + + py::class_(m, "Aggregate") + .def(py::init()); + +* Fixed issues with multiple inheritance with offset base/derived pointers. + `#812 `_, + `#866 `_, + `#960 `_. + +* Fixed reference leak of type objects. + `#1030 `_. + +* Improved support for the ``/std:c++14`` and ``/std:c++latest`` modes + on MSVC 2017. + `#841 `_, + `#999 `_. + +* Fixed detection of private operator new on MSVC. + `#893 `_, + `#918 `_. + +* Intel C++ compiler compatibility fixes. + `#937 `_. + +* Fixed implicit conversion of `py::enum_` to integer types on Python 2.7. + `#821 `_. + +* Added ``py::hash`` to fetch the hash value of Python objects, and + ``.def(hash(py::self))`` to provide the C++ ``std::hash`` as the Python + ``__hash__`` method. + `#1034 `_. + +* Fixed ``__truediv__`` on Python 2 and ``__itruediv__`` on Python 3. + `#867 `_. + +* ``py::capsule`` objects now support the ``name`` attribute. This is useful + for interfacing with ``scipy.LowLevelCallable``. + `#902 `_. + +* Fixed ``py::make_iterator``'s ``__next__()`` for past-the-end calls. + `#897 `_. + +* Added ``error_already_set::matches()`` for checking Python exceptions. + `#772 `_. + +* Deprecated ``py::error_already_set::clear()``. It's no longer needed + following a simplification of the ``py::error_already_set`` class. + `#954 `_. + +* Deprecated ``py::handle::operator==()`` in favor of ``py::handle::is()`` + `#825 `_. + +* Deprecated ``py::object::borrowed``/``py::object::stolen``. + Use ``py::object::borrowed_t{}``/``py::object::stolen_t{}`` instead. + `#771 `_. + +* Changed internal data structure versioning to avoid conflicts between + modules compiled with different revisions of pybind11. + `#1012 `_. + +* Additional compile-time and run-time error checking and more informative messages. + `#786 `_, + `#794 `_, + `#803 `_. + +* Various minor improvements and fixes. + `#764 `_, + `#791 `_, + `#795 `_, + `#840 `_, + `#844 `_, + `#846 `_, + `#849 `_, + `#858 `_, + `#862 `_, + `#871 `_, + `#872 `_, + `#881 `_, + `#888 `_, + `#899 `_, + `#928 `_, + `#931 `_, + `#944 `_, + `#950 `_, + `#952 `_, + `#962 `_, + `#965 `_, + `#970 `_, + `#978 `_, + `#979 `_, + `#986 `_, + `#1020 `_, + `#1027 `_, + `#1037 `_. + +* Testing improvements. + `#798 `_, + `#882 `_, + `#898 `_, + `#900 `_, + `#921 `_, + `#923 `_, + `#963 `_. + +v2.1.1 (April 7, 2017) +----------------------------------------------------- + +* Fixed minimum version requirement for MSVC 2015u3 + `#773 `_. + +v2.1.0 (March 22, 2017) +----------------------------------------------------- + +* pybind11 now performs function overload resolution in two phases. The first + phase only considers exact type matches, while the second allows for implicit + conversions to take place. A special ``noconvert()`` syntax can be used to + completely disable implicit conversions for specific arguments. + `#643 `_, + `#634 `_, + `#650 `_. + +* Fixed a regression where static properties no longer worked with classes + using multiple inheritance. The ``py::metaclass`` attribute is no longer + necessary (and deprecated as of this release) when binding classes with + static properties. + `#679 `_, + +* Classes bound using ``pybind11`` can now use custom metaclasses. + `#679 `_, + +* ``py::args`` and ``py::kwargs`` can now be mixed with other positional + arguments when binding functions using pybind11. + `#611 `_. + +* Improved support for C++11 unicode string and character types; added + extensive documentation regarding pybind11's string conversion behavior. + `#624 `_, + `#636 `_, + `#715 `_. + +* pybind11 can now avoid expensive copies when converting Eigen arrays to NumPy + arrays (and vice versa). `#610 `_. + +* The "fast path" in ``py::vectorize`` now works for any full-size group of C or + F-contiguous arrays. The non-fast path is also faster since it no longer performs + copies of the input arguments (except when type conversions are necessary). + `#610 `_. + +* Added fast, unchecked access to NumPy arrays via a proxy object. + `#746 `_. + +* Transparent support for class-specific ``operator new`` and + ``operator delete`` implementations. + `#755 `_. + +* Slimmer and more efficient STL-compatible iterator interface for sequence types. + `#662 `_. + +* Improved custom holder type support. + `#607 `_. + +* ``nullptr`` to ``None`` conversion fixed in various builtin type casters. + `#732 `_. + +* ``enum_`` now exposes its members via a special ``__members__`` attribute. + `#666 `_. + +* ``std::vector`` bindings created using ``stl_bind.h`` can now optionally + implement the buffer protocol. `#488 `_. + +* Automated C++ reference documentation using doxygen and breathe. + `#598 `_. + +* Added minimum compiler version assertions. + `#727 `_. + +* Improved compatibility with C++1z. + `#677 `_. + +* Improved ``py::capsule`` API. Can be used to implement cleanup + callbacks that are involved at module destruction time. + `#752 `_. + +* Various minor improvements and fixes. + `#595 `_, + `#588 `_, + `#589 `_, + `#603 `_, + `#619 `_, + `#648 `_, + `#695 `_, + `#720 `_, + `#723 `_, + `#729 `_, + `#724 `_, + `#742 `_, + `#753 `_. + +v2.0.1 (Jan 4, 2017) +----------------------------------------------------- + +* Fix pointer to reference error in type_caster on MSVC + `#583 `_. + +* Fixed a segmentation in the test suite due to a typo + `cd7eac `_. + +v2.0.0 (Jan 1, 2017) +----------------------------------------------------- + +* Fixed a reference counting regression affecting types with custom metaclasses + (introduced in v2.0.0-rc1). + `#571 `_. + +* Quenched a CMake policy warning. + `#570 `_. + +v2.0.0-rc1 (Dec 23, 2016) +----------------------------------------------------- + +The pybind11 developers are excited to issue a release candidate of pybind11 +with a subsequent v2.0.0 release planned in early January next year. + +An incredible amount of effort by went into pybind11 over the last ~5 months, +leading to a release that is jam-packed with exciting new features and numerous +usability improvements. The following list links PRs or individual commits +whenever applicable. + +Happy Christmas! + +* Support for binding C++ class hierarchies that make use of multiple + inheritance. `#410 `_. + +* PyPy support: pybind11 now supports nightly builds of PyPy and will + interoperate with the future 5.7 release. No code changes are necessary, + everything "just" works as usual. Note that we only target the Python 2.7 + branch for now; support for 3.x will be added once its ``cpyext`` extension + support catches up. A few minor features remain unsupported for the time + being (notably dynamic attributes in custom types). + `#527 `_. + +* Significant work on the documentation -- in particular, the monolithic + ``advanced.rst`` file was restructured into a easier to read hierarchical + organization. `#448 `_. + +* Many NumPy-related improvements: + + 1. Object-oriented API to access and modify NumPy ``ndarray`` instances, + replicating much of the corresponding NumPy C API functionality. + `#402 `_. + + 2. NumPy array ``dtype`` array descriptors are now first-class citizens and + are exposed via a new class ``py::dtype``. + + 3. Structured dtypes can be registered using the ``PYBIND11_NUMPY_DTYPE()`` + macro. Special ``array`` constructors accepting dtype objects were also + added. + + One potential caveat involving this change: format descriptor strings + should now be accessed via ``format_descriptor::format()`` (however, for + compatibility purposes, the old syntax ``format_descriptor::value`` will + still work for non-structured data types). `#308 + `_. + + 4. Further improvements to support structured dtypes throughout the system. + `#472 `_, + `#474 `_, + `#459 `_, + `#453 `_, + `#452 `_, and + `#505 `_. + + 5. Fast access operators. `#497 `_. + + 6. Constructors for arrays whose storage is owned by another object. + `#440 `_. + + 7. Added constructors for ``array`` and ``array_t`` explicitly accepting shape + and strides; if strides are not provided, they are deduced assuming + C-contiguity. Also added simplified constructors for 1-dimensional case. + + 8. Added buffer/NumPy support for ``char[N]`` and ``std::array`` types. + + 9. Added ``memoryview`` wrapper type which is constructible from ``buffer_info``. + +* Eigen: many additional conversions and support for non-contiguous + arrays/slices. + `#427 `_, + `#315 `_, + `#316 `_, + `#312 `_, and + `#267 `_ + +* Incompatible changes in ``class_<...>::class_()``: + + 1. Declarations of types that provide access via the buffer protocol must + now include the ``py::buffer_protocol()`` annotation as an argument to + the ``class_`` constructor. + + 2. Declarations of types that require a custom metaclass (i.e. all classes + which include static properties via commands such as + ``def_readwrite_static()``) must now include the ``py::metaclass()`` + annotation as an argument to the ``class_`` constructor. + + These two changes were necessary to make type definitions in pybind11 + future-proof, and to support PyPy via its cpyext mechanism. `#527 + `_. + + + 3. This version of pybind11 uses a redesigned mechanism for instantiating + trampoline classes that are used to override virtual methods from within + Python. This led to the following user-visible syntax change: instead of + + .. code-block:: cpp + + py::class_("MyClass") + .alias() + .... + + write + + .. code-block:: cpp + + py::class_("MyClass") + .... + + Importantly, both the original and the trampoline class are now + specified as an arguments (in arbitrary order) to the ``py::class_`` + template, and the ``alias<..>()`` call is gone. The new scheme has zero + overhead in cases when Python doesn't override any functions of the + underlying C++ class. `rev. 86d825 + `_. + +* Added ``eval`` and ``eval_file`` functions for evaluating expressions and + statements from a string or file. `rev. 0d3fc3 + `_. + +* pybind11 can now create types with a modifiable dictionary. + `#437 `_ and + `#444 `_. + +* Support for translation of arbitrary C++ exceptions to Python counterparts. + `#296 `_ and + `#273 `_. + +* Report full backtraces through mixed C++/Python code, better reporting for + import errors, fixed GIL management in exception processing. + `#537 `_, + `#494 `_, + `rev. e72d95 `_, and + `rev. 099d6e `_. + +* Support for bit-level operations, comparisons, and serialization of C++ + enumerations. `#503 `_, + `#508 `_, + `#380 `_, + `#309 `_. + `#311 `_. + +* The ``class_`` constructor now accepts its template arguments in any order. + `#385 `_. + +* Attribute and item accessors now have a more complete interface which makes + it possible to chain attributes as in + ``obj.attr("a")[key].attr("b").attr("method")(1, 2, 3)``. `#425 + `_. + +* Major redesign of the default and conversion constructors in ``pytypes.h``. + `#464 `_. + +* Added built-in support for ``std::shared_ptr`` holder type. It is no longer + necessary to to include a declaration of the form + ``PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr)`` (though continuing to + do so won't cause an error). + `#454 `_. + +* New ``py::overload_cast`` casting operator to select among multiple possible + overloads of a function. An example: + + .. code-block:: cpp + + py::class_(m, "Pet") + .def("set", py::overload_cast(&Pet::set), "Set the pet's age") + .def("set", py::overload_cast(&Pet::set), "Set the pet's name"); + + This feature only works on C++14-capable compilers. + `#541 `_. + +* C++ types are automatically cast to Python types, e.g. when assigning + them as an attribute. For instance, the following is now legal: + + .. code-block:: cpp + + py::module m = /* ... */ + m.attr("constant") = 123; + + (Previously, a ``py::cast`` call was necessary to avoid a compilation error.) + `#551 `_. + +* Redesigned ``pytest``-based test suite. `#321 `_. + +* Instance tracking to detect reference leaks in test suite. `#324 `_ + +* pybind11 can now distinguish between multiple different instances that are + located at the same memory address, but which have different types. + `#329 `_. + +* Improved logic in ``move`` return value policy. + `#510 `_, + `#297 `_. + +* Generalized unpacking API to permit calling Python functions from C++ using + notation such as ``foo(a1, a2, *args, "ka"_a=1, "kb"_a=2, **kwargs)``. `#372 `_. + +* ``py::print()`` function whose behavior matches that of the native Python + ``print()`` function. `#372 `_. + +* Added ``py::dict`` keyword constructor:``auto d = dict("number"_a=42, + "name"_a="World");``. `#372 `_. + +* Added ``py::str::format()`` method and ``_s`` literal: ``py::str s = "1 + 2 + = {}"_s.format(3);``. `#372 `_. + +* Added ``py::repr()`` function which is equivalent to Python's builtin + ``repr()``. `#333 `_. + +* Improved construction and destruction logic for holder types. It is now + possible to reference instances with smart pointer holder types without + constructing the holder if desired. The ``PYBIND11_DECLARE_HOLDER_TYPE`` + macro now accepts an optional second parameter to indicate whether the holder + type uses intrusive reference counting. + `#533 `_ and + `#561 `_. + +* Mapping a stateless C++ function to Python and back is now "for free" (i.e. + no extra indirections or argument conversion overheads). `rev. 954b79 + `_. + +* Bindings for ``std::valarray``. + `#545 `_. + +* Improved support for C++17 capable compilers. + `#562 `_. + +* Bindings for ``std::optional``. + `#475 `_, + `#476 `_, + `#479 `_, + `#499 `_, and + `#501 `_. + +* ``stl_bind.h``: general improvements and support for ``std::map`` and + ``std::unordered_map``. + `#490 `_, + `#282 `_, + `#235 `_. + +* The ``std::tuple``, ``std::pair``, ``std::list``, and ``std::vector`` type + casters now accept any Python sequence type as input. `rev. 107285 + `_. + +* Improved CMake Python detection on multi-architecture Linux. + `#532 `_. + +* Infrastructure to selectively disable or enable parts of the automatically + generated docstrings. `#486 `_. + +* ``reference`` and ``reference_internal`` are now the default return value + properties for static and non-static properties, respectively. `#473 + `_. (the previous defaults + were ``automatic``). `#473 `_. + +* Support for ``std::unique_ptr`` with non-default deleters or no deleter at + all (``py::nodelete``). `#384 `_. + +* Deprecated ``handle::call()`` method. The new syntax to call Python + functions is simply ``handle()``. It can also be invoked explicitly via + ``handle::operator()``, where ``X`` is an optional return value policy. + +* Print more informative error messages when ``make_tuple()`` or ``cast()`` + fail. `#262 `_. + +* Creation of holder types for classes deriving from + ``std::enable_shared_from_this<>`` now also works for ``const`` values. + `#260 `_. + +* ``make_iterator()`` improvements for better compatibility with various + types (now uses prefix increment operator); it now also accepts iterators + with different begin/end types as long as they are equality comparable. + `#247 `_. + +* ``arg()`` now accepts a wider range of argument types for default values. + `#244 `_. + +* Support ``keep_alive`` where the nurse object may be ``None``. `#341 + `_. + +* Added constructors for ``str`` and ``bytes`` from zero-terminated char + pointers, and from char pointers and length. Added constructors for ``str`` + from ``bytes`` and for ``bytes`` from ``str``, which will perform UTF-8 + decoding/encoding as required. + +* Many other improvements of library internals without user-visible changes + + +1.8.1 (July 12, 2016) +---------------------- +* Fixed a rare but potentially very severe issue when the garbage collector ran + during pybind11 type creation. + +1.8.0 (June 14, 2016) +---------------------- +* Redesigned CMake build system which exports a convenient + ``pybind11_add_module`` function to parent projects. +* ``std::vector<>`` type bindings analogous to Boost.Python's ``indexing_suite`` +* Transparent conversion of sparse and dense Eigen matrices and vectors (``eigen.h``) +* Added an ``ExtraFlags`` template argument to the NumPy ``array_t<>`` wrapper + to disable an enforced cast that may lose precision, e.g. to create overloads + for different precisions and complex vs real-valued matrices. +* Prevent implicit conversion of floating point values to integral types in + function arguments +* Fixed incorrect default return value policy for functions returning a shared + pointer +* Don't allow registering a type via ``class_`` twice +* Don't allow casting a ``None`` value into a C++ lvalue reference +* Fixed a crash in ``enum_::operator==`` that was triggered by the ``help()`` command +* Improved detection of whether or not custom C++ types can be copy/move-constructed +* Extended ``str`` type to also work with ``bytes`` instances +* Added a ``"name"_a`` user defined string literal that is equivalent to ``py::arg("name")``. +* When specifying function arguments via ``py::arg``, the test that verifies + the number of arguments now runs at compile time. +* Added ``[[noreturn]]`` attribute to ``pybind11_fail()`` to quench some + compiler warnings +* List function arguments in exception text when the dispatch code cannot find + a matching overload +* Added ``PYBIND11_OVERLOAD_NAME`` and ``PYBIND11_OVERLOAD_PURE_NAME`` macros which + can be used to override virtual methods whose name differs in C++ and Python + (e.g. ``__call__`` and ``operator()``) +* Various minor ``iterator`` and ``make_iterator()`` improvements +* Transparently support ``__bool__`` on Python 2.x and Python 3.x +* Fixed issue with destructor of unpickled object not being called +* Minor CMake build system improvements on Windows +* New ``pybind11::args`` and ``pybind11::kwargs`` types to create functions which + take an arbitrary number of arguments and keyword arguments +* New syntax to call a Python function from C++ using ``*args`` and ``*kwargs`` +* The functions ``def_property_*`` now correctly process docstring arguments (these + formerly caused a segmentation fault) +* Many ``mkdoc.py`` improvements (enumerations, template arguments, ``DOC()`` + macro accepts more arguments) +* Cygwin support +* Documentation improvements (pickling support, ``keep_alive``, macro usage) + +1.7 (April 30, 2016) +---------------------- +* Added a new ``move`` return value policy that triggers C++11 move semantics. + The automatic return value policy falls back to this case whenever a rvalue + reference is encountered +* Significantly more general GIL state routines that are used instead of + Python's troublesome ``PyGILState_Ensure`` and ``PyGILState_Release`` API +* Redesign of opaque types that drastically simplifies their usage +* Extended ability to pass values of type ``[const] void *`` +* ``keep_alive`` fix: don't fail when there is no patient +* ``functional.h``: acquire the GIL before calling a Python function +* Added Python RAII type wrappers ``none`` and ``iterable`` +* Added ``*args`` and ``*kwargs`` pass-through parameters to + ``pybind11.get_include()`` function +* Iterator improvements and fixes +* Documentation on return value policies and opaque types improved + +1.6 (April 30, 2016) +---------------------- +* Skipped due to upload to PyPI gone wrong and inability to recover + (https://github.com/pypa/packaging-problems/issues/74) + +1.5 (April 21, 2016) +---------------------- +* For polymorphic types, use RTTI to try to return the closest type registered with pybind11 +* Pickling support for serializing and unserializing C++ instances to a byte stream in Python +* Added a convenience routine ``make_iterator()`` which turns a range indicated + by a pair of C++ iterators into a iterable Python object +* Added ``len()`` and a variadic ``make_tuple()`` function +* Addressed a rare issue that could confuse the current virtual function + dispatcher and another that could lead to crashes in multi-threaded + applications +* Added a ``get_include()`` function to the Python module that returns the path + of the directory containing the installed pybind11 header files +* Documentation improvements: import issues, symbol visibility, pickling, limitations +* Added casting support for ``std::reference_wrapper<>`` + +1.4 (April 7, 2016) +-------------------------- +* Transparent type conversion for ``std::wstring`` and ``wchar_t`` +* Allow passing ``nullptr``-valued strings +* Transparent passing of ``void *`` pointers using capsules +* Transparent support for returning values wrapped in ``std::unique_ptr<>`` +* Improved docstring generation for compatibility with Sphinx +* Nicer debug error message when default parameter construction fails +* Support for "opaque" types that bypass the transparent conversion layer for STL containers +* Redesigned type casting interface to avoid ambiguities that could occasionally cause compiler errors +* Redesigned property implementation; fixes crashes due to an unfortunate default return value policy +* Anaconda package generation support + +1.3 (March 8, 2016) +-------------------------- + +* Added support for the Intel C++ compiler (v15+) +* Added support for the STL unordered set/map data structures +* Added support for the STL linked list data structure +* NumPy-style broadcasting support in ``pybind11::vectorize`` +* pybind11 now displays more verbose error messages when ``arg::operator=()`` fails +* pybind11 internal data structures now live in a version-dependent namespace to avoid ABI issues +* Many, many bugfixes involving corner cases and advanced usage + +1.2 (February 7, 2016) +-------------------------- + +* Optional: efficient generation of function signatures at compile time using C++14 +* Switched to a simpler and more general way of dealing with function default + arguments. Unused keyword arguments in function calls are now detected and + cause errors as expected +* New ``keep_alive`` call policy analogous to Boost.Python's ``with_custodian_and_ward`` +* New ``pybind11::base<>`` attribute to indicate a subclass relationship +* Improved interface for RAII type wrappers in ``pytypes.h`` +* Use RAII type wrappers consistently within pybind11 itself. This + fixes various potential refcount leaks when exceptions occur +* Added new ``bytes`` RAII type wrapper (maps to ``string`` in Python 2.7) +* Made handle and related RAII classes const correct, using them more + consistently everywhere now +* Got rid of the ugly ``__pybind11__`` attributes on the Python side---they are + now stored in a C++ hash table that is not visible in Python +* Fixed refcount leaks involving NumPy arrays and bound functions +* Vastly improved handling of shared/smart pointers +* Removed an unnecessary copy operation in ``pybind11::vectorize`` +* Fixed naming clashes when both pybind11 and NumPy headers are included +* Added conversions for additional exception types +* Documentation improvements (using multiple extension modules, smart pointers, + other minor clarifications) +* unified infrastructure for parsing variadic arguments in ``class_`` and cpp_function +* Fixed license text (was: ZLIB, should have been: 3-clause BSD) +* Python 3.2 compatibility +* Fixed remaining issues when accessing types in another plugin module +* Added enum comparison and casting methods +* Improved SFINAE-based detection of whether types are copy-constructible +* Eliminated many warnings about unused variables and the use of ``offsetof()`` +* Support for ``std::array<>`` conversions + +1.1 (December 7, 2015) +-------------------------- + +* Documentation improvements (GIL, wrapping functions, casting, fixed many typos) +* Generalized conversion of integer types +* Improved support for casting function objects +* Improved support for ``std::shared_ptr<>`` conversions +* Initial support for ``std::set<>`` conversions +* Fixed type resolution issue for types defined in a separate plugin module +* Cmake build system improvements +* Factored out generic functionality to non-templated code (smaller code size) +* Added a code size / compile time benchmark vs Boost.Python +* Added an appveyor CI script + +1.0 (October 15, 2015) +------------------------ +* Initial release diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/classes.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/classes.rst new file mode 100644 index 0000000000000000000000000000000000000000..a63f6a1969222d0348282bcea86c9c71ce92d5b7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/classes.rst @@ -0,0 +1,532 @@ +.. _classes: + +Object-oriented code +#################### + +Creating bindings for a custom type +=================================== + +Let's now look at a more complex example where we'll create bindings for a +custom C++ data structure named ``Pet``. Its definition is given below: + +.. code-block:: cpp + + struct Pet { + Pet(const std::string &name) : name(name) { } + void setName(const std::string &name_) { name = name_; } + const std::string &getName() const { return name; } + + std::string name; + }; + +The binding code for ``Pet`` looks as follows: + +.. code-block:: cpp + + #include + + namespace py = pybind11; + + PYBIND11_MODULE(example, m) { + py::class_(m, "Pet") + .def(py::init()) + .def("setName", &Pet::setName) + .def("getName", &Pet::getName); + } + +:class:`class_` creates bindings for a C++ *class* or *struct*-style data +structure. :func:`init` is a convenience function that takes the types of a +constructor's parameters as template arguments and wraps the corresponding +constructor (see the :ref:`custom_constructors` section for details). An +interactive Python session demonstrating this example is shown below: + +.. code-block:: pycon + + % python + >>> import example + >>> p = example.Pet('Molly') + >>> print(p) + + >>> p.getName() + u'Molly' + >>> p.setName('Charly') + >>> p.getName() + u'Charly' + +.. seealso:: + + Static member functions can be bound in the same way using + :func:`class_::def_static`. + +Keyword and default arguments +============================= +It is possible to specify keyword and default arguments using the syntax +discussed in the previous chapter. Refer to the sections :ref:`keyword_args` +and :ref:`default_args` for details. + +Binding lambda functions +======================== + +Note how ``print(p)`` produced a rather useless summary of our data structure in the example above: + +.. code-block:: pycon + + >>> print(p) + + +To address this, we could bind an utility function that returns a human-readable +summary to the special method slot named ``__repr__``. Unfortunately, there is no +suitable functionality in the ``Pet`` data structure, and it would be nice if +we did not have to change it. This can easily be accomplished by binding a +Lambda function instead: + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def("setName", &Pet::setName) + .def("getName", &Pet::getName) + .def("__repr__", + [](const Pet &a) { + return ""; + } + ); + +Both stateless [#f1]_ and stateful lambda closures are supported by pybind11. +With the above change, the same Python code now produces the following output: + +.. code-block:: pycon + + >>> print(p) + + +.. [#f1] Stateless closures are those with an empty pair of brackets ``[]`` as the capture object. + +.. _properties: + +Instance and static fields +========================== + +We can also directly expose the ``name`` field using the +:func:`class_::def_readwrite` method. A similar :func:`class_::def_readonly` +method also exists for ``const`` fields. + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def_readwrite("name", &Pet::name) + // ... remainder ... + +This makes it possible to write + +.. code-block:: pycon + + >>> p = example.Pet('Molly') + >>> p.name + u'Molly' + >>> p.name = 'Charly' + >>> p.name + u'Charly' + +Now suppose that ``Pet::name`` was a private internal variable +that can only be accessed via setters and getters. + +.. code-block:: cpp + + class Pet { + public: + Pet(const std::string &name) : name(name) { } + void setName(const std::string &name_) { name = name_; } + const std::string &getName() const { return name; } + private: + std::string name; + }; + +In this case, the method :func:`class_::def_property` +(:func:`class_::def_property_readonly` for read-only data) can be used to +provide a field-like interface within Python that will transparently call +the setter and getter functions: + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def_property("name", &Pet::getName, &Pet::setName) + // ... remainder ... + +Write only properties can be defined by passing ``nullptr`` as the +input for the read function. + +.. seealso:: + + Similar functions :func:`class_::def_readwrite_static`, + :func:`class_::def_readonly_static` :func:`class_::def_property_static`, + and :func:`class_::def_property_readonly_static` are provided for binding + static variables and properties. Please also see the section on + :ref:`static_properties` in the advanced part of the documentation. + +Dynamic attributes +================== + +Native Python classes can pick up new attributes dynamically: + +.. code-block:: pycon + + >>> class Pet: + ... name = 'Molly' + ... + >>> p = Pet() + >>> p.name = 'Charly' # overwrite existing + >>> p.age = 2 # dynamically add a new attribute + +By default, classes exported from C++ do not support this and the only writable +attributes are the ones explicitly defined using :func:`class_::def_readwrite` +or :func:`class_::def_property`. + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init<>()) + .def_readwrite("name", &Pet::name); + +Trying to set any other attribute results in an error: + +.. code-block:: pycon + + >>> p = example.Pet() + >>> p.name = 'Charly' # OK, attribute defined in C++ + >>> p.age = 2 # fail + AttributeError: 'Pet' object has no attribute 'age' + +To enable dynamic attributes for C++ classes, the :class:`py::dynamic_attr` tag +must be added to the :class:`py::class_` constructor: + +.. code-block:: cpp + + py::class_(m, "Pet", py::dynamic_attr()) + .def(py::init<>()) + .def_readwrite("name", &Pet::name); + +Now everything works as expected: + +.. code-block:: pycon + + >>> p = example.Pet() + >>> p.name = 'Charly' # OK, overwrite value in C++ + >>> p.age = 2 # OK, dynamically add a new attribute + >>> p.__dict__ # just like a native Python class + {'age': 2} + +Note that there is a small runtime cost for a class with dynamic attributes. +Not only because of the addition of a ``__dict__``, but also because of more +expensive garbage collection tracking which must be activated to resolve +possible circular references. Native Python classes incur this same cost by +default, so this is not anything to worry about. By default, pybind11 classes +are more efficient than native Python classes. Enabling dynamic attributes +just brings them on par. + +.. _inheritance: + +Inheritance and automatic downcasting +===================================== + +Suppose now that the example consists of two data structures with an +inheritance relationship: + +.. code-block:: cpp + + struct Pet { + Pet(const std::string &name) : name(name) { } + std::string name; + }; + + struct Dog : Pet { + Dog(const std::string &name) : Pet(name) { } + std::string bark() const { return "woof!"; } + }; + +There are two different ways of indicating a hierarchical relationship to +pybind11: the first specifies the C++ base class as an extra template +parameter of the :class:`class_`: + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def_readwrite("name", &Pet::name); + + // Method 1: template parameter: + py::class_(m, "Dog") + .def(py::init()) + .def("bark", &Dog::bark); + +Alternatively, we can also assign a name to the previously bound ``Pet`` +:class:`class_` object and reference it when binding the ``Dog`` class: + +.. code-block:: cpp + + py::class_ pet(m, "Pet"); + pet.def(py::init()) + .def_readwrite("name", &Pet::name); + + // Method 2: pass parent class_ object: + py::class_(m, "Dog", pet /* <- specify Python parent type */) + .def(py::init()) + .def("bark", &Dog::bark); + +Functionality-wise, both approaches are equivalent. Afterwards, instances will +expose fields and methods of both types: + +.. code-block:: pycon + + >>> p = example.Dog('Molly') + >>> p.name + u'Molly' + >>> p.bark() + u'woof!' + +The C++ classes defined above are regular non-polymorphic types with an +inheritance relationship. This is reflected in Python: + +.. code-block:: cpp + + // Return a base pointer to a derived instance + m.def("pet_store", []() { return std::unique_ptr(new Dog("Molly")); }); + +.. code-block:: pycon + + >>> p = example.pet_store() + >>> type(p) # `Dog` instance behind `Pet` pointer + Pet # no pointer downcasting for regular non-polymorphic types + >>> p.bark() + AttributeError: 'Pet' object has no attribute 'bark' + +The function returned a ``Dog`` instance, but because it's a non-polymorphic +type behind a base pointer, Python only sees a ``Pet``. In C++, a type is only +considered polymorphic if it has at least one virtual function and pybind11 +will automatically recognize this: + +.. code-block:: cpp + + struct PolymorphicPet { + virtual ~PolymorphicPet() = default; + }; + + struct PolymorphicDog : PolymorphicPet { + std::string bark() const { return "woof!"; } + }; + + // Same binding code + py::class_(m, "PolymorphicPet"); + py::class_(m, "PolymorphicDog") + .def(py::init<>()) + .def("bark", &PolymorphicDog::bark); + + // Again, return a base pointer to a derived instance + m.def("pet_store2", []() { return std::unique_ptr(new PolymorphicDog); }); + +.. code-block:: pycon + + >>> p = example.pet_store2() + >>> type(p) + PolymorphicDog # automatically downcast + >>> p.bark() + u'woof!' + +Given a pointer to a polymorphic base, pybind11 performs automatic downcasting +to the actual derived type. Note that this goes beyond the usual situation in +C++: we don't just get access to the virtual functions of the base, we get the +concrete derived type including functions and attributes that the base type may +not even be aware of. + +.. seealso:: + + For more information about polymorphic behavior see :ref:`overriding_virtuals`. + + +Overloaded methods +================== + +Sometimes there are several overloaded C++ methods with the same name taking +different kinds of input arguments: + +.. code-block:: cpp + + struct Pet { + Pet(const std::string &name, int age) : name(name), age(age) { } + + void set(int age_) { age = age_; } + void set(const std::string &name_) { name = name_; } + + std::string name; + int age; + }; + +Attempting to bind ``Pet::set`` will cause an error since the compiler does not +know which method the user intended to select. We can disambiguate by casting +them to function pointers. Binding multiple functions to the same Python name +automatically creates a chain of function overloads that will be tried in +sequence. + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def("set", (void (Pet::*)(int)) &Pet::set, "Set the pet's age") + .def("set", (void (Pet::*)(const std::string &)) &Pet::set, "Set the pet's name"); + +The overload signatures are also visible in the method's docstring: + +.. code-block:: pycon + + >>> help(example.Pet) + + class Pet(__builtin__.object) + | Methods defined here: + | + | __init__(...) + | Signature : (Pet, str, int) -> NoneType + | + | set(...) + | 1. Signature : (Pet, int) -> NoneType + | + | Set the pet's age + | + | 2. Signature : (Pet, str) -> NoneType + | + | Set the pet's name + +If you have a C++14 compatible compiler [#cpp14]_, you can use an alternative +syntax to cast the overloaded function: + +.. code-block:: cpp + + py::class_(m, "Pet") + .def("set", py::overload_cast(&Pet::set), "Set the pet's age") + .def("set", py::overload_cast(&Pet::set), "Set the pet's name"); + +Here, ``py::overload_cast`` only requires the parameter types to be specified. +The return type and class are deduced. This avoids the additional noise of +``void (Pet::*)()`` as seen in the raw cast. If a function is overloaded based +on constness, the ``py::const_`` tag should be used: + +.. code-block:: cpp + + struct Widget { + int foo(int x, float y); + int foo(int x, float y) const; + }; + + py::class_(m, "Widget") + .def("foo_mutable", py::overload_cast(&Widget::foo)) + .def("foo_const", py::overload_cast(&Widget::foo, py::const_)); + +If you prefer the ``py::overload_cast`` syntax but have a C++11 compatible compiler only, +you can use ``py::detail::overload_cast_impl`` with an additional set of parentheses: + +.. code-block:: cpp + + template + using overload_cast_ = pybind11::detail::overload_cast_impl; + + py::class_(m, "Pet") + .def("set", overload_cast_()(&Pet::set), "Set the pet's age") + .def("set", overload_cast_()(&Pet::set), "Set the pet's name"); + +.. [#cpp14] A compiler which supports the ``-std=c++14`` flag + or Visual Studio 2015 Update 2 and newer. + +.. note:: + + To define multiple overloaded constructors, simply declare one after the + other using the ``.def(py::init<...>())`` syntax. The existing machinery + for specifying keyword and default arguments also works. + +Enumerations and internal types +=============================== + +Let's now suppose that the example class contains an internal enumeration type, +e.g.: + +.. code-block:: cpp + + struct Pet { + enum Kind { + Dog = 0, + Cat + }; + + Pet(const std::string &name, Kind type) : name(name), type(type) { } + + std::string name; + Kind type; + }; + +The binding code for this example looks as follows: + +.. code-block:: cpp + + py::class_ pet(m, "Pet"); + + pet.def(py::init()) + .def_readwrite("name", &Pet::name) + .def_readwrite("type", &Pet::type); + + py::enum_(pet, "Kind") + .value("Dog", Pet::Kind::Dog) + .value("Cat", Pet::Kind::Cat) + .export_values(); + +To ensure that the ``Kind`` type is created within the scope of ``Pet``, the +``pet`` :class:`class_` instance must be supplied to the :class:`enum_`. +constructor. The :func:`enum_::export_values` function exports the enum entries +into the parent scope, which should be skipped for newer C++11-style strongly +typed enums. + +.. code-block:: pycon + + >>> p = Pet('Lucy', Pet.Cat) + >>> p.type + Kind.Cat + >>> int(p.type) + 1L + +The entries defined by the enumeration type are exposed in the ``__members__`` property: + +.. code-block:: pycon + + >>> Pet.Kind.__members__ + {'Dog': Kind.Dog, 'Cat': Kind.Cat} + +The ``name`` property returns the name of the enum value as a unicode string. + +.. note:: + + It is also possible to use ``str(enum)``, however these accomplish different + goals. The following shows how these two approaches differ. + + .. code-block:: pycon + + >>> p = Pet( "Lucy", Pet.Cat ) + >>> pet_type = p.type + >>> pet_type + Pet.Cat + >>> str(pet_type) + 'Pet.Cat' + >>> pet_type.name + 'Cat' + +.. note:: + + When the special tag ``py::arithmetic()`` is specified to the ``enum_`` + constructor, pybind11 creates an enumeration that also supports rudimentary + arithmetic and bit-level operations like comparisons, and, or, xor, negation, + etc. + + .. code-block:: cpp + + py::enum_(pet, "Kind", py::arithmetic()) + ... + + By default, these are omitted to conserve space. diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/compiling.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/compiling.rst new file mode 100644 index 0000000000000000000000000000000000000000..c50c7d8afbb9bf0fad068a35ad27d5d411dcbeda --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/compiling.rst @@ -0,0 +1,289 @@ +.. _compiling: + +Build systems +############# + +Building with setuptools +======================== + +For projects on PyPI, building with setuptools is the way to go. Sylvain Corlay +has kindly provided an example project which shows how to set up everything, +including automatic generation of documentation using Sphinx. Please refer to +the [python_example]_ repository. + +.. [python_example] https://github.com/pybind/python_example + +Building with cppimport +======================== + +[cppimport]_ is a small Python import hook that determines whether there is a C++ +source file whose name matches the requested module. If there is, the file is +compiled as a Python extension using pybind11 and placed in the same folder as +the C++ source file. Python is then able to find the module and load it. + +.. [cppimport] https://github.com/tbenthompson/cppimport + +.. _cmake: + +Building with CMake +=================== + +For C++ codebases that have an existing CMake-based build system, a Python +extension module can be created with just a few lines of code: + +.. code-block:: cmake + + cmake_minimum_required(VERSION 2.8.12) + project(example) + + add_subdirectory(pybind11) + pybind11_add_module(example example.cpp) + +This assumes that the pybind11 repository is located in a subdirectory named +:file:`pybind11` and that the code is located in a file named :file:`example.cpp`. +The CMake command ``add_subdirectory`` will import the pybind11 project which +provides the ``pybind11_add_module`` function. It will take care of all the +details needed to build a Python extension module on any platform. + +A working sample project, including a way to invoke CMake from :file:`setup.py` for +PyPI integration, can be found in the [cmake_example]_ repository. + +.. [cmake_example] https://github.com/pybind/cmake_example + +pybind11_add_module +------------------- + +To ease the creation of Python extension modules, pybind11 provides a CMake +function with the following signature: + +.. code-block:: cmake + + pybind11_add_module( [MODULE | SHARED] [EXCLUDE_FROM_ALL] + [NO_EXTRAS] [SYSTEM] [THIN_LTO] source1 [source2 ...]) + +This function behaves very much like CMake's builtin ``add_library`` (in fact, +it's a wrapper function around that command). It will add a library target +called ```` to be built from the listed source files. In addition, it +will take care of all the Python-specific compiler and linker flags as well +as the OS- and Python-version-specific file extension. The produced target +```` can be further manipulated with regular CMake commands. + +``MODULE`` or ``SHARED`` may be given to specify the type of library. If no +type is given, ``MODULE`` is used by default which ensures the creation of a +Python-exclusive module. Specifying ``SHARED`` will create a more traditional +dynamic library which can also be linked from elsewhere. ``EXCLUDE_FROM_ALL`` +removes this target from the default build (see CMake docs for details). + +Since pybind11 is a template library, ``pybind11_add_module`` adds compiler +flags to ensure high quality code generation without bloat arising from long +symbol names and duplication of code in different translation units. It +sets default visibility to *hidden*, which is required for some pybind11 +features and functionality when attempting to load multiple pybind11 modules +compiled under different pybind11 versions. It also adds additional flags +enabling LTO (Link Time Optimization) and strip unneeded symbols. See the +:ref:`FAQ entry ` for a more detailed explanation. These +latter optimizations are never applied in ``Debug`` mode. If ``NO_EXTRAS`` is +given, they will always be disabled, even in ``Release`` mode. However, this +will result in code bloat and is generally not recommended. + +By default, pybind11 and Python headers will be included with ``-I``. In order +to include pybind11 as system library, e.g. to avoid warnings in downstream +code with warn-levels outside of pybind11's scope, set the option ``SYSTEM``. + +As stated above, LTO is enabled by default. Some newer compilers also support +different flavors of LTO such as `ThinLTO`_. Setting ``THIN_LTO`` will cause +the function to prefer this flavor if available. The function falls back to +regular LTO if ``-flto=thin`` is not available. + +.. _ThinLTO: http://clang.llvm.org/docs/ThinLTO.html + +Configuration variables +----------------------- + +By default, pybind11 will compile modules with the C++14 standard, if available +on the target compiler, falling back to C++11 if C++14 support is not +available. Note, however, that this default is subject to change: future +pybind11 releases are expected to migrate to newer C++ standards as they become +available. To override this, the standard flag can be given explicitly in +``PYBIND11_CPP_STANDARD``: + +.. code-block:: cmake + + # Use just one of these: + # GCC/clang: + set(PYBIND11_CPP_STANDARD -std=c++11) + set(PYBIND11_CPP_STANDARD -std=c++14) + set(PYBIND11_CPP_STANDARD -std=c++1z) # Experimental C++17 support + # MSVC: + set(PYBIND11_CPP_STANDARD /std:c++14) + set(PYBIND11_CPP_STANDARD /std:c++latest) # Enables some MSVC C++17 features + + add_subdirectory(pybind11) # or find_package(pybind11) + +Note that this and all other configuration variables must be set **before** the +call to ``add_subdirectory`` or ``find_package``. The variables can also be set +when calling CMake from the command line using the ``-D=`` flag. + +The target Python version can be selected by setting ``PYBIND11_PYTHON_VERSION`` +or an exact Python installation can be specified with ``PYTHON_EXECUTABLE``. +For example: + +.. code-block:: bash + + cmake -DPYBIND11_PYTHON_VERSION=3.6 .. + # or + cmake -DPYTHON_EXECUTABLE=path/to/python .. + +find_package vs. add_subdirectory +--------------------------------- + +For CMake-based projects that don't include the pybind11 repository internally, +an external installation can be detected through ``find_package(pybind11)``. +See the `Config file`_ docstring for details of relevant CMake variables. + +.. code-block:: cmake + + cmake_minimum_required(VERSION 2.8.12) + project(example) + + find_package(pybind11 REQUIRED) + pybind11_add_module(example example.cpp) + +Note that ``find_package(pybind11)`` will only work correctly if pybind11 +has been correctly installed on the system, e. g. after downloading or cloning +the pybind11 repository : + +.. code-block:: bash + + cd pybind11 + mkdir build + cd build + cmake .. + make install + +Once detected, the aforementioned ``pybind11_add_module`` can be employed as +before. The function usage and configuration variables are identical no matter +if pybind11 is added as a subdirectory or found as an installed package. You +can refer to the same [cmake_example]_ repository for a full sample project +-- just swap out ``add_subdirectory`` for ``find_package``. + +.. _Config file: https://github.com/pybind/pybind11/blob/master/tools/pybind11Config.cmake.in + +Advanced: interface library target +---------------------------------- + +When using a version of CMake greater than 3.0, pybind11 can additionally +be used as a special *interface library* . The target ``pybind11::module`` +is available with pybind11 headers, Python headers and libraries as needed, +and C++ compile definitions attached. This target is suitable for linking +to an independently constructed (through ``add_library``, not +``pybind11_add_module``) target in the consuming project. + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.0) + project(example) + + find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) + + add_library(example MODULE main.cpp) + target_link_libraries(example PRIVATE pybind11::module) + set_target_properties(example PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" + SUFFIX "${PYTHON_MODULE_EXTENSION}") + +.. warning:: + + Since pybind11 is a metatemplate library, it is crucial that certain + compiler flags are provided to ensure high quality code generation. In + contrast to the ``pybind11_add_module()`` command, the CMake interface + library only provides the *minimal* set of parameters to ensure that the + code using pybind11 compiles, but it does **not** pass these extra compiler + flags (i.e. this is up to you). + + These include Link Time Optimization (``-flto`` on GCC/Clang/ICPC, ``/GL`` + and ``/LTCG`` on Visual Studio) and .OBJ files with many sections on Visual + Studio (``/bigobj``). The :ref:`FAQ ` contains an + explanation on why these are needed. + +Embedding the Python interpreter +-------------------------------- + +In addition to extension modules, pybind11 also supports embedding Python into +a C++ executable or library. In CMake, simply link with the ``pybind11::embed`` +target. It provides everything needed to get the interpreter running. The Python +headers and libraries are attached to the target. Unlike ``pybind11::module``, +there is no need to manually set any additional properties here. For more +information about usage in C++, see :doc:`/advanced/embedding`. + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.0) + project(example) + + find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) + + add_executable(example main.cpp) + target_link_libraries(example PRIVATE pybind11::embed) + +.. _building_manually: + +Building manually +================= + +pybind11 is a header-only library, hence it is not necessary to link against +any special libraries and there are no intermediate (magic) translation steps. + +On Linux, you can compile an example such as the one given in +:ref:`simple_example` using the following command: + +.. code-block:: bash + + $ c++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix` + +The flags given here assume that you're using Python 3. For Python 2, just +change the executable appropriately (to ``python`` or ``python2``). + +The ``python3 -m pybind11 --includes`` command fetches the include paths for +both pybind11 and Python headers. This assumes that pybind11 has been installed +using ``pip`` or ``conda``. If it hasn't, you can also manually specify +``-I /include`` together with the Python includes path +``python3-config --includes``. + +Note that Python 2.7 modules don't use a special suffix, so you should simply +use ``example.so`` instead of ``example`python3-config --extension-suffix```. +Besides, the ``--extension-suffix`` option may or may not be available, depending +on the distribution; in the latter case, the module extension can be manually +set to ``.so``. + +On Mac OS: the build command is almost the same but it also requires passing +the ``-undefined dynamic_lookup`` flag so as to ignore missing symbols when +building the module: + +.. code-block:: bash + + $ c++ -O3 -Wall -shared -std=c++11 -undefined dynamic_lookup `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix` + +In general, it is advisable to include several additional build parameters +that can considerably reduce the size of the created binary. Refer to section +:ref:`cmake` for a detailed example of a suitable cross-platform CMake-based +build system that works on all platforms including Windows. + +.. note:: + + On Linux and macOS, it's better to (intentionally) not link against + ``libpython``. The symbols will be resolved when the extension library + is loaded into a Python binary. This is preferable because you might + have several different installations of a given Python version (e.g. the + system-provided Python, and one that ships with a piece of commercial + software). In this way, the plugin will work with both versions, instead + of possibly importing a second Python library into a process that already + contains one (which will lead to a segfault). + +Generating binding code automatically +===================================== + +The ``Binder`` project is a tool for automatic generation of pybind11 binding +code by introspecting existing C++ codebases using LLVM/Clang. See the +[binder]_ documentation for details. + +.. [binder] http://cppbinder.readthedocs.io/en/latest/about.html diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/conf.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..fa6332de5209efc6b75c65ae42877f798850da77 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/conf.py @@ -0,0 +1,332 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# pybind11 documentation build configuration file, created by +# sphinx-quickstart on Sun Oct 11 19:23:48 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex +import subprocess + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['breathe'] + +breathe_projects = {'pybind11': '.build/doxygenxml/'} +breathe_default_project = 'pybind11' +breathe_domain_by_extension = {'h': 'cpp'} + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['.templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'pybind11' +copyright = '2017, Wenzel Jakob' +author = 'Wenzel Jakob' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2.5' +# The full version, including alpha/beta/rc tags. +release = '2.5.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['.build', 'release.rst'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +default_role = 'any' + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +#pygments_style = 'monokai' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. + +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + + html_context = { + 'css_files': [ + '_static/theme_overrides.css' + ] + } +else: + html_context = { + 'css_files': [ + '//media.readthedocs.org/css/sphinx_rtd_theme.css', + '//media.readthedocs.org/css/readthedocs-doc-embed.css', + '_static/theme_overrides.css' + ] + } + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'pybind11doc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +'preamble': '\DeclareUnicodeCharacter{00A0}{}', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'pybind11.tex', 'pybind11 Documentation', + 'Wenzel Jakob', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = 'pybind11-logo.png' + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'pybind11', 'pybind11 Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'pybind11', 'pybind11 Documentation', + author, 'pybind11', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + +primary_domain = 'cpp' +highlight_language = 'cpp' + + +def generate_doxygen_xml(app): + build_dir = os.path.join(app.confdir, '.build') + if not os.path.exists(build_dir): + os.mkdir(build_dir) + + try: + subprocess.call(['doxygen', '--version']) + retcode = subprocess.call(['doxygen'], cwd=app.confdir) + if retcode < 0: + sys.stderr.write("doxygen error code: {}\n".format(-retcode)) + except OSError as e: + sys.stderr.write("doxygen execution failed: {}\n".format(e)) + + +def setup(app): + """Add hook for building doxygen xml when needed""" + app.connect("builder-inited", generate_doxygen_xml) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/faq.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/faq.rst new file mode 100644 index 0000000000000000000000000000000000000000..4d491fb87f7f94b807a5f87cee625c2be3801062 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/faq.rst @@ -0,0 +1,324 @@ +Frequently asked questions +########################## + +"ImportError: dynamic module does not define init function" +=========================================================== + +1. Make sure that the name specified in PYBIND11_MODULE is identical to the +filename of the extension library (without prefixes such as .so) + +2. If the above did not fix the issue, you are likely using an incompatible +version of Python (for instance, the extension library was compiled against +Python 2, while the interpreter is running on top of some version of Python +3, or vice versa). + +"Symbol not found: ``__Py_ZeroStruct`` / ``_PyInstanceMethod_Type``" +======================================================================== + +See the first answer. + +"SystemError: dynamic module not initialized properly" +====================================================== + +See the first answer. + +The Python interpreter immediately crashes when importing my module +=================================================================== + +See the first answer. + +CMake doesn't detect the right Python version +============================================= + +The CMake-based build system will try to automatically detect the installed +version of Python and link against that. When this fails, or when there are +multiple versions of Python and it finds the wrong one, delete +``CMakeCache.txt`` and then invoke CMake as follows: + +.. code-block:: bash + + cmake -DPYTHON_EXECUTABLE:FILEPATH= . + +.. _faq_reference_arguments: + +Limitations involving reference arguments +========================================= + +In C++, it's fairly common to pass arguments using mutable references or +mutable pointers, which allows both read and write access to the value +supplied by the caller. This is sometimes done for efficiency reasons, or to +realize functions that have multiple return values. Here are two very basic +examples: + +.. code-block:: cpp + + void increment(int &i) { i++; } + void increment_ptr(int *i) { (*i)++; } + +In Python, all arguments are passed by reference, so there is no general +issue in binding such code from Python. + +However, certain basic Python types (like ``str``, ``int``, ``bool``, +``float``, etc.) are **immutable**. This means that the following attempt +to port the function to Python doesn't have the same effect on the value +provided by the caller -- in fact, it does nothing at all. + +.. code-block:: python + + def increment(i): + i += 1 # nope.. + +pybind11 is also affected by such language-level conventions, which means that +binding ``increment`` or ``increment_ptr`` will also create Python functions +that don't modify their arguments. + +Although inconvenient, one workaround is to encapsulate the immutable types in +a custom type that does allow modifications. + +An other alternative involves binding a small wrapper lambda function that +returns a tuple with all output arguments (see the remainder of the +documentation for examples on binding lambda functions). An example: + +.. code-block:: cpp + + int foo(int &i) { i++; return 123; } + +and the binding code + +.. code-block:: cpp + + m.def("foo", [](int i) { int rv = foo(i); return std::make_tuple(rv, i); }); + + +How can I reduce the build time? +================================ + +It's good practice to split binding code over multiple files, as in the +following example: + +:file:`example.cpp`: + +.. code-block:: cpp + + void init_ex1(py::module &); + void init_ex2(py::module &); + /* ... */ + + PYBIND11_MODULE(example, m) { + init_ex1(m); + init_ex2(m); + /* ... */ + } + +:file:`ex1.cpp`: + +.. code-block:: cpp + + void init_ex1(py::module &m) { + m.def("add", [](int a, int b) { return a + b; }); + } + +:file:`ex2.cpp`: + +.. code-block:: cpp + + void init_ex2(py::module &m) { + m.def("sub", [](int a, int b) { return a - b; }); + } + +:command:`python`: + +.. code-block:: pycon + + >>> import example + >>> example.add(1, 2) + 3 + >>> example.sub(1, 1) + 0 + +As shown above, the various ``init_ex`` functions should be contained in +separate files that can be compiled independently from one another, and then +linked together into the same final shared object. Following this approach +will: + +1. reduce memory requirements per compilation unit. + +2. enable parallel builds (if desired). + +3. allow for faster incremental builds. For instance, when a single class + definition is changed, only a subset of the binding code will generally need + to be recompiled. + +"recursive template instantiation exceeded maximum depth of 256" +================================================================ + +If you receive an error about excessive recursive template evaluation, try +specifying a larger value, e.g. ``-ftemplate-depth=1024`` on GCC/Clang. The +culprit is generally the generation of function signatures at compile time +using C++14 template metaprogramming. + +.. _`faq:hidden_visibility`: + +"‘SomeClass’ declared with greater visibility than the type of its field ‘SomeClass::member’ [-Wattributes]" +============================================================================================================ + +This error typically indicates that you are compiling without the required +``-fvisibility`` flag. pybind11 code internally forces hidden visibility on +all internal code, but if non-hidden (and thus *exported*) code attempts to +include a pybind type (for example, ``py::object`` or ``py::list``) you can run +into this warning. + +To avoid it, make sure you are specifying ``-fvisibility=hidden`` when +compiling pybind code. + +As to why ``-fvisibility=hidden`` is necessary, because pybind modules could +have been compiled under different versions of pybind itself, it is also +important that the symbols defined in one module do not clash with the +potentially-incompatible symbols defined in another. While Python extension +modules are usually loaded with localized symbols (under POSIX systems +typically using ``dlopen`` with the ``RTLD_LOCAL`` flag), this Python default +can be changed, but even if it isn't it is not always enough to guarantee +complete independence of the symbols involved when not using +``-fvisibility=hidden``. + +Additionally, ``-fvisiblity=hidden`` can deliver considerably binary size +savings. (See the following section for more details). + + +.. _`faq:symhidden`: + +How can I create smaller binaries? +================================== + +To do its job, pybind11 extensively relies on a programming technique known as +*template metaprogramming*, which is a way of performing computation at compile +time using type information. Template metaprogamming usually instantiates code +involving significant numbers of deeply nested types that are either completely +removed or reduced to just a few instructions during the compiler's optimization +phase. However, due to the nested nature of these types, the resulting symbol +names in the compiled extension library can be extremely long. For instance, +the included test suite contains the following symbol: + +.. only:: html + + .. code-block:: none + + _​_​Z​N​8​p​y​b​i​n​d​1​1​1​2​c​p​p​_​f​u​n​c​t​i​o​n​C​1​I​v​8​E​x​a​m​p​l​e​2​J​R​N​S​t​3​_​_​1​6​v​e​c​t​o​r​I​N​S​3​_​1​2​b​a​s​i​c​_​s​t​r​i​n​g​I​w​N​S​3​_​1​1​c​h​a​r​_​t​r​a​i​t​s​I​w​E​E​N​S​3​_​9​a​l​l​o​c​a​t​o​r​I​w​E​E​E​E​N​S​8​_​I​S​A​_​E​E​E​E​E​J​N​S​_​4​n​a​m​e​E​N​S​_​7​s​i​b​l​i​n​g​E​N​S​_​9​i​s​_​m​e​t​h​o​d​E​A​2​8​_​c​E​E​E​M​T​0​_​F​T​_​D​p​T​1​_​E​D​p​R​K​T​2​_ + +.. only:: not html + + .. code-block:: cpp + + __ZN8pybind1112cpp_functionC1Iv8Example2JRNSt3__16vectorINS3_12basic_stringIwNS3_11char_traitsIwEENS3_9allocatorIwEEEENS8_ISA_EEEEEJNS_4nameENS_7siblingENS_9is_methodEA28_cEEEMT0_FT_DpT1_EDpRKT2_ + +which is the mangled form of the following function type: + +.. code-block:: cpp + + pybind11::cpp_function::cpp_function, std::__1::allocator >, std::__1::allocator, std::__1::allocator > > >&, pybind11::name, pybind11::sibling, pybind11::is_method, char [28]>(void (Example2::*)(std::__1::vector, std::__1::allocator >, std::__1::allocator, std::__1::allocator > > >&), pybind11::name const&, pybind11::sibling const&, pybind11::is_method const&, char const (&) [28]) + +The memory needed to store just the mangled name of this function (196 bytes) +is larger than the actual piece of code (111 bytes) it represents! On the other +hand, it's silly to even give this function a name -- after all, it's just a +tiny cog in a bigger piece of machinery that is not exposed to the outside +world. So we'll generally only want to export symbols for those functions which +are actually called from the outside. + +This can be achieved by specifying the parameter ``-fvisibility=hidden`` to GCC +and Clang, which sets the default symbol visibility to *hidden*, which has a +tremendous impact on the final binary size of the resulting extension library. +(On Visual Studio, symbols are already hidden by default, so nothing needs to +be done there.) + +In addition to decreasing binary size, ``-fvisibility=hidden`` also avoids +potential serious issues when loading multiple modules and is required for +proper pybind operation. See the previous FAQ entry for more details. + +Working with ancient Visual Studio 2008 builds on Windows +========================================================= + +The official Windows distributions of Python are compiled using truly +ancient versions of Visual Studio that lack good C++11 support. Some users +implicitly assume that it would be impossible to load a plugin built with +Visual Studio 2015 into a Python distribution that was compiled using Visual +Studio 2008. However, no such issue exists: it's perfectly legitimate to +interface DLLs that are built with different compilers and/or C libraries. +Common gotchas to watch out for involve not ``free()``-ing memory region +that that were ``malloc()``-ed in another shared library, using data +structures with incompatible ABIs, and so on. pybind11 is very careful not +to make these types of mistakes. + +How can I properly handle Ctrl-C in long-running functions? +=========================================================== + +Ctrl-C is received by the Python interpreter, and holds it until the GIL +is released, so a long-running function won't be interrupted. + +To interrupt from inside your function, you can use the ``PyErr_CheckSignals()`` +function, that will tell if a signal has been raised on the Python side. This +function merely checks a flag, so its impact is negligible. When a signal has +been received, you must either explicitly interrupt execution by throwing +``py::error_already_set`` (which will propagate the existing +``KeyboardInterrupt``), or clear the error (which you usually will not want): + +.. code-block:: cpp + + PYBIND11_MODULE(example, m) + { + m.def("long running_func", []() + { + for (;;) { + if (PyErr_CheckSignals() != 0) + throw py::error_already_set(); + // Long running iteration + } + }); + } + +Inconsistent detection of Python version in CMake and pybind11 +============================================================== + +The functions ``find_package(PythonInterp)`` and ``find_package(PythonLibs)`` provided by CMake +for Python version detection are not used by pybind11 due to unreliability and limitations that make +them unsuitable for pybind11's needs. Instead pybind provides its own, more reliable Python detection +CMake code. Conflicts can arise, however, when using pybind11 in a project that *also* uses the CMake +Python detection in a system with several Python versions installed. + +This difference may cause inconsistencies and errors if *both* mechanisms are used in the same project. Consider the following +Cmake code executed in a system with Python 2.7 and 3.x installed: + +.. code-block:: cmake + + find_package(PythonInterp) + find_package(PythonLibs) + find_package(pybind11) + +It will detect Python 2.7 and pybind11 will pick it as well. + +In contrast this code: + +.. code-block:: cmake + + find_package(pybind11) + find_package(PythonInterp) + find_package(PythonLibs) + +will detect Python 3.x for pybind11 and may crash on ``find_package(PythonLibs)`` afterwards. + +It is advised to avoid using ``find_package(PythonInterp)`` and ``find_package(PythonLibs)`` from CMake and rely +on pybind11 in detecting Python version. If this is not possible CMake machinery should be called *before* including pybind11. + +How to cite this project? +========================= + +We suggest the following BibTeX template to cite pybind11 in scientific +discourse: + +.. code-block:: bash + + @misc{pybind11, + author = {Wenzel Jakob and Jason Rhinelander and Dean Moldovan}, + year = {2017}, + note = {https://github.com/pybind/pybind11}, + title = {pybind11 -- Seamless operability between C++11 and Python} + } diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/index.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..d236611b7224454415f395194cb72f783a42af37 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/index.rst @@ -0,0 +1,47 @@ +.. only: not latex + + .. image:: pybind11-logo.png + +pybind11 --- Seamless operability between C++11 and Python +========================================================== + +.. only: not latex + + Contents: + +.. toctree:: + :maxdepth: 1 + + intro + changelog + upgrade + +.. toctree:: + :caption: The Basics + :maxdepth: 2 + + basics + classes + compiling + +.. toctree:: + :caption: Advanced Topics + :maxdepth: 2 + + advanced/functions + advanced/classes + advanced/exceptions + advanced/smart_ptrs + advanced/cast/index + advanced/pycpp/index + advanced/embedding + advanced/misc + +.. toctree:: + :caption: Extra Information + :maxdepth: 1 + + faq + benchmark + limitations + reference diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/intro.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/intro.rst new file mode 100644 index 0000000000000000000000000000000000000000..10e1799a19d4a2be8efb8f58515b290ef36514f8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/intro.rst @@ -0,0 +1,93 @@ +.. image:: pybind11-logo.png + +About this project +================== +**pybind11** is a lightweight header-only library that exposes C++ types in Python +and vice versa, mainly to create Python bindings of existing C++ code. Its +goals and syntax are similar to the excellent `Boost.Python`_ library by David +Abrahams: to minimize boilerplate code in traditional extension modules by +inferring type information using compile-time introspection. + +.. _Boost.Python: http://www.boost.org/doc/libs/release/libs/python/doc/index.html + +The main issue with Boost.Python—and the reason for creating such a similar +project—is Boost. Boost is an enormously large and complex suite of utility +libraries that works with almost every C++ compiler in existence. This +compatibility has its cost: arcane template tricks and workarounds are +necessary to support the oldest and buggiest of compiler specimens. Now that +C++11-compatible compilers are widely available, this heavy machinery has +become an excessively large and unnecessary dependency. +Think of this library as a tiny self-contained version of Boost.Python with +everything stripped away that isn't relevant for binding generation. Without +comments, the core header files only require ~4K lines of code and depend on +Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This +compact implementation was possible thanks to some of the new C++11 language +features (specifically: tuples, lambda functions and variadic templates). Since +its creation, this library has grown beyond Boost.Python in many ways, leading +to dramatically simpler binding code in many common situations. + +Core features +************* +The following core C++ features can be mapped to Python + +- Functions accepting and returning custom data structures per value, reference, or pointer +- Instance methods and static methods +- Overloaded functions +- Instance attributes and static attributes +- Arbitrary exception types +- Enumerations +- Callbacks +- Iterators and ranges +- Custom operators +- Single and multiple inheritance +- STL data structures +- Smart pointers with reference counting like ``std::shared_ptr`` +- Internal references with correct reference counting +- C++ classes with virtual (and pure virtual) methods can be extended in Python + +Goodies +******* +In addition to the core functionality, pybind11 provides some extra goodies: + +- Python 2.7, 3.x, and PyPy (PyPy2.7 >= 5.7) are supported with an + implementation-agnostic interface. + +- It is possible to bind C++11 lambda functions with captured variables. The + lambda capture data is stored inside the resulting Python function object. + +- pybind11 uses C++11 move constructors and move assignment operators whenever + possible to efficiently transfer custom data types. + +- It's easy to expose the internal storage of custom data types through + Pythons' buffer protocols. This is handy e.g. for fast conversion between + C++ matrix classes like Eigen and NumPy without expensive copy operations. + +- pybind11 can automatically vectorize functions so that they are transparently + applied to all entries of one or more NumPy array arguments. + +- Python's slice-based access and assignment operations can be supported with + just a few lines of code. + +- Everything is contained in just a few header files; there is no need to link + against any additional libraries. + +- Binaries are generally smaller by a factor of at least 2 compared to + equivalent bindings generated by Boost.Python. A recent pybind11 conversion + of `PyRosetta`_, an enormous Boost.Python binding project, reported a binary + size reduction of **5.4x** and compile time reduction by **5.8x**. + +- Function signatures are precomputed at compile time (using ``constexpr``), + leading to smaller binaries. + +- With little extra effort, C++ types can be pickled and unpickled similar to + regular Python objects. + +.. _PyRosetta: http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf + +Supported compilers +******************* + +1. Clang/LLVM (any non-ancient version with C++11 support) +2. GCC 4.8 or newer +3. Microsoft Visual Studio 2015 or newer +4. Intel C++ compiler v17 or newer (v16 with pybind11 v2.0 and v15 with pybind11 v2.0 and a `workaround `_ ) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/limitations.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/limitations.rst new file mode 100644 index 0000000000000000000000000000000000000000..a1a4f1affa2c9b993fe8749a102088171daa6e22 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/limitations.rst @@ -0,0 +1,20 @@ +Limitations +########### + +pybind11 strives to be a general solution to binding generation, but it also has +certain limitations: + +- pybind11 casts away ``const``-ness in function arguments and return values. + This is in line with the Python language, which has no concept of ``const`` + values. This means that some additional care is needed to avoid bugs that + would be caught by the type checker in a traditional C++ program. + +- The NumPy interface ``pybind11::array`` greatly simplifies accessing + numerical data from C++ (and vice versa), but it's not a full-blown array + class like ``Eigen::Array`` or ``boost.multi_array``. + +These features could be implemented but would lead to a significant increase in +complexity. I've decided to draw the line here to keep this project simple and +compact. Users who absolutely require these features are encouraged to fork +pybind11. + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11-logo.png b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4cbad54f797d3ced04d4048f282df5e4336d4af4 Binary files /dev/null and b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11-logo.png differ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python1.png b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python1.png new file mode 100644 index 0000000000000000000000000000000000000000..833231f240809884fb6eb4079db528b9b3c0a9ac Binary files /dev/null and b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python1.png differ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python1.svg b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python1.svg new file mode 100644 index 0000000000000000000000000000000000000000..5bf950e6fdc81676d9a9774926a623b4f6a2e2a8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python1.svg @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python2.png b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python2.png new file mode 100644 index 0000000000000000000000000000000000000000..9f17272c50663957d6ae6d8e23fdd5a15757e71f Binary files /dev/null and b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python2.png differ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python2.svg b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python2.svg new file mode 100644 index 0000000000000000000000000000000000000000..5ed6530ca112cbe643d5dd6d6fde385c4edea6b5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/pybind11_vs_boost_python2.svg @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/reference.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/reference.rst new file mode 100644 index 0000000000000000000000000000000000000000..a9fbe60015ca466e71a37f6f9cd9866bfa7adfe5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/reference.rst @@ -0,0 +1,117 @@ +.. _reference: + +.. warning:: + + Please be advised that the reference documentation discussing pybind11 + internals is currently incomplete. Please refer to the previous sections + and the pybind11 header files for the nitty gritty details. + +Reference +######### + +.. _macros: + +Macros +====== + +.. doxygendefine:: PYBIND11_MODULE + +.. _core_types: + +Convenience classes for arbitrary Python types +============================================== + +Common member functions +----------------------- + +.. doxygenclass:: object_api + :members: + +Without reference counting +-------------------------- + +.. doxygenclass:: handle + :members: + +With reference counting +----------------------- + +.. doxygenclass:: object + :members: + +.. doxygenfunction:: reinterpret_borrow + +.. doxygenfunction:: reinterpret_steal + +Convenience classes for specific Python types +============================================= + +.. doxygenclass:: module + :members: + +.. doxygengroup:: pytypes + :members: + +.. _extras: + +Passing extra arguments to ``def`` or ``class_`` +================================================ + +.. doxygengroup:: annotations + :members: + +Embedding the interpreter +========================= + +.. doxygendefine:: PYBIND11_EMBEDDED_MODULE + +.. doxygenfunction:: initialize_interpreter + +.. doxygenfunction:: finalize_interpreter + +.. doxygenclass:: scoped_interpreter + +Redirecting C++ streams +======================= + +.. doxygenclass:: scoped_ostream_redirect + +.. doxygenclass:: scoped_estream_redirect + +.. doxygenfunction:: add_ostream_redirect + +Python built-in functions +========================= + +.. doxygengroup:: python_builtins + :members: + +Inheritance +=========== + +See :doc:`/classes` and :doc:`/advanced/classes` for more detail. + +.. doxygendefine:: PYBIND11_OVERLOAD + +.. doxygendefine:: PYBIND11_OVERLOAD_PURE + +.. doxygendefine:: PYBIND11_OVERLOAD_NAME + +.. doxygendefine:: PYBIND11_OVERLOAD_PURE_NAME + +.. doxygenfunction:: get_overload + +Exceptions +========== + +.. doxygenclass:: error_already_set + :members: + +.. doxygenclass:: builtin_exception + :members: + + +Literals +======== + +.. doxygennamespace:: literals diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/release.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/release.rst new file mode 100644 index 0000000000000000000000000000000000000000..9846f971a6ff88e40ceeaf16e14227ba3b6ae63c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/release.rst @@ -0,0 +1,21 @@ +To release a new version of pybind11: + +- Update the version number and push to pypi + - Update ``pybind11/_version.py`` (set release version, remove 'dev'). + - Update ``PYBIND11_VERSION_MAJOR`` etc. in ``include/pybind11/detail/common.h``. + - Ensure that all the information in ``setup.py`` is up-to-date. + - Update version in ``docs/conf.py``. + - Tag release date in ``docs/changelog.rst``. + - ``git add`` and ``git commit``. + - if new minor version: ``git checkout -b vX.Y``, ``git push -u origin vX.Y`` + - ``git tag -a vX.Y.Z -m 'vX.Y.Z release'``. + - ``git push`` + - ``git push --tags``. + - ``python setup.py sdist upload``. + - ``python setup.py bdist_wheel upload``. +- Get back to work + - Update ``_version.py`` (add 'dev' and increment minor). + - Update version in ``docs/conf.py`` + - Update version macros in ``include/pybind11/common.h`` + - ``git add`` and ``git commit``. + ``git push`` diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/requirements.txt b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..3818fe80eecc9e91b3a164885d94dffda28d8d35 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/requirements.txt @@ -0,0 +1 @@ +breathe == 4.5.0 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/upgrade.rst b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/upgrade.rst new file mode 100644 index 0000000000000000000000000000000000000000..3f5697391b7e1062115494087c1fcddab8f79c5a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/docs/upgrade.rst @@ -0,0 +1,404 @@ +Upgrade guide +############# + +This is a companion guide to the :doc:`changelog`. While the changelog briefly +lists all of the new features, improvements and bug fixes, this upgrade guide +focuses only the subset which directly impacts your experience when upgrading +to a new version. But it goes into more detail. This includes things like +deprecated APIs and their replacements, build system changes, general code +modernization and other useful information. + + +v2.2 +==== + +Deprecation of the ``PYBIND11_PLUGIN`` macro +-------------------------------------------- + +``PYBIND11_MODULE`` is now the preferred way to create module entry points. +The old macro emits a compile-time deprecation warning. + +.. code-block:: cpp + + // old + PYBIND11_PLUGIN(example) { + py::module m("example", "documentation string"); + + m.def("add", [](int a, int b) { return a + b; }); + + return m.ptr(); + } + + // new + PYBIND11_MODULE(example, m) { + m.doc() = "documentation string"; // optional + + m.def("add", [](int a, int b) { return a + b; }); + } + + +New API for defining custom constructors and pickling functions +--------------------------------------------------------------- + +The old placement-new custom constructors have been deprecated. The new approach +uses ``py::init()`` and factory functions to greatly improve type safety. + +Placement-new can be called accidentally with an incompatible type (without any +compiler errors or warnings), or it can initialize the same object multiple times +if not careful with the Python-side ``__init__`` calls. The new-style custom +constructors prevent such mistakes. See :ref:`custom_constructors` for details. + +.. code-block:: cpp + + // old -- deprecated (runtime warning shown only in debug mode) + py::class(m, "Foo") + .def("__init__", [](Foo &self, ...) { + new (&self) Foo(...); // uses placement-new + }); + + // new + py::class(m, "Foo") + .def(py::init([](...) { // Note: no `self` argument + return new Foo(...); // return by raw pointer + // or: return std::make_unique(...); // return by holder + // or: return Foo(...); // return by value (move constructor) + })); + +Mirroring the custom constructor changes, ``py::pickle()`` is now the preferred +way to get and set object state. See :ref:`pickling` for details. + +.. code-block:: cpp + + // old -- deprecated (runtime warning shown only in debug mode) + py::class(m, "Foo") + ... + .def("__getstate__", [](const Foo &self) { + return py::make_tuple(self.value1(), self.value2(), ...); + }) + .def("__setstate__", [](Foo &self, py::tuple t) { + new (&self) Foo(t[0].cast(), ...); + }); + + // new + py::class(m, "Foo") + ... + .def(py::pickle( + [](const Foo &self) { // __getstate__ + return py::make_tuple(f.value1(), f.value2(), ...); // unchanged + }, + [](py::tuple t) { // __setstate__, note: no `self` argument + return new Foo(t[0].cast(), ...); + // or: return std::make_unique(...); // return by holder + // or: return Foo(...); // return by value (move constructor) + } + )); + +For both the constructors and pickling, warnings are shown at module +initialization time (on import, not when the functions are called). +They're only visible when compiled in debug mode. Sample warning: + +.. code-block:: none + + pybind11-bound class 'mymodule.Foo' is using an old-style placement-new '__init__' + which has been deprecated. See the upgrade guide in pybind11's docs. + + +Stricter enforcement of hidden symbol visibility for pybind11 modules +--------------------------------------------------------------------- + +pybind11 now tries to actively enforce hidden symbol visibility for modules. +If you're using either one of pybind11's :doc:`CMake or Python build systems +` (the two example repositories) and you haven't been exporting any +symbols, there's nothing to be concerned about. All the changes have been done +transparently in the background. If you were building manually or relied on +specific default visibility, read on. + +Setting default symbol visibility to *hidden* has always been recommended for +pybind11 (see :ref:`faq:symhidden`). On Linux and macOS, hidden symbol +visibility (in conjunction with the ``strip`` utility) yields much smaller +module binaries. `CPython's extension docs`_ also recommend hiding symbols +by default, with the goal of avoiding symbol name clashes between modules. +Starting with v2.2, pybind11 enforces this more strictly: (1) by declaring +all symbols inside the ``pybind11`` namespace as hidden and (2) by including +the ``-fvisibility=hidden`` flag on Linux and macOS (only for extension +modules, not for embedding the interpreter). + +.. _CPython's extension docs: https://docs.python.org/3/extending/extending.html#providing-a-c-api-for-an-extension-module + +The namespace-scope hidden visibility is done automatically in pybind11's +headers and it's generally transparent to users. It ensures that: + +* Modules compiled with different pybind11 versions don't clash with each other. + +* Some new features, like ``py::module_local`` bindings, can work as intended. + +The ``-fvisibility=hidden`` flag applies the same visibility to user bindings +outside of the ``pybind11`` namespace. It's now set automatic by pybind11's +CMake and Python build systems, but this needs to be done manually by users +of other build systems. Adding this flag: + +* Minimizes the chances of symbol conflicts between modules. E.g. if two + unrelated modules were statically linked to different (ABI-incompatible) + versions of the same third-party library, a symbol clash would be likely + (and would end with unpredictable results). + +* Produces smaller binaries on Linux and macOS, as pointed out previously. + +Within pybind11's CMake build system, ``pybind11_add_module`` has always been +setting the ``-fvisibility=hidden`` flag in release mode. From now on, it's +being applied unconditionally, even in debug mode and it can no longer be opted +out of with the ``NO_EXTRAS`` option. The ``pybind11::module`` target now also +adds this flag to it's interface. The ``pybind11::embed`` target is unchanged. + +The most significant change here is for the ``pybind11::module`` target. If you +were previously relying on default visibility, i.e. if your Python module was +doubling as a shared library with dependents, you'll need to either export +symbols manually (recommended for cross-platform libraries) or factor out the +shared library (and have the Python module link to it like the other +dependents). As a temporary workaround, you can also restore default visibility +using the CMake code below, but this is not recommended in the long run: + +.. code-block:: cmake + + target_link_libraries(mymodule PRIVATE pybind11::module) + + add_library(restore_default_visibility INTERFACE) + target_compile_options(restore_default_visibility INTERFACE -fvisibility=default) + target_link_libraries(mymodule PRIVATE restore_default_visibility) + + +Local STL container bindings +---------------------------- + +Previous pybind11 versions could only bind types globally -- all pybind11 +modules, even unrelated ones, would have access to the same exported types. +However, this would also result in a conflict if two modules exported the +same C++ type, which is especially problematic for very common types, e.g. +``std::vector``. :ref:`module_local` were added to resolve this (see +that section for a complete usage guide). + +``py::class_`` still defaults to global bindings (because these types are +usually unique across modules), however in order to avoid clashes of opaque +types, ``py::bind_vector`` and ``py::bind_map`` will now bind STL containers +as ``py::module_local`` if their elements are: builtins (``int``, ``float``, +etc.), not bound using ``py::class_``, or bound as ``py::module_local``. For +example, this change allows multiple modules to bind ``std::vector`` +without causing conflicts. See :ref:`stl_bind` for more details. + +When upgrading to this version, if you have multiple modules which depend on +a single global binding of an STL container, note that all modules can still +accept foreign ``py::module_local`` types in the direction of Python-to-C++. +The locality only affects the C++-to-Python direction. If this is needed in +multiple modules, you'll need to either: + +* Add a copy of the same STL binding to all of the modules which need it. + +* Restore the global status of that single binding by marking it + ``py::module_local(false)``. + +The latter is an easy workaround, but in the long run it would be best to +localize all common type bindings in order to avoid conflicts with +third-party modules. + + +Negative strides for Python buffer objects and numpy arrays +----------------------------------------------------------- + +Support for negative strides required changing the integer type from unsigned +to signed in the interfaces of ``py::buffer_info`` and ``py::array``. If you +have compiler warnings enabled, you may notice some new conversion warnings +after upgrading. These can be resolved using ``static_cast``. + + +Deprecation of some ``py::object`` APIs +--------------------------------------- + +To compare ``py::object`` instances by pointer, you should now use +``obj1.is(obj2)`` which is equivalent to ``obj1 is obj2`` in Python. +Previously, pybind11 used ``operator==`` for this (``obj1 == obj2``), but +that could be confusing and is now deprecated (so that it can eventually +be replaced with proper rich object comparison in a future release). + +For classes which inherit from ``py::object``, ``borrowed`` and ``stolen`` +were previously available as protected constructor tags. Now the types +should be used directly instead: ``borrowed_t{}`` and ``stolen_t{}`` +(`#771 `_). + + +Stricter compile-time error checking +------------------------------------ + +Some error checks have been moved from run time to compile time. Notably, +automatic conversion of ``std::shared_ptr`` is not possible when ``T`` is +not directly registered with ``py::class_`` (e.g. ``std::shared_ptr`` +or ``std::shared_ptr>`` are not automatically convertible). +Attempting to bind a function with such arguments now results in a compile-time +error instead of waiting to fail at run time. + +``py::init<...>()`` constructor definitions are also stricter and now prevent +bindings which could cause unexpected behavior: + +.. code-block:: cpp + + struct Example { + Example(int &); + }; + + py::class_(m, "Example") + .def(py::init()); // OK, exact match + // .def(py::init()); // compile-time error, mismatch + +A non-``const`` lvalue reference is not allowed to bind to an rvalue. However, +note that a constructor taking ``const T &`` can still be registered using +``py::init()`` because a ``const`` lvalue reference can bind to an rvalue. + +v2.1 +==== + +Minimum compiler versions are enforced at compile time +------------------------------------------------------ + +The minimums also apply to v2.0 but the check is now explicit and a compile-time +error is raised if the compiler does not meet the requirements: + +* GCC >= 4.8 +* clang >= 3.3 (appleclang >= 5.0) +* MSVC >= 2015u3 +* Intel C++ >= 15.0 + + +The ``py::metaclass`` attribute is not required for static properties +--------------------------------------------------------------------- + +Binding classes with static properties is now possible by default. The +zero-parameter version of ``py::metaclass()`` is deprecated. However, a new +one-parameter ``py::metaclass(python_type)`` version was added for rare +cases when a custom metaclass is needed to override pybind11's default. + +.. code-block:: cpp + + // old -- emits a deprecation warning + py::class_(m, "Foo", py::metaclass()) + .def_property_readonly_static("foo", ...); + + // new -- static properties work without the attribute + py::class_(m, "Foo") + .def_property_readonly_static("foo", ...); + + // new -- advanced feature, override pybind11's default metaclass + py::class_(m, "Bar", py::metaclass(custom_python_type)) + ... + + +v2.0 +==== + +Breaking changes in ``py::class_`` +---------------------------------- + +These changes were necessary to make type definitions in pybind11 +future-proof, to support PyPy via its ``cpyext`` mechanism (`#527 +`_), and to improve efficiency +(`rev. 86d825 `_). + +1. Declarations of types that provide access via the buffer protocol must + now include the ``py::buffer_protocol()`` annotation as an argument to + the ``py::class_`` constructor. + + .. code-block:: cpp + + py::class_("Matrix", py::buffer_protocol()) + .def(py::init<...>()) + .def_buffer(...); + +2. Classes which include static properties (e.g. ``def_readwrite_static()``) + must now include the ``py::metaclass()`` attribute. Note: this requirement + has since been removed in v2.1. If you're upgrading from 1.x, it's + recommended to skip directly to v2.1 or newer. + +3. This version of pybind11 uses a redesigned mechanism for instantiating + trampoline classes that are used to override virtual methods from within + Python. This led to the following user-visible syntax change: + + .. code-block:: cpp + + // old v1.x syntax + py::class_("MyClass") + .alias() + ... + + // new v2.x syntax + py::class_("MyClass") + ... + + Importantly, both the original and the trampoline class are now specified + as arguments to the ``py::class_`` template, and the ``alias<..>()`` call + is gone. The new scheme has zero overhead in cases when Python doesn't + override any functions of the underlying C++ class. + `rev. 86d825 `_. + + The class type must be the first template argument given to ``py::class_`` + while the trampoline can be mixed in arbitrary order with other arguments + (see the following section). + + +Deprecation of the ``py::base()`` attribute +---------------------------------------------- + +``py::base()`` was deprecated in favor of specifying ``T`` as a template +argument to ``py::class_``. This new syntax also supports multiple inheritance. +Note that, while the type being exported must be the first argument in the +``py::class_`` template, the order of the following types (bases, +holder and/or trampoline) is not important. + +.. code-block:: cpp + + // old v1.x + py::class_("Derived", py::base()); + + // new v2.x + py::class_("Derived"); + + // new -- multiple inheritance + py::class_("Derived"); + + // new -- apart from `Derived` the argument order can be arbitrary + py::class_("Derived"); + + +Out-of-the-box support for ``std::shared_ptr`` +---------------------------------------------- + +The relevant type caster is now built in, so it's no longer necessary to +include a declaration of the form: + +.. code-block:: cpp + + PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) + +Continuing to do so won’t cause an error or even a deprecation warning, +but it's completely redundant. + + +Deprecation of a few ``py::object`` APIs +---------------------------------------- + +All of the old-style calls emit deprecation warnings. + ++---------------------------------------+---------------------------------------------+ +| Old syntax | New syntax | ++=======================================+=============================================+ +| ``obj.call(args...)`` | ``obj(args...)`` | ++---------------------------------------+---------------------------------------------+ +| ``obj.str()`` | ``py::str(obj)`` | ++---------------------------------------+---------------------------------------------+ +| ``auto l = py::list(obj); l.check()`` | ``py::isinstance(obj)`` | ++---------------------------------------+---------------------------------------------+ +| ``py::object(ptr, true)`` | ``py::reinterpret_borrow(ptr)`` | ++---------------------------------------+---------------------------------------------+ +| ``py::object(ptr, false)`` | ``py::reinterpret_steal(ptr)`` | ++---------------------------------------+---------------------------------------------+ +| ``if (obj.attr("foo"))`` | ``if (py::hasattr(obj, "foo"))`` | ++---------------------------------------+---------------------------------------------+ +| ``if (obj["bar"])`` | ``if (obj.contains("bar"))`` | ++---------------------------------------+---------------------------------------------+ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/attr.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/attr.h new file mode 100644 index 0000000000000000000000000000000000000000..6962d6fc53b4b4b7f323e2a7f742b6312144c161 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/attr.h @@ -0,0 +1,493 @@ +/* + pybind11/attr.h: Infrastructure for processing custom + type and function attributes + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "cast.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/// \addtogroup annotations +/// @{ + +/// Annotation for methods +struct is_method { handle class_; is_method(const handle &c) : class_(c) { } }; + +/// Annotation for operators +struct is_operator { }; + +/// Annotation for parent scope +struct scope { handle value; scope(const handle &s) : value(s) { } }; + +/// Annotation for documentation +struct doc { const char *value; doc(const char *value) : value(value) { } }; + +/// Annotation for function names +struct name { const char *value; name(const char *value) : value(value) { } }; + +/// Annotation indicating that a function is an overload associated with a given "sibling" +struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } }; + +/// Annotation indicating that a class derives from another given type +template struct base { + PYBIND11_DEPRECATED("base() was deprecated in favor of specifying 'T' as a template argument to class_") + base() { } +}; + +/// Keep patient alive while nurse lives +template struct keep_alive { }; + +/// Annotation indicating that a class is involved in a multiple inheritance relationship +struct multiple_inheritance { }; + +/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class +struct dynamic_attr { }; + +/// Annotation which enables the buffer protocol for a type +struct buffer_protocol { }; + +/// Annotation which requests that a special metaclass is created for a type +struct metaclass { + handle value; + + PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.") + metaclass() {} + + /// Override pybind11's default metaclass + explicit metaclass(handle value) : value(value) { } +}; + +/// Annotation that marks a class as local to the module: +struct module_local { const bool value; constexpr module_local(bool v = true) : value(v) { } }; + +/// Annotation to mark enums as an arithmetic type +struct arithmetic { }; + +/** \rst + A call policy which places one or more guard variables (``Ts...``) around the function call. + + For example, this definition: + + .. code-block:: cpp + + m.def("foo", foo, py::call_guard()); + + is equivalent to the following pseudocode: + + .. code-block:: cpp + + m.def("foo", [](args...) { + T scope_guard; + return foo(args...); // forwarded arguments + }); + \endrst */ +template struct call_guard; + +template <> struct call_guard<> { using type = detail::void_type; }; + +template +struct call_guard { + static_assert(std::is_default_constructible::value, + "The guard type must be default constructible"); + + using type = T; +}; + +template +struct call_guard { + struct type { + T guard{}; // Compose multiple guard types with left-to-right default-constructor order + typename call_guard::type next{}; + }; +}; + +/// @} annotations + +NAMESPACE_BEGIN(detail) +/* Forward declarations */ +enum op_id : int; +enum op_type : int; +struct undefined_t; +template struct op_; +inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret); + +/// Internal data structure which holds metadata about a keyword argument +struct argument_record { + const char *name; ///< Argument name + const char *descr; ///< Human-readable version of the argument value + handle value; ///< Associated Python object + bool convert : 1; ///< True if the argument is allowed to convert when loading + bool none : 1; ///< True if None is allowed when loading + + argument_record(const char *name, const char *descr, handle value, bool convert, bool none) + : name(name), descr(descr), value(value), convert(convert), none(none) { } +}; + +/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.) +struct function_record { + function_record() + : is_constructor(false), is_new_style_constructor(false), is_stateless(false), + is_operator(false), has_args(false), has_kwargs(false), is_method(false) { } + + /// Function name + char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ + + // User-specified documentation string + char *doc = nullptr; + + /// Human-readable version of the function signature + char *signature = nullptr; + + /// List of registered keyword arguments + std::vector args; + + /// Pointer to lambda function which converts arguments and performs the actual call + handle (*impl) (function_call &) = nullptr; + + /// Storage for the wrapped function pointer and captured data, if any + void *data[3] = { }; + + /// Pointer to custom destructor for 'data' (if needed) + void (*free_data) (function_record *ptr) = nullptr; + + /// Return value policy associated with this function + return_value_policy policy = return_value_policy::automatic; + + /// True if name == '__init__' + bool is_constructor : 1; + + /// True if this is a new-style `__init__` defined in `detail/init.h` + bool is_new_style_constructor : 1; + + /// True if this is a stateless function pointer + bool is_stateless : 1; + + /// True if this is an operator (__add__), etc. + bool is_operator : 1; + + /// True if the function has a '*args' argument + bool has_args : 1; + + /// True if the function has a '**kwargs' argument + bool has_kwargs : 1; + + /// True if this is a method + bool is_method : 1; + + /// Number of arguments (including py::args and/or py::kwargs, if present) + std::uint16_t nargs; + + /// Python method object + PyMethodDef *def = nullptr; + + /// Python handle to the parent scope (a class or a module) + handle scope; + + /// Python handle to the sibling function representing an overload chain + handle sibling; + + /// Pointer to next overload + function_record *next = nullptr; +}; + +/// Special data structure which (temporarily) holds metadata about a bound class +struct type_record { + PYBIND11_NOINLINE type_record() + : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false), + default_holder(true), module_local(false) { } + + /// Handle to the parent scope + handle scope; + + /// Name of the class + const char *name = nullptr; + + // Pointer to RTTI type_info data structure + const std::type_info *type = nullptr; + + /// How large is the underlying C++ type? + size_t type_size = 0; + + /// What is the alignment of the underlying C++ type? + size_t type_align = 0; + + /// How large is the type's holder? + size_t holder_size = 0; + + /// The global operator new can be overridden with a class-specific variant + void *(*operator_new)(size_t) = nullptr; + + /// Function pointer to class_<..>::init_instance + void (*init_instance)(instance *, const void *) = nullptr; + + /// Function pointer to class_<..>::dealloc + void (*dealloc)(detail::value_and_holder &) = nullptr; + + /// List of base classes of the newly created type + list bases; + + /// Optional docstring + const char *doc = nullptr; + + /// Custom metaclass (optional) + handle metaclass; + + /// Multiple inheritance marker + bool multiple_inheritance : 1; + + /// Does the class manage a __dict__? + bool dynamic_attr : 1; + + /// Does the class implement the buffer protocol? + bool buffer_protocol : 1; + + /// Is the default (unique_ptr) holder type used? + bool default_holder : 1; + + /// Is the class definition local to the module shared object? + bool module_local : 1; + + PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *)) { + auto base_info = detail::get_type_info(base, false); + if (!base_info) { + std::string tname(base.name()); + detail::clean_type_id(tname); + pybind11_fail("generic_type: type \"" + std::string(name) + + "\" referenced unknown base type \"" + tname + "\""); + } + + if (default_holder != base_info->default_holder) { + std::string tname(base.name()); + detail::clean_type_id(tname); + pybind11_fail("generic_type: type \"" + std::string(name) + "\" " + + (default_holder ? "does not have" : "has") + + " a non-default holder type while its base \"" + tname + "\" " + + (base_info->default_holder ? "does not" : "does")); + } + + bases.append((PyObject *) base_info->type); + + if (base_info->type->tp_dictoffset != 0) + dynamic_attr = true; + + if (caster) + base_info->implicit_casts.emplace_back(type, caster); + } +}; + +inline function_call::function_call(const function_record &f, handle p) : + func(f), parent(p) { + args.reserve(f.nargs); + args_convert.reserve(f.nargs); +} + +/// Tag for a new-style `__init__` defined in `detail/init.h` +struct is_new_style_constructor { }; + +/** + * Partial template specializations to process custom attributes provided to + * cpp_function_ and class_. These are either used to initialize the respective + * fields in the type_record and function_record data structures or executed at + * runtime to deal with custom call policies (e.g. keep_alive). + */ +template struct process_attribute; + +template struct process_attribute_default { + /// Default implementation: do nothing + static void init(const T &, function_record *) { } + static void init(const T &, type_record *) { } + static void precall(function_call &) { } + static void postcall(function_call &, handle) { } +}; + +/// Process an attribute specifying the function's name +template <> struct process_attribute : process_attribute_default { + static void init(const name &n, function_record *r) { r->name = const_cast(n.value); } +}; + +/// Process an attribute specifying the function's docstring +template <> struct process_attribute : process_attribute_default { + static void init(const doc &n, function_record *r) { r->doc = const_cast(n.value); } +}; + +/// Process an attribute specifying the function's docstring (provided as a C-style string) +template <> struct process_attribute : process_attribute_default { + static void init(const char *d, function_record *r) { r->doc = const_cast(d); } + static void init(const char *d, type_record *r) { r->doc = const_cast(d); } +}; +template <> struct process_attribute : process_attribute { }; + +/// Process an attribute indicating the function's return value policy +template <> struct process_attribute : process_attribute_default { + static void init(const return_value_policy &p, function_record *r) { r->policy = p; } +}; + +/// Process an attribute which indicates that this is an overloaded function associated with a given sibling +template <> struct process_attribute : process_attribute_default { + static void init(const sibling &s, function_record *r) { r->sibling = s.value; } +}; + +/// Process an attribute which indicates that this function is a method +template <> struct process_attribute : process_attribute_default { + static void init(const is_method &s, function_record *r) { r->is_method = true; r->scope = s.class_; } +}; + +/// Process an attribute which indicates the parent scope of a method +template <> struct process_attribute : process_attribute_default { + static void init(const scope &s, function_record *r) { r->scope = s.value; } +}; + +/// Process an attribute which indicates that this function is an operator +template <> struct process_attribute : process_attribute_default { + static void init(const is_operator &, function_record *r) { r->is_operator = true; } +}; + +template <> struct process_attribute : process_attribute_default { + static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = true; } +}; + +/// Process a keyword argument attribute (*without* a default value) +template <> struct process_attribute : process_attribute_default { + static void init(const arg &a, function_record *r) { + if (r->is_method && r->args.empty()) + r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/); + r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); + } +}; + +/// Process a keyword argument attribute (*with* a default value) +template <> struct process_attribute : process_attribute_default { + static void init(const arg_v &a, function_record *r) { + if (r->is_method && r->args.empty()) + r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/); + + if (!a.value) { +#if !defined(NDEBUG) + std::string descr("'"); + if (a.name) descr += std::string(a.name) + ": "; + descr += a.type + "'"; + if (r->is_method) { + if (r->name) + descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'"; + else + descr += " in method of '" + (std::string) str(r->scope) + "'"; + } else if (r->name) { + descr += " in function '" + (std::string) r->name + "'"; + } + pybind11_fail("arg(): could not convert default argument " + + descr + " into a Python object (type not registered yet?)"); +#else + pybind11_fail("arg(): could not convert default argument " + "into a Python object (type not registered yet?). " + "Compile in debug mode for more information."); +#endif + } + r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); + } +}; + +/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that) +template +struct process_attribute::value>> : process_attribute_default { + static void init(const handle &h, type_record *r) { r->bases.append(h); } +}; + +/// Process a parent class attribute (deprecated, does not support multiple inheritance) +template +struct process_attribute> : process_attribute_default> { + static void init(const base &, type_record *r) { r->add_base(typeid(T), nullptr); } +}; + +/// Process a multiple inheritance attribute +template <> +struct process_attribute : process_attribute_default { + static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const module_local &l, type_record *r) { r->module_local = l.value; } +}; + +/// Process an 'arithmetic' attribute for enums (does nothing here) +template <> +struct process_attribute : process_attribute_default {}; + +template +struct process_attribute> : process_attribute_default> { }; + +/** + * Process a keep_alive call policy -- invokes keep_alive_impl during the + * pre-call handler if both Nurse, Patient != 0 and use the post-call handler + * otherwise + */ +template struct process_attribute> : public process_attribute_default> { + template = 0> + static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); } + template = 0> + static void postcall(function_call &, handle) { } + template = 0> + static void precall(function_call &) { } + template = 0> + static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); } +}; + +/// Recursively iterate over variadic template arguments +template struct process_attributes { + static void init(const Args&... args, function_record *r) { + int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; + ignore_unused(unused); + } + static void init(const Args&... args, type_record *r) { + int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; + ignore_unused(unused); + } + static void precall(function_call &call) { + int unused[] = { 0, (process_attribute::type>::precall(call), 0) ... }; + ignore_unused(unused); + } + static void postcall(function_call &call, handle fn_ret) { + int unused[] = { 0, (process_attribute::type>::postcall(call, fn_ret), 0) ... }; + ignore_unused(unused); + } +}; + +template +using is_call_guard = is_instantiation; + +/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found) +template +using extract_guard_t = typename exactly_one_t, Extra...>::type; + +/// Check the number of named arguments at compile time +template ::value...), + size_t self = constexpr_sum(std::is_same::value...)> +constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) { + return named == 0 || (self + named + has_args + has_kwargs) == nargs; +} + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/buffer_info.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/buffer_info.h new file mode 100644 index 0000000000000000000000000000000000000000..1f4115a1fa312e9ad451180e5ae2794453505829 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/buffer_info.h @@ -0,0 +1,114 @@ +/* + pybind11/buffer_info.h: Python buffer object interface + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/common.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/// Information record describing a Python buffer object +struct buffer_info { + void *ptr = nullptr; // Pointer to the underlying storage + ssize_t itemsize = 0; // Size of individual items in bytes + ssize_t size = 0; // Total number of entries + std::string format; // For homogeneous buffers, this should be set to format_descriptor::format() + ssize_t ndim = 0; // Number of dimensions + std::vector shape; // Shape of the tensor (1 entry per dimension) + std::vector strides; // Number of bytes between adjacent entries (for each per dimension) + bool readonly = false; // flag to indicate if the underlying storage may be written to + + buffer_info() { } + + buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, + detail::any_container shape_in, detail::any_container strides_in, bool readonly=false) + : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), + shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) { + if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) + pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); + for (size_t i = 0; i < (size_t) ndim; ++i) + size *= shape[i]; + } + + template + buffer_info(T *ptr, detail::any_container shape_in, detail::any_container strides_in, bool readonly=false) + : buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor::format(), static_cast(shape_in->size()), std::move(shape_in), std::move(strides_in), readonly) { } + + buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size, bool readonly=false) + : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) { } + + template + buffer_info(T *ptr, ssize_t size, bool readonly=false) + : buffer_info(ptr, sizeof(T), format_descriptor::format(), size, readonly) { } + + template + buffer_info(const T *ptr, ssize_t size, bool readonly=true) + : buffer_info(const_cast(ptr), sizeof(T), format_descriptor::format(), size, readonly) { } + + explicit buffer_info(Py_buffer *view, bool ownview = true) + : buffer_info(view->buf, view->itemsize, view->format, view->ndim, + {view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}, view->readonly) { + this->view = view; + this->ownview = ownview; + } + + buffer_info(const buffer_info &) = delete; + buffer_info& operator=(const buffer_info &) = delete; + + buffer_info(buffer_info &&other) { + (*this) = std::move(other); + } + + buffer_info& operator=(buffer_info &&rhs) { + ptr = rhs.ptr; + itemsize = rhs.itemsize; + size = rhs.size; + format = std::move(rhs.format); + ndim = rhs.ndim; + shape = std::move(rhs.shape); + strides = std::move(rhs.strides); + std::swap(view, rhs.view); + std::swap(ownview, rhs.ownview); + readonly = rhs.readonly; + return *this; + } + + ~buffer_info() { + if (view && ownview) { PyBuffer_Release(view); delete view; } + } + +private: + struct private_ctr_tag { }; + + buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, + detail::any_container &&shape_in, detail::any_container &&strides_in, bool readonly) + : buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) { } + + Py_buffer *view = nullptr; + bool ownview = false; +}; + +NAMESPACE_BEGIN(detail) + +template struct compare_buffer_info { + static bool compare(const buffer_info& b) { + return b.format == format_descriptor::format() && b.itemsize == (ssize_t) sizeof(T); + } +}; + +template struct compare_buffer_info::value>> { + static bool compare(const buffer_info& b) { + return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor::value || + ((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned::value ? "L" : "l")) || + ((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned::value ? "N" : "n"))); + } +}; + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/cast.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/cast.h new file mode 100644 index 0000000000000000000000000000000000000000..a0b4d1ba9e5b33d3b3b8b20fb66ad3b3187d6deb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/cast.h @@ -0,0 +1,2179 @@ +/* + pybind11/cast.h: Partial template specializations to cast between + C++ and Python types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pytypes.h" +#include "detail/typeid.h" +#include "detail/descr.h" +#include "detail/internals.h" +#include +#include +#include +#include + +#if defined(PYBIND11_CPP17) +# if defined(__has_include) +# if __has_include() +# define PYBIND11_HAS_STRING_VIEW +# endif +# elif defined(_MSC_VER) +# define PYBIND11_HAS_STRING_VIEW +# endif +#endif +#ifdef PYBIND11_HAS_STRING_VIEW +#include +#endif + +#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L +# define PYBIND11_HAS_U8STRING +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/// A life support system for temporary objects created by `type_caster::load()`. +/// Adding a patient will keep it alive up until the enclosing function returns. +class loader_life_support { +public: + /// A new patient frame is created when a function is entered + loader_life_support() { + get_internals().loader_patient_stack.push_back(nullptr); + } + + /// ... and destroyed after it returns + ~loader_life_support() { + auto &stack = get_internals().loader_patient_stack; + if (stack.empty()) + pybind11_fail("loader_life_support: internal error"); + + auto ptr = stack.back(); + stack.pop_back(); + Py_CLEAR(ptr); + + // A heuristic to reduce the stack's capacity (e.g. after long recursive calls) + if (stack.capacity() > 16 && stack.size() != 0 && stack.capacity() / stack.size() > 2) + stack.shrink_to_fit(); + } + + /// This can only be used inside a pybind11-bound function, either by `argument_loader` + /// at argument preparation time or by `py::cast()` at execution time. + PYBIND11_NOINLINE static void add_patient(handle h) { + auto &stack = get_internals().loader_patient_stack; + if (stack.empty()) + throw cast_error("When called outside a bound function, py::cast() cannot " + "do Python -> C++ conversions which require the creation " + "of temporary values"); + + auto &list_ptr = stack.back(); + if (list_ptr == nullptr) { + list_ptr = PyList_New(1); + if (!list_ptr) + pybind11_fail("loader_life_support: error allocating list"); + PyList_SET_ITEM(list_ptr, 0, h.inc_ref().ptr()); + } else { + auto result = PyList_Append(list_ptr, h.ptr()); + if (result == -1) + pybind11_fail("loader_life_support: error adding patient"); + } + } +}; + +// Gets the cache entry for the given type, creating it if necessary. The return value is the pair +// returned by emplace, i.e. an iterator for the entry and a bool set to `true` if the entry was +// just created. +inline std::pair all_type_info_get_cache(PyTypeObject *type); + +// Populates a just-created cache entry. +PYBIND11_NOINLINE inline void all_type_info_populate(PyTypeObject *t, std::vector &bases) { + std::vector check; + for (handle parent : reinterpret_borrow(t->tp_bases)) + check.push_back((PyTypeObject *) parent.ptr()); + + auto const &type_dict = get_internals().registered_types_py; + for (size_t i = 0; i < check.size(); i++) { + auto type = check[i]; + // Ignore Python2 old-style class super type: + if (!PyType_Check((PyObject *) type)) continue; + + // Check `type` in the current set of registered python types: + auto it = type_dict.find(type); + if (it != type_dict.end()) { + // We found a cache entry for it, so it's either pybind-registered or has pre-computed + // pybind bases, but we have to make sure we haven't already seen the type(s) before: we + // want to follow Python/virtual C++ rules that there should only be one instance of a + // common base. + for (auto *tinfo : it->second) { + // NB: Could use a second set here, rather than doing a linear search, but since + // having a large number of immediate pybind11-registered types seems fairly + // unlikely, that probably isn't worthwhile. + bool found = false; + for (auto *known : bases) { + if (known == tinfo) { found = true; break; } + } + if (!found) bases.push_back(tinfo); + } + } + else if (type->tp_bases) { + // It's some python type, so keep follow its bases classes to look for one or more + // registered types + if (i + 1 == check.size()) { + // When we're at the end, we can pop off the current element to avoid growing + // `check` when adding just one base (which is typical--i.e. when there is no + // multiple inheritance) + check.pop_back(); + i--; + } + for (handle parent : reinterpret_borrow(type->tp_bases)) + check.push_back((PyTypeObject *) parent.ptr()); + } + } +} + +/** + * Extracts vector of type_info pointers of pybind-registered roots of the given Python type. Will + * be just 1 pybind type for the Python type of a pybind-registered class, or for any Python-side + * derived class that uses single inheritance. Will contain as many types as required for a Python + * class that uses multiple inheritance to inherit (directly or indirectly) from multiple + * pybind-registered classes. Will be empty if neither the type nor any base classes are + * pybind-registered. + * + * The value is cached for the lifetime of the Python type. + */ +inline const std::vector &all_type_info(PyTypeObject *type) { + auto ins = all_type_info_get_cache(type); + if (ins.second) + // New cache entry: populate it + all_type_info_populate(type, ins.first->second); + + return ins.first->second; +} + +/** + * Gets a single pybind11 type info for a python type. Returns nullptr if neither the type nor any + * ancestors are pybind11-registered. Throws an exception if there are multiple bases--use + * `all_type_info` instead if you want to support multiple bases. + */ +PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) { + auto &bases = all_type_info(type); + if (bases.size() == 0) + return nullptr; + if (bases.size() > 1) + pybind11_fail("pybind11::detail::get_type_info: type has multiple pybind11-registered bases"); + return bases.front(); +} + +inline detail::type_info *get_local_type_info(const std::type_index &tp) { + auto &locals = registered_local_types_cpp(); + auto it = locals.find(tp); + if (it != locals.end()) + return it->second; + return nullptr; +} + +inline detail::type_info *get_global_type_info(const std::type_index &tp) { + auto &types = get_internals().registered_types_cpp; + auto it = types.find(tp); + if (it != types.end()) + return it->second; + return nullptr; +} + +/// Return the type info for a given C++ type; on lookup failure can either throw or return nullptr. +PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_index &tp, + bool throw_if_missing = false) { + if (auto ltype = get_local_type_info(tp)) + return ltype; + if (auto gtype = get_global_type_info(tp)) + return gtype; + + if (throw_if_missing) { + std::string tname = tp.name(); + detail::clean_type_id(tname); + pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname + "\""); + } + return nullptr; +} + +PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp, bool throw_if_missing) { + detail::type_info *type_info = get_type_info(tp, throw_if_missing); + return handle(type_info ? ((PyObject *) type_info->type) : nullptr); +} + +struct value_and_holder { + instance *inst = nullptr; + size_t index = 0u; + const detail::type_info *type = nullptr; + void **vh = nullptr; + + // Main constructor for a found value/holder: + value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) : + inst{i}, index{index}, type{type}, + vh{inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[vpos]} + {} + + // Default constructor (used to signal a value-and-holder not found by get_value_and_holder()) + value_and_holder() {} + + // Used for past-the-end iterator + value_and_holder(size_t index) : index{index} {} + + template V *&value_ptr() const { + return reinterpret_cast(vh[0]); + } + // True if this `value_and_holder` has a non-null value pointer + explicit operator bool() const { return value_ptr(); } + + template H &holder() const { + return reinterpret_cast(vh[1]); + } + bool holder_constructed() const { + return inst->simple_layout + ? inst->simple_holder_constructed + : inst->nonsimple.status[index] & instance::status_holder_constructed; + } + void set_holder_constructed(bool v = true) { + if (inst->simple_layout) + inst->simple_holder_constructed = v; + else if (v) + inst->nonsimple.status[index] |= instance::status_holder_constructed; + else + inst->nonsimple.status[index] &= (uint8_t) ~instance::status_holder_constructed; + } + bool instance_registered() const { + return inst->simple_layout + ? inst->simple_instance_registered + : inst->nonsimple.status[index] & instance::status_instance_registered; + } + void set_instance_registered(bool v = true) { + if (inst->simple_layout) + inst->simple_instance_registered = v; + else if (v) + inst->nonsimple.status[index] |= instance::status_instance_registered; + else + inst->nonsimple.status[index] &= (uint8_t) ~instance::status_instance_registered; + } +}; + +// Container for accessing and iterating over an instance's values/holders +struct values_and_holders { +private: + instance *inst; + using type_vec = std::vector; + const type_vec &tinfo; + +public: + values_and_holders(instance *inst) : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {} + + struct iterator { + private: + instance *inst = nullptr; + const type_vec *types = nullptr; + value_and_holder curr; + friend struct values_and_holders; + iterator(instance *inst, const type_vec *tinfo) + : inst{inst}, types{tinfo}, + curr(inst /* instance */, + types->empty() ? nullptr : (*types)[0] /* type info */, + 0, /* vpos: (non-simple types only): the first vptr comes first */ + 0 /* index */) + {} + // Past-the-end iterator: + iterator(size_t end) : curr(end) {} + public: + bool operator==(const iterator &other) { return curr.index == other.curr.index; } + bool operator!=(const iterator &other) { return curr.index != other.curr.index; } + iterator &operator++() { + if (!inst->simple_layout) + curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs; + ++curr.index; + curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr; + return *this; + } + value_and_holder &operator*() { return curr; } + value_and_holder *operator->() { return &curr; } + }; + + iterator begin() { return iterator(inst, &tinfo); } + iterator end() { return iterator(tinfo.size()); } + + iterator find(const type_info *find_type) { + auto it = begin(), endit = end(); + while (it != endit && it->type != find_type) ++it; + return it; + } + + size_t size() { return tinfo.size(); } +}; + +/** + * Extracts C++ value and holder pointer references from an instance (which may contain multiple + * values/holders for python-side multiple inheritance) that match the given type. Throws an error + * if the given type (or ValueType, if omitted) is not a pybind11 base of the given instance. If + * `find_type` is omitted (or explicitly specified as nullptr) the first value/holder are returned, + * regardless of type (and the resulting .type will be nullptr). + * + * The returned object should be short-lived: in particular, it must not outlive the called-upon + * instance. + */ +PYBIND11_NOINLINE inline value_and_holder instance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/, bool throw_if_missing /*= true in common.h*/) { + // Optimize common case: + if (!find_type || Py_TYPE(this) == find_type->type) + return value_and_holder(this, find_type, 0, 0); + + detail::values_and_holders vhs(this); + auto it = vhs.find(find_type); + if (it != vhs.end()) + return *it; + + if (!throw_if_missing) + return value_and_holder(); + +#if defined(NDEBUG) + pybind11_fail("pybind11::detail::instance::get_value_and_holder: " + "type is not a pybind11 base of the given instance " + "(compile in debug mode for type details)"); +#else + pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" + + std::string(find_type->type->tp_name) + "' is not a pybind11 base of the given `" + + std::string(Py_TYPE(this)->tp_name) + "' instance"); +#endif +} + +PYBIND11_NOINLINE inline void instance::allocate_layout() { + auto &tinfo = all_type_info(Py_TYPE(this)); + + const size_t n_types = tinfo.size(); + + if (n_types == 0) + pybind11_fail("instance allocation failed: new instance has no pybind11-registered base types"); + + simple_layout = + n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs(); + + // Simple path: no python-side multiple inheritance, and a small-enough holder + if (simple_layout) { + simple_value_holder[0] = nullptr; + simple_holder_constructed = false; + simple_instance_registered = false; + } + else { // multiple base types or a too-large holder + // Allocate space to hold: [v1*][h1][v2*][h2]...[bb...] where [vN*] is a value pointer, + // [hN] is the (uninitialized) holder instance for value N, and [bb...] is a set of bool + // values that tracks whether each associated holder has been initialized. Each [block] is + // padded, if necessary, to an integer multiple of sizeof(void *). + size_t space = 0; + for (auto t : tinfo) { + space += 1; // value pointer + space += t->holder_size_in_ptrs; // holder instance + } + size_t flags_at = space; + space += size_in_ptrs(n_types); // status bytes (holder_constructed and instance_registered) + + // Allocate space for flags, values, and holders, and initialize it to 0 (flags and values, + // in particular, need to be 0). Use Python's memory allocation functions: in Python 3.6 + // they default to using pymalloc, which is designed to be efficient for small allocations + // like the one we're doing here; in earlier versions (and for larger allocations) they are + // just wrappers around malloc. +#if PY_VERSION_HEX >= 0x03050000 + nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *)); + if (!nonsimple.values_and_holders) throw std::bad_alloc(); +#else + nonsimple.values_and_holders = (void **) PyMem_New(void *, space); + if (!nonsimple.values_and_holders) throw std::bad_alloc(); + std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *)); +#endif + nonsimple.status = reinterpret_cast(&nonsimple.values_and_holders[flags_at]); + } + owned = true; +} + +PYBIND11_NOINLINE inline void instance::deallocate_layout() { + if (!simple_layout) + PyMem_Free(nonsimple.values_and_holders); +} + +PYBIND11_NOINLINE inline bool isinstance_generic(handle obj, const std::type_info &tp) { + handle type = detail::get_type_handle(tp, false); + if (!type) + return false; + return isinstance(obj, type); +} + +PYBIND11_NOINLINE inline std::string error_string() { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred"); + return "Unknown internal error occurred"; + } + + error_scope scope; // Preserve error state + + std::string errorString; + if (scope.type) { + errorString += handle(scope.type).attr("__name__").cast(); + errorString += ": "; + } + if (scope.value) + errorString += (std::string) str(scope.value); + + PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace); + +#if PY_MAJOR_VERSION >= 3 + if (scope.trace != nullptr) + PyException_SetTraceback(scope.value, scope.trace); +#endif + +#if !defined(PYPY_VERSION) + if (scope.trace) { + PyTracebackObject *trace = (PyTracebackObject *) scope.trace; + + /* Get the deepest trace possible */ + while (trace->tb_next) + trace = trace->tb_next; + + PyFrameObject *frame = trace->tb_frame; + errorString += "\n\nAt:\n"; + while (frame) { + int lineno = PyFrame_GetLineNumber(frame); + errorString += + " " + handle(frame->f_code->co_filename).cast() + + "(" + std::to_string(lineno) + "): " + + handle(frame->f_code->co_name).cast() + "\n"; + frame = frame->f_back; + } + } +#endif + + return errorString; +} + +PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail::type_info *type ) { + auto &instances = get_internals().registered_instances; + auto range = instances.equal_range(ptr); + for (auto it = range.first; it != range.second; ++it) { + for (auto vh : values_and_holders(it->second)) { + if (vh.type == type) + return handle((PyObject *) it->second); + } + } + return handle(); +} + +inline PyThreadState *get_thread_state_unchecked() { +#if defined(PYPY_VERSION) + return PyThreadState_GET(); +#elif PY_VERSION_HEX < 0x03000000 + return _PyThreadState_Current; +#elif PY_VERSION_HEX < 0x03050000 + return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current); +#elif PY_VERSION_HEX < 0x03050200 + return (PyThreadState*) _PyThreadState_Current.value; +#else + return _PyThreadState_UncheckedGet(); +#endif +} + +// Forward declarations +inline void keep_alive_impl(handle nurse, handle patient); +inline PyObject *make_new_instance(PyTypeObject *type); + +class type_caster_generic { +public: + PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info) + : typeinfo(get_type_info(type_info)), cpptype(&type_info) { } + + type_caster_generic(const type_info *typeinfo) + : typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) { } + + bool load(handle src, bool convert) { + return load_impl(src, convert); + } + + PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent, + const detail::type_info *tinfo, + void *(*copy_constructor)(const void *), + void *(*move_constructor)(const void *), + const void *existing_holder = nullptr) { + if (!tinfo) // no type info: error will be set already + return handle(); + + void *src = const_cast(_src); + if (src == nullptr) + return none().release(); + + auto it_instances = get_internals().registered_instances.equal_range(src); + for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) { + for (auto instance_type : detail::all_type_info(Py_TYPE(it_i->second))) { + if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) + return handle((PyObject *) it_i->second).inc_ref(); + } + } + + auto inst = reinterpret_steal(make_new_instance(tinfo->type)); + auto wrapper = reinterpret_cast(inst.ptr()); + wrapper->owned = false; + void *&valueptr = values_and_holders(wrapper).begin()->value_ptr(); + + switch (policy) { + case return_value_policy::automatic: + case return_value_policy::take_ownership: + valueptr = src; + wrapper->owned = true; + break; + + case return_value_policy::automatic_reference: + case return_value_policy::reference: + valueptr = src; + wrapper->owned = false; + break; + + case return_value_policy::copy: + if (copy_constructor) + valueptr = copy_constructor(src); + else { +#if defined(NDEBUG) + throw cast_error("return_value_policy = copy, but type is " + "non-copyable! (compile in debug mode for details)"); +#else + std::string type_name(tinfo->cpptype->name()); + detail::clean_type_id(type_name); + throw cast_error("return_value_policy = copy, but type " + + type_name + " is non-copyable!"); +#endif + } + wrapper->owned = true; + break; + + case return_value_policy::move: + if (move_constructor) + valueptr = move_constructor(src); + else if (copy_constructor) + valueptr = copy_constructor(src); + else { +#if defined(NDEBUG) + throw cast_error("return_value_policy = move, but type is neither " + "movable nor copyable! " + "(compile in debug mode for details)"); +#else + std::string type_name(tinfo->cpptype->name()); + detail::clean_type_id(type_name); + throw cast_error("return_value_policy = move, but type " + + type_name + " is neither movable nor copyable!"); +#endif + } + wrapper->owned = true; + break; + + case return_value_policy::reference_internal: + valueptr = src; + wrapper->owned = false; + keep_alive_impl(inst, parent); + break; + + default: + throw cast_error("unhandled return_value_policy: should not happen!"); + } + + tinfo->init_instance(wrapper, existing_holder); + + return inst.release(); + } + + // Base methods for generic caster; there are overridden in copyable_holder_caster + void load_value(value_and_holder &&v_h) { + auto *&vptr = v_h.value_ptr(); + // Lazy allocation for unallocated values: + if (vptr == nullptr) { + auto *type = v_h.type ? v_h.type : typeinfo; + if (type->operator_new) { + vptr = type->operator_new(type->type_size); + } else { + #if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912) + if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + vptr = ::operator new(type->type_size, + std::align_val_t(type->type_align)); + else + #endif + vptr = ::operator new(type->type_size); + } + } + value = vptr; + } + bool try_implicit_casts(handle src, bool convert) { + for (auto &cast : typeinfo->implicit_casts) { + type_caster_generic sub_caster(*cast.first); + if (sub_caster.load(src, convert)) { + value = cast.second(sub_caster.value); + return true; + } + } + return false; + } + bool try_direct_conversions(handle src) { + for (auto &converter : *typeinfo->direct_conversions) { + if (converter(src.ptr(), value)) + return true; + } + return false; + } + void check_holder_compat() {} + + PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) { + auto caster = type_caster_generic(ti); + if (caster.load(src, false)) + return caster.value; + return nullptr; + } + + /// Try to load with foreign typeinfo, if available. Used when there is no + /// native typeinfo, or when the native one wasn't able to produce a value. + PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) { + constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID; + const auto pytype = src.get_type(); + if (!hasattr(pytype, local_key)) + return false; + + type_info *foreign_typeinfo = reinterpret_borrow(getattr(pytype, local_key)); + // Only consider this foreign loader if actually foreign and is a loader of the correct cpp type + if (foreign_typeinfo->module_local_load == &local_load + || (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) + return false; + + if (auto result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) { + value = result; + return true; + } + return false; + } + + // Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant + // bits of code between here and copyable_holder_caster where the two classes need different + // logic (without having to resort to virtual inheritance). + template + PYBIND11_NOINLINE bool load_impl(handle src, bool convert) { + if (!src) return false; + if (!typeinfo) return try_load_foreign_module_local(src); + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) return false; + value = nullptr; + return true; + } + + auto &this_ = static_cast(*this); + this_.check_holder_compat(); + + PyTypeObject *srctype = Py_TYPE(src.ptr()); + + // Case 1: If src is an exact type match for the target type then we can reinterpret_cast + // the instance's value pointer to the target type: + if (srctype == typeinfo->type) { + this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder()); + return true; + } + // Case 2: We have a derived class + else if (PyType_IsSubtype(srctype, typeinfo->type)) { + auto &bases = all_type_info(srctype); + bool no_cpp_mi = typeinfo->simple_type; + + // Case 2a: the python type is a Python-inherited derived class that inherits from just + // one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of + // the right type and we can use reinterpret_cast. + // (This is essentially the same as case 2b, but because not using multiple inheritance + // is extremely common, we handle it specially to avoid the loop iterator and type + // pointer lookup overhead) + if (bases.size() == 1 && (no_cpp_mi || bases.front()->type == typeinfo->type)) { + this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder()); + return true; + } + // Case 2b: the python type inherits from multiple C++ bases. Check the bases to see if + // we can find an exact match (or, for a simple C++ type, an inherited match); if so, we + // can safely reinterpret_cast to the relevant pointer. + else if (bases.size() > 1) { + for (auto base : bases) { + if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type) : base->type == typeinfo->type) { + this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder(base)); + return true; + } + } + } + + // Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type match + // in the registered bases, above, so try implicit casting (needed for proper C++ casting + // when MI is involved). + if (this_.try_implicit_casts(src, convert)) + return true; + } + + // Perform an implicit conversion + if (convert) { + for (auto &converter : typeinfo->implicit_conversions) { + auto temp = reinterpret_steal(converter(src.ptr(), typeinfo->type)); + if (load_impl(temp, false)) { + loader_life_support::add_patient(temp); + return true; + } + } + if (this_.try_direct_conversions(src)) + return true; + } + + // Failed to match local typeinfo. Try again with global. + if (typeinfo->module_local) { + if (auto gtype = get_global_type_info(*typeinfo->cpptype)) { + typeinfo = gtype; + return load(src, false); + } + } + + // Global typeinfo has precedence over foreign module_local + return try_load_foreign_module_local(src); + } + + + // Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast + // isn't needed or can't be used. If the type is unknown, sets the error and returns a pair + // with .second = nullptr. (p.first = nullptr is not an error: it becomes None). + PYBIND11_NOINLINE static std::pair src_and_type( + const void *src, const std::type_info &cast_type, const std::type_info *rtti_type = nullptr) { + if (auto *tpi = get_type_info(cast_type)) + return {src, const_cast(tpi)}; + + // Not found, set error: + std::string tname = rtti_type ? rtti_type->name() : cast_type.name(); + detail::clean_type_id(tname); + std::string msg = "Unregistered type : " + tname; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return {nullptr, nullptr}; + } + + const type_info *typeinfo = nullptr; + const std::type_info *cpptype = nullptr; + void *value = nullptr; +}; + +/** + * Determine suitable casting operator for pointer-or-lvalue-casting type casters. The type caster + * needs to provide `operator T*()` and `operator T&()` operators. + * + * If the type supports moving the value away via an `operator T&&() &&` method, it should use + * `movable_cast_op_type` instead. + */ +template +using cast_op_type = + conditional_t>::value, + typename std::add_pointer>::type, + typename std::add_lvalue_reference>::type>; + +/** + * Determine suitable casting operator for a type caster with a movable value. Such a type caster + * needs to provide `operator T*()`, `operator T&()`, and `operator T&&() &&`. The latter will be + * called in appropriate contexts where the value can be moved rather than copied. + * + * These operator are automatically provided when using the PYBIND11_TYPE_CASTER macro. + */ +template +using movable_cast_op_type = + conditional_t::type>::value, + typename std::add_pointer>::type, + conditional_t::value, + typename std::add_rvalue_reference>::type, + typename std::add_lvalue_reference>::type>>; + +// std::is_copy_constructible isn't quite enough: it lets std::vector (and similar) through when +// T is non-copyable, but code containing such a copy constructor fails to actually compile. +template struct is_copy_constructible : std::is_copy_constructible {}; + +// Specialization for types that appear to be copy constructible but also look like stl containers +// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if +// so, copy constructability depends on whether the value_type is copy constructible. +template struct is_copy_constructible, + std::is_same, + // Avoid infinite recursion + negation> + >::value>> : is_copy_constructible {}; + +// Likewise for std::pair +// (after C++17 it is mandatory that the copy constructor not exist when the two types aren't themselves +// copy constructible, but this can not be relied upon when T1 or T2 are themselves containers). +template struct is_copy_constructible> + : all_of, is_copy_constructible> {}; + +// The same problems arise with std::is_copy_assignable, so we use the same workaround. +template struct is_copy_assignable : std::is_copy_assignable {}; +template struct is_copy_assignable, + std::is_same + >::value>> : is_copy_assignable {}; +template struct is_copy_assignable> + : all_of, is_copy_assignable> {}; + +NAMESPACE_END(detail) + +// polymorphic_type_hook::get(src, tinfo) determines whether the object pointed +// to by `src` actually is an instance of some class derived from `itype`. +// If so, it sets `tinfo` to point to the std::type_info representing that derived +// type, and returns a pointer to the start of the most-derived object of that type +// (in which `src` is a subobject; this will be the same address as `src` in most +// single inheritance cases). If not, or if `src` is nullptr, it simply returns `src` +// and leaves `tinfo` at its default value of nullptr. +// +// The default polymorphic_type_hook just returns src. A specialization for polymorphic +// types determines the runtime type of the passed object and adjusts the this-pointer +// appropriately via dynamic_cast. This is what enables a C++ Animal* to appear +// to Python as a Dog (if Dog inherits from Animal, Animal is polymorphic, Dog is +// registered with pybind11, and this Animal is in fact a Dog). +// +// You may specialize polymorphic_type_hook yourself for types that want to appear +// polymorphic to Python but do not use C++ RTTI. (This is a not uncommon pattern +// in performance-sensitive applications, used most notably in LLVM.) +template +struct polymorphic_type_hook +{ + static const void *get(const itype *src, const std::type_info*&) { return src; } +}; +template +struct polymorphic_type_hook::value>> +{ + static const void *get(const itype *src, const std::type_info*& type) { + type = src ? &typeid(*src) : nullptr; + return dynamic_cast(src); + } +}; + +NAMESPACE_BEGIN(detail) + +/// Generic type caster for objects stored on the heap +template class type_caster_base : public type_caster_generic { + using itype = intrinsic_t; + +public: + static constexpr auto name = _(); + + type_caster_base() : type_caster_base(typeid(type)) { } + explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { } + + static handle cast(const itype &src, return_value_policy policy, handle parent) { + if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) + policy = return_value_policy::copy; + return cast(&src, policy, parent); + } + + static handle cast(itype &&src, return_value_policy, handle parent) { + return cast(&src, return_value_policy::move, parent); + } + + // Returns a (pointer, type_info) pair taking care of necessary type lookup for a + // polymorphic type (using RTTI by default, but can be overridden by specializing + // polymorphic_type_hook). If the instance isn't derived, returns the base version. + static std::pair src_and_type(const itype *src) { + auto &cast_type = typeid(itype); + const std::type_info *instance_type = nullptr; + const void *vsrc = polymorphic_type_hook::get(src, instance_type); + if (instance_type && !same_type(cast_type, *instance_type)) { + // This is a base pointer to a derived type. If the derived type is registered + // with pybind11, we want to make the full derived object available. + // In the typical case where itype is polymorphic, we get the correct + // derived pointer (which may be != base pointer) by a dynamic_cast to + // most derived type. If itype is not polymorphic, we won't get here + // except via a user-provided specialization of polymorphic_type_hook, + // and the user has promised that no this-pointer adjustment is + // required in that case, so it's OK to use static_cast. + if (const auto *tpi = get_type_info(*instance_type)) + return {vsrc, tpi}; + } + // Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer, so + // don't do a cast + return type_caster_generic::src_and_type(src, cast_type, instance_type); + } + + static handle cast(const itype *src, return_value_policy policy, handle parent) { + auto st = src_and_type(src); + return type_caster_generic::cast( + st.first, policy, parent, st.second, + make_copy_constructor(src), make_move_constructor(src)); + } + + static handle cast_holder(const itype *src, const void *holder) { + auto st = src_and_type(src); + return type_caster_generic::cast( + st.first, return_value_policy::take_ownership, {}, st.second, + nullptr, nullptr, holder); + } + + template using cast_op_type = detail::cast_op_type; + + operator itype*() { return (type *) value; } + operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); } + +protected: + using Constructor = void *(*)(const void *); + + /* Only enabled when the types are {copy,move}-constructible *and* when the type + does not have a private operator new implementation. */ + template ::value>> + static auto make_copy_constructor(const T *x) -> decltype(new T(*x), Constructor{}) { + return [](const void *arg) -> void * { + return new T(*reinterpret_cast(arg)); + }; + } + + template ::value>> + static auto make_move_constructor(const T *x) -> decltype(new T(std::move(*const_cast(x))), Constructor{}) { + return [](const void *arg) -> void * { + return new T(std::move(*const_cast(reinterpret_cast(arg)))); + }; + } + + static Constructor make_copy_constructor(...) { return nullptr; } + static Constructor make_move_constructor(...) { return nullptr; } +}; + +template class type_caster : public type_caster_base { }; +template using make_caster = type_caster>; + +// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T +template typename make_caster::template cast_op_type cast_op(make_caster &caster) { + return caster.operator typename make_caster::template cast_op_type(); +} +template typename make_caster::template cast_op_type::type> +cast_op(make_caster &&caster) { + return std::move(caster).operator + typename make_caster::template cast_op_type::type>(); +} + +template class type_caster> { +private: + using caster_t = make_caster; + caster_t subcaster; + using subcaster_cast_op_type = typename caster_t::template cast_op_type; + static_assert(std::is_same::type &, subcaster_cast_op_type>::value, + "std::reference_wrapper caster requires T to have a caster with an `T &` operator"); +public: + bool load(handle src, bool convert) { return subcaster.load(src, convert); } + static constexpr auto name = caster_t::name; + static handle cast(const std::reference_wrapper &src, return_value_policy policy, handle parent) { + // It is definitely wrong to take ownership of this pointer, so mask that rvp + if (policy == return_value_policy::take_ownership || policy == return_value_policy::automatic) + policy = return_value_policy::automatic_reference; + return caster_t::cast(&src.get(), policy, parent); + } + template using cast_op_type = std::reference_wrapper; + operator std::reference_wrapper() { return subcaster.operator subcaster_cast_op_type&(); } +}; + +#define PYBIND11_TYPE_CASTER(type, py_name) \ + protected: \ + type value; \ + public: \ + static constexpr auto name = py_name; \ + template >::value, int> = 0> \ + static handle cast(T_ *src, return_value_policy policy, handle parent) { \ + if (!src) return none().release(); \ + if (policy == return_value_policy::take_ownership) { \ + auto h = cast(std::move(*src), policy, parent); delete src; return h; \ + } else { \ + return cast(*src, policy, parent); \ + } \ + } \ + operator type*() { return &value; } \ + operator type&() { return value; } \ + operator type&&() && { return std::move(value); } \ + template using cast_op_type = pybind11::detail::movable_cast_op_type + + +template using is_std_char_type = any_of< + std::is_same, /* std::string */ +#if defined(PYBIND11_HAS_U8STRING) + std::is_same, /* std::u8string */ +#endif + std::is_same, /* std::u16string */ + std::is_same, /* std::u32string */ + std::is_same /* std::wstring */ +>; + +template +struct type_caster::value && !is_std_char_type::value>> { + using _py_type_0 = conditional_t; + using _py_type_1 = conditional_t::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>; + using py_type = conditional_t::value, double, _py_type_1>; +public: + + bool load(handle src, bool convert) { + py_type py_value; + + if (!src) + return false; + + if (std::is_floating_point::value) { + if (convert || PyFloat_Check(src.ptr())) + py_value = (py_type) PyFloat_AsDouble(src.ptr()); + else + return false; + } else if (PyFloat_Check(src.ptr())) { + return false; + } else if (std::is_unsigned::value) { + py_value = as_unsigned(src.ptr()); + } else { // signed integer: + py_value = sizeof(T) <= sizeof(long) + ? (py_type) PyLong_AsLong(src.ptr()) + : (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr()); + } + + bool py_err = py_value == (py_type) -1 && PyErr_Occurred(); + + // Protect std::numeric_limits::min/max with parentheses + if (py_err || (std::is_integral::value && sizeof(py_type) != sizeof(T) && + (py_value < (py_type) (std::numeric_limits::min)() || + py_value > (py_type) (std::numeric_limits::max)()))) { + bool type_error = py_err && PyErr_ExceptionMatches( +#if PY_VERSION_HEX < 0x03000000 && !defined(PYPY_VERSION) + PyExc_SystemError +#else + PyExc_TypeError +#endif + ); + PyErr_Clear(); + if (type_error && convert && PyNumber_Check(src.ptr())) { + auto tmp = reinterpret_steal(std::is_floating_point::value + ? PyNumber_Float(src.ptr()) + : PyNumber_Long(src.ptr())); + PyErr_Clear(); + return load(tmp, false); + } + return false; + } + + value = (T) py_value; + return true; + } + + template + static typename std::enable_if::value, handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyFloat_FromDouble((double) src); + } + + template + static typename std::enable_if::value && std::is_signed::value && (sizeof(U) <= sizeof(long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PYBIND11_LONG_FROM_SIGNED((long) src); + } + + template + static typename std::enable_if::value && std::is_unsigned::value && (sizeof(U) <= sizeof(unsigned long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PYBIND11_LONG_FROM_UNSIGNED((unsigned long) src); + } + + template + static typename std::enable_if::value && std::is_signed::value && (sizeof(U) > sizeof(long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromLongLong((long long) src); + } + + template + static typename std::enable_if::value && std::is_unsigned::value && (sizeof(U) > sizeof(unsigned long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromUnsignedLongLong((unsigned long long) src); + } + + PYBIND11_TYPE_CASTER(T, _::value>("int", "float")); +}; + +template struct void_caster { +public: + bool load(handle src, bool) { + if (src && src.is_none()) + return true; + return false; + } + static handle cast(T, return_value_policy /* policy */, handle /* parent */) { + return none().inc_ref(); + } + PYBIND11_TYPE_CASTER(T, _("None")); +}; + +template <> class type_caster : public void_caster {}; + +template <> class type_caster : public type_caster { +public: + using type_caster::cast; + + bool load(handle h, bool) { + if (!h) { + return false; + } else if (h.is_none()) { + value = nullptr; + return true; + } + + /* Check if this is a capsule */ + if (isinstance(h)) { + value = reinterpret_borrow(h); + return true; + } + + /* Check if this is a C++ type */ + auto &bases = all_type_info((PyTypeObject *) h.get_type().ptr()); + if (bases.size() == 1) { // Only allowing loading from a single-value type + value = values_and_holders(reinterpret_cast(h.ptr())).begin()->value_ptr(); + return true; + } + + /* Fail */ + return false; + } + + static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) { + if (ptr) + return capsule(ptr).release(); + else + return none().inc_ref(); + } + + template using cast_op_type = void*&; + operator void *&() { return value; } + static constexpr auto name = _("capsule"); +private: + void *value = nullptr; +}; + +template <> class type_caster : public void_caster { }; + +template <> class type_caster { +public: + bool load(handle src, bool convert) { + if (!src) return false; + else if (src.ptr() == Py_True) { value = true; return true; } + else if (src.ptr() == Py_False) { value = false; return true; } + else if (convert || !strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name)) { + // (allow non-implicit conversion for numpy booleans) + + Py_ssize_t res = -1; + if (src.is_none()) { + res = 0; // None is implicitly converted to False + } + #if defined(PYPY_VERSION) + // On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr exists + else if (hasattr(src, PYBIND11_BOOL_ATTR)) { + res = PyObject_IsTrue(src.ptr()); + } + #else + // Alternate approach for CPython: this does the same as the above, but optimized + // using the CPython API so as to avoid an unneeded attribute lookup. + else if (auto tp_as_number = src.ptr()->ob_type->tp_as_number) { + if (PYBIND11_NB_BOOL(tp_as_number)) { + res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr()); + } + } + #endif + if (res == 0 || res == 1) { + value = (bool) res; + return true; + } else { + PyErr_Clear(); + } + } + return false; + } + static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) { + return handle(src ? Py_True : Py_False).inc_ref(); + } + PYBIND11_TYPE_CASTER(bool, _("bool")); +}; + +// Helper class for UTF-{8,16,32} C++ stl strings: +template struct string_caster { + using CharT = typename StringType::value_type; + + // Simplify life by being able to assume standard char sizes (the standard only guarantees + // minimums, but Python requires exact sizes) + static_assert(!std::is_same::value || sizeof(CharT) == 1, "Unsupported char size != 1"); +#if defined(PYBIND11_HAS_U8STRING) + static_assert(!std::is_same::value || sizeof(CharT) == 1, "Unsupported char8_t size != 1"); +#endif + static_assert(!std::is_same::value || sizeof(CharT) == 2, "Unsupported char16_t size != 2"); + static_assert(!std::is_same::value || sizeof(CharT) == 4, "Unsupported char32_t size != 4"); + // wchar_t can be either 16 bits (Windows) or 32 (everywhere else) + static_assert(!std::is_same::value || sizeof(CharT) == 2 || sizeof(CharT) == 4, + "Unsupported wchar_t size != 2/4"); + static constexpr size_t UTF_N = 8 * sizeof(CharT); + + bool load(handle src, bool) { +#if PY_MAJOR_VERSION < 3 + object temp; +#endif + handle load_src = src; + if (!src) { + return false; + } else if (!PyUnicode_Check(load_src.ptr())) { +#if PY_MAJOR_VERSION >= 3 + return load_bytes(load_src); +#else + if (std::is_same::value) { + return load_bytes(load_src); + } + + // The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false + if (!PYBIND11_BYTES_CHECK(load_src.ptr())) + return false; + + temp = reinterpret_steal(PyUnicode_FromObject(load_src.ptr())); + if (!temp) { PyErr_Clear(); return false; } + load_src = temp; +#endif + } + + object utfNbytes = reinterpret_steal(PyUnicode_AsEncodedString( + load_src.ptr(), UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr)); + if (!utfNbytes) { PyErr_Clear(); return false; } + + const CharT *buffer = reinterpret_cast(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); + size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT); + if (UTF_N > 8) { buffer++; length--; } // Skip BOM for UTF-16/32 + value = StringType(buffer, length); + + // If we're loading a string_view we need to keep the encoded Python object alive: + if (IsView) + loader_life_support::add_patient(utfNbytes); + + return true; + } + + static handle cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) { + const char *buffer = reinterpret_cast(src.data()); + ssize_t nbytes = ssize_t(src.size() * sizeof(CharT)); + handle s = decode_utfN(buffer, nbytes); + if (!s) throw error_already_set(); + return s; + } + + PYBIND11_TYPE_CASTER(StringType, _(PYBIND11_STRING_NAME)); + +private: + static handle decode_utfN(const char *buffer, ssize_t nbytes) { +#if !defined(PYPY_VERSION) + return + UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) : + UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) : + PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr); +#else + // PyPy seems to have multiple problems related to PyUnicode_UTF*: the UTF8 version + // sometimes segfaults for unknown reasons, while the UTF16 and 32 versions require a + // non-const char * arguments, which is also a nuisance, so bypass the whole thing by just + // passing the encoding as a string value, which works properly: + return PyUnicode_Decode(buffer, nbytes, UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr); +#endif + } + + // When loading into a std::string or char*, accept a bytes object as-is (i.e. + // without any encoding/decoding attempt). For other C++ char sizes this is a no-op. + // which supports loading a unicode from a str, doesn't take this path. + template + bool load_bytes(enable_if_t::value, handle> src) { + if (PYBIND11_BYTES_CHECK(src.ptr())) { + // We were passed a Python 3 raw bytes; accept it into a std::string or char* + // without any encoding attempt. + const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr()); + if (bytes) { + value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr())); + return true; + } + } + + return false; + } + + template + bool load_bytes(enable_if_t::value, handle>) { return false; } +}; + +template +struct type_caster, enable_if_t::value>> + : string_caster> {}; + +#ifdef PYBIND11_HAS_STRING_VIEW +template +struct type_caster, enable_if_t::value>> + : string_caster, true> {}; +#endif + +// Type caster for C-style strings. We basically use a std::string type caster, but also add the +// ability to use None as a nullptr char* (which the string caster doesn't allow). +template struct type_caster::value>> { + using StringType = std::basic_string; + using StringCaster = type_caster; + StringCaster str_caster; + bool none = false; + CharT one_char = 0; +public: + bool load(handle src, bool convert) { + if (!src) return false; + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) return false; + none = true; + return true; + } + return str_caster.load(src, convert); + } + + static handle cast(const CharT *src, return_value_policy policy, handle parent) { + if (src == nullptr) return pybind11::none().inc_ref(); + return StringCaster::cast(StringType(src), policy, parent); + } + + static handle cast(CharT src, return_value_policy policy, handle parent) { + if (std::is_same::value) { + handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr); + if (!s) throw error_already_set(); + return s; + } + return StringCaster::cast(StringType(1, src), policy, parent); + } + + operator CharT*() { return none ? nullptr : const_cast(static_cast(str_caster).c_str()); } + operator CharT&() { + if (none) + throw value_error("Cannot convert None to a character"); + + auto &value = static_cast(str_caster); + size_t str_len = value.size(); + if (str_len == 0) + throw value_error("Cannot convert empty string to a character"); + + // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that + // is too high, and one for multiple unicode characters (caught later), so we need to figure + // out how long the first encoded character is in bytes to distinguish between these two + // errors. We also allow want to allow unicode characters U+0080 through U+00FF, as those + // can fit into a single char value. + if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) { + unsigned char v0 = static_cast(value[0]); + size_t char0_bytes = !(v0 & 0x80) ? 1 : // low bits only: 0-127 + (v0 & 0xE0) == 0xC0 ? 2 : // 0b110xxxxx - start of 2-byte sequence + (v0 & 0xF0) == 0xE0 ? 3 : // 0b1110xxxx - start of 3-byte sequence + 4; // 0b11110xxx - start of 4-byte sequence + + if (char0_bytes == str_len) { + // If we have a 128-255 value, we can decode it into a single char: + if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) { // 0x110000xx 0x10xxxxxx + one_char = static_cast(((v0 & 3) << 6) + (static_cast(value[1]) & 0x3F)); + return one_char; + } + // Otherwise we have a single character, but it's > U+00FF + throw value_error("Character code point not in range(0x100)"); + } + } + + // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a + // surrogate pair with total length 2 instantly indicates a range error (but not a "your + // string was too long" error). + else if (StringCaster::UTF_N == 16 && str_len == 2) { + one_char = static_cast(value[0]); + if (one_char >= 0xD800 && one_char < 0xE000) + throw value_error("Character code point not in range(0x10000)"); + } + + if (str_len != 1) + throw value_error("Expected a character, but multi-character string found"); + + one_char = value[0]; + return one_char; + } + + static constexpr auto name = _(PYBIND11_STRING_NAME); + template using cast_op_type = pybind11::detail::cast_op_type<_T>; +}; + +// Base implementation for std::tuple and std::pair +template class Tuple, typename... Ts> class tuple_caster { + using type = Tuple; + static constexpr auto size = sizeof...(Ts); + using indices = make_index_sequence; +public: + + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + const auto seq = reinterpret_borrow(src); + if (seq.size() != size) + return false; + return load_impl(seq, convert, indices{}); + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + return cast_impl(std::forward(src), policy, parent, indices{}); + } + + static constexpr auto name = _("Tuple[") + concat(make_caster::name...) + _("]"); + + template using cast_op_type = type; + + operator type() & { return implicit_cast(indices{}); } + operator type() && { return std::move(*this).implicit_cast(indices{}); } + +protected: + template + type implicit_cast(index_sequence) & { return type(cast_op(std::get(subcasters))...); } + template + type implicit_cast(index_sequence) && { return type(cast_op(std::move(std::get(subcasters)))...); } + + static constexpr bool load_impl(const sequence &, bool, index_sequence<>) { return true; } + + template + bool load_impl(const sequence &seq, bool convert, index_sequence) { +#ifdef __cpp_fold_expressions + if ((... || !std::get(subcasters).load(seq[Is], convert))) + return false; +#else + for (bool r : {std::get(subcasters).load(seq[Is], convert)...}) + if (!r) + return false; +#endif + return true; + } + + /* Implementation: Convert a C++ tuple into a Python tuple */ + template + static handle cast_impl(T &&src, return_value_policy policy, handle parent, index_sequence) { + std::array entries{{ + reinterpret_steal(make_caster::cast(std::get(std::forward(src)), policy, parent))... + }}; + for (const auto &entry: entries) + if (!entry) + return handle(); + tuple result(size); + int counter = 0; + for (auto & entry: entries) + PyTuple_SET_ITEM(result.ptr(), counter++, entry.release().ptr()); + return result.release(); + } + + Tuple...> subcasters; +}; + +template class type_caster> + : public tuple_caster {}; + +template class type_caster> + : public tuple_caster {}; + +/// Helper class which abstracts away certain actions. Users can provide specializations for +/// custom holders, but it's only necessary if the type has a non-standard interface. +template +struct holder_helper { + static auto get(const T &p) -> decltype(p.get()) { return p.get(); } +}; + +/// Type caster for holder types like std::shared_ptr, etc. +template +struct copyable_holder_caster : public type_caster_base { +public: + using base = type_caster_base; + static_assert(std::is_base_of>::value, + "Holder classes are only supported for custom types"); + using base::base; + using base::cast; + using base::typeinfo; + using base::value; + + bool load(handle src, bool convert) { + return base::template load_impl>(src, convert); + } + + explicit operator type*() { return this->value; } + explicit operator type&() { return *(this->value); } + explicit operator holder_type*() { return std::addressof(holder); } + + // Workaround for Intel compiler bug + // see pybind11 issue 94 + #if defined(__ICC) || defined(__INTEL_COMPILER) + operator holder_type&() { return holder; } + #else + explicit operator holder_type&() { return holder; } + #endif + + static handle cast(const holder_type &src, return_value_policy, handle) { + const auto *ptr = holder_helper::get(src); + return type_caster_base::cast_holder(ptr, &src); + } + +protected: + friend class type_caster_generic; + void check_holder_compat() { + if (typeinfo->default_holder) + throw cast_error("Unable to load a custom holder type from a default-holder instance"); + } + + bool load_value(value_and_holder &&v_h) { + if (v_h.holder_constructed()) { + value = v_h.value_ptr(); + holder = v_h.template holder(); + return true; + } else { + throw cast_error("Unable to cast from non-held to held instance (T& to Holder) " +#if defined(NDEBUG) + "(compile in debug mode for type information)"); +#else + "of type '" + type_id() + "''"); +#endif + } + } + + template ::value, int> = 0> + bool try_implicit_casts(handle, bool) { return false; } + + template ::value, int> = 0> + bool try_implicit_casts(handle src, bool convert) { + for (auto &cast : typeinfo->implicit_casts) { + copyable_holder_caster sub_caster(*cast.first); + if (sub_caster.load(src, convert)) { + value = cast.second(sub_caster.value); + holder = holder_type(sub_caster.holder, (type *) value); + return true; + } + } + return false; + } + + static bool try_direct_conversions(handle) { return false; } + + + holder_type holder; +}; + +/// Specialize for the common std::shared_ptr, so users don't need to +template +class type_caster> : public copyable_holder_caster> { }; + +template +struct move_only_holder_caster { + static_assert(std::is_base_of, type_caster>::value, + "Holder classes are only supported for custom types"); + + static handle cast(holder_type &&src, return_value_policy, handle) { + auto *ptr = holder_helper::get(src); + return type_caster_base::cast_holder(ptr, std::addressof(src)); + } + static constexpr auto name = type_caster_base::name; +}; + +template +class type_caster> + : public move_only_holder_caster> { }; + +template +using type_caster_holder = conditional_t::value, + copyable_holder_caster, + move_only_holder_caster>; + +template struct always_construct_holder { static constexpr bool value = Value; }; + +/// Create a specialization for custom holder types (silently ignores std::shared_ptr) +#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \ + namespace pybind11 { namespace detail { \ + template \ + struct always_construct_holder : always_construct_holder { }; \ + template \ + class type_caster::value>> \ + : public type_caster_holder { }; \ + }} + +// PYBIND11_DECLARE_HOLDER_TYPE holder types: +template struct is_holder_type : + std::is_base_of, detail::type_caster> {}; +// Specialization for always-supported unique_ptr holders: +template struct is_holder_type> : + std::true_type {}; + +template struct handle_type_name { static constexpr auto name = _(); }; +template <> struct handle_type_name { static constexpr auto name = _(PYBIND11_BYTES_NAME); }; +template <> struct handle_type_name { static constexpr auto name = _("*args"); }; +template <> struct handle_type_name { static constexpr auto name = _("**kwargs"); }; + +template +struct pyobject_caster { + template ::value, int> = 0> + bool load(handle src, bool /* convert */) { value = src; return static_cast(value); } + + template ::value, int> = 0> + bool load(handle src, bool /* convert */) { + if (!isinstance(src)) + return false; + value = reinterpret_borrow(src); + return true; + } + + static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { + return src.inc_ref(); + } + PYBIND11_TYPE_CASTER(type, handle_type_name::name); +}; + +template +class type_caster::value>> : public pyobject_caster { }; + +// Our conditions for enabling moving are quite restrictive: +// At compile time: +// - T needs to be a non-const, non-pointer, non-reference type +// - type_caster::operator T&() must exist +// - the type must be move constructible (obviously) +// At run-time: +// - if the type is non-copy-constructible, the object must be the sole owner of the type (i.e. it +// must have ref_count() == 1)h +// If any of the above are not satisfied, we fall back to copying. +template using move_is_plain_type = satisfies_none_of; +template struct move_always : std::false_type {}; +template struct move_always, + negation>, + std::is_move_constructible, + std::is_same>().operator T&()), T&> +>::value>> : std::true_type {}; +template struct move_if_unreferenced : std::false_type {}; +template struct move_if_unreferenced, + negation>, + std::is_move_constructible, + std::is_same>().operator T&()), T&> +>::value>> : std::true_type {}; +template using move_never = none_of, move_if_unreferenced>; + +// Detect whether returning a `type` from a cast on type's type_caster is going to result in a +// reference or pointer to a local variable of the type_caster. Basically, only +// non-reference/pointer `type`s and reference/pointers from a type_caster_generic are safe; +// everything else returns a reference/pointer to a local variable. +template using cast_is_temporary_value_reference = bool_constant< + (std::is_reference::value || std::is_pointer::value) && + !std::is_base_of>::value && + !std::is_same, void>::value +>; + +// When a value returned from a C++ function is being cast back to Python, we almost always want to +// force `policy = move`, regardless of the return value policy the function/method was declared +// with. +template struct return_value_policy_override { + static return_value_policy policy(return_value_policy p) { return p; } +}; + +template struct return_value_policy_override>::value, void>> { + static return_value_policy policy(return_value_policy p) { + return !std::is_lvalue_reference::value && + !std::is_pointer::value + ? return_value_policy::move : p; + } +}; + +// Basic python -> C++ casting; throws if casting fails +template type_caster &load_type(type_caster &conv, const handle &handle) { + if (!conv.load(handle, true)) { +#if defined(NDEBUG) + throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)"); +#else + throw cast_error("Unable to cast Python instance of type " + + (std::string) str(handle.get_type()) + " to C++ type '" + type_id() + "'"); +#endif + } + return conv; +} +// Wrapper around the above that also constructs and returns a type_caster +template make_caster load_type(const handle &handle) { + make_caster conv; + load_type(conv, handle); + return conv; +} + +NAMESPACE_END(detail) + +// pytype -> C++ type +template ::value, int> = 0> +T cast(const handle &handle) { + using namespace detail; + static_assert(!cast_is_temporary_value_reference::value, + "Unable to cast type to reference: value is local to type caster"); + return cast_op(load_type(handle)); +} + +// pytype -> pytype (calls converting constructor) +template ::value, int> = 0> +T cast(const handle &handle) { return T(reinterpret_borrow(handle)); } + +// C++ type -> py::object +template ::value, int> = 0> +object cast(const T &value, return_value_policy policy = return_value_policy::automatic_reference, + handle parent = handle()) { + if (policy == return_value_policy::automatic) + policy = std::is_pointer::value ? return_value_policy::take_ownership : return_value_policy::copy; + else if (policy == return_value_policy::automatic_reference) + policy = std::is_pointer::value ? return_value_policy::reference : return_value_policy::copy; + return reinterpret_steal(detail::make_caster::cast(value, policy, parent)); +} + +template T handle::cast() const { return pybind11::cast(*this); } +template <> inline void handle::cast() const { return; } + +template +detail::enable_if_t::value, T> move(object &&obj) { + if (obj.ref_count() > 1) +#if defined(NDEBUG) + throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references" + " (compile in debug mode for details)"); +#else + throw cast_error("Unable to move from Python " + (std::string) str(obj.get_type()) + + " instance to C++ " + type_id() + " instance: instance has multiple references"); +#endif + + // Move into a temporary and return that, because the reference may be a local value of `conv` + T ret = std::move(detail::load_type(obj).operator T&()); + return ret; +} + +// Calling cast() on an rvalue calls pybind::cast with the object rvalue, which does: +// - If we have to move (because T has no copy constructor), do it. This will fail if the moved +// object has multiple references, but trying to copy will fail to compile. +// - If both movable and copyable, check ref count: if 1, move; otherwise copy +// - Otherwise (not movable), copy. +template detail::enable_if_t::value, T> cast(object &&object) { + return move(std::move(object)); +} +template detail::enable_if_t::value, T> cast(object &&object) { + if (object.ref_count() > 1) + return cast(object); + else + return move(std::move(object)); +} +template detail::enable_if_t::value, T> cast(object &&object) { + return cast(object); +} + +template T object::cast() const & { return pybind11::cast(*this); } +template T object::cast() && { return pybind11::cast(std::move(*this)); } +template <> inline void object::cast() const & { return; } +template <> inline void object::cast() && { return; } + +NAMESPACE_BEGIN(detail) + +// Declared in pytypes.h: +template ::value, int>> +object object_or_cast(T &&o) { return pybind11::cast(std::forward(o)); } + +struct overload_unused {}; // Placeholder type for the unneeded (and dead code) static variable in the OVERLOAD_INT macro +template using overload_caster_t = conditional_t< + cast_is_temporary_value_reference::value, make_caster, overload_unused>; + +// Trampoline use: for reference/pointer types to value-converted values, we do a value cast, then +// store the result in the given variable. For other types, this is a no-op. +template enable_if_t::value, T> cast_ref(object &&o, make_caster &caster) { + return cast_op(load_type(caster, o)); +} +template enable_if_t::value, T> cast_ref(object &&, overload_unused &) { + pybind11_fail("Internal error: cast_ref fallback invoked"); } + +// Trampoline use: Having a pybind11::cast with an invalid reference type is going to static_assert, even +// though if it's in dead code, so we provide a "trampoline" to pybind11::cast that only does anything in +// cases where pybind11::cast is valid. +template enable_if_t::value, T> cast_safe(object &&o) { + return pybind11::cast(std::move(o)); } +template enable_if_t::value, T> cast_safe(object &&) { + pybind11_fail("Internal error: cast_safe fallback invoked"); } +template <> inline void cast_safe(object &&) {} + +NAMESPACE_END(detail) + +template +tuple make_tuple() { return tuple(0); } + +template tuple make_tuple(Args&&... args_) { + constexpr size_t size = sizeof...(Args); + std::array args { + { reinterpret_steal(detail::make_caster::cast( + std::forward(args_), policy, nullptr))... } + }; + for (size_t i = 0; i < args.size(); i++) { + if (!args[i]) { +#if defined(NDEBUG) + throw cast_error("make_tuple(): unable to convert arguments to Python object (compile in debug mode for details)"); +#else + std::array argtypes { {type_id()...} }; + throw cast_error("make_tuple(): unable to convert argument of type '" + + argtypes[i] + "' to Python object"); +#endif + } + } + tuple result(size); + int counter = 0; + for (auto &arg_value : args) + PyTuple_SET_ITEM(result.ptr(), counter++, arg_value.release().ptr()); + return result; +} + +/// \ingroup annotations +/// Annotation for arguments +struct arg { + /// Constructs an argument with the name of the argument; if null or omitted, this is a positional argument. + constexpr explicit arg(const char *name = nullptr) : name(name), flag_noconvert(false), flag_none(true) { } + /// Assign a value to this argument + template arg_v operator=(T &&value) const; + /// Indicate that the type should not be converted in the type caster + arg &noconvert(bool flag = true) { flag_noconvert = flag; return *this; } + /// Indicates that the argument should/shouldn't allow None (e.g. for nullable pointer args) + arg &none(bool flag = true) { flag_none = flag; return *this; } + + const char *name; ///< If non-null, this is a named kwargs argument + bool flag_noconvert : 1; ///< If set, do not allow conversion (requires a supporting type caster!) + bool flag_none : 1; ///< If set (the default), allow None to be passed to this argument +}; + +/// \ingroup annotations +/// Annotation for arguments with values +struct arg_v : arg { +private: + template + arg_v(arg &&base, T &&x, const char *descr = nullptr) + : arg(base), + value(reinterpret_steal( + detail::make_caster::cast(x, return_value_policy::automatic, {}) + )), + descr(descr) +#if !defined(NDEBUG) + , type(type_id()) +#endif + { } + +public: + /// Direct construction with name, default, and description + template + arg_v(const char *name, T &&x, const char *descr = nullptr) + : arg_v(arg(name), std::forward(x), descr) { } + + /// Called internally when invoking `py::arg("a") = value` + template + arg_v(const arg &base, T &&x, const char *descr = nullptr) + : arg_v(arg(base), std::forward(x), descr) { } + + /// Same as `arg::noconvert()`, but returns *this as arg_v&, not arg& + arg_v &noconvert(bool flag = true) { arg::noconvert(flag); return *this; } + + /// Same as `arg::nonone()`, but returns *this as arg_v&, not arg& + arg_v &none(bool flag = true) { arg::none(flag); return *this; } + + /// The default value + object value; + /// The (optional) description of the default value + const char *descr; +#if !defined(NDEBUG) + /// The C++ type name of the default value (only available when compiled in debug mode) + std::string type; +#endif +}; + +template +arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward(value)}; } + +/// Alias for backward compatibility -- to be removed in version 2.0 +template using arg_t = arg_v; + +inline namespace literals { +/** \rst + String literal version of `arg` + \endrst */ +constexpr arg operator"" _a(const char *name, size_t) { return arg(name); } +} + +NAMESPACE_BEGIN(detail) + +// forward declaration (definition in attr.h) +struct function_record; + +/// Internal data associated with a single function call +struct function_call { + function_call(const function_record &f, handle p); // Implementation in attr.h + + /// The function data: + const function_record &func; + + /// Arguments passed to the function: + std::vector args; + + /// The `convert` value the arguments should be loaded with + std::vector args_convert; + + /// Extra references for the optional `py::args` and/or `py::kwargs` arguments (which, if + /// present, are also in `args` but without a reference). + object args_ref, kwargs_ref; + + /// The parent, if any + handle parent; + + /// If this is a call to an initializer, this argument contains `self` + handle init_self; +}; + + +/// Helper class which loads arguments for C++ functions called from Python +template +class argument_loader { + using indices = make_index_sequence; + + template using argument_is_args = std::is_same, args>; + template using argument_is_kwargs = std::is_same, kwargs>; + // Get args/kwargs argument positions relative to the end of the argument list: + static constexpr auto args_pos = constexpr_first() - (int) sizeof...(Args), + kwargs_pos = constexpr_first() - (int) sizeof...(Args); + + static constexpr bool args_kwargs_are_last = kwargs_pos >= - 1 && args_pos >= kwargs_pos - 1; + + static_assert(args_kwargs_are_last, "py::args/py::kwargs are only permitted as the last argument(s) of a function"); + +public: + static constexpr bool has_kwargs = kwargs_pos < 0; + static constexpr bool has_args = args_pos < 0; + + static constexpr auto arg_names = concat(type_descr(make_caster::name)...); + + bool load_args(function_call &call) { + return load_impl_sequence(call, indices{}); + } + + template + enable_if_t::value, Return> call(Func &&f) && { + return std::move(*this).template call_impl(std::forward(f), indices{}, Guard{}); + } + + template + enable_if_t::value, void_type> call(Func &&f) && { + std::move(*this).template call_impl(std::forward(f), indices{}, Guard{}); + return void_type(); + } + +private: + + static bool load_impl_sequence(function_call &, index_sequence<>) { return true; } + + template + bool load_impl_sequence(function_call &call, index_sequence) { +#ifdef __cpp_fold_expressions + if ((... || !std::get(argcasters).load(call.args[Is], call.args_convert[Is]))) + return false; +#else + for (bool r : {std::get(argcasters).load(call.args[Is], call.args_convert[Is])...}) + if (!r) + return false; +#endif + return true; + } + + template + Return call_impl(Func &&f, index_sequence, Guard &&) && { + return std::forward(f)(cast_op(std::move(std::get(argcasters)))...); + } + + std::tuple...> argcasters; +}; + +/// Helper class which collects only positional arguments for a Python function call. +/// A fancier version below can collect any argument, but this one is optimal for simple calls. +template +class simple_collector { +public: + template + explicit simple_collector(Ts &&...values) + : m_args(pybind11::make_tuple(std::forward(values)...)) { } + + const tuple &args() const & { return m_args; } + dict kwargs() const { return {}; } + + tuple args() && { return std::move(m_args); } + + /// Call a Python function and pass the collected arguments + object call(PyObject *ptr) const { + PyObject *result = PyObject_CallObject(ptr, m_args.ptr()); + if (!result) + throw error_already_set(); + return reinterpret_steal(result); + } + +private: + tuple m_args; +}; + +/// Helper class which collects positional, keyword, * and ** arguments for a Python function call +template +class unpacking_collector { +public: + template + explicit unpacking_collector(Ts &&...values) { + // Tuples aren't (easily) resizable so a list is needed for collection, + // but the actual function call strictly requires a tuple. + auto args_list = list(); + int _[] = { 0, (process(args_list, std::forward(values)), 0)... }; + ignore_unused(_); + + m_args = std::move(args_list); + } + + const tuple &args() const & { return m_args; } + const dict &kwargs() const & { return m_kwargs; } + + tuple args() && { return std::move(m_args); } + dict kwargs() && { return std::move(m_kwargs); } + + /// Call a Python function and pass the collected arguments + object call(PyObject *ptr) const { + PyObject *result = PyObject_Call(ptr, m_args.ptr(), m_kwargs.ptr()); + if (!result) + throw error_already_set(); + return reinterpret_steal(result); + } + +private: + template + void process(list &args_list, T &&x) { + auto o = reinterpret_steal(detail::make_caster::cast(std::forward(x), policy, {})); + if (!o) { +#if defined(NDEBUG) + argument_cast_error(); +#else + argument_cast_error(std::to_string(args_list.size()), type_id()); +#endif + } + args_list.append(o); + } + + void process(list &args_list, detail::args_proxy ap) { + for (const auto &a : ap) + args_list.append(a); + } + + void process(list &/*args_list*/, arg_v a) { + if (!a.name) +#if defined(NDEBUG) + nameless_argument_error(); +#else + nameless_argument_error(a.type); +#endif + + if (m_kwargs.contains(a.name)) { +#if defined(NDEBUG) + multiple_values_error(); +#else + multiple_values_error(a.name); +#endif + } + if (!a.value) { +#if defined(NDEBUG) + argument_cast_error(); +#else + argument_cast_error(a.name, a.type); +#endif + } + m_kwargs[a.name] = a.value; + } + + void process(list &/*args_list*/, detail::kwargs_proxy kp) { + if (!kp) + return; + for (const auto &k : reinterpret_borrow(kp)) { + if (m_kwargs.contains(k.first)) { +#if defined(NDEBUG) + multiple_values_error(); +#else + multiple_values_error(str(k.first)); +#endif + } + m_kwargs[k.first] = k.second; + } + } + + [[noreturn]] static void nameless_argument_error() { + throw type_error("Got kwargs without a name; only named arguments " + "may be passed via py::arg() to a python function call. " + "(compile in debug mode for details)"); + } + [[noreturn]] static void nameless_argument_error(std::string type) { + throw type_error("Got kwargs without a name of type '" + type + "'; only named " + "arguments may be passed via py::arg() to a python function call. "); + } + [[noreturn]] static void multiple_values_error() { + throw type_error("Got multiple values for keyword argument " + "(compile in debug mode for details)"); + } + + [[noreturn]] static void multiple_values_error(std::string name) { + throw type_error("Got multiple values for keyword argument '" + name + "'"); + } + + [[noreturn]] static void argument_cast_error() { + throw cast_error("Unable to convert call argument to Python object " + "(compile in debug mode for details)"); + } + + [[noreturn]] static void argument_cast_error(std::string name, std::string type) { + throw cast_error("Unable to convert call argument '" + name + + "' of type '" + type + "' to Python object"); + } + +private: + tuple m_args; + dict m_kwargs; +}; + +/// Collect only positional arguments for a Python function call +template ...>::value>> +simple_collector collect_arguments(Args &&...args) { + return simple_collector(std::forward(args)...); +} + +/// Collect all arguments, including keywords and unpacking (only instantiated when needed) +template ...>::value>> +unpacking_collector collect_arguments(Args &&...args) { + // Following argument order rules for generalized unpacking according to PEP 448 + static_assert( + constexpr_last() < constexpr_first() + && constexpr_last() < constexpr_first(), + "Invalid function call: positional args must precede keywords and ** unpacking; " + "* unpacking must precede ** unpacking" + ); + return unpacking_collector(std::forward(args)...); +} + +template +template +object object_api::operator()(Args &&...args) const { + return detail::collect_arguments(std::forward(args)...).call(derived().ptr()); +} + +template +template +object object_api::call(Args &&...args) const { + return operator()(std::forward(args)...); +} + +NAMESPACE_END(detail) + +#define PYBIND11_MAKE_OPAQUE(...) \ + namespace pybind11 { namespace detail { \ + template<> class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> { }; \ + }} + +/// Lets you pass a type containing a `,` through a macro parameter without needing a separate +/// typedef, e.g.: `PYBIND11_OVERLOAD(PYBIND11_TYPE(ReturnType), PYBIND11_TYPE(Parent), f, arg)` +#define PYBIND11_TYPE(...) __VA_ARGS__ + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/chrono.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/chrono.h new file mode 100644 index 0000000000000000000000000000000000000000..ea777e69658e37540972d06ea94ae9850a7166e2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/chrono.h @@ -0,0 +1,184 @@ +/* + pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime + + Copyright (c) 2016 Trent Houliston and + Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include +#include +#include +#include + +// Backport the PyDateTime_DELTA functions from Python3.3 if required +#ifndef PyDateTime_DELTA_GET_DAYS +#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days) +#endif +#ifndef PyDateTime_DELTA_GET_SECONDS +#define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds) +#endif +#ifndef PyDateTime_DELTA_GET_MICROSECONDS +#define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta*)o)->microseconds) +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +template class duration_caster { +public: + typedef typename type::rep rep; + typedef typename type::period period; + + typedef std::chrono::duration> days; + + bool load(handle src, bool) { + using namespace std::chrono; + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + if (!src) return false; + // If invoked with datetime.delta object + if (PyDelta_Check(src.ptr())) { + value = type(duration_cast>( + days(PyDateTime_DELTA_GET_DAYS(src.ptr())) + + seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) + + microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr())))); + return true; + } + // If invoked with a float we assume it is seconds and convert + else if (PyFloat_Check(src.ptr())) { + value = type(duration_cast>(duration(PyFloat_AsDouble(src.ptr())))); + return true; + } + else return false; + } + + // If this is a duration just return it back + static const std::chrono::duration& get_duration(const std::chrono::duration &src) { + return src; + } + + // If this is a time_point get the time_since_epoch + template static std::chrono::duration get_duration(const std::chrono::time_point> &src) { + return src.time_since_epoch(); + } + + static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) { + using namespace std::chrono; + + // Use overloaded function to get our duration from our source + // Works out if it is a duration or time_point and get the duration + auto d = get_duration(src); + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + // Declare these special duration types so the conversions happen with the correct primitive types (int) + using dd_t = duration>; + using ss_t = duration>; + using us_t = duration; + + auto dd = duration_cast(d); + auto subd = d - dd; + auto ss = duration_cast(subd); + auto us = duration_cast(subd - ss); + return PyDelta_FromDSU(dd.count(), ss.count(), us.count()); + } + + PYBIND11_TYPE_CASTER(type, _("datetime.timedelta")); +}; + +// This is for casting times on the system clock into datetime.datetime instances +template class type_caster> { +public: + typedef std::chrono::time_point type; + bool load(handle src, bool) { + using namespace std::chrono; + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + if (!src) return false; + + std::tm cal; + microseconds msecs; + + if (PyDateTime_Check(src.ptr())) { + cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr()); + cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr()); + cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr()); + cal.tm_mday = PyDateTime_GET_DAY(src.ptr()); + cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; + cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900; + cal.tm_isdst = -1; + msecs = microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr())); + } else if (PyDate_Check(src.ptr())) { + cal.tm_sec = 0; + cal.tm_min = 0; + cal.tm_hour = 0; + cal.tm_mday = PyDateTime_GET_DAY(src.ptr()); + cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; + cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900; + cal.tm_isdst = -1; + msecs = microseconds(0); + } else if (PyTime_Check(src.ptr())) { + cal.tm_sec = PyDateTime_TIME_GET_SECOND(src.ptr()); + cal.tm_min = PyDateTime_TIME_GET_MINUTE(src.ptr()); + cal.tm_hour = PyDateTime_TIME_GET_HOUR(src.ptr()); + cal.tm_mday = 1; // This date (day, month, year) = (1, 0, 70) + cal.tm_mon = 0; // represents 1-Jan-1970, which is the first + cal.tm_year = 70; // earliest available date for Python's datetime + cal.tm_isdst = -1; + msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr())); + } + else return false; + + value = system_clock::from_time_t(std::mktime(&cal)) + msecs; + return true; + } + + static handle cast(const std::chrono::time_point &src, return_value_policy /* policy */, handle /* parent */) { + using namespace std::chrono; + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + std::time_t tt = system_clock::to_time_t(time_point_cast(src)); + // this function uses static memory so it's best to copy it out asap just in case + // otherwise other code that is using localtime may break this (not just python code) + std::tm localtime = *std::localtime(&tt); + + // Declare these special duration types so the conversions happen with the correct primitive types (int) + using us_t = duration; + + return PyDateTime_FromDateAndTime(localtime.tm_year + 1900, + localtime.tm_mon + 1, + localtime.tm_mday, + localtime.tm_hour, + localtime.tm_min, + localtime.tm_sec, + (duration_cast(src.time_since_epoch() % seconds(1))).count()); + } + PYBIND11_TYPE_CASTER(type, _("datetime.datetime")); +}; + +// Other clocks that are not the system clock are not measured as datetime.datetime objects +// since they are not measured on calendar time. So instead we just make them timedeltas +// Or if they have passed us a time as a float we convert that +template class type_caster> +: public duration_caster> { +}; + +template class type_caster> +: public duration_caster> { +}; + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/common.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/common.h new file mode 100644 index 0000000000000000000000000000000000000000..6c8a4f1e88e493ee08d24e668639c8d495fd49b1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/common.h @@ -0,0 +1,2 @@ +#include "detail/common.h" +#warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'." diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/complex.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/complex.h new file mode 100644 index 0000000000000000000000000000000000000000..3f8963857177631b207b84c097fc939b6aaf7278 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/complex.h @@ -0,0 +1,65 @@ +/* + pybind11/complex.h: Complex number support + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include + +/// glibc defines I as a macro which breaks things, e.g., boost template names +#ifdef I +# undef I +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +template struct format_descriptor, detail::enable_if_t::value>> { + static constexpr const char c = format_descriptor::c; + static constexpr const char value[3] = { 'Z', c, '\0' }; + static std::string format() { return std::string(value); } +}; + +#ifndef PYBIND11_CPP17 + +template constexpr const char format_descriptor< + std::complex, detail::enable_if_t::value>>::value[3]; + +#endif + +NAMESPACE_BEGIN(detail) + +template struct is_fmt_numeric, detail::enable_if_t::value>> { + static constexpr bool value = true; + static constexpr int index = is_fmt_numeric::index + 3; +}; + +template class type_caster> { +public: + bool load(handle src, bool convert) { + if (!src) + return false; + if (!convert && !PyComplex_Check(src.ptr())) + return false; + Py_complex result = PyComplex_AsCComplex(src.ptr()); + if (result.real == -1.0 && PyErr_Occurred()) { + PyErr_Clear(); + return false; + } + value = std::complex((T) result.real, (T) result.imag); + return true; + } + + static handle cast(const std::complex &src, return_value_policy /* policy */, handle /* parent */) { + return PyComplex_FromDoubles((double) src.real(), (double) src.imag()); + } + + PYBIND11_TYPE_CASTER(std::complex, _("complex")); +}; +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/class.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/class.h new file mode 100644 index 0000000000000000000000000000000000000000..edfa7de68c0177c37c9eb958bf473398d37c1d8f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/class.h @@ -0,0 +1,639 @@ +/* + pybind11/detail/class.h: Python C API implementation details for py::class_ + + Copyright (c) 2017 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "../attr.h" +#include "../options.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +#if PY_VERSION_HEX >= 0x03030000 +# define PYBIND11_BUILTIN_QUALNAME +# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) +#else +// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type +// signatures; in 3.3+ this macro expands to nothing: +# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) setattr((PyObject *) obj, "__qualname__", nameobj) +#endif + +inline PyTypeObject *type_incref(PyTypeObject *type) { + Py_INCREF(type); + return type; +} + +#if !defined(PYPY_VERSION) + +/// `pybind11_static_property.__get__()`: Always pass the class instead of the instance. +extern "C" inline PyObject *pybind11_static_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) { + return PyProperty_Type.tp_descr_get(self, cls, cls); +} + +/// `pybind11_static_property.__set__()`: Just like the above `__get__()`. +extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObject *value) { + PyObject *cls = PyType_Check(obj) ? obj : (PyObject *) Py_TYPE(obj); + return PyProperty_Type.tp_descr_set(self, cls, value); +} + +/** A `static_property` is the same as a `property` but the `__get__()` and `__set__()` + methods are modified to always use the object type instead of a concrete instance. + Return value: New reference. */ +inline PyTypeObject *make_static_property_type() { + constexpr auto *name = "pybind11_static_property"; + auto name_obj = reinterpret_steal(PYBIND11_FROM_STRING(name)); + + /* Danger zone: from now (and until PyType_Ready), make sure to + issue no Python C API calls which could potentially invoke the + garbage collector (the GC will call type_traverse(), which will in + turn find the newly constructed type in an invalid state) */ + auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0); + if (!heap_type) + pybind11_fail("make_static_property_type(): error allocating type!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = name; + type->tp_base = type_incref(&PyProperty_Type); + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + type->tp_descr_get = pybind11_static_get; + type->tp_descr_set = pybind11_static_set; + + if (PyType_Ready(type) < 0) + pybind11_fail("make_static_property_type(): failure in PyType_Ready()!"); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); + + return type; +} + +#else // PYPY + +/** PyPy has some issues with the above C API, so we evaluate Python code instead. + This function will only be called once so performance isn't really a concern. + Return value: New reference. */ +inline PyTypeObject *make_static_property_type() { + auto d = dict(); + PyObject *result = PyRun_String(R"(\ + class pybind11_static_property(property): + def __get__(self, obj, cls): + return property.__get__(self, cls, cls) + + def __set__(self, obj, value): + cls = obj if isinstance(obj, type) else type(obj) + property.__set__(self, cls, value) + )", Py_file_input, d.ptr(), d.ptr() + ); + if (result == nullptr) + throw error_already_set(); + Py_DECREF(result); + return (PyTypeObject *) d["pybind11_static_property"].cast().release().ptr(); +} + +#endif // PYPY + +/** Types with static properties need to handle `Type.static_prop = x` in a specific way. + By default, Python replaces the `static_property` itself, but for wrapped C++ types + we need to call `static_property.__set__()` in order to propagate the new value to + the underlying C++ data structure. */ +extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyObject* value) { + // Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw + // descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`). + PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name); + + // The following assignment combinations are possible: + // 1. `Type.static_prop = value` --> descr_set: `Type.static_prop.__set__(value)` + // 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop` + // 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment + const auto static_prop = (PyObject *) get_internals().static_property_type; + const auto call_descr_set = descr && PyObject_IsInstance(descr, static_prop) + && !PyObject_IsInstance(value, static_prop); + if (call_descr_set) { + // Call `static_property.__set__()` instead of replacing the `static_property`. +#if !defined(PYPY_VERSION) + return Py_TYPE(descr)->tp_descr_set(descr, obj, value); +#else + if (PyObject *result = PyObject_CallMethod(descr, "__set__", "OO", obj, value)) { + Py_DECREF(result); + return 0; + } else { + return -1; + } +#endif + } else { + // Replace existing attribute. + return PyType_Type.tp_setattro(obj, name, value); + } +} + +#if PY_MAJOR_VERSION >= 3 +/** + * Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing + * methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function, + * when called on a class, or a PyMethod, when called on an instance. Override that behaviour here + * to do a special case bypass for PyInstanceMethod_Types. + */ +extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name) { + PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name); + if (descr && PyInstanceMethod_Check(descr)) { + Py_INCREF(descr); + return descr; + } + else { + return PyType_Type.tp_getattro(obj, name); + } +} +#endif + +/** This metaclass is assigned by default to all pybind11 types and is required in order + for static properties to function correctly. Users may override this using `py::metaclass`. + Return value: New reference. */ +inline PyTypeObject* make_default_metaclass() { + constexpr auto *name = "pybind11_type"; + auto name_obj = reinterpret_steal(PYBIND11_FROM_STRING(name)); + + /* Danger zone: from now (and until PyType_Ready), make sure to + issue no Python C API calls which could potentially invoke the + garbage collector (the GC will call type_traverse(), which will in + turn find the newly constructed type in an invalid state) */ + auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0); + if (!heap_type) + pybind11_fail("make_default_metaclass(): error allocating metaclass!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = name; + type->tp_base = type_incref(&PyType_Type); + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + + type->tp_setattro = pybind11_meta_setattro; +#if PY_MAJOR_VERSION >= 3 + type->tp_getattro = pybind11_meta_getattro; +#endif + + if (PyType_Ready(type) < 0) + pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!"); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); + + return type; +} + +/// For multiple inheritance types we need to recursively register/deregister base pointers for any +/// base classes with pointers that are difference from the instance value pointer so that we can +/// correctly recognize an offset base class pointer. This calls a function with any offset base ptrs. +inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo, instance *self, + bool (*f)(void * /*parentptr*/, instance * /*self*/)) { + for (handle h : reinterpret_borrow(tinfo->type->tp_bases)) { + if (auto parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) { + for (auto &c : parent_tinfo->implicit_casts) { + if (c.first == tinfo->cpptype) { + auto *parentptr = c.second(valueptr); + if (parentptr != valueptr) + f(parentptr, self); + traverse_offset_bases(parentptr, parent_tinfo, self, f); + break; + } + } + } + } +} + +inline bool register_instance_impl(void *ptr, instance *self) { + get_internals().registered_instances.emplace(ptr, self); + return true; // unused, but gives the same signature as the deregister func +} +inline bool deregister_instance_impl(void *ptr, instance *self) { + auto ®istered_instances = get_internals().registered_instances; + auto range = registered_instances.equal_range(ptr); + for (auto it = range.first; it != range.second; ++it) { + if (Py_TYPE(self) == Py_TYPE(it->second)) { + registered_instances.erase(it); + return true; + } + } + return false; +} + +inline void register_instance(instance *self, void *valptr, const type_info *tinfo) { + register_instance_impl(valptr, self); + if (!tinfo->simple_ancestors) + traverse_offset_bases(valptr, tinfo, self, register_instance_impl); +} + +inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) { + bool ret = deregister_instance_impl(valptr, self); + if (!tinfo->simple_ancestors) + traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl); + return ret; +} + +/// Instance creation function for all pybind11 types. It allocates the internal instance layout for +/// holding C++ objects and holders. Allocation is done lazily (the first time the instance is cast +/// to a reference or pointer), and initialization is done by an `__init__` function. +inline PyObject *make_new_instance(PyTypeObject *type) { +#if defined(PYPY_VERSION) + // PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first inherited + // object is a a plain Python type (i.e. not derived from an extension type). Fix it. + ssize_t instance_size = static_cast(sizeof(instance)); + if (type->tp_basicsize < instance_size) { + type->tp_basicsize = instance_size; + } +#endif + PyObject *self = type->tp_alloc(type, 0); + auto inst = reinterpret_cast(self); + // Allocate the value/holder internals: + inst->allocate_layout(); + + inst->owned = true; + + return self; +} + +/// Instance creation function for all pybind11 types. It only allocates space for the +/// C++ object, but doesn't call the constructor -- an `__init__` function must do that. +extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *) { + return make_new_instance(type); +} + +/// An `__init__` function constructs the C++ object. Users should provide at least one +/// of these using `py::init` or directly with `.def(__init__, ...)`. Otherwise, the +/// following default function will be used which simply throws an exception. +extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) { + PyTypeObject *type = Py_TYPE(self); + std::string msg; +#if defined(PYPY_VERSION) + msg += handle((PyObject *) type).attr("__module__").cast() + "."; +#endif + msg += type->tp_name; + msg += ": No constructor defined!"; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return -1; +} + +inline void add_patient(PyObject *nurse, PyObject *patient) { + auto &internals = get_internals(); + auto instance = reinterpret_cast(nurse); + instance->has_patients = true; + Py_INCREF(patient); + internals.patients[nurse].push_back(patient); +} + +inline void clear_patients(PyObject *self) { + auto instance = reinterpret_cast(self); + auto &internals = get_internals(); + auto pos = internals.patients.find(self); + assert(pos != internals.patients.end()); + // Clearing the patients can cause more Python code to run, which + // can invalidate the iterator. Extract the vector of patients + // from the unordered_map first. + auto patients = std::move(pos->second); + internals.patients.erase(pos); + instance->has_patients = false; + for (PyObject *&patient : patients) + Py_CLEAR(patient); +} + +/// Clears all internal data from the instance and removes it from registered instances in +/// preparation for deallocation. +inline void clear_instance(PyObject *self) { + auto instance = reinterpret_cast(self); + + // Deallocate any values/holders, if present: + for (auto &v_h : values_and_holders(instance)) { + if (v_h) { + + // We have to deregister before we call dealloc because, for virtual MI types, we still + // need to be able to get the parent pointers. + if (v_h.instance_registered() && !deregister_instance(instance, v_h.value_ptr(), v_h.type)) + pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!"); + + if (instance->owned || v_h.holder_constructed()) + v_h.type->dealloc(v_h); + } + } + // Deallocate the value/holder layout internals: + instance->deallocate_layout(); + + if (instance->weakrefs) + PyObject_ClearWeakRefs(self); + + PyObject **dict_ptr = _PyObject_GetDictPtr(self); + if (dict_ptr) + Py_CLEAR(*dict_ptr); + + if (instance->has_patients) + clear_patients(self); +} + +/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc` +/// to destroy the C++ object itself, while the rest is Python bookkeeping. +extern "C" inline void pybind11_object_dealloc(PyObject *self) { + clear_instance(self); + + auto type = Py_TYPE(self); + type->tp_free(self); + +#if PY_VERSION_HEX < 0x03080000 + // `type->tp_dealloc != pybind11_object_dealloc` means that we're being called + // as part of a derived type's dealloc, in which case we're not allowed to decref + // the type here. For cross-module compatibility, we shouldn't compare directly + // with `pybind11_object_dealloc`, but with the common one stashed in internals. + auto pybind11_object_type = (PyTypeObject *) get_internals().instance_base; + if (type->tp_dealloc == pybind11_object_type->tp_dealloc) + Py_DECREF(type); +#else + // This was not needed before Python 3.8 (Python issue 35810) + // https://github.com/pybind/pybind11/issues/1946 + Py_DECREF(type); +#endif +} + +/** Create the type which can be used as a common base for all classes. This is + needed in order to satisfy Python's requirements for multiple inheritance. + Return value: New reference. */ +inline PyObject *make_object_base_type(PyTypeObject *metaclass) { + constexpr auto *name = "pybind11_object"; + auto name_obj = reinterpret_steal(PYBIND11_FROM_STRING(name)); + + /* Danger zone: from now (and until PyType_Ready), make sure to + issue no Python C API calls which could potentially invoke the + garbage collector (the GC will call type_traverse(), which will in + turn find the newly constructed type in an invalid state) */ + auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0); + if (!heap_type) + pybind11_fail("make_object_base_type(): error allocating type!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = name; + type->tp_base = type_incref(&PyBaseObject_Type); + type->tp_basicsize = static_cast(sizeof(instance)); + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + + type->tp_new = pybind11_object_new; + type->tp_init = pybind11_object_init; + type->tp_dealloc = pybind11_object_dealloc; + + /* Support weak references (needed for the keep_alive feature) */ + type->tp_weaklistoffset = offsetof(instance, weakrefs); + + if (PyType_Ready(type) < 0) + pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string()); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); + + assert(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); + return (PyObject *) heap_type; +} + +/// dynamic_attr: Support for `d = instance.__dict__`. +extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + if (!dict) + dict = PyDict_New(); + Py_XINCREF(dict); + return dict; +} + +/// dynamic_attr: Support for `instance.__dict__ = dict()`. +extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) { + if (!PyDict_Check(new_dict)) { + PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'", + Py_TYPE(new_dict)->tp_name); + return -1; + } + PyObject *&dict = *_PyObject_GetDictPtr(self); + Py_INCREF(new_dict); + Py_CLEAR(dict); + dict = new_dict; + return 0; +} + +/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`. +extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + Py_VISIT(dict); + return 0; +} + +/// dynamic_attr: Allow the GC to clear the dictionary. +extern "C" inline int pybind11_clear(PyObject *self) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + Py_CLEAR(dict); + return 0; +} + +/// Give instances of this type a `__dict__` and opt into garbage collection. +inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) { + auto type = &heap_type->ht_type; +#if defined(PYPY_VERSION) + pybind11_fail(std::string(type->tp_name) + ": dynamic attributes are " + "currently not supported in " + "conjunction with PyPy!"); +#endif + type->tp_flags |= Py_TPFLAGS_HAVE_GC; + type->tp_dictoffset = type->tp_basicsize; // place dict at the end + type->tp_basicsize += (ssize_t)sizeof(PyObject *); // and allocate enough space for it + type->tp_traverse = pybind11_traverse; + type->tp_clear = pybind11_clear; + + static PyGetSetDef getset[] = { + {const_cast("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr}, + {nullptr, nullptr, nullptr, nullptr, nullptr} + }; + type->tp_getset = getset; +} + +/// buffer_protocol: Fill in the view as specified by flags. +extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int flags) { + // Look for a `get_buffer` implementation in this type's info or any bases (following MRO). + type_info *tinfo = nullptr; + for (auto type : reinterpret_borrow(Py_TYPE(obj)->tp_mro)) { + tinfo = get_type_info((PyTypeObject *) type.ptr()); + if (tinfo && tinfo->get_buffer) + break; + } + if (view == nullptr || !tinfo || !tinfo->get_buffer) { + if (view) + view->obj = nullptr; + PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error"); + return -1; + } + std::memset(view, 0, sizeof(Py_buffer)); + buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data); + view->obj = obj; + view->ndim = 1; + view->internal = info; + view->buf = info->ptr; + view->itemsize = info->itemsize; + view->len = view->itemsize; + for (auto s : info->shape) + view->len *= s; + view->readonly = info->readonly; + if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) { + if (view) + view->obj = nullptr; + PyErr_SetString(PyExc_BufferError, "Writable buffer requested for readonly storage"); + return -1; + } + if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) + view->format = const_cast(info->format.c_str()); + if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { + view->ndim = (int) info->ndim; + view->strides = &info->strides[0]; + view->shape = &info->shape[0]; + } + Py_INCREF(view->obj); + return 0; +} + +/// buffer_protocol: Release the resources of the buffer. +extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) { + delete (buffer_info *) view->internal; +} + +/// Give this type a buffer interface. +inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) { + heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer; +#if PY_MAJOR_VERSION < 3 + heap_type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; +#endif + + heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer; + heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer; +} + +/** Create a brand new Python type according to the `type_record` specification. + Return value: New reference. */ +inline PyObject* make_new_python_type(const type_record &rec) { + auto name = reinterpret_steal(PYBIND11_FROM_STRING(rec.name)); + + auto qualname = name; + if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) { +#if PY_MAJOR_VERSION >= 3 + qualname = reinterpret_steal( + PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr())); +#else + qualname = str(rec.scope.attr("__qualname__").cast() + "." + rec.name); +#endif + } + + object module; + if (rec.scope) { + if (hasattr(rec.scope, "__module__")) + module = rec.scope.attr("__module__"); + else if (hasattr(rec.scope, "__name__")) + module = rec.scope.attr("__name__"); + } + + auto full_name = c_str( +#if !defined(PYPY_VERSION) + module ? str(module).cast() + "." + rec.name : +#endif + rec.name); + + char *tp_doc = nullptr; + if (rec.doc && options::show_user_defined_docstrings()) { + /* Allocate memory for docstring (using PyObject_MALLOC, since + Python will free this later on) */ + size_t size = strlen(rec.doc) + 1; + tp_doc = (char *) PyObject_MALLOC(size); + memcpy((void *) tp_doc, rec.doc, size); + } + + auto &internals = get_internals(); + auto bases = tuple(rec.bases); + auto base = (bases.size() == 0) ? internals.instance_base + : bases[0].ptr(); + + /* Danger zone: from now (and until PyType_Ready), make sure to + issue no Python C API calls which could potentially invoke the + garbage collector (the GC will call type_traverse(), which will in + turn find the newly constructed type in an invalid state) */ + auto metaclass = rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr() + : internals.default_metaclass; + + auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0); + if (!heap_type) + pybind11_fail(std::string(rec.name) + ": Unable to create type object!"); + + heap_type->ht_name = name.release().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = qualname.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = full_name; + type->tp_doc = tp_doc; + type->tp_base = type_incref((PyTypeObject *)base); + type->tp_basicsize = static_cast(sizeof(instance)); + if (bases.size() > 0) + type->tp_bases = bases.release().ptr(); + + /* Don't inherit base __init__ */ + type->tp_init = pybind11_object_init; + + /* Supported protocols */ + type->tp_as_number = &heap_type->as_number; + type->tp_as_sequence = &heap_type->as_sequence; + type->tp_as_mapping = &heap_type->as_mapping; +#if PY_VERSION_HEX >= 0x03050000 + type->tp_as_async = &heap_type->as_async; +#endif + + /* Flags */ + type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; +#if PY_MAJOR_VERSION < 3 + type->tp_flags |= Py_TPFLAGS_CHECKTYPES; +#endif + + if (rec.dynamic_attr) + enable_dynamic_attributes(heap_type); + + if (rec.buffer_protocol) + enable_buffer_protocol(heap_type); + + if (PyType_Ready(type) < 0) + pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!"); + + assert(rec.dynamic_attr ? PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC) + : !PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); + + /* Register type with the parent scope */ + if (rec.scope) + setattr(rec.scope, rec.name, (PyObject *) type); + else + Py_INCREF(type); // Keep it alive forever (reference leak) + + if (module) // Needed by pydoc + setattr((PyObject *) type, "__module__", module); + + PYBIND11_SET_OLDPY_QUALNAME(type, qualname); + + return (PyObject *) type; +} + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/common.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/common.h new file mode 100644 index 0000000000000000000000000000000000000000..e53f502d6860d5e0dd4acbcc4fd7d61acb1a36be --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/common.h @@ -0,0 +1,820 @@ +/* + pybind11/detail/common.h -- Basic macros + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#if !defined(NAMESPACE_BEGIN) +# define NAMESPACE_BEGIN(name) namespace name { +#endif +#if !defined(NAMESPACE_END) +# define NAMESPACE_END(name) } +#endif + +// Robust support for some features and loading modules compiled against different pybind versions +// requires forcing hidden visibility on pybind code, so we enforce this by setting the attribute on +// the main `pybind11` namespace. +#if !defined(PYBIND11_NAMESPACE) +# ifdef __GNUG__ +# define PYBIND11_NAMESPACE pybind11 __attribute__((visibility("hidden"))) +# else +# define PYBIND11_NAMESPACE pybind11 +# endif +#endif + +#if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER) +# if __cplusplus >= 201402L +# define PYBIND11_CPP14 +# if __cplusplus >= 201703L +# define PYBIND11_CPP17 +# endif +# endif +#elif defined(_MSC_VER) && __cplusplus == 199711L +// MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard is fully implemented) +// Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3 or newer +# if _MSVC_LANG >= 201402L +# define PYBIND11_CPP14 +# if _MSVC_LANG > 201402L && _MSC_VER >= 1910 +# define PYBIND11_CPP17 +# endif +# endif +#endif + +// Compiler version assertions +#if defined(__INTEL_COMPILER) +# if __INTEL_COMPILER < 1700 +# error pybind11 requires Intel C++ compiler v17 or newer +# endif +#elif defined(__clang__) && !defined(__apple_build_version__) +# if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3) +# error pybind11 requires clang 3.3 or newer +# endif +#elif defined(__clang__) +// Apple changes clang version macros to its Xcode version; the first Xcode release based on +// (upstream) clang 3.3 was Xcode 5: +# if __clang_major__ < 5 +# error pybind11 requires Xcode/clang 5.0 or newer +# endif +#elif defined(__GNUG__) +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) +# error pybind11 requires gcc 4.8 or newer +# endif +#elif defined(_MSC_VER) +// Pybind hits various compiler bugs in 2015u2 and earlier, and also makes use of some stl features +// (e.g. std::negation) added in 2015u3: +# if _MSC_FULL_VER < 190024210 +# error pybind11 requires MSVC 2015 update 3 or newer +# endif +#endif + +#if !defined(PYBIND11_EXPORT) +# if defined(WIN32) || defined(_WIN32) +# define PYBIND11_EXPORT __declspec(dllexport) +# else +# define PYBIND11_EXPORT __attribute__ ((visibility("default"))) +# endif +#endif + +#if defined(_MSC_VER) +# define PYBIND11_NOINLINE __declspec(noinline) +#else +# define PYBIND11_NOINLINE __attribute__ ((noinline)) +#endif + +#if defined(PYBIND11_CPP14) +# define PYBIND11_DEPRECATED(reason) [[deprecated(reason)]] +#else +# define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason))) +#endif + +#define PYBIND11_VERSION_MAJOR 2 +#define PYBIND11_VERSION_MINOR 5 +#define PYBIND11_VERSION_PATCH 0 + +/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode +#if defined(_MSC_VER) +# if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 4) +# define HAVE_ROUND 1 +# endif +# pragma warning(push) +# pragma warning(disable: 4510 4610 4512 4005) +# if defined(_DEBUG) && !defined(Py_DEBUG) +# define PYBIND11_DEBUG_MARKER +# undef _DEBUG +# endif +#endif + +#include +#include +#include + +/* Python #defines overrides on all sorts of core functions, which + tends to weak havok in C++ codebases that expect these to work + like regular functions (potentially with several overloads) */ +#if defined(isalnum) +# undef isalnum +# undef isalpha +# undef islower +# undef isspace +# undef isupper +# undef tolower +# undef toupper +#endif + +#if defined(copysign) +# undef copysign +#endif + +#if defined(_MSC_VER) +# if defined(PYBIND11_DEBUG_MARKER) +# define _DEBUG +# undef PYBIND11_DEBUG_MARKER +# endif +# pragma warning(pop) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions +#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr) +#define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check +#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION +#define PYBIND11_BYTES_CHECK PyBytes_Check +#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString +#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize +#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize +#define PYBIND11_BYTES_AS_STRING PyBytes_AsString +#define PYBIND11_BYTES_SIZE PyBytes_Size +#define PYBIND11_LONG_CHECK(o) PyLong_Check(o) +#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o) +#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) o) +#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) o) +#define PYBIND11_BYTES_NAME "bytes" +#define PYBIND11_STRING_NAME "str" +#define PYBIND11_SLICE_OBJECT PyObject +#define PYBIND11_FROM_STRING PyUnicode_FromString +#define PYBIND11_STR_TYPE ::pybind11::str +#define PYBIND11_BOOL_ATTR "__bool__" +#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool) +// Providing a separate declaration to make Clang's -Wmissing-prototypes happy +#define PYBIND11_PLUGIN_IMPL(name) \ + extern "C" PYBIND11_EXPORT PyObject *PyInit_##name(); \ + extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() + +#else +#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_) +#define PYBIND11_INSTANCE_METHOD_CHECK PyMethod_Check +#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyMethod_GET_FUNCTION +#define PYBIND11_BYTES_CHECK PyString_Check +#define PYBIND11_BYTES_FROM_STRING PyString_FromString +#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize +#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize +#define PYBIND11_BYTES_AS_STRING PyString_AsString +#define PYBIND11_BYTES_SIZE PyString_Size +#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o)) +#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o)) +#define PYBIND11_LONG_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed. +#define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed. +#define PYBIND11_BYTES_NAME "str" +#define PYBIND11_STRING_NAME "unicode" +#define PYBIND11_SLICE_OBJECT PySliceObject +#define PYBIND11_FROM_STRING PyString_FromString +#define PYBIND11_STR_TYPE ::pybind11::bytes +#define PYBIND11_BOOL_ATTR "__nonzero__" +#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero) +// Providing a separate PyInit decl to make Clang's -Wmissing-prototypes happy +#define PYBIND11_PLUGIN_IMPL(name) \ + static PyObject *pybind11_init_wrapper(); \ + extern "C" PYBIND11_EXPORT void init##name(); \ + extern "C" PYBIND11_EXPORT void init##name() { \ + (void)pybind11_init_wrapper(); \ + } \ + PyObject *pybind11_init_wrapper() +#endif + +#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200 +extern "C" { + struct _Py_atomic_address { void *value; }; + PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current; +} +#endif + +#define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code +#define PYBIND11_STRINGIFY(x) #x +#define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x) +#define PYBIND11_CONCAT(first, second) first##second +#define PYBIND11_ENSURE_INTERNALS_READY \ + pybind11::detail::get_internals(); + +#define PYBIND11_CHECK_PYTHON_VERSION \ + { \ + const char *compiled_ver = PYBIND11_TOSTRING(PY_MAJOR_VERSION) \ + "." PYBIND11_TOSTRING(PY_MINOR_VERSION); \ + const char *runtime_ver = Py_GetVersion(); \ + size_t len = std::strlen(compiled_ver); \ + if (std::strncmp(runtime_ver, compiled_ver, len) != 0 \ + || (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) { \ + PyErr_Format(PyExc_ImportError, \ + "Python version mismatch: module was compiled for Python %s, " \ + "but the interpreter version is incompatible: %s.", \ + compiled_ver, runtime_ver); \ + return nullptr; \ + } \ + } + +#define PYBIND11_CATCH_INIT_EXCEPTIONS \ + catch (pybind11::error_already_set &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } \ + +/** \rst + ***Deprecated in favor of PYBIND11_MODULE*** + + This macro creates the entry point that will be invoked when the Python interpreter + imports a plugin library. Please create a `module` in the function body and return + the pointer to its underlying Python object at the end. + + .. code-block:: cpp + + PYBIND11_PLUGIN(example) { + pybind11::module m("example", "pybind11 example plugin"); + /// Set up bindings here + return m.ptr(); + } +\endrst */ +#define PYBIND11_PLUGIN(name) \ + PYBIND11_DEPRECATED("PYBIND11_PLUGIN is deprecated, use PYBIND11_MODULE") \ + static PyObject *pybind11_init(); \ + PYBIND11_PLUGIN_IMPL(name) { \ + PYBIND11_CHECK_PYTHON_VERSION \ + PYBIND11_ENSURE_INTERNALS_READY \ + try { \ + return pybind11_init(); \ + } PYBIND11_CATCH_INIT_EXCEPTIONS \ + } \ + PyObject *pybind11_init() + +/** \rst + This macro creates the entry point that will be invoked when the Python interpreter + imports an extension module. The module name is given as the fist argument and it + should not be in quotes. The second macro argument defines a variable of type + `py::module` which can be used to initialize the module. + + .. code-block:: cpp + + PYBIND11_MODULE(example, m) { + m.doc() = "pybind11 example module"; + + // Add bindings here + m.def("foo", []() { + return "Hello, World!"; + }); + } +\endrst */ +#define PYBIND11_MODULE(name, variable) \ + static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \ + PYBIND11_PLUGIN_IMPL(name) { \ + PYBIND11_CHECK_PYTHON_VERSION \ + PYBIND11_ENSURE_INTERNALS_READY \ + auto m = pybind11::module(PYBIND11_TOSTRING(name)); \ + try { \ + PYBIND11_CONCAT(pybind11_init_, name)(m); \ + return m.ptr(); \ + } PYBIND11_CATCH_INIT_EXCEPTIONS \ + } \ + void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable) + + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +using ssize_t = Py_ssize_t; +using size_t = std::size_t; + +/// Approach used to cast a previously unknown C++ instance into a Python object +enum class return_value_policy : uint8_t { + /** This is the default return value policy, which falls back to the policy + return_value_policy::take_ownership when the return value is a pointer. + Otherwise, it uses return_value::move or return_value::copy for rvalue + and lvalue references, respectively. See below for a description of what + all of these different policies do. */ + automatic = 0, + + /** As above, but use policy return_value_policy::reference when the return + value is a pointer. This is the default conversion policy for function + arguments when calling Python functions manually from C++ code (i.e. via + handle::operator()). You probably won't need to use this. */ + automatic_reference, + + /** Reference an existing object (i.e. do not create a new copy) and take + ownership. Python will call the destructor and delete operator when the + object’s reference count reaches zero. Undefined behavior ensues when + the C++ side does the same.. */ + take_ownership, + + /** Create a new copy of the returned object, which will be owned by + Python. This policy is comparably safe because the lifetimes of the two + instances are decoupled. */ + copy, + + /** Use std::move to move the return value contents into a new instance + that will be owned by Python. This policy is comparably safe because the + lifetimes of the two instances (move source and destination) are + decoupled. */ + move, + + /** Reference an existing object, but do not take ownership. The C++ side + is responsible for managing the object’s lifetime and deallocating it + when it is no longer used. Warning: undefined behavior will ensue when + the C++ side deletes an object that is still referenced and used by + Python. */ + reference, + + /** This policy only applies to methods and properties. It references the + object without taking ownership similar to the above + return_value_policy::reference policy. In contrast to that policy, the + function or property’s implicit this argument (called the parent) is + considered to be the the owner of the return value (the child). + pybind11 then couples the lifetime of the parent to the child via a + reference relationship that ensures that the parent cannot be garbage + collected while Python is still using the child. More advanced + variations of this scheme are also possible using combinations of + return_value_policy::reference and the keep_alive call policy */ + reference_internal +}; + +NAMESPACE_BEGIN(detail) + +inline static constexpr int log2(size_t n, int k = 0) { return (n <= 1) ? k : log2(n >> 1, k + 1); } + +// Returns the size as a multiple of sizeof(void *), rounded up. +inline static constexpr size_t size_in_ptrs(size_t s) { return 1 + ((s - 1) >> log2(sizeof(void *))); } + +/** + * The space to allocate for simple layout instance holders (see below) in multiple of the size of + * a pointer (e.g. 2 means 16 bytes on 64-bit architectures). The default is the minimum required + * to holder either a std::unique_ptr or std::shared_ptr (which is almost always + * sizeof(std::shared_ptr)). + */ +constexpr size_t instance_simple_holder_in_ptrs() { + static_assert(sizeof(std::shared_ptr) >= sizeof(std::unique_ptr), + "pybind assumes std::shared_ptrs are at least as big as std::unique_ptrs"); + return size_in_ptrs(sizeof(std::shared_ptr)); +} + +// Forward declarations +struct type_info; +struct value_and_holder; + +struct nonsimple_values_and_holders { + void **values_and_holders; + uint8_t *status; +}; + +/// The 'instance' type which needs to be standard layout (need to be able to use 'offsetof') +struct instance { + PyObject_HEAD + /// Storage for pointers and holder; see simple_layout, below, for a description + union { + void *simple_value_holder[1 + instance_simple_holder_in_ptrs()]; + nonsimple_values_and_holders nonsimple; + }; + /// Weak references + PyObject *weakrefs; + /// If true, the pointer is owned which means we're free to manage it with a holder. + bool owned : 1; + /** + * An instance has two possible value/holder layouts. + * + * Simple layout (when this flag is true), means the `simple_value_holder` is set with a pointer + * and the holder object governing that pointer, i.e. [val1*][holder]. This layout is applied + * whenever there is no python-side multiple inheritance of bound C++ types *and* the type's + * holder will fit in the default space (which is large enough to hold either a std::unique_ptr + * or std::shared_ptr). + * + * Non-simple layout applies when using custom holders that require more space than `shared_ptr` + * (which is typically the size of two pointers), or when multiple inheritance is used on the + * python side. Non-simple layout allocates the required amount of memory to have multiple + * bound C++ classes as parents. Under this layout, `nonsimple.values_and_holders` is set to a + * pointer to allocated space of the required space to hold a sequence of value pointers and + * holders followed `status`, a set of bit flags (1 byte each), i.e. + * [val1*][holder1][val2*][holder2]...[bb...] where each [block] is rounded up to a multiple of + * `sizeof(void *)`. `nonsimple.status` is, for convenience, a pointer to the + * beginning of the [bb...] block (but not independently allocated). + * + * Status bits indicate whether the associated holder is constructed (& + * status_holder_constructed) and whether the value pointer is registered (& + * status_instance_registered) in `registered_instances`. + */ + bool simple_layout : 1; + /// For simple layout, tracks whether the holder has been constructed + bool simple_holder_constructed : 1; + /// For simple layout, tracks whether the instance is registered in `registered_instances` + bool simple_instance_registered : 1; + /// If true, get_internals().patients has an entry for this object + bool has_patients : 1; + + /// Initializes all of the above type/values/holders data (but not the instance values themselves) + void allocate_layout(); + + /// Destroys/deallocates all of the above + void deallocate_layout(); + + /// Returns the value_and_holder wrapper for the given type (or the first, if `find_type` + /// omitted). Returns a default-constructed (with `.inst = nullptr`) object on failure if + /// `throw_if_missing` is false. + value_and_holder get_value_and_holder(const type_info *find_type = nullptr, bool throw_if_missing = true); + + /// Bit values for the non-simple status flags + static constexpr uint8_t status_holder_constructed = 1; + static constexpr uint8_t status_instance_registered = 2; +}; + +static_assert(std::is_standard_layout::value, "Internal error: `pybind11::detail::instance` is not standard layout!"); + +/// from __cpp_future__ import (convenient aliases from C++14/17) +#if defined(PYBIND11_CPP14) && (!defined(_MSC_VER) || _MSC_VER >= 1910) +using std::enable_if_t; +using std::conditional_t; +using std::remove_cv_t; +using std::remove_reference_t; +#else +template using enable_if_t = typename std::enable_if::type; +template using conditional_t = typename std::conditional::type; +template using remove_cv_t = typename std::remove_cv::type; +template using remove_reference_t = typename std::remove_reference::type; +#endif + +/// Index sequences +#if defined(PYBIND11_CPP14) +using std::index_sequence; +using std::make_index_sequence; +#else +template struct index_sequence { }; +template struct make_index_sequence_impl : make_index_sequence_impl { }; +template struct make_index_sequence_impl <0, S...> { typedef index_sequence type; }; +template using make_index_sequence = typename make_index_sequence_impl::type; +#endif + +/// Make an index sequence of the indices of true arguments +template struct select_indices_impl { using type = ISeq; }; +template struct select_indices_impl, I, B, Bs...> + : select_indices_impl, index_sequence>, I + 1, Bs...> {}; +template using select_indices = typename select_indices_impl, 0, Bs...>::type; + +/// Backports of std::bool_constant and std::negation to accommodate older compilers +template using bool_constant = std::integral_constant; +template struct negation : bool_constant { }; + +template struct void_t_impl { using type = void; }; +template using void_t = typename void_t_impl::type; + +/// Compile-time all/any/none of that check the boolean value of all template types +#if defined(__cpp_fold_expressions) && !(defined(_MSC_VER) && (_MSC_VER < 1916)) +template using all_of = bool_constant<(Ts::value && ...)>; +template using any_of = bool_constant<(Ts::value || ...)>; +#elif !defined(_MSC_VER) +template struct bools {}; +template using all_of = std::is_same< + bools, + bools>; +template using any_of = negation...>>; +#else +// MSVC has trouble with the above, but supports std::conjunction, which we can use instead (albeit +// at a slight loss of compilation efficiency). +template using all_of = std::conjunction; +template using any_of = std::disjunction; +#endif +template using none_of = negation>; + +template class... Predicates> using satisfies_all_of = all_of...>; +template class... Predicates> using satisfies_any_of = any_of...>; +template class... Predicates> using satisfies_none_of = none_of...>; + +/// Strip the class from a method type +template struct remove_class { }; +template struct remove_class { typedef R type(A...); }; +template struct remove_class { typedef R type(A...); }; + +/// Helper template to strip away type modifiers +template struct intrinsic_type { typedef T type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template using intrinsic_t = typename intrinsic_type::type; + +/// Helper type to replace 'void' in some expressions +struct void_type { }; + +/// Helper template which holds a list of types +template struct type_list { }; + +/// Compile-time integer sum +#ifdef __cpp_fold_expressions +template constexpr size_t constexpr_sum(Ts... ns) { return (0 + ... + size_t{ns}); } +#else +constexpr size_t constexpr_sum() { return 0; } +template +constexpr size_t constexpr_sum(T n, Ts... ns) { return size_t{n} + constexpr_sum(ns...); } +#endif + +NAMESPACE_BEGIN(constexpr_impl) +/// Implementation details for constexpr functions +constexpr int first(int i) { return i; } +template +constexpr int first(int i, T v, Ts... vs) { return v ? i : first(i + 1, vs...); } + +constexpr int last(int /*i*/, int result) { return result; } +template +constexpr int last(int i, int result, T v, Ts... vs) { return last(i + 1, v ? i : result, vs...); } +NAMESPACE_END(constexpr_impl) + +/// Return the index of the first type in Ts which satisfies Predicate. Returns sizeof...(Ts) if +/// none match. +template class Predicate, typename... Ts> +constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate::value...); } + +/// Return the index of the last type in Ts which satisfies Predicate, or -1 if none match. +template class Predicate, typename... Ts> +constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate::value...); } + +/// Return the Nth element from the parameter pack +template +struct pack_element { using type = typename pack_element::type; }; +template +struct pack_element<0, T, Ts...> { using type = T; }; + +/// Return the one and only type which matches the predicate, or Default if none match. +/// If more than one type matches the predicate, fail at compile-time. +template class Predicate, typename Default, typename... Ts> +struct exactly_one { + static constexpr auto found = constexpr_sum(Predicate::value...); + static_assert(found <= 1, "Found more than one type matching the predicate"); + + static constexpr auto index = found ? constexpr_first() : 0; + using type = conditional_t::type, Default>; +}; +template class P, typename Default> +struct exactly_one { using type = Default; }; + +template class Predicate, typename Default, typename... Ts> +using exactly_one_t = typename exactly_one::type; + +/// Defer the evaluation of type T until types Us are instantiated +template struct deferred_type { using type = T; }; +template using deferred_t = typename deferred_type::type; + +/// Like is_base_of, but requires a strict base (i.e. `is_strict_base_of::value == false`, +/// unlike `std::is_base_of`) +template using is_strict_base_of = bool_constant< + std::is_base_of::value && !std::is_same::value>; + +/// Like is_base_of, but also requires that the base type is accessible (i.e. that a Derived pointer +/// can be converted to a Base pointer) +template using is_accessible_base_of = bool_constant< + std::is_base_of::value && std::is_convertible::value>; + +template class Base> +struct is_template_base_of_impl { + template static std::true_type check(Base *); + static std::false_type check(...); +}; + +/// Check if a template is the base of a type. For example: +/// `is_template_base_of` is true if `struct T : Base {}` where U can be anything +template class Base, typename T> +#if !defined(_MSC_VER) +using is_template_base_of = decltype(is_template_base_of_impl::check((intrinsic_t*)nullptr)); +#else // MSVC2015 has trouble with decltype in template aliases +struct is_template_base_of : decltype(is_template_base_of_impl::check((intrinsic_t*)nullptr)) { }; +#endif + +/// Check if T is an instantiation of the template `Class`. For example: +/// `is_instantiation` is true if `T == shared_ptr` where U can be anything. +template class Class, typename T> +struct is_instantiation : std::false_type { }; +template class Class, typename... Us> +struct is_instantiation> : std::true_type { }; + +/// Check if T is std::shared_ptr where U can be anything +template using is_shared_ptr = is_instantiation; + +/// Check if T looks like an input iterator +template struct is_input_iterator : std::false_type {}; +template +struct is_input_iterator()), decltype(++std::declval())>> + : std::true_type {}; + +template using is_function_pointer = bool_constant< + std::is_pointer::value && std::is_function::type>::value>; + +template struct strip_function_object { + using type = typename remove_class::type; +}; + +// Extracts the function signature from a function, function pointer or lambda. +template > +using function_signature_t = conditional_t< + std::is_function::value, + F, + typename conditional_t< + std::is_pointer::value || std::is_member_pointer::value, + std::remove_pointer, + strip_function_object + >::type +>; + +/// Returns true if the type looks like a lambda: that is, isn't a function, pointer or member +/// pointer. Note that this can catch all sorts of other things, too; this is intended to be used +/// in a place where passing a lambda makes sense. +template using is_lambda = satisfies_none_of, + std::is_function, std::is_pointer, std::is_member_pointer>; + +/// Ignore that a variable is unused in compiler warnings +inline void ignore_unused(const int *) { } + +/// Apply a function over each element of a parameter pack +#ifdef __cpp_fold_expressions +#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) (((PATTERN), void()), ...) +#else +using expand_side_effects = bool[]; +#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) pybind11::detail::expand_side_effects{ ((PATTERN), void(), false)..., false } +#endif + +NAMESPACE_END(detail) + +/// C++ bindings of builtin Python exceptions +class builtin_exception : public std::runtime_error { +public: + using std::runtime_error::runtime_error; + /// Set the error using the Python C API + virtual void set_error() const = 0; +}; + +#define PYBIND11_RUNTIME_EXCEPTION(name, type) \ + class name : public builtin_exception { public: \ + using builtin_exception::builtin_exception; \ + name() : name("") { } \ + void set_error() const override { PyErr_SetString(type, what()); } \ + }; + +PYBIND11_RUNTIME_EXCEPTION(stop_iteration, PyExc_StopIteration) +PYBIND11_RUNTIME_EXCEPTION(index_error, PyExc_IndexError) +PYBIND11_RUNTIME_EXCEPTION(key_error, PyExc_KeyError) +PYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError) +PYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError) +PYBIND11_RUNTIME_EXCEPTION(buffer_error, PyExc_BufferError) +PYBIND11_RUNTIME_EXCEPTION(import_error, PyExc_ImportError) +PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error +PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally + +[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); } +[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); } + +template struct format_descriptor { }; + +NAMESPACE_BEGIN(detail) +// Returns the index of the given type in the type char array below, and in the list in numpy.h +// The order here is: bool; 8 ints ((signed,unsigned)x(8,16,32,64)bits); float,double,long double; +// complex float,double,long double. Note that the long double types only participate when long +// double is actually longer than double (it isn't under MSVC). +// NB: not only the string below but also complex.h and numpy.h rely on this order. +template struct is_fmt_numeric { static constexpr bool value = false; }; +template struct is_fmt_numeric::value>> { + static constexpr bool value = true; + static constexpr int index = std::is_same::value ? 0 : 1 + ( + std::is_integral::value ? detail::log2(sizeof(T))*2 + std::is_unsigned::value : 8 + ( + std::is_same::value ? 1 : std::is_same::value ? 2 : 0)); +}; +NAMESPACE_END(detail) + +template struct format_descriptor::value>> { + static constexpr const char c = "?bBhHiIqQfdg"[detail::is_fmt_numeric::index]; + static constexpr const char value[2] = { c, '\0' }; + static std::string format() { return std::string(1, c); } +}; + +#if !defined(PYBIND11_CPP17) + +template constexpr const char format_descriptor< + T, detail::enable_if_t::value>>::value[2]; + +#endif + +/// RAII wrapper that temporarily clears any Python error state +struct error_scope { + PyObject *type, *value, *trace; + error_scope() { PyErr_Fetch(&type, &value, &trace); } + ~error_scope() { PyErr_Restore(type, value, trace); } +}; + +/// Dummy destructor wrapper that can be used to expose classes with a private destructor +struct nodelete { template void operator()(T*) { } }; + +NAMESPACE_BEGIN(detail) +template +struct overload_cast_impl { + constexpr overload_cast_impl() {} // MSVC 2015 needs this + + template + constexpr auto operator()(Return (*pf)(Args...)) const noexcept + -> decltype(pf) { return pf; } + + template + constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept + -> decltype(pmf) { return pmf; } + + template + constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept + -> decltype(pmf) { return pmf; } +}; +NAMESPACE_END(detail) + +// overload_cast requires variable templates: C++14 +#if defined(PYBIND11_CPP14) +#define PYBIND11_OVERLOAD_CAST 1 +/// Syntax sugar for resolving overloaded function pointers: +/// - regular: static_cast(&Class::func) +/// - sweet: overload_cast(&Class::func) +template +static constexpr detail::overload_cast_impl overload_cast = {}; +// MSVC 2015 only accepts this particular initialization syntax for this variable template. +#endif + +/// Const member function selector for overload_cast +/// - regular: static_cast(&Class::func) +/// - sweet: overload_cast(&Class::func, const_) +static constexpr auto const_ = std::true_type{}; + +#if !defined(PYBIND11_CPP14) // no overload_cast: providing something that static_assert-fails: +template struct overload_cast { + static_assert(detail::deferred_t::value, + "pybind11::overload_cast<...> requires compiling in C++14 mode"); +}; +#endif // overload_cast + +NAMESPACE_BEGIN(detail) + +// Adaptor for converting arbitrary container arguments into a vector; implicitly convertible from +// any standard container (or C-style array) supporting std::begin/std::end, any singleton +// arithmetic type (if T is arithmetic), or explicitly constructible from an iterator pair. +template +class any_container { + std::vector v; +public: + any_container() = default; + + // Can construct from a pair of iterators + template ::value>> + any_container(It first, It last) : v(first, last) { } + + // Implicit conversion constructor from any arbitrary container type with values convertible to T + template ())), T>::value>> + any_container(const Container &c) : any_container(std::begin(c), std::end(c)) { } + + // initializer_list's aren't deducible, so don't get matched by the above template; we need this + // to explicitly allow implicit conversion from one: + template ::value>> + any_container(const std::initializer_list &c) : any_container(c.begin(), c.end()) { } + + // Avoid copying if given an rvalue vector of the correct type. + any_container(std::vector &&v) : v(std::move(v)) { } + + // Moves the vector out of an rvalue any_container + operator std::vector &&() && { return std::move(v); } + + // Dereferencing obtains a reference to the underlying vector + std::vector &operator*() { return v; } + const std::vector &operator*() const { return v; } + + // -> lets you call methods on the underlying vector + std::vector *operator->() { return &v; } + const std::vector *operator->() const { return &v; } +}; + +NAMESPACE_END(detail) + + + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/descr.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/descr.h new file mode 100644 index 0000000000000000000000000000000000000000..8d404e534694750c61541edbdd4d3bf20daf0c61 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/descr.h @@ -0,0 +1,100 @@ +/* + pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "common.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +#if !defined(_MSC_VER) +# define PYBIND11_DESCR_CONSTEXPR static constexpr +#else +# define PYBIND11_DESCR_CONSTEXPR const +#endif + +/* Concatenate type signatures at compile time */ +template +struct descr { + char text[N + 1]; + + constexpr descr() : text{'\0'} { } + constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence()) { } + + template + constexpr descr(char const (&s)[N+1], index_sequence) : text{s[Is]..., '\0'} { } + + template + constexpr descr(char c, Chars... cs) : text{c, static_cast(cs)..., '\0'} { } + + static constexpr std::array types() { + return {{&typeid(Ts)..., nullptr}}; + } +}; + +template +constexpr descr plus_impl(const descr &a, const descr &b, + index_sequence, index_sequence) { + return {a.text[Is1]..., b.text[Is2]...}; +} + +template +constexpr descr operator+(const descr &a, const descr &b) { + return plus_impl(a, b, make_index_sequence(), make_index_sequence()); +} + +template +constexpr descr _(char const(&text)[N]) { return descr(text); } +constexpr descr<0> _(char const(&)[1]) { return {}; } + +template struct int_to_str : int_to_str { }; +template struct int_to_str<0, Digits...> { + static constexpr auto digits = descr(('0' + Digits)...); +}; + +// Ternary description (like std::conditional) +template +constexpr enable_if_t> _(char const(&text1)[N1], char const(&)[N2]) { + return _(text1); +} +template +constexpr enable_if_t> _(char const(&)[N1], char const(&text2)[N2]) { + return _(text2); +} + +template +constexpr enable_if_t _(const T1 &d, const T2 &) { return d; } +template +constexpr enable_if_t _(const T1 &, const T2 &d) { return d; } + +template auto constexpr _() -> decltype(int_to_str::digits) { + return int_to_str::digits; +} + +template constexpr descr<1, Type> _() { return {'%'}; } + +constexpr descr<0> concat() { return {}; } + +template +constexpr descr concat(const descr &descr) { return descr; } + +template +constexpr auto concat(const descr &d, const Args &...args) + -> decltype(std::declval>() + concat(args...)) { + return d + _(", ") + concat(args...); +} + +template +constexpr descr type_descr(const descr &descr) { + return _("{") + descr + _("}"); +} + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/init.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/init.h new file mode 100644 index 0000000000000000000000000000000000000000..acfe00bdb702e2e64e27d62342a80031d5105cd3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/init.h @@ -0,0 +1,335 @@ +/* + pybind11/detail/init.h: init factory function implementation and support code. + + Copyright (c) 2017 Jason Rhinelander + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "class.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +template <> +class type_caster { +public: + bool load(handle h, bool) { + value = reinterpret_cast(h.ptr()); + return true; + } + + template using cast_op_type = value_and_holder &; + operator value_and_holder &() { return *value; } + static constexpr auto name = _(); + +private: + value_and_holder *value = nullptr; +}; + +NAMESPACE_BEGIN(initimpl) + +inline void no_nullptr(void *ptr) { + if (!ptr) throw type_error("pybind11::init(): factory function returned nullptr"); +} + +// Implementing functions for all forms of py::init<...> and py::init(...) +template using Cpp = typename Class::type; +template using Alias = typename Class::type_alias; +template using Holder = typename Class::holder_type; + +template using is_alias_constructible = std::is_constructible, Cpp &&>; + +// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance. +template = 0> +bool is_alias(Cpp *ptr) { + return dynamic_cast *>(ptr) != nullptr; +} +// Failing fallback version of the above for a no-alias class (always returns false) +template +constexpr bool is_alias(void *) { return false; } + +// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall +// back to brace aggregate initiailization so that for aggregate initialization can be used with +// py::init, e.g. `py::init` to initialize a `struct T { int a; int b; }`. For +// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually +// works, but will not do the expected thing when `T` has an `initializer_list` constructor). +template ::value, int> = 0> +inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward(args)...); } +template ::value, int> = 0> +inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward(args)...}; } + +// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with +// an alias to provide only a single Cpp factory function as long as the Alias can be +// constructed from an rvalue reference of the base Cpp type. This means that Alias classes +// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to +// inherit all the base class constructors. +template +void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/, + value_and_holder &v_h, Cpp &&base) { + v_h.value_ptr() = new Alias(std::move(base)); +} +template +[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/, + value_and_holder &, Cpp &&) { + throw type_error("pybind11::init(): unable to convert returned instance to required " + "alias class: no `Alias(Class &&)` constructor available"); +} + +// Error-generating fallback for factories that don't match one of the below construction +// mechanisms. +template +void construct(...) { + static_assert(!std::is_same::value /* always false */, + "pybind11::init(): init function must return a compatible pointer, " + "holder, or value"); +} + +// Pointer return v1: the factory function returns a class pointer for a registered class. +// If we don't need an alias (because this class doesn't have one, or because the final type is +// inherited on the Python side) we can simply take over ownership. Otherwise we need to try to +// construct an Alias from the returned base instance. +template +void construct(value_and_holder &v_h, Cpp *ptr, bool need_alias) { + no_nullptr(ptr); + if (Class::has_alias && need_alias && !is_alias(ptr)) { + // We're going to try to construct an alias by moving the cpp type. Whether or not + // that succeeds, we still need to destroy the original cpp pointer (either the + // moved away leftover, if the alias construction works, or the value itself if we + // throw an error), but we can't just call `delete ptr`: it might have a special + // deleter, or might be shared_from_this. So we construct a holder around it as if + // it was a normal instance, then steal the holder away into a local variable; thus + // the holder and destruction happens when we leave the C++ scope, and the holder + // class gets to handle the destruction however it likes. + v_h.value_ptr() = ptr; + v_h.set_instance_registered(true); // To prevent init_instance from registering it + v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder + Holder temp_holder(std::move(v_h.holder>())); // Steal the holder + v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null + v_h.set_instance_registered(false); + + construct_alias_from_cpp(is_alias_constructible{}, v_h, std::move(*ptr)); + } else { + // Otherwise the type isn't inherited, so we don't need an Alias + v_h.value_ptr() = ptr; + } +} + +// Pointer return v2: a factory that always returns an alias instance ptr. We simply take over +// ownership of the pointer. +template = 0> +void construct(value_and_holder &v_h, Alias *alias_ptr, bool) { + no_nullptr(alias_ptr); + v_h.value_ptr() = static_cast *>(alias_ptr); +} + +// Holder return: copy its pointer, and move or copy the returned holder into the new instance's +// holder. This also handles types like std::shared_ptr and std::unique_ptr where T is a +// derived type (through those holder's implicit conversion from derived class holder constructors). +template +void construct(value_and_holder &v_h, Holder holder, bool need_alias) { + auto *ptr = holder_helper>::get(holder); + // If we need an alias, check that the held pointer is actually an alias instance + if (Class::has_alias && need_alias && !is_alias(ptr)) + throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance " + "is not an alias instance"); + + v_h.value_ptr() = ptr; + v_h.type->init_instance(v_h.inst, &holder); +} + +// return-by-value version 1: returning a cpp class by value. If the class has an alias and an +// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct +// the alias from the base when needed (i.e. because of Python-side inheritance). When we don't +// need it, we simply move-construct the cpp value into a new instance. +template +void construct(value_and_holder &v_h, Cpp &&result, bool need_alias) { + static_assert(std::is_move_constructible>::value, + "pybind11::init() return-by-value factory function requires a movable class"); + if (Class::has_alias && need_alias) + construct_alias_from_cpp(is_alias_constructible{}, v_h, std::move(result)); + else + v_h.value_ptr() = new Cpp(std::move(result)); +} + +// return-by-value version 2: returning a value of the alias type itself. We move-construct an +// Alias instance (even if no the python-side inheritance is involved). The is intended for +// cases where Alias initialization is always desired. +template +void construct(value_and_holder &v_h, Alias &&result, bool) { + static_assert(std::is_move_constructible>::value, + "pybind11::init() return-by-alias-value factory function requires a movable alias class"); + v_h.value_ptr() = new Alias(std::move(result)); +} + +// Implementing class for py::init<...>() +template +struct constructor { + template = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } + + template , Args...>::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + if (Py_TYPE(v_h.inst) == v_h.type->type) + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + else + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } + + template , Args...>::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } +}; + +// Implementing class for py::init_alias<...>() +template struct alias_constructor { + template , Args...>::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } +}; + +// Implementation class for py::init(Func) and py::init(Func, AliasFunc) +template , typename = function_signature_t> +struct factory; + +// Specialization for py::init(Func) +template +struct factory { + remove_reference_t class_factory; + + factory(Func &&f) : class_factory(std::forward(f)) { } + + // The given class either has no alias or has no separate alias factory; + // this always constructs the class itself. If the class is registered with an alias + // type and an alias instance is needed (i.e. because the final type is a Python class + // inheriting from the C++ type) the returned value needs to either already be an alias + // instance, or the alias needs to be constructible from a `Class &&` argument. + template + void execute(Class &cl, const Extra &...extra) && { + #if defined(PYBIND11_CPP14) + cl.def("__init__", [func = std::move(class_factory)] + #else + auto &func = class_factory; + cl.def("__init__", [func] + #endif + (value_and_holder &v_h, Args... args) { + construct(v_h, func(std::forward(args)...), + Py_TYPE(v_h.inst) != v_h.type->type); + }, is_new_style_constructor(), extra...); + } +}; + +// Specialization for py::init(Func, AliasFunc) +template +struct factory { + static_assert(sizeof...(CArgs) == sizeof...(AArgs), + "pybind11::init(class_factory, alias_factory): class and alias factories " + "must have identical argument signatures"); + static_assert(all_of...>::value, + "pybind11::init(class_factory, alias_factory): class and alias factories " + "must have identical argument signatures"); + + remove_reference_t class_factory; + remove_reference_t alias_factory; + + factory(CFunc &&c, AFunc &&a) + : class_factory(std::forward(c)), alias_factory(std::forward(a)) { } + + // The class factory is called when the `self` type passed to `__init__` is the direct + // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype. + template + void execute(Class &cl, const Extra&... extra) && { + static_assert(Class::has_alias, "The two-argument version of `py::init()` can " + "only be used if the class has an alias"); + #if defined(PYBIND11_CPP14) + cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)] + #else + auto &class_func = class_factory; + auto &alias_func = alias_factory; + cl.def("__init__", [class_func, alias_func] + #endif + (value_and_holder &v_h, CArgs... args) { + if (Py_TYPE(v_h.inst) == v_h.type->type) + // If the instance type equals the registered type we don't have inheritance, so + // don't need the alias and can construct using the class function: + construct(v_h, class_func(std::forward(args)...), false); + else + construct(v_h, alias_func(std::forward(args)...), true); + }, is_new_style_constructor(), extra...); + } +}; + +/// Set just the C++ state. Same as `__init__`. +template +void setstate(value_and_holder &v_h, T &&result, bool need_alias) { + construct(v_h, std::forward(result), need_alias); +} + +/// Set both the C++ and Python states +template ::value, int> = 0> +void setstate(value_and_holder &v_h, std::pair &&result, bool need_alias) { + construct(v_h, std::move(result.first), need_alias); + setattr((PyObject *) v_h.inst, "__dict__", result.second); +} + +/// Implementation for py::pickle(GetState, SetState) +template , typename = function_signature_t> +struct pickle_factory; + +template +struct pickle_factory { + static_assert(std::is_same, intrinsic_t>::value, + "The type returned by `__getstate__` must be the same " + "as the argument accepted by `__setstate__`"); + + remove_reference_t get; + remove_reference_t set; + + pickle_factory(Get get, Set set) + : get(std::forward(get)), set(std::forward(set)) { } + + template + void execute(Class &cl, const Extra &...extra) && { + cl.def("__getstate__", std::move(get)); + +#if defined(PYBIND11_CPP14) + cl.def("__setstate__", [func = std::move(set)] +#else + auto &func = set; + cl.def("__setstate__", [func] +#endif + (value_and_holder &v_h, ArgState state) { + setstate(v_h, func(std::forward(state)), + Py_TYPE(v_h.inst) != v_h.type->type); + }, is_new_style_constructor(), extra...); + } +}; + +NAMESPACE_END(initimpl) +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/internals.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/internals.h new file mode 100644 index 0000000000000000000000000000000000000000..6224dfb22632033a67c33ffaa33e09a1d4c842ba --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/internals.h @@ -0,0 +1,349 @@ +/* + pybind11/detail/internals.h: Internal data structure and related functions + + Copyright (c) 2017 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "../pytypes.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) +// Forward declarations +inline PyTypeObject *make_static_property_type(); +inline PyTypeObject *make_default_metaclass(); +inline PyObject *make_object_base_type(PyTypeObject *metaclass); + +// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new +// Thread Specific Storage (TSS) API. +#if PY_VERSION_HEX >= 0x03070000 +# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr +# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key)) +# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value)) +# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr) +# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key) +#else + // Usually an int but a long on Cygwin64 with Python 3.x +# define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0 +# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key)) +# if PY_MAJOR_VERSION < 3 +# define PYBIND11_TLS_DELETE_VALUE(key) \ + PyThread_delete_key_value(key) +# define PYBIND11_TLS_REPLACE_VALUE(key, value) \ + do { \ + PyThread_delete_key_value((key)); \ + PyThread_set_key_value((key), (value)); \ + } while (false) +# else +# define PYBIND11_TLS_DELETE_VALUE(key) \ + PyThread_set_key_value((key), nullptr) +# define PYBIND11_TLS_REPLACE_VALUE(key, value) \ + PyThread_set_key_value((key), (value)) +# endif +# define PYBIND11_TLS_FREE(key) (void)key +#endif + +// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly +// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module +// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under +// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name, +// which works. If not under a known-good stl, provide our own name-based hash and equality +// functions that use the type name. +#if defined(__GLIBCXX__) +inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; } +using type_hash = std::hash; +using type_equal_to = std::equal_to; +#else +inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { + return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; +} + +struct type_hash { + size_t operator()(const std::type_index &t) const { + size_t hash = 5381; + const char *ptr = t.name(); + while (auto c = static_cast(*ptr++)) + hash = (hash * 33) ^ c; + return hash; + } +}; + +struct type_equal_to { + bool operator()(const std::type_index &lhs, const std::type_index &rhs) const { + return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; + } +}; +#endif + +template +using type_map = std::unordered_map; + +struct overload_hash { + inline size_t operator()(const std::pair& v) const { + size_t value = std::hash()(v.first); + value ^= std::hash()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2); + return value; + } +}; + +/// Internal data structure used to track registered instances and types. +/// Whenever binary incompatible changes are made to this structure, +/// `PYBIND11_INTERNALS_VERSION` must be incremented. +struct internals { + type_map registered_types_cpp; // std::type_index -> pybind11's type information + std::unordered_map> registered_types_py; // PyTypeObject* -> base type_info(s) + std::unordered_multimap registered_instances; // void * -> instance* + std::unordered_set, overload_hash> inactive_overload_cache; + type_map> direct_conversions; + std::unordered_map> patients; + std::forward_list registered_exception_translators; + std::unordered_map shared_data; // Custom data to be shared across extensions + std::vector loader_patient_stack; // Used by `loader_life_support` + std::forward_list static_strings; // Stores the std::strings backing detail::c_str() + PyTypeObject *static_property_type; + PyTypeObject *default_metaclass; + PyObject *instance_base; +#if defined(WITH_THREAD) + PYBIND11_TLS_KEY_INIT(tstate); + PyInterpreterState *istate = nullptr; + ~internals() { + // This destructor is called *after* Py_Finalize() in finalize_interpreter(). + // That *SHOULD BE* fine. The following details what happens whe PyThread_tss_free is called. + // PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does nothing. + // PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree. + // PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX). Neither + // of those have anything to do with CPython internals. + // PyMem_RawFree *requires* that the `tstate` be allocated with the CPython allocator. + PYBIND11_TLS_FREE(tstate); + } +#endif +}; + +/// Additional type information which does not fit into the PyTypeObject. +/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`. +struct type_info { + PyTypeObject *type; + const std::type_info *cpptype; + size_t type_size, type_align, holder_size_in_ptrs; + void *(*operator_new)(size_t); + void (*init_instance)(instance *, const void *); + void (*dealloc)(value_and_holder &v_h); + std::vector implicit_conversions; + std::vector> implicit_casts; + std::vector *direct_conversions; + buffer_info *(*get_buffer)(PyObject *, void *) = nullptr; + void *get_buffer_data = nullptr; + void *(*module_local_load)(PyObject *, const type_info *) = nullptr; + /* A simple type never occurs as a (direct or indirect) parent + * of a class that makes use of multiple inheritance */ + bool simple_type : 1; + /* True if there is no multiple inheritance in this type's inheritance tree */ + bool simple_ancestors : 1; + /* for base vs derived holder_type checks */ + bool default_holder : 1; + /* true if this is a type registered with py::module_local */ + bool module_local : 1; +}; + +/// Tracks the `internals` and `type_info` ABI version independent of the main library version +#define PYBIND11_INTERNALS_VERSION 4 + +/// On MSVC, debug and release builds are not ABI-compatible! +#if defined(_MSC_VER) && defined(_DEBUG) +# define PYBIND11_BUILD_TYPE "_debug" +#else +# define PYBIND11_BUILD_TYPE "" +#endif + +/// Let's assume that different compilers are ABI-incompatible. +#if defined(_MSC_VER) +# define PYBIND11_COMPILER_TYPE "_msvc" +#elif defined(__INTEL_COMPILER) +# define PYBIND11_COMPILER_TYPE "_icc" +#elif defined(__clang__) +# define PYBIND11_COMPILER_TYPE "_clang" +#elif defined(__PGI) +# define PYBIND11_COMPILER_TYPE "_pgi" +#elif defined(__MINGW32__) +# define PYBIND11_COMPILER_TYPE "_mingw" +#elif defined(__CYGWIN__) +# define PYBIND11_COMPILER_TYPE "_gcc_cygwin" +#elif defined(__GNUC__) +# define PYBIND11_COMPILER_TYPE "_gcc" +#else +# define PYBIND11_COMPILER_TYPE "_unknown" +#endif + +#if defined(_LIBCPP_VERSION) +# define PYBIND11_STDLIB "_libcpp" +#elif defined(__GLIBCXX__) || defined(__GLIBCPP__) +# define PYBIND11_STDLIB "_libstdcpp" +#else +# define PYBIND11_STDLIB "" +#endif + +/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility. +#if defined(__GXX_ABI_VERSION) +# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION) +#else +# define PYBIND11_BUILD_ABI "" +#endif + +#if defined(WITH_THREAD) +# define PYBIND11_INTERNALS_KIND "" +#else +# define PYBIND11_INTERNALS_KIND "_without_thread" +#endif + +#define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \ + PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" + +#define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \ + PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE "__" + +/// Each module locally stores a pointer to the `internals` data. The data +/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`. +inline internals **&get_internals_pp() { + static internals **internals_pp = nullptr; + return internals_pp; +} + +inline void translate_exception(std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (error_already_set &e) { e.restore(); return; + } catch (const builtin_exception &e) { e.set_error(); return; + } catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return; + } catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return; + } catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::overflow_error &e) { PyErr_SetString(PyExc_OverflowError, e.what()); return; + } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return; + } catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!"); + return; + } +} + +#if !defined(__GLIBCXX__) +inline void translate_local_exception(std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (error_already_set &e) { e.restore(); return; + } catch (const builtin_exception &e) { e.set_error(); return; + } +} +#endif + +/// Return a reference to the current `internals` data +PYBIND11_NOINLINE inline internals &get_internals() { + auto **&internals_pp = get_internals_pp(); + if (internals_pp && *internals_pp) + return **internals_pp; + + // Ensure that the GIL is held since we will need to make Python calls. + // Cannot use py::gil_scoped_acquire here since that constructor calls get_internals. + struct gil_scoped_acquire_local { + gil_scoped_acquire_local() : state (PyGILState_Ensure()) {} + ~gil_scoped_acquire_local() { PyGILState_Release(state); } + const PyGILState_STATE state; + } gil; + + constexpr auto *id = PYBIND11_INTERNALS_ID; + auto builtins = handle(PyEval_GetBuiltins()); + if (builtins.contains(id) && isinstance(builtins[id])) { + internals_pp = static_cast(capsule(builtins[id])); + + // We loaded builtins through python's builtins, which means that our `error_already_set` + // and `builtin_exception` may be different local classes than the ones set up in the + // initial exception translator, below, so add another for our local exception classes. + // + // libstdc++ doesn't require this (types there are identified only by name) +#if !defined(__GLIBCXX__) + (*internals_pp)->registered_exception_translators.push_front(&translate_local_exception); +#endif + } else { + if (!internals_pp) internals_pp = new internals*(); + auto *&internals_ptr = *internals_pp; + internals_ptr = new internals(); +#if defined(WITH_THREAD) + PyEval_InitThreads(); + PyThreadState *tstate = PyThreadState_Get(); + #if PY_VERSION_HEX >= 0x03070000 + internals_ptr->tstate = PyThread_tss_alloc(); + if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate)) + pybind11_fail("get_internals: could not successfully initialize the TSS key!"); + PyThread_tss_set(internals_ptr->tstate, tstate); + #else + internals_ptr->tstate = PyThread_create_key(); + if (internals_ptr->tstate == -1) + pybind11_fail("get_internals: could not successfully initialize the TLS key!"); + PyThread_set_key_value(internals_ptr->tstate, tstate); + #endif + internals_ptr->istate = tstate->interp; +#endif + builtins[id] = capsule(internals_pp); + internals_ptr->registered_exception_translators.push_front(&translate_exception); + internals_ptr->static_property_type = make_static_property_type(); + internals_ptr->default_metaclass = make_default_metaclass(); + internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass); + } + return **internals_pp; +} + +/// Works like `internals.registered_types_cpp`, but for module-local registered types: +inline type_map ®istered_local_types_cpp() { + static type_map locals{}; + return locals; +} + +/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its +/// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only +/// cleared when the program exits or after interpreter shutdown (when embedding), and so are +/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name). +template +const char *c_str(Args &&...args) { + auto &strings = get_internals().static_strings; + strings.emplace_front(std::forward(args)...); + return strings.front().c_str(); +} + +NAMESPACE_END(detail) + +/// Returns a named pointer that is shared among all extension modules (using the same +/// pybind11 version) running in the current interpreter. Names starting with underscores +/// are reserved for internal usage. Returns `nullptr` if no matching entry was found. +inline PYBIND11_NOINLINE void *get_shared_data(const std::string &name) { + auto &internals = detail::get_internals(); + auto it = internals.shared_data.find(name); + return it != internals.shared_data.end() ? it->second : nullptr; +} + +/// Set the shared data that can be later recovered by `get_shared_data()`. +inline PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) { + detail::get_internals().shared_data[name] = data; + return data; +} + +/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if +/// such entry exists. Otherwise, a new object of default-constructible type `T` is +/// added to the shared data under the given name and a reference to it is returned. +template +T &get_or_create_shared_data(const std::string &name) { + auto &internals = detail::get_internals(); + auto it = internals.shared_data.find(name); + T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr); + if (!ptr) { + ptr = new T(); + internals.shared_data[name] = ptr; + } + return *ptr; +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/typeid.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/typeid.h new file mode 100644 index 0000000000000000000000000000000000000000..9c8a4fc69a9760112757a59fd88d237e2831104a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/detail/typeid.h @@ -0,0 +1,55 @@ +/* + pybind11/detail/typeid.h: Compiler-independent access to type identifiers + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include +#include + +#if defined(__GNUG__) +#include +#endif + +#include "common.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) +/// Erase all occurrences of a substring +inline void erase_all(std::string &string, const std::string &search) { + for (size_t pos = 0;;) { + pos = string.find(search, pos); + if (pos == std::string::npos) break; + string.erase(pos, search.length()); + } +} + +PYBIND11_NOINLINE inline void clean_type_id(std::string &name) { +#if defined(__GNUG__) + int status = 0; + std::unique_ptr res { + abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free }; + if (status == 0) + name = res.get(); +#else + detail::erase_all(name, "class "); + detail::erase_all(name, "struct "); + detail::erase_all(name, "enum "); +#endif + detail::erase_all(name, "pybind11::"); +} +NAMESPACE_END(detail) + +/// Return a string representation of a C++ type +template static std::string type_id() { + std::string name(typeid(T).name()); + detail::clean_type_id(name); + return name; +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/eigen.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/eigen.h new file mode 100644 index 0000000000000000000000000000000000000000..d963d9650b66ccda93b4cfd0702beeed37c08dd2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/eigen.h @@ -0,0 +1,607 @@ +/* + pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "numpy.h" + +#if defined(__INTEL_COMPILER) +# pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem) +#elif defined(__GNUG__) || defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +# ifdef __clang__ +// Eigen generates a bunch of implicit-copy-constructor-is-deprecated warnings with -Wdeprecated +// under Clang, so disable that warning here: +# pragma GCC diagnostic ignored "-Wdeprecated" +# endif +# if __GNUC__ >= 7 +# pragma GCC diagnostic ignored "-Wint-in-bool-context" +# endif +#endif + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +# pragma warning(disable: 4996) // warning C4996: std::unary_negate is deprecated in C++17 +#endif + +#include +#include + +// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit +// move constructors that break things. We could detect this an explicitly copy, but an extra copy +// of matrices seems highly undesirable. +static_assert(EIGEN_VERSION_AT_LEAST(3,2,7), "Eigen support in pybind11 requires Eigen >= 3.2.7"); + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides: +using EigenDStride = Eigen::Stride; +template using EigenDRef = Eigen::Ref; +template using EigenDMap = Eigen::Map; + +NAMESPACE_BEGIN(detail) + +#if EIGEN_VERSION_AT_LEAST(3,3,0) +using EigenIndex = Eigen::Index; +#else +using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE; +#endif + +// Matches Eigen::Map, Eigen::Ref, blocks, etc: +template using is_eigen_dense_map = all_of, std::is_base_of, T>>; +template using is_eigen_mutable_map = std::is_base_of, T>; +template using is_eigen_dense_plain = all_of>, is_template_base_of>; +template using is_eigen_sparse = is_template_base_of; +// Test for objects inheriting from EigenBase that aren't captured by the above. This +// basically covers anything that can be assigned to a dense matrix but that don't have a typical +// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and +// SelfAdjointView fall into this category. +template using is_eigen_other = all_of< + is_template_base_of, + negation, is_eigen_dense_plain, is_eigen_sparse>> +>; + +// Captures numpy/eigen conformability status (returned by EigenProps::conformable()): +template struct EigenConformable { + bool conformable = false; + EigenIndex rows = 0, cols = 0; + EigenDStride stride{0, 0}; // Only valid if negativestrides is false! + bool negativestrides = false; // If true, do not use stride! + + EigenConformable(bool fits = false) : conformable{fits} {} + // Matrix type: + EigenConformable(EigenIndex r, EigenIndex c, + EigenIndex rstride, EigenIndex cstride) : + conformable{true}, rows{r}, cols{c} { + // TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747 + if (rstride < 0 || cstride < 0) { + negativestrides = true; + } else { + stride = {EigenRowMajor ? rstride : cstride /* outer stride */, + EigenRowMajor ? cstride : rstride /* inner stride */ }; + } + } + // Vector type: + EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride) + : EigenConformable(r, c, r == 1 ? c*stride : stride, c == 1 ? r : r*stride) {} + + template bool stride_compatible() const { + // To have compatible strides, we need (on both dimensions) one of fully dynamic strides, + // matching strides, or a dimension size of 1 (in which case the stride value is irrelevant) + return + !negativestrides && + (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() || + (EigenRowMajor ? cols : rows) == 1) && + (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() || + (EigenRowMajor ? rows : cols) == 1); + } + operator bool() const { return conformable; } +}; + +template struct eigen_extract_stride { using type = Type; }; +template +struct eigen_extract_stride> { using type = StrideType; }; +template +struct eigen_extract_stride> { using type = StrideType; }; + +// Helper struct for extracting information from an Eigen type +template struct EigenProps { + using Type = Type_; + using Scalar = typename Type::Scalar; + using StrideType = typename eigen_extract_stride::type; + static constexpr EigenIndex + rows = Type::RowsAtCompileTime, + cols = Type::ColsAtCompileTime, + size = Type::SizeAtCompileTime; + static constexpr bool + row_major = Type::IsRowMajor, + vector = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1 + fixed_rows = rows != Eigen::Dynamic, + fixed_cols = cols != Eigen::Dynamic, + fixed = size != Eigen::Dynamic, // Fully-fixed size + dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size + + template using if_zero = std::integral_constant; + static constexpr EigenIndex inner_stride = if_zero::value, + outer_stride = if_zero::value; + static constexpr bool dynamic_stride = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic; + static constexpr bool requires_row_major = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1; + static constexpr bool requires_col_major = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1; + + // Takes an input array and determines whether we can make it fit into the Eigen type. If + // the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector + // (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type). + static EigenConformable conformable(const array &a) { + const auto dims = a.ndim(); + if (dims < 1 || dims > 2) + return false; + + if (dims == 2) { // Matrix type: require exact match (or dynamic) + + EigenIndex + np_rows = a.shape(0), + np_cols = a.shape(1), + np_rstride = a.strides(0) / static_cast(sizeof(Scalar)), + np_cstride = a.strides(1) / static_cast(sizeof(Scalar)); + if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols)) + return false; + + return {np_rows, np_cols, np_rstride, np_cstride}; + } + + // Otherwise we're storing an n-vector. Only one of the strides will be used, but whichever + // is used, we want the (single) numpy stride value. + const EigenIndex n = a.shape(0), + stride = a.strides(0) / static_cast(sizeof(Scalar)); + + if (vector) { // Eigen type is a compile-time vector + if (fixed && size != n) + return false; // Vector size mismatch + return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride}; + } + else if (fixed) { + // The type has a fixed size, but is not a vector: abort + return false; + } + else if (fixed_cols) { + // Since this isn't a vector, cols must be != 1. We allow this only if it exactly + // equals the number of elements (rows is Dynamic, and so 1 row is allowed). + if (cols != n) return false; + return {1, n, stride}; + } + else { + // Otherwise it's either fully dynamic, or column dynamic; both become a column vector + if (fixed_rows && rows != n) return false; + return {n, 1, stride}; + } + } + + static constexpr bool show_writeable = is_eigen_dense_map::value && is_eigen_mutable_map::value; + static constexpr bool show_order = is_eigen_dense_map::value; + static constexpr bool show_c_contiguous = show_order && requires_row_major; + static constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major; + + static constexpr auto descriptor = + _("numpy.ndarray[") + npy_format_descriptor::name + + _("[") + _(_<(size_t) rows>(), _("m")) + + _(", ") + _(_<(size_t) cols>(), _("n")) + + _("]") + + // For a reference type (e.g. Ref) we have other constraints that might need to be + // satisfied: writeable=True (for a mutable reference), and, depending on the map's stride + // options, possibly f_contiguous or c_contiguous. We include them in the descriptor output + // to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to + // see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you + // *gave* a numpy.ndarray of the right type and dimensions. + _(", flags.writeable", "") + + _(", flags.c_contiguous", "") + + _(", flags.f_contiguous", "") + + _("]"); +}; + +// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data, +// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array. +template handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) { + constexpr ssize_t elem_size = sizeof(typename props::Scalar); + array a; + if (props::vector) + a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base); + else + a = array({ src.rows(), src.cols() }, { elem_size * src.rowStride(), elem_size * src.colStride() }, + src.data(), base); + + if (!writeable) + array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_; + + return a.release(); +} + +// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that +// reference the Eigen object's data with `base` as the python-registered base class (if omitted, +// the base will be set to None, and lifetime management is up to the caller). The numpy array is +// non-writeable if the given type is const. +template +handle eigen_ref_array(Type &src, handle parent = none()) { + // none here is to get past array's should-we-copy detection, which currently always + // copies when there is no base. Setting the base to None should be harmless. + return eigen_array_cast(src, parent, !std::is_const::value); +} + +// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a numpy +// array that references the encapsulated data with a python-side reference to the capsule to tie +// its destruction to that of any dependent python objects. Const-ness is determined by whether or +// not the Type of the pointer given is const. +template ::value>> +handle eigen_encapsulate(Type *src) { + capsule base(src, [](void *o) { delete static_cast(o); }); + return eigen_ref_array(*src, base); +} + +// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense +// types. +template +struct type_caster::value>> { + using Scalar = typename Type::Scalar; + using props = EigenProps; + + bool load(handle src, bool convert) { + // If we're in no-convert mode, only load if given an array of the correct type + if (!convert && !isinstance>(src)) + return false; + + // Coerce into an array, but don't do type conversion yet; the copy below handles it. + auto buf = array::ensure(src); + + if (!buf) + return false; + + auto dims = buf.ndim(); + if (dims < 1 || dims > 2) + return false; + + auto fits = props::conformable(buf); + if (!fits) + return false; + + // Allocate the new type, then build a numpy reference into it + value = Type(fits.rows, fits.cols); + auto ref = reinterpret_steal(eigen_ref_array(value)); + if (dims == 1) ref = ref.squeeze(); + else if (ref.ndim() == 1) buf = buf.squeeze(); + + int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr()); + + if (result < 0) { // Copy failed! + PyErr_Clear(); + return false; + } + + return true; + } + +private: + + // Cast implementation + template + static handle cast_impl(CType *src, return_value_policy policy, handle parent) { + switch (policy) { + case return_value_policy::take_ownership: + case return_value_policy::automatic: + return eigen_encapsulate(src); + case return_value_policy::move: + return eigen_encapsulate(new CType(std::move(*src))); + case return_value_policy::copy: + return eigen_array_cast(*src); + case return_value_policy::reference: + case return_value_policy::automatic_reference: + return eigen_ref_array(*src); + case return_value_policy::reference_internal: + return eigen_ref_array(*src, parent); + default: + throw cast_error("unhandled return_value_policy: should not happen!"); + }; + } + +public: + + // Normal returned non-reference, non-const value: + static handle cast(Type &&src, return_value_policy /* policy */, handle parent) { + return cast_impl(&src, return_value_policy::move, parent); + } + // If you return a non-reference const, we mark the numpy array readonly: + static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) { + return cast_impl(&src, return_value_policy::move, parent); + } + // lvalue reference return; default (automatic) becomes copy + static handle cast(Type &src, return_value_policy policy, handle parent) { + if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) + policy = return_value_policy::copy; + return cast_impl(&src, policy, parent); + } + // const lvalue reference return; default (automatic) becomes copy + static handle cast(const Type &src, return_value_policy policy, handle parent) { + if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) + policy = return_value_policy::copy; + return cast(&src, policy, parent); + } + // non-const pointer return + static handle cast(Type *src, return_value_policy policy, handle parent) { + return cast_impl(src, policy, parent); + } + // const pointer return + static handle cast(const Type *src, return_value_policy policy, handle parent) { + return cast_impl(src, policy, parent); + } + + static constexpr auto name = props::descriptor; + + operator Type*() { return &value; } + operator Type&() { return value; } + operator Type&&() && { return std::move(value); } + template using cast_op_type = movable_cast_op_type; + +private: + Type value; +}; + +// Base class for casting reference/map/block/etc. objects back to python. +template struct eigen_map_caster { +private: + using props = EigenProps; + +public: + + // Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has + // to stay around), but we'll allow it under the assumption that you know what you're doing (and + // have an appropriate keep_alive in place). We return a numpy array pointing directly at the + // ref's data (The numpy array ends up read-only if the ref was to a const matrix type.) Note + // that this means you need to ensure you don't destroy the object in some other way (e.g. with + // an appropriate keep_alive, or with a reference to a statically allocated matrix). + static handle cast(const MapType &src, return_value_policy policy, handle parent) { + switch (policy) { + case return_value_policy::copy: + return eigen_array_cast(src); + case return_value_policy::reference_internal: + return eigen_array_cast(src, parent, is_eigen_mutable_map::value); + case return_value_policy::reference: + case return_value_policy::automatic: + case return_value_policy::automatic_reference: + return eigen_array_cast(src, none(), is_eigen_mutable_map::value); + default: + // move, take_ownership don't make any sense for a ref/map: + pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type"); + } + } + + static constexpr auto name = props::descriptor; + + // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return + // types but not bound arguments). We still provide them (with an explicitly delete) so that + // you end up here if you try anyway. + bool load(handle, bool) = delete; + operator MapType() = delete; + template using cast_op_type = MapType; +}; + +// We can return any map-like object (but can only load Refs, specialized next): +template struct type_caster::value>> + : eigen_map_caster {}; + +// Loader for Ref<...> arguments. See the documentation for info on how to make this work without +// copying (it requires some extra effort in many cases). +template +struct type_caster< + Eigen::Ref, + enable_if_t>::value> +> : public eigen_map_caster> { +private: + using Type = Eigen::Ref; + using props = EigenProps; + using Scalar = typename props::Scalar; + using MapType = Eigen::Map; + using Array = array_t; + static constexpr bool need_writeable = is_eigen_mutable_map::value; + // Delay construction (these have no default constructor) + std::unique_ptr map; + std::unique_ptr ref; + // Our array. When possible, this is just a numpy array pointing to the source data, but + // sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an incompatible + // layout, or is an array of a type that needs to be converted). Using a numpy temporary + // (rather than an Eigen temporary) saves an extra copy when we need both type conversion and + // storage order conversion. (Note that we refuse to use this temporary copy when loading an + // argument for a Ref with M non-const, i.e. a read-write reference). + Array copy_or_ref; +public: + bool load(handle src, bool convert) { + // First check whether what we have is already an array of the right type. If not, we can't + // avoid a copy (because the copy is also going to do type conversion). + bool need_copy = !isinstance(src); + + EigenConformable fits; + if (!need_copy) { + // We don't need a converting copy, but we also need to check whether the strides are + // compatible with the Ref's stride requirements + Array aref = reinterpret_borrow(src); + + if (aref && (!need_writeable || aref.writeable())) { + fits = props::conformable(aref); + if (!fits) return false; // Incompatible dimensions + if (!fits.template stride_compatible()) + need_copy = true; + else + copy_or_ref = std::move(aref); + } + else { + need_copy = true; + } + } + + if (need_copy) { + // We need to copy: If we need a mutable reference, or we're not supposed to convert + // (either because we're in the no-convert overload pass, or because we're explicitly + // instructed not to copy (via `py::arg().noconvert()`) we have to fail loading. + if (!convert || need_writeable) return false; + + Array copy = Array::ensure(src); + if (!copy) return false; + fits = props::conformable(copy); + if (!fits || !fits.template stride_compatible()) + return false; + copy_or_ref = std::move(copy); + loader_life_support::add_patient(copy_or_ref); + } + + ref.reset(); + map.reset(new MapType(data(copy_or_ref), fits.rows, fits.cols, make_stride(fits.stride.outer(), fits.stride.inner()))); + ref.reset(new Type(*map)); + + return true; + } + + operator Type*() { return ref.get(); } + operator Type&() { return *ref; } + template using cast_op_type = pybind11::detail::cast_op_type<_T>; + +private: + template ::value, int> = 0> + Scalar *data(Array &a) { return a.mutable_data(); } + + template ::value, int> = 0> + const Scalar *data(Array &a) { return a.data(); } + + // Attempt to figure out a constructor of `Stride` that will work. + // If both strides are fixed, use a default constructor: + template using stride_ctor_default = bool_constant< + S::InnerStrideAtCompileTime != Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic && + std::is_default_constructible::value>; + // Otherwise, if there is a two-index constructor, assume it is (outer,inner) like + // Eigen::Stride, and use it: + template using stride_ctor_dual = bool_constant< + !stride_ctor_default::value && std::is_constructible::value>; + // Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use + // it (passing whichever stride is dynamic). + template using stride_ctor_outer = bool_constant< + !any_of, stride_ctor_dual>::value && + S::OuterStrideAtCompileTime == Eigen::Dynamic && S::InnerStrideAtCompileTime != Eigen::Dynamic && + std::is_constructible::value>; + template using stride_ctor_inner = bool_constant< + !any_of, stride_ctor_dual>::value && + S::InnerStrideAtCompileTime == Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic && + std::is_constructible::value>; + + template ::value, int> = 0> + static S make_stride(EigenIndex, EigenIndex) { return S(); } + template ::value, int> = 0> + static S make_stride(EigenIndex outer, EigenIndex inner) { return S(outer, inner); } + template ::value, int> = 0> + static S make_stride(EigenIndex outer, EigenIndex) { return S(outer); } + template ::value, int> = 0> + static S make_stride(EigenIndex, EigenIndex inner) { return S(inner); } + +}; + +// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not +// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout). +// load() is not supported, but we can cast them into the python domain by first copying to a +// regular Eigen::Matrix, then casting that. +template +struct type_caster::value>> { +protected: + using Matrix = Eigen::Matrix; + using props = EigenProps; +public: + static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { + handle h = eigen_encapsulate(new Matrix(src)); + return h; + } + static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); } + + static constexpr auto name = props::descriptor; + + // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return + // types but not bound arguments). We still provide them (with an explicitly delete) so that + // you end up here if you try anyway. + bool load(handle, bool) = delete; + operator Type() = delete; + template using cast_op_type = Type; +}; + +template +struct type_caster::value>> { + typedef typename Type::Scalar Scalar; + typedef remove_reference_t().outerIndexPtr())> StorageIndex; + typedef typename Type::Index Index; + static constexpr bool rowMajor = Type::IsRowMajor; + + bool load(handle src, bool) { + if (!src) + return false; + + auto obj = reinterpret_borrow(src); + object sparse_module = module::import("scipy.sparse"); + object matrix_type = sparse_module.attr( + rowMajor ? "csr_matrix" : "csc_matrix"); + + if (!obj.get_type().is(matrix_type)) { + try { + obj = matrix_type(obj); + } catch (const error_already_set &) { + return false; + } + } + + auto values = array_t((object) obj.attr("data")); + auto innerIndices = array_t((object) obj.attr("indices")); + auto outerIndices = array_t((object) obj.attr("indptr")); + auto shape = pybind11::tuple((pybind11::object) obj.attr("shape")); + auto nnz = obj.attr("nnz").cast(); + + if (!values || !innerIndices || !outerIndices) + return false; + + value = Eigen::MappedSparseMatrix( + shape[0].cast(), shape[1].cast(), nnz, + outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data()); + + return true; + } + + static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { + const_cast(src).makeCompressed(); + + object matrix_type = module::import("scipy.sparse").attr( + rowMajor ? "csr_matrix" : "csc_matrix"); + + array data(src.nonZeros(), src.valuePtr()); + array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr()); + array innerIndices(src.nonZeros(), src.innerIndexPtr()); + + return matrix_type( + std::make_tuple(data, innerIndices, outerIndices), + std::make_pair(src.rows(), src.cols()) + ).release(); + } + + PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[") + + npy_format_descriptor::name + _("]")); +}; + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(__GNUG__) || defined(__clang__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/embed.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/embed.h new file mode 100644 index 0000000000000000000000000000000000000000..f814c783e7b072d93e6d9d098c61e8d7ecc75af8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/embed.h @@ -0,0 +1,202 @@ +/* + pybind11/embed.h: Support for embedding the interpreter + + Copyright (c) 2017 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include "eval.h" + +#if defined(PYPY_VERSION) +# error Embedding the interpreter is not supported with PyPy +#endif + +#if PY_MAJOR_VERSION >= 3 +# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + extern "C" PyObject *pybind11_init_impl_##name(); \ + extern "C" PyObject *pybind11_init_impl_##name() { \ + return pybind11_init_wrapper_##name(); \ + } +#else +# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + extern "C" void pybind11_init_impl_##name(); \ + extern "C" void pybind11_init_impl_##name() { \ + pybind11_init_wrapper_##name(); \ + } +#endif + +/** \rst + Add a new module to the table of builtins for the interpreter. Must be + defined in global scope. The first macro parameter is the name of the + module (without quotes). The second parameter is the variable which will + be used as the interface to add functions and classes to the module. + + .. code-block:: cpp + + PYBIND11_EMBEDDED_MODULE(example, m) { + // ... initialize functions and classes here + m.def("foo", []() { + return "Hello, World!"; + }); + } + \endrst */ +#define PYBIND11_EMBEDDED_MODULE(name, variable) \ + static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \ + static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \ + auto m = pybind11::module(PYBIND11_TOSTRING(name)); \ + try { \ + PYBIND11_CONCAT(pybind11_init_, name)(m); \ + return m.ptr(); \ + } catch (pybind11::error_already_set &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } \ + } \ + PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + pybind11::detail::embedded_module name(PYBIND11_TOSTRING(name), \ + PYBIND11_CONCAT(pybind11_init_impl_, name)); \ + void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable) + + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks. +struct embedded_module { +#if PY_MAJOR_VERSION >= 3 + using init_t = PyObject *(*)(); +#else + using init_t = void (*)(); +#endif + embedded_module(const char *name, init_t init) { + if (Py_IsInitialized()) + pybind11_fail("Can't add new modules after the interpreter has been initialized"); + + auto result = PyImport_AppendInittab(name, init); + if (result == -1) + pybind11_fail("Insufficient memory to add a new module"); + } +}; + +NAMESPACE_END(detail) + +/** \rst + Initialize the Python interpreter. No other pybind11 or CPython API functions can be + called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The + optional parameter can be used to skip the registration of signal handlers (see the + `Python documentation`_ for details). Calling this function again after the interpreter + has already been initialized is a fatal error. + + If initializing the Python interpreter fails, then the program is terminated. (This + is controlled by the CPython runtime and is an exception to pybind11's normal behavior + of throwing exceptions on errors.) + + .. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx + \endrst */ +inline void initialize_interpreter(bool init_signal_handlers = true) { + if (Py_IsInitialized()) + pybind11_fail("The interpreter is already running"); + + Py_InitializeEx(init_signal_handlers ? 1 : 0); + + // Make .py files in the working directory available by default + module::import("sys").attr("path").cast().append("."); +} + +/** \rst + Shut down the Python interpreter. No pybind11 or CPython API functions can be called + after this. In addition, pybind11 objects must not outlive the interpreter: + + .. code-block:: cpp + + { // BAD + py::initialize_interpreter(); + auto hello = py::str("Hello, World!"); + py::finalize_interpreter(); + } // <-- BOOM, hello's destructor is called after interpreter shutdown + + { // GOOD + py::initialize_interpreter(); + { // scoped + auto hello = py::str("Hello, World!"); + } // <-- OK, hello is cleaned up properly + py::finalize_interpreter(); + } + + { // BETTER + py::scoped_interpreter guard{}; + auto hello = py::str("Hello, World!"); + } + + .. warning:: + + The interpreter can be restarted by calling `initialize_interpreter` again. + Modules created using pybind11 can be safely re-initialized. However, Python + itself cannot completely unload binary extension modules and there are several + caveats with regard to interpreter restarting. All the details can be found + in the CPython documentation. In short, not all interpreter memory may be + freed, either due to reference cycles or user-created global data. + + \endrst */ +inline void finalize_interpreter() { + handle builtins(PyEval_GetBuiltins()); + const char *id = PYBIND11_INTERNALS_ID; + + // Get the internals pointer (without creating it if it doesn't exist). It's possible for the + // internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()` + // during destruction), so we get the pointer-pointer here and check it after Py_Finalize(). + detail::internals **internals_ptr_ptr = detail::get_internals_pp(); + // It could also be stashed in builtins, so look there too: + if (builtins.contains(id) && isinstance(builtins[id])) + internals_ptr_ptr = capsule(builtins[id]); + + Py_Finalize(); + + if (internals_ptr_ptr) { + delete *internals_ptr_ptr; + *internals_ptr_ptr = nullptr; + } +} + +/** \rst + Scope guard version of `initialize_interpreter` and `finalize_interpreter`. + This a move-only guard and only a single instance can exist. + + .. code-block:: cpp + + #include + + int main() { + py::scoped_interpreter guard{}; + py::print(Hello, World!); + } // <-- interpreter shutdown + \endrst */ +class scoped_interpreter { +public: + scoped_interpreter(bool init_signal_handlers = true) { + initialize_interpreter(init_signal_handlers); + } + + scoped_interpreter(const scoped_interpreter &) = delete; + scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; } + scoped_interpreter &operator=(const scoped_interpreter &) = delete; + scoped_interpreter &operator=(scoped_interpreter &&) = delete; + + ~scoped_interpreter() { + if (is_valid) + finalize_interpreter(); + } + +private: + bool is_valid = true; +}; + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/eval.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/eval.h new file mode 100644 index 0000000000000000000000000000000000000000..ea85ba1dbee607bda225cdbdb7b0341f54f1215f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/eval.h @@ -0,0 +1,117 @@ +/* + pybind11/exec.h: Support for evaluating Python expressions and statements + from strings and files + + Copyright (c) 2016 Klemens Morgenstern and + Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +enum eval_mode { + /// Evaluate a string containing an isolated expression + eval_expr, + + /// Evaluate a string containing a single statement. Returns \c none + eval_single_statement, + + /// Evaluate a string containing a sequence of statement. Returns \c none + eval_statements +}; + +template +object eval(str expr, object global = globals(), object local = object()) { + if (!local) + local = global; + + /* PyRun_String does not accept a PyObject / encoding specifier, + this seems to be the only alternative */ + std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr; + + int start; + switch (mode) { + case eval_expr: start = Py_eval_input; break; + case eval_single_statement: start = Py_single_input; break; + case eval_statements: start = Py_file_input; break; + default: pybind11_fail("invalid evaluation mode"); + } + + PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr()); + if (!result) + throw error_already_set(); + return reinterpret_steal(result); +} + +template +object eval(const char (&s)[N], object global = globals(), object local = object()) { + /* Support raw string literals by removing common leading whitespace */ + auto expr = (s[0] == '\n') ? str(module::import("textwrap").attr("dedent")(s)) + : str(s); + return eval(expr, global, local); +} + +inline void exec(str expr, object global = globals(), object local = object()) { + eval(expr, global, local); +} + +template +void exec(const char (&s)[N], object global = globals(), object local = object()) { + eval(s, global, local); +} + +template +object eval_file(str fname, object global = globals(), object local = object()) { + if (!local) + local = global; + + int start; + switch (mode) { + case eval_expr: start = Py_eval_input; break; + case eval_single_statement: start = Py_single_input; break; + case eval_statements: start = Py_file_input; break; + default: pybind11_fail("invalid evaluation mode"); + } + + int closeFile = 1; + std::string fname_str = (std::string) fname; +#if PY_VERSION_HEX >= 0x03040000 + FILE *f = _Py_fopen_obj(fname.ptr(), "r"); +#elif PY_VERSION_HEX >= 0x03000000 + FILE *f = _Py_fopen(fname.ptr(), "r"); +#else + /* No unicode support in open() :( */ + auto fobj = reinterpret_steal(PyFile_FromString( + const_cast(fname_str.c_str()), + const_cast("r"))); + FILE *f = nullptr; + if (fobj) + f = PyFile_AsFile(fobj.ptr()); + closeFile = 0; +#endif + if (!f) { + PyErr_Clear(); + pybind11_fail("File \"" + fname_str + "\" could not be opened!"); + } + +#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION) + PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(), + local.ptr()); + (void) closeFile; +#else + PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), + local.ptr(), closeFile); +#endif + + if (!result) + throw error_already_set(); + return reinterpret_steal(result); +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/functional.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/functional.h new file mode 100644 index 0000000000000000000000000000000000000000..f8bda648318d9d7e3f93b55e6cef244bd8f0adb5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/functional.h @@ -0,0 +1,101 @@ +/* + pybind11/functional.h: std::function<> support + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +template +struct type_caster> { + using type = std::function; + using retval_type = conditional_t::value, void_type, Return>; + using function_type = Return (*) (Args...); + +public: + bool load(handle src, bool convert) { + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) return false; + return true; + } + + if (!isinstance(src)) + return false; + + auto func = reinterpret_borrow(src); + + /* + When passing a C++ function as an argument to another C++ + function via Python, every function call would normally involve + a full C++ -> Python -> C++ roundtrip, which can be prohibitive. + Here, we try to at least detect the case where the function is + stateless (i.e. function pointer or lambda function without + captured variables), in which case the roundtrip can be avoided. + */ + if (auto cfunc = func.cpp_function()) { + auto c = reinterpret_borrow(PyCFunction_GET_SELF(cfunc.ptr())); + auto rec = (function_record *) c; + + if (rec && rec->is_stateless && + same_type(typeid(function_type), *reinterpret_cast(rec->data[1]))) { + struct capture { function_type f; }; + value = ((capture *) &rec->data)->f; + return true; + } + } + + // ensure GIL is held during functor destruction + struct func_handle { + function f; + func_handle(function&& f_) : f(std::move(f_)) {} + func_handle(const func_handle&) = default; + ~func_handle() { + gil_scoped_acquire acq; + function kill_f(std::move(f)); + } + }; + + // to emulate 'move initialization capture' in C++11 + struct func_wrapper { + func_handle hfunc; + func_wrapper(func_handle&& hf): hfunc(std::move(hf)) {} + Return operator()(Args... args) const { + gil_scoped_acquire acq; + object retval(hfunc.f(std::forward(args)...)); + /* Visual studio 2015 parser issue: need parentheses around this expression */ + return (retval.template cast()); + } + }; + + value = func_wrapper(func_handle(std::move(func))); + return true; + } + + template + static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) { + if (!f_) + return none().inc_ref(); + + auto result = f_.template target(); + if (result) + return cpp_function(*result, policy).release(); + else + return cpp_function(std::forward(f_), policy).release(); + } + + PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster::name...) + _("], ") + + make_caster::name + _("]")); +}; + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/iostream.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/iostream.h new file mode 100644 index 0000000000000000000000000000000000000000..c43b7c93a6ca588e9f15dec1ca6ca1ca492b9375 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/iostream.h @@ -0,0 +1,209 @@ +/* + pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python + + Copyright (c) 2017 Henry F. Schreiner + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" + +#include +#include +#include +#include +#include + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +// Buffer that writes to Python instead of C++ +class pythonbuf : public std::streambuf { +private: + using traits_type = std::streambuf::traits_type; + + const size_t buf_size; + std::unique_ptr d_buffer; + object pywrite; + object pyflush; + + int overflow(int c) { + if (!traits_type::eq_int_type(c, traits_type::eof())) { + *pptr() = traits_type::to_char_type(c); + pbump(1); + } + return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof(); + } + + int sync() { + if (pbase() != pptr()) { + // This subtraction cannot be negative, so dropping the sign + str line(pbase(), static_cast(pptr() - pbase())); + + { + gil_scoped_acquire tmp; + pywrite(line); + pyflush(); + } + + setp(pbase(), epptr()); + } + return 0; + } + +public: + + pythonbuf(object pyostream, size_t buffer_size = 1024) + : buf_size(buffer_size), + d_buffer(new char[buf_size]), + pywrite(pyostream.attr("write")), + pyflush(pyostream.attr("flush")) { + setp(d_buffer.get(), d_buffer.get() + buf_size - 1); + } + + pythonbuf(pythonbuf&&) = default; + + /// Sync before destroy + ~pythonbuf() { + sync(); + } +}; + +NAMESPACE_END(detail) + + +/** \rst + This a move-only guard that redirects output. + + .. code-block:: cpp + + #include + + ... + + { + py::scoped_ostream_redirect output; + std::cout << "Hello, World!"; // Python stdout + } // <-- return std::cout to normal + + You can explicitly pass the c++ stream and the python object, + for example to guard stderr instead. + + .. code-block:: cpp + + { + py::scoped_ostream_redirect output{std::cerr, py::module::import("sys").attr("stderr")}; + std::cerr << "Hello, World!"; + } + \endrst */ +class scoped_ostream_redirect { +protected: + std::streambuf *old; + std::ostream &costream; + detail::pythonbuf buffer; + +public: + scoped_ostream_redirect( + std::ostream &costream = std::cout, + object pyostream = module::import("sys").attr("stdout")) + : costream(costream), buffer(pyostream) { + old = costream.rdbuf(&buffer); + } + + ~scoped_ostream_redirect() { + costream.rdbuf(old); + } + + scoped_ostream_redirect(const scoped_ostream_redirect &) = delete; + scoped_ostream_redirect(scoped_ostream_redirect &&other) = default; + scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete; + scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete; +}; + + +/** \rst + Like `scoped_ostream_redirect`, but redirects cerr by default. This class + is provided primary to make ``py::call_guard`` easier to make. + + .. code-block:: cpp + + m.def("noisy_func", &noisy_func, + py::call_guard()); + +\endrst */ +class scoped_estream_redirect : public scoped_ostream_redirect { +public: + scoped_estream_redirect( + std::ostream &costream = std::cerr, + object pyostream = module::import("sys").attr("stderr")) + : scoped_ostream_redirect(costream,pyostream) {} +}; + + +NAMESPACE_BEGIN(detail) + +// Class to redirect output as a context manager. C++ backend. +class OstreamRedirect { + bool do_stdout_; + bool do_stderr_; + std::unique_ptr redirect_stdout; + std::unique_ptr redirect_stderr; + +public: + OstreamRedirect(bool do_stdout = true, bool do_stderr = true) + : do_stdout_(do_stdout), do_stderr_(do_stderr) {} + + void enter() { + if (do_stdout_) + redirect_stdout.reset(new scoped_ostream_redirect()); + if (do_stderr_) + redirect_stderr.reset(new scoped_estream_redirect()); + } + + void exit() { + redirect_stdout.reset(); + redirect_stderr.reset(); + } +}; + +NAMESPACE_END(detail) + +/** \rst + This is a helper function to add a C++ redirect context manager to Python + instead of using a C++ guard. To use it, add the following to your binding code: + + .. code-block:: cpp + + #include + + ... + + py::add_ostream_redirect(m, "ostream_redirect"); + + You now have a Python context manager that redirects your output: + + .. code-block:: python + + with m.ostream_redirect(): + m.print_to_cout_function() + + This manager can optionally be told which streams to operate on: + + .. code-block:: python + + with m.ostream_redirect(stdout=true, stderr=true): + m.noisy_function_with_error_printing() + + \endrst */ +inline class_ add_ostream_redirect(module m, std::string name = "ostream_redirect") { + return class_(m, name.c_str(), module_local()) + .def(init(), arg("stdout")=true, arg("stderr")=true) + .def("__enter__", &detail::OstreamRedirect::enter) + .def("__exit__", [](detail::OstreamRedirect &self_, args) { self_.exit(); }); +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/numpy.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/numpy.h new file mode 100644 index 0000000000000000000000000000000000000000..ba41a223d0f438247256b5d12f5585c6a790ca0e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/numpy.h @@ -0,0 +1,1642 @@ +/* + pybind11/numpy.h: Basic NumPy support, vectorize() wrapper + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include "complex.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +/* This will be true on all flat address space platforms and allows us to reduce the + whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size + and dimension types (e.g. shape, strides, indexing), instead of inflicting this + upon the library user. */ +static_assert(sizeof(ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t"); + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +class array; // Forward declaration + +NAMESPACE_BEGIN(detail) +template struct npy_format_descriptor; + +struct PyArrayDescr_Proxy { + PyObject_HEAD + PyObject *typeobj; + char kind; + char type; + char byteorder; + char flags; + int type_num; + int elsize; + int alignment; + char *subarray; + PyObject *fields; + PyObject *names; +}; + +struct PyArray_Proxy { + PyObject_HEAD + char *data; + int nd; + ssize_t *dimensions; + ssize_t *strides; + PyObject *base; + PyObject *descr; + int flags; +}; + +struct PyVoidScalarObject_Proxy { + PyObject_VAR_HEAD + char *obval; + PyArrayDescr_Proxy *descr; + int flags; + PyObject *base; +}; + +struct numpy_type_info { + PyObject* dtype_ptr; + std::string format_str; +}; + +struct numpy_internals { + std::unordered_map registered_dtypes; + + numpy_type_info *get_type_info(const std::type_info& tinfo, bool throw_if_missing = true) { + auto it = registered_dtypes.find(std::type_index(tinfo)); + if (it != registered_dtypes.end()) + return &(it->second); + if (throw_if_missing) + pybind11_fail(std::string("NumPy type info missing for ") + tinfo.name()); + return nullptr; + } + + template numpy_type_info *get_type_info(bool throw_if_missing = true) { + return get_type_info(typeid(typename std::remove_cv::type), throw_if_missing); + } +}; + +inline PYBIND11_NOINLINE void load_numpy_internals(numpy_internals* &ptr) { + ptr = &get_or_create_shared_data("_numpy_internals"); +} + +inline numpy_internals& get_numpy_internals() { + static numpy_internals* ptr = nullptr; + if (!ptr) + load_numpy_internals(ptr); + return *ptr; +} + +template struct same_size { + template using as = bool_constant; +}; + +template constexpr int platform_lookup() { return -1; } + +// Lookup a type according to its size, and return a value corresponding to the NumPy typenum. +template +constexpr int platform_lookup(int I, Ints... Is) { + return sizeof(Concrete) == sizeof(T) ? I : platform_lookup(Is...); +} + +struct npy_api { + enum constants { + NPY_ARRAY_C_CONTIGUOUS_ = 0x0001, + NPY_ARRAY_F_CONTIGUOUS_ = 0x0002, + NPY_ARRAY_OWNDATA_ = 0x0004, + NPY_ARRAY_FORCECAST_ = 0x0010, + NPY_ARRAY_ENSUREARRAY_ = 0x0040, + NPY_ARRAY_ALIGNED_ = 0x0100, + NPY_ARRAY_WRITEABLE_ = 0x0400, + NPY_BOOL_ = 0, + NPY_BYTE_, NPY_UBYTE_, + NPY_SHORT_, NPY_USHORT_, + NPY_INT_, NPY_UINT_, + NPY_LONG_, NPY_ULONG_, + NPY_LONGLONG_, NPY_ULONGLONG_, + NPY_FLOAT_, NPY_DOUBLE_, NPY_LONGDOUBLE_, + NPY_CFLOAT_, NPY_CDOUBLE_, NPY_CLONGDOUBLE_, + NPY_OBJECT_ = 17, + NPY_STRING_, NPY_UNICODE_, NPY_VOID_, + // Platform-dependent normalization + NPY_INT8_ = NPY_BYTE_, + NPY_UINT8_ = NPY_UBYTE_, + NPY_INT16_ = NPY_SHORT_, + NPY_UINT16_ = NPY_USHORT_, + // `npy_common.h` defines the integer aliases. In order, it checks: + // NPY_BITSOF_LONG, NPY_BITSOF_LONGLONG, NPY_BITSOF_INT, NPY_BITSOF_SHORT, NPY_BITSOF_CHAR + // and assigns the alias to the first matching size, so we should check in this order. + NPY_INT32_ = platform_lookup( + NPY_LONG_, NPY_INT_, NPY_SHORT_), + NPY_UINT32_ = platform_lookup( + NPY_ULONG_, NPY_UINT_, NPY_USHORT_), + NPY_INT64_ = platform_lookup( + NPY_LONG_, NPY_LONGLONG_, NPY_INT_), + NPY_UINT64_ = platform_lookup( + NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_), + }; + + typedef struct { + Py_intptr_t *ptr; + int len; + } PyArray_Dims; + + static npy_api& get() { + static npy_api api = lookup(); + return api; + } + + bool PyArray_Check_(PyObject *obj) const { + return (bool) PyObject_TypeCheck(obj, PyArray_Type_); + } + bool PyArrayDescr_Check_(PyObject *obj) const { + return (bool) PyObject_TypeCheck(obj, PyArrayDescr_Type_); + } + + unsigned int (*PyArray_GetNDArrayCFeatureVersion_)(); + PyObject *(*PyArray_DescrFromType_)(int); + PyObject *(*PyArray_NewFromDescr_) + (PyTypeObject *, PyObject *, int, Py_intptr_t *, + Py_intptr_t *, void *, int, PyObject *); + PyObject *(*PyArray_DescrNewFromType_)(int); + int (*PyArray_CopyInto_)(PyObject *, PyObject *); + PyObject *(*PyArray_NewCopy_)(PyObject *, int); + PyTypeObject *PyArray_Type_; + PyTypeObject *PyVoidArrType_Type_; + PyTypeObject *PyArrayDescr_Type_; + PyObject *(*PyArray_DescrFromScalar_)(PyObject *); + PyObject *(*PyArray_FromAny_) (PyObject *, PyObject *, int, int, int, PyObject *); + int (*PyArray_DescrConverter_) (PyObject *, PyObject **); + bool (*PyArray_EquivTypes_) (PyObject *, PyObject *); + int (*PyArray_GetArrayParamsFromObject_)(PyObject *, PyObject *, char, PyObject **, int *, + Py_ssize_t *, PyObject **, PyObject *); + PyObject *(*PyArray_Squeeze_)(PyObject *); + int (*PyArray_SetBaseObject_)(PyObject *, PyObject *); + PyObject* (*PyArray_Resize_)(PyObject*, PyArray_Dims*, int, int); +private: + enum functions { + API_PyArray_GetNDArrayCFeatureVersion = 211, + API_PyArray_Type = 2, + API_PyArrayDescr_Type = 3, + API_PyVoidArrType_Type = 39, + API_PyArray_DescrFromType = 45, + API_PyArray_DescrFromScalar = 57, + API_PyArray_FromAny = 69, + API_PyArray_Resize = 80, + API_PyArray_CopyInto = 82, + API_PyArray_NewCopy = 85, + API_PyArray_NewFromDescr = 94, + API_PyArray_DescrNewFromType = 9, + API_PyArray_DescrConverter = 174, + API_PyArray_EquivTypes = 182, + API_PyArray_GetArrayParamsFromObject = 278, + API_PyArray_Squeeze = 136, + API_PyArray_SetBaseObject = 282 + }; + + static npy_api lookup() { + module m = module::import("numpy.core.multiarray"); + auto c = m.attr("_ARRAY_API"); +#if PY_MAJOR_VERSION >= 3 + void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL); +#else + void **api_ptr = (void **) PyCObject_AsVoidPtr(c.ptr()); +#endif + npy_api api; +#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func]; + DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion); + if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7) + pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0"); + DECL_NPY_API(PyArray_Type); + DECL_NPY_API(PyVoidArrType_Type); + DECL_NPY_API(PyArrayDescr_Type); + DECL_NPY_API(PyArray_DescrFromType); + DECL_NPY_API(PyArray_DescrFromScalar); + DECL_NPY_API(PyArray_FromAny); + DECL_NPY_API(PyArray_Resize); + DECL_NPY_API(PyArray_CopyInto); + DECL_NPY_API(PyArray_NewCopy); + DECL_NPY_API(PyArray_NewFromDescr); + DECL_NPY_API(PyArray_DescrNewFromType); + DECL_NPY_API(PyArray_DescrConverter); + DECL_NPY_API(PyArray_EquivTypes); + DECL_NPY_API(PyArray_GetArrayParamsFromObject); + DECL_NPY_API(PyArray_Squeeze); + DECL_NPY_API(PyArray_SetBaseObject); +#undef DECL_NPY_API + return api; + } +}; + +inline PyArray_Proxy* array_proxy(void* ptr) { + return reinterpret_cast(ptr); +} + +inline const PyArray_Proxy* array_proxy(const void* ptr) { + return reinterpret_cast(ptr); +} + +inline PyArrayDescr_Proxy* array_descriptor_proxy(PyObject* ptr) { + return reinterpret_cast(ptr); +} + +inline const PyArrayDescr_Proxy* array_descriptor_proxy(const PyObject* ptr) { + return reinterpret_cast(ptr); +} + +inline bool check_flags(const void* ptr, int flag) { + return (flag == (array_proxy(ptr)->flags & flag)); +} + +template struct is_std_array : std::false_type { }; +template struct is_std_array> : std::true_type { }; +template struct is_complex : std::false_type { }; +template struct is_complex> : std::true_type { }; + +template struct array_info_scalar { + typedef T type; + static constexpr bool is_array = false; + static constexpr bool is_empty = false; + static constexpr auto extents = _(""); + static void append_extents(list& /* shape */) { } +}; +// Computes underlying type and a comma-separated list of extents for array +// types (any mix of std::array and built-in arrays). An array of char is +// treated as scalar because it gets special handling. +template struct array_info : array_info_scalar { }; +template struct array_info> { + using type = typename array_info::type; + static constexpr bool is_array = true; + static constexpr bool is_empty = (N == 0) || array_info::is_empty; + static constexpr size_t extent = N; + + // appends the extents to shape + static void append_extents(list& shape) { + shape.append(N); + array_info::append_extents(shape); + } + + static constexpr auto extents = _::is_array>( + concat(_(), array_info::extents), _() + ); +}; +// For numpy we have special handling for arrays of characters, so we don't include +// the size in the array extents. +template struct array_info : array_info_scalar { }; +template struct array_info> : array_info_scalar> { }; +template struct array_info : array_info> { }; +template using remove_all_extents_t = typename array_info::type; + +template using is_pod_struct = all_of< + std::is_standard_layout, // since we're accessing directly in memory we need a standard layout type +#if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || defined(_GLIBCXX_USE_CXX11_ABI) + // _GLIBCXX_USE_CXX11_ABI indicates that we're using libstdc++ from GCC 5 or newer, independent + // of the actual compiler (Clang can also use libstdc++, but it always defines __GNUC__ == 4). + std::is_trivially_copyable, +#else + // GCC 4 doesn't implement is_trivially_copyable, so approximate it + std::is_trivially_destructible, + satisfies_any_of, +#endif + satisfies_none_of +>; + +template ssize_t byte_offset_unsafe(const Strides &) { return 0; } +template +ssize_t byte_offset_unsafe(const Strides &strides, ssize_t i, Ix... index) { + return i * strides[Dim] + byte_offset_unsafe(strides, index...); +} + +/** + * Proxy class providing unsafe, unchecked const access to array data. This is constructed through + * the `unchecked()` method of `array` or the `unchecked()` method of `array_t`. `Dims` + * will be -1 for dimensions determined at runtime. + */ +template +class unchecked_reference { +protected: + static constexpr bool Dynamic = Dims < 0; + const unsigned char *data_; + // Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to + // make large performance gains on big, nested loops, but requires compile-time dimensions + conditional_t> + shape_, strides_; + const ssize_t dims_; + + friend class pybind11::array; + // Constructor for compile-time dimensions: + template + unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t) + : data_{reinterpret_cast(data)}, dims_{Dims} { + for (size_t i = 0; i < (size_t) dims_; i++) { + shape_[i] = shape[i]; + strides_[i] = strides[i]; + } + } + // Constructor for runtime dimensions: + template + unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t dims) + : data_{reinterpret_cast(data)}, shape_{shape}, strides_{strides}, dims_{dims} {} + +public: + /** + * Unchecked const reference access to data at the given indices. For a compile-time known + * number of dimensions, this requires the correct number of arguments; for run-time + * dimensionality, this is not checked (and so is up to the caller to use safely). + */ + template const T &operator()(Ix... index) const { + static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic, + "Invalid number of indices for unchecked array reference"); + return *reinterpret_cast(data_ + byte_offset_unsafe(strides_, ssize_t(index)...)); + } + /** + * Unchecked const reference access to data; this operator only participates if the reference + * is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`. + */ + template > + const T &operator[](ssize_t index) const { return operator()(index); } + + /// Pointer access to the data at the given indices. + template const T *data(Ix... ix) const { return &operator()(ssize_t(ix)...); } + + /// Returns the item size, i.e. sizeof(T) + constexpr static ssize_t itemsize() { return sizeof(T); } + + /// Returns the shape (i.e. size) of dimension `dim` + ssize_t shape(ssize_t dim) const { return shape_[(size_t) dim]; } + + /// Returns the number of dimensions of the array + ssize_t ndim() const { return dims_; } + + /// Returns the total number of elements in the referenced array, i.e. the product of the shapes + template + enable_if_t size() const { + return std::accumulate(shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies()); + } + template + enable_if_t size() const { + return std::accumulate(shape_, shape_ + ndim(), (ssize_t) 1, std::multiplies()); + } + + /// Returns the total number of bytes used by the referenced data. Note that the actual span in + /// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice). + ssize_t nbytes() const { + return size() * itemsize(); + } +}; + +template +class unchecked_mutable_reference : public unchecked_reference { + friend class pybind11::array; + using ConstBase = unchecked_reference; + using ConstBase::ConstBase; + using ConstBase::Dynamic; +public: + /// Mutable, unchecked access to data at the given indices. + template T& operator()(Ix... index) { + static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic, + "Invalid number of indices for unchecked array reference"); + return const_cast(ConstBase::operator()(index...)); + } + /** + * Mutable, unchecked access data at the given index; this operator only participates if the + * reference is to a 1-dimensional array (or has runtime dimensions). When present, this is + * exactly equivalent to `obj(index)`. + */ + template > + T &operator[](ssize_t index) { return operator()(index); } + + /// Mutable pointer access to the data at the given indices. + template T *mutable_data(Ix... ix) { return &operator()(ssize_t(ix)...); } +}; + +template +struct type_caster> { + static_assert(Dim == 0 && Dim > 0 /* always fail */, "unchecked array proxy object is not castable"); +}; +template +struct type_caster> : type_caster> {}; + +NAMESPACE_END(detail) + +class dtype : public object { +public: + PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_); + + explicit dtype(const buffer_info &info) { + dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format))); + // If info.itemsize == 0, use the value calculated from the format string + m_ptr = descr.strip_padding(info.itemsize ? info.itemsize : descr.itemsize()).release().ptr(); + } + + explicit dtype(const std::string &format) { + m_ptr = from_args(pybind11::str(format)).release().ptr(); + } + + dtype(const char *format) : dtype(std::string(format)) { } + + dtype(list names, list formats, list offsets, ssize_t itemsize) { + dict args; + args["names"] = names; + args["formats"] = formats; + args["offsets"] = offsets; + args["itemsize"] = pybind11::int_(itemsize); + m_ptr = from_args(args).release().ptr(); + } + + /// This is essentially the same as calling numpy.dtype(args) in Python. + static dtype from_args(object args) { + PyObject *ptr = nullptr; + if (!detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) || !ptr) + throw error_already_set(); + return reinterpret_steal(ptr); + } + + /// Return dtype associated with a C++ type. + template static dtype of() { + return detail::npy_format_descriptor::type>::dtype(); + } + + /// Size of the data type in bytes. + ssize_t itemsize() const { + return detail::array_descriptor_proxy(m_ptr)->elsize; + } + + /// Returns true for structured data types. + bool has_fields() const { + return detail::array_descriptor_proxy(m_ptr)->names != nullptr; + } + + /// Single-character type code. + char kind() const { + return detail::array_descriptor_proxy(m_ptr)->kind; + } + +private: + static object _dtype_from_pep3118() { + static PyObject *obj = module::import("numpy.core._internal") + .attr("_dtype_from_pep3118").cast().release().ptr(); + return reinterpret_borrow(obj); + } + + dtype strip_padding(ssize_t itemsize) { + // Recursively strip all void fields with empty names that are generated for + // padding fields (as of NumPy v1.11). + if (!has_fields()) + return *this; + + struct field_descr { PYBIND11_STR_TYPE name; object format; pybind11::int_ offset; }; + std::vector field_descriptors; + + for (auto field : attr("fields").attr("items")()) { + auto spec = field.cast(); + auto name = spec[0].cast(); + auto format = spec[1].cast()[0].cast(); + auto offset = spec[1].cast()[1].cast(); + if (!len(name) && format.kind() == 'V') + continue; + field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset}); + } + + std::sort(field_descriptors.begin(), field_descriptors.end(), + [](const field_descr& a, const field_descr& b) { + return a.offset.cast() < b.offset.cast(); + }); + + list names, formats, offsets; + for (auto& descr : field_descriptors) { + names.append(descr.name); + formats.append(descr.format); + offsets.append(descr.offset); + } + return dtype(names, formats, offsets, itemsize); + } +}; + +class array : public buffer { +public: + PYBIND11_OBJECT_CVT(array, buffer, detail::npy_api::get().PyArray_Check_, raw_array) + + enum { + c_style = detail::npy_api::NPY_ARRAY_C_CONTIGUOUS_, + f_style = detail::npy_api::NPY_ARRAY_F_CONTIGUOUS_, + forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_ + }; + + array() : array({{0}}, static_cast(nullptr)) {} + + using ShapeContainer = detail::any_container; + using StridesContainer = detail::any_container; + + // Constructs an array taking shape/strides from arbitrary container types + array(const pybind11::dtype &dt, ShapeContainer shape, StridesContainer strides, + const void *ptr = nullptr, handle base = handle()) { + + if (strides->empty()) + *strides = c_strides(*shape, dt.itemsize()); + + auto ndim = shape->size(); + if (ndim != strides->size()) + pybind11_fail("NumPy: shape ndim doesn't match strides ndim"); + auto descr = dt; + + int flags = 0; + if (base && ptr) { + if (isinstance(base)) + /* Copy flags from base (except ownership bit) */ + flags = reinterpret_borrow(base).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_; + else + /* Writable by default, easy to downgrade later on if needed */ + flags = detail::npy_api::NPY_ARRAY_WRITEABLE_; + } + + auto &api = detail::npy_api::get(); + auto tmp = reinterpret_steal(api.PyArray_NewFromDescr_( + api.PyArray_Type_, descr.release().ptr(), (int) ndim, shape->data(), strides->data(), + const_cast(ptr), flags, nullptr)); + if (!tmp) + throw error_already_set(); + if (ptr) { + if (base) { + api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr()); + } else { + tmp = reinterpret_steal(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */)); + } + } + m_ptr = tmp.release().ptr(); + } + + array(const pybind11::dtype &dt, ShapeContainer shape, const void *ptr = nullptr, handle base = handle()) + : array(dt, std::move(shape), {}, ptr, base) { } + + template ::value && !std::is_same::value>> + array(const pybind11::dtype &dt, T count, const void *ptr = nullptr, handle base = handle()) + : array(dt, {{count}}, ptr, base) { } + + template + array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle()) + : array(pybind11::dtype::of(), std::move(shape), std::move(strides), ptr, base) { } + + template + array(ShapeContainer shape, const T *ptr, handle base = handle()) + : array(std::move(shape), {}, ptr, base) { } + + template + explicit array(ssize_t count, const T *ptr, handle base = handle()) : array({count}, {}, ptr, base) { } + + explicit array(const buffer_info &info) + : array(pybind11::dtype(info), info.shape, info.strides, info.ptr) { } + + /// Array descriptor (dtype) + pybind11::dtype dtype() const { + return reinterpret_borrow(detail::array_proxy(m_ptr)->descr); + } + + /// Total number of elements + ssize_t size() const { + return std::accumulate(shape(), shape() + ndim(), (ssize_t) 1, std::multiplies()); + } + + /// Byte size of a single element + ssize_t itemsize() const { + return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize; + } + + /// Total number of bytes + ssize_t nbytes() const { + return size() * itemsize(); + } + + /// Number of dimensions + ssize_t ndim() const { + return detail::array_proxy(m_ptr)->nd; + } + + /// Base object + object base() const { + return reinterpret_borrow(detail::array_proxy(m_ptr)->base); + } + + /// Dimensions of the array + const ssize_t* shape() const { + return detail::array_proxy(m_ptr)->dimensions; + } + + /// Dimension along a given axis + ssize_t shape(ssize_t dim) const { + if (dim >= ndim()) + fail_dim_check(dim, "invalid axis"); + return shape()[dim]; + } + + /// Strides of the array + const ssize_t* strides() const { + return detail::array_proxy(m_ptr)->strides; + } + + /// Stride along a given axis + ssize_t strides(ssize_t dim) const { + if (dim >= ndim()) + fail_dim_check(dim, "invalid axis"); + return strides()[dim]; + } + + /// Return the NumPy array flags + int flags() const { + return detail::array_proxy(m_ptr)->flags; + } + + /// If set, the array is writeable (otherwise the buffer is read-only) + bool writeable() const { + return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_WRITEABLE_); + } + + /// If set, the array owns the data (will be freed when the array is deleted) + bool owndata() const { + return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_OWNDATA_); + } + + /// Pointer to the contained data. If index is not provided, points to the + /// beginning of the buffer. May throw if the index would lead to out of bounds access. + template const void* data(Ix... index) const { + return static_cast(detail::array_proxy(m_ptr)->data + offset_at(index...)); + } + + /// Mutable pointer to the contained data. If index is not provided, points to the + /// beginning of the buffer. May throw if the index would lead to out of bounds access. + /// May throw if the array is not writeable. + template void* mutable_data(Ix... index) { + check_writeable(); + return static_cast(detail::array_proxy(m_ptr)->data + offset_at(index...)); + } + + /// Byte offset from beginning of the array to a given index (full or partial). + /// May throw if the index would lead to out of bounds access. + template ssize_t offset_at(Ix... index) const { + if ((ssize_t) sizeof...(index) > ndim()) + fail_dim_check(sizeof...(index), "too many indices for an array"); + return byte_offset(ssize_t(index)...); + } + + ssize_t offset_at() const { return 0; } + + /// Item count from beginning of the array to a given index (full or partial). + /// May throw if the index would lead to out of bounds access. + template ssize_t index_at(Ix... index) const { + return offset_at(index...) / itemsize(); + } + + /** + * Returns a proxy object that provides access to the array's data without bounds or + * dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with + * care: the array must not be destroyed or reshaped for the duration of the returned object, + * and the caller must take care not to access invalid dimensions or dimension indices. + */ + template detail::unchecked_mutable_reference mutable_unchecked() & { + if (Dims >= 0 && ndim() != Dims) + throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + + "; expected " + std::to_string(Dims)); + return detail::unchecked_mutable_reference(mutable_data(), shape(), strides(), ndim()); + } + + /** + * Returns a proxy object that provides const access to the array's data without bounds or + * dimensionality checking. Unlike `mutable_unchecked()`, this does not require that the + * underlying array have the `writable` flag. Use with care: the array must not be destroyed or + * reshaped for the duration of the returned object, and the caller must take care not to access + * invalid dimensions or dimension indices. + */ + template detail::unchecked_reference unchecked() const & { + if (Dims >= 0 && ndim() != Dims) + throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + + "; expected " + std::to_string(Dims)); + return detail::unchecked_reference(data(), shape(), strides(), ndim()); + } + + /// Return a new view with all of the dimensions of length 1 removed + array squeeze() { + auto& api = detail::npy_api::get(); + return reinterpret_steal(api.PyArray_Squeeze_(m_ptr)); + } + + /// Resize array to given shape + /// If refcheck is true and more that one reference exist to this array + /// then resize will succeed only if it makes a reshape, i.e. original size doesn't change + void resize(ShapeContainer new_shape, bool refcheck = true) { + detail::npy_api::PyArray_Dims d = { + new_shape->data(), int(new_shape->size()) + }; + // try to resize, set ordering param to -1 cause it's not used anyway + object new_array = reinterpret_steal( + detail::npy_api::get().PyArray_Resize_(m_ptr, &d, int(refcheck), -1) + ); + if (!new_array) throw error_already_set(); + if (isinstance(new_array)) { *this = std::move(new_array); } + } + + /// Ensure that the argument is a NumPy array + /// In case of an error, nullptr is returned and the Python error is cleared. + static array ensure(handle h, int ExtraFlags = 0) { + auto result = reinterpret_steal(raw_array(h.ptr(), ExtraFlags)); + if (!result) + PyErr_Clear(); + return result; + } + +protected: + template friend struct detail::npy_format_descriptor; + + void fail_dim_check(ssize_t dim, const std::string& msg) const { + throw index_error(msg + ": " + std::to_string(dim) + + " (ndim = " + std::to_string(ndim()) + ")"); + } + + template ssize_t byte_offset(Ix... index) const { + check_dimensions(index...); + return detail::byte_offset_unsafe(strides(), ssize_t(index)...); + } + + void check_writeable() const { + if (!writeable()) + throw std::domain_error("array is not writeable"); + } + + // Default, C-style strides + static std::vector c_strides(const std::vector &shape, ssize_t itemsize) { + auto ndim = shape.size(); + std::vector strides(ndim, itemsize); + if (ndim > 0) + for (size_t i = ndim - 1; i > 0; --i) + strides[i - 1] = strides[i] * shape[i]; + return strides; + } + + // F-style strides; default when constructing an array_t with `ExtraFlags & f_style` + static std::vector f_strides(const std::vector &shape, ssize_t itemsize) { + auto ndim = shape.size(); + std::vector strides(ndim, itemsize); + for (size_t i = 1; i < ndim; ++i) + strides[i] = strides[i - 1] * shape[i - 1]; + return strides; + } + + template void check_dimensions(Ix... index) const { + check_dimensions_impl(ssize_t(0), shape(), ssize_t(index)...); + } + + void check_dimensions_impl(ssize_t, const ssize_t*) const { } + + template void check_dimensions_impl(ssize_t axis, const ssize_t* shape, ssize_t i, Ix... index) const { + if (i >= *shape) { + throw index_error(std::string("index ") + std::to_string(i) + + " is out of bounds for axis " + std::to_string(axis) + + " with size " + std::to_string(*shape)); + } + check_dimensions_impl(axis + 1, shape + 1, index...); + } + + /// Create array from any object -- always returns a new reference + static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) { + if (ptr == nullptr) { + PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array from a nullptr"); + return nullptr; + } + return detail::npy_api::get().PyArray_FromAny_( + ptr, nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr); + } +}; + +template class array_t : public array { +private: + struct private_ctor {}; + // Delegating constructor needed when both moving and accessing in the same constructor + array_t(private_ctor, ShapeContainer &&shape, StridesContainer &&strides, const T *ptr, handle base) + : array(std::move(shape), std::move(strides), ptr, base) {} +public: + static_assert(!detail::array_info::is_array, "Array types cannot be used with array_t"); + + using value_type = T; + + array_t() : array(0, static_cast(nullptr)) {} + array_t(handle h, borrowed_t) : array(h, borrowed_t{}) { } + array_t(handle h, stolen_t) : array(h, stolen_t{}) { } + + PYBIND11_DEPRECATED("Use array_t::ensure() instead") + array_t(handle h, bool is_borrowed) : array(raw_array_t(h.ptr()), stolen_t{}) { + if (!m_ptr) PyErr_Clear(); + if (!is_borrowed) Py_XDECREF(h.ptr()); + } + + array_t(const object &o) : array(raw_array_t(o.ptr()), stolen_t{}) { + if (!m_ptr) throw error_already_set(); + } + + explicit array_t(const buffer_info& info) : array(info) { } + + array_t(ShapeContainer shape, StridesContainer strides, const T *ptr = nullptr, handle base = handle()) + : array(std::move(shape), std::move(strides), ptr, base) { } + + explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle()) + : array_t(private_ctor{}, std::move(shape), + ExtraFlags & f_style ? f_strides(*shape, itemsize()) : c_strides(*shape, itemsize()), + ptr, base) { } + + explicit array_t(size_t count, const T *ptr = nullptr, handle base = handle()) + : array({count}, {}, ptr, base) { } + + constexpr ssize_t itemsize() const { + return sizeof(T); + } + + template ssize_t index_at(Ix... index) const { + return offset_at(index...) / itemsize(); + } + + template const T* data(Ix... index) const { + return static_cast(array::data(index...)); + } + + template T* mutable_data(Ix... index) { + return static_cast(array::mutable_data(index...)); + } + + // Reference to element at a given index + template const T& at(Ix... index) const { + if ((ssize_t) sizeof...(index) != ndim()) + fail_dim_check(sizeof...(index), "index dimension mismatch"); + return *(static_cast(array::data()) + byte_offset(ssize_t(index)...) / itemsize()); + } + + // Mutable reference to element at a given index + template T& mutable_at(Ix... index) { + if ((ssize_t) sizeof...(index) != ndim()) + fail_dim_check(sizeof...(index), "index dimension mismatch"); + return *(static_cast(array::mutable_data()) + byte_offset(ssize_t(index)...) / itemsize()); + } + + /** + * Returns a proxy object that provides access to the array's data without bounds or + * dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with + * care: the array must not be destroyed or reshaped for the duration of the returned object, + * and the caller must take care not to access invalid dimensions or dimension indices. + */ + template detail::unchecked_mutable_reference mutable_unchecked() & { + return array::mutable_unchecked(); + } + + /** + * Returns a proxy object that provides const access to the array's data without bounds or + * dimensionality checking. Unlike `unchecked()`, this does not require that the underlying + * array have the `writable` flag. Use with care: the array must not be destroyed or reshaped + * for the duration of the returned object, and the caller must take care not to access invalid + * dimensions or dimension indices. + */ + template detail::unchecked_reference unchecked() const & { + return array::unchecked(); + } + + /// Ensure that the argument is a NumPy array of the correct dtype (and if not, try to convert + /// it). In case of an error, nullptr is returned and the Python error is cleared. + static array_t ensure(handle h) { + auto result = reinterpret_steal(raw_array_t(h.ptr())); + if (!result) + PyErr_Clear(); + return result; + } + + static bool check_(handle h) { + const auto &api = detail::npy_api::get(); + return api.PyArray_Check_(h.ptr()) + && api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr, dtype::of().ptr()); + } + +protected: + /// Create array from any object -- always returns a new reference + static PyObject *raw_array_t(PyObject *ptr) { + if (ptr == nullptr) { + PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr"); + return nullptr; + } + return detail::npy_api::get().PyArray_FromAny_( + ptr, dtype::of().release().ptr(), 0, 0, + detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr); + } +}; + +template +struct format_descriptor::value>> { + static std::string format() { + return detail::npy_format_descriptor::type>::format(); + } +}; + +template struct format_descriptor { + static std::string format() { return std::to_string(N) + "s"; } +}; +template struct format_descriptor> { + static std::string format() { return std::to_string(N) + "s"; } +}; + +template +struct format_descriptor::value>> { + static std::string format() { + return format_descriptor< + typename std::remove_cv::type>::type>::format(); + } +}; + +template +struct format_descriptor::is_array>> { + static std::string format() { + using namespace detail; + static constexpr auto extents = _("(") + array_info::extents + _(")"); + return extents.text + format_descriptor>::format(); + } +}; + +NAMESPACE_BEGIN(detail) +template +struct pyobject_caster> { + using type = array_t; + + bool load(handle src, bool convert) { + if (!convert && !type::check_(src)) + return false; + value = type::ensure(src); + return static_cast(value); + } + + static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { + return src.inc_ref(); + } + PYBIND11_TYPE_CASTER(type, handle_type_name::name); +}; + +template +struct compare_buffer_info::value>> { + static bool compare(const buffer_info& b) { + return npy_api::get().PyArray_EquivTypes_(dtype::of().ptr(), dtype(b).ptr()); + } +}; + +template +struct npy_format_descriptor_name; + +template +struct npy_format_descriptor_name::value>> { + static constexpr auto name = _::value>( + _("bool"), _::value>("int", "uint") + _() + ); +}; + +template +struct npy_format_descriptor_name::value>> { + static constexpr auto name = _::value || std::is_same::value>( + _("float") + _(), _("longdouble") + ); +}; + +template +struct npy_format_descriptor_name::value>> { + static constexpr auto name = _::value + || std::is_same::value>( + _("complex") + _(), _("longcomplex") + ); +}; + +template +struct npy_format_descriptor::value>> + : npy_format_descriptor_name { +private: + // NB: the order here must match the one in common.h + constexpr static const int values[15] = { + npy_api::NPY_BOOL_, + npy_api::NPY_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_INT16_, npy_api::NPY_UINT16_, + npy_api::NPY_INT32_, npy_api::NPY_UINT32_, npy_api::NPY_INT64_, npy_api::NPY_UINT64_, + npy_api::NPY_FLOAT_, npy_api::NPY_DOUBLE_, npy_api::NPY_LONGDOUBLE_, + npy_api::NPY_CFLOAT_, npy_api::NPY_CDOUBLE_, npy_api::NPY_CLONGDOUBLE_ + }; + +public: + static constexpr int value = values[detail::is_fmt_numeric::index]; + + static pybind11::dtype dtype() { + if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) + return reinterpret_steal(ptr); + pybind11_fail("Unsupported buffer format!"); + } +}; + +#define PYBIND11_DECL_CHAR_FMT \ + static constexpr auto name = _("S") + _(); \ + static pybind11::dtype dtype() { return pybind11::dtype(std::string("S") + std::to_string(N)); } +template struct npy_format_descriptor { PYBIND11_DECL_CHAR_FMT }; +template struct npy_format_descriptor> { PYBIND11_DECL_CHAR_FMT }; +#undef PYBIND11_DECL_CHAR_FMT + +template struct npy_format_descriptor::is_array>> { +private: + using base_descr = npy_format_descriptor::type>; +public: + static_assert(!array_info::is_empty, "Zero-sized arrays are not supported"); + + static constexpr auto name = _("(") + array_info::extents + _(")") + base_descr::name; + static pybind11::dtype dtype() { + list shape; + array_info::append_extents(shape); + return pybind11::dtype::from_args(pybind11::make_tuple(base_descr::dtype(), shape)); + } +}; + +template struct npy_format_descriptor::value>> { +private: + using base_descr = npy_format_descriptor::type>; +public: + static constexpr auto name = base_descr::name; + static pybind11::dtype dtype() { return base_descr::dtype(); } +}; + +struct field_descriptor { + const char *name; + ssize_t offset; + ssize_t size; + std::string format; + dtype descr; +}; + +inline PYBIND11_NOINLINE void register_structured_dtype( + any_container fields, + const std::type_info& tinfo, ssize_t itemsize, + bool (*direct_converter)(PyObject *, void *&)) { + + auto& numpy_internals = get_numpy_internals(); + if (numpy_internals.get_type_info(tinfo, false)) + pybind11_fail("NumPy: dtype is already registered"); + + // Use ordered fields because order matters as of NumPy 1.14: + // https://docs.scipy.org/doc/numpy/release.html#multiple-field-indexing-assignment-of-structured-arrays + std::vector ordered_fields(std::move(fields)); + std::sort(ordered_fields.begin(), ordered_fields.end(), + [](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; }); + + list names, formats, offsets; + for (auto& field : ordered_fields) { + if (!field.descr) + pybind11_fail(std::string("NumPy: unsupported field dtype: `") + + field.name + "` @ " + tinfo.name()); + names.append(PYBIND11_STR_TYPE(field.name)); + formats.append(field.descr); + offsets.append(pybind11::int_(field.offset)); + } + auto dtype_ptr = pybind11::dtype(names, formats, offsets, itemsize).release().ptr(); + + // There is an existing bug in NumPy (as of v1.11): trailing bytes are + // not encoded explicitly into the format string. This will supposedly + // get fixed in v1.12; for further details, see these: + // - https://github.com/numpy/numpy/issues/7797 + // - https://github.com/numpy/numpy/pull/7798 + // Because of this, we won't use numpy's logic to generate buffer format + // strings and will just do it ourselves. + ssize_t offset = 0; + std::ostringstream oss; + // mark the structure as unaligned with '^', because numpy and C++ don't + // always agree about alignment (particularly for complex), and we're + // explicitly listing all our padding. This depends on none of the fields + // overriding the endianness. Putting the ^ in front of individual fields + // isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049 + oss << "^T{"; + for (auto& field : ordered_fields) { + if (field.offset > offset) + oss << (field.offset - offset) << 'x'; + oss << field.format << ':' << field.name << ':'; + offset = field.offset + field.size; + } + if (itemsize > offset) + oss << (itemsize - offset) << 'x'; + oss << '}'; + auto format_str = oss.str(); + + // Sanity check: verify that NumPy properly parses our buffer format string + auto& api = npy_api::get(); + auto arr = array(buffer_info(nullptr, itemsize, format_str, 1)); + if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr())) + pybind11_fail("NumPy: invalid buffer descriptor!"); + + auto tindex = std::type_index(tinfo); + numpy_internals.registered_dtypes[tindex] = { dtype_ptr, format_str }; + get_internals().direct_conversions[tindex].push_back(direct_converter); +} + +template struct npy_format_descriptor { + static_assert(is_pod_struct::value, "Attempt to use a non-POD or unimplemented POD type as a numpy dtype"); + + static constexpr auto name = make_caster::name; + + static pybind11::dtype dtype() { + return reinterpret_borrow(dtype_ptr()); + } + + static std::string format() { + static auto format_str = get_numpy_internals().get_type_info(true)->format_str; + return format_str; + } + + static void register_dtype(any_container fields) { + register_structured_dtype(std::move(fields), typeid(typename std::remove_cv::type), + sizeof(T), &direct_converter); + } + +private: + static PyObject* dtype_ptr() { + static PyObject* ptr = get_numpy_internals().get_type_info(true)->dtype_ptr; + return ptr; + } + + static bool direct_converter(PyObject *obj, void*& value) { + auto& api = npy_api::get(); + if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) + return false; + if (auto descr = reinterpret_steal(api.PyArray_DescrFromScalar_(obj))) { + if (api.PyArray_EquivTypes_(dtype_ptr(), descr.ptr())) { + value = ((PyVoidScalarObject_Proxy *) obj)->obval; + return true; + } + } + return false; + } +}; + +#ifdef __CLION_IDE__ // replace heavy macro with dummy code for the IDE (doesn't affect code) +# define PYBIND11_NUMPY_DTYPE(Type, ...) ((void)0) +# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) ((void)0) +#else + +#define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name) \ + ::pybind11::detail::field_descriptor { \ + Name, offsetof(T, Field), sizeof(decltype(std::declval().Field)), \ + ::pybind11::format_descriptor().Field)>::format(), \ + ::pybind11::detail::npy_format_descriptor().Field)>::dtype() \ + } + +// Extract name, offset and format descriptor for a struct field +#define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field) + +// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro +// (C) William Swanson, Paul Fultz +#define PYBIND11_EVAL0(...) __VA_ARGS__ +#define PYBIND11_EVAL1(...) PYBIND11_EVAL0 (PYBIND11_EVAL0 (PYBIND11_EVAL0 (__VA_ARGS__))) +#define PYBIND11_EVAL2(...) PYBIND11_EVAL1 (PYBIND11_EVAL1 (PYBIND11_EVAL1 (__VA_ARGS__))) +#define PYBIND11_EVAL3(...) PYBIND11_EVAL2 (PYBIND11_EVAL2 (PYBIND11_EVAL2 (__VA_ARGS__))) +#define PYBIND11_EVAL4(...) PYBIND11_EVAL3 (PYBIND11_EVAL3 (PYBIND11_EVAL3 (__VA_ARGS__))) +#define PYBIND11_EVAL(...) PYBIND11_EVAL4 (PYBIND11_EVAL4 (PYBIND11_EVAL4 (__VA_ARGS__))) +#define PYBIND11_MAP_END(...) +#define PYBIND11_MAP_OUT +#define PYBIND11_MAP_COMMA , +#define PYBIND11_MAP_GET_END() 0, PYBIND11_MAP_END +#define PYBIND11_MAP_NEXT0(test, next, ...) next PYBIND11_MAP_OUT +#define PYBIND11_MAP_NEXT1(test, next) PYBIND11_MAP_NEXT0 (test, next, 0) +#define PYBIND11_MAP_NEXT(test, next) PYBIND11_MAP_NEXT1 (PYBIND11_MAP_GET_END test, next) +#ifdef _MSC_VER // MSVC is not as eager to expand macros, hence this workaround +#define PYBIND11_MAP_LIST_NEXT1(test, next) \ + PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)) +#else +#define PYBIND11_MAP_LIST_NEXT1(test, next) \ + PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0) +#endif +#define PYBIND11_MAP_LIST_NEXT(test, next) \ + PYBIND11_MAP_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next) +#define PYBIND11_MAP_LIST0(f, t, x, peek, ...) \ + f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST1) (f, t, peek, __VA_ARGS__) +#define PYBIND11_MAP_LIST1(f, t, x, peek, ...) \ + f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST0) (f, t, peek, __VA_ARGS__) +// PYBIND11_MAP_LIST(f, t, a1, a2, ...) expands to f(t, a1), f(t, a2), ... +#define PYBIND11_MAP_LIST(f, t, ...) \ + PYBIND11_EVAL (PYBIND11_MAP_LIST1 (f, t, __VA_ARGS__, (), 0)) + +#define PYBIND11_NUMPY_DTYPE(Type, ...) \ + ::pybind11::detail::npy_format_descriptor::register_dtype \ + (::std::vector<::pybind11::detail::field_descriptor> \ + {PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)}) + +#ifdef _MSC_VER +#define PYBIND11_MAP2_LIST_NEXT1(test, next) \ + PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)) +#else +#define PYBIND11_MAP2_LIST_NEXT1(test, next) \ + PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0) +#endif +#define PYBIND11_MAP2_LIST_NEXT(test, next) \ + PYBIND11_MAP2_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next) +#define PYBIND11_MAP2_LIST0(f, t, x1, x2, peek, ...) \ + f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST1) (f, t, peek, __VA_ARGS__) +#define PYBIND11_MAP2_LIST1(f, t, x1, x2, peek, ...) \ + f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST0) (f, t, peek, __VA_ARGS__) +// PYBIND11_MAP2_LIST(f, t, a1, a2, ...) expands to f(t, a1, a2), f(t, a3, a4), ... +#define PYBIND11_MAP2_LIST(f, t, ...) \ + PYBIND11_EVAL (PYBIND11_MAP2_LIST1 (f, t, __VA_ARGS__, (), 0)) + +#define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \ + ::pybind11::detail::npy_format_descriptor::register_dtype \ + (::std::vector<::pybind11::detail::field_descriptor> \ + {PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)}) + +#endif // __CLION_IDE__ + +template +using array_iterator = typename std::add_pointer::type; + +template +array_iterator array_begin(const buffer_info& buffer) { + return array_iterator(reinterpret_cast(buffer.ptr)); +} + +template +array_iterator array_end(const buffer_info& buffer) { + return array_iterator(reinterpret_cast(buffer.ptr) + buffer.size); +} + +class common_iterator { +public: + using container_type = std::vector; + using value_type = container_type::value_type; + using size_type = container_type::size_type; + + common_iterator() : p_ptr(0), m_strides() {} + + common_iterator(void* ptr, const container_type& strides, const container_type& shape) + : p_ptr(reinterpret_cast(ptr)), m_strides(strides.size()) { + m_strides.back() = static_cast(strides.back()); + for (size_type i = m_strides.size() - 1; i != 0; --i) { + size_type j = i - 1; + value_type s = static_cast(shape[i]); + m_strides[j] = strides[j] + m_strides[i] - strides[i] * s; + } + } + + void increment(size_type dim) { + p_ptr += m_strides[dim]; + } + + void* data() const { + return p_ptr; + } + +private: + char* p_ptr; + container_type m_strides; +}; + +template class multi_array_iterator { +public: + using container_type = std::vector; + + multi_array_iterator(const std::array &buffers, + const container_type &shape) + : m_shape(shape.size()), m_index(shape.size(), 0), + m_common_iterator() { + + // Manual copy to avoid conversion warning if using std::copy + for (size_t i = 0; i < shape.size(); ++i) + m_shape[i] = shape[i]; + + container_type strides(shape.size()); + for (size_t i = 0; i < N; ++i) + init_common_iterator(buffers[i], shape, m_common_iterator[i], strides); + } + + multi_array_iterator& operator++() { + for (size_t j = m_index.size(); j != 0; --j) { + size_t i = j - 1; + if (++m_index[i] != m_shape[i]) { + increment_common_iterator(i); + break; + } else { + m_index[i] = 0; + } + } + return *this; + } + + template T* data() const { + return reinterpret_cast(m_common_iterator[K].data()); + } + +private: + + using common_iter = common_iterator; + + void init_common_iterator(const buffer_info &buffer, + const container_type &shape, + common_iter &iterator, + container_type &strides) { + auto buffer_shape_iter = buffer.shape.rbegin(); + auto buffer_strides_iter = buffer.strides.rbegin(); + auto shape_iter = shape.rbegin(); + auto strides_iter = strides.rbegin(); + + while (buffer_shape_iter != buffer.shape.rend()) { + if (*shape_iter == *buffer_shape_iter) + *strides_iter = *buffer_strides_iter; + else + *strides_iter = 0; + + ++buffer_shape_iter; + ++buffer_strides_iter; + ++shape_iter; + ++strides_iter; + } + + std::fill(strides_iter, strides.rend(), 0); + iterator = common_iter(buffer.ptr, strides, shape); + } + + void increment_common_iterator(size_t dim) { + for (auto &iter : m_common_iterator) + iter.increment(dim); + } + + container_type m_shape; + container_type m_index; + std::array m_common_iterator; +}; + +enum class broadcast_trivial { non_trivial, c_trivial, f_trivial }; + +// Populates the shape and number of dimensions for the set of buffers. Returns a broadcast_trivial +// enum value indicating whether the broadcast is "trivial"--that is, has each buffer being either a +// singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous (`f_trivial`) storage +// buffer; returns `non_trivial` otherwise. +template +broadcast_trivial broadcast(const std::array &buffers, ssize_t &ndim, std::vector &shape) { + ndim = std::accumulate(buffers.begin(), buffers.end(), ssize_t(0), [](ssize_t res, const buffer_info &buf) { + return std::max(res, buf.ndim); + }); + + shape.clear(); + shape.resize((size_t) ndim, 1); + + // Figure out the output size, and make sure all input arrays conform (i.e. are either size 1 or + // the full size). + for (size_t i = 0; i < N; ++i) { + auto res_iter = shape.rbegin(); + auto end = buffers[i].shape.rend(); + for (auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end; ++shape_iter, ++res_iter) { + const auto &dim_size_in = *shape_iter; + auto &dim_size_out = *res_iter; + + // Each input dimension can either be 1 or `n`, but `n` values must match across buffers + if (dim_size_out == 1) + dim_size_out = dim_size_in; + else if (dim_size_in != 1 && dim_size_in != dim_size_out) + pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!"); + } + } + + bool trivial_broadcast_c = true; + bool trivial_broadcast_f = true; + for (size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) { + if (buffers[i].size == 1) + continue; + + // Require the same number of dimensions: + if (buffers[i].ndim != ndim) + return broadcast_trivial::non_trivial; + + // Require all dimensions be full-size: + if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin())) + return broadcast_trivial::non_trivial; + + // Check for C contiguity (but only if previous inputs were also C contiguous) + if (trivial_broadcast_c) { + ssize_t expect_stride = buffers[i].itemsize; + auto end = buffers[i].shape.crend(); + for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin(); + trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) { + if (expect_stride == *stride_iter) + expect_stride *= *shape_iter; + else + trivial_broadcast_c = false; + } + } + + // Check for Fortran contiguity (if previous inputs were also F contiguous) + if (trivial_broadcast_f) { + ssize_t expect_stride = buffers[i].itemsize; + auto end = buffers[i].shape.cend(); + for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin(); + trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) { + if (expect_stride == *stride_iter) + expect_stride *= *shape_iter; + else + trivial_broadcast_f = false; + } + } + } + + return + trivial_broadcast_c ? broadcast_trivial::c_trivial : + trivial_broadcast_f ? broadcast_trivial::f_trivial : + broadcast_trivial::non_trivial; +} + +template +struct vectorize_arg { + static_assert(!std::is_rvalue_reference::value, "Functions with rvalue reference arguments cannot be vectorized"); + // The wrapped function gets called with this type: + using call_type = remove_reference_t; + // Is this a vectorized argument? + static constexpr bool vectorize = + satisfies_any_of::value && + satisfies_none_of::value && + (!std::is_reference::value || + (std::is_lvalue_reference::value && std::is_const::value)); + // Accept this type: an array for vectorized types, otherwise the type as-is: + using type = conditional_t, array::forcecast>, T>; +}; + +template +struct vectorize_helper { +private: + static constexpr size_t N = sizeof...(Args); + static constexpr size_t NVectorized = constexpr_sum(vectorize_arg::vectorize...); + static_assert(NVectorized >= 1, + "pybind11::vectorize(...) requires a function with at least one vectorizable argument"); + +public: + template + explicit vectorize_helper(T &&f) : f(std::forward(f)) { } + + object operator()(typename vectorize_arg::type... args) { + return run(args..., + make_index_sequence(), + select_indices::vectorize...>(), + make_index_sequence()); + } + +private: + remove_reference_t f; + + // Internal compiler error in MSVC 19.16.27025.1 (Visual Studio 2017 15.9.4), when compiling with "/permissive-" flag + // when arg_call_types is manually inlined. + using arg_call_types = std::tuple::call_type...>; + template using param_n_t = typename std::tuple_element::type; + + // Runs a vectorized function given arguments tuple and three index sequences: + // - Index is the full set of 0 ... (N-1) argument indices; + // - VIndex is the subset of argument indices with vectorized parameters, letting us access + // vectorized arguments (anything not in this sequence is passed through) + // - BIndex is a incremental sequence (beginning at 0) of the same size as VIndex, so that + // we can store vectorized buffer_infos in an array (argument VIndex has its buffer at + // index BIndex in the array). + template object run( + typename vectorize_arg::type &...args, + index_sequence i_seq, index_sequence vi_seq, index_sequence bi_seq) { + + // Pointers to values the function was called with; the vectorized ones set here will start + // out as array_t pointers, but they will be changed them to T pointers before we make + // call the wrapped function. Non-vectorized pointers are left as-is. + std::array params{{ &args... }}; + + // The array of `buffer_info`s of vectorized arguments: + std::array buffers{{ reinterpret_cast(params[VIndex])->request()... }}; + + /* Determine dimensions parameters of output array */ + ssize_t nd = 0; + std::vector shape(0); + auto trivial = broadcast(buffers, nd, shape); + size_t ndim = (size_t) nd; + + size_t size = std::accumulate(shape.begin(), shape.end(), (size_t) 1, std::multiplies()); + + // If all arguments are 0-dimension arrays (i.e. single values) return a plain value (i.e. + // not wrapped in an array). + if (size == 1 && ndim == 0) { + PYBIND11_EXPAND_SIDE_EFFECTS(params[VIndex] = buffers[BIndex].ptr); + return cast(f(*reinterpret_cast *>(params[Index])...)); + } + + array_t result; + if (trivial == broadcast_trivial::f_trivial) result = array_t(shape); + else result = array_t(shape); + + if (size == 0) return std::move(result); + + /* Call the function */ + if (trivial == broadcast_trivial::non_trivial) + apply_broadcast(buffers, params, result, i_seq, vi_seq, bi_seq); + else + apply_trivial(buffers, params, result.mutable_data(), size, i_seq, vi_seq, bi_seq); + + return std::move(result); + } + + template + void apply_trivial(std::array &buffers, + std::array ¶ms, + Return *out, + size_t size, + index_sequence, index_sequence, index_sequence) { + + // Initialize an array of mutable byte references and sizes with references set to the + // appropriate pointer in `params`; as we iterate, we'll increment each pointer by its size + // (except for singletons, which get an increment of 0). + std::array, NVectorized> vecparams{{ + std::pair( + reinterpret_cast(params[VIndex] = buffers[BIndex].ptr), + buffers[BIndex].size == 1 ? 0 : sizeof(param_n_t) + )... + }}; + + for (size_t i = 0; i < size; ++i) { + out[i] = f(*reinterpret_cast *>(params[Index])...); + for (auto &x : vecparams) x.first += x.second; + } + } + + template + void apply_broadcast(std::array &buffers, + std::array ¶ms, + array_t &output_array, + index_sequence, index_sequence, index_sequence) { + + buffer_info output = output_array.request(); + multi_array_iterator input_iter(buffers, output.shape); + + for (array_iterator iter = array_begin(output), end = array_end(output); + iter != end; + ++iter, ++input_iter) { + PYBIND11_EXPAND_SIDE_EFFECTS(( + params[VIndex] = input_iter.template data() + )); + *iter = f(*reinterpret_cast *>(std::get(params))...); + } + } +}; + +template +vectorize_helper +vectorize_extractor(const Func &f, Return (*) (Args ...)) { + return detail::vectorize_helper(f); +} + +template struct handle_type_name> { + static constexpr auto name = _("numpy.ndarray[") + npy_format_descriptor::name + _("]"); +}; + +NAMESPACE_END(detail) + +// Vanilla pointer vectorizer: +template +detail::vectorize_helper +vectorize(Return (*f) (Args ...)) { + return detail::vectorize_helper(f); +} + +// lambda vectorizer: +template ::value, int> = 0> +auto vectorize(Func &&f) -> decltype( + detail::vectorize_extractor(std::forward(f), (detail::function_signature_t *) nullptr)) { + return detail::vectorize_extractor(std::forward(f), (detail::function_signature_t *) nullptr); +} + +// Vectorize a class method (non-const): +template ())), Return, Class *, Args...>> +Helper vectorize(Return (Class::*f)(Args...)) { + return Helper(std::mem_fn(f)); +} + +// Vectorize a class method (const): +template ())), Return, const Class *, Args...>> +Helper vectorize(Return (Class::*f)(Args...) const) { + return Helper(std::mem_fn(f)); +} + +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/operators.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/operators.h new file mode 100644 index 0000000000000000000000000000000000000000..b3dd62c3b6452467838f48380c91661b429bfc7b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/operators.h @@ -0,0 +1,168 @@ +/* + pybind11/operator.h: Metatemplates for operator overloading + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" + +#if defined(__clang__) && !defined(__INTEL_COMPILER) +# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type())) +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/// Enumeration with all supported operator types +enum op_id : int { + op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow, op_lshift, + op_rshift, op_and, op_xor, op_or, op_neg, op_pos, op_abs, op_invert, + op_int, op_long, op_float, op_str, op_cmp, op_gt, op_ge, op_lt, op_le, + op_eq, op_ne, op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift, + op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool, op_nonzero, + op_repr, op_truediv, op_itruediv, op_hash +}; + +enum op_type : int { + op_l, /* base type on left */ + op_r, /* base type on right */ + op_u /* unary operator */ +}; + +struct self_t { }; +static const self_t self = self_t(); + +/// Type for an unused type slot +struct undefined_t { }; + +/// Don't warn about an unused variable +inline self_t __self() { return self; } + +/// base template of operator implementations +template struct op_impl { }; + +/// Operator implementation generator +template struct op_ { + template void execute(Class &cl, const Extra&... extra) const { + using Base = typename Class::type; + using L_type = conditional_t::value, Base, L>; + using R_type = conditional_t::value, Base, R>; + using op = op_impl; + cl.def(op::name(), &op::execute, is_operator(), extra...); + #if PY_MAJOR_VERSION < 3 + if (id == op_truediv || id == op_itruediv) + cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__", + &op::execute, is_operator(), extra...); + #endif + } + template void execute_cast(Class &cl, const Extra&... extra) const { + using Base = typename Class::type; + using L_type = conditional_t::value, Base, L>; + using R_type = conditional_t::value, Base, R>; + using op = op_impl; + cl.def(op::name(), &op::execute_cast, is_operator(), extra...); + #if PY_MAJOR_VERSION < 3 + if (id == op_truediv || id == op_itruediv) + cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__", + &op::execute, is_operator(), extra...); + #endif + } +}; + +#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \ + static B execute_cast(const L &l, const R &r) { return B(expr); } \ +}; \ +template struct op_impl { \ + static char const* name() { return "__" #rid "__"; } \ + static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \ + static B execute_cast(const R &r, const L &l) { return B(expr); } \ +}; \ +inline op_ op(const self_t &, const self_t &) { \ + return op_(); \ +} \ +template op_ op(const self_t &, const T &) { \ + return op_(); \ +} \ +template op_ op(const T &, const self_t &) { \ + return op_(); \ +} + +#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \ + static B execute_cast(L &l, const R &r) { return B(expr); } \ +}; \ +template op_ op(const self_t &, const T &) { \ + return op_(); \ +} + +#define PYBIND11_UNARY_OPERATOR(id, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(const L &l) -> decltype(expr) { return expr; } \ + static B execute_cast(const L &l) { return B(expr); } \ +}; \ +inline op_ op(const self_t &) { \ + return op_(); \ +} + +PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r) +PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r) +PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l * r) +PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r) +PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r) +PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r) +PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r) +PYBIND11_BINARY_OPERATOR(and, rand, operator&, l & r) +PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r) +PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r) +PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r) +PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r) +PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r) +PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r) +PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r) +PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r) +//PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r)) +PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r) +PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r) +PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r) +PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r) +PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r) +PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r) +PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r) +PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r) +PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r) +PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r) +PYBIND11_UNARY_OPERATOR(neg, operator-, -l) +PYBIND11_UNARY_OPERATOR(pos, operator+, +l) +PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l)) +PYBIND11_UNARY_OPERATOR(hash, hash, std::hash()(l)) +PYBIND11_UNARY_OPERATOR(invert, operator~, (~l)) +PYBIND11_UNARY_OPERATOR(bool, operator!, !!l) +PYBIND11_UNARY_OPERATOR(int, int_, (int) l) +PYBIND11_UNARY_OPERATOR(float, float_, (double) l) + +#undef PYBIND11_BINARY_OPERATOR +#undef PYBIND11_INPLACE_OPERATOR +#undef PYBIND11_UNARY_OPERATOR +NAMESPACE_END(detail) + +using detail::self; + +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/options.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/options.h new file mode 100644 index 0000000000000000000000000000000000000000..cc1e1f6f0f28950729baacc1ddf1ac8fe78ad421 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/options.h @@ -0,0 +1,65 @@ +/* + pybind11/options.h: global settings that are configurable at runtime. + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/common.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +class options { +public: + + // Default RAII constructor, which leaves settings as they currently are. + options() : previous_state(global_state()) {} + + // Class is non-copyable. + options(const options&) = delete; + options& operator=(const options&) = delete; + + // Destructor, which restores settings that were in effect before. + ~options() { + global_state() = previous_state; + } + + // Setter methods (affect the global state): + + options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; } + + options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; } + + options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; } + + options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; } + + // Getter methods (return the global state): + + static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; } + + static bool show_function_signatures() { return global_state().show_function_signatures; } + + // This type is not meant to be allocated on the heap. + void* operator new(size_t) = delete; + +private: + + struct state { + bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings. + bool show_function_signatures = true; //< Include auto-generated function signatures in docstrings. + }; + + static state &global_state() { + static state instance; + return instance; + } + + state previous_state; +}; + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/pybind11.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/pybind11.h new file mode 100644 index 0000000000000000000000000000000000000000..d95d61f7bb8c240e463cf3c6f4c673288039e3be --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/pybind11.h @@ -0,0 +1,2183 @@ +/* + pybind11/pybind11.h: Main header file of the C++11 python + binding generator library + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#if defined(__INTEL_COMPILER) +# pragma warning push +# pragma warning disable 68 // integer conversion resulted in a change of sign +# pragma warning disable 186 // pointless comparison of unsigned integer with zero +# pragma warning disable 878 // incompatible exception specifications +# pragma warning disable 1334 // the "template" keyword used for syntactic disambiguation may only be used within a template +# pragma warning disable 1682 // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem) +# pragma warning disable 1786 // function "strdup" was declared deprecated +# pragma warning disable 1875 // offsetof applied to non-POD (Plain Old Data) types is nonstandard +# pragma warning disable 2196 // warning #2196: routine is both "inline" and "noinline" +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +# pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted +# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning) +# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name +# pragma warning(disable: 4702) // warning C4702: unreachable code +# pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified +#elif defined(__GNUG__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-but-set-parameter" +# pragma GCC diagnostic ignored "-Wunused-but-set-variable" +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +# pragma GCC diagnostic ignored "-Wstrict-aliasing" +# pragma GCC diagnostic ignored "-Wattributes" +# if __GNUC__ >= 7 +# pragma GCC diagnostic ignored "-Wnoexcept-type" +# endif +#endif + +#include "attr.h" +#include "options.h" +#include "detail/class.h" +#include "detail/init.h" + +#if defined(__GNUG__) && !defined(__clang__) +# include +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object +class cpp_function : public function { +public: + cpp_function() { } + cpp_function(std::nullptr_t) { } + + /// Construct a cpp_function from a vanilla function pointer + template + cpp_function(Return (*f)(Args...), const Extra&... extra) { + initialize(f, f, extra...); + } + + /// Construct a cpp_function from a lambda function (possibly with internal state) + template ::value>> + cpp_function(Func &&f, const Extra&... extra) { + initialize(std::forward(f), + (detail::function_signature_t *) nullptr, extra...); + } + + /// Construct a cpp_function from a class method (non-const) + template + cpp_function(Return (Class::*f)(Arg...), const Extra&... extra) { + initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + (Return (*) (Class *, Arg...)) nullptr, extra...); + } + + /// Construct a cpp_function from a class method (const) + template + cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) { + initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + (Return (*)(const Class *, Arg ...)) nullptr, extra...); + } + + /// Return the function name + object name() const { return attr("__name__"); } + +protected: + /// Space optimization: don't inline this frequently instantiated fragment + PYBIND11_NOINLINE detail::function_record *make_function_record() { + return new detail::function_record(); + } + + /// Special internal constructor for functors, lambda functions, etc. + template + void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) { + using namespace detail; + struct capture { remove_reference_t f; }; + + /* Store the function including any extra state it might have (e.g. a lambda capture object) */ + auto rec = make_function_record(); + + /* Store the capture object directly in the function record if there is enough space */ + if (sizeof(capture) <= sizeof(rec->data)) { + /* Without these pragmas, GCC warns that there might not be + enough space to use the placement new operator. However, the + 'if' statement above ensures that this is the case. */ +#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 6 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wplacement-new" +#endif + new ((capture *) &rec->data) capture { std::forward(f) }; +#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 6 +# pragma GCC diagnostic pop +#endif + if (!std::is_trivially_destructible::value) + rec->free_data = [](function_record *r) { ((capture *) &r->data)->~capture(); }; + } else { + rec->data[0] = new capture { std::forward(f) }; + rec->free_data = [](function_record *r) { delete ((capture *) r->data[0]); }; + } + + /* Type casters for the function arguments and return value */ + using cast_in = argument_loader; + using cast_out = make_caster< + conditional_t::value, void_type, Return> + >; + + static_assert(expected_num_args(sizeof...(Args), cast_in::has_args, cast_in::has_kwargs), + "The number of argument annotations does not match the number of function arguments"); + + /* Dispatch code which converts function arguments and performs the actual function call */ + rec->impl = [](function_call &call) -> handle { + cast_in args_converter; + + /* Try to cast the function arguments into the C++ domain */ + if (!args_converter.load_args(call)) + return PYBIND11_TRY_NEXT_OVERLOAD; + + /* Invoke call policy pre-call hook */ + process_attributes::precall(call); + + /* Get a pointer to the capture object */ + auto data = (sizeof(capture) <= sizeof(call.func.data) + ? &call.func.data : call.func.data[0]); + capture *cap = const_cast(reinterpret_cast(data)); + + /* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */ + return_value_policy policy = return_value_policy_override::policy(call.func.policy); + + /* Function scope guard -- defaults to the compile-to-nothing `void_type` */ + using Guard = extract_guard_t; + + /* Perform the function call */ + handle result = cast_out::cast( + std::move(args_converter).template call(cap->f), policy, call.parent); + + /* Invoke call policy post-call hook */ + process_attributes::postcall(call, result); + + return result; + }; + + /* Process any user-provided function attributes */ + process_attributes::init(extra..., rec); + + /* Generate a readable signature describing the function's arguments and return value types */ + static constexpr auto signature = _("(") + cast_in::arg_names + _(") -> ") + cast_out::name; + PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types(); + + /* Register the function with Python from generic (non-templated) code */ + initialize_generic(rec, signature.text, types.data(), sizeof...(Args)); + + if (cast_in::has_args) rec->has_args = true; + if (cast_in::has_kwargs) rec->has_kwargs = true; + + /* Stash some additional information used by an important optimization in 'functional.h' */ + using FunctionType = Return (*)(Args...); + constexpr bool is_function_ptr = + std::is_convertible::value && + sizeof(capture) == sizeof(void *); + if (is_function_ptr) { + rec->is_stateless = true; + rec->data[1] = const_cast(reinterpret_cast(&typeid(FunctionType))); + } + } + + /// Register a function call with Python (generic non-templated code goes here) + void initialize_generic(detail::function_record *rec, const char *text, + const std::type_info *const *types, size_t args) { + + /* Create copies of all referenced C-style strings */ + rec->name = strdup(rec->name ? rec->name : ""); + if (rec->doc) rec->doc = strdup(rec->doc); + for (auto &a: rec->args) { + if (a.name) + a.name = strdup(a.name); + if (a.descr) + a.descr = strdup(a.descr); + else if (a.value) + a.descr = strdup(a.value.attr("__repr__")().cast().c_str()); + } + + rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__"); + +#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING) + if (rec->is_constructor && !rec->is_new_style_constructor) { + const auto class_name = std::string(((PyTypeObject *) rec->scope.ptr())->tp_name); + const auto func_name = std::string(rec->name); + PyErr_WarnEx( + PyExc_FutureWarning, + ("pybind11-bound class '" + class_name + "' is using an old-style " + "placement-new '" + func_name + "' which has been deprecated. See " + "the upgrade guide in pybind11's docs. This message is only visible " + "when compiled in debug mode.").c_str(), 0 + ); + } +#endif + + /* Generate a proper function signature */ + std::string signature; + size_t type_index = 0, arg_index = 0; + for (auto *pc = text; *pc != '\0'; ++pc) { + const auto c = *pc; + + if (c == '{') { + // Write arg name for everything except *args and **kwargs. + if (*(pc + 1) == '*') + continue; + + if (arg_index < rec->args.size() && rec->args[arg_index].name) { + signature += rec->args[arg_index].name; + } else if (arg_index == 0 && rec->is_method) { + signature += "self"; + } else { + signature += "arg" + std::to_string(arg_index - (rec->is_method ? 1 : 0)); + } + signature += ": "; + } else if (c == '}') { + // Write default value if available. + if (arg_index < rec->args.size() && rec->args[arg_index].descr) { + signature += " = "; + signature += rec->args[arg_index].descr; + } + arg_index++; + } else if (c == '%') { + const std::type_info *t = types[type_index++]; + if (!t) + pybind11_fail("Internal error while parsing type signature (1)"); + if (auto tinfo = detail::get_type_info(*t)) { + handle th((PyObject *) tinfo->type); + signature += + th.attr("__module__").cast() + "." + + th.attr("__qualname__").cast(); // Python 3.3+, but we backport it to earlier versions + } else if (rec->is_new_style_constructor && arg_index == 0) { + // A new-style `__init__` takes `self` as `value_and_holder`. + // Rewrite it to the proper class type. + signature += + rec->scope.attr("__module__").cast() + "." + + rec->scope.attr("__qualname__").cast(); + } else { + std::string tname(t->name()); + detail::clean_type_id(tname); + signature += tname; + } + } else { + signature += c; + } + } + if (arg_index != args || types[type_index] != nullptr) + pybind11_fail("Internal error while parsing type signature (2)"); + +#if PY_MAJOR_VERSION < 3 + if (strcmp(rec->name, "__next__") == 0) { + std::free(rec->name); + rec->name = strdup("next"); + } else if (strcmp(rec->name, "__bool__") == 0) { + std::free(rec->name); + rec->name = strdup("__nonzero__"); + } +#endif + rec->signature = strdup(signature.c_str()); + rec->args.shrink_to_fit(); + rec->nargs = (std::uint16_t) args; + + if (rec->sibling && PYBIND11_INSTANCE_METHOD_CHECK(rec->sibling.ptr())) + rec->sibling = PYBIND11_INSTANCE_METHOD_GET_FUNCTION(rec->sibling.ptr()); + + detail::function_record *chain = nullptr, *chain_start = rec; + if (rec->sibling) { + if (PyCFunction_Check(rec->sibling.ptr())) { + auto rec_capsule = reinterpret_borrow(PyCFunction_GET_SELF(rec->sibling.ptr())); + chain = (detail::function_record *) rec_capsule; + /* Never append a method to an overload chain of a parent class; + instead, hide the parent's overloads in this case */ + if (!chain->scope.is(rec->scope)) + chain = nullptr; + } + // Don't trigger for things like the default __init__, which are wrapper_descriptors that we are intentionally replacing + else if (!rec->sibling.is_none() && rec->name[0] != '_') + pybind11_fail("Cannot overload existing non-function object \"" + std::string(rec->name) + + "\" with a function of the same name"); + } + + if (!chain) { + /* No existing overload was found, create a new function object */ + rec->def = new PyMethodDef(); + std::memset(rec->def, 0, sizeof(PyMethodDef)); + rec->def->ml_name = rec->name; + rec->def->ml_meth = reinterpret_cast(reinterpret_cast(*dispatcher)); + rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS; + + capsule rec_capsule(rec, [](void *ptr) { + destruct((detail::function_record *) ptr); + }); + + object scope_module; + if (rec->scope) { + if (hasattr(rec->scope, "__module__")) { + scope_module = rec->scope.attr("__module__"); + } else if (hasattr(rec->scope, "__name__")) { + scope_module = rec->scope.attr("__name__"); + } + } + + m_ptr = PyCFunction_NewEx(rec->def, rec_capsule.ptr(), scope_module.ptr()); + if (!m_ptr) + pybind11_fail("cpp_function::cpp_function(): Could not allocate function object"); + } else { + /* Append at the end of the overload chain */ + m_ptr = rec->sibling.ptr(); + inc_ref(); + chain_start = chain; + if (chain->is_method != rec->is_method) + pybind11_fail("overloading a method with both static and instance methods is not supported; " + #if defined(NDEBUG) + "compile in debug mode for more details" + #else + "error while attempting to bind " + std::string(rec->is_method ? "instance" : "static") + " method " + + std::string(pybind11::str(rec->scope.attr("__name__"))) + "." + std::string(rec->name) + signature + #endif + ); + while (chain->next) + chain = chain->next; + chain->next = rec; + } + + std::string signatures; + int index = 0; + /* Create a nice pydoc rec including all signatures and + docstrings of the functions in the overload chain */ + if (chain && options::show_function_signatures()) { + // First a generic signature + signatures += rec->name; + signatures += "(*args, **kwargs)\n"; + signatures += "Overloaded function.\n\n"; + } + // Then specific overload signatures + bool first_user_def = true; + for (auto it = chain_start; it != nullptr; it = it->next) { + if (options::show_function_signatures()) { + if (index > 0) signatures += "\n"; + if (chain) + signatures += std::to_string(++index) + ". "; + signatures += rec->name; + signatures += it->signature; + signatures += "\n"; + } + if (it->doc && strlen(it->doc) > 0 && options::show_user_defined_docstrings()) { + // If we're appending another docstring, and aren't printing function signatures, we + // need to append a newline first: + if (!options::show_function_signatures()) { + if (first_user_def) first_user_def = false; + else signatures += "\n"; + } + if (options::show_function_signatures()) signatures += "\n"; + signatures += it->doc; + if (options::show_function_signatures()) signatures += "\n"; + } + } + + /* Install docstring */ + PyCFunctionObject *func = (PyCFunctionObject *) m_ptr; + if (func->m_ml->ml_doc) + std::free(const_cast(func->m_ml->ml_doc)); + func->m_ml->ml_doc = strdup(signatures.c_str()); + + if (rec->is_method) { + m_ptr = PYBIND11_INSTANCE_METHOD_NEW(m_ptr, rec->scope.ptr()); + if (!m_ptr) + pybind11_fail("cpp_function::cpp_function(): Could not allocate instance method object"); + Py_DECREF(func); + } + } + + /// When a cpp_function is GCed, release any memory allocated by pybind11 + static void destruct(detail::function_record *rec) { + while (rec) { + detail::function_record *next = rec->next; + if (rec->free_data) + rec->free_data(rec); + std::free((char *) rec->name); + std::free((char *) rec->doc); + std::free((char *) rec->signature); + for (auto &arg: rec->args) { + std::free(const_cast(arg.name)); + std::free(const_cast(arg.descr)); + arg.value.dec_ref(); + } + if (rec->def) { + std::free(const_cast(rec->def->ml_doc)); + delete rec->def; + } + delete rec; + rec = next; + } + } + + /// Main dispatch logic for calls to functions bound using pybind11 + static PyObject *dispatcher(PyObject *self, PyObject *args_in, PyObject *kwargs_in) { + using namespace detail; + + /* Iterator over the list of potentially admissible overloads */ + const function_record *overloads = (function_record *) PyCapsule_GetPointer(self, nullptr), + *it = overloads; + + /* Need to know how many arguments + keyword arguments there are to pick the right overload */ + const size_t n_args_in = (size_t) PyTuple_GET_SIZE(args_in); + + handle parent = n_args_in > 0 ? PyTuple_GET_ITEM(args_in, 0) : nullptr, + result = PYBIND11_TRY_NEXT_OVERLOAD; + + auto self_value_and_holder = value_and_holder(); + if (overloads->is_constructor) { + const auto tinfo = get_type_info((PyTypeObject *) overloads->scope.ptr()); + const auto pi = reinterpret_cast(parent.ptr()); + self_value_and_holder = pi->get_value_and_holder(tinfo, false); + + if (!self_value_and_holder.type || !self_value_and_holder.inst) { + PyErr_SetString(PyExc_TypeError, "__init__(self, ...) called with invalid `self` argument"); + return nullptr; + } + + // If this value is already registered it must mean __init__ is invoked multiple times; + // we really can't support that in C++, so just ignore the second __init__. + if (self_value_and_holder.instance_registered()) + return none().release().ptr(); + } + + try { + // We do this in two passes: in the first pass, we load arguments with `convert=false`; + // in the second, we allow conversion (except for arguments with an explicit + // py::arg().noconvert()). This lets us prefer calls without conversion, with + // conversion as a fallback. + std::vector second_pass; + + // However, if there are no overloads, we can just skip the no-convert pass entirely + const bool overloaded = it != nullptr && it->next != nullptr; + + for (; it != nullptr; it = it->next) { + + /* For each overload: + 1. Copy all positional arguments we were given, also checking to make sure that + named positional arguments weren't *also* specified via kwarg. + 2. If we weren't given enough, try to make up the omitted ones by checking + whether they were provided by a kwarg matching the `py::arg("name")` name. If + so, use it (and remove it from kwargs; if not, see if the function binding + provided a default that we can use. + 3. Ensure that either all keyword arguments were "consumed", or that the function + takes a kwargs argument to accept unconsumed kwargs. + 4. Any positional arguments still left get put into a tuple (for args), and any + leftover kwargs get put into a dict. + 5. Pack everything into a vector; if we have py::args or py::kwargs, they are an + extra tuple or dict at the end of the positional arguments. + 6. Call the function call dispatcher (function_record::impl) + + If one of these fail, move on to the next overload and keep trying until we get a + result other than PYBIND11_TRY_NEXT_OVERLOAD. + */ + + const function_record &func = *it; + size_t pos_args = func.nargs; // Number of positional arguments that we need + if (func.has_args) --pos_args; // (but don't count py::args + if (func.has_kwargs) --pos_args; // or py::kwargs) + + if (!func.has_args && n_args_in > pos_args) + continue; // Too many arguments for this overload + + if (n_args_in < pos_args && func.args.size() < pos_args) + continue; // Not enough arguments given, and not enough defaults to fill in the blanks + + function_call call(func, parent); + + size_t args_to_copy = (std::min)(pos_args, n_args_in); // Protect std::min with parentheses + size_t args_copied = 0; + + // 0. Inject new-style `self` argument + if (func.is_new_style_constructor) { + // The `value` may have been preallocated by an old-style `__init__` + // if it was a preceding candidate for overload resolution. + if (self_value_and_holder) + self_value_and_holder.type->dealloc(self_value_and_holder); + + call.init_self = PyTuple_GET_ITEM(args_in, 0); + call.args.push_back(reinterpret_cast(&self_value_and_holder)); + call.args_convert.push_back(false); + ++args_copied; + } + + // 1. Copy any position arguments given. + bool bad_arg = false; + for (; args_copied < args_to_copy; ++args_copied) { + const argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr; + if (kwargs_in && arg_rec && arg_rec->name && PyDict_GetItemString(kwargs_in, arg_rec->name)) { + bad_arg = true; + break; + } + + handle arg(PyTuple_GET_ITEM(args_in, args_copied)); + if (arg_rec && !arg_rec->none && arg.is_none()) { + bad_arg = true; + break; + } + call.args.push_back(arg); + call.args_convert.push_back(arg_rec ? arg_rec->convert : true); + } + if (bad_arg) + continue; // Maybe it was meant for another overload (issue #688) + + // We'll need to copy this if we steal some kwargs for defaults + dict kwargs = reinterpret_borrow(kwargs_in); + + // 2. Check kwargs and, failing that, defaults that may help complete the list + if (args_copied < pos_args) { + bool copied_kwargs = false; + + for (; args_copied < pos_args; ++args_copied) { + const auto &arg = func.args[args_copied]; + + handle value; + if (kwargs_in && arg.name) + value = PyDict_GetItemString(kwargs.ptr(), arg.name); + + if (value) { + // Consume a kwargs value + if (!copied_kwargs) { + kwargs = reinterpret_steal(PyDict_Copy(kwargs.ptr())); + copied_kwargs = true; + } + PyDict_DelItemString(kwargs.ptr(), arg.name); + } else if (arg.value) { + value = arg.value; + } + + if (value) { + call.args.push_back(value); + call.args_convert.push_back(arg.convert); + } + else + break; + } + + if (args_copied < pos_args) + continue; // Not enough arguments, defaults, or kwargs to fill the positional arguments + } + + // 3. Check everything was consumed (unless we have a kwargs arg) + if (kwargs && kwargs.size() > 0 && !func.has_kwargs) + continue; // Unconsumed kwargs, but no py::kwargs argument to accept them + + // 4a. If we have a py::args argument, create a new tuple with leftovers + if (func.has_args) { + tuple extra_args; + if (args_to_copy == 0) { + // We didn't copy out any position arguments from the args_in tuple, so we + // can reuse it directly without copying: + extra_args = reinterpret_borrow(args_in); + } else if (args_copied >= n_args_in) { + extra_args = tuple(0); + } else { + size_t args_size = n_args_in - args_copied; + extra_args = tuple(args_size); + for (size_t i = 0; i < args_size; ++i) { + extra_args[i] = PyTuple_GET_ITEM(args_in, args_copied + i); + } + } + call.args.push_back(extra_args); + call.args_convert.push_back(false); + call.args_ref = std::move(extra_args); + } + + // 4b. If we have a py::kwargs, pass on any remaining kwargs + if (func.has_kwargs) { + if (!kwargs.ptr()) + kwargs = dict(); // If we didn't get one, send an empty one + call.args.push_back(kwargs); + call.args_convert.push_back(false); + call.kwargs_ref = std::move(kwargs); + } + + // 5. Put everything in a vector. Not technically step 5, we've been building it + // in `call.args` all along. + #if !defined(NDEBUG) + if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs) + pybind11_fail("Internal error: function call dispatcher inserted wrong number of arguments!"); + #endif + + std::vector second_pass_convert; + if (overloaded) { + // We're in the first no-convert pass, so swap out the conversion flags for a + // set of all-false flags. If the call fails, we'll swap the flags back in for + // the conversion-allowed call below. + second_pass_convert.resize(func.nargs, false); + call.args_convert.swap(second_pass_convert); + } + + // 6. Call the function. + try { + loader_life_support guard{}; + result = func.impl(call); + } catch (reference_cast_error &) { + result = PYBIND11_TRY_NEXT_OVERLOAD; + } + + if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) + break; + + if (overloaded) { + // The (overloaded) call failed; if the call has at least one argument that + // permits conversion (i.e. it hasn't been explicitly specified `.noconvert()`) + // then add this call to the list of second pass overloads to try. + for (size_t i = func.is_method ? 1 : 0; i < pos_args; i++) { + if (second_pass_convert[i]) { + // Found one: swap the converting flags back in and store the call for + // the second pass. + call.args_convert.swap(second_pass_convert); + second_pass.push_back(std::move(call)); + break; + } + } + } + } + + if (overloaded && !second_pass.empty() && result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) { + // The no-conversion pass finished without success, try again with conversion allowed + for (auto &call : second_pass) { + try { + loader_life_support guard{}; + result = call.func.impl(call); + } catch (reference_cast_error &) { + result = PYBIND11_TRY_NEXT_OVERLOAD; + } + + if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) { + // The error reporting logic below expects 'it' to be valid, as it would be + // if we'd encountered this failure in the first-pass loop. + if (!result) + it = &call.func; + break; + } + } + } + } catch (error_already_set &e) { + e.restore(); + return nullptr; +#if defined(__GNUG__) && !defined(__clang__) + } catch ( abi::__forced_unwind& ) { + throw; +#endif + } catch (...) { + /* When an exception is caught, give each registered exception + translator a chance to translate it to a Python exception + in reverse order of registration. + + A translator may choose to do one of the following: + + - catch the exception and call PyErr_SetString or PyErr_SetObject + to set a standard (or custom) Python exception, or + - do nothing and let the exception fall through to the next translator, or + - delegate translation to the next translator by throwing a new type of exception. */ + + auto last_exception = std::current_exception(); + auto ®istered_exception_translators = get_internals().registered_exception_translators; + for (auto& translator : registered_exception_translators) { + try { + translator(last_exception); + } catch (...) { + last_exception = std::current_exception(); + continue; + } + return nullptr; + } + PyErr_SetString(PyExc_SystemError, "Exception escaped from default exception translator!"); + return nullptr; + } + + auto append_note_if_missing_header_is_suspected = [](std::string &msg) { + if (msg.find("std::") != std::string::npos) { + msg += "\n\n" + "Did you forget to `#include `? Or ,\n" + ", , etc. Some automatic\n" + "conversions are optional and require extra headers to be included\n" + "when compiling your pybind11 module."; + } + }; + + if (result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) { + if (overloads->is_operator) + return handle(Py_NotImplemented).inc_ref().ptr(); + + std::string msg = std::string(overloads->name) + "(): incompatible " + + std::string(overloads->is_constructor ? "constructor" : "function") + + " arguments. The following argument types are supported:\n"; + + int ctr = 0; + for (const function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) { + msg += " "+ std::to_string(++ctr) + ". "; + + bool wrote_sig = false; + if (overloads->is_constructor) { + // For a constructor, rewrite `(self: Object, arg0, ...) -> NoneType` as `Object(arg0, ...)` + std::string sig = it2->signature; + size_t start = sig.find('(') + 7; // skip "(self: " + if (start < sig.size()) { + // End at the , for the next argument + size_t end = sig.find(", "), next = end + 2; + size_t ret = sig.rfind(" -> "); + // Or the ), if there is no comma: + if (end >= sig.size()) next = end = sig.find(')'); + if (start < end && next < sig.size()) { + msg.append(sig, start, end - start); + msg += '('; + msg.append(sig, next, ret - next); + wrote_sig = true; + } + } + } + if (!wrote_sig) msg += it2->signature; + + msg += "\n"; + } + msg += "\nInvoked with: "; + auto args_ = reinterpret_borrow(args_in); + bool some_args = false; + for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) { + if (!some_args) some_args = true; + else msg += ", "; + msg += pybind11::repr(args_[ti]); + } + if (kwargs_in) { + auto kwargs = reinterpret_borrow(kwargs_in); + if (kwargs.size() > 0) { + if (some_args) msg += "; "; + msg += "kwargs: "; + bool first = true; + for (auto kwarg : kwargs) { + if (first) first = false; + else msg += ", "; + msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second); + } + } + } + + append_note_if_missing_header_is_suspected(msg); + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return nullptr; + } else if (!result) { + std::string msg = "Unable to convert function return value to a " + "Python type! The signature was\n\t"; + msg += it->signature; + append_note_if_missing_header_is_suspected(msg); + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return nullptr; + } else { + if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) { + auto *pi = reinterpret_cast(parent.ptr()); + self_value_and_holder.type->init_instance(pi, nullptr); + } + return result.ptr(); + } + } +}; + +/// Wrapper for Python extension modules +class module : public object { +public: + PYBIND11_OBJECT_DEFAULT(module, object, PyModule_Check) + + /// Create a new top-level Python module with the given name and docstring + explicit module(const char *name, const char *doc = nullptr) { + if (!options::show_user_defined_docstrings()) doc = nullptr; +#if PY_MAJOR_VERSION >= 3 + PyModuleDef *def = new PyModuleDef(); + std::memset(def, 0, sizeof(PyModuleDef)); + def->m_name = name; + def->m_doc = doc; + def->m_size = -1; + Py_INCREF(def); + m_ptr = PyModule_Create(def); +#else + m_ptr = Py_InitModule3(name, nullptr, doc); +#endif + if (m_ptr == nullptr) + pybind11_fail("Internal error in module::module()"); + inc_ref(); + } + + /** \rst + Create Python binding for a new function within the module scope. ``Func`` + can be a plain C++ function, a function pointer, or a lambda function. For + details on the ``Extra&& ... extra`` argument, see section :ref:`extras`. + \endrst */ + template + module &def(const char *name_, Func &&f, const Extra& ... extra) { + cpp_function func(std::forward(f), name(name_), scope(*this), + sibling(getattr(*this, name_, none())), extra...); + // NB: allow overwriting here because cpp_function sets up a chain with the intention of + // overwriting (and has already checked internally that it isn't overwriting non-functions). + add_object(name_, func, true /* overwrite */); + return *this; + } + + /** \rst + Create and return a new Python submodule with the given name and docstring. + This also works recursively, i.e. + + .. code-block:: cpp + + py::module m("example", "pybind11 example plugin"); + py::module m2 = m.def_submodule("sub", "A submodule of 'example'"); + py::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'"); + \endrst */ + module def_submodule(const char *name, const char *doc = nullptr) { + std::string full_name = std::string(PyModule_GetName(m_ptr)) + + std::string(".") + std::string(name); + auto result = reinterpret_borrow(PyImport_AddModule(full_name.c_str())); + if (doc && options::show_user_defined_docstrings()) + result.attr("__doc__") = pybind11::str(doc); + attr(name) = result; + return result; + } + + /// Import and return a module or throws `error_already_set`. + static module import(const char *name) { + PyObject *obj = PyImport_ImportModule(name); + if (!obj) + throw error_already_set(); + return reinterpret_steal(obj); + } + + /// Reload the module or throws `error_already_set`. + void reload() { + PyObject *obj = PyImport_ReloadModule(ptr()); + if (!obj) + throw error_already_set(); + *this = reinterpret_steal(obj); + } + + // Adds an object to the module using the given name. Throws if an object with the given name + // already exists. + // + // overwrite should almost always be false: attempting to overwrite objects that pybind11 has + // established will, in most cases, break things. + PYBIND11_NOINLINE void add_object(const char *name, handle obj, bool overwrite = false) { + if (!overwrite && hasattr(*this, name)) + pybind11_fail("Error during initialization: multiple incompatible definitions with name \"" + + std::string(name) + "\""); + + PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */); + } +}; + +/// \ingroup python_builtins +/// Return a dictionary representing the global variables in the current execution frame, +/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded). +inline dict globals() { + PyObject *p = PyEval_GetGlobals(); + return reinterpret_borrow(p ? p : module::import("__main__").attr("__dict__").ptr()); +} + +NAMESPACE_BEGIN(detail) +/// Generic support for creating new Python heap types +class generic_type : public object { + template friend class class_; +public: + PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check) +protected: + void initialize(const type_record &rec) { + if (rec.scope && hasattr(rec.scope, rec.name)) + pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec.name) + + "\": an object with that name is already defined"); + + if (rec.module_local ? get_local_type_info(*rec.type) : get_global_type_info(*rec.type)) + pybind11_fail("generic_type: type \"" + std::string(rec.name) + + "\" is already registered!"); + + m_ptr = make_new_python_type(rec); + + /* Register supplemental type information in C++ dict */ + auto *tinfo = new detail::type_info(); + tinfo->type = (PyTypeObject *) m_ptr; + tinfo->cpptype = rec.type; + tinfo->type_size = rec.type_size; + tinfo->type_align = rec.type_align; + tinfo->operator_new = rec.operator_new; + tinfo->holder_size_in_ptrs = size_in_ptrs(rec.holder_size); + tinfo->init_instance = rec.init_instance; + tinfo->dealloc = rec.dealloc; + tinfo->simple_type = true; + tinfo->simple_ancestors = true; + tinfo->default_holder = rec.default_holder; + tinfo->module_local = rec.module_local; + + auto &internals = get_internals(); + auto tindex = std::type_index(*rec.type); + tinfo->direct_conversions = &internals.direct_conversions[tindex]; + if (rec.module_local) + registered_local_types_cpp()[tindex] = tinfo; + else + internals.registered_types_cpp[tindex] = tinfo; + internals.registered_types_py[(PyTypeObject *) m_ptr] = { tinfo }; + + if (rec.bases.size() > 1 || rec.multiple_inheritance) { + mark_parents_nonsimple(tinfo->type); + tinfo->simple_ancestors = false; + } + else if (rec.bases.size() == 1) { + auto parent_tinfo = get_type_info((PyTypeObject *) rec.bases[0].ptr()); + tinfo->simple_ancestors = parent_tinfo->simple_ancestors; + } + + if (rec.module_local) { + // Stash the local typeinfo and loader so that external modules can access it. + tinfo->module_local_load = &type_caster_generic::local_load; + setattr(m_ptr, PYBIND11_MODULE_LOCAL_ID, capsule(tinfo)); + } + } + + /// Helper function which tags all parents of a type using mult. inheritance + void mark_parents_nonsimple(PyTypeObject *value) { + auto t = reinterpret_borrow(value->tp_bases); + for (handle h : t) { + auto tinfo2 = get_type_info((PyTypeObject *) h.ptr()); + if (tinfo2) + tinfo2->simple_type = false; + mark_parents_nonsimple((PyTypeObject *) h.ptr()); + } + } + + void install_buffer_funcs( + buffer_info *(*get_buffer)(PyObject *, void *), + void *get_buffer_data) { + PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr; + auto tinfo = detail::get_type_info(&type->ht_type); + + if (!type->ht_type.tp_as_buffer) + pybind11_fail( + "To be able to register buffer protocol support for the type '" + + std::string(tinfo->type->tp_name) + + "' the associated class<>(..) invocation must " + "include the pybind11::buffer_protocol() annotation!"); + + tinfo->get_buffer = get_buffer; + tinfo->get_buffer_data = get_buffer_data; + } + + // rec_func must be set for either fget or fset. + void def_property_static_impl(const char *name, + handle fget, handle fset, + detail::function_record *rec_func) { + const auto is_static = rec_func && !(rec_func->is_method && rec_func->scope); + const auto has_doc = rec_func && rec_func->doc && pybind11::options::show_user_defined_docstrings(); + auto property = handle((PyObject *) (is_static ? get_internals().static_property_type + : &PyProperty_Type)); + attr(name) = property(fget.ptr() ? fget : none(), + fset.ptr() ? fset : none(), + /*deleter*/none(), + pybind11::str(has_doc ? rec_func->doc : "")); + } +}; + +/// Set the pointer to operator new if it exists. The cast is needed because it can be overloaded. +template (T::operator new))>> +void set_operator_new(type_record *r) { r->operator_new = &T::operator new; } + +template void set_operator_new(...) { } + +template struct has_operator_delete : std::false_type { }; +template struct has_operator_delete(T::operator delete))>> + : std::true_type { }; +template struct has_operator_delete_size : std::false_type { }; +template struct has_operator_delete_size(T::operator delete))>> + : std::true_type { }; +/// Call class-specific delete if it exists or global otherwise. Can also be an overload set. +template ::value, int> = 0> +void call_operator_delete(T *p, size_t, size_t) { T::operator delete(p); } +template ::value && has_operator_delete_size::value, int> = 0> +void call_operator_delete(T *p, size_t s, size_t) { T::operator delete(p, s); } + +inline void call_operator_delete(void *p, size_t s, size_t a) { + (void)s; (void)a; + #if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912) + if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__) { + #ifdef __cpp_sized_deallocation + ::operator delete(p, s, std::align_val_t(a)); + #else + ::operator delete(p, std::align_val_t(a)); + #endif + return; + } + #endif + #ifdef __cpp_sized_deallocation + ::operator delete(p, s); + #else + ::operator delete(p); + #endif +} + +NAMESPACE_END(detail) + +/// Given a pointer to a member function, cast it to its `Derived` version. +/// Forward everything else unchanged. +template +auto method_adaptor(F &&f) -> decltype(std::forward(f)) { return std::forward(f); } + +template +auto method_adaptor(Return (Class::*pmf)(Args...)) -> Return (Derived::*)(Args...) { + static_assert(detail::is_accessible_base_of::value, + "Cannot bind an inaccessible base class method; use a lambda definition instead"); + return pmf; +} + +template +auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(Args...) const { + static_assert(detail::is_accessible_base_of::value, + "Cannot bind an inaccessible base class method; use a lambda definition instead"); + return pmf; +} + +template +class class_ : public detail::generic_type { + template using is_holder = detail::is_holder_type; + template using is_subtype = detail::is_strict_base_of; + template using is_base = detail::is_strict_base_of; + // struct instead of using here to help MSVC: + template struct is_valid_class_option : + detail::any_of, is_subtype, is_base> {}; + +public: + using type = type_; + using type_alias = detail::exactly_one_t; + constexpr static bool has_alias = !std::is_void::value; + using holder_type = detail::exactly_one_t, options...>; + + static_assert(detail::all_of...>::value, + "Unknown/invalid class_ template parameters provided"); + + static_assert(!has_alias || std::is_polymorphic::value, + "Cannot use an alias class with a non-polymorphic type"); + + PYBIND11_OBJECT(class_, generic_type, PyType_Check) + + template + class_(handle scope, const char *name, const Extra &... extra) { + using namespace detail; + + // MI can only be specified via class_ template options, not constructor parameters + static_assert( + none_of...>::value || // no base class arguments, or: + ( constexpr_sum(is_pyobject::value...) == 1 && // Exactly one base + constexpr_sum(is_base::value...) == 0 && // no template option bases + none_of...>::value), // no multiple_inheritance attr + "Error: multiple inheritance bases must be specified via class_ template options"); + + type_record record; + record.scope = scope; + record.name = name; + record.type = &typeid(type); + record.type_size = sizeof(conditional_t); + record.type_align = alignof(conditional_t&); + record.holder_size = sizeof(holder_type); + record.init_instance = init_instance; + record.dealloc = dealloc; + record.default_holder = detail::is_instantiation::value; + + set_operator_new(&record); + + /* Register base classes specified via template arguments to class_, if any */ + PYBIND11_EXPAND_SIDE_EFFECTS(add_base(record)); + + /* Process optional arguments, if any */ + process_attributes::init(extra..., &record); + + generic_type::initialize(record); + + if (has_alias) { + auto &instances = record.module_local ? registered_local_types_cpp() : get_internals().registered_types_cpp; + instances[std::type_index(typeid(type_alias))] = instances[std::type_index(typeid(type))]; + } + } + + template ::value, int> = 0> + static void add_base(detail::type_record &rec) { + rec.add_base(typeid(Base), [](void *src) -> void * { + return static_cast(reinterpret_cast(src)); + }); + } + + template ::value, int> = 0> + static void add_base(detail::type_record &) { } + + template + class_ &def(const char *name_, Func&& f, const Extra&... extra) { + cpp_function cf(method_adaptor(std::forward(f)), name(name_), is_method(*this), + sibling(getattr(*this, name_, none())), extra...); + attr(cf.name()) = cf; + return *this; + } + + template class_ & + def_static(const char *name_, Func &&f, const Extra&... extra) { + static_assert(!std::is_member_function_pointer::value, + "def_static(...) called with a non-static member function pointer"); + cpp_function cf(std::forward(f), name(name_), scope(*this), + sibling(getattr(*this, name_, none())), extra...); + attr(cf.name()) = staticmethod(cf); + return *this; + } + + template + class_ &def(const detail::op_ &op, const Extra&... extra) { + op.execute(*this, extra...); + return *this; + } + + template + class_ & def_cast(const detail::op_ &op, const Extra&... extra) { + op.execute_cast(*this, extra...); + return *this; + } + + template + class_ &def(const detail::initimpl::constructor &init, const Extra&... extra) { + init.execute(*this, extra...); + return *this; + } + + template + class_ &def(const detail::initimpl::alias_constructor &init, const Extra&... extra) { + init.execute(*this, extra...); + return *this; + } + + template + class_ &def(detail::initimpl::factory &&init, const Extra&... extra) { + std::move(init).execute(*this, extra...); + return *this; + } + + template + class_ &def(detail::initimpl::pickle_factory &&pf, const Extra &...extra) { + std::move(pf).execute(*this, extra...); + return *this; + } + + template class_& def_buffer(Func &&func) { + struct capture { Func func; }; + capture *ptr = new capture { std::forward(func) }; + install_buffer_funcs([](PyObject *obj, void *ptr) -> buffer_info* { + detail::make_caster caster; + if (!caster.load(obj, false)) + return nullptr; + return new buffer_info(((capture *) ptr)->func(caster)); + }, ptr); + return *this; + } + + template + class_ &def_buffer(Return (Class::*func)(Args...)) { + return def_buffer([func] (type &obj) { return (obj.*func)(); }); + } + + template + class_ &def_buffer(Return (Class::*func)(Args...) const) { + return def_buffer([func] (const type &obj) { return (obj.*func)(); }); + } + + template + class_ &def_readwrite(const char *name, D C::*pm, const Extra&... extra) { + static_assert(std::is_same::value || std::is_base_of::value, "def_readwrite() requires a class member (or base class member)"); + cpp_function fget([pm](const type &c) -> const D &{ return c.*pm; }, is_method(*this)), + fset([pm](type &c, const D &value) { c.*pm = value; }, is_method(*this)); + def_property(name, fget, fset, return_value_policy::reference_internal, extra...); + return *this; + } + + template + class_ &def_readonly(const char *name, const D C::*pm, const Extra& ...extra) { + static_assert(std::is_same::value || std::is_base_of::value, "def_readonly() requires a class member (or base class member)"); + cpp_function fget([pm](const type &c) -> const D &{ return c.*pm; }, is_method(*this)); + def_property_readonly(name, fget, return_value_policy::reference_internal, extra...); + return *this; + } + + template + class_ &def_readwrite_static(const char *name, D *pm, const Extra& ...extra) { + cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this)), + fset([pm](object, const D &value) { *pm = value; }, scope(*this)); + def_property_static(name, fget, fset, return_value_policy::reference, extra...); + return *this; + } + + template + class_ &def_readonly_static(const char *name, const D *pm, const Extra& ...extra) { + cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this)); + def_property_readonly_static(name, fget, return_value_policy::reference, extra...); + return *this; + } + + /// Uses return_value_policy::reference_internal by default + template + class_ &def_property_readonly(const char *name, const Getter &fget, const Extra& ...extra) { + return def_property_readonly(name, cpp_function(method_adaptor(fget)), + return_value_policy::reference_internal, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property_readonly(const char *name, const cpp_function &fget, const Extra& ...extra) { + return def_property(name, fget, nullptr, extra...); + } + + /// Uses return_value_policy::reference by default + template + class_ &def_property_readonly_static(const char *name, const Getter &fget, const Extra& ...extra) { + return def_property_readonly_static(name, cpp_function(fget), return_value_policy::reference, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property_readonly_static(const char *name, const cpp_function &fget, const Extra& ...extra) { + return def_property_static(name, fget, nullptr, extra...); + } + + /// Uses return_value_policy::reference_internal by default + template + class_ &def_property(const char *name, const Getter &fget, const Setter &fset, const Extra& ...extra) { + return def_property(name, fget, cpp_function(method_adaptor(fset)), extra...); + } + template + class_ &def_property(const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) { + return def_property(name, cpp_function(method_adaptor(fget)), fset, + return_value_policy::reference_internal, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) { + return def_property_static(name, fget, fset, is_method(*this), extra...); + } + + /// Uses return_value_policy::reference by default + template + class_ &def_property_static(const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) { + return def_property_static(name, cpp_function(fget), fset, return_value_policy::reference, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) { + static_assert( 0 == detail::constexpr_sum(std::is_base_of::value...), + "Argument annotations are not allowed for properties"); + auto rec_fget = get_function_record(fget), rec_fset = get_function_record(fset); + auto *rec_active = rec_fget; + if (rec_fget) { + char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific documentation string */ + detail::process_attributes::init(extra..., rec_fget); + if (rec_fget->doc && rec_fget->doc != doc_prev) { + free(doc_prev); + rec_fget->doc = strdup(rec_fget->doc); + } + } + if (rec_fset) { + char *doc_prev = rec_fset->doc; + detail::process_attributes::init(extra..., rec_fset); + if (rec_fset->doc && rec_fset->doc != doc_prev) { + free(doc_prev); + rec_fset->doc = strdup(rec_fset->doc); + } + if (! rec_active) rec_active = rec_fset; + } + def_property_static_impl(name, fget, fset, rec_active); + return *this; + } + +private: + /// Initialize holder object, variant 1: object derives from enable_shared_from_this + template + static void init_holder(detail::instance *inst, detail::value_and_holder &v_h, + const holder_type * /* unused */, const std::enable_shared_from_this * /* dummy */) { + try { + auto sh = std::dynamic_pointer_cast( + v_h.value_ptr()->shared_from_this()); + if (sh) { + new (std::addressof(v_h.holder())) holder_type(std::move(sh)); + v_h.set_holder_constructed(); + } + } catch (const std::bad_weak_ptr &) {} + + if (!v_h.holder_constructed() && inst->owned) { + new (std::addressof(v_h.holder())) holder_type(v_h.value_ptr()); + v_h.set_holder_constructed(); + } + } + + static void init_holder_from_existing(const detail::value_and_holder &v_h, + const holder_type *holder_ptr, std::true_type /*is_copy_constructible*/) { + new (std::addressof(v_h.holder())) holder_type(*reinterpret_cast(holder_ptr)); + } + + static void init_holder_from_existing(const detail::value_and_holder &v_h, + const holder_type *holder_ptr, std::false_type /*is_copy_constructible*/) { + new (std::addressof(v_h.holder())) holder_type(std::move(*const_cast(holder_ptr))); + } + + /// Initialize holder object, variant 2: try to construct from existing holder object, if possible + static void init_holder(detail::instance *inst, detail::value_and_holder &v_h, + const holder_type *holder_ptr, const void * /* dummy -- not enable_shared_from_this) */) { + if (holder_ptr) { + init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible()); + v_h.set_holder_constructed(); + } else if (inst->owned || detail::always_construct_holder::value) { + new (std::addressof(v_h.holder())) holder_type(v_h.value_ptr()); + v_h.set_holder_constructed(); + } + } + + /// Performs instance initialization including constructing a holder and registering the known + /// instance. Should be called as soon as the `type` value_ptr is set for an instance. Takes an + /// optional pointer to an existing holder to use; if not specified and the instance is + /// `.owned`, a new holder will be constructed to manage the value pointer. + static void init_instance(detail::instance *inst, const void *holder_ptr) { + auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type))); + if (!v_h.instance_registered()) { + register_instance(inst, v_h.value_ptr(), v_h.type); + v_h.set_instance_registered(); + } + init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr()); + } + + /// Deallocates an instance; via holder, if constructed; otherwise via operator delete. + static void dealloc(detail::value_and_holder &v_h) { + if (v_h.holder_constructed()) { + v_h.holder().~holder_type(); + v_h.set_holder_constructed(false); + } + else { + detail::call_operator_delete(v_h.value_ptr(), + v_h.type->type_size, + v_h.type->type_align + ); + } + v_h.value_ptr() = nullptr; + } + + static detail::function_record *get_function_record(handle h) { + h = detail::get_function(h); + return h ? (detail::function_record *) reinterpret_borrow(PyCFunction_GET_SELF(h.ptr())) + : nullptr; + } +}; + +/// Binds an existing constructor taking arguments Args... +template detail::initimpl::constructor init() { return {}; } +/// Like `init()`, but the instance is always constructed through the alias class (even +/// when not inheriting on the Python side). +template detail::initimpl::alias_constructor init_alias() { return {}; } + +/// Binds a factory function as a constructor +template > +Ret init(Func &&f) { return {std::forward(f)}; } + +/// Dual-argument factory function: the first function is called when no alias is needed, the second +/// when an alias is needed (i.e. due to python-side inheritance). Arguments must be identical. +template > +Ret init(CFunc &&c, AFunc &&a) { + return {std::forward(c), std::forward(a)}; +} + +/// Binds pickling functions `__getstate__` and `__setstate__` and ensures that the type +/// returned by `__getstate__` is the same as the argument accepted by `__setstate__`. +template +detail::initimpl::pickle_factory pickle(GetState &&g, SetState &&s) { + return {std::forward(g), std::forward(s)}; +} + +NAMESPACE_BEGIN(detail) +struct enum_base { + enum_base(handle base, handle parent) : m_base(base), m_parent(parent) { } + + PYBIND11_NOINLINE void init(bool is_arithmetic, bool is_convertible) { + m_base.attr("__entries") = dict(); + auto property = handle((PyObject *) &PyProperty_Type); + auto static_property = handle((PyObject *) get_internals().static_property_type); + + m_base.attr("__repr__") = cpp_function( + [](handle arg) -> str { + handle type = arg.get_type(); + object type_name = type.attr("__name__"); + dict entries = type.attr("__entries"); + for (const auto &kv : entries) { + object other = kv.second[int_(0)]; + if (other.equal(arg)) + return pybind11::str("{}.{}").format(type_name, kv.first); + } + return pybind11::str("{}.???").format(type_name); + }, is_method(m_base) + ); + + m_base.attr("name") = property(cpp_function( + [](handle arg) -> str { + dict entries = arg.get_type().attr("__entries"); + for (const auto &kv : entries) { + if (handle(kv.second[int_(0)]).equal(arg)) + return pybind11::str(kv.first); + } + return "???"; + }, is_method(m_base) + )); + + m_base.attr("__doc__") = static_property(cpp_function( + [](handle arg) -> std::string { + std::string docstring; + dict entries = arg.attr("__entries"); + if (((PyTypeObject *) arg.ptr())->tp_doc) + docstring += std::string(((PyTypeObject *) arg.ptr())->tp_doc) + "\n\n"; + docstring += "Members:"; + for (const auto &kv : entries) { + auto key = std::string(pybind11::str(kv.first)); + auto comment = kv.second[int_(1)]; + docstring += "\n\n " + key; + if (!comment.is_none()) + docstring += " : " + (std::string) pybind11::str(comment); + } + return docstring; + } + ), none(), none(), ""); + + m_base.attr("__members__") = static_property(cpp_function( + [](handle arg) -> dict { + dict entries = arg.attr("__entries"), m; + for (const auto &kv : entries) + m[kv.first] = kv.second[int_(0)]; + return m; + }), none(), none(), "" + ); + + #define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior) \ + m_base.attr(op) = cpp_function( \ + [](object a, object b) { \ + if (!a.get_type().is(b.get_type())) \ + strict_behavior; \ + return expr; \ + }, \ + is_method(m_base)) + + #define PYBIND11_ENUM_OP_CONV(op, expr) \ + m_base.attr(op) = cpp_function( \ + [](object a_, object b_) { \ + int_ a(a_), b(b_); \ + return expr; \ + }, \ + is_method(m_base)) + + #define PYBIND11_ENUM_OP_CONV_LHS(op, expr) \ + m_base.attr(op) = cpp_function( \ + [](object a_, object b) { \ + int_ a(a_); \ + return expr; \ + }, \ + is_method(m_base)) + + if (is_convertible) { + PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b)); + PYBIND11_ENUM_OP_CONV_LHS("__ne__", b.is_none() || !a.equal(b)); + + if (is_arithmetic) { + PYBIND11_ENUM_OP_CONV("__lt__", a < b); + PYBIND11_ENUM_OP_CONV("__gt__", a > b); + PYBIND11_ENUM_OP_CONV("__le__", a <= b); + PYBIND11_ENUM_OP_CONV("__ge__", a >= b); + PYBIND11_ENUM_OP_CONV("__and__", a & b); + PYBIND11_ENUM_OP_CONV("__rand__", a & b); + PYBIND11_ENUM_OP_CONV("__or__", a | b); + PYBIND11_ENUM_OP_CONV("__ror__", a | b); + PYBIND11_ENUM_OP_CONV("__xor__", a ^ b); + PYBIND11_ENUM_OP_CONV("__rxor__", a ^ b); + m_base.attr("__invert__") = cpp_function( + [](object arg) { return ~(int_(arg)); }, is_method(m_base)); + } + } else { + PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false); + PYBIND11_ENUM_OP_STRICT("__ne__", !int_(a).equal(int_(b)), return true); + + if (is_arithmetic) { + #define PYBIND11_THROW throw type_error("Expected an enumeration of matching type!"); + PYBIND11_ENUM_OP_STRICT("__lt__", int_(a) < int_(b), PYBIND11_THROW); + PYBIND11_ENUM_OP_STRICT("__gt__", int_(a) > int_(b), PYBIND11_THROW); + PYBIND11_ENUM_OP_STRICT("__le__", int_(a) <= int_(b), PYBIND11_THROW); + PYBIND11_ENUM_OP_STRICT("__ge__", int_(a) >= int_(b), PYBIND11_THROW); + #undef PYBIND11_THROW + } + } + + #undef PYBIND11_ENUM_OP_CONV_LHS + #undef PYBIND11_ENUM_OP_CONV + #undef PYBIND11_ENUM_OP_STRICT + + object getstate = cpp_function( + [](object arg) { return int_(arg); }, is_method(m_base)); + + m_base.attr("__getstate__") = getstate; + m_base.attr("__hash__") = getstate; + } + + PYBIND11_NOINLINE void value(char const* name_, object value, const char *doc = nullptr) { + dict entries = m_base.attr("__entries"); + str name(name_); + if (entries.contains(name)) { + std::string type_name = (std::string) str(m_base.attr("__name__")); + throw value_error(type_name + ": element \"" + std::string(name_) + "\" already exists!"); + } + + entries[name] = std::make_pair(value, doc); + m_base.attr(name) = value; + } + + PYBIND11_NOINLINE void export_values() { + dict entries = m_base.attr("__entries"); + for (const auto &kv : entries) + m_parent.attr(kv.first) = kv.second[int_(0)]; + } + + handle m_base; + handle m_parent; +}; + +NAMESPACE_END(detail) + +/// Binds C++ enumerations and enumeration classes to Python +template class enum_ : public class_ { +public: + using Base = class_; + using Base::def; + using Base::attr; + using Base::def_property_readonly; + using Base::def_property_readonly_static; + using Scalar = typename std::underlying_type::type; + + template + enum_(const handle &scope, const char *name, const Extra&... extra) + : class_(scope, name, extra...), m_base(*this, scope) { + constexpr bool is_arithmetic = detail::any_of...>::value; + constexpr bool is_convertible = std::is_convertible::value; + m_base.init(is_arithmetic, is_convertible); + + def(init([](Scalar i) { return static_cast(i); })); + def("__int__", [](Type value) { return (Scalar) value; }); + #if PY_MAJOR_VERSION < 3 + def("__long__", [](Type value) { return (Scalar) value; }); + #endif + #if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 8) + def("__index__", [](Type value) { return (Scalar) value; }); + #endif + + cpp_function setstate( + [](Type &value, Scalar arg) { value = static_cast(arg); }, + is_method(*this)); + attr("__setstate__") = setstate; + } + + /// Export enumeration entries into the parent scope + enum_& export_values() { + m_base.export_values(); + return *this; + } + + /// Add an enumeration entry + enum_& value(char const* name, Type value, const char *doc = nullptr) { + m_base.value(name, pybind11::cast(value, return_value_policy::copy), doc); + return *this; + } + +private: + detail::enum_base m_base; +}; + +NAMESPACE_BEGIN(detail) + + +inline void keep_alive_impl(handle nurse, handle patient) { + if (!nurse || !patient) + pybind11_fail("Could not activate keep_alive!"); + + if (patient.is_none() || nurse.is_none()) + return; /* Nothing to keep alive or nothing to be kept alive by */ + + auto tinfo = all_type_info(Py_TYPE(nurse.ptr())); + if (!tinfo.empty()) { + /* It's a pybind-registered type, so we can store the patient in the + * internal list. */ + add_patient(nurse.ptr(), patient.ptr()); + } + else { + /* Fall back to clever approach based on weak references taken from + * Boost.Python. This is not used for pybind-registered types because + * the objects can be destroyed out-of-order in a GC pass. */ + cpp_function disable_lifesupport( + [patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); }); + + weakref wr(nurse, disable_lifesupport); + + patient.inc_ref(); /* reference patient and leak the weak reference */ + (void) wr.release(); + } +} + +PYBIND11_NOINLINE inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) { + auto get_arg = [&](size_t n) { + if (n == 0) + return ret; + else if (n == 1 && call.init_self) + return call.init_self; + else if (n <= call.args.size()) + return call.args[n - 1]; + return handle(); + }; + + keep_alive_impl(get_arg(Nurse), get_arg(Patient)); +} + +inline std::pair all_type_info_get_cache(PyTypeObject *type) { + auto res = get_internals().registered_types_py +#ifdef __cpp_lib_unordered_map_try_emplace + .try_emplace(type); +#else + .emplace(type, std::vector()); +#endif + if (res.second) { + // New cache entry created; set up a weak reference to automatically remove it if the type + // gets destroyed: + weakref((PyObject *) type, cpp_function([type](handle wr) { + get_internals().registered_types_py.erase(type); + wr.dec_ref(); + })).release(); + } + + return res; +} + +template +struct iterator_state { + Iterator it; + Sentinel end; + bool first_or_done; +}; + +NAMESPACE_END(detail) + +/// Makes a python iterator from a first and past-the-end C++ InputIterator. +template ()), + typename... Extra> +iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) { + typedef detail::iterator_state state; + + if (!detail::get_type_info(typeid(state), false)) { + class_(handle(), "iterator", pybind11::module_local()) + .def("__iter__", [](state &s) -> state& { return s; }) + .def("__next__", [](state &s) -> ValueType { + if (!s.first_or_done) + ++s.it; + else + s.first_or_done = false; + if (s.it == s.end) { + s.first_or_done = true; + throw stop_iteration(); + } + return *s.it; + }, std::forward(extra)..., Policy); + } + + return cast(state{first, last, true}); +} + +/// Makes an python iterator over the keys (`.first`) of a iterator over pairs from a +/// first and past-the-end InputIterator. +template ()).first), + typename... Extra> +iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) { + typedef detail::iterator_state state; + + if (!detail::get_type_info(typeid(state), false)) { + class_(handle(), "iterator", pybind11::module_local()) + .def("__iter__", [](state &s) -> state& { return s; }) + .def("__next__", [](state &s) -> KeyType { + if (!s.first_or_done) + ++s.it; + else + s.first_or_done = false; + if (s.it == s.end) { + s.first_or_done = true; + throw stop_iteration(); + } + return (*s.it).first; + }, std::forward(extra)..., Policy); + } + + return cast(state{first, last, true}); +} + +/// Makes an iterator over values of an stl container or other container supporting +/// `std::begin()`/`std::end()` +template iterator make_iterator(Type &value, Extra&&... extra) { + return make_iterator(std::begin(value), std::end(value), extra...); +} + +/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting +/// `std::begin()`/`std::end()` +template iterator make_key_iterator(Type &value, Extra&&... extra) { + return make_key_iterator(std::begin(value), std::end(value), extra...); +} + +template void implicitly_convertible() { + struct set_flag { + bool &flag; + set_flag(bool &flag) : flag(flag) { flag = true; } + ~set_flag() { flag = false; } + }; + auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * { + static bool currently_used = false; + if (currently_used) // implicit conversions are non-reentrant + return nullptr; + set_flag flag_helper(currently_used); + if (!detail::make_caster().load(obj, false)) + return nullptr; + tuple args(1); + args[0] = obj; + PyObject *result = PyObject_Call((PyObject *) type, args.ptr(), nullptr); + if (result == nullptr) + PyErr_Clear(); + return result; + }; + + if (auto tinfo = detail::get_type_info(typeid(OutputType))) + tinfo->implicit_conversions.push_back(implicit_caster); + else + pybind11_fail("implicitly_convertible: Unable to find type " + type_id()); +} + +template +void register_exception_translator(ExceptionTranslator&& translator) { + detail::get_internals().registered_exception_translators.push_front( + std::forward(translator)); +} + +/** + * Wrapper to generate a new Python exception type. + * + * This should only be used with PyErr_SetString for now. + * It is not (yet) possible to use as a py::base. + * Template type argument is reserved for future use. + */ +template +class exception : public object { +public: + exception() = default; + exception(handle scope, const char *name, PyObject *base = PyExc_Exception) { + std::string full_name = scope.attr("__name__").cast() + + std::string(".") + name; + m_ptr = PyErr_NewException(const_cast(full_name.c_str()), base, NULL); + if (hasattr(scope, name)) + pybind11_fail("Error during initialization: multiple incompatible " + "definitions with name \"" + std::string(name) + "\""); + scope.attr(name) = *this; + } + + // Sets the current python exception to this exception object with the given message + void operator()(const char *message) { + PyErr_SetString(m_ptr, message); + } +}; + +NAMESPACE_BEGIN(detail) +// Returns a reference to a function-local static exception object used in the simple +// register_exception approach below. (It would be simpler to have the static local variable +// directly in register_exception, but that makes clang <3.5 segfault - issue #1349). +template +exception &get_exception_object() { static exception ex; return ex; } +NAMESPACE_END(detail) + +/** + * Registers a Python exception in `m` of the given `name` and installs an exception translator to + * translate the C++ exception to the created Python exception using the exceptions what() method. + * This is intended for simple exception translations; for more complex translation, register the + * exception object and translator directly. + */ +template +exception ®ister_exception(handle scope, + const char *name, + PyObject *base = PyExc_Exception) { + auto &ex = detail::get_exception_object(); + if (!ex) ex = exception(scope, name, base); + + register_exception_translator([](std::exception_ptr p) { + if (!p) return; + try { + std::rethrow_exception(p); + } catch (const CppException &e) { + detail::get_exception_object()(e.what()); + } + }); + return ex; +} + +NAMESPACE_BEGIN(detail) +PYBIND11_NOINLINE inline void print(tuple args, dict kwargs) { + auto strings = tuple(args.size()); + for (size_t i = 0; i < args.size(); ++i) { + strings[i] = str(args[i]); + } + auto sep = kwargs.contains("sep") ? kwargs["sep"] : cast(" "); + auto line = sep.attr("join")(strings); + + object file; + if (kwargs.contains("file")) { + file = kwargs["file"].cast(); + } else { + try { + file = module::import("sys").attr("stdout"); + } catch (const error_already_set &) { + /* If print() is called from code that is executed as + part of garbage collection during interpreter shutdown, + importing 'sys' can fail. Give up rather than crashing the + interpreter in this case. */ + return; + } + } + + auto write = file.attr("write"); + write(line); + write(kwargs.contains("end") ? kwargs["end"] : cast("\n")); + + if (kwargs.contains("flush") && kwargs["flush"].cast()) + file.attr("flush")(); +} +NAMESPACE_END(detail) + +template +void print(Args &&...args) { + auto c = detail::collect_arguments(std::forward(args)...); + detail::print(c.args(), c.kwargs()); +} + +#if defined(WITH_THREAD) && !defined(PYPY_VERSION) + +/* The functions below essentially reproduce the PyGILState_* API using a RAII + * pattern, but there are a few important differences: + * + * 1. When acquiring the GIL from an non-main thread during the finalization + * phase, the GILState API blindly terminates the calling thread, which + * is often not what is wanted. This API does not do this. + * + * 2. The gil_scoped_release function can optionally cut the relationship + * of a PyThreadState and its associated thread, which allows moving it to + * another thread (this is a fairly rare/advanced use case). + * + * 3. The reference count of an acquired thread state can be controlled. This + * can be handy to prevent cases where callbacks issued from an external + * thread would otherwise constantly construct and destroy thread state data + * structures. + * + * See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an + * example which uses features 2 and 3 to migrate the Python thread of + * execution to another thread (to run the event loop on the original thread, + * in this case). + */ + +class gil_scoped_acquire { +public: + PYBIND11_NOINLINE gil_scoped_acquire() { + auto const &internals = detail::get_internals(); + tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate); + + if (!tstate) { + /* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if + calling from a Python thread). Since we use a different key, this ensures + we don't create a new thread state and deadlock in PyEval_AcquireThread + below. Note we don't save this state with internals.tstate, since we don't + create it we would fail to clear it (its reference count should be > 0). */ + tstate = PyGILState_GetThisThreadState(); + } + + if (!tstate) { + tstate = PyThreadState_New(internals.istate); + #if !defined(NDEBUG) + if (!tstate) + pybind11_fail("scoped_acquire: could not create thread state!"); + #endif + tstate->gilstate_counter = 0; + PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate); + } else { + release = detail::get_thread_state_unchecked() != tstate; + } + + if (release) { + /* Work around an annoying assertion in PyThreadState_Swap */ + #if defined(Py_DEBUG) + PyInterpreterState *interp = tstate->interp; + tstate->interp = nullptr; + #endif + PyEval_AcquireThread(tstate); + #if defined(Py_DEBUG) + tstate->interp = interp; + #endif + } + + inc_ref(); + } + + void inc_ref() { + ++tstate->gilstate_counter; + } + + PYBIND11_NOINLINE void dec_ref() { + --tstate->gilstate_counter; + #if !defined(NDEBUG) + if (detail::get_thread_state_unchecked() != tstate) + pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); + if (tstate->gilstate_counter < 0) + pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!"); + #endif + if (tstate->gilstate_counter == 0) { + #if !defined(NDEBUG) + if (!release) + pybind11_fail("scoped_acquire::dec_ref(): internal error!"); + #endif + PyThreadState_Clear(tstate); + PyThreadState_DeleteCurrent(); + PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate); + release = false; + } + } + + PYBIND11_NOINLINE ~gil_scoped_acquire() { + dec_ref(); + if (release) + PyEval_SaveThread(); + } +private: + PyThreadState *tstate = nullptr; + bool release = true; +}; + +class gil_scoped_release { +public: + explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) { + // `get_internals()` must be called here unconditionally in order to initialize + // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an + // initialization race could occur as multiple threads try `gil_scoped_acquire`. + const auto &internals = detail::get_internals(); + tstate = PyEval_SaveThread(); + if (disassoc) { + auto key = internals.tstate; + PYBIND11_TLS_DELETE_VALUE(key); + } + } + ~gil_scoped_release() { + if (!tstate) + return; + PyEval_RestoreThread(tstate); + if (disassoc) { + auto key = detail::get_internals().tstate; + PYBIND11_TLS_REPLACE_VALUE(key, tstate); + } + } +private: + PyThreadState *tstate; + bool disassoc; +}; +#elif defined(PYPY_VERSION) +class gil_scoped_acquire { + PyGILState_STATE state; +public: + gil_scoped_acquire() { state = PyGILState_Ensure(); } + ~gil_scoped_acquire() { PyGILState_Release(state); } +}; + +class gil_scoped_release { + PyThreadState *state; +public: + gil_scoped_release() { state = PyEval_SaveThread(); } + ~gil_scoped_release() { PyEval_RestoreThread(state); } +}; +#else +class gil_scoped_acquire { }; +class gil_scoped_release { }; +#endif + +error_already_set::~error_already_set() { + if (m_type) { + gil_scoped_acquire gil; + error_scope scope; + m_type.release().dec_ref(); + m_value.release().dec_ref(); + m_trace.release().dec_ref(); + } +} + +inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) { + handle self = detail::get_object_handle(this_ptr, this_type); + if (!self) + return function(); + handle type = self.get_type(); + auto key = std::make_pair(type.ptr(), name); + + /* Cache functions that aren't overloaded in Python to avoid + many costly Python dictionary lookups below */ + auto &cache = detail::get_internals().inactive_overload_cache; + if (cache.find(key) != cache.end()) + return function(); + + function overload = getattr(self, name, function()); + if (overload.is_cpp_function()) { + cache.insert(key); + return function(); + } + + /* Don't call dispatch code if invoked from overridden function. + Unfortunately this doesn't work on PyPy. */ +#if !defined(PYPY_VERSION) + PyFrameObject *frame = PyThreadState_Get()->frame; + if (frame && (std::string) str(frame->f_code->co_name) == name && + frame->f_code->co_argcount > 0) { + PyFrame_FastToLocals(frame); + PyObject *self_caller = PyDict_GetItem( + frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0)); + if (self_caller == self.ptr()) + return function(); + } +#else + /* PyPy currently doesn't provide a detailed cpyext emulation of + frame objects, so we have to emulate this using Python. This + is going to be slow..*/ + dict d; d["self"] = self; d["name"] = pybind11::str(name); + PyObject *result = PyRun_String( + "import inspect\n" + "frame = inspect.currentframe()\n" + "if frame is not None:\n" + " frame = frame.f_back\n" + " if frame is not None and str(frame.f_code.co_name) == name and " + "frame.f_code.co_argcount > 0:\n" + " self_caller = frame.f_locals[frame.f_code.co_varnames[0]]\n" + " if self_caller == self:\n" + " self = None\n", + Py_file_input, d.ptr(), d.ptr()); + if (result == nullptr) + throw error_already_set(); + if (d["self"].is_none()) + return function(); + Py_DECREF(result); +#endif + + return overload; +} + +/** \rst + Try to retrieve a python method by the provided name from the instance pointed to by the this_ptr. + + :this_ptr: The pointer to the object the overload should be retrieved for. This should be the first + non-trampoline class encountered in the inheritance chain. + :name: The name of the overloaded Python method to retrieve. + :return: The Python method by this name from the object or an empty function wrapper. + \endrst */ +template function get_overload(const T *this_ptr, const char *name) { + auto tinfo = detail::get_type_info(typeid(T)); + return tinfo ? get_type_overload(this_ptr, tinfo, name) : function(); +} + +#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) { \ + pybind11::gil_scoped_acquire gil; \ + pybind11::function overload = pybind11::get_overload(static_cast(this), name); \ + if (overload) { \ + auto o = overload(__VA_ARGS__); \ + if (pybind11::detail::cast_is_temporary_value_reference::value) { \ + static pybind11::detail::overload_caster_t caster; \ + return pybind11::detail::cast_ref(std::move(o), caster); \ + } \ + else return pybind11::detail::cast_safe(std::move(o)); \ + } \ + } + +/** \rst + Macro to populate the virtual method in the trampoline class. This macro tries to look up a method named 'fn' + from the Python side, deals with the :ref:`gil` and necessary argument conversions to call this method and return + the appropriate type. See :ref:`overriding_virtuals` for more information. This macro should be used when the method + name in C is not the same as the method name in Python. For example with `__str__`. + + .. code-block:: cpp + + std::string toString() override { + PYBIND11_OVERLOAD_NAME( + std::string, // Return type (ret_type) + Animal, // Parent class (cname) + toString, // Name of function in C++ (name) + "__str__", // Name of method in Python (fn) + ); + } +\endrst */ +#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \ + PYBIND11_OVERLOAD_INT(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \ + return cname::fn(__VA_ARGS__) + +/** \rst + Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERLOAD_NAME`, except that it + throws if no overload can be found. +\endrst */ +#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \ + PYBIND11_OVERLOAD_INT(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \ + pybind11::pybind11_fail("Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\""); + +/** \rst + Macro to populate the virtual method in the trampoline class. This macro tries to look up the method + from the Python side, deals with the :ref:`gil` and necessary argument conversions to call this method and return + the appropriate type. This macro should be used if the method name in C and in Python are identical. + See :ref:`overriding_virtuals` for more information. + + .. code-block:: cpp + + class PyAnimal : public Animal { + public: + // Inherit the constructors + using Animal::Animal; + + // Trampoline (need one for each virtual function) + std::string go(int n_times) override { + PYBIND11_OVERLOAD_PURE( + std::string, // Return type (ret_type) + Animal, // Parent class (cname) + go, // Name of function in C++ (must match Python name) (fn) + n_times // Argument(s) (...) + ); + } + }; +\endrst */ +#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \ + PYBIND11_OVERLOAD_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__) + +/** \rst + Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERLOAD`, except that it throws + if no overload can be found. +\endrst */ +#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \ + PYBIND11_OVERLOAD_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__) + +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +# pragma warning(pop) +#elif defined(__GNUG__) && !defined(__clang__) +# pragma GCC diagnostic pop +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/pytypes.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/pytypes.h new file mode 100644 index 0000000000000000000000000000000000000000..4003d6918492b82543e7a58a44594eea2f3b60dd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/pytypes.h @@ -0,0 +1,1484 @@ +/* + pybind11/pytypes.h: Convenience wrapper classes for basic Python types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/common.h" +#include "buffer_info.h" +#include +#include + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/* A few forward declarations */ +class handle; class object; +class str; class iterator; +struct arg; struct arg_v; + +NAMESPACE_BEGIN(detail) +class args_proxy; +inline bool isinstance_generic(handle obj, const std::type_info &tp); + +// Accessor forward declarations +template class accessor; +namespace accessor_policies { + struct obj_attr; + struct str_attr; + struct generic_item; + struct sequence_item; + struct list_item; + struct tuple_item; +} +using obj_attr_accessor = accessor; +using str_attr_accessor = accessor; +using item_accessor = accessor; +using sequence_accessor = accessor; +using list_accessor = accessor; +using tuple_accessor = accessor; + +/// Tag and check to identify a class which implements the Python object API +class pyobject_tag { }; +template using is_pyobject = std::is_base_of>; + +/** \rst + A mixin class which adds common functions to `handle`, `object` and various accessors. + The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``. +\endrst */ +template +class object_api : public pyobject_tag { + const Derived &derived() const { return static_cast(*this); } + +public: + /** \rst + Return an iterator equivalent to calling ``iter()`` in Python. The object + must be a collection which supports the iteration protocol. + \endrst */ + iterator begin() const; + /// Return a sentinel which ends iteration. + iterator end() const; + + /** \rst + Return an internal functor to invoke the object's sequence protocol. Casting + the returned ``detail::item_accessor`` instance to a `handle` or `object` + subclass causes a corresponding call to ``__getitem__``. Assigning a `handle` + or `object` subclass causes a call to ``__setitem__``. + \endrst */ + item_accessor operator[](handle key) const; + /// See above (the only difference is that they key is provided as a string literal) + item_accessor operator[](const char *key) const; + + /** \rst + Return an internal functor to access the object's attributes. Casting the + returned ``detail::obj_attr_accessor`` instance to a `handle` or `object` + subclass causes a corresponding call to ``getattr``. Assigning a `handle` + or `object` subclass causes a call to ``setattr``. + \endrst */ + obj_attr_accessor attr(handle key) const; + /// See above (the only difference is that they key is provided as a string literal) + str_attr_accessor attr(const char *key) const; + + /** \rst + Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple`` + or ``list`` for a function call. Applying another * to the result yields + ** unpacking, e.g. to unpack a dict as function keyword arguments. + See :ref:`calling_python_functions`. + \endrst */ + args_proxy operator*() const; + + /// Check if the given item is contained within this object, i.e. ``item in obj``. + template bool contains(T &&item) const; + + /** \rst + Assuming the Python object is a function or implements the ``__call__`` + protocol, ``operator()`` invokes the underlying function, passing an + arbitrary set of parameters. The result is returned as a `object` and + may need to be converted back into a Python object using `handle::cast()`. + + When some of the arguments cannot be converted to Python objects, the + function will throw a `cast_error` exception. When the Python function + call fails, a `error_already_set` exception is thrown. + \endrst */ + template + object operator()(Args &&...args) const; + template + PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)") + object call(Args&&... args) const; + + /// Equivalent to ``obj is other`` in Python. + bool is(object_api const& other) const { return derived().ptr() == other.derived().ptr(); } + /// Equivalent to ``obj is None`` in Python. + bool is_none() const { return derived().ptr() == Py_None; } + /// Equivalent to obj == other in Python + bool equal(object_api const &other) const { return rich_compare(other, Py_EQ); } + bool not_equal(object_api const &other) const { return rich_compare(other, Py_NE); } + bool operator<(object_api const &other) const { return rich_compare(other, Py_LT); } + bool operator<=(object_api const &other) const { return rich_compare(other, Py_LE); } + bool operator>(object_api const &other) const { return rich_compare(other, Py_GT); } + bool operator>=(object_api const &other) const { return rich_compare(other, Py_GE); } + + object operator-() const; + object operator~() const; + object operator+(object_api const &other) const; + object operator+=(object_api const &other) const; + object operator-(object_api const &other) const; + object operator-=(object_api const &other) const; + object operator*(object_api const &other) const; + object operator*=(object_api const &other) const; + object operator/(object_api const &other) const; + object operator/=(object_api const &other) const; + object operator|(object_api const &other) const; + object operator|=(object_api const &other) const; + object operator&(object_api const &other) const; + object operator&=(object_api const &other) const; + object operator^(object_api const &other) const; + object operator^=(object_api const &other) const; + object operator<<(object_api const &other) const; + object operator<<=(object_api const &other) const; + object operator>>(object_api const &other) const; + object operator>>=(object_api const &other) const; + + PYBIND11_DEPRECATED("Use py::str(obj) instead") + pybind11::str str() const; + + /// Get or set the object's docstring, i.e. ``obj.__doc__``. + str_attr_accessor doc() const; + + /// Return the object's current reference count + int ref_count() const { return static_cast(Py_REFCNT(derived().ptr())); } + /// Return a handle to the Python type object underlying the instance + handle get_type() const; + +private: + bool rich_compare(object_api const &other, int value) const; +}; + +NAMESPACE_END(detail) + +/** \rst + Holds a reference to a Python object (no reference counting) + + The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a + ``PyObject *`` in Python's C API). It does not perform any automatic reference + counting and merely provides a basic C++ interface to various Python API functions. + + .. seealso:: + The `object` class inherits from `handle` and adds automatic reference + counting features. +\endrst */ +class handle : public detail::object_api { +public: + /// The default constructor creates a handle with a ``nullptr``-valued pointer + handle() = default; + /// Creates a ``handle`` from the given raw Python object pointer + handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject* + + /// Return the underlying ``PyObject *`` pointer + PyObject *ptr() const { return m_ptr; } + PyObject *&ptr() { return m_ptr; } + + /** \rst + Manually increase the reference count of the Python object. Usually, it is + preferable to use the `object` class which derives from `handle` and calls + this function automatically. Returns a reference to itself. + \endrst */ + const handle& inc_ref() const & { Py_XINCREF(m_ptr); return *this; } + + /** \rst + Manually decrease the reference count of the Python object. Usually, it is + preferable to use the `object` class which derives from `handle` and calls + this function automatically. Returns a reference to itself. + \endrst */ + const handle& dec_ref() const & { Py_XDECREF(m_ptr); return *this; } + + /** \rst + Attempt to cast the Python object into the given C++ type. A `cast_error` + will be throw upon failure. + \endrst */ + template T cast() const; + /// Return ``true`` when the `handle` wraps a valid Python object + explicit operator bool() const { return m_ptr != nullptr; } + /** \rst + Deprecated: Check that the underlying pointers are the same. + Equivalent to ``obj1 is obj2`` in Python. + \endrst */ + PYBIND11_DEPRECATED("Use obj1.is(obj2) instead") + bool operator==(const handle &h) const { return m_ptr == h.m_ptr; } + PYBIND11_DEPRECATED("Use !obj1.is(obj2) instead") + bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; } + PYBIND11_DEPRECATED("Use handle::operator bool() instead") + bool check() const { return m_ptr != nullptr; } +protected: + PyObject *m_ptr = nullptr; +}; + +/** \rst + Holds a reference to a Python object (with reference counting) + + Like `handle`, the `object` class is a thin wrapper around an arbitrary Python + object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it + optionally increases the object's reference count upon construction, and it + *always* decreases the reference count when the `object` instance goes out of + scope and is destructed. When using `object` instances consistently, it is much + easier to get reference counting right at the first attempt. +\endrst */ +class object : public handle { +public: + object() = default; + PYBIND11_DEPRECATED("Use reinterpret_borrow() or reinterpret_steal()") + object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); } + /// Copy constructor; always increases the reference count + object(const object &o) : handle(o) { inc_ref(); } + /// Move constructor; steals the object from ``other`` and preserves its reference count + object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; } + /// Destructor; automatically calls `handle::dec_ref()` + ~object() { dec_ref(); } + + /** \rst + Resets the internal pointer to ``nullptr`` without without decreasing the + object's reference count. The function returns a raw handle to the original + Python object. + \endrst */ + handle release() { + PyObject *tmp = m_ptr; + m_ptr = nullptr; + return handle(tmp); + } + + object& operator=(const object &other) { + other.inc_ref(); + dec_ref(); + m_ptr = other.m_ptr; + return *this; + } + + object& operator=(object &&other) noexcept { + if (this != &other) { + handle temp(m_ptr); + m_ptr = other.m_ptr; + other.m_ptr = nullptr; + temp.dec_ref(); + } + return *this; + } + + // Calling cast() on an object lvalue just copies (via handle::cast) + template T cast() const &; + // Calling on an object rvalue does a move, if needed and/or possible + template T cast() &&; + +protected: + // Tags for choosing constructors from raw PyObject * + struct borrowed_t { }; + struct stolen_t { }; + + template friend T reinterpret_borrow(handle); + template friend T reinterpret_steal(handle); + +public: + // Only accessible from derived classes and the reinterpret_* functions + object(handle h, borrowed_t) : handle(h) { inc_ref(); } + object(handle h, stolen_t) : handle(h) { } +}; + +/** \rst + Declare that a `handle` or ``PyObject *`` is a certain type and borrow the reference. + The target type ``T`` must be `object` or one of its derived classes. The function + doesn't do any conversions or checks. It's up to the user to make sure that the + target type is correct. + + .. code-block:: cpp + + PyObject *p = PyList_GetItem(obj, index); + py::object o = reinterpret_borrow(p); + // or + py::tuple t = reinterpret_borrow(p); // <-- `p` must be already be a `tuple` +\endrst */ +template T reinterpret_borrow(handle h) { return {h, object::borrowed_t{}}; } + +/** \rst + Like `reinterpret_borrow`, but steals the reference. + + .. code-block:: cpp + + PyObject *p = PyObject_Str(obj); + py::str s = reinterpret_steal(p); // <-- `p` must be already be a `str` +\endrst */ +template T reinterpret_steal(handle h) { return {h, object::stolen_t{}}; } + +NAMESPACE_BEGIN(detail) +inline std::string error_string(); +NAMESPACE_END(detail) + +/// Fetch and hold an error which was already set in Python. An instance of this is typically +/// thrown to propagate python-side errors back through C++ which can either be caught manually or +/// else falls back to the function dispatcher (which then raises the captured error back to +/// python). +class error_already_set : public std::runtime_error { +public: + /// Constructs a new exception from the current Python error indicator, if any. The current + /// Python error indicator will be cleared. + error_already_set() : std::runtime_error(detail::error_string()) { + PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr()); + } + + error_already_set(const error_already_set &) = default; + error_already_set(error_already_set &&) = default; + + inline ~error_already_set(); + + /// Give the currently-held error back to Python, if any. If there is currently a Python error + /// already set it is cleared first. After this call, the current object no longer stores the + /// error variables (but the `.what()` string is still available). + void restore() { PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr()); } + + // Does nothing; provided for backwards compatibility. + PYBIND11_DEPRECATED("Use of error_already_set.clear() is deprecated") + void clear() {} + + /// Check if the currently trapped error type matches the given Python exception class (or a + /// subclass thereof). May also be passed a tuple to search for any exception class matches in + /// the given tuple. + bool matches(handle exc) const { return PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()); } + + const object& type() const { return m_type; } + const object& value() const { return m_value; } + const object& trace() const { return m_trace; } + +private: + object m_type, m_value, m_trace; +}; + +/** \defgroup python_builtins _ + Unless stated otherwise, the following C++ functions behave the same + as their Python counterparts. + */ + +/** \ingroup python_builtins + \rst + Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of + `object` or a class which was exposed to Python as ``py::class_``. +\endrst */ +template ::value, int> = 0> +bool isinstance(handle obj) { return T::check_(obj); } + +template ::value, int> = 0> +bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T)); } + +template <> inline bool isinstance(handle obj) = delete; +template <> inline bool isinstance(handle obj) { return obj.ptr() != nullptr; } + +/// \ingroup python_builtins +/// Return true if ``obj`` is an instance of the ``type``. +inline bool isinstance(handle obj, handle type) { + const auto result = PyObject_IsInstance(obj.ptr(), type.ptr()); + if (result == -1) + throw error_already_set(); + return result != 0; +} + +/// \addtogroup python_builtins +/// @{ +inline bool hasattr(handle obj, handle name) { + return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1; +} + +inline bool hasattr(handle obj, const char *name) { + return PyObject_HasAttrString(obj.ptr(), name) == 1; +} + +inline void delattr(handle obj, handle name) { + if (PyObject_DelAttr(obj.ptr(), name.ptr()) != 0) { throw error_already_set(); } +} + +inline void delattr(handle obj, const char *name) { + if (PyObject_DelAttrString(obj.ptr(), name) != 0) { throw error_already_set(); } +} + +inline object getattr(handle obj, handle name) { + PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr()); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); +} + +inline object getattr(handle obj, const char *name) { + PyObject *result = PyObject_GetAttrString(obj.ptr(), name); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); +} + +inline object getattr(handle obj, handle name, handle default_) { + if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) { + return reinterpret_steal(result); + } else { + PyErr_Clear(); + return reinterpret_borrow(default_); + } +} + +inline object getattr(handle obj, const char *name, handle default_) { + if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) { + return reinterpret_steal(result); + } else { + PyErr_Clear(); + return reinterpret_borrow(default_); + } +} + +inline void setattr(handle obj, handle name, handle value) { + if (PyObject_SetAttr(obj.ptr(), name.ptr(), value.ptr()) != 0) { throw error_already_set(); } +} + +inline void setattr(handle obj, const char *name, handle value) { + if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); } +} + +inline ssize_t hash(handle obj) { + auto h = PyObject_Hash(obj.ptr()); + if (h == -1) { throw error_already_set(); } + return h; +} + +/// @} python_builtins + +NAMESPACE_BEGIN(detail) +inline handle get_function(handle value) { + if (value) { +#if PY_MAJOR_VERSION >= 3 + if (PyInstanceMethod_Check(value.ptr())) + value = PyInstanceMethod_GET_FUNCTION(value.ptr()); + else +#endif + if (PyMethod_Check(value.ptr())) + value = PyMethod_GET_FUNCTION(value.ptr()); + } + return value; +} + +// Helper aliases/functions to support implicit casting of values given to python accessors/methods. +// When given a pyobject, this simply returns the pyobject as-is; for other C++ type, the value goes +// through pybind11::cast(obj) to convert it to an `object`. +template ::value, int> = 0> +auto object_or_cast(T &&o) -> decltype(std::forward(o)) { return std::forward(o); } +// The following casting version is implemented in cast.h: +template ::value, int> = 0> +object object_or_cast(T &&o); +// Match a PyObject*, which we want to convert directly to handle via its converting constructor +inline handle object_or_cast(PyObject *ptr) { return ptr; } + +template +class accessor : public object_api> { + using key_type = typename Policy::key_type; + +public: + accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) { } + accessor(const accessor &) = default; + accessor(accessor &&) = default; + + // accessor overload required to override default assignment operator (templates are not allowed + // to replace default compiler-generated assignments). + void operator=(const accessor &a) && { std::move(*this).operator=(handle(a)); } + void operator=(const accessor &a) & { operator=(handle(a)); } + + template void operator=(T &&value) && { + Policy::set(obj, key, object_or_cast(std::forward(value))); + } + template void operator=(T &&value) & { + get_cache() = reinterpret_borrow(object_or_cast(std::forward(value))); + } + + template + PYBIND11_DEPRECATED("Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)") + explicit operator enable_if_t::value || + std::is_same::value, bool>() const { + return hasattr(obj, key); + } + template + PYBIND11_DEPRECATED("Use of obj[key] as bool is deprecated in favor of obj.contains(key)") + explicit operator enable_if_t::value, bool>() const { + return obj.contains(key); + } + + operator object() const { return get_cache(); } + PyObject *ptr() const { return get_cache().ptr(); } + template T cast() const { return get_cache().template cast(); } + +private: + object &get_cache() const { + if (!cache) { cache = Policy::get(obj, key); } + return cache; + } + +private: + handle obj; + key_type key; + mutable object cache; +}; + +NAMESPACE_BEGIN(accessor_policies) +struct obj_attr { + using key_type = object; + static object get(handle obj, handle key) { return getattr(obj, key); } + static void set(handle obj, handle key, handle val) { setattr(obj, key, val); } +}; + +struct str_attr { + using key_type = const char *; + static object get(handle obj, const char *key) { return getattr(obj, key); } + static void set(handle obj, const char *key, handle val) { setattr(obj, key, val); } +}; + +struct generic_item { + using key_type = object; + + static object get(handle obj, handle key) { + PyObject *result = PyObject_GetItem(obj.ptr(), key.ptr()); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); + } + + static void set(handle obj, handle key, handle val) { + if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) { throw error_already_set(); } + } +}; + +struct sequence_item { + using key_type = size_t; + + static object get(handle obj, size_t index) { + PyObject *result = PySequence_GetItem(obj.ptr(), static_cast(index)); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); + } + + static void set(handle obj, size_t index, handle val) { + // PySequence_SetItem does not steal a reference to 'val' + if (PySequence_SetItem(obj.ptr(), static_cast(index), val.ptr()) != 0) { + throw error_already_set(); + } + } +}; + +struct list_item { + using key_type = size_t; + + static object get(handle obj, size_t index) { + PyObject *result = PyList_GetItem(obj.ptr(), static_cast(index)); + if (!result) { throw error_already_set(); } + return reinterpret_borrow(result); + } + + static void set(handle obj, size_t index, handle val) { + // PyList_SetItem steals a reference to 'val' + if (PyList_SetItem(obj.ptr(), static_cast(index), val.inc_ref().ptr()) != 0) { + throw error_already_set(); + } + } +}; + +struct tuple_item { + using key_type = size_t; + + static object get(handle obj, size_t index) { + PyObject *result = PyTuple_GetItem(obj.ptr(), static_cast(index)); + if (!result) { throw error_already_set(); } + return reinterpret_borrow(result); + } + + static void set(handle obj, size_t index, handle val) { + // PyTuple_SetItem steals a reference to 'val' + if (PyTuple_SetItem(obj.ptr(), static_cast(index), val.inc_ref().ptr()) != 0) { + throw error_already_set(); + } + } +}; +NAMESPACE_END(accessor_policies) + +/// STL iterator template used for tuple, list, sequence and dict +template +class generic_iterator : public Policy { + using It = generic_iterator; + +public: + using difference_type = ssize_t; + using iterator_category = typename Policy::iterator_category; + using value_type = typename Policy::value_type; + using reference = typename Policy::reference; + using pointer = typename Policy::pointer; + + generic_iterator() = default; + generic_iterator(handle seq, ssize_t index) : Policy(seq, index) { } + + reference operator*() const { return Policy::dereference(); } + reference operator[](difference_type n) const { return *(*this + n); } + pointer operator->() const { return **this; } + + It &operator++() { Policy::increment(); return *this; } + It operator++(int) { auto copy = *this; Policy::increment(); return copy; } + It &operator--() { Policy::decrement(); return *this; } + It operator--(int) { auto copy = *this; Policy::decrement(); return copy; } + It &operator+=(difference_type n) { Policy::advance(n); return *this; } + It &operator-=(difference_type n) { Policy::advance(-n); return *this; } + + friend It operator+(const It &a, difference_type n) { auto copy = a; return copy += n; } + friend It operator+(difference_type n, const It &b) { return b + n; } + friend It operator-(const It &a, difference_type n) { auto copy = a; return copy -= n; } + friend difference_type operator-(const It &a, const It &b) { return a.distance_to(b); } + + friend bool operator==(const It &a, const It &b) { return a.equal(b); } + friend bool operator!=(const It &a, const It &b) { return !(a == b); } + friend bool operator< (const It &a, const It &b) { return b - a > 0; } + friend bool operator> (const It &a, const It &b) { return b < a; } + friend bool operator>=(const It &a, const It &b) { return !(a < b); } + friend bool operator<=(const It &a, const It &b) { return !(a > b); } +}; + +NAMESPACE_BEGIN(iterator_policies) +/// Quick proxy class needed to implement ``operator->`` for iterators which can't return pointers +template +struct arrow_proxy { + T value; + + arrow_proxy(T &&value) : value(std::move(value)) { } + T *operator->() const { return &value; } +}; + +/// Lightweight iterator policy using just a simple pointer: see ``PySequence_Fast_ITEMS`` +class sequence_fast_readonly { +protected: + using iterator_category = std::random_access_iterator_tag; + using value_type = handle; + using reference = const handle; + using pointer = arrow_proxy; + + sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) { } + + reference dereference() const { return *ptr; } + void increment() { ++ptr; } + void decrement() { --ptr; } + void advance(ssize_t n) { ptr += n; } + bool equal(const sequence_fast_readonly &b) const { return ptr == b.ptr; } + ssize_t distance_to(const sequence_fast_readonly &b) const { return ptr - b.ptr; } + +private: + PyObject **ptr; +}; + +/// Full read and write access using the sequence protocol: see ``detail::sequence_accessor`` +class sequence_slow_readwrite { +protected: + using iterator_category = std::random_access_iterator_tag; + using value_type = object; + using reference = sequence_accessor; + using pointer = arrow_proxy; + + sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) { } + + reference dereference() const { return {obj, static_cast(index)}; } + void increment() { ++index; } + void decrement() { --index; } + void advance(ssize_t n) { index += n; } + bool equal(const sequence_slow_readwrite &b) const { return index == b.index; } + ssize_t distance_to(const sequence_slow_readwrite &b) const { return index - b.index; } + +private: + handle obj; + ssize_t index; +}; + +/// Python's dictionary protocol permits this to be a forward iterator +class dict_readonly { +protected: + using iterator_category = std::forward_iterator_tag; + using value_type = std::pair; + using reference = const value_type; + using pointer = arrow_proxy; + + dict_readonly() = default; + dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); } + + reference dereference() const { return {key, value}; } + void increment() { if (!PyDict_Next(obj.ptr(), &pos, &key, &value)) { pos = -1; } } + bool equal(const dict_readonly &b) const { return pos == b.pos; } + +private: + handle obj; + PyObject *key = nullptr, *value = nullptr; + ssize_t pos = -1; +}; +NAMESPACE_END(iterator_policies) + +#if !defined(PYPY_VERSION) +using tuple_iterator = generic_iterator; +using list_iterator = generic_iterator; +#else +using tuple_iterator = generic_iterator; +using list_iterator = generic_iterator; +#endif + +using sequence_iterator = generic_iterator; +using dict_iterator = generic_iterator; + +inline bool PyIterable_Check(PyObject *obj) { + PyObject *iter = PyObject_GetIter(obj); + if (iter) { + Py_DECREF(iter); + return true; + } else { + PyErr_Clear(); + return false; + } +} + +inline bool PyNone_Check(PyObject *o) { return o == Py_None; } +#if PY_MAJOR_VERSION >= 3 +inline bool PyEllipsis_Check(PyObject *o) { return o == Py_Ellipsis; } +#endif + +inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); } + +inline bool PyStaticMethod_Check(PyObject *o) { return o->ob_type == &PyStaticMethod_Type; } + +class kwargs_proxy : public handle { +public: + explicit kwargs_proxy(handle h) : handle(h) { } +}; + +class args_proxy : public handle { +public: + explicit args_proxy(handle h) : handle(h) { } + kwargs_proxy operator*() const { return kwargs_proxy(*this); } +}; + +/// Python argument categories (using PEP 448 terms) +template using is_keyword = std::is_base_of; +template using is_s_unpacking = std::is_same; // * unpacking +template using is_ds_unpacking = std::is_same; // ** unpacking +template using is_positional = satisfies_none_of; +template using is_keyword_or_ds = satisfies_any_of; + +// Call argument collector forward declarations +template +class simple_collector; +template +class unpacking_collector; + +NAMESPACE_END(detail) + +// TODO: After the deprecated constructors are removed, this macro can be simplified by +// inheriting ctors: `using Parent::Parent`. It's not an option right now because +// the `using` statement triggers the parent deprecation warning even if the ctor +// isn't even used. +#define PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ + public: \ + PYBIND11_DEPRECATED("Use reinterpret_borrow<"#Name">() or reinterpret_steal<"#Name">()") \ + Name(handle h, bool is_borrowed) : Parent(is_borrowed ? Parent(h, borrowed_t{}) : Parent(h, stolen_t{})) { } \ + Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) { } \ + Name(handle h, stolen_t) : Parent(h, stolen_t{}) { } \ + PYBIND11_DEPRECATED("Use py::isinstance(obj) instead") \ + bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } \ + static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } + +#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \ + PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ + /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \ + Name(const object &o) \ + : Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) \ + { if (!m_ptr) throw error_already_set(); } \ + Name(object &&o) \ + : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) \ + { if (!m_ptr) throw error_already_set(); } \ + template \ + Name(const ::pybind11::detail::accessor &a) : Name(object(a)) { } + +#define PYBIND11_OBJECT(Name, Parent, CheckFun) \ + PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ + /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \ + Name(const object &o) : Parent(o) { } \ + Name(object &&o) : Parent(std::move(o)) { } + +#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \ + PYBIND11_OBJECT(Name, Parent, CheckFun) \ + Name() : Parent() { } + +/// \addtogroup pytypes +/// @{ + +/** \rst + Wraps a Python iterator so that it can also be used as a C++ input iterator + + Caveat: copying an iterator does not (and cannot) clone the internal + state of the Python iterable. This also applies to the post-increment + operator. This iterator should only be used to retrieve the current + value using ``operator*()``. +\endrst */ +class iterator : public object { +public: + using iterator_category = std::input_iterator_tag; + using difference_type = ssize_t; + using value_type = handle; + using reference = const handle; + using pointer = const handle *; + + PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check) + + iterator& operator++() { + advance(); + return *this; + } + + iterator operator++(int) { + auto rv = *this; + advance(); + return rv; + } + + reference operator*() const { + if (m_ptr && !value.ptr()) { + auto& self = const_cast(*this); + self.advance(); + } + return value; + } + + pointer operator->() const { operator*(); return &value; } + + /** \rst + The value which marks the end of the iteration. ``it == iterator::sentinel()`` + is equivalent to catching ``StopIteration`` in Python. + + .. code-block:: cpp + + void foo(py::iterator it) { + while (it != py::iterator::sentinel()) { + // use `*it` + ++it; + } + } + \endrst */ + static iterator sentinel() { return {}; } + + friend bool operator==(const iterator &a, const iterator &b) { return a->ptr() == b->ptr(); } + friend bool operator!=(const iterator &a, const iterator &b) { return a->ptr() != b->ptr(); } + +private: + void advance() { + value = reinterpret_steal(PyIter_Next(m_ptr)); + if (PyErr_Occurred()) { throw error_already_set(); } + } + +private: + object value = {}; +}; + +class iterable : public object { +public: + PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check) +}; + +class bytes; + +class str : public object { +public: + PYBIND11_OBJECT_CVT(str, object, detail::PyUnicode_Check_Permissive, raw_str) + + str(const char *c, size_t n) + : object(PyUnicode_FromStringAndSize(c, (ssize_t) n), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate string object!"); + } + + // 'explicit' is explicitly omitted from the following constructors to allow implicit conversion to py::str from C++ string-like objects + str(const char *c = "") + : object(PyUnicode_FromString(c), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate string object!"); + } + + str(const std::string &s) : str(s.data(), s.size()) { } + + explicit str(const bytes &b); + + /** \rst + Return a string representation of the object. This is analogous to + the ``str()`` function in Python. + \endrst */ + explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) { } + + operator std::string() const { + object temp = *this; + if (PyUnicode_Check(m_ptr)) { + temp = reinterpret_steal(PyUnicode_AsUTF8String(m_ptr)); + if (!temp) + pybind11_fail("Unable to extract string contents! (encoding issue)"); + } + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) + pybind11_fail("Unable to extract string contents! (invalid type)"); + return std::string(buffer, (size_t) length); + } + + template + str format(Args &&...args) const { + return attr("format")(std::forward(args)...); + } + +private: + /// Return string representation -- always returns a new reference, even if already a str + static PyObject *raw_str(PyObject *op) { + PyObject *str_value = PyObject_Str(op); +#if PY_MAJOR_VERSION < 3 + if (!str_value) throw error_already_set(); + PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr); + Py_XDECREF(str_value); str_value = unicode; +#endif + return str_value; + } +}; +/// @} pytypes + +inline namespace literals { +/** \rst + String literal version of `str` + \endrst */ +inline str operator"" _s(const char *s, size_t size) { return {s, size}; } +} + +/// \addtogroup pytypes +/// @{ +class bytes : public object { +public: + PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK) + + // Allow implicit conversion: + bytes(const char *c = "") + : object(PYBIND11_BYTES_FROM_STRING(c), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); + } + + bytes(const char *c, size_t n) + : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, (ssize_t) n), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); + } + + // Allow implicit conversion: + bytes(const std::string &s) : bytes(s.data(), s.size()) { } + + explicit bytes(const pybind11::str &s); + + operator std::string() const { + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) + pybind11_fail("Unable to extract bytes contents!"); + return std::string(buffer, (size_t) length); + } +}; + +inline bytes::bytes(const pybind11::str &s) { + object temp = s; + if (PyUnicode_Check(s.ptr())) { + temp = reinterpret_steal(PyUnicode_AsUTF8String(s.ptr())); + if (!temp) + pybind11_fail("Unable to extract string contents! (encoding issue)"); + } + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) + pybind11_fail("Unable to extract string contents! (invalid type)"); + auto obj = reinterpret_steal(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length)); + if (!obj) + pybind11_fail("Could not allocate bytes object!"); + m_ptr = obj.release().ptr(); +} + +inline str::str(const bytes& b) { + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) + pybind11_fail("Unable to extract bytes contents!"); + auto obj = reinterpret_steal(PyUnicode_FromStringAndSize(buffer, (ssize_t) length)); + if (!obj) + pybind11_fail("Could not allocate string object!"); + m_ptr = obj.release().ptr(); +} + +class none : public object { +public: + PYBIND11_OBJECT(none, object, detail::PyNone_Check) + none() : object(Py_None, borrowed_t{}) { } +}; + +#if PY_MAJOR_VERSION >= 3 +class ellipsis : public object { +public: + PYBIND11_OBJECT(ellipsis, object, detail::PyEllipsis_Check) + ellipsis() : object(Py_Ellipsis, borrowed_t{}) { } +}; +#endif + +class bool_ : public object { +public: + PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool) + bool_() : object(Py_False, borrowed_t{}) { } + // Allow implicit conversion from and to `bool`: + bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { } + operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; } + +private: + /// Return the truth value of an object -- always returns a new reference + static PyObject *raw_bool(PyObject *op) { + const auto value = PyObject_IsTrue(op); + if (value == -1) return nullptr; + return handle(value ? Py_True : Py_False).inc_ref().ptr(); + } +}; + +NAMESPACE_BEGIN(detail) +// Converts a value to the given unsigned type. If an error occurs, you get back (Unsigned) -1; +// otherwise you get back the unsigned long or unsigned long long value cast to (Unsigned). +// (The distinction is critically important when casting a returned -1 error value to some other +// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes). +template +Unsigned as_unsigned(PyObject *o) { + if (sizeof(Unsigned) <= sizeof(unsigned long) +#if PY_VERSION_HEX < 0x03000000 + || PyInt_Check(o) +#endif + ) { + unsigned long v = PyLong_AsUnsignedLong(o); + return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; + } + else { + unsigned long long v = PyLong_AsUnsignedLongLong(o); + return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; + } +} +NAMESPACE_END(detail) + +class int_ : public object { +public: + PYBIND11_OBJECT_CVT(int_, object, PYBIND11_LONG_CHECK, PyNumber_Long) + int_() : object(PyLong_FromLong(0), stolen_t{}) { } + // Allow implicit conversion from C++ integral types: + template ::value, int> = 0> + int_(T value) { + if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + m_ptr = PyLong_FromLong((long) value); + else + m_ptr = PyLong_FromUnsignedLong((unsigned long) value); + } else { + if (std::is_signed::value) + m_ptr = PyLong_FromLongLong((long long) value); + else + m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value); + } + if (!m_ptr) pybind11_fail("Could not allocate int object!"); + } + + template ::value, int> = 0> + operator T() const { + return std::is_unsigned::value + ? detail::as_unsigned(m_ptr) + : sizeof(T) <= sizeof(long) + ? (T) PyLong_AsLong(m_ptr) + : (T) PYBIND11_LONG_AS_LONGLONG(m_ptr); + } +}; + +class float_ : public object { +public: + PYBIND11_OBJECT_CVT(float_, object, PyFloat_Check, PyNumber_Float) + // Allow implicit conversion from float/double: + float_(float value) : object(PyFloat_FromDouble((double) value), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate float object!"); + } + float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate float object!"); + } + operator float() const { return (float) PyFloat_AsDouble(m_ptr); } + operator double() const { return (double) PyFloat_AsDouble(m_ptr); } +}; + +class weakref : public object { +public: + PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check) + explicit weakref(handle obj, handle callback = {}) + : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate weak reference!"); + } +}; + +class slice : public object { +public: + PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check) + slice(ssize_t start_, ssize_t stop_, ssize_t step_) { + int_ start(start_), stop(stop_), step(step_); + m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); + if (!m_ptr) pybind11_fail("Could not allocate slice object!"); + } + bool compute(size_t length, size_t *start, size_t *stop, size_t *step, + size_t *slicelength) const { + return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, + (ssize_t) length, (ssize_t *) start, + (ssize_t *) stop, (ssize_t *) step, + (ssize_t *) slicelength) == 0; + } + bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, + ssize_t *slicelength) const { + return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, + length, start, + stop, step, + slicelength) == 0; + } +}; + +class capsule : public object { +public: + PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact) + PYBIND11_DEPRECATED("Use reinterpret_borrow() or reinterpret_steal()") + capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed_t{}) : object(ptr, stolen_t{})) { } + + explicit capsule(const void *value, const char *name = nullptr, void (*destructor)(PyObject *) = nullptr) + : object(PyCapsule_New(const_cast(value), name, destructor), stolen_t{}) { + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + + PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input") + capsule(const void *value, void (*destruct)(PyObject *)) + : object(PyCapsule_New(const_cast(value), nullptr, destruct), stolen_t{}) { + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + + capsule(const void *value, void (*destructor)(void *)) { + m_ptr = PyCapsule_New(const_cast(value), nullptr, [](PyObject *o) { + auto destructor = reinterpret_cast(PyCapsule_GetContext(o)); + void *ptr = PyCapsule_GetPointer(o, nullptr); + destructor(ptr); + }); + + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + + if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) + pybind11_fail("Could not set capsule context!"); + } + + capsule(void (*destructor)()) { + m_ptr = PyCapsule_New(reinterpret_cast(destructor), nullptr, [](PyObject *o) { + auto destructor = reinterpret_cast(PyCapsule_GetPointer(o, nullptr)); + destructor(); + }); + + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + + template operator T *() const { + auto name = this->name(); + T * result = static_cast(PyCapsule_GetPointer(m_ptr, name)); + if (!result) pybind11_fail("Unable to extract capsule contents!"); + return result; + } + + const char *name() const { return PyCapsule_GetName(m_ptr); } +}; + +class tuple : public object { +public: + PYBIND11_OBJECT_CVT(tuple, object, PyTuple_Check, PySequence_Tuple) + explicit tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate tuple object!"); + } + size_t size() const { return (size_t) PyTuple_Size(m_ptr); } + bool empty() const { return size() == 0; } + detail::tuple_accessor operator[](size_t index) const { return {*this, index}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } + detail::tuple_iterator begin() const { return {*this, 0}; } + detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; } +}; + +class dict : public object { +public: + PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict) + dict() : object(PyDict_New(), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate dict object!"); + } + template ...>::value>, + // MSVC workaround: it can't compile an out-of-line definition, so defer the collector + typename collector = detail::deferred_t, Args...>> + explicit dict(Args &&...args) : dict(collector(std::forward(args)...).kwargs()) { } + + size_t size() const { return (size_t) PyDict_Size(m_ptr); } + bool empty() const { return size() == 0; } + detail::dict_iterator begin() const { return {*this, 0}; } + detail::dict_iterator end() const { return {}; } + void clear() const { PyDict_Clear(ptr()); } + template bool contains(T &&key) const { + return PyDict_Contains(m_ptr, detail::object_or_cast(std::forward(key)).ptr()) == 1; + } + +private: + /// Call the `dict` Python type -- always returns a new reference + static PyObject *raw_dict(PyObject *op) { + if (PyDict_Check(op)) + return handle(op).inc_ref().ptr(); + return PyObject_CallFunctionObjArgs((PyObject *) &PyDict_Type, op, nullptr); + } +}; + +class sequence : public object { +public: + PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check) + size_t size() const { return (size_t) PySequence_Size(m_ptr); } + bool empty() const { return size() == 0; } + detail::sequence_accessor operator[](size_t index) const { return {*this, index}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } + detail::sequence_iterator begin() const { return {*this, 0}; } + detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; } +}; + +class list : public object { +public: + PYBIND11_OBJECT_CVT(list, object, PyList_Check, PySequence_List) + explicit list(size_t size = 0) : object(PyList_New((ssize_t) size), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate list object!"); + } + size_t size() const { return (size_t) PyList_Size(m_ptr); } + bool empty() const { return size() == 0; } + detail::list_accessor operator[](size_t index) const { return {*this, index}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } + detail::list_iterator begin() const { return {*this, 0}; } + detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; } + template void append(T &&val) const { + PyList_Append(m_ptr, detail::object_or_cast(std::forward(val)).ptr()); + } + template void insert(size_t index, T &&val) const { + PyList_Insert(m_ptr, static_cast(index), + detail::object_or_cast(std::forward(val)).ptr()); + } +}; + +class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) }; +class kwargs : public dict { PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check) }; + +class set : public object { +public: + PYBIND11_OBJECT_CVT(set, object, PySet_Check, PySet_New) + set() : object(PySet_New(nullptr), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate set object!"); + } + size_t size() const { return (size_t) PySet_Size(m_ptr); } + bool empty() const { return size() == 0; } + template bool add(T &&val) const { + return PySet_Add(m_ptr, detail::object_or_cast(std::forward(val)).ptr()) == 0; + } + void clear() const { PySet_Clear(m_ptr); } + template bool contains(T &&val) const { + return PySet_Contains(m_ptr, detail::object_or_cast(std::forward(val)).ptr()) == 1; + } +}; + +class function : public object { +public: + PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check) + handle cpp_function() const { + handle fun = detail::get_function(m_ptr); + if (fun && PyCFunction_Check(fun.ptr())) + return fun; + return handle(); + } + bool is_cpp_function() const { return (bool) cpp_function(); } +}; + +class staticmethod : public object { +public: + PYBIND11_OBJECT_CVT(staticmethod, object, detail::PyStaticMethod_Check, PyStaticMethod_New) +}; + +class buffer : public object { +public: + PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer) + + buffer_info request(bool writable = false) const { + int flags = PyBUF_STRIDES | PyBUF_FORMAT; + if (writable) flags |= PyBUF_WRITABLE; + Py_buffer *view = new Py_buffer(); + if (PyObject_GetBuffer(m_ptr, view, flags) != 0) { + delete view; + throw error_already_set(); + } + return buffer_info(view); + } +}; + +class memoryview : public object { +public: + explicit memoryview(const buffer_info& info) { + static Py_buffer buf { }; + // Py_buffer uses signed sizes, strides and shape!.. + static std::vector py_strides { }; + static std::vector py_shape { }; + buf.buf = info.ptr; + buf.itemsize = info.itemsize; + buf.format = const_cast(info.format.c_str()); + buf.ndim = (int) info.ndim; + buf.len = info.size; + py_strides.clear(); + py_shape.clear(); + for (size_t i = 0; i < (size_t) info.ndim; ++i) { + py_strides.push_back(info.strides[i]); + py_shape.push_back(info.shape[i]); + } + buf.strides = py_strides.data(); + buf.shape = py_shape.data(); + buf.suboffsets = nullptr; + buf.readonly = info.readonly; + buf.internal = nullptr; + + m_ptr = PyMemoryView_FromBuffer(&buf); + if (!m_ptr) + pybind11_fail("Unable to create memoryview from buffer descriptor"); + } + + PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject) +}; +/// @} pytypes + +/// \addtogroup python_builtins +/// @{ +inline size_t len(handle h) { + ssize_t result = PyObject_Length(h.ptr()); + if (result < 0) + pybind11_fail("Unable to compute length of object"); + return (size_t) result; +} + +inline size_t len_hint(handle h) { +#if PY_VERSION_HEX >= 0x03040000 + ssize_t result = PyObject_LengthHint(h.ptr(), 0); +#else + ssize_t result = PyObject_Length(h.ptr()); +#endif + if (result < 0) { + // Sometimes a length can't be determined at all (eg generators) + // In which case simply return 0 + PyErr_Clear(); + return 0; + } + return (size_t) result; +} + +inline str repr(handle h) { + PyObject *str_value = PyObject_Repr(h.ptr()); + if (!str_value) throw error_already_set(); +#if PY_MAJOR_VERSION < 3 + PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr); + Py_XDECREF(str_value); str_value = unicode; + if (!str_value) throw error_already_set(); +#endif + return reinterpret_steal(str_value); +} + +inline iterator iter(handle obj) { + PyObject *result = PyObject_GetIter(obj.ptr()); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); +} +/// @} python_builtins + +NAMESPACE_BEGIN(detail) +template iterator object_api::begin() const { return iter(derived()); } +template iterator object_api::end() const { return iterator::sentinel(); } +template item_accessor object_api::operator[](handle key) const { + return {derived(), reinterpret_borrow(key)}; +} +template item_accessor object_api::operator[](const char *key) const { + return {derived(), pybind11::str(key)}; +} +template obj_attr_accessor object_api::attr(handle key) const { + return {derived(), reinterpret_borrow(key)}; +} +template str_attr_accessor object_api::attr(const char *key) const { + return {derived(), key}; +} +template args_proxy object_api::operator*() const { + return args_proxy(derived().ptr()); +} +template template bool object_api::contains(T &&item) const { + return attr("__contains__")(std::forward(item)).template cast(); +} + +template +pybind11::str object_api::str() const { return pybind11::str(derived()); } + +template +str_attr_accessor object_api::doc() const { return attr("__doc__"); } + +template +handle object_api::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); } + +template +bool object_api::rich_compare(object_api const &other, int value) const { + int rv = PyObject_RichCompareBool(derived().ptr(), other.derived().ptr(), value); + if (rv == -1) + throw error_already_set(); + return rv == 1; +} + +#define PYBIND11_MATH_OPERATOR_UNARY(op, fn) \ + template object object_api::op() const { \ + object result = reinterpret_steal(fn(derived().ptr())); \ + if (!result.ptr()) \ + throw error_already_set(); \ + return result; \ + } + +#define PYBIND11_MATH_OPERATOR_BINARY(op, fn) \ + template \ + object object_api::op(object_api const &other) const { \ + object result = reinterpret_steal( \ + fn(derived().ptr(), other.derived().ptr())); \ + if (!result.ptr()) \ + throw error_already_set(); \ + return result; \ + } + +PYBIND11_MATH_OPERATOR_UNARY (operator~, PyNumber_Invert) +PYBIND11_MATH_OPERATOR_UNARY (operator-, PyNumber_Negative) +PYBIND11_MATH_OPERATOR_BINARY(operator+, PyNumber_Add) +PYBIND11_MATH_OPERATOR_BINARY(operator+=, PyNumber_InPlaceAdd) +PYBIND11_MATH_OPERATOR_BINARY(operator-, PyNumber_Subtract) +PYBIND11_MATH_OPERATOR_BINARY(operator-=, PyNumber_InPlaceSubtract) +PYBIND11_MATH_OPERATOR_BINARY(operator*, PyNumber_Multiply) +PYBIND11_MATH_OPERATOR_BINARY(operator*=, PyNumber_InPlaceMultiply) +PYBIND11_MATH_OPERATOR_BINARY(operator/, PyNumber_TrueDivide) +PYBIND11_MATH_OPERATOR_BINARY(operator/=, PyNumber_InPlaceTrueDivide) +PYBIND11_MATH_OPERATOR_BINARY(operator|, PyNumber_Or) +PYBIND11_MATH_OPERATOR_BINARY(operator|=, PyNumber_InPlaceOr) +PYBIND11_MATH_OPERATOR_BINARY(operator&, PyNumber_And) +PYBIND11_MATH_OPERATOR_BINARY(operator&=, PyNumber_InPlaceAnd) +PYBIND11_MATH_OPERATOR_BINARY(operator^, PyNumber_Xor) +PYBIND11_MATH_OPERATOR_BINARY(operator^=, PyNumber_InPlaceXor) +PYBIND11_MATH_OPERATOR_BINARY(operator<<, PyNumber_Lshift) +PYBIND11_MATH_OPERATOR_BINARY(operator<<=, PyNumber_InPlaceLshift) +PYBIND11_MATH_OPERATOR_BINARY(operator>>, PyNumber_Rshift) +PYBIND11_MATH_OPERATOR_BINARY(operator>>=, PyNumber_InPlaceRshift) + +#undef PYBIND11_MATH_OPERATOR_UNARY +#undef PYBIND11_MATH_OPERATOR_BINARY + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/stl.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/stl.h new file mode 100644 index 0000000000000000000000000000000000000000..32f8d294ac5f67ad0ef6502e81091e7b81ad63ec --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/stl.h @@ -0,0 +1,386 @@ +/* + pybind11/stl.h: Transparent conversion for STL data types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +#ifdef __has_include +// std::optional (but including it in c++14 mode isn't allowed) +# if defined(PYBIND11_CPP17) && __has_include() +# include +# define PYBIND11_HAS_OPTIONAL 1 +# endif +// std::experimental::optional (but not allowed in c++11 mode) +# if defined(PYBIND11_CPP14) && (__has_include() && \ + !__has_include()) +# include +# define PYBIND11_HAS_EXP_OPTIONAL 1 +# endif +// std::variant +# if defined(PYBIND11_CPP17) && __has_include() +# include +# define PYBIND11_HAS_VARIANT 1 +# endif +#elif defined(_MSC_VER) && defined(PYBIND11_CPP17) +# include +# include +# define PYBIND11_HAS_OPTIONAL 1 +# define PYBIND11_HAS_VARIANT 1 +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for +/// forwarding a container element). Typically used indirect via forwarded_type(), below. +template +using forwarded_type = conditional_t< + std::is_lvalue_reference::value, remove_reference_t &, remove_reference_t &&>; + +/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically +/// used for forwarding a container's elements. +template +forwarded_type forward_like(U &&u) { + return std::forward>(std::forward(u)); +} + +template struct set_caster { + using type = Type; + using key_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto s = reinterpret_borrow(src); + value.clear(); + for (auto entry : s) { + key_conv conv; + if (!conv.load(entry, convert)) + return false; + value.insert(cast_op(std::move(conv))); + } + return true; + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + if (!std::is_lvalue_reference::value) + policy = return_value_policy_override::policy(policy); + pybind11::set s; + for (auto &&value : src) { + auto value_ = reinterpret_steal(key_conv::cast(forward_like(value), policy, parent)); + if (!value_ || !s.add(value_)) + return handle(); + } + return s.release(); + } + + PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name + _("]")); +}; + +template struct map_caster { + using key_conv = make_caster; + using value_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto d = reinterpret_borrow(src); + value.clear(); + for (auto it : d) { + key_conv kconv; + value_conv vconv; + if (!kconv.load(it.first.ptr(), convert) || + !vconv.load(it.second.ptr(), convert)) + return false; + value.emplace(cast_op(std::move(kconv)), cast_op(std::move(vconv))); + } + return true; + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + dict d; + return_value_policy policy_key = policy; + return_value_policy policy_value = policy; + if (!std::is_lvalue_reference::value) { + policy_key = return_value_policy_override::policy(policy_key); + policy_value = return_value_policy_override::policy(policy_value); + } + for (auto &&kv : src) { + auto key = reinterpret_steal(key_conv::cast(forward_like(kv.first), policy_key, parent)); + auto value = reinterpret_steal(value_conv::cast(forward_like(kv.second), policy_value, parent)); + if (!key || !value) + return handle(); + d[key] = value; + } + return d.release(); + } + + PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name + _(", ") + value_conv::name + _("]")); +}; + +template struct list_caster { + using value_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src) || isinstance(src)) + return false; + auto s = reinterpret_borrow(src); + value.clear(); + reserve_maybe(s, &value); + for (auto it : s) { + value_conv conv; + if (!conv.load(it, convert)) + return false; + value.push_back(cast_op(std::move(conv))); + } + return true; + } + +private: + template ().reserve(0)), void>::value, int> = 0> + void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); } + void reserve_maybe(sequence, void *) { } + +public: + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + if (!std::is_lvalue_reference::value) + policy = return_value_policy_override::policy(policy); + list l(src.size()); + size_t index = 0; + for (auto &&value : src) { + auto value_ = reinterpret_steal(value_conv::cast(forward_like(value), policy, parent)); + if (!value_) + return handle(); + PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference + } + return l.release(); + } + + PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name + _("]")); +}; + +template struct type_caster> + : list_caster, Type> { }; + +template struct type_caster> + : list_caster, Type> { }; + +template struct type_caster> + : list_caster, Type> { }; + +template struct array_caster { + using value_conv = make_caster; + +private: + template + bool require_size(enable_if_t size) { + if (value.size() != size) + value.resize(size); + return true; + } + template + bool require_size(enable_if_t size) { + return size == Size; + } + +public: + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto l = reinterpret_borrow(src); + if (!require_size(l.size())) + return false; + size_t ctr = 0; + for (auto it : l) { + value_conv conv; + if (!conv.load(it, convert)) + return false; + value[ctr++] = cast_op(std::move(conv)); + } + return true; + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + list l(src.size()); + size_t index = 0; + for (auto &&value : src) { + auto value_ = reinterpret_steal(value_conv::cast(forward_like(value), policy, parent)); + if (!value_) + return handle(); + PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference + } + return l.release(); + } + + PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name + _(_(""), _("[") + _() + _("]")) + _("]")); +}; + +template struct type_caster> + : array_caster, Type, false, Size> { }; + +template struct type_caster> + : array_caster, Type, true> { }; + +template struct type_caster> + : set_caster, Key> { }; + +template struct type_caster> + : set_caster, Key> { }; + +template struct type_caster> + : map_caster, Key, Value> { }; + +template struct type_caster> + : map_caster, Key, Value> { }; + +// This type caster is intended to be used for std::optional and std::experimental::optional +template struct optional_caster { + using value_conv = make_caster; + + template + static handle cast(T_ &&src, return_value_policy policy, handle parent) { + if (!src) + return none().inc_ref(); + policy = return_value_policy_override::policy(policy); + return value_conv::cast(*std::forward(src), policy, parent); + } + + bool load(handle src, bool convert) { + if (!src) { + return false; + } else if (src.is_none()) { + return true; // default-constructed value is already empty + } + value_conv inner_caster; + if (!inner_caster.load(src, convert)) + return false; + + value.emplace(cast_op(std::move(inner_caster))); + return true; + } + + PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]")); +}; + +#if PYBIND11_HAS_OPTIONAL +template struct type_caster> + : public optional_caster> {}; + +template<> struct type_caster + : public void_caster {}; +#endif + +#if PYBIND11_HAS_EXP_OPTIONAL +template struct type_caster> + : public optional_caster> {}; + +template<> struct type_caster + : public void_caster {}; +#endif + +/// Visit a variant and cast any found type to Python +struct variant_caster_visitor { + return_value_policy policy; + handle parent; + + using result_type = handle; // required by boost::variant in C++11 + + template + result_type operator()(T &&src) const { + return make_caster::cast(std::forward(src), policy, parent); + } +}; + +/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar +/// `namespace::variant` types which provide a `namespace::visit()` function are handled here +/// automatically using argument-dependent lookup. Users can provide specializations for other +/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`. +template class Variant> +struct visit_helper { + template + static auto call(Args &&...args) -> decltype(visit(std::forward(args)...)) { + return visit(std::forward(args)...); + } +}; + +/// Generic variant caster +template struct variant_caster; + +template class V, typename... Ts> +struct variant_caster> { + static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative."); + + template + bool load_alternative(handle src, bool convert, type_list) { + auto caster = make_caster(); + if (caster.load(src, convert)) { + value = cast_op(caster); + return true; + } + return load_alternative(src, convert, type_list{}); + } + + bool load_alternative(handle, bool, type_list<>) { return false; } + + bool load(handle src, bool convert) { + // Do a first pass without conversions to improve constructor resolution. + // E.g. `py::int_(1).cast>()` needs to fill the `int` + // slot of the variant. Without two-pass loading `double` would be filled + // because it appears first and a conversion is possible. + if (convert && load_alternative(src, false, type_list{})) + return true; + return load_alternative(src, convert, type_list{}); + } + + template + static handle cast(Variant &&src, return_value_policy policy, handle parent) { + return visit_helper::call(variant_caster_visitor{policy, parent}, + std::forward(src)); + } + + using Type = V; + PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster::name...) + _("]")); +}; + +#if PYBIND11_HAS_VARIANT +template +struct type_caster> : variant_caster> { }; +#endif + +NAMESPACE_END(detail) + +inline std::ostream &operator<<(std::ostream &os, const handle &obj) { + os << (std::string) str(obj); + return os; +} + +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/stl_bind.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/stl_bind.h new file mode 100644 index 0000000000000000000000000000000000000000..da233eca99ab10a223a0e526a55175bbe966ab6a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/include/pybind11/stl_bind.h @@ -0,0 +1,656 @@ +/* + pybind11/std_bind.h: Binding generators for STL data types + + Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/common.h" +#include "operators.h" + +#include +#include + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/* SFINAE helper class used by 'is_comparable */ +template struct container_traits { + template static std::true_type test_comparable(decltype(std::declval() == std::declval())*); + template static std::false_type test_comparable(...); + template static std::true_type test_value(typename T2::value_type *); + template static std::false_type test_value(...); + template static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *); + template static std::false_type test_pair(...); + + static constexpr const bool is_comparable = std::is_same(nullptr))>::value; + static constexpr const bool is_pair = std::is_same(nullptr, nullptr))>::value; + static constexpr const bool is_vector = std::is_same(nullptr))>::value; + static constexpr const bool is_element = !is_pair && !is_vector; +}; + +/* Default: is_comparable -> std::false_type */ +template +struct is_comparable : std::false_type { }; + +/* For non-map data structures, check whether operator== can be instantiated */ +template +struct is_comparable< + T, enable_if_t::is_element && + container_traits::is_comparable>> + : std::true_type { }; + +/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */ +template +struct is_comparable::is_vector>> { + static constexpr const bool value = + is_comparable::value; +}; + +/* For pairs, recursively check the two data types */ +template +struct is_comparable::is_pair>> { + static constexpr const bool value = + is_comparable::value && + is_comparable::value; +}; + +/* Fallback functions */ +template void vector_if_copy_constructible(const Args &...) { } +template void vector_if_equal_operator(const Args &...) { } +template void vector_if_insertion_operator(const Args &...) { } +template void vector_modifiers(const Args &...) { } + +template +void vector_if_copy_constructible(enable_if_t::value, Class_> &cl) { + cl.def(init(), "Copy constructor"); +} + +template +void vector_if_equal_operator(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + + cl.def(self == self); + cl.def(self != self); + + cl.def("count", + [](const Vector &v, const T &x) { + return std::count(v.begin(), v.end(), x); + }, + arg("x"), + "Return the number of times ``x`` appears in the list" + ); + + cl.def("remove", [](Vector &v, const T &x) { + auto p = std::find(v.begin(), v.end(), x); + if (p != v.end()) + v.erase(p); + else + throw value_error(); + }, + arg("x"), + "Remove the first item from the list whose value is x. " + "It is an error if there is no such item." + ); + + cl.def("__contains__", + [](const Vector &v, const T &x) { + return std::find(v.begin(), v.end(), x) != v.end(); + }, + arg("x"), + "Return true the container contains ``x``" + ); +} + +// Vector modifiers -- requires a copyable vector_type: +// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems +// silly to allow deletion but not insertion, so include them here too.) +template +void vector_modifiers(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + using SizeType = typename Vector::size_type; + using DiffType = typename Vector::difference_type; + + auto wrap_i = [](DiffType i, SizeType n) { + if (i < 0) + i += n; + if (i < 0 || (SizeType)i >= n) + throw index_error(); + return i; + }; + + cl.def("append", + [](Vector &v, const T &value) { v.push_back(value); }, + arg("x"), + "Add an item to the end of the list"); + + cl.def(init([](iterable it) { + auto v = std::unique_ptr(new Vector()); + v->reserve(len_hint(it)); + for (handle h : it) + v->push_back(h.cast()); + return v.release(); + })); + + cl.def("clear", + [](Vector &v) { + v.clear(); + }, + "Clear the contents" + ); + + cl.def("extend", + [](Vector &v, const Vector &src) { + v.insert(v.end(), src.begin(), src.end()); + }, + arg("L"), + "Extend the list by appending all the items in the given list" + ); + + cl.def("extend", + [](Vector &v, iterable it) { + const size_t old_size = v.size(); + v.reserve(old_size + len_hint(it)); + try { + for (handle h : it) { + v.push_back(h.cast()); + } + } catch (const cast_error &) { + v.erase(v.begin() + static_cast(old_size), v.end()); + try { + v.shrink_to_fit(); + } catch (const std::exception &) { + // Do nothing + } + throw; + } + }, + arg("L"), + "Extend the list by appending all the items in the given list" + ); + + cl.def("insert", + [](Vector &v, DiffType i, const T &x) { + // Can't use wrap_i; i == v.size() is OK + if (i < 0) + i += v.size(); + if (i < 0 || (SizeType)i > v.size()) + throw index_error(); + v.insert(v.begin() + i, x); + }, + arg("i") , arg("x"), + "Insert an item at a given position." + ); + + cl.def("pop", + [](Vector &v) { + if (v.empty()) + throw index_error(); + T t = v.back(); + v.pop_back(); + return t; + }, + "Remove and return the last item" + ); + + cl.def("pop", + [wrap_i](Vector &v, DiffType i) { + i = wrap_i(i, v.size()); + T t = v[(SizeType) i]; + v.erase(v.begin() + i); + return t; + }, + arg("i"), + "Remove and return the item at index ``i``" + ); + + cl.def("__setitem__", + [wrap_i](Vector &v, DiffType i, const T &t) { + i = wrap_i(i, v.size()); + v[(SizeType)i] = t; + } + ); + + /// Slicing protocol + cl.def("__getitem__", + [](const Vector &v, slice slice) -> Vector * { + size_t start, stop, step, slicelength; + + if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw error_already_set(); + + Vector *seq = new Vector(); + seq->reserve((size_t) slicelength); + + for (size_t i=0; ipush_back(v[start]); + start += step; + } + return seq; + }, + arg("s"), + "Retrieve list elements using a slice object" + ); + + cl.def("__setitem__", + [](Vector &v, slice slice, const Vector &value) { + size_t start, stop, step, slicelength; + if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw error_already_set(); + + if (slicelength != value.size()) + throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); + + for (size_t i=0; i), +// we have to access by copying; otherwise we return by reference. +template using vector_needs_copy = negation< + std::is_same()[typename Vector::size_type()]), typename Vector::value_type &>>; + +// The usual case: access and iterate by reference +template +void vector_accessor(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + using SizeType = typename Vector::size_type; + using DiffType = typename Vector::difference_type; + using ItType = typename Vector::iterator; + + auto wrap_i = [](DiffType i, SizeType n) { + if (i < 0) + i += n; + if (i < 0 || (SizeType)i >= n) + throw index_error(); + return i; + }; + + cl.def("__getitem__", + [wrap_i](Vector &v, DiffType i) -> T & { + i = wrap_i(i, v.size()); + return v[(SizeType)i]; + }, + return_value_policy::reference_internal // ref + keepalive + ); + + cl.def("__iter__", + [](Vector &v) { + return make_iterator< + return_value_policy::reference_internal, ItType, ItType, T&>( + v.begin(), v.end()); + }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); +} + +// The case for special objects, like std::vector, that have to be returned-by-copy: +template +void vector_accessor(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + using SizeType = typename Vector::size_type; + using DiffType = typename Vector::difference_type; + using ItType = typename Vector::iterator; + cl.def("__getitem__", + [](const Vector &v, DiffType i) -> T { + if (i < 0 && (i += v.size()) < 0) + throw index_error(); + if ((SizeType)i >= v.size()) + throw index_error(); + return v[(SizeType)i]; + } + ); + + cl.def("__iter__", + [](Vector &v) { + return make_iterator< + return_value_policy::copy, ItType, ItType, T>( + v.begin(), v.end()); + }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); +} + +template auto vector_if_insertion_operator(Class_ &cl, std::string const &name) + -> decltype(std::declval() << std::declval(), void()) { + using size_type = typename Vector::size_type; + + cl.def("__repr__", + [name](Vector &v) { + std::ostringstream s; + s << name << '['; + for (size_type i=0; i < v.size(); ++i) { + s << v[i]; + if (i != v.size() - 1) + s << ", "; + } + s << ']'; + return s.str(); + }, + "Return the canonical string representation of this list." + ); +} + +// Provide the buffer interface for vectors if we have data() and we have a format for it +// GCC seems to have "void std::vector::data()" - doing SFINAE on the existence of data() is insufficient, we need to check it returns an appropriate pointer +template +struct vector_has_data_and_format : std::false_type {}; +template +struct vector_has_data_and_format::format(), std::declval().data()), typename Vector::value_type*>::value>> : std::true_type {}; + +// Add the buffer interface to a vector +template +enable_if_t...>::value> +vector_buffer(Class_& cl) { + using T = typename Vector::value_type; + + static_assert(vector_has_data_and_format::value, "There is not an appropriate format descriptor for this vector"); + + // numpy.h declares this for arbitrary types, but it may raise an exception and crash hard at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here + format_descriptor::format(); + + cl.def_buffer([](Vector& v) -> buffer_info { + return buffer_info(v.data(), static_cast(sizeof(T)), format_descriptor::format(), 1, {v.size()}, {sizeof(T)}); + }); + + cl.def(init([](buffer buf) { + auto info = buf.request(); + if (info.ndim != 1 || info.strides[0] % static_cast(sizeof(T))) + throw type_error("Only valid 1D buffers can be copied to a vector"); + if (!detail::compare_buffer_info::compare(info) || (ssize_t) sizeof(T) != info.itemsize) + throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor::format() + ")"); + + auto vec = std::unique_ptr(new Vector()); + vec->reserve((size_t) info.shape[0]); + T *p = static_cast(info.ptr); + ssize_t step = info.strides[0] / static_cast(sizeof(T)); + T *end = p + info.shape[0] * step; + for (; p != end; p += step) + vec->push_back(*p); + return vec.release(); + })); + + return; +} + +template +enable_if_t...>::value> vector_buffer(Class_&) {} + +NAMESPACE_END(detail) + +// +// std::vector +// +template , typename... Args> +class_ bind_vector(handle scope, std::string const &name, Args&&... args) { + using Class_ = class_; + + // If the value_type is unregistered (e.g. a converting type) or is itself registered + // module-local then make the vector binding module-local as well: + using vtype = typename Vector::value_type; + auto vtype_info = detail::get_type_info(typeid(vtype)); + bool local = !vtype_info || vtype_info->module_local; + + Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward(args)...); + + // Declare the buffer interface if a buffer_protocol() is passed in + detail::vector_buffer(cl); + + cl.def(init<>()); + + // Register copy constructor (if possible) + detail::vector_if_copy_constructible(cl); + + // Register comparison-related operators and functions (if possible) + detail::vector_if_equal_operator(cl); + + // Register stream insertion operator (if possible) + detail::vector_if_insertion_operator(cl, name); + + // Modifiers require copyable vector value type + detail::vector_modifiers(cl); + + // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive + detail::vector_accessor(cl); + + cl.def("__bool__", + [](const Vector &v) -> bool { + return !v.empty(); + }, + "Check whether the list is nonempty" + ); + + cl.def("__len__", &Vector::size); + + + + +#if 0 + // C++ style functions deprecated, leaving it here as an example + cl.def(init()); + + cl.def("resize", + (void (Vector::*) (size_type count)) & Vector::resize, + "changes the number of elements stored"); + + cl.def("erase", + [](Vector &v, SizeType i) { + if (i >= v.size()) + throw index_error(); + v.erase(v.begin() + i); + }, "erases element at index ``i``"); + + cl.def("empty", &Vector::empty, "checks whether the container is empty"); + cl.def("size", &Vector::size, "returns the number of elements"); + cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); + cl.def("pop_back", &Vector::pop_back, "removes the last element"); + + cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements"); + cl.def("reserve", &Vector::reserve, "reserves storage"); + cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage"); + cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory"); + + cl.def("clear", &Vector::clear, "clears the contents"); + cl.def("swap", &Vector::swap, "swaps the contents"); + + cl.def("front", [](Vector &v) { + if (v.size()) return v.front(); + else throw index_error(); + }, "access the first element"); + + cl.def("back", [](Vector &v) { + if (v.size()) return v.back(); + else throw index_error(); + }, "access the last element "); + +#endif + + return cl; +} + + + +// +// std::map, std::unordered_map +// + +NAMESPACE_BEGIN(detail) + +/* Fallback functions */ +template void map_if_insertion_operator(const Args &...) { } +template void map_assignment(const Args &...) { } + +// Map assignment when copy-assignable: just copy the value +template +void map_assignment(enable_if_t::value, Class_> &cl) { + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + + cl.def("__setitem__", + [](Map &m, const KeyType &k, const MappedType &v) { + auto it = m.find(k); + if (it != m.end()) it->second = v; + else m.emplace(k, v); + } + ); +} + +// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting +template +void map_assignment(enable_if_t< + !is_copy_assignable::value && + is_copy_constructible::value, + Class_> &cl) { + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + + cl.def("__setitem__", + [](Map &m, const KeyType &k, const MappedType &v) { + // We can't use m[k] = v; because value type might not be default constructable + auto r = m.emplace(k, v); + if (!r.second) { + // value type is not copy assignable so the only way to insert it is to erase it first... + m.erase(r.first); + m.emplace(k, v); + } + } + ); +} + + +template auto map_if_insertion_operator(Class_ &cl, std::string const &name) +-> decltype(std::declval() << std::declval() << std::declval(), void()) { + + cl.def("__repr__", + [name](Map &m) { + std::ostringstream s; + s << name << '{'; + bool f = false; + for (auto const &kv : m) { + if (f) + s << ", "; + s << kv.first << ": " << kv.second; + f = true; + } + s << '}'; + return s.str(); + }, + "Return the canonical string representation of this map." + ); +} + + +NAMESPACE_END(detail) + +template , typename... Args> +class_ bind_map(handle scope, const std::string &name, Args&&... args) { + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + using Class_ = class_; + + // If either type is a non-module-local bound type then make the map binding non-local as well; + // otherwise (e.g. both types are either module-local or converting) the map will be + // module-local. + auto tinfo = detail::get_type_info(typeid(MappedType)); + bool local = !tinfo || tinfo->module_local; + if (local) { + tinfo = detail::get_type_info(typeid(KeyType)); + local = !tinfo || tinfo->module_local; + } + + Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward(args)...); + + cl.def(init<>()); + + // Register stream insertion operator (if possible) + detail::map_if_insertion_operator(cl, name); + + cl.def("__bool__", + [](const Map &m) -> bool { return !m.empty(); }, + "Check whether the map is nonempty" + ); + + cl.def("__iter__", + [](Map &m) { return make_key_iterator(m.begin(), m.end()); }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); + + cl.def("items", + [](Map &m) { return make_iterator(m.begin(), m.end()); }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); + + cl.def("__getitem__", + [](Map &m, const KeyType &k) -> MappedType & { + auto it = m.find(k); + if (it == m.end()) + throw key_error(); + return it->second; + }, + return_value_policy::reference_internal // ref + keepalive + ); + + cl.def("__contains__", + [](Map &m, const KeyType &k) -> bool { + auto it = m.find(k); + if (it == m.end()) + return false; + return true; + } + ); + + // Assignment provided only if the type is copyable + detail::map_assignment(cl); + + cl.def("__delitem__", + [](Map &m, const KeyType &k) { + auto it = m.find(k); + if (it == m.end()) + throw key_error(); + m.erase(it); + } + ); + + cl.def("__len__", &Map::size); + + return cl; +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/pybind11/__init__.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/pybind11/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4b1de3efaaf9e352b1c6701238b5ad6caf0eac3a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/pybind11/__init__.py @@ -0,0 +1,12 @@ +from ._version import version_info, __version__ # noqa: F401 imported but unused + + +def get_include(user=False): + import os + d = os.path.dirname(__file__) + if os.path.exists(os.path.join(d, "include")): + # Package is installed + return os.path.join(d, "include") + else: + # Package is from a source directory + return os.path.join(os.path.dirname(d), "include") diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/pybind11/__main__.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/pybind11/__main__.py new file mode 100644 index 0000000000000000000000000000000000000000..89b263a8ad2461e5e039c3d00d1505393a1a0ab3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/pybind11/__main__.py @@ -0,0 +1,36 @@ +from __future__ import print_function + +import argparse +import sys +import sysconfig + +from . import get_include + + +def print_includes(): + dirs = [sysconfig.get_path('include'), + sysconfig.get_path('platinclude'), + get_include()] + + # Make unique but preserve order + unique_dirs = [] + for d in dirs: + if d not in unique_dirs: + unique_dirs.append(d) + + print(' '.join('-I' + d for d in unique_dirs)) + + +def main(): + parser = argparse.ArgumentParser(prog='python -m pybind11') + parser.add_argument('--includes', action='store_true', + help='Include flags for both pybind11 and Python headers.') + args = parser.parse_args() + if not sys.argv[1:]: + parser.print_help() + if args.includes: + print_includes() + + +if __name__ == '__main__': + main() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/pybind11/_version.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/pybind11/_version.py new file mode 100644 index 0000000000000000000000000000000000000000..8d5aa5c7675609643f294bd56fc77598e93b9bcf --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/pybind11/_version.py @@ -0,0 +1,2 @@ +version_info = (2, 5, 0) +__version__ = '.'.join(map(str, version_info)) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/setup.cfg b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/setup.cfg new file mode 100644 index 0000000000000000000000000000000000000000..002f38d10e46472657ff8228139e0f92b0d5bc10 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/setup.cfg @@ -0,0 +1,12 @@ +[bdist_wheel] +universal=1 + +[flake8] +max-line-length = 99 +show_source = True +exclude = .git, __pycache__, build, dist, docs, tools, venv +ignore = + # required for pretty matrix formatting: multiple spaces after `,` and `[` + E201, E241, W504, + # camelcase 'cPickle' imported as lowercase 'pickle' + N813 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/setup.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..473ea1ee082f59f16c5568a9ef66ef4ae1c19706 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/setup.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python + +# Setup script for PyPI; use CMakeFile.txt to build extension modules + +from setuptools import setup +from distutils.command.install_headers import install_headers +from distutils.command.build_py import build_py +from pybind11 import __version__ +import os + +package_data = [ + 'include/pybind11/detail/class.h', + 'include/pybind11/detail/common.h', + 'include/pybind11/detail/descr.h', + 'include/pybind11/detail/init.h', + 'include/pybind11/detail/internals.h', + 'include/pybind11/detail/typeid.h', + 'include/pybind11/attr.h', + 'include/pybind11/buffer_info.h', + 'include/pybind11/cast.h', + 'include/pybind11/chrono.h', + 'include/pybind11/common.h', + 'include/pybind11/complex.h', + 'include/pybind11/eigen.h', + 'include/pybind11/embed.h', + 'include/pybind11/eval.h', + 'include/pybind11/functional.h', + 'include/pybind11/iostream.h', + 'include/pybind11/numpy.h', + 'include/pybind11/operators.h', + 'include/pybind11/options.h', + 'include/pybind11/pybind11.h', + 'include/pybind11/pytypes.h', + 'include/pybind11/stl.h', + 'include/pybind11/stl_bind.h', +] + +# Prevent installation of pybind11 headers by setting +# PYBIND11_USE_CMAKE. +if os.environ.get('PYBIND11_USE_CMAKE'): + headers = [] +else: + headers = package_data + + +class InstallHeaders(install_headers): + """Use custom header installer because the default one flattens subdirectories""" + def run(self): + if not self.distribution.headers: + return + + for header in self.distribution.headers: + subdir = os.path.dirname(os.path.relpath(header, 'include/pybind11')) + install_dir = os.path.join(self.install_dir, subdir) + self.mkpath(install_dir) + + (out, _) = self.copy_file(header, install_dir) + self.outfiles.append(out) + + +# Install the headers inside the package as well +class BuildPy(build_py): + def build_package_data(self): + build_py.build_package_data(self) + for header in package_data: + target = os.path.join(self.build_lib, 'pybind11', header) + self.mkpath(os.path.dirname(target)) + self.copy_file(header, target, preserve_mode=False) + + +setup( + name='pybind11', + version=__version__, + description='Seamless operability between C++11 and Python', + author='Wenzel Jakob', + author_email='wenzel.jakob@epfl.ch', + url='https://github.com/pybind/pybind11', + download_url='https://github.com/pybind/pybind11/tarball/v' + __version__, + packages=['pybind11'], + license='BSD', + headers=headers, + zip_safe=False, + cmdclass=dict(install_headers=InstallHeaders, build_py=BuildPy), + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: Utilities', + 'Programming Language :: C++', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'License :: OSI Approved :: BSD License' + ], + keywords='C++11, Python bindings', + long_description="""pybind11 is a lightweight header-only library that +exposes C++ types in Python and vice versa, mainly to create Python bindings of +existing C++ code. Its goals and syntax are similar to the excellent +Boost.Python by David Abrahams: to minimize boilerplate code in traditional +extension modules by inferring type information using compile-time +introspection. + +The main issue with Boost.Python-and the reason for creating such a similar +project-is Boost. Boost is an enormously large and complex suite of utility +libraries that works with almost every C++ compiler in existence. This +compatibility has its cost: arcane template tricks and workarounds are +necessary to support the oldest and buggiest of compiler specimens. Now that +C++11-compatible compilers are widely available, this heavy machinery has +become an excessively large and unnecessary dependency. + +Think of this library as a tiny self-contained version of Boost.Python with +everything stripped away that isn't relevant for binding generation. Without +comments, the core header files only require ~4K lines of code and depend on +Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This +compact implementation was possible thanks to some of the new C++11 language +features (specifically: tuples, lambda functions and variadic templates). Since +its creation, this library has grown beyond Boost.Python in many ways, leading +to dramatically simpler binding code in many common situations.""") diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..765c47adb0af2908528136c36fbfe8fbba8b724f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/CMakeLists.txt @@ -0,0 +1,259 @@ +# CMakeLists.txt -- Build system for the pybind11 test suite +# +# Copyright (c) 2015 Wenzel Jakob +# +# All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +cmake_minimum_required(VERSION 2.8.12) + +option(PYBIND11_WERROR "Report all warnings as errors" OFF) + +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + # We're being loaded directly, i.e. not via add_subdirectory, so make this + # work as its own project and load the pybind11Config to get the tools we need + project(pybind11_tests CXX) + + find_package(pybind11 REQUIRED CONFIG) +endif() + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting tests build type to MinSizeRel as none was specified") + set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" + "MinSizeRel" "RelWithDebInfo") +endif() + +# Full set of test files (you can override these; see below) +set(PYBIND11_TEST_FILES + test_async.cpp + test_buffers.cpp + test_builtin_casters.cpp + test_call_policies.cpp + test_callbacks.cpp + test_chrono.cpp + test_class.cpp + test_constants_and_functions.cpp + test_copy_move.cpp + test_docstring_options.cpp + test_eigen.cpp + test_enum.cpp + test_eval.cpp + test_exceptions.cpp + test_factory_constructors.cpp + test_gil_scoped.cpp + test_iostream.cpp + test_kwargs_and_defaults.cpp + test_local_bindings.cpp + test_methods_and_attributes.cpp + test_modules.cpp + test_multiple_inheritance.cpp + test_numpy_array.cpp + test_numpy_dtypes.cpp + test_numpy_vectorize.cpp + test_opaque_types.cpp + test_operator_overloading.cpp + test_pickling.cpp + test_pytypes.cpp + test_sequences_and_iterators.cpp + test_smart_ptr.cpp + test_stl.cpp + test_stl_binders.cpp + test_tagbased_polymorphic.cpp + test_union.cpp + test_virtual_functions.cpp +) + +# Invoking cmake with something like: +# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_picking.cpp" .. +# lets you override the tests that get compiled and run. You can restore to all tests with: +# cmake -DPYBIND11_TEST_OVERRIDE= .. +if (PYBIND11_TEST_OVERRIDE) + set(PYBIND11_TEST_FILES ${PYBIND11_TEST_OVERRIDE}) +endif() + +# Skip test_async for Python < 3.5 +list(FIND PYBIND11_TEST_FILES test_async.cpp PYBIND11_TEST_FILES_ASYNC_I) +if((PYBIND11_TEST_FILES_ASYNC_I GREATER -1) AND ("${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" VERSION_LESS 3.5)) + message(STATUS "Skipping test_async because Python version ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} < 3.5") + list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_ASYNC_I}) +endif() + +string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}") + +# Contains the set of test files that require pybind11_cross_module_tests to be +# built; if none of these are built (i.e. because TEST_OVERRIDE is used and +# doesn't include them) the second module doesn't get built. +set(PYBIND11_CROSS_MODULE_TESTS + test_exceptions.py + test_local_bindings.py + test_stl.py + test_stl_binders.py +) + +set(PYBIND11_CROSS_MODULE_GIL_TESTS + test_gil_scoped.py +) + +# Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but +# keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed" +# skip message). +list(FIND PYBIND11_TEST_FILES test_eigen.cpp PYBIND11_TEST_FILES_EIGEN_I) +if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1) + # Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake). + # Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also + # produces a fatal error if loaded from a pre-3.0 cmake. + if (NOT CMAKE_VERSION VERSION_LESS 3.0) + find_package(Eigen3 3.2.7 QUIET CONFIG) + if (EIGEN3_FOUND) + if (EIGEN3_VERSION_STRING AND NOT EIGEN3_VERSION_STRING VERSION_LESS 3.3.1) + set(PYBIND11_EIGEN_VIA_TARGET 1) + endif() + endif() + endif() + if (NOT EIGEN3_FOUND) + # Couldn't load via target, so fall back to allowing module mode finding, which will pick up + # tools/FindEigen3.cmake + find_package(Eigen3 3.2.7 QUIET) + endif() + + if(EIGEN3_FOUND) + # Eigen 3.3.1+ cmake sets EIGEN3_VERSION_STRING (and hard codes the version when installed + # rather than looking it up in the cmake script); older versions, and the + # tools/FindEigen3.cmake, set EIGEN3_VERSION instead. + if(NOT EIGEN3_VERSION AND EIGEN3_VERSION_STRING) + set(EIGEN3_VERSION ${EIGEN3_VERSION_STRING}) + endif() + message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}") + else() + list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I}) + message(STATUS "Building tests WITHOUT Eigen") + endif() +endif() + +# Optional dependency for some tests (boost::variant is only supported with version >= 1.56) +find_package(Boost 1.56) + +# Compile with compiler warnings turned on +function(pybind11_enable_warnings target_name) + if(MSVC) + target_compile_options(${target_name} PRIVATE /W4) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)") + target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual -Wdeprecated) + endif() + + if(PYBIND11_WERROR) + if(MSVC) + target_compile_options(${target_name} PRIVATE /WX) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)") + target_compile_options(${target_name} PRIVATE -Werror) + endif() + endif() +endfunction() + +set(test_targets pybind11_tests) + +# Build pybind11_cross_module_tests if any test_whatever.py are being built that require it +foreach(t ${PYBIND11_CROSS_MODULE_TESTS}) + list(FIND PYBIND11_PYTEST_FILES ${t} i) + if (i GREATER -1) + list(APPEND test_targets pybind11_cross_module_tests) + break() + endif() +endforeach() + +foreach(t ${PYBIND11_CROSS_MODULE_GIL_TESTS}) + list(FIND PYBIND11_PYTEST_FILES ${t} i) + if (i GREATER -1) + list(APPEND test_targets cross_module_gil_utils) + break() + endif() +endforeach() + +set(testdir ${CMAKE_CURRENT_SOURCE_DIR}) +foreach(target ${test_targets}) + set(test_files ${PYBIND11_TEST_FILES}) + if(NOT target STREQUAL "pybind11_tests") + set(test_files "") + endif() + + # Create the binding library + pybind11_add_module(${target} THIN_LTO ${target}.cpp ${test_files} ${PYBIND11_HEADERS}) + pybind11_enable_warnings(${target}) + + if(MSVC) + target_compile_options(${target} PRIVATE /utf-8) + endif() + + if(EIGEN3_FOUND) + if (PYBIND11_EIGEN_VIA_TARGET) + target_link_libraries(${target} PRIVATE Eigen3::Eigen) + else() + target_include_directories(${target} PRIVATE ${EIGEN3_INCLUDE_DIR}) + endif() + target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_EIGEN) + endif() + + if(Boost_FOUND) + target_include_directories(${target} PRIVATE ${Boost_INCLUDE_DIRS}) + target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST) + endif() + + # Always write the output file directly into the 'tests' directory (even on MSVC) + if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir}) + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${config} config) + set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} ${testdir}) + endforeach() + endif() +endforeach() + +# Make sure pytest is found or produce a fatal error +if(NOT PYBIND11_PYTEST_FOUND) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import pytest; print(pytest.__version__)" + RESULT_VARIABLE pytest_not_found OUTPUT_VARIABLE pytest_version ERROR_QUIET) + if(pytest_not_found) + message(FATAL_ERROR "Running the tests requires pytest. Please install it manually" + " (try: ${PYTHON_EXECUTABLE} -m pip install pytest)") + elseif(pytest_version VERSION_LESS 3.0) + message(FATAL_ERROR "Running the tests requires pytest >= 3.0. Found: ${pytest_version}" + "Please update it (try: ${PYTHON_EXECUTABLE} -m pip install -U pytest)") + endif() + set(PYBIND11_PYTEST_FOUND TRUE CACHE INTERNAL "") +endif() + +if(CMAKE_VERSION VERSION_LESS 3.2) + set(PYBIND11_USES_TERMINAL "") +else() + set(PYBIND11_USES_TERMINAL "USES_TERMINAL") +endif() + +# A single command to compile and run the tests +add_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_PYTEST_FILES} + DEPENDS ${test_targets} WORKING_DIRECTORY ${testdir} ${PYBIND11_USES_TERMINAL}) + +if(PYBIND11_TEST_OVERRIDE) + add_custom_command(TARGET pytest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect") +endif() + +# Add a check target to run all the tests, starting with pytest (we add dependencies to this below) +add_custom_target(check DEPENDS pytest) + +# The remaining tests only apply when being built as part of the pybind11 project, but not if the +# tests are being built independently. +if (NOT PROJECT_NAME STREQUAL "pybind11") + return() +endif() + +# Add a post-build comment to show the primary test suite .so size and, if a previous size, compare it: +add_custom_command(TARGET pybind11_tests POST_BUILD + COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/libsize.py + $ ${CMAKE_CURRENT_BINARY_DIR}/sosize-$.txt) + +# Test embedding the interpreter. Provides the `cpptest` target. +add_subdirectory(test_embed) + +# Test CMake build using functions and targets from subdirectory or installed location +add_subdirectory(test_cmake_build) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/conftest.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..57f681c66fd396877acc877a643a3bdd2097af24 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/conftest.py @@ -0,0 +1,244 @@ +"""pytest configuration + +Extends output capture as needed by pybind11: ignore constructors, optional unordered lines. +Adds docstring and exceptions message sanitizers: ignore Python 2 vs 3 differences. +""" + +import pytest +import textwrap +import difflib +import re +import sys +import contextlib +import platform +import gc + +_unicode_marker = re.compile(r'u(\'[^\']*\')') +_long_marker = re.compile(r'([0-9])L') +_hexadecimal = re.compile(r'0x[0-9a-fA-F]+') + +# test_async.py requires support for async and await +collect_ignore = [] +if sys.version_info[:2] < (3, 5): + collect_ignore.append("test_async.py") + + +def _strip_and_dedent(s): + """For triple-quote strings""" + return textwrap.dedent(s.lstrip('\n').rstrip()) + + +def _split_and_sort(s): + """For output which does not require specific line order""" + return sorted(_strip_and_dedent(s).splitlines()) + + +def _make_explanation(a, b): + """Explanation for a failed assert -- the a and b arguments are List[str]""" + return ["--- actual / +++ expected"] + [line.strip('\n') for line in difflib.ndiff(a, b)] + + +class Output(object): + """Basic output post-processing and comparison""" + def __init__(self, string): + self.string = string + self.explanation = [] + + def __str__(self): + return self.string + + def __eq__(self, other): + # Ignore constructor/destructor output which is prefixed with "###" + a = [line for line in self.string.strip().splitlines() if not line.startswith("###")] + b = _strip_and_dedent(other).splitlines() + if a == b: + return True + else: + self.explanation = _make_explanation(a, b) + return False + + +class Unordered(Output): + """Custom comparison for output without strict line ordering""" + def __eq__(self, other): + a = _split_and_sort(self.string) + b = _split_and_sort(other) + if a == b: + return True + else: + self.explanation = _make_explanation(a, b) + return False + + +class Capture(object): + def __init__(self, capfd): + self.capfd = capfd + self.out = "" + self.err = "" + + def __enter__(self): + self.capfd.readouterr() + return self + + def __exit__(self, *args): + self.out, self.err = self.capfd.readouterr() + + def __eq__(self, other): + a = Output(self.out) + b = other + if a == b: + return True + else: + self.explanation = a.explanation + return False + + def __str__(self): + return self.out + + def __contains__(self, item): + return item in self.out + + @property + def unordered(self): + return Unordered(self.out) + + @property + def stderr(self): + return Output(self.err) + + +@pytest.fixture +def capture(capsys): + """Extended `capsys` with context manager and custom equality operators""" + return Capture(capsys) + + +class SanitizedString(object): + def __init__(self, sanitizer): + self.sanitizer = sanitizer + self.string = "" + self.explanation = [] + + def __call__(self, thing): + self.string = self.sanitizer(thing) + return self + + def __eq__(self, other): + a = self.string + b = _strip_and_dedent(other) + if a == b: + return True + else: + self.explanation = _make_explanation(a.splitlines(), b.splitlines()) + return False + + +def _sanitize_general(s): + s = s.strip() + s = s.replace("pybind11_tests.", "m.") + s = s.replace("unicode", "str") + s = _long_marker.sub(r"\1", s) + s = _unicode_marker.sub(r"\1", s) + return s + + +def _sanitize_docstring(thing): + s = thing.__doc__ + s = _sanitize_general(s) + return s + + +@pytest.fixture +def doc(): + """Sanitize docstrings and add custom failure explanation""" + return SanitizedString(_sanitize_docstring) + + +def _sanitize_message(thing): + s = str(thing) + s = _sanitize_general(s) + s = _hexadecimal.sub("0", s) + return s + + +@pytest.fixture +def msg(): + """Sanitize messages and add custom failure explanation""" + return SanitizedString(_sanitize_message) + + +# noinspection PyUnusedLocal +def pytest_assertrepr_compare(op, left, right): + """Hook to insert custom failure explanation""" + if hasattr(left, 'explanation'): + return left.explanation + + +@contextlib.contextmanager +def suppress(exception): + """Suppress the desired exception""" + try: + yield + except exception: + pass + + +def gc_collect(): + ''' Run the garbage collector twice (needed when running + reference counting tests with PyPy) ''' + gc.collect() + gc.collect() + + +def pytest_configure(): + """Add import suppression and test requirements to `pytest` namespace""" + try: + import numpy as np + except ImportError: + np = None + try: + import scipy + except ImportError: + scipy = None + try: + from pybind11_tests.eigen import have_eigen + except ImportError: + have_eigen = False + pypy = platform.python_implementation() == "PyPy" + + skipif = pytest.mark.skipif + pytest.suppress = suppress + pytest.requires_numpy = skipif(not np, reason="numpy is not installed") + pytest.requires_scipy = skipif(not np, reason="scipy is not installed") + pytest.requires_eigen_and_numpy = skipif(not have_eigen or not np, + reason="eigen and/or numpy are not installed") + pytest.requires_eigen_and_scipy = skipif( + not have_eigen or not scipy, reason="eigen and/or scipy are not installed") + pytest.unsupported_on_pypy = skipif(pypy, reason="unsupported on PyPy") + pytest.unsupported_on_py2 = skipif(sys.version_info.major < 3, + reason="unsupported on Python 2.x") + pytest.gc_collect = gc_collect + + +def _test_import_pybind11(): + """Early diagnostic for test module initialization errors + + When there is an error during initialization, the first import will report the + real error while all subsequent imports will report nonsense. This import test + is done early (in the pytest configuration file, before any tests) in order to + avoid the noise of having all tests fail with identical error messages. + + Any possible exception is caught here and reported manually *without* the stack + trace. This further reduces noise since the trace would only show pytest internals + which are not useful for debugging pybind11 module issues. + """ + # noinspection PyBroadException + try: + import pybind11_tests # noqa: F401 imported but unused + except Exception as e: + print("Failed to import pybind11_tests from pytest:") + print(" {}: {}".format(type(e).__name__, e)) + sys.exit(1) + + +_test_import_pybind11() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/constructor_stats.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/constructor_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..431e5acef9cfcb0d52e28fc86f98b3c0b0db9281 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/constructor_stats.h @@ -0,0 +1,276 @@ +#pragma once +/* + tests/constructor_stats.h -- framework for printing and tracking object + instance lifetimes in example/test code. + + Copyright (c) 2016 Jason Rhinelander + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. + +This header provides a few useful tools for writing examples or tests that want to check and/or +display object instance lifetimes. It requires that you include this header and add the following +function calls to constructors: + + class MyClass { + MyClass() { ...; print_default_created(this); } + ~MyClass() { ...; print_destroyed(this); } + MyClass(const MyClass &c) { ...; print_copy_created(this); } + MyClass(MyClass &&c) { ...; print_move_created(this); } + MyClass(int a, int b) { ...; print_created(this, a, b); } + MyClass &operator=(const MyClass &c) { ...; print_copy_assigned(this); } + MyClass &operator=(MyClass &&c) { ...; print_move_assigned(this); } + + ... + } + +You can find various examples of these in several of the existing testing .cpp files. (Of course +you don't need to add any of the above constructors/operators that you don't actually have, except +for the destructor). + +Each of these will print an appropriate message such as: + + ### MyClass @ 0x2801910 created via default constructor + ### MyClass @ 0x27fa780 created 100 200 + ### MyClass @ 0x2801910 destroyed + ### MyClass @ 0x27fa780 destroyed + +You can also include extra arguments (such as the 100, 200 in the output above, coming from the +value constructor) for all of the above methods which will be included in the output. + +For testing, each of these also keeps track the created instances and allows you to check how many +of the various constructors have been invoked from the Python side via code such as: + + from pybind11_tests import ConstructorStats + cstats = ConstructorStats.get(MyClass) + print(cstats.alive()) + print(cstats.default_constructions) + +Note that `.alive()` should usually be the first thing you call as it invokes Python's garbage +collector to actually destroy objects that aren't yet referenced. + +For everything except copy and move constructors and destructors, any extra values given to the +print_...() function is stored in a class-specific values list which you can retrieve and inspect +from the ConstructorStats instance `.values()` method. + +In some cases, when you need to track instances of a C++ class not registered with pybind11, you +need to add a function returning the ConstructorStats for the C++ class; this can be done with: + + m.def("get_special_cstats", &ConstructorStats::get, py::return_value_policy::reference) + +Finally, you can suppress the output messages, but keep the constructor tracking (for +inspection/testing in python) by using the functions with `print_` replaced with `track_` (e.g. +`track_copy_created(this)`). + +*/ + +#include "pybind11_tests.h" +#include +#include +#include +#include + +class ConstructorStats { +protected: + std::unordered_map _instances; // Need a map rather than set because members can shared address with parents + std::list _values; // Used to track values (e.g. of value constructors) +public: + int default_constructions = 0; + int copy_constructions = 0; + int move_constructions = 0; + int copy_assignments = 0; + int move_assignments = 0; + + void copy_created(void *inst) { + created(inst); + copy_constructions++; + } + + void move_created(void *inst) { + created(inst); + move_constructions++; + } + + void default_created(void *inst) { + created(inst); + default_constructions++; + } + + void created(void *inst) { + ++_instances[inst]; + } + + void destroyed(void *inst) { + if (--_instances[inst] < 0) + throw std::runtime_error("cstats.destroyed() called with unknown " + "instance; potential double-destruction " + "or a missing cstats.created()"); + } + + static void gc() { + // Force garbage collection to ensure any pending destructors are invoked: +#if defined(PYPY_VERSION) + PyObject *globals = PyEval_GetGlobals(); + PyObject *result = PyRun_String( + "import gc\n" + "for i in range(2):" + " gc.collect()\n", + Py_file_input, globals, globals); + if (result == nullptr) + throw py::error_already_set(); + Py_DECREF(result); +#else + py::module::import("gc").attr("collect")(); +#endif + } + + int alive() { + gc(); + int total = 0; + for (const auto &p : _instances) + if (p.second > 0) + total += p.second; + return total; + } + + void value() {} // Recursion terminator + // Takes one or more values, converts them to strings, then stores them. + template void value(const T &v, Tmore &&...args) { + std::ostringstream oss; + oss << v; + _values.push_back(oss.str()); + value(std::forward(args)...); + } + + // Move out stored values + py::list values() { + py::list l; + for (const auto &v : _values) l.append(py::cast(v)); + _values.clear(); + return l; + } + + // Gets constructor stats from a C++ type index + static ConstructorStats& get(std::type_index type) { + static std::unordered_map all_cstats; + return all_cstats[type]; + } + + // Gets constructor stats from a C++ type + template static ConstructorStats& get() { +#if defined(PYPY_VERSION) + gc(); +#endif + return get(typeid(T)); + } + + // Gets constructor stats from a Python class + static ConstructorStats& get(py::object class_) { + auto &internals = py::detail::get_internals(); + const std::type_index *t1 = nullptr, *t2 = nullptr; + try { + auto *type_info = internals.registered_types_py.at((PyTypeObject *) class_.ptr()).at(0); + for (auto &p : internals.registered_types_cpp) { + if (p.second == type_info) { + if (t1) { + t2 = &p.first; + break; + } + t1 = &p.first; + } + } + } + catch (const std::out_of_range&) {} + if (!t1) throw std::runtime_error("Unknown class passed to ConstructorStats::get()"); + auto &cs1 = get(*t1); + // If we have both a t1 and t2 match, one is probably the trampoline class; return whichever + // has more constructions (typically one or the other will be 0) + if (t2) { + auto &cs2 = get(*t2); + int cs1_total = cs1.default_constructions + cs1.copy_constructions + cs1.move_constructions + (int) cs1._values.size(); + int cs2_total = cs2.default_constructions + cs2.copy_constructions + cs2.move_constructions + (int) cs2._values.size(); + if (cs2_total > cs1_total) return cs2; + } + return cs1; + } +}; + +// To track construction/destruction, you need to call these methods from the various +// constructors/operators. The ones that take extra values record the given values in the +// constructor stats values for later inspection. +template void track_copy_created(T *inst) { ConstructorStats::get().copy_created(inst); } +template void track_move_created(T *inst) { ConstructorStats::get().move_created(inst); } +template void track_copy_assigned(T *, Values &&...values) { + auto &cst = ConstructorStats::get(); + cst.copy_assignments++; + cst.value(std::forward(values)...); +} +template void track_move_assigned(T *, Values &&...values) { + auto &cst = ConstructorStats::get(); + cst.move_assignments++; + cst.value(std::forward(values)...); +} +template void track_default_created(T *inst, Values &&...values) { + auto &cst = ConstructorStats::get(); + cst.default_created(inst); + cst.value(std::forward(values)...); +} +template void track_created(T *inst, Values &&...values) { + auto &cst = ConstructorStats::get(); + cst.created(inst); + cst.value(std::forward(values)...); +} +template void track_destroyed(T *inst) { + ConstructorStats::get().destroyed(inst); +} +template void track_values(T *, Values &&...values) { + ConstructorStats::get().value(std::forward(values)...); +} + +/// Don't cast pointers to Python, print them as strings +inline const char *format_ptrs(const char *p) { return p; } +template +py::str format_ptrs(T *p) { return "{:#x}"_s.format(reinterpret_cast(p)); } +template +auto format_ptrs(T &&x) -> decltype(std::forward(x)) { return std::forward(x); } + +template +void print_constr_details(T *inst, const std::string &action, Output &&...output) { + py::print("###", py::type_id(), "@", format_ptrs(inst), action, + format_ptrs(std::forward(output))...); +} + +// Verbose versions of the above: +template void print_copy_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values + print_constr_details(inst, "created via copy constructor", values...); + track_copy_created(inst); +} +template void print_move_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values + print_constr_details(inst, "created via move constructor", values...); + track_move_created(inst); +} +template void print_copy_assigned(T *inst, Values &&...values) { + print_constr_details(inst, "assigned via copy assignment", values...); + track_copy_assigned(inst, values...); +} +template void print_move_assigned(T *inst, Values &&...values) { + print_constr_details(inst, "assigned via move assignment", values...); + track_move_assigned(inst, values...); +} +template void print_default_created(T *inst, Values &&...values) { + print_constr_details(inst, "created via default constructor", values...); + track_default_created(inst, values...); +} +template void print_created(T *inst, Values &&...values) { + print_constr_details(inst, "created", values...); + track_created(inst, values...); +} +template void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values + print_constr_details(inst, "destroyed", values...); + track_destroyed(inst); +} +template void print_values(T *inst, Values &&...values) { + print_constr_details(inst, ":", values...); + track_values(inst, values...); +} + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/cross_module_gil_utils.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/cross_module_gil_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07db9f6e48a10dfd2d4370c3daff6e793d6675d2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/cross_module_gil_utils.cpp @@ -0,0 +1,73 @@ +/* + tests/cross_module_gil_utils.cpp -- tools for acquiring GIL from a different module + + Copyright (c) 2019 Google LLC + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ +#include +#include + +// This file mimics a DSO that makes pybind11 calls but does not define a +// PYBIND11_MODULE. The purpose is to test that such a DSO can create a +// py::gil_scoped_acquire when the running thread is in a GIL-released state. +// +// Note that we define a Python module here for convenience, but in general +// this need not be the case. The typical scenario would be a DSO that implements +// shared logic used internally by multiple pybind11 modules. + +namespace { + +namespace py = pybind11; +void gil_acquire() { py::gil_scoped_acquire gil; } + +constexpr char kModuleName[] = "cross_module_gil_utils"; + +#if PY_MAJOR_VERSION >= 3 +struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + kModuleName, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + NULL +}; +#else +PyMethodDef module_methods[] = { + {NULL, NULL, 0, NULL} +}; +#endif + +} // namespace + +extern "C" PYBIND11_EXPORT +#if PY_MAJOR_VERSION >= 3 +PyObject* PyInit_cross_module_gil_utils() +#else +void initcross_module_gil_utils() +#endif +{ + + PyObject* m = +#if PY_MAJOR_VERSION >= 3 + PyModule_Create(&moduledef); +#else + Py_InitModule(kModuleName, module_methods); +#endif + + if (m != NULL) { + static_assert( + sizeof(&gil_acquire) == sizeof(void*), + "Function pointer must have the same size as void*"); + PyModule_AddObject(m, "gil_acquire_funcaddr", + PyLong_FromVoidPtr(reinterpret_cast(&gil_acquire))); + } + +#if PY_MAJOR_VERSION >= 3 + return m; +#endif +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/local_bindings.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/local_bindings.h new file mode 100644 index 0000000000000000000000000000000000000000..b6afb808664de1fdbde011a9bf7c38d3a8794127 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/local_bindings.h @@ -0,0 +1,64 @@ +#pragma once +#include "pybind11_tests.h" + +/// Simple class used to test py::local: +template class LocalBase { +public: + LocalBase(int i) : i(i) { } + int i = -1; +}; + +/// Registered with py::module_local in both main and secondary modules: +using LocalType = LocalBase<0>; +/// Registered without py::module_local in both modules: +using NonLocalType = LocalBase<1>; +/// A second non-local type (for stl_bind tests): +using NonLocal2 = LocalBase<2>; +/// Tests within-module, different-compilation-unit local definition conflict: +using LocalExternal = LocalBase<3>; +/// Mixed: registered local first, then global +using MixedLocalGlobal = LocalBase<4>; +/// Mixed: global first, then local +using MixedGlobalLocal = LocalBase<5>; + +/// Registered with py::module_local only in the secondary module: +using ExternalType1 = LocalBase<6>; +using ExternalType2 = LocalBase<7>; + +using LocalVec = std::vector; +using LocalVec2 = std::vector; +using LocalMap = std::unordered_map; +using NonLocalVec = std::vector; +using NonLocalVec2 = std::vector; +using NonLocalMap = std::unordered_map; +using NonLocalMap2 = std::unordered_map; + +PYBIND11_MAKE_OPAQUE(LocalVec); +PYBIND11_MAKE_OPAQUE(LocalVec2); +PYBIND11_MAKE_OPAQUE(LocalMap); +PYBIND11_MAKE_OPAQUE(NonLocalVec); +//PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2 +PYBIND11_MAKE_OPAQUE(NonLocalMap); +PYBIND11_MAKE_OPAQUE(NonLocalMap2); + + +// Simple bindings (used with the above): +template +py::class_ bind_local(Args && ...args) { + return py::class_(std::forward(args)...) + .def(py::init()) + .def("get", [](T &i) { return i.i + Adjust; }); +}; + +// Simulate a foreign library base class (to match the example in the docs): +namespace pets { +class Pet { +public: + Pet(std::string name) : name_(name) {} + std::string name_; + const std::string &name() { return name_; } +}; +} + +struct MixGL { int i; MixGL(int i) : i{i} {} }; +struct MixGL2 { int i; MixGL2(int i) : i{i} {} }; diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/object.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/object.h new file mode 100644 index 0000000000000000000000000000000000000000..9235f19c20bff3afb59c6880a84c809205eff6ea --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/object.h @@ -0,0 +1,175 @@ +#if !defined(__OBJECT_H) +#define __OBJECT_H + +#include +#include "constructor_stats.h" + +/// Reference counted object base class +class Object { +public: + /// Default constructor + Object() { print_default_created(this); } + + /// Copy constructor + Object(const Object &) : m_refCount(0) { print_copy_created(this); } + + /// Return the current reference count + int getRefCount() const { return m_refCount; }; + + /// Increase the object's reference count by one + void incRef() const { ++m_refCount; } + + /** \brief Decrease the reference count of + * the object and possibly deallocate it. + * + * The object will automatically be deallocated once + * the reference count reaches zero. + */ + void decRef(bool dealloc = true) const { + --m_refCount; + if (m_refCount == 0 && dealloc) + delete this; + else if (m_refCount < 0) + throw std::runtime_error("Internal error: reference count < 0!"); + } + + virtual std::string toString() const = 0; +protected: + /** \brief Virtual protected deconstructor. + * (Will only be called by \ref ref) + */ + virtual ~Object() { print_destroyed(this); } +private: + mutable std::atomic m_refCount { 0 }; +}; + +// Tag class used to track constructions of ref objects. When we track constructors, below, we +// track and print out the actual class (e.g. ref), and *also* add a fake tracker for +// ref_tag. This lets us check that the total number of ref constructors/destructors is +// correct without having to check each individual ref type individually. +class ref_tag {}; + +/** + * \brief Reference counting helper + * + * The \a ref refeference template is a simple wrapper to store a + * pointer to an object. It takes care of increasing and decreasing + * the reference count of the object. When the last reference goes + * out of scope, the associated object will be deallocated. + * + * \ingroup libcore + */ +template class ref { +public: + /// Create a nullptr reference + ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); } + + /// Construct a reference from a pointer + ref(T *ptr) : m_ptr(ptr) { + if (m_ptr) ((Object *) m_ptr)->incRef(); + + print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer"); + + } + + /// Copy constructor + ref(const ref &r) : m_ptr(r.m_ptr) { + if (m_ptr) + ((Object *) m_ptr)->incRef(); + + print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this); + } + + /// Move constructor + ref(ref &&r) : m_ptr(r.m_ptr) { + r.m_ptr = nullptr; + + print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this); + } + + /// Destroy this reference + ~ref() { + if (m_ptr) + ((Object *) m_ptr)->decRef(); + + print_destroyed(this); track_destroyed((ref_tag*) this); + } + + /// Move another reference into the current one + ref& operator=(ref&& r) { + print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this); + + if (*this == r) + return *this; + if (m_ptr) + ((Object *) m_ptr)->decRef(); + m_ptr = r.m_ptr; + r.m_ptr = nullptr; + return *this; + } + + /// Overwrite this reference with another reference + ref& operator=(const ref& r) { + print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this); + + if (m_ptr == r.m_ptr) + return *this; + if (m_ptr) + ((Object *) m_ptr)->decRef(); + m_ptr = r.m_ptr; + if (m_ptr) + ((Object *) m_ptr)->incRef(); + return *this; + } + + /// Overwrite this reference with a pointer to another object + ref& operator=(T *ptr) { + print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer"); + + if (m_ptr == ptr) + return *this; + if (m_ptr) + ((Object *) m_ptr)->decRef(); + m_ptr = ptr; + if (m_ptr) + ((Object *) m_ptr)->incRef(); + return *this; + } + + /// Compare this reference with another reference + bool operator==(const ref &r) const { return m_ptr == r.m_ptr; } + + /// Compare this reference with another reference + bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; } + + /// Compare this reference with a pointer + bool operator==(const T* ptr) const { return m_ptr == ptr; } + + /// Compare this reference with a pointer + bool operator!=(const T* ptr) const { return m_ptr != ptr; } + + /// Access the object referenced by this reference + T* operator->() { return m_ptr; } + + /// Access the object referenced by this reference + const T* operator->() const { return m_ptr; } + + /// Return a C++ reference to the referenced object + T& operator*() { return *m_ptr; } + + /// Return a const C++ reference to the referenced object + const T& operator*() const { return *m_ptr; } + + /// Return a pointer to the referenced object + operator T* () { return m_ptr; } + + /// Return a const pointer to the referenced object + T* get_ptr() { return m_ptr; } + + /// Return a pointer to the referenced object + const T* get_ptr() const { return m_ptr; } +private: + T *m_ptr; +}; + +#endif /* __OBJECT_H */ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pybind11_cross_module_tests.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pybind11_cross_module_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f705e310611619dff319f9b5d53b71e6fd54aec5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pybind11_cross_module_tests.cpp @@ -0,0 +1,123 @@ +/* + tests/pybind11_cross_module_tests.cpp -- contains tests that require multiple modules + + Copyright (c) 2017 Jason Rhinelander + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "local_bindings.h" +#include +#include + +PYBIND11_MODULE(pybind11_cross_module_tests, m) { + m.doc() = "pybind11 cross-module test module"; + + // test_local_bindings.py tests: + // + // Definitions here are tested by importing both this module and the + // relevant pybind11_tests submodule from a test_whatever.py + + // test_load_external + bind_local(m, "ExternalType1", py::module_local()); + bind_local(m, "ExternalType2", py::module_local()); + + // test_exceptions.py + m.def("raise_runtime_error", []() { PyErr_SetString(PyExc_RuntimeError, "My runtime error"); throw py::error_already_set(); }); + m.def("raise_value_error", []() { PyErr_SetString(PyExc_ValueError, "My value error"); throw py::error_already_set(); }); + m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); }); + m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); }); + m.def("throw_stop_iteration", []() { throw py::stop_iteration(); }); + + // test_local_bindings.py + // Local to both: + bind_local(m, "LocalType", py::module_local()) + .def("get2", [](LocalType &t) { return t.i + 2; }) + ; + + // Can only be called with our python type: + m.def("local_value", [](LocalType &l) { return l.i; }); + + // test_nonlocal_failure + // This registration will fail (global registration when LocalFail is already registered + // globally in the main test module): + m.def("register_nonlocal", [m]() { + bind_local(m, "NonLocalType"); + }); + + // test_stl_bind_local + // stl_bind.h binders defaults to py::module_local if the types are local or converting: + py::bind_vector(m, "LocalVec"); + py::bind_map(m, "LocalMap"); + + // test_stl_bind_global + // and global if the type (or one of the types, for the map) is global (so these will fail, + // assuming pybind11_tests is already loaded): + m.def("register_nonlocal_vec", [m]() { + py::bind_vector(m, "NonLocalVec"); + }); + m.def("register_nonlocal_map", [m]() { + py::bind_map(m, "NonLocalMap"); + }); + // The default can, however, be overridden to global using `py::module_local()` or + // `py::module_local(false)`. + // Explicitly made local: + py::bind_vector(m, "NonLocalVec2", py::module_local()); + // Explicitly made global (and so will fail to bind): + m.def("register_nonlocal_map2", [m]() { + py::bind_map(m, "NonLocalMap2", py::module_local(false)); + }); + + // test_mixed_local_global + // We try this both with the global type registered first and vice versa (the order shouldn't + // matter). + m.def("register_mixed_global_local", [m]() { + bind_local(m, "MixedGlobalLocal", py::module_local()); + }); + m.def("register_mixed_local_global", [m]() { + bind_local(m, "MixedLocalGlobal", py::module_local(false)); + }); + m.def("get_mixed_gl", [](int i) { return MixedGlobalLocal(i); }); + m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); }); + + // test_internal_locals_differ + m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); }); + + // test_stl_caster_vs_stl_bind + py::bind_vector>(m, "VectorInt"); + + m.def("load_vector_via_binding", [](std::vector &v) { + return std::accumulate(v.begin(), v.end(), 0); + }); + + // test_cross_module_calls + m.def("return_self", [](LocalVec *v) { return v; }); + m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); }); + + class Dog : public pets::Pet { public: Dog(std::string name) : Pet(name) {}; }; + py::class_(m, "Pet", py::module_local()) + .def("name", &pets::Pet::name); + // Binding for local extending class: + py::class_(m, "Dog") + .def(py::init()); + m.def("pet_name", [](pets::Pet &p) { return p.name(); }); + + py::class_(m, "MixGL", py::module_local()).def(py::init()); + m.def("get_gl_value", [](MixGL &o) { return o.i + 100; }); + + py::class_(m, "MixGL2", py::module_local()).def(py::init()); + + // test_vector_bool + // We can't test both stl.h and stl_bind.h conversions of `std::vector` within + // the same module (it would be an ODR violation). Therefore `bind_vector` of `bool` + // is defined here and tested in `test_stl_binders.py`. + py::bind_vector>(m, "VectorBool"); + + // test_missing_header_message + // The main module already includes stl.h, but we need to test the error message + // which appears when this header is missing. + m.def("missing_header_arg", [](std::vector) { }); + m.def("missing_header_return", []() { return std::vector(); }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pybind11_tests.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pybind11_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bc7d2c3e7abf700c4f6256d8811cc7495c09bf80 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pybind11_tests.cpp @@ -0,0 +1,93 @@ +/* + tests/pybind11_tests.cpp -- pybind example plugin + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" + +#include +#include + +/* +For testing purposes, we define a static global variable here in a function that each individual +test .cpp calls with its initialization lambda. It's convenient here because we can just not +compile some test files to disable/ignore some of the test code. + +It is NOT recommended as a way to use pybind11 in practice, however: the initialization order will +be essentially random, which is okay for our test scripts (there are no dependencies between the +individual pybind11 test .cpp files), but most likely not what you want when using pybind11 +productively. + +Instead, see the "How can I reduce the build time?" question in the "Frequently asked questions" +section of the documentation for good practice on splitting binding code over multiple files. +*/ +std::list> &initializers() { + static std::list> inits; + return inits; +} + +test_initializer::test_initializer(Initializer init) { + initializers().push_back(init); +} + +test_initializer::test_initializer(const char *submodule_name, Initializer init) { + initializers().push_back([=](py::module &parent) { + auto m = parent.def_submodule(submodule_name); + init(m); + }); +} + +void bind_ConstructorStats(py::module &m) { + py::class_(m, "ConstructorStats") + .def("alive", &ConstructorStats::alive) + .def("values", &ConstructorStats::values) + .def_readwrite("default_constructions", &ConstructorStats::default_constructions) + .def_readwrite("copy_assignments", &ConstructorStats::copy_assignments) + .def_readwrite("move_assignments", &ConstructorStats::move_assignments) + .def_readwrite("copy_constructions", &ConstructorStats::copy_constructions) + .def_readwrite("move_constructions", &ConstructorStats::move_constructions) + .def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal) + + // Not exactly ConstructorStats, but related: expose the internal pybind number of registered instances + // to allow instance cleanup checks (invokes a GC first) + .def_static("detail_reg_inst", []() { + ConstructorStats::gc(); + return py::detail::get_internals().registered_instances.size(); + }) + ; +} + +PYBIND11_MODULE(pybind11_tests, m) { + m.doc() = "pybind11 test module"; + + bind_ConstructorStats(m); + +#if !defined(NDEBUG) + m.attr("debug_enabled") = true; +#else + m.attr("debug_enabled") = false; +#endif + + py::class_(m, "UserType", "A `py::class_` type for testing") + .def(py::init<>()) + .def(py::init()) + .def("get_value", &UserType::value, "Get value using a method") + .def("set_value", &UserType::set, "Set value using a method") + .def_property("value", &UserType::value, &UserType::set, "Get/set value using a property") + .def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); }); + + py::class_(m, "IncType") + .def(py::init<>()) + .def(py::init()) + .def("__repr__", [](const IncType& u) { return "IncType({})"_s.format(u.value()); }); + + for (const auto &initializer : initializers()) + initializer(m); + + if (!py::hasattr(m, "have_eigen")) m.attr("have_eigen") = false; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pybind11_tests.h b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pybind11_tests.h new file mode 100644 index 0000000000000000000000000000000000000000..90963a5dea7a2c56fa955ceaade53282708e2d85 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pybind11_tests.h @@ -0,0 +1,65 @@ +#pragma once +#include + +#if defined(_MSC_VER) && _MSC_VER < 1910 +// We get some really long type names here which causes MSVC 2015 to emit warnings +# pragma warning(disable: 4503) // warning C4503: decorated name length exceeded, name was truncated +#endif + +namespace py = pybind11; +using namespace pybind11::literals; + +class test_initializer { + using Initializer = void (*)(py::module &); + +public: + test_initializer(Initializer init); + test_initializer(const char *submodule_name, Initializer init); +}; + +#define TEST_SUBMODULE(name, variable) \ + void test_submodule_##name(py::module &); \ + test_initializer name(#name, test_submodule_##name); \ + void test_submodule_##name(py::module &variable) + + +/// Dummy type which is not exported anywhere -- something to trigger a conversion error +struct UnregisteredType { }; + +/// A user-defined type which is exported and can be used by any test +class UserType { +public: + UserType() = default; + UserType(int i) : i(i) { } + + int value() const { return i; } + void set(int set) { i = set; } + +private: + int i = -1; +}; + +/// Like UserType, but increments `value` on copy for quick reference vs. copy tests +class IncType : public UserType { +public: + using UserType::UserType; + IncType() = default; + IncType(const IncType &other) : IncType(other.value() + 1) { } + IncType(IncType &&) = delete; + IncType &operator=(const IncType &) = delete; + IncType &operator=(IncType &&) = delete; +}; + +/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast context. +/// Used to test recursive casters (e.g. std::tuple, stl containers). +struct RValueCaster {}; +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) +template<> class type_caster { +public: + PYBIND11_TYPE_CASTER(RValueCaster, _("RValueCaster")); + static handle cast(RValueCaster &&, return_value_policy, handle) { return py::str("rvalue").release(); } + static handle cast(const RValueCaster &, return_value_policy, handle) { return py::str("lvalue").release(); } +}; +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pytest.ini b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pytest.ini new file mode 100644 index 0000000000000000000000000000000000000000..f209964a477cc7bb5695c46e188545aaf36919ef --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/pytest.ini @@ -0,0 +1,16 @@ +[pytest] +minversion = 3.0 +norecursedirs = test_cmake_build test_embed +addopts = + # show summary of skipped tests + -rs + # capture only Python print and C++ py::print, but not C output (low-level Python errors) + --capture=sys +filterwarnings = + # make warnings into errors but ignore certain third-party extension issues + error + # importing scipy submodules on some version of Python + ignore::ImportWarning + # bogus numpy ABI warning (see numpy/#432) + ignore:.*numpy.dtype size changed.*:RuntimeWarning + ignore:.*numpy.ufunc size changed.*:RuntimeWarning diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_async.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_async.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0ad0d535048fbb825b444e743193c743551cdd4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_async.cpp @@ -0,0 +1,26 @@ +/* + tests/test_async.cpp -- __await__ support + + Copyright (c) 2019 Google Inc. + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +TEST_SUBMODULE(async_module, m) { + struct DoesNotSupportAsync {}; + py::class_(m, "DoesNotSupportAsync") + .def(py::init<>()); + struct SupportsAsync {}; + py::class_(m, "SupportsAsync") + .def(py::init<>()) + .def("__await__", [](const SupportsAsync& self) -> py::object { + static_cast(self); + py::object loop = py::module::import("asyncio.events").attr("get_event_loop")(); + py::object f = loop.attr("create_future")(); + f.attr("set_result")(5); + return f.attr("__await__")(); + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_async.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_async.py new file mode 100644 index 0000000000000000000000000000000000000000..e1c959d60260986195fb17fcc3bf580612503f8b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_async.py @@ -0,0 +1,23 @@ +import asyncio +import pytest +from pybind11_tests import async_module as m + + +@pytest.fixture +def event_loop(): + loop = asyncio.new_event_loop() + yield loop + loop.close() + + +async def get_await_result(x): + return await x + + +def test_await(event_loop): + assert 5 == event_loop.run_until_complete(get_await_result(m.SupportsAsync())) + + +def test_await_missing(event_loop): + with pytest.raises(TypeError): + event_loop.run_until_complete(get_await_result(m.DoesNotSupportAsync())) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_buffers.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_buffers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1bc67ff7b66e86d7bf94de845e5737261f2a1280 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_buffers.cpp @@ -0,0 +1,195 @@ +/* + tests/test_buffers.cpp -- supporting Pythons' buffer protocol + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" + +TEST_SUBMODULE(buffers, m) { + // test_from_python / test_to_python: + class Matrix { + public: + Matrix(ssize_t rows, ssize_t cols) : m_rows(rows), m_cols(cols) { + print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); + m_data = new float[(size_t) (rows*cols)]; + memset(m_data, 0, sizeof(float) * (size_t) (rows * cols)); + } + + Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) { + print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); + m_data = new float[(size_t) (m_rows * m_cols)]; + memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols)); + } + + Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) { + print_move_created(this); + s.m_rows = 0; + s.m_cols = 0; + s.m_data = nullptr; + } + + ~Matrix() { + print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); + delete[] m_data; + } + + Matrix &operator=(const Matrix &s) { + print_copy_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); + delete[] m_data; + m_rows = s.m_rows; + m_cols = s.m_cols; + m_data = new float[(size_t) (m_rows * m_cols)]; + memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols)); + return *this; + } + + Matrix &operator=(Matrix &&s) { + print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); + if (&s != this) { + delete[] m_data; + m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data; + s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr; + } + return *this; + } + + float operator()(ssize_t i, ssize_t j) const { + return m_data[(size_t) (i*m_cols + j)]; + } + + float &operator()(ssize_t i, ssize_t j) { + return m_data[(size_t) (i*m_cols + j)]; + } + + float *data() { return m_data; } + + ssize_t rows() const { return m_rows; } + ssize_t cols() const { return m_cols; } + private: + ssize_t m_rows; + ssize_t m_cols; + float *m_data; + }; + py::class_(m, "Matrix", py::buffer_protocol()) + .def(py::init()) + /// Construct from a buffer + .def(py::init([](py::buffer const b) { + py::buffer_info info = b.request(); + if (info.format != py::format_descriptor::format() || info.ndim != 2) + throw std::runtime_error("Incompatible buffer format!"); + + auto v = new Matrix(info.shape[0], info.shape[1]); + memcpy(v->data(), info.ptr, sizeof(float) * (size_t) (v->rows() * v->cols())); + return v; + })) + + .def("rows", &Matrix::rows) + .def("cols", &Matrix::cols) + + /// Bare bones interface + .def("__getitem__", [](const Matrix &m, std::pair i) { + if (i.first >= m.rows() || i.second >= m.cols()) + throw py::index_error(); + return m(i.first, i.second); + }) + .def("__setitem__", [](Matrix &m, std::pair i, float v) { + if (i.first >= m.rows() || i.second >= m.cols()) + throw py::index_error(); + m(i.first, i.second) = v; + }) + /// Provide buffer access + .def_buffer([](Matrix &m) -> py::buffer_info { + return py::buffer_info( + m.data(), /* Pointer to buffer */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */ + sizeof(float) } + ); + }) + ; + + + // test_inherited_protocol + class SquareMatrix : public Matrix { + public: + SquareMatrix(ssize_t n) : Matrix(n, n) { } + }; + // Derived classes inherit the buffer protocol and the buffer access function + py::class_(m, "SquareMatrix") + .def(py::init()); + + + // test_pointer_to_member_fn + // Tests that passing a pointer to member to the base class works in + // the derived class. + struct Buffer { + int32_t value = 0; + + py::buffer_info get_buffer_info() { + return py::buffer_info(&value, sizeof(value), + py::format_descriptor::format(), 1); + } + }; + py::class_(m, "Buffer", py::buffer_protocol()) + .def(py::init<>()) + .def_readwrite("value", &Buffer::value) + .def_buffer(&Buffer::get_buffer_info); + + + class ConstBuffer { + std::unique_ptr value; + + public: + int32_t get_value() const { return *value; } + void set_value(int32_t v) { *value = v; } + + py::buffer_info get_buffer_info() const { + return py::buffer_info(value.get(), sizeof(*value), + py::format_descriptor::format(), 1); + } + + ConstBuffer() : value(new int32_t{0}) { }; + }; + py::class_(m, "ConstBuffer", py::buffer_protocol()) + .def(py::init<>()) + .def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value) + .def_buffer(&ConstBuffer::get_buffer_info); + + struct DerivedBuffer : public Buffer { }; + py::class_(m, "DerivedBuffer", py::buffer_protocol()) + .def(py::init<>()) + .def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value) + .def_buffer(&DerivedBuffer::get_buffer_info); + + struct BufferReadOnly { + const uint8_t value = 0; + BufferReadOnly(uint8_t value): value(value) {} + + py::buffer_info get_buffer_info() { + return py::buffer_info(&value, 1); + } + }; + py::class_(m, "BufferReadOnly", py::buffer_protocol()) + .def(py::init()) + .def_buffer(&BufferReadOnly::get_buffer_info); + + struct BufferReadOnlySelect { + uint8_t value = 0; + bool readonly = false; + + py::buffer_info get_buffer_info() { + return py::buffer_info(&value, 1, readonly); + } + }; + py::class_(m, "BufferReadOnlySelect", py::buffer_protocol()) + .def(py::init<>()) + .def_readwrite("value", &BufferReadOnlySelect::value) + .def_readwrite("readonly", &BufferReadOnlySelect::readonly) + .def_buffer(&BufferReadOnlySelect::get_buffer_info); + +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_buffers.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_buffers.py new file mode 100644 index 0000000000000000000000000000000000000000..bf7aaed70da89c353d5e7049e76a92103ea52f0e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_buffers.py @@ -0,0 +1,118 @@ +import io +import struct +import sys + +import pytest + +from pybind11_tests import buffers as m +from pybind11_tests import ConstructorStats + +PY3 = sys.version_info[0] >= 3 + +pytestmark = pytest.requires_numpy + +with pytest.suppress(ImportError): + import numpy as np + + +def test_from_python(): + with pytest.raises(RuntimeError) as excinfo: + m.Matrix(np.array([1, 2, 3])) # trying to assign a 1D array + assert str(excinfo.value) == "Incompatible buffer format!" + + m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + m4 = m.Matrix(m3) + + for i in range(m4.rows()): + for j in range(m4.cols()): + assert m3[i, j] == m4[i, j] + + cstats = ConstructorStats.get(m.Matrix) + assert cstats.alive() == 1 + del m3, m4 + assert cstats.alive() == 0 + assert cstats.values() == ["2x3 matrix"] + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Don't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + +# PyPy: Memory leak in the "np.array(m, copy=False)" call +# https://bitbucket.org/pypy/pypy/issues/2444 +@pytest.unsupported_on_pypy +def test_to_python(): + mat = m.Matrix(5, 4) + assert memoryview(mat).shape == (5, 4) + + assert mat[2, 3] == 0 + mat[2, 3] = 4.0 + mat[3, 2] = 7.0 + assert mat[2, 3] == 4 + assert mat[3, 2] == 7 + assert struct.unpack_from('f', mat, (3 * 4 + 2) * 4) == (7, ) + assert struct.unpack_from('f', mat, (2 * 4 + 3) * 4) == (4, ) + + mat2 = np.array(mat, copy=False) + assert mat2.shape == (5, 4) + assert abs(mat2).sum() == 11 + assert mat2[2, 3] == 4 and mat2[3, 2] == 7 + mat2[2, 3] = 5 + assert mat2[2, 3] == 5 + + cstats = ConstructorStats.get(m.Matrix) + assert cstats.alive() == 1 + del mat + pytest.gc_collect() + assert cstats.alive() == 1 + del mat2 # holds a mat reference + pytest.gc_collect() + assert cstats.alive() == 0 + assert cstats.values() == ["5x4 matrix"] + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Don't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + +@pytest.unsupported_on_pypy +def test_inherited_protocol(): + """SquareMatrix is derived from Matrix and inherits the buffer protocol""" + + matrix = m.SquareMatrix(5) + assert memoryview(matrix).shape == (5, 5) + assert np.asarray(matrix).shape == (5, 5) + + +@pytest.unsupported_on_pypy +def test_pointer_to_member_fn(): + for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]: + buf = cls() + buf.value = 0x12345678 + value = struct.unpack('i', bytearray(buf))[0] + assert value == 0x12345678 + + +@pytest.unsupported_on_pypy +def test_readonly_buffer(): + buf = m.BufferReadOnly(0x64) + view = memoryview(buf) + assert view[0] == 0x64 if PY3 else b'd' + assert view.readonly + + +@pytest.unsupported_on_pypy +def test_selective_readonly_buffer(): + buf = m.BufferReadOnlySelect() + + memoryview(buf)[0] = 0x64 if PY3 else b'd' + assert buf.value == 0x64 + + io.BytesIO(b'A').readinto(buf) + assert buf.value == ord(b'A') + + buf.readonly = True + with pytest.raises(TypeError): + memoryview(buf)[0] = 0 if PY3 else b'\0' + with pytest.raises(TypeError): + io.BytesIO(b'1').readinto(buf) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_builtin_casters.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_builtin_casters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..acb2446912c2ba5b3e4bcf5c671bb69194c726f8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_builtin_casters.cpp @@ -0,0 +1,188 @@ +/* + tests/test_builtin_casters.cpp -- Casters available without any additional headers + + Copyright (c) 2017 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +TEST_SUBMODULE(builtin_casters, m) { + // test_simple_string + m.def("string_roundtrip", [](const char *s) { return s; }); + + // test_unicode_conversion + // Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null byte + char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/, mathbfA32 = 0x1d400 /*𝐀*/; + char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82, mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00; + std::wstring wstr; + wstr.push_back(0x61); // a + wstr.push_back(0x2e18); // ⸘ + if (sizeof(wchar_t) == 2) { wstr.push_back(mathbfA16_1); wstr.push_back(mathbfA16_2); } // 𝐀, utf16 + else { wstr.push_back((wchar_t) mathbfA32); } // 𝐀, utf32 + wstr.push_back(0x7a); // z + + m.def("good_utf8_string", []() { return std::string((const char*)u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀 + m.def("good_utf16_string", [=]() { return std::u16string({ b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16 }); }); // b‽🎂𝐀z + m.def("good_utf32_string", [=]() { return std::u32string({ a32, mathbfA32, cake32, ib32, z32 }); }); // a𝐀🎂‽z + m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z + m.def("bad_utf8_string", []() { return std::string("abc\xd0" "def"); }); + m.def("bad_utf16_string", [=]() { return std::u16string({ b16, char16_t(0xd800), z16 }); }); + // Under Python 2.7, invalid unicode UTF-32 characters don't appear to trigger UnicodeDecodeError + if (PY_MAJOR_VERSION >= 3) + m.def("bad_utf32_string", [=]() { return std::u32string({ a32, char32_t(0xd800), z32 }); }); + if (PY_MAJOR_VERSION >= 3 || sizeof(wchar_t) == 2) + m.def("bad_wchar_string", [=]() { return std::wstring({ wchar_t(0x61), wchar_t(0xd800) }); }); + m.def("u8_Z", []() -> char { return 'Z'; }); + m.def("u8_eacute", []() -> char { return '\xe9'; }); + m.def("u16_ibang", [=]() -> char16_t { return ib16; }); + m.def("u32_mathbfA", [=]() -> char32_t { return mathbfA32; }); + m.def("wchar_heart", []() -> wchar_t { return 0x2665; }); + + // test_single_char_arguments + m.attr("wchar_size") = py::cast(sizeof(wchar_t)); + m.def("ord_char", [](char c) -> int { return static_cast(c); }); + m.def("ord_char_lv", [](char &c) -> int { return static_cast(c); }); + m.def("ord_char16", [](char16_t c) -> uint16_t { return c; }); + m.def("ord_char16_lv", [](char16_t &c) -> uint16_t { return c; }); + m.def("ord_char32", [](char32_t c) -> uint32_t { return c; }); + m.def("ord_wchar", [](wchar_t c) -> int { return c; }); + + // test_bytes_to_string + m.def("strlen", [](char *s) { return strlen(s); }); + m.def("string_length", [](std::string s) { return s.length(); }); + +#ifdef PYBIND11_HAS_U8STRING + m.attr("has_u8string") = true; + m.def("good_utf8_u8string", []() { return std::u8string(u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀 + m.def("bad_utf8_u8string", []() { return std::u8string((const char8_t*)"abc\xd0" "def"); }); + + m.def("u8_char8_Z", []() -> char8_t { return u8'Z'; }); + + // test_single_char_arguments + m.def("ord_char8", [](char8_t c) -> int { return static_cast(c); }); + m.def("ord_char8_lv", [](char8_t &c) -> int { return static_cast(c); }); +#endif + + // test_string_view +#ifdef PYBIND11_HAS_STRING_VIEW + m.attr("has_string_view") = true; + m.def("string_view_print", [](std::string_view s) { py::print(s, s.size()); }); + m.def("string_view16_print", [](std::u16string_view s) { py::print(s, s.size()); }); + m.def("string_view32_print", [](std::u32string_view s) { py::print(s, s.size()); }); + m.def("string_view_chars", [](std::string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; }); + m.def("string_view16_chars", [](std::u16string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; }); + m.def("string_view32_chars", [](std::u32string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; }); + m.def("string_view_return", []() { return std::string_view((const char*)u8"utf8 secret \U0001f382"); }); + m.def("string_view16_return", []() { return std::u16string_view(u"utf16 secret \U0001f382"); }); + m.def("string_view32_return", []() { return std::u32string_view(U"utf32 secret \U0001f382"); }); + +# ifdef PYBIND11_HAS_U8STRING + m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); }); + m.def("string_view8_chars", [](std::u8string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; }); + m.def("string_view8_return", []() { return std::u8string_view(u8"utf8 secret \U0001f382"); }); +# endif +#endif + + // test_integer_casting + m.def("i32_str", [](std::int32_t v) { return std::to_string(v); }); + m.def("u32_str", [](std::uint32_t v) { return std::to_string(v); }); + m.def("i64_str", [](std::int64_t v) { return std::to_string(v); }); + m.def("u64_str", [](std::uint64_t v) { return std::to_string(v); }); + + // test_tuple + m.def("pair_passthrough", [](std::pair input) { + return std::make_pair(input.second, input.first); + }, "Return a pair in reversed order"); + m.def("tuple_passthrough", [](std::tuple input) { + return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input)); + }, "Return a triple in reversed order"); + m.def("empty_tuple", []() { return std::tuple<>(); }); + static std::pair lvpair; + static std::tuple lvtuple; + static std::pair>> lvnested; + m.def("rvalue_pair", []() { return std::make_pair(RValueCaster{}, RValueCaster{}); }); + m.def("lvalue_pair", []() -> const decltype(lvpair) & { return lvpair; }); + m.def("rvalue_tuple", []() { return std::make_tuple(RValueCaster{}, RValueCaster{}, RValueCaster{}); }); + m.def("lvalue_tuple", []() -> const decltype(lvtuple) & { return lvtuple; }); + m.def("rvalue_nested", []() { + return std::make_pair(RValueCaster{}, std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{}))); }); + m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; }); + + // test_builtins_cast_return_none + m.def("return_none_string", []() -> std::string * { return nullptr; }); + m.def("return_none_char", []() -> const char * { return nullptr; }); + m.def("return_none_bool", []() -> bool * { return nullptr; }); + m.def("return_none_int", []() -> int * { return nullptr; }); + m.def("return_none_float", []() -> float * { return nullptr; }); + + // test_none_deferred + m.def("defer_none_cstring", [](char *) { return false; }); + m.def("defer_none_cstring", [](py::none) { return true; }); + m.def("defer_none_custom", [](UserType *) { return false; }); + m.def("defer_none_custom", [](py::none) { return true; }); + m.def("nodefer_none_void", [](void *) { return true; }); + m.def("nodefer_none_void", [](py::none) { return false; }); + + // test_void_caster + m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile + m.def("cast_nullptr_t", []() { return std::nullptr_t{}; }); + + // test_bool_caster + m.def("bool_passthrough", [](bool arg) { return arg; }); + m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg().noconvert()); + + // test_reference_wrapper + m.def("refwrap_builtin", [](std::reference_wrapper p) { return 10 * p.get(); }); + m.def("refwrap_usertype", [](std::reference_wrapper p) { return p.get().value(); }); + // Not currently supported (std::pair caster has return-by-value cast operator); + // triggers static_assert failure. + //m.def("refwrap_pair", [](std::reference_wrapper>) { }); + + m.def("refwrap_list", [](bool copy) { + static IncType x1(1), x2(2); + py::list l; + for (auto &f : {std::ref(x1), std::ref(x2)}) { + l.append(py::cast(f, copy ? py::return_value_policy::copy + : py::return_value_policy::reference)); + } + return l; + }, "copy"_a); + + m.def("refwrap_iiw", [](const IncType &w) { return w.value(); }); + m.def("refwrap_call_iiw", [](IncType &w, py::function f) { + py::list l; + l.append(f(std::ref(w))); + l.append(f(std::cref(w))); + IncType x(w.value()); + l.append(f(std::ref(x))); + IncType y(w.value()); + auto r3 = std::ref(y); + l.append(f(r3)); + return l; + }); + + // test_complex + m.def("complex_cast", [](float x) { return "{}"_s.format(x); }); + m.def("complex_cast", [](std::complex x) { return "({}, {})"_s.format(x.real(), x.imag()); }); + + // test int vs. long (Python 2) + m.def("int_cast", []() {return (int) 42;}); + m.def("long_cast", []() {return (long) 42;}); + m.def("longlong_cast", []() {return ULLONG_MAX;}); + + /// test void* cast operator + m.def("test_void_caster", []() -> bool { + void *v = (void *) 0xabcd; + py::object o = py::cast(v); + return py::cast(o) == v; + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_builtin_casters.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_builtin_casters.py new file mode 100644 index 0000000000000000000000000000000000000000..91422588cf6f880b40daaa9d635f94cd70d459ad --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_builtin_casters.py @@ -0,0 +1,385 @@ +# Python < 3 needs this: coding=utf-8 +import pytest + +from pybind11_tests import builtin_casters as m +from pybind11_tests import UserType, IncType + + +def test_simple_string(): + assert m.string_roundtrip("const char *") == "const char *" + + +def test_unicode_conversion(): + """Tests unicode conversion and error reporting.""" + assert m.good_utf8_string() == u"Say utf8‽ 🎂 𝐀" + assert m.good_utf16_string() == u"b‽🎂𝐀z" + assert m.good_utf32_string() == u"a𝐀🎂‽z" + assert m.good_wchar_string() == u"a⸘𝐀z" + if hasattr(m, "has_u8string"): + assert m.good_utf8_u8string() == u"Say utf8‽ 🎂 𝐀" + + with pytest.raises(UnicodeDecodeError): + m.bad_utf8_string() + + with pytest.raises(UnicodeDecodeError): + m.bad_utf16_string() + + # These are provided only if they actually fail (they don't when 32-bit and under Python 2.7) + if hasattr(m, "bad_utf32_string"): + with pytest.raises(UnicodeDecodeError): + m.bad_utf32_string() + if hasattr(m, "bad_wchar_string"): + with pytest.raises(UnicodeDecodeError): + m.bad_wchar_string() + if hasattr(m, "has_u8string"): + with pytest.raises(UnicodeDecodeError): + m.bad_utf8_u8string() + + assert m.u8_Z() == 'Z' + assert m.u8_eacute() == u'é' + assert m.u16_ibang() == u'‽' + assert m.u32_mathbfA() == u'𝐀' + assert m.wchar_heart() == u'♥' + if hasattr(m, "has_u8string"): + assert m.u8_char8_Z() == 'Z' + + +def test_single_char_arguments(): + """Tests failures for passing invalid inputs to char-accepting functions""" + def toobig_message(r): + return "Character code point not in range({0:#x})".format(r) + toolong_message = "Expected a character, but multi-character string found" + + assert m.ord_char(u'a') == 0x61 # simple ASCII + assert m.ord_char_lv(u'b') == 0x62 + assert m.ord_char(u'é') == 0xE9 # requires 2 bytes in utf-8, but can be stuffed in a char + with pytest.raises(ValueError) as excinfo: + assert m.ord_char(u'Ā') == 0x100 # requires 2 bytes, doesn't fit in a char + assert str(excinfo.value) == toobig_message(0x100) + with pytest.raises(ValueError) as excinfo: + assert m.ord_char(u'ab') + assert str(excinfo.value) == toolong_message + + assert m.ord_char16(u'a') == 0x61 + assert m.ord_char16(u'é') == 0xE9 + assert m.ord_char16_lv(u'ê') == 0xEA + assert m.ord_char16(u'Ā') == 0x100 + assert m.ord_char16(u'‽') == 0x203d + assert m.ord_char16(u'♥') == 0x2665 + assert m.ord_char16_lv(u'♡') == 0x2661 + with pytest.raises(ValueError) as excinfo: + assert m.ord_char16(u'🎂') == 0x1F382 # requires surrogate pair + assert str(excinfo.value) == toobig_message(0x10000) + with pytest.raises(ValueError) as excinfo: + assert m.ord_char16(u'aa') + assert str(excinfo.value) == toolong_message + + assert m.ord_char32(u'a') == 0x61 + assert m.ord_char32(u'é') == 0xE9 + assert m.ord_char32(u'Ā') == 0x100 + assert m.ord_char32(u'‽') == 0x203d + assert m.ord_char32(u'♥') == 0x2665 + assert m.ord_char32(u'🎂') == 0x1F382 + with pytest.raises(ValueError) as excinfo: + assert m.ord_char32(u'aa') + assert str(excinfo.value) == toolong_message + + assert m.ord_wchar(u'a') == 0x61 + assert m.ord_wchar(u'é') == 0xE9 + assert m.ord_wchar(u'Ā') == 0x100 + assert m.ord_wchar(u'‽') == 0x203d + assert m.ord_wchar(u'♥') == 0x2665 + if m.wchar_size == 2: + with pytest.raises(ValueError) as excinfo: + assert m.ord_wchar(u'🎂') == 0x1F382 # requires surrogate pair + assert str(excinfo.value) == toobig_message(0x10000) + else: + assert m.ord_wchar(u'🎂') == 0x1F382 + with pytest.raises(ValueError) as excinfo: + assert m.ord_wchar(u'aa') + assert str(excinfo.value) == toolong_message + + if hasattr(m, "has_u8string"): + assert m.ord_char8(u'a') == 0x61 # simple ASCII + assert m.ord_char8_lv(u'b') == 0x62 + assert m.ord_char8(u'é') == 0xE9 # requires 2 bytes in utf-8, but can be stuffed in a char + with pytest.raises(ValueError) as excinfo: + assert m.ord_char8(u'Ā') == 0x100 # requires 2 bytes, doesn't fit in a char + assert str(excinfo.value) == toobig_message(0x100) + with pytest.raises(ValueError) as excinfo: + assert m.ord_char8(u'ab') + assert str(excinfo.value) == toolong_message + + +def test_bytes_to_string(): + """Tests the ability to pass bytes to C++ string-accepting functions. Note that this is + one-way: the only way to return bytes to Python is via the pybind11::bytes class.""" + # Issue #816 + import sys + byte = bytes if sys.version_info[0] < 3 else str + + assert m.strlen(byte("hi")) == 2 + assert m.string_length(byte("world")) == 5 + assert m.string_length(byte("a\x00b")) == 3 + assert m.strlen(byte("a\x00b")) == 1 # C-string limitation + + # passing in a utf8 encoded string should work + assert m.string_length(u'💩'.encode("utf8")) == 4 + + +@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no ") +def test_string_view(capture): + """Tests support for C++17 string_view arguments and return values""" + assert m.string_view_chars("Hi") == [72, 105] + assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82] + assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xd83c, 0xdf82] + assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874] + if hasattr(m, "has_u8string"): + assert m.string_view8_chars("Hi") == [72, 105] + assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82] + + assert m.string_view_return() == "utf8 secret 🎂" + assert m.string_view16_return() == "utf16 secret 🎂" + assert m.string_view32_return() == "utf32 secret 🎂" + if hasattr(m, "has_u8string"): + assert m.string_view8_return() == "utf8 secret 🎂" + + with capture: + m.string_view_print("Hi") + m.string_view_print("utf8 🎂") + m.string_view16_print("utf16 🎂") + m.string_view32_print("utf32 🎂") + assert capture == """ + Hi 2 + utf8 🎂 9 + utf16 🎂 8 + utf32 🎂 7 + """ + if hasattr(m, "has_u8string"): + with capture: + m.string_view8_print("Hi") + m.string_view8_print("utf8 🎂") + assert capture == """ + Hi 2 + utf8 🎂 9 + """ + + with capture: + m.string_view_print("Hi, ascii") + m.string_view_print("Hi, utf8 🎂") + m.string_view16_print("Hi, utf16 🎂") + m.string_view32_print("Hi, utf32 🎂") + assert capture == """ + Hi, ascii 9 + Hi, utf8 🎂 13 + Hi, utf16 🎂 12 + Hi, utf32 🎂 11 + """ + if hasattr(m, "has_u8string"): + with capture: + m.string_view8_print("Hi, ascii") + m.string_view8_print("Hi, utf8 🎂") + assert capture == """ + Hi, ascii 9 + Hi, utf8 🎂 13 + """ + + +def test_integer_casting(): + """Issue #929 - out-of-range integer values shouldn't be accepted""" + import sys + assert m.i32_str(-1) == "-1" + assert m.i64_str(-1) == "-1" + assert m.i32_str(2000000000) == "2000000000" + assert m.u32_str(2000000000) == "2000000000" + if sys.version_info < (3,): + assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long' + assert m.i64_str(long(-1)) == "-1" # noqa: F821 undefined name 'long' + assert m.i64_str(long(-999999999999)) == "-999999999999" # noqa: F821 undefined name + assert m.u64_str(long(999999999999)) == "999999999999" # noqa: F821 undefined name 'long' + else: + assert m.i64_str(-999999999999) == "-999999999999" + assert m.u64_str(999999999999) == "999999999999" + + with pytest.raises(TypeError) as excinfo: + m.u32_str(-1) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.u64_str(-1) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.i32_str(-3000000000) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.i32_str(3000000000) + assert "incompatible function arguments" in str(excinfo.value) + + if sys.version_info < (3,): + with pytest.raises(TypeError) as excinfo: + m.u32_str(long(-1)) # noqa: F821 undefined name 'long' + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.u64_str(long(-1)) # noqa: F821 undefined name 'long' + assert "incompatible function arguments" in str(excinfo.value) + + +def test_tuple(doc): + """std::pair <-> tuple & std::tuple <-> tuple""" + assert m.pair_passthrough((True, "test")) == ("test", True) + assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True) + # Any sequence can be cast to a std::pair or std::tuple + assert m.pair_passthrough([True, "test"]) == ("test", True) + assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True) + assert m.empty_tuple() == () + + assert doc(m.pair_passthrough) == """ + pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool] + + Return a pair in reversed order + """ + assert doc(m.tuple_passthrough) == """ + tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool] + + Return a triple in reversed order + """ + + assert m.rvalue_pair() == ("rvalue", "rvalue") + assert m.lvalue_pair() == ("lvalue", "lvalue") + assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue") + assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue") + assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue"))) + assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue"))) + + +def test_builtins_cast_return_none(): + """Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None""" + assert m.return_none_string() is None + assert m.return_none_char() is None + assert m.return_none_bool() is None + assert m.return_none_int() is None + assert m.return_none_float() is None + + +def test_none_deferred(): + """None passed as various argument types should defer to other overloads""" + assert not m.defer_none_cstring("abc") + assert m.defer_none_cstring(None) + assert not m.defer_none_custom(UserType()) + assert m.defer_none_custom(None) + assert m.nodefer_none_void(None) + + +def test_void_caster(): + assert m.load_nullptr_t(None) is None + assert m.cast_nullptr_t() is None + + +def test_reference_wrapper(): + """std::reference_wrapper for builtin and user types""" + assert m.refwrap_builtin(42) == 420 + assert m.refwrap_usertype(UserType(42)) == 42 + + with pytest.raises(TypeError) as excinfo: + m.refwrap_builtin(None) + assert "incompatible function arguments" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + m.refwrap_usertype(None) + assert "incompatible function arguments" in str(excinfo.value) + + a1 = m.refwrap_list(copy=True) + a2 = m.refwrap_list(copy=True) + assert [x.value for x in a1] == [2, 3] + assert [x.value for x in a2] == [2, 3] + assert not a1[0] is a2[0] and not a1[1] is a2[1] + + b1 = m.refwrap_list(copy=False) + b2 = m.refwrap_list(copy=False) + assert [x.value for x in b1] == [1, 2] + assert [x.value for x in b2] == [1, 2] + assert b1[0] is b2[0] and b1[1] is b2[1] + + assert m.refwrap_iiw(IncType(5)) == 5 + assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10] + + +def test_complex_cast(): + """std::complex casts""" + assert m.complex_cast(1) == "1.0" + assert m.complex_cast(2j) == "(0.0, 2.0)" + + +def test_bool_caster(): + """Test bool caster implicit conversions.""" + convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert + + def require_implicit(v): + pytest.raises(TypeError, noconvert, v) + + def cant_convert(v): + pytest.raises(TypeError, convert, v) + + # straight up bool + assert convert(True) is True + assert convert(False) is False + assert noconvert(True) is True + assert noconvert(False) is False + + # None requires implicit conversion + require_implicit(None) + assert convert(None) is False + + class A(object): + def __init__(self, x): + self.x = x + + def __nonzero__(self): + return self.x + + def __bool__(self): + return self.x + + class B(object): + pass + + # Arbitrary objects are not accepted + cant_convert(object()) + cant_convert(B()) + + # Objects with __nonzero__ / __bool__ defined can be converted + require_implicit(A(True)) + assert convert(A(True)) is True + assert convert(A(False)) is False + + +@pytest.requires_numpy +def test_numpy_bool(): + import numpy as np + convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert + + def cant_convert(v): + pytest.raises(TypeError, convert, v) + + # np.bool_ is not considered implicit + assert convert(np.bool_(True)) is True + assert convert(np.bool_(False)) is False + assert noconvert(np.bool_(True)) is True + assert noconvert(np.bool_(False)) is False + cant_convert(np.zeros(2, dtype='int')) + + +def test_int_long(): + """In Python 2, a C++ int should return a Python int rather than long + if possible: longs are not always accepted where ints are used (such + as the argument to sys.exit()). A C++ long long is always a Python + long.""" + + import sys + must_be_long = type(getattr(sys, 'maxint', 1) + 1) + assert isinstance(m.int_cast(), int) + assert isinstance(m.long_cast(), int) + assert isinstance(m.longlong_cast(), must_be_long) + + +def test_void_caster_2(): + assert m.test_void_caster() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_call_policies.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_call_policies.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd24557834b9e40706be518d6eb9f0a774361581 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_call_policies.cpp @@ -0,0 +1,100 @@ +/* + tests/test_call_policies.cpp -- keep_alive and call_guard + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +struct CustomGuard { + static bool enabled; + + CustomGuard() { enabled = true; } + ~CustomGuard() { enabled = false; } + + static const char *report_status() { return enabled ? "guarded" : "unguarded"; } +}; +bool CustomGuard::enabled = false; + +struct DependentGuard { + static bool enabled; + + DependentGuard() { enabled = CustomGuard::enabled; } + ~DependentGuard() { enabled = false; } + + static const char *report_status() { return enabled ? "guarded" : "unguarded"; } +}; +bool DependentGuard::enabled = false; + +TEST_SUBMODULE(call_policies, m) { + // Parent/Child are used in: + // test_keep_alive_argument, test_keep_alive_return_value, test_alive_gc_derived, + // test_alive_gc_multi_derived, test_return_none, test_keep_alive_constructor + class Child { + public: + Child() { py::print("Allocating child."); } + Child(const Child &) = default; + Child(Child &&) = default; + ~Child() { py::print("Releasing child."); } + }; + py::class_(m, "Child") + .def(py::init<>()); + + class Parent { + public: + Parent() { py::print("Allocating parent."); } + ~Parent() { py::print("Releasing parent."); } + void addChild(Child *) { } + Child *returnChild() { return new Child(); } + Child *returnNullChild() { return nullptr; } + }; + py::class_(m, "Parent") + .def(py::init<>()) + .def(py::init([](Child *) { return new Parent(); }), py::keep_alive<1, 2>()) + .def("addChild", &Parent::addChild) + .def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>()) + .def("returnChild", &Parent::returnChild) + .def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>()) + .def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>()) + .def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>()); + +#if !defined(PYPY_VERSION) + // test_alive_gc + class ParentGC : public Parent { + public: + using Parent::Parent; + }; + py::class_(m, "ParentGC", py::dynamic_attr()) + .def(py::init<>()); +#endif + + // test_call_guard + m.def("unguarded_call", &CustomGuard::report_status); + m.def("guarded_call", &CustomGuard::report_status, py::call_guard()); + + m.def("multiple_guards_correct_order", []() { + return CustomGuard::report_status() + std::string(" & ") + DependentGuard::report_status(); + }, py::call_guard()); + + m.def("multiple_guards_wrong_order", []() { + return DependentGuard::report_status() + std::string(" & ") + CustomGuard::report_status(); + }, py::call_guard()); + +#if defined(WITH_THREAD) && !defined(PYPY_VERSION) + // `py::call_guard()` should work in PyPy as well, + // but it's unclear how to test it without `PyGILState_GetThisThreadState`. + auto report_gil_status = []() { + auto is_gil_held = false; + if (auto tstate = py::detail::get_thread_state_unchecked()) + is_gil_held = (tstate == PyGILState_GetThisThreadState()); + + return is_gil_held ? "GIL held" : "GIL released"; + }; + + m.def("with_gil", report_gil_status); + m.def("without_gil", report_gil_status, py::call_guard()); +#endif +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_call_policies.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_call_policies.py new file mode 100644 index 0000000000000000000000000000000000000000..7c835599c2d736440243c1834f00a01f03ec5f28 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_call_policies.py @@ -0,0 +1,187 @@ +import pytest +from pybind11_tests import call_policies as m +from pybind11_tests import ConstructorStats + + +def test_keep_alive_argument(capture): + n_inst = ConstructorStats.detail_reg_inst() + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.addChild(m.Child()) + assert ConstructorStats.detail_reg_inst() == n_inst + 1 + assert capture == """ + Allocating child. + Releasing child. + """ + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == "Releasing parent." + + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.addChildKeepAlive(m.Child()) + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + assert capture == "Allocating child." + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_keep_alive_return_value(capture): + n_inst = ConstructorStats.detail_reg_inst() + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.returnChild() + assert ConstructorStats.detail_reg_inst() == n_inst + 1 + assert capture == """ + Allocating child. + Releasing child. + """ + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == "Releasing parent." + + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.returnChildKeepAlive() + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + assert capture == "Allocating child." + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + """ + + +# https://bitbucket.org/pypy/pypy/issues/2447 +@pytest.unsupported_on_pypy +def test_alive_gc(capture): + n_inst = ConstructorStats.detail_reg_inst() + p = m.ParentGC() + p.addChildKeepAlive(m.Child()) + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + lst = [p] + lst.append(lst) # creates a circular reference + with capture: + del p, lst + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_alive_gc_derived(capture): + class Derived(m.Parent): + pass + + n_inst = ConstructorStats.detail_reg_inst() + p = Derived() + p.addChildKeepAlive(m.Child()) + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + lst = [p] + lst.append(lst) # creates a circular reference + with capture: + del p, lst + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_alive_gc_multi_derived(capture): + class Derived(m.Parent, m.Child): + def __init__(self): + m.Parent.__init__(self) + m.Child.__init__(self) + + n_inst = ConstructorStats.detail_reg_inst() + p = Derived() + p.addChildKeepAlive(m.Child()) + # +3 rather than +2 because Derived corresponds to two registered instances + assert ConstructorStats.detail_reg_inst() == n_inst + 3 + lst = [p] + lst.append(lst) # creates a circular reference + with capture: + del p, lst + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + Releasing child. + """ + + +def test_return_none(capture): + n_inst = ConstructorStats.detail_reg_inst() + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.returnNullChildKeepAliveChild() + assert ConstructorStats.detail_reg_inst() == n_inst + 1 + assert capture == "" + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == "Releasing parent." + + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.returnNullChildKeepAliveParent() + assert ConstructorStats.detail_reg_inst() == n_inst + 1 + assert capture == "" + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == "Releasing parent." + + +def test_keep_alive_constructor(capture): + n_inst = ConstructorStats.detail_reg_inst() + + with capture: + p = m.Parent(m.Child()) + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + assert capture == """ + Allocating child. + Allocating parent. + """ + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_call_guard(): + assert m.unguarded_call() == "unguarded" + assert m.guarded_call() == "guarded" + + assert m.multiple_guards_correct_order() == "guarded & guarded" + assert m.multiple_guards_wrong_order() == "unguarded & guarded" + + if hasattr(m, "with_gil"): + assert m.with_gil() == "GIL held" + assert m.without_gil() == "GIL released" diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_callbacks.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_callbacks.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71b88c44c7650a7e7b3f37cee19359e15bbb0270 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_callbacks.cpp @@ -0,0 +1,168 @@ +/* + tests/test_callbacks.cpp -- callbacks + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include +#include + + +int dummy_function(int i) { return i + 1; } + +TEST_SUBMODULE(callbacks, m) { + // test_callbacks, test_function_signatures + m.def("test_callback1", [](py::object func) { return func(); }); + m.def("test_callback2", [](py::object func) { return func("Hello", 'x', true, 5); }); + m.def("test_callback3", [](const std::function &func) { + return "func(43) = " + std::to_string(func(43)); }); + m.def("test_callback4", []() -> std::function { return [](int i) { return i+1; }; }); + m.def("test_callback5", []() { + return py::cpp_function([](int i) { return i+1; }, py::arg("number")); + }); + + // test_keyword_args_and_generalized_unpacking + m.def("test_tuple_unpacking", [](py::function f) { + auto t1 = py::make_tuple(2, 3); + auto t2 = py::make_tuple(5, 6); + return f("positional", 1, *t1, 4, *t2); + }); + + m.def("test_dict_unpacking", [](py::function f) { + auto d1 = py::dict("key"_a="value", "a"_a=1); + auto d2 = py::dict(); + auto d3 = py::dict("b"_a=2); + return f("positional", 1, **d1, **d2, **d3); + }); + + m.def("test_keyword_args", [](py::function f) { + return f("x"_a=10, "y"_a=20); + }); + + m.def("test_unpacking_and_keywords1", [](py::function f) { + auto args = py::make_tuple(2); + auto kwargs = py::dict("d"_a=4); + return f(1, *args, "c"_a=3, **kwargs); + }); + + m.def("test_unpacking_and_keywords2", [](py::function f) { + auto kwargs1 = py::dict("a"_a=1); + auto kwargs2 = py::dict("c"_a=3, "d"_a=4); + return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5, + "key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5); + }); + + m.def("test_unpacking_error1", [](py::function f) { + auto kwargs = py::dict("x"_a=3); + return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword + }); + + m.def("test_unpacking_error2", [](py::function f) { + auto kwargs = py::dict("x"_a=3); + return f(**kwargs, "x"_a=1); // duplicate keyword after ** + }); + + m.def("test_arg_conversion_error1", [](py::function f) { + f(234, UnregisteredType(), "kw"_a=567); + }); + + m.def("test_arg_conversion_error2", [](py::function f) { + f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567); + }); + + // test_lambda_closure_cleanup + struct Payload { + Payload() { print_default_created(this); } + ~Payload() { print_destroyed(this); } + Payload(const Payload &) { print_copy_created(this); } + Payload(Payload &&) { print_move_created(this); } + }; + // Export the payload constructor statistics for testing purposes: + m.def("payload_cstats", &ConstructorStats::get); + /* Test cleanup of lambda closure */ + m.def("test_cleanup", []() -> std::function { + Payload p; + + return [p]() { + /* p should be cleaned up when the returned function is garbage collected */ + (void) p; + }; + }); + + // test_cpp_function_roundtrip + /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */ + m.def("dummy_function", &dummy_function); + m.def("dummy_function2", [](int i, int j) { return i + j; }); + m.def("roundtrip", [](std::function f, bool expect_none = false) { + if (expect_none && f) + throw std::runtime_error("Expected None to be converted to empty std::function"); + return f; + }, py::arg("f"), py::arg("expect_none")=false); + m.def("test_dummy_function", [](const std::function &f) -> std::string { + using fn_type = int (*)(int); + auto result = f.target(); + if (!result) { + auto r = f(1); + return "can't convert to function pointer: eval(1) = " + std::to_string(r); + } else if (*result == dummy_function) { + auto r = (*result)(1); + return "matches dummy_function: eval(1) = " + std::to_string(r); + } else { + return "argument does NOT match dummy_function. This should never happen!"; + } + }); + + class AbstractBase { public: virtual unsigned int func() = 0; }; + m.def("func_accepting_func_accepting_base", [](std::function) { }); + + struct MovableObject { + bool valid = true; + + MovableObject() = default; + MovableObject(const MovableObject &) = default; + MovableObject &operator=(const MovableObject &) = default; + MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; } + MovableObject &operator=(MovableObject &&o) { + valid = o.valid; + o.valid = false; + return *this; + } + }; + py::class_(m, "MovableObject"); + + // test_movable_object + m.def("callback_with_movable", [](std::function f) { + auto x = MovableObject(); + f(x); // lvalue reference shouldn't move out object + return x.valid; // must still return `true` + }); + + // test_bound_method_callback + struct CppBoundMethodTest {}; + py::class_(m, "CppBoundMethodTest") + .def(py::init<>()) + .def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; }); + + // test async Python callbacks + using callback_f = std::function; + m.def("test_async_callback", [](callback_f f, py::list work) { + // make detached thread that calls `f` with piece of work after a little delay + auto start_f = [f](int j) { + auto invoke_f = [f, j] { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + f(j); + }; + auto t = std::thread(std::move(invoke_f)); + t.detach(); + }; + + // spawn worker threads + for (auto i : work) + start_f(py::cast(i)); + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_callbacks.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_callbacks.py new file mode 100644 index 0000000000000000000000000000000000000000..6439c8e72a1e0f644624b7d1a0f96138d32402ab --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_callbacks.py @@ -0,0 +1,136 @@ +import pytest +from pybind11_tests import callbacks as m +from threading import Thread + + +def test_callbacks(): + from functools import partial + + def func1(): + return "func1" + + def func2(a, b, c, d): + return "func2", a, b, c, d + + def func3(a): + return "func3({})".format(a) + + assert m.test_callback1(func1) == "func1" + assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5) + assert m.test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4) + assert m.test_callback1(partial(func3, "partial")) == "func3(partial)" + assert m.test_callback3(lambda i: i + 1) == "func(43) = 44" + + f = m.test_callback4() + assert f(43) == 44 + f = m.test_callback5() + assert f(number=43) == 44 + + +def test_bound_method_callback(): + # Bound Python method: + class MyClass: + def double(self, val): + return 2 * val + + z = MyClass() + assert m.test_callback3(z.double) == "func(43) = 86" + + z = m.CppBoundMethodTest() + assert m.test_callback3(z.triple) == "func(43) = 129" + + +def test_keyword_args_and_generalized_unpacking(): + + def f(*args, **kwargs): + return args, kwargs + + assert m.test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {}) + assert m.test_dict_unpacking(f) == (("positional", 1), {"key": "value", "a": 1, "b": 2}) + assert m.test_keyword_args(f) == ((), {"x": 10, "y": 20}) + assert m.test_unpacking_and_keywords1(f) == ((1, 2), {"c": 3, "d": 4}) + assert m.test_unpacking_and_keywords2(f) == ( + ("positional", 1, 2, 3, 4, 5), + {"key": "value", "a": 1, "b": 2, "c": 3, "d": 4, "e": 5} + ) + + with pytest.raises(TypeError) as excinfo: + m.test_unpacking_error1(f) + assert "Got multiple values for keyword argument" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + m.test_unpacking_error2(f) + assert "Got multiple values for keyword argument" in str(excinfo.value) + + with pytest.raises(RuntimeError) as excinfo: + m.test_arg_conversion_error1(f) + assert "Unable to convert call argument" in str(excinfo.value) + + with pytest.raises(RuntimeError) as excinfo: + m.test_arg_conversion_error2(f) + assert "Unable to convert call argument" in str(excinfo.value) + + +def test_lambda_closure_cleanup(): + m.test_cleanup() + cstats = m.payload_cstats() + assert cstats.alive() == 0 + assert cstats.copy_constructions == 1 + assert cstats.move_constructions >= 1 + + +def test_cpp_function_roundtrip(): + """Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer""" + + assert m.test_dummy_function(m.dummy_function) == "matches dummy_function: eval(1) = 2" + assert (m.test_dummy_function(m.roundtrip(m.dummy_function)) == + "matches dummy_function: eval(1) = 2") + assert m.roundtrip(None, expect_none=True) is None + assert (m.test_dummy_function(lambda x: x + 2) == + "can't convert to function pointer: eval(1) = 3") + + with pytest.raises(TypeError) as excinfo: + m.test_dummy_function(m.dummy_function2) + assert "incompatible function arguments" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + m.test_dummy_function(lambda x, y: x + y) + assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument", + "takes exactly 2 arguments")) + + +def test_function_signatures(doc): + assert doc(m.test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str" + assert doc(m.test_callback4) == "test_callback4() -> Callable[[int], int]" + + +def test_movable_object(): + assert m.callback_with_movable(lambda _: None) is True + + +def test_async_callbacks(): + # serves as state for async callback + class Item: + def __init__(self, value): + self.value = value + + res = [] + + # generate stateful lambda that will store result in `res` + def gen_f(): + s = Item(3) + return lambda j: res.append(s.value + j) + + # do some work async + work = [1, 2, 3, 4] + m.test_async_callback(gen_f(), work) + # wait until work is done + from time import sleep + sleep(0.5) + assert sum(res) == sum([x + 3 for x in work]) + + +def test_async_async_callbacks(): + t = Thread(target=test_async_callbacks) + t.start() + t.join() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_chrono.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_chrono.cpp new file mode 100644 index 0000000000000000000000000000000000000000..899d08d8d8542cad92a58bf32b04ab3b74aebb75 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_chrono.cpp @@ -0,0 +1,55 @@ +/* + tests/test_chrono.cpp -- test conversions to/from std::chrono types + + Copyright (c) 2016 Trent Houliston and + Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include + +TEST_SUBMODULE(chrono, m) { + using system_time = std::chrono::system_clock::time_point; + using steady_time = std::chrono::steady_clock::time_point; + + using timespan = std::chrono::duration; + using timestamp = std::chrono::time_point; + + // test_chrono_system_clock + // Return the current time off the wall clock + m.def("test_chrono1", []() { return std::chrono::system_clock::now(); }); + + // test_chrono_system_clock_roundtrip + // Round trip the passed in system clock time + m.def("test_chrono2", [](system_time t) { return t; }); + + // test_chrono_duration_roundtrip + // Round trip the passed in duration + m.def("test_chrono3", [](std::chrono::system_clock::duration d) { return d; }); + + // test_chrono_duration_subtraction_equivalence + // Difference between two passed in time_points + m.def("test_chrono4", [](system_time a, system_time b) { return a - b; }); + + // test_chrono_steady_clock + // Return the current time off the steady_clock + m.def("test_chrono5", []() { return std::chrono::steady_clock::now(); }); + + // test_chrono_steady_clock_roundtrip + // Round trip a steady clock timepoint + m.def("test_chrono6", [](steady_time t) { return t; }); + + // test_floating_point_duration + // Roundtrip a duration in microseconds from a float argument + m.def("test_chrono7", [](std::chrono::microseconds t) { return t; }); + // Float durations (issue #719) + m.def("test_chrono_float_diff", [](std::chrono::duration a, std::chrono::duration b) { + return a - b; }); + + m.def("test_nano_timepoint", [](timestamp start, timespan delta) -> timestamp { + return start + delta; + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_chrono.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_chrono.py new file mode 100644 index 0000000000000000000000000000000000000000..55c95440655145f9b3c0c77d9e2d878a29f7fb45 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_chrono.py @@ -0,0 +1,176 @@ +from pybind11_tests import chrono as m +import datetime + + +def test_chrono_system_clock(): + + # Get the time from both c++ and datetime + date1 = m.test_chrono1() + date2 = datetime.datetime.today() + + # The returned value should be a datetime + assert isinstance(date1, datetime.datetime) + + # The numbers should vary by a very small amount (time it took to execute) + diff = abs(date1 - date2) + + # There should never be a days/seconds difference + assert diff.days == 0 + assert diff.seconds == 0 + + # We test that no more than about 0.5 seconds passes here + # This makes sure that the dates created are very close to the same + # but if the testing system is incredibly overloaded this should still pass + assert diff.microseconds < 500000 + + +def test_chrono_system_clock_roundtrip(): + date1 = datetime.datetime.today() + + # Roundtrip the time + date2 = m.test_chrono2(date1) + + # The returned value should be a datetime + assert isinstance(date2, datetime.datetime) + + # They should be identical (no information lost on roundtrip) + diff = abs(date1 - date2) + assert diff.days == 0 + assert diff.seconds == 0 + assert diff.microseconds == 0 + + +def test_chrono_system_clock_roundtrip_date(): + date1 = datetime.date.today() + + # Roundtrip the time + datetime2 = m.test_chrono2(date1) + date2 = datetime2.date() + time2 = datetime2.time() + + # The returned value should be a datetime + assert isinstance(datetime2, datetime.datetime) + assert isinstance(date2, datetime.date) + assert isinstance(time2, datetime.time) + + # They should be identical (no information lost on roundtrip) + diff = abs(date1 - date2) + assert diff.days == 0 + assert diff.seconds == 0 + assert diff.microseconds == 0 + + # Year, Month & Day should be the same after the round trip + assert date1.year == date2.year + assert date1.month == date2.month + assert date1.day == date2.day + + # There should be no time information + assert time2.hour == 0 + assert time2.minute == 0 + assert time2.second == 0 + assert time2.microsecond == 0 + + +def test_chrono_system_clock_roundtrip_time(): + time1 = datetime.datetime.today().time() + + # Roundtrip the time + datetime2 = m.test_chrono2(time1) + date2 = datetime2.date() + time2 = datetime2.time() + + # The returned value should be a datetime + assert isinstance(datetime2, datetime.datetime) + assert isinstance(date2, datetime.date) + assert isinstance(time2, datetime.time) + + # Hour, Minute, Second & Microsecond should be the same after the round trip + assert time1.hour == time2.hour + assert time1.minute == time2.minute + assert time1.second == time2.second + assert time1.microsecond == time2.microsecond + + # There should be no date information (i.e. date = python base date) + assert date2.year == 1970 + assert date2.month == 1 + assert date2.day == 1 + + +def test_chrono_duration_roundtrip(): + + # Get the difference between two times (a timedelta) + date1 = datetime.datetime.today() + date2 = datetime.datetime.today() + diff = date2 - date1 + + # Make sure this is a timedelta + assert isinstance(diff, datetime.timedelta) + + cpp_diff = m.test_chrono3(diff) + + assert cpp_diff.days == diff.days + assert cpp_diff.seconds == diff.seconds + assert cpp_diff.microseconds == diff.microseconds + + +def test_chrono_duration_subtraction_equivalence(): + + date1 = datetime.datetime.today() + date2 = datetime.datetime.today() + + diff = date2 - date1 + cpp_diff = m.test_chrono4(date2, date1) + + assert cpp_diff.days == diff.days + assert cpp_diff.seconds == diff.seconds + assert cpp_diff.microseconds == diff.microseconds + + +def test_chrono_duration_subtraction_equivalence_date(): + + date1 = datetime.date.today() + date2 = datetime.date.today() + + diff = date2 - date1 + cpp_diff = m.test_chrono4(date2, date1) + + assert cpp_diff.days == diff.days + assert cpp_diff.seconds == diff.seconds + assert cpp_diff.microseconds == diff.microseconds + + +def test_chrono_steady_clock(): + time1 = m.test_chrono5() + assert isinstance(time1, datetime.timedelta) + + +def test_chrono_steady_clock_roundtrip(): + time1 = datetime.timedelta(days=10, seconds=10, microseconds=100) + time2 = m.test_chrono6(time1) + + assert isinstance(time2, datetime.timedelta) + + # They should be identical (no information lost on roundtrip) + assert time1.days == time2.days + assert time1.seconds == time2.seconds + assert time1.microseconds == time2.microseconds + + +def test_floating_point_duration(): + # Test using a floating point number in seconds + time = m.test_chrono7(35.525123) + + assert isinstance(time, datetime.timedelta) + + assert time.seconds == 35 + assert 525122 <= time.microseconds <= 525123 + + diff = m.test_chrono_float_diff(43.789012, 1.123456) + assert diff.seconds == 42 + assert 665556 <= diff.microseconds <= 665557 + + +def test_nano_timepoint(): + time = datetime.datetime.now() + time1 = m.test_nano_timepoint(time, datetime.timedelta(seconds=60)) + assert(time1 == time + datetime.timedelta(seconds=60)) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_class.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_class.cpp new file mode 100644 index 0000000000000000000000000000000000000000..499d0cc511fdb7b644e75635e874fcb20e6dae78 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_class.cpp @@ -0,0 +1,422 @@ +/* + tests/test_class.cpp -- test py::class_ definitions and basic functionality + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include "local_bindings.h" +#include + +#if defined(_MSC_VER) +# pragma warning(disable: 4324) // warning C4324: structure was padded due to alignment specifier +#endif + +// test_brace_initialization +struct NoBraceInitialization { + NoBraceInitialization(std::vector v) : vec{std::move(v)} {} + template + NoBraceInitialization(std::initializer_list l) : vec(l) {} + + std::vector vec; +}; + +TEST_SUBMODULE(class_, m) { + // test_instance + struct NoConstructor { + NoConstructor() = default; + NoConstructor(const NoConstructor &) = default; + NoConstructor(NoConstructor &&) = default; + static NoConstructor *new_instance() { + auto *ptr = new NoConstructor(); + print_created(ptr, "via new_instance"); + return ptr; + } + ~NoConstructor() { print_destroyed(this); } + }; + + py::class_(m, "NoConstructor") + .def_static("new_instance", &NoConstructor::new_instance, "Return an instance"); + + // test_inheritance + class Pet { + public: + Pet(const std::string &name, const std::string &species) + : m_name(name), m_species(species) {} + std::string name() const { return m_name; } + std::string species() const { return m_species; } + private: + std::string m_name; + std::string m_species; + }; + + class Dog : public Pet { + public: + Dog(const std::string &name) : Pet(name, "dog") {} + std::string bark() const { return "Woof!"; } + }; + + class Rabbit : public Pet { + public: + Rabbit(const std::string &name) : Pet(name, "parrot") {} + }; + + class Hamster : public Pet { + public: + Hamster(const std::string &name) : Pet(name, "rodent") {} + }; + + class Chimera : public Pet { + Chimera() : Pet("Kimmy", "chimera") {} + }; + + py::class_ pet_class(m, "Pet"); + pet_class + .def(py::init()) + .def("name", &Pet::name) + .def("species", &Pet::species); + + /* One way of declaring a subclass relationship: reference parent's class_ object */ + py::class_(m, "Dog", pet_class) + .def(py::init()); + + /* Another way of declaring a subclass relationship: reference parent's C++ type */ + py::class_(m, "Rabbit") + .def(py::init()); + + /* And another: list parent in class template arguments */ + py::class_(m, "Hamster") + .def(py::init()); + + /* Constructors are not inherited by default */ + py::class_(m, "Chimera"); + + m.def("pet_name_species", [](const Pet &pet) { return pet.name() + " is a " + pet.species(); }); + m.def("dog_bark", [](const Dog &dog) { return dog.bark(); }); + + // test_automatic_upcasting + struct BaseClass { + BaseClass() = default; + BaseClass(const BaseClass &) = default; + BaseClass(BaseClass &&) = default; + virtual ~BaseClass() {} + }; + struct DerivedClass1 : BaseClass { }; + struct DerivedClass2 : BaseClass { }; + + py::class_(m, "BaseClass").def(py::init<>()); + py::class_(m, "DerivedClass1").def(py::init<>()); + py::class_(m, "DerivedClass2").def(py::init<>()); + + m.def("return_class_1", []() -> BaseClass* { return new DerivedClass1(); }); + m.def("return_class_2", []() -> BaseClass* { return new DerivedClass2(); }); + m.def("return_class_n", [](int n) -> BaseClass* { + if (n == 1) return new DerivedClass1(); + if (n == 2) return new DerivedClass2(); + return new BaseClass(); + }); + m.def("return_none", []() -> BaseClass* { return nullptr; }); + + // test_isinstance + m.def("check_instances", [](py::list l) { + return py::make_tuple( + py::isinstance(l[0]), + py::isinstance(l[1]), + py::isinstance(l[2]), + py::isinstance(l[3]), + py::isinstance(l[4]), + py::isinstance(l[5]), + py::isinstance(l[6]) + ); + }); + + // test_mismatched_holder + struct MismatchBase1 { }; + struct MismatchDerived1 : MismatchBase1 { }; + + struct MismatchBase2 { }; + struct MismatchDerived2 : MismatchBase2 { }; + + m.def("mismatched_holder_1", []() { + auto mod = py::module::import("__main__"); + py::class_>(mod, "MismatchBase1"); + py::class_(mod, "MismatchDerived1"); + }); + m.def("mismatched_holder_2", []() { + auto mod = py::module::import("__main__"); + py::class_(mod, "MismatchBase2"); + py::class_, + MismatchBase2>(mod, "MismatchDerived2"); + }); + + // test_override_static + // #511: problem with inheritance + overwritten def_static + struct MyBase { + static std::unique_ptr make() { + return std::unique_ptr(new MyBase()); + } + }; + + struct MyDerived : MyBase { + static std::unique_ptr make() { + return std::unique_ptr(new MyDerived()); + } + }; + + py::class_(m, "MyBase") + .def_static("make", &MyBase::make); + + py::class_(m, "MyDerived") + .def_static("make", &MyDerived::make) + .def_static("make2", &MyDerived::make); + + // test_implicit_conversion_life_support + struct ConvertibleFromUserType { + int i; + + ConvertibleFromUserType(UserType u) : i(u.value()) { } + }; + + py::class_(m, "AcceptsUserType") + .def(py::init()); + py::implicitly_convertible(); + + m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; }); + m.def("implicitly_convert_variable", [](py::object o) { + // `o` is `UserType` and `r` is a reference to a temporary created by implicit + // conversion. This is valid when called inside a bound function because the temp + // object is attached to the same life support system as the arguments. + const auto &r = o.cast(); + return r.i; + }); + m.add_object("implicitly_convert_variable_fail", [&] { + auto f = [](PyObject *, PyObject *args) -> PyObject * { + auto o = py::reinterpret_borrow(args)[0]; + try { // It should fail here because there is no life support. + o.cast(); + } catch (const py::cast_error &e) { + return py::str(e.what()).release().ptr(); + } + return py::str().release().ptr(); + }; + + auto def = new PyMethodDef{"f", f, METH_VARARGS, nullptr}; + return py::reinterpret_steal(PyCFunction_NewEx(def, nullptr, m.ptr())); + }()); + + // test_operator_new_delete + struct HasOpNewDel { + std::uint64_t i; + static void *operator new(size_t s) { py::print("A new", s); return ::operator new(s); } + static void *operator new(size_t s, void *ptr) { py::print("A placement-new", s); return ptr; } + static void operator delete(void *p) { py::print("A delete"); return ::operator delete(p); } + }; + struct HasOpNewDelSize { + std::uint32_t i; + static void *operator new(size_t s) { py::print("B new", s); return ::operator new(s); } + static void *operator new(size_t s, void *ptr) { py::print("B placement-new", s); return ptr; } + static void operator delete(void *p, size_t s) { py::print("B delete", s); return ::operator delete(p); } + }; + struct AliasedHasOpNewDelSize { + std::uint64_t i; + static void *operator new(size_t s) { py::print("C new", s); return ::operator new(s); } + static void *operator new(size_t s, void *ptr) { py::print("C placement-new", s); return ptr; } + static void operator delete(void *p, size_t s) { py::print("C delete", s); return ::operator delete(p); } + virtual ~AliasedHasOpNewDelSize() = default; + }; + struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize { + PyAliasedHasOpNewDelSize() = default; + PyAliasedHasOpNewDelSize(int) { } + std::uint64_t j; + }; + struct HasOpNewDelBoth { + std::uint32_t i[8]; + static void *operator new(size_t s) { py::print("D new", s); return ::operator new(s); } + static void *operator new(size_t s, void *ptr) { py::print("D placement-new", s); return ptr; } + static void operator delete(void *p) { py::print("D delete"); return ::operator delete(p); } + static void operator delete(void *p, size_t s) { py::print("D wrong delete", s); return ::operator delete(p); } + }; + py::class_(m, "HasOpNewDel").def(py::init<>()); + py::class_(m, "HasOpNewDelSize").def(py::init<>()); + py::class_(m, "HasOpNewDelBoth").def(py::init<>()); + py::class_ aliased(m, "AliasedHasOpNewDelSize"); + aliased.def(py::init<>()); + aliased.attr("size_noalias") = py::int_(sizeof(AliasedHasOpNewDelSize)); + aliased.attr("size_alias") = py::int_(sizeof(PyAliasedHasOpNewDelSize)); + + // This test is actually part of test_local_bindings (test_duplicate_local), but we need a + // definition in a different compilation unit within the same module: + bind_local(m, "LocalExternal", py::module_local()); + + // test_bind_protected_functions + class ProtectedA { + protected: + int foo() const { return value; } + + private: + int value = 42; + }; + + class PublicistA : public ProtectedA { + public: + using ProtectedA::foo; + }; + + py::class_(m, "ProtectedA") + .def(py::init<>()) +#if !defined(_MSC_VER) || _MSC_VER >= 1910 + .def("foo", &PublicistA::foo); +#else + .def("foo", static_cast(&PublicistA::foo)); +#endif + + class ProtectedB { + public: + virtual ~ProtectedB() = default; + + protected: + virtual int foo() const { return value; } + + private: + int value = 42; + }; + + class TrampolineB : public ProtectedB { + public: + int foo() const override { PYBIND11_OVERLOAD(int, ProtectedB, foo, ); } + }; + + class PublicistB : public ProtectedB { + public: + using ProtectedB::foo; + }; + + py::class_(m, "ProtectedB") + .def(py::init<>()) +#if !defined(_MSC_VER) || _MSC_VER >= 1910 + .def("foo", &PublicistB::foo); +#else + .def("foo", static_cast(&PublicistB::foo)); +#endif + + // test_brace_initialization + struct BraceInitialization { + int field1; + std::string field2; + }; + + py::class_(m, "BraceInitialization") + .def(py::init()) + .def_readwrite("field1", &BraceInitialization::field1) + .def_readwrite("field2", &BraceInitialization::field2); + // We *don't* want to construct using braces when the given constructor argument maps to a + // constructor, because brace initialization could go to the wrong place (in particular when + // there is also an `initializer_list`-accept constructor): + py::class_(m, "NoBraceInitialization") + .def(py::init>()) + .def_readonly("vec", &NoBraceInitialization::vec); + + // test_reentrant_implicit_conversion_failure + // #1035: issue with runaway reentrant implicit conversion + struct BogusImplicitConversion { + BogusImplicitConversion(const BogusImplicitConversion &) { } + }; + + py::class_(m, "BogusImplicitConversion") + .def(py::init()); + + py::implicitly_convertible(); + + // test_qualname + // #1166: nested class docstring doesn't show nested name + // Also related: tests that __qualname__ is set properly + struct NestBase {}; + struct Nested {}; + py::class_ base(m, "NestBase"); + base.def(py::init<>()); + py::class_(base, "Nested") + .def(py::init<>()) + .def("fn", [](Nested &, int, NestBase &, Nested &) {}) + .def("fa", [](Nested &, int, NestBase &, Nested &) {}, + "a"_a, "b"_a, "c"_a); + base.def("g", [](NestBase &, Nested &) {}); + base.def("h", []() { return NestBase(); }); + + // test_error_after_conversion + // The second-pass path through dispatcher() previously didn't + // remember which overload was used, and would crash trying to + // generate a useful error message + + struct NotRegistered {}; + struct StringWrapper { std::string str; }; + m.def("test_error_after_conversions", [](int) {}); + m.def("test_error_after_conversions", + [](StringWrapper) -> NotRegistered { return {}; }); + py::class_(m, "StringWrapper").def(py::init()); + py::implicitly_convertible(); + + #if defined(PYBIND11_CPP17) + struct alignas(1024) Aligned { + std::uintptr_t ptr() const { return (uintptr_t) this; } + }; + py::class_(m, "Aligned") + .def(py::init<>()) + .def("ptr", &Aligned::ptr); + #endif +} + +template class BreaksBase { public: virtual ~BreaksBase() = default; }; +template class BreaksTramp : public BreaksBase {}; +// These should all compile just fine: +typedef py::class_, std::unique_ptr>, BreaksTramp<1>> DoesntBreak1; +typedef py::class_, BreaksTramp<2>, std::unique_ptr>> DoesntBreak2; +typedef py::class_, std::unique_ptr>> DoesntBreak3; +typedef py::class_, BreaksTramp<4>> DoesntBreak4; +typedef py::class_> DoesntBreak5; +typedef py::class_, std::shared_ptr>, BreaksTramp<6>> DoesntBreak6; +typedef py::class_, BreaksTramp<7>, std::shared_ptr>> DoesntBreak7; +typedef py::class_, std::shared_ptr>> DoesntBreak8; +#define CHECK_BASE(N) static_assert(std::is_same>::value, \ + "DoesntBreak" #N " has wrong type!") +CHECK_BASE(1); CHECK_BASE(2); CHECK_BASE(3); CHECK_BASE(4); CHECK_BASE(5); CHECK_BASE(6); CHECK_BASE(7); CHECK_BASE(8); +#define CHECK_ALIAS(N) static_assert(DoesntBreak##N::has_alias && std::is_same>::value, \ + "DoesntBreak" #N " has wrong type_alias!") +#define CHECK_NOALIAS(N) static_assert(!DoesntBreak##N::has_alias && std::is_void::value, \ + "DoesntBreak" #N " has type alias, but shouldn't!") +CHECK_ALIAS(1); CHECK_ALIAS(2); CHECK_NOALIAS(3); CHECK_ALIAS(4); CHECK_NOALIAS(5); CHECK_ALIAS(6); CHECK_ALIAS(7); CHECK_NOALIAS(8); +#define CHECK_HOLDER(N, TYPE) static_assert(std::is_same>>::value, \ + "DoesntBreak" #N " has wrong holder_type!") +CHECK_HOLDER(1, unique); CHECK_HOLDER(2, unique); CHECK_HOLDER(3, unique); CHECK_HOLDER(4, unique); CHECK_HOLDER(5, unique); +CHECK_HOLDER(6, shared); CHECK_HOLDER(7, shared); CHECK_HOLDER(8, shared); + +// There's no nice way to test that these fail because they fail to compile; leave them here, +// though, so that they can be manually tested by uncommenting them (and seeing that compilation +// failures occurs). + +// We have to actually look into the type: the typedef alone isn't enough to instantiate the type: +#define CHECK_BROKEN(N) static_assert(std::is_same>::value, \ + "Breaks1 has wrong type!"); + +//// Two holder classes: +//typedef py::class_, std::unique_ptr>, std::unique_ptr>> Breaks1; +//CHECK_BROKEN(1); +//// Two aliases: +//typedef py::class_, BreaksTramp<-2>, BreaksTramp<-2>> Breaks2; +//CHECK_BROKEN(2); +//// Holder + 2 aliases +//typedef py::class_, std::unique_ptr>, BreaksTramp<-3>, BreaksTramp<-3>> Breaks3; +//CHECK_BROKEN(3); +//// Alias + 2 holders +//typedef py::class_, std::unique_ptr>, BreaksTramp<-4>, std::shared_ptr>> Breaks4; +//CHECK_BROKEN(4); +//// Invalid option (not a subclass or holder) +//typedef py::class_, BreaksTramp<-4>> Breaks5; +//CHECK_BROKEN(5); +//// Invalid option: multiple inheritance not supported: +//template <> struct BreaksBase<-8> : BreaksBase<-6>, BreaksBase<-7> {}; +//typedef py::class_, BreaksBase<-6>, BreaksBase<-7>> Breaks8; +//CHECK_BROKEN(8); diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_class.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_class.py new file mode 100644 index 0000000000000000000000000000000000000000..ed63ca8538bf639ddfee1d418e3a804f44027b76 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_class.py @@ -0,0 +1,281 @@ +import pytest + +from pybind11_tests import class_ as m +from pybind11_tests import UserType, ConstructorStats + + +def test_repr(): + # In Python 3.3+, repr() accesses __qualname__ + assert "pybind11_type" in repr(type(UserType)) + assert "UserType" in repr(UserType) + + +def test_instance(msg): + with pytest.raises(TypeError) as excinfo: + m.NoConstructor() + assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!" + + instance = m.NoConstructor.new_instance() + + cstats = ConstructorStats.get(m.NoConstructor) + assert cstats.alive() == 1 + del instance + assert cstats.alive() == 0 + + +def test_docstrings(doc): + assert doc(UserType) == "A `py::class_` type for testing" + assert UserType.__name__ == "UserType" + assert UserType.__module__ == "pybind11_tests" + assert UserType.get_value.__name__ == "get_value" + assert UserType.get_value.__module__ == "pybind11_tests" + + assert doc(UserType.get_value) == """ + get_value(self: m.UserType) -> int + + Get value using a method + """ + assert doc(UserType.value) == "Get/set value using a property" + + assert doc(m.NoConstructor.new_instance) == """ + new_instance() -> m.class_.NoConstructor + + Return an instance + """ + + +def test_qualname(doc): + """Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we + backport the attribute) and that generated docstrings properly use it and the module name""" + assert m.NestBase.__qualname__ == "NestBase" + assert m.NestBase.Nested.__qualname__ == "NestBase.Nested" + + assert doc(m.NestBase.__init__) == """ + __init__(self: m.class_.NestBase) -> None + """ + assert doc(m.NestBase.g) == """ + g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None + """ + assert doc(m.NestBase.Nested.__init__) == """ + __init__(self: m.class_.NestBase.Nested) -> None + """ + assert doc(m.NestBase.Nested.fn) == """ + fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None + """ # noqa: E501 line too long + assert doc(m.NestBase.Nested.fa) == """ + fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None + """ # noqa: E501 line too long + assert m.NestBase.__module__ == "pybind11_tests.class_" + assert m.NestBase.Nested.__module__ == "pybind11_tests.class_" + + +def test_inheritance(msg): + roger = m.Rabbit('Rabbit') + assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot" + assert m.pet_name_species(roger) == "Rabbit is a parrot" + + polly = m.Pet('Polly', 'parrot') + assert polly.name() + " is a " + polly.species() == "Polly is a parrot" + assert m.pet_name_species(polly) == "Polly is a parrot" + + molly = m.Dog('Molly') + assert molly.name() + " is a " + molly.species() == "Molly is a dog" + assert m.pet_name_species(molly) == "Molly is a dog" + + fred = m.Hamster('Fred') + assert fred.name() + " is a " + fred.species() == "Fred is a rodent" + + assert m.dog_bark(molly) == "Woof!" + + with pytest.raises(TypeError) as excinfo: + m.dog_bark(polly) + assert msg(excinfo.value) == """ + dog_bark(): incompatible function arguments. The following argument types are supported: + 1. (arg0: m.class_.Dog) -> str + + Invoked with: + """ + + with pytest.raises(TypeError) as excinfo: + m.Chimera("lion", "goat") + assert "No constructor defined!" in str(excinfo.value) + + +def test_automatic_upcasting(): + assert type(m.return_class_1()).__name__ == "DerivedClass1" + assert type(m.return_class_2()).__name__ == "DerivedClass2" + assert type(m.return_none()).__name__ == "NoneType" + # Repeat these a few times in a random order to ensure no invalid caching is applied + assert type(m.return_class_n(1)).__name__ == "DerivedClass1" + assert type(m.return_class_n(2)).__name__ == "DerivedClass2" + assert type(m.return_class_n(0)).__name__ == "BaseClass" + assert type(m.return_class_n(2)).__name__ == "DerivedClass2" + assert type(m.return_class_n(2)).__name__ == "DerivedClass2" + assert type(m.return_class_n(0)).__name__ == "BaseClass" + assert type(m.return_class_n(1)).__name__ == "DerivedClass1" + + +def test_isinstance(): + objects = [tuple(), dict(), m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4 + expected = (True, True, True, True, True, False, False) + assert m.check_instances(objects) == expected + + +def test_mismatched_holder(): + import re + + with pytest.raises(RuntimeError) as excinfo: + m.mismatched_holder_1() + assert re.match('generic_type: type ".*MismatchDerived1" does not have a non-default ' + 'holder type while its base ".*MismatchBase1" does', str(excinfo.value)) + + with pytest.raises(RuntimeError) as excinfo: + m.mismatched_holder_2() + assert re.match('generic_type: type ".*MismatchDerived2" has a non-default holder type ' + 'while its base ".*MismatchBase2" does not', str(excinfo.value)) + + +def test_override_static(): + """#511: problem with inheritance + overwritten def_static""" + b = m.MyBase.make() + d1 = m.MyDerived.make2() + d2 = m.MyDerived.make() + + assert isinstance(b, m.MyBase) + assert isinstance(d1, m.MyDerived) + assert isinstance(d2, m.MyDerived) + + +def test_implicit_conversion_life_support(): + """Ensure the lifetime of temporary objects created for implicit conversions""" + assert m.implicitly_convert_argument(UserType(5)) == 5 + assert m.implicitly_convert_variable(UserType(5)) == 5 + + assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5)) + + +def test_operator_new_delete(capture): + """Tests that class-specific operator new/delete functions are invoked""" + + class SubAliased(m.AliasedHasOpNewDelSize): + pass + + with capture: + a = m.HasOpNewDel() + b = m.HasOpNewDelSize() + d = m.HasOpNewDelBoth() + assert capture == """ + A new 8 + B new 4 + D new 32 + """ + sz_alias = str(m.AliasedHasOpNewDelSize.size_alias) + sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias) + with capture: + c = m.AliasedHasOpNewDelSize() + c2 = SubAliased() + assert capture == ( + "C new " + sz_noalias + "\n" + + "C new " + sz_alias + "\n" + ) + + with capture: + del a + pytest.gc_collect() + del b + pytest.gc_collect() + del d + pytest.gc_collect() + assert capture == """ + A delete + B delete 4 + D delete + """ + + with capture: + del c + pytest.gc_collect() + del c2 + pytest.gc_collect() + assert capture == ( + "C delete " + sz_noalias + "\n" + + "C delete " + sz_alias + "\n" + ) + + +def test_bind_protected_functions(): + """Expose protected member functions to Python using a helper class""" + a = m.ProtectedA() + assert a.foo() == 42 + + b = m.ProtectedB() + assert b.foo() == 42 + + class C(m.ProtectedB): + def __init__(self): + m.ProtectedB.__init__(self) + + def foo(self): + return 0 + + c = C() + assert c.foo() == 0 + + +def test_brace_initialization(): + """ Tests that simple POD classes can be constructed using C++11 brace initialization """ + a = m.BraceInitialization(123, "test") + assert a.field1 == 123 + assert a.field2 == "test" + + # Tests that a non-simple class doesn't get brace initialization (if the + # class defines an initializer_list constructor, in particular, it would + # win over the expected constructor). + b = m.NoBraceInitialization([123, 456]) + assert b.vec == [123, 456] + + +@pytest.unsupported_on_pypy +def test_class_refcount(): + """Instances must correctly increase/decrease the reference count of their types (#1029)""" + from sys import getrefcount + + class PyDog(m.Dog): + pass + + for cls in m.Dog, PyDog: + refcount_1 = getrefcount(cls) + molly = [cls("Molly") for _ in range(10)] + refcount_2 = getrefcount(cls) + + del molly + pytest.gc_collect() + refcount_3 = getrefcount(cls) + + assert refcount_1 == refcount_3 + assert refcount_2 > refcount_1 + + +def test_reentrant_implicit_conversion_failure(msg): + # ensure that there is no runaway reentrant implicit conversion (#1035) + with pytest.raises(TypeError) as excinfo: + m.BogusImplicitConversion(0) + assert msg(excinfo.value) == ''' + __init__(): incompatible constructor arguments. The following argument types are supported: + 1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion) + + Invoked with: 0 + ''' + + +def test_error_after_conversions(): + with pytest.raises(TypeError) as exc_info: + m.test_error_after_conversions("hello") + assert str(exc_info.value).startswith( + "Unable to convert function return value to a Python type!") + + +def test_aligned(): + if hasattr(m, "Aligned"): + p = m.Aligned().ptr() + assert p % 1024 == 0 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..c9b5fcb2e72ab3cb87eff93e8a7ac3dd7f67000c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/CMakeLists.txt @@ -0,0 +1,58 @@ +add_custom_target(test_cmake_build) + +if(CMAKE_VERSION VERSION_LESS 3.1) + # 3.0 needed for interface library for subdirectory_target/installed_target + # 3.1 needed for cmake -E env for testing + return() +endif() + +include(CMakeParseArguments) +function(pybind11_add_build_test name) + cmake_parse_arguments(ARG "INSTALL" "" "" ${ARGN}) + + set(build_options "-DCMAKE_PREFIX_PATH=${PROJECT_BINARY_DIR}/mock_install" + "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + "-DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE}" + "-DPYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}") + if(NOT ARG_INSTALL) + list(APPEND build_options "-DPYBIND11_PROJECT_DIR=${PROJECT_SOURCE_DIR}") + endif() + + add_custom_target(test_${name} ${CMAKE_CTEST_COMMAND} + --quiet --output-log ${name}.log + --build-and-test "${CMAKE_CURRENT_SOURCE_DIR}/${name}" + "${CMAKE_CURRENT_BINARY_DIR}/${name}" + --build-config Release + --build-noclean + --build-generator ${CMAKE_GENERATOR} + $<$:--build-generator-platform> ${CMAKE_GENERATOR_PLATFORM} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-target check + --build-options ${build_options} + ) + if(ARG_INSTALL) + add_dependencies(test_${name} mock_install) + endif() + add_dependencies(test_cmake_build test_${name}) +endfunction() + +pybind11_add_build_test(subdirectory_function) +pybind11_add_build_test(subdirectory_target) +if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy") + pybind11_add_build_test(subdirectory_embed) +endif() + +if(PYBIND11_INSTALL) + add_custom_target(mock_install ${CMAKE_COMMAND} + "-DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}/mock_install" + -P "${PROJECT_BINARY_DIR}/cmake_install.cmake" + ) + + pybind11_add_build_test(installed_function INSTALL) + pybind11_add_build_test(installed_target INSTALL) + if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy") + pybind11_add_build_test(installed_embed INSTALL) + endif() +endif() + +add_dependencies(check test_cmake_build) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/embed.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/embed.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9581d2fdb0a1629b9d0839acc033c20fecbe880 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/embed.cpp @@ -0,0 +1,21 @@ +#include +namespace py = pybind11; + +PYBIND11_EMBEDDED_MODULE(test_cmake_build, m) { + m.def("add", [](int i, int j) { return i + j; }); +} + +int main(int argc, char *argv[]) { + if (argc != 2) + throw std::runtime_error("Expected test.py file as the first argument"); + auto test_py_file = argv[1]; + + py::scoped_interpreter guard{}; + + auto m = py::module::import("test_cmake_build"); + if (m.attr("add")(1, 2).cast() != 3) + throw std::runtime_error("embed.cpp failed"); + + py::module::import("sys").attr("argv") = py::make_tuple("test.py", "embed.cpp"); + py::eval_file(test_py_file, py::globals()); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/installed_embed/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/installed_embed/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7fc09c2191b45564091443f5e1b7069896738cb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/installed_embed/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.0) +project(test_installed_embed CXX) + +set(CMAKE_MODULE_PATH "") +find_package(pybind11 CONFIG REQUIRED) +message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") + +add_executable(test_cmake_build ../embed.cpp) +target_link_libraries(test_cmake_build PRIVATE pybind11::embed) + +# Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::embed). +# This may be needed to resolve header conflicts, e.g. between Python release and debug headers. +set_target_properties(test_cmake_build PROPERTIES NO_SYSTEM_FROM_IMPORTED ON) + +add_custom_target(check $ ${PROJECT_SOURCE_DIR}/../test.py) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/installed_function/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/installed_function/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0c20a8a3634ea7e33859c5009ba2c9edd1b011a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/installed_function/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 2.8.12) +project(test_installed_module CXX) + +set(CMAKE_MODULE_PATH "") + +find_package(pybind11 CONFIG REQUIRED) +message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") + +pybind11_add_module(test_cmake_build SHARED NO_EXTRAS ../main.cpp) + +add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$ + ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/installed_target/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/installed_target/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd3ae6f7d84ccb6b7cf9ff58c71cd37a90d6710a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/installed_target/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.0) +project(test_installed_target CXX) + +set(CMAKE_MODULE_PATH "") + +find_package(pybind11 CONFIG REQUIRED) +message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") + +add_library(test_cmake_build MODULE ../main.cpp) + +target_link_libraries(test_cmake_build PRIVATE pybind11::module) + +# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib +set_target_properties(test_cmake_build PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" + SUFFIX "${PYTHON_MODULE_EXTENSION}") + +# Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::module). +# This may be needed to resolve header conflicts, e.g. between Python release and debug headers. +set_target_properties(test_cmake_build PROPERTIES NO_SYSTEM_FROM_IMPORTED ON) + +add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$ + ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/main.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e30f2c4b9a31205185d2b221a994dc001a30730a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/main.cpp @@ -0,0 +1,6 @@ +#include +namespace py = pybind11; + +PYBIND11_MODULE(test_cmake_build, m) { + m.def("add", [](int i, int j) { return i + j; }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..88ba60dd523ce0e5ba98a3604fb91fcd4376f980 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.0) +project(test_subdirectory_embed CXX) + +set(PYBIND11_INSTALL ON CACHE BOOL "") +set(PYBIND11_EXPORT_NAME test_export) + +add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11) + +# Test basic target functionality +add_executable(test_cmake_build ../embed.cpp) +target_link_libraries(test_cmake_build PRIVATE pybind11::embed) + +add_custom_target(check $ ${PROJECT_SOURCE_DIR}/../test.py) + +# Test custom export group -- PYBIND11_EXPORT_NAME +add_library(test_embed_lib ../embed.cpp) +target_link_libraries(test_embed_lib PRIVATE pybind11::embed) + +install(TARGETS test_embed_lib + EXPORT test_export + ARCHIVE DESTINATION bin + LIBRARY DESTINATION lib + RUNTIME DESTINATION lib) +install(EXPORT test_export + DESTINATION lib/cmake/test_export/test_export-Targets.cmake) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/subdirectory_function/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/subdirectory_function/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..278007aebd1c130cce62772decb6a19cd77e3fbb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/subdirectory_function/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 2.8.12) +project(test_subdirectory_module CXX) + +add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11) +pybind11_add_module(test_cmake_build THIN_LTO ../main.cpp) + +add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$ + ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/subdirectory_target/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/subdirectory_target/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b142d62a931a3636e4074a6d39be5a0e7052689 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/subdirectory_target/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.0) +project(test_subdirectory_target CXX) + +add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11) + +add_library(test_cmake_build MODULE ../main.cpp) + +target_link_libraries(test_cmake_build PRIVATE pybind11::module) + +# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib +set_target_properties(test_cmake_build PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" + SUFFIX "${PYTHON_MODULE_EXTENSION}") + +add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$ + ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/test.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/test.py new file mode 100644 index 0000000000000000000000000000000000000000..1467a61dc0e75c05c8a91ce3b8bc6c2338ff8c3e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_cmake_build/test.py @@ -0,0 +1,5 @@ +import sys +import test_cmake_build + +assert test_cmake_build.add(1, 2) == 3 +print("{} imports, runs, and adds: 1 + 2 = 3".format(sys.argv[1])) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_constants_and_functions.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_constants_and_functions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8ec74b7bc77c9ddf87073d40e9a8c8c9c2115f0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_constants_and_functions.cpp @@ -0,0 +1,127 @@ +/* + tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw byte strings + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +enum MyEnum { EFirstEntry = 1, ESecondEntry }; + +std::string test_function1() { + return "test_function()"; +} + +std::string test_function2(MyEnum k) { + return "test_function(enum=" + std::to_string(k) + ")"; +} + +std::string test_function3(int i) { + return "test_function(" + std::to_string(i) + ")"; +} + +py::str test_function4() { return "test_function()"; } +py::str test_function4(char *) { return "test_function(char *)"; } +py::str test_function4(int, float) { return "test_function(int, float)"; } +py::str test_function4(float, int) { return "test_function(float, int)"; } + +py::bytes return_bytes() { + const char *data = "\x01\x00\x02\x00"; + return std::string(data, 4); +} + +std::string print_bytes(py::bytes bytes) { + std::string ret = "bytes["; + const auto value = static_cast(bytes); + for (size_t i = 0; i < value.length(); ++i) { + ret += std::to_string(static_cast(value[i])) + " "; + } + ret.back() = ']'; + return ret; +} + +// Test that we properly handle C++17 exception specifiers (which are part of the function signature +// in C++17). These should all still work before C++17, but don't affect the function signature. +namespace test_exc_sp { +int f1(int x) noexcept { return x+1; } +int f2(int x) noexcept(true) { return x+2; } +int f3(int x) noexcept(false) { return x+3; } +#if defined(__GNUG__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated" +#endif +int f4(int x) throw() { return x+4; } // Deprecated equivalent to noexcept(true) +#if defined(__GNUG__) +# pragma GCC diagnostic pop +#endif +struct C { + int m1(int x) noexcept { return x-1; } + int m2(int x) const noexcept { return x-2; } + int m3(int x) noexcept(true) { return x-3; } + int m4(int x) const noexcept(true) { return x-4; } + int m5(int x) noexcept(false) { return x-5; } + int m6(int x) const noexcept(false) { return x-6; } +#if defined(__GNUG__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated" +#endif + int m7(int x) throw() { return x-7; } + int m8(int x) const throw() { return x-8; } +#if defined(__GNUG__) +# pragma GCC diagnostic pop +#endif +}; +} + + +TEST_SUBMODULE(constants_and_functions, m) { + // test_constants + m.attr("some_constant") = py::int_(14); + + // test_function_overloading + m.def("test_function", &test_function1); + m.def("test_function", &test_function2); + m.def("test_function", &test_function3); + +#if defined(PYBIND11_OVERLOAD_CAST) + m.def("test_function", py::overload_cast<>(&test_function4)); + m.def("test_function", py::overload_cast(&test_function4)); + m.def("test_function", py::overload_cast(&test_function4)); + m.def("test_function", py::overload_cast(&test_function4)); +#else + m.def("test_function", static_cast(&test_function4)); + m.def("test_function", static_cast(&test_function4)); + m.def("test_function", static_cast(&test_function4)); + m.def("test_function", static_cast(&test_function4)); +#endif + + py::enum_(m, "MyEnum") + .value("EFirstEntry", EFirstEntry) + .value("ESecondEntry", ESecondEntry) + .export_values(); + + // test_bytes + m.def("return_bytes", &return_bytes); + m.def("print_bytes", &print_bytes); + + // test_exception_specifiers + using namespace test_exc_sp; + py::class_(m, "C") + .def(py::init<>()) + .def("m1", &C::m1) + .def("m2", &C::m2) + .def("m3", &C::m3) + .def("m4", &C::m4) + .def("m5", &C::m5) + .def("m6", &C::m6) + .def("m7", &C::m7) + .def("m8", &C::m8) + ; + m.def("f1", f1); + m.def("f2", f2); + m.def("f3", f3); + m.def("f4", f4); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_constants_and_functions.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_constants_and_functions.py new file mode 100644 index 0000000000000000000000000000000000000000..472682d619db83c4f87cc645ecbf81a751d38936 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_constants_and_functions.py @@ -0,0 +1,39 @@ +from pybind11_tests import constants_and_functions as m + + +def test_constants(): + assert m.some_constant == 14 + + +def test_function_overloading(): + assert m.test_function() == "test_function()" + assert m.test_function(7) == "test_function(7)" + assert m.test_function(m.MyEnum.EFirstEntry) == "test_function(enum=1)" + assert m.test_function(m.MyEnum.ESecondEntry) == "test_function(enum=2)" + + assert m.test_function() == "test_function()" + assert m.test_function("abcd") == "test_function(char *)" + assert m.test_function(1, 1.0) == "test_function(int, float)" + assert m.test_function(1, 1.0) == "test_function(int, float)" + assert m.test_function(2.0, 2) == "test_function(float, int)" + + +def test_bytes(): + assert m.print_bytes(m.return_bytes()) == "bytes[1 0 2 0]" + + +def test_exception_specifiers(): + c = m.C() + assert c.m1(2) == 1 + assert c.m2(3) == 1 + assert c.m3(5) == 2 + assert c.m4(7) == 3 + assert c.m5(10) == 5 + assert c.m6(14) == 8 + assert c.m7(20) == 13 + assert c.m8(29) == 21 + + assert m.f1(33) == 34 + assert m.f2(53) == 55 + assert m.f3(86) == 89 + assert m.f4(140) == 144 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_copy_move.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_copy_move.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98d5e0a0bd5d4f1499c0462a737134885bcfba99 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_copy_move.cpp @@ -0,0 +1,213 @@ +/* + tests/test_copy_move_policies.cpp -- 'copy' and 'move' return value policies + and related tests + + Copyright (c) 2016 Ben North + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include + +template +struct empty { + static const derived& get_one() { return instance_; } + static derived instance_; +}; + +struct lacking_copy_ctor : public empty { + lacking_copy_ctor() {} + lacking_copy_ctor(const lacking_copy_ctor& other) = delete; +}; + +template <> lacking_copy_ctor empty::instance_ = {}; + +struct lacking_move_ctor : public empty { + lacking_move_ctor() {} + lacking_move_ctor(const lacking_move_ctor& other) = delete; + lacking_move_ctor(lacking_move_ctor&& other) = delete; +}; + +template <> lacking_move_ctor empty::instance_ = {}; + +/* Custom type caster move/copy test classes */ +class MoveOnlyInt { +public: + MoveOnlyInt() { print_default_created(this); } + MoveOnlyInt(int v) : value{std::move(v)} { print_created(this, value); } + MoveOnlyInt(MoveOnlyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); } + MoveOnlyInt &operator=(MoveOnlyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; } + MoveOnlyInt(const MoveOnlyInt &) = delete; + MoveOnlyInt &operator=(const MoveOnlyInt &) = delete; + ~MoveOnlyInt() { print_destroyed(this); } + + int value; +}; +class MoveOrCopyInt { +public: + MoveOrCopyInt() { print_default_created(this); } + MoveOrCopyInt(int v) : value{std::move(v)} { print_created(this, value); } + MoveOrCopyInt(MoveOrCopyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); } + MoveOrCopyInt &operator=(MoveOrCopyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; } + MoveOrCopyInt(const MoveOrCopyInt &c) { print_copy_created(this, c.value); value = c.value; } + MoveOrCopyInt &operator=(const MoveOrCopyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; } + ~MoveOrCopyInt() { print_destroyed(this); } + + int value; +}; +class CopyOnlyInt { +public: + CopyOnlyInt() { print_default_created(this); } + CopyOnlyInt(int v) : value{std::move(v)} { print_created(this, value); } + CopyOnlyInt(const CopyOnlyInt &c) { print_copy_created(this, c.value); value = c.value; } + CopyOnlyInt &operator=(const CopyOnlyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; } + ~CopyOnlyInt() { print_destroyed(this); } + + int value; +}; +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) +template <> struct type_caster { + PYBIND11_TYPE_CASTER(MoveOnlyInt, _("MoveOnlyInt")); + bool load(handle src, bool) { value = MoveOnlyInt(src.cast()); return true; } + static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } +}; + +template <> struct type_caster { + PYBIND11_TYPE_CASTER(MoveOrCopyInt, _("MoveOrCopyInt")); + bool load(handle src, bool) { value = MoveOrCopyInt(src.cast()); return true; } + static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } +}; + +template <> struct type_caster { +protected: + CopyOnlyInt value; +public: + static constexpr auto name = _("CopyOnlyInt"); + bool load(handle src, bool) { value = CopyOnlyInt(src.cast()); return true; } + static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } + static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) { + if (!src) return none().release(); + return cast(*src, policy, parent); + } + operator CopyOnlyInt*() { return &value; } + operator CopyOnlyInt&() { return value; } + template using cast_op_type = pybind11::detail::cast_op_type; +}; +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) + +TEST_SUBMODULE(copy_move_policies, m) { + // test_lacking_copy_ctor + py::class_(m, "lacking_copy_ctor") + .def_static("get_one", &lacking_copy_ctor::get_one, + py::return_value_policy::copy); + // test_lacking_move_ctor + py::class_(m, "lacking_move_ctor") + .def_static("get_one", &lacking_move_ctor::get_one, + py::return_value_policy::move); + + // test_move_and_copy_casts + m.def("move_and_copy_casts", [](py::object o) { + int r = 0; + r += py::cast(o).value; /* moves */ + r += py::cast(o).value; /* moves */ + r += py::cast(o).value; /* copies */ + MoveOrCopyInt m1(py::cast(o)); /* moves */ + MoveOnlyInt m2(py::cast(o)); /* moves */ + CopyOnlyInt m3(py::cast(o)); /* copies */ + r += m1.value + m2.value + m3.value; + + return r; + }); + + // test_move_and_copy_loads + m.def("move_only", [](MoveOnlyInt m) { return m.value; }); + m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; }); + m.def("copy_only", [](CopyOnlyInt m) { return m.value; }); + m.def("move_pair", [](std::pair p) { + return p.first.value + p.second.value; + }); + m.def("move_tuple", [](std::tuple t) { + return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value; + }); + m.def("copy_tuple", [](std::tuple t) { + return std::get<0>(t).value + std::get<1>(t).value; + }); + m.def("move_copy_nested", [](std::pair>, MoveOrCopyInt>> x) { + return x.first.value + std::get<0>(x.second.first).value + std::get<1>(x.second.first).value + + std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value; + }); + m.def("move_and_copy_cstats", []() { + ConstructorStats::gc(); + // Reset counts to 0 so that previous tests don't affect later ones: + auto &mc = ConstructorStats::get(); + mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions = 0; + auto &mo = ConstructorStats::get(); + mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions = 0; + auto &co = ConstructorStats::get(); + co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions = 0; + py::dict d; + d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference); + d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference); + d["CopyOnlyInt"] = py::cast(co, py::return_value_policy::reference); + return d; + }); +#ifdef PYBIND11_HAS_OPTIONAL + // test_move_and_copy_load_optional + m.attr("has_optional") = true; + m.def("move_optional", [](std::optional o) { + return o->value; + }); + m.def("move_or_copy_optional", [](std::optional o) { + return o->value; + }); + m.def("copy_optional", [](std::optional o) { + return o->value; + }); + m.def("move_optional_tuple", [](std::optional> x) { + return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value; + }); +#else + m.attr("has_optional") = false; +#endif + + // #70 compilation issue if operator new is not public + struct PrivateOpNew { + int value = 1; + private: +#if defined(_MSC_VER) +# pragma warning(disable: 4822) // warning C4822: local class member function does not have a body +#endif + void *operator new(size_t bytes); + }; + py::class_(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value); + m.def("private_op_new_value", []() { return PrivateOpNew(); }); + m.def("private_op_new_reference", []() -> const PrivateOpNew & { + static PrivateOpNew x{}; + return x; + }, py::return_value_policy::reference); + + // test_move_fallback + // #389: rvp::move should fall-through to copy on non-movable objects + struct MoveIssue1 { + int v; + MoveIssue1(int v) : v{v} {} + MoveIssue1(const MoveIssue1 &c) = default; + MoveIssue1(MoveIssue1 &&) = delete; + }; + py::class_(m, "MoveIssue1").def(py::init()).def_readwrite("value", &MoveIssue1::v); + + struct MoveIssue2 { + int v; + MoveIssue2(int v) : v{v} {} + MoveIssue2(MoveIssue2 &&) = default; + }; + py::class_(m, "MoveIssue2").def(py::init()).def_readwrite("value", &MoveIssue2::v); + + m.def("get_moveissue1", [](int i) { return new MoveIssue1(i); }, py::return_value_policy::move); + m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_copy_move.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_copy_move.py new file mode 100644 index 0000000000000000000000000000000000000000..0e671d969608739e5b0b09e7d778cb5a3e4b374f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_copy_move.py @@ -0,0 +1,112 @@ +import pytest +from pybind11_tests import copy_move_policies as m + + +def test_lacking_copy_ctor(): + with pytest.raises(RuntimeError) as excinfo: + m.lacking_copy_ctor.get_one() + assert "is non-copyable!" in str(excinfo.value) + + +def test_lacking_move_ctor(): + with pytest.raises(RuntimeError) as excinfo: + m.lacking_move_ctor.get_one() + assert "is neither movable nor copyable!" in str(excinfo.value) + + +def test_move_and_copy_casts(): + """Cast some values in C++ via custom type casters and count the number of moves/copies.""" + + cstats = m.move_and_copy_cstats() + c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] + + # The type move constructions/assignments below each get incremented: the move assignment comes + # from the type_caster load; the move construction happens when extracting that via a cast or + # loading into an argument. + assert m.move_and_copy_casts(3) == 18 + assert c_m.copy_assignments + c_m.copy_constructions == 0 + assert c_m.move_assignments == 2 + assert c_m.move_constructions >= 2 + assert c_mc.alive() == 0 + assert c_mc.copy_assignments + c_mc.copy_constructions == 0 + assert c_mc.move_assignments == 2 + assert c_mc.move_constructions >= 2 + assert c_c.alive() == 0 + assert c_c.copy_assignments == 2 + assert c_c.copy_constructions >= 2 + assert c_m.alive() + c_mc.alive() + c_c.alive() == 0 + + +def test_move_and_copy_loads(): + """Call some functions that load arguments via custom type casters and count the number of + moves/copies.""" + + cstats = m.move_and_copy_cstats() + c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] + + assert m.move_only(10) == 10 # 1 move, c_m + assert m.move_or_copy(11) == 11 # 1 move, c_mc + assert m.copy_only(12) == 12 # 1 copy, c_c + assert m.move_pair((13, 14)) == 27 # 1 c_m move, 1 c_mc move + assert m.move_tuple((15, 16, 17)) == 48 # 2 c_m moves, 1 c_mc move + assert m.copy_tuple((18, 19)) == 37 # 2 c_c copies + # Direct constructions: 2 c_m moves, 2 c_mc moves, 1 c_c copy + # Extra moves/copies when moving pairs/tuples: 3 c_m, 3 c_mc, 2 c_c + assert m.move_copy_nested((1, ((2, 3, (4,)), 5))) == 15 + + assert c_m.copy_assignments + c_m.copy_constructions == 0 + assert c_m.move_assignments == 6 + assert c_m.move_constructions == 9 + assert c_mc.copy_assignments + c_mc.copy_constructions == 0 + assert c_mc.move_assignments == 5 + assert c_mc.move_constructions == 8 + assert c_c.copy_assignments == 4 + assert c_c.copy_constructions == 6 + assert c_m.alive() + c_mc.alive() + c_c.alive() == 0 + + +@pytest.mark.skipif(not m.has_optional, reason='no ') +def test_move_and_copy_load_optional(): + """Tests move/copy loads of std::optional arguments""" + + cstats = m.move_and_copy_cstats() + c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] + + # The extra move/copy constructions below come from the std::optional move (which has to move + # its arguments): + assert m.move_optional(10) == 10 # c_m: 1 move assign, 2 move construct + assert m.move_or_copy_optional(11) == 11 # c_mc: 1 move assign, 2 move construct + assert m.copy_optional(12) == 12 # c_c: 1 copy assign, 2 copy construct + # 1 move assign + move construct moves each of c_m, c_mc, 1 c_c copy + # +1 move/copy construct each from moving the tuple + # +1 move/copy construct each from moving the optional (which moves the tuple again) + assert m.move_optional_tuple((3, 4, 5)) == 12 + + assert c_m.copy_assignments + c_m.copy_constructions == 0 + assert c_m.move_assignments == 2 + assert c_m.move_constructions == 5 + assert c_mc.copy_assignments + c_mc.copy_constructions == 0 + assert c_mc.move_assignments == 2 + assert c_mc.move_constructions == 5 + assert c_c.copy_assignments == 2 + assert c_c.copy_constructions == 5 + assert c_m.alive() + c_mc.alive() + c_c.alive() == 0 + + +def test_private_op_new(): + """An object with a private `operator new` cannot be returned by value""" + + with pytest.raises(RuntimeError) as excinfo: + m.private_op_new_value() + assert "is neither movable nor copyable" in str(excinfo.value) + + assert m.private_op_new_reference().value == 1 + + +def test_move_fallback(): + """#389: rvp::move should fall-through to copy on non-movable objects""" + + m2 = m.get_moveissue2(2) + assert m2.value == 2 + m1 = m.get_moveissue1(1) + assert m1.value == 1 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_docstring_options.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_docstring_options.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c8f79fd5f6308caab1ee2d22525af2a408eca07 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_docstring_options.cpp @@ -0,0 +1,61 @@ +/* + tests/test_docstring_options.cpp -- generation of docstrings and signatures + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +TEST_SUBMODULE(docstring_options, m) { + // test_docstring_options + { + py::options options; + options.disable_function_signatures(); + + m.def("test_function1", [](int, int) {}, py::arg("a"), py::arg("b")); + m.def("test_function2", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); + + m.def("test_overloaded1", [](int) {}, py::arg("i"), "Overload docstring"); + m.def("test_overloaded1", [](double) {}, py::arg("d")); + + m.def("test_overloaded2", [](int) {}, py::arg("i"), "overload docstring 1"); + m.def("test_overloaded2", [](double) {}, py::arg("d"), "overload docstring 2"); + + m.def("test_overloaded3", [](int) {}, py::arg("i")); + m.def("test_overloaded3", [](double) {}, py::arg("d"), "Overload docstr"); + + options.enable_function_signatures(); + + m.def("test_function3", [](int, int) {}, py::arg("a"), py::arg("b")); + m.def("test_function4", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); + + options.disable_function_signatures().disable_user_defined_docstrings(); + + m.def("test_function5", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); + + { + py::options nested_options; + nested_options.enable_user_defined_docstrings(); + m.def("test_function6", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); + } + } + + m.def("test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); + + { + py::options options; + options.disable_user_defined_docstrings(); + + struct DocstringTestFoo { + int value; + void setValue(int v) { value = v; } + int getValue() const { return value; } + }; + py::class_(m, "DocstringTestFoo", "This is a class docstring") + .def_property("value_prop", &DocstringTestFoo::getValue, &DocstringTestFoo::setValue, "This is a property docstring") + ; + } +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_docstring_options.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_docstring_options.py new file mode 100644 index 0000000000000000000000000000000000000000..0dbca609ef9ab9f5409871a2b069f7ddd698a6ac --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_docstring_options.py @@ -0,0 +1,38 @@ +from pybind11_tests import docstring_options as m + + +def test_docstring_options(): + # options.disable_function_signatures() + assert not m.test_function1.__doc__ + + assert m.test_function2.__doc__ == "A custom docstring" + + # docstring specified on just the first overload definition: + assert m.test_overloaded1.__doc__ == "Overload docstring" + + # docstring on both overloads: + assert m.test_overloaded2.__doc__ == "overload docstring 1\noverload docstring 2" + + # docstring on only second overload: + assert m.test_overloaded3.__doc__ == "Overload docstr" + + # options.enable_function_signatures() + assert m.test_function3.__doc__ .startswith("test_function3(a: int, b: int) -> None") + + assert m.test_function4.__doc__ .startswith("test_function4(a: int, b: int) -> None") + assert m.test_function4.__doc__ .endswith("A custom docstring\n") + + # options.disable_function_signatures() + # options.disable_user_defined_docstrings() + assert not m.test_function5.__doc__ + + # nested options.enable_user_defined_docstrings() + assert m.test_function6.__doc__ == "A custom docstring" + + # RAII destructor + assert m.test_function7.__doc__ .startswith("test_function7(a: int, b: int) -> None") + assert m.test_function7.__doc__ .endswith("A custom docstring\n") + + # Suppression of user-defined docstrings for non-function objects + assert not m.DocstringTestFoo.__doc__ + assert not m.DocstringTestFoo.value_prop.__doc__ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eigen.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eigen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aba088d72b0007f9a3d5e3066b72355977688374 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eigen.cpp @@ -0,0 +1,329 @@ +/* + tests/eigen.cpp -- automatic conversion of Eigen types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include +#include + +#if defined(_MSC_VER) +# pragma warning(disable: 4996) // C4996: std::unary_negation is deprecated +#endif + +#include + +using MatrixXdR = Eigen::Matrix; + + + +// Sets/resets a testing reference matrix to have values of 10*r + c, where r and c are the +// (1-based) row/column number. +template void reset_ref(M &x) { + for (int i = 0; i < x.rows(); i++) for (int j = 0; j < x.cols(); j++) + x(i, j) = 11 + 10*i + j; +} + +// Returns a static, column-major matrix +Eigen::MatrixXd &get_cm() { + static Eigen::MatrixXd *x; + if (!x) { + x = new Eigen::MatrixXd(3, 3); + reset_ref(*x); + } + return *x; +} +// Likewise, but row-major +MatrixXdR &get_rm() { + static MatrixXdR *x; + if (!x) { + x = new MatrixXdR(3, 3); + reset_ref(*x); + } + return *x; +} +// Resets the values of the static matrices returned by get_cm()/get_rm() +void reset_refs() { + reset_ref(get_cm()); + reset_ref(get_rm()); +} + +// Returns element 2,1 from a matrix (used to test copy/nocopy) +double get_elem(Eigen::Ref m) { return m(2, 1); }; + + +// Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix +// reference is referencing rows/columns correctly). +template Eigen::MatrixXd adjust_matrix(MatrixArgType m) { + Eigen::MatrixXd ret(m); + for (int c = 0; c < m.cols(); c++) for (int r = 0; r < m.rows(); r++) + ret(r, c) += 10*r + 100*c; + return ret; +} + +struct CustomOperatorNew { + CustomOperatorNew() = default; + + Eigen::Matrix4d a = Eigen::Matrix4d::Zero(); + Eigen::Matrix4d b = Eigen::Matrix4d::Identity(); + + EIGEN_MAKE_ALIGNED_OPERATOR_NEW; +}; + +TEST_SUBMODULE(eigen, m) { + using FixedMatrixR = Eigen::Matrix; + using FixedMatrixC = Eigen::Matrix; + using DenseMatrixR = Eigen::Matrix; + using DenseMatrixC = Eigen::Matrix; + using FourRowMatrixC = Eigen::Matrix; + using FourColMatrixC = Eigen::Matrix; + using FourRowMatrixR = Eigen::Matrix; + using FourColMatrixR = Eigen::Matrix; + using SparseMatrixR = Eigen::SparseMatrix; + using SparseMatrixC = Eigen::SparseMatrix; + + m.attr("have_eigen") = true; + + // various tests + m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; }); + m.def("double_row", [](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; }); + m.def("double_complex", [](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; }); + m.def("double_threec", [](py::EigenDRef x) { x *= 2; }); + m.def("double_threer", [](py::EigenDRef x) { x *= 2; }); + m.def("double_mat_cm", [](Eigen::MatrixXf x) -> Eigen::MatrixXf { return 2.0f * x; }); + m.def("double_mat_rm", [](DenseMatrixR x) -> DenseMatrixR { return 2.0f * x; }); + + // test_eigen_ref_to_python + // Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended + m.def("cholesky1", [](Eigen::Ref x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); + m.def("cholesky2", [](const Eigen::Ref &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); + m.def("cholesky3", [](const Eigen::Ref &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); + m.def("cholesky4", [](Eigen::Ref x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); + + // test_eigen_ref_mutators + // Mutators: these add some value to the given element using Eigen, but Eigen should be mapping into + // the numpy array data and so the result should show up there. There are three versions: one that + // works on a contiguous-row matrix (numpy's default), one for a contiguous-column matrix, and one + // for any matrix. + auto add_rm = [](Eigen::Ref x, int r, int c, double v) { x(r,c) += v; }; + auto add_cm = [](Eigen::Ref x, int r, int c, double v) { x(r,c) += v; }; + + // Mutators (Eigen maps into numpy variables): + m.def("add_rm", add_rm); // Only takes row-contiguous + m.def("add_cm", add_cm); // Only takes column-contiguous + // Overloaded versions that will accept either row or column contiguous: + m.def("add1", add_rm); + m.def("add1", add_cm); + m.def("add2", add_cm); + m.def("add2", add_rm); + // This one accepts a matrix of any stride: + m.def("add_any", [](py::EigenDRef x, int r, int c, double v) { x(r,c) += v; }); + + // Return mutable references (numpy maps into eigen variables) + m.def("get_cm_ref", []() { return Eigen::Ref(get_cm()); }); + m.def("get_rm_ref", []() { return Eigen::Ref(get_rm()); }); + // The same references, but non-mutable (numpy maps into eigen variables, but is !writeable) + m.def("get_cm_const_ref", []() { return Eigen::Ref(get_cm()); }); + m.def("get_rm_const_ref", []() { return Eigen::Ref(get_rm()); }); + + m.def("reset_refs", reset_refs); // Restores get_{cm,rm}_ref to original values + + // Increments and returns ref to (same) matrix + m.def("incr_matrix", [](Eigen::Ref m, double v) { + m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v); + return m; + }, py::return_value_policy::reference); + + // Same, but accepts a matrix of any strides + m.def("incr_matrix_any", [](py::EigenDRef m, double v) { + m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v); + return m; + }, py::return_value_policy::reference); + + // Returns an eigen slice of even rows + m.def("even_rows", [](py::EigenDRef m) { + return py::EigenDMap( + m.data(), (m.rows() + 1) / 2, m.cols(), + py::EigenDStride(m.outerStride(), 2 * m.innerStride())); + }, py::return_value_policy::reference); + + // Returns an eigen slice of even columns + m.def("even_cols", [](py::EigenDRef m) { + return py::EigenDMap( + m.data(), m.rows(), (m.cols() + 1) / 2, + py::EigenDStride(2 * m.outerStride(), m.innerStride())); + }, py::return_value_policy::reference); + + // Returns diagonals: a vector-like object with an inner stride != 1 + m.def("diagonal", [](const Eigen::Ref &x) { return x.diagonal(); }); + m.def("diagonal_1", [](const Eigen::Ref &x) { return x.diagonal<1>(); }); + m.def("diagonal_n", [](const Eigen::Ref &x, int index) { return x.diagonal(index); }); + + // Return a block of a matrix (gives non-standard strides) + m.def("block", [](const Eigen::Ref &x, int start_row, int start_col, int block_rows, int block_cols) { + return x.block(start_row, start_col, block_rows, block_cols); + }); + + // test_eigen_return_references, test_eigen_keepalive + // return value referencing/copying tests: + class ReturnTester { + Eigen::MatrixXd mat = create(); + public: + ReturnTester() { print_created(this); } + ~ReturnTester() { print_destroyed(this); } + static Eigen::MatrixXd create() { return Eigen::MatrixXd::Ones(10, 10); } + static const Eigen::MatrixXd createConst() { return Eigen::MatrixXd::Ones(10, 10); } + Eigen::MatrixXd &get() { return mat; } + Eigen::MatrixXd *getPtr() { return &mat; } + const Eigen::MatrixXd &view() { return mat; } + const Eigen::MatrixXd *viewPtr() { return &mat; } + Eigen::Ref ref() { return mat; } + Eigen::Ref refConst() { return mat; } + Eigen::Block block(int r, int c, int nrow, int ncol) { return mat.block(r, c, nrow, ncol); } + Eigen::Block blockConst(int r, int c, int nrow, int ncol) const { return mat.block(r, c, nrow, ncol); } + py::EigenDMap corners() { return py::EigenDMap(mat.data(), + py::EigenDStride(mat.outerStride() * (mat.outerSize()-1), mat.innerStride() * (mat.innerSize()-1))); } + py::EigenDMap cornersConst() const { return py::EigenDMap(mat.data(), + py::EigenDStride(mat.outerStride() * (mat.outerSize()-1), mat.innerStride() * (mat.innerSize()-1))); } + }; + using rvp = py::return_value_policy; + py::class_(m, "ReturnTester") + .def(py::init<>()) + .def_static("create", &ReturnTester::create) + .def_static("create_const", &ReturnTester::createConst) + .def("get", &ReturnTester::get, rvp::reference_internal) + .def("get_ptr", &ReturnTester::getPtr, rvp::reference_internal) + .def("view", &ReturnTester::view, rvp::reference_internal) + .def("view_ptr", &ReturnTester::view, rvp::reference_internal) + .def("copy_get", &ReturnTester::get) // Default rvp: copy + .def("copy_view", &ReturnTester::view) // " + .def("ref", &ReturnTester::ref) // Default for Ref is to reference + .def("ref_const", &ReturnTester::refConst) // Likewise, but const + .def("ref_safe", &ReturnTester::ref, rvp::reference_internal) + .def("ref_const_safe", &ReturnTester::refConst, rvp::reference_internal) + .def("copy_ref", &ReturnTester::ref, rvp::copy) + .def("copy_ref_const", &ReturnTester::refConst, rvp::copy) + .def("block", &ReturnTester::block) + .def("block_safe", &ReturnTester::block, rvp::reference_internal) + .def("block_const", &ReturnTester::blockConst, rvp::reference_internal) + .def("copy_block", &ReturnTester::block, rvp::copy) + .def("corners", &ReturnTester::corners, rvp::reference_internal) + .def("corners_const", &ReturnTester::cornersConst, rvp::reference_internal) + ; + + // test_special_matrix_objects + // Returns a DiagonalMatrix with diagonal (1,2,3,...) + m.def("incr_diag", [](int k) { + Eigen::DiagonalMatrix m(k); + for (int i = 0; i < k; i++) m.diagonal()[i] = i+1; + return m; + }); + + // Returns a SelfAdjointView referencing the lower triangle of m + m.def("symmetric_lower", [](const Eigen::MatrixXi &m) { + return m.selfadjointView(); + }); + // Returns a SelfAdjointView referencing the lower triangle of m + m.def("symmetric_upper", [](const Eigen::MatrixXi &m) { + return m.selfadjointView(); + }); + + // Test matrix for various functions below. + Eigen::MatrixXf mat(5, 6); + mat << 0, 3, 0, 0, 0, 11, + 22, 0, 0, 0, 17, 11, + 7, 5, 0, 1, 0, 11, + 0, 0, 0, 0, 0, 11, + 0, 0, 14, 0, 8, 11; + + // test_fixed, and various other tests + m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); }); + m.def("fixed_r_const", [mat]() -> const FixedMatrixR { return FixedMatrixR(mat); }); + m.def("fixed_c", [mat]() -> FixedMatrixC { return FixedMatrixC(mat); }); + m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; }); + m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; }); + // test_mutator_descriptors + m.def("fixed_mutator_r", [](Eigen::Ref) {}); + m.def("fixed_mutator_c", [](Eigen::Ref) {}); + m.def("fixed_mutator_a", [](py::EigenDRef) {}); + // test_dense + m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); }); + m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); }); + m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; }); + m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; }); + // test_sparse, test_sparse_signature + m.def("sparse_r", [mat]() -> SparseMatrixR { return Eigen::SparseView(mat); }); + m.def("sparse_c", [mat]() -> SparseMatrixC { return Eigen::SparseView(mat); }); + m.def("sparse_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; }); + m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; }); + // test_partially_fixed + m.def("partial_copy_four_rm_r", [](const FourRowMatrixR &m) -> FourRowMatrixR { return m; }); + m.def("partial_copy_four_rm_c", [](const FourColMatrixR &m) -> FourColMatrixR { return m; }); + m.def("partial_copy_four_cm_r", [](const FourRowMatrixC &m) -> FourRowMatrixC { return m; }); + m.def("partial_copy_four_cm_c", [](const FourColMatrixC &m) -> FourColMatrixC { return m; }); + + // test_cpp_casting + // Test that we can cast a numpy object to a Eigen::MatrixXd explicitly + m.def("cpp_copy", [](py::handle m) { return m.cast()(1, 0); }); + m.def("cpp_ref_c", [](py::handle m) { return m.cast>()(1, 0); }); + m.def("cpp_ref_r", [](py::handle m) { return m.cast>()(1, 0); }); + m.def("cpp_ref_any", [](py::handle m) { return m.cast>()(1, 0); }); + + + // test_nocopy_wrapper + // Test that we can prevent copying into an argument that would normally copy: First a version + // that would allow copying (if types or strides don't match) for comparison: + m.def("get_elem", &get_elem); + // Now this alternative that calls the tells pybind to fail rather than copy: + m.def("get_elem_nocopy", [](Eigen::Ref m) -> double { return get_elem(m); }, + py::arg().noconvert()); + // Also test a row-major-only no-copy const ref: + m.def("get_elem_rm_nocopy", [](Eigen::Ref> &m) -> long { return m(2, 1); }, + py::arg().noconvert()); + + // test_issue738 + // Issue #738: 1xN or Nx1 2D matrices were neither accepted nor properly copied with an + // incompatible stride value on the length-1 dimension--but that should be allowed (without + // requiring a copy!) because the stride value can be safely ignored on a size-1 dimension. + m.def("iss738_f1", &adjust_matrix &>, py::arg().noconvert()); + m.def("iss738_f2", &adjust_matrix> &>, py::arg().noconvert()); + + // test_issue1105 + // Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense + // eigen Vector or RowVector, the argument would fail to load because the numpy copy would fail: + // numpy won't broadcast a Nx1 into a 1-dimensional vector. + m.def("iss1105_col", [](Eigen::VectorXd) { return true; }); + m.def("iss1105_row", [](Eigen::RowVectorXd) { return true; }); + + // test_named_arguments + // Make sure named arguments are working properly: + m.def("matrix_multiply", [](const py::EigenDRef A, const py::EigenDRef B) + -> Eigen::MatrixXd { + if (A.cols() != B.rows()) throw std::domain_error("Nonconformable matrices!"); + return A * B; + }, py::arg("A"), py::arg("B")); + + // test_custom_operator_new + py::class_(m, "CustomOperatorNew") + .def(py::init<>()) + .def_readonly("a", &CustomOperatorNew::a) + .def_readonly("b", &CustomOperatorNew::b); + + // test_eigen_ref_life_support + // In case of a failure (the caster's temp array does not live long enough), creating + // a new array (np.ones(10)) increases the chances that the temp array will be garbage + // collected and/or that its memory will be overridden with different values. + m.def("get_elem_direct", [](Eigen::Ref v) { + py::module::import("numpy").attr("ones")(10); + return v(5); + }); + m.def("get_elem_indirect", [](std::vector> v) { + py::module::import("numpy").attr("ones")(10); + return v[0](5); + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eigen.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eigen.py new file mode 100644 index 0000000000000000000000000000000000000000..55d935173ee4d742e72d5503e6619925d8437f9b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eigen.py @@ -0,0 +1,694 @@ +import pytest +from pybind11_tests import ConstructorStats + +pytestmark = pytest.requires_eigen_and_numpy + +with pytest.suppress(ImportError): + from pybind11_tests import eigen as m + import numpy as np + + ref = np.array([[ 0., 3, 0, 0, 0, 11], + [22, 0, 0, 0, 17, 11], + [ 7, 5, 0, 1, 0, 11], + [ 0, 0, 0, 0, 0, 11], + [ 0, 0, 14, 0, 8, 11]]) + + +def assert_equal_ref(mat): + np.testing.assert_array_equal(mat, ref) + + +def assert_sparse_equal_ref(sparse_mat): + assert_equal_ref(sparse_mat.toarray()) + + +def test_fixed(): + assert_equal_ref(m.fixed_c()) + assert_equal_ref(m.fixed_r()) + assert_equal_ref(m.fixed_copy_r(m.fixed_r())) + assert_equal_ref(m.fixed_copy_c(m.fixed_c())) + assert_equal_ref(m.fixed_copy_r(m.fixed_c())) + assert_equal_ref(m.fixed_copy_c(m.fixed_r())) + + +def test_dense(): + assert_equal_ref(m.dense_r()) + assert_equal_ref(m.dense_c()) + assert_equal_ref(m.dense_copy_r(m.dense_r())) + assert_equal_ref(m.dense_copy_c(m.dense_c())) + assert_equal_ref(m.dense_copy_r(m.dense_c())) + assert_equal_ref(m.dense_copy_c(m.dense_r())) + + +def test_partially_fixed(): + ref2 = np.array([[0., 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]) + np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2), ref2) + np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2), ref2) + np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]]) + np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :]) + np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]) + np.testing.assert_array_equal( + m.partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]) + + np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2), ref2) + np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2), ref2) + np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]]) + np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :]) + np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]) + np.testing.assert_array_equal( + m.partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]) + + # TypeError should be raise for a shape mismatch + functions = [m.partial_copy_four_rm_r, m.partial_copy_four_rm_c, + m.partial_copy_four_cm_r, m.partial_copy_four_cm_c] + matrix_with_wrong_shape = [[1, 2], + [3, 4]] + for f in functions: + with pytest.raises(TypeError) as excinfo: + f(matrix_with_wrong_shape) + assert "incompatible function arguments" in str(excinfo.value) + + +def test_mutator_descriptors(): + zr = np.arange(30, dtype='float32').reshape(5, 6) # row-major + zc = zr.reshape(6, 5).transpose() # column-major + + m.fixed_mutator_r(zr) + m.fixed_mutator_c(zc) + m.fixed_mutator_a(zr) + m.fixed_mutator_a(zc) + with pytest.raises(TypeError) as excinfo: + m.fixed_mutator_r(zc) + assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.c_contiguous]) -> None' + in str(excinfo.value)) + with pytest.raises(TypeError) as excinfo: + m.fixed_mutator_c(zr) + assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.f_contiguous]) -> None' + in str(excinfo.value)) + with pytest.raises(TypeError) as excinfo: + m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype='float32')) + assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable]) -> None' + in str(excinfo.value)) + zr.flags.writeable = False + with pytest.raises(TypeError): + m.fixed_mutator_r(zr) + with pytest.raises(TypeError): + m.fixed_mutator_a(zr) + + +def test_cpp_casting(): + assert m.cpp_copy(m.fixed_r()) == 22. + assert m.cpp_copy(m.fixed_c()) == 22. + z = np.array([[5., 6], [7, 8]]) + assert m.cpp_copy(z) == 7. + assert m.cpp_copy(m.get_cm_ref()) == 21. + assert m.cpp_copy(m.get_rm_ref()) == 21. + assert m.cpp_ref_c(m.get_cm_ref()) == 21. + assert m.cpp_ref_r(m.get_rm_ref()) == 21. + with pytest.raises(RuntimeError) as excinfo: + # Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles + m.cpp_ref_any(m.fixed_c()) + assert 'Unable to cast Python instance' in str(excinfo.value) + with pytest.raises(RuntimeError) as excinfo: + # Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles + m.cpp_ref_any(m.fixed_r()) + assert 'Unable to cast Python instance' in str(excinfo.value) + assert m.cpp_ref_any(m.ReturnTester.create()) == 1. + + assert m.cpp_ref_any(m.get_cm_ref()) == 21. + assert m.cpp_ref_any(m.get_cm_ref()) == 21. + + +def test_pass_readonly_array(): + z = np.full((5, 6), 42.0) + z.flags.writeable = False + np.testing.assert_array_equal(z, m.fixed_copy_r(z)) + np.testing.assert_array_equal(m.fixed_r_const(), m.fixed_r()) + assert not m.fixed_r_const().flags.writeable + np.testing.assert_array_equal(m.fixed_copy_r(m.fixed_r_const()), m.fixed_r_const()) + + +def test_nonunit_stride_from_python(): + counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3)) + second_row = counting_mat[1, :] + second_col = counting_mat[:, 1] + np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col) + np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col) + np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col) + + counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3)) + slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]] + for slice_idx, ref_mat in enumerate(slices): + np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat) + np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat) + + # Mutator: + m.double_threer(second_row) + m.double_threec(second_col) + np.testing.assert_array_equal(counting_mat, [[0., 2, 2], [6, 16, 10], [6, 14, 8]]) + + +def test_negative_stride_from_python(msg): + """Eigen doesn't support (as of yet) negative strides. When a function takes an Eigen matrix by + copy or const reference, we can pass a numpy array that has negative strides. Otherwise, an + exception will be thrown as Eigen will not be able to map the numpy array.""" + + counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3)) + counting_mat = counting_mat[::-1, ::-1] + second_row = counting_mat[1, :] + second_col = counting_mat[:, 1] + np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col) + np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col) + np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col) + + counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3)) + counting_3d = counting_3d[::-1, ::-1, ::-1] + slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]] + for slice_idx, ref_mat in enumerate(slices): + np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat) + np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat) + + # Mutator: + with pytest.raises(TypeError) as excinfo: + m.double_threer(second_row) + assert msg(excinfo.value) == """ + double_threer(): incompatible function arguments. The following argument types are supported: + 1. (arg0: numpy.ndarray[float32[1, 3], flags.writeable]) -> None + + Invoked with: """ + repr(np.array([ 5., 4., 3.], dtype='float32')) # noqa: E501 line too long + + with pytest.raises(TypeError) as excinfo: + m.double_threec(second_col) + assert msg(excinfo.value) == """ + double_threec(): incompatible function arguments. The following argument types are supported: + 1. (arg0: numpy.ndarray[float32[3, 1], flags.writeable]) -> None + + Invoked with: """ + repr(np.array([ 7., 4., 1.], dtype='float32')) # noqa: E501 line too long + + +def test_nonunit_stride_to_python(): + assert np.all(m.diagonal(ref) == ref.diagonal()) + assert np.all(m.diagonal_1(ref) == ref.diagonal(1)) + for i in range(-5, 7): + assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), "m.diagonal_n({})".format(i) + + assert np.all(m.block(ref, 2, 1, 3, 3) == ref[2:5, 1:4]) + assert np.all(m.block(ref, 1, 4, 4, 2) == ref[1:, 4:]) + assert np.all(m.block(ref, 1, 4, 3, 2) == ref[1:4, 4:]) + + +def test_eigen_ref_to_python(): + chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4] + for i, chol in enumerate(chols, start=1): + mymat = chol(np.array([[1., 2, 4], [2, 13, 23], [4, 23, 77]])) + assert np.all(mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])), "cholesky{}".format(i) + + +def assign_both(a1, a2, r, c, v): + a1[r, c] = v + a2[r, c] = v + + +def array_copy_but_one(a, r, c, v): + z = np.array(a, copy=True) + z[r, c] = v + return z + + +def test_eigen_return_references(): + """Tests various ways of returning references and non-referencing copies""" + + master = np.ones((10, 10)) + a = m.ReturnTester() + a_get1 = a.get() + assert not a_get1.flags.owndata and a_get1.flags.writeable + assign_both(a_get1, master, 3, 3, 5) + a_get2 = a.get_ptr() + assert not a_get2.flags.owndata and a_get2.flags.writeable + assign_both(a_get1, master, 2, 3, 6) + + a_view1 = a.view() + assert not a_view1.flags.owndata and not a_view1.flags.writeable + with pytest.raises(ValueError): + a_view1[2, 3] = 4 + a_view2 = a.view_ptr() + assert not a_view2.flags.owndata and not a_view2.flags.writeable + with pytest.raises(ValueError): + a_view2[2, 3] = 4 + + a_copy1 = a.copy_get() + assert a_copy1.flags.owndata and a_copy1.flags.writeable + np.testing.assert_array_equal(a_copy1, master) + a_copy1[7, 7] = -44 # Shouldn't affect anything else + c1want = array_copy_but_one(master, 7, 7, -44) + a_copy2 = a.copy_view() + assert a_copy2.flags.owndata and a_copy2.flags.writeable + np.testing.assert_array_equal(a_copy2, master) + a_copy2[4, 4] = -22 # Shouldn't affect anything else + c2want = array_copy_but_one(master, 4, 4, -22) + + a_ref1 = a.ref() + assert not a_ref1.flags.owndata and a_ref1.flags.writeable + assign_both(a_ref1, master, 1, 1, 15) + a_ref2 = a.ref_const() + assert not a_ref2.flags.owndata and not a_ref2.flags.writeable + with pytest.raises(ValueError): + a_ref2[5, 5] = 33 + a_ref3 = a.ref_safe() + assert not a_ref3.flags.owndata and a_ref3.flags.writeable + assign_both(a_ref3, master, 0, 7, 99) + a_ref4 = a.ref_const_safe() + assert not a_ref4.flags.owndata and not a_ref4.flags.writeable + with pytest.raises(ValueError): + a_ref4[7, 0] = 987654321 + + a_copy3 = a.copy_ref() + assert a_copy3.flags.owndata and a_copy3.flags.writeable + np.testing.assert_array_equal(a_copy3, master) + a_copy3[8, 1] = 11 + c3want = array_copy_but_one(master, 8, 1, 11) + a_copy4 = a.copy_ref_const() + assert a_copy4.flags.owndata and a_copy4.flags.writeable + np.testing.assert_array_equal(a_copy4, master) + a_copy4[8, 4] = 88 + c4want = array_copy_but_one(master, 8, 4, 88) + + a_block1 = a.block(3, 3, 2, 2) + assert not a_block1.flags.owndata and a_block1.flags.writeable + a_block1[0, 0] = 55 + master[3, 3] = 55 + a_block2 = a.block_safe(2, 2, 3, 2) + assert not a_block2.flags.owndata and a_block2.flags.writeable + a_block2[2, 1] = -123 + master[4, 3] = -123 + a_block3 = a.block_const(6, 7, 4, 3) + assert not a_block3.flags.owndata and not a_block3.flags.writeable + with pytest.raises(ValueError): + a_block3[2, 2] = -44444 + + a_copy5 = a.copy_block(2, 2, 2, 3) + assert a_copy5.flags.owndata and a_copy5.flags.writeable + np.testing.assert_array_equal(a_copy5, master[2:4, 2:5]) + a_copy5[1, 1] = 777 + c5want = array_copy_but_one(master[2:4, 2:5], 1, 1, 777) + + a_corn1 = a.corners() + assert not a_corn1.flags.owndata and a_corn1.flags.writeable + a_corn1 *= 50 + a_corn1[1, 1] = 999 + master[0, 0] = 50 + master[0, 9] = 50 + master[9, 0] = 50 + master[9, 9] = 999 + a_corn2 = a.corners_const() + assert not a_corn2.flags.owndata and not a_corn2.flags.writeable + with pytest.raises(ValueError): + a_corn2[1, 0] = 51 + + # All of the changes made all the way along should be visible everywhere + # now (except for the copies, of course) + np.testing.assert_array_equal(a_get1, master) + np.testing.assert_array_equal(a_get2, master) + np.testing.assert_array_equal(a_view1, master) + np.testing.assert_array_equal(a_view2, master) + np.testing.assert_array_equal(a_ref1, master) + np.testing.assert_array_equal(a_ref2, master) + np.testing.assert_array_equal(a_ref3, master) + np.testing.assert_array_equal(a_ref4, master) + np.testing.assert_array_equal(a_block1, master[3:5, 3:5]) + np.testing.assert_array_equal(a_block2, master[2:5, 2:4]) + np.testing.assert_array_equal(a_block3, master[6:10, 7:10]) + np.testing.assert_array_equal(a_corn1, master[0::master.shape[0] - 1, 0::master.shape[1] - 1]) + np.testing.assert_array_equal(a_corn2, master[0::master.shape[0] - 1, 0::master.shape[1] - 1]) + + np.testing.assert_array_equal(a_copy1, c1want) + np.testing.assert_array_equal(a_copy2, c2want) + np.testing.assert_array_equal(a_copy3, c3want) + np.testing.assert_array_equal(a_copy4, c4want) + np.testing.assert_array_equal(a_copy5, c5want) + + +def assert_keeps_alive(cl, method, *args): + cstats = ConstructorStats.get(cl) + start_with = cstats.alive() + a = cl() + assert cstats.alive() == start_with + 1 + z = method(a, *args) + assert cstats.alive() == start_with + 1 + del a + # Here's the keep alive in action: + assert cstats.alive() == start_with + 1 + del z + # Keep alive should have expired: + assert cstats.alive() == start_with + + +def test_eigen_keepalive(): + a = m.ReturnTester() + cstats = ConstructorStats.get(m.ReturnTester) + assert cstats.alive() == 1 + unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)] + copies = [a.copy_get(), a.copy_view(), a.copy_ref(), a.copy_ref_const(), + a.copy_block(4, 3, 2, 1)] + del a + assert cstats.alive() == 0 + del unsafe + del copies + + for meth in [m.ReturnTester.get, m.ReturnTester.get_ptr, m.ReturnTester.view, + m.ReturnTester.view_ptr, m.ReturnTester.ref_safe, m.ReturnTester.ref_const_safe, + m.ReturnTester.corners, m.ReturnTester.corners_const]: + assert_keeps_alive(m.ReturnTester, meth) + + for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]: + assert_keeps_alive(m.ReturnTester, meth, 4, 3, 2, 1) + + +def test_eigen_ref_mutators(): + """Tests Eigen's ability to mutate numpy values""" + + orig = np.array([[1., 2, 3], [4, 5, 6], [7, 8, 9]]) + zr = np.array(orig) + zc = np.array(orig, order='F') + m.add_rm(zr, 1, 0, 100) + assert np.all(zr == np.array([[1., 2, 3], [104, 5, 6], [7, 8, 9]])) + m.add_cm(zc, 1, 0, 200) + assert np.all(zc == np.array([[1., 2, 3], [204, 5, 6], [7, 8, 9]])) + + m.add_any(zr, 1, 0, 20) + assert np.all(zr == np.array([[1., 2, 3], [124, 5, 6], [7, 8, 9]])) + m.add_any(zc, 1, 0, 10) + assert np.all(zc == np.array([[1., 2, 3], [214, 5, 6], [7, 8, 9]])) + + # Can't reference a col-major array with a row-major Ref, and vice versa: + with pytest.raises(TypeError): + m.add_rm(zc, 1, 0, 1) + with pytest.raises(TypeError): + m.add_cm(zr, 1, 0, 1) + + # Overloads: + m.add1(zr, 1, 0, -100) + m.add2(zr, 1, 0, -20) + assert np.all(zr == orig) + m.add1(zc, 1, 0, -200) + m.add2(zc, 1, 0, -10) + assert np.all(zc == orig) + + # a non-contiguous slice (this won't work on either the row- or + # column-contiguous refs, but should work for the any) + cornersr = zr[0::2, 0::2] + cornersc = zc[0::2, 0::2] + + assert np.all(cornersr == np.array([[1., 3], [7, 9]])) + assert np.all(cornersc == np.array([[1., 3], [7, 9]])) + + with pytest.raises(TypeError): + m.add_rm(cornersr, 0, 1, 25) + with pytest.raises(TypeError): + m.add_cm(cornersr, 0, 1, 25) + with pytest.raises(TypeError): + m.add_rm(cornersc, 0, 1, 25) + with pytest.raises(TypeError): + m.add_cm(cornersc, 0, 1, 25) + m.add_any(cornersr, 0, 1, 25) + m.add_any(cornersc, 0, 1, 44) + assert np.all(zr == np.array([[1., 2, 28], [4, 5, 6], [7, 8, 9]])) + assert np.all(zc == np.array([[1., 2, 47], [4, 5, 6], [7, 8, 9]])) + + # You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method: + zro = zr[0:4, 0:4] + zro.flags.writeable = False + with pytest.raises(TypeError): + m.add_rm(zro, 0, 0, 0) + with pytest.raises(TypeError): + m.add_any(zro, 0, 0, 0) + with pytest.raises(TypeError): + m.add1(zro, 0, 0, 0) + with pytest.raises(TypeError): + m.add2(zro, 0, 0, 0) + + # integer array shouldn't be passable to a double-matrix-accepting mutating func: + zi = np.array([[1, 2], [3, 4]]) + with pytest.raises(TypeError): + m.add_rm(zi) + + +def test_numpy_ref_mutators(): + """Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)""" + + m.reset_refs() # In case another test already changed it + + zc = m.get_cm_ref() + zcro = m.get_cm_const_ref() + zr = m.get_rm_ref() + zrro = m.get_rm_const_ref() + + assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4 + + assert not zc.flags.owndata and zc.flags.writeable + assert not zr.flags.owndata and zr.flags.writeable + assert not zcro.flags.owndata and not zcro.flags.writeable + assert not zrro.flags.owndata and not zrro.flags.writeable + + zc[1, 2] = 99 + expect = np.array([[11., 12, 13], [21, 22, 99], [31, 32, 33]]) + # We should have just changed zc, of course, but also zcro and the original eigen matrix + assert np.all(zc == expect) + assert np.all(zcro == expect) + assert np.all(m.get_cm_ref() == expect) + + zr[1, 2] = 99 + assert np.all(zr == expect) + assert np.all(zrro == expect) + assert np.all(m.get_rm_ref() == expect) + + # Make sure the readonly ones are numpy-readonly: + with pytest.raises(ValueError): + zcro[1, 2] = 6 + with pytest.raises(ValueError): + zrro[1, 2] = 6 + + # We should be able to explicitly copy like this (and since we're copying, + # the const should drop away) + y1 = np.array(m.get_cm_const_ref()) + + assert y1.flags.owndata and y1.flags.writeable + # We should get copies of the eigen data, which was modified above: + assert y1[1, 2] == 99 + y1[1, 2] += 12 + assert y1[1, 2] == 111 + assert zc[1, 2] == 99 # Make sure we aren't referencing the original + + +def test_both_ref_mutators(): + """Tests a complex chain of nested eigen/numpy references""" + + m.reset_refs() # In case another test already changed it + + z = m.get_cm_ref() # numpy -> eigen + z[0, 2] -= 3 + z2 = m.incr_matrix(z, 1) # numpy -> eigen -> numpy -> eigen + z2[1, 1] += 6 + z3 = m.incr_matrix(z, 2) # (numpy -> eigen)^3 + z3[2, 2] += -5 + z4 = m.incr_matrix(z, 3) # (numpy -> eigen)^4 + z4[1, 1] -= 1 + z5 = m.incr_matrix(z, 4) # (numpy -> eigen)^5 + z5[0, 0] = 0 + assert np.all(z == z2) + assert np.all(z == z3) + assert np.all(z == z4) + assert np.all(z == z5) + expect = np.array([[0., 22, 20], [31, 37, 33], [41, 42, 38]]) + assert np.all(z == expect) + + y = np.array(range(100), dtype='float64').reshape(10, 10) + y2 = m.incr_matrix_any(y, 10) # np -> eigen -> np + y3 = m.incr_matrix_any(y2[0::2, 0::2], -33) # np -> eigen -> np slice -> np -> eigen -> np + y4 = m.even_rows(y3) # numpy -> eigen slice -> (... y3) + y5 = m.even_cols(y4) # numpy -> eigen slice -> (... y4) + y6 = m.incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5) + + # Apply same mutations using just numpy: + yexpect = np.array(range(100), dtype='float64').reshape(10, 10) + yexpect += 10 + yexpect[0::2, 0::2] -= 33 + yexpect[0::4, 0::4] += 1000 + assert np.all(y6 == yexpect[0::4, 0::4]) + assert np.all(y5 == yexpect[0::4, 0::4]) + assert np.all(y4 == yexpect[0::4, 0::2]) + assert np.all(y3 == yexpect[0::2, 0::2]) + assert np.all(y2 == yexpect) + assert np.all(y == yexpect) + + +def test_nocopy_wrapper(): + # get_elem requires a column-contiguous matrix reference, but should be + # callable with other types of matrix (via copying): + int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order='F') + dbl_matrix_colmajor = np.array(int_matrix_colmajor, dtype='double', order='F', copy=True) + int_matrix_rowmajor = np.array(int_matrix_colmajor, order='C', copy=True) + dbl_matrix_rowmajor = np.array(int_matrix_rowmajor, dtype='double', order='C', copy=True) + + # All should be callable via get_elem: + assert m.get_elem(int_matrix_colmajor) == 8 + assert m.get_elem(dbl_matrix_colmajor) == 8 + assert m.get_elem(int_matrix_rowmajor) == 8 + assert m.get_elem(dbl_matrix_rowmajor) == 8 + + # All but the second should fail with m.get_elem_nocopy: + with pytest.raises(TypeError) as excinfo: + m.get_elem_nocopy(int_matrix_colmajor) + assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.f_contiguous' in str(excinfo.value)) + assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8 + with pytest.raises(TypeError) as excinfo: + m.get_elem_nocopy(int_matrix_rowmajor) + assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.f_contiguous' in str(excinfo.value)) + with pytest.raises(TypeError) as excinfo: + m.get_elem_nocopy(dbl_matrix_rowmajor) + assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.f_contiguous' in str(excinfo.value)) + + # For the row-major test, we take a long matrix in row-major, so only the third is allowed: + with pytest.raises(TypeError) as excinfo: + m.get_elem_rm_nocopy(int_matrix_colmajor) + assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.c_contiguous' in str(excinfo.value)) + with pytest.raises(TypeError) as excinfo: + m.get_elem_rm_nocopy(dbl_matrix_colmajor) + assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.c_contiguous' in str(excinfo.value)) + assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8 + with pytest.raises(TypeError) as excinfo: + m.get_elem_rm_nocopy(dbl_matrix_rowmajor) + assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.c_contiguous' in str(excinfo.value)) + + +def test_eigen_ref_life_support(): + """Ensure the lifetime of temporary arrays created by the `Ref` caster + + The `Ref` caster sometimes creates a copy which needs to stay alive. This needs to + happen both for directs casts (just the array) or indirectly (e.g. list of arrays). + """ + + a = np.full(shape=10, fill_value=8, dtype=np.int8) + assert m.get_elem_direct(a) == 8 + + list_of_a = [a] + assert m.get_elem_indirect(list_of_a) == 8 + + +def test_special_matrix_objects(): + assert np.all(m.incr_diag(7) == np.diag([1., 2, 3, 4, 5, 6, 7])) + + asymm = np.array([[ 1., 2, 3, 4], + [ 5, 6, 7, 8], + [ 9, 10, 11, 12], + [13, 14, 15, 16]]) + symm_lower = np.array(asymm) + symm_upper = np.array(asymm) + for i in range(4): + for j in range(i + 1, 4): + symm_lower[i, j] = symm_lower[j, i] + symm_upper[j, i] = symm_upper[i, j] + + assert np.all(m.symmetric_lower(asymm) == symm_lower) + assert np.all(m.symmetric_upper(asymm) == symm_upper) + + +def test_dense_signature(doc): + assert doc(m.double_col) == """ + double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]] + """ + assert doc(m.double_row) == """ + double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]] + """ + assert doc(m.double_complex) == """ + double_complex(arg0: numpy.ndarray[complex64[m, 1]]) -> numpy.ndarray[complex64[m, 1]] + """ + assert doc(m.double_mat_rm) == """ + double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]] + """ + + +def test_named_arguments(): + a = np.array([[1.0, 2], [3, 4], [5, 6]]) + b = np.ones((2, 1)) + + assert np.all(m.matrix_multiply(a, b) == np.array([[3.], [7], [11]])) + assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.], [7], [11]])) + assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.], [7], [11]])) + + with pytest.raises(ValueError) as excinfo: + m.matrix_multiply(b, a) + assert str(excinfo.value) == 'Nonconformable matrices!' + + with pytest.raises(ValueError) as excinfo: + m.matrix_multiply(A=b, B=a) + assert str(excinfo.value) == 'Nonconformable matrices!' + + with pytest.raises(ValueError) as excinfo: + m.matrix_multiply(B=a, A=b) + assert str(excinfo.value) == 'Nonconformable matrices!' + + +@pytest.requires_eigen_and_scipy +def test_sparse(): + assert_sparse_equal_ref(m.sparse_r()) + assert_sparse_equal_ref(m.sparse_c()) + assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_r())) + assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_c())) + assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_c())) + assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_r())) + + +@pytest.requires_eigen_and_scipy +def test_sparse_signature(doc): + assert doc(m.sparse_copy_r) == """ + sparse_copy_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32] + """ # noqa: E501 line too long + assert doc(m.sparse_copy_c) == """ + sparse_copy_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32] + """ # noqa: E501 line too long + + +def test_issue738(): + """Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)""" + assert np.all(m.iss738_f1(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]])) + assert np.all(m.iss738_f1(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]])) + + assert np.all(m.iss738_f2(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]])) + assert np.all(m.iss738_f2(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]])) + + +def test_issue1105(): + """Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen + compile-time row vectors or column vector""" + assert m.iss1105_row(np.ones((1, 7))) + assert m.iss1105_col(np.ones((7, 1))) + + # These should still fail (incompatible dimensions): + with pytest.raises(TypeError) as excinfo: + m.iss1105_row(np.ones((7, 1))) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.iss1105_col(np.ones((1, 7))) + assert "incompatible function arguments" in str(excinfo.value) + + +def test_custom_operator_new(): + """Using Eigen types as member variables requires a class-specific + operator new with proper alignment""" + + o = m.CustomOperatorNew() + np.testing.assert_allclose(o.a, 0.0) + np.testing.assert_allclose(o.b.diagonal(), 1.0) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b4f1f843e7194859adfa484bcbf6299f92885fa --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/CMakeLists.txt @@ -0,0 +1,41 @@ +if(${PYTHON_MODULE_EXTENSION} MATCHES "pypy") + add_custom_target(cpptest) # Dummy target on PyPy. Embedding is not supported. + set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") + return() +endif() + +find_package(Catch 1.9.3) +if(CATCH_FOUND) + message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}") +else() + message(STATUS "Catch not detected. Interpreter tests will be skipped. Install Catch headers" + " manually or use `cmake -DDOWNLOAD_CATCH=1` to fetch them automatically.") + return() +endif() + +add_executable(test_embed + catch.cpp + test_interpreter.cpp +) +target_include_directories(test_embed PRIVATE ${CATCH_INCLUDE_DIR}) +pybind11_enable_warnings(test_embed) + +if(NOT CMAKE_VERSION VERSION_LESS 3.0) + target_link_libraries(test_embed PRIVATE pybind11::embed) +else() + target_include_directories(test_embed PRIVATE ${PYBIND11_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS}) + target_compile_options(test_embed PRIVATE ${PYBIND11_CPP_STANDARD}) + target_link_libraries(test_embed PRIVATE ${PYTHON_LIBRARIES}) +endif() + +find_package(Threads REQUIRED) +target_link_libraries(test_embed PUBLIC ${CMAKE_THREAD_LIBS_INIT}) + +add_custom_target(cpptest COMMAND $ + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +pybind11_add_module(external_module THIN_LTO external_module.cpp) +set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +add_dependencies(cpptest external_module) + +add_dependencies(check cpptest) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/catch.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/catch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd137385cb32250b8640169934fb96aa5e80f069 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/catch.cpp @@ -0,0 +1,22 @@ +// The Catch implementation is compiled here. This is a standalone +// translation unit to avoid recompiling it for every test change. + +#include + +#ifdef _MSC_VER +// Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to catch +// 2.0.1; this should be fixed in the next catch release after 2.0.1). +# pragma warning(disable: 4996) +#endif + +#define CATCH_CONFIG_RUNNER +#include + +namespace py = pybind11; + +int main(int argc, char *argv[]) { + py::scoped_interpreter guard{}; + auto result = Catch::Session().run(argc, argv); + + return result < 0xff ? result : 0xff; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/external_module.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/external_module.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9a6058b179400545479412e5549d7a54f94caeb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/external_module.cpp @@ -0,0 +1,23 @@ +#include + +namespace py = pybind11; + +/* Simple test module/test class to check that the referenced internals data of external pybind11 + * modules aren't preserved over a finalize/initialize. + */ + +PYBIND11_MODULE(external_module, m) { + class A { + public: + A(int value) : v{value} {}; + int v; + }; + + py::class_(m, "A") + .def(py::init()) + .def_readwrite("value", &A::v); + + m.def("internals_at", []() { + return reinterpret_cast(&py::detail::get_internals()); + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/test_interpreter.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/test_interpreter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..222bd565fbffd6484db09876ae9cceabffcb69cd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/test_interpreter.cpp @@ -0,0 +1,284 @@ +#include + +#ifdef _MSC_VER +// Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to catch +// 2.0.1; this should be fixed in the next catch release after 2.0.1). +# pragma warning(disable: 4996) +#endif + +#include + +#include +#include +#include + +namespace py = pybind11; +using namespace py::literals; + +class Widget { +public: + Widget(std::string message) : message(message) { } + virtual ~Widget() = default; + + std::string the_message() const { return message; } + virtual int the_answer() const = 0; + +private: + std::string message; +}; + +class PyWidget final : public Widget { + using Widget::Widget; + + int the_answer() const override { PYBIND11_OVERLOAD_PURE(int, Widget, the_answer); } +}; + +PYBIND11_EMBEDDED_MODULE(widget_module, m) { + py::class_(m, "Widget") + .def(py::init()) + .def_property_readonly("the_message", &Widget::the_message); + + m.def("add", [](int i, int j) { return i + j; }); +} + +PYBIND11_EMBEDDED_MODULE(throw_exception, ) { + throw std::runtime_error("C++ Error"); +} + +PYBIND11_EMBEDDED_MODULE(throw_error_already_set, ) { + auto d = py::dict(); + d["missing"].cast(); +} + +TEST_CASE("Pass classes and data between modules defined in C++ and Python") { + auto module = py::module::import("test_interpreter"); + REQUIRE(py::hasattr(module, "DerivedWidget")); + + auto locals = py::dict("hello"_a="Hello, World!", "x"_a=5, **module.attr("__dict__")); + py::exec(R"( + widget = DerivedWidget("{} - {}".format(hello, x)) + message = widget.the_message + )", py::globals(), locals); + REQUIRE(locals["message"].cast() == "Hello, World! - 5"); + + auto py_widget = module.attr("DerivedWidget")("The question"); + auto message = py_widget.attr("the_message"); + REQUIRE(message.cast() == "The question"); + + const auto &cpp_widget = py_widget.cast(); + REQUIRE(cpp_widget.the_answer() == 42); +} + +TEST_CASE("Import error handling") { + REQUIRE_NOTHROW(py::module::import("widget_module")); + REQUIRE_THROWS_WITH(py::module::import("throw_exception"), + "ImportError: C++ Error"); + REQUIRE_THROWS_WITH(py::module::import("throw_error_already_set"), + Catch::Contains("ImportError: KeyError")); +} + +TEST_CASE("There can be only one interpreter") { + static_assert(std::is_move_constructible::value, ""); + static_assert(!std::is_move_assignable::value, ""); + static_assert(!std::is_copy_constructible::value, ""); + static_assert(!std::is_copy_assignable::value, ""); + + REQUIRE_THROWS_WITH(py::initialize_interpreter(), "The interpreter is already running"); + REQUIRE_THROWS_WITH(py::scoped_interpreter(), "The interpreter is already running"); + + py::finalize_interpreter(); + REQUIRE_NOTHROW(py::scoped_interpreter()); + { + auto pyi1 = py::scoped_interpreter(); + auto pyi2 = std::move(pyi1); + } + py::initialize_interpreter(); +} + +bool has_pybind11_internals_builtin() { + auto builtins = py::handle(PyEval_GetBuiltins()); + return builtins.contains(PYBIND11_INTERNALS_ID); +}; + +bool has_pybind11_internals_static() { + auto **&ipp = py::detail::get_internals_pp(); + return ipp && *ipp; +} + +TEST_CASE("Restart the interpreter") { + // Verify pre-restart state. + REQUIRE(py::module::import("widget_module").attr("add")(1, 2).cast() == 3); + REQUIRE(has_pybind11_internals_builtin()); + REQUIRE(has_pybind11_internals_static()); + REQUIRE(py::module::import("external_module").attr("A")(123).attr("value").cast() == 123); + + // local and foreign module internals should point to the same internals: + REQUIRE(reinterpret_cast(*py::detail::get_internals_pp()) == + py::module::import("external_module").attr("internals_at")().cast()); + + // Restart the interpreter. + py::finalize_interpreter(); + REQUIRE(Py_IsInitialized() == 0); + + py::initialize_interpreter(); + REQUIRE(Py_IsInitialized() == 1); + + // Internals are deleted after a restart. + REQUIRE_FALSE(has_pybind11_internals_builtin()); + REQUIRE_FALSE(has_pybind11_internals_static()); + pybind11::detail::get_internals(); + REQUIRE(has_pybind11_internals_builtin()); + REQUIRE(has_pybind11_internals_static()); + REQUIRE(reinterpret_cast(*py::detail::get_internals_pp()) == + py::module::import("external_module").attr("internals_at")().cast()); + + // Make sure that an interpreter with no get_internals() created until finalize still gets the + // internals destroyed + py::finalize_interpreter(); + py::initialize_interpreter(); + bool ran = false; + py::module::import("__main__").attr("internals_destroy_test") = + py::capsule(&ran, [](void *ran) { py::detail::get_internals(); *static_cast(ran) = true; }); + REQUIRE_FALSE(has_pybind11_internals_builtin()); + REQUIRE_FALSE(has_pybind11_internals_static()); + REQUIRE_FALSE(ran); + py::finalize_interpreter(); + REQUIRE(ran); + py::initialize_interpreter(); + REQUIRE_FALSE(has_pybind11_internals_builtin()); + REQUIRE_FALSE(has_pybind11_internals_static()); + + // C++ modules can be reloaded. + auto cpp_module = py::module::import("widget_module"); + REQUIRE(cpp_module.attr("add")(1, 2).cast() == 3); + + // C++ type information is reloaded and can be used in python modules. + auto py_module = py::module::import("test_interpreter"); + auto py_widget = py_module.attr("DerivedWidget")("Hello after restart"); + REQUIRE(py_widget.attr("the_message").cast() == "Hello after restart"); +} + +TEST_CASE("Subinterpreter") { + // Add tags to the modules in the main interpreter and test the basics. + py::module::import("__main__").attr("main_tag") = "main interpreter"; + { + auto m = py::module::import("widget_module"); + m.attr("extension_module_tag") = "added to module in main interpreter"; + + REQUIRE(m.attr("add")(1, 2).cast() == 3); + } + REQUIRE(has_pybind11_internals_builtin()); + REQUIRE(has_pybind11_internals_static()); + + /// Create and switch to a subinterpreter. + auto main_tstate = PyThreadState_Get(); + auto sub_tstate = Py_NewInterpreter(); + + // Subinterpreters get their own copy of builtins. detail::get_internals() still + // works by returning from the static variable, i.e. all interpreters share a single + // global pybind11::internals; + REQUIRE_FALSE(has_pybind11_internals_builtin()); + REQUIRE(has_pybind11_internals_static()); + + // Modules tags should be gone. + REQUIRE_FALSE(py::hasattr(py::module::import("__main__"), "tag")); + { + auto m = py::module::import("widget_module"); + REQUIRE_FALSE(py::hasattr(m, "extension_module_tag")); + + // Function bindings should still work. + REQUIRE(m.attr("add")(1, 2).cast() == 3); + } + + // Restore main interpreter. + Py_EndInterpreter(sub_tstate); + PyThreadState_Swap(main_tstate); + + REQUIRE(py::hasattr(py::module::import("__main__"), "main_tag")); + REQUIRE(py::hasattr(py::module::import("widget_module"), "extension_module_tag")); +} + +TEST_CASE("Execution frame") { + // When the interpreter is embedded, there is no execution frame, but `py::exec` + // should still function by using reasonable globals: `__main__.__dict__`. + py::exec("var = dict(number=42)"); + REQUIRE(py::globals()["var"]["number"].cast() == 42); +} + +TEST_CASE("Threads") { + // Restart interpreter to ensure threads are not initialized + py::finalize_interpreter(); + py::initialize_interpreter(); + REQUIRE_FALSE(has_pybind11_internals_static()); + + constexpr auto num_threads = 10; + auto locals = py::dict("count"_a=0); + + { + py::gil_scoped_release gil_release{}; + REQUIRE(has_pybind11_internals_static()); + + auto threads = std::vector(); + for (auto i = 0; i < num_threads; ++i) { + threads.emplace_back([&]() { + py::gil_scoped_acquire gil{}; + locals["count"] = locals["count"].cast() + 1; + }); + } + + for (auto &thread : threads) { + thread.join(); + } + } + + REQUIRE(locals["count"].cast() == num_threads); +} + +// Scope exit utility https://stackoverflow.com/a/36644501/7255855 +struct scope_exit { + std::function f_; + explicit scope_exit(std::function f) noexcept : f_(std::move(f)) {} + ~scope_exit() { if (f_) f_(); } +}; + +TEST_CASE("Reload module from file") { + // Disable generation of cached bytecode (.pyc files) for this test, otherwise + // Python might pick up an old version from the cache instead of the new versions + // of the .py files generated below + auto sys = py::module::import("sys"); + bool dont_write_bytecode = sys.attr("dont_write_bytecode").cast(); + sys.attr("dont_write_bytecode") = true; + // Reset the value at scope exit + scope_exit reset_dont_write_bytecode([&]() { + sys.attr("dont_write_bytecode") = dont_write_bytecode; + }); + + std::string module_name = "test_module_reload"; + std::string module_file = module_name + ".py"; + + // Create the module .py file + std::ofstream test_module(module_file); + test_module << "def test():\n"; + test_module << " return 1\n"; + test_module.close(); + // Delete the file at scope exit + scope_exit delete_module_file([&]() { + std::remove(module_file.c_str()); + }); + + // Import the module from file + auto module = py::module::import(module_name.c_str()); + int result = module.attr("test")().cast(); + REQUIRE(result == 1); + + // Update the module .py file with a small change + test_module.open(module_file); + test_module << "def test():\n"; + test_module << " return 2\n"; + test_module.close(); + + // Reload the module + module.reload(); + result = module.attr("test")().cast(); + REQUIRE(result == 2); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/test_interpreter.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/test_interpreter.py new file mode 100644 index 0000000000000000000000000000000000000000..26a0479216942d5fa91ae59b4e9f07ab4d45f942 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_embed/test_interpreter.py @@ -0,0 +1,9 @@ +from widget_module import Widget + + +class DerivedWidget(Widget): + def __init__(self, message): + super(DerivedWidget, self).__init__(message) + + def the_answer(self): + return 42 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_enum.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_enum.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3153089208c964346e2fc39cafad8d0b372f1154 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_enum.cpp @@ -0,0 +1,87 @@ +/* + tests/test_enums.cpp -- enumerations + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +TEST_SUBMODULE(enums, m) { + // test_unscoped_enum + enum UnscopedEnum { + EOne = 1, + ETwo, + EThree + }; + py::enum_(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration") + .value("EOne", EOne, "Docstring for EOne") + .value("ETwo", ETwo, "Docstring for ETwo") + .value("EThree", EThree, "Docstring for EThree") + .export_values(); + + // test_scoped_enum + enum class ScopedEnum { + Two = 2, + Three + }; + py::enum_(m, "ScopedEnum", py::arithmetic()) + .value("Two", ScopedEnum::Two) + .value("Three", ScopedEnum::Three); + + m.def("test_scoped_enum", [](ScopedEnum z) { + return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three"); + }); + + // test_binary_operators + enum Flags { + Read = 4, + Write = 2, + Execute = 1 + }; + py::enum_(m, "Flags", py::arithmetic()) + .value("Read", Flags::Read) + .value("Write", Flags::Write) + .value("Execute", Flags::Execute) + .export_values(); + + // test_implicit_conversion + class ClassWithUnscopedEnum { + public: + enum EMode { + EFirstMode = 1, + ESecondMode + }; + + static EMode test_function(EMode mode) { + return mode; + } + }; + py::class_ exenum_class(m, "ClassWithUnscopedEnum"); + exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function); + py::enum_(exenum_class, "EMode") + .value("EFirstMode", ClassWithUnscopedEnum::EFirstMode) + .value("ESecondMode", ClassWithUnscopedEnum::ESecondMode) + .export_values(); + + // test_enum_to_int + m.def("test_enum_to_int", [](int) { }); + m.def("test_enum_to_uint", [](uint32_t) { }); + m.def("test_enum_to_long_long", [](long long) { }); + + // test_duplicate_enum_name + enum SimpleEnum + { + ONE, TWO, THREE + }; + + m.def("register_bad_enum", [m]() { + py::enum_(m, "SimpleEnum") + .value("ONE", SimpleEnum::ONE) //NOTE: all value function calls are called with the same first parameter value + .value("ONE", SimpleEnum::TWO) + .value("ONE", SimpleEnum::THREE) + .export_values(); + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_enum.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_enum.py new file mode 100644 index 0000000000000000000000000000000000000000..7fe9b618d6e80d4b52d9ae5280c9896a76ad2c88 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_enum.py @@ -0,0 +1,206 @@ +import pytest +from pybind11_tests import enums as m + + +def test_unscoped_enum(): + assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne" + assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo" + assert str(m.EOne) == "UnscopedEnum.EOne" + + # name property + assert m.UnscopedEnum.EOne.name == "EOne" + assert m.UnscopedEnum.ETwo.name == "ETwo" + assert m.EOne.name == "EOne" + # name readonly + with pytest.raises(AttributeError): + m.UnscopedEnum.EOne.name = "" + # name returns a copy + foo = m.UnscopedEnum.EOne.name + foo = "bar" + assert m.UnscopedEnum.EOne.name == "EOne" + + # __members__ property + assert m.UnscopedEnum.__members__ == \ + {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree} + # __members__ readonly + with pytest.raises(AttributeError): + m.UnscopedEnum.__members__ = {} + # __members__ returns a copy + foo = m.UnscopedEnum.__members__ + foo["bar"] = "baz" + assert m.UnscopedEnum.__members__ == \ + {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo, "EThree": m.UnscopedEnum.EThree} + + for docstring_line in '''An unscoped enumeration + +Members: + + EOne : Docstring for EOne + + ETwo : Docstring for ETwo + + EThree : Docstring for EThree'''.split('\n'): + assert docstring_line in m.UnscopedEnum.__doc__ + + # Unscoped enums will accept ==/!= int comparisons + y = m.UnscopedEnum.ETwo + assert y == 2 + assert 2 == y + assert y != 3 + assert 3 != y + # Compare with None + assert (y != None) # noqa: E711 + assert not (y == None) # noqa: E711 + # Compare with an object + assert (y != object()) + assert not (y == object()) + # Compare with string + assert y != "2" + assert "2" != y + assert not ("2" == y) + assert not (y == "2") + + with pytest.raises(TypeError): + y < object() + + with pytest.raises(TypeError): + y <= object() + + with pytest.raises(TypeError): + y > object() + + with pytest.raises(TypeError): + y >= object() + + with pytest.raises(TypeError): + y | object() + + with pytest.raises(TypeError): + y & object() + + with pytest.raises(TypeError): + y ^ object() + + assert int(m.UnscopedEnum.ETwo) == 2 + assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo" + + # order + assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo + assert m.UnscopedEnum.EOne < 2 + assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne + assert m.UnscopedEnum.ETwo > 1 + assert m.UnscopedEnum.ETwo <= 2 + assert m.UnscopedEnum.ETwo >= 2 + assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo + assert m.UnscopedEnum.EOne <= 2 + assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne + assert m.UnscopedEnum.ETwo >= 1 + assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne) + assert not (2 < m.UnscopedEnum.EOne) + + # arithmetic + assert m.UnscopedEnum.EOne & m.UnscopedEnum.EThree == m.UnscopedEnum.EOne + assert m.UnscopedEnum.EOne | m.UnscopedEnum.ETwo == m.UnscopedEnum.EThree + assert m.UnscopedEnum.EOne ^ m.UnscopedEnum.EThree == m.UnscopedEnum.ETwo + + +def test_scoped_enum(): + assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three" + z = m.ScopedEnum.Two + assert m.test_scoped_enum(z) == "ScopedEnum::Two" + + # Scoped enums will *NOT* accept ==/!= int comparisons (Will always return False) + assert not z == 3 + assert not 3 == z + assert z != 3 + assert 3 != z + # Compare with None + assert (z != None) # noqa: E711 + assert not (z == None) # noqa: E711 + # Compare with an object + assert (z != object()) + assert not (z == object()) + # Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions) + with pytest.raises(TypeError): + z > 3 + with pytest.raises(TypeError): + z < 3 + with pytest.raises(TypeError): + z >= 3 + with pytest.raises(TypeError): + z <= 3 + + # order + assert m.ScopedEnum.Two < m.ScopedEnum.Three + assert m.ScopedEnum.Three > m.ScopedEnum.Two + assert m.ScopedEnum.Two <= m.ScopedEnum.Three + assert m.ScopedEnum.Two <= m.ScopedEnum.Two + assert m.ScopedEnum.Two >= m.ScopedEnum.Two + assert m.ScopedEnum.Three >= m.ScopedEnum.Two + + +def test_implicit_conversion(): + assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode" + assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode" + + f = m.ClassWithUnscopedEnum.test_function + first = m.ClassWithUnscopedEnum.EFirstMode + second = m.ClassWithUnscopedEnum.ESecondMode + + assert f(first) == 1 + + assert f(first) == f(first) + assert not f(first) != f(first) + + assert f(first) != f(second) + assert not f(first) == f(second) + + assert f(first) == int(f(first)) + assert not f(first) != int(f(first)) + + assert f(first) != int(f(second)) + assert not f(first) == int(f(second)) + + # noinspection PyDictCreation + x = {f(first): 1, f(second): 2} + x[f(first)] = 3 + x[f(second)] = 4 + # Hashing test + assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}" + + +def test_binary_operators(): + assert int(m.Flags.Read) == 4 + assert int(m.Flags.Write) == 2 + assert int(m.Flags.Execute) == 1 + assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7 + assert int(m.Flags.Read | m.Flags.Write) == 6 + assert int(m.Flags.Read | m.Flags.Execute) == 5 + assert int(m.Flags.Write | m.Flags.Execute) == 3 + assert int(m.Flags.Write | 1) == 3 + assert ~m.Flags.Write == -3 + + state = m.Flags.Read | m.Flags.Write + assert (state & m.Flags.Read) != 0 + assert (state & m.Flags.Write) != 0 + assert (state & m.Flags.Execute) == 0 + assert (state & 1) == 0 + + state2 = ~state + assert state2 == -7 + assert int(state ^ state2) == -1 + + +def test_enum_to_int(): + m.test_enum_to_int(m.Flags.Read) + m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode) + m.test_enum_to_uint(m.Flags.Read) + m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode) + m.test_enum_to_long_long(m.Flags.Read) + m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode) + + +def test_duplicate_enum_name(): + with pytest.raises(ValueError) as excinfo: + m.register_bad_enum() + assert str(excinfo.value) == 'SimpleEnum: element "ONE" already exists!' diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eval.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eval.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0948219117df7d8fd64dba3130d36e1307f272b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eval.cpp @@ -0,0 +1,91 @@ +/* + tests/test_eval.cpp -- Usage of eval() and eval_file() + + Copyright (c) 2016 Klemens D. Morgenstern + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + + +#include +#include "pybind11_tests.h" + +TEST_SUBMODULE(eval_, m) { + // test_evals + + auto global = py::dict(py::module::import("__main__").attr("__dict__")); + + m.def("test_eval_statements", [global]() { + auto local = py::dict(); + local["call_test"] = py::cpp_function([&]() -> int { + return 42; + }); + + // Regular string literal + py::exec( + "message = 'Hello World!'\n" + "x = call_test()", + global, local + ); + + // Multi-line raw string literal + py::exec(R"( + if x == 42: + print(message) + else: + raise RuntimeError + )", global, local + ); + auto x = local["x"].cast(); + + return x == 42; + }); + + m.def("test_eval", [global]() { + auto local = py::dict(); + local["x"] = py::int_(42); + auto x = py::eval("x", global, local); + return x.cast() == 42; + }); + + m.def("test_eval_single_statement", []() { + auto local = py::dict(); + local["call_test"] = py::cpp_function([&]() -> int { + return 42; + }); + + auto result = py::eval("x = call_test()", py::dict(), local); + auto x = local["x"].cast(); + return result.is_none() && x == 42; + }); + + m.def("test_eval_file", [global](py::str filename) { + auto local = py::dict(); + local["y"] = py::int_(43); + + int val_out; + local["call_test2"] = py::cpp_function([&](int value) { val_out = value; }); + + auto result = py::eval_file(filename, global, local); + return val_out == 43 && result.is_none(); + }); + + m.def("test_eval_failure", []() { + try { + py::eval("nonsense code ..."); + } catch (py::error_already_set &) { + return true; + } + return false; + }); + + m.def("test_eval_file_failure", []() { + try { + py::eval_file("non-existing file"); + } catch (std::exception &) { + return true; + } + return false; + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eval.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eval.py new file mode 100644 index 0000000000000000000000000000000000000000..bda4ef6bf6aef3054cd28aeca79504f07a8f814e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eval.py @@ -0,0 +1,17 @@ +import os +from pybind11_tests import eval_ as m + + +def test_evals(capture): + with capture: + assert m.test_eval_statements() + assert capture == "Hello World!" + + assert m.test_eval() + assert m.test_eval_single_statement() + + filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py") + assert m.test_eval_file(filename) + + assert m.test_eval_failure() + assert m.test_eval_file_failure() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eval_call.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eval_call.py new file mode 100644 index 0000000000000000000000000000000000000000..53c7e721fec9490a208be8deafed5e4c27363425 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_eval_call.py @@ -0,0 +1,4 @@ +# This file is called from 'test_eval.py' + +if 'call_test2' in locals(): + call_test2(y) # noqa: F821 undefined name diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_exceptions.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_exceptions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56cd9bc48f751bc9d75e2c1ac6d846a909af8976 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_exceptions.cpp @@ -0,0 +1,197 @@ +/* + tests/test_custom-exceptions.cpp -- exception translation + + Copyright (c) 2016 Pim Schellart + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +// A type that should be raised as an exception in Python +class MyException : public std::exception { +public: + explicit MyException(const char * m) : message{m} {} + virtual const char * what() const noexcept override {return message.c_str();} +private: + std::string message = ""; +}; + +// A type that should be translated to a standard Python exception +class MyException2 : public std::exception { +public: + explicit MyException2(const char * m) : message{m} {} + virtual const char * what() const noexcept override {return message.c_str();} +private: + std::string message = ""; +}; + +// A type that is not derived from std::exception (and is thus unknown) +class MyException3 { +public: + explicit MyException3(const char * m) : message{m} {} + virtual const char * what() const noexcept {return message.c_str();} +private: + std::string message = ""; +}; + +// A type that should be translated to MyException +// and delegated to its exception translator +class MyException4 : public std::exception { +public: + explicit MyException4(const char * m) : message{m} {} + virtual const char * what() const noexcept override {return message.c_str();} +private: + std::string message = ""; +}; + + +// Like the above, but declared via the helper function +class MyException5 : public std::logic_error { +public: + explicit MyException5(const std::string &what) : std::logic_error(what) {} +}; + +// Inherits from MyException5 +class MyException5_1 : public MyException5 { + using MyException5::MyException5; +}; + +struct PythonCallInDestructor { + PythonCallInDestructor(const py::dict &d) : d(d) {} + ~PythonCallInDestructor() { d["good"] = true; } + + py::dict d; +}; + +TEST_SUBMODULE(exceptions, m) { + m.def("throw_std_exception", []() { + throw std::runtime_error("This exception was intentionally thrown."); + }); + + // make a new custom exception and use it as a translation target + static py::exception ex(m, "MyException"); + py::register_exception_translator([](std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (const MyException &e) { + // Set MyException as the active python error + ex(e.what()); + } + }); + + // register new translator for MyException2 + // no need to store anything here because this type will + // never by visible from Python + py::register_exception_translator([](std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (const MyException2 &e) { + // Translate this exception to a standard RuntimeError + PyErr_SetString(PyExc_RuntimeError, e.what()); + } + }); + + // register new translator for MyException4 + // which will catch it and delegate to the previously registered + // translator for MyException by throwing a new exception + py::register_exception_translator([](std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (const MyException4 &e) { + throw MyException(e.what()); + } + }); + + // A simple exception translation: + auto ex5 = py::register_exception(m, "MyException5"); + // A slightly more complicated one that declares MyException5_1 as a subclass of MyException5 + py::register_exception(m, "MyException5_1", ex5.ptr()); + + m.def("throws1", []() { throw MyException("this error should go to a custom type"); }); + m.def("throws2", []() { throw MyException2("this error should go to a standard Python exception"); }); + m.def("throws3", []() { throw MyException3("this error cannot be translated"); }); + m.def("throws4", []() { throw MyException4("this error is rethrown"); }); + m.def("throws5", []() { throw MyException5("this is a helper-defined translated exception"); }); + m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); }); + m.def("throws_logic_error", []() { throw std::logic_error("this error should fall through to the standard handler"); }); + m.def("throws_overflow_error", []() {throw std::overflow_error(""); }); + m.def("exception_matches", []() { + py::dict foo; + try { + // Assign to a py::object to force read access of nonexistent dict entry + py::object o = foo["bar"]; + } + catch (py::error_already_set& ex) { + if (!ex.matches(PyExc_KeyError)) throw; + return true; + } + return false; + }); + m.def("exception_matches_base", []() { + py::dict foo; + try { + // Assign to a py::object to force read access of nonexistent dict entry + py::object o = foo["bar"]; + } + catch (py::error_already_set &ex) { + if (!ex.matches(PyExc_Exception)) throw; + return true; + } + return false; + }); + m.def("modulenotfound_exception_matches_base", []() { + try { + // On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError + py::module::import("nonexistent"); + } + catch (py::error_already_set &ex) { + if (!ex.matches(PyExc_ImportError)) throw; + return true; + } + return false; + }); + + m.def("throw_already_set", [](bool err) { + if (err) + PyErr_SetString(PyExc_ValueError, "foo"); + try { + throw py::error_already_set(); + } catch (const std::runtime_error& e) { + if ((err && e.what() != std::string("ValueError: foo")) || + (!err && e.what() != std::string("Unknown internal error occurred"))) + { + PyErr_Clear(); + throw std::runtime_error("error message mismatch"); + } + } + PyErr_Clear(); + if (err) + PyErr_SetString(PyExc_ValueError, "foo"); + throw py::error_already_set(); + }); + + m.def("python_call_in_destructor", [](py::dict d) { + try { + PythonCallInDestructor set_dict_in_destructor(d); + PyErr_SetString(PyExc_ValueError, "foo"); + throw py::error_already_set(); + } catch (const py::error_already_set&) { + return true; + } + return false; + }); + + // test_nested_throws + m.def("try_catch", [m](py::object exc_type, py::function f, py::args args) { + try { f(*args); } + catch (py::error_already_set &ex) { + if (ex.matches(exc_type)) + py::print(ex.what()); + else + throw; + } + }); + +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_exceptions.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..ac2b3603ec9101a815c38a1bc81e5c18ea79c7fe --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_exceptions.py @@ -0,0 +1,150 @@ +import pytest + +from pybind11_tests import exceptions as m +import pybind11_cross_module_tests as cm + + +def test_std_exception(msg): + with pytest.raises(RuntimeError) as excinfo: + m.throw_std_exception() + assert msg(excinfo.value) == "This exception was intentionally thrown." + + +def test_error_already_set(msg): + with pytest.raises(RuntimeError) as excinfo: + m.throw_already_set(False) + assert msg(excinfo.value) == "Unknown internal error occurred" + + with pytest.raises(ValueError) as excinfo: + m.throw_already_set(True) + assert msg(excinfo.value) == "foo" + + +def test_cross_module_exceptions(): + with pytest.raises(RuntimeError) as excinfo: + cm.raise_runtime_error() + assert str(excinfo.value) == "My runtime error" + + with pytest.raises(ValueError) as excinfo: + cm.raise_value_error() + assert str(excinfo.value) == "My value error" + + with pytest.raises(ValueError) as excinfo: + cm.throw_pybind_value_error() + assert str(excinfo.value) == "pybind11 value error" + + with pytest.raises(TypeError) as excinfo: + cm.throw_pybind_type_error() + assert str(excinfo.value) == "pybind11 type error" + + with pytest.raises(StopIteration) as excinfo: + cm.throw_stop_iteration() + + +def test_python_call_in_catch(): + d = {} + assert m.python_call_in_destructor(d) is True + assert d["good"] is True + + +def test_exception_matches(): + assert m.exception_matches() + assert m.exception_matches_base() + assert m.modulenotfound_exception_matches_base() + + +def test_custom(msg): + # Can we catch a MyException? + with pytest.raises(m.MyException) as excinfo: + m.throws1() + assert msg(excinfo.value) == "this error should go to a custom type" + + # Can we translate to standard Python exceptions? + with pytest.raises(RuntimeError) as excinfo: + m.throws2() + assert msg(excinfo.value) == "this error should go to a standard Python exception" + + # Can we handle unknown exceptions? + with pytest.raises(RuntimeError) as excinfo: + m.throws3() + assert msg(excinfo.value) == "Caught an unknown exception!" + + # Can we delegate to another handler by rethrowing? + with pytest.raises(m.MyException) as excinfo: + m.throws4() + assert msg(excinfo.value) == "this error is rethrown" + + # Can we fall-through to the default handler? + with pytest.raises(RuntimeError) as excinfo: + m.throws_logic_error() + assert msg(excinfo.value) == "this error should fall through to the standard handler" + + # OverFlow error translation. + with pytest.raises(OverflowError) as excinfo: + m.throws_overflow_error() + + # Can we handle a helper-declared exception? + with pytest.raises(m.MyException5) as excinfo: + m.throws5() + assert msg(excinfo.value) == "this is a helper-defined translated exception" + + # Exception subclassing: + with pytest.raises(m.MyException5) as excinfo: + m.throws5_1() + assert msg(excinfo.value) == "MyException5 subclass" + assert isinstance(excinfo.value, m.MyException5_1) + + with pytest.raises(m.MyException5_1) as excinfo: + m.throws5_1() + assert msg(excinfo.value) == "MyException5 subclass" + + with pytest.raises(m.MyException5) as excinfo: + try: + m.throws5() + except m.MyException5_1: + raise RuntimeError("Exception error: caught child from parent") + assert msg(excinfo.value) == "this is a helper-defined translated exception" + + +def test_nested_throws(capture): + """Tests nested (e.g. C++ -> Python -> C++) exception handling""" + + def throw_myex(): + raise m.MyException("nested error") + + def throw_myex5(): + raise m.MyException5("nested error 5") + + # In the comments below, the exception is caught in the first step, thrown in the last step + + # C++ -> Python + with capture: + m.try_catch(m.MyException5, throw_myex5) + assert str(capture).startswith("MyException5: nested error 5") + + # Python -> C++ -> Python + with pytest.raises(m.MyException) as excinfo: + m.try_catch(m.MyException5, throw_myex) + assert str(excinfo.value) == "nested error" + + def pycatch(exctype, f, *args): + try: + f(*args) + except m.MyException as e: + print(e) + + # C++ -> Python -> C++ -> Python + with capture: + m.try_catch( + m.MyException5, pycatch, m.MyException, m.try_catch, m.MyException, throw_myex5) + assert str(capture).startswith("MyException5: nested error 5") + + # C++ -> Python -> C++ + with capture: + m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4) + assert capture == "this error is rethrown" + + # Python -> C++ -> Python -> C++ + with pytest.raises(m.MyException5) as excinfo: + m.try_catch(m.MyException, pycatch, m.MyException, m.throws5) + assert str(excinfo.value) == "this is a helper-defined translated exception" diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_factory_constructors.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_factory_constructors.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5cfbfdc3f8f856e3a953113d25778c09d1b9baa4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_factory_constructors.cpp @@ -0,0 +1,338 @@ +/* + tests/test_factory_constructors.cpp -- tests construction from a factory function + via py::init_factory() + + Copyright (c) 2017 Jason Rhinelander + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include + +// Classes for testing python construction via C++ factory function: +// Not publicly constructible, copyable, or movable: +class TestFactory1 { + friend class TestFactoryHelper; + TestFactory1() : value("(empty)") { print_default_created(this); } + TestFactory1(int v) : value(std::to_string(v)) { print_created(this, value); } + TestFactory1(std::string v) : value(std::move(v)) { print_created(this, value); } + TestFactory1(TestFactory1 &&) = delete; + TestFactory1(const TestFactory1 &) = delete; + TestFactory1 &operator=(TestFactory1 &&) = delete; + TestFactory1 &operator=(const TestFactory1 &) = delete; +public: + std::string value; + ~TestFactory1() { print_destroyed(this); } +}; +// Non-public construction, but moveable: +class TestFactory2 { + friend class TestFactoryHelper; + TestFactory2() : value("(empty2)") { print_default_created(this); } + TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); } + TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); } +public: + TestFactory2(TestFactory2 &&m) { value = std::move(m.value); print_move_created(this); } + TestFactory2 &operator=(TestFactory2 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } + std::string value; + ~TestFactory2() { print_destroyed(this); } +}; +// Mixed direct/factory construction: +class TestFactory3 { +protected: + friend class TestFactoryHelper; + TestFactory3() : value("(empty3)") { print_default_created(this); } + TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); } +public: + TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); } + TestFactory3(TestFactory3 &&m) { value = std::move(m.value); print_move_created(this); } + TestFactory3 &operator=(TestFactory3 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } + std::string value; + virtual ~TestFactory3() { print_destroyed(this); } +}; +// Inheritance test +class TestFactory4 : public TestFactory3 { +public: + TestFactory4() : TestFactory3() { print_default_created(this); } + TestFactory4(int v) : TestFactory3(v) { print_created(this, v); } + virtual ~TestFactory4() { print_destroyed(this); } +}; +// Another class for an invalid downcast test +class TestFactory5 : public TestFactory3 { +public: + TestFactory5(int i) : TestFactory3(i) { print_created(this, i); } + virtual ~TestFactory5() { print_destroyed(this); } +}; + +class TestFactory6 { +protected: + int value; + bool alias = false; +public: + TestFactory6(int i) : value{i} { print_created(this, i); } + TestFactory6(TestFactory6 &&f) { print_move_created(this); value = f.value; alias = f.alias; } + TestFactory6(const TestFactory6 &f) { print_copy_created(this); value = f.value; alias = f.alias; } + virtual ~TestFactory6() { print_destroyed(this); } + virtual int get() { return value; } + bool has_alias() { return alias; } +}; +class PyTF6 : public TestFactory6 { +public: + // Special constructor that allows the factory to construct a PyTF6 from a TestFactory6 only + // when an alias is needed: + PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) { alias = true; print_created(this, "move", value); } + PyTF6(int i) : TestFactory6(i) { alias = true; print_created(this, i); } + PyTF6(PyTF6 &&f) : TestFactory6(std::move(f)) { print_move_created(this); } + PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); } + PyTF6(std::string s) : TestFactory6((int) s.size()) { alias = true; print_created(this, s); } + virtual ~PyTF6() { print_destroyed(this); } + int get() override { PYBIND11_OVERLOAD(int, TestFactory6, get, /*no args*/); } +}; + +class TestFactory7 { +protected: + int value; + bool alias = false; +public: + TestFactory7(int i) : value{i} { print_created(this, i); } + TestFactory7(TestFactory7 &&f) { print_move_created(this); value = f.value; alias = f.alias; } + TestFactory7(const TestFactory7 &f) { print_copy_created(this); value = f.value; alias = f.alias; } + virtual ~TestFactory7() { print_destroyed(this); } + virtual int get() { return value; } + bool has_alias() { return alias; } +}; +class PyTF7 : public TestFactory7 { +public: + PyTF7(int i) : TestFactory7(i) { alias = true; print_created(this, i); } + PyTF7(PyTF7 &&f) : TestFactory7(std::move(f)) { print_move_created(this); } + PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); } + virtual ~PyTF7() { print_destroyed(this); } + int get() override { PYBIND11_OVERLOAD(int, TestFactory7, get, /*no args*/); } +}; + + +class TestFactoryHelper { +public: + // Non-movable, non-copyable type: + // Return via pointer: + static TestFactory1 *construct1() { return new TestFactory1(); } + // Holder: + static std::unique_ptr construct1(int a) { return std::unique_ptr(new TestFactory1(a)); } + // pointer again + static TestFactory1 *construct1_string(std::string a) { return new TestFactory1(a); } + + // Moveable type: + // pointer: + static TestFactory2 *construct2() { return new TestFactory2(); } + // holder: + static std::unique_ptr construct2(int a) { return std::unique_ptr(new TestFactory2(a)); } + // by value moving: + static TestFactory2 construct2(std::string a) { return TestFactory2(a); } + + // shared_ptr holder type: + // pointer: + static TestFactory3 *construct3() { return new TestFactory3(); } + // holder: + static std::shared_ptr construct3(int a) { return std::shared_ptr(new TestFactory3(a)); } +}; + +TEST_SUBMODULE(factory_constructors, m) { + + // Define various trivial types to allow simpler overload resolution: + py::module m_tag = m.def_submodule("tag"); +#define MAKE_TAG_TYPE(Name) \ + struct Name##_tag {}; \ + py::class_(m_tag, #Name "_tag").def(py::init<>()); \ + m_tag.attr(#Name) = py::cast(Name##_tag{}) + MAKE_TAG_TYPE(pointer); + MAKE_TAG_TYPE(unique_ptr); + MAKE_TAG_TYPE(move); + MAKE_TAG_TYPE(shared_ptr); + MAKE_TAG_TYPE(derived); + MAKE_TAG_TYPE(TF4); + MAKE_TAG_TYPE(TF5); + MAKE_TAG_TYPE(null_ptr); + MAKE_TAG_TYPE(base); + MAKE_TAG_TYPE(invalid_base); + MAKE_TAG_TYPE(alias); + MAKE_TAG_TYPE(unaliasable); + MAKE_TAG_TYPE(mixed); + + // test_init_factory_basic, test_bad_type + py::class_(m, "TestFactory1") + .def(py::init([](unique_ptr_tag, int v) { return TestFactoryHelper::construct1(v); })) + .def(py::init(&TestFactoryHelper::construct1_string)) // raw function pointer + .def(py::init([](pointer_tag) { return TestFactoryHelper::construct1(); })) + .def(py::init([](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); })) + .def_readwrite("value", &TestFactory1::value) + ; + py::class_(m, "TestFactory2") + .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); })) + .def(py::init([](unique_ptr_tag, std::string v) { return TestFactoryHelper::construct2(v); })) + .def(py::init([](move_tag) { return TestFactoryHelper::construct2(); })) + .def_readwrite("value", &TestFactory2::value) + ; + + // Stateful & reused: + int c = 1; + auto c4a = [c](pointer_tag, TF4_tag, int a) { (void) c; return new TestFactory4(a);}; + + // test_init_factory_basic, test_init_factory_casting + py::class_>(m, "TestFactory3") + .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); })) + .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); })) + .def("__init__", [](TestFactory3 &self, std::string v) { new (&self) TestFactory3(v); }) // placement-new ctor + + // factories returning a derived type: + .def(py::init(c4a)) // derived ptr + .def(py::init([](pointer_tag, TF5_tag, int a) { return new TestFactory5(a); })) + // derived shared ptr: + .def(py::init([](shared_ptr_tag, TF4_tag, int a) { return std::make_shared(a); })) + .def(py::init([](shared_ptr_tag, TF5_tag, int a) { return std::make_shared(a); })) + + // Returns nullptr: + .def(py::init([](null_ptr_tag) { return (TestFactory3 *) nullptr; })) + + .def_readwrite("value", &TestFactory3::value) + ; + + // test_init_factory_casting + py::class_>(m, "TestFactory4") + .def(py::init(c4a)) // pointer + ; + + // Doesn't need to be registered, but registering makes getting ConstructorStats easier: + py::class_>(m, "TestFactory5"); + + // test_init_factory_alias + // Alias testing + py::class_(m, "TestFactory6") + .def(py::init([](base_tag, int i) { return TestFactory6(i); })) + .def(py::init([](alias_tag, int i) { return PyTF6(i); })) + .def(py::init([](alias_tag, std::string s) { return PyTF6(s); })) + .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); })) + .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); })) + .def(py::init([](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); })) + + .def("get", &TestFactory6::get) + .def("has_alias", &TestFactory6::has_alias) + + .def_static("get_cstats", &ConstructorStats::get, py::return_value_policy::reference) + .def_static("get_alias_cstats", &ConstructorStats::get, py::return_value_policy::reference) + ; + + // test_init_factory_dual + // Separate alias constructor testing + py::class_>(m, "TestFactory7") + .def(py::init( + [](int i) { return TestFactory7(i); }, + [](int i) { return PyTF7(i); })) + .def(py::init( + [](pointer_tag, int i) { return new TestFactory7(i); }, + [](pointer_tag, int i) { return new PyTF7(i); })) + .def(py::init( + [](mixed_tag, int i) { return new TestFactory7(i); }, + [](mixed_tag, int i) { return PyTF7(i); })) + .def(py::init( + [](mixed_tag, std::string s) { return TestFactory7((int) s.size()); }, + [](mixed_tag, std::string s) { return new PyTF7((int) s.size()); })) + .def(py::init( + [](base_tag, pointer_tag, int i) { return new TestFactory7(i); }, + [](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); })) + .def(py::init( + [](alias_tag, pointer_tag, int i) { return new PyTF7(i); }, + [](alias_tag, pointer_tag, int i) { return new PyTF7(10*i); })) + .def(py::init( + [](shared_ptr_tag, base_tag, int i) { return std::make_shared(i); }, + [](shared_ptr_tag, base_tag, int i) { auto *p = new PyTF7(i); return std::shared_ptr(p); })) + .def(py::init( + [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared(i); }, + [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared(i); })) // <-- invalid alias factory + + .def("get", &TestFactory7::get) + .def("has_alias", &TestFactory7::has_alias) + + .def_static("get_cstats", &ConstructorStats::get, py::return_value_policy::reference) + .def_static("get_alias_cstats", &ConstructorStats::get, py::return_value_policy::reference) + ; + + // test_placement_new_alternative + // Class with a custom new operator but *without* a placement new operator (issue #948) + class NoPlacementNew { + public: + NoPlacementNew(int i) : i(i) { } + static void *operator new(std::size_t s) { + auto *p = ::operator new(s); + py::print("operator new called, returning", reinterpret_cast(p)); + return p; + } + static void operator delete(void *p) { + py::print("operator delete called on", reinterpret_cast(p)); + ::operator delete(p); + } + int i; + }; + // As of 2.2, `py::init` no longer requires placement new + py::class_(m, "NoPlacementNew") + .def(py::init()) + .def(py::init([]() { return new NoPlacementNew(100); })) + .def_readwrite("i", &NoPlacementNew::i) + ; + + + // test_reallocations + // Class that has verbose operator_new/operator_delete calls + struct NoisyAlloc { + NoisyAlloc(const NoisyAlloc &) = default; + NoisyAlloc(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); } + NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); } + ~NoisyAlloc() { py::print("~NoisyAlloc()"); } + + static void *operator new(size_t s) { py::print("noisy new"); return ::operator new(s); } + static void *operator new(size_t, void *p) { py::print("noisy placement new"); return p; } + static void operator delete(void *p, size_t) { py::print("noisy delete"); ::operator delete(p); } + static void operator delete(void *, void *) { py::print("noisy placement delete"); } +#if defined(_MSC_VER) && _MSC_VER < 1910 + // MSVC 2015 bug: the above "noisy delete" isn't invoked (fixed in MSVC 2017) + static void operator delete(void *p) { py::print("noisy delete"); ::operator delete(p); } +#endif + }; + py::class_(m, "NoisyAlloc") + // Since these overloads have the same number of arguments, the dispatcher will try each of + // them until the arguments convert. Thus we can get a pre-allocation here when passing a + // single non-integer: + .def("__init__", [](NoisyAlloc *a, int i) { new (a) NoisyAlloc(i); }) // Regular constructor, runs first, requires preallocation + .def(py::init([](double d) { return new NoisyAlloc(d); })) + + // The two-argument version: first the factory pointer overload. + .def(py::init([](int i, int) { return new NoisyAlloc(i); })) + // Return-by-value: + .def(py::init([](double d, int) { return NoisyAlloc(d); })) + // Old-style placement new init; requires preallocation + .def("__init__", [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); }) + // Requires deallocation of previous overload preallocated value: + .def(py::init([](int i, double) { return new NoisyAlloc(i); })) + // Regular again: requires yet another preallocation + .def("__init__", [](NoisyAlloc &a, int i, std::string) { new (&a) NoisyAlloc(i); }) + ; + + + + + // static_assert testing (the following def's should all fail with appropriate compilation errors): +#if 0 + struct BadF1Base {}; + struct BadF1 : BadF1Base {}; + struct PyBadF1 : BadF1 {}; + py::class_> bf1(m, "BadF1"); + // wrapped factory function must return a compatible pointer, holder, or value + bf1.def(py::init([]() { return 3; })); + // incompatible factory function pointer return type + bf1.def(py::init([]() { static int three = 3; return &three; })); + // incompatible factory function std::shared_ptr return type: cannot convert shared_ptr to holder + // (non-polymorphic base) + bf1.def(py::init([]() { return std::shared_ptr(new BadF1()); })); +#endif +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_factory_constructors.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_factory_constructors.py new file mode 100644 index 0000000000000000000000000000000000000000..78a3910ada9df3b7047fae33959fc5b978b2a850 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_factory_constructors.py @@ -0,0 +1,459 @@ +import pytest +import re + +from pybind11_tests import factory_constructors as m +from pybind11_tests.factory_constructors import tag +from pybind11_tests import ConstructorStats + + +def test_init_factory_basic(): + """Tests py::init_factory() wrapper around various ways of returning the object""" + + cstats = [ConstructorStats.get(c) for c in [m.TestFactory1, m.TestFactory2, m.TestFactory3]] + cstats[0].alive() # force gc + n_inst = ConstructorStats.detail_reg_inst() + + x1 = m.TestFactory1(tag.unique_ptr, 3) + assert x1.value == "3" + y1 = m.TestFactory1(tag.pointer) + assert y1.value == "(empty)" + z1 = m.TestFactory1("hi!") + assert z1.value == "hi!" + + assert ConstructorStats.detail_reg_inst() == n_inst + 3 + + x2 = m.TestFactory2(tag.move) + assert x2.value == "(empty2)" + y2 = m.TestFactory2(tag.pointer, 7) + assert y2.value == "7" + z2 = m.TestFactory2(tag.unique_ptr, "hi again") + assert z2.value == "hi again" + + assert ConstructorStats.detail_reg_inst() == n_inst + 6 + + x3 = m.TestFactory3(tag.shared_ptr) + assert x3.value == "(empty3)" + y3 = m.TestFactory3(tag.pointer, 42) + assert y3.value == "42" + z3 = m.TestFactory3("bye") + assert z3.value == "bye" + + with pytest.raises(TypeError) as excinfo: + m.TestFactory3(tag.null_ptr) + assert str(excinfo.value) == "pybind11::init(): factory function returned nullptr" + + assert [i.alive() for i in cstats] == [3, 3, 3] + assert ConstructorStats.detail_reg_inst() == n_inst + 9 + + del x1, y2, y3, z3 + assert [i.alive() for i in cstats] == [2, 2, 1] + assert ConstructorStats.detail_reg_inst() == n_inst + 5 + del x2, x3, y1, z1, z2 + assert [i.alive() for i in cstats] == [0, 0, 0] + assert ConstructorStats.detail_reg_inst() == n_inst + + assert [i.values() for i in cstats] == [ + ["3", "hi!"], + ["7", "hi again"], + ["42", "bye"] + ] + assert [i.default_constructions for i in cstats] == [1, 1, 1] + + +def test_init_factory_signature(msg): + with pytest.raises(TypeError) as excinfo: + m.TestFactory1("invalid", "constructor", "arguments") + assert msg(excinfo.value) == """ + __init__(): incompatible constructor arguments. The following argument types are supported: + 1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) + 2. m.factory_constructors.TestFactory1(arg0: str) + 3. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.pointer_tag) + 4. m.factory_constructors.TestFactory1(arg0: handle, arg1: int, arg2: handle) + + Invoked with: 'invalid', 'constructor', 'arguments' + """ # noqa: E501 line too long + + assert msg(m.TestFactory1.__init__.__doc__) == """ + __init__(*args, **kwargs) + Overloaded function. + + 1. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) -> None + + 2. __init__(self: m.factory_constructors.TestFactory1, arg0: str) -> None + + 3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None + + 4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None + """ # noqa: E501 line too long + + +def test_init_factory_casting(): + """Tests py::init_factory() wrapper with various upcasting and downcasting returns""" + + cstats = [ConstructorStats.get(c) for c in [m.TestFactory3, m.TestFactory4, m.TestFactory5]] + cstats[0].alive() # force gc + n_inst = ConstructorStats.detail_reg_inst() + + # Construction from derived references: + a = m.TestFactory3(tag.pointer, tag.TF4, 4) + assert a.value == "4" + b = m.TestFactory3(tag.shared_ptr, tag.TF4, 5) + assert b.value == "5" + c = m.TestFactory3(tag.pointer, tag.TF5, 6) + assert c.value == "6" + d = m.TestFactory3(tag.shared_ptr, tag.TF5, 7) + assert d.value == "7" + + assert ConstructorStats.detail_reg_inst() == n_inst + 4 + + # Shared a lambda with TF3: + e = m.TestFactory4(tag.pointer, tag.TF4, 8) + assert e.value == "8" + + assert ConstructorStats.detail_reg_inst() == n_inst + 5 + assert [i.alive() for i in cstats] == [5, 3, 2] + + del a + assert [i.alive() for i in cstats] == [4, 2, 2] + assert ConstructorStats.detail_reg_inst() == n_inst + 4 + + del b, c, e + assert [i.alive() for i in cstats] == [1, 0, 1] + assert ConstructorStats.detail_reg_inst() == n_inst + 1 + + del d + assert [i.alive() for i in cstats] == [0, 0, 0] + assert ConstructorStats.detail_reg_inst() == n_inst + + assert [i.values() for i in cstats] == [ + ["4", "5", "6", "7", "8"], + ["4", "5", "8"], + ["6", "7"] + ] + + +def test_init_factory_alias(): + """Tests py::init_factory() wrapper with value conversions and alias types""" + + cstats = [m.TestFactory6.get_cstats(), m.TestFactory6.get_alias_cstats()] + cstats[0].alive() # force gc + n_inst = ConstructorStats.detail_reg_inst() + + a = m.TestFactory6(tag.base, 1) + assert a.get() == 1 + assert not a.has_alias() + b = m.TestFactory6(tag.alias, "hi there") + assert b.get() == 8 + assert b.has_alias() + c = m.TestFactory6(tag.alias, 3) + assert c.get() == 3 + assert c.has_alias() + d = m.TestFactory6(tag.alias, tag.pointer, 4) + assert d.get() == 4 + assert d.has_alias() + e = m.TestFactory6(tag.base, tag.pointer, 5) + assert e.get() == 5 + assert not e.has_alias() + f = m.TestFactory6(tag.base, tag.alias, tag.pointer, 6) + assert f.get() == 6 + assert f.has_alias() + + assert ConstructorStats.detail_reg_inst() == n_inst + 6 + assert [i.alive() for i in cstats] == [6, 4] + + del a, b, e + assert [i.alive() for i in cstats] == [3, 3] + assert ConstructorStats.detail_reg_inst() == n_inst + 3 + del f, c, d + assert [i.alive() for i in cstats] == [0, 0] + assert ConstructorStats.detail_reg_inst() == n_inst + + class MyTest(m.TestFactory6): + def __init__(self, *args): + m.TestFactory6.__init__(self, *args) + + def get(self): + return -5 + m.TestFactory6.get(self) + + # Return Class by value, moved into new alias: + z = MyTest(tag.base, 123) + assert z.get() == 118 + assert z.has_alias() + + # Return alias by value, moved into new alias: + y = MyTest(tag.alias, "why hello!") + assert y.get() == 5 + assert y.has_alias() + + # Return Class by pointer, moved into new alias then original destroyed: + x = MyTest(tag.base, tag.pointer, 47) + assert x.get() == 42 + assert x.has_alias() + + assert ConstructorStats.detail_reg_inst() == n_inst + 3 + assert [i.alive() for i in cstats] == [3, 3] + del x, y, z + assert [i.alive() for i in cstats] == [0, 0] + assert ConstructorStats.detail_reg_inst() == n_inst + + assert [i.values() for i in cstats] == [ + ["1", "8", "3", "4", "5", "6", "123", "10", "47"], + ["hi there", "3", "4", "6", "move", "123", "why hello!", "move", "47"] + ] + + +def test_init_factory_dual(): + """Tests init factory functions with dual main/alias factory functions""" + from pybind11_tests.factory_constructors import TestFactory7 + + cstats = [TestFactory7.get_cstats(), TestFactory7.get_alias_cstats()] + cstats[0].alive() # force gc + n_inst = ConstructorStats.detail_reg_inst() + + class PythFactory7(TestFactory7): + def get(self): + return 100 + TestFactory7.get(self) + + a1 = TestFactory7(1) + a2 = PythFactory7(2) + assert a1.get() == 1 + assert a2.get() == 102 + assert not a1.has_alias() + assert a2.has_alias() + + b1 = TestFactory7(tag.pointer, 3) + b2 = PythFactory7(tag.pointer, 4) + assert b1.get() == 3 + assert b2.get() == 104 + assert not b1.has_alias() + assert b2.has_alias() + + c1 = TestFactory7(tag.mixed, 5) + c2 = PythFactory7(tag.mixed, 6) + assert c1.get() == 5 + assert c2.get() == 106 + assert not c1.has_alias() + assert c2.has_alias() + + d1 = TestFactory7(tag.base, tag.pointer, 7) + d2 = PythFactory7(tag.base, tag.pointer, 8) + assert d1.get() == 7 + assert d2.get() == 108 + assert not d1.has_alias() + assert d2.has_alias() + + # Both return an alias; the second multiplies the value by 10: + e1 = TestFactory7(tag.alias, tag.pointer, 9) + e2 = PythFactory7(tag.alias, tag.pointer, 10) + assert e1.get() == 9 + assert e2.get() == 200 + assert e1.has_alias() + assert e2.has_alias() + + f1 = TestFactory7(tag.shared_ptr, tag.base, 11) + f2 = PythFactory7(tag.shared_ptr, tag.base, 12) + assert f1.get() == 11 + assert f2.get() == 112 + assert not f1.has_alias() + assert f2.has_alias() + + g1 = TestFactory7(tag.shared_ptr, tag.invalid_base, 13) + assert g1.get() == 13 + assert not g1.has_alias() + with pytest.raises(TypeError) as excinfo: + PythFactory7(tag.shared_ptr, tag.invalid_base, 14) + assert (str(excinfo.value) == + "pybind11::init(): construction failed: returned holder-wrapped instance is not an " + "alias instance") + + assert [i.alive() for i in cstats] == [13, 7] + assert ConstructorStats.detail_reg_inst() == n_inst + 13 + + del a1, a2, b1, d1, e1, e2 + assert [i.alive() for i in cstats] == [7, 4] + assert ConstructorStats.detail_reg_inst() == n_inst + 7 + del b2, c1, c2, d2, f1, f2, g1 + assert [i.alive() for i in cstats] == [0, 0] + assert ConstructorStats.detail_reg_inst() == n_inst + + assert [i.values() for i in cstats] == [ + ["1", "2", "3", "4", "5", "6", "7", "8", "9", "100", "11", "12", "13", "14"], + ["2", "4", "6", "8", "9", "100", "12"] + ] + + +def test_no_placement_new(capture): + """Prior to 2.2, `py::init<...>` relied on the type supporting placement + new; this tests a class without placement new support.""" + with capture: + a = m.NoPlacementNew(123) + + found = re.search(r'^operator new called, returning (\d+)\n$', str(capture)) + assert found + assert a.i == 123 + with capture: + del a + pytest.gc_collect() + assert capture == "operator delete called on " + found.group(1) + + with capture: + b = m.NoPlacementNew() + + found = re.search(r'^operator new called, returning (\d+)\n$', str(capture)) + assert found + assert b.i == 100 + with capture: + del b + pytest.gc_collect() + assert capture == "operator delete called on " + found.group(1) + + +def test_multiple_inheritance(): + class MITest(m.TestFactory1, m.TestFactory2): + def __init__(self): + m.TestFactory1.__init__(self, tag.unique_ptr, 33) + m.TestFactory2.__init__(self, tag.move) + + a = MITest() + assert m.TestFactory1.value.fget(a) == "33" + assert m.TestFactory2.value.fget(a) == "(empty2)" + + +def create_and_destroy(*args): + a = m.NoisyAlloc(*args) + print("---") + del a + pytest.gc_collect() + + +def strip_comments(s): + return re.sub(r'\s+#.*', '', s) + + +def test_reallocations(capture, msg): + """When the constructor is overloaded, previous overloads can require a preallocated value. + This test makes sure that such preallocated values only happen when they might be necessary, + and that they are deallocated properly""" + + pytest.gc_collect() + + with capture: + create_and_destroy(1) + assert msg(capture) == """ + noisy new + noisy placement new + NoisyAlloc(int 1) + --- + ~NoisyAlloc() + noisy delete + """ + with capture: + create_and_destroy(1.5) + assert msg(capture) == strip_comments(""" + noisy new # allocation required to attempt first overload + noisy delete # have to dealloc before considering factory init overload + noisy new # pointer factory calling "new", part 1: allocation + NoisyAlloc(double 1.5) # ... part two, invoking constructor + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + with capture: + create_and_destroy(2, 3) + assert msg(capture) == strip_comments(""" + noisy new # pointer factory calling "new", allocation + NoisyAlloc(int 2) # constructor + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + with capture: + create_and_destroy(2.5, 3) + assert msg(capture) == strip_comments(""" + NoisyAlloc(double 2.5) # construction (local func variable: operator_new not called) + noisy new # return-by-value "new" part 1: allocation + ~NoisyAlloc() # moved-away local func variable destruction + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + with capture: + create_and_destroy(3.5, 4.5) + assert msg(capture) == strip_comments(""" + noisy new # preallocation needed before invoking placement-new overload + noisy placement new # Placement new + NoisyAlloc(double 3.5) # construction + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + with capture: + create_and_destroy(4, 0.5) + assert msg(capture) == strip_comments(""" + noisy new # preallocation needed before invoking placement-new overload + noisy delete # deallocation of preallocated storage + noisy new # Factory pointer allocation + NoisyAlloc(int 4) # factory pointer construction + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + with capture: + create_and_destroy(5, "hi") + assert msg(capture) == strip_comments(""" + noisy new # preallocation needed before invoking first placement new + noisy delete # delete before considering new-style constructor + noisy new # preallocation for second placement new + noisy placement new # Placement new in the second placement new overload + NoisyAlloc(int 5) # construction + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + +@pytest.unsupported_on_py2 +def test_invalid_self(): + """Tests invocation of the pybind-registered base class with an invalid `self` argument. You + can only actually do this on Python 3: Python 2 raises an exception itself if you try.""" + class NotPybindDerived(object): + pass + + # Attempts to initialize with an invalid type passed as `self`: + class BrokenTF1(m.TestFactory1): + def __init__(self, bad): + if bad == 1: + a = m.TestFactory2(tag.pointer, 1) + m.TestFactory1.__init__(a, tag.pointer) + elif bad == 2: + a = NotPybindDerived() + m.TestFactory1.__init__(a, tag.pointer) + + # Same as above, but for a class with an alias: + class BrokenTF6(m.TestFactory6): + def __init__(self, bad): + if bad == 1: + a = m.TestFactory2(tag.pointer, 1) + m.TestFactory6.__init__(a, tag.base, 1) + elif bad == 2: + a = m.TestFactory2(tag.pointer, 1) + m.TestFactory6.__init__(a, tag.alias, 1) + elif bad == 3: + m.TestFactory6.__init__(NotPybindDerived.__new__(NotPybindDerived), tag.base, 1) + elif bad == 4: + m.TestFactory6.__init__(NotPybindDerived.__new__(NotPybindDerived), tag.alias, 1) + + for arg in (1, 2): + with pytest.raises(TypeError) as excinfo: + BrokenTF1(arg) + assert str(excinfo.value) == "__init__(self, ...) called with invalid `self` argument" + + for arg in (1, 2, 3, 4): + with pytest.raises(TypeError) as excinfo: + BrokenTF6(arg) + assert str(excinfo.value) == "__init__(self, ...) called with invalid `self` argument" diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_gil_scoped.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_gil_scoped.cpp new file mode 100644 index 0000000000000000000000000000000000000000..76c17fdc78c8f65d87b15cdaf75d341b0ef92980 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_gil_scoped.cpp @@ -0,0 +1,52 @@ +/* + tests/test_gil_scoped.cpp -- acquire and release gil + + Copyright (c) 2017 Borja Zarco (Google LLC) + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include + + +class VirtClass { +public: + virtual ~VirtClass() {} + virtual void virtual_func() {} + virtual void pure_virtual_func() = 0; +}; + +class PyVirtClass : public VirtClass { + void virtual_func() override { + PYBIND11_OVERLOAD(void, VirtClass, virtual_func,); + } + void pure_virtual_func() override { + PYBIND11_OVERLOAD_PURE(void, VirtClass, pure_virtual_func,); + } +}; + +TEST_SUBMODULE(gil_scoped, m) { + py::class_(m, "VirtClass") + .def(py::init<>()) + .def("virtual_func", &VirtClass::virtual_func) + .def("pure_virtual_func", &VirtClass::pure_virtual_func); + + m.def("test_callback_py_obj", + [](py::object func) { func(); }); + m.def("test_callback_std_func", + [](const std::function &func) { func(); }); + m.def("test_callback_virtual_func", + [](VirtClass &virt) { virt.virtual_func(); }); + m.def("test_callback_pure_virtual_func", + [](VirtClass &virt) { virt.pure_virtual_func(); }); + m.def("test_cross_module_gil", + []() { + auto cm = py::module::import("cross_module_gil_utils"); + auto gil_acquire = reinterpret_cast( + PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr())); + py::gil_scoped_release gil_release; + gil_acquire(); + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_gil_scoped.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_gil_scoped.py new file mode 100644 index 0000000000000000000000000000000000000000..1548337cccbc3df0929a32a51f328038be8190fe --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_gil_scoped.py @@ -0,0 +1,85 @@ +import multiprocessing +import threading +from pybind11_tests import gil_scoped as m + + +def _run_in_process(target, *args, **kwargs): + """Runs target in process and returns its exitcode after 10s (None if still alive).""" + process = multiprocessing.Process(target=target, args=args, kwargs=kwargs) + process.daemon = True + try: + process.start() + # Do not need to wait much, 10s should be more than enough. + process.join(timeout=10) + return process.exitcode + finally: + if process.is_alive(): + process.terminate() + + +def _python_to_cpp_to_python(): + """Calls different C++ functions that come back to Python.""" + class ExtendedVirtClass(m.VirtClass): + def virtual_func(self): + pass + + def pure_virtual_func(self): + pass + + extended = ExtendedVirtClass() + m.test_callback_py_obj(lambda: None) + m.test_callback_std_func(lambda: None) + m.test_callback_virtual_func(extended) + m.test_callback_pure_virtual_func(extended) + + +def _python_to_cpp_to_python_from_threads(num_threads, parallel=False): + """Calls different C++ functions that come back to Python, from Python threads.""" + threads = [] + for _ in range(num_threads): + thread = threading.Thread(target=_python_to_cpp_to_python) + thread.daemon = True + thread.start() + if parallel: + threads.append(thread) + else: + thread.join() + for thread in threads: + thread.join() + + +def test_python_to_cpp_to_python_from_thread(): + """Makes sure there is no GIL deadlock when running in a thread. + + It runs in a separate process to be able to stop and assert if it deadlocks. + """ + assert _run_in_process(_python_to_cpp_to_python_from_threads, 1) == 0 + + +def test_python_to_cpp_to_python_from_thread_multiple_parallel(): + """Makes sure there is no GIL deadlock when running in a thread multiple times in parallel. + + It runs in a separate process to be able to stop and assert if it deadlocks. + """ + assert _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=True) == 0 + + +def test_python_to_cpp_to_python_from_thread_multiple_sequential(): + """Makes sure there is no GIL deadlock when running in a thread multiple times sequentially. + + It runs in a separate process to be able to stop and assert if it deadlocks. + """ + assert _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=False) == 0 + + +def test_python_to_cpp_to_python_from_process(): + """Makes sure there is no GIL deadlock when using processes. + + This test is for completion, but it was never an issue. + """ + assert _run_in_process(_python_to_cpp_to_python) == 0 + + +def test_cross_module_gil(): + """Makes sure that the GIL can be acquired by another module from a GIL-released state.""" + m.test_cross_module_gil() # Should not raise a SIGSEGV diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_iostream.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_iostream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e67f88af5fd2d377221a6fcd6c890dec5344df48 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_iostream.cpp @@ -0,0 +1,73 @@ +/* + tests/test_iostream.cpp -- Usage of scoped_output_redirect + + Copyright (c) 2017 Henry F. Schreiner + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + + +#include +#include "pybind11_tests.h" +#include + + +void noisy_function(std::string msg, bool flush) { + + std::cout << msg; + if (flush) + std::cout << std::flush; +} + +void noisy_funct_dual(std::string msg, std::string emsg) { + std::cout << msg; + std::cerr << emsg; +} + +TEST_SUBMODULE(iostream, m) { + + add_ostream_redirect(m); + + // test_evals + + m.def("captured_output_default", [](std::string msg) { + py::scoped_ostream_redirect redir; + std::cout << msg << std::flush; + }); + + m.def("captured_output", [](std::string msg) { + py::scoped_ostream_redirect redir(std::cout, py::module::import("sys").attr("stdout")); + std::cout << msg << std::flush; + }); + + m.def("guard_output", &noisy_function, + py::call_guard(), + py::arg("msg"), py::arg("flush")=true); + + m.def("captured_err", [](std::string msg) { + py::scoped_ostream_redirect redir(std::cerr, py::module::import("sys").attr("stderr")); + std::cerr << msg << std::flush; + }); + + m.def("noisy_function", &noisy_function, py::arg("msg"), py::arg("flush") = true); + + m.def("dual_guard", &noisy_funct_dual, + py::call_guard(), + py::arg("msg"), py::arg("emsg")); + + m.def("raw_output", [](std::string msg) { + std::cout << msg << std::flush; + }); + + m.def("raw_err", [](std::string msg) { + std::cerr << msg << std::flush; + }); + + m.def("captured_dual", [](std::string msg, std::string emsg) { + py::scoped_ostream_redirect redirout(std::cout, py::module::import("sys").attr("stdout")); + py::scoped_ostream_redirect redirerr(std::cerr, py::module::import("sys").attr("stderr")); + std::cout << msg << std::flush; + std::cerr << emsg << std::flush; + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_iostream.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_iostream.py new file mode 100644 index 0000000000000000000000000000000000000000..27095b2705981596f136460d3b1517285be4c81c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_iostream.py @@ -0,0 +1,214 @@ +from pybind11_tests import iostream as m +import sys + +from contextlib import contextmanager + +try: + # Python 3 + from io import StringIO +except ImportError: + # Python 2 + try: + from cStringIO import StringIO + except ImportError: + from StringIO import StringIO + +try: + # Python 3.4 + from contextlib import redirect_stdout +except ImportError: + @contextmanager + def redirect_stdout(target): + original = sys.stdout + sys.stdout = target + yield + sys.stdout = original + +try: + # Python 3.5 + from contextlib import redirect_stderr +except ImportError: + @contextmanager + def redirect_stderr(target): + original = sys.stderr + sys.stderr = target + yield + sys.stderr = original + + +def test_captured(capsys): + msg = "I've been redirected to Python, I hope!" + m.captured_output(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == '' + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == '' + + m.captured_err(msg) + stdout, stderr = capsys.readouterr() + assert stdout == '' + assert stderr == msg + + +def test_captured_large_string(capsys): + # Make this bigger than the buffer used on the C++ side: 1024 chars + msg = "I've been redirected to Python, I hope!" + msg = msg * (1024 // len(msg) + 1) + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == '' + + +def test_guard_capture(capsys): + msg = "I've been redirected to Python, I hope!" + m.guard_output(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == '' + + +def test_series_captured(capture): + with capture: + m.captured_output("a") + m.captured_output("b") + assert capture == "ab" + + +def test_flush(capfd): + msg = "(not flushed)" + msg2 = "(flushed)" + + with m.ostream_redirect(): + m.noisy_function(msg, flush=False) + stdout, stderr = capfd.readouterr() + assert stdout == '' + + m.noisy_function(msg2, flush=True) + stdout, stderr = capfd.readouterr() + assert stdout == msg + msg2 + + m.noisy_function(msg, flush=False) + + stdout, stderr = capfd.readouterr() + assert stdout == msg + + +def test_not_captured(capfd): + msg = "Something that should not show up in log" + stream = StringIO() + with redirect_stdout(stream): + m.raw_output(msg) + stdout, stderr = capfd.readouterr() + assert stdout == msg + assert stderr == '' + assert stream.getvalue() == '' + + stream = StringIO() + with redirect_stdout(stream): + m.captured_output(msg) + stdout, stderr = capfd.readouterr() + assert stdout == '' + assert stderr == '' + assert stream.getvalue() == msg + + +def test_err(capfd): + msg = "Something that should not show up in log" + stream = StringIO() + with redirect_stderr(stream): + m.raw_err(msg) + stdout, stderr = capfd.readouterr() + assert stdout == '' + assert stderr == msg + assert stream.getvalue() == '' + + stream = StringIO() + with redirect_stderr(stream): + m.captured_err(msg) + stdout, stderr = capfd.readouterr() + assert stdout == '' + assert stderr == '' + assert stream.getvalue() == msg + + +def test_multi_captured(capfd): + stream = StringIO() + with redirect_stdout(stream): + m.captured_output("a") + m.raw_output("b") + m.captured_output("c") + m.raw_output("d") + stdout, stderr = capfd.readouterr() + assert stdout == 'bd' + assert stream.getvalue() == 'ac' + + +def test_dual(capsys): + m.captured_dual("a", "b") + stdout, stderr = capsys.readouterr() + assert stdout == "a" + assert stderr == "b" + + +def test_redirect(capfd): + msg = "Should not be in log!" + stream = StringIO() + with redirect_stdout(stream): + m.raw_output(msg) + stdout, stderr = capfd.readouterr() + assert stdout == msg + assert stream.getvalue() == '' + + stream = StringIO() + with redirect_stdout(stream): + with m.ostream_redirect(): + m.raw_output(msg) + stdout, stderr = capfd.readouterr() + assert stdout == '' + assert stream.getvalue() == msg + + stream = StringIO() + with redirect_stdout(stream): + m.raw_output(msg) + stdout, stderr = capfd.readouterr() + assert stdout == msg + assert stream.getvalue() == '' + + +def test_redirect_err(capfd): + msg = "StdOut" + msg2 = "StdErr" + + stream = StringIO() + with redirect_stderr(stream): + with m.ostream_redirect(stdout=False): + m.raw_output(msg) + m.raw_err(msg2) + stdout, stderr = capfd.readouterr() + assert stdout == msg + assert stderr == '' + assert stream.getvalue() == msg2 + + +def test_redirect_both(capfd): + msg = "StdOut" + msg2 = "StdErr" + + stream = StringIO() + stream2 = StringIO() + with redirect_stdout(stream): + with redirect_stderr(stream2): + with m.ostream_redirect(): + m.raw_output(msg) + m.raw_err(msg2) + stdout, stderr = capfd.readouterr() + assert stdout == '' + assert stderr == '' + assert stream.getvalue() == msg + assert stream2.getvalue() == msg2 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_kwargs_and_defaults.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_kwargs_and_defaults.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6563fb9ad3f0744578056897abe1ed451e386a52 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_kwargs_and_defaults.cpp @@ -0,0 +1,102 @@ +/* + tests/test_kwargs_and_defaults.cpp -- keyword arguments and default values + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include + +TEST_SUBMODULE(kwargs_and_defaults, m) { + auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); }; + + // test_named_arguments + m.def("kw_func0", kw_func); + m.def("kw_func1", kw_func, py::arg("x"), py::arg("y")); + m.def("kw_func2", kw_func, py::arg("x") = 100, py::arg("y") = 200); + m.def("kw_func3", [](const char *) { }, py::arg("data") = std::string("Hello world!")); + + /* A fancier default argument */ + std::vector list{{13, 17}}; + m.def("kw_func4", [](const std::vector &entries) { + std::string ret = "{"; + for (int i : entries) + ret += std::to_string(i) + " "; + ret.back() = '}'; + return ret; + }, py::arg("myList") = list); + + m.def("kw_func_udl", kw_func, "x"_a, "y"_a=300); + m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a=0); + + // test_args_and_kwargs + m.def("args_function", [](py::args args) -> py::tuple { + return std::move(args); + }); + m.def("args_kwargs_function", [](py::args args, py::kwargs kwargs) { + return py::make_tuple(args, kwargs); + }); + + // test_mixed_args_and_kwargs + m.def("mixed_plus_args", [](int i, double j, py::args args) { + return py::make_tuple(i, j, args); + }); + m.def("mixed_plus_kwargs", [](int i, double j, py::kwargs kwargs) { + return py::make_tuple(i, j, kwargs); + }); + auto mixed_plus_both = [](int i, double j, py::args args, py::kwargs kwargs) { + return py::make_tuple(i, j, args, kwargs); + }; + m.def("mixed_plus_args_kwargs", mixed_plus_both); + + m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both, + py::arg("i") = 1, py::arg("j") = 3.14159); + + // test_args_refcount + // PyPy needs a garbage collection to get the reference count values to match CPython's behaviour + #ifdef PYPY_VERSION + #define GC_IF_NEEDED ConstructorStats::gc() + #else + #define GC_IF_NEEDED + #endif + m.def("arg_refcount_h", [](py::handle h) { GC_IF_NEEDED; return h.ref_count(); }); + m.def("arg_refcount_h", [](py::handle h, py::handle, py::handle) { GC_IF_NEEDED; return h.ref_count(); }); + m.def("arg_refcount_o", [](py::object o) { GC_IF_NEEDED; return o.ref_count(); }); + m.def("args_refcount", [](py::args a) { + GC_IF_NEEDED; + py::tuple t(a.size()); + for (size_t i = 0; i < a.size(); i++) + // Use raw Python API here to avoid an extra, intermediate incref on the tuple item: + t[i] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast(i))); + return t; + }); + m.def("mixed_args_refcount", [](py::object o, py::args a) { + GC_IF_NEEDED; + py::tuple t(a.size() + 1); + t[0] = o.ref_count(); + for (size_t i = 0; i < a.size(); i++) + // Use raw Python API here to avoid an extra, intermediate incref on the tuple item: + t[i + 1] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast(i))); + return t; + }); + + // pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end. + // Uncomment these to test that the static_assert is indeed working: +// m.def("bad_args1", [](py::args, int) {}); +// m.def("bad_args2", [](py::kwargs, int) {}); +// m.def("bad_args3", [](py::kwargs, py::args) {}); +// m.def("bad_args4", [](py::args, int, py::kwargs) {}); +// m.def("bad_args5", [](py::args, py::kwargs, int) {}); +// m.def("bad_args6", [](py::args, py::args) {}); +// m.def("bad_args7", [](py::kwargs, py::kwargs) {}); + + // test_function_signatures (along with most of the above) + struct KWClass { void foo(int, float) {} }; + py::class_(m, "KWClass") + .def("foo0", &KWClass::foo) + .def("foo1", &KWClass::foo, "x"_a, "y"_a); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_kwargs_and_defaults.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_kwargs_and_defaults.py new file mode 100644 index 0000000000000000000000000000000000000000..27a05a0241321ab6ee6912cd9686a6ccf1e00c0b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_kwargs_and_defaults.py @@ -0,0 +1,147 @@ +import pytest +from pybind11_tests import kwargs_and_defaults as m + + +def test_function_signatures(doc): + assert doc(m.kw_func0) == "kw_func0(arg0: int, arg1: int) -> str" + assert doc(m.kw_func1) == "kw_func1(x: int, y: int) -> str" + assert doc(m.kw_func2) == "kw_func2(x: int = 100, y: int = 200) -> str" + assert doc(m.kw_func3) == "kw_func3(data: str = 'Hello world!') -> None" + assert doc(m.kw_func4) == "kw_func4(myList: List[int] = [13, 17]) -> str" + assert doc(m.kw_func_udl) == "kw_func_udl(x: int, y: int = 300) -> str" + assert doc(m.kw_func_udl_z) == "kw_func_udl_z(x: int, y: int = 0) -> str" + assert doc(m.args_function) == "args_function(*args) -> tuple" + assert doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple" + assert doc(m.KWClass.foo0) == \ + "foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None" + assert doc(m.KWClass.foo1) == \ + "foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None" + + +def test_named_arguments(msg): + assert m.kw_func0(5, 10) == "x=5, y=10" + + assert m.kw_func1(5, 10) == "x=5, y=10" + assert m.kw_func1(5, y=10) == "x=5, y=10" + assert m.kw_func1(y=10, x=5) == "x=5, y=10" + + assert m.kw_func2() == "x=100, y=200" + assert m.kw_func2(5) == "x=5, y=200" + assert m.kw_func2(x=5) == "x=5, y=200" + assert m.kw_func2(y=10) == "x=100, y=10" + assert m.kw_func2(5, 10) == "x=5, y=10" + assert m.kw_func2(x=5, y=10) == "x=5, y=10" + + with pytest.raises(TypeError) as excinfo: + # noinspection PyArgumentList + m.kw_func2(x=5, y=10, z=12) + assert excinfo.match( + r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))' + '{3}$') + + assert m.kw_func4() == "{13 17}" + assert m.kw_func4(myList=[1, 2, 3]) == "{1 2 3}" + + assert m.kw_func_udl(x=5, y=10) == "x=5, y=10" + assert m.kw_func_udl_z(x=5) == "x=5, y=0" + + +def test_arg_and_kwargs(): + args = 'arg1_value', 'arg2_value', 3 + assert m.args_function(*args) == args + + args = 'a1', 'a2' + kwargs = dict(arg3='a3', arg4=4) + assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs) + + +def test_mixed_args_and_kwargs(msg): + mpa = m.mixed_plus_args + mpk = m.mixed_plus_kwargs + mpak = m.mixed_plus_args_kwargs + mpakd = m.mixed_plus_args_kwargs_defaults + + assert mpa(1, 2.5, 4, 99.5, None) == (1, 2.5, (4, 99.5, None)) + assert mpa(1, 2.5) == (1, 2.5, ()) + with pytest.raises(TypeError) as excinfo: + assert mpa(1) + assert msg(excinfo.value) == """ + mixed_plus_args(): incompatible function arguments. The following argument types are supported: + 1. (arg0: int, arg1: float, *args) -> tuple + + Invoked with: 1 + """ # noqa: E501 line too long + with pytest.raises(TypeError) as excinfo: + assert mpa() + assert msg(excinfo.value) == """ + mixed_plus_args(): incompatible function arguments. The following argument types are supported: + 1. (arg0: int, arg1: float, *args) -> tuple + + Invoked with: + """ # noqa: E501 line too long + + assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (-2, 3.5, {'e': 2.71828, 'pi': 3.14159}) + assert mpak(7, 7.7, 7.77, 7.777, 7.7777, minusseven=-7) == ( + 7, 7.7, (7.77, 7.777, 7.7777), {'minusseven': -7}) + assert mpakd() == (1, 3.14159, (), {}) + assert mpakd(3) == (3, 3.14159, (), {}) + assert mpakd(j=2.71828) == (1, 2.71828, (), {}) + assert mpakd(k=42) == (1, 3.14159, (), {'k': 42}) + assert mpakd(1, 1, 2, 3, 5, 8, then=13, followedby=21) == ( + 1, 1, (2, 3, 5, 8), {'then': 13, 'followedby': 21}) + # Arguments specified both positionally and via kwargs should fail: + with pytest.raises(TypeError) as excinfo: + assert mpakd(1, i=1) + assert msg(excinfo.value) == """ + mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported: + 1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple + + Invoked with: 1; kwargs: i=1 + """ # noqa: E501 line too long + with pytest.raises(TypeError) as excinfo: + assert mpakd(1, 2, j=1) + assert msg(excinfo.value) == """ + mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported: + 1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple + + Invoked with: 1, 2; kwargs: j=1 + """ # noqa: E501 line too long + + +def test_args_refcount(): + """Issue/PR #1216 - py::args elements get double-inc_ref()ed when combined with regular + arguments""" + refcount = m.arg_refcount_h + + myval = 54321 + expected = refcount(myval) + assert m.arg_refcount_h(myval) == expected + assert m.arg_refcount_o(myval) == expected + 1 + assert m.arg_refcount_h(myval) == expected + assert refcount(myval) == expected + + assert m.mixed_plus_args(1, 2.0, "a", myval) == (1, 2.0, ("a", myval)) + assert refcount(myval) == expected + + assert m.mixed_plus_kwargs(3, 4.0, a=1, b=myval) == (3, 4.0, {"a": 1, "b": myval}) + assert refcount(myval) == expected + + assert m.args_function(-1, myval) == (-1, myval) + assert refcount(myval) == expected + + assert m.mixed_plus_args_kwargs(5, 6.0, myval, a=myval) == (5, 6.0, (myval,), {"a": myval}) + assert refcount(myval) == expected + + assert m.args_kwargs_function(7, 8, myval, a=1, b=myval) == \ + ((7, 8, myval), {"a": 1, "b": myval}) + assert refcount(myval) == expected + + exp3 = refcount(myval, myval, myval) + assert m.args_refcount(myval, myval, myval) == (exp3, exp3, exp3) + assert refcount(myval) == expected + + # This function takes the first arg as a `py::object` and the rest as a `py::args`. Unlike the + # previous case, when we have both positional and `py::args` we need to construct a new tuple + # for the `py::args`; in the previous case, we could simply inc_ref and pass on Python's input + # tuple without having to inc_ref the individual elements, but here we can't, hence the extra + # refs. + assert m.mixed_args_refcount(myval, myval, myval) == (exp3 + 3, exp3 + 3, exp3 + 3) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_local_bindings.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_local_bindings.cpp new file mode 100644 index 0000000000000000000000000000000000000000..97c02dbeb567c3699aa48f150bd8ec9dd3cd951f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_local_bindings.cpp @@ -0,0 +1,101 @@ +/* + tests/test_local_bindings.cpp -- tests the py::module_local class feature which makes a class + binding local to the module in which it is defined. + + Copyright (c) 2017 Jason Rhinelander + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "local_bindings.h" +#include +#include +#include + +TEST_SUBMODULE(local_bindings, m) { + // test_load_external + m.def("load_external1", [](ExternalType1 &e) { return e.i; }); + m.def("load_external2", [](ExternalType2 &e) { return e.i; }); + + // test_local_bindings + // Register a class with py::module_local: + bind_local(m, "LocalType", py::module_local()) + .def("get3", [](LocalType &t) { return t.i + 3; }) + ; + + m.def("local_value", [](LocalType &l) { return l.i; }); + + // test_nonlocal_failure + // The main pybind11 test module is loaded first, so this registration will succeed (the second + // one, in pybind11_cross_module_tests.cpp, is designed to fail): + bind_local(m, "NonLocalType") + .def(py::init()) + .def("get", [](LocalType &i) { return i.i; }) + ; + + // test_duplicate_local + // py::module_local declarations should be visible across compilation units that get linked together; + // this tries to register a duplicate local. It depends on a definition in test_class.cpp and + // should raise a runtime error from the duplicate definition attempt. If test_class isn't + // available it *also* throws a runtime error (with "test_class not enabled" as value). + m.def("register_local_external", [m]() { + auto main = py::module::import("pybind11_tests"); + if (py::hasattr(main, "class_")) { + bind_local(m, "LocalExternal", py::module_local()); + } + else throw std::runtime_error("test_class not enabled"); + }); + + // test_stl_bind_local + // stl_bind.h binders defaults to py::module_local if the types are local or converting: + py::bind_vector(m, "LocalVec"); + py::bind_map(m, "LocalMap"); + // and global if the type (or one of the types, for the map) is global: + py::bind_vector(m, "NonLocalVec"); + py::bind_map(m, "NonLocalMap"); + + // test_stl_bind_global + // They can, however, be overridden to global using `py::module_local(false)`: + bind_local(m, "NonLocal2"); + py::bind_vector(m, "LocalVec2", py::module_local()); + py::bind_map(m, "NonLocalMap2", py::module_local(false)); + + // test_mixed_local_global + // We try this both with the global type registered first and vice versa (the order shouldn't + // matter). + m.def("register_mixed_global", [m]() { + bind_local(m, "MixedGlobalLocal", py::module_local(false)); + }); + m.def("register_mixed_local", [m]() { + bind_local(m, "MixedLocalGlobal", py::module_local()); + }); + m.def("get_mixed_gl", [](int i) { return MixedGlobalLocal(i); }); + m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); }); + + // test_internal_locals_differ + m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); }); + + // test_stl_caster_vs_stl_bind + m.def("load_vector_via_caster", [](std::vector v) { + return std::accumulate(v.begin(), v.end(), 0); + }); + + // test_cross_module_calls + m.def("return_self", [](LocalVec *v) { return v; }); + m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); }); + + class Cat : public pets::Pet { public: Cat(std::string name) : Pet(name) {}; }; + py::class_(m, "Pet", py::module_local()) + .def("get_name", &pets::Pet::name); + // Binding for local extending class: + py::class_(m, "Cat") + .def(py::init()); + m.def("pet_name", [](pets::Pet &p) { return p.name(); }); + + py::class_(m, "MixGL").def(py::init()); + m.def("get_gl_value", [](MixGL &o) { return o.i + 10; }); + + py::class_(m, "MixGL2").def(py::init()); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_local_bindings.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_local_bindings.py new file mode 100644 index 0000000000000000000000000000000000000000..b380376e2b871bd7605ff348b9f984a13d731154 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_local_bindings.py @@ -0,0 +1,226 @@ +import pytest + +from pybind11_tests import local_bindings as m + + +def test_load_external(): + """Load a `py::module_local` type that's only registered in an external module""" + import pybind11_cross_module_tests as cm + + assert m.load_external1(cm.ExternalType1(11)) == 11 + assert m.load_external2(cm.ExternalType2(22)) == 22 + + with pytest.raises(TypeError) as excinfo: + assert m.load_external2(cm.ExternalType1(21)) == 21 + assert "incompatible function arguments" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + assert m.load_external1(cm.ExternalType2(12)) == 12 + assert "incompatible function arguments" in str(excinfo.value) + + +def test_local_bindings(): + """Tests that duplicate `py::module_local` class bindings work across modules""" + + # Make sure we can load the second module with the conflicting (but local) definition: + import pybind11_cross_module_tests as cm + + i1 = m.LocalType(5) + assert i1.get() == 4 + assert i1.get3() == 8 + + i2 = cm.LocalType(10) + assert i2.get() == 11 + assert i2.get2() == 12 + + assert not hasattr(i1, 'get2') + assert not hasattr(i2, 'get3') + + # Loading within the local module + assert m.local_value(i1) == 5 + assert cm.local_value(i2) == 10 + + # Cross-module loading works as well (on failure, the type loader looks for + # external module-local converters): + assert m.local_value(i2) == 10 + assert cm.local_value(i1) == 5 + + +def test_nonlocal_failure(): + """Tests that attempting to register a non-local type in multiple modules fails""" + import pybind11_cross_module_tests as cm + + with pytest.raises(RuntimeError) as excinfo: + cm.register_nonlocal() + assert str(excinfo.value) == 'generic_type: type "NonLocalType" is already registered!' + + +def test_duplicate_local(): + """Tests expected failure when registering a class twice with py::local in the same module""" + with pytest.raises(RuntimeError) as excinfo: + m.register_local_external() + import pybind11_tests + assert str(excinfo.value) == ( + 'generic_type: type "LocalExternal" is already registered!' + if hasattr(pybind11_tests, 'class_') else 'test_class not enabled') + + +def test_stl_bind_local(): + import pybind11_cross_module_tests as cm + + v1, v2 = m.LocalVec(), cm.LocalVec() + v1.append(m.LocalType(1)) + v1.append(m.LocalType(2)) + v2.append(cm.LocalType(1)) + v2.append(cm.LocalType(2)) + + # Cross module value loading: + v1.append(cm.LocalType(3)) + v2.append(m.LocalType(3)) + + assert [i.get() for i in v1] == [0, 1, 2] + assert [i.get() for i in v2] == [2, 3, 4] + + v3, v4 = m.NonLocalVec(), cm.NonLocalVec2() + v3.append(m.NonLocalType(1)) + v3.append(m.NonLocalType(2)) + v4.append(m.NonLocal2(3)) + v4.append(m.NonLocal2(4)) + + assert [i.get() for i in v3] == [1, 2] + assert [i.get() for i in v4] == [13, 14] + + d1, d2 = m.LocalMap(), cm.LocalMap() + d1["a"] = v1[0] + d1["b"] = v1[1] + d2["c"] = v2[0] + d2["d"] = v2[1] + assert {i: d1[i].get() for i in d1} == {'a': 0, 'b': 1} + assert {i: d2[i].get() for i in d2} == {'c': 2, 'd': 3} + + +def test_stl_bind_global(): + import pybind11_cross_module_tests as cm + + with pytest.raises(RuntimeError) as excinfo: + cm.register_nonlocal_map() + assert str(excinfo.value) == 'generic_type: type "NonLocalMap" is already registered!' + + with pytest.raises(RuntimeError) as excinfo: + cm.register_nonlocal_vec() + assert str(excinfo.value) == 'generic_type: type "NonLocalVec" is already registered!' + + with pytest.raises(RuntimeError) as excinfo: + cm.register_nonlocal_map2() + assert str(excinfo.value) == 'generic_type: type "NonLocalMap2" is already registered!' + + +def test_mixed_local_global(): + """Local types take precedence over globally registered types: a module with a `module_local` + type can be registered even if the type is already registered globally. With the module, + casting will go to the local type; outside the module casting goes to the global type.""" + import pybind11_cross_module_tests as cm + m.register_mixed_global() + m.register_mixed_local() + + a = [] + a.append(m.MixedGlobalLocal(1)) + a.append(m.MixedLocalGlobal(2)) + a.append(m.get_mixed_gl(3)) + a.append(m.get_mixed_lg(4)) + + assert [x.get() for x in a] == [101, 1002, 103, 1004] + + cm.register_mixed_global_local() + cm.register_mixed_local_global() + a.append(m.MixedGlobalLocal(5)) + a.append(m.MixedLocalGlobal(6)) + a.append(cm.MixedGlobalLocal(7)) + a.append(cm.MixedLocalGlobal(8)) + a.append(m.get_mixed_gl(9)) + a.append(m.get_mixed_lg(10)) + a.append(cm.get_mixed_gl(11)) + a.append(cm.get_mixed_lg(12)) + + assert [x.get() for x in a] == \ + [101, 1002, 103, 1004, 105, 1006, 207, 2008, 109, 1010, 211, 2012] + + +def test_internal_locals_differ(): + """Makes sure the internal local type map differs across the two modules""" + import pybind11_cross_module_tests as cm + assert m.local_cpp_types_addr() != cm.local_cpp_types_addr() + + +def test_stl_caster_vs_stl_bind(msg): + """One module uses a generic vector caster from `` while the other + exports `std::vector` via `py:bind_vector` and `py::module_local`""" + import pybind11_cross_module_tests as cm + + v1 = cm.VectorInt([1, 2, 3]) + assert m.load_vector_via_caster(v1) == 6 + assert cm.load_vector_via_binding(v1) == 6 + + v2 = [1, 2, 3] + assert m.load_vector_via_caster(v2) == 6 + with pytest.raises(TypeError) as excinfo: + cm.load_vector_via_binding(v2) == 6 + assert msg(excinfo.value) == """ + load_vector_via_binding(): incompatible function arguments. The following argument types are supported: + 1. (arg0: pybind11_cross_module_tests.VectorInt) -> int + + Invoked with: [1, 2, 3] + """ # noqa: E501 line too long + + +def test_cross_module_calls(): + import pybind11_cross_module_tests as cm + + v1 = m.LocalVec() + v1.append(m.LocalType(1)) + v2 = cm.LocalVec() + v2.append(cm.LocalType(2)) + + # Returning the self pointer should get picked up as returning an existing + # instance (even when that instance is of a foreign, non-local type). + assert m.return_self(v1) is v1 + assert cm.return_self(v2) is v2 + assert m.return_self(v2) is v2 + assert cm.return_self(v1) is v1 + + assert m.LocalVec is not cm.LocalVec + # Returning a copy, on the other hand, always goes to the local type, + # regardless of where the source type came from. + assert type(m.return_copy(v1)) is m.LocalVec + assert type(m.return_copy(v2)) is m.LocalVec + assert type(cm.return_copy(v1)) is cm.LocalVec + assert type(cm.return_copy(v2)) is cm.LocalVec + + # Test the example given in the documentation (which also tests inheritance casting): + mycat = m.Cat("Fluffy") + mydog = cm.Dog("Rover") + assert mycat.get_name() == "Fluffy" + assert mydog.name() == "Rover" + assert m.Cat.__base__.__name__ == "Pet" + assert cm.Dog.__base__.__name__ == "Pet" + assert m.Cat.__base__ is not cm.Dog.__base__ + assert m.pet_name(mycat) == "Fluffy" + assert m.pet_name(mydog) == "Rover" + assert cm.pet_name(mycat) == "Fluffy" + assert cm.pet_name(mydog) == "Rover" + + assert m.MixGL is not cm.MixGL + a = m.MixGL(1) + b = cm.MixGL(2) + assert m.get_gl_value(a) == 11 + assert m.get_gl_value(b) == 12 + assert cm.get_gl_value(a) == 101 + assert cm.get_gl_value(b) == 102 + + c, d = m.MixGL2(3), cm.MixGL2(4) + with pytest.raises(TypeError) as excinfo: + m.get_gl_value(c) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.get_gl_value(d) + assert "incompatible function arguments" in str(excinfo.value) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_methods_and_attributes.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_methods_and_attributes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c7b82f13d005bc62a37b7a272bb4b7ff277b9e60 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_methods_and_attributes.cpp @@ -0,0 +1,460 @@ +/* + tests/test_methods_and_attributes.cpp -- constructors, deconstructors, attribute access, + __str__, argument and return value conventions + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" + +#if !defined(PYBIND11_OVERLOAD_CAST) +template +using overload_cast_ = pybind11::detail::overload_cast_impl; +#endif + +class ExampleMandA { +public: + ExampleMandA() { print_default_created(this); } + ExampleMandA(int value) : value(value) { print_created(this, value); } + ExampleMandA(const ExampleMandA &e) : value(e.value) { print_copy_created(this); } + ExampleMandA(ExampleMandA &&e) : value(e.value) { print_move_created(this); } + ~ExampleMandA() { print_destroyed(this); } + + std::string toString() { + return "ExampleMandA[value=" + std::to_string(value) + "]"; + } + + void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; } + void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; } + + void add1(ExampleMandA other) { value += other.value; } // passing by value + void add2(ExampleMandA &other) { value += other.value; } // passing by reference + void add3(const ExampleMandA &other) { value += other.value; } // passing by const reference + void add4(ExampleMandA *other) { value += other->value; } // passing by pointer + void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer + + void add6(int other) { value += other; } // passing by value + void add7(int &other) { value += other; } // passing by reference + void add8(const int &other) { value += other; } // passing by const reference + void add9(int *other) { value += *other; } // passing by pointer + void add10(const int *other) { value += *other; } // passing by const pointer + + ExampleMandA self1() { return *this; } // return by value + ExampleMandA &self2() { return *this; } // return by reference + const ExampleMandA &self3() { return *this; } // return by const reference + ExampleMandA *self4() { return this; } // return by pointer + const ExampleMandA *self5() { return this; } // return by const pointer + + int internal1() { return value; } // return by value + int &internal2() { return value; } // return by reference + const int &internal3() { return value; } // return by const reference + int *internal4() { return &value; } // return by pointer + const int *internal5() { return &value; } // return by const pointer + + py::str overloaded() { return "()"; } + py::str overloaded(int) { return "(int)"; } + py::str overloaded(int, float) { return "(int, float)"; } + py::str overloaded(float, int) { return "(float, int)"; } + py::str overloaded(int, int) { return "(int, int)"; } + py::str overloaded(float, float) { return "(float, float)"; } + py::str overloaded(int) const { return "(int) const"; } + py::str overloaded(int, float) const { return "(int, float) const"; } + py::str overloaded(float, int) const { return "(float, int) const"; } + py::str overloaded(int, int) const { return "(int, int) const"; } + py::str overloaded(float, float) const { return "(float, float) const"; } + + static py::str overloaded(float) { return "static float"; } + + int value = 0; +}; + +struct TestProperties { + int value = 1; + static int static_value; + + int get() const { return value; } + void set(int v) { value = v; } + + static int static_get() { return static_value; } + static void static_set(int v) { static_value = v; } +}; +int TestProperties::static_value = 1; + +struct TestPropertiesOverride : TestProperties { + int value = 99; + static int static_value; +}; +int TestPropertiesOverride::static_value = 99; + +struct TestPropRVP { + UserType v1{1}; + UserType v2{1}; + static UserType sv1; + static UserType sv2; + + const UserType &get1() const { return v1; } + const UserType &get2() const { return v2; } + UserType get_rvalue() const { return v2; } + void set1(int v) { v1.set(v); } + void set2(int v) { v2.set(v); } +}; +UserType TestPropRVP::sv1(1); +UserType TestPropRVP::sv2(1); + +// py::arg/py::arg_v testing: these arguments just record their argument when invoked +class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; }; +class ArgInspector2 { public: std::string arg = "(default arg inspector 2)"; }; +class ArgAlwaysConverts { }; +namespace pybind11 { namespace detail { +template <> struct type_caster { +public: + PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1")); + + bool load(handle src, bool convert) { + value.arg = "loading ArgInspector1 argument " + + std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. " + "Argument value = " + (std::string) str(src); + return true; + } + + static handle cast(const ArgInspector1 &src, return_value_policy, handle) { + return str(src.arg).release(); + } +}; +template <> struct type_caster { +public: + PYBIND11_TYPE_CASTER(ArgInspector2, _("ArgInspector2")); + + bool load(handle src, bool convert) { + value.arg = "loading ArgInspector2 argument " + + std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. " + "Argument value = " + (std::string) str(src); + return true; + } + + static handle cast(const ArgInspector2 &src, return_value_policy, handle) { + return str(src.arg).release(); + } +}; +template <> struct type_caster { +public: + PYBIND11_TYPE_CASTER(ArgAlwaysConverts, _("ArgAlwaysConverts")); + + bool load(handle, bool convert) { + return convert; + } + + static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) { + return py::none().release(); + } +}; +}} + +// test_custom_caster_destruction +class DestructionTester { +public: + DestructionTester() { print_default_created(this); } + ~DestructionTester() { print_destroyed(this); } + DestructionTester(const DestructionTester &) { print_copy_created(this); } + DestructionTester(DestructionTester &&) { print_move_created(this); } + DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; } + DestructionTester &operator=(DestructionTester &&) { print_move_assigned(this); return *this; } +}; +namespace pybind11 { namespace detail { +template <> struct type_caster { + PYBIND11_TYPE_CASTER(DestructionTester, _("DestructionTester")); + bool load(handle, bool) { return true; } + + static handle cast(const DestructionTester &, return_value_policy, handle) { + return py::bool_(true).release(); + } +}; +}} + +// Test None-allowed py::arg argument policy +class NoneTester { public: int answer = 42; }; +int none1(const NoneTester &obj) { return obj.answer; } +int none2(NoneTester *obj) { return obj ? obj->answer : -1; } +int none3(std::shared_ptr &obj) { return obj ? obj->answer : -1; } +int none4(std::shared_ptr *obj) { return obj && *obj ? (*obj)->answer : -1; } +int none5(std::shared_ptr obj) { return obj ? obj->answer : -1; } + +struct StrIssue { + int val = -1; + + StrIssue() = default; + StrIssue(int i) : val{i} {} +}; + +// Issues #854, #910: incompatible function args when member function/pointer is in unregistered base class +class UnregisteredBase { +public: + void do_nothing() const {} + void increase_value() { rw_value++; ro_value += 0.25; } + void set_int(int v) { rw_value = v; } + int get_int() const { return rw_value; } + double get_double() const { return ro_value; } + int rw_value = 42; + double ro_value = 1.25; +}; +class RegisteredDerived : public UnregisteredBase { +public: + using UnregisteredBase::UnregisteredBase; + double sum() const { return rw_value + ro_value; } +}; + +TEST_SUBMODULE(methods_and_attributes, m) { + // test_methods_and_attributes + py::class_ emna(m, "ExampleMandA"); + emna.def(py::init<>()) + .def(py::init()) + .def(py::init()) + .def("add1", &ExampleMandA::add1) + .def("add2", &ExampleMandA::add2) + .def("add3", &ExampleMandA::add3) + .def("add4", &ExampleMandA::add4) + .def("add5", &ExampleMandA::add5) + .def("add6", &ExampleMandA::add6) + .def("add7", &ExampleMandA::add7) + .def("add8", &ExampleMandA::add8) + .def("add9", &ExampleMandA::add9) + .def("add10", &ExampleMandA::add10) + .def("self1", &ExampleMandA::self1) + .def("self2", &ExampleMandA::self2) + .def("self3", &ExampleMandA::self3) + .def("self4", &ExampleMandA::self4) + .def("self5", &ExampleMandA::self5) + .def("internal1", &ExampleMandA::internal1) + .def("internal2", &ExampleMandA::internal2) + .def("internal3", &ExampleMandA::internal3) + .def("internal4", &ExampleMandA::internal4) + .def("internal5", &ExampleMandA::internal5) +#if defined(PYBIND11_OVERLOAD_CAST) + .def("overloaded", py::overload_cast<>(&ExampleMandA::overloaded)) + .def("overloaded", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded_float", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded_const", py::overload_cast(&ExampleMandA::overloaded, py::const_)) + .def("overloaded_const", py::overload_cast(&ExampleMandA::overloaded, py::const_)) + .def("overloaded_const", py::overload_cast(&ExampleMandA::overloaded, py::const_)) + .def("overloaded_const", py::overload_cast(&ExampleMandA::overloaded, py::const_)) + .def("overloaded_const", py::overload_cast(&ExampleMandA::overloaded, py::const_)) +#else + // Use both the traditional static_cast method and the C++11 compatible overload_cast_ + .def("overloaded", overload_cast_<>()(&ExampleMandA::overloaded)) + .def("overloaded", overload_cast_()(&ExampleMandA::overloaded)) + .def("overloaded", overload_cast_()(&ExampleMandA::overloaded)) + .def("overloaded", static_cast(&ExampleMandA::overloaded)) + .def("overloaded", static_cast(&ExampleMandA::overloaded)) + .def("overloaded", static_cast(&ExampleMandA::overloaded)) + .def("overloaded_float", overload_cast_()(&ExampleMandA::overloaded)) + .def("overloaded_const", overload_cast_()(&ExampleMandA::overloaded, py::const_)) + .def("overloaded_const", overload_cast_()(&ExampleMandA::overloaded, py::const_)) + .def("overloaded_const", static_cast(&ExampleMandA::overloaded)) + .def("overloaded_const", static_cast(&ExampleMandA::overloaded)) + .def("overloaded_const", static_cast(&ExampleMandA::overloaded)) +#endif + // test_no_mixed_overloads + // Raise error if trying to mix static/non-static overloads on the same name: + .def_static("add_mixed_overloads1", []() { + auto emna = py::reinterpret_borrow>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA")); + emna.def ("overload_mixed1", static_cast(&ExampleMandA::overloaded)) + .def_static("overload_mixed1", static_cast(&ExampleMandA::overloaded)); + }) + .def_static("add_mixed_overloads2", []() { + auto emna = py::reinterpret_borrow>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA")); + emna.def_static("overload_mixed2", static_cast(&ExampleMandA::overloaded)) + .def ("overload_mixed2", static_cast(&ExampleMandA::overloaded)); + }) + .def("__str__", &ExampleMandA::toString) + .def_readwrite("value", &ExampleMandA::value); + + // test_copy_method + // Issue #443: can't call copied methods in Python 3 + emna.attr("add2b") = emna.attr("add2"); + + // test_properties, test_static_properties, test_static_cls + py::class_(m, "TestProperties") + .def(py::init<>()) + .def_readonly("def_readonly", &TestProperties::value) + .def_readwrite("def_readwrite", &TestProperties::value) + .def_property("def_writeonly", nullptr, + [](TestProperties& s,int v) { s.value = v; } ) + .def_property("def_property_writeonly", nullptr, &TestProperties::set) + .def_property_readonly("def_property_readonly", &TestProperties::get) + .def_property("def_property", &TestProperties::get, &TestProperties::set) + .def_property("def_property_impossible", nullptr, nullptr) + .def_readonly_static("def_readonly_static", &TestProperties::static_value) + .def_readwrite_static("def_readwrite_static", &TestProperties::static_value) + .def_property_static("def_writeonly_static", nullptr, + [](py::object, int v) { TestProperties::static_value = v; }) + .def_property_readonly_static("def_property_readonly_static", + [](py::object) { return TestProperties::static_get(); }) + .def_property_static("def_property_writeonly_static", nullptr, + [](py::object, int v) { return TestProperties::static_set(v); }) + .def_property_static("def_property_static", + [](py::object) { return TestProperties::static_get(); }, + [](py::object, int v) { TestProperties::static_set(v); }) + .def_property_static("static_cls", + [](py::object cls) { return cls; }, + [](py::object cls, py::function f) { f(cls); }); + + py::class_(m, "TestPropertiesOverride") + .def(py::init<>()) + .def_readonly("def_readonly", &TestPropertiesOverride::value) + .def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value); + + auto static_get1 = [](py::object) -> const UserType & { return TestPropRVP::sv1; }; + auto static_get2 = [](py::object) -> const UserType & { return TestPropRVP::sv2; }; + auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.set(v); }; + auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.set(v); }; + auto rvp_copy = py::return_value_policy::copy; + + // test_property_return_value_policies + py::class_(m, "TestPropRVP") + .def(py::init<>()) + .def_property_readonly("ro_ref", &TestPropRVP::get1) + .def_property_readonly("ro_copy", &TestPropRVP::get2, rvp_copy) + .def_property_readonly("ro_func", py::cpp_function(&TestPropRVP::get2, rvp_copy)) + .def_property("rw_ref", &TestPropRVP::get1, &TestPropRVP::set1) + .def_property("rw_copy", &TestPropRVP::get2, &TestPropRVP::set2, rvp_copy) + .def_property("rw_func", py::cpp_function(&TestPropRVP::get2, rvp_copy), &TestPropRVP::set2) + .def_property_readonly_static("static_ro_ref", static_get1) + .def_property_readonly_static("static_ro_copy", static_get2, rvp_copy) + .def_property_readonly_static("static_ro_func", py::cpp_function(static_get2, rvp_copy)) + .def_property_static("static_rw_ref", static_get1, static_set1) + .def_property_static("static_rw_copy", static_get2, static_set2, rvp_copy) + .def_property_static("static_rw_func", py::cpp_function(static_get2, rvp_copy), static_set2) + // test_property_rvalue_policy + .def_property_readonly("rvalue", &TestPropRVP::get_rvalue) + .def_property_readonly_static("static_rvalue", [](py::object) { return UserType(1); }); + + // test_metaclass_override + struct MetaclassOverride { }; + py::class_(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type)) + .def_property_readonly_static("readonly", [](py::object) { return 1; }); + +#if !defined(PYPY_VERSION) + // test_dynamic_attributes + class DynamicClass { + public: + DynamicClass() { print_default_created(this); } + ~DynamicClass() { print_destroyed(this); } + }; + py::class_(m, "DynamicClass", py::dynamic_attr()) + .def(py::init()); + + class CppDerivedDynamicClass : public DynamicClass { }; + py::class_(m, "CppDerivedDynamicClass") + .def(py::init()); +#endif + + // test_noconvert_args + // + // Test converting. The ArgAlwaysConverts is just there to make the first no-conversion pass + // fail so that our call always ends up happening via the second dispatch (the one that allows + // some conversion). + class ArgInspector { + public: + ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; } + std::string g(ArgInspector1 a, const ArgInspector1 &b, int c, ArgInspector2 *d, ArgAlwaysConverts) { + return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg; + } + static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; } + }; + py::class_(m, "ArgInspector") + .def(py::init<>()) + .def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts()) + .def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts()) + .def_static("h", &ArgInspector::h, py::arg().noconvert(), py::arg() = ArgAlwaysConverts()) + ; + m.def("arg_inspect_func", [](ArgInspector2 a, ArgInspector1 b, ArgAlwaysConverts) { return a.arg + "\n" + b.arg; }, + py::arg().noconvert(false), py::arg_v(nullptr, ArgInspector1()).noconvert(true), py::arg() = ArgAlwaysConverts()); + + m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f")); + m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert()); + m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i")); + m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert()); + + // test_bad_arg_default + // Issue/PR #648: bad arg default debugging output +#if !defined(NDEBUG) + m.attr("debug_enabled") = true; +#else + m.attr("debug_enabled") = false; +#endif + m.def("bad_arg_def_named", []{ + auto m = py::module::import("pybind11_tests"); + m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg("a") = UnregisteredType()); + }); + m.def("bad_arg_def_unnamed", []{ + auto m = py::module::import("pybind11_tests"); + m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType()); + }); + + // test_accepts_none + py::class_>(m, "NoneTester") + .def(py::init<>()); + m.def("no_none1", &none1, py::arg().none(false)); + m.def("no_none2", &none2, py::arg().none(false)); + m.def("no_none3", &none3, py::arg().none(false)); + m.def("no_none4", &none4, py::arg().none(false)); + m.def("no_none5", &none5, py::arg().none(false)); + m.def("ok_none1", &none1); + m.def("ok_none2", &none2, py::arg().none(true)); + m.def("ok_none3", &none3); + m.def("ok_none4", &none4, py::arg().none(true)); + m.def("ok_none5", &none5); + + // test_str_issue + // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid + py::class_(m, "StrIssue") + .def(py::init()) + .def(py::init<>()) + .def("__str__", [](const StrIssue &si) { + return "StrIssue[" + std::to_string(si.val) + "]"; } + ); + + // test_unregistered_base_implementations + // + // Issues #854/910: incompatible function args when member function/pointer is in unregistered + // base class The methods and member pointers below actually resolve to members/pointers in + // UnregisteredBase; before this test/fix they would be registered via lambda with a first + // argument of an unregistered type, and thus uncallable. + py::class_(m, "RegisteredDerived") + .def(py::init<>()) + .def("do_nothing", &RegisteredDerived::do_nothing) + .def("increase_value", &RegisteredDerived::increase_value) + .def_readwrite("rw_value", &RegisteredDerived::rw_value) + .def_readonly("ro_value", &RegisteredDerived::ro_value) + // These should trigger a static_assert if uncommented + //.def_readwrite("fails", &UserType::value) // should trigger a static_assert if uncommented + //.def_readonly("fails", &UserType::value) // should trigger a static_assert if uncommented + .def_property("rw_value_prop", &RegisteredDerived::get_int, &RegisteredDerived::set_int) + .def_property_readonly("ro_value_prop", &RegisteredDerived::get_double) + // This one is in the registered class: + .def("sum", &RegisteredDerived::sum) + ; + + using Adapted = decltype(py::method_adaptor(&RegisteredDerived::do_nothing)); + static_assert(std::is_same::value, ""); + + // test_custom_caster_destruction + // Test that `take_ownership` works on types with a custom type caster when given a pointer + + // default policy: don't take ownership: + m.def("custom_caster_no_destroy", []() { static auto *dt = new DestructionTester(); return dt; }); + + m.def("custom_caster_destroy", []() { return new DestructionTester(); }, + py::return_value_policy::take_ownership); // Takes ownership: destroy when finished + m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); }, + py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction) + m.def("destruction_tester_cstats", &ConstructorStats::get, py::return_value_policy::reference); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_methods_and_attributes.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_methods_and_attributes.py new file mode 100644 index 0000000000000000000000000000000000000000..f1c862be85d93f68f1cc65bcd6609bf5b1cc593d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_methods_and_attributes.py @@ -0,0 +1,512 @@ +import pytest +from pybind11_tests import methods_and_attributes as m +from pybind11_tests import ConstructorStats + + +def test_methods_and_attributes(): + instance1 = m.ExampleMandA() + instance2 = m.ExampleMandA(32) + + instance1.add1(instance2) + instance1.add2(instance2) + instance1.add3(instance2) + instance1.add4(instance2) + instance1.add5(instance2) + instance1.add6(32) + instance1.add7(32) + instance1.add8(32) + instance1.add9(32) + instance1.add10(32) + + assert str(instance1) == "ExampleMandA[value=320]" + assert str(instance2) == "ExampleMandA[value=32]" + assert str(instance1.self1()) == "ExampleMandA[value=320]" + assert str(instance1.self2()) == "ExampleMandA[value=320]" + assert str(instance1.self3()) == "ExampleMandA[value=320]" + assert str(instance1.self4()) == "ExampleMandA[value=320]" + assert str(instance1.self5()) == "ExampleMandA[value=320]" + + assert instance1.internal1() == 320 + assert instance1.internal2() == 320 + assert instance1.internal3() == 320 + assert instance1.internal4() == 320 + assert instance1.internal5() == 320 + + assert instance1.overloaded() == "()" + assert instance1.overloaded(0) == "(int)" + assert instance1.overloaded(1, 1.0) == "(int, float)" + assert instance1.overloaded(2.0, 2) == "(float, int)" + assert instance1.overloaded(3, 3) == "(int, int)" + assert instance1.overloaded(4., 4.) == "(float, float)" + assert instance1.overloaded_const(-3) == "(int) const" + assert instance1.overloaded_const(5, 5.0) == "(int, float) const" + assert instance1.overloaded_const(6.0, 6) == "(float, int) const" + assert instance1.overloaded_const(7, 7) == "(int, int) const" + assert instance1.overloaded_const(8., 8.) == "(float, float) const" + assert instance1.overloaded_float(1, 1) == "(float, float)" + assert instance1.overloaded_float(1, 1.) == "(float, float)" + assert instance1.overloaded_float(1., 1) == "(float, float)" + assert instance1.overloaded_float(1., 1.) == "(float, float)" + + assert instance1.value == 320 + instance1.value = 100 + assert str(instance1) == "ExampleMandA[value=100]" + + cstats = ConstructorStats.get(m.ExampleMandA) + assert cstats.alive() == 2 + del instance1, instance2 + assert cstats.alive() == 0 + assert cstats.values() == ["32"] + assert cstats.default_constructions == 1 + assert cstats.copy_constructions == 3 + assert cstats.move_constructions >= 1 + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + +def test_copy_method(): + """Issue #443: calling copied methods fails in Python 3""" + + m.ExampleMandA.add2c = m.ExampleMandA.add2 + m.ExampleMandA.add2d = m.ExampleMandA.add2b + a = m.ExampleMandA(123) + assert a.value == 123 + a.add2(m.ExampleMandA(-100)) + assert a.value == 23 + a.add2b(m.ExampleMandA(20)) + assert a.value == 43 + a.add2c(m.ExampleMandA(6)) + assert a.value == 49 + a.add2d(m.ExampleMandA(-7)) + assert a.value == 42 + + +def test_properties(): + instance = m.TestProperties() + + assert instance.def_readonly == 1 + with pytest.raises(AttributeError): + instance.def_readonly = 2 + + instance.def_readwrite = 2 + assert instance.def_readwrite == 2 + + assert instance.def_property_readonly == 2 + with pytest.raises(AttributeError): + instance.def_property_readonly = 3 + + instance.def_property = 3 + assert instance.def_property == 3 + + with pytest.raises(AttributeError) as excinfo: + dummy = instance.def_property_writeonly # noqa: F841 unused var + assert "unreadable attribute" in str(excinfo.value) + + instance.def_property_writeonly = 4 + assert instance.def_property_readonly == 4 + + with pytest.raises(AttributeError) as excinfo: + dummy = instance.def_property_impossible # noqa: F841 unused var + assert "unreadable attribute" in str(excinfo.value) + + with pytest.raises(AttributeError) as excinfo: + instance.def_property_impossible = 5 + assert "can't set attribute" in str(excinfo.value) + + +def test_static_properties(): + assert m.TestProperties.def_readonly_static == 1 + with pytest.raises(AttributeError) as excinfo: + m.TestProperties.def_readonly_static = 2 + assert "can't set attribute" in str(excinfo.value) + + m.TestProperties.def_readwrite_static = 2 + assert m.TestProperties.def_readwrite_static == 2 + + with pytest.raises(AttributeError) as excinfo: + dummy = m.TestProperties.def_writeonly_static # noqa: F841 unused var + assert "unreadable attribute" in str(excinfo.value) + + m.TestProperties.def_writeonly_static = 3 + assert m.TestProperties.def_readonly_static == 3 + + assert m.TestProperties.def_property_readonly_static == 3 + with pytest.raises(AttributeError) as excinfo: + m.TestProperties.def_property_readonly_static = 99 + assert "can't set attribute" in str(excinfo.value) + + m.TestProperties.def_property_static = 4 + assert m.TestProperties.def_property_static == 4 + + with pytest.raises(AttributeError) as excinfo: + dummy = m.TestProperties.def_property_writeonly_static + assert "unreadable attribute" in str(excinfo.value) + + m.TestProperties.def_property_writeonly_static = 5 + assert m.TestProperties.def_property_static == 5 + + # Static property read and write via instance + instance = m.TestProperties() + + m.TestProperties.def_readwrite_static = 0 + assert m.TestProperties.def_readwrite_static == 0 + assert instance.def_readwrite_static == 0 + + instance.def_readwrite_static = 2 + assert m.TestProperties.def_readwrite_static == 2 + assert instance.def_readwrite_static == 2 + + with pytest.raises(AttributeError) as excinfo: + dummy = instance.def_property_writeonly_static # noqa: F841 unused var + assert "unreadable attribute" in str(excinfo.value) + + instance.def_property_writeonly_static = 4 + assert instance.def_property_static == 4 + + # It should be possible to override properties in derived classes + assert m.TestPropertiesOverride().def_readonly == 99 + assert m.TestPropertiesOverride.def_readonly_static == 99 + + +def test_static_cls(): + """Static property getter and setters expect the type object as the their only argument""" + + instance = m.TestProperties() + assert m.TestProperties.static_cls is m.TestProperties + assert instance.static_cls is m.TestProperties + + def check_self(self): + assert self is m.TestProperties + + m.TestProperties.static_cls = check_self + instance.static_cls = check_self + + +def test_metaclass_override(): + """Overriding pybind11's default metaclass changes the behavior of `static_property`""" + + assert type(m.ExampleMandA).__name__ == "pybind11_type" + assert type(m.MetaclassOverride).__name__ == "type" + + assert m.MetaclassOverride.readonly == 1 + assert type(m.MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property" + + # Regular `type` replaces the property instead of calling `__set__()` + m.MetaclassOverride.readonly = 2 + assert m.MetaclassOverride.readonly == 2 + assert isinstance(m.MetaclassOverride.__dict__["readonly"], int) + + +def test_no_mixed_overloads(): + from pybind11_tests import debug_enabled + + with pytest.raises(RuntimeError) as excinfo: + m.ExampleMandA.add_mixed_overloads1() + assert (str(excinfo.value) == + "overloading a method with both static and instance methods is not supported; " + + ("compile in debug mode for more details" if not debug_enabled else + "error while attempting to bind static method ExampleMandA.overload_mixed1" + "(arg0: float) -> str") + ) + + with pytest.raises(RuntimeError) as excinfo: + m.ExampleMandA.add_mixed_overloads2() + assert (str(excinfo.value) == + "overloading a method with both static and instance methods is not supported; " + + ("compile in debug mode for more details" if not debug_enabled else + "error while attempting to bind instance method ExampleMandA.overload_mixed2" + "(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)" + " -> str") + ) + + +@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"]) +def test_property_return_value_policies(access): + if not access.startswith("static"): + obj = m.TestPropRVP() + else: + obj = m.TestPropRVP + + ref = getattr(obj, access + "_ref") + assert ref.value == 1 + ref.value = 2 + assert getattr(obj, access + "_ref").value == 2 + ref.value = 1 # restore original value for static properties + + copy = getattr(obj, access + "_copy") + assert copy.value == 1 + copy.value = 2 + assert getattr(obj, access + "_copy").value == 1 + + copy = getattr(obj, access + "_func") + assert copy.value == 1 + copy.value = 2 + assert getattr(obj, access + "_func").value == 1 + + +def test_property_rvalue_policy(): + """When returning an rvalue, the return value policy is automatically changed from + `reference(_internal)` to `move`. The following would not work otherwise.""" + + instance = m.TestPropRVP() + o = instance.rvalue + assert o.value == 1 + + os = m.TestPropRVP.static_rvalue + assert os.value == 1 + + +# https://bitbucket.org/pypy/pypy/issues/2447 +@pytest.unsupported_on_pypy +def test_dynamic_attributes(): + instance = m.DynamicClass() + assert not hasattr(instance, "foo") + assert "foo" not in dir(instance) + + # Dynamically add attribute + instance.foo = 42 + assert hasattr(instance, "foo") + assert instance.foo == 42 + assert "foo" in dir(instance) + + # __dict__ should be accessible and replaceable + assert "foo" in instance.__dict__ + instance.__dict__ = {"bar": True} + assert not hasattr(instance, "foo") + assert hasattr(instance, "bar") + + with pytest.raises(TypeError) as excinfo: + instance.__dict__ = [] + assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'" + + cstats = ConstructorStats.get(m.DynamicClass) + assert cstats.alive() == 1 + del instance + assert cstats.alive() == 0 + + # Derived classes should work as well + class PythonDerivedDynamicClass(m.DynamicClass): + pass + + for cls in m.CppDerivedDynamicClass, PythonDerivedDynamicClass: + derived = cls() + derived.foobar = 100 + assert derived.foobar == 100 + + assert cstats.alive() == 1 + del derived + assert cstats.alive() == 0 + + +# https://bitbucket.org/pypy/pypy/issues/2447 +@pytest.unsupported_on_pypy +def test_cyclic_gc(): + # One object references itself + instance = m.DynamicClass() + instance.circular_reference = instance + + cstats = ConstructorStats.get(m.DynamicClass) + assert cstats.alive() == 1 + del instance + assert cstats.alive() == 0 + + # Two object reference each other + i1 = m.DynamicClass() + i2 = m.DynamicClass() + i1.cycle = i2 + i2.cycle = i1 + + assert cstats.alive() == 2 + del i1, i2 + assert cstats.alive() == 0 + + +def test_noconvert_args(msg): + a = m.ArgInspector() + assert msg(a.f("hi")) == """ + loading ArgInspector1 argument WITH conversion allowed. Argument value = hi + """ + assert msg(a.g("this is a", "this is b")) == """ + loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a + loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b + 13 + loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) + """ # noqa: E501 line too long + assert msg(a.g("this is a", "this is b", 42)) == """ + loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a + loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b + 42 + loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) + """ # noqa: E501 line too long + assert msg(a.g("this is a", "this is b", 42, "this is d")) == """ + loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a + loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b + 42 + loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d + """ + assert (a.h("arg 1") == + "loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1") + assert msg(m.arg_inspect_func("A1", "A2")) == """ + loading ArgInspector2 argument WITH conversion allowed. Argument value = A1 + loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2 + """ + + assert m.floats_preferred(4) == 2.0 + assert m.floats_only(4.0) == 2.0 + with pytest.raises(TypeError) as excinfo: + m.floats_only(4) + assert msg(excinfo.value) == """ + floats_only(): incompatible function arguments. The following argument types are supported: + 1. (f: float) -> float + + Invoked with: 4 + """ + + assert m.ints_preferred(4) == 2 + assert m.ints_preferred(True) == 0 + with pytest.raises(TypeError) as excinfo: + m.ints_preferred(4.0) + assert msg(excinfo.value) == """ + ints_preferred(): incompatible function arguments. The following argument types are supported: + 1. (i: int) -> int + + Invoked with: 4.0 + """ # noqa: E501 line too long + + assert m.ints_only(4) == 2 + with pytest.raises(TypeError) as excinfo: + m.ints_only(4.0) + assert msg(excinfo.value) == """ + ints_only(): incompatible function arguments. The following argument types are supported: + 1. (i: int) -> int + + Invoked with: 4.0 + """ + + +def test_bad_arg_default(msg): + from pybind11_tests import debug_enabled + + with pytest.raises(RuntimeError) as excinfo: + m.bad_arg_def_named() + assert msg(excinfo.value) == ( + "arg(): could not convert default argument 'a: UnregisteredType' in function " + "'should_fail' into a Python object (type not registered yet?)" + if debug_enabled else + "arg(): could not convert default argument into a Python object (type not registered " + "yet?). Compile in debug mode for more information." + ) + + with pytest.raises(RuntimeError) as excinfo: + m.bad_arg_def_unnamed() + assert msg(excinfo.value) == ( + "arg(): could not convert default argument 'UnregisteredType' in function " + "'should_fail' into a Python object (type not registered yet?)" + if debug_enabled else + "arg(): could not convert default argument into a Python object (type not registered " + "yet?). Compile in debug mode for more information." + ) + + +def test_accepts_none(msg): + a = m.NoneTester() + assert m.no_none1(a) == 42 + assert m.no_none2(a) == 42 + assert m.no_none3(a) == 42 + assert m.no_none4(a) == 42 + assert m.no_none5(a) == 42 + assert m.ok_none1(a) == 42 + assert m.ok_none2(a) == 42 + assert m.ok_none3(a) == 42 + assert m.ok_none4(a) == 42 + assert m.ok_none5(a) == 42 + + with pytest.raises(TypeError) as excinfo: + m.no_none1(None) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.no_none2(None) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.no_none3(None) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.no_none4(None) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.no_none5(None) + assert "incompatible function arguments" in str(excinfo.value) + + # The first one still raises because you can't pass None as a lvalue reference arg: + with pytest.raises(TypeError) as excinfo: + assert m.ok_none1(None) == -1 + assert msg(excinfo.value) == """ + ok_none1(): incompatible function arguments. The following argument types are supported: + 1. (arg0: m.methods_and_attributes.NoneTester) -> int + + Invoked with: None + """ + + # The rest take the argument as pointer or holder, and accept None: + assert m.ok_none2(None) == -1 + assert m.ok_none3(None) == -1 + assert m.ok_none4(None) == -1 + assert m.ok_none5(None) == -1 + + +def test_str_issue(msg): + """#283: __str__ called on uninitialized instance when constructor arguments invalid""" + + assert str(m.StrIssue(3)) == "StrIssue[3]" + + with pytest.raises(TypeError) as excinfo: + str(m.StrIssue("no", "such", "constructor")) + assert msg(excinfo.value) == """ + __init__(): incompatible constructor arguments. The following argument types are supported: + 1. m.methods_and_attributes.StrIssue(arg0: int) + 2. m.methods_and_attributes.StrIssue() + + Invoked with: 'no', 'such', 'constructor' + """ + + +def test_unregistered_base_implementations(): + a = m.RegisteredDerived() + a.do_nothing() + assert a.rw_value == 42 + assert a.ro_value == 1.25 + a.rw_value += 5 + assert a.sum() == 48.25 + a.increase_value() + assert a.rw_value == 48 + assert a.ro_value == 1.5 + assert a.sum() == 49.5 + assert a.rw_value_prop == 48 + a.rw_value_prop += 1 + assert a.rw_value_prop == 49 + a.increase_value() + assert a.ro_value_prop == 1.75 + + +def test_custom_caster_destruction(): + """Tests that returning a pointer to a type that gets converted with a custom type caster gets + destroyed when the function has py::return_value_policy::take_ownership policy applied.""" + + cstats = m.destruction_tester_cstats() + # This one *doesn't* have take_ownership: the pointer should be used but not destroyed: + z = m.custom_caster_no_destroy() + assert cstats.alive() == 1 and cstats.default_constructions == 1 + assert z + + # take_ownership applied: this constructs a new object, casts it, then destroys it: + z = m.custom_caster_destroy() + assert z + assert cstats.default_constructions == 2 + + # Same, but with a const pointer return (which should *not* inhibit destruction): + z = m.custom_caster_destroy_const() + assert z + assert cstats.default_constructions == 3 + + # Make sure we still only have the original object (from ..._no_destroy()) alive: + assert cstats.alive() == 1 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_modules.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_modules.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1475fa62357b9b2f2b31b844b2479557665f152 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_modules.cpp @@ -0,0 +1,98 @@ +/* + tests/test_modules.cpp -- nested modules, importing modules, and + internal references + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" + +TEST_SUBMODULE(modules, m) { + // test_nested_modules + py::module m_sub = m.def_submodule("subsubmodule"); + m_sub.def("submodule_func", []() { return "submodule_func()"; }); + + // test_reference_internal + class A { + public: + A(int v) : v(v) { print_created(this, v); } + ~A() { print_destroyed(this); } + A(const A&) { print_copy_created(this); } + A& operator=(const A ©) { print_copy_assigned(this); v = copy.v; return *this; } + std::string toString() { return "A[" + std::to_string(v) + "]"; } + private: + int v; + }; + py::class_(m_sub, "A") + .def(py::init()) + .def("__repr__", &A::toString); + + class B { + public: + B() { print_default_created(this); } + ~B() { print_destroyed(this); } + B(const B&) { print_copy_created(this); } + B& operator=(const B ©) { print_copy_assigned(this); a1 = copy.a1; a2 = copy.a2; return *this; } + A &get_a1() { return a1; } + A &get_a2() { return a2; } + + A a1{1}; + A a2{2}; + }; + py::class_(m_sub, "B") + .def(py::init<>()) + .def("get_a1", &B::get_a1, "Return the internal A 1", py::return_value_policy::reference_internal) + .def("get_a2", &B::get_a2, "Return the internal A 2", py::return_value_policy::reference_internal) + .def_readwrite("a1", &B::a1) // def_readonly uses an internal reference return policy by default + .def_readwrite("a2", &B::a2); + + m.attr("OD") = py::module::import("collections").attr("OrderedDict"); + + // test_duplicate_registration + // Registering two things with the same name + m.def("duplicate_registration", []() { + class Dupe1 { }; + class Dupe2 { }; + class Dupe3 { }; + class DupeException { }; + + auto dm = py::module("dummy"); + auto failures = py::list(); + + py::class_(dm, "Dupe1"); + py::class_(dm, "Dupe2"); + dm.def("dupe1_factory", []() { return Dupe1(); }); + py::exception(dm, "DupeException"); + + try { + py::class_(dm, "Dupe1"); + failures.append("Dupe1 class"); + } catch (std::runtime_error &) {} + try { + dm.def("Dupe1", []() { return Dupe1(); }); + failures.append("Dupe1 function"); + } catch (std::runtime_error &) {} + try { + py::class_(dm, "dupe1_factory"); + failures.append("dupe1_factory"); + } catch (std::runtime_error &) {} + try { + py::exception(dm, "Dupe2"); + failures.append("Dupe2"); + } catch (std::runtime_error &) {} + try { + dm.def("DupeException", []() { return 30; }); + failures.append("DupeException1"); + } catch (std::runtime_error &) {} + try { + py::class_(dm, "DupeException"); + failures.append("DupeException2"); + } catch (std::runtime_error &) {} + + return failures; + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_modules.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_modules.py new file mode 100644 index 0000000000000000000000000000000000000000..2552838c2b888809067c6b524301ce972a400892 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_modules.py @@ -0,0 +1,72 @@ +from pybind11_tests import modules as m +from pybind11_tests.modules import subsubmodule as ms +from pybind11_tests import ConstructorStats + + +def test_nested_modules(): + import pybind11_tests + assert pybind11_tests.__name__ == "pybind11_tests" + assert pybind11_tests.modules.__name__ == "pybind11_tests.modules" + assert pybind11_tests.modules.subsubmodule.__name__ == "pybind11_tests.modules.subsubmodule" + assert m.__name__ == "pybind11_tests.modules" + assert ms.__name__ == "pybind11_tests.modules.subsubmodule" + + assert ms.submodule_func() == "submodule_func()" + + +def test_reference_internal(): + b = ms.B() + assert str(b.get_a1()) == "A[1]" + assert str(b.a1) == "A[1]" + assert str(b.get_a2()) == "A[2]" + assert str(b.a2) == "A[2]" + + b.a1 = ms.A(42) + b.a2 = ms.A(43) + assert str(b.get_a1()) == "A[42]" + assert str(b.a1) == "A[42]" + assert str(b.get_a2()) == "A[43]" + assert str(b.a2) == "A[43]" + + astats, bstats = ConstructorStats.get(ms.A), ConstructorStats.get(ms.B) + assert astats.alive() == 2 + assert bstats.alive() == 1 + del b + assert astats.alive() == 0 + assert bstats.alive() == 0 + assert astats.values() == ['1', '2', '42', '43'] + assert bstats.values() == [] + assert astats.default_constructions == 0 + assert bstats.default_constructions == 1 + assert astats.copy_constructions == 0 + assert bstats.copy_constructions == 0 + # assert astats.move_constructions >= 0 # Don't invoke any + # assert bstats.move_constructions >= 0 # Don't invoke any + assert astats.copy_assignments == 2 + assert bstats.copy_assignments == 0 + assert astats.move_assignments == 0 + assert bstats.move_assignments == 0 + + +def test_importing(): + from pybind11_tests.modules import OD + from collections import OrderedDict + + assert OD is OrderedDict + assert str(OD([(1, 'a'), (2, 'b')])) == "OrderedDict([(1, 'a'), (2, 'b')])" + + +def test_pydoc(): + """Pydoc needs to be able to provide help() for everything inside a pybind11 module""" + import pybind11_tests + import pydoc + + assert pybind11_tests.__name__ == "pybind11_tests" + assert pybind11_tests.__doc__ == "pybind11 test module" + assert pydoc.text.docmodule(pybind11_tests) + + +def test_duplicate_registration(): + """Registering two things with the same name""" + + assert m.duplicate_registration() == [] diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_multiple_inheritance.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_multiple_inheritance.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba1674fb2d0f8c6e69e2473d1f57595fdca379ff --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_multiple_inheritance.cpp @@ -0,0 +1,220 @@ +/* + tests/test_multiple_inheritance.cpp -- multiple inheritance, + implicit MI casts + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" + +// Many bases for testing that multiple inheritance from many classes (i.e. requiring extra +// space for holder constructed flags) works. +template struct BaseN { + BaseN(int i) : i(i) { } + int i; +}; + +// test_mi_static_properties +struct Vanilla { + std::string vanilla() { return "Vanilla"; }; +}; +struct WithStatic1 { + static std::string static_func1() { return "WithStatic1"; }; + static int static_value1; +}; +struct WithStatic2 { + static std::string static_func2() { return "WithStatic2"; }; + static int static_value2; +}; +struct VanillaStaticMix1 : Vanilla, WithStatic1, WithStatic2 { + static std::string static_func() { return "VanillaStaticMix1"; } + static int static_value; +}; +struct VanillaStaticMix2 : WithStatic1, Vanilla, WithStatic2 { + static std::string static_func() { return "VanillaStaticMix2"; } + static int static_value; +}; +int WithStatic1::static_value1 = 1; +int WithStatic2::static_value2 = 2; +int VanillaStaticMix1::static_value = 12; +int VanillaStaticMix2::static_value = 12; + +TEST_SUBMODULE(multiple_inheritance, m) { + + // test_multiple_inheritance_mix1 + // test_multiple_inheritance_mix2 + struct Base1 { + Base1(int i) : i(i) { } + int foo() { return i; } + int i; + }; + py::class_ b1(m, "Base1"); + b1.def(py::init()) + .def("foo", &Base1::foo); + + struct Base2 { + Base2(int i) : i(i) { } + int bar() { return i; } + int i; + }; + py::class_ b2(m, "Base2"); + b2.def(py::init()) + .def("bar", &Base2::bar); + + + // test_multiple_inheritance_cpp + struct Base12 : Base1, Base2 { + Base12(int i, int j) : Base1(i), Base2(j) { } + }; + struct MIType : Base12 { + MIType(int i, int j) : Base12(i, j) { } + }; + py::class_(m, "Base12"); + py::class_(m, "MIType") + .def(py::init()); + + + // test_multiple_inheritance_python_many_bases + #define PYBIND11_BASEN(N) py::class_>(m, "BaseN" #N).def(py::init()).def("f" #N, [](BaseN &b) { return b.i + N; }) + PYBIND11_BASEN( 1); PYBIND11_BASEN( 2); PYBIND11_BASEN( 3); PYBIND11_BASEN( 4); + PYBIND11_BASEN( 5); PYBIND11_BASEN( 6); PYBIND11_BASEN( 7); PYBIND11_BASEN( 8); + PYBIND11_BASEN( 9); PYBIND11_BASEN(10); PYBIND11_BASEN(11); PYBIND11_BASEN(12); + PYBIND11_BASEN(13); PYBIND11_BASEN(14); PYBIND11_BASEN(15); PYBIND11_BASEN(16); + PYBIND11_BASEN(17); + + // Uncommenting this should result in a compile time failure (MI can only be specified via + // template parameters because pybind has to know the types involved; see discussion in #742 for + // details). +// struct Base12v2 : Base1, Base2 { +// Base12v2(int i, int j) : Base1(i), Base2(j) { } +// }; +// py::class_(m, "Base12v2", b1, b2) +// .def(py::init()); + + + // test_multiple_inheritance_virtbase + // Test the case where not all base classes are specified, and where pybind11 requires the + // py::multiple_inheritance flag to perform proper casting between types. + struct Base1a { + Base1a(int i) : i(i) { } + int foo() { return i; } + int i; + }; + py::class_>(m, "Base1a") + .def(py::init()) + .def("foo", &Base1a::foo); + + struct Base2a { + Base2a(int i) : i(i) { } + int bar() { return i; } + int i; + }; + py::class_>(m, "Base2a") + .def(py::init()) + .def("bar", &Base2a::bar); + + struct Base12a : Base1a, Base2a { + Base12a(int i, int j) : Base1a(i), Base2a(j) { } + }; + py::class_>(m, "Base12a", py::multiple_inheritance()) + .def(py::init()); + + m.def("bar_base2a", [](Base2a *b) { return b->bar(); }); + m.def("bar_base2a_sharedptr", [](std::shared_ptr b) { return b->bar(); }); + + // test_mi_unaligned_base + // test_mi_base_return + // Issue #801: invalid casting to derived type with MI bases + struct I801B1 { int a = 1; I801B1() = default; I801B1(const I801B1 &) = default; virtual ~I801B1() = default; }; + struct I801B2 { int b = 2; I801B2() = default; I801B2(const I801B2 &) = default; virtual ~I801B2() = default; }; + struct I801C : I801B1, I801B2 {}; + struct I801D : I801C {}; // Indirect MI + // Unregistered classes: + struct I801B3 { int c = 3; virtual ~I801B3() = default; }; + struct I801E : I801B3, I801D {}; + + py::class_>(m, "I801B1").def(py::init<>()).def_readonly("a", &I801B1::a); + py::class_>(m, "I801B2").def(py::init<>()).def_readonly("b", &I801B2::b); + py::class_>(m, "I801C").def(py::init<>()); + py::class_>(m, "I801D").def(py::init<>()); + + // Two separate issues here: first, we want to recognize a pointer to a base type as being a + // known instance even when the pointer value is unequal (i.e. due to a non-first + // multiple-inheritance base class): + m.def("i801b1_c", [](I801C *c) { return static_cast(c); }); + m.def("i801b2_c", [](I801C *c) { return static_cast(c); }); + m.def("i801b1_d", [](I801D *d) { return static_cast(d); }); + m.def("i801b2_d", [](I801D *d) { return static_cast(d); }); + + // Second, when returned a base class pointer to a derived instance, we cannot assume that the + // pointer is `reinterpret_cast`able to the derived pointer because, like above, the base class + // pointer could be offset. + m.def("i801c_b1", []() -> I801B1 * { return new I801C(); }); + m.def("i801c_b2", []() -> I801B2 * { return new I801C(); }); + m.def("i801d_b1", []() -> I801B1 * { return new I801D(); }); + m.def("i801d_b2", []() -> I801B2 * { return new I801D(); }); + + // Return a base class pointer to a pybind-registered type when the actual derived type + // isn't pybind-registered (and uses multiple-inheritance to offset the pybind base) + m.def("i801e_c", []() -> I801C * { return new I801E(); }); + m.def("i801e_b2", []() -> I801B2 * { return new I801E(); }); + + + // test_mi_static_properties + py::class_(m, "Vanilla") + .def(py::init<>()) + .def("vanilla", &Vanilla::vanilla); + + py::class_(m, "WithStatic1") + .def(py::init<>()) + .def_static("static_func1", &WithStatic1::static_func1) + .def_readwrite_static("static_value1", &WithStatic1::static_value1); + + py::class_(m, "WithStatic2") + .def(py::init<>()) + .def_static("static_func2", &WithStatic2::static_func2) + .def_readwrite_static("static_value2", &WithStatic2::static_value2); + + py::class_( + m, "VanillaStaticMix1") + .def(py::init<>()) + .def_static("static_func", &VanillaStaticMix1::static_func) + .def_readwrite_static("static_value", &VanillaStaticMix1::static_value); + + py::class_( + m, "VanillaStaticMix2") + .def(py::init<>()) + .def_static("static_func", &VanillaStaticMix2::static_func) + .def_readwrite_static("static_value", &VanillaStaticMix2::static_value); + + +#if !defined(PYPY_VERSION) + struct WithDict { }; + struct VanillaDictMix1 : Vanilla, WithDict { }; + struct VanillaDictMix2 : WithDict, Vanilla { }; + py::class_(m, "WithDict", py::dynamic_attr()).def(py::init<>()); + py::class_(m, "VanillaDictMix1").def(py::init<>()); + py::class_(m, "VanillaDictMix2").def(py::init<>()); +#endif + + // test_diamond_inheritance + // Issue #959: segfault when constructing diamond inheritance instance + // All of these have int members so that there will be various unequal pointers involved. + struct B { int b; B() = default; B(const B&) = default; virtual ~B() = default; }; + struct C0 : public virtual B { int c0; }; + struct C1 : public virtual B { int c1; }; + struct D : public C0, public C1 { int d; }; + py::class_(m, "B") + .def("b", [](B *self) { return self; }); + py::class_(m, "C0") + .def("c0", [](C0 *self) { return self; }); + py::class_(m, "C1") + .def("c1", [](C1 *self) { return self; }); + py::class_(m, "D") + .def(py::init<>()); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_multiple_inheritance.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_multiple_inheritance.py new file mode 100644 index 0000000000000000000000000000000000000000..475dd3b3d8a96ecfdd46201f237d791ca81a979e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_multiple_inheritance.py @@ -0,0 +1,349 @@ +import pytest +from pybind11_tests import ConstructorStats +from pybind11_tests import multiple_inheritance as m + + +def test_multiple_inheritance_cpp(): + mt = m.MIType(3, 4) + + assert mt.foo() == 3 + assert mt.bar() == 4 + + +def test_multiple_inheritance_mix1(): + class Base1: + def __init__(self, i): + self.i = i + + def foo(self): + return self.i + + class MITypePy(Base1, m.Base2): + def __init__(self, i, j): + Base1.__init__(self, i) + m.Base2.__init__(self, j) + + mt = MITypePy(3, 4) + + assert mt.foo() == 3 + assert mt.bar() == 4 + + +def test_multiple_inheritance_mix2(): + + class Base2: + def __init__(self, i): + self.i = i + + def bar(self): + return self.i + + class MITypePy(m.Base1, Base2): + def __init__(self, i, j): + m.Base1.__init__(self, i) + Base2.__init__(self, j) + + mt = MITypePy(3, 4) + + assert mt.foo() == 3 + assert mt.bar() == 4 + + +def test_multiple_inheritance_python(): + + class MI1(m.Base1, m.Base2): + def __init__(self, i, j): + m.Base1.__init__(self, i) + m.Base2.__init__(self, j) + + class B1(object): + def v(self): + return 1 + + class MI2(B1, m.Base1, m.Base2): + def __init__(self, i, j): + B1.__init__(self) + m.Base1.__init__(self, i) + m.Base2.__init__(self, j) + + class MI3(MI2): + def __init__(self, i, j): + MI2.__init__(self, i, j) + + class MI4(MI3, m.Base2): + def __init__(self, i, j): + MI3.__init__(self, i, j) + # This should be ignored (Base2 is already initialized via MI2): + m.Base2.__init__(self, i + 100) + + class MI5(m.Base2, B1, m.Base1): + def __init__(self, i, j): + B1.__init__(self) + m.Base1.__init__(self, i) + m.Base2.__init__(self, j) + + class MI6(m.Base2, B1): + def __init__(self, i): + m.Base2.__init__(self, i) + B1.__init__(self) + + class B2(B1): + def v(self): + return 2 + + class B3(object): + def v(self): + return 3 + + class B4(B3, B2): + def v(self): + return 4 + + class MI7(B4, MI6): + def __init__(self, i): + B4.__init__(self) + MI6.__init__(self, i) + + class MI8(MI6, B3): + def __init__(self, i): + MI6.__init__(self, i) + B3.__init__(self) + + class MI8b(B3, MI6): + def __init__(self, i): + B3.__init__(self) + MI6.__init__(self, i) + + mi1 = MI1(1, 2) + assert mi1.foo() == 1 + assert mi1.bar() == 2 + + mi2 = MI2(3, 4) + assert mi2.v() == 1 + assert mi2.foo() == 3 + assert mi2.bar() == 4 + + mi3 = MI3(5, 6) + assert mi3.v() == 1 + assert mi3.foo() == 5 + assert mi3.bar() == 6 + + mi4 = MI4(7, 8) + assert mi4.v() == 1 + assert mi4.foo() == 7 + assert mi4.bar() == 8 + + mi5 = MI5(10, 11) + assert mi5.v() == 1 + assert mi5.foo() == 10 + assert mi5.bar() == 11 + + mi6 = MI6(12) + assert mi6.v() == 1 + assert mi6.bar() == 12 + + mi7 = MI7(13) + assert mi7.v() == 4 + assert mi7.bar() == 13 + + mi8 = MI8(14) + assert mi8.v() == 1 + assert mi8.bar() == 14 + + mi8b = MI8b(15) + assert mi8b.v() == 3 + assert mi8b.bar() == 15 + + +def test_multiple_inheritance_python_many_bases(): + + class MIMany14(m.BaseN1, m.BaseN2, m.BaseN3, m.BaseN4): + def __init__(self): + m.BaseN1.__init__(self, 1) + m.BaseN2.__init__(self, 2) + m.BaseN3.__init__(self, 3) + m.BaseN4.__init__(self, 4) + + class MIMany58(m.BaseN5, m.BaseN6, m.BaseN7, m.BaseN8): + def __init__(self): + m.BaseN5.__init__(self, 5) + m.BaseN6.__init__(self, 6) + m.BaseN7.__init__(self, 7) + m.BaseN8.__init__(self, 8) + + class MIMany916(m.BaseN9, m.BaseN10, m.BaseN11, m.BaseN12, m.BaseN13, m.BaseN14, m.BaseN15, + m.BaseN16): + def __init__(self): + m.BaseN9.__init__(self, 9) + m.BaseN10.__init__(self, 10) + m.BaseN11.__init__(self, 11) + m.BaseN12.__init__(self, 12) + m.BaseN13.__init__(self, 13) + m.BaseN14.__init__(self, 14) + m.BaseN15.__init__(self, 15) + m.BaseN16.__init__(self, 16) + + class MIMany19(MIMany14, MIMany58, m.BaseN9): + def __init__(self): + MIMany14.__init__(self) + MIMany58.__init__(self) + m.BaseN9.__init__(self, 9) + + class MIMany117(MIMany14, MIMany58, MIMany916, m.BaseN17): + def __init__(self): + MIMany14.__init__(self) + MIMany58.__init__(self) + MIMany916.__init__(self) + m.BaseN17.__init__(self, 17) + + # Inherits from 4 registered C++ classes: can fit in one pointer on any modern arch: + a = MIMany14() + for i in range(1, 4): + assert getattr(a, "f" + str(i))() == 2 * i + + # Inherits from 8: requires 1/2 pointers worth of holder flags on 32/64-bit arch: + b = MIMany916() + for i in range(9, 16): + assert getattr(b, "f" + str(i))() == 2 * i + + # Inherits from 9: requires >= 2 pointers worth of holder flags + c = MIMany19() + for i in range(1, 9): + assert getattr(c, "f" + str(i))() == 2 * i + + # Inherits from 17: requires >= 3 pointers worth of holder flags + d = MIMany117() + for i in range(1, 17): + assert getattr(d, "f" + str(i))() == 2 * i + + +def test_multiple_inheritance_virtbase(): + + class MITypePy(m.Base12a): + def __init__(self, i, j): + m.Base12a.__init__(self, i, j) + + mt = MITypePy(3, 4) + assert mt.bar() == 4 + assert m.bar_base2a(mt) == 4 + assert m.bar_base2a_sharedptr(mt) == 4 + + +def test_mi_static_properties(): + """Mixing bases with and without static properties should be possible + and the result should be independent of base definition order""" + + for d in (m.VanillaStaticMix1(), m.VanillaStaticMix2()): + assert d.vanilla() == "Vanilla" + assert d.static_func1() == "WithStatic1" + assert d.static_func2() == "WithStatic2" + assert d.static_func() == d.__class__.__name__ + + m.WithStatic1.static_value1 = 1 + m.WithStatic2.static_value2 = 2 + assert d.static_value1 == 1 + assert d.static_value2 == 2 + assert d.static_value == 12 + + d.static_value1 = 0 + assert d.static_value1 == 0 + d.static_value2 = 0 + assert d.static_value2 == 0 + d.static_value = 0 + assert d.static_value == 0 + + +@pytest.unsupported_on_pypy +def test_mi_dynamic_attributes(): + """Mixing bases with and without dynamic attribute support""" + + for d in (m.VanillaDictMix1(), m.VanillaDictMix2()): + d.dynamic = 1 + assert d.dynamic == 1 + + +def test_mi_unaligned_base(): + """Returning an offset (non-first MI) base class pointer should recognize the instance""" + + n_inst = ConstructorStats.detail_reg_inst() + + c = m.I801C() + d = m.I801D() + # + 4 below because we have the two instances, and each instance has offset base I801B2 + assert ConstructorStats.detail_reg_inst() == n_inst + 4 + b1c = m.i801b1_c(c) + assert b1c is c + b2c = m.i801b2_c(c) + assert b2c is c + b1d = m.i801b1_d(d) + assert b1d is d + b2d = m.i801b2_d(d) + assert b2d is d + + assert ConstructorStats.detail_reg_inst() == n_inst + 4 # no extra instances + del c, b1c, b2c + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + del d, b1d, b2d + assert ConstructorStats.detail_reg_inst() == n_inst + + +def test_mi_base_return(): + """Tests returning an offset (non-first MI) base class pointer to a derived instance""" + + n_inst = ConstructorStats.detail_reg_inst() + + c1 = m.i801c_b1() + assert type(c1) is m.I801C + assert c1.a == 1 + assert c1.b == 2 + + d1 = m.i801d_b1() + assert type(d1) is m.I801D + assert d1.a == 1 + assert d1.b == 2 + + assert ConstructorStats.detail_reg_inst() == n_inst + 4 + + c2 = m.i801c_b2() + assert type(c2) is m.I801C + assert c2.a == 1 + assert c2.b == 2 + + d2 = m.i801d_b2() + assert type(d2) is m.I801D + assert d2.a == 1 + assert d2.b == 2 + + assert ConstructorStats.detail_reg_inst() == n_inst + 8 + + del c2 + assert ConstructorStats.detail_reg_inst() == n_inst + 6 + del c1, d1, d2 + assert ConstructorStats.detail_reg_inst() == n_inst + + # Returning an unregistered derived type with a registered base; we won't + # pick up the derived type, obviously, but should still work (as an object + # of whatever type was returned). + e1 = m.i801e_c() + assert type(e1) is m.I801C + assert e1.a == 1 + assert e1.b == 2 + + e2 = m.i801e_b2() + assert type(e2) is m.I801B2 + assert e2.b == 2 + + +def test_diamond_inheritance(): + """Tests that diamond inheritance works as expected (issue #959)""" + + # Issue #959: this shouldn't segfault: + d = m.D() + + # Make sure all the various distinct pointers are all recognized as registered instances: + assert d is d.c0() + assert d is d.c1() + assert d is d.b() + assert d is d.c0().b() + assert d is d.c1().b() + assert d is d.c0().c1().b().c0().b() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_array.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_array.cpp new file mode 100644 index 0000000000000000000000000000000000000000..156a3bfa8ed74581ad0cf0e2e2d3595be524cb44 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_array.cpp @@ -0,0 +1,390 @@ +/* + tests/test_numpy_array.cpp -- test core array functionality + + Copyright (c) 2016 Ivan Smirnov + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +#include +#include + +#include + +// Size / dtype checks. +struct DtypeCheck { + py::dtype numpy{}; + py::dtype pybind11{}; +}; + +template +DtypeCheck get_dtype_check(const char* name) { + py::module np = py::module::import("numpy"); + DtypeCheck check{}; + check.numpy = np.attr("dtype")(np.attr(name)); + check.pybind11 = py::dtype::of(); + return check; +} + +std::vector get_concrete_dtype_checks() { + return { + // Normalization + get_dtype_check("int8"), + get_dtype_check("uint8"), + get_dtype_check("int16"), + get_dtype_check("uint16"), + get_dtype_check("int32"), + get_dtype_check("uint32"), + get_dtype_check("int64"), + get_dtype_check("uint64") + }; +} + +struct DtypeSizeCheck { + std::string name{}; + int size_cpp{}; + int size_numpy{}; + // For debugging. + py::dtype dtype{}; +}; + +template +DtypeSizeCheck get_dtype_size_check() { + DtypeSizeCheck check{}; + check.name = py::type_id(); + check.size_cpp = sizeof(T); + check.dtype = py::dtype::of(); + check.size_numpy = check.dtype.attr("itemsize").template cast(); + return check; +} + +std::vector get_platform_dtype_size_checks() { + return { + get_dtype_size_check(), + get_dtype_size_check(), + get_dtype_size_check(), + get_dtype_size_check(), + get_dtype_size_check(), + get_dtype_size_check(), + get_dtype_size_check(), + get_dtype_size_check(), + }; +} + +// Arrays. +using arr = py::array; +using arr_t = py::array_t; +static_assert(std::is_same::value, ""); + +template arr data(const arr& a, Ix... index) { + return arr(a.nbytes() - a.offset_at(index...), (const uint8_t *) a.data(index...)); +} + +template arr data_t(const arr_t& a, Ix... index) { + return arr(a.size() - a.index_at(index...), a.data(index...)); +} + +template arr& mutate_data(arr& a, Ix... index) { + auto ptr = (uint8_t *) a.mutable_data(index...); + for (ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++) + ptr[i] = (uint8_t) (ptr[i] * 2); + return a; +} + +template arr_t& mutate_data_t(arr_t& a, Ix... index) { + auto ptr = a.mutable_data(index...); + for (ssize_t i = 0; i < a.size() - a.index_at(index...); i++) + ptr[i]++; + return a; +} + +template ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); } +template ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); } +template ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); } +template ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); } +template ssize_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); } +template arr_t& mutate_at_t(arr_t& a, Ix... idx) { a.mutable_at(idx...)++; return a; } + +#define def_index_fn(name, type) \ + sm.def(#name, [](type a) { return name(a); }); \ + sm.def(#name, [](type a, int i) { return name(a, i); }); \ + sm.def(#name, [](type a, int i, int j) { return name(a, i, j); }); \ + sm.def(#name, [](type a, int i, int j, int k) { return name(a, i, j, k); }); + +template py::handle auxiliaries(T &&r, T2 &&r2) { + if (r.ndim() != 2) throw std::domain_error("error: ndim != 2"); + py::list l; + l.append(*r.data(0, 0)); + l.append(*r2.mutable_data(0, 0)); + l.append(r.data(0, 1) == r2.mutable_data(0, 1)); + l.append(r.ndim()); + l.append(r.itemsize()); + l.append(r.shape(0)); + l.append(r.shape(1)); + l.append(r.size()); + l.append(r.nbytes()); + return l.release(); +} + +// note: declaration at local scope would create a dangling reference! +static int data_i = 42; + +TEST_SUBMODULE(numpy_array, sm) { + try { py::module::import("numpy"); } + catch (...) { return; } + + // test_dtypes + py::class_(sm, "DtypeCheck") + .def_readonly("numpy", &DtypeCheck::numpy) + .def_readonly("pybind11", &DtypeCheck::pybind11) + .def("__repr__", [](const DtypeCheck& self) { + return py::str("").format( + self.numpy, self.pybind11); + }); + sm.def("get_concrete_dtype_checks", &get_concrete_dtype_checks); + + py::class_(sm, "DtypeSizeCheck") + .def_readonly("name", &DtypeSizeCheck::name) + .def_readonly("size_cpp", &DtypeSizeCheck::size_cpp) + .def_readonly("size_numpy", &DtypeSizeCheck::size_numpy) + .def("__repr__", [](const DtypeSizeCheck& self) { + return py::str("").format( + self.name, self.size_cpp, self.size_numpy, self.dtype); + }); + sm.def("get_platform_dtype_size_checks", &get_platform_dtype_size_checks); + + // test_array_attributes + sm.def("ndim", [](const arr& a) { return a.ndim(); }); + sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); }); + sm.def("shape", [](const arr& a, ssize_t dim) { return a.shape(dim); }); + sm.def("strides", [](const arr& a) { return arr(a.ndim(), a.strides()); }); + sm.def("strides", [](const arr& a, ssize_t dim) { return a.strides(dim); }); + sm.def("writeable", [](const arr& a) { return a.writeable(); }); + sm.def("size", [](const arr& a) { return a.size(); }); + sm.def("itemsize", [](const arr& a) { return a.itemsize(); }); + sm.def("nbytes", [](const arr& a) { return a.nbytes(); }); + sm.def("owndata", [](const arr& a) { return a.owndata(); }); + + // test_index_offset + def_index_fn(index_at, const arr&); + def_index_fn(index_at_t, const arr_t&); + def_index_fn(offset_at, const arr&); + def_index_fn(offset_at_t, const arr_t&); + // test_data + def_index_fn(data, const arr&); + def_index_fn(data_t, const arr_t&); + // test_mutate_data, test_mutate_readonly + def_index_fn(mutate_data, arr&); + def_index_fn(mutate_data_t, arr_t&); + def_index_fn(at_t, const arr_t&); + def_index_fn(mutate_at_t, arr_t&); + + // test_make_c_f_array + sm.def("make_f_array", [] { return py::array_t({ 2, 2 }, { 4, 8 }); }); + sm.def("make_c_array", [] { return py::array_t({ 2, 2 }, { 8, 4 }); }); + + // test_empty_shaped_array + sm.def("make_empty_shaped_array", [] { return py::array(py::dtype("f"), {}, {}); }); + // test numpy scalars (empty shape, ndim==0) + sm.def("scalar_int", []() { return py::array(py::dtype("i"), {}, {}, &data_i); }); + + // test_wrap + sm.def("wrap", [](py::array a) { + return py::array( + a.dtype(), + {a.shape(), a.shape() + a.ndim()}, + {a.strides(), a.strides() + a.ndim()}, + a.data(), + a + ); + }); + + // test_numpy_view + struct ArrayClass { + int data[2] = { 1, 2 }; + ArrayClass() { py::print("ArrayClass()"); } + ~ArrayClass() { py::print("~ArrayClass()"); } + }; + py::class_(sm, "ArrayClass") + .def(py::init<>()) + .def("numpy_view", [](py::object &obj) { + py::print("ArrayClass::numpy_view()"); + ArrayClass &a = obj.cast(); + return py::array_t({2}, {4}, a.data, obj); + } + ); + + // test_cast_numpy_int64_to_uint64 + sm.def("function_taking_uint64", [](uint64_t) { }); + + // test_isinstance + sm.def("isinstance_untyped", [](py::object yes, py::object no) { + return py::isinstance(yes) && !py::isinstance(no); + }); + sm.def("isinstance_typed", [](py::object o) { + return py::isinstance>(o) && !py::isinstance>(o); + }); + + // test_constructors + sm.def("default_constructors", []() { + return py::dict( + "array"_a=py::array(), + "array_t"_a=py::array_t(), + "array_t"_a=py::array_t() + ); + }); + sm.def("converting_constructors", [](py::object o) { + return py::dict( + "array"_a=py::array(o), + "array_t"_a=py::array_t(o), + "array_t"_a=py::array_t(o) + ); + }); + + // test_overload_resolution + sm.def("overloaded", [](py::array_t) { return "double"; }); + sm.def("overloaded", [](py::array_t) { return "float"; }); + sm.def("overloaded", [](py::array_t) { return "int"; }); + sm.def("overloaded", [](py::array_t) { return "unsigned short"; }); + sm.def("overloaded", [](py::array_t) { return "long long"; }); + sm.def("overloaded", [](py::array_t>) { return "double complex"; }); + sm.def("overloaded", [](py::array_t>) { return "float complex"; }); + + sm.def("overloaded2", [](py::array_t>) { return "double complex"; }); + sm.def("overloaded2", [](py::array_t) { return "double"; }); + sm.def("overloaded2", [](py::array_t>) { return "float complex"; }); + sm.def("overloaded2", [](py::array_t) { return "float"; }); + + // Only accept the exact types: + sm.def("overloaded3", [](py::array_t) { return "int"; }, py::arg().noconvert()); + sm.def("overloaded3", [](py::array_t) { return "double"; }, py::arg().noconvert()); + + // Make sure we don't do unsafe coercion (e.g. float to int) when not using forcecast, but + // rather that float gets converted via the safe (conversion to double) overload: + sm.def("overloaded4", [](py::array_t) { return "long long"; }); + sm.def("overloaded4", [](py::array_t) { return "double"; }); + + // But we do allow conversion to int if forcecast is enabled (but only if no overload matches + // without conversion) + sm.def("overloaded5", [](py::array_t) { return "unsigned int"; }); + sm.def("overloaded5", [](py::array_t) { return "double"; }); + + // test_greedy_string_overload + // Issue 685: ndarray shouldn't go to std::string overload + sm.def("issue685", [](std::string) { return "string"; }); + sm.def("issue685", [](py::array) { return "array"; }); + sm.def("issue685", [](py::object) { return "other"; }); + + // test_array_unchecked_fixed_dims + sm.def("proxy_add2", [](py::array_t a, double v) { + auto r = a.mutable_unchecked<2>(); + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + r(i, j) += v; + }, py::arg().noconvert(), py::arg()); + + sm.def("proxy_init3", [](double start) { + py::array_t a({ 3, 3, 3 }); + auto r = a.mutable_unchecked<3>(); + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) + r(i, j, k) = start++; + return a; + }); + sm.def("proxy_init3F", [](double start) { + py::array_t a({ 3, 3, 3 }); + auto r = a.mutable_unchecked<3>(); + for (ssize_t k = 0; k < r.shape(2); k++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t i = 0; i < r.shape(0); i++) + r(i, j, k) = start++; + return a; + }); + sm.def("proxy_squared_L2_norm", [](py::array_t a) { + auto r = a.unchecked<1>(); + double sumsq = 0; + for (ssize_t i = 0; i < r.shape(0); i++) + sumsq += r[i] * r(i); // Either notation works for a 1D array + return sumsq; + }); + + sm.def("proxy_auxiliaries2", [](py::array_t a) { + auto r = a.unchecked<2>(); + auto r2 = a.mutable_unchecked<2>(); + return auxiliaries(r, r2); + }); + + // test_array_unchecked_dyn_dims + // Same as the above, but without a compile-time dimensions specification: + sm.def("proxy_add2_dyn", [](py::array_t a, double v) { + auto r = a.mutable_unchecked(); + if (r.ndim() != 2) throw std::domain_error("error: ndim != 2"); + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + r(i, j) += v; + }, py::arg().noconvert(), py::arg()); + sm.def("proxy_init3_dyn", [](double start) { + py::array_t a({ 3, 3, 3 }); + auto r = a.mutable_unchecked(); + if (r.ndim() != 3) throw std::domain_error("error: ndim != 3"); + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) + r(i, j, k) = start++; + return a; + }); + sm.def("proxy_auxiliaries2_dyn", [](py::array_t a) { + return auxiliaries(a.unchecked(), a.mutable_unchecked()); + }); + + sm.def("array_auxiliaries2", [](py::array_t a) { + return auxiliaries(a, a); + }); + + // test_array_failures + // Issue #785: Uninformative "Unknown internal error" exception when constructing array from empty object: + sm.def("array_fail_test", []() { return py::array(py::object()); }); + sm.def("array_t_fail_test", []() { return py::array_t(py::object()); }); + // Make sure the error from numpy is being passed through: + sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); }); + + // test_initializer_list + // Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous + sm.def("array_initializer_list1", []() { return py::array_t(1); }); // { 1 } also works, but clang warns about it + sm.def("array_initializer_list2", []() { return py::array_t({ 1, 2 }); }); + sm.def("array_initializer_list3", []() { return py::array_t({ 1, 2, 3 }); }); + sm.def("array_initializer_list4", []() { return py::array_t({ 1, 2, 3, 4 }); }); + + // test_array_resize + // reshape array to 2D without changing size + sm.def("array_reshape2", [](py::array_t a) { + const ssize_t dim_sz = (ssize_t)std::sqrt(a.size()); + if (dim_sz * dim_sz != a.size()) + throw std::domain_error("array_reshape2: input array total size is not a squared integer"); + a.resize({dim_sz, dim_sz}); + }); + + // resize to 3D array with each dimension = N + sm.def("array_resize3", [](py::array_t a, size_t N, bool refcheck) { + a.resize({N, N, N}, refcheck); + }); + + // test_array_create_and_resize + // return 2D array with Nrows = Ncols = N + sm.def("create_and_resize", [](size_t N) { + py::array_t a; + a.resize({N, N}); + std::fill(a.mutable_data(), a.mutable_data() + a.size(), 42.); + return a; + }); + +#if PY_MAJOR_VERSION >= 3 + sm.def("index_using_ellipsis", [](py::array a) { + return a[py::make_tuple(0, py::ellipsis(), 0)]; + }); +#endif +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_array.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_array.py new file mode 100644 index 0000000000000000000000000000000000000000..d0a6324dfdef832aec694cd6034a7032de8a5e3e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_array.py @@ -0,0 +1,447 @@ +import pytest +from pybind11_tests import numpy_array as m + +pytestmark = pytest.requires_numpy + +with pytest.suppress(ImportError): + import numpy as np + + +def test_dtypes(): + # See issue #1328. + # - Platform-dependent sizes. + for size_check in m.get_platform_dtype_size_checks(): + print(size_check) + assert size_check.size_cpp == size_check.size_numpy, size_check + # - Concrete sizes. + for check in m.get_concrete_dtype_checks(): + print(check) + assert check.numpy == check.pybind11, check + if check.numpy.num != check.pybind11.num: + print("NOTE: typenum mismatch for {}: {} != {}".format( + check, check.numpy.num, check.pybind11.num)) + + +@pytest.fixture(scope='function') +def arr(): + return np.array([[1, 2, 3], [4, 5, 6]], '=u2') + + +def test_array_attributes(): + a = np.array(0, 'f8') + assert m.ndim(a) == 0 + assert all(m.shape(a) == []) + assert all(m.strides(a) == []) + with pytest.raises(IndexError) as excinfo: + m.shape(a, 0) + assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)' + with pytest.raises(IndexError) as excinfo: + m.strides(a, 0) + assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)' + assert m.writeable(a) + assert m.size(a) == 1 + assert m.itemsize(a) == 8 + assert m.nbytes(a) == 8 + assert m.owndata(a) + + a = np.array([[1, 2, 3], [4, 5, 6]], 'u2').view() + a.flags.writeable = False + assert m.ndim(a) == 2 + assert all(m.shape(a) == [2, 3]) + assert m.shape(a, 0) == 2 + assert m.shape(a, 1) == 3 + assert all(m.strides(a) == [6, 2]) + assert m.strides(a, 0) == 6 + assert m.strides(a, 1) == 2 + with pytest.raises(IndexError) as excinfo: + m.shape(a, 2) + assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)' + with pytest.raises(IndexError) as excinfo: + m.strides(a, 2) + assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)' + assert not m.writeable(a) + assert m.size(a) == 6 + assert m.itemsize(a) == 2 + assert m.nbytes(a) == 12 + assert not m.owndata(a) + + +@pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)]) +def test_index_offset(arr, args, ret): + assert m.index_at(arr, *args) == ret + assert m.index_at_t(arr, *args) == ret + assert m.offset_at(arr, *args) == ret * arr.dtype.itemsize + assert m.offset_at_t(arr, *args) == ret * arr.dtype.itemsize + + +def test_dim_check_fail(arr): + for func in (m.index_at, m.index_at_t, m.offset_at, m.offset_at_t, m.data, m.data_t, + m.mutate_data, m.mutate_data_t): + with pytest.raises(IndexError) as excinfo: + func(arr, 1, 2, 3) + assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)' + + +@pytest.mark.parametrize('args, ret', + [([], [1, 2, 3, 4, 5, 6]), + ([1], [4, 5, 6]), + ([0, 1], [2, 3, 4, 5, 6]), + ([1, 2], [6])]) +def test_data(arr, args, ret): + from sys import byteorder + assert all(m.data_t(arr, *args) == ret) + assert all(m.data(arr, *args)[(0 if byteorder == 'little' else 1)::2] == ret) + assert all(m.data(arr, *args)[(1 if byteorder == 'little' else 0)::2] == 0) + + +@pytest.mark.parametrize('dim', [0, 1, 3]) +def test_at_fail(arr, dim): + for func in m.at_t, m.mutate_at_t: + with pytest.raises(IndexError) as excinfo: + func(arr, *([0] * dim)) + assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim) + + +def test_at(arr): + assert m.at_t(arr, 0, 2) == 3 + assert m.at_t(arr, 1, 0) == 4 + + assert all(m.mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6]) + assert all(m.mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6]) + + +def test_mutate_readonly(arr): + arr.flags.writeable = False + for func, args in (m.mutate_data, ()), (m.mutate_data_t, ()), (m.mutate_at_t, (0, 0)): + with pytest.raises(ValueError) as excinfo: + func(arr, *args) + assert str(excinfo.value) == 'array is not writeable' + + +def test_mutate_data(arr): + assert all(m.mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12]) + assert all(m.mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24]) + assert all(m.mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48]) + assert all(m.mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96]) + assert all(m.mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192]) + + assert all(m.mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193]) + assert all(m.mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194]) + assert all(m.mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195]) + assert all(m.mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196]) + assert all(m.mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197]) + + +def test_bounds_check(arr): + for func in (m.index_at, m.index_at_t, m.data, m.data_t, + m.mutate_data, m.mutate_data_t, m.at_t, m.mutate_at_t): + with pytest.raises(IndexError) as excinfo: + func(arr, 2, 0) + assert str(excinfo.value) == 'index 2 is out of bounds for axis 0 with size 2' + with pytest.raises(IndexError) as excinfo: + func(arr, 0, 4) + assert str(excinfo.value) == 'index 4 is out of bounds for axis 1 with size 3' + + +def test_make_c_f_array(): + assert m.make_c_array().flags.c_contiguous + assert not m.make_c_array().flags.f_contiguous + assert m.make_f_array().flags.f_contiguous + assert not m.make_f_array().flags.c_contiguous + + +def test_make_empty_shaped_array(): + m.make_empty_shaped_array() + + # empty shape means numpy scalar, PEP 3118 + assert m.scalar_int().ndim == 0 + assert m.scalar_int().shape == () + assert m.scalar_int() == 42 + + +def test_wrap(): + def assert_references(a, b, base=None): + from distutils.version import LooseVersion + if base is None: + base = a + assert a is not b + assert a.__array_interface__['data'][0] == b.__array_interface__['data'][0] + assert a.shape == b.shape + assert a.strides == b.strides + assert a.flags.c_contiguous == b.flags.c_contiguous + assert a.flags.f_contiguous == b.flags.f_contiguous + assert a.flags.writeable == b.flags.writeable + assert a.flags.aligned == b.flags.aligned + if LooseVersion(np.__version__) >= LooseVersion("1.14.0"): + assert a.flags.writebackifcopy == b.flags.writebackifcopy + else: + assert a.flags.updateifcopy == b.flags.updateifcopy + assert np.all(a == b) + assert not b.flags.owndata + assert b.base is base + if a.flags.writeable and a.ndim == 2: + a[0, 0] = 1234 + assert b[0, 0] == 1234 + + a1 = np.array([1, 2], dtype=np.int16) + assert a1.flags.owndata and a1.base is None + a2 = m.wrap(a1) + assert_references(a1, a2) + + a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='F') + assert a1.flags.owndata and a1.base is None + a2 = m.wrap(a1) + assert_references(a1, a2) + + a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='C') + a1.flags.writeable = False + a2 = m.wrap(a1) + assert_references(a1, a2) + + a1 = np.random.random((4, 4, 4)) + a2 = m.wrap(a1) + assert_references(a1, a2) + + a1t = a1.transpose() + a2 = m.wrap(a1t) + assert_references(a1t, a2, a1) + + a1d = a1.diagonal() + a2 = m.wrap(a1d) + assert_references(a1d, a2, a1) + + a1m = a1[::-1, ::-1, ::-1] + a2 = m.wrap(a1m) + assert_references(a1m, a2, a1) + + +def test_numpy_view(capture): + with capture: + ac = m.ArrayClass() + ac_view_1 = ac.numpy_view() + ac_view_2 = ac.numpy_view() + assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32)) + del ac + pytest.gc_collect() + assert capture == """ + ArrayClass() + ArrayClass::numpy_view() + ArrayClass::numpy_view() + """ + ac_view_1[0] = 4 + ac_view_1[1] = 3 + assert ac_view_2[0] == 4 + assert ac_view_2[1] == 3 + with capture: + del ac_view_1 + del ac_view_2 + pytest.gc_collect() + pytest.gc_collect() + assert capture == """ + ~ArrayClass() + """ + + +@pytest.unsupported_on_pypy +def test_cast_numpy_int64_to_uint64(): + m.function_taking_uint64(123) + m.function_taking_uint64(np.uint64(123)) + + +def test_isinstance(): + assert m.isinstance_untyped(np.array([1, 2, 3]), "not an array") + assert m.isinstance_typed(np.array([1.0, 2.0, 3.0])) + + +def test_constructors(): + defaults = m.default_constructors() + for a in defaults.values(): + assert a.size == 0 + assert defaults["array"].dtype == np.array([]).dtype + assert defaults["array_t"].dtype == np.int32 + assert defaults["array_t"].dtype == np.float64 + + results = m.converting_constructors([1, 2, 3]) + for a in results.values(): + np.testing.assert_array_equal(a, [1, 2, 3]) + assert results["array"].dtype == np.int_ + assert results["array_t"].dtype == np.int32 + assert results["array_t"].dtype == np.float64 + + +def test_overload_resolution(msg): + # Exact overload matches: + assert m.overloaded(np.array([1], dtype='float64')) == 'double' + assert m.overloaded(np.array([1], dtype='float32')) == 'float' + assert m.overloaded(np.array([1], dtype='ushort')) == 'unsigned short' + assert m.overloaded(np.array([1], dtype='intc')) == 'int' + assert m.overloaded(np.array([1], dtype='longlong')) == 'long long' + assert m.overloaded(np.array([1], dtype='complex')) == 'double complex' + assert m.overloaded(np.array([1], dtype='csingle')) == 'float complex' + + # No exact match, should call first convertible version: + assert m.overloaded(np.array([1], dtype='uint8')) == 'double' + + with pytest.raises(TypeError) as excinfo: + m.overloaded("not an array") + assert msg(excinfo.value) == """ + overloaded(): incompatible function arguments. The following argument types are supported: + 1. (arg0: numpy.ndarray[float64]) -> str + 2. (arg0: numpy.ndarray[float32]) -> str + 3. (arg0: numpy.ndarray[int32]) -> str + 4. (arg0: numpy.ndarray[uint16]) -> str + 5. (arg0: numpy.ndarray[int64]) -> str + 6. (arg0: numpy.ndarray[complex128]) -> str + 7. (arg0: numpy.ndarray[complex64]) -> str + + Invoked with: 'not an array' + """ + + assert m.overloaded2(np.array([1], dtype='float64')) == 'double' + assert m.overloaded2(np.array([1], dtype='float32')) == 'float' + assert m.overloaded2(np.array([1], dtype='complex64')) == 'float complex' + assert m.overloaded2(np.array([1], dtype='complex128')) == 'double complex' + assert m.overloaded2(np.array([1], dtype='float32')) == 'float' + + assert m.overloaded3(np.array([1], dtype='float64')) == 'double' + assert m.overloaded3(np.array([1], dtype='intc')) == 'int' + expected_exc = """ + overloaded3(): incompatible function arguments. The following argument types are supported: + 1. (arg0: numpy.ndarray[int32]) -> str + 2. (arg0: numpy.ndarray[float64]) -> str + + Invoked with: """ + + with pytest.raises(TypeError) as excinfo: + m.overloaded3(np.array([1], dtype='uintc')) + assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype='uint32')) + with pytest.raises(TypeError) as excinfo: + m.overloaded3(np.array([1], dtype='float32')) + assert msg(excinfo.value) == expected_exc + repr(np.array([1.], dtype='float32')) + with pytest.raises(TypeError) as excinfo: + m.overloaded3(np.array([1], dtype='complex')) + assert msg(excinfo.value) == expected_exc + repr(np.array([1. + 0.j])) + + # Exact matches: + assert m.overloaded4(np.array([1], dtype='double')) == 'double' + assert m.overloaded4(np.array([1], dtype='longlong')) == 'long long' + # Non-exact matches requiring conversion. Since float to integer isn't a + # save conversion, it should go to the double overload, but short can go to + # either (and so should end up on the first-registered, the long long). + assert m.overloaded4(np.array([1], dtype='float32')) == 'double' + assert m.overloaded4(np.array([1], dtype='short')) == 'long long' + + assert m.overloaded5(np.array([1], dtype='double')) == 'double' + assert m.overloaded5(np.array([1], dtype='uintc')) == 'unsigned int' + assert m.overloaded5(np.array([1], dtype='float32')) == 'unsigned int' + + +def test_greedy_string_overload(): + """Tests fix for #685 - ndarray shouldn't go to std::string overload""" + + assert m.issue685("abc") == "string" + assert m.issue685(np.array([97, 98, 99], dtype='b')) == "array" + assert m.issue685(123) == "other" + + +def test_array_unchecked_fixed_dims(msg): + z1 = np.array([[1, 2], [3, 4]], dtype='float64') + m.proxy_add2(z1, 10) + assert np.all(z1 == [[11, 12], [13, 14]]) + + with pytest.raises(ValueError) as excinfo: + m.proxy_add2(np.array([1., 2, 3]), 5.0) + assert msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2" + + expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int') + assert np.all(m.proxy_init3(3.0) == expect_c) + expect_f = np.transpose(expect_c) + assert np.all(m.proxy_init3F(3.0) == expect_f) + + assert m.proxy_squared_L2_norm(np.array(range(6))) == 55 + assert m.proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55 + + assert m.proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32] + assert m.proxy_auxiliaries2(z1) == m.array_auxiliaries2(z1) + + +def test_array_unchecked_dyn_dims(msg): + z1 = np.array([[1, 2], [3, 4]], dtype='float64') + m.proxy_add2_dyn(z1, 10) + assert np.all(z1 == [[11, 12], [13, 14]]) + + expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int') + assert np.all(m.proxy_init3_dyn(3.0) == expect_c) + + assert m.proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32] + assert m.proxy_auxiliaries2_dyn(z1) == m.array_auxiliaries2(z1) + + +def test_array_failure(): + with pytest.raises(ValueError) as excinfo: + m.array_fail_test() + assert str(excinfo.value) == 'cannot create a pybind11::array from a nullptr' + + with pytest.raises(ValueError) as excinfo: + m.array_t_fail_test() + assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr' + + with pytest.raises(ValueError) as excinfo: + m.array_fail_test_negative_size() + assert str(excinfo.value) == 'negative dimensions are not allowed' + + +def test_initializer_list(): + assert m.array_initializer_list1().shape == (1,) + assert m.array_initializer_list2().shape == (1, 2) + assert m.array_initializer_list3().shape == (1, 2, 3) + assert m.array_initializer_list4().shape == (1, 2, 3, 4) + + +def test_array_resize(msg): + a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='float64') + m.array_reshape2(a) + assert(a.size == 9) + assert(np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]])) + + # total size change should succced with refcheck off + m.array_resize3(a, 4, False) + assert(a.size == 64) + # ... and fail with refcheck on + try: + m.array_resize3(a, 3, True) + except ValueError as e: + assert(str(e).startswith("cannot resize an array")) + # transposed array doesn't own data + b = a.transpose() + try: + m.array_resize3(b, 3, False) + except ValueError as e: + assert(str(e).startswith("cannot resize this array: it does not own its data")) + # ... but reshape should be fine + m.array_reshape2(b) + assert(b.shape == (8, 8)) + + +@pytest.unsupported_on_pypy +def test_array_create_and_resize(msg): + a = m.create_and_resize(2) + assert(a.size == 4) + assert(np.all(a == 42.)) + + +@pytest.unsupported_on_py2 +def test_index_using_ellipsis(): + a = m.index_using_ellipsis(np.zeros((5, 6, 7))) + assert a.shape == (6,) + + +@pytest.unsupported_on_pypy +def test_dtype_refcount_leak(): + from sys import getrefcount + dtype = np.dtype(np.float_) + a = np.array([1], dtype=dtype) + before = getrefcount(dtype) + m.ndim(a) + after = getrefcount(dtype) + assert after == before diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_dtypes.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_dtypes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..467e0253f7eb422da4fff3b4db7e4836fc2c11f2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_dtypes.cpp @@ -0,0 +1,474 @@ +/* + tests/test_numpy_dtypes.cpp -- Structured and compound NumPy dtypes + + Copyright (c) 2016 Ivan Smirnov + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include + +#ifdef __GNUC__ +#define PYBIND11_PACKED(cls) cls __attribute__((__packed__)) +#else +#define PYBIND11_PACKED(cls) __pragma(pack(push, 1)) cls __pragma(pack(pop)) +#endif + +namespace py = pybind11; + +struct SimpleStruct { + bool bool_; + uint32_t uint_; + float float_; + long double ldbl_; +}; + +std::ostream& operator<<(std::ostream& os, const SimpleStruct& v) { + return os << "s:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_; +} + +struct SimpleStructReordered { + bool bool_; + float float_; + uint32_t uint_; + long double ldbl_; +}; + +PYBIND11_PACKED(struct PackedStruct { + bool bool_; + uint32_t uint_; + float float_; + long double ldbl_; +}); + +std::ostream& operator<<(std::ostream& os, const PackedStruct& v) { + return os << "p:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_; +} + +PYBIND11_PACKED(struct NestedStruct { + SimpleStruct a; + PackedStruct b; +}); + +std::ostream& operator<<(std::ostream& os, const NestedStruct& v) { + return os << "n:a=" << v.a << ";b=" << v.b; +} + +struct PartialStruct { + bool bool_; + uint32_t uint_; + float float_; + uint64_t dummy2; + long double ldbl_; +}; + +struct PartialNestedStruct { + uint64_t dummy1; + PartialStruct a; + uint64_t dummy2; +}; + +struct UnboundStruct { }; + +struct StringStruct { + char a[3]; + std::array b; +}; + +struct ComplexStruct { + std::complex cflt; + std::complex cdbl; +}; + +std::ostream& operator<<(std::ostream& os, const ComplexStruct& v) { + return os << "c:" << v.cflt << "," << v.cdbl; +} + +struct ArrayStruct { + char a[3][4]; + int32_t b[2]; + std::array c; + std::array d[4]; +}; + +PYBIND11_PACKED(struct StructWithUglyNames { + int8_t __x__; + uint64_t __y__; +}); + +enum class E1 : int64_t { A = -1, B = 1 }; +enum E2 : uint8_t { X = 1, Y = 2 }; + +PYBIND11_PACKED(struct EnumStruct { + E1 e1; + E2 e2; +}); + +std::ostream& operator<<(std::ostream& os, const StringStruct& v) { + os << "a='"; + for (size_t i = 0; i < 3 && v.a[i]; i++) os << v.a[i]; + os << "',b='"; + for (size_t i = 0; i < 3 && v.b[i]; i++) os << v.b[i]; + return os << "'"; +} + +std::ostream& operator<<(std::ostream& os, const ArrayStruct& v) { + os << "a={"; + for (int i = 0; i < 3; i++) { + if (i > 0) + os << ','; + os << '{'; + for (int j = 0; j < 3; j++) + os << v.a[i][j] << ','; + os << v.a[i][3] << '}'; + } + os << "},b={" << v.b[0] << ',' << v.b[1]; + os << "},c={" << int(v.c[0]) << ',' << int(v.c[1]) << ',' << int(v.c[2]); + os << "},d={"; + for (int i = 0; i < 4; i++) { + if (i > 0) + os << ','; + os << '{' << v.d[i][0] << ',' << v.d[i][1] << '}'; + } + return os << '}'; +} + +std::ostream& operator<<(std::ostream& os, const EnumStruct& v) { + return os << "e1=" << (v.e1 == E1::A ? "A" : "B") << ",e2=" << (v.e2 == E2::X ? "X" : "Y"); +} + +template +py::array mkarray_via_buffer(size_t n) { + return py::array(py::buffer_info(nullptr, sizeof(T), + py::format_descriptor::format(), + 1, { n }, { sizeof(T) })); +} + +#define SET_TEST_VALS(s, i) do { \ + s.bool_ = (i) % 2 != 0; \ + s.uint_ = (uint32_t) (i); \ + s.float_ = (float) (i) * 1.5f; \ + s.ldbl_ = (long double) (i) * -2.5L; } while (0) + +template +py::array_t create_recarray(size_t n) { + auto arr = mkarray_via_buffer(n); + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (size_t i = 0; i < n; i++) { + SET_TEST_VALS(ptr[i], i); + } + return arr; +} + +template +py::list print_recarray(py::array_t arr) { + const auto req = arr.request(); + const auto ptr = static_cast(req.ptr); + auto l = py::list(); + for (ssize_t i = 0; i < req.size; i++) { + std::stringstream ss; + ss << ptr[i]; + l.append(py::str(ss.str())); + } + return l; +} + +py::array_t test_array_ctors(int i) { + using arr_t = py::array_t; + + std::vector data { 1, 2, 3, 4, 5, 6 }; + std::vector shape { 3, 2 }; + std::vector strides { 8, 4 }; + + auto ptr = data.data(); + auto vptr = (void *) ptr; + auto dtype = py::dtype("int32"); + + py::buffer_info buf_ndim1(vptr, 4, "i", 6); + py::buffer_info buf_ndim1_null(nullptr, 4, "i", 6); + py::buffer_info buf_ndim2(vptr, 4, "i", 2, shape, strides); + py::buffer_info buf_ndim2_null(nullptr, 4, "i", 2, shape, strides); + + auto fill = [](py::array arr) { + auto req = arr.request(); + for (int i = 0; i < 6; i++) ((int32_t *) req.ptr)[i] = i + 1; + return arr; + }; + + switch (i) { + // shape: (3, 2) + case 10: return arr_t(shape, strides, ptr); + case 11: return py::array(shape, strides, ptr); + case 12: return py::array(dtype, shape, strides, vptr); + case 13: return arr_t(shape, ptr); + case 14: return py::array(shape, ptr); + case 15: return py::array(dtype, shape, vptr); + case 16: return arr_t(buf_ndim2); + case 17: return py::array(buf_ndim2); + // shape: (3, 2) - post-fill + case 20: return fill(arr_t(shape, strides)); + case 21: return py::array(shape, strides, ptr); // can't have nullptr due to templated ctor + case 22: return fill(py::array(dtype, shape, strides)); + case 23: return fill(arr_t(shape)); + case 24: return py::array(shape, ptr); // can't have nullptr due to templated ctor + case 25: return fill(py::array(dtype, shape)); + case 26: return fill(arr_t(buf_ndim2_null)); + case 27: return fill(py::array(buf_ndim2_null)); + // shape: (6, ) + case 30: return arr_t(6, ptr); + case 31: return py::array(6, ptr); + case 32: return py::array(dtype, 6, vptr); + case 33: return arr_t(buf_ndim1); + case 34: return py::array(buf_ndim1); + // shape: (6, ) + case 40: return fill(arr_t(6)); + case 41: return py::array(6, ptr); // can't have nullptr due to templated ctor + case 42: return fill(py::array(dtype, 6)); + case 43: return fill(arr_t(buf_ndim1_null)); + case 44: return fill(py::array(buf_ndim1_null)); + } + return arr_t(); +} + +py::list test_dtype_ctors() { + py::list list; + list.append(py::dtype("int32")); + list.append(py::dtype(std::string("float64"))); + list.append(py::dtype::from_args(py::str("bool"))); + py::list names, offsets, formats; + py::dict dict; + names.append(py::str("a")); names.append(py::str("b")); dict["names"] = names; + offsets.append(py::int_(1)); offsets.append(py::int_(10)); dict["offsets"] = offsets; + formats.append(py::dtype("int32")); formats.append(py::dtype("float64")); dict["formats"] = formats; + dict["itemsize"] = py::int_(20); + list.append(py::dtype::from_args(dict)); + list.append(py::dtype(names, formats, offsets, 20)); + list.append(py::dtype(py::buffer_info((void *) 0, sizeof(unsigned int), "I", 1))); + list.append(py::dtype(py::buffer_info((void *) 0, 0, "T{i:a:f:b:}", 1))); + return list; +} + +struct A {}; +struct B {}; + +TEST_SUBMODULE(numpy_dtypes, m) { + try { py::module::import("numpy"); } + catch (...) { return; } + + // typeinfo may be registered before the dtype descriptor for scalar casts to work... + py::class_(m, "SimpleStruct"); + + PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); + PYBIND11_NUMPY_DTYPE(SimpleStructReordered, bool_, uint_, float_, ldbl_); + PYBIND11_NUMPY_DTYPE(PackedStruct, bool_, uint_, float_, ldbl_); + PYBIND11_NUMPY_DTYPE(NestedStruct, a, b); + PYBIND11_NUMPY_DTYPE(PartialStruct, bool_, uint_, float_, ldbl_); + PYBIND11_NUMPY_DTYPE(PartialNestedStruct, a); + PYBIND11_NUMPY_DTYPE(StringStruct, a, b); + PYBIND11_NUMPY_DTYPE(ArrayStruct, a, b, c, d); + PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2); + PYBIND11_NUMPY_DTYPE(ComplexStruct, cflt, cdbl); + + // ... or after + py::class_(m, "PackedStruct"); + + PYBIND11_NUMPY_DTYPE_EX(StructWithUglyNames, __x__, "x", __y__, "y"); + + // If uncommented, this should produce a static_assert failure telling the user that the struct + // is not a POD type +// struct NotPOD { std::string v; NotPOD() : v("hi") {}; }; +// PYBIND11_NUMPY_DTYPE(NotPOD, v); + + // Check that dtypes can be registered programmatically, both from + // initializer lists of field descriptors and from other containers. + py::detail::npy_format_descriptor::register_dtype( + {} + ); + py::detail::npy_format_descriptor::register_dtype( + std::vector{} + ); + + // test_recarray, test_scalar_conversion + m.def("create_rec_simple", &create_recarray); + m.def("create_rec_packed", &create_recarray); + m.def("create_rec_nested", [](size_t n) { // test_signature + py::array_t arr = mkarray_via_buffer(n); + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (size_t i = 0; i < n; i++) { + SET_TEST_VALS(ptr[i].a, i); + SET_TEST_VALS(ptr[i].b, i + 1); + } + return arr; + }); + m.def("create_rec_partial", &create_recarray); + m.def("create_rec_partial_nested", [](size_t n) { + py::array_t arr = mkarray_via_buffer(n); + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (size_t i = 0; i < n; i++) { + SET_TEST_VALS(ptr[i].a, i); + } + return arr; + }); + m.def("print_rec_simple", &print_recarray); + m.def("print_rec_packed", &print_recarray); + m.def("print_rec_nested", &print_recarray); + + // test_format_descriptors + m.def("get_format_unbound", []() { return py::format_descriptor::format(); }); + m.def("print_format_descriptors", []() { + py::list l; + for (const auto &fmt : { + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format() + }) { + l.append(py::cast(fmt)); + } + return l; + }); + + // test_dtype + m.def("print_dtypes", []() { + py::list l; + for (const py::handle &d : { + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of() + }) + l.append(py::str(d)); + return l; + }); + m.def("test_dtype_ctors", &test_dtype_ctors); + m.def("test_dtype_methods", []() { + py::list list; + auto dt1 = py::dtype::of(); + auto dt2 = py::dtype::of(); + list.append(dt1); list.append(dt2); + list.append(py::bool_(dt1.has_fields())); list.append(py::bool_(dt2.has_fields())); + list.append(py::int_(dt1.itemsize())); list.append(py::int_(dt2.itemsize())); + return list; + }); + struct TrailingPaddingStruct { + int32_t a; + char b; + }; + PYBIND11_NUMPY_DTYPE(TrailingPaddingStruct, a, b); + m.def("trailing_padding_dtype", []() { return py::dtype::of(); }); + + // test_string_array + m.def("create_string_array", [](bool non_empty) { + py::array_t arr = mkarray_via_buffer(non_empty ? 4 : 0); + if (non_empty) { + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (ssize_t i = 0; i < req.size * req.itemsize; i++) + static_cast(req.ptr)[i] = 0; + ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a'; + ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a'; + ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a'; + + ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b'; + ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b'; + + ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c'; + } + return arr; + }); + m.def("print_string_array", &print_recarray); + + // test_array_array + m.def("create_array_array", [](size_t n) { + py::array_t arr = mkarray_via_buffer(n); + auto ptr = (ArrayStruct *) arr.mutable_data(); + for (size_t i = 0; i < n; i++) { + for (size_t j = 0; j < 3; j++) + for (size_t k = 0; k < 4; k++) + ptr[i].a[j][k] = char('A' + (i * 100 + j * 10 + k) % 26); + for (size_t j = 0; j < 2; j++) + ptr[i].b[j] = int32_t(i * 1000 + j); + for (size_t j = 0; j < 3; j++) + ptr[i].c[j] = uint8_t(i * 10 + j); + for (size_t j = 0; j < 4; j++) + for (size_t k = 0; k < 2; k++) + ptr[i].d[j][k] = float(i) * 100.0f + float(j) * 10.0f + float(k); + } + return arr; + }); + m.def("print_array_array", &print_recarray); + + // test_enum_array + m.def("create_enum_array", [](size_t n) { + py::array_t arr = mkarray_via_buffer(n); + auto ptr = (EnumStruct *) arr.mutable_data(); + for (size_t i = 0; i < n; i++) { + ptr[i].e1 = static_cast(-1 + ((int) i % 2) * 2); + ptr[i].e2 = static_cast(1 + (i % 2)); + } + return arr; + }); + m.def("print_enum_array", &print_recarray); + + // test_complex_array + m.def("create_complex_array", [](size_t n) { + py::array_t arr = mkarray_via_buffer(n); + auto ptr = (ComplexStruct *) arr.mutable_data(); + for (size_t i = 0; i < n; i++) { + ptr[i].cflt.real(float(i)); + ptr[i].cflt.imag(float(i) + 0.25f); + ptr[i].cdbl.real(double(i) + 0.5); + ptr[i].cdbl.imag(double(i) + 0.75); + } + return arr; + }); + m.def("print_complex_array", &print_recarray); + + // test_array_constructors + m.def("test_array_ctors", &test_array_ctors); + + // test_compare_buffer_info + struct CompareStruct { + bool x; + uint32_t y; + float z; + }; + PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z); + m.def("compare_buffer_info", []() { + py::list list; + list.append(py::bool_(py::detail::compare_buffer_info::compare(py::buffer_info(nullptr, sizeof(float), "f", 1)))); + list.append(py::bool_(py::detail::compare_buffer_info::compare(py::buffer_info(nullptr, sizeof(int), "I", 1)))); + list.append(py::bool_(py::detail::compare_buffer_info::compare(py::buffer_info(nullptr, sizeof(long), "l", 1)))); + list.append(py::bool_(py::detail::compare_buffer_info::compare(py::buffer_info(nullptr, sizeof(long), sizeof(long) == sizeof(int) ? "i" : "q", 1)))); + list.append(py::bool_(py::detail::compare_buffer_info::compare(py::buffer_info(nullptr, sizeof(CompareStruct), "T{?:x:3xI:y:f:z:}", 1)))); + return list; + }); + m.def("buffer_to_dtype", [](py::buffer& buf) { return py::dtype(buf.request()); }); + + // test_scalar_conversion + m.def("f_simple", [](SimpleStruct s) { return s.uint_ * 10; }); + m.def("f_packed", [](PackedStruct s) { return s.uint_ * 10; }); + m.def("f_nested", [](NestedStruct s) { return s.a.uint_ * 10; }); + + // test_register_dtype + m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); }); + + // test_str_leak + m.def("dtype_wrapper", [](py::object d) { return py::dtype::from_args(std::move(d)); }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_dtypes.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_dtypes.py new file mode 100644 index 0000000000000000000000000000000000000000..2e638851749fcd5685bf569897d1b95274f24653 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_dtypes.py @@ -0,0 +1,310 @@ +import re +import pytest +from pybind11_tests import numpy_dtypes as m + +pytestmark = pytest.requires_numpy + +with pytest.suppress(ImportError): + import numpy as np + + +@pytest.fixture(scope='module') +def simple_dtype(): + ld = np.dtype('longdouble') + return np.dtype({'names': ['bool_', 'uint_', 'float_', 'ldbl_'], + 'formats': ['?', 'u4', 'f4', 'f{}'.format(ld.itemsize)], + 'offsets': [0, 4, 8, (16 if ld.alignment > 4 else 12)]}) + + +@pytest.fixture(scope='module') +def packed_dtype(): + return np.dtype([('bool_', '?'), ('uint_', 'u4'), ('float_', 'f4'), ('ldbl_', 'g')]) + + +def dt_fmt(): + from sys import byteorder + e = '<' if byteorder == 'little' else '>' + return ("{{'names':['bool_','uint_','float_','ldbl_']," + " 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}']," + " 'offsets':[0,4,8,{}], 'itemsize':{}}}") + + +def simple_dtype_fmt(): + ld = np.dtype('longdouble') + simple_ld_off = 12 + 4 * (ld.alignment > 4) + return dt_fmt().format(ld.itemsize, simple_ld_off, simple_ld_off + ld.itemsize) + + +def packed_dtype_fmt(): + from sys import byteorder + return "[('bool_', '?'), ('uint_', '{e}u4'), ('float_', '{e}f4'), ('ldbl_', '{e}f{}')]".format( + np.dtype('longdouble').itemsize, e='<' if byteorder == 'little' else '>') + + +def partial_ld_offset(): + return 12 + 4 * (np.dtype('uint64').alignment > 4) + 8 + 8 * ( + np.dtype('longdouble').alignment > 8) + + +def partial_dtype_fmt(): + ld = np.dtype('longdouble') + partial_ld_off = partial_ld_offset() + return dt_fmt().format(ld.itemsize, partial_ld_off, partial_ld_off + ld.itemsize) + + +def partial_nested_fmt(): + ld = np.dtype('longdouble') + partial_nested_off = 8 + 8 * (ld.alignment > 8) + partial_ld_off = partial_ld_offset() + partial_nested_size = partial_nested_off * 2 + partial_ld_off + ld.itemsize + return "{{'names':['a'], 'formats':[{}], 'offsets':[{}], 'itemsize':{}}}".format( + partial_dtype_fmt(), partial_nested_off, partial_nested_size) + + +def assert_equal(actual, expected_data, expected_dtype): + np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype)) + + +def test_format_descriptors(): + with pytest.raises(RuntimeError) as excinfo: + m.get_format_unbound() + assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value)) + + ld = np.dtype('longdouble') + ldbl_fmt = ('4x' if ld.alignment > 4 else '') + ld.char + ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}" + dbl = np.dtype('double') + partial_fmt = ("^T{?:bool_:3xI:uint_:f:float_:" + + str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) + + "xg:ldbl_:}") + nested_extra = str(max(8, ld.alignment)) + assert m.print_format_descriptors() == [ + ss_fmt, + "^T{?:bool_:I:uint_:f:float_:g:ldbl_:}", + "^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}", + partial_fmt, + "^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}", + "^T{3s:a:3s:b:}", + "^T{(3)4s:a:(2)i:b:(3)B:c:1x(4, 2)f:d:}", + '^T{q:e1:B:e2:}', + '^T{Zf:cflt:Zd:cdbl:}' + ] + + +def test_dtype(simple_dtype): + from sys import byteorder + e = '<' if byteorder == 'little' else '>' + + assert m.print_dtypes() == [ + simple_dtype_fmt(), + packed_dtype_fmt(), + "[('a', {}), ('b', {})]".format(simple_dtype_fmt(), packed_dtype_fmt()), + partial_dtype_fmt(), + partial_nested_fmt(), + "[('a', 'S3'), ('b', 'S3')]", + ("{{'names':['a','b','c','d'], " + + "'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('" + e + "f4', (4, 2))], " + + "'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e), + "[('e1', '" + e + "i8'), ('e2', 'u1')]", + "[('x', 'i1'), ('y', '" + e + "u8')]", + "[('cflt', '" + e + "c8'), ('cdbl', '" + e + "c16')]" + ] + + d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'], + 'offsets': [1, 10], 'itemsize': 20}) + d2 = np.dtype([('a', 'i4'), ('b', 'f4')]) + assert m.test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'), + np.dtype('bool'), d1, d1, np.dtype('uint32'), d2] + + assert m.test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True, + np.dtype('int32').itemsize, simple_dtype.itemsize] + + assert m.trailing_padding_dtype() == m.buffer_to_dtype(np.zeros(1, m.trailing_padding_dtype())) + + +def test_recarray(simple_dtype, packed_dtype): + elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)] + + for func, dtype in [(m.create_rec_simple, simple_dtype), (m.create_rec_packed, packed_dtype)]: + arr = func(0) + assert arr.dtype == dtype + assert_equal(arr, [], simple_dtype) + assert_equal(arr, [], packed_dtype) + + arr = func(3) + assert arr.dtype == dtype + assert_equal(arr, elements, simple_dtype) + assert_equal(arr, elements, packed_dtype) + + if dtype == simple_dtype: + assert m.print_rec_simple(arr) == [ + "s:0,0,0,-0", + "s:1,1,1.5,-2.5", + "s:0,2,3,-5" + ] + else: + assert m.print_rec_packed(arr) == [ + "p:0,0,0,-0", + "p:1,1,1.5,-2.5", + "p:0,2,3,-5" + ] + + nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)]) + + arr = m.create_rec_nested(0) + assert arr.dtype == nested_dtype + assert_equal(arr, [], nested_dtype) + + arr = m.create_rec_nested(3) + assert arr.dtype == nested_dtype + assert_equal(arr, [((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)), + ((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)), + ((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5))], nested_dtype) + assert m.print_rec_nested(arr) == [ + "n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5", + "n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5", + "n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5" + ] + + arr = m.create_rec_partial(3) + assert str(arr.dtype) == partial_dtype_fmt() + partial_dtype = arr.dtype + assert '' not in arr.dtype.fields + assert partial_dtype.itemsize > simple_dtype.itemsize + assert_equal(arr, elements, simple_dtype) + assert_equal(arr, elements, packed_dtype) + + arr = m.create_rec_partial_nested(3) + assert str(arr.dtype) == partial_nested_fmt() + assert '' not in arr.dtype.fields + assert '' not in arr.dtype.fields['a'][0].fields + assert arr.dtype.itemsize > partial_dtype.itemsize + np.testing.assert_equal(arr['a'], m.create_rec_partial(3)) + + +def test_array_constructors(): + data = np.arange(1, 7, dtype='int32') + for i in range(8): + np.testing.assert_array_equal(m.test_array_ctors(10 + i), data.reshape((3, 2))) + np.testing.assert_array_equal(m.test_array_ctors(20 + i), data.reshape((3, 2))) + for i in range(5): + np.testing.assert_array_equal(m.test_array_ctors(30 + i), data) + np.testing.assert_array_equal(m.test_array_ctors(40 + i), data) + + +def test_string_array(): + arr = m.create_string_array(True) + assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]" + assert m.print_string_array(arr) == [ + "a='',b=''", + "a='a',b='a'", + "a='ab',b='ab'", + "a='abc',b='abc'" + ] + dtype = arr.dtype + assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc'] + assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc'] + arr = m.create_string_array(False) + assert dtype == arr.dtype + + +def test_array_array(): + from sys import byteorder + e = '<' if byteorder == 'little' else '>' + + arr = m.create_array_array(3) + assert str(arr.dtype) == ( + "{{'names':['a','b','c','d'], " + + "'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " + + "'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e) + assert m.print_array_array(arr) == [ + "a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," + + "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}", + "a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," + + "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}", + "a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001}," + + "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}", + ] + assert arr['a'].tolist() == [[b'ABCD', b'KLMN', b'UVWX'], + [b'WXYZ', b'GHIJ', b'QRST'], + [b'STUV', b'CDEF', b'MNOP']] + assert arr['b'].tolist() == [[0, 1], [1000, 1001], [2000, 2001]] + assert m.create_array_array(0).dtype == arr.dtype + + +def test_enum_array(): + from sys import byteorder + e = '<' if byteorder == 'little' else '>' + + arr = m.create_enum_array(3) + dtype = arr.dtype + assert dtype == np.dtype([('e1', e + 'i8'), ('e2', 'u1')]) + assert m.print_enum_array(arr) == [ + "e1=A,e2=X", + "e1=B,e2=Y", + "e1=A,e2=X" + ] + assert arr['e1'].tolist() == [-1, 1, -1] + assert arr['e2'].tolist() == [1, 2, 1] + assert m.create_enum_array(0).dtype == dtype + + +def test_complex_array(): + from sys import byteorder + e = '<' if byteorder == 'little' else '>' + + arr = m.create_complex_array(3) + dtype = arr.dtype + assert dtype == np.dtype([('cflt', e + 'c8'), ('cdbl', e + 'c16')]) + assert m.print_complex_array(arr) == [ + "c:(0,0.25),(0.5,0.75)", + "c:(1,1.25),(1.5,1.75)", + "c:(2,2.25),(2.5,2.75)" + ] + assert arr['cflt'].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j] + assert arr['cdbl'].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j] + assert m.create_complex_array(0).dtype == dtype + + +def test_signature(doc): + assert doc(m.create_rec_nested) == \ + "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]" + + +def test_scalar_conversion(): + n = 3 + arrays = [m.create_rec_simple(n), m.create_rec_packed(n), + m.create_rec_nested(n), m.create_enum_array(n)] + funcs = [m.f_simple, m.f_packed, m.f_nested] + + for i, func in enumerate(funcs): + for j, arr in enumerate(arrays): + if i == j and i < 2: + assert [func(arr[k]) for k in range(n)] == [k * 10 for k in range(n)] + else: + with pytest.raises(TypeError) as excinfo: + func(arr[0]) + assert 'incompatible function arguments' in str(excinfo.value) + + +def test_register_dtype(): + with pytest.raises(RuntimeError) as excinfo: + m.register_dtype() + assert 'dtype is already registered' in str(excinfo.value) + + +@pytest.unsupported_on_pypy +def test_str_leak(): + from sys import getrefcount + fmt = "f4" + pytest.gc_collect() + start = getrefcount(fmt) + d = m.dtype_wrapper(fmt) + assert d is np.dtype("f4") + del d + pytest.gc_collect() + assert getrefcount(fmt) == start + + +def test_compare_buffer_info(): + assert all(m.compare_buffer_info()) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_vectorize.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_vectorize.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a875a74b99e95285ad5733616ad3f2ff1d0b2900 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_vectorize.cpp @@ -0,0 +1,89 @@ +/* + tests/test_numpy_vectorize.cpp -- auto-vectorize functions over NumPy array + arguments + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include + +double my_func(int x, float y, double z) { + py::print("my_func(x:int={}, y:float={:.0f}, z:float={:.0f})"_s.format(x, y, z)); + return (float) x*y*z; +} + +TEST_SUBMODULE(numpy_vectorize, m) { + try { py::module::import("numpy"); } + catch (...) { return; } + + // test_vectorize, test_docs, test_array_collapse + // Vectorize all arguments of a function (though non-vector arguments are also allowed) + m.def("vectorized_func", py::vectorize(my_func)); + + // Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization) + m.def("vectorized_func2", + [](py::array_t x, py::array_t y, float z) { + return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(x, y); + } + ); + + // Vectorize a complex-valued function + m.def("vectorized_func3", py::vectorize( + [](std::complex c) { return c * std::complex(2.f); } + )); + + // test_type_selection + // Numpy function which only accepts specific data types + m.def("selective_func", [](py::array_t) { return "Int branch taken."; }); + m.def("selective_func", [](py::array_t) { return "Float branch taken."; }); + m.def("selective_func", [](py::array_t, py::array::c_style>) { return "Complex float branch taken."; }); + + + // test_passthrough_arguments + // Passthrough test: references and non-pod types should be automatically passed through (in the + // function definition below, only `b`, `d`, and `g` are vectorized): + struct NonPODClass { + NonPODClass(int v) : value{v} {} + int value; + }; + py::class_(m, "NonPODClass").def(py::init()); + m.def("vec_passthrough", py::vectorize( + [](double *a, double b, py::array_t c, const int &d, int &e, NonPODClass f, const double g) { + return *a + b + c.at(0) + d + e + f.value + g; + } + )); + + // test_method_vectorization + struct VectorizeTestClass { + VectorizeTestClass(int v) : value{v} {}; + float method(int x, float y) { return y + (float) (x + value); } + int value = 0; + }; + py::class_ vtc(m, "VectorizeTestClass"); + vtc .def(py::init()) + .def_readwrite("value", &VectorizeTestClass::value); + + // Automatic vectorizing of methods + vtc.def("method", py::vectorize(&VectorizeTestClass::method)); + + // test_trivial_broadcasting + // Internal optimization test for whether the input is trivially broadcastable: + py::enum_(m, "trivial") + .value("f_trivial", py::detail::broadcast_trivial::f_trivial) + .value("c_trivial", py::detail::broadcast_trivial::c_trivial) + .value("non_trivial", py::detail::broadcast_trivial::non_trivial); + m.def("vectorized_is_trivial", []( + py::array_t arg1, + py::array_t arg2, + py::array_t arg3 + ) { + ssize_t ndim; + std::vector shape; + std::array buffers {{ arg1.request(), arg2.request(), arg3.request() }}; + return py::detail::broadcast(buffers, ndim, shape); + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_vectorize.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_vectorize.py new file mode 100644 index 0000000000000000000000000000000000000000..0e9c883978a1a717edf8630172ba3168c350abf9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_numpy_vectorize.py @@ -0,0 +1,196 @@ +import pytest +from pybind11_tests import numpy_vectorize as m + +pytestmark = pytest.requires_numpy + +with pytest.suppress(ImportError): + import numpy as np + + +def test_vectorize(capture): + assert np.isclose(m.vectorized_func3(np.array(3 + 7j)), [6 + 14j]) + + for f in [m.vectorized_func, m.vectorized_func2]: + with capture: + assert np.isclose(f(1, 2, 3), 6) + assert capture == "my_func(x:int=1, y:float=2, z:float=3)" + with capture: + assert np.isclose(f(np.array(1), np.array(2), 3), 6) + assert capture == "my_func(x:int=1, y:float=2, z:float=3)" + with capture: + assert np.allclose(f(np.array([1, 3]), np.array([2, 4]), 3), [6, 36]) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=3) + my_func(x:int=3, y:float=4, z:float=3) + """ + with capture: + a = np.array([[1, 2], [3, 4]], order='F') + b = np.array([[10, 20], [30, 40]], order='F') + c = 3 + result = f(a, b, c) + assert np.allclose(result, a * b * c) + assert result.flags.f_contiguous + # All inputs are F order and full or singletons, so we the result is in col-major order: + assert capture == """ + my_func(x:int=1, y:float=10, z:float=3) + my_func(x:int=3, y:float=30, z:float=3) + my_func(x:int=2, y:float=20, z:float=3) + my_func(x:int=4, y:float=40, z:float=3) + """ + with capture: + a, b, c = np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=3) + my_func(x:int=3, y:float=4, z:float=3) + my_func(x:int=5, y:float=6, z:float=3) + my_func(x:int=7, y:float=8, z:float=3) + my_func(x:int=9, y:float=10, z:float=3) + my_func(x:int=11, y:float=12, z:float=3) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=2) + my_func(x:int=2, y:float=3, z:float=2) + my_func(x:int=3, y:float=4, z:float=2) + my_func(x:int=4, y:float=2, z:float=2) + my_func(x:int=5, y:float=3, z:float=2) + my_func(x:int=6, y:float=4, z:float=2) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=2) + my_func(x:int=2, y:float=2, z:float=2) + my_func(x:int=3, y:float=2, z:float=2) + my_func(x:int=4, y:float=3, z:float=2) + my_func(x:int=5, y:float=3, z:float=2) + my_func(x:int=6, y:float=3, z:float=2) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]], order='F'), np.array([[2], [3]]), 2 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=2) + my_func(x:int=2, y:float=2, z:float=2) + my_func(x:int=3, y:float=2, z:float=2) + my_func(x:int=4, y:float=3, z:float=2) + my_func(x:int=5, y:float=3, z:float=2) + my_func(x:int=6, y:float=3, z:float=2) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]])[::, ::2], np.array([[2], [3]]), 2 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=2) + my_func(x:int=3, y:float=2, z:float=2) + my_func(x:int=4, y:float=3, z:float=2) + my_func(x:int=6, y:float=3, z:float=2) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]], order='F')[::, ::2], np.array([[2], [3]]), 2 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=2) + my_func(x:int=3, y:float=2, z:float=2) + my_func(x:int=4, y:float=3, z:float=2) + my_func(x:int=6, y:float=3, z:float=2) + """ + + +def test_type_selection(): + assert m.selective_func(np.array([1], dtype=np.int32)) == "Int branch taken." + assert m.selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken." + assert m.selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken." + + +def test_docs(doc): + assert doc(m.vectorized_func) == """ + vectorized_func(arg0: numpy.ndarray[int32], arg1: numpy.ndarray[float32], arg2: numpy.ndarray[float64]) -> object + """ # noqa: E501 line too long + + +def test_trivial_broadcasting(): + trivial, vectorized_is_trivial = m.trivial, m.vectorized_is_trivial + + assert vectorized_is_trivial(1, 2, 3) == trivial.c_trivial + assert vectorized_is_trivial(np.array(1), np.array(2), 3) == trivial.c_trivial + assert vectorized_is_trivial(np.array([1, 3]), np.array([2, 4]), 3) == trivial.c_trivial + assert trivial.c_trivial == vectorized_is_trivial( + np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3) + assert vectorized_is_trivial( + np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2) == trivial.non_trivial + assert vectorized_is_trivial( + np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2) == trivial.non_trivial + z1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype='int32') + z2 = np.array(z1, dtype='float32') + z3 = np.array(z1, dtype='float64') + assert vectorized_is_trivial(z1, z2, z3) == trivial.c_trivial + assert vectorized_is_trivial(1, z2, z3) == trivial.c_trivial + assert vectorized_is_trivial(z1, 1, z3) == trivial.c_trivial + assert vectorized_is_trivial(z1, z2, 1) == trivial.c_trivial + assert vectorized_is_trivial(z1[::2, ::2], 1, 1) == trivial.non_trivial + assert vectorized_is_trivial(1, 1, z1[::2, ::2]) == trivial.c_trivial + assert vectorized_is_trivial(1, 1, z3[::2, ::2]) == trivial.non_trivial + assert vectorized_is_trivial(z1, 1, z3[1::4, 1::4]) == trivial.c_trivial + + y1 = np.array(z1, order='F') + y2 = np.array(y1) + y3 = np.array(y1) + assert vectorized_is_trivial(y1, y2, y3) == trivial.f_trivial + assert vectorized_is_trivial(y1, 1, 1) == trivial.f_trivial + assert vectorized_is_trivial(1, y2, 1) == trivial.f_trivial + assert vectorized_is_trivial(1, 1, y3) == trivial.f_trivial + assert vectorized_is_trivial(y1, z2, 1) == trivial.non_trivial + assert vectorized_is_trivial(z1[1::4, 1::4], y2, 1) == trivial.f_trivial + assert vectorized_is_trivial(y1[1::4, 1::4], z2, 1) == trivial.c_trivial + + assert m.vectorized_func(z1, z2, z3).flags.c_contiguous + assert m.vectorized_func(y1, y2, y3).flags.f_contiguous + assert m.vectorized_func(z1, 1, 1).flags.c_contiguous + assert m.vectorized_func(1, y2, 1).flags.f_contiguous + assert m.vectorized_func(z1[1::4, 1::4], y2, 1).flags.f_contiguous + assert m.vectorized_func(y1[1::4, 1::4], z2, 1).flags.c_contiguous + + +def test_passthrough_arguments(doc): + assert doc(m.vec_passthrough) == ( + "vec_passthrough(" + ", ".join([ + "arg0: float", + "arg1: numpy.ndarray[float64]", + "arg2: numpy.ndarray[float64]", + "arg3: numpy.ndarray[int32]", + "arg4: int", + "arg5: m.numpy_vectorize.NonPODClass", + "arg6: numpy.ndarray[float64]"]) + ") -> object") + + b = np.array([[10, 20, 30]], dtype='float64') + c = np.array([100, 200]) # NOT a vectorized argument + d = np.array([[1000], [2000], [3000]], dtype='int') + g = np.array([[1000000, 2000000, 3000000]], dtype='int') # requires casting + assert np.all( + m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g) == + np.array([[1111111, 2111121, 3111131], + [1112111, 2112121, 3112131], + [1113111, 2113121, 3113131]])) + + +def test_method_vectorization(): + o = m.VectorizeTestClass(3) + x = np.array([1, 2], dtype='int') + y = np.array([[10], [20]], dtype='float32') + assert np.all(o.method(x, y) == [[14, 15], [24, 25]]) + + +def test_array_collapse(): + assert not isinstance(m.vectorized_func(1, 2, 3), np.ndarray) + assert not isinstance(m.vectorized_func(np.array(1), 2, 3), np.ndarray) + z = m.vectorized_func([1], 2, 3) + assert isinstance(z, np.ndarray) + assert z.shape == (1, ) + z = m.vectorized_func(1, [[[2]]], 3) + assert isinstance(z, np.ndarray) + assert z.shape == (1, 1, 1) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_opaque_types.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_opaque_types.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d20d9a01c8592e844fb909b336fd5c8e969b9e0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_opaque_types.cpp @@ -0,0 +1,67 @@ +/* + tests/test_opaque_types.cpp -- opaque types, passing void pointers + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include +#include + +// IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures +// +// This also deliberately doesn't use the below StringList type alias to test +// that MAKE_OPAQUE can handle a type containing a `,`. (The `std::allocator` +// bit is just the default `std::vector` allocator). +PYBIND11_MAKE_OPAQUE(std::vector>); + +using StringList = std::vector>; + +TEST_SUBMODULE(opaque_types, m) { + // test_string_list + py::class_(m, "StringList") + .def(py::init<>()) + .def("pop_back", &StringList::pop_back) + /* There are multiple versions of push_back(), etc. Select the right ones. */ + .def("push_back", (void (StringList::*)(const std::string &)) &StringList::push_back) + .def("back", (std::string &(StringList::*)()) &StringList::back) + .def("__len__", [](const StringList &v) { return v.size(); }) + .def("__iter__", [](StringList &v) { + return py::make_iterator(v.begin(), v.end()); + }, py::keep_alive<0, 1>()); + + class ClassWithSTLVecProperty { + public: + StringList stringList; + }; + py::class_(m, "ClassWithSTLVecProperty") + .def(py::init<>()) + .def_readwrite("stringList", &ClassWithSTLVecProperty::stringList); + + m.def("print_opaque_list", [](const StringList &l) { + std::string ret = "Opaque list: ["; + bool first = true; + for (auto entry : l) { + if (!first) + ret += ", "; + ret += entry; + first = false; + } + return ret + "]"; + }); + + // test_pointers + m.def("return_void_ptr", []() { return (void *) 0x1234; }); + m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast(ptr); }); + m.def("return_null_str", []() { return (char *) nullptr; }); + m.def("get_null_str_value", [](char *ptr) { return reinterpret_cast(ptr); }); + + m.def("return_unique_ptr", []() -> std::unique_ptr { + StringList *result = new StringList(); + result->push_back("some value"); + return std::unique_ptr(result); + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_opaque_types.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_opaque_types.py new file mode 100644 index 0000000000000000000000000000000000000000..6b3802fdbafd33f245406b3b7dab787b3bb1cdb2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_opaque_types.py @@ -0,0 +1,46 @@ +import pytest +from pybind11_tests import opaque_types as m +from pybind11_tests import ConstructorStats, UserType + + +def test_string_list(): + lst = m.StringList() + lst.push_back("Element 1") + lst.push_back("Element 2") + assert m.print_opaque_list(lst) == "Opaque list: [Element 1, Element 2]" + assert lst.back() == "Element 2" + + for i, k in enumerate(lst, start=1): + assert k == "Element {}".format(i) + lst.pop_back() + assert m.print_opaque_list(lst) == "Opaque list: [Element 1]" + + cvp = m.ClassWithSTLVecProperty() + assert m.print_opaque_list(cvp.stringList) == "Opaque list: []" + + cvp.stringList = lst + cvp.stringList.push_back("Element 3") + assert m.print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]" + + +def test_pointers(msg): + living_before = ConstructorStats.get(UserType).alive() + assert m.get_void_ptr_value(m.return_void_ptr()) == 0x1234 + assert m.get_void_ptr_value(UserType()) # Should also work for other C++ types + assert ConstructorStats.get(UserType).alive() == living_before + + with pytest.raises(TypeError) as excinfo: + m.get_void_ptr_value([1, 2, 3]) # This should not work + assert msg(excinfo.value) == """ + get_void_ptr_value(): incompatible function arguments. The following argument types are supported: + 1. (arg0: capsule) -> int + + Invoked with: [1, 2, 3] + """ # noqa: E501 line too long + + assert m.return_null_str() is None + assert m.get_null_str_value(m.return_null_str()) is not None + + ptr = m.return_unique_ptr() + assert "StringList" in repr(ptr) + assert m.print_opaque_list(ptr) == "Opaque list: [some value]" diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_operator_overloading.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_operator_overloading.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b111704b81660f86c0a94a9d7f5a2802c3bcb5d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_operator_overloading.cpp @@ -0,0 +1,171 @@ +/* + tests/test_operator_overloading.cpp -- operator overloading + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include +#include + +class Vector2 { +public: + Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); } + Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); } + Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; } + Vector2 &operator=(const Vector2 &v) { x = v.x; y = v.y; print_copy_assigned(this); return *this; } + Vector2 &operator=(Vector2 &&v) { x = v.x; y = v.y; v.x = v.y = 0; print_move_assigned(this); return *this; } + ~Vector2() { print_destroyed(this); } + + std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; } + + Vector2 operator-() const { return Vector2(-x, -y); } + Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } + Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); } + Vector2 operator-(float value) const { return Vector2(x - value, y - value); } + Vector2 operator+(float value) const { return Vector2(x + value, y + value); } + Vector2 operator*(float value) const { return Vector2(x * value, y * value); } + Vector2 operator/(float value) const { return Vector2(x / value, y / value); } + Vector2 operator*(const Vector2 &v) const { return Vector2(x * v.x, y * v.y); } + Vector2 operator/(const Vector2 &v) const { return Vector2(x / v.x, y / v.y); } + Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; } + Vector2& operator-=(const Vector2 &v) { x -= v.x; y -= v.y; return *this; } + Vector2& operator*=(float v) { x *= v; y *= v; return *this; } + Vector2& operator/=(float v) { x /= v; y /= v; return *this; } + Vector2& operator*=(const Vector2 &v) { x *= v.x; y *= v.y; return *this; } + Vector2& operator/=(const Vector2 &v) { x /= v.x; y /= v.y; return *this; } + + friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); } + friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); } + friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); } + friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); } +private: + float x, y; +}; + +class C1 { }; +class C2 { }; + +int operator+(const C1 &, const C1 &) { return 11; } +int operator+(const C2 &, const C2 &) { return 22; } +int operator+(const C2 &, const C1 &) { return 21; } +int operator+(const C1 &, const C2 &) { return 12; } + +namespace std { + template<> + struct hash { + // Not a good hash function, but easy to test + size_t operator()(const Vector2 &) { return 4; } + }; +} + +// MSVC warns about unknown pragmas, and warnings are errors. +#ifndef _MSC_VER + #pragma GCC diagnostic push + // clang 7.0.0 and Apple LLVM 10.0.1 introduce `-Wself-assign-overloaded` to + // `-Wall`, which is used here for overloading (e.g. `py::self += py::self `). + // Here, we suppress the warning using `#pragma diagnostic`. + // Taken from: https://github.com/RobotLocomotion/drake/commit/aaf84b46 + // TODO(eric): This could be resolved using a function / functor (e.g. `py::self()`). + #if (__APPLE__) && (__clang__) + #if (__clang_major__ >= 10) && (__clang_minor__ >= 0) && (__clang_patchlevel__ >= 1) + #pragma GCC diagnostic ignored "-Wself-assign-overloaded" + #endif + #elif (__clang__) + #if (__clang_major__ >= 7) + #pragma GCC diagnostic ignored "-Wself-assign-overloaded" + #endif + #endif +#endif + +TEST_SUBMODULE(operators, m) { + + // test_operator_overloading + py::class_(m, "Vector2") + .def(py::init()) + .def(py::self + py::self) + .def(py::self + float()) + .def(py::self - py::self) + .def(py::self - float()) + .def(py::self * float()) + .def(py::self / float()) + .def(py::self * py::self) + .def(py::self / py::self) + .def(py::self += py::self) + .def(py::self -= py::self) + .def(py::self *= float()) + .def(py::self /= float()) + .def(py::self *= py::self) + .def(py::self /= py::self) + .def(float() + py::self) + .def(float() - py::self) + .def(float() * py::self) + .def(float() / py::self) + .def(-py::self) + .def("__str__", &Vector2::toString) + .def(hash(py::self)) + ; + + m.attr("Vector") = m.attr("Vector2"); + + // test_operators_notimplemented + // #393: need to return NotSupported to ensure correct arithmetic operator behavior + py::class_(m, "C1") + .def(py::init<>()) + .def(py::self + py::self); + + py::class_(m, "C2") + .def(py::init<>()) + .def(py::self + py::self) + .def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; }) + .def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; }); + + // test_nested + // #328: first member in a class can't be used in operators + struct NestABase { int value = -2; }; + py::class_(m, "NestABase") + .def(py::init<>()) + .def_readwrite("value", &NestABase::value); + + struct NestA : NestABase { + int value = 3; + NestA& operator+=(int i) { value += i; return *this; } + }; + py::class_(m, "NestA") + .def(py::init<>()) + .def(py::self += int()) + .def("as_base", [](NestA &a) -> NestABase& { + return (NestABase&) a; + }, py::return_value_policy::reference_internal); + m.def("get_NestA", [](const NestA &a) { return a.value; }); + + struct NestB { + NestA a; + int value = 4; + NestB& operator-=(int i) { value -= i; return *this; } + }; + py::class_(m, "NestB") + .def(py::init<>()) + .def(py::self -= int()) + .def_readwrite("a", &NestB::a); + m.def("get_NestB", [](const NestB &b) { return b.value; }); + + struct NestC { + NestB b; + int value = 5; + NestC& operator*=(int i) { value *= i; return *this; } + }; + py::class_(m, "NestC") + .def(py::init<>()) + .def(py::self *= int()) + .def_readwrite("b", &NestC::b); + m.def("get_NestC", [](const NestC &c) { return c.value; }); +} + +#ifndef _MSC_VER + #pragma GCC diagnostic pop +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_operator_overloading.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_operator_overloading.py new file mode 100644 index 0000000000000000000000000000000000000000..bd36ac2a52aa8ead2049957ab68d648e1feed2ad --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_operator_overloading.py @@ -0,0 +1,108 @@ +import pytest +from pybind11_tests import operators as m +from pybind11_tests import ConstructorStats + + +def test_operator_overloading(): + v1 = m.Vector2(1, 2) + v2 = m.Vector(3, -1) + assert str(v1) == "[1.000000, 2.000000]" + assert str(v2) == "[3.000000, -1.000000]" + + assert str(-v2) == "[-3.000000, 1.000000]" + + assert str(v1 + v2) == "[4.000000, 1.000000]" + assert str(v1 - v2) == "[-2.000000, 3.000000]" + assert str(v1 - 8) == "[-7.000000, -6.000000]" + assert str(v1 + 8) == "[9.000000, 10.000000]" + assert str(v1 * 8) == "[8.000000, 16.000000]" + assert str(v1 / 8) == "[0.125000, 0.250000]" + assert str(8 - v1) == "[7.000000, 6.000000]" + assert str(8 + v1) == "[9.000000, 10.000000]" + assert str(8 * v1) == "[8.000000, 16.000000]" + assert str(8 / v1) == "[8.000000, 4.000000]" + assert str(v1 * v2) == "[3.000000, -2.000000]" + assert str(v2 / v1) == "[3.000000, -0.500000]" + + v1 += 2 * v2 + assert str(v1) == "[7.000000, 0.000000]" + v1 -= v2 + assert str(v1) == "[4.000000, 1.000000]" + v1 *= 2 + assert str(v1) == "[8.000000, 2.000000]" + v1 /= 16 + assert str(v1) == "[0.500000, 0.125000]" + v1 *= v2 + assert str(v1) == "[1.500000, -0.125000]" + v2 /= v1 + assert str(v2) == "[2.000000, 8.000000]" + + assert hash(v1) == 4 + + cstats = ConstructorStats.get(m.Vector2) + assert cstats.alive() == 2 + del v1 + assert cstats.alive() == 1 + del v2 + assert cstats.alive() == 0 + assert cstats.values() == ['[1.000000, 2.000000]', '[3.000000, -1.000000]', + '[-3.000000, 1.000000]', '[4.000000, 1.000000]', + '[-2.000000, 3.000000]', '[-7.000000, -6.000000]', + '[9.000000, 10.000000]', '[8.000000, 16.000000]', + '[0.125000, 0.250000]', '[7.000000, 6.000000]', + '[9.000000, 10.000000]', '[8.000000, 16.000000]', + '[8.000000, 4.000000]', '[3.000000, -2.000000]', + '[3.000000, -0.500000]', '[6.000000, -2.000000]'] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + assert cstats.move_constructions >= 10 + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + +def test_operators_notimplemented(): + """#393: need to return NotSupported to ensure correct arithmetic operator behavior""" + + c1, c2 = m.C1(), m.C2() + assert c1 + c1 == 11 + assert c2 + c2 == 22 + assert c2 + c1 == 21 + assert c1 + c2 == 12 + + +def test_nested(): + """#328: first member in a class can't be used in operators""" + + a = m.NestA() + b = m.NestB() + c = m.NestC() + + a += 10 + assert m.get_NestA(a) == 13 + b.a += 100 + assert m.get_NestA(b.a) == 103 + c.b.a += 1000 + assert m.get_NestA(c.b.a) == 1003 + b -= 1 + assert m.get_NestB(b) == 3 + c.b -= 3 + assert m.get_NestB(c.b) == 1 + c *= 7 + assert m.get_NestC(c) == 35 + + abase = a.as_base() + assert abase.value == -2 + a.as_base().value += 44 + assert abase.value == 42 + assert c.b.a.as_base().value == -2 + c.b.a.as_base().value += 44 + assert c.b.a.as_base().value == 42 + + del c + pytest.gc_collect() + del a # Shouldn't delete while abase is still alive + pytest.gc_collect() + + assert abase.value == 42 + del abase, b + pytest.gc_collect() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pickling.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pickling.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9dc63bda3b5949032fbcd30e7aa4e7db2072dcff --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pickling.cpp @@ -0,0 +1,130 @@ +/* + tests/test_pickling.cpp -- pickle support + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +TEST_SUBMODULE(pickling, m) { + // test_roundtrip + class Pickleable { + public: + Pickleable(const std::string &value) : m_value(value) { } + const std::string &value() const { return m_value; } + + void setExtra1(int extra1) { m_extra1 = extra1; } + void setExtra2(int extra2) { m_extra2 = extra2; } + int extra1() const { return m_extra1; } + int extra2() const { return m_extra2; } + private: + std::string m_value; + int m_extra1 = 0; + int m_extra2 = 0; + }; + + class PickleableNew : public Pickleable { + public: + using Pickleable::Pickleable; + }; + + py::class_(m, "Pickleable") + .def(py::init()) + .def("value", &Pickleable::value) + .def("extra1", &Pickleable::extra1) + .def("extra2", &Pickleable::extra2) + .def("setExtra1", &Pickleable::setExtra1) + .def("setExtra2", &Pickleable::setExtra2) + // For details on the methods below, refer to + // http://docs.python.org/3/library/pickle.html#pickling-class-instances + .def("__getstate__", [](const Pickleable &p) { + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(p.value(), p.extra1(), p.extra2()); + }) + .def("__setstate__", [](Pickleable &p, py::tuple t) { + if (t.size() != 3) + throw std::runtime_error("Invalid state!"); + /* Invoke the constructor (need to use in-place version) */ + new (&p) Pickleable(t[0].cast()); + + /* Assign any additional state */ + p.setExtra1(t[1].cast()); + p.setExtra2(t[2].cast()); + }); + + py::class_(m, "PickleableNew") + .def(py::init()) + .def(py::pickle( + [](const PickleableNew &p) { + return py::make_tuple(p.value(), p.extra1(), p.extra2()); + }, + [](py::tuple t) { + if (t.size() != 3) + throw std::runtime_error("Invalid state!"); + auto p = PickleableNew(t[0].cast()); + + p.setExtra1(t[1].cast()); + p.setExtra2(t[2].cast()); + return p; + } + )); + +#if !defined(PYPY_VERSION) + // test_roundtrip_with_dict + class PickleableWithDict { + public: + PickleableWithDict(const std::string &value) : value(value) { } + + std::string value; + int extra; + }; + + class PickleableWithDictNew : public PickleableWithDict { + public: + using PickleableWithDict::PickleableWithDict; + }; + + py::class_(m, "PickleableWithDict", py::dynamic_attr()) + .def(py::init()) + .def_readwrite("value", &PickleableWithDict::value) + .def_readwrite("extra", &PickleableWithDict::extra) + .def("__getstate__", [](py::object self) { + /* Also include __dict__ in state */ + return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__")); + }) + .def("__setstate__", [](py::object self, py::tuple t) { + if (t.size() != 3) + throw std::runtime_error("Invalid state!"); + /* Cast and construct */ + auto& p = self.cast(); + new (&p) PickleableWithDict(t[0].cast()); + + /* Assign C++ state */ + p.extra = t[1].cast(); + + /* Assign Python state */ + self.attr("__dict__") = t[2]; + }); + + py::class_(m, "PickleableWithDictNew") + .def(py::init()) + .def(py::pickle( + [](py::object self) { + return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__")); + }, + [](const py::tuple &t) { + if (t.size() != 3) + throw std::runtime_error("Invalid state!"); + + auto cpp_state = PickleableWithDictNew(t[0].cast()); + cpp_state.extra = t[1].cast(); + + auto py_state = t[2].cast(); + return std::make_pair(cpp_state, py_state); + } + )); +#endif +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pickling.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pickling.py new file mode 100644 index 0000000000000000000000000000000000000000..5ae05aaa0caec9fac0d9098729ebf5a1537a7dc6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pickling.py @@ -0,0 +1,42 @@ +import pytest +from pybind11_tests import pickling as m + +try: + import cPickle as pickle # Use cPickle on Python 2.7 +except ImportError: + import pickle + + +@pytest.mark.parametrize("cls_name", ["Pickleable", "PickleableNew"]) +def test_roundtrip(cls_name): + cls = getattr(m, cls_name) + p = cls("test_value") + p.setExtra1(15) + p.setExtra2(48) + + data = pickle.dumps(p, 2) # Must use pickle protocol >= 2 + p2 = pickle.loads(data) + assert p2.value() == p.value() + assert p2.extra1() == p.extra1() + assert p2.extra2() == p.extra2() + + +@pytest.unsupported_on_pypy +@pytest.mark.parametrize("cls_name", ["PickleableWithDict", "PickleableWithDictNew"]) +def test_roundtrip_with_dict(cls_name): + cls = getattr(m, cls_name) + p = cls("test_value") + p.extra = 15 + p.dynamic = "Attribute" + + data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL) + p2 = pickle.loads(data) + assert p2.value == p.value + assert p2.extra == p.extra + assert p2.dynamic == p.dynamic + + +def test_enum_pickle(): + from pybind11_tests import enums as e + data = pickle.dumps(e.EOne, 2) + assert e.EOne == pickle.loads(data) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pytypes.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pytypes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..244e1db0d2bef0f6c9bfef55fd1b594c56142fc1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pytypes.cpp @@ -0,0 +1,310 @@ +/* + tests/test_pytypes.cpp -- Python type casters + + Copyright (c) 2017 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + + +TEST_SUBMODULE(pytypes, m) { + // test_list + m.def("get_list", []() { + py::list list; + list.append("value"); + py::print("Entry at position 0:", list[0]); + list[0] = py::str("overwritten"); + list.insert(0, "inserted-0"); + list.insert(2, "inserted-2"); + return list; + }); + m.def("print_list", [](py::list list) { + int index = 0; + for (auto item : list) + py::print("list item {}: {}"_s.format(index++, item)); + }); + + // test_set + m.def("get_set", []() { + py::set set; + set.add(py::str("key1")); + set.add("key2"); + set.add(std::string("key3")); + return set; + }); + m.def("print_set", [](py::set set) { + for (auto item : set) + py::print("key:", item); + }); + m.def("set_contains", [](py::set set, py::object key) { + return set.contains(key); + }); + m.def("set_contains", [](py::set set, const char* key) { + return set.contains(key); + }); + + // test_dict + m.def("get_dict", []() { return py::dict("key"_a="value"); }); + m.def("print_dict", [](py::dict dict) { + for (auto item : dict) + py::print("key: {}, value={}"_s.format(item.first, item.second)); + }); + m.def("dict_keyword_constructor", []() { + auto d1 = py::dict("x"_a=1, "y"_a=2); + auto d2 = py::dict("z"_a=3, **d1); + return d2; + }); + m.def("dict_contains", [](py::dict dict, py::object val) { + return dict.contains(val); + }); + m.def("dict_contains", [](py::dict dict, const char* val) { + return dict.contains(val); + }); + + // test_str + m.def("str_from_string", []() { return py::str(std::string("baz")); }); + m.def("str_from_bytes", []() { return py::str(py::bytes("boo", 3)); }); + m.def("str_from_object", [](const py::object& obj) { return py::str(obj); }); + m.def("repr_from_object", [](const py::object& obj) { return py::repr(obj); }); + + m.def("str_format", []() { + auto s1 = "{} + {} = {}"_s.format(1, 2, 3); + auto s2 = "{a} + {b} = {c}"_s.format("a"_a=1, "b"_a=2, "c"_a=3); + return py::make_tuple(s1, s2); + }); + + // test_bytes + m.def("bytes_from_string", []() { return py::bytes(std::string("foo")); }); + m.def("bytes_from_str", []() { return py::bytes(py::str("bar", 3)); }); + + // test_capsule + m.def("return_capsule_with_destructor", []() { + py::print("creating capsule"); + return py::capsule([]() { + py::print("destructing capsule"); + }); + }); + + m.def("return_capsule_with_destructor_2", []() { + py::print("creating capsule"); + return py::capsule((void *) 1234, [](void *ptr) { + py::print("destructing capsule: {}"_s.format((size_t) ptr)); + }); + }); + + m.def("return_capsule_with_name_and_destructor", []() { + auto capsule = py::capsule((void *) 1234, "pointer type description", [](PyObject *ptr) { + if (ptr) { + auto name = PyCapsule_GetName(ptr); + py::print("destructing capsule ({}, '{}')"_s.format( + (size_t) PyCapsule_GetPointer(ptr, name), name + )); + } + }); + void *contents = capsule; + py::print("created capsule ({}, '{}')"_s.format((size_t) contents, capsule.name())); + return capsule; + }); + + // test_accessors + m.def("accessor_api", [](py::object o) { + auto d = py::dict(); + + d["basic_attr"] = o.attr("basic_attr"); + + auto l = py::list(); + for (const auto &item : o.attr("begin_end")) { + l.append(item); + } + d["begin_end"] = l; + + d["operator[object]"] = o.attr("d")["operator[object]"_s]; + d["operator[char *]"] = o.attr("d")["operator[char *]"]; + + d["attr(object)"] = o.attr("sub").attr("attr_obj"); + d["attr(char *)"] = o.attr("sub").attr("attr_char"); + try { + o.attr("sub").attr("missing").ptr(); + } catch (const py::error_already_set &) { + d["missing_attr_ptr"] = "raised"_s; + } + try { + o.attr("missing").attr("doesn't matter"); + } catch (const py::error_already_set &) { + d["missing_attr_chain"] = "raised"_s; + } + + d["is_none"] = o.attr("basic_attr").is_none(); + + d["operator()"] = o.attr("func")(1); + d["operator*"] = o.attr("func")(*o.attr("begin_end")); + + // Test implicit conversion + py::list implicit_list = o.attr("begin_end"); + d["implicit_list"] = implicit_list; + py::dict implicit_dict = o.attr("__dict__"); + d["implicit_dict"] = implicit_dict; + + return d; + }); + + m.def("tuple_accessor", [](py::tuple existing_t) { + try { + existing_t[0] = 1; + } catch (const py::error_already_set &) { + // --> Python system error + // Only new tuples (refcount == 1) are mutable + auto new_t = py::tuple(3); + for (size_t i = 0; i < new_t.size(); ++i) { + new_t[i] = i; + } + return new_t; + } + return py::tuple(); + }); + + m.def("accessor_assignment", []() { + auto l = py::list(1); + l[0] = 0; + + auto d = py::dict(); + d["get"] = l[0]; + auto var = l[0]; + d["deferred_get"] = var; + l[0] = 1; + d["set"] = l[0]; + var = 99; // this assignment should not overwrite l[0] + d["deferred_set"] = l[0]; + d["var"] = var; + + return d; + }); + + // test_constructors + m.def("default_constructors", []() { + return py::dict( + "str"_a=py::str(), + "bool"_a=py::bool_(), + "int"_a=py::int_(), + "float"_a=py::float_(), + "tuple"_a=py::tuple(), + "list"_a=py::list(), + "dict"_a=py::dict(), + "set"_a=py::set() + ); + }); + + m.def("converting_constructors", [](py::dict d) { + return py::dict( + "str"_a=py::str(d["str"]), + "bool"_a=py::bool_(d["bool"]), + "int"_a=py::int_(d["int"]), + "float"_a=py::float_(d["float"]), + "tuple"_a=py::tuple(d["tuple"]), + "list"_a=py::list(d["list"]), + "dict"_a=py::dict(d["dict"]), + "set"_a=py::set(d["set"]), + "memoryview"_a=py::memoryview(d["memoryview"]) + ); + }); + + m.def("cast_functions", [](py::dict d) { + // When converting between Python types, obj.cast() should be the same as T(obj) + return py::dict( + "str"_a=d["str"].cast(), + "bool"_a=d["bool"].cast(), + "int"_a=d["int"].cast(), + "float"_a=d["float"].cast(), + "tuple"_a=d["tuple"].cast(), + "list"_a=d["list"].cast(), + "dict"_a=d["dict"].cast(), + "set"_a=d["set"].cast(), + "memoryview"_a=d["memoryview"].cast() + ); + }); + + m.def("get_implicit_casting", []() { + py::dict d; + d["char*_i1"] = "abc"; + const char *c2 = "abc"; + d["char*_i2"] = c2; + d["char*_e"] = py::cast(c2); + d["char*_p"] = py::str(c2); + + d["int_i1"] = 42; + int i = 42; + d["int_i2"] = i; + i++; + d["int_e"] = py::cast(i); + i++; + d["int_p"] = py::int_(i); + + d["str_i1"] = std::string("str"); + std::string s2("str1"); + d["str_i2"] = s2; + s2[3] = '2'; + d["str_e"] = py::cast(s2); + s2[3] = '3'; + d["str_p"] = py::str(s2); + + py::list l(2); + l[0] = 3; + l[1] = py::cast(6); + l.append(9); + l.append(py::cast(12)); + l.append(py::int_(15)); + + return py::dict( + "d"_a=d, + "l"_a=l + ); + }); + + // test_print + m.def("print_function", []() { + py::print("Hello, World!"); + py::print(1, 2.0, "three", true, std::string("-- multiple args")); + auto args = py::make_tuple("and", "a", "custom", "separator"); + py::print("*args", *args, "sep"_a="-"); + py::print("no new line here", "end"_a=" -- "); + py::print("next print"); + + auto py_stderr = py::module::import("sys").attr("stderr"); + py::print("this goes to stderr", "file"_a=py_stderr); + + py::print("flush", "flush"_a=true); + + py::print("{a} + {b} = {c}"_s.format("a"_a="py::print", "b"_a="str.format", "c"_a="this")); + }); + + m.def("print_failure", []() { py::print(42, UnregisteredType()); }); + + m.def("hash_function", [](py::object obj) { return py::hash(obj); }); + + m.def("test_number_protocol", [](py::object a, py::object b) { + py::list l; + l.append(a.equal(b)); + l.append(a.not_equal(b)); + l.append(a < b); + l.append(a <= b); + l.append(a > b); + l.append(a >= b); + l.append(a + b); + l.append(a - b); + l.append(a * b); + l.append(a / b); + l.append(a | b); + l.append(a & b); + l.append(a ^ b); + l.append(a >> b); + l.append(a << b); + return l; + }); + + m.def("test_list_slicing", [](py::list a) { + return a[py::slice(0, -1, 2)]; + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pytypes.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pytypes.py new file mode 100644 index 0000000000000000000000000000000000000000..0e8d6c33a730a89e084f0ef357ea006c9a92d2e5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_pytypes.py @@ -0,0 +1,263 @@ +from __future__ import division +import pytest +import sys + +from pybind11_tests import pytypes as m +from pybind11_tests import debug_enabled + + +def test_list(capture, doc): + with capture: + lst = m.get_list() + assert lst == ["inserted-0", "overwritten", "inserted-2"] + + lst.append("value2") + m.print_list(lst) + assert capture.unordered == """ + Entry at position 0: value + list item 0: inserted-0 + list item 1: overwritten + list item 2: inserted-2 + list item 3: value2 + """ + + assert doc(m.get_list) == "get_list() -> list" + assert doc(m.print_list) == "print_list(arg0: list) -> None" + + +def test_set(capture, doc): + s = m.get_set() + assert s == {"key1", "key2", "key3"} + + with capture: + s.add("key4") + m.print_set(s) + assert capture.unordered == """ + key: key1 + key: key2 + key: key3 + key: key4 + """ + + assert not m.set_contains(set([]), 42) + assert m.set_contains({42}, 42) + assert m.set_contains({"foo"}, "foo") + + assert doc(m.get_list) == "get_list() -> list" + assert doc(m.print_list) == "print_list(arg0: list) -> None" + + +def test_dict(capture, doc): + d = m.get_dict() + assert d == {"key": "value"} + + with capture: + d["key2"] = "value2" + m.print_dict(d) + assert capture.unordered == """ + key: key, value=value + key: key2, value=value2 + """ + + assert not m.dict_contains({}, 42) + assert m.dict_contains({42: None}, 42) + assert m.dict_contains({"foo": None}, "foo") + + assert doc(m.get_dict) == "get_dict() -> dict" + assert doc(m.print_dict) == "print_dict(arg0: dict) -> None" + + assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3} + + +def test_str(doc): + assert m.str_from_string().encode().decode() == "baz" + assert m.str_from_bytes().encode().decode() == "boo" + + assert doc(m.str_from_bytes) == "str_from_bytes() -> str" + + class A(object): + def __str__(self): + return "this is a str" + + def __repr__(self): + return "this is a repr" + + assert m.str_from_object(A()) == "this is a str" + assert m.repr_from_object(A()) == "this is a repr" + + s1, s2 = m.str_format() + assert s1 == "1 + 2 = 3" + assert s1 == s2 + + +def test_bytes(doc): + assert m.bytes_from_string().decode() == "foo" + assert m.bytes_from_str().decode() == "bar" + + assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format( + "bytes" if sys.version_info[0] == 3 else "str" + ) + + +def test_capsule(capture): + pytest.gc_collect() + with capture: + a = m.return_capsule_with_destructor() + del a + pytest.gc_collect() + assert capture.unordered == """ + creating capsule + destructing capsule + """ + + with capture: + a = m.return_capsule_with_destructor_2() + del a + pytest.gc_collect() + assert capture.unordered == """ + creating capsule + destructing capsule: 1234 + """ + + with capture: + a = m.return_capsule_with_name_and_destructor() + del a + pytest.gc_collect() + assert capture.unordered == """ + created capsule (1234, 'pointer type description') + destructing capsule (1234, 'pointer type description') + """ + + +def test_accessors(): + class SubTestObject: + attr_obj = 1 + attr_char = 2 + + class TestObject: + basic_attr = 1 + begin_end = [1, 2, 3] + d = {"operator[object]": 1, "operator[char *]": 2} + sub = SubTestObject() + + def func(self, x, *args): + return self.basic_attr + x + sum(args) + + d = m.accessor_api(TestObject()) + assert d["basic_attr"] == 1 + assert d["begin_end"] == [1, 2, 3] + assert d["operator[object]"] == 1 + assert d["operator[char *]"] == 2 + assert d["attr(object)"] == 1 + assert d["attr(char *)"] == 2 + assert d["missing_attr_ptr"] == "raised" + assert d["missing_attr_chain"] == "raised" + assert d["is_none"] is False + assert d["operator()"] == 2 + assert d["operator*"] == 7 + assert d["implicit_list"] == [1, 2, 3] + assert all(x in TestObject.__dict__ for x in d["implicit_dict"]) + + assert m.tuple_accessor(tuple()) == (0, 1, 2) + + d = m.accessor_assignment() + assert d["get"] == 0 + assert d["deferred_get"] == 0 + assert d["set"] == 1 + assert d["deferred_set"] == 1 + assert d["var"] == 99 + + +def test_constructors(): + """C++ default and converting constructors are equivalent to type calls in Python""" + types = [str, bool, int, float, tuple, list, dict, set] + expected = {t.__name__: t() for t in types} + assert m.default_constructors() == expected + + data = { + str: 42, + bool: "Not empty", + int: "42", + float: "+1e3", + tuple: range(3), + list: range(3), + dict: [("two", 2), ("one", 1), ("three", 3)], + set: [4, 4, 5, 6, 6, 6], + memoryview: b'abc' + } + inputs = {k.__name__: v for k, v in data.items()} + expected = {k.__name__: k(v) for k, v in data.items()} + + assert m.converting_constructors(inputs) == expected + assert m.cast_functions(inputs) == expected + + # Converting constructors and cast functions should just reference rather + # than copy when no conversion is needed: + noconv1 = m.converting_constructors(expected) + for k in noconv1: + assert noconv1[k] is expected[k] + + noconv2 = m.cast_functions(expected) + for k in noconv2: + assert noconv2[k] is expected[k] + + +def test_implicit_casting(): + """Tests implicit casting when assigning or appending to dicts and lists.""" + z = m.get_implicit_casting() + assert z['d'] == { + 'char*_i1': 'abc', 'char*_i2': 'abc', 'char*_e': 'abc', 'char*_p': 'abc', + 'str_i1': 'str', 'str_i2': 'str1', 'str_e': 'str2', 'str_p': 'str3', + 'int_i1': 42, 'int_i2': 42, 'int_e': 43, 'int_p': 44 + } + assert z['l'] == [3, 6, 9, 12, 15] + + +def test_print(capture): + with capture: + m.print_function() + assert capture == """ + Hello, World! + 1 2.0 three True -- multiple args + *args-and-a-custom-separator + no new line here -- next print + flush + py::print + str.format = this + """ + assert capture.stderr == "this goes to stderr" + + with pytest.raises(RuntimeError) as excinfo: + m.print_failure() + assert str(excinfo.value) == "make_tuple(): unable to convert " + ( + "argument of type 'UnregisteredType' to Python object" + if debug_enabled else + "arguments to Python object (compile in debug mode for details)" + ) + + +def test_hash(): + class Hashable(object): + def __init__(self, value): + self.value = value + + def __hash__(self): + return self.value + + class Unhashable(object): + __hash__ = None + + assert m.hash_function(Hashable(42)) == 42 + with pytest.raises(TypeError): + m.hash_function(Unhashable()) + + +def test_number_protocol(): + for a, b in [(1, 1), (3, 5)]: + li = [a == b, a != b, a < b, a <= b, a > b, a >= b, a + b, + a - b, a * b, a / b, a | b, a & b, a ^ b, a >> b, a << b] + assert m.test_number_protocol(a, b) == li + + +def test_list_slicing(): + li = list(range(100)) + assert li[::2] == m.test_list_slicing(li) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_sequences_and_iterators.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_sequences_and_iterators.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87ccf99d628126bc35a0880434d04e3d8b7dc47d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_sequences_and_iterators.cpp @@ -0,0 +1,353 @@ +/* + tests/test_sequences_and_iterators.cpp -- supporting Pythons' sequence protocol, iterators, + etc. + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include +#include + +template +class NonZeroIterator { + const T* ptr_; +public: + NonZeroIterator(const T* ptr) : ptr_(ptr) {} + const T& operator*() const { return *ptr_; } + NonZeroIterator& operator++() { ++ptr_; return *this; } +}; + +class NonZeroSentinel {}; + +template +bool operator==(const NonZeroIterator>& it, const NonZeroSentinel&) { + return !(*it).first || !(*it).second; +} + +template +py::list test_random_access_iterator(PythonType x) { + if (x.size() < 5) + throw py::value_error("Please provide at least 5 elements for testing."); + + auto checks = py::list(); + auto assert_equal = [&checks](py::handle a, py::handle b) { + auto result = PyObject_RichCompareBool(a.ptr(), b.ptr(), Py_EQ); + if (result == -1) { throw py::error_already_set(); } + checks.append(result != 0); + }; + + auto it = x.begin(); + assert_equal(x[0], *it); + assert_equal(x[0], it[0]); + assert_equal(x[1], it[1]); + + assert_equal(x[1], *(++it)); + assert_equal(x[1], *(it++)); + assert_equal(x[2], *it); + assert_equal(x[3], *(it += 1)); + assert_equal(x[2], *(--it)); + assert_equal(x[2], *(it--)); + assert_equal(x[1], *it); + assert_equal(x[0], *(it -= 1)); + + assert_equal(it->attr("real"), x[0].attr("real")); + assert_equal((it + 1)->attr("real"), x[1].attr("real")); + + assert_equal(x[1], *(it + 1)); + assert_equal(x[1], *(1 + it)); + it += 3; + assert_equal(x[1], *(it - 2)); + + checks.append(static_cast(x.end() - x.begin()) == x.size()); + checks.append((x.begin() + static_cast(x.size())) == x.end()); + checks.append(x.begin() < x.end()); + + return checks; +} + +TEST_SUBMODULE(sequences_and_iterators, m) { + // test_sliceable + class Sliceable{ + public: + Sliceable(int n): size(n) {} + int start,stop,step; + int size; + }; + py::class_(m,"Sliceable") + .def(py::init()) + .def("__getitem__",[](const Sliceable &s, py::slice slice) { + ssize_t start, stop, step, slicelength; + if (!slice.compute(s.size, &start, &stop, &step, &slicelength)) + throw py::error_already_set(); + int istart = static_cast(start); + int istop = static_cast(stop); + int istep = static_cast(step); + return std::make_tuple(istart,istop,istep); + }) + ; + + // test_sequence + class Sequence { + public: + Sequence(size_t size) : m_size(size) { + print_created(this, "of size", m_size); + m_data = new float[size]; + memset(m_data, 0, sizeof(float) * size); + } + Sequence(const std::vector &value) : m_size(value.size()) { + print_created(this, "of size", m_size, "from std::vector"); + m_data = new float[m_size]; + memcpy(m_data, &value[0], sizeof(float) * m_size); + } + Sequence(const Sequence &s) : m_size(s.m_size) { + print_copy_created(this); + m_data = new float[m_size]; + memcpy(m_data, s.m_data, sizeof(float)*m_size); + } + Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) { + print_move_created(this); + s.m_size = 0; + s.m_data = nullptr; + } + + ~Sequence() { print_destroyed(this); delete[] m_data; } + + Sequence &operator=(const Sequence &s) { + if (&s != this) { + delete[] m_data; + m_size = s.m_size; + m_data = new float[m_size]; + memcpy(m_data, s.m_data, sizeof(float)*m_size); + } + print_copy_assigned(this); + return *this; + } + + Sequence &operator=(Sequence &&s) { + if (&s != this) { + delete[] m_data; + m_size = s.m_size; + m_data = s.m_data; + s.m_size = 0; + s.m_data = nullptr; + } + print_move_assigned(this); + return *this; + } + + bool operator==(const Sequence &s) const { + if (m_size != s.size()) return false; + for (size_t i = 0; i < m_size; ++i) + if (m_data[i] != s[i]) + return false; + return true; + } + bool operator!=(const Sequence &s) const { return !operator==(s); } + + float operator[](size_t index) const { return m_data[index]; } + float &operator[](size_t index) { return m_data[index]; } + + bool contains(float v) const { + for (size_t i = 0; i < m_size; ++i) + if (v == m_data[i]) + return true; + return false; + } + + Sequence reversed() const { + Sequence result(m_size); + for (size_t i = 0; i < m_size; ++i) + result[m_size - i - 1] = m_data[i]; + return result; + } + + size_t size() const { return m_size; } + + const float *begin() const { return m_data; } + const float *end() const { return m_data+m_size; } + + private: + size_t m_size; + float *m_data; + }; + py::class_(m, "Sequence") + .def(py::init()) + .def(py::init&>()) + /// Bare bones interface + .def("__getitem__", [](const Sequence &s, size_t i) { + if (i >= s.size()) throw py::index_error(); + return s[i]; + }) + .def("__setitem__", [](Sequence &s, size_t i, float v) { + if (i >= s.size()) throw py::index_error(); + s[i] = v; + }) + .def("__len__", &Sequence::size) + /// Optional sequence protocol operations + .def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); }, + py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */) + .def("__contains__", [](const Sequence &s, float v) { return s.contains(v); }) + .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); }) + /// Slicing protocol (optional) + .def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* { + size_t start, stop, step, slicelength; + if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) + throw py::error_already_set(); + Sequence *seq = new Sequence(slicelength); + for (size_t i = 0; i < slicelength; ++i) { + (*seq)[i] = s[start]; start += step; + } + return seq; + }) + .def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) { + size_t start, stop, step, slicelength; + if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) + throw py::error_already_set(); + if (slicelength != value.size()) + throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); + for (size_t i = 0; i < slicelength; ++i) { + s[start] = value[i]; start += step; + } + }) + /// Comparisons + .def(py::self == py::self) + .def(py::self != py::self) + // Could also define py::self + py::self for concatenation, etc. + ; + + // test_map_iterator + // Interface of a map-like object that isn't (directly) an unordered_map, but provides some basic + // map-like functionality. + class StringMap { + public: + StringMap() = default; + StringMap(std::unordered_map init) + : map(std::move(init)) {} + + void set(std::string key, std::string val) { map[key] = val; } + std::string get(std::string key) const { return map.at(key); } + size_t size() const { return map.size(); } + private: + std::unordered_map map; + public: + decltype(map.cbegin()) begin() const { return map.cbegin(); } + decltype(map.cend()) end() const { return map.cend(); } + }; + py::class_(m, "StringMap") + .def(py::init<>()) + .def(py::init>()) + .def("__getitem__", [](const StringMap &map, std::string key) { + try { return map.get(key); } + catch (const std::out_of_range&) { + throw py::key_error("key '" + key + "' does not exist"); + } + }) + .def("__setitem__", &StringMap::set) + .def("__len__", &StringMap::size) + .def("__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); }, + py::keep_alive<0, 1>()) + .def("items", [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); }, + py::keep_alive<0, 1>()) + ; + + // test_generalized_iterators + class IntPairs { + public: + IntPairs(std::vector> data) : data_(std::move(data)) {} + const std::pair* begin() const { return data_.data(); } + private: + std::vector> data_; + }; + py::class_(m, "IntPairs") + .def(py::init>>()) + .def("nonzero", [](const IntPairs& s) { + return py::make_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); + }, py::keep_alive<0, 1>()) + .def("nonzero_keys", [](const IntPairs& s) { + return py::make_key_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); + }, py::keep_alive<0, 1>()) + ; + + +#if 0 + // Obsolete: special data structure for exposing custom iterator types to python + // kept here for illustrative purposes because there might be some use cases which + // are not covered by the much simpler py::make_iterator + + struct PySequenceIterator { + PySequenceIterator(const Sequence &seq, py::object ref) : seq(seq), ref(ref) { } + + float next() { + if (index == seq.size()) + throw py::stop_iteration(); + return seq[index++]; + } + + const Sequence &seq; + py::object ref; // keep a reference + size_t index = 0; + }; + + py::class_(seq, "Iterator") + .def("__iter__", [](PySequenceIterator &it) -> PySequenceIterator& { return it; }) + .def("__next__", &PySequenceIterator::next); + + On the actual Sequence object, the iterator would be constructed as follows: + .def("__iter__", [](py::object s) { return PySequenceIterator(s.cast(), s); }) +#endif + + // test_python_iterator_in_cpp + m.def("object_to_list", [](py::object o) { + auto l = py::list(); + for (auto item : o) { + l.append(item); + } + return l; + }); + + m.def("iterator_to_list", [](py::iterator it) { + auto l = py::list(); + while (it != py::iterator::sentinel()) { + l.append(*it); + ++it; + } + return l; + }); + + // Make sure that py::iterator works with std algorithms + m.def("count_none", [](py::object o) { + return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); + }); + + m.def("find_none", [](py::object o) { + auto it = std::find_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); + return it->is_none(); + }); + + m.def("count_nonzeros", [](py::dict d) { + return std::count_if(d.begin(), d.end(), [](std::pair p) { + return p.second.cast() != 0; + }); + }); + + m.def("tuple_iterator", &test_random_access_iterator); + m.def("list_iterator", &test_random_access_iterator); + m.def("sequence_iterator", &test_random_access_iterator); + + // test_iterator_passthrough + // #181: iterator passthrough did not compile + m.def("iterator_passthrough", [](py::iterator s) -> py::iterator { + return py::make_iterator(std::begin(s), std::end(s)); + }); + + // test_iterator_rvp + // #388: Can't make iterators via make_iterator() with different r/v policies + static std::vector list = { 1, 2, 3 }; + m.def("make_iterator_1", []() { return py::make_iterator(list); }); + m.def("make_iterator_2", []() { return py::make_iterator(list); }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_sequences_and_iterators.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_sequences_and_iterators.py new file mode 100644 index 0000000000000000000000000000000000000000..6bd16064059aaf259f7ba4beada81744a1b4f682 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_sequences_and_iterators.py @@ -0,0 +1,171 @@ +import pytest +from pybind11_tests import sequences_and_iterators as m +from pybind11_tests import ConstructorStats + + +def isclose(a, b, rel_tol=1e-05, abs_tol=0.0): + """Like math.isclose() from Python 3.5""" + return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) + + +def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0): + return all(isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list)) + + +def test_generalized_iterators(): + assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero()) == [(1, 2), (3, 4)] + assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero()) == [(1, 2)] + assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero()) == [] + + assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_keys()) == [1, 3] + assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_keys()) == [1] + assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_keys()) == [] + + # __next__ must continue to raise StopIteration + it = m.IntPairs([(0, 0)]).nonzero() + for _ in range(3): + with pytest.raises(StopIteration): + next(it) + + it = m.IntPairs([(0, 0)]).nonzero_keys() + for _ in range(3): + with pytest.raises(StopIteration): + next(it) + + +def test_sliceable(): + sliceable = m.Sliceable(100) + assert sliceable[::] == (0, 100, 1) + assert sliceable[10::] == (10, 100, 1) + assert sliceable[:10:] == (0, 10, 1) + assert sliceable[::10] == (0, 100, 10) + assert sliceable[-10::] == (90, 100, 1) + assert sliceable[:-10:] == (0, 90, 1) + assert sliceable[::-10] == (99, -1, -10) + assert sliceable[50:60:1] == (50, 60, 1) + assert sliceable[50:60:-1] == (50, 60, -1) + + +def test_sequence(): + cstats = ConstructorStats.get(m.Sequence) + + s = m.Sequence(5) + assert cstats.values() == ['of size', '5'] + + assert "Sequence" in repr(s) + assert len(s) == 5 + assert s[0] == 0 and s[3] == 0 + assert 12.34 not in s + s[0], s[3] = 12.34, 56.78 + assert 12.34 in s + assert isclose(s[0], 12.34) and isclose(s[3], 56.78) + + rev = reversed(s) + assert cstats.values() == ['of size', '5'] + + rev2 = s[::-1] + assert cstats.values() == ['of size', '5'] + + it = iter(m.Sequence(0)) + for _ in range(3): # __next__ must continue to raise StopIteration + with pytest.raises(StopIteration): + next(it) + assert cstats.values() == ['of size', '0'] + + expected = [0, 56.78, 0, 0, 12.34] + assert allclose(rev, expected) + assert allclose(rev2, expected) + assert rev == rev2 + + rev[0::2] = m.Sequence([2.0, 2.0, 2.0]) + assert cstats.values() == ['of size', '3', 'from std::vector'] + + assert allclose(rev, [2, 56.78, 2, 0, 2]) + + assert cstats.alive() == 4 + del it + assert cstats.alive() == 3 + del s + assert cstats.alive() == 2 + del rev + assert cstats.alive() == 1 + del rev2 + assert cstats.alive() == 0 + + assert cstats.values() == [] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + assert cstats.move_constructions >= 1 + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + +def test_map_iterator(): + sm = m.StringMap({'hi': 'bye', 'black': 'white'}) + assert sm['hi'] == 'bye' + assert len(sm) == 2 + assert sm['black'] == 'white' + + with pytest.raises(KeyError): + assert sm['orange'] + sm['orange'] = 'banana' + assert sm['orange'] == 'banana' + + expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'} + for k in sm: + assert sm[k] == expected[k] + for k, v in sm.items(): + assert v == expected[k] + + it = iter(m.StringMap({})) + for _ in range(3): # __next__ must continue to raise StopIteration + with pytest.raises(StopIteration): + next(it) + + +def test_python_iterator_in_cpp(): + t = (1, 2, 3) + assert m.object_to_list(t) == [1, 2, 3] + assert m.object_to_list(iter(t)) == [1, 2, 3] + assert m.iterator_to_list(iter(t)) == [1, 2, 3] + + with pytest.raises(TypeError) as excinfo: + m.object_to_list(1) + assert "object is not iterable" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + m.iterator_to_list(1) + assert "incompatible function arguments" in str(excinfo.value) + + def bad_next_call(): + raise RuntimeError("py::iterator::advance() should propagate errors") + + with pytest.raises(RuntimeError) as excinfo: + m.iterator_to_list(iter(bad_next_call, None)) + assert str(excinfo.value) == "py::iterator::advance() should propagate errors" + + lst = [1, None, 0, None] + assert m.count_none(lst) == 2 + assert m.find_none(lst) is True + assert m.count_nonzeros({"a": 0, "b": 1, "c": 2}) == 2 + + r = range(5) + assert all(m.tuple_iterator(tuple(r))) + assert all(m.list_iterator(list(r))) + assert all(m.sequence_iterator(r)) + + +def test_iterator_passthrough(): + """#181: iterator passthrough did not compile""" + from pybind11_tests.sequences_and_iterators import iterator_passthrough + + assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15] + + +def test_iterator_rvp(): + """#388: Can't make iterators via make_iterator() with different r/v policies """ + import pybind11_tests.sequences_and_iterators as m + + assert list(m.make_iterator_1()) == [1, 2, 3] + assert list(m.make_iterator_2()) == [1, 2, 3] + assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2())) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_smart_ptr.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_smart_ptr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87c9be8c2bf4747c22edc1a3cd7f524ea908ee0b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_smart_ptr.cpp @@ -0,0 +1,366 @@ +/* + tests/test_smart_ptr.cpp -- binding classes with custom reference counting, + implicit conversions between types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#if defined(_MSC_VER) && _MSC_VER < 1910 +# pragma warning(disable: 4702) // unreachable code in system header +#endif + +#include "pybind11_tests.h" +#include "object.h" + +// Make pybind aware of the ref-counted wrapper type (s): + +// ref is a wrapper for 'Object' which uses intrusive reference counting +// It is always possible to construct a ref from an Object* pointer without +// possible inconsistencies, hence the 'true' argument at the end. +PYBIND11_DECLARE_HOLDER_TYPE(T, ref, true); +// Make pybind11 aware of the non-standard getter member function +namespace pybind11 { namespace detail { + template + struct holder_helper> { + static const T *get(const ref &p) { return p.get_ptr(); } + }; +}} + +// The following is not required anymore for std::shared_ptr, but it should compile without error: +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); + +// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the +// holder size to trigger the non-simple-layout internal instance layout for single inheritance with +// large holder type: +template class huge_unique_ptr { + std::unique_ptr ptr; + uint64_t padding[10]; +public: + huge_unique_ptr(T *p) : ptr(p) {}; + T *get() { return ptr.get(); } +}; +PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr); + +// Simple custom holder that works like unique_ptr +template +class custom_unique_ptr { + std::unique_ptr impl; +public: + custom_unique_ptr(T* p) : impl(p) { } + T* get() const { return impl.get(); } + T* release_ptr() { return impl.release(); } +}; +PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr); + +// Simple custom holder that works like shared_ptr and has operator& overload +// To obtain address of an instance of this holder pybind should use std::addressof +// Attempt to get address via operator& may leads to segmentation fault +template +class shared_ptr_with_addressof_operator { + std::shared_ptr impl; +public: + shared_ptr_with_addressof_operator( ) = default; + shared_ptr_with_addressof_operator(T* p) : impl(p) { } + T* get() const { return impl.get(); } + T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); } +}; +PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator); + +// Simple custom holder that works like unique_ptr and has operator& overload +// To obtain address of an instance of this holder pybind should use std::addressof +// Attempt to get address via operator& may leads to segmentation fault +template +class unique_ptr_with_addressof_operator { + std::unique_ptr impl; +public: + unique_ptr_with_addressof_operator() = default; + unique_ptr_with_addressof_operator(T* p) : impl(p) { } + T* get() const { return impl.get(); } + T* release_ptr() { return impl.release(); } + T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); } +}; +PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator); + + +TEST_SUBMODULE(smart_ptr, m) { + + // test_smart_ptr + + // Object implementation in `object.h` + py::class_> obj(m, "Object"); + obj.def("getRefCount", &Object::getRefCount); + + // Custom object with builtin reference counting (see 'object.h' for the implementation) + class MyObject1 : public Object { + public: + MyObject1(int value) : value(value) { print_created(this, toString()); } + std::string toString() const { return "MyObject1[" + std::to_string(value) + "]"; } + protected: + virtual ~MyObject1() { print_destroyed(this); } + private: + int value; + }; + py::class_>(m, "MyObject1", obj) + .def(py::init()); + py::implicitly_convertible(); + + m.def("make_object_1", []() -> Object * { return new MyObject1(1); }); + m.def("make_object_2", []() -> ref { return new MyObject1(2); }); + m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); }); + m.def("make_myobject1_2", []() -> ref { return new MyObject1(5); }); + m.def("print_object_1", [](const Object *obj) { py::print(obj->toString()); }); + m.def("print_object_2", [](ref obj) { py::print(obj->toString()); }); + m.def("print_object_3", [](const ref &obj) { py::print(obj->toString()); }); + m.def("print_object_4", [](const ref *obj) { py::print((*obj)->toString()); }); + m.def("print_myobject1_1", [](const MyObject1 *obj) { py::print(obj->toString()); }); + m.def("print_myobject1_2", [](ref obj) { py::print(obj->toString()); }); + m.def("print_myobject1_3", [](const ref &obj) { py::print(obj->toString()); }); + m.def("print_myobject1_4", [](const ref *obj) { py::print((*obj)->toString()); }); + + // Expose constructor stats for the ref type + m.def("cstats_ref", &ConstructorStats::get); + + + // Object managed by a std::shared_ptr<> + class MyObject2 { + public: + MyObject2(const MyObject2 &) = default; + MyObject2(int value) : value(value) { print_created(this, toString()); } + std::string toString() const { return "MyObject2[" + std::to_string(value) + "]"; } + virtual ~MyObject2() { print_destroyed(this); } + private: + int value; + }; + py::class_>(m, "MyObject2") + .def(py::init()); + m.def("make_myobject2_1", []() { return new MyObject2(6); }); + m.def("make_myobject2_2", []() { return std::make_shared(7); }); + m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); }); + m.def("print_myobject2_2", [](std::shared_ptr obj) { py::print(obj->toString()); }); + m.def("print_myobject2_3", [](const std::shared_ptr &obj) { py::print(obj->toString()); }); + m.def("print_myobject2_4", [](const std::shared_ptr *obj) { py::print((*obj)->toString()); }); + + // Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<> + class MyObject3 : public std::enable_shared_from_this { + public: + MyObject3(const MyObject3 &) = default; + MyObject3(int value) : value(value) { print_created(this, toString()); } + std::string toString() const { return "MyObject3[" + std::to_string(value) + "]"; } + virtual ~MyObject3() { print_destroyed(this); } + private: + int value; + }; + py::class_>(m, "MyObject3") + .def(py::init()); + m.def("make_myobject3_1", []() { return new MyObject3(8); }); + m.def("make_myobject3_2", []() { return std::make_shared(9); }); + m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); }); + m.def("print_myobject3_2", [](std::shared_ptr obj) { py::print(obj->toString()); }); + m.def("print_myobject3_3", [](const std::shared_ptr &obj) { py::print(obj->toString()); }); + m.def("print_myobject3_4", [](const std::shared_ptr *obj) { py::print((*obj)->toString()); }); + + // test_smart_ptr_refcounting + m.def("test_object1_refcounting", []() { + ref o = new MyObject1(0); + bool good = o->getRefCount() == 1; + py::object o2 = py::cast(o, py::return_value_policy::reference); + // always request (partial) ownership for objects with intrusive + // reference counting even when using the 'reference' RVP + good &= o->getRefCount() == 2; + return good; + }); + + // test_unique_nodelete + // Object with a private destructor + class MyObject4 { + public: + MyObject4(int value) : value{value} { print_created(this); } + int value; + private: + ~MyObject4() { print_destroyed(this); } + }; + py::class_>(m, "MyObject4") + .def(py::init()) + .def_readwrite("value", &MyObject4::value); + + // test_unique_deleter + // Object with std::unique_ptr where D is not matching the base class + // Object with a protected destructor + class MyObject4a { + public: + MyObject4a(int i) { + value = i; + print_created(this); + }; + int value; + protected: + virtual ~MyObject4a() { print_destroyed(this); } + }; + py::class_>(m, "MyObject4a") + .def(py::init()) + .def_readwrite("value", &MyObject4a::value); + + // Object derived but with public destructor and no Deleter in default holder + class MyObject4b : public MyObject4a { + public: + MyObject4b(int i) : MyObject4a(i) { print_created(this); } + ~MyObject4b() { print_destroyed(this); } + }; + py::class_(m, "MyObject4b") + .def(py::init()); + + // test_large_holder + class MyObject5 { // managed by huge_unique_ptr + public: + MyObject5(int value) : value{value} { print_created(this); } + ~MyObject5() { print_destroyed(this); } + int value; + }; + py::class_>(m, "MyObject5") + .def(py::init()) + .def_readwrite("value", &MyObject5::value); + + // test_shared_ptr_and_references + struct SharedPtrRef { + struct A { + A() { print_created(this); } + A(const A &) { print_copy_created(this); } + A(A &&) { print_move_created(this); } + ~A() { print_destroyed(this); } + }; + + A value = {}; + std::shared_ptr shared = std::make_shared(); + }; + using A = SharedPtrRef::A; + py::class_>(m, "A"); + py::class_(m, "SharedPtrRef") + .def(py::init<>()) + .def_readonly("ref", &SharedPtrRef::value) + .def_property_readonly("copy", [](const SharedPtrRef &s) { return s.value; }, + py::return_value_policy::copy) + .def_readonly("holder_ref", &SharedPtrRef::shared) + .def_property_readonly("holder_copy", [](const SharedPtrRef &s) { return s.shared; }, + py::return_value_policy::copy) + .def("set_ref", [](SharedPtrRef &, const A &) { return true; }) + .def("set_holder", [](SharedPtrRef &, std::shared_ptr) { return true; }); + + // test_shared_ptr_from_this_and_references + struct SharedFromThisRef { + struct B : std::enable_shared_from_this { + B() { print_created(this); } + B(const B &) : std::enable_shared_from_this() { print_copy_created(this); } + B(B &&) : std::enable_shared_from_this() { print_move_created(this); } + ~B() { print_destroyed(this); } + }; + + B value = {}; + std::shared_ptr shared = std::make_shared(); + }; + using B = SharedFromThisRef::B; + py::class_>(m, "B"); + py::class_(m, "SharedFromThisRef") + .def(py::init<>()) + .def_readonly("bad_wp", &SharedFromThisRef::value) + .def_property_readonly("ref", [](const SharedFromThisRef &s) -> const B & { return *s.shared; }) + .def_property_readonly("copy", [](const SharedFromThisRef &s) { return s.value; }, + py::return_value_policy::copy) + .def_readonly("holder_ref", &SharedFromThisRef::shared) + .def_property_readonly("holder_copy", [](const SharedFromThisRef &s) { return s.shared; }, + py::return_value_policy::copy) + .def("set_ref", [](SharedFromThisRef &, const B &) { return true; }) + .def("set_holder", [](SharedFromThisRef &, std::shared_ptr) { return true; }); + + // Issue #865: shared_from_this doesn't work with virtual inheritance + struct SharedFromThisVBase : std::enable_shared_from_this { + SharedFromThisVBase() = default; + SharedFromThisVBase(const SharedFromThisVBase &) = default; + virtual ~SharedFromThisVBase() = default; + }; + struct SharedFromThisVirt : virtual SharedFromThisVBase {}; + static std::shared_ptr sft(new SharedFromThisVirt()); + py::class_>(m, "SharedFromThisVirt") + .def_static("get", []() { return sft.get(); }); + + // test_move_only_holder + struct C { + C() { print_created(this); } + ~C() { print_destroyed(this); } + }; + py::class_>(m, "TypeWithMoveOnlyHolder") + .def_static("make", []() { return custom_unique_ptr(new C); }); + + // test_holder_with_addressof_operator + struct TypeForHolderWithAddressOf { + TypeForHolderWithAddressOf() { print_created(this); } + TypeForHolderWithAddressOf(const TypeForHolderWithAddressOf &) { print_copy_created(this); } + TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) { print_move_created(this); } + ~TypeForHolderWithAddressOf() { print_destroyed(this); } + std::string toString() const { + return "TypeForHolderWithAddressOf[" + std::to_string(value) + "]"; + } + int value = 42; + }; + using HolderWithAddressOf = shared_ptr_with_addressof_operator; + py::class_(m, "TypeForHolderWithAddressOf") + .def_static("make", []() { return HolderWithAddressOf(new TypeForHolderWithAddressOf); }) + .def("get", [](const HolderWithAddressOf &self) { return self.get(); }) + .def("print_object_1", [](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); }) + .def("print_object_2", [](HolderWithAddressOf obj) { py::print(obj.get()->toString()); }) + .def("print_object_3", [](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); }) + .def("print_object_4", [](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); }); + + // test_move_only_holder_with_addressof_operator + struct TypeForMoveOnlyHolderWithAddressOf { + TypeForMoveOnlyHolderWithAddressOf(int value) : value{value} { print_created(this); } + ~TypeForMoveOnlyHolderWithAddressOf() { print_destroyed(this); } + std::string toString() const { + return "MoveOnlyHolderWithAddressOf[" + std::to_string(value) + "]"; + } + int value; + }; + using MoveOnlyHolderWithAddressOf = unique_ptr_with_addressof_operator; + py::class_(m, "TypeForMoveOnlyHolderWithAddressOf") + .def_static("make", []() { return MoveOnlyHolderWithAddressOf(new TypeForMoveOnlyHolderWithAddressOf(0)); }) + .def_readwrite("value", &TypeForMoveOnlyHolderWithAddressOf::value) + .def("print_object", [](const TypeForMoveOnlyHolderWithAddressOf *obj) { py::print(obj->toString()); }); + + // test_smart_ptr_from_default + struct HeldByDefaultHolder { }; + py::class_(m, "HeldByDefaultHolder") + .def(py::init<>()) + .def_static("load_shared_ptr", [](std::shared_ptr) {}); + + // test_shared_ptr_gc + // #187: issue involving std::shared_ptr<> return value policy & garbage collection + struct ElementBase { + virtual ~ElementBase() { } /* Force creation of virtual table */ + }; + py::class_>(m, "ElementBase"); + + struct ElementA : ElementBase { + ElementA(int v) : v(v) { } + int value() { return v; } + int v; + }; + py::class_>(m, "ElementA") + .def(py::init()) + .def("value", &ElementA::value); + + struct ElementList { + void add(std::shared_ptr e) { l.push_back(e); } + std::vector> l; + }; + py::class_>(m, "ElementList") + .def(py::init<>()) + .def("add", &ElementList::add) + .def("get", [](ElementList &el) { + py::list list; + for (auto &e : el.l) + list.append(py::cast(e)); + return list; + }); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_smart_ptr.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_smart_ptr.py new file mode 100644 index 0000000000000000000000000000000000000000..c6627043bd32858f165b287cdb7f51da6fa95c6e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_smart_ptr.py @@ -0,0 +1,286 @@ +import pytest +from pybind11_tests import smart_ptr as m +from pybind11_tests import ConstructorStats + + +def test_smart_ptr(capture): + # Object1 + for i, o in enumerate([m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1): + assert o.getRefCount() == 1 + with capture: + m.print_object_1(o) + m.print_object_2(o) + m.print_object_3(o) + m.print_object_4(o) + assert capture == "MyObject1[{i}]\n".format(i=i) * 4 + + for i, o in enumerate([m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], + start=4): + print(o) + with capture: + if not isinstance(o, int): + m.print_object_1(o) + m.print_object_2(o) + m.print_object_3(o) + m.print_object_4(o) + m.print_myobject1_1(o) + m.print_myobject1_2(o) + m.print_myobject1_3(o) + m.print_myobject1_4(o) + assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8) + + cstats = ConstructorStats.get(m.MyObject1) + assert cstats.alive() == 0 + expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4 + assert cstats.values() == expected_values + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + # Object2 + for i, o in zip([8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]): + print(o) + with capture: + m.print_myobject2_1(o) + m.print_myobject2_2(o) + m.print_myobject2_3(o) + m.print_myobject2_4(o) + assert capture == "MyObject2[{i}]\n".format(i=i) * 4 + + cstats = ConstructorStats.get(m.MyObject2) + assert cstats.alive() == 1 + o = None + assert cstats.alive() == 0 + assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]'] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + # Object3 + for i, o in zip([9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]): + print(o) + with capture: + m.print_myobject3_1(o) + m.print_myobject3_2(o) + m.print_myobject3_3(o) + m.print_myobject3_4(o) + assert capture == "MyObject3[{i}]\n".format(i=i) * 4 + + cstats = ConstructorStats.get(m.MyObject3) + assert cstats.alive() == 1 + o = None + assert cstats.alive() == 0 + assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]'] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + # Object + cstats = ConstructorStats.get(m.Object) + assert cstats.alive() == 0 + assert cstats.values() == [] + assert cstats.default_constructions == 10 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + # ref<> + cstats = m.cstats_ref() + assert cstats.alive() == 0 + assert cstats.values() == ['from pointer'] * 10 + assert cstats.default_constructions == 30 + assert cstats.copy_constructions == 12 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 30 + assert cstats.move_assignments == 0 + + +def test_smart_ptr_refcounting(): + assert m.test_object1_refcounting() + + +def test_unique_nodelete(): + o = m.MyObject4(23) + assert o.value == 23 + cstats = ConstructorStats.get(m.MyObject4) + assert cstats.alive() == 1 + del o + assert cstats.alive() == 1 # Leak, but that's intentional + + +def test_unique_nodelete4a(): + o = m.MyObject4a(23) + assert o.value == 23 + cstats = ConstructorStats.get(m.MyObject4a) + assert cstats.alive() == 1 + del o + assert cstats.alive() == 1 # Leak, but that's intentional + + +def test_unique_deleter(): + o = m.MyObject4b(23) + assert o.value == 23 + cstats4a = ConstructorStats.get(m.MyObject4a) + assert cstats4a.alive() == 2 # Two because of previous test + cstats4b = ConstructorStats.get(m.MyObject4b) + assert cstats4b.alive() == 1 + del o + assert cstats4a.alive() == 1 # Should now only be one leftover from previous test + assert cstats4b.alive() == 0 # Should be deleted + + +def test_large_holder(): + o = m.MyObject5(5) + assert o.value == 5 + cstats = ConstructorStats.get(m.MyObject5) + assert cstats.alive() == 1 + del o + assert cstats.alive() == 0 + + +def test_shared_ptr_and_references(): + s = m.SharedPtrRef() + stats = ConstructorStats.get(m.A) + assert stats.alive() == 2 + + ref = s.ref # init_holder_helper(holder_ptr=false, owned=false) + assert stats.alive() == 2 + assert s.set_ref(ref) + with pytest.raises(RuntimeError) as excinfo: + assert s.set_holder(ref) + assert "Unable to cast from non-held to held instance" in str(excinfo.value) + + copy = s.copy # init_holder_helper(holder_ptr=false, owned=true) + assert stats.alive() == 3 + assert s.set_ref(copy) + assert s.set_holder(copy) + + holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false) + assert stats.alive() == 3 + assert s.set_ref(holder_ref) + assert s.set_holder(holder_ref) + + holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true) + assert stats.alive() == 3 + assert s.set_ref(holder_copy) + assert s.set_holder(holder_copy) + + del ref, copy, holder_ref, holder_copy, s + assert stats.alive() == 0 + + +def test_shared_ptr_from_this_and_references(): + s = m.SharedFromThisRef() + stats = ConstructorStats.get(m.B) + assert stats.alive() == 2 + + ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false) + assert stats.alive() == 2 + assert s.set_ref(ref) + assert s.set_holder(ref) # std::enable_shared_from_this can create a holder from a reference + + bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true) + assert stats.alive() == 2 + assert s.set_ref(bad_wp) + with pytest.raises(RuntimeError) as excinfo: + assert s.set_holder(bad_wp) + assert "Unable to cast from non-held to held instance" in str(excinfo.value) + + copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false) + assert stats.alive() == 3 + assert s.set_ref(copy) + assert s.set_holder(copy) + + holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false) + assert stats.alive() == 3 + assert s.set_ref(holder_ref) + assert s.set_holder(holder_ref) + + holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false) + assert stats.alive() == 3 + assert s.set_ref(holder_copy) + assert s.set_holder(holder_copy) + + del ref, bad_wp, copy, holder_ref, holder_copy, s + assert stats.alive() == 0 + + z = m.SharedFromThisVirt.get() + y = m.SharedFromThisVirt.get() + assert y is z + + +def test_move_only_holder(): + a = m.TypeWithMoveOnlyHolder.make() + stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder) + assert stats.alive() == 1 + del a + assert stats.alive() == 0 + + +def test_holder_with_addressof_operator(): + # this test must not throw exception from c++ + a = m.TypeForHolderWithAddressOf.make() + a.print_object_1() + a.print_object_2() + a.print_object_3() + a.print_object_4() + + stats = ConstructorStats.get(m.TypeForHolderWithAddressOf) + assert stats.alive() == 1 + + np = m.TypeForHolderWithAddressOf.make() + assert stats.alive() == 2 + del a + assert stats.alive() == 1 + del np + assert stats.alive() == 0 + + b = m.TypeForHolderWithAddressOf.make() + c = b + assert b.get() is c.get() + assert stats.alive() == 1 + + del b + assert stats.alive() == 1 + + del c + assert stats.alive() == 0 + + +def test_move_only_holder_with_addressof_operator(): + a = m.TypeForMoveOnlyHolderWithAddressOf.make() + a.print_object() + + stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf) + assert stats.alive() == 1 + + a.value = 42 + assert a.value == 42 + + del a + assert stats.alive() == 0 + + +def test_smart_ptr_from_default(): + instance = m.HeldByDefaultHolder() + with pytest.raises(RuntimeError) as excinfo: + m.HeldByDefaultHolder.load_shared_ptr(instance) + assert "Unable to load a custom holder type from a " \ + "default-holder instance" in str(excinfo.value) + + +def test_shared_ptr_gc(): + """#187: issue involving std::shared_ptr<> return value policy & garbage collection""" + el = m.ElementList() + for i in range(10): + el.add(m.ElementA(i)) + pytest.gc_collect() + for i, v in enumerate(el.get()): + assert i == v.value() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..207c9fb2bf8749e902ed8a30836ff0b73d826f42 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl.cpp @@ -0,0 +1,284 @@ +/* + tests/test_stl.cpp -- STL type casters + + Copyright (c) 2017 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include + +#include +#include + +// Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14 +#if PYBIND11_HAS_VARIANT +using std::variant; +#elif defined(PYBIND11_TEST_BOOST) && (!defined(_MSC_VER) || _MSC_VER >= 1910) +# include +# define PYBIND11_HAS_VARIANT 1 +using boost::variant; + +namespace pybind11 { namespace detail { +template +struct type_caster> : variant_caster> {}; + +template <> +struct visit_helper { + template + static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) { + return boost::apply_visitor(args...); + } +}; +}} // namespace pybind11::detail +#endif + +PYBIND11_MAKE_OPAQUE(std::vector>); + +/// Issue #528: templated constructor +struct TplCtorClass { + template TplCtorClass(const T &) { } + bool operator==(const TplCtorClass &) const { return true; } +}; + +namespace std { + template <> + struct hash { size_t operator()(const TplCtorClass &) const { return 0; } }; +} + + +TEST_SUBMODULE(stl, m) { + // test_vector + m.def("cast_vector", []() { return std::vector{1}; }); + m.def("load_vector", [](const std::vector &v) { return v.at(0) == 1 && v.at(1) == 2; }); + // `std::vector` is special because it returns proxy objects instead of references + m.def("cast_bool_vector", []() { return std::vector{true, false}; }); + m.def("load_bool_vector", [](const std::vector &v) { + return v.at(0) == true && v.at(1) == false; + }); + // Unnumbered regression (caused by #936): pointers to stl containers aren't castable + static std::vector lvv{2}; + m.def("cast_ptr_vector", []() { return &lvv; }); + + // test_deque + m.def("cast_deque", []() { return std::deque{1}; }); + m.def("load_deque", [](const std::deque &v) { return v.at(0) == 1 && v.at(1) == 2; }); + + // test_array + m.def("cast_array", []() { return std::array {{1 , 2}}; }); + m.def("load_array", [](const std::array &a) { return a[0] == 1 && a[1] == 2; }); + + // test_valarray + m.def("cast_valarray", []() { return std::valarray{1, 4, 9}; }); + m.def("load_valarray", [](const std::valarray& v) { + return v.size() == 3 && v[0] == 1 && v[1] == 4 && v[2] == 9; + }); + + // test_map + m.def("cast_map", []() { return std::map{{"key", "value"}}; }); + m.def("load_map", [](const std::map &map) { + return map.at("key") == "value" && map.at("key2") == "value2"; + }); + + // test_set + m.def("cast_set", []() { return std::set{"key1", "key2"}; }); + m.def("load_set", [](const std::set &set) { + return set.count("key1") && set.count("key2") && set.count("key3"); + }); + + // test_recursive_casting + m.def("cast_rv_vector", []() { return std::vector{2}; }); + m.def("cast_rv_array", []() { return std::array(); }); + // NB: map and set keys are `const`, so while we technically do move them (as `const Type &&`), + // casters don't typically do anything with that, which means they fall to the `const Type &` + // caster. + m.def("cast_rv_map", []() { return std::unordered_map{{"a", RValueCaster{}}}; }); + m.def("cast_rv_nested", []() { + std::vector>, 2>> v; + v.emplace_back(); // add an array + v.back()[0].emplace_back(); // add a map to the array + v.back()[0].back().emplace("b", RValueCaster{}); + v.back()[0].back().emplace("c", RValueCaster{}); + v.back()[1].emplace_back(); // add a map to the array + v.back()[1].back().emplace("a", RValueCaster{}); + return v; + }); + static std::array lva; + static std::unordered_map lvm{{"a", RValueCaster{}}, {"b", RValueCaster{}}}; + static std::unordered_map>>> lvn; + lvn["a"].emplace_back(); // add a list + lvn["a"].back().emplace_back(); // add an array + lvn["a"].emplace_back(); // another list + lvn["a"].back().emplace_back(); // add an array + lvn["b"].emplace_back(); // add a list + lvn["b"].back().emplace_back(); // add an array + lvn["b"].back().emplace_back(); // add another array + m.def("cast_lv_vector", []() -> const decltype(lvv) & { return lvv; }); + m.def("cast_lv_array", []() -> const decltype(lva) & { return lva; }); + m.def("cast_lv_map", []() -> const decltype(lvm) & { return lvm; }); + m.def("cast_lv_nested", []() -> const decltype(lvn) & { return lvn; }); + // #853: + m.def("cast_unique_ptr_vector", []() { + std::vector> v; + v.emplace_back(new UserType{7}); + v.emplace_back(new UserType{42}); + return v; + }); + + // test_move_out_container + struct MoveOutContainer { + struct Value { int value; }; + std::list move_list() const { return {{0}, {1}, {2}}; } + }; + py::class_(m, "MoveOutContainerValue") + .def_readonly("value", &MoveOutContainer::Value::value); + py::class_(m, "MoveOutContainer") + .def(py::init<>()) + .def_property_readonly("move_list", &MoveOutContainer::move_list); + + // Class that can be move- and copy-constructed, but not assigned + struct NoAssign { + int value; + + explicit NoAssign(int value = 0) : value(value) { } + NoAssign(const NoAssign &) = default; + NoAssign(NoAssign &&) = default; + + NoAssign &operator=(const NoAssign &) = delete; + NoAssign &operator=(NoAssign &&) = delete; + }; + py::class_(m, "NoAssign", "Class with no C++ assignment operators") + .def(py::init<>()) + .def(py::init()); + +#ifdef PYBIND11_HAS_OPTIONAL + // test_optional + m.attr("has_optional") = true; + + using opt_int = std::optional; + using opt_no_assign = std::optional; + m.def("double_or_zero", [](const opt_int& x) -> int { + return x.value_or(0) * 2; + }); + m.def("half_or_none", [](int x) -> opt_int { + return x ? opt_int(x / 2) : opt_int(); + }); + m.def("test_nullopt", [](opt_int x) { + return x.value_or(42); + }, py::arg_v("x", std::nullopt, "None")); + m.def("test_no_assign", [](const opt_no_assign &x) { + return x ? x->value : 42; + }, py::arg_v("x", std::nullopt, "None")); + + m.def("nodefer_none_optional", [](std::optional) { return true; }); + m.def("nodefer_none_optional", [](py::none) { return false; }); +#endif + +#ifdef PYBIND11_HAS_EXP_OPTIONAL + // test_exp_optional + m.attr("has_exp_optional") = true; + + using exp_opt_int = std::experimental::optional; + using exp_opt_no_assign = std::experimental::optional; + m.def("double_or_zero_exp", [](const exp_opt_int& x) -> int { + return x.value_or(0) * 2; + }); + m.def("half_or_none_exp", [](int x) -> exp_opt_int { + return x ? exp_opt_int(x / 2) : exp_opt_int(); + }); + m.def("test_nullopt_exp", [](exp_opt_int x) { + return x.value_or(42); + }, py::arg_v("x", std::experimental::nullopt, "None")); + m.def("test_no_assign_exp", [](const exp_opt_no_assign &x) { + return x ? x->value : 42; + }, py::arg_v("x", std::experimental::nullopt, "None")); +#endif + +#ifdef PYBIND11_HAS_VARIANT + static_assert(std::is_same::value, + "visitor::result_type is required by boost::variant in C++11 mode"); + + struct visitor { + using result_type = const char *; + + result_type operator()(int) { return "int"; } + result_type operator()(std::string) { return "std::string"; } + result_type operator()(double) { return "double"; } + result_type operator()(std::nullptr_t) { return "std::nullptr_t"; } + }; + + // test_variant + m.def("load_variant", [](variant v) { + return py::detail::visit_helper::call(visitor(), v); + }); + m.def("load_variant_2pass", [](variant v) { + return py::detail::visit_helper::call(visitor(), v); + }); + m.def("cast_variant", []() { + using V = variant; + return py::make_tuple(V(5), V("Hello")); + }); +#endif + + // #528: templated constructor + // (no python tests: the test here is that this compiles) + m.def("tpl_ctor_vector", [](std::vector &) {}); + m.def("tpl_ctor_map", [](std::unordered_map &) {}); + m.def("tpl_ctor_set", [](std::unordered_set &) {}); +#if defined(PYBIND11_HAS_OPTIONAL) + m.def("tpl_constr_optional", [](std::optional &) {}); +#elif defined(PYBIND11_HAS_EXP_OPTIONAL) + m.def("tpl_constr_optional", [](std::experimental::optional &) {}); +#endif + + // test_vec_of_reference_wrapper + // #171: Can't return STL structures containing reference wrapper + m.def("return_vec_of_reference_wrapper", [](std::reference_wrapper p4) { + static UserType p1{1}, p2{2}, p3{3}; + return std::vector> { + std::ref(p1), std::ref(p2), std::ref(p3), p4 + }; + }); + + // test_stl_pass_by_pointer + m.def("stl_pass_by_pointer", [](std::vector* v) { return *v; }, "v"_a=nullptr); + + // #1258: pybind11/stl.h converts string to vector + m.def("func_with_string_or_vector_string_arg_overload", [](std::vector) { return 1; }); + m.def("func_with_string_or_vector_string_arg_overload", [](std::list) { return 2; }); + m.def("func_with_string_or_vector_string_arg_overload", [](std::string) { return 3; }); + + class Placeholder { + public: + Placeholder() { print_created(this); } + Placeholder(const Placeholder &) = delete; + ~Placeholder() { print_destroyed(this); } + }; + py::class_(m, "Placeholder"); + + /// test_stl_vector_ownership + m.def("test_stl_ownership", + []() { + std::vector result; + result.push_back(new Placeholder()); + return result; + }, + py::return_value_policy::take_ownership); + + m.def("array_cast_sequence", [](std::array x) { return x; }); + + /// test_issue_1561 + struct Issue1561Inner { std::string data; }; + struct Issue1561Outer { std::vector list; }; + + py::class_(m, "Issue1561Inner") + .def(py::init()) + .def_readwrite("data", &Issue1561Inner::data); + + py::class_(m, "Issue1561Outer") + .def(py::init<>()) + .def_readwrite("list", &Issue1561Outer::list); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl.py new file mode 100644 index 0000000000000000000000000000000000000000..2335cb9fdfe1cf611176256282639aa816eb7bdc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl.py @@ -0,0 +1,241 @@ +import pytest + +from pybind11_tests import stl as m +from pybind11_tests import UserType +from pybind11_tests import ConstructorStats + + +def test_vector(doc): + """std::vector <-> list""" + lst = m.cast_vector() + assert lst == [1] + lst.append(2) + assert m.load_vector(lst) + assert m.load_vector(tuple(lst)) + + assert m.cast_bool_vector() == [True, False] + assert m.load_bool_vector([True, False]) + + assert doc(m.cast_vector) == "cast_vector() -> List[int]" + assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool" + + # Test regression caused by 936: pointers to stl containers weren't castable + assert m.cast_ptr_vector() == ["lvalue", "lvalue"] + + +def test_deque(doc): + """std::deque <-> list""" + lst = m.cast_deque() + assert lst == [1] + lst.append(2) + assert m.load_deque(lst) + assert m.load_deque(tuple(lst)) + + +def test_array(doc): + """std::array <-> list""" + lst = m.cast_array() + assert lst == [1, 2] + assert m.load_array(lst) + + assert doc(m.cast_array) == "cast_array() -> List[int[2]]" + assert doc(m.load_array) == "load_array(arg0: List[int[2]]) -> bool" + + +def test_valarray(doc): + """std::valarray <-> list""" + lst = m.cast_valarray() + assert lst == [1, 4, 9] + assert m.load_valarray(lst) + + assert doc(m.cast_valarray) == "cast_valarray() -> List[int]" + assert doc(m.load_valarray) == "load_valarray(arg0: List[int]) -> bool" + + +def test_map(doc): + """std::map <-> dict""" + d = m.cast_map() + assert d == {"key": "value"} + assert "key" in d + d["key2"] = "value2" + assert "key2" in d + assert m.load_map(d) + + assert doc(m.cast_map) == "cast_map() -> Dict[str, str]" + assert doc(m.load_map) == "load_map(arg0: Dict[str, str]) -> bool" + + +def test_set(doc): + """std::set <-> set""" + s = m.cast_set() + assert s == {"key1", "key2"} + s.add("key3") + assert m.load_set(s) + + assert doc(m.cast_set) == "cast_set() -> Set[str]" + assert doc(m.load_set) == "load_set(arg0: Set[str]) -> bool" + + +def test_recursive_casting(): + """Tests that stl casters preserve lvalue/rvalue context for container values""" + assert m.cast_rv_vector() == ["rvalue", "rvalue"] + assert m.cast_lv_vector() == ["lvalue", "lvalue"] + assert m.cast_rv_array() == ["rvalue", "rvalue", "rvalue"] + assert m.cast_lv_array() == ["lvalue", "lvalue"] + assert m.cast_rv_map() == {"a": "rvalue"} + assert m.cast_lv_map() == {"a": "lvalue", "b": "lvalue"} + assert m.cast_rv_nested() == [[[{"b": "rvalue", "c": "rvalue"}], [{"a": "rvalue"}]]] + assert m.cast_lv_nested() == { + "a": [[["lvalue", "lvalue"]], [["lvalue", "lvalue"]]], + "b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]] + } + + # Issue #853 test case: + z = m.cast_unique_ptr_vector() + assert z[0].value == 7 and z[1].value == 42 + + +def test_move_out_container(): + """Properties use the `reference_internal` policy by default. If the underlying function + returns an rvalue, the policy is automatically changed to `move` to avoid referencing + a temporary. In case the return value is a container of user-defined types, the policy + also needs to be applied to the elements, not just the container.""" + c = m.MoveOutContainer() + moved_out_list = c.move_list + assert [x.value for x in moved_out_list] == [0, 1, 2] + + +@pytest.mark.skipif(not hasattr(m, "has_optional"), reason='no ') +def test_optional(): + assert m.double_or_zero(None) == 0 + assert m.double_or_zero(42) == 84 + pytest.raises(TypeError, m.double_or_zero, 'foo') + + assert m.half_or_none(0) is None + assert m.half_or_none(42) == 21 + pytest.raises(TypeError, m.half_or_none, 'foo') + + assert m.test_nullopt() == 42 + assert m.test_nullopt(None) == 42 + assert m.test_nullopt(42) == 42 + assert m.test_nullopt(43) == 43 + + assert m.test_no_assign() == 42 + assert m.test_no_assign(None) == 42 + assert m.test_no_assign(m.NoAssign(43)) == 43 + pytest.raises(TypeError, m.test_no_assign, 43) + + assert m.nodefer_none_optional(None) + + +@pytest.mark.skipif(not hasattr(m, "has_exp_optional"), reason='no ') +def test_exp_optional(): + assert m.double_or_zero_exp(None) == 0 + assert m.double_or_zero_exp(42) == 84 + pytest.raises(TypeError, m.double_or_zero_exp, 'foo') + + assert m.half_or_none_exp(0) is None + assert m.half_or_none_exp(42) == 21 + pytest.raises(TypeError, m.half_or_none_exp, 'foo') + + assert m.test_nullopt_exp() == 42 + assert m.test_nullopt_exp(None) == 42 + assert m.test_nullopt_exp(42) == 42 + assert m.test_nullopt_exp(43) == 43 + + assert m.test_no_assign_exp() == 42 + assert m.test_no_assign_exp(None) == 42 + assert m.test_no_assign_exp(m.NoAssign(43)) == 43 + pytest.raises(TypeError, m.test_no_assign_exp, 43) + + +@pytest.mark.skipif(not hasattr(m, "load_variant"), reason='no ') +def test_variant(doc): + assert m.load_variant(1) == "int" + assert m.load_variant("1") == "std::string" + assert m.load_variant(1.0) == "double" + assert m.load_variant(None) == "std::nullptr_t" + + assert m.load_variant_2pass(1) == "int" + assert m.load_variant_2pass(1.0) == "double" + + assert m.cast_variant() == (5, "Hello") + + assert doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str" + + +def test_vec_of_reference_wrapper(): + """#171: Can't return reference wrappers (or STL structures containing them)""" + assert str(m.return_vec_of_reference_wrapper(UserType(4))) == \ + "[UserType(1), UserType(2), UserType(3), UserType(4)]" + + +def test_stl_pass_by_pointer(msg): + """Passing nullptr or None to an STL container pointer is not expected to work""" + with pytest.raises(TypeError) as excinfo: + m.stl_pass_by_pointer() # default value is `nullptr` + assert msg(excinfo.value) == """ + stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported: + 1. (v: List[int] = None) -> List[int] + + Invoked with: + """ # noqa: E501 line too long + + with pytest.raises(TypeError) as excinfo: + m.stl_pass_by_pointer(None) + assert msg(excinfo.value) == """ + stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported: + 1. (v: List[int] = None) -> List[int] + + Invoked with: None + """ # noqa: E501 line too long + + assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3] + + +def test_missing_header_message(): + """Trying convert `list` to a `std::vector`, or vice versa, without including + should result in a helpful suggestion in the error message""" + import pybind11_cross_module_tests as cm + + expected_message = ("Did you forget to `#include `? Or ,\n" + ", , etc. Some automatic\n" + "conversions are optional and require extra headers to be included\n" + "when compiling your pybind11 module.") + + with pytest.raises(TypeError) as excinfo: + cm.missing_header_arg([1.0, 2.0, 3.0]) + assert expected_message in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + cm.missing_header_return() + assert expected_message in str(excinfo.value) + + +def test_function_with_string_and_vector_string_arg(): + """Check if a string is NOT implicitly converted to a list, which was the + behavior before fix of issue #1258""" + assert m.func_with_string_or_vector_string_arg_overload(('A', 'B', )) == 2 + assert m.func_with_string_or_vector_string_arg_overload(['A', 'B']) == 2 + assert m.func_with_string_or_vector_string_arg_overload('A') == 3 + + +def test_stl_ownership(): + cstats = ConstructorStats.get(m.Placeholder) + assert cstats.alive() == 0 + r = m.test_stl_ownership() + assert len(r) == 1 + del r + assert cstats.alive() == 0 + + +def test_array_cast_sequence(): + assert m.array_cast_sequence((1, 2, 3)) == [1, 2, 3] + + +def test_issue_1561(): + """ check fix for issue #1561 """ + bar = m.Issue1561Outer() + bar.list = [m.Issue1561Inner('bar')] + bar.list + assert bar.list[0].data == 'bar' diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl_binders.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl_binders.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8688874091219f5a5035f5eb46e976e7408080b8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl_binders.cpp @@ -0,0 +1,129 @@ +/* + tests/test_stl_binders.cpp -- Usage of stl_binders functions + + Copyright (c) 2016 Sergey Lyskov + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +#include +#include +#include +#include +#include + +class El { +public: + El() = delete; + El(int v) : a(v) { } + + int a; +}; + +std::ostream & operator<<(std::ostream &s, El const&v) { + s << "El{" << v.a << '}'; + return s; +} + +/// Issue #487: binding std::vector with E non-copyable +class E_nc { +public: + explicit E_nc(int i) : value{i} {} + E_nc(const E_nc &) = delete; + E_nc &operator=(const E_nc &) = delete; + E_nc(E_nc &&) = default; + E_nc &operator=(E_nc &&) = default; + + int value; +}; + +template Container *one_to_n(int n) { + auto v = new Container(); + for (int i = 1; i <= n; i++) + v->emplace_back(i); + return v; +} + +template Map *times_ten(int n) { + auto m = new Map(); + for (int i = 1; i <= n; i++) + m->emplace(int(i), E_nc(10*i)); + return m; +} + +template NestMap *times_hundred(int n) { + auto m = new NestMap(); + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + (*m)[i].emplace(int(j*10), E_nc(100*j)); + return m; +} + +TEST_SUBMODULE(stl_binders, m) { + // test_vector_int + py::bind_vector>(m, "VectorInt", py::buffer_protocol()); + + // test_vector_custom + py::class_(m, "El") + .def(py::init()); + py::bind_vector>(m, "VectorEl"); + py::bind_vector>>(m, "VectorVectorEl"); + + // test_map_string_double + py::bind_map>(m, "MapStringDouble"); + py::bind_map>(m, "UnorderedMapStringDouble"); + + // test_map_string_double_const + py::bind_map>(m, "MapStringDoubleConst"); + py::bind_map>(m, "UnorderedMapStringDoubleConst"); + + py::class_(m, "ENC") + .def(py::init()) + .def_readwrite("value", &E_nc::value); + + // test_noncopyable_containers + py::bind_vector>(m, "VectorENC"); + m.def("get_vnc", &one_to_n>, py::return_value_policy::reference); + py::bind_vector>(m, "DequeENC"); + m.def("get_dnc", &one_to_n>, py::return_value_policy::reference); + py::bind_map>(m, "MapENC"); + m.def("get_mnc", ×_ten>, py::return_value_policy::reference); + py::bind_map>(m, "UmapENC"); + m.def("get_umnc", ×_ten>, py::return_value_policy::reference); + // Issue #1885: binding nested std::map> with E non-copyable + py::bind_map>>(m, "MapVecENC"); + m.def("get_nvnc", [](int n) + { + auto m = new std::map>(); + for (int i = 1; i <= n; i++) + for (int j = 1; j <= n; j++) + (*m)[i].emplace_back(j); + return m; + }, py::return_value_policy::reference); + py::bind_map>>(m, "MapMapENC"); + m.def("get_nmnc", ×_hundred>>, py::return_value_policy::reference); + py::bind_map>>(m, "UmapUmapENC"); + m.def("get_numnc", ×_hundred>>, py::return_value_policy::reference); + + // test_vector_buffer + py::bind_vector>(m, "VectorUChar", py::buffer_protocol()); + // no dtype declared for this version: + struct VUndeclStruct { bool w; uint32_t x; double y; bool z; }; + m.def("create_undeclstruct", [m] () mutable { + py::bind_vector>(m, "VectorUndeclStruct", py::buffer_protocol()); + }); + + // The rest depends on numpy: + try { py::module::import("numpy"); } + catch (...) { return; } + + // test_vector_buffer_numpy + struct VStruct { bool w; uint32_t x; double y; bool z; }; + PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z); + py::class_(m, "VStruct").def_readwrite("x", &VStruct::x); + py::bind_vector>(m, "VectorStruct", py::buffer_protocol()); + m.def("get_vectorstruct", [] {return std::vector {{0, 5, 3.0, 1}, {1, 30, -1e4, 0}};}); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl_binders.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl_binders.py new file mode 100644 index 0000000000000000000000000000000000000000..c7b7e8535283d333b496ec5392dec6f6686e16c4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_stl_binders.py @@ -0,0 +1,276 @@ +import pytest +import sys +from pybind11_tests import stl_binders as m + +with pytest.suppress(ImportError): + import numpy as np + + +def test_vector_int(): + v_int = m.VectorInt([0, 0]) + assert len(v_int) == 2 + assert bool(v_int) is True + + # test construction from a generator + v_int1 = m.VectorInt(x for x in range(5)) + assert v_int1 == m.VectorInt([0, 1, 2, 3, 4]) + + v_int2 = m.VectorInt([0, 0]) + assert v_int == v_int2 + v_int2[1] = 1 + assert v_int != v_int2 + + v_int2.append(2) + v_int2.insert(0, 1) + v_int2.insert(0, 2) + v_int2.insert(0, 3) + v_int2.insert(6, 3) + assert str(v_int2) == "VectorInt[3, 2, 1, 0, 1, 2, 3]" + with pytest.raises(IndexError): + v_int2.insert(8, 4) + + v_int.append(99) + v_int2[2:-2] = v_int + assert v_int2 == m.VectorInt([3, 2, 0, 0, 99, 2, 3]) + del v_int2[1:3] + assert v_int2 == m.VectorInt([3, 0, 99, 2, 3]) + del v_int2[0] + assert v_int2 == m.VectorInt([0, 99, 2, 3]) + + v_int2.extend(m.VectorInt([4, 5])) + assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5]) + + v_int2.extend([6, 7]) + assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7]) + + # test error handling, and that the vector is unchanged + with pytest.raises(RuntimeError): + v_int2.extend([8, 'a']) + + assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7]) + + # test extending from a generator + v_int2.extend(x for x in range(5)) + assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4]) + + # test negative indexing + assert v_int2[-1] == 4 + + # insert with negative index + v_int2.insert(-1, 88) + assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 88, 4]) + + # delete negative index + del v_int2[-1] + assert v_int2 == m.VectorInt([0, 99, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 88]) + + v_int2.clear() + assert len(v_int2) == 0 + +# related to the PyPy's buffer protocol. +@pytest.unsupported_on_pypy +def test_vector_buffer(): + b = bytearray([1, 2, 3, 4]) + v = m.VectorUChar(b) + assert v[1] == 2 + v[2] = 5 + mv = memoryview(v) # We expose the buffer interface + if sys.version_info.major > 2: + assert mv[2] == 5 + mv[2] = 6 + else: + assert mv[2] == '\x05' + mv[2] = '\x06' + assert v[2] == 6 + + with pytest.raises(RuntimeError) as excinfo: + m.create_undeclstruct() # Undeclared struct contents, no buffer interface + assert "NumPy type info missing for " in str(excinfo.value) + + +@pytest.unsupported_on_pypy +@pytest.requires_numpy +def test_vector_buffer_numpy(): + a = np.array([1, 2, 3, 4], dtype=np.int32) + with pytest.raises(TypeError): + m.VectorInt(a) + + a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], dtype=np.uintc) + v = m.VectorInt(a[0, :]) + assert len(v) == 4 + assert v[2] == 3 + ma = np.asarray(v) + ma[2] = 5 + assert v[2] == 5 + + v = m.VectorInt(a[:, 1]) + assert len(v) == 3 + assert v[2] == 10 + + v = m.get_vectorstruct() + assert v[0].x == 5 + ma = np.asarray(v) + ma[1]['x'] = 99 + assert v[1].x == 99 + + v = m.VectorStruct(np.zeros(3, dtype=np.dtype([('w', 'bool'), ('x', 'I'), + ('y', 'float64'), ('z', 'bool')], align=True))) + assert len(v) == 3 + + +def test_vector_bool(): + import pybind11_cross_module_tests as cm + + vv_c = cm.VectorBool() + for i in range(10): + vv_c.append(i % 2 == 0) + for i in range(10): + assert vv_c[i] == (i % 2 == 0) + assert str(vv_c) == "VectorBool[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]" + + +def test_vector_custom(): + v_a = m.VectorEl() + v_a.append(m.El(1)) + v_a.append(m.El(2)) + assert str(v_a) == "VectorEl[El{1}, El{2}]" + + vv_a = m.VectorVectorEl() + vv_a.append(v_a) + vv_b = vv_a[0] + assert str(vv_b) == "VectorEl[El{1}, El{2}]" + + +def test_map_string_double(): + mm = m.MapStringDouble() + mm['a'] = 1 + mm['b'] = 2.5 + + assert list(mm) == ['a', 'b'] + assert list(mm.items()) == [('a', 1), ('b', 2.5)] + assert str(mm) == "MapStringDouble{a: 1, b: 2.5}" + + um = m.UnorderedMapStringDouble() + um['ua'] = 1.1 + um['ub'] = 2.6 + + assert sorted(list(um)) == ['ua', 'ub'] + assert sorted(list(um.items())) == [('ua', 1.1), ('ub', 2.6)] + assert "UnorderedMapStringDouble" in str(um) + + +def test_map_string_double_const(): + mc = m.MapStringDoubleConst() + mc['a'] = 10 + mc['b'] = 20.5 + assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}" + + umc = m.UnorderedMapStringDoubleConst() + umc['a'] = 11 + umc['b'] = 21.5 + + str(umc) + + +def test_noncopyable_containers(): + # std::vector + vnc = m.get_vnc(5) + for i in range(0, 5): + assert vnc[i].value == i + 1 + + for i, j in enumerate(vnc, start=1): + assert j.value == i + + # std::deque + dnc = m.get_dnc(5) + for i in range(0, 5): + assert dnc[i].value == i + 1 + + i = 1 + for j in dnc: + assert(j.value == i) + i += 1 + + # std::map + mnc = m.get_mnc(5) + for i in range(1, 6): + assert mnc[i].value == 10 * i + + vsum = 0 + for k, v in mnc.items(): + assert v.value == 10 * k + vsum += v.value + + assert vsum == 150 + + # std::unordered_map + mnc = m.get_umnc(5) + for i in range(1, 6): + assert mnc[i].value == 10 * i + + vsum = 0 + for k, v in mnc.items(): + assert v.value == 10 * k + vsum += v.value + + assert vsum == 150 + + # nested std::map + nvnc = m.get_nvnc(5) + for i in range(1, 6): + for j in range(0, 5): + assert nvnc[i][j].value == j + 1 + + for k, v in nvnc.items(): + for i, j in enumerate(v, start=1): + assert j.value == i + + # nested std::map + nmnc = m.get_nmnc(5) + for i in range(1, 6): + for j in range(10, 60, 10): + assert nmnc[i][j].value == 10 * j + + vsum = 0 + for k_o, v_o in nmnc.items(): + for k_i, v_i in v_o.items(): + assert v_i.value == 10 * k_i + vsum += v_i.value + + assert vsum == 7500 + + # nested std::unordered_map + numnc = m.get_numnc(5) + for i in range(1, 6): + for j in range(10, 60, 10): + assert numnc[i][j].value == 10 * j + + vsum = 0 + for k_o, v_o in numnc.items(): + for k_i, v_i in v_o.items(): + assert v_i.value == 10 * k_i + vsum += v_i.value + + assert vsum == 7500 + + +def test_map_delitem(): + mm = m.MapStringDouble() + mm['a'] = 1 + mm['b'] = 2.5 + + assert list(mm) == ['a', 'b'] + assert list(mm.items()) == [('a', 1), ('b', 2.5)] + del mm['a'] + assert list(mm) == ['b'] + assert list(mm.items()) == [('b', 2.5)] + + um = m.UnorderedMapStringDouble() + um['ua'] = 1.1 + um['ub'] = 2.6 + + assert sorted(list(um)) == ['ua', 'ub'] + assert sorted(list(um.items())) == [('ua', 1.1), ('ub', 2.6)] + del um['ua'] + assert sorted(list(um)) == ['ub'] + assert sorted(list(um.items())) == [('ub', 2.6)] diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_tagbased_polymorphic.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_tagbased_polymorphic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..272e460c998249c0dbf58b5f3de675ff0e478649 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_tagbased_polymorphic.cpp @@ -0,0 +1,136 @@ +/* + tests/test_tagbased_polymorphic.cpp -- test of polymorphic_type_hook + + Copyright (c) 2018 Hudson River Trading LLC + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include + +struct Animal +{ + enum class Kind { + Unknown = 0, + Dog = 100, Labrador, Chihuahua, LastDog = 199, + Cat = 200, Panther, LastCat = 299 + }; + static const std::type_info* type_of_kind(Kind kind); + static std::string name_of_kind(Kind kind); + + const Kind kind; + const std::string name; + + protected: + Animal(const std::string& _name, Kind _kind) + : kind(_kind), name(_name) + {} +}; + +struct Dog : Animal +{ + Dog(const std::string& _name, Kind _kind = Kind::Dog) : Animal(_name, _kind) {} + std::string bark() const { return name_of_kind(kind) + " " + name + " goes " + sound; } + std::string sound = "WOOF!"; +}; + +struct Labrador : Dog +{ + Labrador(const std::string& _name, int _excitement = 9001) + : Dog(_name, Kind::Labrador), excitement(_excitement) {} + int excitement; +}; + +struct Chihuahua : Dog +{ + Chihuahua(const std::string& _name) : Dog(_name, Kind::Chihuahua) { sound = "iyiyiyiyiyi"; } + std::string bark() const { return Dog::bark() + " and runs in circles"; } +}; + +struct Cat : Animal +{ + Cat(const std::string& _name, Kind _kind = Kind::Cat) : Animal(_name, _kind) {} + std::string purr() const { return "mrowr"; } +}; + +struct Panther : Cat +{ + Panther(const std::string& _name) : Cat(_name, Kind::Panther) {} + std::string purr() const { return "mrrrRRRRRR"; } +}; + +std::vector> create_zoo() +{ + std::vector> ret; + ret.emplace_back(new Labrador("Fido", 15000)); + + // simulate some new type of Dog that the Python bindings + // haven't been updated for; it should still be considered + // a Dog, not just an Animal. + ret.emplace_back(new Dog("Ginger", Dog::Kind(150))); + + ret.emplace_back(new Chihuahua("Hertzl")); + ret.emplace_back(new Cat("Tiger", Cat::Kind::Cat)); + ret.emplace_back(new Panther("Leo")); + return ret; +} + +const std::type_info* Animal::type_of_kind(Kind kind) +{ + switch (kind) { + case Kind::Unknown: break; + + case Kind::Dog: break; + case Kind::Labrador: return &typeid(Labrador); + case Kind::Chihuahua: return &typeid(Chihuahua); + case Kind::LastDog: break; + + case Kind::Cat: break; + case Kind::Panther: return &typeid(Panther); + case Kind::LastCat: break; + } + + if (kind >= Kind::Dog && kind <= Kind::LastDog) return &typeid(Dog); + if (kind >= Kind::Cat && kind <= Kind::LastCat) return &typeid(Cat); + return nullptr; +} + +std::string Animal::name_of_kind(Kind kind) +{ + std::string raw_name = type_of_kind(kind)->name(); + py::detail::clean_type_id(raw_name); + return raw_name; +} + +namespace pybind11 { + template + struct polymorphic_type_hook::value>> + { + static const void *get(const itype *src, const std::type_info*& type) + { type = src ? Animal::type_of_kind(src->kind) : nullptr; return src; } + }; +} + +TEST_SUBMODULE(tagbased_polymorphic, m) { + py::class_(m, "Animal") + .def_readonly("name", &Animal::name); + py::class_(m, "Dog") + .def(py::init()) + .def_readwrite("sound", &Dog::sound) + .def("bark", &Dog::bark); + py::class_(m, "Labrador") + .def(py::init(), "name"_a, "excitement"_a = 9001) + .def_readwrite("excitement", &Labrador::excitement); + py::class_(m, "Chihuahua") + .def(py::init()) + .def("bark", &Chihuahua::bark); + py::class_(m, "Cat") + .def(py::init()) + .def("purr", &Cat::purr); + py::class_(m, "Panther") + .def(py::init()) + .def("purr", &Panther::purr); + m.def("create_zoo", &create_zoo); +}; diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_tagbased_polymorphic.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_tagbased_polymorphic.py new file mode 100644 index 0000000000000000000000000000000000000000..2574d7de77bf062daee2c78436c0a104cd37a8ae --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_tagbased_polymorphic.py @@ -0,0 +1,20 @@ +from pybind11_tests import tagbased_polymorphic as m + + +def test_downcast(): + zoo = m.create_zoo() + assert [type(animal) for animal in zoo] == [ + m.Labrador, m.Dog, m.Chihuahua, m.Cat, m.Panther + ] + assert [animal.name for animal in zoo] == [ + "Fido", "Ginger", "Hertzl", "Tiger", "Leo" + ] + zoo[1].sound = "woooooo" + assert [dog.bark() for dog in zoo[:3]] == [ + "Labrador Fido goes WOOF!", + "Dog Ginger goes woooooo", + "Chihuahua Hertzl goes iyiyiyiyiyi and runs in circles" + ] + assert [cat.purr() for cat in zoo[3:]] == ["mrowr", "mrrrRRRRRR"] + zoo[0].excitement -= 1000 + assert zoo[0].excitement == 14000 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_union.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_union.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b98ea216ca0b272978134d9dd1d1eff1b804ad5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_union.cpp @@ -0,0 +1,22 @@ +/* + tests/test_class.cpp -- test py::class_ definitions and basic functionality + + Copyright (c) 2019 Roland Dreier + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +TEST_SUBMODULE(union_, m) { + union TestUnion { + int value_int; + unsigned value_uint; + }; + + py::class_(m, "TestUnion") + .def(py::init<>()) + .def_readonly("as_int", &TestUnion::value_int) + .def_readwrite("as_uint", &TestUnion::value_uint); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_union.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_union.py new file mode 100644 index 0000000000000000000000000000000000000000..e1866e701dec2085f9b38b862fc197b008ea9096 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_union.py @@ -0,0 +1,8 @@ +from pybind11_tests import union_ as m + + +def test_union(): + instance = m.TestUnion() + + instance.as_uint = 10 + assert instance.as_int == 10 diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_virtual_functions.cpp b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_virtual_functions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ccf018d997041c543a4dc4aec5875a6dca7c6914 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_virtual_functions.cpp @@ -0,0 +1,479 @@ +/* + tests/test_virtual_functions.cpp -- overriding virtual functions from Python + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include +#include + +/* This is an example class that we'll want to be able to extend from Python */ +class ExampleVirt { +public: + ExampleVirt(int state) : state(state) { print_created(this, state); } + ExampleVirt(const ExampleVirt &e) : state(e.state) { print_copy_created(this); } + ExampleVirt(ExampleVirt &&e) : state(e.state) { print_move_created(this); e.state = 0; } + virtual ~ExampleVirt() { print_destroyed(this); } + + virtual int run(int value) { + py::print("Original implementation of " + "ExampleVirt::run(state={}, value={}, str1={}, str2={})"_s.format(state, value, get_string1(), *get_string2())); + return state + value; + } + + virtual bool run_bool() = 0; + virtual void pure_virtual() = 0; + + // Returning a reference/pointer to a type converted from python (numbers, strings, etc.) is a + // bit trickier, because the actual int& or std::string& or whatever only exists temporarily, so + // we have to handle it specially in the trampoline class (see below). + virtual const std::string &get_string1() { return str1; } + virtual const std::string *get_string2() { return &str2; } + +private: + int state; + const std::string str1{"default1"}, str2{"default2"}; +}; + +/* This is a wrapper class that must be generated */ +class PyExampleVirt : public ExampleVirt { +public: + using ExampleVirt::ExampleVirt; /* Inherit constructors */ + + int run(int value) override { + /* Generate wrapping code that enables native function overloading */ + PYBIND11_OVERLOAD( + int, /* Return type */ + ExampleVirt, /* Parent class */ + run, /* Name of function */ + value /* Argument(s) */ + ); + } + + bool run_bool() override { + PYBIND11_OVERLOAD_PURE( + bool, /* Return type */ + ExampleVirt, /* Parent class */ + run_bool, /* Name of function */ + /* This function has no arguments. The trailing comma + in the previous line is needed for some compilers */ + ); + } + + void pure_virtual() override { + PYBIND11_OVERLOAD_PURE( + void, /* Return type */ + ExampleVirt, /* Parent class */ + pure_virtual, /* Name of function */ + /* This function has no arguments. The trailing comma + in the previous line is needed for some compilers */ + ); + } + + // We can return reference types for compatibility with C++ virtual interfaces that do so, but + // note they have some significant limitations (see the documentation). + const std::string &get_string1() override { + PYBIND11_OVERLOAD( + const std::string &, /* Return type */ + ExampleVirt, /* Parent class */ + get_string1, /* Name of function */ + /* (no arguments) */ + ); + } + + const std::string *get_string2() override { + PYBIND11_OVERLOAD( + const std::string *, /* Return type */ + ExampleVirt, /* Parent class */ + get_string2, /* Name of function */ + /* (no arguments) */ + ); + } + +}; + +class NonCopyable { +public: + NonCopyable(int a, int b) : value{new int(a*b)} { print_created(this, a, b); } + NonCopyable(NonCopyable &&o) { value = std::move(o.value); print_move_created(this); } + NonCopyable(const NonCopyable &) = delete; + NonCopyable() = delete; + void operator=(const NonCopyable &) = delete; + void operator=(NonCopyable &&) = delete; + std::string get_value() const { + if (value) return std::to_string(*value); else return "(null)"; + } + ~NonCopyable() { print_destroyed(this); } + +private: + std::unique_ptr value; +}; + +// This is like the above, but is both copy and movable. In effect this means it should get moved +// when it is not referenced elsewhere, but copied if it is still referenced. +class Movable { +public: + Movable(int a, int b) : value{a+b} { print_created(this, a, b); } + Movable(const Movable &m) { value = m.value; print_copy_created(this); } + Movable(Movable &&m) { value = std::move(m.value); print_move_created(this); } + std::string get_value() const { return std::to_string(value); } + ~Movable() { print_destroyed(this); } +private: + int value; +}; + +class NCVirt { +public: + virtual ~NCVirt() { } + virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); } + virtual Movable get_movable(int a, int b) = 0; + + std::string print_nc(int a, int b) { return get_noncopyable(a, b).get_value(); } + std::string print_movable(int a, int b) { return get_movable(a, b).get_value(); } +}; +class NCVirtTrampoline : public NCVirt { +#if !defined(__INTEL_COMPILER) + NonCopyable get_noncopyable(int a, int b) override { + PYBIND11_OVERLOAD(NonCopyable, NCVirt, get_noncopyable, a, b); + } +#endif + Movable get_movable(int a, int b) override { + PYBIND11_OVERLOAD_PURE(Movable, NCVirt, get_movable, a, b); + } +}; + +struct Base { + /* for some reason MSVC2015 can't compile this if the function is pure virtual */ + virtual std::string dispatch() const { return {}; }; + virtual ~Base() = default; +}; + +struct DispatchIssue : Base { + virtual std::string dispatch() const { + PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */); + } +}; + +static void test_gil() { + { + py::gil_scoped_acquire lock; + py::print("1st lock acquired"); + + } + + { + py::gil_scoped_acquire lock; + py::print("2nd lock acquired"); + } + +} + +static void test_gil_from_thread() { + py::gil_scoped_release release; + + std::thread t(test_gil); + t.join(); +} + + +// Forward declaration (so that we can put the main tests here; the inherited virtual approaches are +// rather long). +void initialize_inherited_virtuals(py::module &m); + +TEST_SUBMODULE(virtual_functions, m) { + // test_override + py::class_(m, "ExampleVirt") + .def(py::init()) + /* Reference original class in function definitions */ + .def("run", &ExampleVirt::run) + .def("run_bool", &ExampleVirt::run_bool) + .def("pure_virtual", &ExampleVirt::pure_virtual); + + py::class_(m, "NonCopyable") + .def(py::init()); + + py::class_(m, "Movable") + .def(py::init()); + + // test_move_support +#if !defined(__INTEL_COMPILER) + py::class_(m, "NCVirt") + .def(py::init<>()) + .def("get_noncopyable", &NCVirt::get_noncopyable) + .def("get_movable", &NCVirt::get_movable) + .def("print_nc", &NCVirt::print_nc) + .def("print_movable", &NCVirt::print_movable); +#endif + + m.def("runExampleVirt", [](ExampleVirt *ex, int value) { return ex->run(value); }); + m.def("runExampleVirtBool", [](ExampleVirt* ex) { return ex->run_bool(); }); + m.def("runExampleVirtVirtual", [](ExampleVirt *ex) { ex->pure_virtual(); }); + + m.def("cstats_debug", &ConstructorStats::get); + initialize_inherited_virtuals(m); + + // test_alias_delay_initialization1 + // don't invoke Python dispatch classes by default when instantiating C++ classes + // that were not extended on the Python side + struct A { + virtual ~A() {} + virtual void f() { py::print("A.f()"); } + }; + + struct PyA : A { + PyA() { py::print("PyA.PyA()"); } + ~PyA() { py::print("PyA.~PyA()"); } + + void f() override { + py::print("PyA.f()"); + // This convolution just gives a `void`, but tests that PYBIND11_TYPE() works to protect + // a type containing a , + PYBIND11_OVERLOAD(PYBIND11_TYPE(typename std::enable_if::type), A, f); + } + }; + + py::class_(m, "A") + .def(py::init<>()) + .def("f", &A::f); + + m.def("call_f", [](A *a) { a->f(); }); + + // test_alias_delay_initialization2 + // ... unless we explicitly request it, as in this example: + struct A2 { + virtual ~A2() {} + virtual void f() { py::print("A2.f()"); } + }; + + struct PyA2 : A2 { + PyA2() { py::print("PyA2.PyA2()"); } + ~PyA2() { py::print("PyA2.~PyA2()"); } + void f() override { + py::print("PyA2.f()"); + PYBIND11_OVERLOAD(void, A2, f); + } + }; + + py::class_(m, "A2") + .def(py::init_alias<>()) + .def(py::init([](int) { return new PyA2(); })) + .def("f", &A2::f); + + m.def("call_f", [](A2 *a2) { a2->f(); }); + + // test_dispatch_issue + // #159: virtual function dispatch has problems with similar-named functions + py::class_(m, "DispatchIssue") + .def(py::init<>()) + .def("dispatch", &Base::dispatch); + + m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); }); + + // test_override_ref + // #392/397: overriding reference-returning functions + class OverrideTest { + public: + struct A { std::string value = "hi"; }; + std::string v; + A a; + explicit OverrideTest(const std::string &v) : v{v} {} + virtual std::string str_value() { return v; } + virtual std::string &str_ref() { return v; } + virtual A A_value() { return a; } + virtual A &A_ref() { return a; } + virtual ~OverrideTest() = default; + }; + + class PyOverrideTest : public OverrideTest { + public: + using OverrideTest::OverrideTest; + std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); } + // Not allowed (uncommenting should hit a static_assert failure): we can't get a reference + // to a python numeric value, since we only copy values in the numeric type caster: +// std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); } + // But we can work around it like this: + private: + std::string _tmp; + std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); } + public: + std::string &str_ref() override { return _tmp = str_ref_helper(); } + + A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); } + A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); } + }; + + py::class_(m, "OverrideTest_A") + .def_readwrite("value", &OverrideTest::A::value); + py::class_(m, "OverrideTest") + .def(py::init()) + .def("str_value", &OverrideTest::str_value) +// .def("str_ref", &OverrideTest::str_ref) + .def("A_value", &OverrideTest::A_value) + .def("A_ref", &OverrideTest::A_ref); +} + + +// Inheriting virtual methods. We do two versions here: the repeat-everything version and the +// templated trampoline versions mentioned in docs/advanced.rst. +// +// These base classes are exactly the same, but we technically need distinct +// classes for this example code because we need to be able to bind them +// properly (pybind11, sensibly, doesn't allow us to bind the same C++ class to +// multiple python classes). +class A_Repeat { +#define A_METHODS \ +public: \ + virtual int unlucky_number() = 0; \ + virtual std::string say_something(unsigned times) { \ + std::string s = ""; \ + for (unsigned i = 0; i < times; ++i) \ + s += "hi"; \ + return s; \ + } \ + std::string say_everything() { \ + return say_something(1) + " " + std::to_string(unlucky_number()); \ + } +A_METHODS + virtual ~A_Repeat() = default; +}; +class B_Repeat : public A_Repeat { +#define B_METHODS \ +public: \ + int unlucky_number() override { return 13; } \ + std::string say_something(unsigned times) override { \ + return "B says hi " + std::to_string(times) + " times"; \ + } \ + virtual double lucky_number() { return 7.0; } +B_METHODS +}; +class C_Repeat : public B_Repeat { +#define C_METHODS \ +public: \ + int unlucky_number() override { return 4444; } \ + double lucky_number() override { return 888; } +C_METHODS +}; +class D_Repeat : public C_Repeat { +#define D_METHODS // Nothing overridden. +D_METHODS +}; + +// Base classes for templated inheritance trampolines. Identical to the repeat-everything version: +class A_Tpl { A_METHODS; virtual ~A_Tpl() = default; }; +class B_Tpl : public A_Tpl { B_METHODS }; +class C_Tpl : public B_Tpl { C_METHODS }; +class D_Tpl : public C_Tpl { D_METHODS }; + + +// Inheritance approach 1: each trampoline gets every virtual method (11 in total) +class PyA_Repeat : public A_Repeat { +public: + using A_Repeat::A_Repeat; + int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, A_Repeat, unlucky_number, ); } + std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, A_Repeat, say_something, times); } +}; +class PyB_Repeat : public B_Repeat { +public: + using B_Repeat::B_Repeat; + int unlucky_number() override { PYBIND11_OVERLOAD(int, B_Repeat, unlucky_number, ); } + std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, B_Repeat, say_something, times); } + double lucky_number() override { PYBIND11_OVERLOAD(double, B_Repeat, lucky_number, ); } +}; +class PyC_Repeat : public C_Repeat { +public: + using C_Repeat::C_Repeat; + int unlucky_number() override { PYBIND11_OVERLOAD(int, C_Repeat, unlucky_number, ); } + std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, C_Repeat, say_something, times); } + double lucky_number() override { PYBIND11_OVERLOAD(double, C_Repeat, lucky_number, ); } +}; +class PyD_Repeat : public D_Repeat { +public: + using D_Repeat::D_Repeat; + int unlucky_number() override { PYBIND11_OVERLOAD(int, D_Repeat, unlucky_number, ); } + std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, D_Repeat, say_something, times); } + double lucky_number() override { PYBIND11_OVERLOAD(double, D_Repeat, lucky_number, ); } +}; + +// Inheritance approach 2: templated trampoline classes. +// +// Advantages: +// - we have only 2 (template) class and 4 method declarations (one per virtual method, plus one for +// any override of a pure virtual method), versus 4 classes and 6 methods (MI) or 4 classes and 11 +// methods (repeat). +// - Compared to MI, we also don't have to change the non-trampoline inheritance to virtual, and can +// properly inherit constructors. +// +// Disadvantage: +// - the compiler must still generate and compile 14 different methods (more, even, than the 11 +// required for the repeat approach) instead of the 6 required for MI. (If there was no pure +// method (or no pure method override), the number would drop down to the same 11 as the repeat +// approach). +template +class PyA_Tpl : public Base { +public: + using Base::Base; // Inherit constructors + int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, Base, unlucky_number, ); } + std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, Base, say_something, times); } +}; +template +class PyB_Tpl : public PyA_Tpl { +public: + using PyA_Tpl::PyA_Tpl; // Inherit constructors (via PyA_Tpl's inherited constructors) + int unlucky_number() override { PYBIND11_OVERLOAD(int, Base, unlucky_number, ); } + double lucky_number() override { PYBIND11_OVERLOAD(double, Base, lucky_number, ); } +}; +// Since C_Tpl and D_Tpl don't declare any new virtual methods, we don't actually need these (we can +// use PyB_Tpl and PyB_Tpl for the trampoline classes instead): +/* +template class PyC_Tpl : public PyB_Tpl { +public: + using PyB_Tpl::PyB_Tpl; +}; +template class PyD_Tpl : public PyC_Tpl { +public: + using PyC_Tpl::PyC_Tpl; +}; +*/ + +void initialize_inherited_virtuals(py::module &m) { + // test_inherited_virtuals + + // Method 1: repeat + py::class_(m, "A_Repeat") + .def(py::init<>()) + .def("unlucky_number", &A_Repeat::unlucky_number) + .def("say_something", &A_Repeat::say_something) + .def("say_everything", &A_Repeat::say_everything); + py::class_(m, "B_Repeat") + .def(py::init<>()) + .def("lucky_number", &B_Repeat::lucky_number); + py::class_(m, "C_Repeat") + .def(py::init<>()); + py::class_(m, "D_Repeat") + .def(py::init<>()); + + // test_ + // Method 2: Templated trampolines + py::class_>(m, "A_Tpl") + .def(py::init<>()) + .def("unlucky_number", &A_Tpl::unlucky_number) + .def("say_something", &A_Tpl::say_something) + .def("say_everything", &A_Tpl::say_everything); + py::class_>(m, "B_Tpl") + .def(py::init<>()) + .def("lucky_number", &B_Tpl::lucky_number); + py::class_>(m, "C_Tpl") + .def(py::init<>()); + py::class_>(m, "D_Tpl") + .def(py::init<>()); + + + // Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7) + m.def("test_gil", &test_gil); + m.def("test_gil_from_thread", &test_gil_from_thread); +}; diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_virtual_functions.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_virtual_functions.py new file mode 100644 index 0000000000000000000000000000000000000000..5ce9abd3557c69a67f17b63192c6bd06a8bdb66e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tests/test_virtual_functions.py @@ -0,0 +1,377 @@ +import pytest + +from pybind11_tests import virtual_functions as m +from pybind11_tests import ConstructorStats + + +def test_override(capture, msg): + class ExtendedExampleVirt(m.ExampleVirt): + def __init__(self, state): + super(ExtendedExampleVirt, self).__init__(state + 1) + self.data = "Hello world" + + def run(self, value): + print('ExtendedExampleVirt::run(%i), calling parent..' % value) + return super(ExtendedExampleVirt, self).run(value + 1) + + def run_bool(self): + print('ExtendedExampleVirt::run_bool()') + return False + + def get_string1(self): + return "override1" + + def pure_virtual(self): + print('ExtendedExampleVirt::pure_virtual(): %s' % self.data) + + class ExtendedExampleVirt2(ExtendedExampleVirt): + def __init__(self, state): + super(ExtendedExampleVirt2, self).__init__(state + 1) + + def get_string2(self): + return "override2" + + ex12 = m.ExampleVirt(10) + with capture: + assert m.runExampleVirt(ex12, 20) == 30 + assert capture == """ + Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2) + """ # noqa: E501 line too long + + with pytest.raises(RuntimeError) as excinfo: + m.runExampleVirtVirtual(ex12) + assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"' + + ex12p = ExtendedExampleVirt(10) + with capture: + assert m.runExampleVirt(ex12p, 20) == 32 + assert capture == """ + ExtendedExampleVirt::run(20), calling parent.. + Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2) + """ # noqa: E501 line too long + with capture: + assert m.runExampleVirtBool(ex12p) is False + assert capture == "ExtendedExampleVirt::run_bool()" + with capture: + m.runExampleVirtVirtual(ex12p) + assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world" + + ex12p2 = ExtendedExampleVirt2(15) + with capture: + assert m.runExampleVirt(ex12p2, 50) == 68 + assert capture == """ + ExtendedExampleVirt::run(50), calling parent.. + Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2) + """ # noqa: E501 line too long + + cstats = ConstructorStats.get(m.ExampleVirt) + assert cstats.alive() == 3 + del ex12, ex12p, ex12p2 + assert cstats.alive() == 0 + assert cstats.values() == ['10', '11', '17'] + assert cstats.copy_constructions == 0 + assert cstats.move_constructions >= 0 + + +def test_alias_delay_initialization1(capture): + """`A` only initializes its trampoline class when we inherit from it + + If we just create and use an A instance directly, the trampoline initialization is + bypassed and we only initialize an A() instead (for performance reasons). + """ + class B(m.A): + def __init__(self): + super(B, self).__init__() + + def f(self): + print("In python f()") + + # C++ version + with capture: + a = m.A() + m.call_f(a) + del a + pytest.gc_collect() + assert capture == "A.f()" + + # Python version + with capture: + b = B() + m.call_f(b) + del b + pytest.gc_collect() + assert capture == """ + PyA.PyA() + PyA.f() + In python f() + PyA.~PyA() + """ + + +def test_alias_delay_initialization2(capture): + """`A2`, unlike the above, is configured to always initialize the alias + + While the extra initialization and extra class layer has small virtual dispatch + performance penalty, it also allows us to do more things with the trampoline + class such as defining local variables and performing construction/destruction. + """ + class B2(m.A2): + def __init__(self): + super(B2, self).__init__() + + def f(self): + print("In python B2.f()") + + # No python subclass version + with capture: + a2 = m.A2() + m.call_f(a2) + del a2 + pytest.gc_collect() + a3 = m.A2(1) + m.call_f(a3) + del a3 + pytest.gc_collect() + assert capture == """ + PyA2.PyA2() + PyA2.f() + A2.f() + PyA2.~PyA2() + PyA2.PyA2() + PyA2.f() + A2.f() + PyA2.~PyA2() + """ + + # Python subclass version + with capture: + b2 = B2() + m.call_f(b2) + del b2 + pytest.gc_collect() + assert capture == """ + PyA2.PyA2() + PyA2.f() + In python B2.f() + PyA2.~PyA2() + """ + + +# PyPy: Reference count > 1 causes call with noncopyable instance +# to fail in ncv1.print_nc() +@pytest.unsupported_on_pypy +@pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC") +def test_move_support(): + class NCVirtExt(m.NCVirt): + def get_noncopyable(self, a, b): + # Constructs and returns a new instance: + nc = m.NonCopyable(a * a, b * b) + return nc + + def get_movable(self, a, b): + # Return a referenced copy + self.movable = m.Movable(a, b) + return self.movable + + class NCVirtExt2(m.NCVirt): + def get_noncopyable(self, a, b): + # Keep a reference: this is going to throw an exception + self.nc = m.NonCopyable(a, b) + return self.nc + + def get_movable(self, a, b): + # Return a new instance without storing it + return m.Movable(a, b) + + ncv1 = NCVirtExt() + assert ncv1.print_nc(2, 3) == "36" + assert ncv1.print_movable(4, 5) == "9" + ncv2 = NCVirtExt2() + assert ncv2.print_movable(7, 7) == "14" + # Don't check the exception message here because it differs under debug/non-debug mode + with pytest.raises(RuntimeError): + ncv2.print_nc(9, 9) + + nc_stats = ConstructorStats.get(m.NonCopyable) + mv_stats = ConstructorStats.get(m.Movable) + assert nc_stats.alive() == 1 + assert mv_stats.alive() == 1 + del ncv1, ncv2 + assert nc_stats.alive() == 0 + assert mv_stats.alive() == 0 + assert nc_stats.values() == ['4', '9', '9', '9'] + assert mv_stats.values() == ['4', '5', '7', '7'] + assert nc_stats.copy_constructions == 0 + assert mv_stats.copy_constructions == 1 + assert nc_stats.move_constructions >= 0 + assert mv_stats.move_constructions >= 0 + + +def test_dispatch_issue(msg): + """#159: virtual function dispatch has problems with similar-named functions""" + class PyClass1(m.DispatchIssue): + def dispatch(self): + return "Yay.." + + class PyClass2(m.DispatchIssue): + def dispatch(self): + with pytest.raises(RuntimeError) as excinfo: + super(PyClass2, self).dispatch() + assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"' + + p = PyClass1() + return m.dispatch_issue_go(p) + + b = PyClass2() + assert m.dispatch_issue_go(b) == "Yay.." + + +def test_override_ref(): + """#392/397: overriding reference-returning functions""" + o = m.OverrideTest("asdf") + + # Not allowed (see associated .cpp comment) + # i = o.str_ref() + # assert o.str_ref() == "asdf" + assert o.str_value() == "asdf" + + assert o.A_value().value == "hi" + a = o.A_ref() + assert a.value == "hi" + a.value = "bye" + assert a.value == "bye" + + +def test_inherited_virtuals(): + class AR(m.A_Repeat): + def unlucky_number(self): + return 99 + + class AT(m.A_Tpl): + def unlucky_number(self): + return 999 + + obj = AR() + assert obj.say_something(3) == "hihihi" + assert obj.unlucky_number() == 99 + assert obj.say_everything() == "hi 99" + + obj = AT() + assert obj.say_something(3) == "hihihi" + assert obj.unlucky_number() == 999 + assert obj.say_everything() == "hi 999" + + for obj in [m.B_Repeat(), m.B_Tpl()]: + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 13 + assert obj.lucky_number() == 7.0 + assert obj.say_everything() == "B says hi 1 times 13" + + for obj in [m.C_Repeat(), m.C_Tpl()]: + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888.0 + assert obj.say_everything() == "B says hi 1 times 4444" + + class CR(m.C_Repeat): + def lucky_number(self): + return m.C_Repeat.lucky_number(self) + 1.25 + + obj = CR() + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 889.25 + assert obj.say_everything() == "B says hi 1 times 4444" + + class CT(m.C_Tpl): + pass + + obj = CT() + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888.0 + assert obj.say_everything() == "B says hi 1 times 4444" + + class CCR(CR): + def lucky_number(self): + return CR.lucky_number(self) * 10 + + obj = CCR() + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 8892.5 + assert obj.say_everything() == "B says hi 1 times 4444" + + class CCT(CT): + def lucky_number(self): + return CT.lucky_number(self) * 1000 + + obj = CCT() + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888000.0 + assert obj.say_everything() == "B says hi 1 times 4444" + + class DR(m.D_Repeat): + def unlucky_number(self): + return 123 + + def lucky_number(self): + return 42.0 + + for obj in [m.D_Repeat(), m.D_Tpl()]: + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888.0 + assert obj.say_everything() == "B says hi 1 times 4444" + + obj = DR() + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 123 + assert obj.lucky_number() == 42.0 + assert obj.say_everything() == "B says hi 1 times 123" + + class DT(m.D_Tpl): + def say_something(self, times): + return "DT says:" + (' quack' * times) + + def unlucky_number(self): + return 1234 + + def lucky_number(self): + return -4.25 + + obj = DT() + assert obj.say_something(3) == "DT says: quack quack quack" + assert obj.unlucky_number() == 1234 + assert obj.lucky_number() == -4.25 + assert obj.say_everything() == "DT says: quack 1234" + + class DT2(DT): + def say_something(self, times): + return "DT2: " + ('QUACK' * times) + + def unlucky_number(self): + return -3 + + class BT(m.B_Tpl): + def say_something(self, times): + return "BT" * times + + def unlucky_number(self): + return -7 + + def lucky_number(self): + return -1.375 + + obj = BT() + assert obj.say_something(3) == "BTBTBT" + assert obj.unlucky_number() == -7 + assert obj.lucky_number() == -1.375 + assert obj.say_everything() == "BT -7" + + +def test_issue_1454(): + # Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7) + m.test_gil() + m.test_gil_from_thread() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/FindCatch.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/FindCatch.cmake new file mode 100644 index 0000000000000000000000000000000000000000..9d490c5aade2151ebdd8cc84509361ba1c061f84 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/FindCatch.cmake @@ -0,0 +1,57 @@ +# - Find the Catch test framework or download it (single header) +# +# This is a quick module for internal use. It assumes that Catch is +# REQUIRED and that a minimum version is provided (not EXACT). If +# a suitable version isn't found locally, the single header file +# will be downloaded and placed in the build dir: PROJECT_BINARY_DIR. +# +# This code sets the following variables: +# CATCH_INCLUDE_DIR - path to catch.hpp +# CATCH_VERSION - version number + +if(NOT Catch_FIND_VERSION) + message(FATAL_ERROR "A version number must be specified.") +elseif(Catch_FIND_REQUIRED) + message(FATAL_ERROR "This module assumes Catch is not required.") +elseif(Catch_FIND_VERSION_EXACT) + message(FATAL_ERROR "Exact version numbers are not supported, only minimum.") +endif() + +# Extract the version number from catch.hpp +function(_get_catch_version) + file(STRINGS "${CATCH_INCLUDE_DIR}/catch.hpp" version_line REGEX "Catch v.*" LIMIT_COUNT 1) + if(version_line MATCHES "Catch v([0-9]+)\\.([0-9]+)\\.([0-9]+)") + set(CATCH_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}" PARENT_SCOPE) + endif() +endfunction() + +# Download the single-header version of Catch +function(_download_catch version destination_dir) + message(STATUS "Downloading catch v${version}...") + set(url https://github.com/philsquared/Catch/releases/download/v${version}/catch.hpp) + file(DOWNLOAD ${url} "${destination_dir}/catch.hpp" STATUS status) + list(GET status 0 error) + if(error) + message(FATAL_ERROR "Could not download ${url}") + endif() + set(CATCH_INCLUDE_DIR "${destination_dir}" CACHE INTERNAL "") +endfunction() + +# Look for catch locally +find_path(CATCH_INCLUDE_DIR NAMES catch.hpp PATH_SUFFIXES catch) +if(CATCH_INCLUDE_DIR) + _get_catch_version() +endif() + +# Download the header if it wasn't found or if it's outdated +if(NOT CATCH_VERSION OR CATCH_VERSION VERSION_LESS ${Catch_FIND_VERSION}) + if(DOWNLOAD_CATCH) + _download_catch(${Catch_FIND_VERSION} "${PROJECT_BINARY_DIR}/catch/") + _get_catch_version() + else() + set(CATCH_FOUND FALSE) + return() + endif() +endif() + +set(CATCH_FOUND TRUE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/FindEigen3.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/FindEigen3.cmake new file mode 100644 index 0000000000000000000000000000000000000000..9c546a05d859b18c49554d7ee7221cc486b7760e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/FindEigen3.cmake @@ -0,0 +1,81 @@ +# - Try to find Eigen3 lib +# +# This module supports requiring a minimum version, e.g. you can do +# find_package(Eigen3 3.1.2) +# to require version 3.1.2 or newer of Eigen3. +# +# Once done this will define +# +# EIGEN3_FOUND - system has eigen lib with correct version +# EIGEN3_INCLUDE_DIR - the eigen include directory +# EIGEN3_VERSION - eigen version + +# Copyright (c) 2006, 2007 Montel Laurent, +# Copyright (c) 2008, 2009 Gael Guennebaud, +# Copyright (c) 2009 Benoit Jacob +# Redistribution and use is allowed according to the terms of the 2-clause BSD license. + +if(NOT Eigen3_FIND_VERSION) + if(NOT Eigen3_FIND_VERSION_MAJOR) + set(Eigen3_FIND_VERSION_MAJOR 2) + endif(NOT Eigen3_FIND_VERSION_MAJOR) + if(NOT Eigen3_FIND_VERSION_MINOR) + set(Eigen3_FIND_VERSION_MINOR 91) + endif(NOT Eigen3_FIND_VERSION_MINOR) + if(NOT Eigen3_FIND_VERSION_PATCH) + set(Eigen3_FIND_VERSION_PATCH 0) + endif(NOT Eigen3_FIND_VERSION_PATCH) + + set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") +endif(NOT Eigen3_FIND_VERSION) + +macro(_eigen3_check_version) + file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) + + string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") + set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") + set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") + set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") + + set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) + if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK FALSE) + else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK TRUE) + endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + + if(NOT EIGEN3_VERSION_OK) + + message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " + "but at least version ${Eigen3_FIND_VERSION} is required") + endif(NOT EIGEN3_VERSION_OK) +endmacro(_eigen3_check_version) + +if (EIGEN3_INCLUDE_DIR) + + # in cache already + _eigen3_check_version() + set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) + +else (EIGEN3_INCLUDE_DIR) + + find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library + PATHS + ${CMAKE_INSTALL_PREFIX}/include + ${KDE4_INCLUDE_DIR} + PATH_SUFFIXES eigen3 eigen + ) + + if(EIGEN3_INCLUDE_DIR) + _eigen3_check_version() + endif(EIGEN3_INCLUDE_DIR) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) + + mark_as_advanced(EIGEN3_INCLUDE_DIR) + +endif(EIGEN3_INCLUDE_DIR) + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/FindPythonLibsNew.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/FindPythonLibsNew.cmake new file mode 100644 index 0000000000000000000000000000000000000000..9ea6036e33d1606482cd500efc3c8d3dc5eecf92 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/FindPythonLibsNew.cmake @@ -0,0 +1,202 @@ +# - Find python libraries +# This module finds the libraries corresponding to the Python interpreter +# FindPythonInterp provides. +# This code sets the following variables: +# +# PYTHONLIBS_FOUND - have the Python libs been found +# PYTHON_PREFIX - path to the Python installation +# PYTHON_LIBRARIES - path to the python library +# PYTHON_INCLUDE_DIRS - path to where Python.h is found +# PYTHON_MODULE_EXTENSION - lib extension, e.g. '.so' or '.pyd' +# PYTHON_MODULE_PREFIX - lib name prefix: usually an empty string +# PYTHON_SITE_PACKAGES - path to installation site-packages +# PYTHON_IS_DEBUG - whether the Python interpreter is a debug build +# +# Thanks to talljimbo for the patch adding the 'LDVERSION' config +# variable usage. + +#============================================================================= +# Copyright 2001-2009 Kitware, Inc. +# Copyright 2012 Continuum Analytics, Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +# Checking for the extension makes sure that `LibsNew` was found and not just `Libs`. +if(PYTHONLIBS_FOUND AND PYTHON_MODULE_EXTENSION) + return() +endif() + +# Use the Python interpreter to find the libs. +if(PythonLibsNew_FIND_REQUIRED) + find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} REQUIRED) +else() + find_package(PythonInterp ${PythonLibsNew_FIND_VERSION}) +endif() + +if(NOT PYTHONINTERP_FOUND) + set(PYTHONLIBS_FOUND FALSE) + set(PythonLibsNew_FOUND FALSE) + return() +endif() + +# According to http://stackoverflow.com/questions/646518/python-how-to-detect-debug-interpreter +# testing whether sys has the gettotalrefcount function is a reliable, cross-platform +# way to detect a CPython debug interpreter. +# +# The library suffix is from the config var LDVERSION sometimes, otherwise +# VERSION. VERSION will typically be like "2.7" on unix, and "27" on windows. +execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" + "from distutils import sysconfig as s;import sys;import struct; +print('.'.join(str(v) for v in sys.version_info)); +print(sys.prefix); +print(s.get_python_inc(plat_specific=True)); +print(s.get_python_lib(plat_specific=True)); +print(s.get_config_var('SO')); +print(hasattr(sys, 'gettotalrefcount')+0); +print(struct.calcsize('@P')); +print(s.get_config_var('LDVERSION') or s.get_config_var('VERSION')); +print(s.get_config_var('LIBDIR') or ''); +print(s.get_config_var('MULTIARCH') or ''); +" + RESULT_VARIABLE _PYTHON_SUCCESS + OUTPUT_VARIABLE _PYTHON_VALUES + ERROR_VARIABLE _PYTHON_ERROR_VALUE) + +if(NOT _PYTHON_SUCCESS MATCHES 0) + if(PythonLibsNew_FIND_REQUIRED) + message(FATAL_ERROR + "Python config failure:\n${_PYTHON_ERROR_VALUE}") + endif() + set(PYTHONLIBS_FOUND FALSE) + set(PythonLibsNew_FOUND FALSE) + return() +endif() + +# Convert the process output into a list +if(WIN32) + string(REGEX REPLACE "\\\\" "/" _PYTHON_VALUES ${_PYTHON_VALUES}) +endif() +string(REGEX REPLACE ";" "\\\\;" _PYTHON_VALUES ${_PYTHON_VALUES}) +string(REGEX REPLACE "\n" ";" _PYTHON_VALUES ${_PYTHON_VALUES}) +list(GET _PYTHON_VALUES 0 _PYTHON_VERSION_LIST) +list(GET _PYTHON_VALUES 1 PYTHON_PREFIX) +list(GET _PYTHON_VALUES 2 PYTHON_INCLUDE_DIR) +list(GET _PYTHON_VALUES 3 PYTHON_SITE_PACKAGES) +list(GET _PYTHON_VALUES 4 PYTHON_MODULE_EXTENSION) +list(GET _PYTHON_VALUES 5 PYTHON_IS_DEBUG) +list(GET _PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P) +list(GET _PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX) +list(GET _PYTHON_VALUES 8 PYTHON_LIBDIR) +list(GET _PYTHON_VALUES 9 PYTHON_MULTIARCH) + +# Make sure the Python has the same pointer-size as the chosen compiler +# Skip if CMAKE_SIZEOF_VOID_P is not defined +if(CMAKE_SIZEOF_VOID_P AND (NOT "${PYTHON_SIZEOF_VOID_P}" STREQUAL "${CMAKE_SIZEOF_VOID_P}")) + if(PythonLibsNew_FIND_REQUIRED) + math(EXPR _PYTHON_BITS "${PYTHON_SIZEOF_VOID_P} * 8") + math(EXPR _CMAKE_BITS "${CMAKE_SIZEOF_VOID_P} * 8") + message(FATAL_ERROR + "Python config failure: Python is ${_PYTHON_BITS}-bit, " + "chosen compiler is ${_CMAKE_BITS}-bit") + endif() + set(PYTHONLIBS_FOUND FALSE) + set(PythonLibsNew_FOUND FALSE) + return() +endif() + +# The built-in FindPython didn't always give the version numbers +string(REGEX REPLACE "\\." ";" _PYTHON_VERSION_LIST ${_PYTHON_VERSION_LIST}) +list(GET _PYTHON_VERSION_LIST 0 PYTHON_VERSION_MAJOR) +list(GET _PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR) +list(GET _PYTHON_VERSION_LIST 2 PYTHON_VERSION_PATCH) + +# Make sure all directory separators are '/' +string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX "${PYTHON_PREFIX}") +string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}") +string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES "${PYTHON_SITE_PACKAGES}") + +if(CMAKE_HOST_WIN32 AND NOT (MINGW AND DEFINED ENV{MSYSTEM})) + set(PYTHON_LIBRARY + "${PYTHON_PREFIX}/libs/Python${PYTHON_LIBRARY_SUFFIX}.lib") + + # when run in a venv, PYTHON_PREFIX points to it. But the libraries remain in the + # original python installation. They may be found relative to PYTHON_INCLUDE_DIR. + if(NOT EXISTS "${PYTHON_LIBRARY}") + get_filename_component(_PYTHON_ROOT ${PYTHON_INCLUDE_DIR} DIRECTORY) + set(PYTHON_LIBRARY + "${_PYTHON_ROOT}/libs/Python${PYTHON_LIBRARY_SUFFIX}.lib") + endif() + + # raise an error if the python libs are still not found. + if(NOT EXISTS "${PYTHON_LIBRARY}") + message(FATAL_ERROR "Python libraries not found") + endif() + +else() + if(PYTHON_MULTIARCH) + set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}") + else() + set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}") + endif() + #message(STATUS "Searching for Python libs in ${_PYTHON_LIBS_SEARCH}") + # Probably this needs to be more involved. It would be nice if the config + # information the python interpreter itself gave us were more complete. + find_library(PYTHON_LIBRARY + NAMES "python${PYTHON_LIBRARY_SUFFIX}" + PATHS ${_PYTHON_LIBS_SEARCH} + NO_DEFAULT_PATH) + + # If all else fails, just set the name/version and let the linker figure out the path. + if(NOT PYTHON_LIBRARY) + set(PYTHON_LIBRARY python${PYTHON_LIBRARY_SUFFIX}) + endif() +endif() + +MARK_AS_ADVANCED( + PYTHON_LIBRARY + PYTHON_INCLUDE_DIR +) + +# We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the +# cache entries because they are meant to specify the location of a single +# library. We now set the variables listed by the documentation for this +# module. +SET(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") +SET(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") +SET(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}") + +find_package_message(PYTHON + "Found PythonLibs: ${PYTHON_LIBRARY}" + "${PYTHON_EXECUTABLE}${PYTHON_VERSION}") + +set(PYTHONLIBS_FOUND TRUE) +set(PythonLibsNew_FOUND TRUE) diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/check-style.sh b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/check-style.sh new file mode 100755 index 0000000000000000000000000000000000000000..0a9f7d24fcbf5ef4a86dab0bccceb9b331bdb4e7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/check-style.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# +# Script to check include/test code for common pybind11 code style errors. +# +# This script currently checks for +# +# 1. use of tabs instead of spaces +# 2. MSDOS-style CRLF endings +# 3. trailing spaces +# 4. missing space between keyword and parenthesis, e.g.: for(, if(, while( +# 5. Missing space between right parenthesis and brace, e.g. 'for (...){' +# 6. opening brace on its own line. It should always be on the same line as the +# if/while/for/do statement. +# +# Invoke as: tools/check-style.sh +# + +check_style_errors=0 +IFS=$'\n' + +found="$( GREP_COLORS='mt=41' GREP_COLOR='41' grep $'\t' include tests/*.{cpp,py,h} docs/*.rst -rn --color=always )" +if [ -n "$found" ]; then + # The mt=41 sets a red background for matched tabs: + echo -e '\033[31;01mError: found tab characters in the following files:\033[0m' + check_style_errors=1 + echo "$found" | sed -e 's/^/ /' +fi + + +found="$( grep -IUlr $'\r' include tests/*.{cpp,py,h} docs/*.rst --color=always )" +if [ -n "$found" ]; then + echo -e '\033[31;01mError: found CRLF characters in the following files:\033[0m' + check_style_errors=1 + echo "$found" | sed -e 's/^/ /' +fi + +found="$(GREP_COLORS='mt=41' GREP_COLOR='41' grep '[[:blank:]]\+$' include tests/*.{cpp,py,h} docs/*.rst -rn --color=always )" +if [ -n "$found" ]; then + # The mt=41 sets a red background for matched trailing spaces + echo -e '\033[31;01mError: found trailing spaces in the following files:\033[0m' + check_style_errors=1 + echo "$found" | sed -e 's/^/ /' +fi + +found="$(grep '\<\(if\|for\|while\|catch\)(\|){' include tests/*.{cpp,h} -rn --color=always)" +if [ -n "$found" ]; then + echo -e '\033[31;01mError: found the following coding style problems:\033[0m' + check_style_errors=1 + echo "$found" | sed -e 's/^/ /' +fi + +found="$(awk ' +function prefix(filename, lineno) { + return " \033[35m" filename "\033[36m:\033[32m" lineno "\033[36m:\033[0m" +} +function mark(pattern, string) { sub(pattern, "\033[01;31m&\033[0m", string); return string } +last && /^\s*{/ { + print prefix(FILENAME, FNR-1) mark("\\)\\s*$", last) + print prefix(FILENAME, FNR) mark("^\\s*{", $0) + last="" +} +{ last = /(if|for|while|catch|switch)\s*\(.*\)\s*$/ ? $0 : "" } +' $(find include -type f) tests/*.{cpp,h} docs/*.rst)" +if [ -n "$found" ]; then + check_style_errors=1 + echo -e '\033[31;01mError: braces should occur on the same line as the if/while/.. statement. Found issues in the following files:\033[0m' + echo "$found" +fi + +exit $check_style_errors diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/libsize.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/libsize.py new file mode 100644 index 0000000000000000000000000000000000000000..5dcb8b0d020c600d03e97b148d2b56cf3bf23c07 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/libsize.py @@ -0,0 +1,38 @@ +from __future__ import print_function, division +import os +import sys + +# Internal build script for generating debugging test .so size. +# Usage: +# python libsize.py file.so save.txt -- displays the size of file.so and, if save.txt exists, compares it to the +# size in it, then overwrites save.txt with the new size for future runs. + +if len(sys.argv) != 3: + sys.exit("Invalid arguments: usage: python libsize.py file.so save.txt") + +lib = sys.argv[1] +save = sys.argv[2] + +if not os.path.exists(lib): + sys.exit("Error: requested file ({}) does not exist".format(lib)) + +libsize = os.path.getsize(lib) + +print("------", os.path.basename(lib), "file size:", libsize, end='') + +if os.path.exists(save): + with open(save) as sf: + oldsize = int(sf.readline()) + + if oldsize > 0: + change = libsize - oldsize + if change == 0: + print(" (no change)") + else: + print(" (change of {:+} bytes = {:+.2%})".format(change, change / oldsize)) +else: + print() + +with open(save, 'w') as sf: + sf.write(str(libsize)) + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/mkdoc.py b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/mkdoc.py new file mode 100755 index 0000000000000000000000000000000000000000..44164af3d6032938a251f899605b9bc1b12645bc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/mkdoc.py @@ -0,0 +1,379 @@ +#!/usr/bin/env python3 +# +# Syntax: mkdoc.py [-I ..] [.. a list of header files ..] +# +# Extract documentation from C++ header files to use it in Python bindings +# + +import os +import sys +import platform +import re +import textwrap + +from clang import cindex +from clang.cindex import CursorKind +from collections import OrderedDict +from glob import glob +from threading import Thread, Semaphore +from multiprocessing import cpu_count + +RECURSE_LIST = [ + CursorKind.TRANSLATION_UNIT, + CursorKind.NAMESPACE, + CursorKind.CLASS_DECL, + CursorKind.STRUCT_DECL, + CursorKind.ENUM_DECL, + CursorKind.CLASS_TEMPLATE +] + +PRINT_LIST = [ + CursorKind.CLASS_DECL, + CursorKind.STRUCT_DECL, + CursorKind.ENUM_DECL, + CursorKind.ENUM_CONSTANT_DECL, + CursorKind.CLASS_TEMPLATE, + CursorKind.FUNCTION_DECL, + CursorKind.FUNCTION_TEMPLATE, + CursorKind.CONVERSION_FUNCTION, + CursorKind.CXX_METHOD, + CursorKind.CONSTRUCTOR, + CursorKind.FIELD_DECL +] + +PREFIX_BLACKLIST = [ + CursorKind.TRANSLATION_UNIT +] + +CPP_OPERATORS = { + '<=': 'le', '>=': 'ge', '==': 'eq', '!=': 'ne', '[]': 'array', + '+=': 'iadd', '-=': 'isub', '*=': 'imul', '/=': 'idiv', '%=': + 'imod', '&=': 'iand', '|=': 'ior', '^=': 'ixor', '<<=': 'ilshift', + '>>=': 'irshift', '++': 'inc', '--': 'dec', '<<': 'lshift', '>>': + 'rshift', '&&': 'land', '||': 'lor', '!': 'lnot', '~': 'bnot', + '&': 'band', '|': 'bor', '+': 'add', '-': 'sub', '*': 'mul', '/': + 'div', '%': 'mod', '<': 'lt', '>': 'gt', '=': 'assign', '()': 'call' +} + +CPP_OPERATORS = OrderedDict( + sorted(CPP_OPERATORS.items(), key=lambda t: -len(t[0]))) + +job_count = cpu_count() +job_semaphore = Semaphore(job_count) + + +class NoFilenamesError(ValueError): + pass + + +def d(s): + return s if isinstance(s, str) else s.decode('utf8') + + +def sanitize_name(name): + name = re.sub(r'type-parameter-0-([0-9]+)', r'T\1', name) + for k, v in CPP_OPERATORS.items(): + name = name.replace('operator%s' % k, 'operator_%s' % v) + name = re.sub('<.*>', '', name) + name = ''.join([ch if ch.isalnum() else '_' for ch in name]) + name = re.sub('_$', '', re.sub('_+', '_', name)) + return '__doc_' + name + + +def process_comment(comment): + result = '' + + # Remove C++ comment syntax + leading_spaces = float('inf') + for s in comment.expandtabs(tabsize=4).splitlines(): + s = s.strip() + if s.startswith('/*'): + s = s[2:].lstrip('*') + elif s.endswith('*/'): + s = s[:-2].rstrip('*') + elif s.startswith('///'): + s = s[3:] + if s.startswith('*'): + s = s[1:] + if len(s) > 0: + leading_spaces = min(leading_spaces, len(s) - len(s.lstrip())) + result += s + '\n' + + if leading_spaces != float('inf'): + result2 = "" + for s in result.splitlines(): + result2 += s[leading_spaces:] + '\n' + result = result2 + + # Doxygen tags + cpp_group = '([\w:]+)' + param_group = '([\[\w:\]]+)' + + s = result + s = re.sub(r'\\c\s+%s' % cpp_group, r'``\1``', s) + s = re.sub(r'\\a\s+%s' % cpp_group, r'*\1*', s) + s = re.sub(r'\\e\s+%s' % cpp_group, r'*\1*', s) + s = re.sub(r'\\em\s+%s' % cpp_group, r'*\1*', s) + s = re.sub(r'\\b\s+%s' % cpp_group, r'**\1**', s) + s = re.sub(r'\\ingroup\s+%s' % cpp_group, r'', s) + s = re.sub(r'\\param%s?\s+%s' % (param_group, cpp_group), + r'\n\n$Parameter ``\2``:\n\n', s) + s = re.sub(r'\\tparam%s?\s+%s' % (param_group, cpp_group), + r'\n\n$Template parameter ``\2``:\n\n', s) + + for in_, out_ in { + 'return': 'Returns', + 'author': 'Author', + 'authors': 'Authors', + 'copyright': 'Copyright', + 'date': 'Date', + 'remark': 'Remark', + 'sa': 'See also', + 'see': 'See also', + 'extends': 'Extends', + 'throw': 'Throws', + 'throws': 'Throws' + }.items(): + s = re.sub(r'\\%s\s*' % in_, r'\n\n$%s:\n\n' % out_, s) + + s = re.sub(r'\\details\s*', r'\n\n', s) + s = re.sub(r'\\brief\s*', r'', s) + s = re.sub(r'\\short\s*', r'', s) + s = re.sub(r'\\ref\s*', r'', s) + + s = re.sub(r'\\code\s?(.*?)\s?\\endcode', + r"```\n\1\n```\n", s, flags=re.DOTALL) + + # HTML/TeX tags + s = re.sub(r'(.*?)', r'``\1``', s, flags=re.DOTALL) + s = re.sub(r'
(.*?)
', r"```\n\1\n```\n", s, flags=re.DOTALL) + s = re.sub(r'(.*?)', r'*\1*', s, flags=re.DOTALL) + s = re.sub(r'(.*?)', r'**\1**', s, flags=re.DOTALL) + s = re.sub(r'\\f\$(.*?)\\f\$', r'$\1$', s, flags=re.DOTALL) + s = re.sub(r'
  • ', r'\n\n* ', s) + s = re.sub(r'', r'', s) + s = re.sub(r'
  • ', r'\n\n', s) + + s = s.replace('``true``', '``True``') + s = s.replace('``false``', '``False``') + + # Re-flow text + wrapper = textwrap.TextWrapper() + wrapper.expand_tabs = True + wrapper.replace_whitespace = True + wrapper.drop_whitespace = True + wrapper.width = 70 + wrapper.initial_indent = wrapper.subsequent_indent = '' + + result = '' + in_code_segment = False + for x in re.split(r'(```)', s): + if x == '```': + if not in_code_segment: + result += '```\n' + else: + result += '\n```\n\n' + in_code_segment = not in_code_segment + elif in_code_segment: + result += x.strip() + else: + for y in re.split(r'(?: *\n *){2,}', x): + wrapped = wrapper.fill(re.sub(r'\s+', ' ', y).strip()) + if len(wrapped) > 0 and wrapped[0] == '$': + result += wrapped[1:] + '\n' + wrapper.initial_indent = \ + wrapper.subsequent_indent = ' ' * 4 + else: + if len(wrapped) > 0: + result += wrapped + '\n\n' + wrapper.initial_indent = wrapper.subsequent_indent = '' + return result.rstrip().lstrip('\n') + + +def extract(filename, node, prefix, output): + if not (node.location.file is None or + os.path.samefile(d(node.location.file.name), filename)): + return 0 + if node.kind in RECURSE_LIST: + sub_prefix = prefix + if node.kind not in PREFIX_BLACKLIST: + if len(sub_prefix) > 0: + sub_prefix += '_' + sub_prefix += d(node.spelling) + for i in node.get_children(): + extract(filename, i, sub_prefix, output) + if node.kind in PRINT_LIST: + comment = d(node.raw_comment) if node.raw_comment is not None else '' + comment = process_comment(comment) + sub_prefix = prefix + if len(sub_prefix) > 0: + sub_prefix += '_' + if len(node.spelling) > 0: + name = sanitize_name(sub_prefix + d(node.spelling)) + output.append((name, filename, comment)) + + +class ExtractionThread(Thread): + def __init__(self, filename, parameters, output): + Thread.__init__(self) + self.filename = filename + self.parameters = parameters + self.output = output + job_semaphore.acquire() + + def run(self): + print('Processing "%s" ..' % self.filename, file=sys.stderr) + try: + index = cindex.Index( + cindex.conf.lib.clang_createIndex(False, True)) + tu = index.parse(self.filename, self.parameters) + extract(self.filename, tu.cursor, '', self.output) + finally: + job_semaphore.release() + + +def read_args(args): + parameters = [] + filenames = [] + if "-x" not in args: + parameters.extend(['-x', 'c++']) + if not any(it.startswith("-std=") for it in args): + parameters.append('-std=c++11') + + if platform.system() == 'Darwin': + dev_path = '/Applications/Xcode.app/Contents/Developer/' + lib_dir = dev_path + 'Toolchains/XcodeDefault.xctoolchain/usr/lib/' + sdk_dir = dev_path + 'Platforms/MacOSX.platform/Developer/SDKs' + libclang = lib_dir + 'libclang.dylib' + + if os.path.exists(libclang): + cindex.Config.set_library_path(os.path.dirname(libclang)) + + if os.path.exists(sdk_dir): + sysroot_dir = os.path.join(sdk_dir, next(os.walk(sdk_dir))[1][0]) + parameters.append('-isysroot') + parameters.append(sysroot_dir) + elif platform.system() == 'Linux': + # clang doesn't find its own base includes by default on Linux, + # but different distros install them in different paths. + # Try to autodetect, preferring the highest numbered version. + def clang_folder_version(d): + return [int(ver) for ver in re.findall(r'(?:${PYBIND11_CPP_STANDARD}>) + endif() + + get_property(_iid TARGET ${PN}::pybind11 PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + get_property(_ill TARGET ${PN}::module PROPERTY INTERFACE_LINK_LIBRARIES) + set(${PN}_INCLUDE_DIRS ${_iid}) + set(${PN}_LIBRARIES ${_ico} ${_ill}) +endif() +endif() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/pybind11Tools.cmake b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/pybind11Tools.cmake new file mode 100644 index 0000000000000000000000000000000000000000..508e47429e3ef6c5f4419c2d1906ea0de706bbf1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/pybind11-2.5.0/tools/pybind11Tools.cmake @@ -0,0 +1,227 @@ +# tools/pybind11Tools.cmake -- Build system for the pybind11 modules +# +# Copyright (c) 2015 Wenzel Jakob +# +# All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +cmake_minimum_required(VERSION 2.8.12) + +# Add a CMake parameter for choosing a desired Python version +if(NOT PYBIND11_PYTHON_VERSION) + set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling modules") +endif() + +set(Python_ADDITIONAL_VERSIONS 3.9 3.8 3.7 3.6 3.5 3.4) +find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} REQUIRED) + +include(CheckCXXCompilerFlag) +include(CMakeParseArguments) + +if(NOT PYBIND11_CPP_STANDARD AND NOT CMAKE_CXX_STANDARD) + if(NOT MSVC) + check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG) + + if (HAS_CPP14_FLAG) + set(PYBIND11_CPP_STANDARD -std=c++14) + else() + check_cxx_compiler_flag("-std=c++11" HAS_CPP11_FLAG) + if (HAS_CPP11_FLAG) + set(PYBIND11_CPP_STANDARD -std=c++11) + else() + message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!") + endif() + endif() + elseif(MSVC) + set(PYBIND11_CPP_STANDARD /std:c++14) + endif() + + set(PYBIND11_CPP_STANDARD ${PYBIND11_CPP_STANDARD} CACHE STRING + "C++ standard flag, e.g. -std=c++11, -std=c++14, /std:c++14. Defaults to C++14 mode." FORCE) +endif() + +# Checks whether the given CXX/linker flags can compile and link a cxx file. cxxflags and +# linkerflags are lists of flags to use. The result variable is a unique variable name for each set +# of flags: the compilation result will be cached base on the result variable. If the flags work, +# sets them in cxxflags_out/linkerflags_out internal cache variables (in addition to ${result}). +function(_pybind11_return_if_cxx_and_linker_flags_work result cxxflags linkerflags cxxflags_out linkerflags_out) + set(CMAKE_REQUIRED_LIBRARIES ${linkerflags}) + check_cxx_compiler_flag("${cxxflags}" ${result}) + if (${result}) + set(${cxxflags_out} "${cxxflags}" CACHE INTERNAL "" FORCE) + set(${linkerflags_out} "${linkerflags}" CACHE INTERNAL "" FORCE) + endif() +endfunction() + +# Internal: find the appropriate link time optimization flags for this compiler +function(_pybind11_add_lto_flags target_name prefer_thin_lto) + if (NOT DEFINED PYBIND11_LTO_CXX_FLAGS) + set(PYBIND11_LTO_CXX_FLAGS "" CACHE INTERNAL "") + set(PYBIND11_LTO_LINKER_FLAGS "" CACHE INTERNAL "") + + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set(cxx_append "") + set(linker_append "") + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE) + # Clang Gold plugin does not support -Os; append -O3 to MinSizeRel builds to override it + set(linker_append ";$<$:-O3>") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + set(cxx_append ";-fno-fat-lto-objects") + endif() + + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND prefer_thin_lto) + _pybind11_return_if_cxx_and_linker_flags_work(HAS_FLTO_THIN + "-flto=thin${cxx_append}" "-flto=thin${linker_append}" + PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + endif() + + if (NOT HAS_FLTO_THIN) + _pybind11_return_if_cxx_and_linker_flags_work(HAS_FLTO + "-flto${cxx_append}" "-flto${linker_append}" + PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + endif() + elseif (CMAKE_CXX_COMPILER_ID MATCHES "Intel") + # Intel equivalent to LTO is called IPO + _pybind11_return_if_cxx_and_linker_flags_work(HAS_INTEL_IPO + "-ipo" "-ipo" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + elseif(MSVC) + # cmake only interprets libraries as linker flags when they start with a - (otherwise it + # converts /LTCG to \LTCG as if it was a Windows path). Luckily MSVC supports passing flags + # with - instead of /, even if it is a bit non-standard: + _pybind11_return_if_cxx_and_linker_flags_work(HAS_MSVC_GL_LTCG + "/GL" "-LTCG" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + endif() + + if (PYBIND11_LTO_CXX_FLAGS) + message(STATUS "LTO enabled") + else() + message(STATUS "LTO disabled (not supported by the compiler and/or linker)") + endif() + endif() + + # Enable LTO flags if found, except for Debug builds + if (PYBIND11_LTO_CXX_FLAGS) + target_compile_options(${target_name} PRIVATE "$<$>:${PYBIND11_LTO_CXX_FLAGS}>") + endif() + if (PYBIND11_LTO_LINKER_FLAGS) + target_link_libraries(${target_name} PRIVATE "$<$>:${PYBIND11_LTO_LINKER_FLAGS}>") + endif() +endfunction() + +# Build a Python extension module: +# pybind11_add_module( [MODULE | SHARED] [EXCLUDE_FROM_ALL] +# [NO_EXTRAS] [SYSTEM] [THIN_LTO] source1 [source2 ...]) +# +function(pybind11_add_module target_name) + set(options MODULE SHARED EXCLUDE_FROM_ALL NO_EXTRAS SYSTEM THIN_LTO) + cmake_parse_arguments(ARG "${options}" "" "" ${ARGN}) + + if(ARG_MODULE AND ARG_SHARED) + message(FATAL_ERROR "Can't be both MODULE and SHARED") + elseif(ARG_SHARED) + set(lib_type SHARED) + else() + set(lib_type MODULE) + endif() + + if(ARG_EXCLUDE_FROM_ALL) + set(exclude_from_all EXCLUDE_FROM_ALL) + endif() + + add_library(${target_name} ${lib_type} ${exclude_from_all} ${ARG_UNPARSED_ARGUMENTS}) + + if(ARG_SYSTEM) + set(inc_isystem SYSTEM) + endif() + + target_include_directories(${target_name} ${inc_isystem} + PRIVATE ${PYBIND11_INCLUDE_DIR} # from project CMakeLists.txt + PRIVATE ${pybind11_INCLUDE_DIR} # from pybind11Config + PRIVATE ${PYTHON_INCLUDE_DIRS}) + + # Python debug libraries expose slightly different objects + # https://docs.python.org/3.6/c-api/intro.html#debugging-builds + # https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib + if(PYTHON_IS_DEBUG) + target_compile_definitions(${target_name} PRIVATE Py_DEBUG) + endif() + + # The prefix and extension are provided by FindPythonLibsNew.cmake + set_target_properties(${target_name} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}") + set_target_properties(${target_name} PROPERTIES SUFFIX "${PYTHON_MODULE_EXTENSION}") + + # -fvisibility=hidden is required to allow multiple modules compiled against + # different pybind versions to work properly, and for some features (e.g. + # py::module_local). We force it on everything inside the `pybind11` + # namespace; also turning it on for a pybind module compilation here avoids + # potential warnings or issues from having mixed hidden/non-hidden types. + set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden") + set_target_properties(${target_name} PROPERTIES CUDA_VISIBILITY_PRESET "hidden") + + if(WIN32 OR CYGWIN) + # Link against the Python shared library on Windows + target_link_libraries(${target_name} PRIVATE ${PYTHON_LIBRARIES}) + elseif(APPLE) + # It's quite common to have multiple copies of the same Python version + # installed on one's system. E.g.: one copy from the OS and another copy + # that's statically linked into an application like Blender or Maya. + # If we link our plugin library against the OS Python here and import it + # into Blender or Maya later on, this will cause segfaults when multiple + # conflicting Python instances are active at the same time (even when they + # are of the same version). + + # Windows is not affected by this issue since it handles DLL imports + # differently. The solution for Linux and Mac OS is simple: we just don't + # link against the Python library. The resulting shared library will have + # missing symbols, but that's perfectly fine -- they will be resolved at + # import time. + + target_link_libraries(${target_name} PRIVATE "-undefined dynamic_lookup") + + if(ARG_SHARED) + # Suppress CMake >= 3.0 warning for shared libraries + set_target_properties(${target_name} PROPERTIES MACOSX_RPATH ON) + endif() + endif() + + # Make sure C++11/14 are enabled + if(CMAKE_VERSION VERSION_LESS 3.3) + target_compile_options(${target_name} PUBLIC ${PYBIND11_CPP_STANDARD}) + else() + target_compile_options(${target_name} PUBLIC $<$:${PYBIND11_CPP_STANDARD}>) + endif() + + if(ARG_NO_EXTRAS) + return() + endif() + + _pybind11_add_lto_flags(${target_name} ${ARG_THIN_LTO}) + + if (NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo) + # Strip unnecessary sections of the binary on Linux/Mac OS + if(CMAKE_STRIP) + if(APPLE) + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_STRIP} -x $) + else() + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_STRIP} $) + endif() + endif() + endif() + + if(MSVC) + # /MP enables multithreaded builds (relevant when there are many files), /bigobj is + # needed for bigger binding projects due to the limit to 64k addressable sections + target_compile_options(${target_name} PRIVATE /bigobj) + if(CMAKE_VERSION VERSION_LESS 3.11) + target_compile_options(${target_name} PRIVATE $<$>:/MP>) + else() + # Only set these options for C++ files. This is important so that, for + # instance, projects that include other types of source files like CUDA + # .cu files don't get these options propagated to nvcc since that would + # cause the build to fail. + target_compile_options(${target_name} PRIVATE $<$>:$<$:/MP>>) + endif() + endif() +endfunction() diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/allocators.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/allocators.h new file mode 100644 index 0000000000000000000000000000000000000000..98affe03fbfaf78c8985110e089cf2a9abbc74b4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/allocators.h @@ -0,0 +1,271 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ALLOCATORS_H_ +#define RAPIDJSON_ALLOCATORS_H_ + +#include "rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Allocator + +/*! \class rapidjson::Allocator + \brief Concept for allocating, resizing and freeing memory block. + + Note that Malloc() and Realloc() are non-static but Free() is static. + + So if an allocator need to support Free(), it needs to put its pointer in + the header of memory block. + +\code +concept Allocator { + static const bool kNeedFree; //!< Whether this allocator needs to call Free(). + + // Allocate a memory block. + // \param size of the memory block in bytes. + // \returns pointer to the memory block. + void* Malloc(size_t size); + + // Resize a memory block. + // \param originalPtr The pointer to current memory block. Null pointer is permitted. + // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) + // \param newSize the new size in bytes. + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); + + // Free a memory block. + // \param pointer to the memory block. Null pointer is permitted. + static void Free(void *ptr); +}; +\endcode +*/ + +/////////////////////////////////////////////////////////////////////////////// +// CrtAllocator + +//! C-runtime library allocator. +/*! This class is just wrapper for standard C library memory routines. + \note implements Allocator concept +*/ +class CrtAllocator { +public: + static const bool kNeedFree = true; + void* Malloc(size_t size) { + if (size) // behavior of malloc(0) is implementation defined. + return std::malloc(size); + else + return NULL; // standardize to returning NULL. + } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + (void)originalSize; + if (newSize == 0) { + std::free(originalPtr); + return NULL; + } + return std::realloc(originalPtr, newSize); + } + static void Free(void *ptr) { std::free(ptr); } +}; + +/////////////////////////////////////////////////////////////////////////////// +// MemoryPoolAllocator + +//! Default memory allocator used by the parser and DOM. +/*! This allocator allocate memory blocks from pre-allocated memory chunks. + + It does not free memory blocks. And Realloc() only allocate new memory. + + The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. + + User may also supply a buffer as the first chunk. + + If the user-buffer is full then additional chunks are allocated by BaseAllocator. + + The user-buffer is not deallocated by this allocator. + + \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. + \note implements Allocator concept +*/ +template +class MemoryPoolAllocator { +public: + static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) + + //! Constructor with chunkSize. + /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + } + + //! Constructor with user-supplied buffer. + /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. + + The user buffer will not be deallocated when this allocator is destructed. + + \param buffer User supplied buffer. + \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). + \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + RAPIDJSON_ASSERT(buffer != 0); + RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); + chunkHead_ = reinterpret_cast(buffer); + chunkHead_->capacity = size - sizeof(ChunkHeader); + chunkHead_->size = 0; + chunkHead_->next = 0; + } + + //! Destructor. + /*! This deallocates all memory chunks, excluding the user-supplied buffer. + */ + ~MemoryPoolAllocator() { + Clear(); + RAPIDJSON_DELETE(ownBaseAllocator_); + } + + //! Deallocates all memory chunks, excluding the user-supplied buffer. + void Clear() { + while (chunkHead_ && chunkHead_ != userBuffer_) { + ChunkHeader* next = chunkHead_->next; + baseAllocator_->Free(chunkHead_); + chunkHead_ = next; + } + if (chunkHead_ && chunkHead_ == userBuffer_) + chunkHead_->size = 0; // Clear user buffer + } + + //! Computes the total capacity of allocated memory chunks. + /*! \return total capacity in bytes. + */ + size_t Capacity() const { + size_t capacity = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + capacity += c->capacity; + return capacity; + } + + //! Computes the memory blocks allocated. + /*! \return total used bytes. + */ + size_t Size() const { + size_t size = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + size += c->size; + return size; + } + + //! Allocates a memory block. (concept Allocator) + void* Malloc(size_t size) { + if (!size) + return NULL; + + size = RAPIDJSON_ALIGN(size); + if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) + if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) + return NULL; + + void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; + chunkHead_->size += size; + return buffer; + } + + //! Resizes a memory block (concept Allocator) + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + if (originalPtr == 0) + return Malloc(newSize); + + if (newSize == 0) + return NULL; + + originalSize = RAPIDJSON_ALIGN(originalSize); + newSize = RAPIDJSON_ALIGN(newSize); + + // Do not shrink if new size is smaller than original + if (originalSize >= newSize) + return originalPtr; + + // Simply expand it if it is the last allocation and there is sufficient space + if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { + size_t increment = static_cast(newSize - originalSize); + if (chunkHead_->size + increment <= chunkHead_->capacity) { + chunkHead_->size += increment; + return originalPtr; + } + } + + // Realloc process: allocate and copy memory, do not free original buffer. + if (void* newBuffer = Malloc(newSize)) { + if (originalSize) + std::memcpy(newBuffer, originalPtr, originalSize); + return newBuffer; + } + else + return NULL; + } + + //! Frees a memory block (concept Allocator) + static void Free(void *ptr) { (void)ptr; } // Do nothing + +private: + //! Copy constructor is not permitted. + MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; + //! Copy assignment operator is not permitted. + MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; + + //! Creates a new chunk. + /*! \param capacity Capacity of the chunk in bytes. + \return true if success. + */ + bool AddChunk(size_t capacity) { + if (!baseAllocator_) + ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); + if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { + chunk->capacity = capacity; + chunk->size = 0; + chunk->next = chunkHead_; + chunkHead_ = chunk; + return true; + } + else + return false; + } + + static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. + + //! Chunk header for perpending to each chunk. + /*! Chunks are stored as a singly linked list. + */ + struct ChunkHeader { + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). + size_t size; //!< Current size of allocated memory in bytes. + ChunkHeader *next; //!< Next chunk in the linked list. + }; + + ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. + void *userBuffer_; //!< User supplied buffer. + BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. + BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/document.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/document.h new file mode 100644 index 0000000000000000000000000000000000000000..e3e20dfbdc99208b267f3c89d9abae3fcc62126f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/document.h @@ -0,0 +1,2575 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_DOCUMENT_H_ +#define RAPIDJSON_DOCUMENT_H_ + +/*! \file document.h */ + +#include "reader.h" +#include "internal/meta.h" +#include "internal/strfunc.h" +#include "memorystream.h" +#include "encodedstream.h" +#include // placement new +#include + +RAPIDJSON_DIAG_PUSH +#ifdef _MSC_VER +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_OFF(effc++) +#if __GNUC__ >= 6 +RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions +#endif +#endif // __GNUC__ + +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS +#include // std::iterator, std::random_access_iterator_tag +#endif + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +// Forward declaration. +template +class GenericValue; + +template +class GenericDocument; + +//! Name-value pair in a JSON object value. +/*! + This class was internal to GenericValue. It used to be a inner struct. + But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. + https://code.google.com/p/rapidjson/issues/detail?id=64 +*/ +template +struct GenericMember { + GenericValue name; //!< name of member (must be a string) + GenericValue value; //!< value of member. +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericMemberIterator + +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS + +//! (Constant) member iterator for a JSON object value +/*! + \tparam Const Is this a constant iterator? + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. + + This class implements a Random Access Iterator for GenericMember elements + of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. + + \note This iterator implementation is mainly intended to avoid implicit + conversions from iterator values to \c NULL, + e.g. from GenericValue::FindMember. + + \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a + pointer-based implementation, if your platform doesn't provide + the C++ header. + + \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator + */ +template +class GenericMemberIterator + : public std::iterator >::Type> { + + friend class GenericValue; + template friend class GenericMemberIterator; + + typedef GenericMember PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef std::iterator BaseType; + +public: + //! Iterator type itself + typedef GenericMemberIterator Iterator; + //! Constant iterator type + typedef GenericMemberIterator ConstIterator; + //! Non-constant iterator type + typedef GenericMemberIterator NonConstIterator; + + //! Pointer to (const) GenericMember + typedef typename BaseType::pointer Pointer; + //! Reference to (const) GenericMember + typedef typename BaseType::reference Reference; + //! Signed integer type (e.g. \c ptrdiff_t) + typedef typename BaseType::difference_type DifferenceType; + + //! Default constructor (singular value) + /*! Creates an iterator pointing to no element. + \note All operations, except for comparisons, are undefined on such values. + */ + GenericMemberIterator() : ptr_() {} + + //! Iterator conversions to more const + /*! + \param it (Non-const) iterator to copy from + + Allows the creation of an iterator from another GenericMemberIterator + that is "less const". Especially, creating a non-constant iterator + from a constant iterator are disabled: + \li const -> non-const (not ok) + \li const -> const (ok) + \li non-const -> const (ok) + \li non-const -> non-const (ok) + + \note If the \c Const template parameter is already \c false, this + constructor effectively defines a regular copy-constructor. + Otherwise, the copy constructor is implicitly defined. + */ + GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} + Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } + + //! @name stepping + //@{ + Iterator& operator++(){ ++ptr_; return *this; } + Iterator& operator--(){ --ptr_; return *this; } + Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } + Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } + //@} + + //! @name increment/decrement + //@{ + Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } + Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } + + Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } + Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } + //@} + + //! @name relations + //@{ + bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; } + bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; } + bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; } + bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; } + bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; } + bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; } + //@} + + //! @name dereference + //@{ + Reference operator*() const { return *ptr_; } + Pointer operator->() const { return ptr_; } + Reference operator[](DifferenceType n) const { return ptr_[n]; } + //@} + + //! Distance + DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } + +private: + //! Internal constructor from plain pointer + explicit GenericMemberIterator(Pointer p) : ptr_(p) {} + + Pointer ptr_; //!< raw pointer +}; + +#else // RAPIDJSON_NOMEMBERITERATORCLASS + +// class-based member iterator implementation disabled, use plain pointers + +template +struct GenericMemberIterator; + +//! non-const GenericMemberIterator +template +struct GenericMemberIterator { + //! use plain pointer as iterator type + typedef GenericMember* Iterator; +}; +//! const GenericMemberIterator +template +struct GenericMemberIterator { + //! use plain const pointer as iterator type + typedef const GenericMember* Iterator; +}; + +#endif // RAPIDJSON_NOMEMBERITERATORCLASS + +/////////////////////////////////////////////////////////////////////////////// +// GenericStringRef + +//! Reference to a constant string (not taking a copy) +/*! + \tparam CharType character type of the string + + This helper class is used to automatically infer constant string + references for string literals, especially from \c const \b (!) + character arrays. + + The main use is for creating JSON string values without copying the + source string via an \ref Allocator. This requires that the referenced + string pointers have a sufficient lifetime, which exceeds the lifetime + of the associated GenericValue. + + \b Example + \code + Value v("foo"); // ok, no need to copy & calculate length + const char foo[] = "foo"; + v.SetString(foo); // ok + + const char* bar = foo; + // Value x(bar); // not ok, can't rely on bar's lifetime + Value x(StringRef(bar)); // lifetime explicitly guaranteed by user + Value y(StringRef(bar, 3)); // ok, explicitly pass length + \endcode + + \see StringRef, GenericValue::SetString +*/ +template +struct GenericStringRef { + typedef CharType Ch; //!< character type of the string + + //! Create string reference from \c const character array +#ifndef __clang__ // -Wdocumentation + /*! + This constructor implicitly creates a constant string reference from + a \c const character array. It has better performance than + \ref StringRef(const CharType*) by inferring the string \ref length + from the array length, and also supports strings containing null + characters. + + \tparam N length of the string, automatically inferred + + \param str Constant character array, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue + + \post \ref s == str + + \note Constant complexity. + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ +#endif + template + GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT + : s(str), length(N-1) {} + + //! Explicitly create string reference from \c const character pointer +#ifndef __clang__ // -Wdocumentation + /*! + This constructor can be used to \b explicitly create a reference to + a constant string pointer. + + \see StringRef(const CharType*) + + \param str Constant character pointer, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue + + \post \ref s == str + + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ +#endif + explicit GenericStringRef(const CharType* str) + : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); } + + //! Create constant string reference from pointer and length +#ifndef __clang__ // -Wdocumentation + /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \param len length of the string, excluding the trailing NULL terminator + + \post \ref s == str && \ref length == len + \note Constant complexity. + */ +#endif + GenericStringRef(const CharType* str, SizeType len) + : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); } + + GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} + + GenericStringRef& operator=(const GenericStringRef& rhs) { s = rhs.s; length = rhs.length; } + + //! implicit conversion to plain CharType pointer + operator const Ch *() const { return s; } + + const Ch* const s; //!< plain CharType pointer + const SizeType length; //!< length of the string (excluding the trailing NULL terminator) + +private: + //! Disallow construction from non-const array + template + GenericStringRef(CharType (&str)[N]) /* = delete */; +}; + +//! Mark a character pointer as constant string +/*! Mark a plain character pointer as a "string literal". This function + can be used to avoid copying a character string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + \tparam CharType Character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \return GenericStringRef string reference object + \relatesalso GenericStringRef + + \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember +*/ +template +inline GenericStringRef StringRef(const CharType* str) { + return GenericStringRef(str, internal::StrLen(str)); +} + +//! Mark a character pointer as constant string +/*! Mark a plain character pointer as a "string literal". This function + can be used to avoid copying a character string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + + This version has better performance with supplied length, and also + supports string containing null characters. + + \tparam CharType character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \param length The length of source string. + \return GenericStringRef string reference object + \relatesalso GenericStringRef +*/ +template +inline GenericStringRef StringRef(const CharType* str, size_t length) { + return GenericStringRef(str, SizeType(length)); +} + +#if RAPIDJSON_HAS_STDSTRING +//! Mark a string object as constant string +/*! Mark a string object (e.g. \c std::string) as a "string literal". + This function can be used to avoid copying a string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + + \tparam CharType character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \return GenericStringRef string reference object + \relatesalso GenericStringRef + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. +*/ +template +inline GenericStringRef StringRef(const std::basic_string& str) { + return GenericStringRef(str.data(), SizeType(str.size())); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// GenericValue type traits +namespace internal { + +template +struct IsGenericValueImpl : FalseType {}; + +// select candidates according to nested encoding and allocator types +template struct IsGenericValueImpl::Type, typename Void::Type> + : IsBaseOf, T>::Type {}; + +// helper to match arbitrary GenericValue instantiations, including derived classes +template struct IsGenericValue : IsGenericValueImpl::Type {}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// TypeHelper + +namespace internal { + +template +struct TypeHelper {}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsBool(); } + static bool Get(const ValueType& v) { return v.GetBool(); } + static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } + static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt(); } + static int Get(const ValueType& v) { return v.GetInt(); } + static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } + static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint(); } + static unsigned Get(const ValueType& v) { return v.GetUint(); } + static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } + static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt64(); } + static int64_t Get(const ValueType& v) { return v.GetInt64(); } + static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } + static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint64(); } + static uint64_t Get(const ValueType& v) { return v.GetUint64(); } + static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } + static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsDouble(); } + static double Get(const ValueType& v) { return v.GetDouble(); } + static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } + static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsFloat(); } + static float Get(const ValueType& v) { return v.GetFloat(); } + static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } + static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } +}; + +template +struct TypeHelper { + typedef const typename ValueType::Ch* StringType; + static bool Is(const ValueType& v) { return v.IsString(); } + static StringType Get(const ValueType& v) { return v.GetString(); } + static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } + static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } +}; + +#if RAPIDJSON_HAS_STDSTRING +template +struct TypeHelper > { + typedef std::basic_string StringType; + static bool Is(const ValueType& v) { return v.IsString(); } + static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } + static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } +}; +#endif + +template +struct TypeHelper { + typedef typename ValueType::Array ArrayType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArrayType Get(ValueType& v) { return v.GetArray(); } + static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } + static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } +}; + +template +struct TypeHelper { + typedef typename ValueType::ConstArray ArrayType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArrayType Get(const ValueType& v) { return v.GetArray(); } +}; + +template +struct TypeHelper { + typedef typename ValueType::Object ObjectType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ObjectType Get(ValueType& v) { return v.GetObject(); } + static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } + static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; } +}; + +template +struct TypeHelper { + typedef typename ValueType::ConstObject ObjectType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ObjectType Get(const ValueType& v) { return v.GetObject(); } +}; + +} // namespace internal + +// Forward declarations +template class GenericArray; +template class GenericObject; + +/////////////////////////////////////////////////////////////////////////////// +// GenericValue + +//! Represents a JSON value. Use Value for UTF8 encoding and default allocator. +/*! + A JSON value can be one of 7 types. This class is a variant type supporting + these types. + + Use the Value if UTF8 and default allocator + + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. +*/ +template > +class GenericValue { +public: + //! Name-value pair in an object. + typedef GenericMember Member; + typedef Encoding EncodingType; //!< Encoding type from template parameter. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericStringRef StringRefType; //!< Reference to a constant string + typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. + typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. + typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. + typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. + typedef GenericValue ValueType; //!< Value type of itself. + typedef GenericArray Array; + typedef GenericArray ConstArray; + typedef GenericObject Object; + typedef GenericObject ConstObject; + + //!@name Constructors and destructor. + //@{ + + //! Default constructor creates a null value. + GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { + rhs.data_.f.flags = kNullFlag; // give up contents + } +#endif + +private: + //! Copy constructor is not permitted. + GenericValue(const GenericValue& rhs); + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Moving from a GenericDocument is not permitted. + template + GenericValue(GenericDocument&& rhs); + + //! Move assignment from a GenericDocument is not permitted. + template + GenericValue& operator=(GenericDocument&& rhs); +#endif + +public: + + //! Constructor with JSON value type. + /*! This creates a Value of specified type with default content. + \param type Type of the value. + \note Default content for number is zero. + */ + explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { + static const uint16_t defaultFlags[7] = { + kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, + kNumberAnyFlag + }; + RAPIDJSON_ASSERT(type <= kNumberType); + data_.f.flags = defaultFlags[type]; + + // Use ShortString to store empty string. + if (type == kStringType) + data_.ss.SetLength(0); + } + + //! Explicit copy constructor (with allocator) + /*! Creates a copy of a Value by using the given Allocator + \tparam SourceAllocator allocator of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). + \see CopyFrom() + */ + template< typename SourceAllocator > + GenericValue(const GenericValue& rhs, Allocator & allocator); + + //! Constructor for boolean value. + /*! \param b Boolean value + \note This constructor is limited to \em real boolean values and rejects + implicitly converted types like arbitrary pointers. Use an explicit cast + to \c bool, if you want to construct a boolean JSON value in such cases. + */ +#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen + template + explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT // See #472 +#else + explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT +#endif + : data_() { + // safe-guard against failing SFINAE + RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); + data_.f.flags = b ? kTrueFlag : kFalseFlag; + } + + //! Constructor for int value. + explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() { + data_.n.i64 = i; + data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; + } + + //! Constructor for unsigned value. + explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() { + data_.n.u64 = u; + data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); + } + + //! Constructor for int64_t value. + explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() { + data_.n.i64 = i64; + data_.f.flags = kNumberInt64Flag; + if (i64 >= 0) { + data_.f.flags |= kNumberUint64Flag; + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + data_.f.flags |= kUintFlag; + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } + else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } + + //! Constructor for uint64_t value. + explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { + data_.n.u64 = u64; + data_.f.flags = kNumberUint64Flag; + if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) + data_.f.flags |= kInt64Flag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + data_.f.flags |= kUintFlag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } + + //! Constructor for double value. + explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } + + //! Constructor for constant string (i.e. do not make a copy of string) + GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } + + //! Constructor for constant string (i.e. do not make a copy of string) + explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } + +#if RAPIDJSON_HAS_STDSTRING + //! Constructor for copy-string from a string object (i.e. do make a copy of string) + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } +#endif + + //! Constructor for Array. + /*! + \param a An array obtained by \c GetArray(). + \note \c Array is always pass-by-value. + \note the source array is moved into this value and the sourec array becomes empty. + */ + GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { + a.value_.data_ = Data(); + a.value_.data_.f.flags = kArrayFlag; + } + + //! Constructor for Object. + /*! + \param o An object obtained by \c GetObject(). + \note \c Object is always pass-by-value. + \note the source object is moved into this value and the sourec object becomes empty. + */ + GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { + o.value_.data_ = Data(); + o.value_.data_.f.flags = kObjectFlag; + } + + //! Destructor. + /*! Need to destruct elements of array, members of object, or copy-string. + */ + ~GenericValue() { + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + switch(data_.f.flags) { + case kArrayFlag: + { + GenericValue* e = GetElementsPointer(); + for (GenericValue* v = e; v != e + data_.a.size; ++v) + v->~GenericValue(); + Allocator::Free(e); + } + break; + + case kObjectFlag: + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + Allocator::Free(GetMembersPointer()); + break; + + case kCopyStringFlag: + Allocator::Free(const_cast(GetStringPointer())); + break; + + default: + break; // Do nothing for other types. + } + } + } + + //@} + + //!@name Assignment operators + //@{ + + //! Assignment with move semantics. + /*! \param rhs Source of the assignment. It will become a null value after assignment. + */ + GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { + RAPIDJSON_ASSERT(this != &rhs); + this->~GenericValue(); + RawAssign(rhs); + return *this; + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move assignment in C++11 + GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { + return *this = rhs.Move(); + } +#endif + + //! Assignment of constant string reference (no copy) + /*! \param str Constant string reference to be assigned + \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. + \see GenericStringRef, operator=(T) + */ + GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { + GenericValue s(str); + return *this = s; + } + + //! Assignment with primitive types. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value The value to be assigned. + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref SetString(const Ch*, Allocator&) (for copying) or + \ref StringRef() (to explicitly mark the pointer as constant) instead. + All other pointer types would implicitly convert to \c bool, + use \ref SetBool() instead. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) + operator=(T value) { + GenericValue v(value); + return *this = v; + } + + //! Deep-copy assignment from Value + /*! Assigns a \b copy of the Value to the current Value object + \tparam SourceAllocator Allocator type of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator to use for copying + */ + template + GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { + RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); + this->~GenericValue(); + new (this) GenericValue(rhs, allocator); + return *this; + } + + //! Exchange the contents of this value with those of other. + /*! + \param other Another value. + \note Constant complexity. + */ + GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { + GenericValue temp; + temp.RawAssign(*this); + RawAssign(other); + other.RawAssign(temp); + return *this; + } + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.value, b.value); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + + //! Prepare Value for move semantics + /*! \return *this */ + GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } + //@} + + //!@name Equal-to and not-equal-to operators + //@{ + //! Equal-to operator + /*! + \note If an object contains duplicated named member, comparing equality with any object is always \c false. + \note Linear time complexity (number of all values in the subtree and total lengths of all strings). + */ + template + bool operator==(const GenericValue& rhs) const { + typedef GenericValue RhsType; + if (GetType() != rhs.GetType()) + return false; + + switch (GetType()) { + case kObjectType: // Warning: O(n^2) inner-loop + if (data_.o.size != rhs.data_.o.size) + return false; + for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { + typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); + if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) + return false; + } + return true; + + case kArrayType: + if (data_.a.size != rhs.data_.a.size) + return false; + for (SizeType i = 0; i < data_.a.size; i++) + if ((*this)[i] != rhs[i]) + return false; + return true; + + case kStringType: + return StringEqual(rhs); + + case kNumberType: + if (IsDouble() || rhs.IsDouble()) { + double a = GetDouble(); // May convert from integer to double. + double b = rhs.GetDouble(); // Ditto + return a >= b && a <= b; // Prevent -Wfloat-equal + } + else + return data_.n.u64 == rhs.data_.n.u64; + + default: + return true; + } + } + + //! Equal-to operator with const C-string pointer + bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } + +#if RAPIDJSON_HAS_STDSTRING + //! Equal-to operator with string object + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } +#endif + + //! Equal-to operator with primitive types + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false + */ + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } + + //! Not-equal-to operator + /*! \return !(*this == rhs) + */ + template + bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } + + //! Not-equal-to operator with const C-string pointer + bool operator!=(const Ch* rhs) const { return !(*this == rhs); } + + //! Not-equal-to operator with arbitrary types + /*! \return !(*this == rhs) + */ + template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } + + //! Equal-to operator with arbitrary types (symmetric version) + /*! \return (rhs == lhs) + */ + template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } + + //! Not-Equal-to operator with arbitrary types (symmetric version) + /*! \return !(rhs == lhs) + */ + template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } + //@} + + //!@name Type + //@{ + + Type GetType() const { return static_cast(data_.f.flags & kTypeMask); } + bool IsNull() const { return data_.f.flags == kNullFlag; } + bool IsFalse() const { return data_.f.flags == kFalseFlag; } + bool IsTrue() const { return data_.f.flags == kTrueFlag; } + bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } + bool IsObject() const { return data_.f.flags == kObjectFlag; } + bool IsArray() const { return data_.f.flags == kArrayFlag; } + bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } + bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } + bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } + bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } + bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } + bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } + bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } + + // Checks whether a number can be losslessly converted to a double. + bool IsLosslessDouble() const { + if (!IsNumber()) return false; + if (IsUint64()) { + uint64_t u = GetUint64(); + volatile double d = static_cast(u); + return (d >= 0.0) + && (d < static_cast(std::numeric_limits::max())) + && (u == static_cast(d)); + } + if (IsInt64()) { + int64_t i = GetInt64(); + volatile double d = static_cast(i); + return (d >= static_cast(std::numeric_limits::min())) + && (d < static_cast(std::numeric_limits::max())) + && (i == static_cast(d)); + } + return true; // double, int, uint are always lossless + } + + // Checks whether a number is a float (possible lossy). + bool IsFloat() const { + if ((data_.f.flags & kDoubleFlag) == 0) + return false; + double d = GetDouble(); + return d >= -3.4028234e38 && d <= 3.4028234e38; + } + // Checks whether a number can be losslessly converted to a float. + bool IsLosslessFloat() const { + if (!IsNumber()) return false; + double a = GetDouble(); + if (a < static_cast(-std::numeric_limits::max()) + || a > static_cast(std::numeric_limits::max())) + return false; + double b = static_cast(static_cast(a)); + return a >= b && a <= b; // Prevent -Wfloat-equal + } + + //@} + + //!@name Null + //@{ + + GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } + + //@} + + //!@name Bool + //@{ + + bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } + //!< Set boolean value + /*! \post IsBool() == true */ + GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } + + //@} + + //!@name Object + //@{ + + //! Set this value as an empty object. + /*! \post IsObject() == true */ + GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } + + //! Get the number of members in the object. + SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } + + //! Check whether the object is empty. + bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } + + //! Get a value from an object associated with the name. + /*! \pre IsObject() == true + \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) + \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. + Since 0.2, if the name is not correct, it will assert. + If user is unsure whether a member exists, user should use HasMember() first. + A better approach is to use FindMember(). + \note Linear time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { + GenericValue n(StringRef(name)); + return (*this)[n]; + } + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } + + //! Get a value from an object associated with the name. + /*! \pre IsObject() == true + \tparam SourceAllocator Allocator of the \c name value + + \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). + And it can also handle strings with embedded null characters. + + \note Linear time complexity. + */ + template + GenericValue& operator[](const GenericValue& name) { + MemberIterator member = FindMember(name); + if (member != MemberEnd()) + return member->value; + else { + RAPIDJSON_ASSERT(false); // see above note + + // This will generate -Wexit-time-destructors in clang + // static GenericValue NullValue; + // return NullValue; + + // Use static buffer and placement-new to prevent destruction + static char buffer[sizeof(GenericValue)]; + return *new (buffer) GenericValue(); + } + } + template + const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } + +#if RAPIDJSON_HAS_STDSTRING + //! Get a value from an object associated with name (string object). + GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } + const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } +#endif + + //! Const member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } + //! Const \em past-the-end member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } + //! Member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } + //! \em Past-the-end member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } + + //! Check whether a member exists in the object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } + +#if RAPIDJSON_HAS_STDSTRING + //! Check whether a member exists in the object with string object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } +#endif + + //! Check whether a member exists in the object with GenericValue name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + template + bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } + + //! Find member by name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + MemberIterator FindMember(const Ch* name) { + GenericValue n(StringRef(name)); + return FindMember(n); + } + + ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } + + //! Find member by name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + template + MemberIterator FindMember(const GenericValue& name) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + MemberIterator member = MemberBegin(); + for ( ; member != MemberEnd(); ++member) + if (name.StringEqual(member->name)) + break; + return member; + } + template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } + +#if RAPIDJSON_HAS_STDSTRING + //! Find member by string object name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + */ + MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); } + ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); } +#endif + + //! Add a member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c name and \c value will be transferred to this object on success. + \pre IsObject() && name.IsString() + \post name.IsNull() && value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + + ObjectData& o = data_.o; + if (o.size >= o.capacity) { + if (o.capacity == 0) { + o.capacity = kDefaultObjectCapacity; + SetMembersPointer(reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member)))); + } + else { + SizeType oldCapacity = o.capacity; + o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 + SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member)))); + } + } + Member* members = GetMembersPointer(); + members[o.size].name.RawAssign(name); + members[o.size].value.RawAssign(value); + o.size++; + return *this; + } + + //! Add a constant string value as member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Add a string object as member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { + GenericValue v(value, allocator); + return AddMember(name, v, allocator); + } +#endif + + //! Add any primitive value as member (name-value pair) to the object. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param name A string value as name of member. + \param value Value of primitive type \c T as value of member + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref + AddMember(StringRefType, StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized Constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + AddMember(GenericValue& name, T value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + + + //! Add a member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this object on success. + \pre IsObject() + \post value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } + + //! Add a constant string value as member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + + //! Add any primitive value as member (name-value pair) to the object. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param name A constant string reference as name of member. + \param value Value of primitive type \c T as value of member + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref + AddMember(StringRefType, StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized Constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + AddMember(StringRefType name, T value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } + + //! Remove all members in the object. + /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. + \note Linear time complexity. + */ + void RemoveAllMembers() { + RAPIDJSON_ASSERT(IsObject()); + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + data_.o.size = 0; + } + + //! Remove a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note This function may reorder the object members. Use \ref + EraseMember(ConstMemberIterator) if you need to preserve the + relative order of the remaining members. + \note Linear time complexity. + */ + bool RemoveMember(const Ch* name) { + GenericValue n(StringRef(name)); + return RemoveMember(n); + } + +#if RAPIDJSON_HAS_STDSTRING + bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } +#endif + + template + bool RemoveMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + RemoveMember(m); + return true; + } + else + return false; + } + + //! Remove a member in object by iterator. + /*! \param m member iterator (obtained by FindMember() or MemberBegin()). + \return the new iterator after removal. + \note This function may reorder the object members. Use \ref + EraseMember(ConstMemberIterator) if you need to preserve the + relative order of the remaining members. + \note Constant time complexity. + */ + MemberIterator RemoveMember(MemberIterator m) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(GetMembersPointer() != 0); + RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); + + MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); + if (data_.o.size > 1 && m != last) + *m = *last; // Move the last one to this place + else + m->~Member(); // Only one left, just destroy + --data_.o.size; + return m; + } + + //! Remove a member from an object by iterator. + /*! \param pos iterator to the member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() + \return Iterator following the removed element. + If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. + \note This function preserves the relative order of the remaining object + members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator pos) { + return EraseMember(pos, pos +1); + } + + //! Remove members in the range [first, last) from an object. + /*! \param first iterator to the first member to remove + \param last iterator following the last member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() + \return Iterator following the last removed element. + \note This function preserves the relative order of the remaining object + members. + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(GetMembersPointer() != 0); + RAPIDJSON_ASSERT(first >= MemberBegin()); + RAPIDJSON_ASSERT(first <= last); + RAPIDJSON_ASSERT(last <= MemberEnd()); + + MemberIterator pos = MemberBegin() + (first - MemberBegin()); + for (MemberIterator itr = pos; itr != last; ++itr) + itr->~Member(); + std::memmove(&*pos, &*last, static_cast(MemberEnd() - last) * sizeof(Member)); + data_.o.size -= static_cast(last - first); + return pos; + } + + //! Erase a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note Linear time complexity. + */ + bool EraseMember(const Ch* name) { + GenericValue n(StringRef(name)); + return EraseMember(n); + } + +#if RAPIDJSON_HAS_STDSTRING + bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } +#endif + + template + bool EraseMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + EraseMember(m); + return true; + } + else + return false; + } + + Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } + ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } + + //@} + + //!@name Array + //@{ + + //! Set this value as an empty array. + /*! \post IsArray == true */ + GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } + + //! Get the number of elements in array. + SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } + + //! Get the capacity of array. + SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } + + //! Check whether the array is empty. + bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } + + //! Remove all elements in the array. + /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. + \note Linear time complexity. + */ + void Clear() { + RAPIDJSON_ASSERT(IsArray()); + GenericValue* e = GetElementsPointer(); + for (GenericValue* v = e; v != e + data_.a.size; ++v) + v->~GenericValue(); + data_.a.size = 0; + } + + //! Get an element from array by index. + /*! \pre IsArray() == true + \param index Zero-based index of element. + \see operator[](T*) + */ + GenericValue& operator[](SizeType index) { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(index < data_.a.size); + return GetElementsPointer()[index]; + } + const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } + + //! Element iterator + /*! \pre IsArray() == true */ + ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } + //! \em Past-the-end element iterator + /*! \pre IsArray() == true */ + ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } + //! Constant element iterator + /*! \pre IsArray() == true */ + ConstValueIterator Begin() const { return const_cast(*this).Begin(); } + //! Constant \em past-the-end element iterator + /*! \pre IsArray() == true */ + ConstValueIterator End() const { return const_cast(*this).End(); } + + //! Request the array to have enough capacity to store elements. + /*! \param newCapacity The capacity that the array at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (newCapacity > data_.a.capacity) { + SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); + data_.a.capacity = newCapacity; + } + return *this; + } + + //! Append a GenericValue at the end of the array. + /*! \param value Value to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \post value.IsNull() == true + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this array on success. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + */ + GenericValue& PushBack(GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (data_.a.size >= data_.a.capacity) + Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); + GetElementsPointer()[data_.a.size++].RawAssign(value); + return *this; + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { + return PushBack(value, allocator); + } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + + //! Append a constant string reference at the end of the array. + /*! \param value Constant string reference to be appended. + \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + \see GenericStringRef + */ + GenericValue& PushBack(StringRefType value, Allocator& allocator) { + return (*this).template PushBack(value, allocator); + } + + //! Append a primitive value at the end of the array. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value Value of primitive type T to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref PushBack(GenericValue&, Allocator&) or \ref + PushBack(StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + PushBack(T value, Allocator& allocator) { + GenericValue v(value); + return PushBack(v, allocator); + } + + //! Remove the last element in the array. + /*! + \note Constant time complexity. + */ + GenericValue& PopBack() { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(!Empty()); + GetElementsPointer()[--data_.a.size].~GenericValue(); + return *this; + } + + //! Remove an element of array by iterator. + /*! + \param pos iterator to the element to remove + \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() + \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator pos) { + return Erase(pos, pos + 1); + } + + //! Remove elements in the range [first, last) of the array. + /*! + \param first iterator to the first element to remove + \param last iterator following the last element to remove + \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() + \return Iterator following the last removed element. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(data_.a.size > 0); + RAPIDJSON_ASSERT(GetElementsPointer() != 0); + RAPIDJSON_ASSERT(first >= Begin()); + RAPIDJSON_ASSERT(first <= last); + RAPIDJSON_ASSERT(last <= End()); + ValueIterator pos = Begin() + (first - Begin()); + for (ValueIterator itr = pos; itr != last; ++itr) + itr->~GenericValue(); + std::memmove(pos, last, static_cast(End() - last) * sizeof(GenericValue)); + data_.a.size -= static_cast(last - first); + return pos; + } + + Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } + ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } + + //@} + + //!@name Number + //@{ + + int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } + unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } + int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } + uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } + + //! Get the value as double type. + /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless. + */ + double GetDouble() const { + RAPIDJSON_ASSERT(IsNumber()); + if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. + if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double + if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double + if ((data_.f.flags & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision) + RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) + } + + //! Get the value as float type. + /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. + */ + float GetFloat() const { + return static_cast(GetDouble()); + } + + GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } + GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } + GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } + GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } + GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } + GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; } + + //@} + + //!@name String + //@{ + + const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } + + //! Get the length of string. + /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). + */ + SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } + + //! Set this value as a string without copying source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string pointer. + \param length The length of source string, excluding the trailing null terminator. + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == length + \see SetString(StringRefType) + */ + GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } + + //! Set this value as a string without copying source string. + /*! \param s source string reference + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == s.length + */ + GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } + + //! Set this value as a string by copying from source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string. + \param length The length of source string, excluding the trailing null terminator. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } + + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } + +#if RAPIDJSON_HAS_STDSTRING + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); } +#endif + + //@} + + //!@name Array + //@{ + + //! Templated version for checking whether this value is type T. + /*! + \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string + */ + template + bool Is() const { return internal::TypeHelper::Is(*this); } + + template + T Get() const { return internal::TypeHelper::Get(*this); } + + template + T Get() { return internal::TypeHelper::Get(*this); } + + template + ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } + + template + ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } + + //@} + + //! Generate events of this value to a Handler. + /*! This function adopts the GoF visitor pattern. + Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. + It can also be used to deep clone this value via GenericDocument, which is also a Handler. + \tparam Handler type of handler. + \param handler An object implementing concept Handler. + */ + template + bool Accept(Handler& handler) const { + switch(GetType()) { + case kNullType: return handler.Null(); + case kFalseType: return handler.Bool(false); + case kTrueType: return handler.Bool(true); + + case kObjectType: + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) + return false; + for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { + RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. + if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) + return false; + if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) + return false; + } + return handler.EndObject(data_.o.size); + + case kArrayType: + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) + return false; + for (const GenericValue* v = Begin(); v != End(); ++v) + if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) + return false; + return handler.EndArray(data_.a.size); + + case kStringType: + return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); + + default: + RAPIDJSON_ASSERT(GetType() == kNumberType); + if (IsDouble()) return handler.Double(data_.n.d); + else if (IsInt()) return handler.Int(data_.n.i.i); + else if (IsUint()) return handler.Uint(data_.n.u.u); + else if (IsInt64()) return handler.Int64(data_.n.i64); + else return handler.Uint64(data_.n.u64); + } + } + +private: + template friend class GenericValue; + template friend class GenericDocument; + + enum { + kBoolFlag = 0x0008, + kNumberFlag = 0x0010, + kIntFlag = 0x0020, + kUintFlag = 0x0040, + kInt64Flag = 0x0080, + kUint64Flag = 0x0100, + kDoubleFlag = 0x0200, + kStringFlag = 0x0400, + kCopyFlag = 0x0800, + kInlineStrFlag = 0x1000, + + // Initial flags of different types. + kNullFlag = kNullType, + kTrueFlag = kTrueType | kBoolFlag, + kFalseFlag = kFalseType | kBoolFlag, + kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, + kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, + kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, + kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, + kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, + kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, + kConstStringFlag = kStringType | kStringFlag, + kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, + kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, + kObjectFlag = kObjectType, + kArrayFlag = kArrayType, + + kTypeMask = 0x07 + }; + + static const SizeType kDefaultArrayCapacity = 16; + static const SizeType kDefaultObjectCapacity = 16; + + struct Flag { +#if RAPIDJSON_48BITPOINTER_OPTIMIZATION + char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer +#elif RAPIDJSON_64BIT + char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes +#else + char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes +#endif + uint16_t flags; + }; + + struct String { + SizeType length; + SizeType hashcode; //!< reserved + const Ch* str; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars + // (excluding the terminating zero) and store a value to determine the length of the contained + // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string + // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as + // the string terminator as well. For getting the string length back from that value just use + // "MaxSize - str[LenPos]". + // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, + // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). + struct ShortString { + enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; + Ch str[MaxChars]; + + inline static bool Usable(SizeType len) { return (MaxSize >= len); } + inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } + inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } + }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + // By using proper binary layout, retrieval of different integer types do not need conversions. + union Number { +#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN + struct I { + int i; + char padding[4]; + }i; + struct U { + unsigned u; + char padding2[4]; + }u; +#else + struct I { + char padding[4]; + int i; + }i; + struct U { + char padding2[4]; + unsigned u; + }u; +#endif + int64_t i64; + uint64_t u64; + double d; + }; // 8 bytes + + struct ObjectData { + SizeType size; + SizeType capacity; + Member* members; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + struct ArrayData { + SizeType size; + SizeType capacity; + GenericValue* elements; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + union Data { + String s; + ShortString ss; + Number n; + ObjectData o; + ArrayData a; + Flag f; + }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION + + RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } + RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } + RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } + RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } + RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } + RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } + + // Initialize this value as array with initial data, without calling destructor. + void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { + data_.f.flags = kArrayFlag; + if (count) { + GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); + SetElementsPointer(e); + std::memcpy(e, values, count * sizeof(GenericValue)); + } + else + SetElementsPointer(0); + data_.a.size = data_.a.capacity = count; + } + + //! Initialize this value as object with initial data, without calling destructor. + void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { + data_.f.flags = kObjectFlag; + if (count) { + Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); + SetMembersPointer(m); + std::memcpy(m, members, count * sizeof(Member)); + } + else + SetMembersPointer(0); + data_.o.size = data_.o.capacity = count; + } + + //! Initialize this value as constant string, without calling destructor. + void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { + data_.f.flags = kConstStringFlag; + SetStringPointer(s); + data_.s.length = s.length; + } + + //! Initialize this value as copy string with initial data, without calling destructor. + void SetStringRaw(StringRefType s, Allocator& allocator) { + Ch* str = 0; + if (ShortString::Usable(s.length)) { + data_.f.flags = kShortStringFlag; + data_.ss.SetLength(s.length); + str = data_.ss.str; + } else { + data_.f.flags = kCopyStringFlag; + data_.s.length = s.length; + str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); + SetStringPointer(str); + } + std::memcpy(str, s, s.length * sizeof(Ch)); + str[s.length] = '\0'; + } + + //! Assignment without calling destructor + void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { + data_ = rhs.data_; + // data_.f.flags = rhs.data_.f.flags; + rhs.data_.f.flags = kNullFlag; + } + + template + bool StringEqual(const GenericValue& rhs) const { + RAPIDJSON_ASSERT(IsString()); + RAPIDJSON_ASSERT(rhs.IsString()); + + const SizeType len1 = GetStringLength(); + const SizeType len2 = rhs.GetStringLength(); + if(len1 != len2) { return false; } + + const Ch* const str1 = GetString(); + const Ch* const str2 = rhs.GetString(); + if(str1 == str2) { return true; } // fast path for constant string + + return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); + } + + Data data_; +}; + +//! GenericValue with UTF8 encoding +typedef GenericValue > Value; + +/////////////////////////////////////////////////////////////////////////////// +// GenericDocument + +//! A document for parsing JSON text as DOM. +/*! + \note implements Handler concept + \tparam Encoding Encoding for both parsing and string storage. + \tparam Allocator Allocator for allocating memory for the DOM + \tparam StackAllocator Allocator for allocating memory for stack during parsing. + \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. +*/ +template , typename StackAllocator = CrtAllocator> +class GenericDocument : public GenericValue { +public: + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericValue ValueType; //!< Value type of the document. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + + //! Constructor + /*! Creates an empty document of specified type. + \param type Mandatory type of object to create. + \param allocator Optional allocator for allocating memory. + \param stackCapacity Optional initial capacity of stack in bytes. + \param stackAllocator Optional allocator for allocating memory for stack. + */ + explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : + GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + } + + //! Constructor + /*! Creates an empty document which type is Null. + \param allocator Optional allocator for allocating memory. + \param stackCapacity Optional initial capacity of stack in bytes. + \param stackAllocator Optional allocator for allocating memory for stack. + */ + GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : + allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT + : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document + allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + stack_(std::move(rhs.stack_)), + parseResult_(rhs.parseResult_) + { + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.parseResult_ = ParseResult(); + } +#endif + + ~GenericDocument() { + Destroy(); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move assignment in C++11 + GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT + { + // The cast to ValueType is necessary here, because otherwise it would + // attempt to call GenericValue's templated assignment operator. + ValueType::operator=(std::forward(rhs)); + + // Calling the destructor here would prematurely call stack_'s destructor + Destroy(); + + allocator_ = rhs.allocator_; + ownAllocator_ = rhs.ownAllocator_; + stack_ = std::move(rhs.stack_); + parseResult_ = rhs.parseResult_; + + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.parseResult_ = ParseResult(); + + return *this; + } +#endif + + //! Exchange the contents of this document with those of another. + /*! + \param rhs Another document. + \note Constant complexity. + \see GenericValue::Swap + */ + GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { + ValueType::Swap(rhs); + stack_.Swap(rhs.stack_); + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(parseResult_, rhs.parseResult_); + return *this; + } + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.doc, b.doc); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + + //! Populate this document by a generator which produces SAX events. + /*! \tparam Generator A functor with bool f(Handler) prototype. + \param g Generator functor which sends SAX events to the parameter. + \return The document itself for fluent API. + */ + template + GenericDocument& Populate(Generator& g) { + ClearStackOnExit scope(*this); + if (g(*this)) { + RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document + } + return *this; + } + + //!@name Parse from stream + //!@{ + + //! Parse JSON text from an input stream (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam SourceEncoding Encoding of input stream + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + GenericReader reader( + stack_.HasAllocator() ? &stack_.GetAllocator() : 0); + ClearStackOnExit scope(*this); + parseResult_ = reader.template Parse(is, *this); + if (parseResult_) { + RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document + } + return *this; + } + + //! Parse JSON text from an input stream + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } + + //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } + //!@} + + //!@name Parse in-place from mutable string + //!@{ + + //! Parse JSON text from a mutable string + /*! \tparam parseFlags Combination of \ref ParseFlag. + \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseInsitu(Ch* str) { + GenericInsituStringStream s(str); + return ParseStream(s); + } + + //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) + /*! \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + GenericDocument& ParseInsitu(Ch* str) { + return ParseInsitu(str); + } + //!@} + + //!@name Parse from read-only string + //!@{ + + //! Parse JSON text from a read-only string (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \tparam SourceEncoding Transcoding from input Encoding + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const typename SourceEncoding::Ch* str) { + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + GenericStringStream s(str); + return ParseStream(s); + } + + //! Parse JSON text from a read-only string + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } + + //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) + /*! \param str Read-only zero-terminated string to be parsed. + */ + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } + + template + GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + MemoryStream ms(static_cast(str), length * sizeof(typename SourceEncoding::Ch)); + EncodedInputStream is(ms); + ParseStream(is); + return *this; + } + + template + GenericDocument& Parse(const Ch* str, size_t length) { + return Parse(str, length); + } + + GenericDocument& Parse(const Ch* str, size_t length) { + return Parse(str, length); + } + +#if RAPIDJSON_HAS_STDSTRING + template + GenericDocument& Parse(const std::basic_string& str) { + // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) + return Parse(str.c_str()); + } + + template + GenericDocument& Parse(const std::basic_string& str) { + return Parse(str.c_str()); + } + + GenericDocument& Parse(const std::basic_string& str) { + return Parse(str); + } +#endif // RAPIDJSON_HAS_STDSTRING + + //!@} + + //!@name Handling parse errors + //!@{ + + //! Whether a parse error has occured in the last parsing. + bool HasParseError() const { return parseResult_.IsError(); } + + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseError() const { return parseResult_.Code(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const { return parseResult_.Offset(); } + + //! Implicit conversion to get the last parse result +#ifndef __clang // -Wdocumentation + /*! \return \ref ParseResult of the last parse operation + + \code + Document doc; + ParseResult ok = doc.Parse(json); + if (!ok) + printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); + \endcode + */ +#endif + operator ParseResult() const { return parseResult_; } + //!@} + + //! Get the allocator of this document. + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } + + //! Get the capacity of stack in bytes. + size_t GetStackCapacity() const { return stack_.GetCapacity(); } + +private: + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} + ~ClearStackOnExit() { d_.ClearStack(); } + private: + ClearStackOnExit(const ClearStackOnExit&); + ClearStackOnExit& operator=(const ClearStackOnExit&); + GenericDocument& d_; + }; + + // callers of the following private Handler functions + // template friend class GenericReader; // for parsing + template friend class GenericValue; // for deep copying + +public: + // Implementation of Handler + bool Null() { new (stack_.template Push()) ValueType(); return true; } + bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } + bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } + bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } + + bool RawNumber(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + return true; + } + + bool String(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + return true; + } + + bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } + + bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } + + bool EndObject(SizeType memberCount) { + typename ValueType::Member* members = stack_.template Pop(memberCount); + stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); + return true; + } + + bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } + + bool EndArray(SizeType elementCount) { + ValueType* elements = stack_.template Pop(elementCount); + stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); + return true; + } + +private: + //! Prohibit copying + GenericDocument(const GenericDocument&); + //! Prohibit assignment + GenericDocument& operator=(const GenericDocument&); + + void ClearStack() { + if (Allocator::kNeedFree) + while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) + (stack_.template Pop(1))->~ValueType(); + else + stack_.Clear(); + stack_.ShrinkToFit(); + } + + void Destroy() { + RAPIDJSON_DELETE(ownAllocator_); + } + + static const size_t kDefaultStackCapacity = 1024; + Allocator* allocator_; + Allocator* ownAllocator_; + internal::Stack stack_; + ParseResult parseResult_; +}; + +//! GenericDocument with UTF8 encoding +typedef GenericDocument > Document; + +// defined here due to the dependency on GenericDocument +template +template +inline +GenericValue::GenericValue(const GenericValue& rhs, Allocator& allocator) +{ + switch (rhs.GetType()) { + case kObjectType: + case kArrayType: { // perform deep copy via SAX Handler + GenericDocument d(&allocator); + rhs.Accept(d); + RawAssign(*d.stack_.template Pop(1)); + } + break; + case kStringType: + if (rhs.data_.f.flags == kConstStringFlag) { + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + } else { + SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); + } + break; + default: + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + break; + } +} + +//! Helper class for accessing Value of array type. +/*! + Instance of this helper class is obtained by \c GenericValue::GetArray(). + In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. +*/ +template +class GenericArray { +public: + typedef GenericArray ConstArray; + typedef GenericArray Array; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef ValueType* ValueIterator; // This may be const or non-const iterator + typedef const ValueT* ConstValueIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; + + template + friend class GenericValue; + + GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} + GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } + ~GenericArray() {} + + SizeType Size() const { return value_.Size(); } + SizeType Capacity() const { return value_.Capacity(); } + bool Empty() const { return value_.Empty(); } + void Clear() const { value_.Clear(); } + ValueType& operator[](SizeType index) const { return value_[index]; } + ValueIterator Begin() const { return value_.Begin(); } + ValueIterator End() const { return value_.End(); } + GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } + GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + GenericArray PopBack() const { value_.PopBack(); return *this; } + ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR + ValueIterator begin() const { return value_.Begin(); } + ValueIterator end() const { return value_.End(); } +#endif + +private: + GenericArray(); + GenericArray(ValueType& value) : value_(value) {} + ValueType& value_; +}; + +//! Helper class for accessing Value of object type. +/*! + Instance of this helper class is obtained by \c GenericValue::GetObject(). + In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. +*/ +template +class GenericObject { +public: + typedef GenericObject ConstObject; + typedef GenericObject Object; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator + typedef GenericMemberIterator ConstMemberIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename ValueType::Ch Ch; + + template + friend class GenericValue; + + GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} + GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } + ~GenericObject() {} + + SizeType MemberCount() const { return value_.MemberCount(); } + bool ObjectEmpty() const { return value_.ObjectEmpty(); } + template ValueType& operator[](T* name) const { return value_[name]; } + template ValueType& operator[](const GenericValue& name) const { return value_[name]; } +#if RAPIDJSON_HAS_STDSTRING + ValueType& operator[](const std::basic_string& name) const { return value_[name]; } +#endif + MemberIterator MemberBegin() const { return value_.MemberBegin(); } + MemberIterator MemberEnd() const { return value_.MemberEnd(); } + bool HasMember(const Ch* name) const { return value_.HasMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } +#endif + template bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } + MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } + template MemberIterator FindMember(const GenericValue& name) const { return value_.FindMember(name); } +#if RAPIDJSON_HAS_STDSTRING + MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } +#endif + GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#if RAPIDJSON_HAS_STDSTRING + GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#endif + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + void RemoveAllMembers() { return value_.RemoveAllMembers(); } + bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } +#endif + template bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } + MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } + MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } + bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } +#endif + template bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR + MemberIterator begin() const { return value_.MemberBegin(); } + MemberIterator end() const { return value_.MemberEnd(); } +#endif + +private: + GenericObject(); + GenericObject(ValueType& value) : value_(value) {} + ValueType& value_; +}; + +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP + +#endif // RAPIDJSON_DOCUMENT_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/encodedstream.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/encodedstream.h new file mode 100644 index 0000000000000000000000000000000000000000..145068386a0674aa6daa2b63f2fb2821f631f99c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/encodedstream.h @@ -0,0 +1,299 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ENCODEDSTREAM_H_ +#define RAPIDJSON_ENCODEDSTREAM_H_ + +#include "stream.h" +#include "memorystream.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Input byte stream wrapper with a statically bound encoding. +/*! + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam InputByteStream Type of input byte stream. For example, FileReadStream. +*/ +template +class EncodedInputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); +public: + typedef typename Encoding::Ch Ch; + + EncodedInputStream(InputByteStream& is) : is_(is) { + current_ = Encoding::TakeBOM(is_); + } + + Ch Peek() const { return current_; } + Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } + size_t Tell() const { return is_.Tell(); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + EncodedInputStream(const EncodedInputStream&); + EncodedInputStream& operator=(const EncodedInputStream&); + + InputByteStream& is_; + Ch current_; +}; + +//! Specialized for UTF8 MemoryStream. +template <> +class EncodedInputStream, MemoryStream> { +public: + typedef UTF8<>::Ch Ch; + + EncodedInputStream(MemoryStream& is) : is_(is) { + if (static_cast(is_.Peek()) == 0xEFu) is_.Take(); + if (static_cast(is_.Peek()) == 0xBBu) is_.Take(); + if (static_cast(is_.Peek()) == 0xBFu) is_.Take(); + } + Ch Peek() const { return is_.Peek(); } + Ch Take() { return is_.Take(); } + size_t Tell() const { return is_.Tell(); } + + // Not implemented + void Put(Ch) {} + void Flush() {} + Ch* PutBegin() { return 0; } + size_t PutEnd(Ch*) { return 0; } + + MemoryStream& is_; + +private: + EncodedInputStream(const EncodedInputStream&); + EncodedInputStream& operator=(const EncodedInputStream&); +}; + +//! Output byte stream wrapper with statically bound encoding. +/*! + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. +*/ +template +class EncodedOutputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); +public: + typedef typename Encoding::Ch Ch; + + EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { + if (putBOM) + Encoding::PutBOM(os_); + } + + void Put(Ch c) { Encoding::Put(os_, c); } + void Flush() { os_.Flush(); } + + // Not implemented + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + EncodedOutputStream(const EncodedOutputStream&); + EncodedOutputStream& operator=(const EncodedOutputStream&); + + OutputByteStream& os_; +}; + +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x + +//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. +/*! + \tparam CharType Type of character for reading. + \tparam InputByteStream type of input byte stream to be wrapped. +*/ +template +class AutoUTFInputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); +public: + typedef CharType Ch; + + //! Constructor. + /*! + \param is input stream to be wrapped. + \param type UTF encoding type if it is not detected from the stream. + */ + AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + DetectType(); + static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; + takeFunc_ = f[type_]; + current_ = takeFunc_(*is_); + } + + UTFType GetType() const { return type_; } + bool HasBOM() const { return hasBOM_; } + + Ch Peek() const { return current_; } + Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } + size_t Tell() const { return is_->Tell(); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + AutoUTFInputStream(const AutoUTFInputStream&); + AutoUTFInputStream& operator=(const AutoUTFInputStream&); + + // Detect encoding type with BOM or RFC 4627 + void DetectType() { + // BOM (Byte Order Mark): + // 00 00 FE FF UTF-32BE + // FF FE 00 00 UTF-32LE + // FE FF UTF-16BE + // FF FE UTF-16LE + // EF BB BF UTF-8 + + const unsigned char* c = reinterpret_cast(is_->Peek4()); + if (!c) + return; + + unsigned bom = static_cast(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); + hasBOM_ = false; + if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } + else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } + else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } + else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } + else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } + + // RFC 4627: Section 3 + // "Since the first two characters of a JSON text will always be ASCII + // characters [RFC0020], it is possible to determine whether an octet + // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking + // at the pattern of nulls in the first four octets." + // 00 00 00 xx UTF-32BE + // 00 xx 00 xx UTF-16BE + // xx 00 00 00 UTF-32LE + // xx 00 xx 00 UTF-16LE + // xx xx xx xx UTF-8 + + if (!hasBOM_) { + unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); + switch (pattern) { + case 0x08: type_ = kUTF32BE; break; + case 0x0A: type_ = kUTF16BE; break; + case 0x01: type_ = kUTF32LE; break; + case 0x05: type_ = kUTF16LE; break; + case 0x0F: type_ = kUTF8; break; + default: break; // Use type defined by user. + } + } + + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + } + + typedef Ch (*TakeFunc)(InputByteStream& is); + InputByteStream* is_; + UTFType type_; + Ch current_; + TakeFunc takeFunc_; + bool hasBOM_; +}; + +//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. +/*! + \tparam CharType Type of character for writing. + \tparam OutputByteStream type of output byte stream to be wrapped. +*/ +template +class AutoUTFOutputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); +public: + typedef CharType Ch; + + //! Constructor. + /*! + \param os output stream to be wrapped. + \param type UTF encoding type. + \param putBOM Whether to write BOM at the beginning of the stream. + */ + AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + + static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; + putFunc_ = f[type_]; + + if (putBOM) + PutBOM(); + } + + UTFType GetType() const { return type_; } + + void Put(Ch c) { putFunc_(*os_, c); } + void Flush() { os_->Flush(); } + + // Not implemented + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + AutoUTFOutputStream(const AutoUTFOutputStream&); + AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); + + void PutBOM() { + typedef void (*PutBOMFunc)(OutputByteStream&); + static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; + f[type_](*os_); + } + + typedef void (*PutFunc)(OutputByteStream&, Ch); + + OutputByteStream* os_; + UTFType type_; + PutFunc putFunc_; +}; + +#undef RAPIDJSON_ENCODINGS_FUNC + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/encodings.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/encodings.h new file mode 100644 index 0000000000000000000000000000000000000000..baa7c2b17f8d8ee68fa4e9d3416e4f031dfa35e6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/encodings.h @@ -0,0 +1,716 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ENCODINGS_H_ +#define RAPIDJSON_ENCODINGS_H_ + +#include "rapidjson.h" + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data +RAPIDJSON_DIAG_OFF(4702) // unreachable code +#elif defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(overflow) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Encoding + +/*! \class rapidjson::Encoding + \brief Concept for encoding of Unicode characters. + +\code +concept Encoding { + typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. + + enum { supportUnicode = 1 }; // or 0 if not supporting unicode + + //! \brief Encode a Unicode codepoint to an output stream. + //! \param os Output stream. + //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. + template + static void Encode(OutputStream& os, unsigned codepoint); + + //! \brief Decode a Unicode codepoint from an input stream. + //! \param is Input stream. + //! \param codepoint Output of the unicode codepoint. + //! \return true if a valid codepoint can be decoded from the stream. + template + static bool Decode(InputStream& is, unsigned* codepoint); + + //! \brief Validate one Unicode codepoint from an encoded stream. + //! \param is Input stream to obtain codepoint. + //! \param os Output for copying one codepoint. + //! \return true if it is valid. + //! \note This function just validating and copying the codepoint without actually decode it. + template + static bool Validate(InputStream& is, OutputStream& os); + + // The following functions are deal with byte streams. + + //! Take a character from input byte stream, skip BOM if exist. + template + static CharType TakeBOM(InputByteStream& is); + + //! Take a character from input byte stream. + template + static Ch Take(InputByteStream& is); + + //! Put BOM to output byte stream. + template + static void PutBOM(OutputByteStream& os); + + //! Put a character to output byte stream. + template + static void Put(OutputByteStream& os, Ch c); +}; +\endcode +*/ + +/////////////////////////////////////////////////////////////////////////////// +// UTF8 + +//! UTF-8 encoding. +/*! http://en.wikipedia.org/wiki/UTF-8 + http://tools.ietf.org/html/rfc3629 + \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. + \note implements Encoding concept +*/ +template +struct UTF8 { + typedef CharType Ch; + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + if (codepoint <= 0x7F) + os.Put(static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) { + os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) { + os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + } + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + if (codepoint <= 0x7F) + PutUnsafe(os, static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) { + PutUnsafe(os, static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) { + PutUnsafe(os, static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { +#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) +#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define TAIL() COPY(); TRANS(0x70) + typename InputStream::Ch c = is.Take(); + if (!(c & 0x80)) { + *codepoint = static_cast(c); + return true; + } + + unsigned char type = GetRange(static_cast(c)); + if (type >= 32) { + *codepoint = 0; + } else { + *codepoint = (0xFF >> type) & static_cast(c); + } + bool result = true; + switch (type) { + case 2: TAIL(); return result; + case 3: TAIL(); TAIL(); return result; + case 4: COPY(); TRANS(0x50); TAIL(); return result; + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; + case 6: TAIL(); TAIL(); TAIL(); return result; + case 10: COPY(); TRANS(0x20); TAIL(); return result; + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + default: return false; + } +#undef COPY +#undef TRANS +#undef TAIL + } + + template + static bool Validate(InputStream& is, OutputStream& os) { +#define COPY() os.Put(c = is.Take()) +#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define TAIL() COPY(); TRANS(0x70) + Ch c; + COPY(); + if (!(c & 0x80)) + return true; + + bool result = true; + switch (GetRange(static_cast(c))) { + case 2: TAIL(); return result; + case 3: TAIL(); TAIL(); return result; + case 4: COPY(); TRANS(0x50); TAIL(); return result; + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; + case 6: TAIL(); TAIL(); TAIL(); return result; + case 10: COPY(); TRANS(0x20); TAIL(); return result; + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + default: return false; + } +#undef COPY +#undef TRANS +#undef TAIL + } + + static unsigned char GetRange(unsigned char c) { + // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. + static const unsigned char type[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, + }; + return type[c]; + } + + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + typename InputByteStream::Ch c = Take(is); + if (static_cast(c) != 0xEFu) return c; + c = is.Take(); + if (static_cast(c) != 0xBBu) return c; + c = is.Take(); + if (static_cast(c) != 0xBFu) return c; + c = is.Take(); + return c; + } + + template + static Ch Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return static_cast(is.Take()); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xEFu)); + os.Put(static_cast(0xBBu)); + os.Put(static_cast(0xBFu)); + } + + template + static void Put(OutputByteStream& os, Ch c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF16 + +//! UTF-16 encoding. +/*! http://en.wikipedia.org/wiki/UTF-16 + http://tools.ietf.org/html/rfc2781 + \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. + \note implements Encoding concept + + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF16LE and UTF16BE, which handle endianness. +*/ +template +struct UTF16 { + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + os.Put(static_cast(codepoint)); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + os.Put(static_cast((v >> 10) | 0xD800)); + os.Put((v & 0x3FF) | 0xDC00); + } + } + + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + PutUnsafe(os, static_cast(codepoint)); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + PutUnsafe(os, static_cast((v >> 10) | 0xD800)); + PutUnsafe(os, (v & 0x3FF) | 0xDC00); + } + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + typename InputStream::Ch c = is.Take(); + if (c < 0xD800 || c > 0xDFFF) { + *codepoint = static_cast(c); + return true; + } + else if (c <= 0xDBFF) { + *codepoint = (static_cast(c) & 0x3FF) << 10; + c = is.Take(); + *codepoint |= (static_cast(c) & 0x3FF); + *codepoint += 0x10000; + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + typename InputStream::Ch c; + os.Put(static_cast(c = is.Take())); + if (c < 0xD800 || c > 0xDFFF) + return true; + else if (c <= 0xDBFF) { + os.Put(c = is.Take()); + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } +}; + +//! UTF-16 little endian encoding. +template +struct UTF16LE : UTF16 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0xFEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(static_cast(c) & 0xFFu)); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); + } +}; + +//! UTF-16 big endian encoding. +template +struct UTF16BE : UTF16 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0xFEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(static_cast(is.Take())) << 8; + c |= static_cast(is.Take()); + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); + os.Put(static_cast(static_cast(c) & 0xFFu)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF32 + +//! UTF-32 encoding. +/*! http://en.wikipedia.org/wiki/UTF-32 + \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. + \note implements Encoding concept + + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF32LE and UTF32BE, which handle endianness. +*/ +template +struct UTF32 { + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(codepoint); + } + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, codepoint); + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c = is.Take(); + *codepoint = c; + return c <= 0x10FFFF; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c; + os.Put(c = is.Take()); + return c <= 0x10FFFF; + } +}; + +//! UTF-32 little endian enocoding. +template +struct UTF32LE : UTF32 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 24; + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 24) & 0xFFu)); + } +}; + +//! UTF-32 big endian encoding. +template +struct UTF32BE : UTF32 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(static_cast(is.Take())) << 24; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())); + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast((c >> 24) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast(c & 0xFFu)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// ASCII + +//! ASCII encoding. +/*! http://en.wikipedia.org/wiki/ASCII + \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. + \note implements Encoding concept +*/ +template +struct ASCII { + typedef CharType Ch; + + enum { supportUnicode = 0 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + os.Put(static_cast(codepoint & 0xFF)); + } + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + PutUnsafe(os, static_cast(codepoint & 0xFF)); + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + uint8_t c = static_cast(is.Take()); + *codepoint = c; + return c <= 0X7F; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + uint8_t c = static_cast(is.Take()); + os.Put(static_cast(c)); + return c <= 0x7F; + } + + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + uint8_t c = static_cast(Take(is)); + return static_cast(c); + } + + template + static Ch Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return static_cast(is.Take()); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + (void)os; + } + + template + static void Put(OutputByteStream& os, Ch c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// AutoUTF + +//! Runtime-specified UTF encoding type of a stream. +enum UTFType { + kUTF8 = 0, //!< UTF-8. + kUTF16LE = 1, //!< UTF-16 little endian. + kUTF16BE = 2, //!< UTF-16 big endian. + kUTF32LE = 3, //!< UTF-32 little endian. + kUTF32BE = 4 //!< UTF-32 big endian. +}; + +//! Dynamically select encoding according to stream's runtime-specified UTF encoding type. +/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). +*/ +template +struct AutoUTF { + typedef CharType Ch; + + enum { supportUnicode = 1 }; + +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x + + template + RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { + typedef void (*EncodeFunc)(OutputStream&, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; + (*f[os.GetType()])(os, codepoint); + } + + template + RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + typedef void (*EncodeFunc)(OutputStream&, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; + (*f[os.GetType()])(os, codepoint); + } + + template + RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { + typedef bool (*DecodeFunc)(InputStream&, unsigned*); + static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; + return (*f[is.GetType()])(is, codepoint); + } + + template + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + typedef bool (*ValidateFunc)(InputStream&, OutputStream&); + static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; + return (*f[is.GetType()])(is, os); + } + +#undef RAPIDJSON_ENCODINGS_FUNC +}; + +/////////////////////////////////////////////////////////////////////////////// +// Transcoder + +//! Encoding conversion. +template +struct Transcoder { + //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. + template + RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::Encode(os, codepoint); + return true; + } + + template + RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::EncodeUnsafe(os, codepoint); + return true; + } + + //! Validate one Unicode codepoint from an encoded stream. + template + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + return Transcode(is, os); // Since source/target encoding is different, must transcode. + } +}; + +// Forward declaration. +template +inline void PutUnsafe(Stream& stream, typename Stream::Ch c); + +//! Specialization of Transcoder with same source and target encoding. +template +struct Transcoder { + template + RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + + template + RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + + template + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + return Encoding::Validate(is, os); // source/target encoding are the same + } +}; + +RAPIDJSON_NAMESPACE_END + +#if defined(__GNUC__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/error/en.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/error/en.h new file mode 100644 index 0000000000000000000000000000000000000000..2db838bff2399dd02deeadfdbf3af7d008588f63 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/error/en.h @@ -0,0 +1,74 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_EN_H_ +#define RAPIDJSON_ERROR_EN_H_ + +#include "error.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(covered-switch-default) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Maps error code of parsing into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param parseErrorCode Error code obtained in parsing. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. +*/ +inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { + switch (parseErrorCode) { + case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + + case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); + case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); + + case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); + + case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); + case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); + case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); + + case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); + + case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); + case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); + case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); + case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); + case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); + + case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); + case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); + case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); + + case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); + case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); + + default: return RAPIDJSON_ERROR_STRING("Unknown error."); + } +} + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/error/error.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/error/error.h new file mode 100644 index 0000000000000000000000000000000000000000..95cb31a72fe2c335f3e9361c8c3d7478ce4fbdcf --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/error/error.h @@ -0,0 +1,155 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_ERROR_H_ +#define RAPIDJSON_ERROR_ERROR_H_ + +#include "../rapidjson.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +/*! \file error.h */ + +/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_CHARTYPE + +//! Character type of error messages. +/*! \ingroup RAPIDJSON_ERRORS + The default character type is \c char. + On Windows, user can define this macro as \c TCHAR for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_CHARTYPE +#define RAPIDJSON_ERROR_CHARTYPE char +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_STRING + +//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. +/*! \ingroup RAPIDJSON_ERRORS + By default this conversion macro does nothing. + On Windows, user can define this macro as \c _T(x) for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_STRING +#define RAPIDJSON_ERROR_STRING(x) x +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// ParseErrorCode + +//! Error code of parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericReader::Parse, GenericReader::GetParseErrorCode +*/ +enum ParseErrorCode { + kParseErrorNone = 0, //!< No error. + + kParseErrorDocumentEmpty, //!< The document is empty. + kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. + + kParseErrorValueInvalid, //!< Invalid value. + + kParseErrorObjectMissName, //!< Missing a name for object member. + kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. + kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. + + kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. + + kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. + kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. + kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. + kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. + kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. + + kParseErrorNumberTooBig, //!< Number too big to be stored in double. + kParseErrorNumberMissFraction, //!< Miss fraction part in number. + kParseErrorNumberMissExponent, //!< Miss exponent in number. + + kParseErrorTermination, //!< Parsing was terminated. + kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. +}; + +//! Result of parsing (wraps ParseErrorCode) +/*! + \ingroup RAPIDJSON_ERRORS + \code + Document doc; + ParseResult ok = doc.Parse("[42]"); + if (!ok) { + fprintf(stderr, "JSON parse error: %s (%u)", + GetParseError_En(ok.Code()), ok.Offset()); + exit(EXIT_FAILURE); + } + \endcode + \see GenericReader::Parse, GenericDocument::Parse +*/ +struct ParseResult { +public: + //! Default constructor, no error. + ParseResult() : code_(kParseErrorNone), offset_(0) {} + //! Constructor to set an error. + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} + + //! Get the error code. + ParseErrorCode Code() const { return code_; } + //! Get the error offset, if \ref IsError(), 0 otherwise. + size_t Offset() const { return offset_; } + + //! Conversion to \c bool, returns \c true, iff !\ref IsError(). + operator bool() const { return !IsError(); } + //! Whether the result is an error. + bool IsError() const { return code_ != kParseErrorNone; } + + bool operator==(const ParseResult& that) const { return code_ == that.code_; } + bool operator==(ParseErrorCode code) const { return code_ == code; } + friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } + + //! Reset error code. + void Clear() { Set(kParseErrorNone); } + //! Update error code and offset. + void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } + +private: + ParseErrorCode code_; + size_t offset_; +}; + +//! Function pointer type of GetParseError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetParseError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetParseErrorFunc GetParseError = GetParseError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/filereadstream.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/filereadstream.h new file mode 100644 index 0000000000000000000000000000000000000000..b56ea13b34257db5d1f54cb099b2d1da5e0cb1ad --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/filereadstream.h @@ -0,0 +1,99 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FILEREADSTREAM_H_ +#define RAPIDJSON_FILEREADSTREAM_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! File byte stream for input using fread(). +/*! + \note implements Stream concept +*/ +class FileReadStream { +public: + typedef char Ch; //!< Character type (byte). + + //! Constructor. + /*! + \param fp File pointer opened for read. + \param buffer user-supplied buffer. + \param bufferSize size of buffer in bytes. Must >=4 bytes. + */ + FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + RAPIDJSON_ASSERT(fp_ != 0); + RAPIDJSON_ASSERT(bufferSize >= 4); + Read(); + } + + Ch Peek() const { return *current_; } + Ch Take() { Ch c = *current_; Read(); return c; } + size_t Tell() const { return count_ + static_cast(current_ - buffer_); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + return (current_ + 4 <= bufferLast_) ? current_ : 0; + } + +private: + void Read() { + if (current_ < bufferLast_) + ++current_; + else if (!eof_) { + count_ += readCount_; + readCount_ = fread(buffer_, 1, bufferSize_, fp_); + bufferLast_ = buffer_ + readCount_ - 1; + current_ = buffer_; + + if (readCount_ < bufferSize_) { + buffer_[readCount_] = '\0'; + ++bufferLast_; + eof_ = true; + } + } + } + + std::FILE* fp_; + Ch *buffer_; + size_t bufferSize_; + Ch *bufferLast_; + Ch *current_; + size_t readCount_; + size_t count_; //!< Number of characters read + bool eof_; +}; + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/filewritestream.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/filewritestream.h new file mode 100644 index 0000000000000000000000000000000000000000..6378dd60ed47fd5431e3f9825da3b8315b0dc866 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/filewritestream.h @@ -0,0 +1,104 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FILEWRITESTREAM_H_ +#define RAPIDJSON_FILEWRITESTREAM_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of C file stream for input using fread(). +/*! + \note implements Stream concept +*/ +class FileWriteStream { +public: + typedef char Ch; //!< Character type. Only support char. + + FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { + RAPIDJSON_ASSERT(fp_ != 0); + } + + void Put(char c) { + if (current_ >= bufferEnd_) + Flush(); + + *current_++ = c; + } + + void PutN(char c, size_t n) { + size_t avail = static_cast(bufferEnd_ - current_); + while (n > avail) { + std::memset(current_, c, avail); + current_ += avail; + Flush(); + n -= avail; + avail = static_cast(bufferEnd_ - current_); + } + + if (n > 0) { + std::memset(current_, c, n); + current_ += n; + } + } + + void Flush() { + if (current_ != buffer_) { + size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + if (result < static_cast(current_ - buffer_)) { + // failure deliberately ignored at this time + // added to avoid warn_unused_result build errors + } + current_ = buffer_; + } + } + + // Not implemented + char Peek() const { RAPIDJSON_ASSERT(false); return 0; } + char Take() { RAPIDJSON_ASSERT(false); return 0; } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + // Prohibit copy constructor & assignment operator. + FileWriteStream(const FileWriteStream&); + FileWriteStream& operator=(const FileWriteStream&); + + std::FILE* fp_; + char *buffer_; + char *bufferEnd_; + char *current_; +}; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(FileWriteStream& stream, char c, size_t n) { + stream.PutN(c, n); +} + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/fwd.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/fwd.h new file mode 100644 index 0000000000000000000000000000000000000000..e8104e841bcdcaca0bd415c208a746ed7d806ab5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/fwd.h @@ -0,0 +1,151 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FWD_H_ +#define RAPIDJSON_FWD_H_ + +#include "rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN + +// encodings.h + +template struct UTF8; +template struct UTF16; +template struct UTF16BE; +template struct UTF16LE; +template struct UTF32; +template struct UTF32BE; +template struct UTF32LE; +template struct ASCII; +template struct AutoUTF; + +template +struct Transcoder; + +// allocators.h + +class CrtAllocator; + +template +class MemoryPoolAllocator; + +// stream.h + +template +struct GenericStringStream; + +typedef GenericStringStream > StringStream; + +template +struct GenericInsituStringStream; + +typedef GenericInsituStringStream > InsituStringStream; + +// stringbuffer.h + +template +class GenericStringBuffer; + +typedef GenericStringBuffer, CrtAllocator> StringBuffer; + +// filereadstream.h + +class FileReadStream; + +// filewritestream.h + +class FileWriteStream; + +// memorybuffer.h + +template +struct GenericMemoryBuffer; + +typedef GenericMemoryBuffer MemoryBuffer; + +// memorystream.h + +struct MemoryStream; + +// reader.h + +template +struct BaseReaderHandler; + +template +class GenericReader; + +typedef GenericReader, UTF8, CrtAllocator> Reader; + +// writer.h + +template +class Writer; + +// prettywriter.h + +template +class PrettyWriter; + +// document.h + +template +struct GenericMember; + +template +class GenericMemberIterator; + +template +struct GenericStringRef; + +template +class GenericValue; + +typedef GenericValue, MemoryPoolAllocator > Value; + +template +class GenericDocument; + +typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; + +// pointer.h + +template +class GenericPointer; + +typedef GenericPointer Pointer; + +// schema.h + +template +class IGenericRemoteSchemaDocumentProvider; + +template +class GenericSchemaDocument; + +typedef GenericSchemaDocument SchemaDocument; +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + +template < + typename SchemaDocumentType, + typename OutputHandler, + typename StateAllocator> +class GenericSchemaValidator; + +typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_RAPIDJSONFWD_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/biginteger.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/biginteger.h new file mode 100644 index 0000000000000000000000000000000000000000..9d3e88c9981efd7506dada5e1ea2d5a89771540a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/biginteger.h @@ -0,0 +1,290 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_BIGINTEGER_H_ +#define RAPIDJSON_BIGINTEGER_H_ + +#include "../rapidjson.h" + +#if defined(_MSC_VER) && defined(_M_AMD64) +#include // for _umul128 +#pragma intrinsic(_umul128) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +class BigInteger { +public: + typedef uint64_t Type; + + BigInteger(const BigInteger& rhs) : count_(rhs.count_) { + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); + } + + explicit BigInteger(uint64_t u) : count_(1) { + digits_[0] = u; + } + + BigInteger(const char* decimals, size_t length) : count_(1) { + RAPIDJSON_ASSERT(length > 0); + digits_[0] = 0; + size_t i = 0; + const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 + while (length >= kMaxDigitPerIteration) { + AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); + length -= kMaxDigitPerIteration; + i += kMaxDigitPerIteration; + } + + if (length > 0) + AppendDecimal64(decimals + i, decimals + i + length); + } + + BigInteger& operator=(const BigInteger &rhs) + { + if (this != &rhs) { + count_ = rhs.count_; + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); + } + return *this; + } + + BigInteger& operator=(uint64_t u) { + digits_[0] = u; + count_ = 1; + return *this; + } + + BigInteger& operator+=(uint64_t u) { + Type backup = digits_[0]; + digits_[0] += u; + for (size_t i = 0; i < count_ - 1; i++) { + if (digits_[i] >= backup) + return *this; // no carry + backup = digits_[i + 1]; + digits_[i + 1] += 1; + } + + // Last carry + if (digits_[count_ - 1] < backup) + PushBack(1); + + return *this; + } + + BigInteger& operator*=(uint64_t u) { + if (u == 0) return *this = 0; + if (u == 1) return *this; + if (*this == 1) return *this = u; + + uint64_t k = 0; + for (size_t i = 0; i < count_; i++) { + uint64_t hi; + digits_[i] = MulAdd64(digits_[i], u, k, &hi); + k = hi; + } + + if (k > 0) + PushBack(k); + + return *this; + } + + BigInteger& operator*=(uint32_t u) { + if (u == 0) return *this = 0; + if (u == 1) return *this; + if (*this == 1) return *this = u; + + uint64_t k = 0; + for (size_t i = 0; i < count_; i++) { + const uint64_t c = digits_[i] >> 32; + const uint64_t d = digits_[i] & 0xFFFFFFFF; + const uint64_t uc = u * c; + const uint64_t ud = u * d; + const uint64_t p0 = ud + k; + const uint64_t p1 = uc + (p0 >> 32); + digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); + k = p1 >> 32; + } + + if (k > 0) + PushBack(k); + + return *this; + } + + BigInteger& operator<<=(size_t shift) { + if (IsZero() || shift == 0) return *this; + + size_t offset = shift / kTypeBit; + size_t interShift = shift % kTypeBit; + RAPIDJSON_ASSERT(count_ + offset <= kCapacity); + + if (interShift == 0) { + std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); + count_ += offset; + } + else { + digits_[count_] = 0; + for (size_t i = count_; i > 0; i--) + digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); + digits_[offset] = digits_[0] << interShift; + count_ += offset; + if (digits_[count_]) + count_++; + } + + std::memset(digits_, 0, offset * sizeof(Type)); + + return *this; + } + + bool operator==(const BigInteger& rhs) const { + return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; + } + + bool operator==(const Type rhs) const { + return count_ == 1 && digits_[0] == rhs; + } + + BigInteger& MultiplyPow5(unsigned exp) { + static const uint32_t kPow5[12] = { + 5, + 5 * 5, + 5 * 5 * 5, + 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 + }; + if (exp == 0) return *this; + for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 + for (; exp >= 13; exp -= 13) *this *= static_cast(1220703125u); // 5^13 + if (exp > 0) *this *= kPow5[exp - 1]; + return *this; + } + + // Compute absolute difference of this and rhs. + // Assume this != rhs + bool Difference(const BigInteger& rhs, BigInteger* out) const { + int cmp = Compare(rhs); + RAPIDJSON_ASSERT(cmp != 0); + const BigInteger *a, *b; // Makes a > b + bool ret; + if (cmp < 0) { a = &rhs; b = this; ret = true; } + else { a = this; b = &rhs; ret = false; } + + Type borrow = 0; + for (size_t i = 0; i < a->count_; i++) { + Type d = a->digits_[i] - borrow; + if (i < b->count_) + d -= b->digits_[i]; + borrow = (d > a->digits_[i]) ? 1 : 0; + out->digits_[i] = d; + if (d != 0) + out->count_ = i + 1; + } + + return ret; + } + + int Compare(const BigInteger& rhs) const { + if (count_ != rhs.count_) + return count_ < rhs.count_ ? -1 : 1; + + for (size_t i = count_; i-- > 0;) + if (digits_[i] != rhs.digits_[i]) + return digits_[i] < rhs.digits_[i] ? -1 : 1; + + return 0; + } + + size_t GetCount() const { return count_; } + Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } + bool IsZero() const { return count_ == 1 && digits_[0] == 0; } + +private: + void AppendDecimal64(const char* begin, const char* end) { + uint64_t u = ParseUint64(begin, end); + if (IsZero()) + *this = u; + else { + unsigned exp = static_cast(end - begin); + (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u + } + } + + void PushBack(Type digit) { + RAPIDJSON_ASSERT(count_ < kCapacity); + digits_[count_++] = digit; + } + + static uint64_t ParseUint64(const char* begin, const char* end) { + uint64_t r = 0; + for (const char* p = begin; p != end; ++p) { + RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); + r = r * 10u + static_cast(*p - '0'); + } + return r; + } + + // Assume a * b + k < 2^128 + static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t low = _umul128(a, b, outHigh) + k; + if (low < k) + (*outHigh)++; + return low; +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + __extension__ typedef unsigned __int128 uint128; + uint128 p = static_cast(a) * static_cast(b); + p += k; + *outHigh = static_cast(p >> 64); + return static_cast(p); +#else + const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; + uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; + x1 += (x0 >> 32); // can't give carry + x1 += x2; + if (x1 < x2) + x3 += (static_cast(1) << 32); + uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); + uint64_t hi = x3 + (x1 >> 32); + + lo += k; + if (lo < k) + hi++; + *outHigh = hi; + return lo; +#endif + } + + static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 + static const size_t kCapacity = kBitCount / sizeof(Type); + static const size_t kTypeBit = sizeof(Type) * 8; + + Type digits_[kCapacity]; + size_t count_; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_BIGINTEGER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/diyfp.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/diyfp.h new file mode 100644 index 0000000000000000000000000000000000000000..c9fefdc6139b8312834d941b83985d1573554055 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/diyfp.h @@ -0,0 +1,258 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// This is a C++ header-only implementation of Grisu2 algorithm from the publication: +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with +// integers." ACM Sigplan Notices 45.6 (2010): 233-243. + +#ifndef RAPIDJSON_DIYFP_H_ +#define RAPIDJSON_DIYFP_H_ + +#include "../rapidjson.h" + +#if defined(_MSC_VER) && defined(_M_AMD64) +#include +#pragma intrinsic(_BitScanReverse64) +#pragma intrinsic(_umul128) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +struct DiyFp { + DiyFp() : f(), e() {} + + DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} + + explicit DiyFp(double d) { + union { + double d; + uint64_t u64; + } u = { d }; + + int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); + uint64_t significand = (u.u64 & kDpSignificandMask); + if (biased_e != 0) { + f = significand + kDpHiddenBit; + e = biased_e - kDpExponentBias; + } + else { + f = significand; + e = kDpMinExponent + 1; + } + } + + DiyFp operator-(const DiyFp& rhs) const { + return DiyFp(f - rhs.f, e); + } + + DiyFp operator*(const DiyFp& rhs) const { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t h; + uint64_t l = _umul128(f, rhs.f, &h); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + __extension__ typedef unsigned __int128 uint128; + uint128 p = static_cast(f) * static_cast(rhs.f); + uint64_t h = static_cast(p >> 64); + uint64_t l = static_cast(p); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#else + const uint64_t M32 = 0xFFFFFFFF; + const uint64_t a = f >> 32; + const uint64_t b = f & M32; + const uint64_t c = rhs.f >> 32; + const uint64_t d = rhs.f & M32; + const uint64_t ac = a * c; + const uint64_t bc = b * c; + const uint64_t ad = a * d; + const uint64_t bd = b * d; + uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); + tmp += 1U << 31; /// mult_round + return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); +#endif + } + + DiyFp Normalize() const { +#if defined(_MSC_VER) && defined(_M_AMD64) + unsigned long index; + _BitScanReverse64(&index, f); + return DiyFp(f << (63 - index), e - (63 - index)); +#elif defined(__GNUC__) && __GNUC__ >= 4 + int s = __builtin_clzll(f); + return DiyFp(f << s, e - s); +#else + DiyFp res = *this; + while (!(res.f & (static_cast(1) << 63))) { + res.f <<= 1; + res.e--; + } + return res; +#endif + } + + DiyFp NormalizeBoundary() const { + DiyFp res = *this; + while (!(res.f & (kDpHiddenBit << 1))) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); + return res; + } + + void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *plus = pl; + *minus = mi; + } + + double ToDouble() const { + union { + double d; + uint64_t u64; + }u; + const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : + static_cast(e + kDpExponentBias); + u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); + return u.d; + } + + static const int kDiySignificandSize = 64; + static const int kDpSignificandSize = 52; + static const int kDpExponentBias = 0x3FF + kDpSignificandSize; + static const int kDpMaxExponent = 0x7FF - kDpExponentBias; + static const int kDpMinExponent = -kDpExponentBias; + static const int kDpDenormalExponent = -kDpExponentBias + 1; + static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + + uint64_t f; + int e; +}; + +inline DiyFp GetCachedPowerByIndex(size_t index) { + // 10^-348, 10^-340, ..., 10^340 + static const uint64_t kCachedPowers_F[] = { + RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), + RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), + RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), + RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), + RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), + RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), + RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), + RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), + RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), + RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), + RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), + RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), + RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), + RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), + RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), + RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), + RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), + RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), + RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), + RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), + RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), + RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), + RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), + RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), + RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), + RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), + RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), + RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), + RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), + RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), + RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), + RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), + RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), + RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), + RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), + RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), + RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), + RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), + RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), + RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), + RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), + RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), + RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), + RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) + }; + static const int16_t kCachedPowers_E[] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, + -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, + -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, + -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, + -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, + 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, + 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, + 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, + 907, 933, 960, 986, 1013, 1039, 1066 + }; + return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); +} + +inline DiyFp GetCachedPower(int e, int* K) { + + //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; + double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive + int k = static_cast(dk); + if (dk - k > 0.0) + k++; + + unsigned index = static_cast((k >> 3) + 1); + *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table + + return GetCachedPowerByIndex(index); +} + +inline DiyFp GetCachedPower10(int exp, int *outExp) { + unsigned index = (static_cast(exp) + 348u) / 8u; + *outExp = -348 + static_cast(index) * 8; + return GetCachedPowerByIndex(index); + } + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_OFF(padded) +#endif + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_DIYFP_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/dtoa.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/dtoa.h new file mode 100644 index 0000000000000000000000000000000000000000..8d6350e626d01f0ed98e1d6868b3af66fd317e53 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/dtoa.h @@ -0,0 +1,245 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// This is a C++ header-only implementation of Grisu2 algorithm from the publication: +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with +// integers." ACM Sigplan Notices 45.6 (2010): 233-243. + +#ifndef RAPIDJSON_DTOA_ +#define RAPIDJSON_DTOA_ + +#include "itoa.h" // GetDigitsLut() +#include "diyfp.h" +#include "ieee754.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 +#endif + +inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { + while (rest < wp_w && delta - rest >= ten_kappa && + (rest + ten_kappa < wp_w || /// closer + wp_w - rest > rest + ten_kappa - wp_w)) { + buffer[len - 1]--; + rest += ten_kappa; + } +} + +inline unsigned CountDecimalDigit32(uint32_t n) { + // Simple pure C++ implementation was faster than __builtin_clz version in this situation. + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + // Will not reach 10 digits in DigitGen() + //if (n < 1000000000) return 9; + //return 10; + return 9; +} + +inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { + static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); + const DiyFp wp_w = Mp - W; + uint32_t p1 = static_cast(Mp.f >> -one.e); + uint64_t p2 = Mp.f & (one.f - 1); + unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] + *len = 0; + + while (kappa > 0) { + uint32_t d = 0; + switch (kappa) { + case 9: d = p1 / 100000000; p1 %= 100000000; break; + case 8: d = p1 / 10000000; p1 %= 10000000; break; + case 7: d = p1 / 1000000; p1 %= 1000000; break; + case 6: d = p1 / 100000; p1 %= 100000; break; + case 5: d = p1 / 10000; p1 %= 10000; break; + case 4: d = p1 / 1000; p1 %= 1000; break; + case 3: d = p1 / 100; p1 %= 100; break; + case 2: d = p1 / 10; p1 %= 10; break; + case 1: d = p1; p1 = 0; break; + default:; + } + if (d || *len) + buffer[(*len)++] = static_cast('0' + static_cast(d)); + kappa--; + uint64_t tmp = (static_cast(p1) << -one.e) + p2; + if (tmp <= delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); + return; + } + } + + // kappa = 0 + for (;;) { + p2 *= 10; + delta *= 10; + char d = static_cast(p2 >> -one.e); + if (d || *len) + buffer[(*len)++] = static_cast('0' + d); + p2 &= one.f - 1; + kappa--; + if (p2 < delta) { + *K += kappa; + int index = -static_cast(kappa); + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast(kappa)] : 0)); + return; + } + } +} + +inline void Grisu2(double value, char* buffer, int* length, int* K) { + const DiyFp v(value); + DiyFp w_m, w_p; + v.NormalizedBoundaries(&w_m, &w_p); + + const DiyFp c_mk = GetCachedPower(w_p.e, K); + const DiyFp W = v.Normalize() * c_mk; + DiyFp Wp = w_p * c_mk; + DiyFp Wm = w_m * c_mk; + Wm.f++; + Wp.f--; + DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); +} + +inline char* WriteExponent(int K, char* buffer) { + if (K < 0) { + *buffer++ = '-'; + K = -K; + } + + if (K >= 100) { + *buffer++ = static_cast('0' + static_cast(K / 100)); + K %= 100; + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else if (K >= 10) { + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else + *buffer++ = static_cast('0' + static_cast(K)); + + return buffer; +} + +inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { + const int kk = length + k; // 10^(kk-1) <= v < 10^kk + + if (0 <= k && kk <= 21) { + // 1234e7 -> 12340000000 + for (int i = length; i < kk; i++) + buffer[i] = '0'; + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + return &buffer[kk + 2]; + } + else if (0 < kk && kk <= 21) { + // 1234e-2 -> 12.34 + std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); + buffer[kk] = '.'; + if (0 > k + maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[kk + 2]; // Reserve one zero + } + else + return &buffer[length + 1]; + } + else if (-6 < kk && kk <= 0) { + // 1234e-6 -> 0.001234 + const int offset = 2 - kk; + std::memmove(&buffer[offset], &buffer[0], static_cast(length)); + buffer[0] = '0'; + buffer[1] = '.'; + for (int i = 2; i < offset; i++) + buffer[i] = '0'; + if (length - kk > maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = maxDecimalPlaces + 1; i > 2; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[3]; // Reserve one zero + } + else + return &buffer[length + offset]; + } + else if (kk < -maxDecimalPlaces) { + // Truncate to zero + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else if (length == 1) { + // 1e30 + buffer[1] = 'e'; + return WriteExponent(kk - 1, &buffer[2]); + } + else { + // 1234e30 -> 1.234e33 + std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); + buffer[1] = '.'; + buffer[length + 1] = 'e'; + return WriteExponent(kk - 1, &buffer[0 + length + 2]); + } +} + +inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { + RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); + Double d(value); + if (d.IsZero()) { + if (d.Sign()) + *buffer++ = '-'; // -0.0, Issue #289 + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else { + if (value < 0) { + *buffer++ = '-'; + value = -value; + } + int length, K; + Grisu2(value, buffer, &length, &K); + return Prettify(buffer, length, K, maxDecimalPlaces); + } +} + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_DTOA_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/ieee754.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/ieee754.h new file mode 100644 index 0000000000000000000000000000000000000000..82bb0b99e5c247dde8999df261be91e0697e1420 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/ieee754.h @@ -0,0 +1,78 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_IEEE754_ +#define RAPIDJSON_IEEE754_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +class Double { +public: + Double() {} + Double(double d) : d_(d) {} + Double(uint64_t u) : u_(u) {} + + double Value() const { return d_; } + uint64_t Uint64Value() const { return u_; } + + double NextPositiveDouble() const { + RAPIDJSON_ASSERT(!Sign()); + return Double(u_ + 1).Value(); + } + + bool Sign() const { return (u_ & kSignMask) != 0; } + uint64_t Significand() const { return u_ & kSignificandMask; } + int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } + + bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } + bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } + bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } + bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } + bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } + + uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } + int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } + uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } + + static unsigned EffectiveSignificandSize(int order) { + if (order >= -1021) + return 53; + else if (order <= -1074) + return 0; + else + return static_cast(order) + 1074; + } + +private: + static const int kSignificandSize = 52; + static const int kExponentBias = 0x3FF; + static const int kDenormalExponent = 1 - kExponentBias; + static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); + static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + + union { + double d_; + uint64_t u_; + }; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_IEEE754_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/itoa.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/itoa.h new file mode 100644 index 0000000000000000000000000000000000000000..01a4e7e72d7268de6866a5bde9df91aa8114b9d4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/itoa.h @@ -0,0 +1,304 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ITOA_ +#define RAPIDJSON_ITOA_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +inline const char* GetDigitsLut() { + static const char cDigitsLut[200] = { + '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', + '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', + '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', + '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', + '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', + '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', + '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', + '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', + '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', + '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' + }; + return cDigitsLut; +} + +inline char* u32toa(uint32_t value, char* buffer) { + const char* cDigitsLut = GetDigitsLut(); + + if (value < 10000) { + const uint32_t d1 = (value / 100) << 1; + const uint32_t d2 = (value % 100) << 1; + + if (value >= 1000) + *buffer++ = cDigitsLut[d1]; + if (value >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + } + else if (value < 100000000) { + // value = bbbbcccc + const uint32_t b = value / 10000; + const uint32_t c = value % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + if (value >= 10000000) + *buffer++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + else { + // value = aabbbbcccc in decimal + + const uint32_t a = value / 100000000; // 1 to 42 + value %= 100000000; + + if (a >= 10) { + const unsigned i = a << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else + *buffer++ = static_cast('0' + static_cast(a)); + + const uint32_t b = value / 10000; // 0 to 9999 + const uint32_t c = value % 10000; // 0 to 9999 + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + *buffer++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + return buffer; +} + +inline char* i32toa(int32_t value, char* buffer) { + uint32_t u = static_cast(value); + if (value < 0) { + *buffer++ = '-'; + u = ~u + 1; + } + + return u32toa(u, buffer); +} + +inline char* u64toa(uint64_t value, char* buffer) { + const char* cDigitsLut = GetDigitsLut(); + const uint64_t kTen8 = 100000000; + const uint64_t kTen9 = kTen8 * 10; + const uint64_t kTen10 = kTen8 * 100; + const uint64_t kTen11 = kTen8 * 1000; + const uint64_t kTen12 = kTen8 * 10000; + const uint64_t kTen13 = kTen8 * 100000; + const uint64_t kTen14 = kTen8 * 1000000; + const uint64_t kTen15 = kTen8 * 10000000; + const uint64_t kTen16 = kTen8 * kTen8; + + if (value < kTen8) { + uint32_t v = static_cast(value); + if (v < 10000) { + const uint32_t d1 = (v / 100) << 1; + const uint32_t d2 = (v % 100) << 1; + + if (v >= 1000) + *buffer++ = cDigitsLut[d1]; + if (v >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (v >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + } + else { + // value = bbbbcccc + const uint32_t b = v / 10000; + const uint32_t c = v % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + if (value >= 10000000) + *buffer++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + } + else if (value < kTen16) { + const uint32_t v0 = static_cast(value / kTen8); + const uint32_t v1 = static_cast(value % kTen8); + + const uint32_t b0 = v0 / 10000; + const uint32_t c0 = v0 % 10000; + + const uint32_t d1 = (b0 / 100) << 1; + const uint32_t d2 = (b0 % 100) << 1; + + const uint32_t d3 = (c0 / 100) << 1; + const uint32_t d4 = (c0 % 100) << 1; + + const uint32_t b1 = v1 / 10000; + const uint32_t c1 = v1 % 10000; + + const uint32_t d5 = (b1 / 100) << 1; + const uint32_t d6 = (b1 % 100) << 1; + + const uint32_t d7 = (c1 / 100) << 1; + const uint32_t d8 = (c1 % 100) << 1; + + if (value >= kTen15) + *buffer++ = cDigitsLut[d1]; + if (value >= kTen14) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= kTen13) + *buffer++ = cDigitsLut[d2]; + if (value >= kTen12) + *buffer++ = cDigitsLut[d2 + 1]; + if (value >= kTen11) + *buffer++ = cDigitsLut[d3]; + if (value >= kTen10) + *buffer++ = cDigitsLut[d3 + 1]; + if (value >= kTen9) + *buffer++ = cDigitsLut[d4]; + if (value >= kTen8) + *buffer++ = cDigitsLut[d4 + 1]; + + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + else { + const uint32_t a = static_cast(value / kTen16); // 1 to 1844 + value %= kTen16; + + if (a < 10) + *buffer++ = static_cast('0' + static_cast(a)); + else if (a < 100) { + const uint32_t i = a << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else if (a < 1000) { + *buffer++ = static_cast('0' + static_cast(a / 100)); + + const uint32_t i = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else { + const uint32_t i = (a / 100) << 1; + const uint32_t j = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + *buffer++ = cDigitsLut[j]; + *buffer++ = cDigitsLut[j + 1]; + } + + const uint32_t v0 = static_cast(value / kTen8); + const uint32_t v1 = static_cast(value % kTen8); + + const uint32_t b0 = v0 / 10000; + const uint32_t c0 = v0 % 10000; + + const uint32_t d1 = (b0 / 100) << 1; + const uint32_t d2 = (b0 % 100) << 1; + + const uint32_t d3 = (c0 / 100) << 1; + const uint32_t d4 = (c0 % 100) << 1; + + const uint32_t b1 = v1 / 10000; + const uint32_t c1 = v1 % 10000; + + const uint32_t d5 = (b1 / 100) << 1; + const uint32_t d6 = (b1 % 100) << 1; + + const uint32_t d7 = (c1 / 100) << 1; + const uint32_t d8 = (c1 % 100) << 1; + + *buffer++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + + return buffer; +} + +inline char* i64toa(int64_t value, char* buffer) { + uint64_t u = static_cast(value); + if (value < 0) { + *buffer++ = '-'; + u = ~u + 1; + } + + return u64toa(u, buffer); +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ITOA_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/meta.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/meta.h new file mode 100644 index 0000000000000000000000000000000000000000..5a9aaa42866d70fc426be74efbf27c53cdd52a42 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/meta.h @@ -0,0 +1,181 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_META_H_ +#define RAPIDJSON_INTERNAL_META_H_ + +#include "../rapidjson.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif +#if defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(6334) +#endif + +#if RAPIDJSON_HAS_CXX11_TYPETRAITS +#include +#endif + +//@cond RAPIDJSON_INTERNAL +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching +template struct Void { typedef void Type; }; + +/////////////////////////////////////////////////////////////////////////////// +// BoolType, TrueType, FalseType +// +template struct BoolType { + static const bool Value = Cond; + typedef BoolType Type; +}; +typedef BoolType TrueType; +typedef BoolType FalseType; + + +/////////////////////////////////////////////////////////////////////////////// +// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr +// + +template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; +template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; +template struct SelectIfCond : SelectIfImpl::template Apply {}; +template struct SelectIf : SelectIfCond {}; + +template struct AndExprCond : FalseType {}; +template <> struct AndExprCond : TrueType {}; +template struct OrExprCond : TrueType {}; +template <> struct OrExprCond : FalseType {}; + +template struct BoolExpr : SelectIf::Type {}; +template struct NotExpr : SelectIf::Type {}; +template struct AndExpr : AndExprCond::Type {}; +template struct OrExpr : OrExprCond::Type {}; + + +/////////////////////////////////////////////////////////////////////////////// +// AddConst, MaybeAddConst, RemoveConst +template struct AddConst { typedef const T Type; }; +template struct MaybeAddConst : SelectIfCond {}; +template struct RemoveConst { typedef T Type; }; +template struct RemoveConst { typedef T Type; }; + + +/////////////////////////////////////////////////////////////////////////////// +// IsSame, IsConst, IsMoreConst, IsPointer +// +template struct IsSame : FalseType {}; +template struct IsSame : TrueType {}; + +template struct IsConst : FalseType {}; +template struct IsConst : TrueType {}; + +template +struct IsMoreConst + : AndExpr::Type, typename RemoveConst::Type>, + BoolType::Value >= IsConst::Value> >::Type {}; + +template struct IsPointer : FalseType {}; +template struct IsPointer : TrueType {}; + +/////////////////////////////////////////////////////////////////////////////// +// IsBaseOf +// +#if RAPIDJSON_HAS_CXX11_TYPETRAITS + +template struct IsBaseOf + : BoolType< ::std::is_base_of::value> {}; + +#else // simplified version adopted from Boost + +template struct IsBaseOfImpl { + RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); + RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); + + typedef char (&Yes)[1]; + typedef char (&No) [2]; + + template + static Yes Check(const D*, T); + static No Check(const B*, int); + + struct Host { + operator const B*() const; + operator const D*(); + }; + + enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; +}; + +template struct IsBaseOf + : OrExpr, BoolExpr > >::Type {}; + +#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS + + +////////////////////////////////////////////////////////////////////////// +// EnableIf / DisableIf +// +template struct EnableIfCond { typedef T Type; }; +template struct EnableIfCond { /* empty */ }; + +template struct DisableIfCond { typedef T Type; }; +template struct DisableIfCond { /* empty */ }; + +template +struct EnableIf : EnableIfCond {}; + +template +struct DisableIf : DisableIfCond {}; + +// SFINAE helpers +struct SfinaeTag {}; +template struct RemoveSfinaeTag; +template struct RemoveSfinaeTag { typedef T Type; }; + +#define RAPIDJSON_REMOVEFPTR_(type) \ + typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ + < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type + +#define RAPIDJSON_ENABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type * = NULL + +#define RAPIDJSON_DISABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type * = NULL + +#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type + +#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type + +} // namespace internal +RAPIDJSON_NAMESPACE_END +//@endcond + +#if defined(__GNUC__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_META_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/pow10.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/pow10.h new file mode 100644 index 0000000000000000000000000000000000000000..02f475d705fcbc478c38b529863210595ffe14c4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/pow10.h @@ -0,0 +1,55 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_POW10_ +#define RAPIDJSON_POW10_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Computes integer powers of 10 in double (10.0^n). +/*! This function uses lookup table for fast and accurate results. + \param n non-negative exponent. Must <= 308. + \return 10.0^n +*/ +inline double Pow10(int n) { + static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes + 1e+0, + 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, + 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, + 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, + 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, + 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, + 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, + 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, + 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, + 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, + 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, + 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, + 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, + 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, + 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, + 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, + 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 + }; + RAPIDJSON_ASSERT(n >= 0 && n <= 308); + return e[n]; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_POW10_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/regex.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/regex.h new file mode 100644 index 0000000000000000000000000000000000000000..422a5240bf568017e1c21d191cfa5f343194ec29 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/regex.h @@ -0,0 +1,701 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_REGEX_H_ +#define RAPIDJSON_INTERNAL_REGEX_H_ + +#include "../allocators.h" +#include "../stream.h" +#include "stack.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(implicit-fallthrough) +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +#ifndef RAPIDJSON_REGEX_VERBOSE +#define RAPIDJSON_REGEX_VERBOSE 0 +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +/////////////////////////////////////////////////////////////////////////////// +// GenericRegex + +static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 +static const SizeType kRegexInvalidRange = ~SizeType(0); + +//! Regular expression engine with subset of ECMAscript grammar. +/*! + Supported regular expression syntax: + - \c ab Concatenation + - \c a|b Alternation + - \c a? Zero or one + - \c a* Zero or more + - \c a+ One or more + - \c a{3} Exactly 3 times + - \c a{3,} At least 3 times + - \c a{3,5} 3 to 5 times + - \c (ab) Grouping + - \c ^a At the beginning + - \c a$ At the end + - \c . Any character + - \c [abc] Character classes + - \c [a-c] Character class range + - \c [a-z0-9_] Character class combination + - \c [^abc] Negated character classes + - \c [^a-c] Negated character class range + - \c [\b] Backspace (U+0008) + - \c \\| \\\\ ... Escape characters + - \c \\f Form feed (U+000C) + - \c \\n Line feed (U+000A) + - \c \\r Carriage return (U+000D) + - \c \\t Tab (U+0009) + - \c \\v Vertical tab (U+000B) + + \note This is a Thompson NFA engine, implemented with reference to + Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", + https://swtch.com/~rsc/regexp/regexp1.html +*/ +template +class GenericRegex { +public: + typedef typename Encoding::Ch Ch; + + GenericRegex(const Ch* source, Allocator* allocator = 0) : + states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), + stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_() + { + GenericStringStream ss(source); + DecodedStream > ds(ss); + Parse(ds); + } + + ~GenericRegex() { + Allocator::Free(stateSet_); + } + + bool IsValid() const { + return root_ != kRegexInvalidState; + } + + template + bool Match(InputStream& is) const { + return SearchWithAnchoring(is, true, true); + } + + bool Match(const Ch* s) const { + GenericStringStream is(s); + return Match(is); + } + + template + bool Search(InputStream& is) const { + return SearchWithAnchoring(is, anchorBegin_, anchorEnd_); + } + + bool Search(const Ch* s) const { + GenericStringStream is(s); + return Search(is); + } + +private: + enum Operator { + kZeroOrOne, + kZeroOrMore, + kOneOrMore, + kConcatenation, + kAlternation, + kLeftParenthesis + }; + + static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.' + static const unsigned kRangeCharacterClass = 0xFFFFFFFE; + static const unsigned kRangeNegationFlag = 0x80000000; + + struct Range { + unsigned start; // + unsigned end; + SizeType next; + }; + + struct State { + SizeType out; //!< Equals to kInvalid for matching state + SizeType out1; //!< Equals to non-kInvalid for split + SizeType rangeStart; + unsigned codepoint; + }; + + struct Frag { + Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} + SizeType start; + SizeType out; //!< link-list of all output states + SizeType minIndex; + }; + + template + class DecodedStream { + public: + DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } + unsigned Peek() { return codepoint_; } + unsigned Take() { + unsigned c = codepoint_; + if (c) // No further decoding when '\0' + Decode(); + return c; + } + + private: + void Decode() { + if (!Encoding::Decode(ss_, &codepoint_)) + codepoint_ = 0; + } + + SourceStream& ss_; + unsigned codepoint_; + }; + + State& GetState(SizeType index) { + RAPIDJSON_ASSERT(index < stateCount_); + return states_.template Bottom()[index]; + } + + const State& GetState(SizeType index) const { + RAPIDJSON_ASSERT(index < stateCount_); + return states_.template Bottom()[index]; + } + + Range& GetRange(SizeType index) { + RAPIDJSON_ASSERT(index < rangeCount_); + return ranges_.template Bottom()[index]; + } + + const Range& GetRange(SizeType index) const { + RAPIDJSON_ASSERT(index < rangeCount_); + return ranges_.template Bottom()[index]; + } + + template + void Parse(DecodedStream& ds) { + Allocator allocator; + Stack operandStack(&allocator, 256); // Frag + Stack operatorStack(&allocator, 256); // Operator + Stack atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis) + + *atomCountStack.template Push() = 0; + + unsigned codepoint; + while (ds.Peek() != 0) { + switch (codepoint = ds.Take()) { + case '^': + anchorBegin_ = true; + break; + + case '$': + anchorEnd_ = true; + break; + + case '|': + while (!operatorStack.Empty() && *operatorStack.template Top() < kAlternation) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + *operatorStack.template Push() = kAlternation; + *atomCountStack.template Top() = 0; + break; + + case '(': + *operatorStack.template Push() = kLeftParenthesis; + *atomCountStack.template Push() = 0; + break; + + case ')': + while (!operatorStack.Empty() && *operatorStack.template Top() != kLeftParenthesis) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + if (operatorStack.Empty()) + return; + operatorStack.template Pop(1); + atomCountStack.template Pop(1); + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '?': + if (!Eval(operandStack, kZeroOrOne)) + return; + break; + + case '*': + if (!Eval(operandStack, kZeroOrMore)) + return; + break; + + case '+': + if (!Eval(operandStack, kOneOrMore)) + return; + break; + + case '{': + { + unsigned n, m; + if (!ParseUnsigned(ds, &n)) + return; + + if (ds.Peek() == ',') { + ds.Take(); + if (ds.Peek() == '}') + m = kInfinityQuantifier; + else if (!ParseUnsigned(ds, &m) || m < n) + return; + } + else + m = n; + + if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') + return; + ds.Take(); + } + break; + + case '.': + PushOperand(operandStack, kAnyCharacterClass); + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '[': + { + SizeType range; + if (!ParseRange(ds, &range)) + return; + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); + GetState(s).rangeStart = range; + *operandStack.template Push() = Frag(s, s, s); + } + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '\\': // Escape character + if (!CharacterEscape(ds, &codepoint)) + return; // Unsupported escape character + // fall through to default + + default: // Pattern character + PushOperand(operandStack, codepoint); + ImplicitConcatenation(atomCountStack, operatorStack); + } + } + + while (!operatorStack.Empty()) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + + // Link the operand to matching state. + if (operandStack.GetSize() == sizeof(Frag)) { + Frag* e = operandStack.template Pop(1); + Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); + root_ = e->start; + +#if RAPIDJSON_REGEX_VERBOSE + printf("root: %d\n", root_); + for (SizeType i = 0; i < stateCount_ ; i++) { + State& s = GetState(i); + printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); + } + printf("\n"); +#endif + } + + // Preallocate buffer for SearchWithAnchoring() + RAPIDJSON_ASSERT(stateSet_ == 0); + if (stateCount_ > 0) { + stateSet_ = static_cast(states_.GetAllocator().Malloc(GetStateSetSize())); + state0_.template Reserve(stateCount_); + state1_.template Reserve(stateCount_); + } + } + + SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { + State* s = states_.template Push(); + s->out = out; + s->out1 = out1; + s->codepoint = codepoint; + s->rangeStart = kRegexInvalidRange; + return stateCount_++; + } + + void PushOperand(Stack& operandStack, unsigned codepoint) { + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); + *operandStack.template Push() = Frag(s, s, s); + } + + void ImplicitConcatenation(Stack& atomCountStack, Stack& operatorStack) { + if (*atomCountStack.template Top()) + *operatorStack.template Push() = kConcatenation; + (*atomCountStack.template Top())++; + } + + SizeType Append(SizeType l1, SizeType l2) { + SizeType old = l1; + while (GetState(l1).out != kRegexInvalidState) + l1 = GetState(l1).out; + GetState(l1).out = l2; + return old; + } + + void Patch(SizeType l, SizeType s) { + for (SizeType next; l != kRegexInvalidState; l = next) { + next = GetState(l).out; + GetState(l).out = s; + } + } + + bool Eval(Stack& operandStack, Operator op) { + switch (op) { + case kConcatenation: + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); + { + Frag e2 = *operandStack.template Pop(1); + Frag e1 = *operandStack.template Pop(1); + Patch(e1.out, e2.start); + *operandStack.template Push() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); + } + return true; + + case kAlternation: + if (operandStack.GetSize() >= sizeof(Frag) * 2) { + Frag e2 = *operandStack.template Pop(1); + Frag e1 = *operandStack.template Pop(1); + SizeType s = NewState(e1.start, e2.start, 0); + *operandStack.template Push() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex)); + return true; + } + return false; + + case kZeroOrOne: + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + *operandStack.template Push() = Frag(s, Append(e.out, s), e.minIndex); + return true; + } + return false; + + case kZeroOrMore: + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + Patch(e.out, s); + *operandStack.template Push() = Frag(s, s, e.minIndex); + return true; + } + return false; + + default: + RAPIDJSON_ASSERT(op == kOneOrMore); + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + Patch(e.out, s); + *operandStack.template Push() = Frag(e.start, s, e.minIndex); + return true; + } + return false; + } + } + + bool EvalQuantifier(Stack& operandStack, unsigned n, unsigned m) { + RAPIDJSON_ASSERT(n <= m); + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); + + if (n == 0) { + if (m == 0) // a{0} not support + return false; + else if (m == kInfinityQuantifier) + Eval(operandStack, kZeroOrMore); // a{0,} -> a* + else { + Eval(operandStack, kZeroOrOne); // a{0,5} -> a? + for (unsigned i = 0; i < m - 1; i++) + CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? + for (unsigned i = 0; i < m - 1; i++) + Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? + } + return true; + } + + for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a + CloneTopOperand(operandStack); + + if (m == kInfinityQuantifier) + Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ + else if (m > n) { + CloneTopOperand(operandStack); // a{3,5} -> a a a a + Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? + for (unsigned i = n; i < m - 1; i++) + CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? + for (unsigned i = n; i < m; i++) + Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? + } + + for (unsigned i = 0; i < n - 1; i++) + Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? + + return true; + } + + static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } + + void CloneTopOperand(Stack& operandStack) { + const Frag src = *operandStack.template Top(); // Copy constructor to prevent invalidation + SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) + State* s = states_.template Push(count); + memcpy(s, &GetState(src.minIndex), count * sizeof(State)); + for (SizeType j = 0; j < count; j++) { + if (s[j].out != kRegexInvalidState) + s[j].out += count; + if (s[j].out1 != kRegexInvalidState) + s[j].out1 += count; + } + *operandStack.template Push() = Frag(src.start + count, src.out + count, src.minIndex + count); + stateCount_ += count; + } + + template + bool ParseUnsigned(DecodedStream& ds, unsigned* u) { + unsigned r = 0; + if (ds.Peek() < '0' || ds.Peek() > '9') + return false; + while (ds.Peek() >= '0' && ds.Peek() <= '9') { + if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 + return false; // overflow + r = r * 10 + (ds.Take() - '0'); + } + *u = r; + return true; + } + + template + bool ParseRange(DecodedStream& ds, SizeType* range) { + bool isBegin = true; + bool negate = false; + int step = 0; + SizeType start = kRegexInvalidRange; + SizeType current = kRegexInvalidRange; + unsigned codepoint; + while ((codepoint = ds.Take()) != 0) { + if (isBegin) { + isBegin = false; + if (codepoint == '^') { + negate = true; + continue; + } + } + + switch (codepoint) { + case ']': + if (start == kRegexInvalidRange) + return false; // Error: nothing inside [] + if (step == 2) { // Add trailing '-' + SizeType r = NewRange('-'); + RAPIDJSON_ASSERT(current != kRegexInvalidRange); + GetRange(current).next = r; + } + if (negate) + GetRange(start).start |= kRangeNegationFlag; + *range = start; + return true; + + case '\\': + if (ds.Peek() == 'b') { + ds.Take(); + codepoint = 0x0008; // Escape backspace character + } + else if (!CharacterEscape(ds, &codepoint)) + return false; + // fall through to default + + default: + switch (step) { + case 1: + if (codepoint == '-') { + step++; + break; + } + // fall through to step 0 for other characters + + case 0: + { + SizeType r = NewRange(codepoint); + if (current != kRegexInvalidRange) + GetRange(current).next = r; + if (start == kRegexInvalidRange) + start = r; + current = r; + } + step = 1; + break; + + default: + RAPIDJSON_ASSERT(step == 2); + GetRange(current).end = codepoint; + step = 0; + } + } + } + return false; + } + + SizeType NewRange(unsigned codepoint) { + Range* r = ranges_.template Push(); + r->start = r->end = codepoint; + r->next = kRegexInvalidRange; + return rangeCount_++; + } + + template + bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { + unsigned codepoint; + switch (codepoint = ds.Take()) { + case '^': + case '$': + case '|': + case '(': + case ')': + case '?': + case '*': + case '+': + case '.': + case '[': + case ']': + case '{': + case '}': + case '\\': + *escapedCodepoint = codepoint; return true; + case 'f': *escapedCodepoint = 0x000C; return true; + case 'n': *escapedCodepoint = 0x000A; return true; + case 'r': *escapedCodepoint = 0x000D; return true; + case 't': *escapedCodepoint = 0x0009; return true; + case 'v': *escapedCodepoint = 0x000B; return true; + default: + return false; // Unsupported escape character + } + } + + template + bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const { + RAPIDJSON_ASSERT(IsValid()); + DecodedStream ds(is); + + state0_.Clear(); + Stack *current = &state0_, *next = &state1_; + const size_t stateSetSize = GetStateSetSize(); + std::memset(stateSet_, 0, stateSetSize); + + bool matched = AddState(*current, root_); + unsigned codepoint; + while (!current->Empty() && (codepoint = ds.Take()) != 0) { + std::memset(stateSet_, 0, stateSetSize); + next->Clear(); + matched = false; + for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { + const State& sr = GetState(*s); + if (sr.codepoint == codepoint || + sr.codepoint == kAnyCharacterClass || + (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) + { + matched = AddState(*next, sr.out) || matched; + if (!anchorEnd && matched) + return true; + } + if (!anchorBegin) + AddState(*next, root_); + } + internal::Swap(current, next); + } + + return matched; + } + + size_t GetStateSetSize() const { + return (stateCount_ + 31) / 32 * 4; + } + + // Return whether the added states is a match state + bool AddState(Stack& l, SizeType index) const { + RAPIDJSON_ASSERT(index != kRegexInvalidState); + + const State& s = GetState(index); + if (s.out1 != kRegexInvalidState) { // Split + bool matched = AddState(l, s.out); + return AddState(l, s.out1) || matched; + } + else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) { + stateSet_[index >> 5] |= (1 << (index & 31)); + *l.template PushUnsafe() = index; + } + return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. + } + + bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { + bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0; + while (rangeIndex != kRegexInvalidRange) { + const Range& r = GetRange(rangeIndex); + if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end) + return yes; + rangeIndex = r.next; + } + return !yes; + } + + Stack states_; + Stack ranges_; + SizeType root_; + SizeType stateCount_; + SizeType rangeCount_; + + static const unsigned kInfinityQuantifier = ~0u; + + // For SearchWithAnchoring() + uint32_t* stateSet_; // allocated by states_.GetAllocator() + mutable Stack state0_; + mutable Stack state1_; + bool anchorBegin_; + bool anchorEnd_; +}; + +typedef GenericRegex > Regex; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_REGEX_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/stack.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/stack.h new file mode 100644 index 0000000000000000000000000000000000000000..022c9aab41173b19368736c4ad5804bf805a0a2b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/stack.h @@ -0,0 +1,230 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_STACK_H_ +#define RAPIDJSON_INTERNAL_STACK_H_ + +#include "../allocators.h" +#include "swap.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +/////////////////////////////////////////////////////////////////////////////// +// Stack + +//! A type-unsafe stack for storing different types of data. +/*! \tparam Allocator Allocator for allocating stack memory. +*/ +template +class Stack { +public: + // Optimization note: Do not allocate memory for stack_ in constructor. + // Do it lazily when first Push() -> Expand() -> Resize(). + Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Stack(Stack&& rhs) + : allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + stack_(rhs.stack_), + stackTop_(rhs.stackTop_), + stackEnd_(rhs.stackEnd_), + initialCapacity_(rhs.initialCapacity_) + { + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.stack_ = 0; + rhs.stackTop_ = 0; + rhs.stackEnd_ = 0; + rhs.initialCapacity_ = 0; + } +#endif + + ~Stack() { + Destroy(); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Stack& operator=(Stack&& rhs) { + if (&rhs != this) + { + Destroy(); + + allocator_ = rhs.allocator_; + ownAllocator_ = rhs.ownAllocator_; + stack_ = rhs.stack_; + stackTop_ = rhs.stackTop_; + stackEnd_ = rhs.stackEnd_; + initialCapacity_ = rhs.initialCapacity_; + + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.stack_ = 0; + rhs.stackTop_ = 0; + rhs.stackEnd_ = 0; + rhs.initialCapacity_ = 0; + } + return *this; + } +#endif + + void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(stack_, rhs.stack_); + internal::Swap(stackTop_, rhs.stackTop_); + internal::Swap(stackEnd_, rhs.stackEnd_); + internal::Swap(initialCapacity_, rhs.initialCapacity_); + } + + void Clear() { stackTop_ = stack_; } + + void ShrinkToFit() { + if (Empty()) { + // If the stack is empty, completely deallocate the memory. + Allocator::Free(stack_); + stack_ = 0; + stackTop_ = 0; + stackEnd_ = 0; + } + else + Resize(GetSize()); + } + + // Optimization note: try to minimize the size of this function for force inline. + // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. + template + RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { + // Expand the stack if needed + if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) + Expand(count); + } + + template + RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { + Reserve(count); + return PushUnsafe(count); + } + + template + RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { + RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); + T* ret = reinterpret_cast(stackTop_); + stackTop_ += sizeof(T) * count; + return ret; + } + + template + T* Pop(size_t count) { + RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); + stackTop_ -= count * sizeof(T); + return reinterpret_cast(stackTop_); + } + + template + T* Top() { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stackTop_ - sizeof(T)); + } + + template + const T* Top() const { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stackTop_ - sizeof(T)); + } + + template + T* End() { return reinterpret_cast(stackTop_); } + + template + const T* End() const { return reinterpret_cast(stackTop_); } + + template + T* Bottom() { return reinterpret_cast(stack_); } + + template + const T* Bottom() const { return reinterpret_cast(stack_); } + + bool HasAllocator() const { + return allocator_ != 0; + } + + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } + + bool Empty() const { return stackTop_ == stack_; } + size_t GetSize() const { return static_cast(stackTop_ - stack_); } + size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } + +private: + template + void Expand(size_t count) { + // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. + size_t newCapacity; + if (stack_ == 0) { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + newCapacity = initialCapacity_; + } else { + newCapacity = GetCapacity(); + newCapacity += (newCapacity + 1) / 2; + } + size_t newSize = GetSize() + sizeof(T) * count; + if (newCapacity < newSize) + newCapacity = newSize; + + Resize(newCapacity); + } + + void Resize(size_t newCapacity) { + const size_t size = GetSize(); // Backup the current size + stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); + stackTop_ = stack_ + size; + stackEnd_ = stack_ + newCapacity; + } + + void Destroy() { + Allocator::Free(stack_); + RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack + } + + // Prohibit copy constructor & assignment operator. + Stack(const Stack&); + Stack& operator=(const Stack&); + + Allocator* allocator_; + Allocator* ownAllocator_; + char *stack_; + char *stackTop_; + char *stackEnd_; + size_t initialCapacity_; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_STACK_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/strfunc.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/strfunc.h new file mode 100644 index 0000000000000000000000000000000000000000..2edfae526788916e12a2b474da5f4a10a875f042 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/strfunc.h @@ -0,0 +1,55 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ +#define RAPIDJSON_INTERNAL_STRFUNC_H_ + +#include "../stream.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Custom strlen() which works on different character types. +/*! \tparam Ch Character type (e.g. char, wchar_t, short) + \param s Null-terminated input string. + \return Number of characters in the string. + \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. +*/ +template +inline SizeType StrLen(const Ch* s) { + const Ch* p = s; + while (*p) ++p; + return SizeType(p - s); +} + +//! Returns number of code points in a encoded string. +template +bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { + GenericStringStream is(s); + const typename Encoding::Ch* end = s + length; + SizeType count = 0; + while (is.src_ < end) { + unsigned codepoint; + if (!Encoding::Decode(is, &codepoint)) + return false; + count++; + } + *outCount = count; + return true; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/strtod.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/strtod.h new file mode 100644 index 0000000000000000000000000000000000000000..289c413b07b04495cc32981e2c6979fbef0e0269 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/strtod.h @@ -0,0 +1,269 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_STRTOD_ +#define RAPIDJSON_STRTOD_ + +#include "ieee754.h" +#include "biginteger.h" +#include "diyfp.h" +#include "pow10.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +inline double FastPath(double significand, int exp) { + if (exp < -308) + return 0.0; + else if (exp >= 0) + return significand * internal::Pow10(exp); + else + return significand / internal::Pow10(-exp); +} + +inline double StrtodNormalPrecision(double d, int p) { + if (p < -308) { + // Prevent expSum < -308, making Pow10(p) = 0 + d = FastPath(d, -308); + d = FastPath(d, p + 308); + } + else + d = FastPath(d, p); + return d; +} + +template +inline T Min3(T a, T b, T c) { + T m = a; + if (m > b) m = b; + if (m > c) m = c; + return m; +} + +inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { + const Double db(b); + const uint64_t bInt = db.IntegerSignificand(); + const int bExp = db.IntegerExponent(); + const int hExp = bExp - 1; + + int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; + + // Adjust for decimal exponent + if (dExp >= 0) { + dS_Exp2 += dExp; + dS_Exp5 += dExp; + } + else { + bS_Exp2 -= dExp; + bS_Exp5 -= dExp; + hS_Exp2 -= dExp; + hS_Exp5 -= dExp; + } + + // Adjust for binary exponent + if (bExp >= 0) + bS_Exp2 += bExp; + else { + dS_Exp2 -= bExp; + hS_Exp2 -= bExp; + } + + // Adjust for half ulp exponent + if (hExp >= 0) + hS_Exp2 += hExp; + else { + dS_Exp2 -= hExp; + bS_Exp2 -= hExp; + } + + // Remove common power of two factor from all three scaled values + int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); + dS_Exp2 -= common_Exp2; + bS_Exp2 -= common_Exp2; + hS_Exp2 -= common_Exp2; + + BigInteger dS = d; + dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); + + BigInteger bS(bInt); + bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); + + BigInteger hS(1); + hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); + + BigInteger delta(0); + dS.Difference(bS, &delta); + + return delta.Compare(hS); +} + +inline bool StrtodFast(double d, int p, double* result) { + // Use fast path for string-to-double conversion if possible + // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + if (p > 22 && p < 22 + 16) { + // Fast Path Cases In Disguise + d *= internal::Pow10(p - 22); + p = 22; + } + + if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 + *result = FastPath(d, p); + return true; + } + else + return false; +} + +// Compute an approximation and see if it is within 1/2 ULP +inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { + uint64_t significand = 0; + size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 + for (; i < length; i++) { + if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || + (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) + break; + significand = significand * 10u + static_cast(decimals[i] - '0'); + } + + if (i < length && decimals[i] >= '5') // Rounding + significand++; + + size_t remaining = length - i; + const unsigned kUlpShift = 3; + const unsigned kUlp = 1 << kUlpShift; + int64_t error = (remaining == 0) ? 0 : kUlp / 2; + + DiyFp v(significand, 0); + v = v.Normalize(); + error <<= -v.e; + + const int dExp = static_cast(decimalPosition) - static_cast(i) + exp; + + int actualExp; + DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); + if (actualExp != dExp) { + static const DiyFp kPow10[] = { + DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 + DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 + DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 + DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 + DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 + DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 + DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 + }; + int adjustment = dExp - actualExp - 1; + RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); + v = v * kPow10[adjustment]; + if (length + static_cast(adjustment)> 19u) // has more digits than decimal digits in 64-bit + error += kUlp / 2; + } + + v = v * cachedPower; + + error += kUlp + (error == 0 ? 0 : 1); + + const int oldExp = v.e; + v = v.Normalize(); + error <<= oldExp - v.e; + + const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); + unsigned precisionSize = 64 - effectiveSignificandSize; + if (precisionSize + kUlpShift >= 64) { + unsigned scaleExp = (precisionSize + kUlpShift) - 63; + v.f >>= scaleExp; + v.e += scaleExp; + error = (error >> scaleExp) + 1 + static_cast(kUlp); + precisionSize -= scaleExp; + } + + DiyFp rounded(v.f >> precisionSize, v.e + static_cast(precisionSize)); + const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; + const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; + if (precisionBits >= halfWay + static_cast(error)) { + rounded.f++; + if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) + rounded.f >>= 1; + rounded.e++; + } + } + + *result = rounded.ToDouble(); + + return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); +} + +inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { + const BigInteger dInt(decimals, length); + const int dExp = static_cast(decimalPosition) - static_cast(length) + exp; + Double a(approx); + int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); + if (cmp < 0) + return a.Value(); // within half ULP + else if (cmp == 0) { + // Round towards even + if (a.Significand() & 1) + return a.NextPositiveDouble(); + else + return a.Value(); + } + else // adjustment + return a.NextPositiveDouble(); +} + +inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { + RAPIDJSON_ASSERT(d >= 0.0); + RAPIDJSON_ASSERT(length >= 1); + + double result; + if (StrtodFast(d, p, &result)) + return result; + + // Trim leading zeros + while (*decimals == '0' && length > 1) { + length--; + decimals++; + decimalPosition--; + } + + // Trim trailing zeros + while (decimals[length - 1] == '0' && length > 1) { + length--; + decimalPosition--; + exp++; + } + + // Trim right-most digits + const int kMaxDecimalDigit = 780; + if (static_cast(length) > kMaxDecimalDigit) { + int delta = (static_cast(length) - kMaxDecimalDigit); + exp += delta; + decimalPosition -= static_cast(delta); + length = kMaxDecimalDigit; + } + + // If too small, underflow to zero + if (int(length) + exp < -324) + return 0.0; + + if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) + return result; + + // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison + return StrtodBigInteger(result, decimals, length, decimalPosition, exp); +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STRTOD_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/swap.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/swap.h new file mode 100644 index 0000000000000000000000000000000000000000..666e49f97b68d9dbf42304346391d4d2f82cd0bd --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/internal/swap.h @@ -0,0 +1,46 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_SWAP_H_ +#define RAPIDJSON_INTERNAL_SWAP_H_ + +#include "../rapidjson.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Custom swap() to avoid dependency on C++ header +/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. + \note This has the same semantics as std::swap(). +*/ +template +inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { + T tmp = a; + a = b; + b = tmp; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_SWAP_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/istreamwrapper.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/istreamwrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..f5fe28977ebffe0539d60cc9957e27a23f8ac6cc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/istreamwrapper.h @@ -0,0 +1,115 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ +#define RAPIDJSON_ISTREAMWRAPPER_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::istringstream + - \c std::stringstream + - \c std::wistringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wifstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_istream. +*/ + +template +class BasicIStreamWrapper { +public: + typedef typename StreamType::char_type Ch; + BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} + + Ch Peek() const { + typename StreamType::int_type c = stream_.peek(); + return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : '\0'; + } + + Ch Take() { + typename StreamType::int_type c = stream_.get(); + if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { + count_++; + return static_cast(c); + } + else + return '\0'; + } + + // tellg() may return -1 when failed. So we count by ourself. + size_t Tell() const { return count_; } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. + int i; + bool hasError = false; + for (i = 0; i < 4; ++i) { + typename StreamType::int_type c = stream_.get(); + if (c == StreamType::traits_type::eof()) { + hasError = true; + stream_.clear(); + break; + } + peekBuffer_[i] = static_cast(c); + } + for (--i; i >= 0; --i) + stream_.putback(peekBuffer_[i]); + return !hasError ? peekBuffer_ : 0; + } + +private: + BasicIStreamWrapper(const BasicIStreamWrapper&); + BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); + + StreamType& stream_; + size_t count_; //!< Number of characters read. Note: + mutable Ch peekBuffer_[4]; +}; + +typedef BasicIStreamWrapper IStreamWrapper; +typedef BasicIStreamWrapper WIStreamWrapper; + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ISTREAMWRAPPER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/memorybuffer.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/memorybuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..39bee1dec1c036d8ecd48a6ca57de16c168b6819 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/memorybuffer.h @@ -0,0 +1,70 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_MEMORYBUFFER_H_ +#define RAPIDJSON_MEMORYBUFFER_H_ + +#include "stream.h" +#include "internal/stack.h" + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory output byte stream. +/*! + This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. + + It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. + + Differences between MemoryBuffer and StringBuffer: + 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. + 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. + + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept +*/ +template +struct GenericMemoryBuffer { + typedef char Ch; // byte + + GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + + void Put(Ch c) { *stack_.template Push() = c; } + void Flush() {} + + void Clear() { stack_.Clear(); } + void ShrinkToFit() { stack_.ShrinkToFit(); } + Ch* Push(size_t count) { return stack_.template Push(count); } + void Pop(size_t count) { stack_.template Pop(count); } + + const Ch* GetBuffer() const { + return stack_.template Bottom(); + } + + size_t GetSize() const { return stack_.GetSize(); } + + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; +}; + +typedef GenericMemoryBuffer<> MemoryBuffer; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { + std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); +} + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/memorystream.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/memorystream.h new file mode 100644 index 0000000000000000000000000000000000000000..1d71d8a4f0e0ade2b598f995ff811c5570da1c9b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/memorystream.h @@ -0,0 +1,71 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_MEMORYSTREAM_H_ +#define RAPIDJSON_MEMORYSTREAM_H_ + +#include "stream.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory input byte stream. +/*! + This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. + + It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. + + Differences between MemoryStream and StringStream: + 1. StringStream has encoding but MemoryStream is a byte stream. + 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. + 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). + \note implements Stream concept +*/ +struct MemoryStream { + typedef char Ch; // byte + + MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} + + Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } + Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } + size_t Tell() const { return static_cast(src_ - begin_); } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + return Tell() + 4 <= size_ ? src_ : 0; + } + + const Ch* src_; //!< Current read position. + const Ch* begin_; //!< Original head of the string. + const Ch* end_; //!< End of stream. + size_t size_; //!< Size of the stream. +}; + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/msinttypes/inttypes.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/msinttypes/inttypes.h new file mode 100644 index 0000000000000000000000000000000000000000..18111286bf55bc0c89e7f47afcb046bbb02e1781 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/msinttypes/inttypes.h @@ -0,0 +1,316 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +// The above software in this distribution may have been modified by +// THL A29 Limited ("Tencent Modifications"). +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// miloyip: VC supports inttypes.h since VC2013 +#if _MSC_VER >= 1800 +#include +#else + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + +#endif // _MSC_VER >= 1800 + +#endif // _MSC_INTTYPES_H_ ] diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/msinttypes/stdint.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/msinttypes/stdint.h new file mode 100644 index 0000000000000000000000000000000000000000..3d4477b9a024a8f326afe362ce3926e04f4c8ec9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/msinttypes/stdint.h @@ -0,0 +1,300 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +// The above software in this distribution may have been modified by +// THL A29 Limited ("Tencent Modifications"). +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. +#if _MSC_VER >= 1600 // [ +#include + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +#undef INT8_C +#undef INT16_C +#undef INT32_C +#undef INT64_C +#undef UINT8_C +#undef UINT16_C +#undef UINT32_C +#undef UINT64_C + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#else // ] _MSC_VER >= 1700 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we have to wrap include with 'extern "C++" {}' +// or compiler would give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#if defined(__cplusplus) && !defined(_M_ARM) +extern "C" { +#endif +# include +#if defined(__cplusplus) && !defined(_M_ARM) +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/ostreamwrapper.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/ostreamwrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..6f4667c08ad7ba3b05951a95c3be4927c79beb57 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/ostreamwrapper.h @@ -0,0 +1,81 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_OSTREAMWRAPPER_H_ +#define RAPIDJSON_OSTREAMWRAPPER_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::ostringstream + - \c std::stringstream + - \c std::wpstringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wofstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_ostream. +*/ + +template +class BasicOStreamWrapper { +public: + typedef typename StreamType::char_type Ch; + BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} + + void Put(Ch c) { + stream_.put(c); + } + + void Flush() { + stream_.flush(); + } + + // Not implemented + char Peek() const { RAPIDJSON_ASSERT(false); return 0; } + char Take() { RAPIDJSON_ASSERT(false); return 0; } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + BasicOStreamWrapper(const BasicOStreamWrapper&); + BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); + + StreamType& stream_; +}; + +typedef BasicOStreamWrapper OStreamWrapper; +typedef BasicOStreamWrapper WOStreamWrapper; + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_OSTREAMWRAPPER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/pointer.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/pointer.h new file mode 100644 index 0000000000000000000000000000000000000000..0206ac1c8b647e0c1129a41e8af99dd05be10937 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/pointer.h @@ -0,0 +1,1358 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_POINTER_H_ +#define RAPIDJSON_POINTER_H_ + +#include "document.h" +#include "internal/itoa.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token + +//! Error code of parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode +*/ +enum PointerParseErrorCode { + kPointerParseErrorNone = 0, //!< The parse is successful + + kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' + kPointerParseErrorInvalidEscape, //!< Invalid escape + kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment + kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericPointer + +//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. +/*! + This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" + (https://tools.ietf.org/html/rfc6901). + + A JSON pointer is for identifying a specific value in a JSON document + (GenericDocument). It can simplify coding of DOM tree manipulation, because it + can access multiple-level depth of DOM tree with single API call. + + After it parses a string representation (e.g. "/foo/0" or URI fragment + representation (e.g. "#/foo/0") into its internal representation (tokens), + it can be used to resolve a specific value in multiple documents, or sub-tree + of documents. + + Contrary to GenericValue, Pointer can be copy constructed and copy assigned. + Apart from assignment, a Pointer cannot be modified after construction. + + Although Pointer is very convenient, please aware that constructing Pointer + involves parsing and dynamic memory allocation. A special constructor with user- + supplied tokens eliminates these. + + GenericPointer depends on GenericDocument and GenericValue. + + \tparam ValueType The value type of the DOM tree. E.g. GenericValue > + \tparam Allocator The allocator type for allocating memory for internal representation. + + \note GenericPointer uses same encoding of ValueType. + However, Allocator of GenericPointer is independent of Allocator of Value. +*/ +template +class GenericPointer { +public: + typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value + typedef typename ValueType::Ch Ch; //!< Character type from Value + + //! A token is the basic units of internal representation. + /*! + A JSON pointer string representation "/foo/123" is parsed to two tokens: + "foo" and 123. 123 will be represented in both numeric form and string form. + They are resolved according to the actual value type (object or array). + + For token that are not numbers, or the numeric value is out of bound + (greater than limits of SizeType), they are only treated as string form + (i.e. the token's index will be equal to kPointerInvalidIndex). + + This struct is public so that user can create a Pointer without parsing and + allocation, using a special constructor. + */ + struct Token { + const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. + SizeType length; //!< Length of the name. + SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. + }; + + //!@name Constructors and destructor. + //@{ + + //! Default constructor. + GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} + + //! Constructor that parses a string or URI fragment representation. + /*! + \param source A null-terminated, string or URI fragment representation of JSON pointer. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + */ + explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source, internal::StrLen(source)); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Constructor that parses a string or URI fragment representation. + /*! + \param source A string or URI fragment representation of JSON pointer. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + explicit GenericPointer(const std::basic_string& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source.c_str(), source.size()); + } +#endif + + //! Constructor that parses a string or URI fragment representation, with length of the source string. + /*! + \param source A string or URI fragment representation of JSON pointer. + \param length Length of source. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + \note Slightly faster than the overload without length. + */ + GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source, length); + } + + //! Constructor with user-supplied tokens. + /*! + This constructor let user supplies const array of tokens. + This prevents the parsing process and eliminates allocation. + This is preferred for memory constrained environments. + + \param tokens An constant array of tokens representing the JSON pointer. + \param tokenCount Number of tokens. + + \b Example + \code + #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } + #define INDEX(i) { #i, sizeof(#i) - 1, i } + + static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; + static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); + // Equivalent to static const Pointer p("/foo/123"); + + #undef NAME + #undef INDEX + \endcode + */ + GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} + + //! Copy constructor. + GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + *this = rhs; + } + + //! Destructor. + ~GenericPointer() { + if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. + Allocator::Free(tokens_); + RAPIDJSON_DELETE(ownAllocator_); + } + + //! Assignment operator. + GenericPointer& operator=(const GenericPointer& rhs) { + if (this != &rhs) { + // Do not delete ownAllcator + if (nameBuffer_) + Allocator::Free(tokens_); + + tokenCount_ = rhs.tokenCount_; + parseErrorOffset_ = rhs.parseErrorOffset_; + parseErrorCode_ = rhs.parseErrorCode_; + + if (rhs.nameBuffer_) + CopyFromRaw(rhs); // Normally parsed tokens. + else { + tokens_ = rhs.tokens_; // User supplied const tokens. + nameBuffer_ = 0; + } + } + return *this; + } + + //@} + + //!@name Append token + //@{ + + //! Append a token and return a new Pointer + /*! + \param token Token to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const Token& token, Allocator* allocator = 0) const { + GenericPointer r; + r.allocator_ = allocator; + Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); + std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); + r.tokens_[tokenCount_].name = p; + r.tokens_[tokenCount_].length = token.length; + r.tokens_[tokenCount_].index = token.index; + return r; + } + + //! Append a name token with length, and return a new Pointer + /*! + \param name Name to be appended. + \param length Length of name. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { + Token token = { name, length, kPointerInvalidIndex }; + return Append(token, allocator); + } + + //! Append a name token without length, and return a new Pointer + /*! + \param name Name (const Ch*) to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) + Append(T* name, Allocator* allocator = 0) const { + return Append(name, StrLen(name), allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Append a name token, and return a new Pointer + /*! + \param name Name to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const std::basic_string& name, Allocator* allocator = 0) const { + return Append(name.c_str(), static_cast(name.size()), allocator); + } +#endif + + //! Append a index token, and return a new Pointer + /*! + \param index Index to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(SizeType index, Allocator* allocator = 0) const { + char buffer[21]; + char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); + SizeType length = static_cast(end - buffer); + buffer[length] = '\0'; + + if (sizeof(Ch) == 1) { + Token token = { reinterpret_cast(buffer), length, index }; + return Append(token, allocator); + } + else { + Ch name[21]; + for (size_t i = 0; i <= length; i++) + name[i] = buffer[i]; + Token token = { name, length, index }; + return Append(token, allocator); + } + } + + //! Append a token by value, and return a new Pointer + /*! + \param token token to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { + if (token.IsString()) + return Append(token.GetString(), token.GetStringLength(), allocator); + else { + RAPIDJSON_ASSERT(token.IsUint64()); + RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); + return Append(static_cast(token.GetUint64()), allocator); + } + } + + //!@name Handling Parse Error + //@{ + + //! Check whether this is a valid pointer. + bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } + + //! Get the parsing error offset in code unit. + size_t GetParseErrorOffset() const { return parseErrorOffset_; } + + //! Get the parsing error code. + PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } + + //@} + + //! Get the allocator of this pointer. + Allocator& GetAllocator() { return *allocator_; } + + //!@name Tokens + //@{ + + //! Get the token array (const version only). + const Token* GetTokens() const { return tokens_; } + + //! Get the number of tokens. + size_t GetTokenCount() const { return tokenCount_; } + + //@} + + //!@name Equality/inequality operators + //@{ + + //! Equality operator. + /*! + \note When any pointers are invalid, always returns false. + */ + bool operator==(const GenericPointer& rhs) const { + if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) + return false; + + for (size_t i = 0; i < tokenCount_; i++) { + if (tokens_[i].index != rhs.tokens_[i].index || + tokens_[i].length != rhs.tokens_[i].length || + (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) + { + return false; + } + } + + return true; + } + + //! Inequality operator. + /*! + \note When any pointers are invalid, always returns true. + */ + bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } + + //@} + + //!@name Stringify + //@{ + + //! Stringify the pointer into string representation. + /*! + \tparam OutputStream Type of output stream. + \param os The output stream. + */ + template + bool Stringify(OutputStream& os) const { + return Stringify(os); + } + + //! Stringify the pointer into URI fragment representation. + /*! + \tparam OutputStream Type of output stream. + \param os The output stream. + */ + template + bool StringifyUriFragment(OutputStream& os) const { + return Stringify(os); + } + + //@} + + //!@name Create value + //@{ + + //! Create a value in a subtree. + /*! + If the value is not exist, it creates all parent values and a JSON Null value. + So it always succeed and return the newly created or existing value. + + Remind that it may change types of parents according to tokens, so it + potentially removes previously stored values. For example, if a document + was an array, and "/foo" is used to create a value, then the document + will be changed to an object, and all existing array elements are lost. + + \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \param alreadyExist If non-null, it stores whether the resolved value is already exist. + \return The resolved newly created (a JSON Null value), or already exists value. + */ + ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { + RAPIDJSON_ASSERT(IsValid()); + ValueType* v = &root; + bool exist = true; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + if (v->IsArray() && t->name[0] == '-' && t->length == 1) { + v->PushBack(ValueType().Move(), allocator); + v = &((*v)[v->Size() - 1]); + exist = false; + } + else { + if (t->index == kPointerInvalidIndex) { // must be object name + if (!v->IsObject()) + v->SetObject(); // Change to Object + } + else { // object name or array index + if (!v->IsArray() && !v->IsObject()) + v->SetArray(); // Change to Array + } + + if (v->IsArray()) { + if (t->index >= v->Size()) { + v->Reserve(t->index + 1, allocator); + while (t->index >= v->Size()) + v->PushBack(ValueType().Move(), allocator); + exist = false; + } + v = &((*v)[t->index]); + } + else { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) { + v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); + v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end + exist = false; + } + else + v = &m->value; + } + } + } + + if (alreadyExist) + *alreadyExist = exist; + + return *v; + } + + //! Creates a value in a document. + /*! + \param document A document to be resolved. + \param alreadyExist If non-null, it stores whether the resolved value is already exist. + \return The resolved newly created, or already exists value. + */ + template + ValueType& Create(GenericDocument& document, bool* alreadyExist = 0) const { + return Create(document, document.GetAllocator(), alreadyExist); + } + + //@} + + //!@name Query value + //@{ + + //! Query a value in a subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. + \return Pointer to the value if it can be resolved. Otherwise null. + + \note + There are only 3 situations when a value cannot be resolved: + 1. A value in the path is not an array nor object. + 2. An object value does not contain the token. + 3. A token is out of range of an array value. + + Use unresolvedTokenIndex to retrieve the token index. + */ + ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { + RAPIDJSON_ASSERT(IsValid()); + ValueType* v = &root; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + switch (v->GetType()) { + case kObjectType: + { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) + break; + v = &m->value; + } + continue; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + break; + v = &((*v)[t->index]); + continue; + default: + break; + } + + // Error: unresolved token + if (unresolvedTokenIndex) + *unresolvedTokenIndex = static_cast(t - tokens_); + return 0; + } + return v; + } + + //! Query a const value in a const subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \return Pointer to the value if it can be resolved. Otherwise null. + */ + const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { + return Get(const_cast(root), unresolvedTokenIndex); + } + + //@} + + //!@name Query a value with default + //@{ + + //! Query a value in a subtree with default value. + /*! + Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. + So that this function always succeed. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param defaultValue Default value to be cloned if the value was not exists. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + Value& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); + } + + //! Query a value in a subtree with default null-terminated string. + ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + Value& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.SetString(defaultValue, allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Query a value in a subtree with default std::basic_string. + ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + Value& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.SetString(defaultValue, allocator); + } +#endif + + //! Query a value in a subtree with default primitive value. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { + return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); + } + + //! Query a value in a document with default value. + template + ValueType& GetWithDefault(GenericDocument& document, const ValueType& defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + + //! Query a value in a document with default null-terminated string. + template + ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Query a value in a document with default std::basic_string. + template + ValueType& GetWithDefault(GenericDocument& document, const std::basic_string& defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } +#endif + + //! Query a value in a document with default primitive value. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + GetWithDefault(GenericDocument& document, T defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + + //@} + + //!@name Set a value + //@{ + + //! Set a value in a subtree, with move semantics. + /*! + It creates all parents if they are not exist or types are different to the tokens. + So this function always succeeds but potentially remove existing values. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param value Value to be set. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = value; + } + + //! Set a value in a subtree, with copy semantics. + ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator).CopyFrom(value, allocator); + } + + //! Set a null-terminated string in a subtree. + ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value, allocator).Move(); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Set a std::basic_string in a subtree. + ValueType& Set(ValueType& root, const std::basic_string& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value, allocator).Move(); + } +#endif + + //! Set a primitive value in a subtree. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value).Move(); + } + + //! Set a value in a document, with move semantics. + template + ValueType& Set(GenericDocument& document, ValueType& value) const { + return Create(document) = value; + } + + //! Set a value in a document, with copy semantics. + template + ValueType& Set(GenericDocument& document, const ValueType& value) const { + return Create(document).CopyFrom(value, document.GetAllocator()); + } + + //! Set a null-terminated string in a document. + template + ValueType& Set(GenericDocument& document, const Ch* value) const { + return Create(document) = ValueType(value, document.GetAllocator()).Move(); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Sets a std::basic_string in a document. + template + ValueType& Set(GenericDocument& document, const std::basic_string& value) const { + return Create(document) = ValueType(value, document.GetAllocator()).Move(); + } +#endif + + //! Set a primitive value in a document. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + Set(GenericDocument& document, T value) const { + return Create(document) = value; + } + + //@} + + //!@name Swap a value + //@{ + + //! Swap a value with a value in a subtree. + /*! + It creates all parents if they are not exist or types are different to the tokens. + So this function always succeeds but potentially remove existing values. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param value Value to be swapped. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator).Swap(value); + } + + //! Swap a value with a value in a document. + template + ValueType& Swap(GenericDocument& document, ValueType& value) const { + return Create(document).Swap(value); + } + + //@} + + //! Erase a value in a subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \return Whether the resolved value is found and erased. + + \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. + */ + bool Erase(ValueType& root) const { + RAPIDJSON_ASSERT(IsValid()); + if (tokenCount_ == 0) // Cannot erase the root + return false; + + ValueType* v = &root; + const Token* last = tokens_ + (tokenCount_ - 1); + for (const Token *t = tokens_; t != last; ++t) { + switch (v->GetType()) { + case kObjectType: + { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) + return false; + v = &m->value; + } + break; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + return false; + v = &((*v)[t->index]); + break; + default: + return false; + } + } + + switch (v->GetType()) { + case kObjectType: + return v->EraseMember(GenericStringRef(last->name, last->length)); + case kArrayType: + if (last->index == kPointerInvalidIndex || last->index >= v->Size()) + return false; + v->Erase(v->Begin() + last->index); + return true; + default: + return false; + } + } + +private: + //! Clone the content from rhs to this. + /*! + \param rhs Source pointer. + \param extraToken Extra tokens to be allocated. + \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. + \return Start of non-occupied name buffer, for storing extra names. + */ + Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { + if (!allocator_) // allocator is independently owned. + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + + size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens + for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) + nameBufferSize += t->length; + + tokenCount_ = rhs.tokenCount_ + extraToken; + tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); + nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); + if (rhs.tokenCount_ > 0) { + std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); + } + if (nameBufferSize > 0) { + std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); + } + + // Adjust pointers to name buffer + std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; + for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) + t->name += diff; + + return nameBuffer_ + nameBufferSize; + } + + //! Check whether a character should be percent-encoded. + /*! + According to RFC 3986 2.3 Unreserved Characters. + \param c The character (code unit) to be tested. + */ + bool NeedPercentEncode(Ch c) const { + return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); + } + + //! Parse a JSON String or its URI fragment representation into tokens. +#ifndef __clang__ // -Wdocumentation + /*! + \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. + \param length Length of the source string. + \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. + */ +#endif + void Parse(const Ch* source, size_t length) { + RAPIDJSON_ASSERT(source != NULL); + RAPIDJSON_ASSERT(nameBuffer_ == 0); + RAPIDJSON_ASSERT(tokens_ == 0); + + // Create own allocator if user did not supply. + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + + // Count number of '/' as tokenCount + tokenCount_ = 0; + for (const Ch* s = source; s != source + length; s++) + if (*s == '/') + tokenCount_++; + + Token* token = tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); + Ch* name = nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); + size_t i = 0; + + // Detect if it is a URI fragment + bool uriFragment = false; + if (source[i] == '#') { + uriFragment = true; + i++; + } + + if (i != length && source[i] != '/') { + parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; + goto error; + } + + while (i < length) { + RAPIDJSON_ASSERT(source[i] == '/'); + i++; // consumes '/' + + token->name = name; + bool isNumber = true; + + while (i < length && source[i] != '/') { + Ch c = source[i]; + if (uriFragment) { + // Decoding percent-encoding for URI fragment + if (c == '%') { + PercentDecodeStream is(&source[i], source + length); + GenericInsituStringStream os(name); + Ch* begin = os.PutBegin(); + if (!Transcoder, EncodingType>().Validate(is, os) || !is.IsValid()) { + parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; + goto error; + } + size_t len = os.PutEnd(begin); + i += is.Tell() - 1; + if (len == 1) + c = *name; + else { + name += len; + isNumber = false; + i++; + continue; + } + } + else if (NeedPercentEncode(c)) { + parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; + goto error; + } + } + + i++; + + // Escaping "~0" -> '~', "~1" -> '/' + if (c == '~') { + if (i < length) { + c = source[i]; + if (c == '0') c = '~'; + else if (c == '1') c = '/'; + else { + parseErrorCode_ = kPointerParseErrorInvalidEscape; + goto error; + } + i++; + } + else { + parseErrorCode_ = kPointerParseErrorInvalidEscape; + goto error; + } + } + + // First check for index: all of characters are digit + if (c < '0' || c > '9') + isNumber = false; + + *name++ = c; + } + token->length = static_cast(name - token->name); + if (token->length == 0) + isNumber = false; + *name++ = '\0'; // Null terminator + + // Second check for index: more than one digit cannot have leading zero + if (isNumber && token->length > 1 && token->name[0] == '0') + isNumber = false; + + // String to SizeType conversion + SizeType n = 0; + if (isNumber) { + for (size_t j = 0; j < token->length; j++) { + SizeType m = n * 10 + static_cast(token->name[j] - '0'); + if (m < n) { // overflow detection + isNumber = false; + break; + } + n = m; + } + } + + token->index = isNumber ? n : kPointerInvalidIndex; + token++; + } + + RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer + parseErrorCode_ = kPointerParseErrorNone; + return; + + error: + Allocator::Free(tokens_); + nameBuffer_ = 0; + tokens_ = 0; + tokenCount_ = 0; + parseErrorOffset_ = i; + return; + } + + //! Stringify to string or URI fragment representation. + /*! + \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. + \tparam OutputStream type of output stream. + \param os The output stream. + */ + template + bool Stringify(OutputStream& os) const { + RAPIDJSON_ASSERT(IsValid()); + + if (uriFragment) + os.Put('#'); + + for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + os.Put('/'); + for (size_t j = 0; j < t->length; j++) { + Ch c = t->name[j]; + if (c == '~') { + os.Put('~'); + os.Put('0'); + } + else if (c == '/') { + os.Put('~'); + os.Put('1'); + } + else if (uriFragment && NeedPercentEncode(c)) { + // Transcode to UTF8 sequence + GenericStringStream source(&t->name[j]); + PercentEncodeStream target(os); + if (!Transcoder >().Validate(source, target)) + return false; + j += source.Tell() - 1; + } + else + os.Put(c); + } + } + return true; + } + + //! A helper stream for decoding a percent-encoded sequence into code unit. + /*! + This stream decodes %XY triplet into code unit (0-255). + If it encounters invalid characters, it sets output code unit as 0 and + mark invalid, and to be checked by IsValid(). + */ + class PercentDecodeStream { + public: + typedef typename ValueType::Ch Ch; + + //! Constructor + /*! + \param source Start of the stream + \param end Past-the-end of the stream. + */ + PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} + + Ch Take() { + if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet + valid_ = false; + return 0; + } + src_++; + Ch c = 0; + for (int j = 0; j < 2; j++) { + c = static_cast(c << 4); + Ch h = *src_; + if (h >= '0' && h <= '9') c = static_cast(c + h - '0'); + else if (h >= 'A' && h <= 'F') c = static_cast(c + h - 'A' + 10); + else if (h >= 'a' && h <= 'f') c = static_cast(c + h - 'a' + 10); + else { + valid_ = false; + return 0; + } + src_++; + } + return c; + } + + size_t Tell() const { return static_cast(src_ - head_); } + bool IsValid() const { return valid_; } + + private: + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. + const Ch* end_; //!< Past-the-end position. + bool valid_; //!< Whether the parsing is valid. + }; + + //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. + template + class PercentEncodeStream { + public: + PercentEncodeStream(OutputStream& os) : os_(os) {} + void Put(char c) { // UTF-8 must be byte + unsigned char u = static_cast(c); + static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + os_.Put('%'); + os_.Put(hexDigits[u >> 4]); + os_.Put(hexDigits[u & 15]); + } + private: + OutputStream& os_; + }; + + Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. + Allocator* ownAllocator_; //!< Allocator owned by this Pointer. + Ch* nameBuffer_; //!< A buffer containing all names in tokens. + Token* tokens_; //!< A list of tokens. + size_t tokenCount_; //!< Number of tokens in tokens_. + size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. + PointerParseErrorCode parseErrorCode_; //!< Parsing error code. +}; + +//! GenericPointer for Value (UTF-8, default allocator). +typedef GenericPointer Pointer; + +//!@name Helper functions for GenericPointer +//@{ + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer& pointer, typename T::AllocatorType& a) { + return pointer.Create(root, a); +} + +template +typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Create(root, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer& pointer) { + return pointer.Create(document); +} + +template +typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { + return GenericPointer(source, N - 1).Create(document); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { + return pointer.Get(root, unresolvedTokenIndex); +} + +template +const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { + return pointer.Get(root, unresolvedTokenIndex); +} + +template +typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { + return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); +} + +template +const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { + return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const std::basic_string& defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, T2 defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string& defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const std::basic_string& defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, T2 defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string& defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const std::basic_string& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +SetValueByPointer(T& root, const GenericPointer& pointer, T2 value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* value) { + return pointer.Set(document, value); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const std::basic_string& value) { + return pointer.Set(document, value); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +SetValueByPointer(DocumentType& document, const GenericPointer& pointer, T2 value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string& value) { + return GenericPointer(source, N - 1).Set(document, value); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Swap(root, value, a); +} + +template +typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Swap(root, value, a); +} + +template +typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { + return pointer.Swap(document, value); +} + +template +typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Swap(document, value); +} + +////////////////////////////////////////////////////////////////////////////// + +template +bool EraseValueByPointer(T& root, const GenericPointer& pointer) { + return pointer.Erase(root); +} + +template +bool EraseValueByPointer(T& root, const CharType(&source)[N]) { + return GenericPointer(source, N - 1).Erase(root); +} + +//@} + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_POINTER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/prettywriter.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/prettywriter.h new file mode 100644 index 0000000000000000000000000000000000000000..0dcb0fee923fbe3390ed3b4b4cef5b7bf2d8d71c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/prettywriter.h @@ -0,0 +1,255 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_PRETTYWRITER_H_ +#define RAPIDJSON_PRETTYWRITER_H_ + +#include "writer.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Combination of PrettyWriter format flags. +/*! \see PrettyWriter::SetFormatOptions + */ +enum PrettyFormatOptions { + kFormatDefault = 0, //!< Default pretty formatting. + kFormatSingleLineArray = 1 //!< Format arrays on a single line. +}; + +//! Writer with indentation and spacing. +/*! + \tparam OutputStream Type of ouptut os. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class PrettyWriter : public Writer { +public: + typedef Writer Base; + typedef typename Base::Ch Ch; + + //! Constructor + /*! \param os Output stream. + \param allocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} + + + explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} + + //! Set custom indentation. + /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). + \param indentCharCount Number of indent characters for each indentation level. + \note The default indentation is 4 spaces. + */ + PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { + RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); + indentChar_ = indentChar; + indentCharCount_ = indentCharCount; + return *this; + } + + //! Set pretty writer formatting options. + /*! \param options Formatting options. + */ + PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { + formatOptions_ = options; + return *this; + } + + /*! @name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } + bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } + bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } + bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } + bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } + bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } + bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } + + bool RawNumber(const Ch* str, SizeType length, bool copy = false) { + (void)copy; + PrettyPrefix(kNumberType); + return Base::WriteString(str, length); + } + + bool String(const Ch* str, SizeType length, bool copy = false) { + (void)copy; + PrettyPrefix(kStringType); + return Base::WriteString(str, length); + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string& str) { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() { + PrettyPrefix(kObjectType); + new (Base::level_stack_.template Push()) typename Base::Level(false); + return Base::WriteStartObject(); + } + + bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string& str) { + return Key(str.data(), SizeType(str.size())); + } +#endif + + bool EndObject(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); + RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty) { + Base::os_->Put('\n'); + WriteIndent(); + } + bool ret = Base::WriteEndObject(); + (void)ret; + RAPIDJSON_ASSERT(ret == true); + if (Base::level_stack_.Empty()) // end of json text + Base::os_->Flush(); + return true; + } + + bool StartArray() { + PrettyPrefix(kArrayType); + new (Base::level_stack_.template Push()) typename Base::Level(true); + return Base::WriteStartArray(); + } + + bool EndArray(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); + RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { + Base::os_->Put('\n'); + WriteIndent(); + } + bool ret = Base::WriteEndArray(); + (void)ret; + RAPIDJSON_ASSERT(ret == true); + if (Base::level_stack_.Empty()) // end of json text + Base::os_->Flush(); + return true; + } + + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch* str) { return String(str, internal::StrLen(str)); } + bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } + + //@} + + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. + */ + bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); } + +protected: + void PrettyPrefix(Type type) { + (void)type; + if (Base::level_stack_.GetSize() != 0) { // this value is not at root + typename Base::Level* level = Base::level_stack_.template Top(); + + if (level->inArray) { + if (level->valueCount > 0) { + Base::os_->Put(','); // add comma if it is not the first element in array + if (formatOptions_ & kFormatSingleLineArray) + Base::os_->Put(' '); + } + + if (!(formatOptions_ & kFormatSingleLineArray)) { + Base::os_->Put('\n'); + WriteIndent(); + } + } + else { // in object + if (level->valueCount > 0) { + if (level->valueCount % 2 == 0) { + Base::os_->Put(','); + Base::os_->Put('\n'); + } + else { + Base::os_->Put(':'); + Base::os_->Put(' '); + } + } + else + Base::os_->Put('\n'); + + if (level->valueCount % 2 == 0) + WriteIndent(); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else { + RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. + Base::hasRoot_ = true; + } + } + + void WriteIndent() { + size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; + PutN(*Base::os_, static_cast(indentChar_), count); + } + + Ch indentChar_; + unsigned indentCharCount_; + PrettyFormatOptions formatOptions_; + +private: + // Prohibit copy constructor & assignment operator. + PrettyWriter(const PrettyWriter&); + PrettyWriter& operator=(const PrettyWriter&); +}; + +RAPIDJSON_NAMESPACE_END + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/rapidjson.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/rapidjson.h new file mode 100644 index 0000000000000000000000000000000000000000..053b2ce43f9f3cada6c78b76626169a95e99d996 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/rapidjson.h @@ -0,0 +1,615 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_RAPIDJSON_H_ +#define RAPIDJSON_RAPIDJSON_H_ + +/*!\file rapidjson.h + \brief common definitions and configuration + + \see RAPIDJSON_CONFIG + */ + +/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration + \brief Configuration macros for library features + + Some RapidJSON features are configurable to adapt the library to a wide + variety of platforms, environments and usage scenarios. Most of the + features can be configured in terms of overriden or predefined + preprocessor macros at compile-time. + + Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. + + \note These macros should be given on the compiler command-line + (where applicable) to avoid inconsistent values when compiling + different translation units of a single application. + */ + +#include // malloc(), realloc(), free(), size_t +#include // memset(), memcpy(), memmove(), memcmp() + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_VERSION_STRING +// +// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. +// + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +// token stringification +#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) +#define RAPIDJSON_DO_STRINGIFY(x) #x +//!@endcond + +/*! \def RAPIDJSON_MAJOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Major version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_MINOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Minor version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_PATCH_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Patch version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_VERSION_STRING + \ingroup RAPIDJSON_CONFIG + \brief Version of RapidJSON in ".." string format. +*/ +#define RAPIDJSON_MAJOR_VERSION 1 +#define RAPIDJSON_MINOR_VERSION 1 +#define RAPIDJSON_PATCH_VERSION 0 +#define RAPIDJSON_VERSION_STRING \ + RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NAMESPACE_(BEGIN|END) +/*! \def RAPIDJSON_NAMESPACE + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace + + In order to avoid symbol clashes and/or "One Definition Rule" errors + between multiple inclusions of (different versions of) RapidJSON in + a single binary, users can customize the name of the main RapidJSON + namespace. + + In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE + to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple + levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref + RAPIDJSON_NAMESPACE_END need to be defined as well: + + \code + // in some .cpp file + #define RAPIDJSON_NAMESPACE my::rapidjson + #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { + #define RAPIDJSON_NAMESPACE_END } } + #include "rapidjson/..." + \endcode + + \see rapidjson + */ +/*! \def RAPIDJSON_NAMESPACE_BEGIN + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace (opening expression) + \see RAPIDJSON_NAMESPACE +*/ +/*! \def RAPIDJSON_NAMESPACE_END + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace (closing expression) + \see RAPIDJSON_NAMESPACE +*/ +#ifndef RAPIDJSON_NAMESPACE +#define RAPIDJSON_NAMESPACE rapidjson +#endif +#ifndef RAPIDJSON_NAMESPACE_BEGIN +#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { +#endif +#ifndef RAPIDJSON_NAMESPACE_END +#define RAPIDJSON_NAMESPACE_END } +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_HAS_STDSTRING + +#ifndef RAPIDJSON_HAS_STDSTRING +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation +#else +#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default +#endif +/*! \def RAPIDJSON_HAS_STDSTRING + \ingroup RAPIDJSON_CONFIG + \brief Enable RapidJSON support for \c std::string + + By defining this preprocessor symbol to \c 1, several convenience functions for using + \ref rapidjson::GenericValue with \c std::string are enabled, especially + for construction and comparison. + + \hideinitializer +*/ +#endif // !defined(RAPIDJSON_HAS_STDSTRING) + +#if RAPIDJSON_HAS_STDSTRING +#include +#endif // RAPIDJSON_HAS_STDSTRING + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_INT64DEFINE + +/*! \def RAPIDJSON_NO_INT64DEFINE + \ingroup RAPIDJSON_CONFIG + \brief Use external 64-bit integer types. + + RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types + to be available at global scope. + + If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to + prevent RapidJSON from defining its own types. +*/ +#ifndef RAPIDJSON_NO_INT64DEFINE +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 +#include "msinttypes/stdint.h" +#include "msinttypes/inttypes.h" +#else +// Other compilers should have this. +#include +#include +#endif +//!@endcond +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_INT64DEFINE +#endif +#endif // RAPIDJSON_NO_INT64TYPEDEF + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_FORCEINLINE + +#ifndef RAPIDJSON_FORCEINLINE +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#if defined(_MSC_VER) && defined(NDEBUG) +#define RAPIDJSON_FORCEINLINE __forceinline +#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) +#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) +#else +#define RAPIDJSON_FORCEINLINE +#endif +//!@endcond +#endif // RAPIDJSON_FORCEINLINE + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ENDIAN +#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine +#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine + +//! Endianness of the machine. +/*! + \def RAPIDJSON_ENDIAN + \ingroup RAPIDJSON_CONFIG + + GCC 4.6 provided macro for detecting endianness of the target machine. But other + compilers may not have this. User can define RAPIDJSON_ENDIAN to either + \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. + + Default detection implemented with reference to + \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html + \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp +*/ +#ifndef RAPIDJSON_ENDIAN +// Detect with GCC 4.6's macro +# ifdef __BYTE_ORDER__ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# else +# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# endif // __BYTE_ORDER__ +// Detect with GLIBC's endian.h +# elif defined(__GLIBC__) +# include +# if (__BYTE_ORDER == __LITTLE_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif (__BYTE_ORDER == __BIG_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# else +# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# endif // __GLIBC__ +// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro +# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +// Detect with architecture macros +# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(_MSC_VER) && defined(_M_ARM) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(RAPIDJSON_DOXYGEN_RUNNING) +# define RAPIDJSON_ENDIAN +# else +# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# endif +#endif // RAPIDJSON_ENDIAN + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_64BIT + +//! Whether using 64-bit architecture +#ifndef RAPIDJSON_64BIT +#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) +#define RAPIDJSON_64BIT 1 +#else +#define RAPIDJSON_64BIT 0 +#endif +#endif // RAPIDJSON_64BIT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ALIGN + +//! Data alignment of the machine. +/*! \ingroup RAPIDJSON_CONFIG + \param x pointer to align + + Some machines require strict data alignment. Currently the default uses 4 bytes + alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms. + User can customize by defining the RAPIDJSON_ALIGN function macro. +*/ +#ifndef RAPIDJSON_ALIGN +#if RAPIDJSON_64BIT == 1 +#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) +#else +#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_UINT64_C2 + +//! Construct a 64-bit literal by a pair of 32-bit integer. +/*! + 64-bit literal with or without ULL suffix is prone to compiler warnings. + UINT64_C() is C macro which cause compilation problems. + Use this macro to define 64-bit constants by a pair of 32-bit integer. +*/ +#ifndef RAPIDJSON_UINT64_C2 +#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_48BITPOINTER_OPTIMIZATION + +//! Use only lower 48-bit address for some pointers. +/*! + \ingroup RAPIDJSON_CONFIG + + This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. + The higher 16-bit can be used for storing other data. + \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. +*/ +#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 +#else +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 +#endif +#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION + +#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 +#if RAPIDJSON_64BIT != 1 +#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 +#endif +#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast((reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast(reinterpret_cast(x)))) +#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast(reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) +#else +#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) +#define RAPIDJSON_GETPOINTER(type, p) (p) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD + +/*! \def RAPIDJSON_SIMD + \ingroup RAPIDJSON_CONFIG + \brief Enable SSE2/SSE4.2 optimization. + + RapidJSON supports optimized implementations for some parsing operations + based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible + processors. + + To enable these optimizations, two different symbols can be defined; + \code + // Enable SSE2 optimization. + #define RAPIDJSON_SSE2 + + // Enable SSE4.2 optimization. + #define RAPIDJSON_SSE42 + \endcode + + \c RAPIDJSON_SSE42 takes precedence, if both are defined. + + If any of these symbols is defined, RapidJSON defines the macro + \c RAPIDJSON_SIMD to indicate the availability of the optimized code. +*/ +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ + || defined(RAPIDJSON_DOXYGEN_RUNNING) +#define RAPIDJSON_SIMD +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_SIZETYPEDEFINE + +#ifndef RAPIDJSON_NO_SIZETYPEDEFINE +/*! \def RAPIDJSON_NO_SIZETYPEDEFINE + \ingroup RAPIDJSON_CONFIG + \brief User-provided \c SizeType definition. + + In order to avoid using 32-bit size types for indexing strings and arrays, + define this preprocessor symbol and provide the type rapidjson::SizeType + before including RapidJSON: + \code + #define RAPIDJSON_NO_SIZETYPEDEFINE + namespace rapidjson { typedef ::std::size_t SizeType; } + #include "rapidjson/..." + \endcode + + \see rapidjson::SizeType +*/ +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_SIZETYPEDEFINE +#endif +RAPIDJSON_NAMESPACE_BEGIN +//! Size type (for string lengths, array sizes, etc.) +/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, + instead of using \c size_t. Users may override the SizeType by defining + \ref RAPIDJSON_NO_SIZETYPEDEFINE. +*/ +typedef unsigned SizeType; +RAPIDJSON_NAMESPACE_END +#endif + +// always import std::size_t to rapidjson namespace +RAPIDJSON_NAMESPACE_BEGIN +using std::size_t; +RAPIDJSON_NAMESPACE_END + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ASSERT + +//! Assertion. +/*! \ingroup RAPIDJSON_CONFIG + By default, rapidjson uses C \c assert() for internal assertions. + User can override it by defining RAPIDJSON_ASSERT(x) macro. + + \note Parsing errors are handled and can be customized by the + \ref RAPIDJSON_ERRORS APIs. +*/ +#ifndef RAPIDJSON_ASSERT +#include +#define RAPIDJSON_ASSERT(x) assert(x) +#endif // RAPIDJSON_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_STATIC_ASSERT + +// Adopt from boost +#ifndef RAPIDJSON_STATIC_ASSERT +#ifndef __clang__ +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#endif +RAPIDJSON_NAMESPACE_BEGIN +template struct STATIC_ASSERTION_FAILURE; +template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; +template struct StaticAssertTest {}; +RAPIDJSON_NAMESPACE_END + +#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) +#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) +#define RAPIDJSON_DO_JOIN2(X, Y) X##Y + +#if defined(__GNUC__) +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) +#else +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif +#ifndef __clang__ +//!@endcond +#endif + +/*! \def RAPIDJSON_STATIC_ASSERT + \brief (Internal) macro to check for conditions at compile-time + \param x compile-time condition + \hideinitializer + */ +#define RAPIDJSON_STATIC_ASSERT(x) \ + typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ + sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ + RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY + +//! Compiler branching hint for expression with high probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression likely to be true. +*/ +#ifndef RAPIDJSON_LIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) +#else +#define RAPIDJSON_LIKELY(x) (x) +#endif +#endif + +//! Compiler branching hint for expression with low probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression unlikely to be true. +*/ +#ifndef RAPIDJSON_UNLIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define RAPIDJSON_UNLIKELY(x) (x) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Helpers + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN + +#define RAPIDJSON_MULTILINEMACRO_BEGIN do { +#define RAPIDJSON_MULTILINEMACRO_END \ +} while((void)0, 0) + +// adopted from Boost +#define RAPIDJSON_VERSION_CODE(x,y,z) \ + (((x)*100000) + ((y)*100) + (z)) + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF + +#if defined(__GNUC__) +#define RAPIDJSON_GNUC \ + RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) +#endif + +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) + +#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) +#define RAPIDJSON_DIAG_OFF(x) \ + RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) + +// push/pop support in Clang and GCC>=4.6 +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) +#else // GCC >= 4.2, < 4.6 +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ +#endif + +#elif defined(_MSC_VER) + +// pragma (MSVC specific) +#define RAPIDJSON_PRAGMA(x) __pragma(x) +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) + +#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) + +#else + +#define RAPIDJSON_DIAG_OFF(x) /* ignored */ +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ + +#endif // RAPIDJSON_DIAG_* + +/////////////////////////////////////////////////////////////////////////////// +// C++11 features + +#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if defined(__clang__) +#if __has_feature(cxx_rvalue_references) && \ + (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#else +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#endif +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1600) + +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#else +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + +#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT +#if defined(__clang__) +#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) +// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 +#else +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 +#endif +#endif +#if RAPIDJSON_HAS_CXX11_NOEXCEPT +#define RAPIDJSON_NOEXCEPT noexcept +#else +#define RAPIDJSON_NOEXCEPT /* noexcept */ +#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT + +// no automatic detection, yet +#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS +#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 +#endif + +#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR +#if defined(__clang__) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1700) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 +#else +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR + +//!@endcond + +/////////////////////////////////////////////////////////////////////////////// +// new/delete + +#ifndef RAPIDJSON_NEW +///! customization point for global \c new +#define RAPIDJSON_NEW(x) new x +#endif +#ifndef RAPIDJSON_DELETE +///! customization point for global \c delete +#define RAPIDJSON_DELETE(x) delete x +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Type + +/*! \namespace rapidjson + \brief main RapidJSON namespace + \see RAPIDJSON_NAMESPACE +*/ +RAPIDJSON_NAMESPACE_BEGIN + +//! Type of JSON value +enum Type { + kNullType = 0, //!< null + kFalseType = 1, //!< false + kTrueType = 2, //!< true + kObjectType = 3, //!< object + kArrayType = 4, //!< array + kStringType = 5, //!< string + kNumberType = 6 //!< number +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/reader.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/reader.h new file mode 100644 index 0000000000000000000000000000000000000000..19f8849b14c09d2312d2ab9eaa502f3e88f9f735 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/reader.h @@ -0,0 +1,1879 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_READER_H_ +#define RAPIDJSON_READER_H_ + +/*! \file reader.h */ + +#include "allocators.h" +#include "stream.h" +#include "encodedstream.h" +#include "internal/meta.h" +#include "internal/stack.h" +#include "internal/strtod.h" +#include + +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) +#include +#pragma intrinsic(_BitScanForward) +#endif +#ifdef RAPIDJSON_SSE42 +#include +#elif defined(RAPIDJSON_SSE2) +#include +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4702) // unreachable code +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(old-style-cast) +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define RAPIDJSON_NOTHING /* deliberately empty */ +#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ + RAPIDJSON_MULTILINEMACRO_END +#endif +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) +//!@endcond + +/*! \def RAPIDJSON_PARSE_ERROR_NORETURN + \ingroup RAPIDJSON_ERRORS + \brief Macro to indicate a parse error. + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error + \param offset position of the error in JSON input (\c size_t) + + This macros can be used as a customization point for the internal + error handling mechanism of RapidJSON. + + A common usage model is to throw an exception instead of requiring the + caller to explicitly check the \ref rapidjson::GenericReader::Parse's + return value: + + \code + #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ + throw ParseException(parseErrorCode, #parseErrorCode, offset) + + #include // std::runtime_error + #include "rapidjson/error/error.h" // rapidjson::ParseResult + + struct ParseException : std::runtime_error, rapidjson::ParseResult { + ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) + : std::runtime_error(msg), ParseResult(code, offset) {} + }; + + #include "rapidjson/reader.h" + \endcode + + \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse + */ +#ifndef RAPIDJSON_PARSE_ERROR_NORETURN +#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ + SetParseError(parseErrorCode, offset); \ + RAPIDJSON_MULTILINEMACRO_END +#endif + +/*! \def RAPIDJSON_PARSE_ERROR + \ingroup RAPIDJSON_ERRORS + \brief (Internal) macro to indicate and handle a parse error. + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error + \param offset position of the error in JSON input (\c size_t) + + Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. + + \see RAPIDJSON_PARSE_ERROR_NORETURN + \hideinitializer + */ +#ifndef RAPIDJSON_PARSE_ERROR +#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ + RAPIDJSON_MULTILINEMACRO_END +#endif + +#include "error/error.h" // ParseErrorCode, ParseResult + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// ParseFlag + +/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kParseDefaultFlags definition. + + User can define this as any \c ParseFlag combinations. +*/ +#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS +#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags +#endif + +//! Combination of parseFlags +/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream + */ +enum ParseFlag { + kParseNoFlags = 0, //!< No flags are set. + kParseInsituFlag = 1, //!< In-situ(destructive) parsing. + kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. + kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. + kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. + kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). + kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. + kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. + kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. + kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. + kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS +}; + +/////////////////////////////////////////////////////////////////////////////// +// Handler + +/*! \class rapidjson::Handler + \brief Concept for receiving events from GenericReader upon parsing. + The functions return true if no error occurs. If they return false, + the event publisher should terminate the process. +\code +concept Handler { + typename Ch; + + bool Null(); + bool Bool(bool b); + bool Int(int i); + bool Uint(unsigned i); + bool Int64(int64_t i); + bool Uint64(uint64_t i); + bool Double(double d); + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) + bool RawNumber(const Ch* str, SizeType length, bool copy); + bool String(const Ch* str, SizeType length, bool copy); + bool StartObject(); + bool Key(const Ch* str, SizeType length, bool copy); + bool EndObject(SizeType memberCount); + bool StartArray(); + bool EndArray(SizeType elementCount); +}; +\endcode +*/ +/////////////////////////////////////////////////////////////////////////////// +// BaseReaderHandler + +//! Default implementation of Handler. +/*! This can be used as base class of any reader handler. + \note implements Handler concept +*/ +template, typename Derived = void> +struct BaseReaderHandler { + typedef typename Encoding::Ch Ch; + + typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; + + bool Default() { return true; } + bool Null() { return static_cast(*this).Default(); } + bool Bool(bool) { return static_cast(*this).Default(); } + bool Int(int) { return static_cast(*this).Default(); } + bool Uint(unsigned) { return static_cast(*this).Default(); } + bool Int64(int64_t) { return static_cast(*this).Default(); } + bool Uint64(uint64_t) { return static_cast(*this).Default(); } + bool Double(double) { return static_cast(*this).Default(); } + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) + bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } + bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } + bool StartObject() { return static_cast(*this).Default(); } + bool Key(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } + bool EndObject(SizeType) { return static_cast(*this).Default(); } + bool StartArray() { return static_cast(*this).Default(); } + bool EndArray(SizeType) { return static_cast(*this).Default(); } +}; + +/////////////////////////////////////////////////////////////////////////////// +// StreamLocalCopy + +namespace internal { + +template::copyOptimization> +class StreamLocalCopy; + +//! Do copy optimization. +template +class StreamLocalCopy { +public: + StreamLocalCopy(Stream& original) : s(original), original_(original) {} + ~StreamLocalCopy() { original_ = s; } + + Stream s; + +private: + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; + + Stream& original_; +}; + +//! Keep reference. +template +class StreamLocalCopy { +public: + StreamLocalCopy(Stream& original) : s(original) {} + + Stream& s; + +private: + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; +}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// SkipWhitespace + +//! Skip the JSON white spaces in a stream. +/*! \param is A input stream for skipping white spaces. + \note This function has SSE2/SSE4.2 specialization. +*/ +template +void SkipWhitespace(InputStream& is) { + internal::StreamLocalCopy copy(is); + InputStream& s(copy.s); + + typename InputStream::Ch c; + while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t') + s.Take(); +} + +inline const char* SkipWhitespace(const char* p, const char* end) { + while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + return p; +} + +#ifdef RAPIDJSON_SSE42 +//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // The rest of string using SIMD + static const char whitespace[16] = " \n\r\t"; + const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); + if (r != 0) { // some of characters is non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + // The middle of string using SIMD + static const char whitespace[16] = " \n\r\t"; + const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); + + for (; p <= end - 16; p += 16) { + const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); + const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); + if (r != 0) { // some of characters is non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } + + return SkipWhitespace(p, end); +} + +#elif defined(RAPIDJSON_SSE2) + +//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // The rest of string + #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; + #undef C16 + + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = static_cast(~_mm_movemask_epi8(x)); + if (r != 0) { // some of characters may be non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + // The rest of string + #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; + #undef C16 + + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); + + for (; p <= end - 16; p += 16) { + const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = static_cast(~_mm_movemask_epi8(x)); + if (r != 0) { // some of characters may be non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } + + return SkipWhitespace(p, end); +} + +#endif // RAPIDJSON_SSE2 + +#ifdef RAPIDJSON_SIMD +//! Template function specialization for InsituStringStream +template<> inline void SkipWhitespace(InsituStringStream& is) { + is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); +} + +//! Template function specialization for StringStream +template<> inline void SkipWhitespace(StringStream& is) { + is.src_ = SkipWhitespace_SIMD(is.src_); +} + +template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream>& is) { + is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); +} +#endif // RAPIDJSON_SIMD + +/////////////////////////////////////////////////////////////////////////////// +// GenericReader + +//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. +/*! GenericReader parses JSON text from a stream, and send events synchronously to an + object implementing Handler concept. + + It needs to allocate a stack for storing a single decoded string during + non-destructive parsing. + + For in-situ parsing, the decoded string is directly written to the source + text string, no temporary buffer is required. + + A GenericReader object can be reused for parsing multiple JSON text. + + \tparam SourceEncoding Encoding of the input stream. + \tparam TargetEncoding Encoding of the parse output. + \tparam StackAllocator Allocator type for stack. +*/ +template +class GenericReader { +public: + typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type + + //! Constructor. + /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) + \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) + */ + GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {} + + //! Parse JSON text. + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream& is, Handler& handler) { + if (parseFlags & kParseIterativeFlag) + return IterativeParse(is, handler); + + parseResult_.Clear(); + + ClearStackOnExit scope(*this); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + else { + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (!(parseFlags & kParseStopWhenDoneFlag)) { + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + } + } + + return parseResult_; + } + + //! Parse JSON text (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream& is, Handler& handler) { + return Parse(is, handler); + } + + //! Whether a parse error has occured in the last parsing. + bool HasParseError() const { return parseResult_.IsError(); } + + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const { return parseResult_.Offset(); } + +protected: + void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } + +private: + // Prohibit copy constructor & assignment operator. + GenericReader(const GenericReader&); + GenericReader& operator=(const GenericReader&); + + void ClearStack() { stack_.Clear(); } + + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericReader& r) : r_(r) {} + ~ClearStackOnExit() { r_.ClearStack(); } + private: + GenericReader& r_; + ClearStackOnExit(const ClearStackOnExit&); + ClearStackOnExit& operator=(const ClearStackOnExit&); + }; + + template + void SkipWhitespaceAndComments(InputStream& is) { + SkipWhitespace(is); + + if (parseFlags & kParseCommentsFlag) { + while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) { + if (Consume(is, '*')) { + while (true) { + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + else if (Consume(is, '*')) { + if (Consume(is, '/')) + break; + } + else + is.Take(); + } + } + else if (RAPIDJSON_LIKELY(Consume(is, '/'))) + while (is.Peek() != '\0' && is.Take() != '\n'); + else + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + + SkipWhitespace(is); + } + } + } + + // Parse object: { string : value, ... } + template + void ParseObject(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == '{'); + is.Take(); // Skip '{' + + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, '}')) { + if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + + for (SizeType memberCount = 0;;) { + if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); + + ParseString(is, handler, true); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ++memberCount; + + switch (is.Peek()) { + case ',': + is.Take(); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + break; + case '}': + is.Take(); + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + default: + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy + } + + if (parseFlags & kParseTrailingCommasFlag) { + if (is.Peek() == '}') { + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + is.Take(); + return; + } + } + } + } + + // Parse array: [ value, ... ] + template + void ParseArray(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == '['); + is.Take(); // Skip '[' + + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, ']')) { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + + for (SizeType elementCount = 0;;) { + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ++elementCount; + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, ',')) { + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + } + else if (Consume(is, ']')) { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + + if (parseFlags & kParseTrailingCommasFlag) { + if (is.Peek() == ']') { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + is.Take(); + return; + } + } + } + } + + template + void ParseNull(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 'n'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { + if (RAPIDJSON_UNLIKELY(!handler.Null())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + void ParseTrue(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 't'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) { + if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + void ParseFalse(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 'f'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) { + if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { + if (RAPIDJSON_LIKELY(is.Peek() == expect)) { + is.Take(); + return true; + } + else + return false; + } + + // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). + template + unsigned ParseHex4(InputStream& is, size_t escapeOffset) { + unsigned codepoint = 0; + for (int i = 0; i < 4; i++) { + Ch c = is.Peek(); + codepoint <<= 4; + codepoint += static_cast(c); + if (c >= '0' && c <= '9') + codepoint -= '0'; + else if (c >= 'A' && c <= 'F') + codepoint -= 'A' - 10; + else if (c >= 'a' && c <= 'f') + codepoint -= 'a' - 10; + else { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); + } + is.Take(); + } + return codepoint; + } + + template + class StackStream { + public: + typedef CharType Ch; + + StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} + RAPIDJSON_FORCEINLINE void Put(Ch c) { + *stack_.template Push() = c; + ++length_; + } + + RAPIDJSON_FORCEINLINE void* Push(SizeType count) { + length_ += count; + return stack_.template Push(count); + } + + size_t Length() const { return length_; } + + Ch* Pop() { + return stack_.template Pop(length_); + } + + private: + StackStream(const StackStream&); + StackStream& operator=(const StackStream&); + + internal::Stack& stack_; + SizeType length_; + }; + + // Parse string and generate String event. Different code paths for kParseInsituFlag. + template + void ParseString(InputStream& is, Handler& handler, bool isKey = false) { + internal::StreamLocalCopy copy(is); + InputStream& s(copy.s); + + RAPIDJSON_ASSERT(s.Peek() == '\"'); + s.Take(); // Skip '\"' + + bool success = false; + if (parseFlags & kParseInsituFlag) { + typename InputStream::Ch *head = s.PutBegin(); + ParseStringToStream(s, s); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + size_t length = s.PutEnd(head) - 1; + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + const typename TargetEncoding::Ch* const str = reinterpret_cast(head); + success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); + } + else { + StackStream stackStream(stack_); + ParseStringToStream(s, stackStream); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + SizeType length = static_cast(stackStream.Length()) - 1; + const typename TargetEncoding::Ch* const str = stackStream.Pop(); + success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); + } + if (RAPIDJSON_UNLIKELY(!success)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + } + + // Parse string to an output is + // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. + template + RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + static const char escape[256] = { + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', + Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, + 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, + 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 + }; +#undef Z16 +//!@endcond + + for (;;) { + // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation. + if (!(parseFlags & kParseValidateEncodingFlag)) + ScanCopyUnescapedString(is, os); + + Ch c = is.Peek(); + if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape + size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset + is.Take(); + Ch e = is.Peek(); + if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) { + is.Take(); + os.Put(static_cast(escape[static_cast(e)])); + } + else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode + is.Take(); + unsigned codepoint = ParseHex4(is, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { + // Handle UTF-16 surrogate pair + if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + unsigned codepoint2 = ParseHex4(is, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + } + TEncoding::Encode(os, codepoint); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); + } + else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote + is.Take(); + os.Put('\0'); // null-terminate the string + return; + } + else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + if (c == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); + else + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell()); + } + else { + size_t offset = is.Tell(); + if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? + !Transcoder::Validate(is, os) : + !Transcoder::Transcode(is, os)))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); + } + } + } + + template + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { + // Do nothing for generic version + } + +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + const char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + return; + } + else + os.Put(*p++); + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + SizeType length; + #ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; + #else + length = static_cast(__builtin_ffs(r) - 1); + #endif + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) { + SkipUnescapedString(is); + return; + } + + char* p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16, q += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + for (const char* pend = p + length; p != pend; ) + *q++ = *p++; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + p += length; + break; + } + } + + is.src_ = is.dst_ = p; + } +#endif + + template + class NumberStream; + + template + class NumberStream { + public: + typedef typename InputStream::Ch Ch; + + NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } + ~NumberStream() {} + + RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } + RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } + RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } + RAPIDJSON_FORCEINLINE void Push(char) {} + + size_t Tell() { return is.Tell(); } + size_t Length() { return 0; } + const char* Pop() { return 0; } + + protected: + NumberStream& operator=(const NumberStream&); + + InputStream& is; + }; + + template + class NumberStream : public NumberStream { + typedef NumberStream Base; + public: + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} + ~NumberStream() {} + + RAPIDJSON_FORCEINLINE Ch TakePush() { + stackStream.Put(static_cast(Base::is.Peek())); + return Base::is.Take(); + } + + RAPIDJSON_FORCEINLINE void Push(char c) { + stackStream.Put(c); + } + + size_t Length() { return stackStream.Length(); } + + const char* Pop() { + stackStream.Put('\0'); + return stackStream.Pop(); + } + + private: + StackStream stackStream; + }; + + template + class NumberStream : public NumberStream { + typedef NumberStream Base; + public: + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} + ~NumberStream() {} + + RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } + }; + + template + void ParseNumber(InputStream& is, Handler& handler) { + internal::StreamLocalCopy copy(is); + NumberStream s(*this, copy.s); + + size_t startOffset = s.Tell(); + double d = 0.0; + bool useNanOrInf = false; + + // Parse minus + bool minus = Consume(s, '-'); + + // Parse int: zero / ( digit1-9 *DIGIT ) + unsigned i = 0; + uint64_t i64 = 0; + bool use64bit = false; + int significandDigit = 0; + if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) { + i = 0; + s.TakePush(); + } + else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { + i = static_cast(s.TakePush() - '0'); + + if (minus) + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 + if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { + i64 = i; + use64bit = true; + break; + } + } + i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + else + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 + if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { + i64 = i; + use64bit = true; + break; + } + } + i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + } + // Parse NaN or Infinity here + else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { + useNanOrInf = true; + if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) { + d = std::numeric_limits::quiet_NaN(); + } + else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) { + d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); + if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') + && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + + // Parse 64bit int + bool useDouble = false; + if (use64bit) { + if (minus) + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { + d = static_cast(i64); + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + else + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { + d = static_cast(i64); + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + } + + // Force double for big integer + if (useDouble) { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0 + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + d = d * 10 + (s.TakePush() - '0'); + } + } + + // Parse frac = decimal-point 1*DIGIT + int expFrac = 0; + size_t decimalPosition; + if (Consume(s, '.')) { + decimalPosition = s.Length(); + + if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); + + if (!useDouble) { +#if RAPIDJSON_64BIT + // Use i64 to store significand in 64-bit architecture + if (!use64bit) + i64 = i; + + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path + break; + else { + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + --expFrac; + if (i64 != 0) + significandDigit++; + } + } + + d = static_cast(i64); +#else + // Use double to store significand in 32-bit architecture + d = static_cast(use64bit ? i64 : i); +#endif + useDouble = true; + } + + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (significandDigit < 17) { + d = d * 10.0 + (s.TakePush() - '0'); + --expFrac; + if (RAPIDJSON_LIKELY(d > 0.0)) + significandDigit++; + } + else + s.TakePush(); + } + } + else + decimalPosition = s.Length(); // decimal position at the end of integer. + + // Parse exp = e [ minus / plus ] 1*DIGIT + int exp = 0; + if (Consume(s, 'e') || Consume(s, 'E')) { + if (!useDouble) { + d = static_cast(use64bit ? i64 : i); + useDouble = true; + } + + bool expMinus = false; + if (Consume(s, '+')) + ; + else if (Consume(s, '-')) + expMinus = true; + + if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = static_cast(s.Take() - '0'); + if (expMinus) { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = exp * 10 + static_cast(s.Take() - '0'); + if (exp >= 214748364) { // Issue #313: prevent overflow exponent + while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent + s.Take(); + } + } + } + else { // positive exp + int maxExp = 308 - expFrac; + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = exp * 10 + static_cast(s.Take() - '0'); + if (RAPIDJSON_UNLIKELY(exp > maxExp)) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + } + } + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); + + if (expMinus) + exp = -exp; + } + + // Finish parsing, call event according to the type of number. + bool cont = true; + + if (parseFlags & kParseNumbersAsStringsFlag) { + if (parseFlags & kParseInsituFlag) { + s.Pop(); // Pop stack no matter if it will be used or not. + typename InputStream::Ch* head = is.PutBegin(); + const size_t length = s.Tell() - startOffset; + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + // unable to insert the \0 character here, it will erase the comma after this number + const typename TargetEncoding::Ch* const str = reinterpret_cast(head); + cont = handler.RawNumber(str, SizeType(length), false); + } + else { + SizeType numCharsToCopy = static_cast(s.Length()); + StringStream srcStream(s.Pop()); + StackStream dstStream(stack_); + while (numCharsToCopy--) { + Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); + } + dstStream.Put('\0'); + const typename TargetEncoding::Ch* str = dstStream.Pop(); + const SizeType length = static_cast(dstStream.Length()) - 1; + cont = handler.RawNumber(str, SizeType(length), true); + } + } + else { + size_t length = s.Length(); + const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. + + if (useDouble) { + int p = exp + expFrac; + if (parseFlags & kParseFullPrecisionFlag) + d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); + else + d = internal::StrtodNormalPrecision(d, p); + + cont = handler.Double(minus ? -d : d); + } + else if (useNanOrInf) { + cont = handler.Double(d); + } + else { + if (use64bit) { + if (minus) + cont = handler.Int64(static_cast(~i64 + 1)); + else + cont = handler.Uint64(i64); + } + else { + if (minus) + cont = handler.Int(static_cast(~i + 1)); + else + cont = handler.Uint(i); + } + } + } + if (RAPIDJSON_UNLIKELY(!cont)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); + } + + // Parse any JSON value + template + void ParseValue(InputStream& is, Handler& handler) { + switch (is.Peek()) { + case 'n': ParseNull (is, handler); break; + case 't': ParseTrue (is, handler); break; + case 'f': ParseFalse (is, handler); break; + case '"': ParseString(is, handler); break; + case '{': ParseObject(is, handler); break; + case '[': ParseArray (is, handler); break; + default : + ParseNumber(is, handler); + break; + + } + } + + // Iterative Parsing + + // States + enum IterativeParsingState { + IterativeParsingStartState = 0, + IterativeParsingFinishState, + IterativeParsingErrorState, + + // Object states + IterativeParsingObjectInitialState, + IterativeParsingMemberKeyState, + IterativeParsingKeyValueDelimiterState, + IterativeParsingMemberValueState, + IterativeParsingMemberDelimiterState, + IterativeParsingObjectFinishState, + + // Array states + IterativeParsingArrayInitialState, + IterativeParsingElementState, + IterativeParsingElementDelimiterState, + IterativeParsingArrayFinishState, + + // Single value state + IterativeParsingValueState + }; + + enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 }; + + // Tokens + enum Token { + LeftBracketToken = 0, + RightBracketToken, + + LeftCurlyBracketToken, + RightCurlyBracketToken, + + CommaToken, + ColonToken, + + StringToken, + FalseToken, + TrueToken, + NullToken, + NumberToken, + + kTokenCount + }; + + RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define N NumberToken +#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N + // Maps from ASCII to Token + static const unsigned char tokenMap[256] = { + N16, // 00~0F + N16, // 10~1F + N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F + N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F + N16, // 40~4F + N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F + N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F + N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F + N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF + }; +#undef N +#undef N16 +//!@endcond + + if (sizeof(Ch) == 1 || static_cast(c) < 256) + return static_cast(tokenMap[static_cast(c)]); + else + return NumberToken; + } + + RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { + // current state x one lookahead token -> new state + static const char G[cIterativeParsingStateCount][kTokenCount] = { + // Start + { + IterativeParsingArrayInitialState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingValueState, // String + IterativeParsingValueState, // False + IterativeParsingValueState, // True + IterativeParsingValueState, // Null + IterativeParsingValueState // Number + }, + // Finish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Error(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ObjectInitial + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberKey + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingKeyValueDelimiterState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // KeyValueDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberValueState, // String + IterativeParsingMemberValueState, // False + IterativeParsingMemberValueState, // True + IterativeParsingMemberValueState, // Null + IterativeParsingMemberValueState // Number + }, + // MemberValue + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingMemberDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberDelimiter + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ObjectFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ArrayInitial + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // Element + { + IterativeParsingErrorState, // Left bracket + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingElementDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ElementDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // ArrayFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Single Value (sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + } + }; // End of G + + return static_cast(G[state][token]); + } + + // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). + // May return a new state on state pop. + template + RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { + (void)token; + + switch (dst) { + case IterativeParsingErrorState: + return dst; + + case IterativeParsingObjectInitialState: + case IterativeParsingArrayInitialState: + { + // Push the state(Element or MemeberValue) if we are nested in another array or value of member. + // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. + IterativeParsingState n = src; + if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) + n = IterativeParsingElementState; + else if (src == IterativeParsingKeyValueDelimiterState) + n = IterativeParsingMemberValueState; + // Push current state. + *stack_.template Push(1) = n; + // Initialize and push the member/element count. + *stack_.template Push(1) = 0; + // Call handler + bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return dst; + } + } + + case IterativeParsingMemberKeyState: + ParseString(is, handler, true); + if (HasParseError()) + return IterativeParsingErrorState; + else + return dst; + + case IterativeParsingKeyValueDelimiterState: + RAPIDJSON_ASSERT(token == ColonToken); + is.Take(); + return dst; + + case IterativeParsingMemberValueState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return dst; + + case IterativeParsingElementState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return dst; + + case IterativeParsingMemberDelimiterState: + case IterativeParsingElementDelimiterState: + is.Take(); + // Update member/element count. + *stack_.template Top() = *stack_.template Top() + 1; + return dst; + + case IterativeParsingObjectFinishState: + { + // Transit from delimiter is only allowed when trailing commas are enabled + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); + return IterativeParsingErrorState; + } + // Get member count. + SizeType c = *stack_.template Pop(1); + // If the object is not empty, count the last member. + if (src == IterativeParsingMemberValueState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndObject(c); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return n; + } + } + + case IterativeParsingArrayFinishState: + { + // Transit from delimiter is only allowed when trailing commas are enabled + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); + return IterativeParsingErrorState; + } + // Get element count. + SizeType c = *stack_.template Pop(1); + // If the array is not empty, count the last element. + if (src == IterativeParsingElementState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndArray(c); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return n; + } + } + + default: + // This branch is for IterativeParsingValueState actually. + // Use `default:` rather than + // `case IterativeParsingValueState:` is for code coverage. + + // The IterativeParsingStartState is not enumerated in this switch-case. + // It is impossible for that case. And it can be caught by following assertion. + + // The IterativeParsingFinishState is not enumerated in this switch-case either. + // It is a "derivative" state which cannot triggered from Predict() directly. + // Therefore it cannot happen here. And it can be caught by following assertion. + RAPIDJSON_ASSERT(dst == IterativeParsingValueState); + + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return IterativeParsingFinishState; + } + } + + template + void HandleError(IterativeParsingState src, InputStream& is) { + if (HasParseError()) { + // Error flag has been set. + return; + } + + switch (src) { + case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; + case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; + case IterativeParsingObjectInitialState: + case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; + case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; + case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; + case IterativeParsingKeyValueDelimiterState: + case IterativeParsingArrayInitialState: + case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; + default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; + } + } + + template + ParseResult IterativeParse(InputStream& is, Handler& handler) { + parseResult_.Clear(); + ClearStackOnExit scope(*this); + IterativeParsingState state = IterativeParsingStartState; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + while (is.Peek() != '\0') { + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state, t); + IterativeParsingState d = Transit(state, t, n, is, handler); + + if (d == IterativeParsingErrorState) { + HandleError(state, is); + break; + } + + state = d; + + // Do not further consume streams if a root JSON has been parsed. + if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) + break; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + + // Handle the end of file. + if (state != IterativeParsingFinishState) + HandleError(state, is); + + return parseResult_; + } + + static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. + internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. + ParseResult parseResult_; +}; // class GenericReader + +//! Reader with UTF8 encoding and default allocator. +typedef GenericReader, UTF8<> > Reader; + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_READER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/schema.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/schema.h new file mode 100644 index 0000000000000000000000000000000000000000..b182aa27f0bc5b29bfc981e4e48d846ec2ca7489 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/schema.h @@ -0,0 +1,2006 @@ +// Tencent is pleased to support the open source community by making RapidJSON available-> +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License-> You may obtain a copy of the License at +// +// http://opensource->org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied-> See the License for the +// specific language governing permissions and limitations under the License-> + +#ifndef RAPIDJSON_SCHEMA_H_ +#define RAPIDJSON_SCHEMA_H_ + +#include "document.h" +#include "pointer.h" +#include // abs, floor + +#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 +#endif + +#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) +#define RAPIDJSON_SCHEMA_USE_STDREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_STDREGEX 0 +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX +#include "internal/regex.h" +#elif RAPIDJSON_SCHEMA_USE_STDREGEX +#include +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX +#define RAPIDJSON_SCHEMA_HAS_REGEX 1 +#else +#define RAPIDJSON_SCHEMA_HAS_REGEX 0 +#endif + +#ifndef RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_VERBOSE 0 +#endif + +#if RAPIDJSON_SCHEMA_VERBOSE +#include "stringbuffer.h" +#endif + +RAPIDJSON_DIAG_PUSH + +#if defined(__GNUC__) +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_OFF(weak-vtables) +RAPIDJSON_DIAG_OFF(exit-time-destructors) +RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) +RAPIDJSON_DIAG_OFF(variadic-macros) +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Verbose Utilities + +#if RAPIDJSON_SCHEMA_VERBOSE + +namespace internal { + +inline void PrintInvalidKeyword(const char* keyword) { + printf("Fail keyword: %s\n", keyword); +} + +inline void PrintInvalidKeyword(const wchar_t* keyword) { + wprintf(L"Fail keyword: %ls\n", keyword); +} + +inline void PrintInvalidDocument(const char* document) { + printf("Fail document: %s\n\n", document); +} + +inline void PrintInvalidDocument(const wchar_t* document) { + wprintf(L"Fail document: %ls\n\n", document); +} + +inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { + printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); +} + +inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { + wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); +} + +} // namespace internal + +#endif // RAPIDJSON_SCHEMA_VERBOSE + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_INVALID_KEYWORD_RETURN + +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) +#else +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) +#endif + +#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ +RAPIDJSON_MULTILINEMACRO_BEGIN\ + context.invalidKeyword = keyword.GetString();\ + RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ + return false;\ +RAPIDJSON_MULTILINEMACRO_END + +/////////////////////////////////////////////////////////////////////////////// +// Forward declarations + +template +class GenericSchemaDocument; + +namespace internal { + +template +class Schema; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaValidator + +class ISchemaValidator { +public: + virtual ~ISchemaValidator() {} + virtual bool IsValid() const = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaStateFactory + +template +class ISchemaStateFactory { +public: + virtual ~ISchemaStateFactory() {} + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0; + virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; + virtual void* CreateHasher() = 0; + virtual uint64_t GetHashCode(void* hasher) = 0; + virtual void DestroryHasher(void* hasher) = 0; + virtual void* MallocState(size_t size) = 0; + virtual void FreeState(void* p) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Hasher + +// For comparison of compound value +template +class Hasher { +public: + typedef typename Encoding::Ch Ch; + + Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} + + bool Null() { return WriteType(kNullType); } + bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } + bool Int(int i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } + bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } + bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } + bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } + bool Double(double d) { + Number n; + if (d < 0) n.u.i = static_cast(d); + else n.u.u = static_cast(d); + n.d = d; + return WriteNumber(n); + } + + bool RawNumber(const Ch* str, SizeType len, bool) { + WriteBuffer(kNumberType, str, len * sizeof(Ch)); + return true; + } + + bool String(const Ch* str, SizeType len, bool) { + WriteBuffer(kStringType, str, len * sizeof(Ch)); + return true; + } + + bool StartObject() { return true; } + bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } + bool EndObject(SizeType memberCount) { + uint64_t h = Hash(0, kObjectType); + uint64_t* kv = stack_.template Pop(memberCount * 2); + for (SizeType i = 0; i < memberCount; i++) + h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive + *stack_.template Push() = h; + return true; + } + + bool StartArray() { return true; } + bool EndArray(SizeType elementCount) { + uint64_t h = Hash(0, kArrayType); + uint64_t* e = stack_.template Pop(elementCount); + for (SizeType i = 0; i < elementCount; i++) + h = Hash(h, e[i]); // Use hash to achieve element order sensitive + *stack_.template Push() = h; + return true; + } + + bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } + + uint64_t GetHashCode() const { + RAPIDJSON_ASSERT(IsValid()); + return *stack_.template Top(); + } + +private: + static const size_t kDefaultSize = 256; + struct Number { + union U { + uint64_t u; + int64_t i; + }u; + double d; + }; + + bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } + + bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } + + bool WriteBuffer(Type type, const void* data, size_t len) { + // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ + uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); + const unsigned char* d = static_cast(data); + for (size_t i = 0; i < len; i++) + h = Hash(h, d[i]); + *stack_.template Push() = h; + return true; + } + + static uint64_t Hash(uint64_t h, uint64_t d) { + static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); + h ^= d; + h *= kPrime; + return h; + } + + Stack stack_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidationContext + +template +struct SchemaValidationContext { + typedef Schema SchemaType; + typedef ISchemaStateFactory SchemaValidatorFactoryType; + typedef typename SchemaType::ValueType ValueType; + typedef typename ValueType::Ch Ch; + + enum PatternValidatorType { + kPatternValidatorOnly, + kPatternValidatorWithProperty, + kPatternValidatorWithAdditionalProperty + }; + + SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) : + factory(f), + schema(s), + valueSchema(), + invalidKeyword(), + hasher(), + arrayElementHashCodes(), + validators(), + validatorCount(), + patternPropertiesValidators(), + patternPropertiesValidatorCount(), + patternPropertiesSchemas(), + patternPropertiesSchemaCount(), + valuePatternValidatorType(kPatternValidatorOnly), + propertyExist(), + inArray(false), + valueUniqueness(false), + arrayUniqueness(false) + { + } + + ~SchemaValidationContext() { + if (hasher) + factory.DestroryHasher(hasher); + if (validators) { + for (SizeType i = 0; i < validatorCount; i++) + factory.DestroySchemaValidator(validators[i]); + factory.FreeState(validators); + } + if (patternPropertiesValidators) { + for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) + factory.DestroySchemaValidator(patternPropertiesValidators[i]); + factory.FreeState(patternPropertiesValidators); + } + if (patternPropertiesSchemas) + factory.FreeState(patternPropertiesSchemas); + if (propertyExist) + factory.FreeState(propertyExist); + } + + SchemaValidatorFactoryType& factory; + const SchemaType* schema; + const SchemaType* valueSchema; + const Ch* invalidKeyword; + void* hasher; // Only validator access + void* arrayElementHashCodes; // Only validator access this + ISchemaValidator** validators; + SizeType validatorCount; + ISchemaValidator** patternPropertiesValidators; + SizeType patternPropertiesValidatorCount; + const SchemaType** patternPropertiesSchemas; + SizeType patternPropertiesSchemaCount; + PatternValidatorType valuePatternValidatorType; + PatternValidatorType objectPatternValidatorType; + SizeType arrayElementIndex; + bool* propertyExist; + bool inArray; + bool valueUniqueness; + bool arrayUniqueness; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Schema + +template +class Schema { +public: + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename SchemaDocumentType::AllocatorType AllocatorType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef SchemaValidationContext Context; + typedef Schema SchemaType; + typedef GenericValue SValue; + friend class GenericSchemaDocument; + + Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : + allocator_(allocator), + enum_(), + enumCount_(), + not_(), + type_((1 << kTotalSchemaType) - 1), // typeless + validatorCount_(), + properties_(), + additionalPropertiesSchema_(), + patternProperties_(), + patternPropertyCount_(), + propertyCount_(), + minProperties_(), + maxProperties_(SizeType(~0)), + additionalProperties_(true), + hasDependencies_(), + hasRequired_(), + hasSchemaDependencies_(), + additionalItemsSchema_(), + itemsList_(), + itemsTuple_(), + itemsTupleCount_(), + minItems_(), + maxItems_(SizeType(~0)), + additionalItems_(true), + uniqueItems_(false), + pattern_(), + minLength_(0), + maxLength_(~SizeType(0)), + exclusiveMinimum_(false), + exclusiveMaximum_(false) + { + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename ValueType::ConstValueIterator ConstValueIterator; + typedef typename ValueType::ConstMemberIterator ConstMemberIterator; + + if (!value.IsObject()) + return; + + if (const ValueType* v = GetMember(value, GetTypeString())) { + type_ = 0; + if (v->IsString()) + AddType(*v); + else if (v->IsArray()) + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) + AddType(*itr); + } + + if (const ValueType* v = GetMember(value, GetEnumString())) + if (v->IsArray() && v->Size() > 0) { + enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { + typedef Hasher > EnumHasherType; + char buffer[256 + 24]; + MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); + EnumHasherType h(&hasherAllocator, 256); + itr->Accept(h); + enum_[enumCount_++] = h.GetHashCode(); + } + } + + if (schemaDocument) { + AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); + AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); + AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); + } + + if (const ValueType* v = GetMember(value, GetNotString())) { + schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); + notValidatorIndex_ = validatorCount_; + validatorCount_++; + } + + // Object + + const ValueType* properties = GetMember(value, GetPropertiesString()); + const ValueType* required = GetMember(value, GetRequiredString()); + const ValueType* dependencies = GetMember(value, GetDependenciesString()); + { + // Gather properties from properties/required/dependencies + SValue allProperties(kArrayType); + + if (properties && properties->IsObject()) + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) + AddUniqueElement(allProperties, itr->name); + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) + AddUniqueElement(allProperties, *itr); + + if (dependencies && dependencies->IsObject()) + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { + AddUniqueElement(allProperties, itr->name); + if (itr->value.IsArray()) + for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) + if (i->IsString()) + AddUniqueElement(allProperties, *i); + } + + if (allProperties.Size() > 0) { + propertyCount_ = allProperties.Size(); + properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); + for (SizeType i = 0; i < propertyCount_; i++) { + new (&properties_[i]) Property(); + properties_[i].name = allProperties[i]; + properties_[i].schema = GetTypeless(); + } + } + } + + if (properties && properties->IsObject()) { + PointerType q = p.Append(GetPropertiesString(), allocator_); + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { + SizeType index; + if (FindPropertyIndex(itr->name, &index)) + schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); + } + } + + if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { + PointerType q = p.Append(GetPatternPropertiesString(), allocator_); + patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); + patternPropertyCount_ = 0; + + for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { + new (&patternProperties_[patternPropertyCount_]) PatternProperty(); + patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); + schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); + patternPropertyCount_++; + } + } + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) { + SizeType index; + if (FindPropertyIndex(*itr, &index)) { + properties_[index].required = true; + hasRequired_ = true; + } + } + + if (dependencies && dependencies->IsObject()) { + PointerType q = p.Append(GetDependenciesString(), allocator_); + hasDependencies_ = true; + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { + SizeType sourceIndex; + if (FindPropertyIndex(itr->name, &sourceIndex)) { + if (itr->value.IsArray()) { + properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); + std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); + for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { + SizeType targetIndex; + if (FindPropertyIndex(*targetItr, &targetIndex)) + properties_[sourceIndex].dependencies[targetIndex] = true; + } + } + else if (itr->value.IsObject()) { + hasSchemaDependencies_ = true; + schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); + properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; + validatorCount_++; + } + } + } + } + + if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { + if (v->IsBool()) + additionalProperties_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); + } + + AssignIfExist(minProperties_, value, GetMinPropertiesString()); + AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); + + // Array + if (const ValueType* v = GetMember(value, GetItemsString())) { + PointerType q = p.Append(GetItemsString(), allocator_); + if (v->IsObject()) // List validation + schemaDocument->CreateSchema(&itemsList_, q, *v, document); + else if (v->IsArray()) { // Tuple validation + itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); + SizeType index = 0; + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) + schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); + } + } + + AssignIfExist(minItems_, value, GetMinItemsString()); + AssignIfExist(maxItems_, value, GetMaxItemsString()); + + if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { + if (v->IsBool()) + additionalItems_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); + } + + AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); + + // String + AssignIfExist(minLength_, value, GetMinLengthString()); + AssignIfExist(maxLength_, value, GetMaxLengthString()); + + if (const ValueType* v = GetMember(value, GetPatternString())) + pattern_ = CreatePattern(*v); + + // Number + if (const ValueType* v = GetMember(value, GetMinimumString())) + if (v->IsNumber()) + minimum_.CopyFrom(*v, *allocator_); + + if (const ValueType* v = GetMember(value, GetMaximumString())) + if (v->IsNumber()) + maximum_.CopyFrom(*v, *allocator_); + + AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); + AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); + + if (const ValueType* v = GetMember(value, GetMultipleOfString())) + if (v->IsNumber() && v->GetDouble() > 0.0) + multipleOf_.CopyFrom(*v, *allocator_); + } + + ~Schema() { + if (allocator_) { + allocator_->Free(enum_); + } + if (properties_) { + for (SizeType i = 0; i < propertyCount_; i++) + properties_[i].~Property(); + AllocatorType::Free(properties_); + } + if (patternProperties_) { + for (SizeType i = 0; i < patternPropertyCount_; i++) + patternProperties_[i].~PatternProperty(); + AllocatorType::Free(patternProperties_); + } + AllocatorType::Free(itemsTuple_); +#if RAPIDJSON_SCHEMA_HAS_REGEX + if (pattern_) { + pattern_->~RegexType(); + allocator_->Free(pattern_); + } +#endif + } + + bool BeginValue(Context& context) const { + if (context.inArray) { + if (uniqueItems_) + context.valueUniqueness = true; + + if (itemsList_) + context.valueSchema = itemsList_; + else if (itemsTuple_) { + if (context.arrayElementIndex < itemsTupleCount_) + context.valueSchema = itemsTuple_[context.arrayElementIndex]; + else if (additionalItemsSchema_) + context.valueSchema = additionalItemsSchema_; + else if (additionalItems_) + context.valueSchema = GetTypeless(); + else + RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); + } + else + context.valueSchema = GetTypeless(); + + context.arrayElementIndex++; + } + return true; + } + + RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { + if (context.patternPropertiesValidatorCount > 0) { + bool otherValid = false; + SizeType count = context.patternPropertiesValidatorCount; + if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) + otherValid = context.patternPropertiesValidators[--count]->IsValid(); + + bool patternValid = true; + for (SizeType i = 0; i < count; i++) + if (!context.patternPropertiesValidators[i]->IsValid()) { + patternValid = false; + break; + } + + if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { + if (!patternValid) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { + if (!patternValid || !otherValid) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + + if (enum_) { + const uint64_t h = context.factory.GetHashCode(context.hasher); + for (SizeType i = 0; i < enumCount_; i++) + if (enum_[i] == h) + goto foundEnum; + RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); + foundEnum:; + } + + if (allOf_.schemas) + for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) + if (!context.validators[i]->IsValid()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); + + if (anyOf_.schemas) { + for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) + if (context.validators[i]->IsValid()) + goto foundAny; + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); + foundAny:; + } + + if (oneOf_.schemas) { + bool oneValid = false; + for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) + if (context.validators[i]->IsValid()) { + if (oneValid) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + else + oneValid = true; + } + if (!oneValid) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + } + + if (not_ && context.validators[notValidatorIndex_]->IsValid()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); + + return true; + } + + bool Null(Context& context) const { + if (!(type_ & (1 << kNullSchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + return CreateParallelValidator(context); + } + + bool Bool(Context& context, bool) const { + if (!(type_ & (1 << kBooleanSchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + return CreateParallelValidator(context); + } + + bool Int(Context& context, int i) const { + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint(Context& context, unsigned u) const { + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Int64(Context& context, int64_t i) const { + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint64(Context& context, uint64_t u) const { + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Double(Context& context, double d) const { + if (!(type_ & (1 << kNumberSchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) + return false; + + if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) + return false; + + if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) + return false; + + return CreateParallelValidator(context); + } + + bool String(Context& context, const Ch* str, SizeType length, bool) const { + if (!(type_ & (1 << kStringSchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + if (minLength_ != 0 || maxLength_ != SizeType(~0)) { + SizeType count; + if (internal::CountStringCodePoint(str, length, &count)) { + if (count < minLength_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); + if (count > maxLength_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); + } + } + + if (pattern_ && !IsPatternMatch(pattern_, str, length)) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); + + return CreateParallelValidator(context); + } + + bool StartObject(Context& context) const { + if (!(type_ & (1 << kObjectSchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + if (hasDependencies_ || hasRequired_) { + context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); + std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); + } + + if (patternProperties_) { // pre-allocate schema array + SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType + context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType*) * count)); + context.patternPropertiesSchemaCount = 0; + std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); + } + + return CreateParallelValidator(context); + } + + bool Key(Context& context, const Ch* str, SizeType len, bool) const { + if (patternProperties_) { + context.patternPropertiesSchemaCount = 0; + for (SizeType i = 0; i < patternPropertyCount_; i++) + if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; + } + + SizeType index; + if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { + if (context.patternPropertiesSchemaCount > 0) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; + context.valueSchema = GetTypeless(); + context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; + } + else + context.valueSchema = properties_[index].schema; + + if (context.propertyExist) + context.propertyExist[index] = true; + + return true; + } + + if (additionalPropertiesSchema_) { + if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; + context.valueSchema = GetTypeless(); + context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; + } + else + context.valueSchema = additionalPropertiesSchema_; + return true; + } + else if (additionalProperties_) { + context.valueSchema = GetTypeless(); + return true; + } + + if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); + + return true; + } + + bool EndObject(Context& context, SizeType memberCount) const { + if (hasRequired_) + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].required) + if (!context.propertyExist[index]) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); + + if (memberCount < minProperties_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); + + if (memberCount > maxProperties_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); + + if (hasDependencies_) { + for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) + if (context.propertyExist[sourceIndex]) { + if (properties_[sourceIndex].dependencies) { + for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) + if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex]) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); + } + else if (properties_[sourceIndex].dependenciesSchema) + if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); + } + } + + return true; + } + + bool StartArray(Context& context) const { + if (!(type_ & (1 << kArraySchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + context.arrayElementIndex = 0; + context.inArray = true; + + return CreateParallelValidator(context); + } + + bool EndArray(Context& context, SizeType elementCount) const { + context.inArray = false; + + if (elementCount < minItems_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); + + if (elementCount > maxItems_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); + + return true; + } + + // Generate functions for string literal according to Ch +#define RAPIDJSON_STRING_(name, ...) \ + static const ValueType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\ + return v;\ + } + + RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') + RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') + RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') + RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') + RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') + RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') + RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') + RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') + RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') + RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') + RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') + RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') + RAPIDJSON_STRING_(Not, 'n', 'o', 't') + RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') + RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') + RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') + RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') + +#undef RAPIDJSON_STRING_ + +private: + enum SchemaValueType { + kNullSchemaType, + kBooleanSchemaType, + kObjectSchemaType, + kArraySchemaType, + kStringSchemaType, + kNumberSchemaType, + kIntegerSchemaType, + kTotalSchemaType + }; + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + typedef internal::GenericRegex RegexType; +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + typedef std::basic_regex RegexType; +#else + typedef char RegexType; +#endif + + struct SchemaArray { + SchemaArray() : schemas(), count() {} + ~SchemaArray() { AllocatorType::Free(schemas); } + const SchemaType** schemas; + SizeType begin; // begin index of context.validators + SizeType count; + }; + + static const SchemaType* GetTypeless() { + static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); + return &typeless; + } + + template + void AddUniqueElement(V1& a, const V2& v) { + for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) + if (*itr == v) + return; + V1 c(v, *allocator_); + a.PushBack(c, *allocator_); + } + + static const ValueType* GetMember(const ValueType& value, const ValueType& name) { + typename ValueType::ConstMemberIterator itr = value.FindMember(name); + return itr != value.MemberEnd() ? &(itr->value) : 0; + } + + static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { + if (const ValueType* v = GetMember(value, name)) + if (v->IsBool()) + out = v->GetBool(); + } + + static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { + if (const ValueType* v = GetMember(value, name)) + if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) + out = static_cast(v->GetUint64()); + } + + void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { + if (const ValueType* v = GetMember(value, name)) { + if (v->IsArray() && v->Size() > 0) { + PointerType q = p.Append(name, allocator_); + out.count = v->Size(); + out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); + memset(out.schemas, 0, sizeof(Schema*)* out.count); + for (SizeType i = 0; i < out.count; i++) + schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); + out.begin = validatorCount_; + validatorCount_ += out.count; + } + } + } + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + template + RegexType* CreatePattern(const ValueType& value) { + if (value.IsString()) { + RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); + if (!r->IsValid()) { + r->~RegexType(); + AllocatorType::Free(r); + r = 0; + } + return r; + } + return 0; + } + + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { + return pattern->Search(str); + } +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + template + RegexType* CreatePattern(const ValueType& value) { + if (value.IsString()) + try { + return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); + } + catch (const std::regex_error&) { + } + return 0; + } + + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { + std::match_results r; + return std::regex_search(str, str + length, r, *pattern); + } +#else + template + RegexType* CreatePattern(const ValueType&) { return 0; } + + static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } +#endif // RAPIDJSON_SCHEMA_USE_STDREGEX + + void AddType(const ValueType& type) { + if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; + else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; + else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; + else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; + else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; + else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; + else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); + } + + bool CreateParallelValidator(Context& context) const { + if (enum_ || context.arrayUniqueness) + context.hasher = context.factory.CreateHasher(); + + if (validatorCount_) { + RAPIDJSON_ASSERT(context.validators == 0); + context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); + context.validatorCount = validatorCount_; + + if (allOf_.schemas) + CreateSchemaValidators(context, allOf_); + + if (anyOf_.schemas) + CreateSchemaValidators(context, anyOf_); + + if (oneOf_.schemas) + CreateSchemaValidators(context, oneOf_); + + if (not_) + context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_); + + if (hasSchemaDependencies_) { + for (SizeType i = 0; i < propertyCount_; i++) + if (properties_[i].dependenciesSchema) + context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema); + } + } + + return true; + } + + void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const { + for (SizeType i = 0; i < schemas.count; i++) + context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]); + } + + // O(n) + bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { + SizeType len = name.GetStringLength(); + const Ch* str = name.GetString(); + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].name.GetStringLength() == len && + (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) + { + *outIndex = index; + return true; + } + return false; + } + + bool CheckInt(Context& context, int64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + if (!minimum_.IsNull()) { + if (minimum_.IsInt64()) { + if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + else if (minimum_.IsUint64()) { + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() + } + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) { + if (maximum_.IsInt64()) { + if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + else if (maximum_.IsUint64()) + /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64() + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) { + if (multipleOf_.IsUint64()) { + if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckUint(Context& context, uint64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + if (!minimum_.IsNull()) { + if (minimum_.IsUint64()) { + if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + else if (minimum_.IsInt64()) + /* do nothing */; // i >= 0 > minimum.Getint64() + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) { + if (maximum_.IsUint64()) { + if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + else if (maximum_.IsInt64()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) { + if (multipleOf_.IsUint64()) { + if (i % multipleOf_.GetUint64() != 0) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckDoubleMinimum(Context& context, double d) const { + if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + return true; + } + + bool CheckDoubleMaximum(Context& context, double d) const { + if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + return true; + } + + bool CheckDoubleMultipleOf(Context& context, double d) const { + double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); + double q = std::floor(a / b); + double r = a - q * b; + if (r > 0.0) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + return true; + } + + struct Property { + Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} + ~Property() { AllocatorType::Free(dependencies); } + SValue name; + const SchemaType* schema; + const SchemaType* dependenciesSchema; + SizeType dependenciesValidatorIndex; + bool* dependencies; + bool required; + }; + + struct PatternProperty { + PatternProperty() : schema(), pattern() {} + ~PatternProperty() { + if (pattern) { + pattern->~RegexType(); + AllocatorType::Free(pattern); + } + } + const SchemaType* schema; + RegexType* pattern; + }; + + AllocatorType* allocator_; + uint64_t* enum_; + SizeType enumCount_; + SchemaArray allOf_; + SchemaArray anyOf_; + SchemaArray oneOf_; + const SchemaType* not_; + unsigned type_; // bitmask of kSchemaType + SizeType validatorCount_; + SizeType notValidatorIndex_; + + Property* properties_; + const SchemaType* additionalPropertiesSchema_; + PatternProperty* patternProperties_; + SizeType patternPropertyCount_; + SizeType propertyCount_; + SizeType minProperties_; + SizeType maxProperties_; + bool additionalProperties_; + bool hasDependencies_; + bool hasRequired_; + bool hasSchemaDependencies_; + + const SchemaType* additionalItemsSchema_; + const SchemaType* itemsList_; + const SchemaType** itemsTuple_; + SizeType itemsTupleCount_; + SizeType minItems_; + SizeType maxItems_; + bool additionalItems_; + bool uniqueItems_; + + RegexType* pattern_; + SizeType minLength_; + SizeType maxLength_; + + SValue minimum_; + SValue maximum_; + SValue multipleOf_; + bool exclusiveMinimum_; + bool exclusiveMaximum_; +}; + +template +struct TokenHelper { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + *documentStack.template Push() = '/'; + char buffer[21]; + size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); + for (size_t i = 0; i < length; i++) + *documentStack.template Push() = buffer[i]; + } +}; + +// Partial specialized version for char to prevent buffer copying. +template +struct TokenHelper { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + if (sizeof(SizeType) == 4) { + char *buffer = documentStack.template Push(1 + 10); // '/' + uint + *buffer++ = '/'; + const char* end = internal::u32toa(index, buffer); + documentStack.template Pop(static_cast(10 - (end - buffer))); + } + else { + char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 + *buffer++ = '/'; + const char* end = internal::u64toa(index, buffer); + documentStack.template Pop(static_cast(20 - (end - buffer))); + } + } +}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// IGenericRemoteSchemaDocumentProvider + +template +class IGenericRemoteSchemaDocumentProvider { +public: + typedef typename SchemaDocumentType::Ch Ch; + + virtual ~IGenericRemoteSchemaDocumentProvider() {} + virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaDocument + +//! JSON schema document. +/*! + A JSON schema document is a compiled version of a JSON schema. + It is basically a tree of internal::Schema. + + \note This is an immutable class (i.e. its instance cannot be modified after construction). + \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. + \tparam Allocator Allocator type for allocating memory of this document. +*/ +template +class GenericSchemaDocument { +public: + typedef ValueT ValueType; + typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; + typedef Allocator AllocatorType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef internal::Schema SchemaType; + typedef GenericPointer PointerType; + friend class internal::Schema; + template + friend class GenericSchemaValidator; + + //! Constructor. + /*! + Compile a JSON document into schema document. + + \param document A JSON document as source. + \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. + \param allocator An optional allocator instance for allocating memory. Can be null. + */ + explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : + remoteProvider_(remoteProvider), + allocator_(allocator), + ownAllocator_(), + root_(), + schemaMap_(allocator, kInitialSchemaMapSize), + schemaRef_(allocator, kInitialSchemaRefSize) + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + + // Generate root schema, it will call CreateSchema() to create sub-schemas, + // And call AddRefSchema() if there are $ref. + CreateSchemaRecursive(&root_, PointerType(), document, document); + + // Resolve $ref + while (!schemaRef_.Empty()) { + SchemaRefEntry* refEntry = schemaRef_.template Pop(1); + if (const SchemaType* s = GetSchema(refEntry->target)) { + if (refEntry->schema) + *refEntry->schema = s; + + // Create entry in map if not exist + if (!GetSchema(refEntry->source)) { + new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); + } + } + refEntry->~SchemaRefEntry(); + } + + RAPIDJSON_ASSERT(root_ != 0); + + schemaRef_.ShrinkToFit(); // Deallocate all memory for ref + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : + remoteProvider_(rhs.remoteProvider_), + allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + root_(rhs.root_), + schemaMap_(std::move(rhs.schemaMap_)), + schemaRef_(std::move(rhs.schemaRef_)) + { + rhs.remoteProvider_ = 0; + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + } +#endif + + //! Destructor + ~GenericSchemaDocument() { + while (!schemaMap_.Empty()) + schemaMap_.template Pop(1)->~SchemaEntry(); + + RAPIDJSON_DELETE(ownAllocator_); + } + + //! Get the root schema. + const SchemaType& GetRoot() const { return *root_; } + +private: + //! Prohibit copying + GenericSchemaDocument(const GenericSchemaDocument&); + //! Prohibit assignment + GenericSchemaDocument& operator=(const GenericSchemaDocument&); + + struct SchemaRefEntry { + SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} + PointerType source; + PointerType target; + const SchemaType** schema; + }; + + struct SchemaEntry { + SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} + ~SchemaEntry() { + if (owned) { + schema->~SchemaType(); + Allocator::Free(schema); + } + } + PointerType pointer; + SchemaType* schema; + bool owned; + }; + + void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { + if (schema) + *schema = SchemaType::GetTypeless(); + + if (v.GetType() == kObjectType) { + const SchemaType* s = GetSchema(pointer); + if (!s) + CreateSchema(schema, pointer, v, document); + + for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) + CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); + } + else if (v.GetType() == kArrayType) + for (SizeType i = 0; i < v.Size(); i++) + CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); + } + + void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { + RAPIDJSON_ASSERT(pointer.IsValid()); + if (v.IsObject()) { + if (!HandleRefSchema(pointer, schema, v, document)) { + SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); + new (schemaMap_.template Push()) SchemaEntry(pointer, s, true, allocator_); + if (schema) + *schema = s; + } + } + } + + bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) { + static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; + static const ValueType kRefValue(kRefString, 4); + + typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); + if (itr == v.MemberEnd()) + return false; + + if (itr->value.IsString()) { + SizeType len = itr->value.GetStringLength(); + if (len > 0) { + const Ch* s = itr->value.GetString(); + SizeType i = 0; + while (i < len && s[i] != '#') // Find the first # + i++; + + if (i > 0) { // Remote reference, resolve immediately + if (remoteProvider_) { + if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) { + PointerType pointer(&s[i], len - i, allocator_); + if (pointer.IsValid()) { + if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { + if (schema) + *schema = sc; + return true; + } + } + } + } + } + else if (s[i] == '#') { // Local reference, defer resolution + PointerType pointer(&s[i], len - i, allocator_); + if (pointer.IsValid()) { + if (const ValueType* nv = pointer.Get(document)) + if (HandleRefSchema(source, schema, *nv, document)) + return true; + + new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); + return true; + } + } + } + } + return false; + } + + const SchemaType* GetSchema(const PointerType& pointer) const { + for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (pointer == target->pointer) + return target->schema; + return 0; + } + + PointerType GetPointer(const SchemaType* schema) const { + for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (schema == target->schema) + return target->pointer; + return PointerType(); + } + + static const size_t kInitialSchemaMapSize = 64; + static const size_t kInitialSchemaRefSize = 64; + + IRemoteSchemaDocumentProviderType* remoteProvider_; + Allocator *allocator_; + Allocator *ownAllocator_; + const SchemaType* root_; //!< Root schema. + internal::Stack schemaMap_; // Stores created Pointer -> Schemas + internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref +}; + +//! GenericSchemaDocument using Value type. +typedef GenericSchemaDocument SchemaDocument; +//! IGenericRemoteSchemaDocumentProvider using SchemaDocument. +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaValidator + +//! JSON Schema Validator. +/*! + A SAX style JSON schema validator. + It uses a \c GenericSchemaDocument to validate SAX events. + It delegates the incoming SAX events to an output handler. + The default output handler does nothing. + It can be reused multiple times by calling \c Reset(). + + \tparam SchemaDocumentType Type of schema document. + \tparam OutputHandler Type of output handler. Default handler does nothing. + \tparam StateAllocator Allocator for storing the internal validation states. +*/ +template < + typename SchemaDocumentType, + typename OutputHandler = BaseReaderHandler, + typename StateAllocator = CrtAllocator> +class GenericSchemaValidator : + public internal::ISchemaStateFactory, + public internal::ISchemaValidator +{ +public: + typedef typename SchemaDocumentType::SchemaType SchemaType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename SchemaType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + + //! Constructor without output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + outputHandler_(GetNullHandler()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(0) +#endif + { + } + + //! Constructor with output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + OutputHandler& outputHandler, + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + outputHandler_(outputHandler), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(0) +#endif + { + } + + //! Destructor. + ~GenericSchemaValidator() { + Reset(); + RAPIDJSON_DELETE(ownStateAllocator_); + } + + //! Reset the internal states. + void Reset() { + while (!schemaStack_.Empty()) + PopSchema(); + documentStack_.Clear(); + valid_ = true; + } + + //! Checks whether the current state is valid. + // Implementation of ISchemaValidator + virtual bool IsValid() const { return valid_; } + + //! Gets the JSON pointer pointed to the invalid schema. + PointerType GetInvalidSchemaPointer() const { + return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema()); + } + + //! Gets the keyword of invalid schema. + const Ch* GetInvalidSchemaKeyword() const { + return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword; + } + + //! Gets the JSON pointer pointed to the invalid value. + PointerType GetInvalidDocumentPointer() const { + return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); + } + +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ +RAPIDJSON_MULTILINEMACRO_BEGIN\ + *documentStack_.template Push() = '\0';\ + documentStack_.template Pop(1);\ + internal::PrintInvalidDocument(documentStack_.template Bottom());\ +RAPIDJSON_MULTILINEMACRO_END +#else +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() +#endif + +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ + if (!valid_) return false; \ + if (!BeginValue() || !CurrentSchema().method arg1) {\ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ + return valid_ = false;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ + for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ + if (context->hasher)\ + static_cast(context->hasher)->method arg2;\ + if (context->validators)\ + for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ + static_cast(context->validators[i_])->method arg2;\ + if (context->patternPropertiesValidators)\ + for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ + static_cast(context->patternPropertiesValidators[i_])->method arg2;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ + return valid_ = EndValue() && outputHandler_.method arg2 + +#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ + RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) + + bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); } + bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } + bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } + bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } + bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } + bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } + bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } + bool RawNumber(const Ch* str, SizeType length, bool copy) + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + bool String(const Ch* str, SizeType length, bool copy) + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + + bool StartObject() { + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); + return valid_ = outputHandler_.StartObject(); + } + + bool Key(const Ch* str, SizeType len, bool copy) { + if (!valid_) return false; + AppendToken(str, len); + if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); + return valid_ = outputHandler_.Key(str, len, copy); + } + + bool EndObject(SizeType memberCount) { + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); + if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); + } + + bool StartArray() { + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); + return valid_ = outputHandler_.StartArray(); + } + + bool EndArray(SizeType elementCount) { + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); + if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); + } + +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ +#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ +#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ + + // Implementation of ISchemaStateFactory + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) { + return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, +#if RAPIDJSON_SCHEMA_VERBOSE + depth_ + 1, +#endif + &GetStateAllocator()); + } + + virtual void DestroySchemaValidator(ISchemaValidator* validator) { + GenericSchemaValidator* v = static_cast(validator); + v->~GenericSchemaValidator(); + StateAllocator::Free(v); + } + + virtual void* CreateHasher() { + return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); + } + + virtual uint64_t GetHashCode(void* hasher) { + return static_cast(hasher)->GetHashCode(); + } + + virtual void DestroryHasher(void* hasher) { + HasherType* h = static_cast(hasher); + h->~HasherType(); + StateAllocator::Free(h); + } + + virtual void* MallocState(size_t size) { + return GetStateAllocator().Malloc(size); + } + + virtual void FreeState(void* p) { + return StateAllocator::Free(p); + } + +private: + typedef typename SchemaType::Context Context; + typedef GenericValue, StateAllocator> HashCodeArray; + typedef internal::Hasher HasherType; + + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + const SchemaType& root, +#if RAPIDJSON_SCHEMA_VERBOSE + unsigned depth, +#endif + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(root), + outputHandler_(GetNullHandler()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(depth) +#endif + { + } + + StateAllocator& GetStateAllocator() { + if (!stateAllocator_) + stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator()); + return *stateAllocator_; + } + + bool BeginValue() { + if (schemaStack_.Empty()) + PushSchema(root_); + else { + if (CurrentContext().inArray) + internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); + + if (!CurrentSchema().BeginValue(CurrentContext())) + return false; + + SizeType count = CurrentContext().patternPropertiesSchemaCount; + const SchemaType** sa = CurrentContext().patternPropertiesSchemas; + typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; + bool valueUniqueness = CurrentContext().valueUniqueness; + if (CurrentContext().valueSchema) + PushSchema(*CurrentContext().valueSchema); + + if (count > 0) { + CurrentContext().objectPatternValidatorType = patternValidatorType; + ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; + SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; + va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); + for (SizeType i = 0; i < count; i++) + va[validatorCount++] = CreateSchemaValidator(*sa[i]); + } + + CurrentContext().arrayUniqueness = valueUniqueness; + } + return true; + } + + bool EndValue() { + if (!CurrentSchema().EndValue(CurrentContext())) + return false; + +#if RAPIDJSON_SCHEMA_VERBOSE + GenericStringBuffer sb; + schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); + + *documentStack_.template Push() = '\0'; + documentStack_.template Pop(1); + internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); +#endif + + uint64_t h = CurrentContext().arrayUniqueness ? static_cast(CurrentContext().hasher)->GetHashCode() : 0; + + PopSchema(); + + if (!schemaStack_.Empty()) { + Context& context = CurrentContext(); + if (context.valueUniqueness) { + HashCodeArray* a = static_cast(context.arrayElementHashCodes); + if (!a) + CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); + for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) + if (itr->GetUint64() == h) + RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); + a->PushBack(h, GetStateAllocator()); + } + } + + // Remove the last token of document pointer + while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') + ; + + return true; + } + + void AppendToken(const Ch* str, SizeType len) { + documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters + *documentStack_.template PushUnsafe() = '/'; + for (SizeType i = 0; i < len; i++) { + if (str[i] == '~') { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '0'; + } + else if (str[i] == '/') { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '1'; + } + else + *documentStack_.template PushUnsafe() = str[i]; + } + } + + RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, &schema); } + + RAPIDJSON_FORCEINLINE void PopSchema() { + Context* c = schemaStack_.template Pop(1); + if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { + a->~HashCodeArray(); + StateAllocator::Free(a); + } + c->~Context(); + } + + const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } + Context& CurrentContext() { return *schemaStack_.template Top(); } + const Context& CurrentContext() const { return *schemaStack_.template Top(); } + + static OutputHandler& GetNullHandler() { + static OutputHandler nullHandler; + return nullHandler; + } + + static const size_t kDefaultSchemaStackCapacity = 1024; + static const size_t kDefaultDocumentStackCapacity = 256; + const SchemaDocumentType* schemaDocument_; + const SchemaType& root_; + OutputHandler& outputHandler_; + StateAllocator* stateAllocator_; + StateAllocator* ownStateAllocator_; + internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) + internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) + bool valid_; +#if RAPIDJSON_SCHEMA_VERBOSE + unsigned depth_; +#endif +}; + +typedef GenericSchemaValidator SchemaValidator; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidatingReader + +//! A helper class for parsing with validation. +/*! + This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). + + \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam SourceEncoding Encoding of the input stream. + \tparam SchemaDocumentType Type of schema document. + \tparam StackAllocator Allocator type for stack. +*/ +template < + unsigned parseFlags, + typename InputStream, + typename SourceEncoding, + typename SchemaDocumentType = SchemaDocument, + typename StackAllocator = CrtAllocator> +class SchemaValidatingReader { +public: + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename InputStream::Ch Ch; + + //! Constructor + /*! + \param is Input stream. + \param sd Schema document. + */ + SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {} + + template + bool operator()(Handler& handler) { + GenericReader reader; + GenericSchemaValidator validator(sd_, handler); + parseResult_ = reader.template Parse(is_, validator); + + isValid_ = validator.IsValid(); + if (isValid_) { + invalidSchemaPointer_ = PointerType(); + invalidSchemaKeyword_ = 0; + invalidDocumentPointer_ = PointerType(); + } + else { + invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); + invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); + invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); + } + + return parseResult_; + } + + const ParseResult& GetParseResult() const { return parseResult_; } + bool IsValid() const { return isValid_; } + const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } + const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } + const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } + +private: + InputStream& is_; + const SchemaDocumentType& sd_; + + ParseResult parseResult_; + PointerType invalidSchemaPointer_; + const Ch* invalidSchemaKeyword_; + PointerType invalidDocumentPointer_; + bool isValid_; +}; + +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP + +#endif // RAPIDJSON_SCHEMA_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/stream.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/stream.h new file mode 100644 index 0000000000000000000000000000000000000000..fef82c252ffb5cc54a9d7f45f5c8c1b699997a1c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/stream.h @@ -0,0 +1,179 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#include "rapidjson.h" + +#ifndef RAPIDJSON_STREAM_H_ +#define RAPIDJSON_STREAM_H_ + +#include "encodings.h" + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Stream + +/*! \class rapidjson::Stream + \brief Concept for reading and writing characters. + + For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). + + For write-only stream, only need to implement Put() and Flush(). + +\code +concept Stream { + typename Ch; //!< Character type of the stream. + + //! Read the current character from stream without moving the read cursor. + Ch Peek() const; + + //! Read the current character from stream and moving the read cursor to next character. + Ch Take(); + + //! Get the current read cursor. + //! \return Number of characters read from start. + size_t Tell(); + + //! Begin writing operation at the current read pointer. + //! \return The begin writer pointer. + Ch* PutBegin(); + + //! Write a character. + void Put(Ch c); + + //! Flush the buffer. + void Flush(); + + //! End the writing operation. + //! \param begin The begin write pointer returned by PutBegin(). + //! \return Number of characters written. + size_t PutEnd(Ch* begin); +} +\endcode +*/ + +//! Provides additional information for stream. +/*! + By using traits pattern, this type provides a default configuration for stream. + For custom stream, this type can be specialized for other configuration. + See TEST(Reader, CustomStringStream) in readertest.cpp for example. +*/ +template +struct StreamTraits { + //! Whether to make local copy of stream for optimization during parsing. + /*! + By default, for safety, streams do not use local copy optimization. + Stream that can be copied fast should specialize this, like StreamTraits. + */ + enum { copyOptimization = 0 }; +}; + +//! Reserve n characters for writing to a stream. +template +inline void PutReserve(Stream& stream, size_t count) { + (void)stream; + (void)count; +} + +//! Write character to a stream, presuming buffer is reserved. +template +inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { + stream.Put(c); +} + +//! Put N copies of a character to a stream. +template +inline void PutN(Stream& stream, Ch c, size_t n) { + PutReserve(stream, n); + for (size_t i = 0; i < n; i++) + PutUnsafe(stream, c); +} + +/////////////////////////////////////////////////////////////////////////////// +// StringStream + +//! Read-only string stream. +/*! \note implements Stream concept +*/ +template +struct GenericStringStream { + typedef typename Encoding::Ch Ch; + + GenericStringStream(const Ch *src) : src_(src), head_(src) {} + + Ch Peek() const { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() const { return static_cast(src_ - head_); } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. +}; + +template +struct StreamTraits > { + enum { copyOptimization = 1 }; +}; + +//! String stream with UTF8 encoding. +typedef GenericStringStream > StringStream; + +/////////////////////////////////////////////////////////////////////////////// +// InsituStringStream + +//! A read-write string stream. +/*! This string stream is particularly designed for in-situ parsing. + \note implements Stream concept +*/ +template +struct GenericInsituStringStream { + typedef typename Encoding::Ch Ch; + + GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} + + // Read + Ch Peek() { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() { return static_cast(src_ - head_); } + + // Write + void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } + + Ch* PutBegin() { return dst_ = src_; } + size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } + void Flush() {} + + Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } + void Pop(size_t count) { dst_ -= count; } + + Ch* src_; + Ch* dst_; + Ch* head_; +}; + +template +struct StreamTraits > { + enum { copyOptimization = 1 }; +}; + +//! Insitu string stream with UTF8 encoding. +typedef GenericInsituStringStream > InsituStringStream; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STREAM_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/stringbuffer.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/stringbuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..78f34d2098e73e71149ba96b9e93b71020189619 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/stringbuffer.h @@ -0,0 +1,117 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_STRINGBUFFER_H_ +#define RAPIDJSON_STRINGBUFFER_H_ + +#include "stream.h" +#include "internal/stack.h" + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + +#include "internal/stack.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory output stream. +/*! + \tparam Encoding Encoding of the stream. + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept +*/ +template +class GenericStringBuffer { +public: + typedef typename Encoding::Ch Ch; + + GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} + GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { + if (&rhs != this) + stack_ = std::move(rhs.stack_); + return *this; + } +#endif + + void Put(Ch c) { *stack_.template Push() = c; } + void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } + void Flush() {} + + void Clear() { stack_.Clear(); } + void ShrinkToFit() { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.ShrinkToFit(); + stack_.template Pop(1); + } + + void Reserve(size_t count) { stack_.template Reserve(count); } + Ch* Push(size_t count) { return stack_.template Push(count); } + Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } + void Pop(size_t count) { stack_.template Pop(count); } + + const Ch* GetString() const { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.template Pop(1); + + return stack_.template Bottom(); + } + + size_t GetSize() const { return stack_.GetSize(); } + + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; + +private: + // Prohibit copy constructor & assignment operator. + GenericStringBuffer(const GenericStringBuffer&); + GenericStringBuffer& operator=(const GenericStringBuffer&); +}; + +//! String buffer with UTF8 encoding +typedef GenericStringBuffer > StringBuffer; + +template +inline void PutReserve(GenericStringBuffer& stream, size_t count) { + stream.Reserve(count); +} + +template +inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { + stream.PutUnsafe(c); +} + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { + std::memset(stream.stack_.Push(n), c, n * sizeof(c)); +} + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/writer.h b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/writer.h new file mode 100644 index 0000000000000000000000000000000000000000..94f22dd5fce832f85332d3b6b2e18dc72aa2e999 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/rapidjson-1.1.0/rapidjson/writer.h @@ -0,0 +1,610 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_WRITER_H_ +#define RAPIDJSON_WRITER_H_ + +#include "stream.h" +#include "internal/stack.h" +#include "internal/strfunc.h" +#include "internal/dtoa.h" +#include "internal/itoa.h" +#include "stringbuffer.h" +#include // placement new + +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) +#include +#pragma intrinsic(_BitScanForward) +#endif +#ifdef RAPIDJSON_SSE42 +#include +#elif defined(RAPIDJSON_SSE2) +#include +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// WriteFlag + +/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kWriteDefaultFlags definition. + + User can define this as any \c WriteFlag combinations. +*/ +#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS +#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags +#endif + +//! Combination of writeFlags +enum WriteFlag { + kWriteNoFlags = 0, //!< No flags are set. + kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. + kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. + kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS +}; + +//! JSON writer +/*! Writer implements the concept Handler. + It generates JSON text by events to an output os. + + User may programmatically calls the functions of a writer to generate JSON text. + + On the other side, a writer can also be passed to objects that generates events, + + for example Reader::Parse() and Document::Accept(). + + \tparam OutputStream Type of output stream. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. + \note implements Handler concept +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class Writer { +public: + typedef typename SourceEncoding::Ch Ch; + + static const int kDefaultMaxDecimalPlaces = 324; + + //! Constructor + /*! \param os Output stream. + \param stackAllocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + explicit + Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} + + explicit + Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} + + //! Reset the writer with a new stream. + /*! + This function reset the writer with a new stream and default settings, + in order to make a Writer object reusable for output multiple JSONs. + + \param os New output stream. + \code + Writer writer(os1); + writer.StartObject(); + // ... + writer.EndObject(); + + writer.Reset(os2); + writer.StartObject(); + // ... + writer.EndObject(); + \endcode + */ + void Reset(OutputStream& os) { + os_ = &os; + hasRoot_ = false; + level_stack_.Clear(); + } + + //! Checks whether the output is a complete JSON. + /*! + A complete JSON has a complete root object or array. + */ + bool IsComplete() const { + return hasRoot_ && level_stack_.Empty(); + } + + int GetMaxDecimalPlaces() const { + return maxDecimalPlaces_; + } + + //! Sets the maximum number of decimal places for double output. + /*! + This setting truncates the output with specified number of decimal places. + + For example, + + \code + writer.SetMaxDecimalPlaces(3); + writer.StartArray(); + writer.Double(0.12345); // "0.123" + writer.Double(0.0001); // "0.0" + writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent) + writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent) + writer.EndArray(); + \endcode + + The default setting does not truncate any decimal places. You can restore to this setting by calling + \code + writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); + \endcode + */ + void SetMaxDecimalPlaces(int maxDecimalPlaces) { + maxDecimalPlaces_ = maxDecimalPlaces; + } + + /*!@name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } + bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } + bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } + bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } + bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } + bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } + + //! Writes the given \c double value to the stream + /*! + \param d The value to be written. + \return Whether it is succeed. + */ + bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } + + bool RawNumber(const Ch* str, SizeType length, bool copy = false) { + (void)copy; + Prefix(kNumberType); + return EndValue(WriteString(str, length)); + } + + bool String(const Ch* str, SizeType length, bool copy = false) { + (void)copy; + Prefix(kStringType); + return EndValue(WriteString(str, length)); + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string& str) { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() { + Prefix(kObjectType); + new (level_stack_.template Push()) Level(false); + return WriteStartObject(); + } + + bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + + bool EndObject(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); + level_stack_.template Pop(1); + return EndValue(WriteEndObject()); + } + + bool StartArray() { + Prefix(kArrayType); + new (level_stack_.template Push()) Level(true); + return WriteStartArray(); + } + + bool EndArray(SizeType elementCount = 0) { + (void)elementCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); + level_stack_.template Pop(1); + return EndValue(WriteEndArray()); + } + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch* str) { return String(str, internal::StrLen(str)); } + bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } + + //@} + + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + */ + bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); } + +protected: + //! Information for each nested level + struct Level { + Level(bool inArray_) : valueCount(0), inArray(inArray_) {} + size_t valueCount; //!< number of values in this level + bool inArray; //!< true if in array, otherwise in object + }; + + static const size_t kDefaultLevelDepth = 32; + + bool WriteNull() { + PutReserve(*os_, 4); + PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; + } + + bool WriteBool(bool b) { + if (b) { + PutReserve(*os_, 4); + PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); + } + else { + PutReserve(*os_, 5); + PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); + } + return true; + } + + bool WriteInt(int i) { + char buffer[11]; + const char* end = internal::i32toa(i, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteUint(unsigned u) { + char buffer[10]; + const char* end = internal::u32toa(u, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteInt64(int64_t i64) { + char buffer[21]; + const char* end = internal::i64toa(i64, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char* end = internal::u64toa(u64, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteDouble(double d) { + if (internal::Double(d).IsNanOrInf()) { + if (!(writeFlags & kWriteNanAndInfFlag)) + return false; + if (internal::Double(d).IsNan()) { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); + return true; + } + + char buffer[25]; + char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); + PutReserve(*os_, static_cast(end - buffer)); + for (char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteString(const Ch* str, SizeType length) { + static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static const char escape[256] = { +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 + 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 + Z16, Z16, // 30~4F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF +#undef Z16 + }; + + if (TargetEncoding::supportUnicode) + PutReserve(*os_, 2 + length * 6); // "\uxxxx..." + else + PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." + + PutUnsafe(*os_, '\"'); + GenericStringStream is(str); + while (ScanWriteUnescapedString(is, length)) { + const Ch c = is.Peek(); + if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { + // Unicode escaping + unsigned codepoint; + if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) + return false; + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); + if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { + PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); + } + else { + RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); + // Surrogate pair + unsigned s = codepoint - 0x010000; + unsigned lead = (s >> 10) + 0xD800; + unsigned trail = (s & 0x3FF) + 0xDC00; + PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(lead ) & 15]); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); + PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(trail ) & 15]); + } + } + else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { + is.Take(); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, static_cast(escape[static_cast(c)])); + if (escape[static_cast(c)] == 'u') { + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, hexDigits[static_cast(c) >> 4]); + PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); + } + } + else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; + } + PutUnsafe(*os_, '\"'); + return true; + } + + bool ScanWriteUnescapedString(GenericStringStream& is, size_t length) { + return RAPIDJSON_LIKELY(is.Tell() < length); + } + + bool WriteStartObject() { os_->Put('{'); return true; } + bool WriteEndObject() { os_->Put('}'); return true; } + bool WriteStartArray() { os_->Put('['); return true; } + bool WriteEndArray() { os_->Put(']'); return true; } + + bool WriteRawValue(const Ch* json, size_t length) { + PutReserve(*os_, length); + for (size_t i = 0; i < length; i++) { + RAPIDJSON_ASSERT(json[i] != '\0'); + PutUnsafe(*os_, json[i]); + } + return true; + } + + void Prefix(Type type) { + (void)type; + if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root + Level* level = level_stack_.template Top(); + if (level->valueCount > 0) { + if (level->inArray) + os_->Put(','); // add comma if it is not the first element in array + else // in object + os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else { + RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. + hasRoot_ = true; + } + } + + // Flush the value if it is the top level one. + bool EndValue(bool ret) { + if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text + os_->Flush(); + return ret; + } + + OutputStream* os_; + internal::Stack level_stack_; + int maxDecimalPlaces_; + bool hasRoot_; + +private: + // Prohibit copy constructor & assignment operator. + Writer(const Writer&); + Writer& operator=(const Writer&); +}; + +// Full specialization for StringStream to prevent memory copying + +template<> +inline bool Writer::WriteInt(int i) { + char *buffer = os_->Push(11); + const char* end = internal::i32toa(i, buffer); + os_->Pop(static_cast(11 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteUint(unsigned u) { + char *buffer = os_->Push(10); + const char* end = internal::u32toa(u, buffer); + os_->Pop(static_cast(10 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteInt64(int64_t i64) { + char *buffer = os_->Push(21); + const char* end = internal::i64toa(i64, buffer); + os_->Pop(static_cast(21 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteUint64(uint64_t u) { + char *buffer = os_->Push(20); + const char* end = internal::u64toa(u, buffer); + os_->Pop(static_cast(20 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteDouble(double d) { + if (internal::Double(d).IsNanOrInf()) { + // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). + if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) + return false; + if (internal::Double(d).IsNan()) { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); + return true; + } + + char *buffer = os_->Push(25); + char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); + os_->Pop(static_cast(25 - (end - buffer))); + return true; +} + +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); + + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; + + const char* p = is.src_; + const char* end = is.head_ + length; + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; + + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (; p != endAligned; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + SizeType len; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + len = offset; +#else + len = static_cast(__builtin_ffs(r) - 1); +#endif + char* q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) + +RAPIDJSON_NAMESPACE_END + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/Arg.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/Arg.h new file mode 100644 index 0000000000000000000000000000000000000000..3ad3e779fdf06e6d943bb05055ecd48d8c4022eb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/Arg.h @@ -0,0 +1,693 @@ +// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- + +/****************************************************************************** + * + * file: Arg.h + * + * Copyright (c) 2003, Michael E. Smoot . + * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno . + * Copyright (c) 2017 Google Inc. + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + + +#ifndef TCLAP_ARGUMENT_H +#define TCLAP_ARGUMENT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(HAVE_SSTREAM) +#include +typedef std::istringstream istringstream; +#elif defined(HAVE_STRSTREAM) +#include +typedef std::istrstream istringstream; +#else +#error "Need a stringstream (sstream or strstream) to compile!" +#endif + +#include +#include +#include +#include +#include + +namespace TCLAP { + +/** + * A virtual base class that defines the essential data for all arguments. + * This class, or one of its existing children, must be subclassed to do + * anything. + */ +class Arg +{ + private: + /** + * Prevent accidental copying. + */ + Arg(const Arg& rhs); + + /** + * Prevent accidental copying. + */ + Arg& operator=(const Arg& rhs); + + /** + * Indicates whether the rest of the arguments should be ignored. + */ + static bool& ignoreRestRef() { static bool ign = false; return ign; } + + /** + * The delimiter that separates an argument flag/name from the + * value. + */ + static char& delimiterRef() { static char delim = ' '; return delim; } + + protected: + + /** + * The single char flag used to identify the argument. + * This value (preceded by a dash {-}), can be used to identify + * an argument on the command line. The _flag can be blank, + * in fact this is how unlabeled args work. Unlabeled args must + * override appropriate functions to get correct handling. Note + * that the _flag does NOT include the dash as part of the flag. + */ + std::string _flag; + + /** + * A single word namd identifying the argument. + * This value (preceded by two dashed {--}) can also be used + * to identify an argument on the command line. Note that the + * _name does NOT include the two dashes as part of the _name. The + * _name cannot be blank. + */ + std::string _name; + + /** + * Description of the argument. + */ + std::string _description; + + /** + * Indicating whether the argument is required. + */ + bool _required; + + /** + * Label to be used in usage description. Normally set to + * "required", but can be changed when necessary. + */ + std::string _requireLabel; + + /** + * Indicates whether a value is required for the argument. + * Note that the value may be required but the argument/value + * combination may not be, as specified by _required. + */ + bool _valueRequired; + + /** + * Indicates whether the argument has been set. + * Indicates that a value on the command line has matched the + * name/flag of this argument and the values have been set accordingly. + */ + bool _alreadySet; + + /** + * A pointer to a visitor object. + * The visitor allows special handling to occur as soon as the + * argument is matched. This defaults to NULL and should not + * be used unless absolutely necessary. + */ + Visitor* _visitor; + + /** + * Whether this argument can be ignored, if desired. + */ + bool _ignoreable; + + /** + * Indicates that the arg was set as part of an XOR and not on the + * command line. + */ + bool _xorSet; + + bool _acceptsMultipleValues; + + /** + * Performs the special handling described by the Visitor. + */ + void _checkWithVisitor() const; + + /** + * Primary constructor. YOU (yes you) should NEVER construct an Arg + * directly, this is a base class that is extended by various children + * that are meant to be used. Use SwitchArg, ValueArg, MultiArg, + * UnlabeledValueArg, or UnlabeledMultiArg instead. + * + * \param flag - The flag identifying the argument. + * \param name - The name identifying the argument. + * \param desc - The description of the argument, used in the usage. + * \param req - Whether the argument is required. + * \param valreq - Whether the a value is required for the argument. + * \param v - The visitor checked by the argument. Defaults to NULL. + */ + Arg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + bool valreq, + Visitor* v = NULL ); + + public: + /** + * Destructor. + */ + virtual ~Arg(); + + /** + * Adds this to the specified list of Args. + * \param argList - The list to add this to. + */ + virtual void addToList( std::list& argList ) const; + + /** + * Begin ignoring arguments since the "--" argument was specified. + */ + static void beginIgnoring() { ignoreRestRef() = true; } + + /** + * Whether to ignore the rest. + */ + static bool ignoreRest() { return ignoreRestRef(); } + + /** + * The delimiter that separates an argument flag/name from the + * value. + */ + static char delimiter() { return delimiterRef(); } + + /** + * The char used as a place holder when SwitchArgs are combined. + * Currently set to the bell char (ASCII 7). + */ + static char blankChar() { return (char)7; } + + /** + * The char that indicates the beginning of a flag. Defaults to '-', but + * clients can define TCLAP_FLAGSTARTCHAR to override. + */ +#ifndef TCLAP_FLAGSTARTCHAR +#define TCLAP_FLAGSTARTCHAR '-' +#endif + static char flagStartChar() { return TCLAP_FLAGSTARTCHAR; } + + /** + * The sting that indicates the beginning of a flag. Defaults to "-", but + * clients can define TCLAP_FLAGSTARTSTRING to override. Should be the same + * as TCLAP_FLAGSTARTCHAR. + */ +#ifndef TCLAP_FLAGSTARTSTRING +#define TCLAP_FLAGSTARTSTRING "-" +#endif + static const std::string flagStartString() { return TCLAP_FLAGSTARTSTRING; } + + /** + * The sting that indicates the beginning of a name. Defaults to "--", but + * clients can define TCLAP_NAMESTARTSTRING to override. + */ +#ifndef TCLAP_NAMESTARTSTRING +#define TCLAP_NAMESTARTSTRING "--" +#endif + static const std::string nameStartString() { return TCLAP_NAMESTARTSTRING; } + + /** + * The name used to identify the ignore rest argument. + */ + static const std::string ignoreNameString() { return "ignore_rest"; } + + /** + * Sets the delimiter for all arguments. + * \param c - The character that delimits flags/names from values. + */ + static void setDelimiter( char c ) { delimiterRef() = c; } + + /** + * Pure virtual method meant to handle the parsing and value assignment + * of the string on the command line. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. What is + * passed in from main. + */ + virtual bool processArg(int *i, std::vector& args) = 0; + + /** + * Operator ==. + * Equality operator. Must be virtual to handle unlabeled args. + * \param a - The Arg to be compared to this. + */ + virtual bool operator==(const Arg& a) const; + + /** + * Returns the argument flag. + */ + const std::string& getFlag() const; + + /** + * Returns the argument name. + */ + const std::string& getName() const; + + /** + * Returns the argument description. + */ + std::string getDescription() const; + + /** + * Indicates whether the argument is required. + */ + virtual bool isRequired() const; + + /** + * Sets _required to true. This is used by the XorHandler. + * You really have no reason to ever use it. + */ + void forceRequired(); + + /** + * Sets the _alreadySet value to true. This is used by the XorHandler. + * You really have no reason to ever use it. + */ + void xorSet(); + + /** + * Indicates whether a value must be specified for argument. + */ + bool isValueRequired() const; + + /** + * Indicates whether the argument has already been set. Only true + * if the arg has been matched on the command line. + */ + bool isSet() const; + + /** + * Indicates whether the argument can be ignored, if desired. + */ + bool isIgnoreable() const; + + /** + * A method that tests whether a string matches this argument. + * This is generally called by the processArg() method. This + * method could be re-implemented by a child to change how + * arguments are specified on the command line. + * \param s - The string to be compared to the flag/name to determine + * whether the arg matches. + */ + virtual bool argMatches( const std::string& s ) const; + + /** + * Returns a simple string representation of the argument. + * Primarily for debugging. + */ + virtual std::string toString() const; + + /** + * Returns a short ID for the usage. + * \param valueId - The value used in the id. + */ + virtual std::string shortID( const std::string& valueId = "val" ) const; + + /** + * Returns a long ID for the usage. + * \param valueId - The value used in the id. + */ + virtual std::string longID( const std::string& valueId = "val" ) const; + + /** + * Trims a value off of the flag. + * \param flag - The string from which the flag and value will be + * trimmed. Contains the flag once the value has been trimmed. + * \param value - Where the value trimmed from the string will + * be stored. + */ + virtual void trimFlag( std::string& flag, std::string& value ) const; + + /** + * Checks whether a given string has blank chars, indicating that + * it is a combined SwitchArg. If so, return true, otherwise return + * false. + * \param s - string to be checked. + */ + bool _hasBlanks( const std::string& s ) const; + + /** + * Sets the requireLabel. Used by XorHandler. You shouldn't ever + * use this. + * \param s - Set the requireLabel to this value. + */ + void setRequireLabel( const std::string& s ); + + /** + * Used for MultiArgs and XorHandler to determine whether args + * can still be set. + */ + virtual bool allowMore(); + + /** + * Use by output classes to determine whether an Arg accepts + * multiple values. + */ + virtual bool acceptsMultipleValues(); + + /** + * Clears the Arg object and allows it to be reused by new + * command lines. + */ + virtual void reset(); +}; + +/** + * Typedef of an Arg list iterator. + */ +typedef std::list::iterator ArgListIterator; + +/** + * Typedef of an Arg vector iterator. + */ +typedef std::vector::iterator ArgVectorIterator; + +/** + * Typedef of a Visitor list iterator. + */ +typedef std::list::iterator VisitorListIterator; + +/* + * Extract a value of type T from it's string representation contained + * in strVal. The ValueLike parameter used to select the correct + * specialization of ExtractValue depending on the value traits of T. + * ValueLike traits use operator>> to assign the value from strVal. + */ +template void +ExtractValue(T &destVal, const std::string& strVal, ValueLike vl) +{ + static_cast(vl); // Avoid warning about unused vl + istringstream is(strVal.c_str()); + + int valuesRead = 0; + while ( is.good() ) { + if ( is.peek() != EOF ) +#ifdef TCLAP_SETBASE_ZERO + is >> std::setbase(0) >> destVal; +#else + is >> destVal; +#endif + else + break; + + valuesRead++; + } + + if ( is.fail() ) + throw( ArgParseException("Couldn't read argument value " + "from string '" + strVal + "'")); + + + if ( valuesRead > 1 ) + throw( ArgParseException("More than one valid value parsed from " + "string '" + strVal + "'")); + +} + +/* + * Extract a value of type T from it's string representation contained + * in strVal. The ValueLike parameter used to select the correct + * specialization of ExtractValue depending on the value traits of T. + * StringLike uses assignment (operator=) to assign from strVal. + */ +template void +ExtractValue(T &destVal, const std::string& strVal, StringLike sl) +{ + static_cast(sl); // Avoid warning about unused sl + SetString(destVal, strVal); +} + +////////////////////////////////////////////////////////////////////// +//BEGIN Arg.cpp +////////////////////////////////////////////////////////////////////// + +inline Arg::Arg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + bool valreq, + Visitor* v) : + _flag(flag), + _name(name), + _description(desc), + _required(req), + _requireLabel("required"), + _valueRequired(valreq), + _alreadySet(false), + _visitor( v ), + _ignoreable(true), + _xorSet(false), + _acceptsMultipleValues(false) +{ + if ( _flag.length() > 1 ) + throw(SpecificationException( + "Argument flag can only be one character long", toString() ) ); + + if ( _name != ignoreNameString() && + ( _flag == Arg::flagStartString() || + _flag == Arg::nameStartString() || + _flag == " " ) ) + throw(SpecificationException("Argument flag cannot be either '" + + Arg::flagStartString() + "' or '" + + Arg::nameStartString() + "' or a space.", + toString() ) ); + + if ( ( _name.substr( 0, Arg::flagStartString().length() ) == Arg::flagStartString() ) || + ( _name.substr( 0, Arg::nameStartString().length() ) == Arg::nameStartString() ) || + ( _name.find( " ", 0 ) != std::string::npos ) ) + throw(SpecificationException("Argument name begin with either '" + + Arg::flagStartString() + "' or '" + + Arg::nameStartString() + "' or space.", + toString() ) ); + +} + +inline Arg::~Arg() { } + +inline std::string Arg::shortID( const std::string& valueId ) const +{ + std::string id = ""; + + if ( _flag != "" ) + id = Arg::flagStartString() + _flag; + else + id = Arg::nameStartString() + _name; + + if ( _valueRequired ) + id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">"; + + if ( !_required ) + id = "[" + id + "]"; + + return id; +} + +inline std::string Arg::longID( const std::string& valueId ) const +{ + std::string id = ""; + + if ( _flag != "" ) + { + id += Arg::flagStartString() + _flag; + + if ( _valueRequired ) + id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">"; + + id += ", "; + } + + id += Arg::nameStartString() + _name; + + if ( _valueRequired ) + id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">"; + + return id; + +} + +inline bool Arg::operator==(const Arg& a) const +{ + if ( ( _flag != "" && _flag == a._flag ) || _name == a._name) + return true; + else + return false; +} + +inline std::string Arg::getDescription() const +{ + std::string desc = ""; + if ( _required ) + desc = "(" + _requireLabel + ") "; + +// if ( _valueRequired ) +// desc += "(value required) "; + + desc += _description; + return desc; +} + +inline const std::string& Arg::getFlag() const { return _flag; } + +inline const std::string& Arg::getName() const { return _name; } + +inline bool Arg::isRequired() const { return _required; } + +inline bool Arg::isValueRequired() const { return _valueRequired; } + +inline bool Arg::isSet() const +{ + if ( _alreadySet && !_xorSet ) + return true; + else + return false; +} + +inline bool Arg::isIgnoreable() const { return _ignoreable; } + +inline void Arg::setRequireLabel( const std::string& s) +{ + _requireLabel = s; +} + +inline bool Arg::argMatches( const std::string& argFlag ) const +{ + if ( ( argFlag == Arg::flagStartString() + _flag && _flag != "" ) || + argFlag == Arg::nameStartString() + _name ) + return true; + else + return false; +} + +inline std::string Arg::toString() const +{ + std::string s = ""; + + if ( _flag != "" ) + s += Arg::flagStartString() + _flag + " "; + + s += "(" + Arg::nameStartString() + _name + ")"; + + return s; +} + +inline void Arg::_checkWithVisitor() const +{ + if ( _visitor != NULL ) + _visitor->visit(); +} + +/** + * Implementation of trimFlag. + */ +inline void Arg::trimFlag(std::string& flag, std::string& value) const +{ + int stop = 0; + for ( int i = 0; static_cast(i) < flag.length(); i++ ) + if ( flag[i] == Arg::delimiter() ) + { + stop = i; + break; + } + + if ( stop > 1 ) + { + value = flag.substr(stop+1); + flag = flag.substr(0,stop); + } + +} + +/** + * Implementation of _hasBlanks. + */ +inline bool Arg::_hasBlanks( const std::string& s ) const +{ + for ( int i = 1; static_cast(i) < s.length(); i++ ) + if ( s[i] == Arg::blankChar() ) + return true; + + return false; +} + +inline void Arg::forceRequired() +{ + _required = true; +} + +inline void Arg::xorSet() +{ + _alreadySet = true; + _xorSet = true; +} + +/** + * Overridden by Args that need to added to the end of the list. + */ +inline void Arg::addToList( std::list& argList ) const +{ + argList.push_front( const_cast(this) ); +} + +inline bool Arg::allowMore() +{ + return false; +} + +inline bool Arg::acceptsMultipleValues() +{ + return _acceptsMultipleValues; +} + +inline void Arg::reset() +{ + _xorSet = false; + _alreadySet = false; +} + +////////////////////////////////////////////////////////////////////// +//END Arg.cpp +////////////////////////////////////////////////////////////////////// + +} //namespace TCLAP + +#endif + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ArgException.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ArgException.h new file mode 100644 index 0000000000000000000000000000000000000000..f789d1cfcd4fac8e197d7ee71435a6c4a0d00070 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ArgException.h @@ -0,0 +1,200 @@ +// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- + +/****************************************************************************** + * + * file: ArgException.h + * + * Copyright (c) 2003, Michael E. Smoot . + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + + +#ifndef TCLAP_ARG_EXCEPTION_H +#define TCLAP_ARG_EXCEPTION_H + +#include +#include + +namespace TCLAP { + +/** + * A simple class that defines and argument exception. Should be caught + * whenever a CmdLine is created and parsed. + */ +class ArgException : public std::exception +{ + public: + + /** + * Constructor. + * \param text - The text of the exception. + * \param id - The text identifying the argument source. + * \param td - Text describing the type of ArgException it is. + * of the exception. + */ + ArgException( const std::string& text = "undefined exception", + const std::string& id = "undefined", + const std::string& td = "Generic ArgException") + : std::exception(), + _errorText(text), + _argId( id ), + _typeDescription(td) + { } + + /** + * Destructor. + */ + virtual ~ArgException() throw() { } + + /** + * Returns the error text. + */ + std::string error() const { return ( _errorText ); } + + /** + * Returns the argument id. + */ + std::string argId() const + { + if ( _argId == "undefined" ) + return " "; + else + return ( "Argument: " + _argId ); + } + + /** + * Returns the arg id and error text. + */ + const char* what() const throw() + { + static std::string ex; + ex = _argId + " -- " + _errorText; + return ex.c_str(); + } + + /** + * Returns the type of the exception. Used to explain and distinguish + * between different child exceptions. + */ + std::string typeDescription() const + { + return _typeDescription; + } + + + private: + + /** + * The text of the exception message. + */ + std::string _errorText; + + /** + * The argument related to this exception. + */ + std::string _argId; + + /** + * Describes the type of the exception. Used to distinguish + * between different child exceptions. + */ + std::string _typeDescription; + +}; + +/** + * Thrown from within the child Arg classes when it fails to properly + * parse the argument it has been passed. + */ +class ArgParseException : public ArgException +{ + public: + /** + * Constructor. + * \param text - The text of the exception. + * \param id - The text identifying the argument source + * of the exception. + */ + ArgParseException( const std::string& text = "undefined exception", + const std::string& id = "undefined" ) + : ArgException( text, + id, + std::string( "Exception found while parsing " ) + + std::string( "the value the Arg has been passed." )) + { } +}; + +/** + * Thrown from CmdLine when the arguments on the command line are not + * properly specified, e.g. too many arguments, required argument missing, etc. + */ +class CmdLineParseException : public ArgException +{ + public: + /** + * Constructor. + * \param text - The text of the exception. + * \param id - The text identifying the argument source + * of the exception. + */ + CmdLineParseException( const std::string& text = "undefined exception", + const std::string& id = "undefined" ) + : ArgException( text, + id, + std::string( "Exception found when the values ") + + std::string( "on the command line do not meet ") + + std::string( "the requirements of the defined ") + + std::string( "Args." )) + { } +}; + +/** + * Thrown from Arg and CmdLine when an Arg is improperly specified, e.g. + * same flag as another Arg, same name, etc. + */ +class SpecificationException : public ArgException +{ + public: + /** + * Constructor. + * \param text - The text of the exception. + * \param id - The text identifying the argument source + * of the exception. + */ + SpecificationException( const std::string& text = "undefined exception", + const std::string& id = "undefined" ) + : ArgException( text, + id, + std::string("Exception found when an Arg object ")+ + std::string("is improperly defined by the ") + + std::string("developer." )) + { } + +}; + +class ExitException { +public: + ExitException(int estat) : _estat(estat) {} + + int getExitStatus() const { return _estat; } + +private: + int _estat; +}; + +} // namespace TCLAP + +#endif + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ArgTraits.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ArgTraits.h new file mode 100644 index 0000000000000000000000000000000000000000..7ae85a9e51b49b5f36549ea1dc6affc853f304a0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ArgTraits.h @@ -0,0 +1,88 @@ +// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- + +/****************************************************************************** + * + * file: ArgTraits.h + * + * Copyright (c) 2007, Daniel Aarno, Michael E. Smoot . + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +// This is an internal tclap file, you should probably not have to +// include this directly + +#ifndef TCLAP_ARGTRAITS_H +#define TCLAP_ARGTRAITS_H + +namespace TCLAP { + +// We use two empty structs to get compile type specialization +// function to work + +/** + * A value like argument value type is a value that can be set using + * operator>>. This is the default value type. + */ +struct ValueLike { + typedef ValueLike ValueCategory; + virtual ~ValueLike() {} +}; + +/** + * A string like argument value type is a value that can be set using + * operator=(string). Useful if the value type contains spaces which + * will be broken up into individual tokens by operator>>. + */ +struct StringLike { + virtual ~StringLike() {} +}; + +/** + * A class can inherit from this object to make it have string like + * traits. This is a compile time thing and does not add any overhead + * to the inherenting class. + */ +struct StringLikeTrait { + typedef StringLike ValueCategory; + virtual ~StringLikeTrait() {} +}; + +/** + * A class can inherit from this object to make it have value like + * traits. This is a compile time thing and does not add any overhead + * to the inherenting class. + */ +struct ValueLikeTrait { + typedef ValueLike ValueCategory; + virtual ~ValueLikeTrait() {} +}; + +/** + * Arg traits are used to get compile type specialization when parsing + * argument values. Using an ArgTraits you can specify the way that + * values gets assigned to any particular type during parsing. The two + * supported types are StringLike and ValueLike. + */ +template +struct ArgTraits { + typedef typename T::ValueCategory ValueCategory; + virtual ~ArgTraits() {} + //typedef ValueLike ValueCategory; +}; + +} // namespace + +#endif + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/CmdLine.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/CmdLine.h new file mode 100644 index 0000000000000000000000000000000000000000..c91e656c8e2f742dd84a3865b94d2e588bf9211e --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/CmdLine.h @@ -0,0 +1,633 @@ +// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- + +/****************************************************************************** + * + * file: CmdLine.h + * + * Copyright (c) 2003, Michael E. Smoot . + * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_CMDLINE_H +#define TCLAP_CMDLINE_H + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include // Needed for exit(), which isn't defined in some envs. + +namespace TCLAP { + +template void DelPtr(T ptr) +{ + delete ptr; +} + +template void ClearContainer(C &c) +{ + typedef typename C::value_type value_type; + std::for_each(c.begin(), c.end(), DelPtr); + c.clear(); +} + + +/** + * The base class that manages the command line definition and passes + * along the parsing to the appropriate Arg classes. + */ +class CmdLine : public CmdLineInterface +{ + protected: + + /** + * The list of arguments that will be tested against the + * command line. + */ + std::list _argList; + + /** + * The name of the program. Set to argv[0]. + */ + std::string _progName; + + /** + * A message used to describe the program. Used in the usage output. + */ + std::string _message; + + /** + * The version to be displayed with the --version switch. + */ + std::string _version; + + /** + * The number of arguments that are required to be present on + * the command line. This is set dynamically, based on the + * Args added to the CmdLine object. + */ + int _numRequired; + + /** + * The character that is used to separate the argument flag/name + * from the value. Defaults to ' ' (space). + */ + char _delimiter; + + /** + * The handler that manages xoring lists of args. + */ + XorHandler _xorHandler; + + /** + * A list of Args to be explicitly deleted when the destructor + * is called. At the moment, this only includes the three default + * Args. + */ + std::list _argDeleteOnExitList; + + /** + * A list of Visitors to be explicitly deleted when the destructor + * is called. At the moment, these are the Visitors created for the + * default Args. + */ + std::list _visitorDeleteOnExitList; + + /** + * Object that handles all output for the CmdLine. + */ + CmdLineOutput* _output; + + /** + * Should CmdLine handle parsing exceptions internally? + */ + bool _handleExceptions; + + /** + * Throws an exception listing the missing args. + */ + void missingArgsException(); + + /** + * Checks whether a name/flag string matches entirely matches + * the Arg::blankChar. Used when multiple switches are combined + * into a single argument. + * \param s - The message to be used in the usage. + */ + bool _emptyCombined(const std::string& s); + + /** + * Perform a delete ptr; operation on ptr when this object is deleted. + */ + void deleteOnExit(Arg* ptr); + + /** + * Perform a delete ptr; operation on ptr when this object is deleted. + */ + void deleteOnExit(Visitor* ptr); + +private: + + /** + * Prevent accidental copying. + */ + CmdLine(const CmdLine& rhs); + CmdLine& operator=(const CmdLine& rhs); + + /** + * Encapsulates the code common to the constructors + * (which is all of it). + */ + void _constructor(); + + + /** + * Is set to true when a user sets the output object. We use this so + * that we don't delete objects that are created outside of this lib. + */ + bool _userSetOutput; + + /** + * Whether or not to automatically create help and version switches. + */ + bool _helpAndVersion; + + public: + + /** + * Command line constructor. Defines how the arguments will be + * parsed. + * \param message - The message to be used in the usage + * output. + * \param delimiter - The character that is used to separate + * the argument flag/name from the value. Defaults to ' ' (space). + * \param version - The version number to be used in the + * --version switch. + * \param helpAndVersion - Whether or not to create the Help and + * Version switches. Defaults to true. + */ + CmdLine(const std::string& message, + const char delimiter = ' ', + const std::string& version = "none", + bool helpAndVersion = true); + + /** + * Deletes any resources allocated by a CmdLine object. + */ + virtual ~CmdLine(); + + /** + * Adds an argument to the list of arguments to be parsed. + * \param a - Argument to be added. + */ + void add( Arg& a ); + + /** + * An alternative add. Functionally identical. + * \param a - Argument to be added. + */ + void add( Arg* a ); + + /** + * Add two Args that will be xor'd. If this method is used, add does + * not need to be called. + * \param a - Argument to be added and xor'd. + * \param b - Argument to be added and xor'd. + */ + void xorAdd( Arg& a, Arg& b ); + + /** + * Add a list of Args that will be xor'd. If this method is used, + * add does not need to be called. + * \param xors - List of Args to be added and xor'd. + */ + void xorAdd( std::vector& xors ); + + /** + * Parses the command line. + * \param argc - Number of arguments. + * \param argv - Array of arguments. + */ + void parse(int argc, const char * const * argv); + + /** + * Parses the command line. + * \param args - A vector of strings representing the args. + * args[0] is still the program name. + */ + void parse(std::vector& args); + + /** + * + */ + CmdLineOutput* getOutput(); + + /** + * + */ + void setOutput(CmdLineOutput* co); + + /** + * + */ + std::string& getVersion(); + + /** + * + */ + std::string& getProgramName(); + + /** + * + */ + std::list& getArgList(); + + /** + * + */ + XorHandler& getXorHandler(); + + /** + * + */ + char getDelimiter(); + + /** + * + */ + std::string& getMessage(); + + /** + * + */ + bool hasHelpAndVersion(); + + /** + * Disables or enables CmdLine's internal parsing exception handling. + * + * @param state Should CmdLine handle parsing exceptions internally? + */ + void setExceptionHandling(const bool state); + + /** + * Returns the current state of the internal exception handling. + * + * @retval true Parsing exceptions are handled internally. + * @retval false Parsing exceptions are propagated to the caller. + */ + bool getExceptionHandling() const; + + /** + * Allows the CmdLine object to be reused. + */ + void reset(); + +}; + + +/////////////////////////////////////////////////////////////////////////////// +//Begin CmdLine.cpp +/////////////////////////////////////////////////////////////////////////////// + +inline CmdLine::CmdLine(const std::string& m, + char delim, + const std::string& v, + bool help ) + : + _argList(std::list()), + _progName("not_set_yet"), + _message(m), + _version(v), + _numRequired(0), + _delimiter(delim), + _xorHandler(XorHandler()), + _argDeleteOnExitList(std::list()), + _visitorDeleteOnExitList(std::list()), + _output(0), + _handleExceptions(true), + _userSetOutput(false), + _helpAndVersion(help) +{ + _constructor(); +} + +inline CmdLine::~CmdLine() +{ + ClearContainer(_argDeleteOnExitList); + ClearContainer(_visitorDeleteOnExitList); + + if ( !_userSetOutput ) { + delete _output; + _output = 0; + } +} + +inline void CmdLine::_constructor() +{ + _output = new StdOutput; + + Arg::setDelimiter( _delimiter ); + + Visitor* v; + + if ( _helpAndVersion ) + { + v = new HelpVisitor( this, &_output ); + SwitchArg* help = new SwitchArg("h","help", + "Displays usage information and exits.", + false, v); + add( help ); + deleteOnExit(help); + deleteOnExit(v); + + v = new VersionVisitor( this, &_output ); + SwitchArg* vers = new SwitchArg("","version", + "Displays version information and exits.", + false, v); + add( vers ); + deleteOnExit(vers); + deleteOnExit(v); + } + + v = new IgnoreRestVisitor(); + SwitchArg* ignore = new SwitchArg(Arg::flagStartString(), + Arg::ignoreNameString(), + "Ignores the rest of the labeled arguments following this flag.", + false, v); + add( ignore ); + deleteOnExit(ignore); + deleteOnExit(v); +} + +inline void CmdLine::xorAdd( std::vector& ors ) +{ + _xorHandler.add( ors ); + + for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++) + { + (*it)->forceRequired(); + (*it)->setRequireLabel( "OR required" ); + add( *it ); + } +} + +inline void CmdLine::xorAdd( Arg& a, Arg& b ) +{ + std::vector ors; + ors.push_back( &a ); + ors.push_back( &b ); + xorAdd( ors ); +} + +inline void CmdLine::add( Arg& a ) +{ + add( &a ); +} + +inline void CmdLine::add( Arg* a ) +{ + for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ ) + if ( *a == *(*it) ) + throw( SpecificationException( + "Argument with same flag/name already exists!", + a->longID() ) ); + + a->addToList( _argList ); + + if ( a->isRequired() ) + _numRequired++; +} + + +inline void CmdLine::parse(int argc, const char * const * argv) +{ + // this step is necessary so that we have easy access to + // mutable strings. + std::vector args; + for (int i = 0; i < argc; i++) + args.push_back(argv[i]); + + parse(args); +} + +inline void CmdLine::parse(std::vector& args) +{ + bool shouldExit = false; + int estat = 0; + + try { + _progName = args.front(); + args.erase(args.begin()); + + int requiredCount = 0; + + for (int i = 0; static_cast(i) < args.size(); i++) + { + bool matched = false; + for (ArgListIterator it = _argList.begin(); + it != _argList.end(); it++) { + if ( (*it)->processArg( &i, args ) ) + { + requiredCount += _xorHandler.check( *it ); + matched = true; + break; + } + } + + // checks to see if the argument is an empty combined + // switch and if so, then we've actually matched it + if ( !matched && _emptyCombined( args[i] ) ) + matched = true; + + if ( !matched && !Arg::ignoreRest() ) + throw(CmdLineParseException("Couldn't find match " + "for argument", + args[i])); + } + + if ( requiredCount < _numRequired ) + missingArgsException(); + + if ( requiredCount > _numRequired ) + throw(CmdLineParseException("Too many arguments!")); + + } catch ( ArgException& e ) { + // If we're not handling the exceptions, rethrow. + if ( !_handleExceptions) { + throw; + } + + try { + _output->failure(*this,e); + } catch ( ExitException &ee ) { + estat = ee.getExitStatus(); + shouldExit = true; + } + } catch (ExitException &ee) { + // If we're not handling the exceptions, rethrow. + if ( !_handleExceptions) { + throw; + } + + estat = ee.getExitStatus(); + shouldExit = true; + } + + if (shouldExit) + exit(estat); +} + +inline bool CmdLine::_emptyCombined(const std::string& s) +{ + if ( s.length() > 0 && s[0] != Arg::flagStartChar() ) + return false; + + for ( int i = 1; static_cast(i) < s.length(); i++ ) + if ( s[i] != Arg::blankChar() ) + return false; + + return true; +} + +inline void CmdLine::missingArgsException() +{ + int count = 0; + + std::string missingArgList; + for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++) + { + if ( (*it)->isRequired() && !(*it)->isSet() ) + { + missingArgList += (*it)->getName(); + missingArgList += ", "; + count++; + } + } + missingArgList = missingArgList.substr(0,missingArgList.length()-2); + + std::string msg; + if ( count > 1 ) + msg = "Required arguments missing: "; + else + msg = "Required argument missing: "; + + msg += missingArgList; + + throw(CmdLineParseException(msg)); +} + +inline void CmdLine::deleteOnExit(Arg* ptr) +{ + _argDeleteOnExitList.push_back(ptr); +} + +inline void CmdLine::deleteOnExit(Visitor* ptr) +{ + _visitorDeleteOnExitList.push_back(ptr); +} + +inline CmdLineOutput* CmdLine::getOutput() +{ + return _output; +} + +inline void CmdLine::setOutput(CmdLineOutput* co) +{ + if ( !_userSetOutput ) + delete _output; + _userSetOutput = true; + _output = co; +} + +inline std::string& CmdLine::getVersion() +{ + return _version; +} + +inline std::string& CmdLine::getProgramName() +{ + return _progName; +} + +inline std::list& CmdLine::getArgList() +{ + return _argList; +} + +inline XorHandler& CmdLine::getXorHandler() +{ + return _xorHandler; +} + +inline char CmdLine::getDelimiter() +{ + return _delimiter; +} + +inline std::string& CmdLine::getMessage() +{ + return _message; +} + +inline bool CmdLine::hasHelpAndVersion() +{ + return _helpAndVersion; +} + +inline void CmdLine::setExceptionHandling(const bool state) +{ + _handleExceptions = state; +} + +inline bool CmdLine::getExceptionHandling() const +{ + return _handleExceptions; +} + +inline void CmdLine::reset() +{ + for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ ) + (*it)->reset(); + + _progName.clear(); +} + +/////////////////////////////////////////////////////////////////////////////// +//End CmdLine.cpp +/////////////////////////////////////////////////////////////////////////////// + + + +} //namespace TCLAP +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/CmdLineInterface.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/CmdLineInterface.h new file mode 100644 index 0000000000000000000000000000000000000000..cf60f34c1cb008743baa9daca564003b3e16d813 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/CmdLineInterface.h @@ -0,0 +1,150 @@ + +/****************************************************************************** + * + * file: CmdLineInterface.h + * + * Copyright (c) 2003, Michael E. Smoot . + * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_COMMANDLINE_INTERFACE_H +#define TCLAP_COMMANDLINE_INTERFACE_H + +#include +#include +#include +#include +#include + + +namespace TCLAP { + +class Arg; +class CmdLineOutput; +class XorHandler; + +/** + * The base class that manages the command line definition and passes + * along the parsing to the appropriate Arg classes. + */ +class CmdLineInterface +{ + public: + + /** + * Destructor + */ + virtual ~CmdLineInterface() {} + + /** + * Adds an argument to the list of arguments to be parsed. + * \param a - Argument to be added. + */ + virtual void add( Arg& a )=0; + + /** + * An alternative add. Functionally identical. + * \param a - Argument to be added. + */ + virtual void add( Arg* a )=0; + + /** + * Add two Args that will be xor'd. + * If this method is used, add does + * not need to be called. + * \param a - Argument to be added and xor'd. + * \param b - Argument to be added and xor'd. + */ + virtual void xorAdd( Arg& a, Arg& b )=0; + + /** + * Add a list of Args that will be xor'd. If this method is used, + * add does not need to be called. + * \param xors - List of Args to be added and xor'd. + */ + virtual void xorAdd( std::vector& xors )=0; + + /** + * Parses the command line. + * \param argc - Number of arguments. + * \param argv - Array of arguments. + */ + virtual void parse(int argc, const char * const * argv)=0; + + /** + * Parses the command line. + * \param args - A vector of strings representing the args. + * args[0] is still the program name. + */ + void parse(std::vector& args); + + /** + * Returns the CmdLineOutput object. + */ + virtual CmdLineOutput* getOutput()=0; + + /** + * \param co - CmdLineOutput object that we want to use instead. + */ + virtual void setOutput(CmdLineOutput* co)=0; + + /** + * Returns the version string. + */ + virtual std::string& getVersion()=0; + + /** + * Returns the program name string. + */ + virtual std::string& getProgramName()=0; + + /** + * Returns the argList. + */ + virtual std::list& getArgList()=0; + + /** + * Returns the XorHandler. + */ + virtual XorHandler& getXorHandler()=0; + + /** + * Returns the delimiter string. + */ + virtual char getDelimiter()=0; + + /** + * Returns the message string. + */ + virtual std::string& getMessage()=0; + + /** + * Indicates whether or not the help and version switches were created + * automatically. + */ + virtual bool hasHelpAndVersion()=0; + + /** + * Resets the instance as if it had just been constructed so that the + * instance can be reused. + */ + virtual void reset()=0; +}; + +} //namespace + + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/CmdLineOutput.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/CmdLineOutput.h new file mode 100644 index 0000000000000000000000000000000000000000..11b893908bbc2ccd624544b3acb606fbe34e4be8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/CmdLineOutput.h @@ -0,0 +1,74 @@ + + +/****************************************************************************** + * + * file: CmdLineOutput.h + * + * Copyright (c) 2004, Michael E. Smoot + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_CMDLINEOUTPUT_H +#define TCLAP_CMDLINEOUTPUT_H + +#include +#include +#include +#include +#include +#include + +namespace TCLAP { + +class CmdLineInterface; +class ArgException; + +/** + * The interface that any output object must implement. + */ +class CmdLineOutput +{ + + public: + + /** + * Virtual destructor. + */ + virtual ~CmdLineOutput() {} + + /** + * Generates some sort of output for the USAGE. + * \param c - The CmdLine object the output is generated for. + */ + virtual void usage(CmdLineInterface& c)=0; + + /** + * Generates some sort of output for the version. + * \param c - The CmdLine object the output is generated for. + */ + virtual void version(CmdLineInterface& c)=0; + + /** + * Generates some sort of output for a failure. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. + */ + virtual void failure( CmdLineInterface& c, + ArgException& e )=0; + +}; + +} //namespace TCLAP +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/Constraint.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/Constraint.h new file mode 100644 index 0000000000000000000000000000000000000000..21dc06f984e8613d770d72ecbf43c2414a5d52d8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/Constraint.h @@ -0,0 +1,68 @@ + +/****************************************************************************** + * + * file: Constraint.h + * + * Copyright (c) 2005, Michael E. Smoot + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_CONSTRAINT_H +#define TCLAP_CONSTRAINT_H + +#include +#include +#include +#include +#include +#include + +namespace TCLAP { + +/** + * The interface that defines the interaction between the Arg and Constraint. + */ +template +class Constraint +{ + + public: + /** + * Returns a description of the Constraint. + */ + virtual std::string description() const =0; + + /** + * Returns the short ID for the Constraint. + */ + virtual std::string shortID() const =0; + + /** + * The method used to verify that the value parsed from the command + * line meets the constraint. + * \param value - The value that will be checked. + */ + virtual bool check(const T& value) const =0; + + /** + * Destructor. + * Silences warnings about Constraint being a base class with virtual + * functions but without a virtual destructor. + */ + virtual ~Constraint() { ; } +}; + +} //namespace TCLAP +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/DocBookOutput.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/DocBookOutput.h new file mode 100644 index 0000000000000000000000000000000000000000..f023824aec497b40ef22cb93a0d2aefcc71f6a8b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/DocBookOutput.h @@ -0,0 +1,300 @@ +// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- + +/****************************************************************************** + * + * file: DocBookOutput.h + * + * Copyright (c) 2004, Michael E. Smoot + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_DOCBOOKOUTPUT_H +#define TCLAP_DOCBOOKOUTPUT_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace TCLAP { + +/** + * A class that generates DocBook output for usage() method for the + * given CmdLine and its Args. + */ +class DocBookOutput : public CmdLineOutput +{ + + public: + + /** + * Prints the usage to stdout. Can be overridden to + * produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void usage(CmdLineInterface& c); + + /** + * Prints the version to stdout. Can be overridden + * to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void version(CmdLineInterface& c); + + /** + * Prints (to stderr) an error message, short usage + * Can be overridden to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. + */ + virtual void failure(CmdLineInterface& c, + ArgException& e ); + + DocBookOutput() : theDelimiter('=') {} + protected: + + /** + * Substitutes the char r for string x in string s. + * \param s - The string to operate on. + * \param r - The char to replace. + * \param x - What to replace r with. + */ + void substituteSpecialChars( std::string& s, char r, std::string& x ); + void removeChar( std::string& s, char r); + void basename( std::string& s ); + + void printShortArg(Arg* it); + void printLongArg(Arg* it); + + char theDelimiter; +}; + + +inline void DocBookOutput::version(CmdLineInterface& _cmd) +{ + std::cout << _cmd.getVersion() << std::endl; +} + +inline void DocBookOutput::usage(CmdLineInterface& _cmd ) +{ + std::list argList = _cmd.getArgList(); + std::string progName = _cmd.getProgramName(); + std::string xversion = _cmd.getVersion(); + theDelimiter = _cmd.getDelimiter(); + XorHandler xorHandler = _cmd.getXorHandler(); + std::vector< std::vector > xorList = xorHandler.getXorList(); + basename(progName); + + std::cout << "" << std::endl; + std::cout << "" << std::endl << std::endl; + + std::cout << "" << std::endl; + + std::cout << "" << std::endl; + std::cout << "" << progName << "" << std::endl; + std::cout << "1" << std::endl; + std::cout << "" << std::endl; + + std::cout << "" << std::endl; + std::cout << "" << progName << "" << std::endl; + std::cout << "" << _cmd.getMessage() << "" << std::endl; + std::cout << "" << std::endl; + + std::cout << "" << std::endl; + std::cout << "" << std::endl; + + std::cout << "" << progName << "" << std::endl; + + // xor + for ( int i = 0; (unsigned int)i < xorList.size(); i++ ) + { + std::cout << "" << std::endl; + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); it++ ) + printShortArg((*it)); + + std::cout << "" << std::endl; + } + + // rest of args + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) + if ( !xorHandler.contains( (*it) ) ) + printShortArg((*it)); + + std::cout << "" << std::endl; + std::cout << "" << std::endl; + + std::cout << "" << std::endl; + std::cout << "Description" << std::endl; + std::cout << "" << std::endl; + std::cout << _cmd.getMessage() << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + + std::cout << "" << std::endl; + std::cout << "Options" << std::endl; + + std::cout << "" << std::endl; + + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) + printLongArg((*it)); + + std::cout << "" << std::endl; + std::cout << "" << std::endl; + + std::cout << "" << std::endl; + std::cout << "Version" << std::endl; + std::cout << "" << std::endl; + std::cout << xversion << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + + std::cout << "" << std::endl; + +} + +inline void DocBookOutput::failure( CmdLineInterface& _cmd, + ArgException& e ) +{ + static_cast(_cmd); // unused + std::cout << e.what() << std::endl; + throw ExitException(1); +} + +inline void DocBookOutput::substituteSpecialChars( std::string& s, + char r, + std::string& x ) +{ + size_t p; + while ( (p = s.find_first_of(r)) != std::string::npos ) + { + s.erase(p,1); + s.insert(p,x); + } +} + +inline void DocBookOutput::removeChar( std::string& s, char r) +{ + size_t p; + while ( (p = s.find_first_of(r)) != std::string::npos ) + { + s.erase(p,1); + } +} + +inline void DocBookOutput::basename( std::string& s ) +{ + size_t p = s.find_last_of('/'); + if ( p != std::string::npos ) + { + s.erase(0, p + 1); + } +} + +inline void DocBookOutput::printShortArg(Arg* a) +{ + std::string lt = "<"; + std::string gt = ">"; + + std::string id = a->shortID(); + substituteSpecialChars(id,'<',lt); + substituteSpecialChars(id,'>',gt); + removeChar(id,'['); + removeChar(id,']'); + + std::string choice = "opt"; + if ( a->isRequired() ) + choice = "plain"; + + std::cout << "acceptsMultipleValues() ) + std::cout << " rep='repeat'"; + + + std::cout << '>'; + if ( !a->getFlag().empty() ) + std::cout << a->flagStartChar() << a->getFlag(); + else + std::cout << a->nameStartString() << a->getName(); + if ( a->isValueRequired() ) + { + std::string arg = a->shortID(); + removeChar(arg,'['); + removeChar(arg,']'); + removeChar(arg,'<'); + removeChar(arg,'>'); + arg.erase(0, arg.find_last_of(theDelimiter) + 1); + std::cout << theDelimiter; + std::cout << "" << arg << ""; + } + std::cout << "" << std::endl; + +} + +inline void DocBookOutput::printLongArg(Arg* a) +{ + std::string lt = "<"; + std::string gt = ">"; + + std::string desc = a->getDescription(); + substituteSpecialChars(desc,'<',lt); + substituteSpecialChars(desc,'>',gt); + + std::cout << "" << std::endl; + + if ( !a->getFlag().empty() ) + { + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + } + + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + + std::cout << "" << std::endl; + std::cout << "" << std::endl; + std::cout << desc << std::endl; + std::cout << "" << std::endl; + std::cout << "" << std::endl; + + std::cout << "" << std::endl; +} + +} //namespace TCLAP +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/HelpVisitor.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/HelpVisitor.h new file mode 100644 index 0000000000000000000000000000000000000000..ee0914420d6814d24a16d76eac0e063a53e1e677 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/HelpVisitor.h @@ -0,0 +1,76 @@ + +/****************************************************************************** + * + * file: HelpVisitor.h + * + * Copyright (c) 2003, Michael E. Smoot . + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_HELP_VISITOR_H +#define TCLAP_HELP_VISITOR_H + +#include +#include +#include + +namespace TCLAP { + +/** + * A Visitor object that calls the usage method of the given CmdLineOutput + * object for the specified CmdLine object. + */ +class HelpVisitor: public Visitor +{ + private: + /** + * Prevent accidental copying. + */ + HelpVisitor(const HelpVisitor& rhs); + HelpVisitor& operator=(const HelpVisitor& rhs); + + protected: + + /** + * The CmdLine the output will be generated for. + */ + CmdLineInterface* _cmd; + + /** + * The output object. + */ + CmdLineOutput** _out; + + public: + + /** + * Constructor. + * \param cmd - The CmdLine the output will be generated for. + * \param out - The type of output. + */ + HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out) + : Visitor(), _cmd( cmd ), _out( out ) { } + + /** + * Calls the usage method of the CmdLineOutput for the + * specified CmdLine. + */ + void visit() { (*_out)->usage(*_cmd); throw ExitException(0); } + +}; + +} + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/IgnoreRestVisitor.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/IgnoreRestVisitor.h new file mode 100644 index 0000000000000000000000000000000000000000..d20f6e075f55ab20884e9938aeef5778cc67d4db --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/IgnoreRestVisitor.h @@ -0,0 +1,52 @@ + +/****************************************************************************** + * + * file: IgnoreRestVisitor.h + * + * Copyright (c) 2003, Michael E. Smoot . + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + + +#ifndef TCLAP_IGNORE_REST_VISITOR_H +#define TCLAP_IGNORE_REST_VISITOR_H + +#include +#include + +namespace TCLAP { + +/** + * A Visitor that tells the CmdLine to begin ignoring arguments after + * this one is parsed. + */ +class IgnoreRestVisitor: public Visitor +{ + public: + + /** + * Constructor. + */ + IgnoreRestVisitor() : Visitor() {} + + /** + * Sets Arg::_ignoreRest. + */ + void visit() { Arg::beginIgnoring(); } +}; + +} + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/MultiArg.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/MultiArg.h new file mode 100644 index 0000000000000000000000000000000000000000..d478df9b89f285158dacd6801de92c3854ecc97d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/MultiArg.h @@ -0,0 +1,433 @@ +/****************************************************************************** + * + * file: MultiArg.h + * + * Copyright (c) 2003, Michael E. Smoot . + * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + + +#ifndef TCLAP_MULTIPLE_ARGUMENT_H +#define TCLAP_MULTIPLE_ARGUMENT_H + +#include +#include + +#include +#include + +namespace TCLAP { +/** + * An argument that allows multiple values of type T to be specified. Very + * similar to a ValueArg, except a vector of values will be returned + * instead of just one. + */ +template +class MultiArg : public Arg +{ +public: + typedef std::vector container_type; + typedef typename container_type::iterator iterator; + typedef typename container_type::const_iterator const_iterator; + +protected: + + /** + * The list of values parsed from the CmdLine. + */ + std::vector _values; + + /** + * The description of type T to be used in the usage. + */ + std::string _typeDesc; + + /** + * A list of constraint on this Arg. + */ + Constraint* _constraint; + + /** + * Extracts the value from the string. + * Attempts to parse string as type T, if this fails an exception + * is thrown. + * \param val - The string to be read. + */ + void _extractValue( const std::string& val ); + + /** + * Used by XorHandler to decide whether to keep parsing for this arg. + */ + bool _allowMore; + +public: + + /** + * Constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + Visitor* v = NULL); + + /** + * Constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param parser - A CmdLine parser object to add this Arg to + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + CmdLineInterface& parser, + Visitor* v = NULL ); + + /** + * Constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + Visitor* v = NULL ); + + /** + * Constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param parser - A CmdLine parser object to add this Arg to + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + CmdLineInterface& parser, + Visitor* v = NULL ); + + /** + * Handles the processing of the argument. + * This re-implements the Arg version of this method to set the + * _value of the argument appropriately. It knows the difference + * between labeled and unlabeled. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. Passed from main(). + */ + virtual bool processArg(int* i, std::vector& args); + + /** + * Returns a vector of type T containing the values parsed from + * the command line. + */ + const std::vector& getValue(); + + /** + * Returns an iterator over the values parsed from the command + * line. + */ + const_iterator begin() const { return _values.begin(); } + + /** + * Returns the end of the values parsed from the command + * line. + */ + const_iterator end() const { return _values.end(); } + + /** + * Returns the a short id string. Used in the usage. + * \param val - value to be used. + */ + virtual std::string shortID(const std::string& val="val") const; + + /** + * Returns the a long id string. Used in the usage. + * \param val - value to be used. + */ + virtual std::string longID(const std::string& val="val") const; + + /** + * Once we've matched the first value, then the arg is no longer + * required. + */ + virtual bool isRequired() const; + + virtual bool allowMore(); + + virtual void reset(); + +private: + /** + * Prevent accidental copying + */ + MultiArg(const MultiArg& rhs); + MultiArg& operator=(const MultiArg& rhs); + +}; + +template +MultiArg::MultiArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + Visitor* v) : + Arg( flag, name, desc, req, true, v ), + _values(std::vector()), + _typeDesc( typeDesc ), + _constraint( NULL ), + _allowMore(false) +{ + _acceptsMultipleValues = true; +} + +template +MultiArg::MultiArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + CmdLineInterface& parser, + Visitor* v) +: Arg( flag, name, desc, req, true, v ), + _values(std::vector()), + _typeDesc( typeDesc ), + _constraint( NULL ), + _allowMore(false) +{ + parser.add( this ); + _acceptsMultipleValues = true; +} + +/** + * + */ +template +MultiArg::MultiArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + Visitor* v) +: Arg( flag, name, desc, req, true, v ), + _values(std::vector()), + _typeDesc( constraint->shortID() ), + _constraint( constraint ), + _allowMore(false) +{ + _acceptsMultipleValues = true; +} + +template +MultiArg::MultiArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + CmdLineInterface& parser, + Visitor* v) +: Arg( flag, name, desc, req, true, v ), + _values(std::vector()), + _typeDesc( constraint->shortID() ), + _constraint( constraint ), + _allowMore(false) +{ + parser.add( this ); + _acceptsMultipleValues = true; +} + +template +const std::vector& MultiArg::getValue() { return _values; } + +template +bool MultiArg::processArg(int *i, std::vector& args) +{ + if ( _ignoreable && Arg::ignoreRest() ) + return false; + + if ( _hasBlanks( args[*i] ) ) + return false; + + std::string flag = args[*i]; + std::string value = ""; + + trimFlag( flag, value ); + + if ( argMatches( flag ) ) + { + if ( Arg::delimiter() != ' ' && value == "" ) + throw( ArgParseException( + "Couldn't find delimiter for this argument!", + toString() ) ); + + // always take the first one, regardless of start string + if ( value == "" ) + { + (*i)++; + if ( static_cast(*i) < args.size() ) + _extractValue( args[*i] ); + else + throw( ArgParseException("Missing a value for this argument!", + toString() ) ); + } + else + _extractValue( value ); + + /* + // continuing taking the args until we hit one with a start string + while ( (unsigned int)(*i)+1 < args.size() && + args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 && + args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) + _extractValue( args[++(*i)] ); + */ + + _alreadySet = true; + _checkWithVisitor(); + + return true; + } + else + return false; +} + +/** + * + */ +template +std::string MultiArg::shortID(const std::string& val) const +{ + static_cast(val); // Ignore input, don't warn + return Arg::shortID(_typeDesc) + " ... "; +} + +/** + * + */ +template +std::string MultiArg::longID(const std::string& val) const +{ + static_cast(val); // Ignore input, don't warn + return Arg::longID(_typeDesc) + " (accepted multiple times)"; +} + +/** + * Once we've matched the first value, then the arg is no longer + * required. + */ +template +bool MultiArg::isRequired() const +{ + if ( _required ) + { + if ( _values.size() > 1 ) + return false; + else + return true; + } + else + return false; + +} + +template +void MultiArg::_extractValue( const std::string& val ) +{ + try { + T tmp; + ExtractValue(tmp, val, typename ArgTraits::ValueCategory()); + _values.push_back(tmp); + } catch( ArgParseException &e) { + throw ArgParseException(e.error(), toString()); + } + + if ( _constraint != NULL ) + if ( ! _constraint->check( _values.back() ) ) + throw( CmdLineParseException( "Value '" + val + + "' does not meet constraint: " + + _constraint->description(), + toString() ) ); +} + +template +bool MultiArg::allowMore() +{ + bool am = _allowMore; + _allowMore = true; + return am; +} + +template +void MultiArg::reset() +{ + Arg::reset(); + _values.clear(); +} + +} // namespace TCLAP + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/MultiSwitchArg.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/MultiSwitchArg.h new file mode 100644 index 0000000000000000000000000000000000000000..208d9985a460720aefbf08bea4e70570c6782483 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/MultiSwitchArg.h @@ -0,0 +1,216 @@ + +/****************************************************************************** +* +* file: MultiSwitchArg.h +* +* Copyright (c) 2003, Michael E. Smoot . +* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. +* Copyright (c) 2005, Michael E. Smoot, Daniel Aarno, Erik Zeek. +* All rights reserved. +* +* See the file COPYING in the top directory of this distribution for +* more information. +* +* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + + +#ifndef TCLAP_MULTI_SWITCH_ARG_H +#define TCLAP_MULTI_SWITCH_ARG_H + +#include +#include + +#include + +namespace TCLAP { + +/** +* A multiple switch argument. If the switch is set on the command line, then +* the getValue method will return the number of times the switch appears. +*/ +class MultiSwitchArg : public SwitchArg +{ + protected: + + /** + * The value of the switch. + */ + int _value; + + /** + * Used to support the reset() method so that ValueArg can be + * reset to their constructed value. + */ + int _default; + + public: + + /** + * MultiSwitchArg constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param init - Optional. The initial/default value of this Arg. + * Defaults to 0. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiSwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + int init = 0, + Visitor* v = NULL); + + + /** + * MultiSwitchArg constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param parser - A CmdLine parser object to add this Arg to + * \param init - Optional. The initial/default value of this Arg. + * Defaults to 0. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + MultiSwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + CmdLineInterface& parser, + int init = 0, + Visitor* v = NULL); + + + /** + * Handles the processing of the argument. + * This re-implements the SwitchArg version of this method to set the + * _value of the argument appropriately. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. Passed + * in from main(). + */ + virtual bool processArg(int* i, std::vector& args); + + /** + * Returns int, the number of times the switch has been set. + */ + int getValue(); + + /** + * Returns the shortID for this Arg. + */ + std::string shortID(const std::string& val) const; + + /** + * Returns the longID for this Arg. + */ + std::string longID(const std::string& val) const; + + void reset(); + +}; + +////////////////////////////////////////////////////////////////////// +//BEGIN MultiSwitchArg.cpp +////////////////////////////////////////////////////////////////////// +inline MultiSwitchArg::MultiSwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + int init, + Visitor* v ) +: SwitchArg(flag, name, desc, false, v), +_value( init ), +_default( init ) +{ } + +inline MultiSwitchArg::MultiSwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + CmdLineInterface& parser, + int init, + Visitor* v ) +: SwitchArg(flag, name, desc, false, v), +_value( init ), +_default( init ) +{ + parser.add( this ); +} + +inline int MultiSwitchArg::getValue() { return _value; } + +inline bool MultiSwitchArg::processArg(int *i, std::vector& args) +{ + if ( _ignoreable && Arg::ignoreRest() ) + return false; + + if ( argMatches( args[*i] )) + { + // so the isSet() method will work + _alreadySet = true; + + // Matched argument: increment value. + ++_value; + + _checkWithVisitor(); + + return true; + } + else if ( combinedSwitchesMatch( args[*i] ) ) + { + // so the isSet() method will work + _alreadySet = true; + + // Matched argument: increment value. + ++_value; + + // Check for more in argument and increment value. + while ( combinedSwitchesMatch( args[*i] ) ) + ++_value; + + _checkWithVisitor(); + + return false; + } + else + return false; +} + +inline std::string +MultiSwitchArg::shortID(const std::string& val) const +{ + return Arg::shortID(val) + " ... "; +} + +inline std::string +MultiSwitchArg::longID(const std::string& val) const +{ + return Arg::longID(val) + " (accepted multiple times)"; +} + +inline void +MultiSwitchArg::reset() +{ + MultiSwitchArg::_value = MultiSwitchArg::_default; +} + +////////////////////////////////////////////////////////////////////// +//END MultiSwitchArg.cpp +////////////////////////////////////////////////////////////////////// + +} //namespace TCLAP + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/OptionalUnlabeledTracker.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/OptionalUnlabeledTracker.h new file mode 100644 index 0000000000000000000000000000000000000000..92f8929785814cb045ea29472f25b2e25c4432b6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/OptionalUnlabeledTracker.h @@ -0,0 +1,62 @@ + + +/****************************************************************************** + * + * file: OptionalUnlabeledTracker.h + * + * Copyright (c) 2005, Michael E. Smoot . + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + + +#ifndef TCLAP_OPTIONAL_UNLABELED_TRACKER_H +#define TCLAP_OPTIONAL_UNLABELED_TRACKER_H + +#include + +namespace TCLAP { + +class OptionalUnlabeledTracker +{ + + public: + + static void check( bool req, const std::string& argName ); + + static void gotOptional() { alreadyOptionalRef() = true; } + + static bool& alreadyOptional() { return alreadyOptionalRef(); } + + private: + + static bool& alreadyOptionalRef() { static bool ct = false; return ct; } +}; + + +inline void OptionalUnlabeledTracker::check( bool req, const std::string& argName ) +{ + if ( OptionalUnlabeledTracker::alreadyOptional() ) + throw( SpecificationException( + "You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg", + argName ) ); + + if ( !req ) + OptionalUnlabeledTracker::gotOptional(); +} + + +} // namespace TCLAP + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/StandardTraits.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/StandardTraits.h new file mode 100644 index 0000000000000000000000000000000000000000..75c9c64b5be5e570fe26288c55c0312063afc10f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/StandardTraits.h @@ -0,0 +1,208 @@ +// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- + +/****************************************************************************** + * + * file: StandardTraits.h + * + * Copyright (c) 2007, Daniel Aarno, Michael E. Smoot . + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +// This is an internal tclap file, you should probably not have to +// include this directly + +#ifndef TCLAP_STANDARD_TRAITS_H +#define TCLAP_STANDARD_TRAITS_H + +#ifdef HAVE_CONFIG_H +#include // To check for long long +#endif + +// If Microsoft has already typedef'd wchar_t as an unsigned +// short, then compiles will break because it's as if we're +// creating ArgTraits twice for unsigned short. Thus... +#ifdef _MSC_VER +#ifndef _NATIVE_WCHAR_T_DEFINED +#define TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS +#endif +#endif + +namespace TCLAP { + +// ====================================================================== +// Integer types +// ====================================================================== + +/** + * longs have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; + +/** + * ints have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; + +/** + * shorts have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; + +/** + * chars have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; + +#ifdef HAVE_LONG_LONG +/** + * long longs have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; +#endif + +// ====================================================================== +// Unsigned integer types +// ====================================================================== + +/** + * unsigned longs have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; + +/** + * unsigned ints have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; + +/** + * unsigned shorts have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; + +/** + * unsigned chars have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; + +// Microsoft implements size_t awkwardly. +#if defined(_MSC_VER) && defined(_M_X64) +/** + * size_ts have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; +#endif + + +#ifdef HAVE_LONG_LONG +/** + * unsigned long longs have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; +#endif + +// ====================================================================== +// Float types +// ====================================================================== + +/** + * floats have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; + +/** + * doubles have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; + +// ====================================================================== +// Other types +// ====================================================================== + +/** + * bools have value-like semantics. + */ +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; + + +/** + * wchar_ts have value-like semantics. + */ +#ifndef TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS +template<> +struct ArgTraits { + typedef ValueLike ValueCategory; +}; +#endif + +/** + * Strings have string like argument traits. + */ +template<> +struct ArgTraits { + typedef StringLike ValueCategory; +}; + +template +void SetString(T &dst, const std::string &src) +{ + dst = src; +} + +} // namespace + +#endif + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/StdOutput.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/StdOutput.h new file mode 100644 index 0000000000000000000000000000000000000000..f224ea205b9774d752cacc532f8ff14daf0b5c48 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/StdOutput.h @@ -0,0 +1,299 @@ +// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- + +/****************************************************************************** + * + * file: StdOutput.h + * + * Copyright (c) 2004, Michael E. Smoot + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_STDCMDLINEOUTPUT_H +#define TCLAP_STDCMDLINEOUTPUT_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace TCLAP { + +/** + * A class that isolates any output from the CmdLine object so that it + * may be easily modified. + */ +class StdOutput : public CmdLineOutput +{ + + public: + + /** + * Prints the usage to stdout. Can be overridden to + * produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void usage(CmdLineInterface& c); + + /** + * Prints the version to stdout. Can be overridden + * to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void version(CmdLineInterface& c); + + /** + * Prints (to stderr) an error message, short usage + * Can be overridden to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. + */ + virtual void failure(CmdLineInterface& c, + ArgException& e ); + + protected: + + /** + * Writes a brief usage message with short args. + * \param c - The CmdLine object the output is generated for. + * \param os - The stream to write the message to. + */ + void _shortUsage( CmdLineInterface& c, std::ostream& os ) const; + + /** + * Writes a longer usage message with long and short args, + * provides descriptions and prints message. + * \param c - The CmdLine object the output is generated for. + * \param os - The stream to write the message to. + */ + void _longUsage( CmdLineInterface& c, std::ostream& os ) const; + + /** + * This function inserts line breaks and indents long strings + * according the params input. It will only break lines at spaces, + * commas and pipes. + * \param os - The stream to be printed to. + * \param s - The string to be printed. + * \param maxWidth - The maxWidth allowed for the output line. + * \param indentSpaces - The number of spaces to indent the first line. + * \param secondLineOffset - The number of spaces to indent the second + * and all subsequent lines in addition to indentSpaces. + */ + void spacePrint( std::ostream& os, + const std::string& s, + int maxWidth, + int indentSpaces, + int secondLineOffset ) const; + +}; + + +inline void StdOutput::version(CmdLineInterface& _cmd) +{ + std::string progName = _cmd.getProgramName(); + std::string xversion = _cmd.getVersion(); + + std::cout << std::endl << progName << " version: " + << xversion << std::endl << std::endl; +} + +inline void StdOutput::usage(CmdLineInterface& _cmd ) +{ + std::cout << std::endl << "USAGE: " << std::endl << std::endl; + + _shortUsage( _cmd, std::cout ); + + std::cout << std::endl << std::endl << "Where: " << std::endl << std::endl; + + _longUsage( _cmd, std::cout ); + + std::cout << std::endl; + +} + +inline void StdOutput::failure( CmdLineInterface& _cmd, + ArgException& e ) +{ + std::string progName = _cmd.getProgramName(); + + std::cerr << "PARSE ERROR: " << e.argId() << std::endl + << " " << e.error() << std::endl << std::endl; + + if ( _cmd.hasHelpAndVersion() ) + { + std::cerr << "Brief USAGE: " << std::endl; + + _shortUsage( _cmd, std::cerr ); + + std::cerr << std::endl << "For complete USAGE and HELP type: " + << std::endl << " " << progName << " " + << Arg::nameStartString() << "help" + << std::endl << std::endl; + } + else + usage(_cmd); + + throw ExitException(1); +} + +inline void +StdOutput::_shortUsage( CmdLineInterface& _cmd, + std::ostream& os ) const +{ + std::list argList = _cmd.getArgList(); + std::string progName = _cmd.getProgramName(); + XorHandler xorHandler = _cmd.getXorHandler(); + std::vector< std::vector > xorList = xorHandler.getXorList(); + + std::string s = progName + " "; + + // first the xor + for ( int i = 0; static_cast(i) < xorList.size(); i++ ) + { + s += " {"; + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); it++ ) + s += (*it)->shortID() + "|"; + + s[s.length()-1] = '}'; + } + + // then the rest + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) + if ( !xorHandler.contains( (*it) ) ) + s += " " + (*it)->shortID(); + + // if the program name is too long, then adjust the second line offset + int secondLineOffset = static_cast(progName.length()) + 2; + if ( secondLineOffset > 75/2 ) + secondLineOffset = static_cast(75/2); + + spacePrint( os, s, 75, 3, secondLineOffset ); +} + +inline void +StdOutput::_longUsage( CmdLineInterface& _cmd, + std::ostream& os ) const +{ + std::list argList = _cmd.getArgList(); + std::string message = _cmd.getMessage(); + XorHandler xorHandler = _cmd.getXorHandler(); + std::vector< std::vector > xorList = xorHandler.getXorList(); + + // first the xor + for ( int i = 0; static_cast(i) < xorList.size(); i++ ) + { + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); + it++ ) + { + spacePrint( os, (*it)->longID(), 75, 3, 3 ); + spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); + + if ( it+1 != xorList[i].end() ) + spacePrint(os, "-- OR --", 75, 9, 0); + } + os << std::endl << std::endl; + } + + // then the rest + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) + if ( !xorHandler.contains( (*it) ) ) + { + spacePrint( os, (*it)->longID(), 75, 3, 3 ); + spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); + os << std::endl; + } + + os << std::endl; + + spacePrint( os, message, 75, 3, 0 ); +} + +inline void StdOutput::spacePrint( std::ostream& os, + const std::string& s, + int maxWidth, + int indentSpaces, + int secondLineOffset ) const +{ + int len = static_cast(s.length()); + + if ( (len + indentSpaces > maxWidth) && maxWidth > 0 ) + { + int allowedLen = maxWidth - indentSpaces; + int start = 0; + while ( start < len ) + { + // find the substring length + // int stringLen = std::min( len - start, allowedLen ); + // doing it this way to support a VisualC++ 2005 bug + using namespace std; + int stringLen = min( len - start, allowedLen ); + + // trim the length so it doesn't end in middle of a word + if ( stringLen == allowedLen ) + while ( stringLen >= 0 && + s[stringLen+start] != ' ' && + s[stringLen+start] != ',' && + s[stringLen+start] != '|' ) + stringLen--; + + // ok, the word is longer than the line, so just split + // wherever the line ends + if ( stringLen <= 0 ) + stringLen = allowedLen; + + // check for newlines + for ( int i = 0; i < stringLen; i++ ) + if ( s[start+i] == '\n' ) + stringLen = i+1; + + // print the indent + for ( int i = 0; i < indentSpaces; i++ ) + os << " "; + + if ( start == 0 ) + { + // handle second line offsets + indentSpaces += secondLineOffset; + + // adjust allowed len + allowedLen -= secondLineOffset; + } + + os << s.substr(start,stringLen) << std::endl; + + // so we don't start a line with a space + while ( s[stringLen+start] == ' ' && start < len ) + start++; + + start += stringLen; + } + } + else + { + for ( int i = 0; i < indentSpaces; i++ ) + os << " "; + os << s << std::endl; + } +} + +} //namespace TCLAP +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/SwitchArg.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/SwitchArg.h new file mode 100644 index 0000000000000000000000000000000000000000..c2e83957ade49535f18a2358eebbfcc38595549c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/SwitchArg.h @@ -0,0 +1,266 @@ + +/****************************************************************************** + * + * file: SwitchArg.h + * + * Copyright (c) 2003, Michael E. Smoot . + * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + + +#ifndef TCLAP_SWITCH_ARG_H +#define TCLAP_SWITCH_ARG_H + +#include +#include + +#include + +namespace TCLAP { + +/** + * A simple switch argument. If the switch is set on the command line, then + * the getValue method will return the opposite of the default value for the + * switch. + */ +class SwitchArg : public Arg +{ + protected: + + /** + * The value of the switch. + */ + bool _value; + + /** + * Used to support the reset() method so that ValueArg can be + * reset to their constructed value. + */ + bool _default; + + public: + + /** + * SwitchArg constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param def - The default value for this Switch. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + SwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool def = false, + Visitor* v = NULL); + + + /** + * SwitchArg constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param parser - A CmdLine parser object to add this Arg to + * \param def - The default value for this Switch. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + SwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + CmdLineInterface& parser, + bool def = false, + Visitor* v = NULL); + + + /** + * Handles the processing of the argument. + * This re-implements the Arg version of this method to set the + * _value of the argument appropriately. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. Passed + * in from main(). + */ + virtual bool processArg(int* i, std::vector& args); + + /** + * Checks a string to see if any of the chars in the string + * match the flag for this Switch. + */ + bool combinedSwitchesMatch(std::string& combined); + + /** + * Returns bool, whether or not the switch has been set. + */ + bool getValue(); + + virtual void reset(); + + private: + /** + * Checks to see if we've found the last match in + * a combined string. + */ + bool lastCombined(std::string& combined); + + /** + * Does the common processing of processArg. + */ + void commonProcessing(); +}; + +////////////////////////////////////////////////////////////////////// +//BEGIN SwitchArg.cpp +////////////////////////////////////////////////////////////////////// +inline SwitchArg::SwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool default_val, + Visitor* v ) +: Arg(flag, name, desc, false, false, v), + _value( default_val ), + _default( default_val ) +{ } + +inline SwitchArg::SwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, + CmdLineInterface& parser, + bool default_val, + Visitor* v ) +: Arg(flag, name, desc, false, false, v), + _value( default_val ), + _default(default_val) +{ + parser.add( this ); +} + +inline bool SwitchArg::getValue() { return _value; } + +inline bool SwitchArg::lastCombined(std::string& combinedSwitches ) +{ + for ( unsigned int i = 1; i < combinedSwitches.length(); i++ ) + if ( combinedSwitches[i] != Arg::blankChar() ) + return false; + + return true; +} + +inline bool SwitchArg::combinedSwitchesMatch(std::string& combinedSwitches ) +{ + // make sure this is actually a combined switch + if ( combinedSwitches.length() > 0 && + combinedSwitches[0] != Arg::flagStartString()[0] ) + return false; + + // make sure it isn't a long name + if ( combinedSwitches.substr( 0, Arg::nameStartString().length() ) == + Arg::nameStartString() ) + return false; + + // make sure the delimiter isn't in the string + if ( combinedSwitches.find_first_of( Arg::delimiter() ) != std::string::npos ) + return false; + + // ok, we're not specifying a ValueArg, so we know that we have + // a combined switch list. + for ( unsigned int i = 1; i < combinedSwitches.length(); i++ ) + if ( _flag.length() > 0 && + combinedSwitches[i] == _flag[0] && + _flag[0] != Arg::flagStartString()[0] ) + { + // update the combined switches so this one is no longer present + // this is necessary so that no unlabeled args are matched + // later in the processing. + //combinedSwitches.erase(i,1); + combinedSwitches[i] = Arg::blankChar(); + return true; + } + + // none of the switches passed in the list match. + return false; +} + +inline void SwitchArg::commonProcessing() +{ + if ( _xorSet ) + throw(CmdLineParseException( + "Mutually exclusive argument already set!", toString())); + + if ( _alreadySet ) + throw(CmdLineParseException("Argument already set!", toString())); + + _alreadySet = true; + + if ( _value == true ) + _value = false; + else + _value = true; + + _checkWithVisitor(); +} + +inline bool SwitchArg::processArg(int *i, std::vector& args) +{ + if ( _ignoreable && Arg::ignoreRest() ) + return false; + + // if the whole string matches the flag or name string + if ( argMatches( args[*i] ) ) + { + commonProcessing(); + + return true; + } + // if a substring matches the flag as part of a combination + else if ( combinedSwitchesMatch( args[*i] ) ) + { + // check again to ensure we don't misinterpret + // this as a MultiSwitchArg + if ( combinedSwitchesMatch( args[*i] ) ) + throw(CmdLineParseException("Argument already set!", + toString())); + + commonProcessing(); + + // We only want to return true if we've found the last combined + // match in the string, otherwise we return true so that other + // switches in the combination will have a chance to match. + return lastCombined( args[*i] ); + } + else + return false; +} + +inline void SwitchArg::reset() +{ + Arg::reset(); + _value = _default; +} +////////////////////////////////////////////////////////////////////// +//End SwitchArg.cpp +////////////////////////////////////////////////////////////////////// + +} //namespace TCLAP + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/UnlabeledMultiArg.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/UnlabeledMultiArg.h new file mode 100644 index 0000000000000000000000000000000000000000..7995bc296e4c19720f1076949c6b7625de36b532 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/UnlabeledMultiArg.h @@ -0,0 +1,301 @@ + +/****************************************************************************** + * + * file: UnlabeledMultiArg.h + * + * Copyright (c) 2003, Michael E. Smoot. + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + + +#ifndef TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H +#define TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H + +#include +#include + +#include +#include + +namespace TCLAP { + +/** + * Just like a MultiArg, except that the arguments are unlabeled. Basically, + * this Arg will slurp up everything that hasn't been matched to another + * Arg. + */ +template +class UnlabeledMultiArg : public MultiArg +{ + + // If compiler has two stage name lookup (as gcc >= 3.4 does) + // this is required to prevent undef. symbols + using MultiArg::_ignoreable; + using MultiArg::_hasBlanks; + using MultiArg::_extractValue; + using MultiArg::_typeDesc; + using MultiArg::_name; + using MultiArg::_description; + using MultiArg::_alreadySet; + using MultiArg::toString; + + public: + + /** + * Constructor. + * \param name - The name of the Arg. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param ignoreable - Whether or not this argument can be ignored + * using the "--" flag. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + UnlabeledMultiArg( const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + bool ignoreable = false, + Visitor* v = NULL ); + /** + * Constructor. + * \param name - The name of the Arg. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param parser - A CmdLine parser object to add this Arg to + * \param ignoreable - Whether or not this argument can be ignored + * using the "--" flag. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + UnlabeledMultiArg( const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + CmdLineInterface& parser, + bool ignoreable = false, + Visitor* v = NULL ); + + /** + * Constructor. + * \param name - The name of the Arg. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param ignoreable - Whether or not this argument can be ignored + * using the "--" flag. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + UnlabeledMultiArg( const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + bool ignoreable = false, + Visitor* v = NULL ); + + /** + * Constructor. + * \param name - The name of the Arg. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param parser - A CmdLine parser object to add this Arg to + * \param ignoreable - Whether or not this argument can be ignored + * using the "--" flag. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + UnlabeledMultiArg( const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + CmdLineInterface& parser, + bool ignoreable = false, + Visitor* v = NULL ); + + /** + * Handles the processing of the argument. + * This re-implements the Arg version of this method to set the + * _value of the argument appropriately. It knows the difference + * between labeled and unlabeled. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. Passed from main(). + */ + virtual bool processArg(int* i, std::vector& args); + + /** + * Returns the a short id string. Used in the usage. + * \param val - value to be used. + */ + virtual std::string shortID(const std::string& val="val") const; + + /** + * Returns the a long id string. Used in the usage. + * \param val - value to be used. + */ + virtual std::string longID(const std::string& val="val") const; + + /** + * Operator ==. + * \param a - The Arg to be compared to this. + */ + virtual bool operator==(const Arg& a) const; + + /** + * Pushes this to back of list rather than front. + * \param argList - The list this should be added to. + */ + virtual void addToList( std::list& argList ) const; +}; + +template +UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + bool ignoreable, + Visitor* v) +: MultiArg("", name, desc, req, typeDesc, v) +{ + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(true, toString()); +} + +template +UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, + const std::string& desc, + bool req, + const std::string& typeDesc, + CmdLineInterface& parser, + bool ignoreable, + Visitor* v) +: MultiArg("", name, desc, req, typeDesc, v) +{ + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(true, toString()); + parser.add( this ); +} + + +template +UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + bool ignoreable, + Visitor* v) +: MultiArg("", name, desc, req, constraint, v) +{ + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(true, toString()); +} + +template +UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, + const std::string& desc, + bool req, + Constraint* constraint, + CmdLineInterface& parser, + bool ignoreable, + Visitor* v) +: MultiArg("", name, desc, req, constraint, v) +{ + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(true, toString()); + parser.add( this ); +} + + +template +bool UnlabeledMultiArg::processArg(int *i, std::vector& args) +{ + + if ( _hasBlanks( args[*i] ) ) + return false; + + // never ignore an unlabeled multi arg + + + // always take the first value, regardless of the start string + _extractValue( args[(*i)] ); + + /* + // continue taking args until we hit the end or a start string + while ( (unsigned int)(*i)+1 < args.size() && + args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 && + args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) + _extractValue( args[++(*i)] ); + */ + + _alreadySet = true; + + return true; +} + +template +std::string UnlabeledMultiArg::shortID(const std::string& val) const +{ + static_cast(val); // Ignore input, don't warn + return std::string("<") + _typeDesc + "> ..."; +} + +template +std::string UnlabeledMultiArg::longID(const std::string& val) const +{ + static_cast(val); // Ignore input, don't warn + return std::string("<") + _typeDesc + "> (accepted multiple times)"; +} + +template +bool UnlabeledMultiArg::operator==(const Arg& a) const +{ + if ( _name == a.getName() || _description == a.getDescription() ) + return true; + else + return false; +} + +template +void UnlabeledMultiArg::addToList( std::list& argList ) const +{ + argList.push_back( const_cast(static_cast(this)) ); +} + +} + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/UnlabeledValueArg.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/UnlabeledValueArg.h new file mode 100644 index 0000000000000000000000000000000000000000..25e85ff1174e113e504559d830ed6e375f99bd74 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/UnlabeledValueArg.h @@ -0,0 +1,340 @@ + +/****************************************************************************** + * + * file: UnlabeledValueArg.h + * + * Copyright (c) 2003, Michael E. Smoot . + * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + + +#ifndef TCLAP_UNLABELED_VALUE_ARGUMENT_H +#define TCLAP_UNLABELED_VALUE_ARGUMENT_H + +#include +#include + +#include +#include + + +namespace TCLAP { + +/** + * The basic unlabeled argument that parses a value. + * This is a template class, which means the type T defines the type + * that a given object will attempt to parse when an UnlabeledValueArg + * is reached in the list of args that the CmdLine iterates over. + */ +template +class UnlabeledValueArg : public ValueArg +{ + + // If compiler has two stage name lookup (as gcc >= 3.4 does) + // this is required to prevent undef. symbols + using ValueArg::_ignoreable; + using ValueArg::_hasBlanks; + using ValueArg::_extractValue; + using ValueArg::_typeDesc; + using ValueArg::_name; + using ValueArg::_description; + using ValueArg::_alreadySet; + using ValueArg::toString; + + public: + + /** + * UnlabeledValueArg constructor. + * \param name - A one word name for the argument. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param ignoreable - Allows you to specify that this argument can be + * ignored if the '--' flag is set. This defaults to false (cannot + * be ignored) and should generally stay that way unless you have + * some special need for certain arguments to be ignored. + * \param v - Optional Visitor. You should leave this blank unless + * you have a very good reason. + */ + UnlabeledValueArg( const std::string& name, + const std::string& desc, + bool req, + T value, + const std::string& typeDesc, + bool ignoreable = false, + Visitor* v = NULL); + + /** + * UnlabeledValueArg constructor. + * \param name - A one word name for the argument. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param parser - A CmdLine parser object to add this Arg to + * \param ignoreable - Allows you to specify that this argument can be + * ignored if the '--' flag is set. This defaults to false (cannot + * be ignored) and should generally stay that way unless you have + * some special need for certain arguments to be ignored. + * \param v - Optional Visitor. You should leave this blank unless + * you have a very good reason. + */ + UnlabeledValueArg( const std::string& name, + const std::string& desc, + bool req, + T value, + const std::string& typeDesc, + CmdLineInterface& parser, + bool ignoreable = false, + Visitor* v = NULL ); + + /** + * UnlabeledValueArg constructor. + * \param name - A one word name for the argument. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param ignoreable - Allows you to specify that this argument can be + * ignored if the '--' flag is set. This defaults to false (cannot + * be ignored) and should generally stay that way unless you have + * some special need for certain arguments to be ignored. + * \param v - Optional Visitor. You should leave this blank unless + * you have a very good reason. + */ + UnlabeledValueArg( const std::string& name, + const std::string& desc, + bool req, + T value, + Constraint* constraint, + bool ignoreable = false, + Visitor* v = NULL ); + + + /** + * UnlabeledValueArg constructor. + * \param name - A one word name for the argument. Note that this is used for + * identification, not as a long flag. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param parser - A CmdLine parser object to add this Arg to + * \param ignoreable - Allows you to specify that this argument can be + * ignored if the '--' flag is set. This defaults to false (cannot + * be ignored) and should generally stay that way unless you have + * some special need for certain arguments to be ignored. + * \param v - Optional Visitor. You should leave this blank unless + * you have a very good reason. + */ + UnlabeledValueArg( const std::string& name, + const std::string& desc, + bool req, + T value, + Constraint* constraint, + CmdLineInterface& parser, + bool ignoreable = false, + Visitor* v = NULL); + + /** + * Handles the processing of the argument. + * This re-implements the Arg version of this method to set the + * _value of the argument appropriately. Handling specific to + * unlabeled arguments. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. + */ + virtual bool processArg(int* i, std::vector& args); + + /** + * Overrides shortID for specific behavior. + */ + virtual std::string shortID(const std::string& val="val") const; + + /** + * Overrides longID for specific behavior. + */ + virtual std::string longID(const std::string& val="val") const; + + /** + * Overrides operator== for specific behavior. + */ + virtual bool operator==(const Arg& a ) const; + + /** + * Instead of pushing to the front of list, push to the back. + * \param argList - The list to add this to. + */ + virtual void addToList( std::list& argList ) const; + +}; + +/** + * Constructor implementation. + */ +template +UnlabeledValueArg::UnlabeledValueArg(const std::string& name, + const std::string& desc, + bool req, + T val, + const std::string& typeDesc, + bool ignoreable, + Visitor* v) +: ValueArg("", name, desc, req, val, typeDesc, v) +{ + _ignoreable = ignoreable; + + OptionalUnlabeledTracker::check(req, toString()); + +} + +template +UnlabeledValueArg::UnlabeledValueArg(const std::string& name, + const std::string& desc, + bool req, + T val, + const std::string& typeDesc, + CmdLineInterface& parser, + bool ignoreable, + Visitor* v) +: ValueArg("", name, desc, req, val, typeDesc, v) +{ + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(req, toString()); + parser.add( this ); +} + +/** + * Constructor implementation. + */ +template +UnlabeledValueArg::UnlabeledValueArg(const std::string& name, + const std::string& desc, + bool req, + T val, + Constraint* constraint, + bool ignoreable, + Visitor* v) +: ValueArg("", name, desc, req, val, constraint, v) +{ + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(req, toString()); +} + +template +UnlabeledValueArg::UnlabeledValueArg(const std::string& name, + const std::string& desc, + bool req, + T val, + Constraint* constraint, + CmdLineInterface& parser, + bool ignoreable, + Visitor* v) +: ValueArg("", name, desc, req, val, constraint, v) +{ + _ignoreable = ignoreable; + OptionalUnlabeledTracker::check(req, toString()); + parser.add( this ); +} + +/** + * Implementation of processArg(). + */ +template +bool UnlabeledValueArg::processArg(int *i, std::vector& args) +{ + + if ( _alreadySet ) + return false; + + if ( _hasBlanks( args[*i] ) ) + return false; + + // never ignore an unlabeled arg + + _extractValue( args[*i] ); + _alreadySet = true; + return true; +} + +/** + * Overriding shortID for specific output. + */ +template +std::string UnlabeledValueArg::shortID(const std::string& val) const +{ + static_cast(val); // Ignore input, don't warn + return std::string("<") + _typeDesc + ">"; +} + +/** + * Overriding longID for specific output. + */ +template +std::string UnlabeledValueArg::longID(const std::string& val) const +{ + static_cast(val); // Ignore input, don't warn + + // Ideally we would like to be able to use RTTI to return the name + // of the type required for this argument. However, g++ at least, + // doesn't appear to return terribly useful "names" of the types. + return std::string("<") + _typeDesc + ">"; +} + +/** + * Overriding operator== for specific behavior. + */ +template +bool UnlabeledValueArg::operator==(const Arg& a ) const +{ + if ( _name == a.getName() || _description == a.getDescription() ) + return true; + else + return false; +} + +template +void UnlabeledValueArg::addToList( std::list& argList ) const +{ + argList.push_back( const_cast(static_cast(this)) ); +} + +} +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ValueArg.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ValueArg.h new file mode 100644 index 0000000000000000000000000000000000000000..2f65e4c985eefa34710ea7415e911516e5ac48a5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ValueArg.h @@ -0,0 +1,425 @@ +/****************************************************************************** + * + * file: ValueArg.h + * + * Copyright (c) 2003, Michael E. Smoot . + * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + + +#ifndef TCLAP_VALUE_ARGUMENT_H +#define TCLAP_VALUE_ARGUMENT_H + +#include +#include + +#include +#include + +namespace TCLAP { + +/** + * The basic labeled argument that parses a value. + * This is a template class, which means the type T defines the type + * that a given object will attempt to parse when the flag/name is matched + * on the command line. While there is nothing stopping you from creating + * an unflagged ValueArg, it is unwise and would cause significant problems. + * Instead use an UnlabeledValueArg. + */ +template +class ValueArg : public Arg +{ + protected: + + /** + * The value parsed from the command line. + * Can be of any type, as long as the >> operator for the type + * is defined. + */ + T _value; + + /** + * Used to support the reset() method so that ValueArg can be + * reset to their constructed value. + */ + T _default; + + /** + * A human readable description of the type to be parsed. + * This is a hack, plain and simple. Ideally we would use RTTI to + * return the name of type T, but until there is some sort of + * consistent support for human readable names, we are left to our + * own devices. + */ + std::string _typeDesc; + + /** + * A Constraint this Arg must conform to. + */ + Constraint* _constraint; + + /** + * Extracts the value from the string. + * Attempts to parse string as type T, if this fails an exception + * is thrown. + * \param val - value to be parsed. + */ + void _extractValue( const std::string& val ); + + public: + + /** + * Labeled ValueArg constructor. + * You could conceivably call this constructor with a blank flag, + * but that would make you a bad person. It would also cause + * an exception to be thrown. If you want an unlabeled argument, + * use the other constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + ValueArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T value, + const std::string& typeDesc, + Visitor* v = NULL); + + + /** + * Labeled ValueArg constructor. + * You could conceivably call this constructor with a blank flag, + * but that would make you a bad person. It would also cause + * an exception to be thrown. If you want an unlabeled argument, + * use the other constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param typeDesc - A short, human readable description of the + * type that this object expects. This is used in the generation + * of the USAGE statement. The goal is to be helpful to the end user + * of the program. + * \param parser - A CmdLine parser object to add this Arg to + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + ValueArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T value, + const std::string& typeDesc, + CmdLineInterface& parser, + Visitor* v = NULL ); + + /** + * Labeled ValueArg constructor. + * You could conceivably call this constructor with a blank flag, + * but that would make you a bad person. It would also cause + * an exception to be thrown. If you want an unlabeled argument, + * use the other constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param parser - A CmdLine parser object to add this Arg to. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + ValueArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T value, + Constraint* constraint, + CmdLineInterface& parser, + Visitor* v = NULL ); + + /** + * Labeled ValueArg constructor. + * You could conceivably call this constructor with a blank flag, + * but that would make you a bad person. It would also cause + * an exception to be thrown. If you want an unlabeled argument, + * use the other constructor. + * \param flag - The one character flag that identifies this + * argument on the command line. + * \param name - A one word name for the argument. Can be + * used as a long flag on the command line. + * \param desc - A description of what the argument is for or + * does. + * \param req - Whether the argument is required on the command + * line. + * \param value - The default value assigned to this argument if it + * is not present on the command line. + * \param constraint - A pointer to a Constraint object used + * to constrain this Arg. + * \param v - An optional visitor. You probably should not + * use this unless you have a very good reason. + */ + ValueArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T value, + Constraint* constraint, + Visitor* v = NULL ); + + /** + * Handles the processing of the argument. + * This re-implements the Arg version of this method to set the + * _value of the argument appropriately. It knows the difference + * between labeled and unlabeled. + * \param i - Pointer the the current argument in the list. + * \param args - Mutable list of strings. Passed + * in from main(). + */ + virtual bool processArg(int* i, std::vector& args); + + /** + * Returns the value of the argument. + */ + T& getValue() ; + + /** + * Specialization of shortID. + * \param val - value to be used. + */ + virtual std::string shortID(const std::string& val = "val") const; + + /** + * Specialization of longID. + * \param val - value to be used. + */ + virtual std::string longID(const std::string& val = "val") const; + + virtual void reset() ; + +private: + /** + * Prevent accidental copying + */ + ValueArg(const ValueArg& rhs); + ValueArg& operator=(const ValueArg& rhs); +}; + + +/** + * Constructor implementation. + */ +template +ValueArg::ValueArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T val, + const std::string& typeDesc, + Visitor* v) +: Arg(flag, name, desc, req, true, v), + _value( val ), + _default( val ), + _typeDesc( typeDesc ), + _constraint( NULL ) +{ } + +template +ValueArg::ValueArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T val, + const std::string& typeDesc, + CmdLineInterface& parser, + Visitor* v) +: Arg(flag, name, desc, req, true, v), + _value( val ), + _default( val ), + _typeDesc( typeDesc ), + _constraint( NULL ) +{ + parser.add( this ); +} + +template +ValueArg::ValueArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T val, + Constraint* constraint, + Visitor* v) +: Arg(flag, name, desc, req, true, v), + _value( val ), + _default( val ), + _typeDesc( constraint->shortID() ), + _constraint( constraint ) +{ } + +template +ValueArg::ValueArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, + T val, + Constraint* constraint, + CmdLineInterface& parser, + Visitor* v) +: Arg(flag, name, desc, req, true, v), + _value( val ), + _default( val ), + _typeDesc( constraint->shortID() ), + _constraint( constraint ) +{ + parser.add( this ); +} + + +/** + * Implementation of getValue(). + */ +template +T& ValueArg::getValue() { return _value; } + +/** + * Implementation of processArg(). + */ +template +bool ValueArg::processArg(int *i, std::vector& args) +{ + if ( _ignoreable && Arg::ignoreRest() ) + return false; + + if ( _hasBlanks( args[*i] ) ) + return false; + + std::string flag = args[*i]; + + std::string value = ""; + trimFlag( flag, value ); + + if ( argMatches( flag ) ) + { + if ( _alreadySet ) + { + if ( _xorSet ) + throw( CmdLineParseException( + "Mutually exclusive argument already set!", + toString()) ); + else + throw( CmdLineParseException("Argument already set!", + toString()) ); + } + + if ( Arg::delimiter() != ' ' && value == "" ) + throw( ArgParseException( + "Couldn't find delimiter for this argument!", + toString() ) ); + + if ( value == "" ) + { + (*i)++; + if ( static_cast(*i) < args.size() ) + _extractValue( args[*i] ); + else + throw( ArgParseException("Missing a value for this argument!", + toString() ) ); + } + else + _extractValue( value ); + + _alreadySet = true; + _checkWithVisitor(); + return true; + } + else + return false; +} + +/** + * Implementation of shortID. + */ +template +std::string ValueArg::shortID(const std::string& val) const +{ + static_cast(val); // Ignore input, don't warn + return Arg::shortID( _typeDesc ); +} + +/** + * Implementation of longID. + */ +template +std::string ValueArg::longID(const std::string& val) const +{ + static_cast(val); // Ignore input, don't warn + return Arg::longID( _typeDesc ); +} + +template +void ValueArg::_extractValue( const std::string& val ) +{ + try { + ExtractValue(_value, val, typename ArgTraits::ValueCategory()); + } catch( ArgParseException &e) { + throw ArgParseException(e.error(), toString()); + } + + if ( _constraint != NULL ) + if ( ! _constraint->check( _value ) ) + throw( CmdLineParseException( "Value '" + val + + + "' does not meet constraint: " + + _constraint->description(), + toString() ) ); +} + +template +void ValueArg::reset() +{ + Arg::reset(); + _value = _default; +} + +} // namespace TCLAP + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ValuesConstraint.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ValuesConstraint.h new file mode 100644 index 0000000000000000000000000000000000000000..d1c1df7010cee0cbd2a78ae880adf591b8d61a20 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ValuesConstraint.h @@ -0,0 +1,139 @@ + + +/****************************************************************************** + * + * file: ValuesConstraint.h + * + * Copyright (c) 2005, Michael E. Smoot + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_VALUESCONSTRAINT_H +#define TCLAP_VALUESCONSTRAINT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +namespace TCLAP { + +/** + * A Constraint that constrains the Arg to only those values specified + * in the constraint. + */ +template +class ValuesConstraint : public Constraint +{ + + public: + + /** + * Constructor. + * \param allowed - vector of allowed values. + */ + ValuesConstraint(std::vector& allowed); + + /** + * Virtual destructor. + */ + virtual ~ValuesConstraint() {} + + /** + * Returns a description of the Constraint. + */ + virtual std::string description() const; + + /** + * Returns the short ID for the Constraint. + */ + virtual std::string shortID() const; + + /** + * The method used to verify that the value parsed from the command + * line meets the constraint. + * \param value - The value that will be checked. + */ + virtual bool check(const T& value) const; + + protected: + + /** + * The list of valid values. + */ + std::vector _allowed; + + /** + * The string used to describe the allowed values of this constraint. + */ + std::string _typeDesc; + +}; + +template +ValuesConstraint::ValuesConstraint(std::vector& allowed) +: _allowed(allowed), + _typeDesc("") +{ + for ( unsigned int i = 0; i < _allowed.size(); i++ ) + { + +#if defined(HAVE_SSTREAM) + std::ostringstream os; +#elif defined(HAVE_STRSTREAM) + std::ostrstream os; +#else +#error "Need a stringstream (sstream or strstream) to compile!" +#endif + + os << _allowed[i]; + + std::string temp( os.str() ); + + if ( i > 0 ) + _typeDesc += "|"; + _typeDesc += temp; + } +} + +template +bool ValuesConstraint::check( const T& val ) const +{ + if ( std::find(_allowed.begin(),_allowed.end(),val) == _allowed.end() ) + return false; + else + return true; +} + +template +std::string ValuesConstraint::shortID() const +{ + return _typeDesc; +} + +template +std::string ValuesConstraint::description() const +{ + return _typeDesc; +} + + +} //namespace TCLAP +#endif + diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/VersionVisitor.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/VersionVisitor.h new file mode 100644 index 0000000000000000000000000000000000000000..3ef8b584e73fdead14edbd053c25a227430480fa --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/VersionVisitor.h @@ -0,0 +1,81 @@ +// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- + +/****************************************************************************** + * + * file: VersionVisitor.h + * + * Copyright (c) 2003, Michael E. Smoot . + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + + +#ifndef TCLAP_VERSION_VISITOR_H +#define TCLAP_VERSION_VISITOR_H + +#include +#include +#include + +namespace TCLAP { + +/** + * A Visitor that will call the version method of the given CmdLineOutput + * for the specified CmdLine object and then exit. + */ +class VersionVisitor: public Visitor +{ + private: + /** + * Prevent accidental copying + */ + VersionVisitor(const VersionVisitor& rhs); + VersionVisitor& operator=(const VersionVisitor& rhs); + + protected: + + /** + * The CmdLine of interest. + */ + CmdLineInterface* _cmd; + + /** + * The output object. + */ + CmdLineOutput** _out; + + public: + + /** + * Constructor. + * \param cmd - The CmdLine the output is generated for. + * \param out - The type of output. + */ + VersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out ) + : Visitor(), _cmd( cmd ), _out( out ) { } + + /** + * Calls the version method of the output object using the + * specified CmdLine. + */ + void visit() { + (*_out)->version(*_cmd); + throw ExitException(0); + } + +}; + +} + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/Visitor.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/Visitor.h new file mode 100644 index 0000000000000000000000000000000000000000..393320a3e0babb5e50c4e657eaef53f070c9d3a3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/Visitor.h @@ -0,0 +1,53 @@ + +/****************************************************************************** + * + * file: Visitor.h + * + * Copyright (c) 2003, Michael E. Smoot . + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + + +#ifndef TCLAP_VISITOR_H +#define TCLAP_VISITOR_H + +namespace TCLAP { + +/** + * A base class that defines the interface for visitors. + */ +class Visitor +{ + public: + + /** + * Constructor. Does nothing. + */ + Visitor() { } + + /** + * Destructor. Does nothing. + */ + virtual ~Visitor() { } + + /** + * Does nothing. Should be overridden by child. + */ + virtual void visit() { } +}; + +} + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/XorHandler.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/XorHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..64fcffce1a99787ac9a7f9ba433973ca0902b696 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/XorHandler.h @@ -0,0 +1,166 @@ + +/****************************************************************************** + * + * file: XorHandler.h + * + * Copyright (c) 2003, Michael E. Smoot . + * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_XORHANDLER_H +#define TCLAP_XORHANDLER_H + +#include +#include +#include +#include +#include + +namespace TCLAP { + +/** + * This class handles lists of Arg's that are to be XOR'd on the command + * line. This is used by CmdLine and you shouldn't ever use it. + */ +class XorHandler +{ + protected: + + /** + * The list of of lists of Arg's to be or'd together. + */ + std::vector< std::vector > _orList; + + public: + + /** + * Constructor. Does nothing. + */ + XorHandler( ) : _orList(std::vector< std::vector >()) {} + + /** + * Add a list of Arg*'s that will be xor'd together. + * \param ors - list of Arg* that will be xor'd. + */ + void add( std::vector& ors ); + + /** + * Checks whether the specified Arg is in one of the xor lists and + * if it does match one, returns the size of the xor list that the + * Arg matched. If the Arg matches, then it also sets the rest of + * the Arg's in the list. You shouldn't use this. + * \param a - The Arg to be checked. + */ + int check( const Arg* a ); + + /** + * Returns the XOR specific short usage. + */ + std::string shortUsage(); + + /** + * Prints the XOR specific long usage. + * \param os - Stream to print to. + */ + void printLongUsage(std::ostream& os); + + /** + * Simply checks whether the Arg is contained in one of the arg + * lists. + * \param a - The Arg to be checked. + */ + bool contains( const Arg* a ); + + std::vector< std::vector >& getXorList(); + +}; + + +////////////////////////////////////////////////////////////////////// +//BEGIN XOR.cpp +////////////////////////////////////////////////////////////////////// +inline void XorHandler::add( std::vector& ors ) +{ + _orList.push_back( ors ); +} + +inline int XorHandler::check( const Arg* a ) +{ + // iterate over each XOR list + for ( int i = 0; static_cast(i) < _orList.size(); i++ ) + { + // if the XOR list contains the arg.. + ArgVectorIterator ait = std::find( _orList[i].begin(), + _orList[i].end(), a ); + if ( ait != _orList[i].end() ) + { + // first check to see if a mutually exclusive switch + // has not already been set + for ( ArgVectorIterator it = _orList[i].begin(); + it != _orList[i].end(); + it++ ) + if ( a != (*it) && (*it)->isSet() ) + throw(CmdLineParseException( + "Mutually exclusive argument already set!", + (*it)->toString())); + + // go through and set each arg that is not a + for ( ArgVectorIterator it = _orList[i].begin(); + it != _orList[i].end(); + it++ ) + if ( a != (*it) ) + (*it)->xorSet(); + + // return the number of required args that have now been set + if ( (*ait)->allowMore() ) + return 0; + else + return static_cast(_orList[i].size()); + } + } + + if ( a->isRequired() ) + return 1; + else + return 0; +} + +inline bool XorHandler::contains( const Arg* a ) +{ + for ( int i = 0; static_cast(i) < _orList.size(); i++ ) + for ( ArgVectorIterator it = _orList[i].begin(); + it != _orList[i].end(); + it++ ) + if ( a == (*it) ) + return true; + + return false; +} + +inline std::vector< std::vector >& XorHandler::getXorList() +{ + return _orList; +} + + + +////////////////////////////////////////////////////////////////////// +//END XOR.cpp +////////////////////////////////////////////////////////////////////// + +} //namespace TCLAP + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ZshCompletionOutput.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ZshCompletionOutput.h new file mode 100644 index 0000000000000000000000000000000000000000..acf655bf7febb31fb37fbddef78bbbdff7869766 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/ZshCompletionOutput.h @@ -0,0 +1,335 @@ +// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- + +/****************************************************************************** + * + * file: ZshCompletionOutput.h + * + * Copyright (c) 2006, Oliver Kiddle + * Copyright (c) 2017 Google Inc. + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_ZSHCOMPLETIONOUTPUT_H +#define TCLAP_ZSHCOMPLETIONOUTPUT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace TCLAP { + +/** + * A class that generates a Zsh completion function as output from the usage() + * method for the given CmdLine and its Args. + */ +class ZshCompletionOutput : public CmdLineOutput +{ + + public: + + ZshCompletionOutput(); + + /** + * Prints the usage to stdout. Can be overridden to + * produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void usage(CmdLineInterface& c); + + /** + * Prints the version to stdout. Can be overridden + * to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + */ + virtual void version(CmdLineInterface& c); + + /** + * Prints (to stderr) an error message, short usage + * Can be overridden to produce alternative behavior. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. + */ + virtual void failure(CmdLineInterface& c, + ArgException& e ); + + protected: + + void basename( std::string& s ); + void quoteSpecialChars( std::string& s ); + + std::string getMutexList( CmdLineInterface& _cmd, Arg* a ); + void printOption( Arg* it, std::string mutex ); + void printArg( Arg* it ); + + std::map common; + char theDelimiter; +}; + +ZshCompletionOutput::ZshCompletionOutput() +: common(std::map()), + theDelimiter('=') +{ + common["host"] = "_hosts"; + common["hostname"] = "_hosts"; + common["file"] = "_files"; + common["filename"] = "_files"; + common["user"] = "_users"; + common["username"] = "_users"; + common["directory"] = "_directories"; + common["path"] = "_directories"; + common["url"] = "_urls"; +} + +inline void ZshCompletionOutput::version(CmdLineInterface& _cmd) +{ + std::cout << _cmd.getVersion() << std::endl; +} + +inline void ZshCompletionOutput::usage(CmdLineInterface& _cmd ) +{ + std::list argList = _cmd.getArgList(); + std::string progName = _cmd.getProgramName(); + std::string xversion = _cmd.getVersion(); + theDelimiter = _cmd.getDelimiter(); + basename(progName); + + std::cout << "#compdef " << progName << std::endl << std::endl << + "# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl << + "_arguments -s -S"; + + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) + { + if ( (*it)->shortID().at(0) == '<' ) + printArg((*it)); + else if ( (*it)->getFlag() != "-" ) + printOption((*it), getMutexList(_cmd, *it)); + } + + std::cout << std::endl; +} + +inline void ZshCompletionOutput::failure( CmdLineInterface& _cmd, + ArgException& e ) +{ + static_cast(_cmd); // unused + std::cout << e.what() << std::endl; +} + +inline void ZshCompletionOutput::quoteSpecialChars( std::string& s ) +{ + size_t idx = s.find_last_of(':'); + while ( idx != std::string::npos ) + { + s.insert(idx, 1, '\\'); + idx = s.find_last_of(':', idx); + } + idx = s.find_last_of('\''); + while ( idx != std::string::npos ) + { + s.insert(idx, "'\\'"); + if (idx == 0) + idx = std::string::npos; + else + idx = s.find_last_of('\'', --idx); + } +} + +inline void ZshCompletionOutput::basename( std::string& s ) +{ + size_t p = s.find_last_of('/'); + if ( p != std::string::npos ) + { + s.erase(0, p + 1); + } +} + +inline void ZshCompletionOutput::printArg(Arg* a) +{ + static int count = 1; + + std::cout << " \\" << std::endl << " '"; + if ( a->acceptsMultipleValues() ) + std::cout << '*'; + else + std::cout << count++; + std::cout << ':'; + if ( !a->isRequired() ) + std::cout << ':'; + + std::cout << a->getName() << ':'; + std::map::iterator compArg = common.find(a->getName()); + if ( compArg != common.end() ) + { + std::cout << compArg->second; + } + else + { + std::cout << "_guard \"^-*\" " << a->getName(); + } + std::cout << '\''; +} + +inline void ZshCompletionOutput::printOption(Arg* a, std::string mutex) +{ + std::string flag = a->flagStartChar() + a->getFlag(); + std::string name = a->nameStartString() + a->getName(); + std::string desc = a->getDescription(); + + // remove full stop and capitalization from description as + // this is the convention for zsh function + if (!desc.compare(0, 12, "(required) ")) + { + desc.erase(0, 12); + } + if (!desc.compare(0, 15, "(OR required) ")) + { + desc.erase(0, 15); + } + size_t len = desc.length(); + if (len && desc.at(--len) == '.') + { + desc.erase(len); + } + if (len) + { + desc.replace(0, 1, 1, tolower(desc.at(0))); + } + + std::cout << " \\" << std::endl << " '" << mutex; + + if ( a->getFlag().empty() ) + { + std::cout << name; + } + else + { + std::cout << "'{" << flag << ',' << name << "}'"; + } + if ( theDelimiter == '=' && a->isValueRequired() ) + std::cout << "=-"; + quoteSpecialChars(desc); + std::cout << '[' << desc << ']'; + + if ( a->isValueRequired() ) + { + std::string arg = a->shortID(); + // Example arg: "[-A ] ... " + size_t pos = arg.rfind(" ... "); + if (pos != std::string::npos) { + arg.erase(pos); + } + + arg.erase(0, arg.find_last_of(theDelimiter) + 1); + if ( arg.at(arg.length()-1) == ']' ) + arg.erase(arg.length()-1); + if ( arg.at(arg.length()-1) == ']' ) + { + arg.erase(arg.length()-1); + } + if ( arg.at(0) == '<' ) + { + arg.erase(arg.length()-1); + arg.erase(0, 1); + } + size_t p = arg.find('|'); + if ( p != std::string::npos ) + { + do + { + arg.replace(p, 1, 1, ' '); + } + while ( (p = arg.find_first_of('|', p)) != std::string::npos ); + quoteSpecialChars(arg); + std::cout << ": :(" << arg << ')'; + } + else + { + std::cout << ':' << arg; + std::map::iterator compArg = common.find(arg); + if ( compArg != common.end() ) + { + std::cout << ':' << compArg->second; + } + } + } + + std::cout << '\''; +} + +inline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Arg* a) +{ + XorHandler xorHandler = _cmd.getXorHandler(); + std::vector< std::vector > xorList = xorHandler.getXorList(); + + if (a->getName() == "help" || a->getName() == "version") + { + return "(-)"; + } + + ostringstream list; + if ( a->acceptsMultipleValues() ) + { + list << '*'; + } + + for ( int i = 0; static_cast(i) < xorList.size(); i++ ) + { + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); + it++) + if ( a == (*it) ) + { + list << '('; + for ( ArgVectorIterator iu = xorList[i].begin(); + iu != xorList[i].end(); + iu++ ) + { + bool notCur = (*iu) != a; + bool hasFlag = !(*iu)->getFlag().empty(); + if ( iu != xorList[i].begin() && (notCur || hasFlag) ) + list << ' '; + if (hasFlag) + list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' '; + if ( notCur || hasFlag ) + list << (*iu)->nameStartString() << (*iu)->getName(); + } + list << ')'; + return list.str(); + } + } + + // wasn't found in xor list + if (!a->getFlag().empty()) { + list << "(" << a->flagStartChar() << a->getFlag() << ' ' << + a->nameStartString() << a->getName() << ')'; + } + + return list.str(); +} + +} //namespace TCLAP +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/sstream.h b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/sstream.h new file mode 100644 index 0000000000000000000000000000000000000000..0118b76b1165ccb5c2152a1cb1736c43639ce36a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/deps/tclap-1.2.2/tclap/sstream.h @@ -0,0 +1,50 @@ +// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- + +/****************************************************************************** + * + * file: sstream.h + * + * Copyright (c) 2003, Michael E. Smoot . + * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno . + * Copyright (c) 2017 Google Inc. + * All rights reserved. + * + * See the file COPYING in the top directory of this distribution for + * more information. + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef TCLAP_SSTREAM_H +#define TCLAP_SSTREAM_H + +#if !defined(HAVE_STRSTREAM) +// Assume sstream is available if strstream is not specified +// (https://sourceforge.net/p/tclap/bugs/23/) +#define HAVE_SSTREAM +#endif + +#if defined(HAVE_SSTREAM) +#include +namespace TCLAP { + typedef std::istringstream istringstream; + typedef std::ostringstream ostringstream; +} +#elif defined(HAVE_STRSTREAM) +#include +namespace TCLAP { + typedef std::istrstream istringstream; + typedef std::ostrstream ostringstream; +} +#else +#error "Need a stringstream (sstream or strstream) to compile!" +#endif + +#endif // TCLAP_SSTREAM_H diff --git a/Packages/SwiftyOpenCC/OpenCC/doc/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/doc/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..c16e2892feaaaa3ddcf4419aec5dfdcf098b4613 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/doc/CMakeLists.txt @@ -0,0 +1,40 @@ +if(BUILD_DOCUMENTATION) + find_package(Doxygen) + if (NOT DOXYGEN_FOUND) + message( + FATAL_ERROR + "Doxygen is needed to build the documentation. Please install it correctly" + ) + endif() + + configure_file( + opencc.doxy.in + opencc.doxy + @ONLY + IMMEDIATE + ) + + add_custom_target( + apidoc + ALL + COMMENT + "Building API Documentation" + COMMAND + doxygen ${PROJECT_BINARY_DIR}/doc/opencc.doxy + SOURCES + ${PROJECT_BINARY_DIR}/doc/opencc.doxy + ) + + install( + DIRECTORY + ${CMAKE_BINARY_DIR}/doc/html + DESTINATION + ${DIR_SHARE_OPENCC}/doc + ) + + set_directory_properties( + PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES + "${CMAKE_BINARY_DIR}/doc/html" + ) +endif() diff --git a/Packages/SwiftyOpenCC/OpenCC/doc/README.md b/Packages/SwiftyOpenCC/OpenCC/doc/README.md new file mode 100644 index 0000000000000000000000000000000000000000..af80640ab544a3f2211198315951eb5aaa102422 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/doc/README.md @@ -0,0 +1,3 @@ +# Document + +http://byvoid.github.io/OpenCC/ diff --git a/Packages/SwiftyOpenCC/OpenCC/doc/opencc.doxy.in b/Packages/SwiftyOpenCC/OpenCC/doc/opencc.doxy.in new file mode 100644 index 0000000000000000000000000000000000000000..a93862d7f4fb034bd03784327ac738671b32d7d1 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/doc/opencc.doxy.in @@ -0,0 +1,1841 @@ +# Doxyfile 1.8.3.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "Open Chinese Convert" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = "@OPENCC_VERSION@" + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "A project for conversion between Traditional and Simplified Chinese" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 2 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = NO + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = NO + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @CMAKE_SOURCE_DIR@/src @CMAKE_SOURCE_DIR@/data @CMAKE_SOURCE_DIR@/README.md @CMAKE_SOURCE_DIR@/node/demo.js + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c *.cpp *.h *.hpp + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = @CMAKE_SOURCE_DIR@ + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page (index.html). +# This can be useful if you have a project on for instance GitHub and want reuse +# the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = README.md + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +#
    +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search engine +# library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/Packages/SwiftyOpenCC/OpenCC/node/configs.gypi b/Packages/SwiftyOpenCC/OpenCC/node/configs.gypi new file mode 100644 index 0000000000000000000000000000000000000000..796107621f5fab3dc69f10e47fe42119d665d1a5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/node/configs.gypi @@ -0,0 +1,25 @@ +{ + "targets": [{ + "target_name": "configs", + "type": "none", + "copies": [{ + "destination": "<(PRODUCT_DIR)", + "files": [ + "../data/config/hk2s.json", + "../data/config/hk2t.json", + "../data/config/jp2t.json", + "../data/config/s2hk.json", + "../data/config/s2t.json", + "../data/config/s2tw.json", + "../data/config/s2twp.json", + "../data/config/t2hk.json", + "../data/config/t2jp.json", + "../data/config/t2s.json", + "../data/config/t2tw.json", + "../data/config/tw2s.json", + "../data/config/tw2sp.json", + "../data/config/tw2t.json", + ] + }] + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/node/demo.js b/Packages/SwiftyOpenCC/OpenCC/node/demo.js new file mode 100644 index 0000000000000000000000000000000000000000..af099eb8d78e35f69c8baad47ba5e2af4851eda4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/node/demo.js @@ -0,0 +1,48 @@ +/** + * @file + * Example of Node.js API. + * + * @license + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @example node/demo.js + * This is an example of how to use the Node.js API. + */ + +// In your project you should replace './opencc' with 'opencc' +const OpenCC = require('./opencc'); + +console.log('OpenCC version', OpenCC.version); + +// Load the default Simplified to Traditional config +const opencc = new OpenCC('s2t.json'); + +// Sync API +const converted = opencc.convertSync("汉字"); +console.log(converted); + +// Async API +opencc.convert("汉字", (err, converted) => { + console.log(err, converted); +}); + +// Async API with Promise +opencc.convertPromise("汉字").then(converted => { + console.log(converted); +}); diff --git a/Packages/SwiftyOpenCC/OpenCC/node/dict.js b/Packages/SwiftyOpenCC/OpenCC/node/dict.js new file mode 100644 index 0000000000000000000000000000000000000000..ef29d7ca332c2f46d4422643ec31a75a2d43fcb6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/node/dict.js @@ -0,0 +1,6 @@ +const OpenCC = require('./opencc'); + +const input = process.argv[2]; +const output = process.argv[3]; + +OpenCC.generateDict(input, output, "text", "ocd2"); diff --git a/Packages/SwiftyOpenCC/OpenCC/node/dicts.gypi b/Packages/SwiftyOpenCC/OpenCC/node/dicts.gypi new file mode 100644 index 0000000000000000000000000000000000000000..99faed868d238b891cfec1dffaea1f1de6b8a247 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/node/dicts.gypi @@ -0,0 +1,182 @@ +{ + "targets": [{ + "target_name": "dicts", + "type": "none", + "variables": { + "cmd": "<(module_root_dir)/node/dict.js", + "dict_merge": "<(module_root_dir)/data/scripts/merge.py", + "dict_reverse": "<(module_root_dir)/data/scripts/reverse.py", + "input_prefix": "<(module_root_dir)/data/dictionary/", + "output_prefix": "<(PRODUCT_DIR)/" + }, + "actions": [{ + "action_name": "STCharacters", + "variables": { + "input": "<(input_prefix)STCharacters.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)STCharacters.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "STPhrases", + "variables": { + "input": "<(input_prefix)STPhrases.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)STPhrases.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "TSCharacters", + "variables": { + "input": "<(input_prefix)TSCharacters.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)TSCharacters.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "TSPhrases", + "variables": { + "input": "<(input_prefix)TSPhrases.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)TSPhrases.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "TWVariants", + "variables": { + "input": "<(input_prefix)TWVariants.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)TWVariants.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "TWVariantsRevPhrases", + "variables": { + "input": "<(input_prefix)TWVariantsRevPhrases.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)TWVariantsRevPhrases.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "JPVariants", + "variables": { + "input": "<(input_prefix)JPVariants.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)JPVariants.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "TWPhrases.txt", + "inputs": ["<(cmd)"], + "outputs": ["<(output_prefix)TWPhrases.txt"], + "action": ["python", "<(dict_merge)", "<(input_prefix)TWPhrasesIT.txt", "<(input_prefix)TWPhrasesName.txt", "<(input_prefix)TWPhrasesOther.txt", "<@(_outputs)"] + }, { + "action_name": "TWVariantsRev.txt", + "variables": { + "input": "<(input_prefix)TWVariants.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)TWVariantsRev.txt"], + "action": ["python", "<(dict_reverse)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "TWPhrasesRev.txt", + "variables": { + "input": "<(output_prefix)TWPhrases.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)TWPhrasesRev.txt"], + "action": ["python", "<(dict_reverse)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "TWPhrases", + "variables": { + "input": "<(output_prefix)TWPhrases.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)TWPhrases.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "TWVariantsRev", + "variables": { + "input": "<(output_prefix)TWVariantsRev.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)TWVariantsRev.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "TWPhrasesRev", + "variables": { + "input": "<(output_prefix)TWPhrasesRev.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)TWPhrasesRev.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "HKVariants", + "variables": { + "input": "<(input_prefix)HKVariants.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)HKVariants.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "HKVariantsRevPhrases", + "variables": { + "input": "<(input_prefix)HKVariantsRevPhrases.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)HKVariantsRevPhrases.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "HKVariantsRev.txt", + "variables": { + "input": "<(input_prefix)HKVariants.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)HKVariantsRev.txt"], + "action": ["python", "<(dict_reverse)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "HKVariantsRev", + "variables": { + "input": "<(output_prefix)HKVariantsRev.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)HKVariantsRev.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "JPVariantsRev.txt", + "variables": { + "input": "<(input_prefix)JPVariants.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)JPVariantsRev.txt"], + "action": ["python", "<(dict_reverse)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "JPVariantsRev", + "variables": { + "input": "<(output_prefix)JPVariantsRev.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)JPVariantsRev.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "JPShinjitaiCharacters", + "variables": { + "input": "<(input_prefix)JPShinjitaiCharacters.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)JPShinjitaiCharacters.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }, { + "action_name": "JPShinjitaiPhrases", + "variables": { + "input": "<(input_prefix)JPShinjitaiPhrases.txt", + }, + "inputs": ["<(input)"], + "outputs": ["<(output_prefix)JPShinjitaiPhrases.ocd2"], + "action": ["node", "<(cmd)", "<(input)", "<@(_outputs)"] + }], + "dependencies": [ + "opencc" + ] + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/node/global.gypi b/Packages/SwiftyOpenCC/OpenCC/node/global.gypi new file mode 100644 index 0000000000000000000000000000000000000000..8ac402e32c7d43e598629498e1e072c605d34558 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/node/global.gypi @@ -0,0 +1,30 @@ +{ + "variables": { + "opencc_version": "1.1.2" + }, + "target_defaults": { + "defines": [ + "VERSION=\"<(opencc_version)\"" + ], + "conditions": [ + ["OS=='linux'", { + "cflags": [ + "-std=c++0x" + ], + "cflags!": ["-fno-exceptions"], + "cflags_cc!": ["-fno-exceptions"], + }], + ["OS=='mac'", { + 'xcode_settings': { + 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', + 'MACOSX_DEPLOYMENT_TARGET': '10.7', + 'OTHER_CPLUSPLUSFLAGS': ["-std=c++11", "-stdlib=libc++"], + 'OTHER_LDFLAGS': ["-stdlib=libc++"] + } + }], + ["OS=='win'", { + "defines": ["Opencc_BUILT_AS_STATIC"] + }] + ] + } +} diff --git a/Packages/SwiftyOpenCC/OpenCC/node/marisa.cc b/Packages/SwiftyOpenCC/OpenCC/node/marisa.cc new file mode 100644 index 0000000000000000000000000000000000000000..85fbe9ee23ace2717cdfb35059776637f603fe9f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/node/marisa.cc @@ -0,0 +1,14 @@ +// For faster build +// Keep include order for VS compatibility. +#include "marisa/trie.cc" +// 1 +#include "marisa/agent.cc" +// 2 +#include "marisa/grimoire/io/reader.cc" +#include "marisa/grimoire/io/writer.cc" +// 3 +#include "marisa/grimoire/io/mapper.cc" +#include "marisa/grimoire/trie/louds-trie.cc" +#include "marisa/grimoire/trie/tail.cc" +#include "marisa/grimoire/vector/bit-vector.cc" +#include "marisa/keyset.cc" diff --git a/Packages/SwiftyOpenCC/OpenCC/node/node_opencc.gypi b/Packages/SwiftyOpenCC/OpenCC/node/node_opencc.gypi new file mode 100644 index 0000000000000000000000000000000000000000..ec113e9d3efb14e95b5063668d5de6bcbb3ecb17 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/node/node_opencc.gypi @@ -0,0 +1,16 @@ +{ + "targets": [{ + "target_name": "opencc", + "sources": [ + "../node/marisa.cc", + "../node/opencc.cc", + ], + "include_dirs": [ + "../src", + "../deps/rapidjson-1.1.0", + "../deps/marisa-0.2.6/include", + "../deps/marisa-0.2.6/lib", + " +#include + +#include "Config.hpp" +#include "Converter.hpp" +#include "DictConverter.hpp" + +// For faster build +#include "Config.cpp" +#include "Conversion.cpp" +#include "ConversionChain.cpp" +#include "Converter.cpp" +#include "Dict.cpp" +#include "DictConverter.cpp" +#include "DictEntry.cpp" +#include "DictGroup.cpp" +#include "Lexicon.cpp" +#include "MarisaDict.cpp" +#include "MaxMatchSegmentation.cpp" +#include "Segmentation.cpp" +#include "SerializedValues.cpp" +#include "TextDict.cpp" +#include "UTF8Util.cpp" + +using namespace opencc; + +std::string ToUtf8String(const v8::Local& val) { + Nan::Utf8String utf8(val); + return std::string(*utf8); +} + +class OpenccBinding : public Nan::ObjectWrap { + struct ConvertRequest { + OpenccBinding* instance; + std::string input; + std::string output; + Nan::Callback* callback; + Optional ex; + + ConvertRequest() + : instance(nullptr), ex(Optional::Null()) {} + }; + + Config config_; + const ConverterPtr converter_; + +public: + explicit OpenccBinding(const std::string configFileName) + : config_(), converter_(config_.NewFromFile(configFileName)) {} + + virtual ~OpenccBinding() {} + + std::string Convert(const std::string& input) { + return converter_->Convert(input); + } + + static NAN_METHOD(Version) { + info.GetReturnValue().Set(Nan::New(VERSION).ToLocalChecked()); + } + + static NAN_METHOD(New) { + OpenccBinding* instance; + + try { + if (info.Length() >= 1 && info[0]->IsString()) { + const std::string configFile = ToUtf8String(info[0]); + instance = new OpenccBinding(configFile); + } else { + instance = new OpenccBinding("s2t.json"); + } + } catch (opencc::Exception& e) { + Nan::ThrowError(e.what()); + return; + } + + instance->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } + + static NAN_METHOD(Convert) { + if (info.Length() < 2 || !info[0]->IsString() || !info[1]->IsFunction()) { + Nan::ThrowTypeError("Wrong arguments"); + return; + } + + ConvertRequest* conv_data = new ConvertRequest; + conv_data->instance = Nan::ObjectWrap::Unwrap(info.This()); + conv_data->input = ToUtf8String(info[0]); + conv_data->callback = new Nan::Callback(info[1].As()); + conv_data->ex = Optional::Null(); + uv_work_t* req = new uv_work_t; + req->data = conv_data; + uv_queue_work(uv_default_loop(), req, DoConvert, + (uv_after_work_cb)AfterConvert); + + return; + } + + static void DoConvert(uv_work_t* req) { + ConvertRequest* conv_data = static_cast(req->data); + OpenccBinding* instance = conv_data->instance; + try { + conv_data->output = instance->Convert(conv_data->input); + } catch (opencc::Exception& e) { + conv_data->ex = Optional(e); + } + } + + static void AfterConvert(uv_work_t* req) { + Nan::HandleScope scope; + ConvertRequest* conv_data = static_cast(req->data); + v8::Local err = Nan::Undefined(); + v8::Local converted = + Nan::New(conv_data->output.c_str()).ToLocalChecked(); + if (!conv_data->ex.IsNull()) { + err = Nan::New(conv_data->ex.Get().what()).ToLocalChecked(); + } + const unsigned argc = 2; + v8::Local argv[argc] = {err, converted}; + Nan::AsyncResource resource("opencc:convert-async-cb"); + conv_data->callback->Call(argc, argv, &resource); + delete conv_data; + delete req; + } + + static NAN_METHOD(ConvertSync) { + if (info.Length() < 1 || !info[0]->IsString()) { + Nan::ThrowTypeError("Wrong arguments"); + return; + } + + OpenccBinding* instance = + Nan::ObjectWrap::Unwrap(info.This()); + + const std::string input = ToUtf8String(info[0]); + std::string output; + try { + output = instance->Convert(input); + } catch (opencc::Exception& e) { + Nan::ThrowError(e.what()); + return; + } + + v8::Local converted = Nan::New(output.c_str()).ToLocalChecked(); + info.GetReturnValue().Set(converted); + } + + static NAN_METHOD(GenerateDict) { + if (info.Length() < 4 || !info[0]->IsString() || !info[1]->IsString() || + !info[2]->IsString() || !info[3]->IsString()) { + Nan::ThrowTypeError("Wrong arguments"); + return; + } + const std::string inputFileName = ToUtf8String(info[0]); + const std::string outputFileName = ToUtf8String(info[1]); + const std::string formatFrom = ToUtf8String(info[2]); + const std::string formatTo = ToUtf8String(info[3]); + try { + opencc::ConvertDictionary(inputFileName, outputFileName, formatFrom, + formatTo); + } catch (opencc::Exception& e) { + Nan::ThrowError(e.what()); + } + } + + static NAN_MODULE_INIT(Init) { + // Prepare constructor template + v8::Local tpl = + Nan::New(OpenccBinding::New); + tpl->SetClassName(Nan::New("Opencc").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + // Methods + Nan::SetMethod(tpl, "version", Version); + Nan::SetMethod(tpl, "generateDict", GenerateDict); + // Prototype + Nan::SetPrototypeMethod(tpl, "convert", Convert); + Nan::SetPrototypeMethod(tpl, "convertSync", ConvertSync); + // Constructor + v8::Local cons = Nan::GetFunction(tpl).ToLocalChecked(); + Nan::Set(target, Nan::New("Opencc").ToLocalChecked(), cons); + } +}; + +NODE_MODULE(binding, OpenccBinding::Init); diff --git a/Packages/SwiftyOpenCC/OpenCC/node/opencc.d.ts b/Packages/SwiftyOpenCC/OpenCC/node/opencc.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..4349f844c33abcf4cfe03ea9b74d1bb5badf4f5a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/node/opencc.d.ts @@ -0,0 +1,9 @@ +declare class OpenCC { + constructor(config: string); + version(): string; + generateDict(inputFileName: string, outputFileName: string, formatFrom: string, formatTo: string): void; + convert(input: string, callback: (err: string, convertedText: string) => void): string; + convertSync(input: string): string; + convertPromise(input: string): Promise; +} +export { OpenCC }; diff --git a/Packages/SwiftyOpenCC/OpenCC/node/opencc.js b/Packages/SwiftyOpenCC/OpenCC/node/opencc.js new file mode 100644 index 0000000000000000000000000000000000000000..f96bfcbfd48d2fbd327817e14ae6778d3bb0de57 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/node/opencc.js @@ -0,0 +1,130 @@ +/** + * @file + * Node.js API. + * + * @license + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @defgroup node_api Node.js API + * + * Node.js language binding + */ + +const path = require('path'); +const bindingPath = require('node-pre-gyp').find(require.resolve('../package.json')); +const binding = require(bindingPath); + +const assetsPath = path.dirname(bindingPath); +const getConfigPath = function (config) { + let configPath = config; + if (config[0] !== '/' && config[1] !== ':') { + // Resolve relative path + configPath = path.join(assetsPath, config); + } + return configPath; +}; + +/** + * OpenCC Node.js API + * + * @class OpenCC + * @constructor + * @ingroup node_api + */ +const OpenCC = module.exports = function (config) { + if (!config) { + config = 's2t.json'; + } + config = getConfigPath(config); + this.handler = new binding.Opencc(config); +}; + +// This is to support both CommonJS and ES module. +OpenCC.OpenCC = OpenCC; + +/** + * The version of OpenCC library. + * + * @fn OpenCC.version + * @memberof OpenCC + * @ingroup node_api + */ +OpenCC.version = binding.Opencc.version(); + +/** + * Generates dictionary from another format. + * + * @fn string generateDict(string inputFileName, string outputFileName, string formatFrom, string formatTo) + * @memberof OpenCC + * @param inputFileName Input dictionary filename. + * @param outputFileName Output dictionary filename. + * @param formatFrom Input dictionary format. + * @param formatTo Input dictionary format. + * @ingroup node_api + */ +OpenCC.generateDict = function (inputFileName, outputFileName, + formatFrom, formatTo) { + return binding.Opencc.generateDict(inputFileName, outputFileName, + formatFrom, formatTo); +} + +/** + * Converts input text. + * + * @fn void convert(string input, function callback) + * @memberof OpenCC + * @param input Input text. + * @param callback Callback function(err, convertedText). + * @ingroup node_api + */ +OpenCC.prototype.convert = function (input, callback) { + return this.handler.convert(input.toString(), callback); +}; + +/** + * Converts input text. + * + * @fn string convertSync(string input) + * @memberof OpenCC + * @param input Input text. + * @return Converted text. + * @ingroup node_api + */ +OpenCC.prototype.convertSync = function (input) { + return this.handler.convertSync(input.toString()); +}; + +/** + * Converts input text asynchronously and returns a Promise. + * + * @fn Promise convertPromise(string input) + * @memberof OpenCC + * @param input Input text. + * @return The Promise that will yield the converted text. + * @ingroup node_api + */ +OpenCC.prototype.convertPromise = function (input) { + const self = this; + return new Promise(function (resolve, reject) { + self.handler.convert(input.toString(), function (err, text) { + if (err) reject(err); + else resolve(text); + }); + }); +}; diff --git a/Packages/SwiftyOpenCC/OpenCC/node/test.js b/Packages/SwiftyOpenCC/OpenCC/node/test.js new file mode 100644 index 0000000000000000000000000000000000000000..70d644412693fd62bcb3c72dd5608e4e19bd469a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/node/test.js @@ -0,0 +1,88 @@ +const assert = require('assert'); +const fs = require('fs'); +const util = require('util'); + +const OpenCC = require('./opencc'); + +const configs = [ + 'hk2s', + 'hk2t', + 'jp2t', + 's2hk', + 's2t', + 's2tw', + 's2twp', + 't2hk', + 't2jp', + 't2s', + 'tw2s', + 'tw2sp', + 'tw2t', +]; + +const testSync = function (config, done) { + const inputName = 'test/testcases/' + config + '.in'; + const outputName = 'test/testcases/' + config + '.ans'; + const configName = config + '.json'; + const opencc = new OpenCC(configName); + const text = fs.readFileSync(inputName, 'utf-8'); + const converted = opencc.convertSync(text); + const answer = fs.readFileSync(outputName, 'utf-8'); + assert.equal(converted, answer); + done(); +}; + +const testAsync = function (config, done) { + const inputName = 'test/testcases/' + config + '.in'; + const outputName = 'test/testcases/' + config + '.ans'; + const configName = config + '.json'; + const opencc = new OpenCC(configName); + fs.readFile(inputName, 'utf-8', function (err, text) { + if (err) return done(err); + opencc.convert(text, function (err, converted) { + if (err) return done(err); + fs.readFile(outputName, 'utf-8', function (err, answer) { + if (err) return done(err); + assert.equal(converted, answer); + done(); + }); + }); + }); +}; + +async function testAsyncPromise(config) { + const inputName = 'test/testcases/' + config + '.in'; + const outputName = 'test/testcases/' + config + '.ans'; + const configName = config + '.json'; + const opencc = new OpenCC(configName); + + const text = await util.promisify(fs.readFile)(inputName, 'utf-8'); + const converted = await opencc.convertPromise(text); + const answer = await util.promisify(fs.readFile)(outputName, 'utf-8'); + + assert.equal(converted, answer); +}; + +describe('Sync API', function () { + configs.forEach(function (config) { + it(config, function (done) { + testSync(config, done); + }); + }); +}); + +describe('Async API', function () { + configs.forEach(function (config) { + it(config, function (done) { + testAsync(config, done); + }); + }); +}); + +describe('Async Promise API', function () { + configs.forEach(function (config) { + it(config, function (done) { + testAsyncPromise(config).then(done); + }); + }); +}); diff --git a/Packages/SwiftyOpenCC/OpenCC/node/ts-demo.ts b/Packages/SwiftyOpenCC/OpenCC/node/ts-demo.ts new file mode 100644 index 0000000000000000000000000000000000000000..7d9e03e110427a4ad5c2e1ee2529bc3b3b1c1b65 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/node/ts-demo.ts @@ -0,0 +1,31 @@ +/** + * @file + * Example of Node.js API. + * + * @license + * Open Chinese Convert + * + * Copyright 2010-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { OpenCC } from './opencc'; + +async function main() { + const converter: OpenCC = new OpenCC('s2t.json'); + const result: string = await converter.convertPromise('汉字'); + console.log(result); +} + +main(); diff --git a/Packages/SwiftyOpenCC/OpenCC/opencc.pc.in b/Packages/SwiftyOpenCC/OpenCC/opencc.pc.in new file mode 100644 index 0000000000000000000000000000000000000000..93ff260b17147b14d34af86fa64e31af0b2f283c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/opencc.pc.in @@ -0,0 +1,11 @@ +prefix=@DIR_PREFIX@ +exec_prefix=${prefix} +libdir=@DIR_LIBRARY@ +includedir=@DIR_INCLUDE@ + +Name: opencc +Description: Open Chinese Convert +Version: @OPENCC_VERSION@ +Requires: +Libs: -L${libdir} -lopencc +Cflags: -I${includedir}/opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/package-lock.json b/Packages/SwiftyOpenCC/OpenCC/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..9245fba775daef69f1b2880e75351e5e6e3afa74 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/package-lock.json @@ -0,0 +1,3261 @@ +{ + "name": "opencc", + "version": "1.1.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "1.1.1", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "nan": "^2.14.2", + "node-pre-gyp": "^0.14.0" + }, + "devDependencies": { + "mocha": "^8.3.0", + "node-pre-gyp-github": "^1.4.3" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@octokit/rest": { + "version": "15.18.3", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-15.18.3.tgz", + "integrity": "sha512-oHABAvvC83tPIuvUfWRaw9eLThFrCxBgywl+KvEwfTFjoCrMOfEaMh0r39+Ub/EEbV345GJiMzN+zPZ4kqOvbA==", + "dev": true, + "dependencies": { + "before-after-hook": "^1.1.0", + "btoa-lite": "^1.0.0", + "debug": "^3.1.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.0", + "lodash": "^4.17.4", + "node-fetch": "^2.1.1", + "universal-user-agent": "^2.0.0", + "url-template": "^2.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@octokit/rest/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@octokit/rest/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "node_modules/are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/before-after-hook": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.4.0.tgz", + "integrity": "sha512-l5r9ir56nda3qu14nAXIlyq1MmUSs0meCIaFAh8HwkFwP1F8eToOuS3ah2VAHHcY04jaYD7FpJC5JTXHYRbkzg==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/btoa-lite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", + "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", + "dev": true + }, + "node_modules/camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.1" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "dependencies": { + "agent-base": "4", + "debug": "3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/macos-release": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz", + "integrity": "sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "dev": true, + "dependencies": { + "mime-db": "1.43.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.0.tgz", + "integrity": "sha512-TQqyC89V1J/Vxx0DhJIXlq9gbbL9XFNdeLQ1+JsnZsVaSOV1z3tWfw0qZmQJGQRIfkvZcs7snQnZnOCKoldq1Q==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 10.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" + }, + "node_modules/nanoid": { + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/needle": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.1.tgz", + "integrity": "sha512-x/gi6ijr4B7fwl6WYL9FwlCvRQKGlUNvnceho8wxkwXqN8jvVmmmATTmZPRRG7b/yC1eode26C2HO9jl78Du9g==", + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "dev": true, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-pre-gyp": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz", + "integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==", + "dependencies": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/node-pre-gyp-github": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/node-pre-gyp-github/-/node-pre-gyp-github-1.4.3.tgz", + "integrity": "sha512-tnJ0iZgzIZnZl7VBgebPYdzOe98dxMnQeDs6+yX1WVdt6IiWu0l4EYes3IY7ZIokRbtJ4iJjqwgGIyQrdfDJSg==", + "dev": true, + "dependencies": { + "@octokit/rest": "^15.9.5", + "commander": "^2.17.0", + "mime-types": "^2.1.19" + }, + "bin": { + "node-pre-gyp-github": "bin/node-pre-gyp-github.js" + } + }, + "node_modules/node-pre-gyp-github/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + }, + "node_modules/npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "dependencies": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-name": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", + "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", + "dev": true, + "dependencies": { + "macos-release": "^2.2.0", + "windows-release": "^3.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dependencies": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/universal-user-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-2.1.0.tgz", + "integrity": "sha512-8itiX7G05Tu3mGDTdNY2fB4KJ8MgZLS54RdG6PkkfwMAavrXu1mV/lls/GABx9O3Rw4PnTtasxrvbMQoBYY92Q==", + "dev": true, + "dependencies": { + "os-name": "^3.0.0" + } + }, + "node_modules/url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/windows-release": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.0.tgz", + "integrity": "sha512-2HetyTg1Y+R+rUgrKeUEhAG/ZuOmTrI1NBb3ZyAGQMYmOJjBBPe4MTodghRkmLJZHwkuPi02anbeGP+Zf401LQ==", + "dev": true, + "dependencies": { + "execa": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/y18n": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@octokit/rest": { + "version": "15.18.3", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-15.18.3.tgz", + "integrity": "sha512-oHABAvvC83tPIuvUfWRaw9eLThFrCxBgywl+KvEwfTFjoCrMOfEaMh0r39+Ub/EEbV345GJiMzN+zPZ4kqOvbA==", + "dev": true, + "requires": { + "before-after-hook": "^1.1.0", + "btoa-lite": "^1.0.0", + "debug": "^3.1.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.0", + "lodash": "^4.17.4", + "node-fetch": "^2.1.1", + "universal-user-agent": "^2.0.0", + "url-template": "^2.0.8" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "before-after-hook": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.4.0.tgz", + "integrity": "sha512-l5r9ir56nda3qu14nAXIlyq1MmUSs0meCIaFAh8HwkFwP1F8eToOuS3ah2VAHHcY04jaYD7FpJC5JTXHYRbkzg==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "btoa-lite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", + "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", + "dev": true + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "requires": { + "minipass": "^2.6.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "macos-release": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz", + "integrity": "sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==", + "dev": true + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "dev": true, + "requires": { + "mime-db": "1.43.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.0.tgz", + "integrity": "sha512-TQqyC89V1J/Vxx0DhJIXlq9gbbL9XFNdeLQ1+JsnZsVaSOV1z3tWfw0qZmQJGQRIfkvZcs7snQnZnOCKoldq1Q==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" + }, + "nanoid": { + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", + "dev": true + }, + "needle": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.1.tgz", + "integrity": "sha512-x/gi6ijr4B7fwl6WYL9FwlCvRQKGlUNvnceho8wxkwXqN8jvVmmmATTmZPRRG7b/yC1eode26C2HO9jl78Du9g==", + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "dev": true + }, + "node-pre-gyp": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz", + "integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + } + }, + "node-pre-gyp-github": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/node-pre-gyp-github/-/node-pre-gyp-github-1.4.3.tgz", + "integrity": "sha512-tnJ0iZgzIZnZl7VBgebPYdzOe98dxMnQeDs6+yX1WVdt6IiWu0l4EYes3IY7ZIokRbtJ4iJjqwgGIyQrdfDJSg==", + "dev": true, + "requires": { + "@octokit/rest": "^15.9.5", + "commander": "^2.17.0", + "mime-types": "^2.1.19" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-name": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", + "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", + "dev": true, + "requires": { + "macos-release": "^2.2.0", + "windows-release": "^3.1.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "universal-user-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-2.1.0.tgz", + "integrity": "sha512-8itiX7G05Tu3mGDTdNY2fB4KJ8MgZLS54RdG6PkkfwMAavrXu1mV/lls/GABx9O3Rw4PnTtasxrvbMQoBYY92Q==", + "dev": true, + "requires": { + "os-name": "^3.0.0" + } + }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "windows-release": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.0.tgz", + "integrity": "sha512-2HetyTg1Y+R+rUgrKeUEhAG/ZuOmTrI1NBb3ZyAGQMYmOJjBBPe4MTodghRkmLJZHwkuPi02anbeGP+Zf401LQ==", + "dev": true, + "requires": { + "execa": "^1.0.0" + } + }, + "workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "y18n": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/Packages/SwiftyOpenCC/OpenCC/package.json b/Packages/SwiftyOpenCC/OpenCC/package.json new file mode 100644 index 0000000000000000000000000000000000000000..d12a1c470ee5544251c3bca09a1c6887013702cc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/package.json @@ -0,0 +1,47 @@ +{ + "name": "opencc", + "version": "1.1.2", + "description": "Conversion between Traditional and Simplified Chinese", + "author": "Carbo Kuo ", + "license": "Apache-2.0", + "main": "node/opencc.js", + "types": "node/opencc.d.ts", + "scripts": { + "test": "mocha -R spec node/test.js", + "deploy": "node-pre-gyp package && (node-pre-gyp-github publish --release || exit 0)", + "install": "node-pre-gyp install --fallback-to-build || node-pre-gyp rebuild" + }, + "engines": { + "node": ">= 8.0.0" + }, + "binary": { + "module_name": "opencc", + "module_path": "./build/Release/", + "host": "https://github.com/BYVoid/OpenCC/releases/download/", + "remote_path": "{version}" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/BYVoid/OpenCC.git" + }, + "bugs": { + "url": "https://github.com/BYVoid/OpenCC/issues" + }, + "homepage": "https://github.com/BYVoid/OpenCC#readme", + "keywords": [ + "opencc", + "Chinese", + "conversion", + "unicode", + "Simplified Chinese", + "Traditional Chinese" + ], + "devDependencies": { + "mocha": "^8.3.0", + "node-pre-gyp-github": "^1.4.3" + }, + "dependencies": { + "nan": "^2.14.2", + "node-pre-gyp": "^0.14.0" + } +} diff --git a/Packages/SwiftyOpenCC/OpenCC/python/.gitignore b/Packages/SwiftyOpenCC/OpenCC/python/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..a262cac70cfdfb9e44e9913d489ee378e9347b5f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/python/.gitignore @@ -0,0 +1,103 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/Packages/SwiftyOpenCC/OpenCC/python/opencc/.gitignore b/Packages/SwiftyOpenCC/OpenCC/python/opencc/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..8840e7698cd56d6f581d881a7a34b1f32e83e928 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/python/opencc/.gitignore @@ -0,0 +1,2 @@ +version.py +clib/ diff --git a/Packages/SwiftyOpenCC/OpenCC/python/opencc/__init__.py b/Packages/SwiftyOpenCC/OpenCC/python/opencc/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f77f80cf972836800199ac478fde54c7499c845c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/python/opencc/__init__.py @@ -0,0 +1,49 @@ +from __future__ import absolute_import, unicode_literals + +import os +import sys + +from opencc.clib import opencc_clib + +__all__ = ['OpenCC', 'CONFIGS', '__version__'] + +__version__ = opencc_clib.__version__ +_thisdir = os.path.dirname(os.path.abspath(__file__)) +_opencc_share_dir = os.path.join(_thisdir, 'clib', 'share', 'opencc') + +if sys.version_info.major == 2: + text_type = unicode # noqa +else: + text_type = str + +if os.path.isdir(_opencc_share_dir): + CONFIGS = [f for f in os.listdir(_opencc_share_dir) if f.endswith('.json')] +else: + CONFIGS = [] + + +def _append_path_to_env(name, path): + value = os.environ.get(name, '') + if path in value: # Path already exists + return + if value == '': + value = path + else: + value += ':' + path + os.environ[name] = value + + +class OpenCC(opencc_clib._OpenCC): + + def __init__(self, config='t2s'): + if not config.endswith('.json'): + config += '.json' + if not os.path.isfile(config): + config = os.path.join(_opencc_share_dir, config) + super(OpenCC, self).__init__(config) + self.config = config + + def convert(self, text): + if isinstance(text, text_type): + text = text.encode('utf-8') + return super(OpenCC, self).convert(text, len(text)) diff --git a/Packages/SwiftyOpenCC/OpenCC/python/tests/test_opencc.py b/Packages/SwiftyOpenCC/OpenCC/python/tests/test_opencc.py new file mode 100644 index 0000000000000000000000000000000000000000..8ca83b7ef68747c73241df38fd655466b2d6f8cb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/python/tests/test_opencc.py @@ -0,0 +1,41 @@ +from __future__ import unicode_literals + +import os +from glob import glob + +_this_dir = os.path.dirname(os.path.abspath(__file__)) +_opencc_rootdir = os.path.abspath(os.path.join(_this_dir, '..', '..')) +_test_assets_dir = os.path.join(_opencc_rootdir, 'test', 'testcases') + + +def test_import(): + import opencc # noqa + + +def test_init_delete_converter(): + import opencc + + for config in opencc.CONFIGS: + converter = opencc.OpenCC(config) + del converter + + +def test_conversion(): + import opencc + + for inpath in glob(os.path.join(_test_assets_dir, '*.in')): + pref = os.path.splitext(inpath)[0] + config = os.path.basename(pref) + converter = opencc.OpenCC(config) + anspath = '{}.{}'.format(pref, 'ans') + assert os.path.isfile(anspath) + + with open(inpath, 'rb') as f: + intexts = [l.strip().decode('utf-8') for l in f] + with open(anspath, 'rb') as f: + anstexts = [l.strip().decode('utf-8') for l in f] + assert len(intexts) == len(anstexts) + + for text, ans in zip(intexts, anstexts): + assert converter.convert(text) == ans, \ + 'Failed to convert {} for {} -> {}'.format(pref, text, ans) diff --git a/Packages/SwiftyOpenCC/OpenCC/release-pypi-linux.sh b/Packages/SwiftyOpenCC/OpenCC/release-pypi-linux.sh new file mode 100644 index 0000000000000000000000000000000000000000..c4b154238e1c04d0ff284eb08bd389c83723088f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/release-pypi-linux.sh @@ -0,0 +1,46 @@ +#!/bin/sh +set -e + +# Different to release-pypi-win.cmd and release-pypi-osx.sh, +# this script has to be ran from a clean dockerfile + +# Random note: The reason why this script is being ran from within a container +# is to ensure glibc compatibility. From what I've seen so far, it appears +# that having multiple glibc versions is a somewhat convoluted process +# and I don't trust myself to be able to manage them well. + +# Download dependenciess +export DEBIAN_FRONTEND=noninteractive +apt update +apt upgrade -y +apt install -y g++ make curl + +cd /opt/OpenCC + +# Download and init conda +MINICONDA_FILENAME=Miniconda3-latest-Linux-x86_64.sh +curl -L -o $MINICONDA_FILENAME \ + "https://repo.continuum.io/miniconda/$MINICONDA_FILENAME" +bash ${MINICONDA_FILENAME} -b -f -p $HOME/miniconda3 +export PATH=$HOME/miniconda3/bin:$PATH +eval "$(conda shell.bash hook)" + +for VERSION in 2.7 3.5 3.6 3.7 3.8; do + # Create and activate environment + conda create -y -n py$VERSION python=$VERSION + conda activate py$VERSION + + # Build and package + pip install --no-cache-dir setuptools wheel cmake + python setup.py build_ext bdist_wheel \ + --plat-name manylinux1_x86_64 + + # Cleanup + conda deactivate + rm -rf build python/opencc/clib OpenCC.egg-info +done + +# Upload to PyPI +conda activate py3.8 +python -m pip install twine +python -m twine upload dist/* diff --git a/Packages/SwiftyOpenCC/OpenCC/release-pypi-macos.sh b/Packages/SwiftyOpenCC/OpenCC/release-pypi-macos.sh new file mode 100644 index 0000000000000000000000000000000000000000..b81b3c7f4297b2f369d2b429e619ed4f58815225 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/release-pypi-macos.sh @@ -0,0 +1,32 @@ +#!/bin/sh +set -e + +# Different to release-pypi-win.cmd and release-pypi-osx.sh, +# this script has to be ran from a clean dockerfile + +# Download and init conda +MINICONDA_FILENAME=Miniconda3-latest-MacOSX-x86_64.sh +curl -L -o $MINICONDA_FILENAME \ + "https://repo.continuum.io/miniconda/$MINICONDA_FILENAME" +bash ${MINICONDA_FILENAME} -b -f -p $HOME/miniconda3 +export PATH=$HOME/miniconda3/bin:$PATH +eval "$(conda shell.bash hook)" + +for VERSION in 2.7 3.5 3.6 3.7 3.8; do + # Create and activate environment + conda create -y -n py$VERSION python=$VERSION + conda activate py$VERSION + + # Build and package + pip install --no-cache-dir setuptools wheel + python setup.py build_ext bdist_wheel + + # Cleanup + conda deactivate + rm -rf build python/opencc/clib OpenCC.egg-info +done + +# Upload to PyPI +conda activate py3.8 +python -m pip install twine +python -m twine upload dist/* diff --git a/Packages/SwiftyOpenCC/OpenCC/release-pypi-windows.cmd b/Packages/SwiftyOpenCC/OpenCC/release-pypi-windows.cmd new file mode 100644 index 0000000000000000000000000000000000000000..eb15dcb2b52ef697752cea1f1ab813ad82ae5755 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/release-pypi-windows.cmd @@ -0,0 +1,32 @@ +@echo off +setlocal EnableDelayedExpansion + +SET VERSIONS=2.7 3.5 3.6 3.7 3.8 +SET SOURCEDIR=%cd% + +REM Build packages +for %%v in (%VERSIONS%) do ( + SET ENV_NAME=py%%v + + REM Create and activate environment + cd %ROOT_DIR% + CALL C:\Miniconda/condabin/conda.bat create -y -n py%%v python=%%v + if !ERRORLEVEL! NEQ 0 (EXIT !ERRORLEVEL!) + CALL C:\Miniconda/condabin/conda.bat activate py%%v + if !ERRORLEVEL! NEQ 0 (EXIT !ERRORLEVEL!) + pip install --no-cache-dir setuptools wheel pytest + if !ERRORLEVEL! NEQ 0 (EXIT !ERRORLEVEL!) + + REM Build and package + python setup.py build_ext bdist_wheel + if !ERRORLEVEL! NEQ 0 (EXIT !ERRORLEVEL!) + + REM Cleanup + CALL C:\Miniconda/condabin/conda.bat deactivate + rmdir /S /Q build python\opencc\clib OpenCC.egg-info +) + +REM Upload to PyPI +C:\Miniconda/condabin/conda.bat activate py3.8 +python -m pip install twine +python -m twine upload dist/* diff --git a/Packages/SwiftyOpenCC/OpenCC/setup.py b/Packages/SwiftyOpenCC/OpenCC/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..af52ba6ca7371b5fc2bb6623a221128791ebcfbc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/setup.py @@ -0,0 +1,217 @@ +import os +import re +import subprocess +import sys +import warnings + +import setuptools +import setuptools.command.build_ext +import wheel.bdist_wheel + +_this_dir = os.path.dirname(os.path.abspath(__file__)) +_clib_dir = os.path.join(_this_dir, 'python', 'opencc', 'clib') +_build_dir = os.path.join(_this_dir, 'build', 'python') + +_cmake_file = os.path.join(_this_dir, 'CMakeLists.txt') +_author_file = os.path.join(_this_dir, 'AUTHORS') +_readme_file = os.path.join(_this_dir, 'README.md') + +try: + sys.path.insert(0, os.path.join(_this_dir, 'python')) + + import opencc # noqa + _libopencc_built = True +except ImportError: + _libopencc_built = False + + +def get_version_info(): + version_info = ['1', '0', '0'] + version_pattern = re.compile( + r'OPENCC_VERSION_(MAJOR|MINOR|REVISION) (\d+)') + with open(_cmake_file, 'rb') as f: + for l in f: + match = version_pattern.search(l.decode('utf-8')) + if not match: + continue + if match.group(1) == 'MAJOR': + version_info[0] = match.group(2) + elif match.group(1) == 'MINOR': + version_info[1] = match.group(2) + elif match.group(1) == 'REVISION': + version_info[2] = match.group(2) + version = '.'.join(version_info) + return version + + +def get_author_info(): + if not os.path.isfile(_author_file): + return 'BYVoid', 'byvoid@byvoid.com' + + authors = [] + emails = [] + author_pattern = re.compile(r'(.+) <(.+)>') + with open(_author_file, 'rb') as f: + for line in f: + match = author_pattern.search(line.decode('utf-8')) + if not match: + continue + authors.append(match.group(1)) + emails.append(match.group(2)) + + if len(authors) == 0: + return 'BYVoid', 'byvoid@byvoid.com' + + return ', '.join(authors), ', '.join(emails) + + +def get_long_description(): + with open(_readme_file, 'rb') as f: + return f.read().decode('utf-8') + + +def build_libopencc(): + if _libopencc_built: + return # Skip building binary file + print('building libopencc into %s' % _build_dir) + + is_windows = sys.platform == 'win32' + + # Make build directories + if is_windows: + subprocess.call('md {}'.format(_build_dir), shell=True) + subprocess.call('md {}'.format(_clib_dir), shell=True) + else: + subprocess.call('mkdir -p {}'.format(_build_dir), shell=True) + subprocess.call('mkdir -p {}'.format(_clib_dir), shell=True) + + # Configure + cmake_args = [ + '-DBUILD_DOCUMENTATION:BOOL=OFF', + '-DBUILD_SHARED_LIBS:BOOL=OFF', + '-DENABLE_GTEST:BOOL=OFF', + '-DENABLE_BENCHMARK:BOOL=OFF', + '-DBUILD_PYTHON:BOOL=ON', + '-DCMAKE_BUILD_TYPE=Release', + '-DCMAKE_INSTALL_PREFIX={}'.format(_clib_dir), + '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={}'.format(_clib_dir), + '-DPYTHON_EXECUTABLE={}'.format(sys.executable), + ] + + if is_windows: + cmake_args += \ + ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE={}'.format(_clib_dir)] + if sys.maxsize > 2**32: + cmake_args += ['-A', 'x64'] + + cmd = ['cmake', '-B', _build_dir] + cmake_args + errno = subprocess.call(cmd) + assert errno == 0, 'Configure failed' + + # Build + cmd = [ + 'cmake', '--build', _build_dir, + '--config', 'Release', + '--target', 'install' + ] + errno = subprocess.call(cmd) + assert errno == 0, 'Build failed' + + # Empty __init__.py file has to be created + # to make opencc.clib a module + with open('{}/__init__.py'.format(_clib_dir), 'w'): + pass + + +class OpenCCExtension(setuptools.Extension, object): + def __init__(self, name, sourcedir=''): + setuptools.Extension.__init__(self, name, sources=[]) + self.sourcedir = os.path.abspath(sourcedir) + + +class BuildExtCommand(setuptools.command.build_ext.build_ext, object): + def build_extension(self, ext): + if isinstance(ext, OpenCCExtension): + build_libopencc() + else: + super(BuildExtCommand, self).build_extension(ext) + + +class BDistWheelCommand(wheel.bdist_wheel.bdist_wheel, object): + """Custom bdsit_wheel command that will change + default plat-name based on PEP 425 and PEP 513 + """ + + @staticmethod + def _determine_platform_tag(): + if sys.platform == 'win32': + if 'amd64' in sys.version.lower(): + return 'win-amd64' + return sys.platform + + if sys.platform == 'darwin': + _, _, _, _, machine = os.uname() + return 'macosx-10.9-{}'.format(machine) + + if os.name == 'posix': + _, _, _, _, machine = os.uname() + return 'manylinux1-{}'.format(machine) + + warnings.warn( + 'Windows macos and linux are all not detected, ' + 'Proper distribution name cannot be determined.') + from distutils.util import get_platform + return get_platform() + + def initialize_options(self): + super(BDistWheelCommand, self).initialize_options() + self.plat_name = self._determine_platform_tag() + + +packages = ['opencc', 'opencc.clib'] + +version_info = get_version_info() +author_info = get_author_info() + +setuptools.setup( + name='OpenCC', + version=version_info, + author=author_info[0], + author_email=author_info[1], + description=" Conversion between Traditional and Simplified Chinese", + long_description=get_long_description(), + long_description_content_type="text/markdown", + url="https://github.com/BYVoid/OpenCC", + + packages=packages, + package_dir={'opencc': 'python/opencc'}, + package_data={str('opencc'): [ + 'clib/opencc_clib*', + 'clib/share/opencc/*', + ]}, + ext_modules=[OpenCCExtension('opencc.clib.opencc_clib', 'python')], + cmdclass={ + 'build_ext': BuildExtCommand, + 'bdist_wheel': BDistWheelCommand + }, + + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'Natural Language :: Chinese (Simplified)', + 'Natural Language :: Chinese (Traditional)', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3', + 'License :: OSI Approved :: Apache Software License', + 'Topic :: Scientific/Engineering', + 'Topic :: Software Development', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: Software Development :: Localization', + 'Topic :: Text Processing :: Linguistic', + ], + license='Apache License 2.0', + keywords=['opencc', 'convert', 'chinese'] +) diff --git a/Packages/SwiftyOpenCC/OpenCC/src/BinaryDict.cpp b/Packages/SwiftyOpenCC/OpenCC/src/BinaryDict.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c577566150e936be574474a0f90ba126b05740a4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/BinaryDict.cpp @@ -0,0 +1,194 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "BinaryDict.hpp" +#include "Lexicon.hpp" + +using namespace opencc; + +size_t BinaryDict::KeyMaxLength() const { + size_t maxLength = 0; + for (const std::unique_ptr& entry : *lexicon) { + maxLength = (std::max)(maxLength, entry->KeyLength()); + } + return maxLength; +} + +void BinaryDict::SerializeToFile(FILE* fp) const { + std::string keyBuf, valueBuf; + std::vector keyOffsets, valueOffsets; + size_t keyTotalLength = 0, valueTotalLength = 0; + ConstructBuffer(keyBuf, keyOffsets, keyTotalLength, valueBuf, valueOffsets, + valueTotalLength); + // Number of items + size_t numItems = lexicon->Length(); + fwrite(&numItems, sizeof(size_t), 1, fp); + + // Data + fwrite(&keyTotalLength, sizeof(size_t), 1, fp); + fwrite(keyBuf.c_str(), sizeof(char), keyTotalLength, fp); + fwrite(&valueTotalLength, sizeof(size_t), 1, fp); + fwrite(valueBuf.c_str(), sizeof(char), valueTotalLength, fp); + + size_t keyCursor = 0, valueCursor = 0; + for (const std::unique_ptr& entry : *lexicon) { + // Number of values + size_t numValues = entry->NumValues(); + fwrite(&numValues, sizeof(size_t), 1, fp); + // Key offset + size_t keyOffset = keyOffsets[keyCursor++]; + fwrite(&keyOffset, sizeof(size_t), 1, fp); + // Values offset + for (size_t i = 0; i < numValues; i++) { + size_t valueOffset = valueOffsets[valueCursor++]; + fwrite(&valueOffset, sizeof(size_t), 1, fp); + } + } + assert(keyCursor == numItems); +} + +BinaryDictPtr BinaryDict::NewFromFile(FILE* fp) { + size_t offsetBound, savedOffset; + savedOffset = ftell(fp); + fseek(fp, 0L, SEEK_END); + offsetBound = ftell(fp) - savedOffset; + fseek(fp, savedOffset, SEEK_SET); + + BinaryDictPtr dict(new BinaryDict(LexiconPtr(new Lexicon))); + + // Number of items + size_t numItems; + size_t unitsRead = fread(&numItems, sizeof(size_t), 1, fp); + if (unitsRead != 1) { + throw InvalidFormat("Invalid OpenCC binary dictionary (numItems)"); + } + + // Keys + size_t keyTotalLength; + unitsRead = fread(&keyTotalLength, sizeof(size_t), 1, fp); + if (unitsRead != 1) { + throw InvalidFormat("Invalid OpenCC binary dictionary (keyTotalLength)"); + } + dict->keyBuffer.resize(keyTotalLength); + unitsRead = fread(const_cast(dict->keyBuffer.c_str()), sizeof(char), + keyTotalLength, fp); + if (unitsRead != keyTotalLength) { + throw InvalidFormat("Invalid OpenCC binary dictionary (keyBuffer)"); + } + + // Values + size_t valueTotalLength; + unitsRead = fread(&valueTotalLength, sizeof(size_t), 1, fp); + if (unitsRead != 1) { + throw InvalidFormat("Invalid OpenCC binary dictionary (valueTotalLength)"); + } + dict->valueBuffer.resize(valueTotalLength); + unitsRead = fread(const_cast(dict->valueBuffer.c_str()), sizeof(char), + valueTotalLength, fp); + if (unitsRead != valueTotalLength) { + throw InvalidFormat("Invalid OpenCC binary dictionary (valueBuffer)"); + } + + // Offsets + for (size_t i = 0; i < numItems; i++) { + // Number of values + size_t numValues; + unitsRead = fread(&numValues, sizeof(size_t), 1, fp); + if (unitsRead != 1) { + throw InvalidFormat("Invalid OpenCC binary dictionary (numValues)"); + } + // Key offset + size_t keyOffset; + unitsRead = fread(&keyOffset, sizeof(size_t), 1, fp); + if (unitsRead != 1 || keyOffset >= offsetBound) { + throw InvalidFormat("Invalid OpenCC binary dictionary (keyOffset)"); + } + std::string key = dict->keyBuffer.c_str() + keyOffset; + // Value offset + std::vector values; + for (size_t j = 0; j < numValues; j++) { + size_t valueOffset; + unitsRead = fread(&valueOffset, sizeof(size_t), 1, fp); + if (unitsRead != 1 || valueOffset >= offsetBound) { + throw InvalidFormat("Invalid OpenCC binary dictionary (valueOffset)"); + } + const char* value = dict->valueBuffer.c_str() + valueOffset; + values.push_back(value); + } + DictEntry* entry = DictEntryFactory::New(key, values); + dict->lexicon->Add(entry); + } + + return dict; +} + +void BinaryDict::ConstructBuffer(std::string& keyBuf, + std::vector& keyOffset, + size_t& keyTotalLength, std::string& valueBuf, + std::vector& valueOffset, + size_t& valueTotalLength) const { + keyTotalLength = 0; + valueTotalLength = 0; + // Calculate total length + for (const std::unique_ptr& entry : *lexicon) { + keyTotalLength += entry->KeyLength() + 1; + assert(entry->NumValues() != 0); + if (entry->NumValues() == 1) { + const auto* svEntry = + static_cast(entry.get()); + valueTotalLength += svEntry->Value().length() + 1; + } else { + const auto* mvEntry = + static_cast(entry.get()); + for (const auto& value : mvEntry->Values()) { + valueTotalLength += value.length() + 1; + } + } + } + // Write keys and values to buffers + keyBuf.resize(keyTotalLength, '\0'); + valueBuf.resize(valueTotalLength, '\0'); + char* pKeyBuffer = const_cast(keyBuf.c_str()); + char* pValueBuffer = const_cast(valueBuf.c_str()); + for (const std::unique_ptr& entry : *lexicon) { + strcpy(pKeyBuffer, entry->Key().c_str()); + keyOffset.push_back(pKeyBuffer - keyBuf.c_str()); + pKeyBuffer += entry->KeyLength() + 1; + if (entry->NumValues() == 1) { + const auto* svEntry = + static_cast(entry.get()); + strcpy(pValueBuffer, svEntry->Value().c_str()); + valueOffset.push_back(pValueBuffer - valueBuf.c_str()); + pValueBuffer += svEntry->Value().length() + 1; + } else { + const auto* mvEntry = + static_cast(entry.get()); + for (const auto& value : mvEntry->Values()) { + strcpy(pValueBuffer, value.c_str()); + valueOffset.push_back(pValueBuffer - valueBuf.c_str()); + pValueBuffer += value.length() + 1; + } + } + } + assert(keyBuf.c_str() + keyTotalLength == pKeyBuffer); + assert(valueBuf.c_str() + valueTotalLength == pValueBuffer); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/BinaryDict.hpp b/Packages/SwiftyOpenCC/OpenCC/src/BinaryDict.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7c23268fea0762d11cdcfbecaff6e9c175ee4af3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/BinaryDict.hpp @@ -0,0 +1,53 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" +#include "SerializableDict.hpp" + +namespace opencc { +/** + * Binary dictionary for faster deserialization + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT BinaryDict : public SerializableDict { +public: + BinaryDict(const LexiconPtr& _lexicon) : lexicon(_lexicon) {} + + virtual ~BinaryDict() {} + + virtual void SerializeToFile(FILE* fp) const; + + static BinaryDictPtr NewFromFile(FILE* fp); + + const LexiconPtr& GetLexicon() const { return lexicon; } + + size_t KeyMaxLength() const; + +private: + LexiconPtr lexicon; + std::string keyBuffer; + std::string valueBuffer; + + void ConstructBuffer(std::string& keyBuffer, std::vector& keyOffset, + size_t& keyTotalLength, std::string& valueBuffer, + std::vector& valueOffset, + size_t& valueTotalLength) const; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/BinaryDictTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/BinaryDictTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..471221acdb544d9108c2ad840a62bc7cf02430e3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/BinaryDictTest.cpp @@ -0,0 +1,54 @@ +/* + * Open Chinese Convert + * + * Copyright 2015-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BinaryDict.hpp" +#include "TextDictTestBase.hpp" + +namespace opencc { + +class BinaryDictTest : public TextDictTestBase { +protected: + BinaryDictTest() + : binDict(new BinaryDict(textDict->GetLexicon())), fileName("dict.bin"){}; + + const BinaryDictPtr binDict; + const std::string fileName; +}; + +TEST_F(BinaryDictTest, Serialization) { + binDict->opencc::SerializableDict::SerializeToFile(fileName); +} + +TEST_F(BinaryDictTest, Deserialization) { + const BinaryDictPtr& deserialized = + SerializableDict::NewFromFile(fileName); + const LexiconPtr& lex1 = binDict->GetLexicon(); + const LexiconPtr& lex2 = deserialized->GetLexicon(); + + // Compare every entry + EXPECT_EQ(lex1->Length(), lex2->Length()); + for (size_t i = 0; i < lex1->Length(); i++) { + EXPECT_EQ(lex1->At(i)->Key(), lex2->At(i)->Key()); + EXPECT_EQ(lex1->At(i)->NumValues(), lex2->At(i)->NumValues()); + } + + const TextDictPtr deserializedTextDict(new TextDict(lex2)); + TestDict(deserializedTextDict); +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/src/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ec11771b3a7b1b4150cd2c447f41d0250c4f205 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/CMakeLists.txt @@ -0,0 +1,178 @@ +include (GenerateExportHeader) +if(NOT USE_SYSTEM_MARISA) + include_directories(../deps/marisa-0.2.6/include) +endif() +if(NOT USE_SYSTEM_RAPIDJSON) + include_directories(../deps/rapidjson-1.1.0) +endif() +if(NOT USE_SYSTEM_TCLAP) + include_directories(../deps/tclap-1.2.2) +endif() + +# Library + +set( + LIBOPENCC_HEADERS + Common.hpp + Config.hpp + Conversion.hpp + ConversionChain.hpp + Converter.hpp + Dict.hpp + DictConverter.hpp + DictEntry.hpp + DictGroup.hpp + Exception.hpp + Export.hpp + Lexicon.hpp + MarisaDict.hpp + MaxMatchSegmentation.hpp + Optional.hpp + PhraseExtract.hpp + Segmentation.hpp + Segments.hpp + SerializableDict.hpp + SerializedValues.hpp + SimpleConverter.hpp + TextDict.hpp + UTF8StringSlice.hpp + UTF8Util.hpp + opencc.h +) + +set( + LIBOPENCC_SOURCES + Config.cpp + Conversion.cpp + ConversionChain.cpp + Converter.cpp + Dict.cpp + DictConverter.cpp + DictEntry.cpp + DictGroup.cpp + Lexicon.cpp + MarisaDict.cpp + MaxMatchSegmentation.cpp + PhraseExtract.cpp + SerializedValues.cpp + SimpleConverter.cpp + Segmentation.cpp + TextDict.cpp + UTF8StringSlice.cpp + UTF8Util.cpp +) + +set(UNITTESTS + ConfigTest + ConversionChainTest + ConversionTest + DictGroupTest + MarisaDictTest + MaxMatchSegmentationTest + PhraseExtractTest + SerializedValuesTest + SimpleConverterTest + TextDictTest + UTF8StringSliceTest + UTF8UtilTest +) + +if (ENABLE_DARTS) + if(NOT USE_SYSTEM_DARTS) + include_directories(../deps/darts-clone) + endif() + set( + LIBOPENCC_HEADERS + ${LIBOPENCC_HEADERS} + BinaryDict.hpp + DartsDict.hpp + ) + set( + LIBOPENCC_SOURCES + ${LIBOPENCC_SOURCES} + BinaryDict.cpp + DartsDict.cpp + ) + set( + UNITTESTS + ${UNITTESTS} + BinaryDictTest + DartsDictTest + ) +endif() + +add_library(libopencc ${LIBOPENCC_SOURCES} ${LIBOPENCC_HEADERS}) +set_target_properties(libopencc PROPERTIES POSITION_INDEPENDENT_CODE ON) +source_group(libopencc FILES ${LIBOPENCC_SOURCES} ${LIBOPENCC_HEADERS}) +target_link_libraries(libopencc marisa) + +GENERATE_EXPORT_HEADER( + libopencc + BASE_NAME OPENCC + EXPORT_MACRO_NAME OPENCC_EXPORT + EXPORT_FILE_NAME Opencc_Export.h + STATIC_DEFINE Opencc_BUILT_AS_STATIC +) + +set_target_properties( + libopencc + PROPERTIES + LINKER_LANGUAGE + CXX + OUTPUT_NAME + opencc + VERSION + 1.1.2 + SOVERSION + 1.1 +) + +# Installation + +install( + TARGETS libopencc + LIBRARY DESTINATION ${DIR_LIBRARY} + ARCHIVE DESTINATION ${DIR_LIBRARY} + RUNTIME DESTINATION bin +) + +install( + FILES ${LIBOPENCC_HEADERS} + DESTINATION ${DIR_INCLUDE}/opencc +) + +# Gtest + +if (ENABLE_GTEST) + if (WIN32) + add_custom_target( + copy_gtest_to_src + ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copying gtest to src" + ) + add_custom_target( + copy_gtest_main_to_src + ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copying gtest_main to src" + ) + endif() + + foreach(TESTCASE ${UNITTESTS}) + add_executable(${TESTCASE} ${TESTCASE}.cpp) + target_link_libraries(${TESTCASE} gtest gtest_main libopencc) + add_test(${TESTCASE} ${TESTCASE}) + if (WIN32) + add_dependencies(${TESTCASE} copy_gtest_to_src copy_gtest_main_to_src) + endif() + endforeach() +endif() + +# Benchmark + +if (ENABLE_BENCHMARK) + add_subdirectory(benchmark) +endif() + +# Subdir + +add_subdirectory(tools) diff --git a/Packages/SwiftyOpenCC/OpenCC/src/CmdLineOutput.hpp b/Packages/SwiftyOpenCC/OpenCC/src/CmdLineOutput.hpp new file mode 100644 index 0000000000000000000000000000000000000000..80419ebb71c14b9e04b3e0bc5210e3be60ef9914 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/CmdLineOutput.hpp @@ -0,0 +1,48 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "tclap/CmdLine.h" + +class CmdLineOutput : public TCLAP::StdOutput { +public: + virtual void usage(TCLAP::CmdLineInterface& cmd) { + std::cout << std::endl + << cmd.getMessage() << std::endl + << "Author: Carbo Kuo " << std::endl + << "Bug Report: http://github.com/BYVoid/OpenCC/issues" + << std::endl + << std::endl + << "Usage: " << std::endl + << std::endl; + + _shortUsage(cmd, std::cout); + std::cout << std::endl; + std::cout << "Options: " << std::endl << std::endl; + _longUsage(cmd, std::cout); + std::cout << std::endl; + } + + virtual void version(TCLAP::CmdLineInterface& cmd) { + std::cout << std::endl + << cmd.getMessage() << std::endl + << "Version: " << cmd.getVersion() << std::endl + << std::endl; + } +}; diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Common.hpp b/Packages/SwiftyOpenCC/OpenCC/src/Common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8d4e2f065207d4dc613da34b4e422e529ece975d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Common.hpp @@ -0,0 +1,84 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// Microsoft Visual C++ specific +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma warning(disable : 4251 4266 4350 4503 4512 4514 4710 4820) +#endif + +#include +#include +#include +#include + +#include "Export.hpp" +#include "Optional.hpp" + +// Forward decalarations and alias +namespace opencc { +class Config; +class Conversion; +class ConversionChain; +class Converter; +class Dict; +class DictEntry; +class DictGroup; +class Lexicon; +class MarisaDict; +class MultiValueDictEntry; +class NoValueDictEntry; +class Segmentation; +class Segments; +class SerializableDict; +class SingleValueDictEntry; +class TextDict; +typedef std::shared_ptr ConversionPtr; +typedef std::shared_ptr ConversionChainPtr; +typedef std::shared_ptr ConverterPtr; +typedef std::shared_ptr DictPtr; +typedef std::shared_ptr DictGroupPtr; +typedef std::shared_ptr LexiconPtr; +typedef std::shared_ptr MarisaDictPtr; +typedef std::shared_ptr SegmentationPtr; +typedef std::shared_ptr SegmentsPtr; +typedef std::shared_ptr SerializableDictPtr; +typedef std::shared_ptr TextDictPtr; + +#ifdef ENABLE_DARTS +class BinaryDict; +class DartsDict; +typedef std::shared_ptr BinaryDictPtr; +typedef std::shared_ptr DartsDictPtr; +#endif + +} // namespace opencc + +#ifndef PKGDATADIR +const std::string PACKAGE_DATA_DIRECTORY = ""; +#else // ifndef PKGDATADIR +const std::string PACKAGE_DATA_DIRECTORY = PKGDATADIR "/"; +#endif // ifndef PKGDATADIR + +#ifndef VERSION +#define VERSION "1.0.*" +#endif // ifndef VERSION + +// The following definitions are provided by CMake +// #define ENABLE_DARTS diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Config.cpp b/Packages/SwiftyOpenCC/OpenCC/src/Config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a3a36b64699d97b4726f998ffcf9011c6673fb36 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Config.cpp @@ -0,0 +1,277 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include "Config.hpp" +#include "ConversionChain.hpp" +#include "Converter.hpp" +#include "DictGroup.hpp" +#include "Exception.hpp" +#include "MarisaDict.hpp" +#include "MaxMatchSegmentation.hpp" +#include "TextDict.hpp" + +#ifdef ENABLE_DARTS +#include "DartsDict.hpp" +#endif + +typedef rapidjson::GenericValue> JSONValue; + +namespace opencc { + +namespace { + +class ConfigInternal { +public: + std::string configDirectory; + std::unordered_map< + std::string, + std::unordered_map>> + dictCache; + + const JSONValue& GetProperty(const JSONValue& doc, const char* name) { + if (!doc.HasMember(name)) { + throw InvalidFormat("Required property not found: " + std::string(name)); + } + return doc[name]; + } + + const JSONValue& GetObjectProperty(const JSONValue& doc, const char* name) { + const JSONValue& obj = GetProperty(doc, name); + if (!obj.IsObject()) { + throw InvalidFormat("Property must be an object: " + std::string(name)); + } + return obj; + } + + const JSONValue& GetArrayProperty(const JSONValue& doc, const char* name) { + const JSONValue& obj = GetProperty(doc, name); + if (!obj.IsArray()) { + throw InvalidFormat("Property must be an array: " + std::string(name)); + } + return obj; + } + + const char* GetStringProperty(const JSONValue& doc, const char* name) { + const JSONValue& obj = GetProperty(doc, name); + if (!obj.IsString()) { + throw InvalidFormat("Property must be a std::string: " + + std::string(name)); + } + return obj.GetString(); + } + + template + DictPtr LoadDictWithPaths(const std::string& fileName) { + // Working directory + std::shared_ptr dict; + if (SerializableDict::TryLoadFromFile(fileName, &dict)) { + return dict; + } + // Configuration directory + if ((configDirectory != "") && SerializableDict::TryLoadFromFile( + configDirectory + fileName, &dict)) { + return dict; + } + // Package data directory + if ((PACKAGE_DATA_DIRECTORY != "") && + SerializableDict::TryLoadFromFile( + PACKAGE_DATA_DIRECTORY + fileName, &dict)) { + return dict; + } + throw FileNotFound(fileName); + } + + DictPtr LoadDictFromFile(const std::string& type, + const std::string& fileName) { + if (type == "text") { + DictPtr dict = LoadDictWithPaths(fileName); + return MarisaDict::NewFromDict(*dict.get()); + } +#ifdef ENABLE_DARTS + if (type == "ocd") { + return LoadDictWithPaths(fileName); + } +#endif + if (type == "ocd2") { + return LoadDictWithPaths(fileName); + } + throw InvalidFormat("Unknown dictionary type: " + type); + return nullptr; + } + + DictPtr ParseDict(const JSONValue& doc) { + // Required: type + std::string type = GetStringProperty(doc, "type"); + + if (type == "group") { + std::list dicts; + const JSONValue& docs = GetArrayProperty(doc, "dicts"); + for (rapidjson::SizeType i = 0; i < docs.Size(); i++) { + if (docs[i].IsObject()) { + DictPtr dict = ParseDict(docs[i]); + dicts.push_back(dict); + } else { + throw InvalidFormat("Element of the array must be an object"); + } + } + return DictGroupPtr(new DictGroup(dicts)); + } else { + std::string fileName = GetStringProperty(doc, "file"); + // Read from cache + DictPtr& cache = dictCache[type][configDirectory][fileName]; + if (cache != nullptr) { + return cache; + } + DictPtr dict = LoadDictFromFile(type, fileName); + + // Update Cache + cache = dict; + return dict; + } + } + + SegmentationPtr ParseSegmentation(const JSONValue& doc) { + SegmentationPtr segmentation; + + // Required: type + std::string type = GetStringProperty(doc, "type"); + if (type == "mmseg") { + // Required: dict + DictPtr dict = ParseDict(GetObjectProperty(doc, "dict")); + segmentation = SegmentationPtr(new MaxMatchSegmentation(dict)); + } else { + throw InvalidFormat("Unknown segmentation type: " + type); + } + return segmentation; + } + + ConversionPtr ParseConversion(const JSONValue& doc) { + // Required: dict + DictPtr dict = ParseDict(GetObjectProperty(doc, "dict")); + ConversionPtr conversion(new Conversion(dict)); + + return conversion; + } + + ConversionChainPtr ParseConversionChain(const JSONValue& docs) { + std::list conversions; + for (rapidjson::SizeType i = 0; i < docs.Size(); i++) { + const JSONValue& doc = docs[i]; + if (doc.IsObject()) { + ConversionPtr conversion = ParseConversion(doc); + conversions.push_back(conversion); + } else { + } + } + ConversionChainPtr chain(new ConversionChain(conversions)); + return chain; + } + + std::string FindConfigFile(std::string fileName) { + std::ifstream ifs; + + // Working directory + ifs.open(UTF8Util::GetPlatformString(fileName).c_str()); + if (ifs.is_open()) { + return fileName; + } + // Package data directory + if (PACKAGE_DATA_DIRECTORY != "") { + std::string prefixedFileName = PACKAGE_DATA_DIRECTORY + fileName; + ifs.open(UTF8Util::GetPlatformString(prefixedFileName).c_str()); + if (ifs.is_open()) { + return prefixedFileName; + } + prefixedFileName += ".json"; + ifs.open(UTF8Util::GetPlatformString(prefixedFileName).c_str()); + if (ifs.is_open()) { + return prefixedFileName; + } + } + throw FileNotFound(fileName); + } +}; +} // namespace + +Config::Config() : internal(new ConfigInternal()) {} + +Config::~Config() { delete (ConfigInternal*)internal; } + +ConverterPtr Config::NewFromFile(const std::string& fileName) { + ConfigInternal* impl = (ConfigInternal*)internal; + std::string prefixedFileName = impl->FindConfigFile(fileName); + std::ifstream ifs(UTF8Util::GetPlatformString(prefixedFileName)); + std::string content(std::istreambuf_iterator(ifs), + (std::istreambuf_iterator())); + +#if defined(_WIN32) || defined(_WIN64) + UTF8Util::ReplaceAll(prefixedFileName, "\\", "/"); +#endif // if defined(_WIN32) || defined(_WIN64) + size_t slashPos = prefixedFileName.rfind("/"); + std::string configDirectory = ""; + if (slashPos != std::string::npos) { + configDirectory = prefixedFileName.substr(0, slashPos) + "/"; + } + return NewFromString(content, configDirectory); +} + +ConverterPtr Config::NewFromString(const std::string& json, + const std::string& configDirectory) { + rapidjson::Document doc; + + doc.ParseInsitu<0>(const_cast(json.c_str())); + if (doc.HasParseError()) { + throw InvalidFormat("Error parsing JSON"); // doc.GetErrorOffset() + } + if (!doc.IsObject()) { + throw InvalidFormat("Root of configuration must be an object"); + } + + // Optional: name + std::string name; + if (doc.HasMember("name") && doc["name"].IsString()) { + name = doc["name"].GetString(); + } + + ConfigInternal* impl = (ConfigInternal*)internal; + if (!configDirectory.empty()) { + if (configDirectory.back() == '/' || configDirectory.back() == '\\') + impl->configDirectory = configDirectory; + else + impl->configDirectory = configDirectory + '/'; + } else { + impl->configDirectory.clear(); + } + + // Required: segmentation + SegmentationPtr segmentation = + impl->ParseSegmentation(impl->GetObjectProperty(doc, "segmentation")); + + // Required: conversion_chain + ConversionChainPtr chain = impl->ParseConversionChain( + impl->GetArrayProperty(doc, "conversion_chain")); + return ConverterPtr(new Converter(name, segmentation, chain)); +} + +}; // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Config.hpp b/Packages/SwiftyOpenCC/OpenCC/src/Config.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7a904cee698d57563c3473c5da1d043227f4c61f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Config.hpp @@ -0,0 +1,42 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" + +namespace opencc { +/** + * Configuration loader + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT Config { +public: + Config(); + + virtual ~Config(); + + ConverterPtr NewFromString(const std::string& json, + const std::string& configDirectory); + + ConverterPtr NewFromFile(const std::string& fileName); + +private: + void* internal; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/ConfigTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/ConfigTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..369c9dd36f6a0680ee6ffaeb650c47ba81ec8156 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/ConfigTest.cpp @@ -0,0 +1,74 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "Config.hpp" +#include "ConfigTestBase.hpp" +#include "Converter.hpp" +#include "Exception.hpp" +#include "TestUtilsUTF8.hpp" + +namespace opencc { + +class ConfigTest : public ConfigTestBase { +protected: + ConfigTest() + : input(utf8("燕燕于飞差池其羽之子于归远送于野")), + expected(utf8("燕燕于飛差池其羽之子于歸遠送於野")) {} + + virtual void SetUp() { converter = config.NewFromFile(CONFIG_TEST_PATH); } + + Config config; + ConverterPtr converter; + const std::string input; + const std::string expected; +}; + +TEST_F(ConfigTest, Convert) { + const std::string& converted = converter->Convert(input); + EXPECT_EQ(expected, converted); +} + +TEST_F(ConfigTest, ConvertBuffer) { + char output[1024]; + const size_t length = converter->Convert(input.c_str(), output); + EXPECT_EQ(expected.length(), length); + EXPECT_EQ(expected, output); +} + +TEST_F(ConfigTest, NonexistingPath) { + const std::string path = "/opencc/no/such/file/or/directory"; + try { + const ConverterPtr _ = config.NewFromFile(path); + } catch (FileNotFound& e) { + EXPECT_EQ(path + " not found or not accessible.", e.what()); + } +} + +TEST_F(ConfigTest, NewFromStringWitoutTrailingSlash) { + std::ifstream ifs(CONFIG_TEST_PATH); + std::string content(std::istreambuf_iterator(ifs), + (std::istreambuf_iterator())); + std::string pathWithoutTrailingSlash = CMAKE_SOURCE_DIR "/test/config_test"; + + const ConverterPtr _ = + config.NewFromString(content, pathWithoutTrailingSlash); +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/ConfigTestBase.hpp b/Packages/SwiftyOpenCC/OpenCC/src/ConfigTestBase.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fc8bb74d23c94341181bd7b961db08ec8bb886ad --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/ConfigTestBase.hpp @@ -0,0 +1,34 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "TestUtils.hpp" + +namespace opencc { + +class ConfigTestBase : public ::testing::Test { +protected: + ConfigTestBase() + : CONFIG_TEST_PATH(CMAKE_SOURCE_DIR + "/test/config_test/config_test.json") {} + + const std::string CONFIG_TEST_PATH; +}; + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Conversion.cpp b/Packages/SwiftyOpenCC/OpenCC/src/Conversion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87a513514296316990189e029293e6f3f245e963 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Conversion.cpp @@ -0,0 +1,51 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Conversion.hpp" +#include "Dict.hpp" + +using namespace opencc; + +std::string Conversion::Convert(const char* phrase) const { + std::ostringstream buffer; + for (const char* pstr = phrase; *pstr != '\0';) { + Optional matched = dict->MatchPrefix(pstr); + size_t matchedLength; + if (matched.IsNull()) { + matchedLength = UTF8Util::NextCharLength(pstr); + buffer << UTF8Util::FromSubstr(pstr, matchedLength); + } else { + matchedLength = matched.Get()->KeyLength(); + buffer << matched.Get()->GetDefault(); + } + pstr += matchedLength; + } + return buffer.str(); +} + +std::string Conversion::Convert(const std::string& phrase) const { + return Convert(phrase.c_str()); +} + +SegmentsPtr Conversion::Convert(const SegmentsPtr& input) const { + SegmentsPtr output(new Segments); + for (const char* segment : *input) { + output->AddSegment(Convert(segment)); + } + return output; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Conversion.hpp b/Packages/SwiftyOpenCC/OpenCC/src/Conversion.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cf73a254a3f9998d0a6620f4494e6637de89e1d9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Conversion.hpp @@ -0,0 +1,47 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" +#include "Segmentation.hpp" + +namespace opencc { +/** + * Conversion interface + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT Conversion { +public: + Conversion(DictPtr _dict) : dict(_dict) {} + + // Convert single phrase + std::string Convert(const std::string& phrase) const; + + // Convert single phrase + std::string Convert(const char* phrase) const; + + // Convert segmented text + SegmentsPtr Convert(const SegmentsPtr& input) const; + + const DictPtr GetDict() const { return dict; } + +private: + const DictPtr dict; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/ConversionChain.cpp b/Packages/SwiftyOpenCC/OpenCC/src/ConversionChain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2bb29e6705a2255ce00e06a5af1c6b67518533e8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/ConversionChain.cpp @@ -0,0 +1,35 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ConversionChain.hpp" +#include "Segments.hpp" + +using namespace opencc; + +ConversionChain::ConversionChain(const std::list _conversions) + : conversions(_conversions) {} + +SegmentsPtr ConversionChain::Convert(const SegmentsPtr& input) const { + SegmentsPtr output = input; + for (auto conversion : conversions) { + output = conversion->Convert(output); + } + return output; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/ConversionChain.hpp b/Packages/SwiftyOpenCC/OpenCC/src/ConversionChain.hpp new file mode 100644 index 0000000000000000000000000000000000000000..28853c67cd042a933e5e11217f3ab24d2438a4bc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/ConversionChain.hpp @@ -0,0 +1,43 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "Common.hpp" +#include "Conversion.hpp" + +namespace opencc { +/** + * Chain of conversions + * Consists of a list of conversions. Converts input in sequence. + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT ConversionChain { +public: + ConversionChain(const std::list _conversions); + + SegmentsPtr Convert(const SegmentsPtr& input) const; + + const std::list GetConversions() const { return conversions; } + +private: + const std::list conversions; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/ConversionChainTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/ConversionChainTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65e076603fc8cfb76fda55fab1d38c8d667405cf --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/ConversionChainTest.cpp @@ -0,0 +1,60 @@ +/* + * Open Chinese Convert + * + * Copyright 2015-2021 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConversionChain.hpp" +#include "DictGroupTestBase.hpp" + +namespace opencc { + +class ConversionChainTest : public DictGroupTestBase { +protected: + ConversionChainTest() {} + + virtual void SetUp() { + dict = CreateDictGroupForConversion(); + conversion = ConversionPtr(new Conversion(dict)); + } + + void SegmentsAssertEquals(const SegmentsPtr& expected, + const SegmentsPtr& actual) { + const size_t length = expected->Length(); + EXPECT_TRUE(length == actual->Length()); + for (size_t i = 0; i < length; i++) { + EXPECT_EQ(std::string(expected->At(i)), std::string(actual->At(i))) + << "i = " << i; + } + } + + DictPtr dict; + ConversionPtr conversion; +}; + +TEST_F(ConversionChainTest, Convert) { + // Variants + const DictPtr& dictVariants = CreateDictForTaiwanVariants(); + const ConversionPtr& conversionVariants = + ConversionPtr(new Conversion(dictVariants)); + const std::list conversions{conversion, conversionVariants}; + const ConversionChainPtr& conversionChain = + ConversionChainPtr(new ConversionChain(conversions)); + const SegmentsPtr& converted = + conversionChain->Convert(SegmentsPtr(new Segments{utf8("里面")})); + SegmentsAssertEquals(SegmentsPtr(new Segments{utf8("裡面")}), converted); +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/ConversionTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/ConversionTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..04a80a7b041eff5114b191d2374bb605136b7956 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/ConversionTest.cpp @@ -0,0 +1,50 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Conversion.hpp" +#include "DictGroupTestBase.hpp" + +namespace opencc { + +class ConversionTest : public DictGroupTestBase { +protected: + ConversionTest() + : input(utf8("太后的头发干燥")), expected(utf8("太后的頭髮乾燥")) {} + + virtual void SetUp() { + dict = CreateDictGroupForConversion(); + conversion = ConversionPtr(new Conversion(dict)); + } + + DictPtr dict; + ConversionPtr conversion; + const std::string input; + const std::string expected; +}; + +TEST_F(ConversionTest, ConvertString) { + const std::string converted = conversion->Convert(input); + EXPECT_EQ(expected, converted); +} + +TEST_F(ConversionTest, ConvertCString) { + const std::string converted = conversion->Convert(input.c_str()); + EXPECT_EQ(expected, converted); +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Converter.cpp b/Packages/SwiftyOpenCC/OpenCC/src/Converter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..209cff489e4dc249d02fc7d583b60a32573af462 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Converter.cpp @@ -0,0 +1,37 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ConversionChain.hpp" +#include "Converter.hpp" +#include "Segments.hpp" + +using namespace opencc; + +std::string Converter::Convert(const std::string& text) const { + const SegmentsPtr& segments = segmentation->Segment(text); + const SegmentsPtr& converted = conversionChain->Convert(segments); + return converted->ToString(); +} + +size_t Converter::Convert(const char* input, char* output) const { + const std::string& converted = Convert(input); + strcpy(output, converted.c_str()); + return converted.length(); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Converter.hpp b/Packages/SwiftyOpenCC/OpenCC/src/Converter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9f1f3f9421b56a120179ef3758bcfb463f30a8a6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Converter.hpp @@ -0,0 +1,51 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" +#include "Segmentation.hpp" + +namespace opencc { +/** + * Controller of segmentation and conversion + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT Converter { +public: + Converter(const std::string& _name, SegmentationPtr _segmentation, + ConversionChainPtr _conversionChain) + : name(_name), segmentation(_segmentation), + conversionChain(_conversionChain) {} + + std::string Convert(const std::string& text) const; + + size_t Convert(const char* input, char* output) const; + + const SegmentationPtr GetSegmentation() const { return segmentation; } + + const ConversionChainPtr GetConversionChain() const { + return conversionChain; + } + +private: + const std::string name; + const SegmentationPtr segmentation; + const ConversionChainPtr conversionChain; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/DartsDict.cpp b/Packages/SwiftyOpenCC/OpenCC/src/DartsDict.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af790b18d9814a08f3b3b9def0ad58099b9bc712 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/DartsDict.cpp @@ -0,0 +1,171 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "BinaryDict.hpp" +#include "DartsDict.hpp" +#include "Lexicon.hpp" +#include "darts.h" + +using namespace opencc; + +static const char* OCDHEADER = "OPENCCDARTS1"; + +class DartsDict::DartsInternal { +public: + BinaryDictPtr binary; + void* buffer; + Darts::DoubleArray* doubleArray; + + DartsInternal() : binary(nullptr), buffer(nullptr), doubleArray(nullptr) {} + + ~DartsInternal() { + if (buffer != nullptr) { + free(buffer); + } + if (doubleArray != nullptr) { + delete doubleArray; + } + } +}; + +DartsDict::DartsDict() { internal = new DartsInternal; } + +DartsDict::~DartsDict() { delete internal; } + +size_t DartsDict::KeyMaxLength() const { return maxLength; } + +Optional DartsDict::Match(const char* word, + size_t len) const { + if (len > maxLength) { + return Optional::Null(); + } + Darts::DoubleArray& dict = *internal->doubleArray; + Darts::DoubleArray::result_pair_type result; + + dict.exactMatchSearch(word, result, len); + if (result.value != -1) { + return Optional( + lexicon->At(static_cast(result.value))); + } else { + return Optional::Null(); + } +} + +Optional DartsDict::MatchPrefix(const char* word, + size_t len) const { + const size_t DEFAULT_NUM_ENTRIES = 64; + Darts::DoubleArray& dict = *internal->doubleArray; + Darts::DoubleArray::value_type results[DEFAULT_NUM_ENTRIES]; + Darts::DoubleArray::value_type maxMatchedResult; + size_t numMatched = dict.commonPrefixSearch( + word, results, DEFAULT_NUM_ENTRIES, (std::min)(maxLength, len)); + if (numMatched == 0) { + return Optional::Null(); + } else if ((numMatched > 0) && (numMatched < DEFAULT_NUM_ENTRIES)) { + maxMatchedResult = results[numMatched - 1]; + } else { + Darts::DoubleArray::value_type* rematchedResults = + new Darts::DoubleArray::value_type[numMatched]; + numMatched = dict.commonPrefixSearch(word, rematchedResults, numMatched, + (std::min)(maxLength, len)); + maxMatchedResult = rematchedResults[numMatched - 1]; + delete[] rematchedResults; + } + if (maxMatchedResult >= 0) { + return Optional( + lexicon->At(static_cast(maxMatchedResult))); + } else { + return Optional::Null(); + } +} + +LexiconPtr DartsDict::GetLexicon() const { return lexicon; } + +DartsDictPtr DartsDict::NewFromFile(FILE* fp) { + DartsDictPtr dict(new DartsDict()); + + Darts::DoubleArray* doubleArray = new Darts::DoubleArray(); + size_t headerLen = strlen(OCDHEADER); + void* buffer = malloc(sizeof(char) * headerLen); + size_t bytesRead = fread(buffer, sizeof(char), headerLen, fp); + if (bytesRead != headerLen || memcmp(buffer, OCDHEADER, headerLen) != 0) { + throw InvalidFormat("Invalid OpenCC dictionary header"); + } + free(buffer); + + size_t dartsSize; + bytesRead = fread(&dartsSize, sizeof(size_t), 1, fp); + if (bytesRead * sizeof(size_t) != sizeof(size_t)) { + throw InvalidFormat("Invalid OpenCC dictionary header (dartsSize)"); + } + buffer = malloc(dartsSize); + bytesRead = fread(buffer, 1, dartsSize, fp); + if (bytesRead != dartsSize) { + throw InvalidFormat("Invalid OpenCC dictionary size of darts mismatch"); + } + doubleArray->set_array(buffer); + + auto internal = dict->internal; + internal->buffer = buffer; + internal->binary = BinaryDict::NewFromFile(fp); + internal->doubleArray = doubleArray; + dict->lexicon = internal->binary->GetLexicon(); + dict->maxLength = internal->binary->KeyMaxLength(); + return dict; +} + +DartsDictPtr DartsDict::NewFromDict(const Dict& thatDict) { + DartsDictPtr dict(new DartsDict()); + + Darts::DoubleArray* doubleArray = new Darts::DoubleArray(); + std::vector keys; + std::vector keys_cstr; + size_t maxLength = 0; + const LexiconPtr& lexicon = thatDict.GetLexicon(); + size_t lexiconCount = lexicon->Length(); + keys.resize(lexiconCount); + keys_cstr.resize(lexiconCount); + for (size_t i = 0; i < lexiconCount; i++) { + const DictEntry* entry = lexicon->At(i); + keys[i] = entry->Key(); + keys_cstr[i] = keys[i].c_str(); + maxLength = (std::max)(entry->KeyLength(), maxLength); + } + doubleArray->build(lexicon->Length(), &keys_cstr[0]); + dict->lexicon = lexicon; + dict->maxLength = maxLength; + auto internal = dict->internal; + internal->doubleArray = doubleArray; + return dict; +} + +void DartsDict::SerializeToFile(FILE* fp) const { + Darts::DoubleArray& dict = *internal->doubleArray; + + fwrite(OCDHEADER, sizeof(char), strlen(OCDHEADER), fp); + + size_t dartsSize = dict.total_size(); + fwrite(&dartsSize, sizeof(size_t), 1, fp); + fwrite(dict.array(), sizeof(char), dartsSize, fp); + + internal->binary.reset(new BinaryDict(lexicon)); + internal->binary->SerializeToFile(fp); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/DartsDict.hpp b/Packages/SwiftyOpenCC/OpenCC/src/DartsDict.hpp new file mode 100644 index 0000000000000000000000000000000000000000..eacc1a8c6f02e2cc31b98fe651c2acf22c6b8ebb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/DartsDict.hpp @@ -0,0 +1,60 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" +#include "SerializableDict.hpp" + +namespace opencc { +/** + * Darts dictionary + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT DartsDict : public Dict, public SerializableDict { +public: + virtual ~DartsDict(); + + virtual size_t KeyMaxLength() const; + + virtual Optional Match(const char* word, size_t len) const; + + virtual Optional MatchPrefix(const char* word, + size_t len) const; + + virtual LexiconPtr GetLexicon() const; + + virtual void SerializeToFile(FILE* fp) const; + + /** + * Constructs a DartsDict from another dictionary. + */ + static DartsDictPtr NewFromDict(const Dict& thatDict); + + static DartsDictPtr NewFromFile(FILE* fp); + +private: + DartsDict(); + + size_t maxLength; + LexiconPtr lexicon; + + class DartsInternal; + DartsInternal* internal; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/DartsDictTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/DartsDictTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1742203cf79e4870e2727a1f9a9fa0f2e9980dc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/DartsDictTest.cpp @@ -0,0 +1,71 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DartsDict.hpp" +#include "TestUtilsUTF8.hpp" +#include "TextDictTestBase.hpp" + +namespace opencc { + +class DartsDictTest : public TextDictTestBase { +protected: + DartsDictTest() + : dartsDict(DartsDict::NewFromDict(*textDict.get())), + fileName("dict.ocd"){}; + + const DartsDictPtr dartsDict; + const std::string fileName; +}; + +TEST_F(DartsDictTest, DictTest) { TestDict(dartsDict); } + +TEST_F(DartsDictTest, Serialization) { + dartsDict->opencc::SerializableDict::SerializeToFile(fileName); +} + +TEST_F(DartsDictTest, Deserialization) { + const DartsDictPtr& deserialized = + SerializableDict::NewFromFile(fileName); + TestDict(deserialized); + + const LexiconPtr& lex1 = dartsDict->GetLexicon(); + const LexiconPtr& lex2 = deserialized->GetLexicon(); + + // Compare every entry + EXPECT_EQ(lex1->Length(), lex2->Length()); + for (size_t i = 0; i < lex1->Length(); i++) { + EXPECT_EQ(lex1->At(i)->Key(), lex2->At(i)->Key()); + EXPECT_EQ(lex1->At(i)->NumValues(), lex2->At(i)->NumValues()); + } + + const TextDictPtr deserializedTextDict(new TextDict(lex2)); + TestDict(deserializedTextDict); +} + +TEST_F(DartsDictTest, ExactMatch) { + auto there = dartsDict->Match("積羽沉舟", 12); + EXPECT_FALSE(there.IsNull()); + auto dictEntry = there.Get(); + EXPECT_EQ(1, dictEntry->NumValues()); + EXPECT_EQ(utf8("羣輕折軸"), dictEntry->GetDefault()); + + auto nowhere = dartsDict->Match("積羽沉舟衆口鑠金", 24); + EXPECT_TRUE(nowhere.IsNull()); +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Dict.cpp b/Packages/SwiftyOpenCC/OpenCC/src/Dict.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0e6f4e4ceb08ee6573921df98d259684fc3fa21f --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Dict.cpp @@ -0,0 +1,58 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "Dict.hpp" + +using namespace opencc; + +Optional Dict::MatchPrefix(const char* word, + size_t wordLen) const { + long len = static_cast((std::min)(KeyMaxLength(), wordLen)); + std::string wordTrunc = UTF8Util::TruncateUTF8(word, len); + const char* wordTruncPtr = wordTrunc.c_str() + len; + for (; len > 0;) { + wordTrunc.resize(static_cast(len)); + wordTruncPtr = wordTrunc.c_str() + len; + const Optional& result = Match(wordTrunc.c_str()); + if (!result.IsNull()) { + return result; + } + len -= static_cast(UTF8Util::PrevCharLength(wordTruncPtr)); + } + return Optional::Null(); +} + +std::vector Dict::MatchAllPrefixes(const char* word, + size_t wordLen) const { + std::vector matchedLengths; + long len = static_cast((std::min)(KeyMaxLength(), wordLen)); + std::string wordTrunc = UTF8Util::TruncateUTF8(word, len); + const char* wordTruncPtr = wordTrunc.c_str() + len; + for (; len > 0; + len -= static_cast(UTF8Util::PrevCharLength(wordTruncPtr))) { + wordTrunc.resize(static_cast(len)); + wordTruncPtr = wordTrunc.c_str() + len; + const Optional& result = Match(wordTrunc.c_str()); + if (!result.IsNull()) { + matchedLengths.push_back(result.Get()); + } + } + return matchedLengths; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Dict.hpp b/Packages/SwiftyOpenCC/OpenCC/src/Dict.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1c810346c17ec7b710434890760bd693e17e2956 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Dict.hpp @@ -0,0 +1,92 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" +#include "DictEntry.hpp" + +namespace opencc { +/** + * Abstract class of dictionary + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT Dict { +public: + /** + * Matches a word exactly and returns the DictEntry or Optional::Null(). + */ + virtual Optional Match(const char* word, + size_t len) const = 0; + + /** + * Matches a word exactly and returns the DictEntry or Optional::Null(). + */ + Optional Match(const std::string& word) const { + return Match(word.c_str(), word.length()); + } + + /** + * Matches the longest matched prefix of a word. + * For example given a dictionary having "a", "an", "b", "ba", "ban", "bana", + * the longest prefix of "banana" matched is "bana". + */ + virtual Optional MatchPrefix(const char* word, + size_t len) const; + + /** + * Matches the longest matched prefix of a word. + */ + Optional MatchPrefix(const char* word) const { + return MatchPrefix(word, KeyMaxLength()); + } + + /** + * Matches the longest matched prefix of a word. + */ + Optional MatchPrefix(const std::string& word) const { + return MatchPrefix(word.c_str(), word.length()); + } + + /** + * Returns all matched prefixes of a word, sorted by the length (desc). + * For example given a dictionary having "a", "an", "b", "ba", "ban", "bana", + * all the matched prefixes of "banana" are "bana", "ban", "ba", "b". + */ + virtual std::vector MatchAllPrefixes(const char* word, + size_t len) const; + + /** + * Returns all matched prefixes of a word, sorted by the length (desc). + */ + std::vector + MatchAllPrefixes(const std::string& word) const { + return MatchAllPrefixes(word.c_str(), word.length()); + } + + /** + * Returns the length of the longest key in the dictionary. + */ + virtual size_t KeyMaxLength() const = 0; + + /** + * Returns all entries in the dictionary. + */ + virtual LexiconPtr GetLexicon() const = 0; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/DictConverter.cpp b/Packages/SwiftyOpenCC/OpenCC/src/DictConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07cf324a8368f374007321713b862db0f312fc4d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/DictConverter.cpp @@ -0,0 +1,69 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DictConverter.hpp" +#include "MarisaDict.hpp" +#include "TextDict.hpp" + +#ifdef ENABLE_DARTS +#include "DartsDict.hpp" +#endif + +using namespace opencc; + +DictPtr LoadDictionary(const std::string& format, + const std::string& inputFileName) { + if (format == "text") { + return SerializableDict::NewFromFile(inputFileName); + } else if (format == "ocd") { +#ifdef ENABLE_DARTS + return SerializableDict::NewFromFile(inputFileName); +#endif + } else if (format == "ocd2") { + return SerializableDict::NewFromFile(inputFileName); + } + fprintf(stderr, "Unknown dictionary format: %s\n", format.c_str()); + exit(2); + return nullptr; +} + +SerializableDictPtr ConvertDict(const std::string& format, const DictPtr dict) { + if (format == "text") { + return TextDict::NewFromDict(*dict.get()); + } else if (format == "ocd") { +#ifdef ENABLE_DARTS + return DartsDict::NewFromDict(*dict.get()); +#endif + } else if (format == "ocd2") { + return MarisaDict::NewFromDict(*dict.get()); + } + fprintf(stderr, "Unknown dictionary format: %s\n", format.c_str()); + exit(2); + return nullptr; +} + +namespace opencc { +void ConvertDictionary(const std::string inputFileName, + const std::string outputFileName, + const std::string formatFrom, + const std::string formatTo) { + DictPtr dictFrom = LoadDictionary(formatFrom, inputFileName); + SerializableDictPtr dictTo = ConvertDict(formatTo, dictFrom); + dictTo->SerializeToFile(outputFileName); +} +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/DictConverter.hpp b/Packages/SwiftyOpenCC/OpenCC/src/DictConverter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4bc4e8a2155fadfd7f0f81899323a44a14068aa9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/DictConverter.hpp @@ -0,0 +1,32 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2017 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" + +namespace opencc { +/** + * Converts a dictionary from a format to another. + * @ingroup opencc_cpp_api + */ +OPENCC_EXPORT void ConvertDictionary(const std::string inputFileName, + const std::string outputFileName, + const std::string formatFrom, + const std::string formatTo); +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/DictEntry.cpp b/Packages/SwiftyOpenCC/OpenCC/src/DictEntry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..542d4eedb0b3ff426be66c0fdf26098be602cc88 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/DictEntry.cpp @@ -0,0 +1,37 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DictEntry.hpp" + +using namespace opencc; + +std::string MultiValueDictEntry::ToString() const { + // TODO escape space + size_t i = 0; + size_t length = Values().size(); + std::ostringstream buffer; + buffer << Key() << '\t'; + for (const std::string& value : Values()) { + buffer << value; + if (i < length - 1) { + buffer << ' '; + } + i++; + } + return buffer.str(); +} \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/src/DictEntry.hpp b/Packages/SwiftyOpenCC/OpenCC/src/DictEntry.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7b2babda52a4123ccb31ddb9f5f8d285d4772a78 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/DictEntry.hpp @@ -0,0 +1,173 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" +#include "Segments.hpp" +#include "UTF8Util.hpp" + +namespace opencc { +/** + * Key-values pair entry + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT DictEntry { +public: + virtual ~DictEntry() {} + + virtual std::string Key() const = 0; + + virtual std::vector Values() const = 0; + + virtual std::string GetDefault() const = 0; + + virtual size_t NumValues() const = 0; + + virtual std::string ToString() const = 0; + + size_t KeyLength() const { return Key().length(); } + + bool operator<(const DictEntry& that) const { return Key() < that.Key(); } + + bool operator==(const DictEntry& that) const { return Key() == that.Key(); } + + static bool UPtrLessThan(const std::unique_ptr& a, + const std::unique_ptr& b) { + return *a < *b; + } +}; + +class OPENCC_EXPORT NoValueDictEntry : public DictEntry { +public: + NoValueDictEntry(const std::string& _key) : key(_key) {} + + virtual ~NoValueDictEntry() {} + + virtual std::string Key() const { return key; } + + virtual std::vector Values() const { + return std::vector(); + } + + virtual std::string GetDefault() const { return key; } + + virtual size_t NumValues() const { return 0; } + + virtual std::string ToString() const { return key; } + +private: + std::string key; +}; + +class OPENCC_EXPORT SingleValueDictEntry : public DictEntry { +public: + virtual std::string Value() const = 0; + + virtual std::vector Values() const { + return std::vector{Value()}; + } + + virtual std::string GetDefault() const { return Value(); } + + virtual size_t NumValues() const { return 1; } + + virtual std::string ToString() const { + return std::string(Key()) + "\t" + Value(); + } +}; + +class OPENCC_EXPORT StrSingleValueDictEntry : public SingleValueDictEntry { +public: + StrSingleValueDictEntry(const std::string& _key, const std::string& _value) + : key(_key), value(_value) {} + + virtual ~StrSingleValueDictEntry() {} + + virtual std::string Key() const { return key; } + + virtual std::string Value() const { return value; } + +private: + std::string key; + std::string value; +}; + +class OPENCC_EXPORT MultiValueDictEntry : public DictEntry { +public: + virtual std::string GetDefault() const { + if (NumValues() > 0) { + return Values().at(0); + } else { + return Key(); + } + } + + virtual std::string ToString() const; +}; + +class OPENCC_EXPORT StrMultiValueDictEntry : public MultiValueDictEntry { +public: + StrMultiValueDictEntry(const std::string& _key, + const std::vector& _values) + : key(_key), values(_values) {} + + virtual ~StrMultiValueDictEntry() {} + + virtual std::string Key() const { return key; } + + size_t NumValues() const { return values.size(); } + + std::vector Values() const { return values; } + +private: + std::string key; + std::vector values; +}; + +class OPENCC_EXPORT DictEntryFactory { +public: + static DictEntry* New(const std::string& key) { + return new NoValueDictEntry(key); + } + + static DictEntry* New(const std::string& key, const std::string& value) { + return new StrSingleValueDictEntry(key, value); + } + + static DictEntry* New(const std::string& key, + const std::vector& values) { + if (values.size() == 0) { + return New(key); + } else if (values.size() == 1) { + return New(key, values.front()); + } + return new StrMultiValueDictEntry(key, values); + } + + static DictEntry* New(const DictEntry* entry) { + if (entry->NumValues() == 0) { + return new NoValueDictEntry(entry->Key()); + } else if (entry->NumValues() == 1) { + return new StrSingleValueDictEntry(entry->Key(), entry->Values().front()); + } else { + return new StrMultiValueDictEntry(entry->Key(), entry->Values()); + } + } +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/DictGroup.cpp b/Packages/SwiftyOpenCC/OpenCC/src/DictGroup.cpp new file mode 100644 index 0000000000000000000000000000000000000000..702752bcfdd73ea016bea7c793ee13a2cb35ea07 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/DictGroup.cpp @@ -0,0 +1,106 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2021 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "DictGroup.hpp" +#include "Lexicon.hpp" +#include "TextDict.hpp" + +using namespace opencc; + +namespace { + +size_t GetKeyMaxLength(const std::list& dicts) { + size_t keyMaxLength = 0; + for (const DictPtr& dict : dicts) { + keyMaxLength = (std::max)(keyMaxLength, dict->KeyMaxLength()); + } + return keyMaxLength; +} + +} // namespace + +DictGroup::DictGroup(const std::list& _dicts) + : keyMaxLength(GetKeyMaxLength(_dicts)), dicts(_dicts) {} + +DictGroup::~DictGroup() {} + +size_t DictGroup::KeyMaxLength() const { return keyMaxLength; } + +Optional DictGroup::Match(const char* word, + size_t len) const { + for (const auto& dict : dicts) { + const Optional& prefix = dict->Match(word, len); + if (!prefix.IsNull()) { + return prefix; + } + } + return Optional::Null(); +} + +Optional DictGroup::MatchPrefix(const char* word, + size_t len) const { + for (const auto& dict : dicts) { + const Optional& prefix = dict->MatchPrefix(word, len); + if (!prefix.IsNull()) { + return prefix; + } + } + return Optional::Null(); +} + +std::vector DictGroup::MatchAllPrefixes(const char* word, + size_t len) const { + std::map matched; + // Match all prefixes from all dictionaries + for (const auto& dict : dicts) { + const std::vector& entries = + dict->MatchAllPrefixes(word, len); + for (const auto& entry : entries) { + size_t entryLen = entry->KeyLength(); + // If the current length has already result, skip + if (matched.find(entryLen) == matched.end()) { + matched[entryLen] = entry; + } + } + } + std::vector matchedEntries; + for (auto i = matched.rbegin(); i != matched.rend(); i++) { + matchedEntries.push_back(i->second); + } + return matchedEntries; +} + +LexiconPtr DictGroup::GetLexicon() const { + LexiconPtr allLexicon(new Lexicon); + for (const auto& dict : dicts) { + const auto& lexicon = dict->GetLexicon(); + for (const std::unique_ptr& item : *lexicon) { + allLexicon->Add(DictEntryFactory::New(item.get())); + } + } + allLexicon->Sort(); + // Fixme deduplicate + return allLexicon; +} + +DictGroupPtr DictGroup::NewFromDict(const Dict& dict) { + TextDictPtr newDict = TextDict::NewFromDict(dict); + return DictGroupPtr(new DictGroup(std::list{newDict})); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/DictGroup.hpp b/Packages/SwiftyOpenCC/OpenCC/src/DictGroup.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fd51d9133da1b6eac3904009edfd07cdc662e57c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/DictGroup.hpp @@ -0,0 +1,57 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "Common.hpp" +#include "Dict.hpp" + +namespace opencc { +/** + * Group of dictionaries + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT DictGroup : public Dict { +public: + DictGroup(const std::list& dicts); + + static DictGroupPtr NewFromDict(const Dict& dict); + + virtual ~DictGroup(); + + virtual size_t KeyMaxLength() const; + + virtual Optional Match(const char* word, size_t len) const; + + virtual Optional MatchPrefix(const char* word, + size_t len) const; + + virtual std::vector MatchAllPrefixes(const char* word, + size_t len) const; + + virtual LexiconPtr GetLexicon() const; + + const std::list GetDicts() const { return dicts; } + +private: + const size_t keyMaxLength; + const std::list dicts; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/DictGroupTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/DictGroupTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c91731ed18e112e5523644fd503212ccf9a8f385 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/DictGroupTest.cpp @@ -0,0 +1,73 @@ +/* + * Open Chinese Convert + * + * Copyright 2015-2021 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DictGroupTestBase.hpp" + +namespace opencc { + +class DictGroupTest : public DictGroupTestBase { +protected: + DictGroupTest() {} +}; + +TEST_F(DictGroupTest, KeyMaxLength) { + const DictGroupPtr& dictGroup = CreateDictGroupForConversion(); + EXPECT_EQ(6, dictGroup->KeyMaxLength()); + EXPECT_EQ(6, dictGroup->GetDicts().front()->KeyMaxLength()); + EXPECT_EQ(3, dictGroup->GetDicts().back()->KeyMaxLength()); +} + +TEST_F(DictGroupTest, SimpleGroupTest) { + const DictGroupPtr& dictGroup = CreateDictGroupForConversion(); + { + const auto& entry = dictGroup->Dict::MatchPrefix(utf8("Unknown")); + EXPECT_TRUE(entry.IsNull()); + } + { + const auto& entry = dictGroup->Dict::MatchPrefix(utf8("里面")); + EXPECT_FALSE(entry.IsNull()); + EXPECT_EQ(3, entry.Get()->KeyLength()); + EXPECT_EQ(utf8("裏"), entry.Get()->GetDefault()); + } + { + const auto& matches = dictGroup->Dict::MatchAllPrefixes(utf8("干燥")); + EXPECT_EQ(2, matches.size()); + EXPECT_EQ(utf8("乾燥"), matches.at(0)->GetDefault()); + EXPECT_EQ(utf8("幹"), matches.at(1)->GetDefault()); + } +} + +TEST_F(DictGroupTest, TaiwanPhraseGroupTest) { + const DictGroupPtr dictGroup(new DictGroup( + std::list{CreateDictForPhrases(), CreateTaiwanPhraseDict()})); + { + const auto& entry = dictGroup->Dict::MatchPrefix(utf8("鼠标")); + EXPECT_EQ(utf8("鼠標"), entry.Get()->GetDefault()); + } + { + const auto& entry = dictGroup->Dict::MatchPrefix(utf8("克罗地亚")); + EXPECT_EQ(utf8("克羅埃西亞"), entry.Get()->GetDefault()); + } + { + const auto& matches = dictGroup->Dict::MatchAllPrefixes(utf8("鼠标")); + EXPECT_EQ(1, matches.size()); + EXPECT_EQ(utf8("鼠標"), matches[0]->GetDefault()); + } +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/DictGroupTestBase.hpp b/Packages/SwiftyOpenCC/OpenCC/src/DictGroupTestBase.hpp new file mode 100644 index 0000000000000000000000000000000000000000..db33f7360a7c381939029c502c097319628677ee --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/DictGroupTestBase.hpp @@ -0,0 +1,37 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "DictGroup.hpp" +#include "TextDictTestBase.hpp" + +namespace opencc { + +class DictGroupTestBase : public TextDictTestBase { +protected: + DictGroupPtr CreateDictGroupForConversion() const { + DictPtr phrasesDict = CreateDictForPhrases(); + DictPtr charactersDict = CreateDictForCharacters(); + DictGroupPtr dictGroup( + new DictGroup(std::list{phrasesDict, charactersDict})); + return dictGroup; + } +}; + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Exception.hpp b/Packages/SwiftyOpenCC/OpenCC/src/Exception.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7875537f60e042135019536daa6943652e60d901 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Exception.hpp @@ -0,0 +1,88 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "Export.hpp" + +#if defined(_MSC_VER) && _MSC_VER < 1900 +// Before Visual Studio 2015 (14.0), C++ 11 "noexcept" qualifier is not +// supported +#define noexcept +#endif // ifdef _MSC_VER + +namespace opencc { + +class OPENCC_EXPORT Exception { +public: + Exception() {} + + virtual ~Exception() throw() {} + + Exception(const std::string& _message) : message(_message) {} + + virtual const char* what() const noexcept { return message.c_str(); } + +protected: + std::string message; +}; + +class OPENCC_EXPORT FileNotFound : public Exception { +public: + FileNotFound(const std::string& fileName) + : Exception(fileName + " not found or not accessible.") {} +}; + +class OPENCC_EXPORT FileNotWritable : public Exception { +public: + FileNotWritable(const std::string& fileName) + : Exception(fileName + " not writable.") {} +}; + +class OPENCC_EXPORT InvalidFormat : public Exception { +public: + InvalidFormat(const std::string& message) + : Exception("Invalid format: " + message) {} +}; + +class OPENCC_EXPORT InvalidTextDictionary : public InvalidFormat { +public: + InvalidTextDictionary(const std::string& _message, size_t lineNum) + : InvalidFormat("") { + std::ostringstream buffer; + buffer << "Invalid text dictionary at line " << lineNum << ": " << _message; + message = buffer.str(); + } +}; + +class OPENCC_EXPORT InvalidUTF8 : public Exception { +public: + InvalidUTF8(const std::string& _message) + : Exception("Invalid UTF8: " + _message) {} +}; + +class OPENCC_EXPORT ShouldNotBeHere : public Exception { +public: + ShouldNotBeHere() : Exception("ShouldNotBeHere! This must be a bug.") {} +}; + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Export.hpp b/Packages/SwiftyOpenCC/OpenCC/src/Export.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0015e880f3e09f4d79511edfa78dbb1081027e11 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Export.hpp @@ -0,0 +1,40 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#if defined(Opencc_BUILT_AS_STATIC) || !defined(_WIN32) +#define OPENCC_EXPORT +#define OPENCC_NO_EXPORT +#else // if defined(Opencc_BUILT_AS_STATIC) || !defined(_WIN32) +#ifndef OPENCC_EXPORT +#ifdef libopencc_EXPORTS + +/* We are building this library */ +#define OPENCC_EXPORT __declspec(dllexport) +#else // ifdef libopencc_EXPORTS + +/* We are using this library */ +#define OPENCC_EXPORT __declspec(dllimport) +#endif // ifdef libopencc_EXPORTS +#endif // ifndef OPENCC_EXPORT + +#ifndef OPENCC_NO_EXPORT +#define OPENCC_NO_EXPORT +#endif // ifndef OPENCC_NO_EXPORT +#endif // if defined(Opencc_BUILT_AS_STATIC) || !defined(_WIN32) diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Lexicon.cpp b/Packages/SwiftyOpenCC/OpenCC/src/Lexicon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a3612455538928ec5cae04950f505194c910cd25 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Lexicon.cpp @@ -0,0 +1,42 @@ +/* + * Open Chinese Convert + * + * Copyright 2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "Lexicon.hpp" +namespace opencc { + +void Lexicon::Sort() { + std::sort(entries.begin(), entries.end(), DictEntry::UPtrLessThan); +} + +bool Lexicon::IsSorted() { + return std::is_sorted(entries.begin(), entries.end(), + DictEntry::UPtrLessThan); +} + +bool Lexicon::IsUnique() { + for (size_t i = 1; i < entries.size(); ++i) { + if (entries[i - 1]->Key() == entries[i]->Key()) { + return false; + } + } + return true; +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Lexicon.hpp b/Packages/SwiftyOpenCC/OpenCC/src/Lexicon.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bb8724c4ad768493365ff01a0bb35ec8c5824e10 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Lexicon.hpp @@ -0,0 +1,67 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" +#include "DictEntry.hpp" + +namespace opencc { +/** + * Storage of all entries + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT Lexicon { +public: + Lexicon() {} + Lexicon(std::vector> entries_) + : entries(std::move(entries_)) {} + Lexicon(const Lexicon&) = delete; + Lexicon& operator=(const Lexicon&) = delete; + + // Lexicon will take the ownership of the entry. + void Add(DictEntry* entry) { entries.emplace_back(entry); } + + void Add(std::unique_ptr entry) { + entries.push_back(std::move(entry)); + } + + void Sort(); + + // Returns true if the lexicon is sorted by key. + bool IsSorted(); + + // Returns true if every key unique (after sorted). + bool IsUnique(); + + const DictEntry* At(size_t index) const { return entries.at(index).get(); } + + size_t Length() const { return entries.size(); } + + std::vector>::const_iterator begin() const { + return entries.begin(); + } + + std::vector>::const_iterator end() const { + return entries.end(); + } + +private: + std::vector> entries; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/MarisaDict.cpp b/Packages/SwiftyOpenCC/OpenCC/src/MarisaDict.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0936f2f56f4de800d06bd55c4e061064131d460a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/MarisaDict.cpp @@ -0,0 +1,166 @@ +/* + * Open Chinese Convert + * + * Copyright 2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "marisa.h" + +#include "Lexicon.hpp" +#include "MarisaDict.hpp" +#include "SerializedValues.hpp" + +using namespace opencc; + +namespace { +static const char* OCD2_HEADER = "OPENCC_MARISA_0.2.5"; +} + +class MarisaDict::MarisaInternal { +public: + std::unique_ptr marisa; + + MarisaInternal() : marisa(new marisa::Trie()) {} +}; + +MarisaDict::MarisaDict() : internal(new MarisaInternal()) {} + +MarisaDict::~MarisaDict() {} + +size_t MarisaDict::KeyMaxLength() const { return maxLength; } + +Optional MarisaDict::Match(const char* word, + size_t len) const { + if (len > maxLength) { + return Optional::Null(); + } + const marisa::Trie& trie = *internal->marisa; + marisa::Agent agent; + agent.set_query(word, len); + if (trie.lookup(agent)) { + return Optional(lexicon->At(agent.key().id())); + } else { + return Optional::Null(); + } +} + +Optional MarisaDict::MatchPrefix(const char* word, + size_t len) const { + const marisa::Trie& trie = *internal->marisa; + marisa::Agent agent; + agent.set_query(word, (std::min)(maxLength, len)); + const DictEntry* match = nullptr; + while (trie.common_prefix_search(agent)) { + match = lexicon->At(agent.key().id()); + } + if (match == nullptr) { + return Optional::Null(); + } else { + return Optional(match); + } +} + +std::vector MarisaDict::MatchAllPrefixes(const char* word, + size_t len) const { + const marisa::Trie& trie = *internal->marisa; + marisa::Agent agent; + agent.set_query(word, (std::min)(maxLength, len)); + std::vector matches; + while (trie.common_prefix_search(agent)) { + matches.push_back(lexicon->At(agent.key().id())); + } + std::reverse(matches.begin(), matches.end()); + return matches; +} + +LexiconPtr MarisaDict::GetLexicon() const { return lexicon; } + +MarisaDictPtr MarisaDict::NewFromFile(FILE* fp) { + // Verify file header + size_t headerLen = strlen(OCD2_HEADER); + void* buffer = malloc(sizeof(char) * headerLen); + size_t bytesRead = fread(buffer, sizeof(char), headerLen, fp); + if (bytesRead != headerLen || memcmp(buffer, OCD2_HEADER, headerLen) != 0) { + throw InvalidFormat("Invalid OpenCC dictionary header"); + } + free(buffer); + // Read Marisa Trie + MarisaDictPtr dict(new MarisaDict()); + marisa::fread(fp, dict->internal->marisa.get()); + std::shared_ptr serialized_values = + SerializedValues::NewFromFile(fp); + LexiconPtr values_lexicon = serialized_values->GetLexicon(); + // Extract lexicon from built Marisa Trie, in order to get the order of keys. + marisa::Agent agent; + agent.set_query(""); + std::vector> entries; + entries.resize(values_lexicon->Length()); + size_t maxLength = 0; + while (dict->internal->marisa->predictive_search(agent)) { + const std::string key(agent.key().ptr(), agent.key().length()); + size_t id = agent.key().id(); + maxLength = (std::max)(key.length(), maxLength); + std::unique_ptr entry( + DictEntryFactory::New(key, values_lexicon->At(id)->Values())); + entries[id] = std::move(entry); + } + // Read values + dict->lexicon.reset(new Lexicon(std::move(entries))); + dict->maxLength = maxLength; + return dict; +} + +MarisaDictPtr MarisaDict::NewFromDict(const Dict& thatDict) { + // Extract lexicon into marisa::Keyset and a map. + const LexiconPtr& thatLexicon = thatDict.GetLexicon(); + size_t maxLength = 0; + marisa::Keyset keyset; + std::unordered_map> key_value_map; + for (size_t i = 0; i < thatLexicon->Length(); i++) { + const DictEntry* entry = thatLexicon->At(i); + keyset.push_back(entry->Key().c_str()); + key_value_map[entry->Key()].reset(DictEntryFactory::New(entry)); + maxLength = (std::max)(entry->KeyLength(), maxLength); + } + // Build Marisa Trie + MarisaDictPtr dict(new MarisaDict()); + dict->internal->marisa->build(keyset); + // Extract lexicon from built Marisa Trie, in order to get the order of keys. + marisa::Agent agent; + agent.set_query(""); + std::vector> entries; + entries.resize(thatLexicon->Length()); + while (dict->internal->marisa->predictive_search(agent)) { + std::string key(agent.key().ptr(), agent.key().length()); + std::unique_ptr entry = std::move(key_value_map[key]); + entries[agent.key().id()] = std::move(entry); + } + // Set lexicon with entries ordered by Marisa Trie key id. + dict->lexicon.reset(new Lexicon(std::move(entries))); + dict->maxLength = maxLength; + return dict; +} + +void MarisaDict::SerializeToFile(FILE* fp) const { + fwrite(OCD2_HEADER, sizeof(char), strlen(OCD2_HEADER), fp); + marisa::fwrite(fp, *internal->marisa); + std::unique_ptr serialized_values( + new SerializedValues(lexicon)); + serialized_values->SerializeToFile(fp); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/MarisaDict.hpp b/Packages/SwiftyOpenCC/OpenCC/src/MarisaDict.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6917c23aa885381d803851ccda080c3684c82c12 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/MarisaDict.hpp @@ -0,0 +1,63 @@ +/* + * Open Chinese Convert + * + * Copyright 2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" +#include "SerializableDict.hpp" + +namespace opencc { +/** + * Darts dictionary + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT MarisaDict : public Dict, public SerializableDict { +public: + virtual ~MarisaDict(); + + virtual size_t KeyMaxLength() const; + + virtual Optional Match(const char* word, size_t len) const; + + virtual Optional MatchPrefix(const char* word, + size_t len) const; + + virtual std::vector MatchAllPrefixes(const char* word, + size_t len) const; + + virtual LexiconPtr GetLexicon() const; + + virtual void SerializeToFile(FILE* fp) const; + + /** + * Constructs a MarisaDict from another dictionary. + */ + static MarisaDictPtr NewFromDict(const Dict& thatDict); + + static MarisaDictPtr NewFromFile(FILE* fp); + +private: + MarisaDict(); + + size_t maxLength; + LexiconPtr lexicon; + + class MarisaInternal; + std::unique_ptr internal; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/MarisaDictTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/MarisaDictTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..66036a4181621c04c2332a9da142e35a29a73b50 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/MarisaDictTest.cpp @@ -0,0 +1,94 @@ +/* + * Open Chinese Convert + * + * Copyright 2020-2021 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MarisaDict.hpp" +#include "TestUtilsUTF8.hpp" +#include "TextDictTestBase.hpp" + +namespace opencc { + +class MarisaDictTest : public TextDictTestBase { +protected: + MarisaDictTest() + : dict(MarisaDict::NewFromDict(*textDict)), fileName("dict.ocd2"){}; + + const MarisaDictPtr dict; + const std::string fileName; +}; + +TEST_F(MarisaDictTest, DictTest) { TestDict(dict); } + +TEST_F(MarisaDictTest, Serialization) { + dict->opencc::SerializableDict::SerializeToFile(fileName); +} + +TEST_F(MarisaDictTest, Deserialization) { + const MarisaDictPtr& deserialized = + SerializableDict::NewFromFile(fileName); + TestDict(deserialized); + + const LexiconPtr& lex1 = dict->GetLexicon(); + const LexiconPtr& lex2 = deserialized->GetLexicon(); + + // Compare every entry + EXPECT_EQ(lex1->Length(), lex2->Length()); + for (size_t i = 0; i < lex1->Length(); i++) { + EXPECT_EQ(lex1->At(i)->Key(), lex2->At(i)->Key()); + EXPECT_EQ(lex1->At(i)->NumValues(), lex2->At(i)->NumValues()); + } +} + +TEST_F(MarisaDictTest, ExactMatch) { + auto there = dict->Match("積羽沉舟", 12); + EXPECT_FALSE(there.IsNull()); + auto dictEntry = there.Get(); + EXPECT_EQ(1, dictEntry->NumValues()); + EXPECT_EQ(utf8("羣輕折軸"), dictEntry->GetDefault()); + + auto nowhere = dict->Match("積羽沉舟衆口鑠金", 24); + EXPECT_TRUE(nowhere.IsNull()); +} + +TEST_F(MarisaDictTest, MatchPrefix) { + { + auto there = dict->MatchPrefix("清華", 3); + EXPECT_FALSE(there.IsNull()); + auto dictEntry = there.Get(); + EXPECT_EQ(utf8("Tsing"), dictEntry->GetDefault()); + } + { + auto there = dict->MatchPrefix("清華", 5); + EXPECT_FALSE(there.IsNull()); + auto dictEntry = there.Get(); + EXPECT_EQ(utf8("Tsing"), dictEntry->GetDefault()); + } + { + auto there = dict->MatchPrefix("清華", 6); + EXPECT_FALSE(there.IsNull()); + auto dictEntry = there.Get(); + EXPECT_EQ(utf8("Tsinghua"), dictEntry->GetDefault()); + } + { + auto there = dict->MatchPrefix("清華", 100); + EXPECT_FALSE(there.IsNull()); + auto dictEntry = there.Get(); + EXPECT_EQ(utf8("Tsinghua"), dictEntry->GetDefault()); + } +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/MaxMatchSegmentation.cpp b/Packages/SwiftyOpenCC/OpenCC/src/MaxMatchSegmentation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5cdd79f8806221fd5452f1a89636ae3c952dfc48 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/MaxMatchSegmentation.cpp @@ -0,0 +1,51 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MaxMatchSegmentation.hpp" + +using namespace opencc; + +SegmentsPtr MaxMatchSegmentation::Segment(const std::string& text) const { + SegmentsPtr segments(new Segments); + const char* segStart = text.c_str(); + size_t segLength = 0; + auto clearBuffer = [&segments, &segStart, &segLength]() { + if (segLength > 0) { + segments->AddSegment(UTF8Util::FromSubstr(segStart, segLength)); + segLength = 0; + } + }; + size_t length = text.length(); + for (const char* pstr = text.c_str(); *pstr != '\0';) { + const Optional& matched = dict->MatchPrefix(pstr, length); + size_t matchedLength; + if (matched.IsNull()) { + matchedLength = UTF8Util::NextCharLength(pstr); + segLength += matchedLength; + } else { + clearBuffer(); + matchedLength = matched.Get()->KeyLength(); + segments->AddSegment(matched.Get()->Key()); + segStart = pstr + matchedLength; + } + pstr += matchedLength; + length -= matchedLength; + } + clearBuffer(); + return segments; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/MaxMatchSegmentation.hpp b/Packages/SwiftyOpenCC/OpenCC/src/MaxMatchSegmentation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1ecc227e2ed0920af95527a25c15854ca4faa698 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/MaxMatchSegmentation.hpp @@ -0,0 +1,43 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" +#include "DictGroup.hpp" +#include "Segmentation.hpp" + +namespace opencc { +/** + * Implementation of maximal match segmentation + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT MaxMatchSegmentation : public Segmentation { +public: + MaxMatchSegmentation(const DictPtr _dict) : dict(_dict) {} + + virtual ~MaxMatchSegmentation() {} + + virtual SegmentsPtr Segment(const std::string& text) const; + + const DictPtr GetDict() const { return dict; } + +private: + const DictPtr dict; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/MaxMatchSegmentationTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/MaxMatchSegmentationTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..775c7efb473941f95699d56b3169136e3b6dcab9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/MaxMatchSegmentationTest.cpp @@ -0,0 +1,46 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MaxMatchSegmentation.hpp" +#include "DictGroupTestBase.hpp" + +namespace opencc { + +class MaxMatchSegmentationTest : public DictGroupTestBase { +protected: + MaxMatchSegmentationTest() {} + + virtual void SetUp() { + dict = CreateDictGroupForConversion(); + segmenter = SegmentationPtr(new MaxMatchSegmentation(dict)); + } + + DictPtr dict; + SegmentationPtr segmenter; +}; + +TEST_F(MaxMatchSegmentationTest, Segment) { + const auto& segments = segmenter->Segment(utf8("太后的头发干燥")); + EXPECT_EQ(4, segments->Length()); + EXPECT_EQ(utf8("太后"), std::string(segments->At(0))); + EXPECT_EQ(utf8("的"), std::string(segments->At(1))); + EXPECT_EQ(utf8("头发"), std::string(segments->At(2))); + EXPECT_EQ(utf8("干燥"), std::string(segments->At(3))); +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Optional.hpp b/Packages/SwiftyOpenCC/OpenCC/src/Optional.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8a510f43b1c9d637678b68209e74b828e5c59648 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Optional.hpp @@ -0,0 +1,76 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace opencc { +/** + * A class that wraps type T into a nullable type. + * @ingroup opencc_cpp_api + */ +template class Optional { +public: + /** + * The constructor of Optional. + */ + Optional(T actual) : isNull(false), data(actual) {} + + /** + * Returns true if the instance is null. + */ + bool IsNull() const { return isNull; } + + /** + * Returns the containing data of the instance. + */ + const T& Get() const { return data; } + + /** + * Constructs a null instance. + */ + static Optional Null() { return Optional(); } + +private: + Optional() : isNull(true) {} + + bool isNull; + T data; +}; + +/** + * Specialization of Optional for pointers. + * + * Reduce a bool. + */ +template class Optional { +private: + Optional() : data(nullptr) {} + + typedef T* TPtr; + TPtr data; + +public: + Optional(TPtr actual) : data(actual) {} + + bool IsNull() const { return data == nullptr; } + + const TPtr& Get() const { return data; } + + static Optional Null() { return Optional(); } +}; +} // namespace opencc \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/src/PhraseExtract.cpp b/Packages/SwiftyOpenCC/OpenCC/src/PhraseExtract.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9a62466b0b8835eab77c15ee2943a2cd86c1359 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/PhraseExtract.cpp @@ -0,0 +1,479 @@ +/* + * Open Chinese Convert + * + * Copyright 2015-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "marisa/trie.h" + +#include "PhraseExtract.hpp" + +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") +#endif + +namespace opencc { + +namespace internal { + +bool ContainsPunctuation(const PhraseExtract::UTF8StringSlice8Bit& word) { + static const std::vector punctuations = { + " ", "\n", "\r", "\t", "-", ",", ".", "?", "!", "*", " ", + ",", "。", "、", ";", ":", "?", "!", "…", "“", "”", "「", + "」", "—", "-", "(", ")", "《", "》", ".", "/", "\"}; + for (const auto& punctuation : punctuations) { + if (word.FindBytePosition(punctuation) != + static_cast(-1)) { + return true; + } + } + return false; +} + +} // namespace internal + +class PhraseExtract::DictType { +public: + typedef PhraseExtract::Signals ValueType; + typedef std::pair ItemType; + + PhraseExtract::Signals& Get(const UTF8StringSlice8Bit& key) { + marisa::Agent agent; + agent.set_query(key.CString(), key.ByteLength()); + if (marisa_trie.lookup(agent)) { + int item_id = marisa_id_item_map[agent.key().id()]; + return items[item_id].second; + } + + throw ShouldNotBeHere(); + } + + PhraseExtract::Signals& AddKey(const UTF8StringSlice8Bit& key) { + return dict[key]; + } + + void Clear() { + ClearDict(); + marisa_trie.clear(); + } + + const std::vector& Items() const { return items; } + + void Build() { + BuildKeys(); + BuildTrie(); + } + +private: + void BuildKeys() { + items.reserve(dict.size()); + for (const auto& item : dict) { + items.push_back(item); + } + ClearDict(); + std::sort( + items.begin(), items.end(), + [](const ItemType& a, const ItemType& b) { return a.first < b.first; }); + } + + void ClearDict() { + std::unordered_map() + .swap(dict); + } + + void BuildTrie() { + std::unordered_map key_item_id_map; + marisa::Keyset keyset; + for (size_t i = 0; i < items.size(); i++) { + const auto& key = items[i].first; + key_item_id_map[key.ToString()] = i; + keyset.push_back(key.CString(), key.ByteLength()); + } + marisa_trie.build(keyset); + marisa::Agent agent; + agent.set_query(""); + marisa_id_item_map.resize(items.size()); + while (marisa_trie.predictive_search(agent)) { + size_t marisa_id = agent.key().id(); + const std::string key(agent.key().ptr(), agent.key().length()); + const auto it = key_item_id_map.find(key); + if (it == key_item_id_map.end()) { + throw ShouldNotBeHere(); + } + int item_id = it->second; + marisa_id_item_map[marisa_id] = item_id; + } + } + + std::unordered_map + dict; + std::vector items; + marisa::Trie marisa_trie; + std::vector marisa_id_item_map; +}; + +using namespace internal; + +bool PhraseExtract::DefaultPreCalculationFilter( + const PhraseExtract&, const PhraseExtract::UTF8StringSlice8Bit&) { + return false; +} + +bool PhraseExtract::DefaultPostCalculationFilter( + const PhraseExtract& phraseExtract, + const PhraseExtract::UTF8StringSlice8Bit& word) { + const PhraseExtract::Signals& signals = phraseExtract.Signal(word); + const double logProbability = phraseExtract.LogProbability(word); + const double cohesionScore = signals.cohesion - logProbability * 0.5; + const double entropyScore = + sqrt((signals.prefixEntropy) * (signals.suffixEntropy + 1)) - + logProbability * 0.85; + bool accept = cohesionScore > 9 && entropyScore > 11 && + signals.prefixEntropy > 0.5 && signals.suffixEntropy > 0 && + signals.prefixEntropy + signals.suffixEntropy > 3; + return !accept; +} + +PhraseExtract::PhraseExtract() + : wordMinLength(2), wordMaxLength(2), prefixSetLength(1), + suffixSetLength(1), preCalculationFilter(DefaultPreCalculationFilter), + postCalculationFilter(DefaultPostCalculationFilter), utf8FullText(""), + signals(new DictType) { + Reset(); +} + +PhraseExtract::~PhraseExtract() { delete signals; } + +void PhraseExtract::Reset() { + prefixesExtracted = false; + suffixesExtracted = false; + frequenciesCalculated = false; + wordCandidatesExtracted = false; + cohesionsCalculated = false; + prefixEntropiesCalculated = false; + suffixEntropiesCalculated = false; + wordsSelected = false; + totalOccurrence = 0; + logTotalOccurrence = 0; + ReleasePrefixes(); + ReleaseSuffixes(); + wordCandidates.clear(); + words.clear(); + signals->Clear(); + utf8FullText = UTF8StringSlice(""); + preCalculationFilter = DefaultPreCalculationFilter; + postCalculationFilter = DefaultPostCalculationFilter; +} + +void PhraseExtract::ExtractSuffixes() { + suffixes.reserve(utf8FullText.UTF8Length() / 2 * + (wordMaxLength + suffixSetLength)); + for (UTF8StringSlice text = utf8FullText; text.UTF8Length() > 0; + text.MoveRight()) { + const LengthType suffixLength = + (std::min)(static_cast(wordMaxLength + suffixSetLength), + text.UTF8Length()); + const UTF8StringSlice& slice = text.Left(suffixLength); + suffixes.push_back(UTF8StringSlice8Bit( + slice.CString(), + static_cast(slice.UTF8Length()), + static_cast(slice.ByteLength()))); + } + suffixes.shrink_to_fit(); + // Sort suffixes + std::sort(suffixes.begin(), suffixes.end()); + suffixesExtracted = true; +} + +void PhraseExtract::ExtractPrefixes() { + prefixes.reserve(utf8FullText.UTF8Length() / 2 * + (wordMaxLength + prefixSetLength)); + for (UTF8StringSlice text = utf8FullText; text.UTF8Length() > 0; + text.MoveLeft()) { + const LengthType prefixLength = + (std::min)(static_cast(wordMaxLength + prefixSetLength), + text.UTF8Length()); + const UTF8StringSlice& slice = text.Right(prefixLength); + prefixes.push_back(UTF8StringSlice8Bit( + slice.CString(), + static_cast(slice.UTF8Length()), + static_cast(slice.ByteLength()))); + } + prefixes.shrink_to_fit(); + // Sort suffixes reversely + std::sort(prefixes.begin(), prefixes.end(), + [](const UTF8StringSlice8Bit& a, const UTF8StringSlice8Bit& b) { + return a.ReverseCompare(b) < 0; + }); + prefixesExtracted = true; +} + +void PhraseExtract::CalculateFrequency() { + if (!suffixesExtracted) { + ExtractSuffixes(); + } + for (const auto& suffix : suffixes) { + for (UTF8StringSlice8Bit::LengthType i = 1; + i <= suffix.UTF8Length() && i <= wordMaxLength; i++) { + const UTF8StringSlice8Bit wordCandidate = suffix.Left(i); + signals->AddKey(wordCandidate).frequency++; + totalOccurrence++; + } + } + logTotalOccurrence = log(totalOccurrence); + signals->Build(); + frequenciesCalculated = true; +} + +void PhraseExtract::ExtractWordCandidates() { + if (!frequenciesCalculated) { + CalculateFrequency(); + } + for (const auto& item : signals->Items()) { + const auto& wordCandidate = item.first; + if (wordCandidate.UTF8Length() < wordMinLength) { + continue; + } + if (ContainsPunctuation(wordCandidate)) { + continue; + } + if (preCalculationFilter(*this, wordCandidate)) { + continue; + } + wordCandidates.push_back(wordCandidate); + } + // Sort by frequency + std::sort(wordCandidates.begin(), wordCandidates.end(), + [this](const UTF8StringSlice8Bit& a, const UTF8StringSlice8Bit& b) { + const size_t freqA = Frequency(a); + const size_t freqB = Frequency(b); + if (freqA > freqB) { + return true; + } else if (freqA < freqB) { + return false; + } else { + return a < b; + } + }); + wordCandidatesExtracted = true; +} + +typedef std::unordered_map + AdjacentSetType; + +template +void CalculatePrefixSuffixEntropy( + const std::vector& presuffixes, + const PhraseExtract::LengthType setLength, + const PhraseExtract::LengthType wordMinLength, + const PhraseExtract::LengthType wordMaxLength, + const std::function& updateEntropy) { + AdjacentSetType adjacentSet; + auto setLength8Bit = + static_cast(setLength); + for (PhraseExtract::LengthType length = wordMinLength; + length <= wordMaxLength; length++) { + adjacentSet.clear(); + PhraseExtract::UTF8StringSlice8Bit lastWord(""); + for (const auto& presuffix : presuffixes) { + if (presuffix.UTF8Length() < length) { + continue; + } + auto length8Bit = + static_cast(length); + const auto& wordCandidate = + SUFFIX ? presuffix.Left(length8Bit) : presuffix.Right(length8Bit); + if (wordCandidate != lastWord) { + updateEntropy(lastWord, adjacentSet); + lastWord = wordCandidate; + } + if (length + setLength <= presuffix.UTF8Length()) { + if (SUFFIX) { + const auto& wordSuffix = + presuffix.SubString(length8Bit, setLength8Bit); + adjacentSet[wordSuffix]++; + } else { + const auto& wordPrefix = presuffix.SubString( + presuffix.UTF8Length() - length8Bit - setLength8Bit, + setLength8Bit); + adjacentSet[wordPrefix]++; + } + } + } + updateEntropy(lastWord, adjacentSet); + } +} + +void PhraseExtract::CalculateSuffixEntropy() { + if (!suffixesExtracted) { + ExtractSuffixes(); + } + if (!frequenciesCalculated) { + CalculateFrequency(); + } + CalculatePrefixSuffixEntropy( + suffixes, suffixSetLength, wordMinLength, wordMaxLength, + [this](const PhraseExtract::UTF8StringSlice8Bit& word, + AdjacentSetType& adjacentSet) { + if (word.UTF8Length() > 0) { + signals->Get(word).suffixEntropy = CalculateEntropy(adjacentSet); + adjacentSet.clear(); + } + }); + suffixEntropiesCalculated = true; +} + +void PhraseExtract::CalculatePrefixEntropy() { + if (!prefixesExtracted) { + ExtractPrefixes(); + } + if (!frequenciesCalculated) { + CalculateFrequency(); + } + CalculatePrefixSuffixEntropy( + prefixes, prefixSetLength, wordMinLength, wordMaxLength, + [this](const PhraseExtract::UTF8StringSlice8Bit& word, + AdjacentSetType& adjacentSet) { + if (word.UTF8Length() > 0) { + signals->Get(word).prefixEntropy = CalculateEntropy(adjacentSet); + adjacentSet.clear(); + } + }); + prefixEntropiesCalculated = true; +} + +void PhraseExtract::CalculateCohesions() { + if (!wordCandidatesExtracted) { + ExtractWordCandidates(); + } + if (!frequenciesCalculated) { + CalculateFrequency(); + } + for (const auto& wordCandidate : wordCandidates) { + signals->Get(wordCandidate).cohesion = CalculateCohesion(wordCandidate); + } + cohesionsCalculated = true; +} + +const PhraseExtract::Signals& +PhraseExtract::Signal(const UTF8StringSlice8Bit& wordCandidate) const { + return signals->Get(wordCandidate); +} + +double PhraseExtract::Cohesion(const UTF8StringSlice8Bit& word) const { + return Signal(word).cohesion; +} + +double PhraseExtract::Entropy(const UTF8StringSlice8Bit& word) const { + return SuffixEntropy(word) + PrefixEntropy(word); +} + +double PhraseExtract::SuffixEntropy(const UTF8StringSlice8Bit& word) const { + return Signal(word).suffixEntropy; +} + +double PhraseExtract::PrefixEntropy(const UTF8StringSlice8Bit& word) const { + return Signal(word).prefixEntropy; +} + +size_t PhraseExtract::Frequency(const UTF8StringSlice8Bit& word) const { + const size_t frequency = Signal(word).frequency; + return frequency; +} + +double PhraseExtract::Probability(const UTF8StringSlice8Bit& word) const { + const size_t frequency = Frequency(word); + return static_cast(frequency) / totalOccurrence; +} + +double PhraseExtract::LogProbability(const UTF8StringSlice8Bit& word) const { + // log(frequency / totalOccurrence) = log(frequency) - log(totalOccurrence) + const size_t frequency = Frequency(word); + return log(frequency) - logTotalOccurrence; +} + +double PhraseExtract::PMI(const UTF8StringSlice8Bit& wordCandidate, + const UTF8StringSlice8Bit& part1, + const UTF8StringSlice8Bit& part2) const { + // PMI(x, y) = log(P(x, y) / (P(x) * P(y))) + // = log(P(x, y)) - log(P(x)) - log(P(y)) + return LogProbability(wordCandidate) - LogProbability(part1) - + LogProbability(part2); +} + +double PhraseExtract::CalculateCohesion( + const UTF8StringSlice8Bit& wordCandidate) const { + // TODO Try average value + double minPMI = INFINITY; + for (UTF8StringSlice8Bit::LengthType leftLength = 1; + leftLength <= wordCandidate.UTF8Length() - 1; leftLength++) { + const auto& leftPart = wordCandidate.Left(leftLength); + const auto& rightPart = + wordCandidate.Right(wordCandidate.UTF8Length() - leftLength); + double pmi = PMI(wordCandidate, leftPart, rightPart); + minPMI = (std::min)(pmi, minPMI); + } + return minPMI; +} + +double PhraseExtract::CalculateEntropy( + const std::unordered_map& choices) const { + double totalChoices = 0; + for (const auto& item : choices) { + totalChoices += item.second; + } + double entropy = 0; + for (const auto& item : choices) { + const size_t occurrence = item.second; + const double probability = occurrence / totalChoices; + entropy += probability * log(probability); + } + if (entropy != 0) { + entropy = -entropy; + } + return entropy; +} + +void PhraseExtract::SelectWords() { + if (!wordCandidatesExtracted) { + ExtractWordCandidates(); + } + if (!cohesionsCalculated) { + CalculateCohesions(); + } + if (!prefixEntropiesCalculated) { + CalculatePrefixEntropy(); + } + if (!suffixEntropiesCalculated) { + CalculateSuffixEntropy(); + } + for (const auto& word : wordCandidates) { + if (!postCalculationFilter(*this, word)) { + words.push_back(word); + } + } + wordsSelected = true; +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/PhraseExtract.hpp b/Packages/SwiftyOpenCC/OpenCC/src/PhraseExtract.hpp new file mode 100644 index 0000000000000000000000000000000000000000..75a165deb0f75ae5f5403b2924d2d54037ef637b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/PhraseExtract.hpp @@ -0,0 +1,195 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "Common.hpp" +#include "UTF8StringSlice.hpp" + +namespace opencc { + +class OPENCC_EXPORT PhraseExtract { +public: + typedef UTF8StringSlice::LengthType LengthType; + + typedef UTF8StringSliceBase UTF8StringSlice8Bit; + + PhraseExtract(); + + virtual ~PhraseExtract(); + + void Extract(const std::string& text) { + SetFullText(text); + ExtractSuffixes(); + CalculateFrequency(); + CalculateSuffixEntropy(); + ReleaseSuffixes(); + ExtractPrefixes(); + CalculatePrefixEntropy(); + ReleasePrefixes(); + ExtractWordCandidates(); + CalculateCohesions(); + SelectWords(); + } + + void SetFullText(const std::string& fullText) { + utf8FullText = UTF8StringSlice(fullText.c_str()); + } + + void SetFullText(const char* fullText) { + utf8FullText = UTF8StringSlice(fullText); + } + + void SetFullText(const UTF8StringSlice& fullText) { utf8FullText = fullText; } + + void SetWordMinLength(const LengthType _wordMinLength) { + wordMinLength = _wordMinLength; + } + + void SetWordMaxLength(const LengthType _wordMaxLength) { + wordMaxLength = _wordMaxLength; + } + + void SetPrefixSetLength(const LengthType _prefixSetLength) { + prefixSetLength = _prefixSetLength; + } + + void SetSuffixSetLength(const LengthType _suffixSetLength) { + suffixSetLength = _suffixSetLength; + } + + // PreCalculationFilter is called after frequencies statistics. + void SetPreCalculationFilter( + const std::function& filter) { + preCalculationFilter = filter; + } + + void SetPostCalculationFilter( + const std::function& filter) { + postCalculationFilter = filter; + } + + void ReleaseSuffixes() { std::vector().swap(suffixes); } + + void ReleasePrefixes() { std::vector().swap(prefixes); } + + const std::vector& Words() const { return words; } + + const std::vector& WordCandidates() const { + return wordCandidates; + } + + struct Signals { + size_t frequency; + double cohesion; + double suffixEntropy; + double prefixEntropy; + }; + + const Signals& Signal(const UTF8StringSlice8Bit& wordCandidate) const; + + double Cohesion(const UTF8StringSlice8Bit& wordCandidate) const; + + double Entropy(const UTF8StringSlice8Bit& wordCandidate) const; + + double SuffixEntropy(const UTF8StringSlice8Bit& wordCandidate) const; + + double PrefixEntropy(const UTF8StringSlice8Bit& wordCandidate) const; + + size_t Frequency(const UTF8StringSlice8Bit& word) const; + + double Probability(const UTF8StringSlice8Bit& word) const; + + double LogProbability(const UTF8StringSlice8Bit& word) const; + + void Reset(); + + void ExtractSuffixes(); + + void ExtractPrefixes(); + + void ExtractWordCandidates(); + + void CalculateFrequency(); + + void CalculateCohesions(); + + void CalculateSuffixEntropy(); + + void CalculatePrefixEntropy(); + + void SelectWords(); + + static bool + DefaultPreCalculationFilter(const PhraseExtract&, + const PhraseExtract::UTF8StringSlice8Bit&); + + static bool + DefaultPostCalculationFilter(const PhraseExtract&, + const PhraseExtract::UTF8StringSlice8Bit&); + +private: + class DictType; + + // Pointwise Mutual Information + double PMI(const UTF8StringSlice8Bit& wordCandidate, + const UTF8StringSlice8Bit& part1, + const UTF8StringSlice8Bit& part2) const; + + double CalculateCohesion(const UTF8StringSlice8Bit& wordCandidate) const; + + double CalculateEntropy( + const std::unordered_map& choices) const; + + LengthType wordMinLength; + LengthType wordMaxLength; + LengthType prefixSetLength; + LengthType suffixSetLength; + std::function + preCalculationFilter; + std::function + postCalculationFilter; + + bool prefixesExtracted; + bool suffixesExtracted; + bool frequenciesCalculated; + bool wordCandidatesExtracted; + bool cohesionsCalculated; + bool prefixEntropiesCalculated; + bool suffixEntropiesCalculated; + bool wordsSelected; + + UTF8StringSlice utf8FullText; + size_t totalOccurrence; + double logTotalOccurrence; + std::vector prefixes; + std::vector suffixes; + std::vector wordCandidates; + std::vector words; + DictType* signals; + + friend class PhraseExtractTest; +}; + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/PhraseExtractTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/PhraseExtractTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..decefac5f1b3bdcf1500dd9ad45cbb6235282408 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/PhraseExtractTest.cpp @@ -0,0 +1,182 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "PhraseExtract.hpp" +#include "TestUtils.hpp" +#include "TestUtilsUTF8.hpp" + +namespace opencc { + +typedef PhraseExtract::UTF8StringSlice8Bit UTF8StringSlice8Bit; + +class PhraseExtractTest : public ::testing::Test { +protected: + PhraseExtractTest() + : siShi(utf8("四是四十是十十四是十四四十是四十")), + punctuation(utf8("一.二.三")) {} + + const std::vector& Suffixes() const { + return phraseExtract.suffixes; + } + + const std::vector& Prefixes() const { + return phraseExtract.prefixes; + } + + PhraseExtract phraseExtract; + + const std::string siShi; + const std::string punctuation; +}; + +TEST_F(PhraseExtractTest, ExtractSuffixes) { + phraseExtract.Reset(); + phraseExtract.SetWordMinLength(1); + phraseExtract.SetWordMaxLength(3); + phraseExtract.SetFullText(siShi); + phraseExtract.ExtractSuffixes(); + EXPECT_EQ( + std::vector( + {"十", "十十四是", "十四四十", "十四是十", "十是十十", "十是四十", + "四十", "四十是十", "四十是四", "四四十是", "四是十四", "四是四十", + "是十十四", "是十四四", "是四十", "是四十是"}), + Suffixes()); +} + +TEST_F(PhraseExtractTest, ExtractPrefixes) { + phraseExtract.Reset(); + phraseExtract.SetWordMinLength(1); + phraseExtract.SetWordMaxLength(3); + phraseExtract.SetFullText(siShi); + phraseExtract.ExtractPrefixes(); + EXPECT_EQ( + std::vector( + {"十是十十", "十四四十", "十是四十", "四是四十", "四十是十", + "十四是十", "四", "是十十四", "四是十四", "是十四四", "四十是四", + "四是四", "四四十是", "是四十是", "四是", "十十四是"}), + Prefixes()); +} + +TEST_F(PhraseExtractTest, CalculateFrequency) { + phraseExtract.Reset(); + phraseExtract.SetWordMinLength(1); + phraseExtract.SetWordMaxLength(3); + phraseExtract.SetFullText(siShi); + phraseExtract.CalculateFrequency(); + EXPECT_EQ(6, phraseExtract.Frequency("四")); + EXPECT_EQ(6, phraseExtract.Frequency("十")); + EXPECT_EQ(4, phraseExtract.Frequency("是")); + EXPECT_EQ(3, phraseExtract.Frequency("四十")); + EXPECT_EQ(2, phraseExtract.Frequency("是四十")); + EXPECT_EQ(2, phraseExtract.Frequency("是四")); + EXPECT_EQ(2, phraseExtract.Frequency("四是")); + EXPECT_DOUBLE_EQ(-2.0149030205422647, phraseExtract.LogProbability("四")); + EXPECT_DOUBLE_EQ(-2.0149030205422647, phraseExtract.LogProbability("十")); + EXPECT_DOUBLE_EQ(-2.4203681286504288, phraseExtract.LogProbability("是")); + EXPECT_DOUBLE_EQ(-2.7080502011022096, phraseExtract.LogProbability("四十")); + EXPECT_DOUBLE_EQ(-3.8066624897703196, phraseExtract.LogProbability("是十十")); +} + +TEST_F(PhraseExtractTest, ExtractWordCandidates) { + phraseExtract.Reset(); + phraseExtract.SetWordMinLength(1); + phraseExtract.SetWordMaxLength(3); + phraseExtract.SetFullText(siShi); + phraseExtract.ExtractWordCandidates(); + EXPECT_EQ(std::vector( + {"十", "四", "是", "四十", "十四", "十是", + "四十是", "四是", "是十", "是四", "是四十", "十十", + "十十四", "十四四", "十四是", "十是十", "十是四", "四四", + "四四十", "四是十", "四是四", "是十十", "是十四"}), + phraseExtract.WordCandidates()); +} + +TEST_F(PhraseExtractTest, CalculateCohesions) { + phraseExtract.Reset(); + phraseExtract.SetWordMinLength(1); + phraseExtract.SetWordMaxLength(3); + phraseExtract.SetFullText(siShi); + phraseExtract.CalculateCohesions(); + EXPECT_DOUBLE_EQ(INFINITY, phraseExtract.Cohesion("四")); + EXPECT_DOUBLE_EQ(1.3217558399823193, phraseExtract.Cohesion("四十")); + EXPECT_DOUBLE_EQ(0.91629073187415511, phraseExtract.Cohesion("十四")); + EXPECT_DOUBLE_EQ(1.3217558399823193, phraseExtract.Cohesion("十是")); + EXPECT_DOUBLE_EQ(1.3217558399823193, phraseExtract.Cohesion("四是四")); + EXPECT_DOUBLE_EQ(1.3217558399823193, phraseExtract.Cohesion("十是十")); +} + +TEST_F(PhraseExtractTest, CalculateSuffixEntropy) { + phraseExtract.Reset(); + phraseExtract.SetWordMinLength(1); + phraseExtract.SetWordMaxLength(3); + phraseExtract.SetFullText(siShi); + phraseExtract.CalculateSuffixEntropy(); + EXPECT_DOUBLE_EQ(1.0549201679861442, phraseExtract.SuffixEntropy("十")); + EXPECT_DOUBLE_EQ(1.0114042647073518, phraseExtract.SuffixEntropy("四")); + EXPECT_DOUBLE_EQ(0.69314718055994529, phraseExtract.SuffixEntropy("十四")); + EXPECT_DOUBLE_EQ(0.69314718055994529, phraseExtract.SuffixEntropy("十是")); + EXPECT_DOUBLE_EQ(0, phraseExtract.SuffixEntropy("四十")); + EXPECT_DOUBLE_EQ(0, phraseExtract.SuffixEntropy("四是四")); + EXPECT_DOUBLE_EQ(0, phraseExtract.SuffixEntropy("十是十")); +} + +TEST_F(PhraseExtractTest, CalculatePrefixEntropy) { + phraseExtract.Reset(); + phraseExtract.SetWordMinLength(1); + phraseExtract.SetWordMaxLength(3); + phraseExtract.SetFullText(siShi); + phraseExtract.CalculatePrefixEntropy(); + EXPECT_DOUBLE_EQ(1.0114042647073516, phraseExtract.PrefixEntropy("十")); + EXPECT_DOUBLE_EQ(1.0549201679861442, phraseExtract.PrefixEntropy("四")); + EXPECT_DOUBLE_EQ(0.69314718055994529, phraseExtract.PrefixEntropy("十四")); + EXPECT_DOUBLE_EQ(0, phraseExtract.PrefixEntropy("十是")); + EXPECT_DOUBLE_EQ(0.63651416829481278, phraseExtract.PrefixEntropy("四十")); + EXPECT_DOUBLE_EQ(0, phraseExtract.PrefixEntropy("四是四")); + EXPECT_DOUBLE_EQ(0, phraseExtract.PrefixEntropy("十是十")); +} + +TEST_F(PhraseExtractTest, SelectWords) { + phraseExtract.Reset(); + phraseExtract.SetWordMinLength(1); + phraseExtract.SetWordMaxLength(3); + phraseExtract.SetFullText(siShi); + phraseExtract.SetPostCalculationFilter( + [](const PhraseExtract& phraseExtract, const UTF8StringSlice8Bit& word) { + return phraseExtract.Frequency(word) == 1; + }); + phraseExtract.SelectWords(); + EXPECT_EQ(std::vector({"十", "四", "是", "四十", "十四", + "十是", "四十是", "四是", "是十", + "是四", "是四十"}), + phraseExtract.Words()); +} + +TEST_F(PhraseExtractTest, Punctuation) { + phraseExtract.Reset(); + phraseExtract.SetWordMinLength(1); + phraseExtract.SetWordMaxLength(2); + phraseExtract.SetFullText(punctuation); + phraseExtract.ExtractPrefixes(); + EXPECT_EQ( + std::vector({"一.", ".二.", "一", "二.三", "一.二"}), + Prefixes()); +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/README.md b/Packages/SwiftyOpenCC/OpenCC/src/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1c98af273697c8b8b6409df21a4f7e9038af4545 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/README.md @@ -0,0 +1,18 @@ +# Source code + +## Dictionary + +### Interface + +* Dict: Declares `Match` and related functions. +* SerializableDict: Declares dictionary serialization and deserialization functions. + +### Implementations + +* TextDict: Tabular separated dictionary format. +* BinaryDict: Stores keys and values in binary format. For serialization only. +* DartsDict: Double-array trie (`.ocd`). +* MarisaDict: Marisa trie (`.ocd2`). +* DictGroup: A wrap of a group of dictionaries. Iterates one by one until a match. + +## Conversion diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Segmentation.cpp b/Packages/SwiftyOpenCC/OpenCC/src/Segmentation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eea099d8ec8a59f94b3e62fdb1838f671f9117fa --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Segmentation.cpp @@ -0,0 +1,17 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Segmentation.hpp b/Packages/SwiftyOpenCC/OpenCC/src/Segmentation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c260ea6de995560929398df37a5c77aecde1700d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Segmentation.hpp @@ -0,0 +1,32 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" + +namespace opencc { +/** + * Abstract segmentation + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT Segmentation { +public: + virtual SegmentsPtr Segment(const std::string& text) const = 0; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/Segments.hpp b/Packages/SwiftyOpenCC/OpenCC/src/Segments.hpp new file mode 100644 index 0000000000000000000000000000000000000000..21c39813c40dce8b641c3d505460ea139aed7be4 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/Segments.hpp @@ -0,0 +1,114 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "Common.hpp" + +namespace opencc { +/** + * Segmented text + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT Segments { +public: + Segments() {} + + Segments(std::initializer_list initList) { + for (const std::string& item : initList) { + AddSegment(item); + } + } + + Segments(std::initializer_list initList) { + for (const std::string& item : initList) { + AddSegment(item); + } + } + + void AddSegment(const char* unmanagedString) { + indexes.push_back(std::make_pair(unmanaged.size(), false)); + unmanaged.push_back(unmanagedString); + } + + void AddSegment(const std::string& str) { + indexes.push_back(std::make_pair(managed.size(), true)); + managed.push_back(str); + } + + class iterator : public std::iterator { + public: + iterator(const Segments* const _segments, size_t _cursor) + : segments(_segments), cursor(_cursor) {} + + iterator& operator++() { + cursor++; + return *this; + } + + bool operator==(const iterator& that) const { + return cursor == that.cursor && segments == that.segments; + } + + bool operator!=(const iterator& that) const { + return !this->operator==(that); + } + + const char* operator*() const { return segments->At(cursor); } + + private: + const Segments* const segments; + size_t cursor; + }; + + const char* At(size_t cursor) const { + const auto& index = indexes[cursor]; + if (index.second) { + return managed[index.first].c_str(); + } else { + return unmanaged[index.first]; + } + } + + size_t Length() const { return indexes.size(); } + + iterator begin() const { return iterator(this, 0); } + + iterator end() const { return iterator(this, indexes.size()); } + + std::string ToString() const { + // TODO implement a nested structure to reduce concatenation, + // like a purely functional differential list + std::ostringstream buffer; + for (const char* segment : *this) { + buffer << segment; + } + return buffer.str(); + } + +private: + Segments(const Segments&) {} + + std::vector unmanaged; + std::vector managed; + // index, managed + std::vector> indexes; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/SerializableDict.hpp b/Packages/SwiftyOpenCC/OpenCC/src/SerializableDict.hpp new file mode 100644 index 0000000000000000000000000000000000000000..17cea8903d7d66c78499d267af64e76b87e4fa8a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/SerializableDict.hpp @@ -0,0 +1,77 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Dict.hpp" + +namespace opencc { +/** + * Serializable dictionary interface + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT SerializableDict { +public: + /** + * Serializes the dictionary and writes in to a file. + */ + virtual void SerializeToFile(FILE* fp) const = 0; + + /** + * Serializes the dictionary and writes in to a file. + */ + virtual void SerializeToFile(const std::string& fileName) const { + FILE* fp = fopen(fileName.c_str(), "wb"); + if (fp == NULL) { + throw FileNotWritable(fileName); + } + SerializeToFile(fp); + fclose(fp); + } + + template + static bool TryLoadFromFile(const std::string& fileName, + std::shared_ptr* dict) { + FILE* fp = +#ifdef _MSC_VER + // well, the 'GetPlatformString' shall return a 'wstring' + _wfopen(UTF8Util::GetPlatformString(fileName).c_str(), L"rb") +#else + fopen(UTF8Util::GetPlatformString(fileName).c_str(), "rb") +#endif // _MSC_VER + ; + + if (fp == NULL) { + return false; + } + std::shared_ptr loadedDict = DICT::NewFromFile(fp); + fclose(fp); + *dict = loadedDict; + return true; + } + + template + static std::shared_ptr NewFromFile(const std::string& fileName) { + std::shared_ptr dict; + if (!TryLoadFromFile(fileName, &dict)) { + throw FileNotFound(fileName); + } + return dict; + } +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/SerializedValues.cpp b/Packages/SwiftyOpenCC/OpenCC/src/SerializedValues.cpp new file mode 100644 index 0000000000000000000000000000000000000000..54f23e018adaaae566ddf2cffc00587a2461b945 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/SerializedValues.cpp @@ -0,0 +1,134 @@ +/* + * Open Chinese Convert + * + * Copyright 2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "Lexicon.hpp" +#include "SerializedValues.hpp" + +using namespace opencc; + +namespace { + +template INT_TYPE ReadInteger(FILE* fp) { + INT_TYPE num; + size_t unitsRead = fread(&num, sizeof(INT_TYPE), 1, fp); + if (unitsRead != 1) { + throw InvalidFormat("Invalid OpenCC binary dictionary."); + } + return num; +} + +template void WriteInteger(FILE* fp, INT_TYPE num) { + size_t unitsWritten = fwrite(&num, sizeof(INT_TYPE), 1, fp); + if (unitsWritten != 1) { + throw InvalidFormat("Cannot write binary dictionary."); + } +} + +} // namespace + +size_t SerializedValues::KeyMaxLength() const { return 0; } + +void SerializedValues::SerializeToFile(FILE* fp) const { + std::string valueBuf; + std::vector valueBytes; + uint32_t valueTotalLength = 0; + ConstructBuffer(&valueBuf, &valueBytes, &valueTotalLength); + // Number of items + uint32_t numItems = static_cast(lexicon->Length()); + WriteInteger(fp, numItems); + + // Data + WriteInteger(fp, valueTotalLength); + fwrite(valueBuf.c_str(), sizeof(char), valueTotalLength, fp); + + size_t valueCursor = 0; + for (const std::unique_ptr& entry : *lexicon) { + // Number of values + uint16_t numValues = static_cast(entry->NumValues()); + WriteInteger(fp, numValues); + // Values offset + for (uint16_t i = 0; i < numValues; i++) { + uint16_t numValueBytes = valueBytes[valueCursor++]; + WriteInteger(fp, numValueBytes); + } + } +} + +std::shared_ptr SerializedValues::NewFromFile(FILE* fp) { + std::shared_ptr dict( + new SerializedValues(LexiconPtr(new Lexicon))); + + // Number of items + uint32_t numItems = ReadInteger(fp); + + // Values + uint32_t valueTotalLength = ReadInteger(fp); + std::string valueBuffer; + valueBuffer.resize(valueTotalLength); + size_t unitsRead = fread(const_cast(valueBuffer.c_str()), sizeof(char), + valueTotalLength, fp); + if (unitsRead != valueTotalLength) { + throw InvalidFormat("Invalid OpenCC binary dictionary (valueBuffer)"); + } + + // Offsets + const char* pValueBuffer = valueBuffer.c_str(); + for (uint32_t i = 0; i < numItems; i++) { + // Number of values + uint16_t numValues = ReadInteger(fp); + // Value offset + std::vector values; + for (uint16_t j = 0; j < numValues; j++) { + const char* value = pValueBuffer; + uint16_t numValueBytes = ReadInteger(fp); + pValueBuffer += numValueBytes; + values.push_back(value); + } + DictEntry* entry = DictEntryFactory::New("", values); + dict->lexicon->Add(entry); + } + + return dict; +} + +void SerializedValues::ConstructBuffer(std::string* valueBuffer, + std::vector* valueBytes, + uint32_t* valueTotalLength) const { + *valueTotalLength = 0; + // Calculate total length. + for (const std::unique_ptr& entry : *lexicon) { + assert(entry->NumValues() != 0); + for (const auto& value : entry->Values()) { + *valueTotalLength += static_cast(value.length()) + 1; + } + } + // Write values to the buffer. + valueBuffer->resize(*valueTotalLength, '\0'); + char* pValueBuffer = const_cast(valueBuffer->c_str()); + for (const std::unique_ptr& entry : *lexicon) { + for (const auto& value : entry->Values()) { + strcpy(pValueBuffer, value.c_str()); + valueBytes->push_back(static_cast(value.length() + 1)); + pValueBuffer += value.length() + 1; + } + } + assert(valueBuffer->c_str() + *valueTotalLength == pValueBuffer); +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/SerializedValues.hpp b/Packages/SwiftyOpenCC/OpenCC/src/SerializedValues.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c17210ba7b743b5b1a81ab7137157391e1118065 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/SerializedValues.hpp @@ -0,0 +1,50 @@ +/* + * Open Chinese Convert + * + * Copyright 2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" +#include "SerializableDict.hpp" + +namespace opencc { +/** + * Binary format for dictionary values serialization. + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT SerializedValues : public SerializableDict { +public: + SerializedValues(const LexiconPtr& _lexicon) : lexicon(_lexicon) {} + + virtual ~SerializedValues() {} + + virtual void SerializeToFile(FILE* fp) const; + + static std::shared_ptr NewFromFile(FILE* fp); + + const LexiconPtr& GetLexicon() const { return lexicon; } + + size_t KeyMaxLength() const; + +private: + LexiconPtr lexicon; + + void ConstructBuffer(std::string* valueBuffer, + std::vector* valueBytes, + uint32_t* valueTotalLength) const; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/SerializedValuesTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/SerializedValuesTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..252514687b5266807aa1eecf9b418a0469f70c5a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/SerializedValuesTest.cpp @@ -0,0 +1,51 @@ +/* + * Open Chinese Convert + * + * Copyright 2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SerializedValues.hpp" +#include "TextDictTestBase.hpp" + +namespace opencc { + +class SerializedValuesTest : public TextDictTestBase { +protected: + SerializedValuesTest() + : binDict(new SerializedValues(textDict->GetLexicon())), + fileName("dict.bin"){}; + + const std::shared_ptr binDict; + const std::string fileName; +}; + +TEST_F(SerializedValuesTest, Serialization) { + binDict->opencc::SerializableDict::SerializeToFile(fileName); +} + +TEST_F(SerializedValuesTest, Deserialization) { + const std::shared_ptr& deserialized = + SerializableDict::NewFromFile(fileName); + const LexiconPtr& lex1 = binDict->GetLexicon(); + const LexiconPtr& lex2 = deserialized->GetLexicon(); + + // Compare every entry + EXPECT_EQ(lex1->Length(), lex2->Length()); + for (size_t i = 0; i < lex1->Length(); i++) { + EXPECT_EQ(lex1->At(i)->NumValues(), lex2->At(i)->NumValues()); + } +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/SimpleConverter.cpp b/Packages/SwiftyOpenCC/OpenCC/src/SimpleConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..417f7a5065759031a7f6a9bd8320e652d4db29c6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/SimpleConverter.cpp @@ -0,0 +1,168 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef _MSC_VER +#define NOMINMAX +#include +#undef NOMINMAX +#endif // _MSC_VER + +#include "Config.hpp" +#include "Converter.hpp" +#include "UTF8Util.hpp" +#include "opencc.h" + +using namespace opencc; + +struct InternalData { + const ConverterPtr converter; + + InternalData(const ConverterPtr& _converter) : converter(_converter) {} +}; + +SimpleConverter::SimpleConverter(const std::string& configFileName) { + try { + Config config; + internalData = new InternalData(config.NewFromFile(configFileName)); + } catch (Exception& ex) { + throw std::runtime_error(ex.what()); + } +} + +SimpleConverter::~SimpleConverter() { delete (InternalData*)internalData; } + +std::string SimpleConverter::Convert(const std::string& input) const { + try { + const InternalData* data = (InternalData*)internalData; + return data->converter->Convert(input); + } catch (Exception& ex) { + throw std::runtime_error(ex.what()); + } +} + +std::string SimpleConverter::Convert(const char* input) const { + return Convert(std::string(input)); +} + +std::string SimpleConverter::Convert(const char* input, size_t length) const { + if (length == static_cast(-1)) { + return Convert(std::string(input)); + } else { + return Convert(UTF8Util::FromSubstr(input, length)); + } +} + +size_t SimpleConverter::Convert(const char* input, char* output) const { + try { + const InternalData* data = (InternalData*)internalData; + return data->converter->Convert(input, output); + } catch (Exception& ex) { + throw std::runtime_error(ex.what()); + } +} + +size_t SimpleConverter::Convert(const char* input, size_t length, + char* output) const { + if (length == static_cast(-1)) { + return Convert(input, output); + } else { + std::string trimmed = UTF8Util::FromSubstr(input, length); + return Convert(trimmed.c_str(), output); + } +} + +static std::string cError; + +opencc_t opencc_open_internal(const char* configFileName) { + try { + if (configFileName == nullptr) { + configFileName = OPENCC_DEFAULT_CONFIG_SIMP_TO_TRAD; + } + SimpleConverter* instance = new SimpleConverter(configFileName); + return instance; + } catch (std::runtime_error& ex) { + cError = ex.what(); + return reinterpret_cast(-1); + } +} + +#ifdef _MSC_VER +opencc_t opencc_open_w(const wchar_t* configFileName) { + try { + if (configFileName == nullptr) { + return opencc_open_internal(nullptr); + } + std::string utf8fn = UTF8Util::U16ToU8(configFileName); + return opencc_open_internal(utf8fn.c_str()); + } catch (std::runtime_error& ex) { + cError = ex.what(); + return reinterpret_cast(-1); + } +} +opencc_t opencc_open(const char* configFileName) { + if (configFileName == nullptr) { + return opencc_open_internal(nullptr); + } + std::wstring wFileName; + int convcnt = MultiByteToWideChar(CP_ACP, 0, configFileName, -1, NULL, 0); + if (convcnt > 0) { + wFileName.resize(convcnt); + MultiByteToWideChar(CP_ACP, 0, configFileName, -1, &wFileName[0], convcnt); + } + return opencc_open_w(wFileName.c_str()); +} +#else +opencc_t opencc_open(const char* configFileName) { + return opencc_open_internal(configFileName); +} +#endif + +int opencc_close(opencc_t opencc) { + SimpleConverter* instance = reinterpret_cast(opencc); + delete instance; + return 0; +} + +size_t opencc_convert_utf8_to_buffer(opencc_t opencc, const char* input, + size_t length, char* output) { + try { + SimpleConverter* instance = reinterpret_cast(opencc); + return instance->Convert(input, length, output); + } catch (std::runtime_error& ex) { + cError = ex.what(); + return static_cast(-1); + } +} + +char* opencc_convert_utf8(opencc_t opencc, const char* input, size_t length) { + try { + SimpleConverter* instance = reinterpret_cast(opencc); + std::string converted = instance->Convert(input, length); + char* output = new char[converted.length() + 1]; + strncpy(output, converted.c_str(), converted.length()); + output[converted.length()] = '\0'; + return output; + } catch (std::runtime_error& ex) { + cError = ex.what(); + return nullptr; + } +} + +void opencc_convert_utf8_free(char* str) { delete[] str; } + +const char* opencc_error(void) { return cError.c_str(); } diff --git a/Packages/SwiftyOpenCC/OpenCC/src/SimpleConverter.hpp b/Packages/SwiftyOpenCC/OpenCC/src/SimpleConverter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..206edea740f0155a767653b9c8ebf4d64138b5f9 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/SimpleConverter.hpp @@ -0,0 +1,93 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Export.hpp" +#include + +#ifndef __OPENCC_SIMPLECONVERTER_HPP_ +#define __OPENCC_SIMPLECONVERTER_HPP_ + +/** + * @defgroup opencc_simple_api OpenCC C++ Simple API + * + * Simple API in C++ language + */ + +namespace opencc { +/** + * A high level converter + * This interface does not require C++11 to compile. + * @ingroup opencc_simple_api + */ +class OPENCC_EXPORT SimpleConverter { +public: + /** + * Constructor of SimpleConverter + * @param configFileName File name of configuration. + */ + SimpleConverter(const std::string& configFileName); + + ~SimpleConverter(); + + /** + * Converts a text + * @param input Text to be converted. + */ + std::string Convert(const std::string& input) const; + + /** + * Converts a text + * @param input A C-Style std::string (terminated by '\0') to be converted. + */ + std::string Convert(const char* input) const; + + /** + * Converts a text + * @param input A C-Style std::string limited by a given length to be + * converted. + * @param length Maximal length in byte of the input std::string. + */ + std::string Convert(const char* input, size_t length) const; + + /** + * Converts a text and writes to an allocated buffer + * Please make sure the buffer has sufficent space. + * @param input A C-Style std::string (terminated by '\0') to be converted. + * @param output Buffer to write the converted text. + * @return Length of converted text. + */ + size_t Convert(const char* input, char* output) const; + + /** + * Converts a text and writes to an allocated buffer + * Please make sure the buffer has sufficent space. + * @param input A C-Style std::string limited by a given length to be + * converted. + * @param length Maximal length in byte of the input std::string. + * @param output Buffer to write the converted text. + * @return Length of converted text. + */ + size_t Convert(const char* input, size_t length, char* output) const; + +private: + const void* internalData; +}; + +} // namespace opencc + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/src/SimpleConverterTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/SimpleConverterTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c645b784282b6f37ca903750edcbf2bc94c8b7b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/SimpleConverterTest.cpp @@ -0,0 +1,80 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ConfigTestBase.hpp" +#include "SimpleConverter.hpp" +#include "TestUtilsUTF8.hpp" +#include "opencc.h" + +namespace opencc { + +class SimpleConverterTest : public ConfigTestBase { +protected: + SimpleConverterTest() {} + + void TestConverter(const std::string& config) const { + const SimpleConverter converter(config); + const std::string& converted = + converter.Convert(utf8("燕燕于飞差池其羽之子于归远送于野")); + EXPECT_EQ(utf8("燕燕于飛差池其羽之子于歸遠送於野"), converted); + } +}; + +TEST_F(SimpleConverterTest, Convert) { TestConverter(CONFIG_TEST_PATH); } + +TEST_F(SimpleConverterTest, Multithreading) { + const auto& routine = [this](const std::string& config) { + TestConverter(config); + }; + std::thread thread1(routine, CONFIG_TEST_PATH); + std::thread thread2(routine, CONFIG_TEST_PATH); + routine(CONFIG_TEST_PATH); + thread1.join(); + thread2.join(); +} + +TEST_F(SimpleConverterTest, CInterface) { + const std::string& text = utf8("燕燕于飞差池其羽之子于归远送于野"); + const std::string& expected = utf8("燕燕于飛差池其羽之子于歸遠送於野"); + { + opencc_t od = opencc_open(CONFIG_TEST_PATH.c_str()); + char* converted = opencc_convert_utf8(od, text.c_str(), (size_t)-1); + EXPECT_EQ(expected, converted); + opencc_convert_utf8_free(converted); + EXPECT_EQ(0, opencc_close(od)); + } + { + char output[1024]; + opencc_t od = opencc_open(CONFIG_TEST_PATH.c_str()); + size_t length = + opencc_convert_utf8_to_buffer(od, text.c_str(), (size_t)-1, output); + EXPECT_EQ(expected.length(), length); + EXPECT_EQ(expected, output); + EXPECT_EQ(0, opencc_close(od)); + } + { + std::string path = "/opencc/no/such/file/or/directory"; + opencc_t od = opencc_open(path.c_str()); + EXPECT_EQ(reinterpret_cast(-1), od); + EXPECT_EQ(path + " not found or not accessible.", opencc_error()); + } +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/TestUtils.hpp b/Packages/SwiftyOpenCC/OpenCC/src/TestUtils.hpp new file mode 100644 index 0000000000000000000000000000000000000000..46ab90df3790ac47149da80f624b78542c51d35d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/TestUtils.hpp @@ -0,0 +1,42 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "gtest/gtest.h" +#include + +namespace opencc { + +using std::string; + +#ifdef _MSC_VER +#define __func__ __FUNCTION__ +#endif // ifdef _MSC_VER + +#define EXPECT_VECTOR_EQ(expected, actual) \ + { \ + const auto& a1 = (expected); \ + const auto& a2 = (actual); \ + EXPECT_EQ(a1.size(), a2.size()); \ + for (size_t i = 0; i < a1.size(); i++) { \ + EXPECT_EQ(a1[i], a2[i]) << "Where i = " << i; \ + } \ + } + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/TestUtilsUTF8.hpp b/Packages/SwiftyOpenCC/OpenCC/src/TestUtilsUTF8.hpp new file mode 100644 index 0000000000000000000000000000000000000000..63784052a87a0b9f1ce5682b6250cfa7138ec477 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/TestUtilsUTF8.hpp @@ -0,0 +1,27 @@ +/* + * Open Chinese Convert + * + * Copyright 2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace opencc { + +#define utf8(str) std::string(str) + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/TextDict.cpp b/Packages/SwiftyOpenCC/OpenCC/src/TextDict.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d256850e352b912423a1781c9dafb7be8d75dcf8 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/TextDict.cpp @@ -0,0 +1,121 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "Lexicon.hpp" +#include "TextDict.hpp" + +using namespace opencc; + +static size_t GetKeyMaxLength(const LexiconPtr& lexicon) { + size_t maxLength = 0; + for (const auto& entry : *lexicon) { + size_t keyLength = entry->KeyLength(); + maxLength = (std::max)(keyLength, maxLength); + } + return maxLength; +} + +static DictEntry* ParseKeyValues(const char* buff, size_t lineNum) { + size_t length; + const char* pbuff = UTF8Util::FindNextInline(buff, '\t'); + if (UTF8Util::IsLineEndingOrFileEnding(*pbuff)) { + throw InvalidTextDictionary("Tabular not found " + std::string(buff), + lineNum); + } + length = static_cast(pbuff - buff); + std::string key = UTF8Util::FromSubstr(buff, length); + std::vector values; + while (!UTF8Util::IsLineEndingOrFileEnding(*pbuff)) { + buff = pbuff = UTF8Util::NextChar(pbuff); + pbuff = UTF8Util::FindNextInline(buff, ' '); + length = static_cast(pbuff - buff); + const std::string& value = UTF8Util::FromSubstr(buff, length); + values.push_back(value); + } + if (values.size() == 0) { + throw InvalidTextDictionary("No value in an item", lineNum); + } else if (values.size() == 1) { + return DictEntryFactory::New(key, values.at(0)); + } else { + return DictEntryFactory::New(key, values); + } +} + +static LexiconPtr ParseLexiconFromFile(FILE* fp) { + const int ENTRY_BUFF_SIZE = 4096; + char buff[ENTRY_BUFF_SIZE]; + LexiconPtr lexicon(new Lexicon); + UTF8Util::SkipUtf8Bom(fp); + size_t lineNum = 1; + while (fgets(buff, ENTRY_BUFF_SIZE, fp)) { + lexicon->Add(ParseKeyValues(buff, lineNum)); + lineNum++; + } + return lexicon; +} + +TextDict::TextDict(const LexiconPtr& _lexicon) + : maxLength(GetKeyMaxLength(_lexicon)), lexicon(_lexicon) { + assert(lexicon->IsSorted()); + assert(lexicon->IsUnique()); +} + +TextDict::~TextDict() {} + +TextDictPtr TextDict::NewFromSortedFile(FILE* fp) { + const LexiconPtr& lexicon = ParseLexiconFromFile(fp); + return TextDictPtr(new TextDict(lexicon)); +} + +TextDictPtr TextDict::NewFromFile(FILE* fp) { + const LexiconPtr& lexicon = ParseLexiconFromFile(fp); + lexicon->Sort(); + if (!lexicon->IsUnique()) { + throw InvalidFormat("The text dictionary contains duplicated keys."); + } + return TextDictPtr(new TextDict(lexicon)); +} + +TextDictPtr TextDict::NewFromDict(const Dict& dict) { + return TextDictPtr(new TextDict(dict.GetLexicon())); +} + +size_t TextDict::KeyMaxLength() const { return maxLength; } + +Optional TextDict::Match(const char* word, size_t len) const { + std::unique_ptr entry( + new NoValueDictEntry(std::string(word, len))); + const auto& found = std::lower_bound(lexicon->begin(), lexicon->end(), entry, + DictEntry::UPtrLessThan); + if ((found != lexicon->end()) && ((*found)->Key() == entry->Key())) { + return Optional(found->get()); + } else { + return Optional::Null(); + } +} + +LexiconPtr TextDict::GetLexicon() const { return lexicon; } + +void TextDict::SerializeToFile(FILE* fp) const { + for (const auto& entry : *lexicon) { + fprintf(fp, "%s\n", entry->ToString().c_str()); + } +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/TextDict.hpp b/Packages/SwiftyOpenCC/OpenCC/src/TextDict.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f1cb67d92e81069a2e74ecb3938acfbaf1d7a21a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/TextDict.hpp @@ -0,0 +1,60 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Common.hpp" +#include "SerializableDict.hpp" + +namespace opencc { +/** + * Text dictionary + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT TextDict : public Dict, public SerializableDict { +public: + /** + * Constructor of TextDict. + * _lexicon must be sorted. + */ + TextDict(const LexiconPtr& _lexicon); + + virtual ~TextDict(); + + virtual size_t KeyMaxLength() const; + + virtual Optional Match(const char* word, size_t len) const; + + virtual LexiconPtr GetLexicon() const; + + virtual void SerializeToFile(FILE* fp) const; + + /** + * Constructs a TextDict from another dictionary. + */ + static TextDictPtr NewFromDict(const Dict& dict); + + static TextDictPtr NewFromFile(FILE* fp); + + static TextDictPtr NewFromSortedFile(FILE* fp); + +private: + const size_t maxLength; + const LexiconPtr lexicon; +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/TextDictTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/TextDictTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0dff7943435939bb500fc2cf8bec7f21eb793cb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/TextDictTest.cpp @@ -0,0 +1,81 @@ +/* + * Open Chinese Convert + * + * Copyright 2015-2021 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TestUtilsUTF8.hpp" +#include "TextDictTestBase.hpp" + +namespace opencc { + +class TextDictTest : public TextDictTestBase { +protected: + TextDictTest() : fileName("dict.txt"){}; + + const std::string fileName; +}; + +TEST_F(TextDictTest, DictTest) { TestDict(textDict); } + +TEST_F(TextDictTest, Serialization) { + textDict->opencc::SerializableDict::SerializeToFile(fileName); +} + +TEST_F(TextDictTest, Deserialization) { + const TextDictPtr& deserialized = + SerializableDict::NewFromFile(fileName); + TestDict(deserialized); +} + +TEST_F(TextDictTest, ExactMatch) { + auto there = textDict->Match("積羽沉舟", 12); + EXPECT_FALSE(there.IsNull()); + auto dictEntry = there.Get(); + EXPECT_EQ(1, dictEntry->NumValues()); + EXPECT_EQ(utf8("羣輕折軸"), dictEntry->GetDefault()); + + auto nowhere = textDict->Match("積羽沉舟衆口鑠金", 24); + EXPECT_TRUE(nowhere.IsNull()); +} + +TEST_F(TextDictTest, MatchPrefix) { + { + auto there = textDict->MatchPrefix("清華", 3); + EXPECT_FALSE(there.IsNull()); + auto dictEntry = there.Get(); + EXPECT_EQ(utf8("Tsing"), dictEntry->GetDefault()); + } + { + auto there = textDict->MatchPrefix("清華", 5); + EXPECT_FALSE(there.IsNull()); + auto dictEntry = there.Get(); + EXPECT_EQ(utf8("Tsing"), dictEntry->GetDefault()); + } + { + auto there = textDict->MatchPrefix("清華", 6); + EXPECT_FALSE(there.IsNull()); + auto dictEntry = there.Get(); + EXPECT_EQ(utf8("Tsinghua"), dictEntry->GetDefault()); + } + { + auto there = textDict->MatchPrefix("清華", 100); + EXPECT_FALSE(there.IsNull()); + auto dictEntry = there.Get(); + EXPECT_EQ(utf8("Tsinghua"), dictEntry->GetDefault()); + } +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/TextDictTestBase.hpp b/Packages/SwiftyOpenCC/OpenCC/src/TextDictTestBase.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e376ffc8fcb121c2b6485a3a606652c5f972094a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/TextDictTestBase.hpp @@ -0,0 +1,148 @@ +/* + * Open Chinese Convert + * + * Copyright 2015-2020 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Lexicon.hpp" +#include "TestUtils.hpp" +#include "TestUtilsUTF8.hpp" +#include "TextDict.hpp" + +namespace opencc { + +class TextDictTestBase : public ::testing::Test { +protected: + TextDictTestBase() : textDict(CreateTextDictForText()){}; + + TextDictPtr CreateTextDictForText() const { + LexiconPtr lexicon(new Lexicon); + lexicon->Add(DictEntryFactory::New("BYVoid", "byv")); + lexicon->Add(DictEntryFactory::New("zigzagzig", "zag")); + lexicon->Add(DictEntryFactory::New(utf8("積羽沉舟"), utf8("羣輕折軸"))); + lexicon->Add(DictEntryFactory::New(utf8("清"), "Tsing")); + lexicon->Add(DictEntryFactory::New(utf8("清華"), "Tsinghua")); + lexicon->Add(DictEntryFactory::New(utf8("清華大學"), "TsinghuaUniversity")); + lexicon->Sort(); + return TextDictPtr(new TextDict(lexicon)); + } + + DictPtr CreateDictForCharacters() const { + LexiconPtr lexicon(new Lexicon); + lexicon->Add(DictEntryFactory::New( + utf8("后"), std::vector{utf8("后"), utf8("後")})); + lexicon->Add(DictEntryFactory::New( + utf8("发"), std::vector{utf8("發"), utf8("髮")})); + lexicon->Add(DictEntryFactory::New( + utf8("干"), + std::vector{utf8("幹"), utf8("乾"), utf8("干")})); + lexicon->Add(DictEntryFactory::New( + utf8("里"), std::vector{utf8("裏"), utf8("里")})); + lexicon->Sort(); + return TextDictPtr(new TextDict(lexicon)); + } + + DictPtr CreateDictForPhrases() const { + LexiconPtr lexicon(new Lexicon); + lexicon->Add(DictEntryFactory::New(utf8("太后"), utf8("太后"))); + lexicon->Add(DictEntryFactory::New(utf8("头发"), utf8("頭髮"))); + lexicon->Add(DictEntryFactory::New(utf8("干燥"), utf8("乾燥"))); + lexicon->Add(DictEntryFactory::New(utf8("鼠标"), utf8("鼠標"))); + lexicon->Sort(); + return TextDictPtr(new TextDict(lexicon)); + } + + DictPtr CreateDictForTaiwanVariants() const { + LexiconPtr lexicon(new Lexicon); + lexicon->Add(DictEntryFactory::New(utf8("裏"), utf8("裡"))); + return TextDictPtr(new TextDict(lexicon)); + } + + DictPtr CreateTaiwanPhraseDict() const { + LexiconPtr lexicon(new Lexicon); + lexicon->Add(DictEntryFactory::New(utf8("鼠标"), utf8("滑鼠"))); + lexicon->Add(DictEntryFactory::New(utf8("服务器"), utf8("伺服器"))); + lexicon->Add(DictEntryFactory::New(utf8("克罗地亚"), utf8("克羅埃西亞"))); + lexicon->Sort(); + return TextDictPtr(new TextDict(lexicon)); + } + + void TestDict(const DictPtr dict) const { + TestMatch(dict); + TestMatchPrefix(dict); + TestMatchAllPrefixes(dict); + } + + void TestMatch(const DictPtr& dict) const { + Optional entry = Optional::Null(); + entry = dict->Match("BYVoid"); + EXPECT_TRUE(!entry.IsNull()); + EXPECT_EQ(utf8("BYVoid"), entry.Get()->Key()); + EXPECT_EQ(utf8("byv"), entry.Get()->GetDefault()); + + entry = dict->Match(""); + EXPECT_TRUE(entry.IsNull()); + + entry = dict->Match("xxx"); + EXPECT_TRUE(entry.IsNull()); + } + + void TestMatchPrefix(const DictPtr& dict) const { + Optional entry = Optional::Null(); + entry = dict->MatchPrefix("BYVoid"); + EXPECT_TRUE(!entry.IsNull()); + EXPECT_EQ(utf8("BYVoid"), entry.Get()->Key()); + EXPECT_EQ(utf8("byv"), entry.Get()->GetDefault()); + + entry = dict->MatchPrefix(utf8("清華大學")); + EXPECT_TRUE(!entry.IsNull()); + EXPECT_EQ(utf8("清華大學"), entry.Get()->Key()); + EXPECT_EQ(utf8("TsinghuaUniversity"), entry.Get()->GetDefault()); + + entry = dict->MatchPrefix("BYVoid123"); + EXPECT_TRUE(!entry.IsNull()); + EXPECT_EQ(utf8("BYVoid"), entry.Get()->Key()); + EXPECT_EQ(utf8("byv"), entry.Get()->GetDefault()); + + entry = dict->MatchPrefix(utf8("積羽沉舟")); + EXPECT_TRUE(!entry.IsNull()); + EXPECT_EQ(utf8("積羽沉舟"), entry.Get()->Key()); + EXPECT_EQ(utf8("羣輕折軸"), entry.Get()->GetDefault()); + + entry = dict->MatchPrefix("Unknown"); + EXPECT_TRUE(entry.IsNull()); + + entry = dict->MatchPrefix(""); + EXPECT_TRUE(entry.IsNull()); + } + + void TestMatchAllPrefixes(const DictPtr& dict) const { + const std::vector matches = + dict->MatchAllPrefixes(utf8("清華大學計算機系")); + EXPECT_EQ(3, matches.size()); + EXPECT_EQ(utf8("清華大學"), matches.at(0)->Key()); + EXPECT_EQ(utf8("TsinghuaUniversity"), matches.at(0)->GetDefault()); + EXPECT_EQ(utf8("清華"), matches.at(1)->Key()); + EXPECT_EQ(utf8("Tsinghua"), matches.at(1)->GetDefault()); + EXPECT_EQ(utf8("清"), matches.at(2)->Key()); + EXPECT_EQ(utf8("Tsing"), matches.at(2)->GetDefault()); + } + + const TextDictPtr textDict; +}; + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/UTF8StringSlice.cpp b/Packages/SwiftyOpenCC/OpenCC/src/UTF8StringSlice.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f55a069d1476bffd753454cd7ef1bb85d2d928be --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/UTF8StringSlice.cpp @@ -0,0 +1,21 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "UTF8StringSlice.hpp" + +namespace opencc {} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/UTF8StringSlice.hpp b/Packages/SwiftyOpenCC/OpenCC/src/UTF8StringSlice.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0c9dfdc6eccd1486f6146776340128b3e9eaa947 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/UTF8StringSlice.hpp @@ -0,0 +1,246 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "Common.hpp" +#include "UTF8Util.hpp" + +namespace opencc { + +namespace internal { + +inline size_t FNVHash(const char* text, const size_t byteLength, + const size_t FNV_prime, const size_t FNV_offset_basis) { + size_t hash = FNV_offset_basis; + for (const char* pstr = text; pstr < text + byteLength; pstr++) { + hash ^= *pstr; + hash *= FNV_prime; + } + return hash; +} + +template size_t FNVHash(const char* text, const size_t byteLength); + +template <> +inline size_t FNVHash<4>(const char* text, const size_t byteLength) { + return FNVHash(text, byteLength, 16777619UL, 2166136261UL); +} + +#if SIZE_MAX == 0xffffffffffffffff +template <> +inline size_t FNVHash<8>(const char* text, const size_t byteLength) { + return FNVHash(text, byteLength, 1099511628211UL, 14695981039346656037UL); +} +#endif + +} // namespace internal + +template class UTF8StringSliceBase { +public: + typedef LENGTH_TYPE LengthType; + + UTF8StringSliceBase(const char* _str) + : str(_str), utf8Length(static_cast(UTF8Util::Length(_str))), + byteLength(static_cast(strlen(_str))) {} + + UTF8StringSliceBase(const char* _str, const LengthType _utf8Length) + : str(_str), utf8Length(_utf8Length) { + CalculateByteLength(); + } + + UTF8StringSliceBase(const char* _str, const LengthType _utf8Length, + const LengthType _byteLength) + : str(_str), utf8Length(_utf8Length), byteLength(_byteLength) { + CalculateByteLength(); + } + + LengthType UTF8Length() const { return utf8Length; } + + LengthType ByteLength() const { return byteLength; } + + UTF8StringSliceBase Left(const LengthType numberOfCharacters) const { + if (numberOfCharacters == UTF8Length()) { + return *this; + } else { + return UTF8StringSliceBase(str, numberOfCharacters); + } + } + + UTF8StringSliceBase Right(const LengthType numberOfCharacters) const { + if (numberOfCharacters == UTF8Length()) { + return *this; + } else { + const char* pstr = str + byteLength; + for (size_t i = 0; i < numberOfCharacters; i++) { + pstr = UTF8Util::PrevChar(pstr); + } + return UTF8StringSliceBase(pstr, numberOfCharacters); + } + } + + UTF8StringSliceBase SubString(const LengthType offset, + const LengthType numberOfCharacters) const { + if (offset == 0) { + return Left(numberOfCharacters); + } else { + const char* pstr = str; + for (size_t i = 0; i < offset; i++) { + pstr = UTF8Util::NextChar(pstr); + } + return UTF8StringSliceBase(pstr, numberOfCharacters); + } + } + + std::string ToString() const { return std::string(str, str + byteLength); } + + const char* CString() const { return str; } + + LengthType CommonPrefixLength(const UTF8StringSliceBase& that) const { + if (str == that.str) { + return (std::min)(utf8Length, that.utf8Length); + } else { + const char* pstr1 = str; + const char* pstr2 = that.str; + for (size_t length = 0; length < utf8Length && length < that.utf8Length; + length++) { + size_t charLen1 = UTF8Util::NextCharLength(pstr1); + size_t charLen2 = UTF8Util::NextCharLength(pstr2); + if (charLen1 != charLen2 || strncmp(pstr1, pstr2, charLen1) != 0) { + return length; + } + pstr1 += charLen1; + pstr2 += charLen2; + } + return 0; + } + } + + void MoveRight() { + if (utf8Length > 0) { + const size_t charLen = UTF8Util::NextCharLength(str); + str += charLen; + utf8Length--; + byteLength -= charLen; + } + } + + void MoveLeft() { + if (utf8Length > 0) { + const size_t charLen = UTF8Util::PrevCharLength(str + byteLength); + utf8Length--; + byteLength -= charLen; + } + } + + int ReverseCompare(const UTF8StringSliceBase& that) const { + const char* pstr1 = str + byteLength; + const char* pstr2 = that.str + that.byteLength; + const size_t length = (std::min)(utf8Length, that.utf8Length); + for (size_t i = 0; i < length; i++) { + const size_t charLen1 = UTF8Util::PrevCharLength(pstr1); + const size_t charLen2 = UTF8Util::PrevCharLength(pstr2); + pstr1 -= charLen1; + pstr2 -= charLen2; + const int cmp = strncmp(pstr1, pstr2, (std::min)(charLen1, charLen2)); + if (cmp < 0) { + return -1; + } else if (cmp > 0) { + return 1; + } else if (charLen1 < charLen2) { + return -1; + } else if (charLen1 > charLen2) { + return 1; + } + } + if (utf8Length < that.utf8Length) { + return -1; + } else if (utf8Length > that.utf8Length) { + return 1; + } else { + return 0; + } + } + + LengthType FindBytePosition(const UTF8StringSliceBase& pattern) const { + return static_cast( + ToString().find(pattern.str, 0, pattern.byteLength)); + } + + bool operator<(const UTF8StringSliceBase& that) const { + return Compare(that) < 0; + } + + bool operator>(const UTF8StringSliceBase& that) const { + return Compare(that) > 0; + } + + bool operator==(const UTF8StringSliceBase& that) const { + return (str == that.str && utf8Length == that.utf8Length) || + Compare(that) == 0; + } + + bool operator!=(const UTF8StringSliceBase& that) const { + return !this->operator==(that); + } + + class Hasher { + public: + size_t operator()(const UTF8StringSliceBase& text) const { + return internal::FNVHash(text.CString(), + text.ByteLength()); + } + }; + +private: + inline int Compare(const UTF8StringSliceBase& that) const { + int cmp = strncmp(str, that.str, (std::min)(byteLength, that.byteLength)); + if (cmp == 0) { + if (utf8Length < that.utf8Length) { + cmp = -1; + } else if (utf8Length > that.utf8Length) { + cmp = 1; + } else { + cmp = 0; + } + } + return cmp; + } + + void CalculateByteLength() { + const char* pstr = str; + for (size_t i = 0; i < utf8Length; i++) { + pstr = UTF8Util::NextChar(pstr); + } + byteLength = static_cast(pstr - str); + } + + const char* str; + LengthType utf8Length; + LengthType byteLength; +}; + +typedef UTF8StringSliceBase UTF8StringSlice; + +template +std::ostream& operator<<(::std::ostream& os, + const UTF8StringSliceBase& str) { + return os << str.ToString(); +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/UTF8StringSliceTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/UTF8StringSliceTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3fcc91b4665d69766763c16154690f722b737a7 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/UTF8StringSliceTest.cpp @@ -0,0 +1,108 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "UTF8StringSlice.hpp" +#include "TestUtils.hpp" + +namespace opencc { + +class UTF8StringSliceTest : public ::testing::Test { +protected: + UTF8StringSliceTest() + : text("天行健,君子以自強不息。地勢坤,君子以厚德載物。"), empty(""){}; + + UTF8StringSlice text; + const UTF8StringSlice empty; +}; + +TEST_F(UTF8StringSliceTest, UTF8Length) { + EXPECT_EQ(0, empty.UTF8Length()); + EXPECT_EQ(24, text.UTF8Length()); +} + +TEST_F(UTF8StringSliceTest, ByteLength) { + EXPECT_EQ(0, empty.ByteLength()); + EXPECT_EQ(72, text.ByteLength()); +} + +TEST_F(UTF8StringSliceTest, Left) { + EXPECT_EQ(UTF8StringSlice("天行健"), text.Left(3)); +} + +TEST_F(UTF8StringSliceTest, Right) { + EXPECT_EQ(UTF8StringSlice("厚德載物。"), text.Right(5)); +} + +TEST_F(UTF8StringSliceTest, SubString) { + EXPECT_EQ(UTF8StringSlice("自強不息"), text.SubString(7, 4)); +} + +TEST_F(UTF8StringSliceTest, ToString) { + EXPECT_EQ("地勢坤", text.SubString(12, 3).ToString()); +} + +TEST_F(UTF8StringSliceTest, Compare) { + EXPECT_TRUE(text.SubString(12, 3) > UTF8StringSlice("一")); + EXPECT_TRUE(text.SubString(12, 3) == UTF8StringSlice("地勢坤")); +} + +TEST_F(UTF8StringSliceTest, MoveRight) { + text.MoveRight(); + EXPECT_EQ(UTF8StringSlice("行健,君子以自強不息。地勢坤,君子以厚德載物。"), + text); + for (size_t i = 0; i < 23; i++) { + text.MoveRight(); + } + EXPECT_EQ(UTF8StringSlice(""), text); + text.MoveRight(); // No effect, because it's already empty + EXPECT_EQ(UTF8StringSlice(""), text); +} + +TEST_F(UTF8StringSliceTest, MoveLeft) { + text.MoveLeft(); + EXPECT_EQ(UTF8StringSlice("天行健,君子以自強不息。地勢坤,君子以厚德載物"), + text); + for (size_t i = 0; i < 22; i++) { + text.MoveLeft(); + } + EXPECT_EQ(UTF8StringSlice("天"), text); + text.MoveLeft(); + text.MoveLeft(); // No effect, because it's already empty + EXPECT_EQ(UTF8StringSlice(""), text); +} + +TEST_F(UTF8StringSliceTest, ReverseCompare) { + EXPECT_EQ(0, UTF8StringSlice("").ReverseCompare(UTF8StringSlice(""))); + EXPECT_EQ(-1, UTF8StringSlice("").ReverseCompare(UTF8StringSlice("大"))); + EXPECT_EQ(-1, UTF8StringSlice("一").ReverseCompare(UTF8StringSlice("二"))); + EXPECT_EQ(-1, UTF8StringSlice("z一").ReverseCompare(UTF8StringSlice("a二"))); + EXPECT_EQ(1, UTF8StringSlice("一一").ReverseCompare(UTF8StringSlice("一"))); +} + +TEST_F(UTF8StringSliceTest, FindBytePosition) { + EXPECT_EQ(0, text.FindBytePosition("")); + EXPECT_EQ(0, text.FindBytePosition("天")); + EXPECT_EQ(9, text.FindBytePosition(",")); + EXPECT_EQ(static_cast(-1), + text.FindBytePosition("a")); + EXPECT_EQ(static_cast(-1), + text.FindBytePosition("\n")); + EXPECT_EQ(3, UTF8StringSlice("了。").FindBytePosition("。")); +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/UTF8Util.cpp b/Packages/SwiftyOpenCC/OpenCC/src/UTF8Util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..41888fd2cb6e3bd1abbae95d590455c31a6c4dc3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/UTF8Util.cpp @@ -0,0 +1,47 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "UTF8Util.hpp" + +using namespace opencc; + +void UTF8Util::SkipUtf8Bom(FILE* fp) { + /* UTF-8 BOM is EF BB BF */ + if (fp == NULL) { + return; + } + /* If we are not at beginning of file, return */ + if (ftell(fp) != 0) { + return; + } + + /* Try to read first 3 bytes */ + int bom[3]; + int n; + for (n = 0; n <= 2 && (bom[n] = getc(fp)) != EOF; n++) { + } + /* If we can only read <3 bytes, push them back */ + /* Or if first 3 bytes is not BOM, push them back */ + if ((n < 3) || (bom[0] != 0xEF) || (bom[1] != 0xBB) || (bom[2] != 0xBF)) { + for (n--; n >= 0; n--) { + ungetc(bom[n], fp); + } + } + + /* Otherwise, BOM is already skipped */ +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/UTF8Util.hpp b/Packages/SwiftyOpenCC/OpenCC/src/UTF8Util.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f1b4b144d62662300c509f9f069520d89c2d581d --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/UTF8Util.hpp @@ -0,0 +1,290 @@ +/* + * Open Chinese Convert + * + * Copyright 2013 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifdef _MSC_VER +#define NOMINMAX +#include +#undef NOMINMAX +#endif // _MSC_VER + +#include + +#include "Common.hpp" +#include "Exception.hpp" + +namespace opencc { +/** + * UTF8 std::string utilities + * @ingroup opencc_cpp_api + */ +class OPENCC_EXPORT UTF8Util { +public: + /** + * Detect UTF8 BOM and skip it. + */ + static void SkipUtf8Bom(FILE* fp); + + /** + * Returns the length in byte for the next UTF8 character. + * On error returns 0. + */ + static size_t NextCharLengthNoException(const char* str) { + char ch = *str; + if ((ch & 0xF0) == 0xE0) { + return 3; + } else if ((ch & 0x80) == 0x00) { + return 1; + } else if ((ch & 0xE0) == 0xC0) { + return 2; + } else if ((ch & 0xF8) == 0xF0) { + return 4; + } else if ((ch & 0xFC) == 0xF8) { + return 5; + } else if ((ch & 0xFE) == 0xFC) { + return 6; + } + return 0; + } + + /** + * Returns the length in byte for the next UTF8 character. + */ + static size_t NextCharLength(const char* str) { + size_t length = NextCharLengthNoException(str); + if (length == 0) { + throw InvalidUTF8(str); + } + return length; + } + + /** + * Returns the length in byte for the previous UTF8 character. + */ + static size_t PrevCharLength(const char* str) { + { + const size_t length = NextCharLengthNoException(str - 3); + if (length == 3) { + return length; + } + } + { + const size_t length = NextCharLengthNoException(str - 1); + if (length == 1) { + return length; + } + } + { + const size_t length = NextCharLengthNoException(str - 2); + if (length == 2) { + return length; + } + } + for (size_t i = 4; i <= 6; i++) { + const size_t length = NextCharLengthNoException(str - i); + if (length == i) { + return length; + } + } + throw InvalidUTF8(str); + } + + /** + * Returns the char* pointer over the next UTF8 character. + */ + static const char* NextChar(const char* str) { + return str + NextCharLength(str); + } + + /** + * Move the char* pointer before the previous UTF8 character. + */ + static const char* PrevChar(const char* str) { + return str - PrevCharLength(str); + } + + /** + * Returns the UTF8 length of a valid UTF8 std::string. + */ + static size_t Length(const char* str) { + size_t length = 0; + while (*str != '\0') { + str = NextChar(str); + length++; + } + return length; + } + + /** + * Finds a character in the same line. + * @param str The text to be searched in. + * @param ch The character to find. + * @return The pointer that points to the found chacter in str or EOL/EOF. + */ + static const char* FindNextInline(const char* str, const char ch) { + while (!IsLineEndingOrFileEnding(*str) && *str != ch) { + str = NextChar(str); + } + return str; + } + + /** + * Returns ture if the character is a line ending or end of file. + */ + static bool IsLineEndingOrFileEnding(const char ch) { + return ch == '\0' || ch == '\n' || ch == '\r'; + } + + /** + * Copies a substd::string with given length to a new std::string. + */ + static std::string FromSubstr(const char* str, size_t length) { + std::string newStr; + newStr.resize(length); + strncpy(const_cast(newStr.c_str()), str, length); + return newStr; + } + + /** + * Returns true if the given std::string is longer or as long as the given + * length. + */ + static bool NotShorterThan(const char* str, size_t byteLength) { + while (byteLength > 0) { + if (*str == '\0') { + return false; + } + byteLength--; + str++; + } + return true; + } + + /** + * Truncates a std::string with a maximal length in byte. + * No UTF8 character will be broken. + */ + static std::string TruncateUTF8(const char* str, size_t maxByteLength) { + std::string wordTrunc; + if (NotShorterThan(str, maxByteLength)) { + size_t len = 0; + const char* pStr = str; + for (;;) { + const size_t charLength = NextCharLength(pStr); + if (len + charLength > maxByteLength) { + break; + } + pStr += charLength; + len += charLength; + } + wordTrunc = FromSubstr(str, len); + } else { + wordTrunc = str; + } + return wordTrunc; + } + + /** + * Replaces all patterns in a std::string in place. + */ + static void ReplaceAll(std::string& str, const char* from, const char* to) { + std::string::size_type pos = 0; + std::string::size_type fromLen = strlen(from); + std::string::size_type toLen = strlen(to); + while ((pos = str.find(from, pos)) != std::string::npos) { + str.replace(pos, fromLen, to); + pos += toLen; + } + } + + /** + * Joins a std::string vector in to a std::string with a separator. + */ + static std::string Join(const std::vector& strings, + const std::string& separator) { + std::ostringstream buffer; + bool first = true; + for (const auto& str : strings) { + if (!first) { + buffer << separator; + } + buffer << str; + first = false; + } + return buffer.str(); + } + + /** + * Joins a std::string vector in to a std::string. + */ + static std::string Join(const std::vector& strings) { + std::ostringstream buffer; + for (const auto& str : strings) { + buffer << str; + } + return buffer.str(); + } + + static void GetByteMap(const char* str, const size_t utf8Length, + std::vector* byteMap) { + if (byteMap->size() < utf8Length) { + byteMap->resize(utf8Length); + } + const char* pstr = str; + for (size_t i = 0; i < utf8Length; i++) { + (*byteMap)[i] = pstr - str; + pstr = NextChar(pstr); + } + } + +#ifdef _MSC_VER + static std::wstring GetPlatformString(const std::string& str) { + return U8ToU16(str); + } +#else + static std::string GetPlatformString(const std::string& str) { return str; } +#endif // _MSC_VER + +#ifdef _MSC_VER + static std::string U16ToU8(const std::wstring& wstr) { + std::string ret; + int length = static_cast(wstr.length()); + int convcnt = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), length, NULL, 0, + NULL, NULL); + if (convcnt > 0) { + ret.resize(convcnt); + WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), length, &ret[0], convcnt, + NULL, NULL); + } + return ret; + } + + static std::wstring U8ToU16(const std::string& str) { + std::wstring ret; + int length = static_cast(str.length()); + int convcnt = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), length, NULL, 0); + if (convcnt > 0) { + ret.resize(convcnt); + MultiByteToWideChar(CP_UTF8, 0, str.c_str(), length, &ret[0], convcnt); + } + return ret; + } +#endif // _MSC_VER +}; +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/UTF8UtilTest.cpp b/Packages/SwiftyOpenCC/OpenCC/src/UTF8UtilTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1516d5e4e1ed595ddf96a3638dfec35e8f7ff22 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/UTF8UtilTest.cpp @@ -0,0 +1,78 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "UTF8Util.hpp" +#include "TestUtils.hpp" + +namespace opencc { + +class UTF8UtilTest : public ::testing::Test { +protected: + UTF8UtilTest() : text("東菄鶇䍶𠍀倲𩜍𢘐"), length(strlen(text)){}; + const char* text; + const size_t length; +}; + +TEST_F(UTF8UtilTest, NextCharLength) { + EXPECT_EQ(3, UTF8Util::NextCharLength(text)); + EXPECT_EQ(3, UTF8Util::NextCharLength(text + 3)); + EXPECT_EQ(3, UTF8Util::NextCharLength(text + 6)); + EXPECT_EQ(3, UTF8Util::NextCharLength(text + 9)); + EXPECT_EQ(4, UTF8Util::NextCharLength(text + 12)); + EXPECT_EQ(3, UTF8Util::NextCharLength(text + 16)); + EXPECT_EQ(4, UTF8Util::NextCharLength(text + 19)); + EXPECT_EQ(4, UTF8Util::NextCharLength(text + 23)); + EXPECT_THROW(EXPECT_EQ(3, UTF8Util::NextCharLength(text + 1)), InvalidUTF8); + EXPECT_THROW(EXPECT_EQ(3, UTF8Util::NextCharLength(text + 2)), InvalidUTF8); +} + +TEST_F(UTF8UtilTest, PrevCharLength) { + EXPECT_EQ(4, UTF8Util::PrevCharLength(text + length)); + EXPECT_EQ(4, UTF8Util::PrevCharLength(text + length - 4)); + EXPECT_EQ(3, UTF8Util::PrevCharLength(text + length - 8)); + EXPECT_THROW(EXPECT_EQ(3, UTF8Util::PrevCharLength(text + 1)), InvalidUTF8); +} + +TEST_F(UTF8UtilTest, Length) { + EXPECT_EQ(0, UTF8Util::Length("")); + EXPECT_EQ(8, UTF8Util::Length(text)); +} + +TEST_F(UTF8UtilTest, NotShorterThan) { + EXPECT_TRUE(UTF8Util::NotShorterThan(text, 0)); + EXPECT_TRUE(UTF8Util::NotShorterThan(text, length)); + EXPECT_FALSE(UTF8Util::NotShorterThan(text, length + 1)); +} + +TEST_F(UTF8UtilTest, TruncateUTF8) { + EXPECT_EQ("", UTF8Util::TruncateUTF8(text, 0)); + EXPECT_EQ("", UTF8Util::TruncateUTF8(text, 1)); + EXPECT_EQ("東", UTF8Util::TruncateUTF8(text, 3)); + EXPECT_EQ("東", UTF8Util::TruncateUTF8(text, 4)); + EXPECT_EQ("東菄鶇䍶𠍀", UTF8Util::TruncateUTF8(text, 16)); + EXPECT_EQ(text, UTF8Util::TruncateUTF8(text, length)); + EXPECT_EQ(text, UTF8Util::TruncateUTF8(text, length + 1)); +} + +TEST_F(UTF8UtilTest, GetByteMap) { + std::vector byteMap; + UTF8Util::GetByteMap(text, 6, &byteMap); + EXPECT_EQ(std::vector({0, 3, 6, 9, 12, 16}), byteMap); +} + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/src/benchmark/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/src/benchmark/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..25a1d1f3fb1be204a9f1700393b9572d43086142 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/benchmark/CMakeLists.txt @@ -0,0 +1,19 @@ +include_directories(..) + +add_executable(performance Performance.cpp) +target_link_libraries(performance benchmark libopencc) +add_test(BenchmarkTest performance) + +if (WIN32) + add_custom_target( + copy_benchmark + ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copying benchmark to src/benchmark" + ) + add_custom_target( + copy_libopencc + ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copying libopencc to src/benchmark" + ) + add_dependencies(performance copy_benchmark copy_libopencc) +endif() diff --git a/Packages/SwiftyOpenCC/OpenCC/src/benchmark/Performance.cpp b/Packages/SwiftyOpenCC/OpenCC/src/benchmark/Performance.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1b646846de297e13d675d46eca9a3f013efc07b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/benchmark/Performance.cpp @@ -0,0 +1,120 @@ +/* + * Open Chinese Convert + * + * Copyright 2020-2021 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#include +#else +#include +#endif + +#include "SimpleConverter.hpp" +#include "TestUtilsUTF8.hpp" + +namespace opencc { + +SimpleConverter* Initialize(const std::string& config_name) { + chdir(PROJECT_BINARY_DIR "/data"); + const std::string config_dir = CMAKE_SOURCE_DIR "/data/config/"; + const std::string config_path = config_dir + config_name + ".json"; + return new SimpleConverter(config_path); +} + +void Convert(const SimpleConverter* converter, const std::string& text) { + converter->Convert(text); +} + +std::string ReadText(const std::string& filename) { + const std::string benchmark_data_dir = CMAKE_SOURCE_DIR "/test/benchmark/"; + const std::string data_path = benchmark_data_dir + filename; + std::ifstream stream(data_path); + return std::string((std::istreambuf_iterator(stream)), + std::istreambuf_iterator()); +} + +static void BM_Initialization(benchmark::State& state, + std::string config_name) { + for (auto _ : state) { + const SimpleConverter* converter = Initialize(config_name); + // Do not count the destruction time. + state.PauseTiming(); + delete converter; + state.ResumeTiming(); + } +} +BENCHMARK_CAPTURE(BM_Initialization, hk2s, "hk2s") + ->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, hk2t, "hk2t") + ->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, jp2t, "jp2t") + ->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, s2hk, "s2hk") + ->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, s2t, "s2t")->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, s2tw, "s2tw") + ->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, s2twp, "s2twp") + ->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, t2hk, "t2hk") + ->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, t2jp, "t2jp") + ->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, t2s, "t2s")->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, tw2s, "tw2s") + ->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, tw2sp, "tw2sp") + ->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Initialization, tw2t, "tw2t") + ->Unit(benchmark::kMillisecond); + +static void BM_Convert2M(benchmark::State& state) { + const std::string config_name = "s2t"; + const std::string text = ReadText("zuozhuan.txt"); + const std::unique_ptr converter(Initialize(config_name)); + for (auto _ : state) { + Convert(converter.get(), text); + } +} +BENCHMARK(BM_Convert2M)->Unit(benchmark::kMillisecond); + +static void BM_Convert(benchmark::State& state, int iteration) { + std::ostringstream os; + for (int i = 0; i < iteration; i++) { + os << "Open Chinese Convert 開放中文轉換" << i << std::endl; + } + const std::string text = os.str(); + const std::string config_name = "s2t"; + const std::unique_ptr converter(Initialize(config_name)); + for (auto _ : state) { + Convert(converter.get(), text); + } +} +BENCHMARK_CAPTURE(BM_Convert, 100, 100)->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Convert, 1000, 1000)->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Convert, 10000, 10000)->Unit(benchmark::kMillisecond); +BENCHMARK_CAPTURE(BM_Convert, 100000, 100000)->Unit(benchmark::kMillisecond); + +} // namespace opencc + +BENCHMARK_MAIN(); diff --git a/Packages/SwiftyOpenCC/OpenCC/src/opencc.h b/Packages/SwiftyOpenCC/OpenCC/src/opencc.h new file mode 100644 index 0000000000000000000000000000000000000000..bc3a9e97b509936585ee8a8e960a80459e7ce299 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/opencc.h @@ -0,0 +1,161 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __OPENCC_H_ +#define __OPENCC_H_ + +#ifdef __cplusplus + +#include "Export.hpp" +#include "SimpleConverter.hpp" +#include + +extern "C" { +#else +#include +#endif + +#ifndef OPENCC_EXPORT +#define OPENCC_EXPORT +#endif + +/** + * @defgroup opencc_c_api OpenCC C API + * + * API in C language + */ + +/** + * Filename of default Simplified to Traditional configuration + * + * @ingroup opencc_c_api + */ +#define OPENCC_DEFAULT_CONFIG_SIMP_TO_TRAD "s2t.json" + +/** + * Filename of default Traditional to Simplified configuration + * + * @ingroup opencc_c_api + */ +#define OPENCC_DEFAULT_CONFIG_TRAD_TO_SIMP "t2s.json" + +/** + * Type of opencc descriptor + * + * @ingroup opencc_c_api + */ +typedef void* opencc_t; + +/** + * Makes an instance of opencc + * + * @param configFileName Location of configuration file. If this is set to NULL, + * OPENCC_DEFAULT_CONFIG_SIMP_TO_TRAD will be loaded. + * @return A description pointer of the newly allocated instance of + * opencc. On error the return value will be (opencc_t) -1. + * @ingroup opencc_c_api + */ +OPENCC_EXPORT opencc_t opencc_open(const char* configFileName); +#ifdef _MSC_VER +/** + * Makes an instance of opencc (wide char / Unicode) + * + * @param configFileName Location of configuration file. If this is set to NULL, + * OPENCC_DEFAULT_CONFIG_SIMP_TO_TRAD will be loaded. + * @return A description pointer of the newly allocated instance of + * opencc. On error the return value will be (opencc_t) -1. + * @ingroup opencc_c_api + */ +OPENCC_EXPORT opencc_t opencc_open_w(const wchar_t* configFileName); +#endif /* _MSC_VER */ + +/** + * Destroys an instance of opencc + * + * @param opencc The description pointer. + * @return 0 on success or non-zero number on failure. + * @ingroup opencc_c_api + */ +OPENCC_EXPORT int opencc_close(opencc_t opencc); + +/** + * Converts UTF-8 std::string + * + * @param opencc The opencc description pointer. + * @param input The UTF-8 encoded std::string. + * @param length The maximum length in byte to convert. If length is (size_t)-1, + * the whole std::string (terminated by '\0') will be converted. + * @param output The buffer to store converted text. You MUST make sure this + * buffer has sufficient space. + * + * @return The length of converted std::string or (size_t)-1 on error. + * + * @ingroup opencc_c_api + */ +OPENCC_EXPORT size_t opencc_convert_utf8_to_buffer(opencc_t opencc, + const char* input, + size_t length, char* output); + +/** + * Converts UTF-8 std::string + * This function returns an allocated C-Style std::string, which stores + * the converted std::string. + * You MUST call opencc_convert_utf8_free() to release allocated memory. + * + * @param opencc The opencc description pointer. + * @param input The UTF-8 encoded std::string. + * @param length The maximum length in byte to convert. If length is (size_t)-1, + * the whole std::string (terminated by '\0') will be converted. + * + * @return The newly allocated UTF-8 std::string that stores text + * converted, or NULL on error. + * @ingroup opencc_c_api + */ +OPENCC_EXPORT char* opencc_convert_utf8(opencc_t opencc, const char* input, + size_t length); + +/** + * Releases allocated buffer by opencc_convert_utf8 + * + * @param str Pointer to the allocated std::string buffer by + * opencc_convert_utf8. + * + * @ingroup opencc_c_api + */ +OPENCC_EXPORT void opencc_convert_utf8_free(char* str); + +/** + * Returns the last error message + * + * Note that this function is the only one which is NOT thread-safe. + * + * @ingroup opencc_c_api + */ +OPENCC_EXPORT const char* opencc_error(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +/** + * @defgroup opencc_cpp_api OpenCC C++ Comprehensive API + * + * Comprehensive API in C++ language + */ + +#endif diff --git a/Packages/SwiftyOpenCC/OpenCC/src/py_opencc.cpp b/Packages/SwiftyOpenCC/OpenCC/src/py_opencc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bcb11b2f9a15d2fb7934e1d24bd5c9a85ff14430 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/py_opencc.cpp @@ -0,0 +1,35 @@ +/* + * Open Chinese Convert + * + * Copyright 2020-2021 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "opencc.h" +#include + +namespace py = pybind11; + +PYBIND11_MODULE(opencc_clib, m) { + py::class_(m, "_OpenCC") + .def(py::init()) + .def("convert", py::overload_cast( + &opencc::SimpleConverter::Convert, py::const_)); + +#ifdef VERSION + m.attr("__version__") = VERSION; +#else + m.attr("__version__") = "dev"; +#endif +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/tools/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/src/tools/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a1a4cd4c06575a72ef21f8b4f9d6c01a544600d3 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/tools/CMakeLists.txt @@ -0,0 +1,22 @@ +include_directories(..) + +# Executables + +## opencc +add_executable(opencc CommandLine.cpp) +target_link_libraries(opencc libopencc) + +## opencc_dict +add_executable(opencc_dict DictConverter.cpp) +target_link_libraries(opencc_dict libopencc) + +## opencc_phrase_extract +add_executable(opencc_phrase_extract PhraseExtract.cpp) +target_link_libraries(opencc_phrase_extract libopencc) + +# Installation + +install( + TARGETS opencc opencc_dict opencc_phrase_extract + RUNTIME DESTINATION bin +) diff --git a/Packages/SwiftyOpenCC/OpenCC/src/tools/CommandLine.cpp b/Packages/SwiftyOpenCC/OpenCC/src/tools/CommandLine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5ba3b9975f11673102e56d235df3d6ba7d671202 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/tools/CommandLine.cpp @@ -0,0 +1,189 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "CmdLineOutput.hpp" +#include "Config.hpp" +#include "Converter.hpp" +#include "UTF8Util.hpp" + +using namespace opencc; + +Optional inputFileName = Optional::Null(); +Optional outputFileName = Optional::Null(); +std::string configFileName; +bool noFlush; +Config config; +ConverterPtr converter; + +FILE* GetOutputStream() { + if (outputFileName.IsNull()) { + return stdout; + } else { + FILE* fp = fopen(outputFileName.Get().c_str(), "w"); + if (!fp) { + throw FileNotWritable(outputFileName.Get()); + } + return fp; + } +} + +void ConvertLineByLine() { + std::istream& inputStream = std::cin; + FILE* fout = GetOutputStream(); + bool isFirstLine = true; + while (!inputStream.eof()) { + if (!isFirstLine) { + fputs("\n", fout); + } else { + isFirstLine = false; + } + std::string line; + std::getline(inputStream, line); + const std::string& converted = converter->Convert(line); + fputs(converted.c_str(), fout); + if (!noFlush) { + // Flush every line if the output stream is stdout. + fflush(fout); + } + } + fclose(fout); +} + +void Convert(std::string fileName) { + const int BUFFER_SIZE = 1024 * 1024; + static bool bufferInitialized = false; + static std::string buffer; + static char* bufferBegin; + static const char* bufferEnd; + static char* bufferPtr; + static size_t bufferSizeAvailble; + if (!bufferInitialized) { + bufferInitialized = true; + buffer.resize(BUFFER_SIZE + 1); + bufferBegin = const_cast(buffer.c_str()); + bufferEnd = buffer.c_str() + BUFFER_SIZE; + bufferPtr = bufferBegin; + bufferSizeAvailble = BUFFER_SIZE; + } + + bool needToRemove = false; + if (!outputFileName.IsNull() && fileName == outputFileName.Get()) { + // Special case: input == output + const std::string tempFileName = std::tmpnam(nullptr); + std::ifstream src(fileName, std::ios::binary); + std::ofstream dst(tempFileName, std::ios::binary); + dst << src.rdbuf(); + dst.close(); + fileName = tempFileName; + needToRemove = true; + } + + FILE* fin = fopen(fileName.c_str(), "r"); + if (!fin) { + throw FileNotFound(fileName); + } + FILE* fout = GetOutputStream(); + while (!feof(fin)) { + size_t length = fread(bufferPtr, sizeof(char), bufferSizeAvailble, fin); + bufferPtr[length] = '\0'; + size_t remainingLength = 0; + std::string remainingTemp; + if (length == bufferSizeAvailble) { + // fread may breaks UTF8 character + // Find the end of last character + char* lastChPtr = bufferBegin; + while (lastChPtr < bufferEnd) { + size_t nextCharLen = UTF8Util::NextCharLength(lastChPtr); + if (lastChPtr + nextCharLen > bufferEnd) { + break; + } + lastChPtr += nextCharLen; + } + remainingLength = bufferEnd - lastChPtr; + if (remainingLength > 0) { + remainingTemp = UTF8Util::FromSubstr(lastChPtr, remainingLength); + *lastChPtr = '\0'; + } + } + // Perform conversion + const std::string& converted = converter->Convert(buffer); + fputs(converted.c_str(), fout); + if (!noFlush) { + // Flush every line if the output stream is stdout. + fflush(fout); + } + // Reset pointer + bufferPtr = bufferBegin + remainingLength; + bufferSizeAvailble = BUFFER_SIZE - remainingLength; + if (remainingLength > 0) { + strncpy(bufferBegin, remainingTemp.c_str(), remainingLength); + } + } + fclose(fout); + if (needToRemove) { + // Remove temporary file. + std::remove(fileName.c_str()); + } +} + +int main(int argc, const char* argv[]) { + try { + TCLAP::CmdLine cmd("Open Chinese Convert (OpenCC) Command Line Tool", ' ', + VERSION); + CmdLineOutput cmdLineOutput; + cmd.setOutput(&cmdLineOutput); + + TCLAP::ValueArg configArg( + "c", "config", "Configuration file", false /* required */, + "s2t.json" /* default */, "file" /* type */, cmd); + TCLAP::ValueArg outputArg( + "o", "output", "Write converted text to .", false /* required */, + "" /* default */, "file" /* type */, cmd); + TCLAP::ValueArg inputArg( + "i", "input", "Read original text from .", false /* required */, + "" /* default */, "file" /* type */, cmd); + TCLAP::ValueArg noFlushArg( + "", "noflush", "Disable flush for every line", false /* required */, + false /* default */, "bool" /* type */, cmd); + cmd.parse(argc, argv); + configFileName = configArg.getValue(); + noFlush = noFlushArg.getValue(); + if (inputArg.isSet()) { + inputFileName = Optional(inputArg.getValue()); + } + if (outputArg.isSet()) { + outputFileName = Optional(outputArg.getValue()); + noFlush = true; + } + converter = config.NewFromFile(configFileName); + bool lineByLine = inputFileName.IsNull(); + if (lineByLine) { + ConvertLineByLine(); + } else { + Convert(inputFileName.Get()); + } + } catch (TCLAP::ArgException& e) { + std::cerr << "error: " << e.error() << " for arg " << e.argId() + << std::endl; + } catch (Exception& e) { + std::cerr << e.what() << std::endl; + } + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/tools/DictConverter.cpp b/Packages/SwiftyOpenCC/OpenCC/src/tools/DictConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb5ea8f3e0d7c5359b9df7a1e9d62d851167d6b2 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/tools/DictConverter.cpp @@ -0,0 +1,57 @@ +/* + * Open Chinese Convert + * + * Copyright 2010-2014 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DictConverter.hpp" +#include "CmdLineOutput.hpp" +#include "Exception.hpp" + +using namespace opencc; + +int main(int argc, const char* argv[]) { + try { + TCLAP::CmdLine cmd("Open Chinese Convert (OpenCC) Dictionary Tool", ' ', + VERSION); + CmdLineOutput cmdLineOutput; + cmd.setOutput(&cmdLineOutput); + + std::vector dictFormats{"text", "ocd2", "ocd"}; + TCLAP::ValuesConstraint allowedVals(dictFormats); + + TCLAP::ValueArg toArg("t", "to", "Output format", + true /* required */, "" /* default */, + &allowedVals /* type */, cmd); + TCLAP::ValueArg fromArg("f", "from", "Input format", + true /* required */, "" /* default */, + &allowedVals /* type */, cmd); + TCLAP::ValueArg outputArg( + "o", "output", "Path to output dictionary", true /* required */, + "" /* default */, "file" /* type */, cmd); + TCLAP::ValueArg inputArg( + "i", "input", "Path to input dictionary", true /* required */, + "" /* default */, "file" /* type */, cmd); + cmd.parse(argc, argv); + ConvertDictionary(inputArg.getValue(), outputArg.getValue(), + fromArg.getValue(), toArg.getValue()); + } catch (TCLAP::ArgException& e) { + std::cerr << "error: " << e.error() << " for arg " << e.argId() + << std::endl; + } catch (Exception& e) { + std::cerr << e.what() << std::endl; + } + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/src/tools/PhraseExtract.cpp b/Packages/SwiftyOpenCC/OpenCC/src/tools/PhraseExtract.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eddb18d9ffe2f5c8b9a3834e526fd0b6609b3bcc --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/src/tools/PhraseExtract.cpp @@ -0,0 +1,76 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "CmdLineOutput.hpp" +#include "PhraseExtract.hpp" + +using opencc::Exception; +using opencc::PhraseExtract; +using opencc::UTF8StringSlice; + +void Extract(const std::vector& inputFiles, + const std::string& outputFile) { + std::ostringstream buffer; + for (const auto& inputFile : inputFiles) { + std::ifstream ifs(inputFile); + const std::string contents((std::istreambuf_iterator(ifs)), + (std::istreambuf_iterator())); + buffer << contents; + } + const std::string& text = buffer.str(); + PhraseExtract extractor; + extractor.SetWordMaxLength(2); + extractor.SetPrefixSetLength(1); + extractor.SetSuffixSetLength(1); + extractor.Extract(text); + std::ofstream ofs(outputFile); + for (const auto& word : extractor.Words()) { + const PhraseExtract::Signals& signals = extractor.Signal(word); + const double entropy = signals.prefixEntropy + signals.suffixEntropy; + const double logProbablity = extractor.LogProbability(word); + ofs << word << " " << signals.frequency << " " << logProbablity << " " + << signals.cohesion << " " << entropy << " " << signals.prefixEntropy + << " " << signals.suffixEntropy << std::endl; + } + ofs.close(); +} + +int main(int argc, const char* argv[]) { + try { + TCLAP::CmdLine cmd("Open Chinese Convert (OpenCC) Phrase Extractor", ' ', + VERSION); + CmdLineOutput cmdLineOutput; + cmd.setOutput(&cmdLineOutput); + TCLAP::UnlabeledMultiArg fileNames( + "fileName", "Input files", true /* required */, "files"); + cmd.add(fileNames); + TCLAP::ValueArg outputArg( + "o", "output", "Output file", true /* required */, "" /* default */, + "file" /* type */, cmd); + cmd.parse(argc, argv); + Extract(fileNames.getValue(), outputArg.getValue()); + } catch (TCLAP::ArgException& e) { + std::cerr << "error: " << e.error() << " for arg " << e.argId() + << std::endl; + } catch (Exception& e) { + std::cerr << e.what() << std::endl; + } + return 0; +} diff --git a/Packages/SwiftyOpenCC/OpenCC/test.cmd b/Packages/SwiftyOpenCC/OpenCC/test.cmd new file mode 100644 index 0000000000000000000000000000000000000000..62b82e1b31ff2f0c5fc4e10621c42708b5a46f22 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test.cmd @@ -0,0 +1,4 @@ +cmake -S. -Bbuild -DCMAKE_INSTALL_PREFIX:PATH=. -DENABLE_GTEST:BOOL=ON -DCMAKE_BUILD_TYPE=Debug +cmake --build build --config Debug --target install +cd build +ctest --verbose -C Debug diff --git a/Packages/SwiftyOpenCC/OpenCC/test/CMakeLists.txt b/Packages/SwiftyOpenCC/OpenCC/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5c4d34682212451a3dd7b37350ad4d4735adba4b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/CMakeLists.txt @@ -0,0 +1,43 @@ +include_directories(../src) + +set(CONFIG_TEST + config_test/config_test.json + config_test/config_test_characters.txt + config_test/config_test_phrases.txt +) + +set(CONFIG_TEST_TARGET_DIR ${PROJECT_BINARY_DIR}/test/config_test) +make_directory(${CONFIG_TEST_TARGET_DIR}) +foreach (CONFIG_TEST_FILE ${CONFIG_TEST}) + configure_file(${CONFIG_TEST_FILE} ${CONFIG_TEST_TARGET_DIR} COPYONLY) +endforeach (CONFIG_TEST_FILE) + +if (ENABLE_GTEST) + if (WIN32) + add_custom_target( + copy_gtest_to_test + ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copying gtest to test" + ) + add_custom_target( + copy_gtest_main_to_test + ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copying gtest_main to test" + ) + endif() + + if(NOT USE_SYSTEM_GTEST) + include_directories(../deps/gtest-1.7.0/include) + endif() + set(UNITTESTS + CommandLineConvertTest + ) + foreach(UNITTEST ${UNITTESTS}) + add_executable(${UNITTEST} ${UNITTEST}.cpp) + target_link_libraries(${UNITTEST} gtest gtest_main libopencc) + add_test(${UNITTEST} ${UNITTEST}) + if (WIN32) + add_dependencies(${UNITTEST} copy_gtest_to_test copy_gtest_main_to_test) + endif() + endforeach(UNITTEST) +endif() diff --git a/Packages/SwiftyOpenCC/OpenCC/test/CommandLineConvertTest.cpp b/Packages/SwiftyOpenCC/OpenCC/test/CommandLineConvertTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50e53d00f20bec620f7fc23bffce465749709e6a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/CommandLineConvertTest.cpp @@ -0,0 +1,112 @@ +/* + * Open Chinese Convert + * + * Copyright 2015 Carbo Kuo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "Common.hpp" +#include "gtest/gtest.h" + +namespace opencc { + +class CommandLineConvertTest : public ::testing::Test { +protected: + CommandLineConvertTest() { GetCurrentWorkingDirectory(); } + + virtual ~CommandLineConvertTest() { free(originalWorkingDirectory); } + + virtual void SetUp() { + ASSERT_NE("", PROJECT_BINARY_DIR); + ASSERT_NE("", CMAKE_SOURCE_DIR); + ASSERT_EQ(0, chdir(PROJECT_BINARY_DIR "/data")); + } + + virtual void TearDown() { ASSERT_EQ(0, chdir(originalWorkingDirectory)); } + + std::string GetFileContents(const std::string& fileName) const { + std::ifstream fs(fileName); + EXPECT_TRUE(fs.is_open()); + const std::string content((std::istreambuf_iterator(fs)), + (std::istreambuf_iterator())); + fs.close(); + return content; + } + + void GetCurrentWorkingDirectory() { + originalWorkingDirectory = getcwd(nullptr, 0); + } + + const char* OpenccCommand() const { +#ifndef _MSC_VER + return PROJECT_BINARY_DIR "/src/tools/opencc"; +#else +#ifdef NDEBUG + return PROJECT_BINARY_DIR "/src/tools/Release/opencc.exe"; +#else + return PROJECT_BINARY_DIR "/src/tools/Debug/opencc.exe"; +#endif +#endif + } + + const char* InputDirectory() const { + return CMAKE_SOURCE_DIR "/test/testcases/"; + } + + const char* OutputDirectory() const { return PROJECT_BINARY_DIR "/test/"; } + + const char* AnswerDirectory() const { + return CMAKE_SOURCE_DIR "/test/testcases/"; + } + + const char* ConfigurationDirectory() const { + return CMAKE_SOURCE_DIR "/data/config/"; + } + + std::string OutputFile(const char* config) const { + return std::string(OutputDirectory()) + config + ".out"; + } + + std::string AnswerFile(const char* config) const { + return std::string(AnswerDirectory()) + config + ".ans"; + } + + std::string TestCommand(const char* config) const { + return OpenccCommand() + std::string("") + " -i " + InputDirectory() + + config + ".in" + " -o " + OutputFile(config) + " -c " + + ConfigurationDirectory() + config + ".json"; + } + + char* originalWorkingDirectory; +}; + +class ConfigurationTest : public CommandLineConvertTest, + public ::testing::WithParamInterface {}; + +TEST_P(ConfigurationTest, Convert) { + const char* config = GetParam(); + ASSERT_EQ(0, system(TestCommand(config).c_str())); + const std::string& output = GetFileContents(OutputFile(config)); + const std::string& answer = GetFileContents(AnswerFile(config)); + ASSERT_EQ(answer, output); +} + +INSTANTIATE_TEST_CASE_P(CommandLine, ConfigurationTest, + ::testing::Values("hk2s", "hk2t", "jp2t", "s2hk", "s2t", + "s2tw", "s2twp", "t2hk", "t2jp", + "t2s", "tw2s", "tw2sp", "tw2t")); + +} // namespace opencc diff --git a/Packages/SwiftyOpenCC/OpenCC/test/benchmark/zuozhuan.txt b/Packages/SwiftyOpenCC/OpenCC/test/benchmark/zuozhuan.txt new file mode 100644 index 0000000000000000000000000000000000000000..7fd74e40f5e203d9850da98aca9b122d472529ca --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/benchmark/zuozhuan.txt @@ -0,0 +1,5706 @@ +左传 + +隐公 + +隐公元年 +【经】元年春王正月。三月,公及邾仪父盟于蔑。夏五月,郑伯克段于鄢。秋七月,天王使宰咺来归惠公、仲子之賵。九月,及宋人盟于宿。冬十有二月,祭伯来。公子益师卒。 +【传】元年春,王周正月。不书即位,摄也。 +三月,公及邾仪父盟于蔑,邾子克也。未王命,故不书爵。曰“仪父”,贵之也。公摄位而欲求好于邾,故为蔑之盟。 +夏四月,费伯帅师城郎。不书,非公命也。 +初,郑武公娶于申,曰武姜,生庄公及共叔段。庄公寤生,惊姜氏,故名曰“寤生”,遂恶之。爱共叔段,欲立之。亟请于武公,公弗许。及庄公即位,为之请制。公曰:“制,岩邑也,虢叔死焉,佗邑唯命。”请京,使居之,谓之京城大叔。祭仲曰:“都,城过百雉,国之害也。先王之制:大都,不过参国之一;中,五之一;小,九之一。今京不度,非制也,君将不堪。”公曰:“姜氏欲之,焉辟害?”对曰:“姜氏何厌之有?不如早为之所,无使滋蔓!蔓,难图也。蔓草犹不可除,况君之宠弟乎?”公曰:“多行不义,必自毙,子姑待之。”   既而大叔命西鄙、北鄙贰于己。公子吕曰:“国不堪贰,君将若之何?欲与大叔,臣请事之;若弗与,则请除之。无生民心。”公曰:“无庸,将自及。”大叔又收贰以为己邑,至于廪延。子封曰:“可矣,厚将得众。”公曰:“不义不昵,厚将崩。” +大叔完、聚,缮甲、兵,具卒,乘,将袭郑,夫人将启之。公闻其期,曰:“可矣!”命子封帅车二百乘以伐京。京叛大叔段,段入于鄢,公伐诸鄢。五月辛丑,大叔出奔共。 +书曰:“郑伯克段于鄢。”段不弟,故不言弟;如二君,故曰克;称郑伯,讥失教也:谓之郑志。不言出奔,难之也。 +遂置姜氏于城颖,而誓之曰:“不及黄泉,无相见也。”既而悔之。颖考叔为颖谷封人,闻之,有献于公,公赐之食,食舍肉。公问之,对曰:“小人有母,皆尝小人之食矣,未尝君之羹,请以遗之。”公曰:“尔有母遗,繄我独无!”颖考叔曰:“敢问何谓也?”公语之故,且告之悔。对曰:“君何患焉?若阙地及泉,隧而相见,其谁曰不然?”公从之。公入而赋:“大隧之中,其乐也融融!”姜出而赋:“大隧之外,其乐也泄泄!”遂为母子如初。 +君子曰:“颖考叔,纯孝也,爱其母,施及庄公。《诗》曰‘孝子不匮,永锡尔类。’其是之谓乎!” +秋七月,天王使宰咺来归惠公、仲子之賵。缓,且子氏未薨,故名。天子七月而葬,同轨毕至;诸侯五月,同盟至;大夫三月,同位至;士逾月,外姻至。赠死不及尸,吊生不及哀,豫凶事,非礼也。 +八月,纪人伐夷。夷不告,故不书。 +有蜚。不为灾,亦不书。 +惠公之季年,败宋师于黄。公立而求成焉。九月,及宋人盟于宿,始通也。 +冬十月庚申,改葬惠公。公弗临,故不书。惠公之薨也,有宋师,太子少,葬故有阙,是以改葬。卫侯来会葬,不见公,亦不书。郑共叔之乱,公孙滑出奔卫。卫人为之伐郑,取廪延。郑人以王师、虢师伐卫南鄙。请师于邾。邾子使私于公子豫,豫请往,公弗许,遂行。及邾人、郑人盟于翼。不书,非公命也。 +新作南门。不书,亦非公命也。 +十二月,祭伯来,非王命也。 +众父卒。公不与小敛,故不书日。 +译文 +鲁惠公第一次所娶正夫人叫做孟子。孟子去世后,续娶个姬妾叫做声子,生了隐公。 +宋武公生女公子仲子。仲子生下来就有字在手掌上,字是“鲁夫人”。意思是她将做鲁国的正室夫人。所以仲子嫁给我国,生了桓公。不久惠公逝世,因此隐公摄政,却奉戴桓公为鲁君。 +元年春季,周王朝历法的正月,《春秋》没有记载隐公即位,这是由于他只是代理国政。 +三月,隐公和邾仪父在蔑会见,邾仪父就是邾子克。由于邾仪父还没有受周朝正式册封,所以《春秋》没有记载他的爵位;称他为“仪父”,是尊重他。隐公代行国政而想要和邾国友好,所以在蔑地举行了盟会。 +夏季四月,费伯率领军队在郎地筑城。《春秋》没有记载,因为不是奉隐公的命令。 +当初,郑武公在申国娶妻,名叫武姜,生了庄公和共叔段两个儿子,庄公降生时是脚先出头后出的,这是难产,使姜氏很惊讶,因此给他取名叫寤生,并且很讨厌他。姜氏喜爱共叔段,想立他为太子,屡次向武公请求,武公不肯答应。等到庄公继位为郑国国君,姜氏请求将制地作为共叔段的封邑,庄公说:“制地是形势险峻的地方,虢叔曾经死在那里。其他地方都可以听命。”姜氏又改请求封京城,让共叔段住在那里,就称他为京城太叔。祭仲说:“凡属国都,城墙周围的长度超过三百丈,就给国家带来祸害。先王制定的制度:大的地方的城墙,不超过国都的三分之一;中等的,不超过五分之一;小的,不超过九分之一。现在京城的城墙不合制度,这不是该有的,您会忍受不了。”庄公说:“姜氏要这样,哪里能避免祸害呢?”祭仲回答说:“姜氏怎么会得到满足?不如及早作安排,不要让她滋生事端,一旦蔓延就难得对付了。蔓延的野草尚且不能铲除掉,何况是您宠爱的弟弟呢?”庄公说:“多作不合情理的事,必然自己垮台。您暂且等着吧!” +不久,太叔命令西部和北部边境既听庄公的命令,又听自己的命令。公子吕说:“国家不能忍受这种两面听命的情况,您打算怎么办?您要把君位让给太叔,下臣就去事奉他;如果不给,那就请除掉他,不要让老百姓产生其他想法。”庄公说:“用不着,他会自食其果的。” +太叔又收取原来两属的地方作为自己的封邑,并扩大到廪延地方。子封(即公子吕)说:“可以动手了。势力一大,将会争得民心。”庄公说:“没有正义就不能号召人,势力虽大,反而会崩溃。” +太叔修理城郭,储备粮草,补充武器装备,充实步兵车兵,准备袭击郑国都城,姜氏则打算作为内应打开城门。庄公听到太叔起兵的日期,说:“可以了。”就命令子封率领二百辆战车进攻京城。京城的人反对太叔。太叔逃到鄢地。庄公又赶到鄢地进攻他。五月二十三日,太叔又逃到共国。 +《春秋》说:“郑伯克段于鄢。”太叔所作所为不像兄弟,所以不说“弟”字;兄弟相争,好像两个国君打仗一样,所以用个“克”字;把庄公称为“郑伯”是讥刺他没有尽教诲之责;《春秋》这样记载就表明了庄公的本来的意思。不说“出奔”,是因为史官下笔有困难。 +郑庄公就把姜氏安置在城颍地方,发誓说:“不到黄泉不再相见。”不久以后又后悔起来。 +郑庄公就把姜氏安置在城颍地方,发誓说:“不到黄泉不再相见。”不久以后又后悔起来。 +郑庄公听了颍考叔的意见。庄公进了隧道,赋诗说:“在大隧中相见,多么快乐啊!”姜氏走出隧道,赋诗说:“走出大隧外,多么舒畅啊。”于是作为母子像从前一样。 +君子说:“颍考叔可算是真正的孝子,爱他的母亲,扩大影响到庄公。《诗》说:‘孝子的孝心没有穷尽,永远可以影响给你的同类。’说的就是这样的事情吧!” +秋季,七月,周平王派遣宰咺来赠送鲁惠公和仲子的吊丧礼品。惠公已经下葬,这是迟了,而仲子还没有死,所以《春秋》直接写了宰咺的名字。 +天子死了七个月后才下葬,诸侯都来参加葬礼;诸侯五个月后下葬,同盟的诸侯参加葬礼;大夫三个月后下葬,官位相同的来参加葬礼;士一个月以后下葬,亲戚参加葬礼。向死者赠送东西没有赶上下葬,向生者吊丧没有赶上举哀的时间,预先赠送有关丧事的东西,这都不合于礼。 +八月,纪国人讨伐夷国。夷国没有前来报告鲁国,所以《春秋》不加记载。 +发现蜚盘虫。没有造成灾害,《春秋》也不加记载。 +鲁惠公的晚年,在黄地打败了宋国。鲁隐公即位,要求和宋人讲和。九月,和宋人在宿地结盟,两国开始友好起来。 +冬季,十月十四日,改葬鲁惠公。隐公不敢以丧主的身份到场哭泣,所以《春秋》不加记载。惠公死的时候,正好遇上和宋国打仗,太子又年幼,葬礼不完备,所以改葬。卫桓公来鲁国参加葬礼,没有见到隐公,《春秋》也不加记载。 +郑国共叔段叛乱,段的儿子公孙滑逃到卫国。卫国人替他进攻郑国,占领了廪延。郑国人率领周天子的军队、虢国的军队进攻卫国南部边境,同时又请求邾国出兵。邾子派人私下和公子豫商量,公子豫请求出兵援救,隐公不允许,公子豫就自己走了,和邾国、郑国在翼地会盟。《春秋》不加记载,因为不是出于隐公的命令。 +新建南门,《春秋》不加记载,也由于不是出于隐公的命令。 +十二月,祭伯来,并不是奉了周王的命令。 +众父去世,隐公没有参加以衣衾加于死者之身的小敛,所以《春秋》不记载死亡的日子。 + +隐公二年 +【经】二年春,公会戎于潜。夏五月,莒人入向。无骇帅师入极。秋八月庚辰,公及戎盟于唐。九月,纪裂繻来逆女。冬十月,伯姬归于纪。纪子帛、莒子盟于密。十有二月乙卯,夫人子氏薨。郑人伐卫。 +【传】二年春,公会戎于潜,修惠公之好也。戎请盟,公辞。 +莒子娶于向,向姜不安莒而归。夏,莒人入向以姜氏还。 +司空无骇入极,费庈父胜之。 +戎请盟。秋,盟于唐,复修戎好也。 +九月,纪裂繻来逆女,卿为君逆也。 +冬,纪子帛、莒子盟于密,鲁故也。 +郑人伐卫,讨公孙滑之乱也。 +译文 +二年春季,鲁隐公在潜地与戎人会见,再一次加强惠公时期的友好关系,戎人请求结盟,隐公婉言拒绝了。 +莒子在向国娶了妻子,向姜在莒国不安心而回到向国。夏季,莒子领兵进入向国,带着向姜回国。 +司空无骇带兵进入极国,派费庈父灭亡了极国。 +戎人请求结盟。秋季,在唐地结盟,这是为了再次加强和戎人的友好关系。 +九月,纪国的裂繻来迎接隐公的女儿,这是卿为了国君而来迎娶的。 +冬季,纪子帛和莒子在密地结盟,这是为了调解鲁国和莒国间的不和睦。 +郑国人进攻卫国,讨伐公孙滑的叛乱。 + +隐公三年 +【经】三年春王二月,己巳,日有食之。三月庚戌,天王崩。夏四月辛卯,君氏卒。秋,武氏子来求赙。八月庚辰,宋公和卒。冬十有二月,齐侯,郑伯盟于石门。癸未,葬宋穆公。 +【传】三年春,王三月壬戌,平王崩,赴以庚戌,故书之。 +夏,君氏卒。声子也。不赴于诸侯,不反哭于寝,不祔于姑,故不曰薨。不称夫人,故不言葬,不书姓。为公故,曰“君氏”。 +郑武公、庄公为平王卿士。王贰于虢,郑伯怨王,王曰“无之”。故周、郑交质。王子狐为质于郑,郑公子忽为质于周。王崩,周人将畀虢公政。四月,郑祭足帅师取温之麦。秋,又取成周之禾。周、郑交恶。 +君子曰:“信不由中,质无益也。明恕而行,要之以礼,虽无有质,谁能间之?苟有明信,涧溪沼沚之毛,苹蘩温藻之菜,筐筥錡釜之器,潢污行潦之水,可荐于鬼神,可羞于王公,而况君子结二国之信。行之以礼,又焉用质?《风》有《采繁》、《采苹》,《雅》有《行苇》、《泂酌》,昭忠信也。” +武氏子来求赙,王未葬也。 +宋穆公疾,召大司马孔父而属殇公焉,曰:“先君舍与夷而立寡人,寡人弗敢忘。若以大夫之灵,得保首领以没,先君若问与夷,其将何辞以对?请子奉之,以主社稷,寡人虽死,亦无悔焉。”对曰:“群臣愿奉冯也。”公曰:“不可。先君以寡人为贤,使主社稷,若弃德不让,是废先君之举也。岂曰能贤?光昭先君之令德,可不务乎?吾子其无废先君之功。”使公子冯出居于郑。八月庚辰,宋穆公卒。殇公即位。 +君子曰:“宋宣公可谓知人矣。立穆公,其子飨之,命以义夫。《商颂》曰:‘殷受命咸宜,百禄是荷。’其是之谓乎!” +冬,齐、郑盟于石门,寻卢之盟也。庚戌,郑伯之车偾于济。 +卫庄公娶于齐东宫得臣之妹,曰庄姜,美而无子,卫人所为赋《硕人》也。又娶于陈,曰厉妫,生孝伯,早死。其娣戴妫生桓公,庄姜以为己子。公子州吁,嬖人之子也,有宠而好兵,公弗禁,庄姜恶之。石碏谏曰:“臣闻爱子,教之以义方,弗纳于邪。骄、奢、淫、泆,所自邪也。四者之来,宠禄过也。将立州吁,乃定之矣,若犹未也,阶之为祸。夫宠而不骄,骄而能降,降而不憾,憾而能珍者鲜矣。且夫贱妨贵,少陵长,远间亲,新间旧,小加大,淫破义,所谓六逆也。君义,臣行,父慈,子孝,兄爱,弟敬,所谓六顺也。去顺效逆,所以速祸也。君人者将祸是务去,而速之,无乃不可乎?”弗听,其子厚与州吁游,禁之,不可。桓公立,乃老。 +译文 +三年春季,周王朝历法的三月二十四日,周平王逝世。讣告上写的是庚戌日,所以《春秋》也记载死日为庚戌,即十二日。 +夏季,君氏死。君氏就是声子,没有发讣告给诸侯,安葬后没有回到祖庙哭祭,没有把神主放在婆婆神主的旁边,所以《春秋》不称“薨”。又由于没有称她为“夫人”,所以不记载下葬的情况,也没有记载她的姓氏。只是因为她是隐公的生母的缘故,所以才称她为“君氏”。 +郑武公、郑庄公先后担任周平王的卿士,平王暗中又将朝政分托给虢公,郑庄公埋怨周平王,平王说:“没有这回事。”所以周、郑交换人质。王子狐在郑国作为人质,郑国的公子忽在周朝作为人质。平王死后,周王室的人想把政权交给虢公。四月,郑国的祭足带兵割取了温地的麦子。秋天,又割取了成周的谷子。周朝和郑国彼此怀恨。君子说:“诚意不发自内心,即使交换人质也没有益处。设身处地将心比心来办事,又用礼仪加以约束,虽然没有人质,又有谁能离间他们?假如确有诚意,即使是山沟、池塘里生长的野草,蘋、蘩、蕴、藻这一类的野菜,一般的竹器和金属器皿,大小道上的积水,都可以献给鬼神,进给王公,何况君子建立了两国的信约,按照礼仪办事,又哪里还用得着人质?《国风》 +有《采繁》、《采蘋》,《大雅》有《行苇》、《泂酌》这些诗篇,就是为了表明忠信的。” +武氏的儿子来鲁国求取办丧事的财物,这是由于周平王还没有举行葬礼。 +宋穆公病重了,召见大司马孔父而把殇公嘱托给他,说:“先君抛弃了他的儿子与夷而立我为国君,我不敢忘记。如果托大夫的福,我能得以保全脑袋,先君如果问起与夷,将用什么话回答呢?请您事奉与夷来主持国家事务,我虽然死去,也不后悔什么了。”孔父回答说:“群臣愿意事奉您的儿子冯啊!”穆公说:“不行,先君认为我有德行,才让我主持国家事务。如果丢掉道德而不让位,这就是废弃了先君的提拔,哪里还能说有什么德行?发扬光大先君的美德,难道能不急于办理吗?您不要废弃先君的功业!”于是命令公子冯到郑国去住。八月初五,宋穆公死,殇公即位。君子说:“宋宣公可以说是能了解人了。立了兄弟穆公,他的儿子却仍然享受了君位,这是他的遗命出于道义。《诗经·商颂》说:‘殷王传授天命都合于道义,所以承受了各种福禄’,就是这种情况。” +冬季,齐国和郑国在石门会盟,这是为了重温在庐地结盟的友好关系。 +冬季某一天,郑伯在济水翻了车。 +卫庄公娶了齐国太子得臣的妹妹,称为庄姜。庄姜漂亮却没有生孩子,卫国人因此为她创作了《硕人》这篇诗。卫庄公又在陈国娶了一个妻子,名叫厉妫,生了孝伯,很早就死了。跟厉妫陪嫁来的妹妹戴妫,生了卫桓公,庄姜就把他作为自己的儿子。 +公子州吁,是卫庄公宠妾的儿子,得到庄公的宠爱,州吁喜欢军器,庄公不加禁止。庄姜很讨厌他。石碏规劝庄公说:“我听说喜欢自己的儿子,应当以道义去教育他,不要使他走上邪路。骄傲、奢侈、放荡、逸乐,这是走上邪路的开始。这四种恶习之所以发生,是由于宠爱和赐予太过份。如果准备立州吁做太子,那就应该定下来;如果还不定下来,会逐渐酿成祸乱。那种受宠而不骄傲,骄傲而能安于地位下降,地位下降而不怨恨,怨恨而能克制的人,是很少见的。而且低贱的妨害尊贵的,年少的驾凌年长的,疏远的离间亲近的,新的离间旧的,弱小的欺侮强大的,淫欲的破坏道义的,这就是六种反常现象。国君行事得宜,臣子服从命令,父亲慈爱,儿子孝顺,兄爱弟、弟敬兄,这就是六种正常现象。去掉正常而效法反常,这就会很快地招致祸害。作为君主,应该尽力于去掉祸害,现在却加速它的到来,恐怕不可以吧!”庄公不听。石碏的儿子石厚和州吁交游,石碏禁止他,石厚不听。卫桓公即位,石碏就告老回家了。 + +隐公四年 +【经】四年春王二月,莒人伐杞,取牟娄。戊申,卫州吁弑其君完。夏,公及宋公遇于清。宋公、陈侯、蔡人、卫人伐郑。秋,翬帅师会宋公、陈侯、蔡人、卫人伐郑。九月,卫人杀州吁于濮。冬十有二月,卫人立晋。 +【传】四年春,卫州吁弑桓公而立。公与宋公为会,将寻宿之盟。未及期,卫人来告乱。夏,公及宋公遇于清。 +宋殇公之即位也,公子冯出奔郑,郑人欲纳之。及卫州吁立,将修先君之怨于郑,而求宠于诸侯以和其民,使告于宋曰:“君若伐郑以除君害,君为主,敝邑以赋与陈、蔡从,则卫国之愿也。”宋人许之。于是,陈、蔡方睦于卫,故宋公、陈侯、蔡人、卫人伐郑,围其东门,五日而还。 +公问于众仲曰:“卫州吁其成乎?”对曰:“臣闻以德和民,不闻以乱。以乱,犹治丝而棼之也。夫州吁,阻兵而安忍。阻兵无众,安忍无亲,众叛亲离,难以济矣。夫兵犹火也,弗戢,将自焚也。夫州吁弑其君而虐用其民,于是乎不务令德,而欲以乱成,必不免矣。” +秋,诸侯复伐郑。宋公使来乞师,公辞之。羽父请以师会之,公弗许,固请而行。故书曰“翬帅师”,疾之也。诸侯之师败郑徒兵,取其禾而还。 +州吁未能和其民,厚问定君于石子。石子曰:“王觐为可。”曰:“何以得觐?”曰:“陈桓公方有宠于王,陈、卫方睦,若朝陈使请,必可得也。”厚从州吁如陈。石碏使告于陈曰:“卫国褊小,老夫耄矣,无能为也。此二人者,实弑寡君,敢即图之。”陈人执之而请莅于卫。九月,卫人使右宰丑莅杀州吁于濮,石碏使其宰乳羊肩莅杀石厚于陈。 +君子曰:“石碏,纯臣也,恶州吁而厚与焉。‘大义灭亲’,其是之谓乎!” +卫人逆公子晋于邢。冬十二月,宣公即位。书曰“卫人立晋”众也。 +译文 +四年春季,卫国的州吁杀了卫桓公而自立为国君。 +鲁隐公和宋殇公会见,打算重温在宿地所建立的友好。还没有到预定的日子,卫国人来报告发生了叛乱。夏季,隐公和宋殇公在清地会见。 +当宋殇公即位的时候,公子冯逃到了郑国。郑国人想送他回国。等到州吁立为国君,准备向郑国报复前代国君结下的怨恨,以此对诸侯讨好,安定国内人心。他派人告诉宋国说:“君王如果进攻郑国,除去君王的祸害,以君王为主,敝邑出兵出物,和陈、蔡两国一道作为属军,这就是卫国的愿望。”宋国答应了。这时候陈国、蔡国正和卫国友好,所以宋殇公、陈桓公、蔡国人、卫国人联合进攻郑国,包围了国都的东门,五天以后才回去。 +鲁隐公向众仲询问说:“卫国的州吁能成功吗?”众仲回答说:“我只听说用德行安定百姓,没有听说用祸乱的。用祸乱,如同要理出乱丝的头绪,反而弄得更加纷乱。州吁这个人,仗恃武力而安于残忍。仗恃武力就没有群众,安于残忍就没有亲附的人。大家背叛,亲近离开,难以成功。军事,就像火一样,不去制止,将会焚烧自己。州吁杀了他的国君,又暴虐地使用百姓,不致力于建立美德,反而想通过祸乱来取得成功,就一定不能免于祸患了。” +秋季,诸侯再次进攻郑国。宋殇公派人前来请求出兵相救,隐公推辞了。羽父请求出兵相会合,隐公不同意。羽父坚决请求以后便前去。所以《春秋》记载说:“翚帅师”,这是表示讨厌他不听命令。诸侯的军队打败了郑国的步兵,割取了那里的谷子便回来。 +州吁不能安定他的百姓。石厚向石碏询问安定君位的办法。石碏说:“朝觐周天子就可以取得合法地位。”石厚说:“如何才能去朝觐呢?”石碏说:“陈桓公正在受到天子的宠信。现在陈、卫两国正互相和睦,如果朝见陈桓公,让他代为请求,就一定可以成功。”于是石厚就跟随州吁到了陈国。石碏派人告诉陈国说:“卫国地方狭小,我老头子年纪已七十多了,不能做什么事了,这两个人,确实杀死了我国君主,请您趁此机会搞掉他们。”陈国人把这两个人抓住,而请卫国派人来陈国处理。九月,卫国人派右宰丑在陈国的濮地杀了州吁,石碏派他的管家獳羊肩在陈国杀了石厚。 +君子说:“石碏真是个忠臣。讨厌州吁,同时加上儿子石厚。‘大义灭亲’就是这样的情况吧!” +卫国人到邢国迎接公子晋。冬季,十二月,卫宣公即位。《春秋》记载说“卫人立晋”,这是说出于大众的意思。 + + +隐公五年 +【经】五年春,公矢鱼于棠。夏四月,葬卫桓公。秋,卫师入郕。九月,考仲子之宫。初献六羽。邾人、郑人伐宋。螟。冬十有二月辛巳,公子彄卒。宋人伐郑,围长葛。 +【传】五年春,公将如棠观鱼者。臧僖伯谏曰:“凡物不足以讲大事,其材不足以备器用,则君不举焉。君将纳民于轨物者也。故讲事以度轨量谓之轨,取材以章物采谓之物,不轨不物谓之乱政。乱政亟行,所以败也。故春蒐夏苗,秋獮冬狩,皆于农隙以讲事也。三年而治兵,入而振旅,归而饮至,以数军实。昭文章,明贵贱,辨等列,顺少长,习威仪也。鸟兽之肉不登于俎,皮革齿牙、骨角毛羽不登于器,则公不射,古之制也。若夫山林川泽之实,器用之资,皂隶之事,官司之守,非君所及也。”公曰:“吾将略地焉。”遂往,陈鱼而观之。僖伯称疾,不从。书曰“公矢鱼于棠”,非礼也,且言远地也。 +曲沃庄伯以郑人、邢人伐翼,王使尹氏、武氏助之。翼侯奔随。 +夏,葬卫桓公。卫乱,是以缓。 +四月,郑人侵卫牧,以报东门之役。卫人以燕师伐郑。郑祭足、原繁、泄驾以三军军其前,使曼伯与子元潜军军其后。燕人畏郑三军而不虞制人。六月,郑二公子以制人败燕师于北制。君子曰:“不备不虞,不可以师。” +曲沃叛王。秋,王命虢公伐曲沃而立哀侯于翼。 +卫之乱也,郕人侵卫,故卫师入郕。 +九月,考仲子之宫,将万焉。公问羽数于众仲。对曰:“天子用八,诸侯用六,大夫四,士二。夫舞所以节八音而行八风,故自八以下。”公从之。于是初献六羽,始用六佾也。 +宋人取邾田。邾人告于郑曰:“请君释憾于宋,敝邑为道。”郑人以王师会之。伐宋,入其郛,以报东门之役。宋人使来告命。公闻其入郛也,将救之,问于使者曰:“师何及?”对曰:“未及国。”公怒,乃止,辞使者曰:“君命寡人同恤社稷之难,今问诸使者,曰‘师未及国’,非寡人之所敢知也。” +冬十二月辛已,臧僖伯卒。公曰:“叔父有憾于寡人,寡人弗敢忘。”葬之加一等。 +宋人伐郑,围长葛,以报入郛之役也。 +译文 +五年春季,鲁隐公准备到棠地观看捕鱼。臧僖伯劝阻说:“凡是一种东西不能用到讲习祭祀和兵戎的大事上,它的材料不能制作礼器和兵器,国君对它就不会采取行动。国君是要把百姓引入正‘轨’、善于取材的人。所以演习大事以端正法度叫做‘轨’,选取材料以制作重要器物叫做‘物’。事情不合于‘轨’、‘物’,叫做乱政。乱政屡次执行,国家将由此败亡。所以春蒐、夏苗、秋狝、冬狩这四种打猎的举动,都是在农业空闲时讲习。每三年大演习一次,进入国都整顿军队,回来祭祖告宗庙,宴请臣下,犒赏随员,以计算俘获的东西。要车服文采鲜明,贵贱有别,辨别等级,少长有序,这是讲习威仪。鸟兽的肉不摆上宗庙的祭器里,它的皮革、牙齿、骨角、毛羽不用到礼器上,国君就不去射它,这是古代的规定。至于山林河泽的产品,一般器物的材料,这是下等人的事情,有关官吏的职责,不是国君所应涉及的。”隐公说:“我是打算视察边境呀!”于是隐公就动身前往棠邑,让捕鱼者摆出捕鱼场面来观看。臧僖伯推说有病,没有跟随前去。《春秋》说:“公矢鱼于棠”,隐公在棠地陈列渔具,这是由于隐公的行为不合于礼制,而且暗示棠地离国都较远。 +曲沃庄伯带领郑军、邢军进攻翼地,周桓王派尹氏、武氏帮助他。在翼地的晋鄂侯逃到随地。 +夏季,安葬卫桓公。由于卫国发生动乱,所以迟缓了。 +四月,郑国人入侵卫国郊外,来报复去年东门这一战役。卫国人带领南燕军队进攻郑国,郑国的祭足、原繁、泄驾带领三军进攻燕军的前面,派曼伯和子元偷偷率领制地的军队袭击燕军的后面。燕国人害怕郑国的三军,而没有防备从制地来的军队。六月,郑国的两个公子曼伯和子元在虎牢关击败了燕军。 +君子说:“不防备意外,就不可以带兵作战。”曲沃背叛周桓王。秋季,周桓王命令虢公进攻曲沃,而在翼地立哀侯为晋君。 +当卫国动乱的时候,郕国人入侵卫国,所以卫国的军队进入郕国。 +九月,祭仲子庙,又准备在庙里献演万舞。隐公向众仲询问执羽舞的人数。众仲回答说:“天子用八行,诸侯用六行,大夫四行,士二行。舞,用来调节八种材料所制乐器的乐音而传播八方之风。所以人数在八行以下。” +隐公听从了。从此以后献演六羽乐舞,开始使用六行舞人。 +宋国人掠取邾国的土地,邾国人告诉郑国说:“请君王攻打宋国,报仇雪恨,敝邑愿意做向导。”郑国人带领周天子的军队和邾军会合,进攻宋国, +进入了外城,以报复去年东门这一战役。宋国人派人前来用国君的名义告急请救。隐公听说军队已经进入外城,打算出兵救援宋国,询问使者说:“军队到了什么地方?”使者欺骗他说:“还没有到国都。”隐公发怒,不去救援。他辞谢使者说:“君王命令我一起为宋国的危难忧虑,现在询问使者,回答说‘军队还没有到国都’,这就不是我所敢知道的了。” +冬季,十二月二十九日,臧僖伯死了。隐公说:“叔父对我有怨恨,我不敢忘记他的忠诚。”于是按照原等级加一级的葬仪安葬他。 +宋国人进攻郑国,包围长葛,以报复攻进外城这一战役。 + +隐公六年 +【经】六年春,郑人来渝平。,夏五月辛酉,公会齐侯盟于艾。秋七月。冬,宋人取长葛。 +【传】六年春,郑人来渝平,更成也。 +翼九宗、五正顷父之子嘉父逆晋侯于随,纳诸鄂。晋人谓之鄂侯。 +夏,盟于艾,始平于齐也。 +五月庚申,郑伯侵陈,大获。 +往岁,郑伯请成于陈,陈侯不许。五父谏曰:“亲仁善邻,国之宝也。君其许郑。”陈侯曰:“宋、卫实难,郑何能为?”遂不许。 +君子曰:“善不可失,恶不可长,其陈桓公之谓乎!长恶不悛,从自及也。虽欲救之,其将能乎?《商书》曰:‘恶之易也,如火之燎于原,不可乡迩,其犹可扑灭?’周任有言曰:‘为国家者,见恶如农夫之务去草焉,芟夷蕴崇之,绝其本根,勿使能殖,则善者信矣。’” +秋,宋人取长葛。 +冬,京师来告饥。公为之请籴于宋、卫、齐、郑,礼也。 +郑伯如周,始朝桓王也。王不礼焉。周桓公言于王曰:“我周之东迁,晋、郑焉依。善郑以劝来者,犹惧不《艸既》,况不礼焉?郑不来矣!” +译文 +六年春季,郑国人来鲁国要求弃怨结好,为的是重新和好。 +晋国翼都的九宗五正顷父的儿子嘉父到随邑迎接晋侯,让他居住在鄂地,晋国人称他为鄂侯。 +夏季,在艾地结盟,开始和齐国结好。 +五月十一日,郑庄公入侵陈国,得到全胜。往年,郑庄公请求与陈国讲和,陈桓公不答应。五父劝谏说:“亲近仁义而和邻国友好,这是国家可宝贵的措施,您还是答应郑国的请求吧!”陈侯说:“宋国和卫国才是真正的祸患,郑国能做什么?”于是就没有答应。 +君子说:“善不可丢失,恶不可滋长,这说的就是陈桓公吧!滋长了恶而不悔改,马上就得自取祸害。纵是挽救,何能办得到!《商书》说:‘恶的蔓延,如同遍地大火,不可以靠拢,难道还能扑灭?’周任有话说:‘治理国和家的人,见到恶,就要像农夫急于除杂草一样,锄掉它聚积起来肥田,挖掉它的老根,不要使它再生长,那么善的事物就能发展了。’” +秋季,宋人占领长葛。 +冬季,京城派人来报告饥荒,隐公就代为向宋、卫、齐、郑诸国请求购买谷物,这是合于礼的。 +郑庄公去周都,第一次朝见周桓王。周桓王不加礼遇。周公对周桓王说:“我们周室东迁,依靠的就是晋国和郑国。友好地对待郑国,用以鼓励后来的人,还恐怕人家不来,何况不以礼接待呢?郑国不会来了。” + +隐公七年 +【经】七年春王三月,叔姬归于纪。滕侯卒。夏,城中丘。齐侯使其弟年来聘。秋,公伐邾。冬,天王使凡伯来聘。戎伐凡伯于楚丘以归。 +【传】七年春,滕侯卒。不书名,未同盟也。凡诸侯同盟,于是称名,故薨则赴以名,告终嗣也,以继好息民,谓之礼经。 +夏,城中丘,书,不时也。 +齐侯使夷仲年来聘,结艾之盟也。 +秋,宋及郑平。七月庚申,盟于宿。公伐邾,为宋讨也。 +初,戎朝于周,发币于公卿,凡伯弗宾。冬,王使凡伯来聘。还,戎伐之于楚丘以归。 +陈及郑平。十二月,陈五父如郑莅盟。壬申,及郑伯盟,歃如忘泄伯曰:“五父必不免,不赖盟矣。” +郑良佐如陈莅盟,辛巳,及陈侯盟,亦知陈之将乱也。 +郑公子忽在王所,故陈侯请妻之。郑伯许之,乃成昏。 +译文 +七年春季,滕侯逝世,《春秋》没有记载滕侯的名字,是由于没有和鲁国同盟的缘故。凡是诸侯各国缔结过同盟,就彼此把国名向神明报告,所以当国君死后则在讣告上也写上名字,这是为了向同盟国报告国君逝世和继承的人,以便继续过去的友好关系,并以此安定人民,这是礼的大法。 +夏季,在中丘筑城。《春秋》加以记载,由于妨碍了农时。 +齐僖公派夷仲年前来聘问,这是为了巩固艾地的盟会。 +秋季,宋国和郑国讲和。七月十七日,在宿地结盟。隐公进攻邾国,这是为宋国而去进攻的。 +当初,戎人朝觐周王,向公卿送了财币,唯有凡伯不以宾礼款待。冬季,周天子派凡伯来鲁国聘问。在回去的路上,戎人在楚丘对他加以截击,俘虏他回去。 +陈国与郑国讲和。十二月,陈国的五父到郑国参与结盟。初二,和郑庄公盟誓,歃血的时候心不在焉。泄伯说:“五父一定不免于祸,因为他不认为结盟是国家的利益。” +郑国的良佐到陈国参加结盟,十一日,和陈侯结盟,看出了陈国将要发生骚乱。 +郑国的公子忽在周桓王那里,所以陈桓公请求把女儿嫁给他。郑庄公同意,于是就订了婚。 + +隐公八年 +【经】八年春,宋公、卫侯遇于垂。三月,郑伯使宛来归祊。庚寅,我入祊。夏六月己亥,蔡侯考父卒。辛亥,宿男卒。秋七月庚午,宋公、齐侯、卫侯盟于瓦屋。八月,葬蔡宣公。九月辛卯,公及莒入盟于浮来。螟。冬十有二月,无骇卒。 +【传】八年春,齐侯将平宋、卫,有会期。宋公以币请于卫,请先相见,卫侯许之,故遇于犬丘。 +郑伯请释泰山之祀而祀周公,以泰山之祊易许田。三月,郑伯使宛来归祊,不祀泰山也。 +夏,虢公忌父始作卿士于周。 +四月甲辰,郑公子忽如陈逆妇妫。辛亥,以妫氏归。甲寅,入于郑。陈金咸子送女。先配而后祖。金咸子曰:“是不为夫妇。诬其祖矣,非礼也,何以能育?” +齐人卒平宋、卫于郑。秋,会于温,盟于瓦屋,以释东门之役,礼也。 +八月丙戌,郑伯以齐人朝王,礼也。 +公及莒人盟于浮来,以成纪好也。 +冬,齐侯使来告成三国。公使众仲对曰:“君释三国之图以鸠其民,君之惠也。寡君闻命矣,敢不承受君之明德。” +无骇卒。羽父请谥与族。公问族于众仲。众仲对曰:“天子建德,因生以赐姓,胙之土而命之氏。诸侯以字为谥,因以为族。官有世功,则有官族,邑亦如之。”公命以字为展氏。 +译文 +八年春季,齐僖公准备要宋、卫两国和郑国讲和,已经有了结盟的日期。宋殇公用财币向卫国请求,希望先行见面。卫宣公同意,所以在犬丘举行非正式会见的仪式。 +郑庄公请求免除对泰山的祭祀而祭祀周公,用泰山旁边的祊地交换鲁国。 +在许地的土田。三月,郑庄公派遣宛来致送祊地,表示不再祭祀泰山了。夏季,虢公忌父开始在成周做卿士。四月初六日,郑公子忽到陈国迎娶妻子妫氏,十三日,带着妫氏回来。 +十六日,进入郑国,陈鍼子送妫氏到郑国。他们先结婚而后告祭祖庙。鍼子说:“这不能算夫妇,欺骗了他的祖先,这不合于礼,怎么能够使子孙繁衍兴旺呢?” +齐国人终于让宋、卫两国和郑国讲和。秋季,在温地会见,在瓦屋结盟, +丢弃东门这一役的旧怨,这是合于礼的。八月某一天,郑庄公带着齐国人朝觐周桓王,这是合于礼的。隐公和莒子在浮来结盟,以达成对纪国的友好。冬季,齐僖公派人来报告宋、卫、郑三国讲和的事。隐公派众仲回答说: +“君王使三国舍弃相互仇敌的图谋,安定他们的百姓,这都是君王的恩惠。寡君听到了,岂敢不承受君王的高明的好行动!” +无骇去世,羽父为他请求谥号和族氏。隐公向众仲询问关于族氏的事。众仲回答说:“天子建立有德之人以做诸侯,根据他的生地而赐姓,分封土地而又赐给他族氏。诸侯以字作为谥号,他的后人又以这作为族氏。先代做官而世代有功绩,就可以用官名作为族氏。也有以封邑为族氏的。”隐公命令以无骇的字作为族氏,就是展氏。 + + +隐公九年 +【经】九年春,天子使南季来聘。三月癸酉,大雨,震电。庚辰,大雨雪。挟卒。夏,城郎。秋七月。冬,公会齐侯于防。 +【传】九年春,王三月癸酉,大雨霖以震,书始也。庚辰,大雨雪,亦如之。书,时失也。凡雨,自三日以往为霖。平地尺为大雪。 +夏,城郎,书,不时也。 +宋公不王。郑伯为王左卿士,以王命讨之,伐宋。宋以入郛之役怨公,不告命。公怒,绝宋使。 +秋,郑人以王命来告伐宋。 +冬,公会齐侯于防,谋伐宋也。 +北戎侵郑,郑伯御之。患戎师,曰;“彼徒我车,惧其侵轶我也。”公子突曰:“使勇而无刚者尝寇,而速去之。君为三覆以待之。戎轻而不整,贪而无亲,胜不相让,败不相救。先者见获必务进,进而遇覆必速奔,后者不救,则无继矣。乃可以逞。”从之。 +戎人之前遇覆者奔。祝聃逐之。衷戎师,前后击之,尽殪。戎师大奔。十一月甲寅,郑人大败戎师。 +译文 +九年春季,周王朝历法的三月初十日,天久下大雨而且打雷闪电,《春秋》记载了开始的日期。十七日,又久下大雨雪,《春秋》也只记开始的日期。所以记载,是由于天时不正常的缘故。凡是下雨,连续下三天以上就叫“霖”。平地雪深一尺就叫“大雪”。 +夏季,在郎地筑城。《春秋》记载这件事,由于妨碍农时。 +宋殇公不去朝见周桓王。这时郑庄公正担任周桓王的卿士,于是用天子的名义讨伐他。郑国进攻宋国。宋国由于被攻外城那次战役对隐公不满,不来报告。隐公发怒,就断绝与宋国的往来。 +秋季,郑国人用天子的名义前来报告进攻宋国。 +冬季,隐公和齐僖公在防地会面,策划进攻宋国。 +北戎人侵略郑国。郑庄公率兵抵御他们,又忧心戎军力量强大,说:“他们是步兵,我们用战车,我很担心他们从后边突然绕到我军之前袭击我们。”公子突说:“派遣一些勇敢而不刚毅的兵士,和敌人一接触就赶紧退走,君王就设下三批伏兵等待他们。戎人轻率而不整肃,贪婪而不团结,打赢了各不相让,打败了各不相救。走到前面的见到有财物俘虏,必然一意前进,前进而遭遇伏兵,必然赶快奔逃。走在后面的人不去救援,敌兵就没有后继者了。这样,我们就可以得胜。”郑庄公听从了公子突的意见。 +戎人的前锋部队遇到了伏兵就奔逃,祝聃追逐他们,把戎军从中截断,前后夹攻,将戎军全部歼灭。戎军后继部队拼命奔逃。十一月二十六日,郑人把戎军打得大败而逃。 + + +隐公十年 +【经】十年春王二月,公会齐侯、郑伯于中丘。夏,翬帅师会齐人、郑人伐宋。六月壬戌,公败宋师于菅。辛未,取郜。辛巳,取防。秋,宋人、卫人入郑。宋人、蔡人、卫人伐戴。郑伯伐取之。冬十月壬午,齐人、郑人入郕。 +【传】十年春,王正月,公会齐侯,郑伯于中丘。癸丑,盟于邓,为师期。 +夏五月羽父先会齐侯、郑伯伐宋。 +六月戊申,公会齐侯、郑伯于老桃。壬戌,公败宋师于菅。庚午,郑师入郜。辛未,归于我。庚辰,郑师入防。辛巳,归于我。 +君子谓:“郑庄公于是乎可谓正矣。以王命讨不庭,不贪其土以劳王爵,正之体也。” +蔡人、卫人、郕人不会王命。 +秋七月庚寅,郑师入郊。犹在郊,宋人、卫人入郑。蔡人从之,伐戴。八月壬戌,郑伯围戴。癸亥,克之,取三师焉。宋、卫既入郑,而以伐戴召蔡人,蔡人怒,故不和而败。 +九月戊寅,郑伯入宋。 +冬,齐人、郑人入郕,讨违王命也。 +译文 +十年春季,周王朝历法的正月,鲁隐公在中丘会见齐僖公、郑庄公。二月二十五日,在邓地结盟,决定出兵日期。夏季五月,羽父事先会合齐僖公、郑庄公,进攻宋国。六月某一天,隐公在老桃会见齐僖公、郑庄公。初七日,隐公在菅地打败宋军。十五日,郑国军队开进郜地。十六日,郑国把郜地归属于我国。二十五日,郑国军队又开进防地。二十六日,郑国把防地归属于我国。 +君子说:“郑庄公这样做,可以说合于正道了。用天子的命令讨伐不来朝觐的诸侯,自己不贪求土地,而以犒赏受天子的爵位的鲁国,这是得到治理政事的本体了。” +蔡国人、卫国人、郕国人没有按照天子的命令会师讨伐宋国。 +秋季,七月初五日,郑国的军队进入本国的远郊,仍然停留在那里。宋军、卫军趁此攻进郑国。蔡军跟在后面进攻戴地。八月初八日,郑庄公包围戴地。初九日,攻克戴地,俘虏了三国军队。 +宋军、卫军已经攻入郑国,而又为了攻打戴地才联合蔡军,蔡国人发怒。 +由于三支军队不合作而失败。九月的一天,郑庄公率军攻入宋国。冬季,齐军、郑军攻入郕国,这是讨伐郕国违背天子的命令。 + + +隐公十一年 +【经】十有一年春,滕侯、薛侯来朝。夏,公会郑伯于时来。秋七月壬午,公及齐侯、郑伯入许。冬十有一月壬辰,公薨。 +【传】十一年春,滕侯、薛侯来朝,争长。薛侯曰:“我先封。”滕侯曰:“我,周之卜正也。薛,庶姓也,我不可以后之。” +公使羽父请于薛侯曰:“君与滕君辱在寡人。周谚有之曰:‘山有木,工则度之;宾有礼,主则择之。’周之宗盟,异姓为后。寡人若朝于薛,不敢与诸任齿。君若辱贶寡人,则愿以滕君为请。” +薛侯许之,乃长滕侯。 +夏,公会郑伯于郲,谋伐许也。 +郑伯将伐许,五月甲辰,授兵于大宫。公孙阏与颖考叔争车,颖考叔挟輈以走,子都拔棘以逐之,及大逵,弗及,子都怒。 +秋七月,公会齐侯、郑伯伐许。庚辰,傅于许,颖考叔取郑伯之旗蝥弧以先登。子都自下射之,颠。瑕叔盈又以蝥弧登,周麾而呼曰:“君登矣!”郑师毕登。壬午,遂入许。许庄公奔卫。 +齐侯以许让公。公曰:“君谓许不共,故从君讨之。许既伏其罪矣,虽君有命,寡人弗敢与闻。”乃与郑人。 +郑伯使许大夫百里奉许叔以居许东偏,曰:“天祸许国,鬼神实不逞于许君,而假手于我寡人。寡人唯是一二父兄不能共亿,其敢以许自为功乎?寡人有弟,不能和协,而使,糊其口于四方,其况能久有许乎?吾子其奉许叔以抚柔此民也,吾将使获也佐吾子。若寡人得没于地,天其以礼悔祸于许?无宁兹许公复奉其社稷。唯我郑国之有请谒焉,如旧昏媾,其能降以相从也。无滋他族,实逼处此,以与我郑国争此土也。吾子孙其覆亡之不暇,而况能禋祀许乎?寡人之使吾子处此,不唯许国之为,亦聊以固吾圉也。” +乃使公孙获处许西偏,曰:“凡而器用财贿,无置于许。我死,乃亟去之。吾先君新邑于此,王室而既卑矣,周之子孙日失其序。夫许,大岳之胤也,天而既厌周德矣,吾其能与许争乎?” +君子谓:“郑庄公于是乎有礼。礼,经国家,定社稷,序民人,利后嗣者也。许无刑而伐之,服而舍之,度德而处之,量力而行之,相时而动,无累后人,可谓知礼矣。” +郑伯使卒出豭,行出犬鸡,以诅射颖考叔者。君子谓:“郑庄公失政刑矣。政以治民,刑以正邪,既无德政,又无威刑,是以及邪。邪而诅之,将何益矣!” +王取邬、刘、功蒍、邗之田于郑,而与郑人苏忿生之田温、原、丝希、樊、隰郕、欑茅、向、盟、州、陉、隤、怀。君子是以知桓王之失郑也。恕而行之,德之则也,礼之经也。己弗能有而以与人,人之不至,不亦宜乎? +郑、息有违言,息侯伐郑。郑伯与战于竟,息师大败而还。君子是以知息之将亡也。不度德,不量力,不亲亲,不征辞,不察有罪,犯五不韪而以伐人,其丧师也,不亦宜乎! +冬十月,郑伯以虢师伐宋。壬戌,大败宋师,以报其入郑也。宋不告命,故不书。凡诸侯有命,告则书,不然则否。师出臧否,亦如之。虽及灭国,灭不告败,胜不告克,不书于策。羽父请杀桓公,将以求大宰。公曰:“为其少故也,吾将授之矣。使营菟裘,吾将老焉。”羽父惧,反谮公于桓公而请弑之。公之为公子也,与郑人战于狐壤,止焉。郑人囚诸尹氏,赂尹氏而祷于其主钟巫,遂与尹氏归而立其主。十一月,公祭钟巫,齐于社圃,馆于寪氏。壬辰,羽父使贼弑公于寪氏,立桓公而讨寪氏,有死者。不书葬,不成丧也。 +译文 +十一年春季,滕侯和薛侯前来朝见鲁君,两人争执行礼的先后。薛侯说:“我先受封。”腾侯说:“我是成周的卜正官,薛国是外姓,我不能落后于他。”鲁隐公派羽父向薛侯商量说:“承君王和滕侯问候寡君,成周的俗话说:‘山上有树木,工匠就加以量测;宾客有礼貌,主人就加以选择。’成周的会盟,异姓在后面。寡人如果到薛国朝见,就不敢和任姓诸国并列,如果承君王加惠于我,那就希望君王同意滕侯的请求。”薛侯同意,就让滕侯先行朝礼。 +夏季,隐公和郑庄公在郲地会见,策划进攻许国。郑庄公准备进攻许国时,五月十四日,在太祖庙内颁发武器。公孙阏(子都)和颍考叔争夺兵车,颍考叔挟起车辕奔跑,子都拔出戟追上去。追到大路上,没有追上,子都很愤怒。 +秋季,七月,隐公会合齐僖公、郑庄公进攻许国。初一日,军队汇合攻打许城。颍考叔拿着郑庄公的旗帜“蝥弧”争先登上城墙,子都从下面用箭射他,颍考叔摔下来死了。瑕叔盈又举着“蝥弧”冲上城,向四周挥动旗帜,大喊说:“国君登城了!”于是郑国的军队全部登上了城墙。初三日,便占领了许国。许庄公逃亡到卫国。 +齐僖公把许国让给隐公。隐公说:“君王说许国不交纳贡品,所以寡人才跟随君王讨伐它。许国既然已经认罪了,虽然君王有这样的好意,我也不敢参与这件事。”于是就把许国领土送给了郑庄公。 +郑庄公让许国大夫百里事奉许叔住在许都的东部边邑,说:“上天降祸于许国,鬼神确实对许君不满意,而借我的手惩罚他。我这儿连一两个父老兄弟都不能和睦共处,难道敢把讨伐许国作为自己的功劳?我有个兄弟,不能和和气气共同过日子,而使他四方求食,我难道还能长久占有许国?您应当事奉许叔来安抚这里的百姓,我准备让公孙获来帮助您。假如我得以善终,上天可能又依礼而撤回加于许国的祸害,让许公再来治理他的同家。那时候只要我郑国对许国有所请求,可能还是会像对待老亲戚一样,降格而同意的。不要让别国逼近我们住的这里,来同我郑国争夺这块土地。我的子孙挽救危亡还来不及,难道还能替许国敬祭祖先吗?我让您留在这里,不仅为了许国,也是姑且巩固我的边疆。”于是就让公孙获住在许城的西部边境,对他说:“凡是你的器用财货,不要放在许国。我死后就赶紧离开这里。我祖先在这里新建城邑,眼看到周王室已经逐渐衰微,我们这些周朝的子孙一天天丢掉自己的事业。而许国,是四岳的后代,上天既然已经厌弃了成周,我哪里还能和许国竞争呢?” +君子说:“郑庄公在这件事情上合乎礼。礼,是治理国家、安定社稷、使百姓有秩序、使后代有利的大法。许国违背法度而庄公讨伐他们,服罪了就宽恕他们,揣度自己德行而决定事情,衡量自己的力量而办理事务,看准了时机而行动,不要让忧虑连累后人,可以说是懂得礼了。” +郑庄公让一百名士兵拿出一头公猪,二十五人拿出一条狗和一只鸡,来诅咒射死颍考叔的凶手。君子说:“郑庄公失掉了政和刑。政用来治理百姓,刑用来纠正邪恶。既缺乏清明的政治,又没有威严的刑法,所以才发生邪恶。已经发生邪恶而加以诅咒,有什么好处!” +周天子在郑国取得邬、刘、蒍、邘的土田,却给了郑国人原来属于苏忿 +生的土田:温、原、絺、樊、隰郕、攒茅、向、盟、州、陉、隤、怀。君子因此而知道桓王会失去郑国了,认为“按照恕道办事,是德的准则,礼的常规。自己不能保有,就拿来送给别人。别人不再来朝见,不也应该吗?” +生的土田:温、原、絺、樊、隰郕、攒茅、向、盟、州、陉、隤、怀。君子因此而知道桓王会失去郑国了,认为“按照恕道办事,是德的准则,礼的常规。自己不能保有,就拿来送给别人。别人不再来朝见,不也应该吗?” +冬季十月,郑庄公带着虢国的军队攻打宋国。十四日,把宋国的军队打得大败,以报复宋国攻入郑国的那次战役。宋国没有前来报告这件事,所以《春秋》没有记载。凡是诸侯发生大事,前来报告就记载,不然就不记载。出兵顺利或者不顺利,也是一样。即使国家被灭亡,被灭的不报告战败,胜利的不报告战胜,也不记载在简册上。 +鲁国大夫羽父请求杀掉桓公,想借此求得宰相的官职。隐公说:“从前由于他年轻的缘故,所以我代为摄政,现在我打算把国君的位子交还给他。已经派人在菟裘建筑房屋,我已经打算退休养老了。”羽父害怕了,反而在鲁桓公那里诬陷鲁隐公而请求桓公杀死隐公。 +隐公还是公子的时候,曾率兵同郑国人在狐壤打仗,被俘获。郑国人把他囚禁在尹氏那里。隐公贿赂尹氏,并在尹氏所祭神主钟巫之前祷告,于是就和尹氏一起回国而在鲁国立了钟巫的神主。十一月,隐公将要祭祀钟巫,在社圃斋戒,住在寪氏那里。十五日,羽父让坏人在寪家刺杀隐公,立桓公为国君,并且讨伐寪氏,寪氏有人被杀害。《春秋》不记载安葬隐公,是由于没有按国君的规格正式为隐公举行丧礼。 + + +桓公 + + +桓公元年 +【经】元年春王正月,公即位。三月,公会郑伯于垂,郑伯以璧假许田。夏四月丁未,公及郑伯盟于越。秋,大水。冬十月。 +【传】元年春,公即位,修好于郑。郑人请复祀周公,卒易祊田。公许之。三月,郑伯以璧假许田,为周公、祊故也。 +夏四月丁未,公及郑伯盟于越,结祊成也。盟曰:“渝盟无享国。” +秋,大水。凡平原出水为大水。 +冬,郑伯拜盟。 +宋华父督见孔父之妻于路,目逆而送之,曰:“美而艳。” +译文 +元年春季,鲁桓公即位,对郑国恢复友好。郑人请求重新祭祀周公、完成祊田的交换。桓公答应了。三月,郑庄公用璧玉来作许田的交易,这是为了请求祭祀周公和以祊交换许田的缘故。 +夏季,四月初二日,鲁桓公和郑庄公在越地结盟,这是为了祊田的交换 +表示友好。誓辞说:“如果违背盟约,就不能享有国家。”秋季,发大水,凡是平原上被水淹了叫做大水。冬季,郑庄公前来拜谢结盟。宋国的华父督在路上见到孔父的妻子,他目迎她从对面走过来,又回头 +从后面盯着她走过去,说:“既美丽,又光彩动人。” + +桓公二年 +【经】二年春,王正月戊申,宋督弑其君与夷及其大夫孔父。滕子来朝。三月,公会齐侯、陈侯、郑伯于稷,以成宋乱。夏四月,取郜大鼎于宋。戊申,纳于大庙。秋七月,杞侯来朝。蔡侯、郑伯会于邓。九月,入杞。公及戎盟于唐。冬,公至自唐。 +【传】二年春,宋督攻孔氏,杀孔父而取其妻。公怒,督惧,遂弑殇公。 +君子以督为有无君之心而后动于恶,故先书弑其君。会于稷以成宋乱,为赂故,立华氏也。 +宋殇公立,十年十一战,民不堪命。孔父嘉为司马,督为大宰,故因民之不堪命,先宣言曰:“司马则然。”已杀孔父而弑殇公,召庄公于郑而立之,以亲郑。以郜大鼎赂公,齐、陈、郑皆有赂,故遂相宋公。 +夏四月,取郜大鼎于宋。戊申,纳于大庙。非礼也。臧哀伯谏曰:“君人者将昭德塞违,以临照百官,犹惧或失之。故昭令德以示子孙:是以清庙茅屋,大路越席,大羹不致,粢食不凿,昭其俭也。衮、冕、黻、珽,带、裳、幅、舄,衡、紞、紘、綖,昭其度也。藻、率、鞞、革□,鞶、厉、游、缨,昭其数也。火、龙、黼、黻,昭其文也。五色比象,昭其物也。锡、鸾、和、铃,昭其声也。三辰旂旗,昭其明也。夫德,俭而有度,登降有数。文、物以纪之,声、明以发之,以临照百官,百官于是乎戒惧,而不敢易纪律。今灭德立违,而置其赂器于大庙,以明示百官,百官象之,其又何诛焉?国家之败,由官邪也。官之失德,宠赂章也。郜鼎在庙,章孰甚焉?武王克商,迁九鼎于雒邑,义士犹或非之,而况将昭违乱之赂器于大庙,其若之何?”公不听。周内史闻之曰:“臧孙达其有后于鲁乎!君违不忘谏之以德。” +秋七月,杞侯来朝,不敬,杞侯归,乃谋伐之。 +蔡侯、郑伯会于邓,始惧楚也。 +九月,入杞,讨不敬也。 +公及戎盟于唐,修旧好也。 +冬,公至自唐,告于庙也。凡公行,告于宗庙;反行,饮至、舍爵,策勋焉,礼也。 +特相会,往来称地,让事也。自参以上,则往称地,来称会,成事也。 +初,晋穆侯之夫人姜氏以条之役生太子,命之曰仇。其弟以千亩之战生,命之曰成师。师服曰:“异哉,君之名子也!夫名以制义,义以出礼,礼以体政,政以正民。是以政成而民听,易则生乱。嘉耦曰妃。怨耦曰仇,古之命也。今君命大子曰仇,弟曰成师,始兆乱矣,兄其替乎?” +惠之二十四年,晋始乱,故封桓叔于曲沃,靖侯之孙栾宾傅之。师服曰:“吾闻国家之立也,本大而末小,是以能固。故天子建国,诸侯立家,卿置侧室,大夫有贰宗,士有隶子弟,庶人、工、商,各有分亲,皆有等衰。是以民服事其上而下无觊觎。今晋,甸侯也,而建国。本既弱矣,其能久乎?” +惠之三十年,晋潘父弑昭侯而立桓叔,不克。晋人立孝侯。 +惠之四十五年,曲沃庄伯伐翼,弑孝侯。翼人立其弟鄂侯。鄂侯生哀侯。哀侯侵陉庭之田。陉庭南鄙启曲沃伐翼。 +译文 +二年春季,宋卿华父督攻打孔氏,杀死了孔父而占有他的妻子。宋殇公发怒,华父督恐惧,就把殇公也杀死了。君子认为华父督心里早已没有国君,然后才产生这种罪恶行动,所以《春秋》先记载“弑其君”。 +鲁桓公和齐僖公、陈桓公、郑庄公在稷地会见,商讨平定宋国的内乱。由于接受了贿赂的缘故,便建立华氏政权。 +宋殇公即位以后,十年之中发生了十一次战争,百姓不能忍受。孔父嘉做司马,华父督做太宰。华父督由于百姓不能忍受,先就宣传说:“这都是司马所造成的。”不久就杀了孔父和殇公,把庄公从郑国召回而立他为国君,以此亲近郑国。同时又把郜国的大鼎送给桓公,对齐、陈、郑诸国也都馈送财礼,所以华父督就当了宋公的宰相。 +夏季,四月,桓公从宋国取来了郜国的大鼎。初九日,把大鼎安放在太庙里。这件事不符合礼制。臧哀伯劝阻说:“作为百姓的君主,要发扬道德而阻塞邪恶,以为百官的表率,即使这样,仍然担心有所失误,所以显扬美德以示范于子孙。因此太庙用茅草盖屋顶,祭天之车用蒲草席铺垫,肉汁不加调料,主食不吃舂过两次的米,这是为了表示节俭。礼服、礼帽、蔽膝、大圭、腰带、裙子、绑腿、鞋子、横簪、瑱绳、冠系、冠布,都各有规定,用来表示衣冠制度。玉垫、佩巾、刀鞘、鞘饰、革带、带饰、飘带、马鞅,各级多少不同,用来表示各个等级规定的数量。画火、画龙、绣黼、绣黻,这都是为了表示文饰。五种颜色绘出各种形象,这都是为了表示色彩。锡铃、鸾铃、衡铃、旗铃,这都是为了表示声音。画有日、月、星的旌旗,这是为了表示明亮。行为的准则应当节俭而有制度,增减也有一定的数量,用文饰、色彩来记录它,用声音、明亮来发扬它,以此向文武百官作明显的表示。百官才有警戒和畏惧,不敢违反纪律。现在废除道德而树立邪恶,把人家贿赂来的器物放在太庙里,公然展示给百官看,百官也模仿这种行为,还能惩罚谁呢?国家的衰败,由于官吏的邪恶。官吏的失德,由于受宠又公开贿赂。郜鼎放在太庙里,彰明较著地受纳贿赂,还有更甚的吗?周武王打败商朝,把九鼎运到洛邑,当时的义士还有人认为他不对,更何况把显然违法叛乱的贿赂器物放在太庙里,这又该如何办?”桓公不听。 +周朝的内使听说了这件事,说:“臧孙达的后代在鲁国可能长享禄位吧!国君违背礼制,他没有忘记以道德来劝阻。” +秋季,七月,杞侯来鲁国朝见,态度不够恭敬。杞侯回国,桓公就策划讨伐他。 +蔡桓侯、郑庄公在邓地会见,从这时起两国开始惧怕楚国。 +九月,攻入杞国,这是由于讨伐杞侯的不恭敬。 +桓公和戎在唐地结盟,这是为了重修过去的友好邦交。 +冬季,桓公从唐地回来,《春秋》所以记载,是由于回来后祭告了宗庙。 +凡是国君出国之前,要祭告宗庙。回来,也要祭告宗庙,还要宴请臣下,互相劝酒、把功劳记载在档案里,这是合于礼的。两国国君单独相会见,来回都只记载会见的地点,这是互相谦让谁为会首的会见。会见的国君在三个以上,那就在去他国时记载会见的地点,他国国君前来就不记载会见地点而仅仅记载会见,这是盟主已在会前决定,只是完成会见手续罢了。 +当初,晋穆侯的夫人姜氏在条地战役的时候生了太子,取名叫仇。仇的 +兄弟是在千亩战役时生的,因此取名叫成师。师服说:“奇怪呀,国君替儿子取这样的名字!取名表示一定的意义,意义产生礼仪,礼仪是政事的骨干,政事端正百姓,所以政事没有失误百姓就服从;相反就发生动乱。相爱的夫妻叫妃,相怨的夫妻叫仇,这是古代人所命名的方法。现在国君给太子取名叫仇,他的兄弟叫成师,这就开始预示祸乱了。做哥哥的恐怕要被废黜了吧!” +兄弟是在千亩战役时生的,因此取名叫成师。师服说:“奇怪呀,国君替儿子取这样的名字!取名表示一定的意义,意义产生礼仪,礼仪是政事的骨干,政事端正百姓,所以政事没有失误百姓就服从;相反就发生动乱。相爱的夫妻叫妃,相怨的夫妻叫仇,这是古代人所命名的方法。现在国君给太子取名叫仇,他的兄弟叫成师,这就开始预示祸乱了。做哥哥的恐怕要被废黜了吧!” +鲁惠公三十年,晋国的潘父杀了昭侯而接纳桓叔,没有成功。晋国人立了孝侯。鲁惠公四十五年,曲沃庄伯攻打翼城,杀了孝侯,翼城人立他的兄弟鄂侯。鄂侯生了哀侯。哀侯侵占陉庭地方的田土。陉庭南部边境的人引导曲沃攻打翼城。 + + +桓公三年 +【经】三年春正月,公会齐侯于嬴。夏,齐侯、卫侯胥命于蒲。六月,公会杞侯于郕。秋七月壬辰朔,日有食之,既。公子翬如齐逆女。九月,齐侯送姜氏于欢。公会齐侯于欢。夫人姜氏至自齐。冬,齐侯使其弟年来聘。有年。 +【传】三年春,曲沃武公伐翼,次于陉庭,韩万御戎,梁弘为右,逐翼侯于汾隰,骖絓而止。夜获之,及栾共叔。 +会于嬴,成昏于齐也。 +夏,齐侯、卫侯胥命于蒲,不盟也。 +公会杞侯于欢,杞求成也。 +秋,公子翬如齐逆女。修先君之好。故曰“公子”。 +齐侯送姜氏于欢,非礼也。凡公女嫁于敌国,姊妹则上卿送之,以礼于先君,公子则下卿送之。于大国,虽公子亦上卿送之。于天子,则诸卿皆行,公不自送。于小国,则上大夫送之。 +冬,齐仲年来聘,致夫人也。 +芮伯万之母芮姜恶芮伯之多宠人也,故逐之,出居于魏。 +译文 +三年春季,曲沃武公进攻翼城,军队驻扎在陉庭。韩万为武公驾车,梁弘作为车右。在汾水边的低洼地追赶晋哀侯,由于骖马被绊住才停下来。夜里,俘获了晋哀侯和栾共叔。 +桓公和齐僖公在嬴地会见,这是由于和齐女订婚。夏季,齐僖公、卫宣公在蒲地只是会谈,没有结盟。桓公和杞侯在郕地会见,这是由于杞国要求议和。秋季,公子翚到齐国迎接齐女,因为是重修前代国君的友好关系,所以 +《春秋》称翚为“公子”。齐僖公护送姜氏出嫁,到了讙地,这是不合于礼的。凡是本国的公室女子出嫁到同等国家,如果是国君的姐妹,就由上卿护送她,以表示对前代国君的尊敬。如果是国君的女儿,就由下卿护送她。出嫁到大国,即便是国君的女儿,也由上卿护送她。嫁给天子,就由各位大臣都去护送,国君不亲自护送。出嫁到小国,就由上大夫护送她。 +冬季,齐仲年前来聘问,这是为了把姜氏护送到鲁都。芮伯万的母亲芮姜嫌恶芮伯的宠姬太多,因此把他赶走,让他住到魏城。 + +桓公四年 +【经】四年春正月,公狩于郎。夏,天王使宰渠伯纠来聘。 +【传】四年春正月,公狩于郎。书,时,礼也。 +夏,周宰渠伯纠来聘。父在,故名。 +秋,秦师侵芮,败焉,小之也。 +冬,王师、秦师围魏,执芮伯以归。 +译文 +四年春季,正月,鲁桓公在郎地打猎。《春秋》记载这件事,是由于这正是(夏历十一月)狩猎之时,合于礼。 +夏季,周朝的宰官渠伯纠来鲁国聘问。由于他的父亲还活着,所以《春秋》写出他的名字。 +秋季,秦国的军队袭击芮国,秦军战败,由于小看了敌人的缘故。 +冬季,周桓王的军队和秦国军队联合包围芮国,俘虏了芮伯回来。 + +桓公五年 +【经】五年春正月,甲戌、己丑,陈侯鲍卒。夏,齐侯郑伯如纪。天王使仍叔之子来聘。葬陈桓公。城祝丘。秋,蔡人、卫人、陈人从王伐郑。大雩。螽。冬,州公如曹。 +【传】五年春正月,甲戌,己丑,陈侯鲍卒,再赴也。于是陈乱,文公子佗杀大子免而代之。公疾病而乱作,国人分散,故再赴。 +夏,齐侯、郑伯朝于纪,欲以袭之。纪人知之。 +王夺郑伯政,郑伯不朝。 +秋,王以诸侯伐郑,郑伯御之。 +王为中军;虢公林父将右军,蔡人、卫人属焉;周公黑肩将左军,陈人属焉。 +郑子元请为左拒以当蔡人、卫人,为右拒以当陈人,曰:“陈乱,民莫有斗心,若先犯之,必奔。王卒顾之,必乱。蔡、卫不枝,固将先奔,既而萃于王卒,可以集事。”从之。曼伯为右拒,祭仲足为左拒,原繁、高渠弥以中军奉公,为鱼丽之陈,先偏后伍,伍承弥缝。战于繻葛,命二拒曰:“旝动而鼓。”蔡、卫、陈皆奔,王卒乱,郑师合以攻之,王卒大败。祝聃射王中肩,王亦能军。祝聃请从之。公曰:“君子不欲多上人,况敢陵天子乎!苟自救也,社稷无陨,多矣。” +夜,郑伯使祭足劳王,且问左右。 +仍叔之子,弱也。 +秋,大雩,书,不时也。凡祀,启蛰而郊,龙见而雩,始杀而尝,闭蛰而烝。过则书。 +冬,淳于公如曹。度其国危,遂不复。 +译文 +五年春季,正月,去年十二月二十一日,今年正月初六,陈侯鲍逝世。《春秋》所以记载两个日子,是由于发了两次讣告而日期不同。当时陈国发生动乱,文公的儿子佗杀了太子免而取代他。陈侯病危的时候动乱发生,国内臣民纷纷离散,因此发了两次讣告 +夏季,齐僖公、郑庄公去纪国访问,想要乘机袭击纪国。纪国人发觉了。周桓王夺去了郑庄公的政权,郑庄公不再朝觐。 +秋季,周桓王带领诸侯讨伐郑国,郑庄公出兵抵御。周桓王率领中军;虢公林父率领右军,蔡军、卫军隶属于右军;周公黑肩率左军,陈军隶属于左军。 +郑国的子元建议用左方阵来对付蔡军和卫军,用右方阵来对付陈军,说:“陈国动乱,百姓都缺乏战斗意志,如果先攻击陈军,他们必定奔逃。周天子的军队看到这种情形,又一定会发生混乱。蔡国和卫国的军队支撑不住,也一定会争先奔逃。这时我们可集中兵力对付周天子的中军,我们就可以获得成功。”郑庄公听从了。曼伯担任右方阵的指挥,祭仲足担任左方阵的指挥,原繁、高渠弥带领中军护卫郑庄公,摆开了叫做鱼丽的阵势,前有偏,后有伍,伍弥补偏的空隙。 +在繻葛双方交战。郑庄公命令左右两边方阵说:“大旗一挥,就击鼓进军。”郑国的军队发起进攻,蔡、卫、陈军一起奔逃,周军因此混乱。郑国的军队从两边合拢来进攻,周军终于大败。祝聃射中周桓王的肩膀,桓王还能指挥军队。祝聃请求前去追赶。郑庄公说:“君子不希望欺人太甚,哪里敢欺凌天子呢?只要能挽救自己,国家免于危亡,这就足够了。” +夜间,郑庄公派遣祭仲足去慰问周桓王,同时也问候他的左右随从。 +仍叔的儿子前来聘问。《春秋》所以记为“仍叔之子”而不记他的名字,是由于他年轻。 +秋季,为求雨而举行大雩祭。《春秋》记载这件事,是由于这不是按时的祭祀。凡是祭祀,昆虫惊动举行郊祭,苍龙角亢二宿出现举行雩祭,秋天寒气降临举行尝祭,昆虫蛰伏举行烝祭。如果过了规定的时间举行祭礼,就要记载。 +冬季,淳于公到曹国。自己估计他的国家将发生危难,因此没有再回国了。 + + +桓公六年 +【经】六年春正月,实来。夏四月,公会纪侯于成。秋八月壬午,大阅。蔡人杀陈佗。九月丁卯,子同生。冬,纪侯来朝。 +【传】六年春,自曹来朝。书曰“实来”,不复其国也。 +楚武王侵随,使薳章求成焉。军于瑕以待之。随人使少师董成。斗伯比言于楚子曰:“吾不得志于汉东也,我则使然。我张吾三军而被吾甲兵,以武临之,彼则惧而协以谋我,故难间也。汉东之国随为大,随张必弃小国,小国离,楚之利也。少师侈,请羸师以张之。”熊率且比曰:“季梁在,何益?”斗伯比曰:“以为后图,少师得其君。”王毁军而纳少师。 +少师归,请追楚师,随侯将许之。季梁止之曰:“天方授楚,楚之蠃,其诱我也,君何急焉?臣闻小之能敌大也,小道大淫。所谓道,忠于民而信于神也。上思利民,忠也;祝史正辞,信也。今民馁而君逞欲,祝史矫举以祭,臣不知其可也。”公曰:“吾牲牷肥腯,粢盛丰备,何则不信?”对曰:“夫民,神之主也。是以圣王先成民而后致力于神。故奉牲以告曰‘博硕肥腯’,谓民力之普存也,谓其畜之硕大蕃滋也,谓其不疾瘯蠡也,谓其备腯咸有也。奉盛以告曰‘洁粢丰盛’,谓其三时不害而民和年丰也。奉酒醴以告曰‘嘉栗旨酒’,谓其上下皆有嘉德而无违心也。所谓馨香,无谗慝也。故务其三时,修其五教,亲其九族,以致其禋祀。于是乎民和而神降之福,故动则有成。今民各有心,而鬼神乏主,君虽独丰,其何福之有!君姑修政而亲兄弟之国,庶免于难。”随侯惧而修政,楚不敢伐。 +夏,会于成,纪来咨谋齐难也。 +北戎伐齐,齐侯使乞师于郑。郑大子忽帅师救齐。六月,大败戎师,获其二帅大良、少良,甲首三百,以献于齐。于是,诸侯之大夫戍齐,齐人馈之饩,使鲁为其班,后郑。郑忽以其有功也,怒,故有郎之师。 +公之未昏于齐也,齐侯欲以文姜妻郑大子忽。大子忽辞,人问其故,大子曰:“人各有耦,齐大,非吾耦也。《诗》云:‘自求多福。’在我而已,大国何为?”君子曰:“善自为谋。”及其败戎师也,齐侯又请妻之,固辞。人问其故,大子曰:“无事于齐,吾犹不敢。今以君命奔齐之急,而受室以归,是以师昏也。民其谓我何?”遂辞诸郑伯。 +秋,大阅,简车马也。 +九月丁卯,子同生,以大子生之礼举之,接以大牢,卜士负之,士妻食之。公与文姜、宗妇命之。 +公问名于申繻。对曰:“名有五,有信,有义,有象,有假,有类。以名生为信,以德命为义,以类命为象,取于物为假,取于父为类。不以国,不以官,不以山川,不以隐疾,不以畜牲,不以器币。周人以讳事神,名,终将讳之。故以国则废名,以官则废职,以山川则废主,以畜牲则废祀,以器币则废礼。晋以僖侯废司徒,宋以武公废司空,先君献,武废二山,是以大物不可以命。”公曰:“是其生也,与吾同物,命之曰同。” +冬,纪侯来朝,请王命以求成于齐,公告不能。 +译文 +六年春季,(淳于公)从曹国前来朝见。《春秋》记载作“实来”,是由于他真正不再回国了。 +楚武王入侵随国,先派薳章去求和,把军队驻在瑕地以等待结果。随国人派少师主持和谈。 +鬬伯比对楚武王说:“我国在汉水东边不能达到目的,是我们自己造成的。我们扩大军队,整顿装备,用武力逼迫别国,他们害怕因而共同来对付我们,所以就难于离间了。在汉水东边的国家中,随国最大。随国要是自高自大,就必然抛弃小国。小国离心,对楚国有利。少师这个人很骄傲,请君王隐藏我军的精锐,而让他看到疲弱的士卒,助长他的骄傲。”熊率且比说:“有季梁在,这样做有什么好处?”鬬伯比说:“这是为以后打算,因为少师可以得到他们国君的信任。”楚武王故意把军容弄得疲疲塌塌来接待少师。 +少师回去,请求追逐楚军。随侯将要答应,季梁劝阻说:“上天正在帮助楚国,楚国军队显得疲塌的样子,是引诱我们。君王何必急于从事?下臣听说小国之所以能够抵抗大国,是小国有道,而大国君主沉溺于私欲。所谓道,就是忠于百姓而取信于神明。上边的人想到对百姓有利,这是忠;祝史真实不欺地祝祷,这是信。现在百姓饥饿而国君放纵个人享乐,祝史浮夸功德来祭祀,下臣不知怎样行得通?”随侯说:“我祭祀用的牲口都既无杂色,又很肥大,黍稷也都丰盛完备,为什么不能取信于神明?”季梁回答说:“百姓,是神明的主人。因此圣王先团结百姓,而后才致力于神明,所以在奉献牺牲的时候祝告说:‘牲口又大又肥。’这是说百姓的财力普遍富足,牲畜肥大而繁殖生长,并没有得病而瘦弱,又有各种优良品种。在奉献黍稷的时候祷告说:‘洁净的粮食盛得满满的。’这是说春、夏、秋三季没有天灾,百姓和睦而收成很好。在奉献甜酒的时候祝告说:‘又好又清的美酒。’这是说上上下下都有美德而没有坏心眼。所谓的祭品芳香,就是人心没有邪念。因为春、夏、秋三季都努力于农耕,修明五教,敦睦九族,用这些行为来致祭神明,百姓便和睦,神灵也降福,所以做任何事情都能成功。现在百姓各有各的想法,鬼神没有依靠,君王一个人祭祀丰富,又能求得什么福气呢?君王姑且修明政治,亲近兄弟国家,看能否免于祸难。”随侯害怕了,从而修明政治,楚国就没有敢来攻打。 +夏季,鲁桓公和纪侯在成地相会。这是由于纪侯前来商谈如何对付齐国灭纪的企图。 +北戎进攻齐国,齐国派人到郑国求援。郑国的太子忽率领军队救援齐国。六月,大败戎军,俘虏了它的两个主帅大良、少良,砍了带甲戎军三百人的脑袋,献给齐国。当时,诸侯的大夫在齐国防守边境,齐国人馈送他们食物,让鲁国来确定致送各国军队的先后次序。鲁国因依照周王朝所定的次序,把郑国排在后面。郑太子忽认为自己有功劳,很恼怒,所以四年之后就有郎地的战役。 +桓公在没有向齐国求婚以前,齐僖公想把文姜嫁给太子忽。太子忽辞谢,别人问为什么,太子忽说:“人人都有合适的配偶,齐国强大,不是我的配偶。《诗》说:‘求于自己,多受福德。’靠我自己就是了,要大国干什么?”君子说:“太子忽善于为自己打算。”等到他打败了戎军,齐僖公又请求把别的女子嫁给他。太子忽坚决辞谢,别人问为什么,太子忽说:“我为齐国 +没有做什么事情,尚且不敢娶他们的女子。现在由于国君的命令急忙地到齐国解救危急,反而娶了妻子回国,这是利用战争而成婚,百姓将会对我有什么议论呢?”于是就用郑庄公的名义辞谢了。 +没有做什么事情,尚且不敢娶他们的女子。现在由于国君的命令急忙地到齐国解救危急,反而娶了妻子回国,这是利用战争而成婚,百姓将会对我有什么议论呢?”于是就用郑庄公的名义辞谢了。 +九月二十四日,儿子同出生,举行太子出生的礼仪:父亲接见儿子时用牛、羊、豕各一的太宰,用占卜选择士人背他,用占卜选择士人的妻子给他喂奶,桓公和文姜、同宗妇人为他取名字。 +桓公向申繻询问取名字的事。申繻回答说:“取名有五种方式,有信,有义,有像,有假,有类。用出生的某一种情况来命名是信,用祥瑞的字眼来命名是义,用相类似的字眼来命名是像,假借某种事物的名称来命名是假,借用和父亲有关的字眼来命名是类。命名不用国名,不用官名,不用山川名,不用疾病名,不用牲畜名,不用器物礼品名。周朝人用避讳来奉事神明,名,在死了以后就要避讳。所以用国名命名,就会废除人名,用官名命名就会改变官称,用山川命名就会改变山川的神名,用牲畜命名就会废除祭祀,用器物礼品命名就会废除礼仪。晋国因为僖公而废除司徒之官,宋国因为武公而废除司空之官名,我国因为先君献公、武公而废除具山、敖山二山之名,所以大的事物不可以用来命名。”桓公说:“这孩子的出生,和我在同一个干支,把他命名叫做同。” +冬季,纪侯前来朝见,请求鲁国代纪国取得周天子的命令去向齐国求和。桓公告诉他说自己做不到。 + + +桓公七年 +【经】七年春二月己亥,焚咸丘。夏,谷伯绥来朝。邓侯吾离来朝。 +【传】七年春,谷伯、邓侯来朝。名,贱之也。 +夏,盟、向求成于郑,既而背之。 +秋,郑人、齐人、卫人伐盟、向。王迁盟、向之民于郏。 +冬,曲沃伯诱晋小子侯,杀之。 +译文 +七年春季,穀伯绥、邓侯吾离来鲁国朝见。《春秋》记载他们的名字,是由于轻视他们。 +夏季,盟邑、向邑向郑国求和,不久又背叛郑国。 +秋季,郑军、齐军、卫军攻打盟邑、向邑。周桓王把盟邑、向邑的百姓迁到郏地。 +冬季,曲沃伯诱骗晋国小子侯,把他杀死了。 + +桓公八年 +【经】八年春正月己卯,烝。天王使家父来聘。夏五月丁丑,烝秋,伐邾。冬十月,雨雪。祭公来,遂逆王后于纪。 +【传】八年春,灭翼。 +随少师有宠。楚斗伯比曰:“可矣。仇有衅,不可失也。” +夏,楚子合诸侯于沈鹿。黄、随不会,使薳章让黄。楚子伐随,军于汉、淮之间。 +季梁请下之:“弗许而后战,所以怒我而怠寇也。”少师谓随侯曰:“必速战。不然,将失楚师。”随侯御之,望楚师。季梁曰:“楚人上左,君必左,无与王遇。且攻其右,右无良焉,必败。偏败,众乃携矣。”少师曰:“不当王,非敌也。”弗从。战于速杞,随师败绩。随侯逸,斗丹获其戎车,与其戎右少师。 +秋,随及楚平。楚子将不许,斗伯比曰:“天去其疾矣,随未可克也。”乃盟而还。 +冬,王命虢仲立晋哀侯之弟缗于晋。 +祭公来,遂逆王后于纪,礼也。 +译文 +八年春季,曲沃伯灭亡了翼邑。随国少师受到宠信。楚国的鬬伯比说:“可以了,敌国内部有了裂痕,不可以失掉机会。” +夏季,楚武王在沈鹿会合诸侯的军队。黄、随两国不参加会见。楚武王派薳章去责备黄国,然后亲自讨伐随国,军队驻扎在汉水、淮水之间。 +季梁建议向楚人表示投降,说:“等他们不肯,然后作战,这样就可以激怒我军而使敌军懈怠。”少师对随侯说:“必须速战,不这样,就会丢失战胜楚军的机会。”随侯率军抵御楚军。远望楚国的军队,季梁说:“楚人以左为尊,国君一定在左军之中,不要和楚王正面作战,姑且攻击他的右军。右军没有好指挥官,必然失败。他们的偏军一败,大众就离散了。”少师说:“不与楚王正面作战,这就表示我们和他不能对等。”随侯又没有听从季梁的话。在速杞交战,随军大败。随侯逃走,鬬丹俘获了随侯的战车和车右少师。 +秋季,随国要同楚国讲和。楚武王本拟不同意。鬬伯比说:“上天已经铲除他们讨厌的少师了,但随国还不可能战胜。”于是订立了盟约而回国。冬季,周桓王命令虢仲立了晋哀侯的兄弟缗为晋侯。祭公到鲁国来,然后到纪国迎接王后,这是合于礼的。 + +桓公九年 +【经】九年春,纪季姜归于京师。夏四月,秋七月。冬,曹伯使其世子射姑来朝。 +【传】九年春,纪季姜归于京师。凡诸侯之女行,唯王后书。 +巴子使韩服告于楚,请与邓为好。楚子使道朔将巴客以聘于邓。邓南鄙郁人攻而夺之币,杀道朔及巴行人。楚子使薳章让于邓,邓人弗受。 +夏,楚使斗廉帅师及巴师围郁。邓养甥、聃甥帅师郁救。三逐巴师,不克。斗廉衡陈其师于巴师之中,以战,而北。邓人逐之,背巴师而夹攻之。邓师大败,郁人宵溃。 +秋,虢仲、芮伯、梁伯、荀侯、贾伯伐曲沃。 +冬,曹大子来朝,宾之以上卿,礼也。享曹大子,初献,乐奏而叹。施父曰:“曹大子其有忧乎?非叹所也。” +译文 +九年春季,纪国的季姜出嫁到京师。凡是诸侯的女儿出嫁,只有出嫁做王后才加以记载。 +巴子派遣韩服向楚国报告,请求和邓国友好。楚武王派遣道朔带领巴国的使者到邓国聘问。邓国南部边境的鄾地人攻击他们,并掠夺财礼,杀死了道朔和巴国的使者。楚武王派遣薳章责备邓国,邓国人拒不接受。 +夏季,楚国派遣鬬廉率领楚军和巴军包围鄾地。邓国的养甥、聃甥率领邓军救援鄾地。邓军三次向巴军发起冲锋,不能得胜。鬬廉率军在巴军之中列为横阵,当与邓军交战时,假装败逃。邓军追逐楚军,巴军就处于他们背后。楚、巴两军夹攻邓军,邓军大败。鄾地人黄昏后就溃散了。 +秋季,虢仲、芮伯、梁伯、荀侯、贾伯,共同出兵讨伐曲沃。 +冬季,曹国的太子来鲁国朝见。用上卿之礼接待他,这是合于礼的。设享礼招待曹太子。首先献酒,接着奏乐,曹太子就叹气。施父说:“曹太子恐怕会有什么忧心事吧?因为这里不是叹息的地方。” + +桓公十年 +【经】十年春王正月,庚申,曹伯终生卒。夏五月,葬曹桓公。秋,公会卫侯于桃丘,弗遇。冬十有二月丙午,齐侯、卫侯、郑伯来战于郎。 +【传】十年春,曹桓公卒。 +虢仲谮其大夫詹父于王。詹父有辞,以王师伐虢。夏,虢公出奔虞。 +秋,秦人纳芮伯万于芮。 +初,虞叔有玉,虞公求旃。弗献。既而悔之。曰:“周谚有之:‘匹夫无罪,怀璧其罪。’吾焉用此,其以贾害也?”乃献。又求其宝剑。叔曰:“是无厌也。无厌,将及我。”遂伐虞公,故虞公出奔共池。 +冬,齐、卫、郑来战于郎,我有辞也。 +初,北戎病齐,诸侯救之。郑公子忽有功焉。齐人饩诸侯,使鲁次之。鲁以周班后郑。郑人怒,请师于齐。齐人以卫师助之。故不称侵伐。先书齐、卫,王爵也。 +译文 +十年春季,曹桓公逝世。 +虢仲在周桓王那里进谗言诬陷大夫詹父。詹父有理,带领周天子的军队进攻虢国。夏季,虢公逃亡到虞国。 +秋季,秦国人把芮伯万送回芮国。 +当初,虞公的兄弟虞叔藏有宝玉,虞公向他索求玉。虞叔没有进献,不久又后悔这件事,说:“周朝的谚语说:‘百姓没有罪,怀藏玉璧就有了罪。’我哪用得着美玉,难道要用它买来祸害?”于是就把玉璧献给了虞公。虞公又向虞叔索求宝剑。虞叔说:“这是没有满足了。满足不了,祸害会连累到我身上。”于是就攻打虞公,所以虞公逃亡到共池。 +冬季,齐国、卫国、郑国联军前来和我军在郎地作战,我国是有理的。 +当初,北戎多次骚扰齐国,使它困疲,诸侯救援齐国,郑国的公子忽有功劳。齐国人给诸侯的军队馈送食物,让鲁国确定馈送的次序。鲁国按周室封爵的次序把郑国排在后面。郑国人发怒,请求齐国出兵。齐国人率领卫国军队帮助郑国,所以《春秋》不称这次战争为“侵伐”。先记载齐国和卫国,是按照周室封爵的次序。 + +桓公十一年 +【经】十有一年春正月,齐人、卫人、郑人盟于恶曹。夏五月癸未,郑伯寤生卒。秋七月,葬郑庄公。九月,宋人执郑祭仲。突归于郑。郑忽出奔卫。柔会宋公、陈侯、蔡叔盟于折。公会宋公于夫钟。冬十月有二月,公会宋公于阚。 +【传】十一年春,齐、卫、郑、宋盟于恶曹。 +楚屈瑕将盟贰、轸。郧人军于蒲骚,将与随、绞、州、蓼伐楚师。莫敖患之。斗廉曰:“郧人军其郊,必不诫,且日虞四邑之至也。君次于郊郢,以御四邑。我以锐师宵加于郧,郧有虞心而恃其城,莫有斗志。若败郧师,四邑必离。”莫敖曰:“盍请济师于王?”对曰:“师克在和,不在众。商、周之不敌,君之所闻也。成军以出,又何济焉?”莫敖曰:“卜之?”对曰:“卜以决疑,不疑何卜?”遂败郧师于蒲骚,卒盟而还。郑昭公之败北戎也,齐人将妻之,昭公辞。祭仲曰:“必取之。君多内宠,子无大援,将不立。三公子皆君也。”弗从。 +夏,郑庄公卒。 +初,祭封人仲足有宠于庄公,庄公使为卿。为公娶邓曼,生昭公,故祭仲立之。宋雍氏女于郑庄公,曰雍姞,生厉公。雍氏宗有宠于宋庄公,故诱祭仲而执之,曰:“不立突,将死。”亦执厉公而求赂焉。祭仲与宋人盟,以厉公归而立之。 +秋九月丁亥,昭公奔卫。己亥,厉公立。 +译文 +十一年春季,齐国、卫国、郑国、宋国在恶曹举行会盟。 +楚国的屈瑕打算和贰、轸两国结盟。郧国人的军队驻扎在蒲骚,准备和随、绞、州、蓼四国一起进攻楚国军队。莫敖担心这件事。鬬廉说:“郧国的军队驻扎在他们的郊区,一定缺乏警戒,并且天天盼望四国军队的来到。您驻在郊郢来抵御这四个国家,我们用精锐部队夜里进攻郧国。郧国一心盼望四国军队,而且又依仗城郭坚固,没有人再有战斗意志。如果打败郧军,四国一定离散。”莫敖说:“何不向君王请求增兵?”鬬廉回答说:“军队能够获胜,在于团结一致,不在于人多。商朝敌不过周朝,这是您所知道的。整顿军队而出兵,又增什么兵呢?”莫敖说:“占卜一下?”鬬廉回答说:“占卜是为了决断疑惑,没有疑惑,为什么占卜?”于是就在蒲骚打败郧国军队,终于和贰、轸两国订立了盟约回国。 +郑昭公打败北戎的时候,齐侯打算把女儿嫁给他,昭公辞谢了。祭仲说:“您一定要娶她。国君姬妾很多,您如果没有有力的外援,将不能继承君位。其他三位公子都可能做国君的。”昭公不同意。 +夏季,郑庄公死。 +当初,祭地封人仲足受到郑庄公的宠信,庄公任命他做卿。祭仲为庄公娶了邓曼,生了昭公。所以祭仲立他为国君。宋国的雍氏把女儿嫁给郑庄公,名叫雍姞,生了厉公。雍氏为人所尊重,受到宋庄公的宠爱,所以就诱骗祭仲而把他抓起来,说:“不立突为国君,就没有你的命。”雍氏还抓了厉公索取财货。祭仲和宋国人结盟,让厉公归国而立他为国君。 +秋季,九月十三日,郑昭公逃亡到卫国。二十五日,郑厉公立为国君。 + +桓公十二年 +【经】十有二年春正月。夏六月壬寅,公会杞侯、莒子盟于曲池。秋七月丁亥,公会宋公、燕人盟于谷丘。八月壬辰,陈侯跃卒。公会宋公于虚。冬十有一月,公会宋公于龟。丙戌,公会郑伯,盟于武父。丙戌,卫侯晋卒。十有二月,及郑师伐宋。丁未,战于宋。 +【传】十二年夏,盟于曲池,平杞、莒也。 +公欲平宋、郑。秋,公及宋公盟于句渎之丘。宋成未可知也,故又会于虚。冬,又会于龟。宋公辞平,故与郑伯盟于武父。遂帅师而伐宋,战焉,宋无信也。 +君子曰:“苟信不继,盟无益也。《诗》云:‘君子屡盟,乱是用长。’无信也。” +楚伐绞,军其南门。莫敖屈瑕曰:“绞小而轻,轻则寡谋,请无扞采樵者以诱之。”从之。绞人获三十人。明日,绞人争出,驱楚役徒于山中。楚人坐其北门,而覆诸山下,大败之,为城下之盟而还。 +伐绞之役,楚师分涉于彭。罗人欲伐之,使伯嘉谍之,三巡数之。 +译文 +十二年,夏季,鲁桓公和杞侯、莒子在曲池会盟,这是让杞国和莒国讲和。 +桓公想和宋国、郑国讲和。秋季,桓公和宋庄公在句渎之丘会盟。由于不知道宋国对议和有无诚意,所以又在虚地会见;冬季,又在龟地会见。宋公拒绝议和,所以桓公和郑厉公在武父结盟,盟后就率领军队进攻宋国。发生这场战争,是因为宋国不讲信用。 +君子说:“如果一再不讲信用,结盟也没有好处。《诗经》说:‘君子多次结盟,反而使动乱滋长。’就是由于没有信用。” +楚国进攻绞国,军队驻扎在南门。莫敖屈瑕说:“绞国地小而人轻浮,轻浮就缺少主意。请对砍柴的人不设保卫,用这引诱他们。”楚王听从了屈瑕的意见。绞军俘获了三十个砍柴人。第二天,绞军争着出城,把楚国的砍柴人赶到山里。楚军坐等在北门,同时在山下设伏兵,大败绞军,强迫绞国订立城下之盟而回国。 +在进攻绞国的这次战役中,楚军分兵渡过彭水。罗国准备攻打楚军,派遣伯嘉去侦探,三次遍数了楚军的人数。 + +桓公十三年 +【经】十有三年春二月,公会纪侯、郑伯。己巳,及齐侯、宋公、卫侯、燕人战。齐师、宋师、卫师、燕师败绩。三月,葬卫宣公。夏,大水。秋七月。冬十月。 +【传】十三年春,楚屈瑕伐罗,斗伯比送之。还,谓其御曰:“莫敖必败。举趾高,心不固矣。”遂见楚子曰:“必济师。”楚子辞焉。入告夫人邓曼。邓曼曰:“大夫其非众之谓,其谓君抚小民以信,训诸司以德,而威莫敖以刑也。莫敖狃于蒲骚之役,将自用也,必小罗。君若不镇抚,其不设备乎?夫固谓君训众而好镇抚之,召诸司而劝之以令德,见莫敖而告诸天之不假易也。不然,夫岂不知楚师之尽行也?”楚子使赖人追之,不及。 +莫敖使徇于师曰:“谏者有刑。”及鄢,乱次以济。遂无次,且不设备。及罗,罗与卢戎两军之。大败之。莫敖缢于荒谷,群帅囚于冶父以听刑。楚子曰:“孤之罪也。”皆免之。 +宋多责赂于郑,郑不堪命。故以纪、鲁及齐与宋、卫、燕战。不书所战,后也。 +郑人来请修好。 +译文 +十三年春季,楚国的屈瑕进攻罗国,鬬伯比为他送行。回来时,对他的御者说:“莫敖一定失败。走路把脚抬得很高,表明他的心神不稳定了。” +于是进见楚武王,说:“一定要增派军队!”楚武王拒绝了,回宫告诉夫人邓曼。邓曼说:“大夫鬬伯比的意思不在人数的多少,而是说君王要以诚信来镇抚百姓,以德义来训诫官员,而以刑法来使莫敖畏惧。莫敖已经满足于蒲骚这一次战功,他会自以为是,必然轻视罗国。君王如果不加控制,不是等于不设防范吗!鬬伯比所说的请君王训诫百姓而好好地安抚督察他们,召集官员们而勉之以美德,见到莫敖而告诉他上天对他的过错是不会宽恕的。 +不是这样,鬬大夫难道不知道楚国军队已经全部出发了?”楚王派赖国人追赶屈瑕,没有追上。 +莫敖派人在军中通告:“敢于进谏的人要受刑罚!”到达鄢水,楚军由于渡河而次序大乱。全军乱七八糟毫无秩序,而且又不设防。到达罗国,罗国和卢戎的军队从两边夹攻楚军,把楚军打得大败。莫敖吊死在荒谷,其他将领们被囚禁在冶父,等待处罚。楚武王说:“这是我的罪过。”把将领们都赦免了。 +宋国多次向郑国索取财货,郑国实在不能忍受,所以率领纪、鲁两国的军队和齐、宋、卫、燕四国的军队交战。《春秋》没有记载战争的地点,是由于桓公迟到了。 +郑国派人来鲁国,请求重修旧好。 + +桓公十四年 +【经】十有四年春正月,公会郑伯于曹。无冰。夏五,郑伯使其弟语来盟。秋八月壬申,御廪灾。乙亥,尝。冬十有二月丁巳,齐侯禄父卒。宋人以齐人、蔡人、卫人、陈人伐郑。 +【传】十四年春,会于曹。曹人致饩,礼也。 +夏,郑子人来寻盟,且修曹之会。 +秋八月壬申,御廪灾。乙亥,尝。书,不害也。 +冬,宋人以诸侯伐郑,报宋之战也。焚渠门,入,及大逵。伐东郊,取牛首。以大宫之椽归,为卢门之椽。 +译文 +十四年春季,鲁桓公和郑厉公在曹国会见。曹国人送来食物,这是合于礼的。 +夏季,郑国的子人前来重温过去盟会的友好,并且也是重温在曹国的会见。 +秋季,八月十五日,储藏祭祀谷物的仓库发生火灾。十八日,举行尝祭。《春秋》所以记载这件事,是表示火灾尚不足为害。 +冬季,宋国人联合诸侯进攻郑国,这是为了报复在宋国的那次战争。诸侯联军焚烧了郑国都城的渠门,进了城到了大街上,攻打东郊,占取牛首,把郑国太庙的椽子拿回去做宋国卢门的椽子。 + +桓公十五年 +【经】十有五年春二月,天王使家父来求车。三月乙未,天王崩。夏四月己巳,葬齐僖公。五月,郑伯突出奔蔡。郑世子忽复归于郑。许叔入于许。公会齐侯于艾。邾人、牟人、葛人来朝。秋九月,郑伯突入于栎。冬十有一月,公会宋公、卫侯、陈侯于衰,伐郑。 +【传】十五年春,天王使家父来求车,非礼也。诸侯不贡车、服,天子不私求财。 +祭仲专,郑伯患之,使其婿雍纠杀之。将享诸郊。雍姬知之,谓其母曰:“父与夫孰亲?”其母曰:“人尽夫也,父一而已,胡可比也?”遂告祭仲曰:“雍氏舍其室而将享子于郊,吾惑之,以告。”祭仲杀雍纠,尸诸周氏之汪。公载以出,曰:“谋及妇人,宜其死也。”夏,厉公出奔蔡。 +六月乙亥,昭公入。 +许叔入于许。 +公会齐侯于艾,谋定许也。 +秋,郑伯因栎人杀檀伯,而遂居栎。 +冬,会于衰,谋伐郑,将纳厉公也。弗克而还。 +译文 +十五年春季,周桓王派大夫家父来鲁国索取车辆,这是不合于礼的。诸侯不进贡车辆、礼服,天子不求取个人财物。 +祭仲专权,郑厉公对他很担心,派祭仲的女婿雍纠去杀他。雍纠准备在郊外宴请祭仲。雍姬知道了,对她母亲说:“父亲与丈夫哪一个更亲近?”她母亲说:“任何男子,都可能成为一个女人的丈夫,父亲却只有一个,怎么能够相比呢?”于是雍姬就告诉祭仲说:“雍氏不在他家里而在郊外宴请您,我怀疑这件事,所以告诉您。”祭仲就杀了雍纠,把尸体摆在周氏的池塘边。郑厉公装载了尸体逃离郑国,说:“大事和妇女商量,死得活该。” +夏季,郑厉公逃亡到蔡国。六月二十二日,郑昭公进入郑国。许叔进入许国都城。桓公和齐襄公在艾地会见,目的是为了谋划安定许国。 +秋季,郑厉公凭借栎地的人杀了檀伯,因而就居住在栎地。 +冬季,鲁桓公与宋庄公、卫惠公、陈庄公在袲地会见,策划进攻郑国,以便护送厉公回国。可是战争失败了,军队各自回国。 + +桓公十六年 +【经】十有六年春正月,公会宋公、蔡侯、卫侯于曹。夏四月,公会宋公、卫侯、陈侯、蔡侯伐郑。秋七月,公至自伐郑。冬,城向。十有一月,卫侯朔出奔齐。 +【传】十六年春正月,会于曹,谋伐郑也。 +夏,伐郑。 +秋七月,公至自伐郑,以饮至之礼也。 +冬,城向,书,时也。 +初,卫宣公烝于夷姜,生急子,属诸右公子。为之娶于齐,而美,公取之,生寿及朔,属寿于左公子。夷姜缢。宣姜与公子朔构急子。公使诸齐,使盗待诸莘,将杀之。寿子告之,使行。不可,曰:“弃父之命,恶用子矣!有无父之国则可也。”及行,饮以酒,寿子载其旌以先,盗杀之。急子至,曰:“我之求也。此何罪?请杀我乎!”又杀之。二公子故怨惠公。 +十一月,左公子泄、右公子职立公子黔牟。惠公奔齐。 +译文 +十六年春季,正月,鲁桓公和宋庄公、蔡桓侯、卫惠公在曹国会见,又策划进攻郑国。 +夏季,进攻郑国。 +秋季七月,桓公进攻郑国回到国内,举行了祭告宗庙、大宴臣下的礼仪。 +冬季,在向地筑城。《春秋》所以记载这件事,是由于不妨碍农时。 +当初,卫宣公和父亲的姬妾夷姜私通,生了急子。卫宣公把急子托给右公子抚养,又为他在齐国娶妻,这个女人很美,卫宣公就自己娶了她,生了寿和朔,把寿嘱托给左公子。夷姜自己吊死了。宣姜和公子朔诬陷急子。卫宣公派急子出使到齐国,指使坏人在莘地等着,打算杀死他。寿子把这件事告诉急子,让他逃走。急子不同意说:“丢掉父亲的命令,哪里还用得着儿子!如果世界上有没有父亲的国家就可以逃到那里去了。”等到临走,寿子用酒把急子灌醉。寿子车上插着太子的旗帜走在前面,坏人就杀了寿子。急子赶到,说:“他们要杀的是我。他有什么罪?请杀死我吧!”坏人又杀了急子。左、右两公子因此怨恨惠公。十一月,左公子泄、右公子职立公子黔牟为国君。卫惠公逃亡到齐国。 + +桓公十七年 +【经】十有七年春正月丙辰,公会齐侯、纪侯盟于黄。二月丙午,公会邾仪父,盟于趡。夏五月丙午,及齐师战于奚。六月丁丑,蔡侯封人卒。秋八月,蔡季自陈归于蔡。癸巳,葬蔡桓侯。及宋人、卫人伐邾。冬十月朔,日有食之。 +【传】十七年春,盟于黄,平齐、纪,且谋卫故也。 +乃邾仪父盟于趡,寻蔑之盟也。 +夏,及齐师战于奚,疆事也。于是齐人侵鲁疆,疆吏来告,公曰:“疆场之事,慎守其一,而备其不虞。姑尽所备焉。事至而战,又何谒焉?” +蔡桓侯卒。蔡人召蔡季于陈。 +秋,蔡季自陈归于蔡,蔡人嘉之也。 +伐邾,宋志也。 +冬十月朔,日有食之。不书日,官失之也。天子有日官,诸侯有日御。日官居卿以底日,礼也。日御不失日,以授百官于朝。 +初,郑伯将以高渠弥为卿,昭公恶之,固谏,不听,昭公立,惧其杀己也。辛卯,弑昭公,而立公子亹。 +君子谓昭公知所恶矣。公子达曰:“高伯其为戮乎?复恶已甚矣。” +译文 +十七年春季,鲁桓公和齐襄公、纪侯在黄地结盟,目的是为了促成齐、纪的和议,同时商量对付卫国。桓公和邾仪父在趡地结盟,这是由于重申蔑地的盟约。夏季,鲁军与齐国军队在奚地发生战争,这是边境局部冲突。当时齐国 +人入侵鲁国的边境,边境官吏前来报告。桓公说:“边境上的事情,谨慎地防守自己一边而且防备发生意外。暂且尽力防备就是了。发生了事情就迎战,又何必先行请示报告呢?” +蔡桓侯去世了,蔡国人把蔡季从陈国召回来。秋季,蔡季从陈国回到蔡国,被立为国君,因为蔡国人都拥护他。进攻邾国,这是宋国的意愿。冬季,十月初一,日蚀。《春秋》没有记载日子,这是史官的漏记。天 +子有日官,诸侯有日御。日官居于卿的地位,以推算历象,这是合于礼的。日御详细记载每月大小和干支,无所遗漏,在朝廷上通告百官。 +当初,郑庄公准备任命高渠弥做卿,昭公讨厌他,坚决劝阻,庄公不听从。昭公即位后,高渠弥畏惧昭公会杀掉自己,就在十月二十二日,杀死昭公而立公子亹。 +君子认为“昭公了解他所讨厌的人”。公子达说:“高伯恐怕要被诛杀的吧!因为他报仇报得太过分了。” + +桓公十八年 +【经】十有八年春王正月,公会齐侯于泺。公与夫人姜氏遂如齐。夏四月丙子,公薨于齐。丁酉,公之丧至自齐。秋七月,冬十有二月己丑,葬我君桓公。 +【传】十八年春,公将有行,遂与姜氏如齐。申繻曰:“女有家,男有室,无相渎也,谓之有礼。易此,必败。” +公会齐侯于泺,遂及文姜如齐。齐侯通焉。公谪之,以告。 +夏四月丙子,享公。使公子彭生乘公,公薨于车。 +鲁人告于齐曰:“寡君畏君之威,不敢宁居,来修旧好,礼成而不反,无所归咎,恶于诸侯。请以彭生除之。”齐人杀彭生。 +秋,齐侯师于首止;子亹会之,高渠弥相。七月戊戌,齐人杀子亹而轘高渠弥,祭仲逆郑子于陈而立之。是行也,祭仲知之,故称疾不往。人曰:“祭仲以知免。”仲曰:“信也。” +周公欲弑庄王而立王子克。辛伯告王,遂与王杀周公黑肩。王子克奔燕。 +初,子仪有宠于桓王,桓王属诸周公。辛伯谏曰:“并后、匹嫡、两政、耦国,乱之本也。”周公弗从,故及。 +译文 +十八年春季,鲁桓公准备外出旅行,便和姜氏到齐国去。申繻劝阻说:“女人有夫家,男人有妻室,不可以互相轻慢,这就叫有礼。违反这一点必然坏事。”桓公和齐襄公在泺地会见,然后就和文姜到了齐国。齐襄公和文姜通奸。桓公责怪文姜,文姜把这件事告诉了齐襄公。 +夏季,四月初十日,齐襄公设宴招待鲁桓公。宴后齐襄公派公子彭生帮助桓公登车,桓公死在车中。 +鲁国人告诉齐襄公说:“我们国君畏惧您的威严,不敢苟安,来到贵国重修旧好,礼仪完成后却没有回国。我国不知道该归罪于谁,在诸侯中造成了恶劣影响。请求用彭生来清除这种影响。”齐国人杀死了彭生。 +秋季,齐襄公率领军队驻扎在首止。子亹前去会见,高渠弥作为首席随员。七月初三日,齐国人杀死了子亹而把高渠弥五马分尸。祭仲到陈国迎接郑子而立他为国君。 +这次会见,祭仲事先预料到情况,所以假称有病而没有去。有人说:“祭仲由于有先见之明,所以才免祸。”祭仲说:“那是对的。” +周公打算杀死周庄王而立王子克。辛伯报告庄王,就帮着庄王杀了周公黑肩。王子克逃亡到燕国。 +当初,子仪受到桓王的宠信,桓王把他嘱托给周公。辛伯曾劝谏周公说:“妾媵并同于王后,庶子相等于嫡子,权臣和卿士互争权力,大城和国都一样,这都是祸乱的根本。”周公不听,所以招致杀身之祸。 + + +庄公 + +庄公元年 +【经】元年春王正月。三月,夫人孙于齐。夏,单伯送王姬。秋,筑王姬之馆于外。冬十月乙亥,陈侯林卒。王使荣叔来锡桓公命。王姬归于齐。齐师迁纪、郱、鄑、郚。 +【传】元年春,不称即位,文姜出故也。 +三月,夫人孙于齐。不称姜氏,绝不为亲,礼也。 +秋,筑王姬之馆于外。为外,礼也。 +译文 +元年春季,《春秋》没有记载鲁庄公即位,这是由于文姜外出没有回国的缘故。 +三月,鲁桓公夫人到了齐国。《春秋》不称姜氏而称夫人,是由于断绝了母子关系,这是合于礼的。 +秋季,在城外建造王姬的行馆。因为王姬不是鲁国的女子,而是周天子的女儿,这是合于礼的。 + +庄公二年 +【经】二年春王二月,葬陈庄公。夏,公子庆父帅师伐于余丘。秋七月,齐王姬卒。冬十有二月,夫人姜氏会齐侯于禚。乙酉,宋公冯卒。 +【传】二年冬,夫人姜氏会齐侯于禚。书,奸也。 +译文 +  二年冬季,夫人姜氏和齐襄公在禚地相会。《春秋》记载这件事,是为揭露他们的奸情。 + +庄公三年 +【经】三年春王正月,溺会齐师伐卫。夏四月,葬宋庄公。五月,葬桓王。秋,纪季以酅入于齐。冬,公次于滑。 +【传】三年春,溺会齐师伐卫,疾之也。 +夏五月,葬桓王,缓也。 +秋,纪季以酅入于齐,纪于是乎始判。 +冬,公次于滑,将会郑伯,谋纪故也。郑伯辞以难。凡师,一宿为舍,再宿为信,过信为次。 +译文 +三年春季,公子溺会合齐国军队攻打卫国,《春秋》单称他的名字溺,不称公子,是表示对他的贬斥。夏季五月,安葬周桓王。这在丧礼的时间上太迟缓了。秋季,纪季把酅地割让给齐国,纪国从这时候开始分裂。冬季,鲁庄公带领护卫军屯驻在滑地多夜,打算会见郑伯,策划纪国的 +事务。郑伯用国内不安定为理由加以推脱。凡是军队在外,住一夜叫做舍,两夜叫做信,两夜以上叫做次。 + +庄公四年 +【经】四年春王二月,夫人姜氏享齐侯于祝丘。三月,纪伯姬卒。夏,齐侯、陈侯、郑伯遇于垂。纪侯大去其国。六月乙丑,齐侯葬纪伯姬。秋七月。冬,公及齐人狩于禚。 +【传】四年春,王三月,楚武王荆尸,授师孑焉,以伐随,将齐,入告夫人邓曼曰:“余心荡。”邓曼叹曰:“王禄尽矣。盈而荡,天之道也。先君其知之矣,故临武事,将发大命,而荡王心焉。若师徒无亏,王薨于行,国之福也。”王遂行,卒于樠木之下。令尹斗祁、莫敖屈重除道、梁溠,营军临随。随人惧,行成。莫敖以王命入盟随侯,且请为会于汉汭,而还。济汉而后发丧。 +纪侯不能下齐,以与纪季。夏,纪侯大去其国,违齐难也。 +译文 +四年春季,周王朝历法的三月,楚武王运用名叫荆尸的军阵,把戟颁发给士兵,要去攻打随国。准备斋戒,进宫告诉夫人邓曼说:“我心神动荡不安。”邓曼叹气说:“君王的福禄尽了。满了就会动荡,这是自然的道理。先君大概知道了,所以面临作战,将要发布征伐命令而使君王心跳。如果军队没有什么损失,而君王死在行军途中,这就是国家之福了。”楚武王于是出征,死在樠树下面。令尹鬬祁、莫敖屈重秘不发丧,开通新路,并在溠水筑桥,在随国境外建筑营垒。随国人恐惧,向楚军求和。莫敖屈重以楚王的名义进入随国,和随侯结盟,而且邀请随侯在汉水转湾处会见,然后退兵。渡过了汉水以后公布丧事。 +纪侯不能屈从齐国,把国家政权让给了纪季。夏季,纪侯永远离开了他的国家,以避免齐国对他所加的祸害。 + +庄公五年 +【经】五年春王正月。夏,夫人姜氏如齐师。秋,郳犁来来朝。冬,公会齐人、宋人、陈人、蔡人伐卫。 +【传】五年秋,郳犁来来朝,名,未王命也。 +冬,伐卫纳惠公也。 +译文 +五年秋季,郳犁来到鲁国朝见。《春秋》只记载他的名字,是因为他还没有得到周天子的封爵。 +冬季,鲁庄公联合齐、宋、陈、蔡四国攻打卫国,目的是为了护送卫惠公回国。 + + +庄公六年 +【经】六年春王正月,王人子突救卫。夏六月,卫侯朔入于卫。秋,公至自伐卫。螟。冬,齐人来归卫俘。 +【传】六年春,王人救卫。 +夏,卫侯入,放公子黔牟于周,放宁跪于秦,杀左公子泄、右公子职,乃即位。 +君子以二公子之立黔牟为不度矣。夫能固位者,必度于本末而后立衷焉。不知其本,不谋。知本之不枝,弗强。《诗》云:“本枝百世。” +冬,齐人来归卫宝,文姜请之也。 +楚文王伐申,过邓。邓祁侯曰:“吾甥也。”止而享之。骓甥、聃甥、养甥请杀楚子,邓侯弗许。三甥曰:“亡邓国者,必此人也。若不早图,后君噬齐。其及图之乎?图之,此为时矣。”邓侯曰:“人将不食吾余。”对曰:“若不从三臣,抑社稷实不血食,而君焉取余?”弗从。还年,楚子伐邓。十六年,楚复伐邓,灭之。 +译文 +六年春季,周庄王的属官叫子突的率军救援卫国。 +夏季,卫惠公回国,放逐公子黔牟到成周,放逐甯跪到秦国,杀了左公子泄、右公子职,这才即位。 +君子认为左、右二公子扶立黔牟为国君,“是一种很欠考虑始终的行为。对能够巩固自己地位的人,必须考虑他的各方面,然后用适当的方式立他为国君。不了解他的根本,就是缺乏谋略;了解到虽有根本却没有枝叶,就不要勉强树立他。《诗》说:‘有本有枝,繁衍百世。’” +冬季,齐国人前来归还卫国的宝器,这是由于文姜的请求。 +楚文王进攻申国,路过邓国。邓祁侯说:“他是我的外甥。把他留下而设宴招待他。骓甥、聃甥、养甥请求杀掉楚文王。邓侯不允许。这三甥都说:“灭亡邓国的,必定是这个人。如果不早打主意,君王后悔便来不及了。现在下手还来得及!下手吧,现在正是时候!”邓侯说:“如果这样做,人们会唾弃我而不吃我剩下的东西的。”三位外甥回答说:“如果不听我们三个人的话,土地和五谷的神明就得不到祭享,君王到哪里去取得祭神的剩余?”邓祁侯还是不答应。攻打申国回国的那一年,楚王进攻邓国。庄公十六年,楚国再次攻打邓国,终于灭亡了邓国。 + +庄公七年 +【经】七年春,夫人姜氏会齐侯于防。夏四月辛卯,夜,恒星不见。夜中,星陨如雨。秋,大水。无麦、苗。冬,夫人姜氏会齐侯于谷。 +【传】七年春,文姜会齐侯于防,齐志也。 +夏,恒星不见,夜明也。星陨如雨,与雨偕也。 +秋,无麦苗,不害嘉谷也。 +译文 +七年春季,文姜和齐襄公在防地相会,这是出于齐襄公的主意。 +夏季,看不到常见的星星,这是由于夜空明亮的缘故。流星坠落而且带着雨点,这是和雨一起落下来的。 +秋季,麦子不收,小苗不长,但没有影响黍稷的收成。 + +庄公八年 +【经】八年春王正月,师次于郎,以俟陈人,蔡人。甲午,治兵。夏,师及齐师围郕,郕降于齐师。秋,师还。冬十有一月癸未,齐无知弑其君诸儿。 +【传】八年春,治兵于庙,礼也。 +夏,师及齐师围郕。郕降于齐师。仲庆父请伐齐师。公曰:“不可。我实不德,齐师何罪?罪我之由。《夏书》曰:‘皋陶迈种德,德,乃降。’姑务修德以待时乎。”秋,师还。君子是以善鲁庄公。 +齐侯使连称、管至父戍葵丘。瓜时而往,曰:“及瓜而代。”期戍,公问不至。请代,弗许。故谋作乱。 +僖公之母弟曰夷仲年,生公孙无知,有宠于僖公,衣服礼秩如适。襄公绌之。二人因之以作乱。连称有从妹在公宫,无宠,使间公,曰:“捷,吾以女为夫人。” +冬十二月,齐侯游于姑棼,遂田于贝丘。见大豕,从者曰:“公子彭生也。”公怒曰:“彭生敢见!”射之,豕人立而啼。公惧,坠于车,伤足丧屦。反,诛屦于徒人费。弗得,鞭之,见血。走出,遇贼于门,劫而束之。费曰:“我奚御哉!”袒而示之背,信之。费请先入,伏公而出,斗,死于门中。石之纷如死于阶下。遂入,杀孟阳于床。曰:“非君也,不类。”见公之足于户下,遂弑之,而立无知。 +初、襄公立,无常。鲍叔牙曰:“君使民慢,乱将作矣。”奉公子小白出奔莒。乱作,管夷吾、召忽奉公子纠来奔。 +初,公孙无知虐于雍廪。 +译文 +八年春季,鲁庄公在太庙把武器发给军队,这是合于礼的。 +夏季,鲁军和齐军包围郕国。郕国向齐军投降。仲庆父请求进攻齐军。庄公说:“不行,我实在缺乏德行,齐军有什么罪?罪是由我引起的。《夏书》说:‘皋陶勉力培育德行,德行具备,别人就会降服。’我们姑且致力于修养德行,以等待时机吧!” +秋季,军队回国。君子因此而赞美鲁庄公。 +齐襄公派连称、管至父驻守葵丘,瓜熟的时节前去,说:“到明年瓜熟的时候派人替代你们。”驻守了一周年,齐襄公的命令并没有下来。连称、管至父请求派人替代,齐襄公不同意,因此就策划叛乱。 +齐僖公的同母兄弟叫夷仲年,生了公孙无知,受到僖公的宠信,衣服礼仪等种种待遇都和嫡子一样。齐襄公降低了公孙无知的待遇。连称、管至父两个人就利用公孙无知而发动叛变。连称有个堂妹在齐襄公的后宫,不得宠,就让她去侦察襄公的情况。公孙无知说:“事情成功,我把你立为君夫人。” +冬季,十二月,齐襄公在姑棼游玩,就在贝丘打猎。看到一头大野猪,随从说:“这是公子彭生啊!”齐襄公发怒说:“彭生敢来见我!”就用箭射它。野猪像人一样站起身啼叫。齐襄公害怕,从车上摔下来,伤了脚,丢了鞋。回去以后,责令徒人费去找鞋,费找不着,齐襄公就鞭打他,打得皮开血出。费走出去,在宫门口遇到叛贼。叛贼把他劫走并捆起来。费说:“我哪里会抵抗你们啊!”解开衣服让他们看自己的背后。叛贼相信了。费表示愿意和他们一起行动,请求先进宫去。进去以后把齐襄公隐藏起来,然后出宫同其他宦官和叛贼格斗,死在宫门里,石之纷如死在台阶下。叛贼就进入宫中,在床上杀了孟阳,说:“不是国君,样子不像。”一眼看到齐襄公的脚露出在门下边,就把他杀死了,而拥立无知为国君。 +当初,齐襄公即位,施政没有准则,使人不知所措。鲍叔牙说:“国君放纵,百姓懈怠,祸乱将要发生了。”就事奉公子小白避乱到莒国。叛乱发生,管夷吾、召忽事奉公子纠逃避到鲁国来。 +当初,公孙无知对待雍廪很暴虐。 + +庄公九年 +【经】九年春,齐人杀无知。公及齐大夫盟于既。夏,公伐齐纳子纠。齐小白入于齐。秋七月丁酉,葬齐襄公。八月庚申,及齐师战于乾时,我师败绩。九月,齐人取子纠杀之。冬,浚洙。 +【传】九年春,雍廪杀无知。 +公及齐大夫盟于既,齐无君也。 +夏,公伐齐,纳子纠。桓公自莒先入。 +秋,师及齐师战于乾时,我师败绩,公丧戎路,传乘而归。秦子、梁子以公旗辟于下道,是以皆止。 +鲍叔帅师来言曰:“子纠,亲也,请君讨之。管、召、仇也,请受而甘心焉。”乃杀子纠于生窦,召忽死之。管仲请囚,鲍叔受之,乃堂阜而税之。归而以告曰:“管夷吾治于高傒,使相可也。”公从之。 +译文 +九年春季,雍廪杀死公孙无知。 +鲁庄公和齐国的大夫在蔇地结盟,这是由于当时齐国没有国君。 +夏季,庄公进攻齐国,护送公子纠回国即位。齐桓公从莒国抢先回到齐国。 +秋季,我军和齐军在乾时作战,我军大败。庄公丧失战车,乘坐轻车逃了回来。秦子、梁子打着庄公的旗号躲在小道上作掩护,都被齐军俘虏了。 +鲍叔率领军队代表齐桓公来鲁国说:“子纠,是我齐君的亲人,请君王代我齐国讨伐。管仲、召忽,是我齐君的仇人,请把他们交给我齐国才能甘心。”于是就在生窦把公子纠杀死,召忽也自杀了。管仲请求把他押送回齐国,鲍叔接受请求,到了齐境堂阜就把他释放了。回国后,鲍叔报告齐桓公说:“管仲治国的才能比高傒都强,可以让他辅助君主。”齐桓公听从了这个意见。 + +庄公十年 +【经】十年春王正月,公败齐师于长勺。二月,公侵宋。三月,宋人迁宿。夏六月,齐师、宋师次于郎。公败宋师于乘丘。秋九月,荆败蔡师于莘,以蔡侯献舞归。冬十月,齐师灭谭,谭子奔莒。 +【传】十年春,齐师伐我。公将战,曹刿请见。其乡人曰:“肉食者谋之,又何间焉。”刿曰:“肉食者鄙,未能远谋。”乃入见。问何以战。公曰:“衣食所安,弗敢专也,必以分人。”对曰:“小惠未遍,民弗从也。”公曰:“牺牲玉帛,弗敢加也,必以信。”对曰:“小信未孚,神弗福也。”公曰:“小大之狱,虽不能察,必以情。”对曰:“忠之属也,可以一战,战则请从。”   公与之乘。战于长勺。公将鼓之。刿曰;“未可。”齐人三鼓,刿曰:“可矣。”齐师败绩。公将驰之。刿曰:“未可。”下,视其辙,登,轼而望之,曰:“可矣。”遂逐齐师。 +既克,公问其故。对曰:“夫战,勇气也,一鼓作气,再而衰,三而竭。彼竭我盈,故克之。夫大国难测也,惧有伏焉。吾视其辙乱,望其旗靡,故逐之。” +夏六月,齐师、宋师次于郎。公子偃曰:“宋师不整,可败也。宋败,齐必还,请击之。”公弗许。自雩门窃出,蒙皋比而先犯之。公从之。大败宋师于乘丘。齐师乃还。 +蔡哀侯娶于陈,息侯亦娶焉。息妫将归,过蔡。蔡侯曰:“吾姨也。”止而见之,弗宾。息侯闻之,怒,使谓楚文王曰:“伐我,吾求救于蔡而伐之。”楚子从之。秋九月,楚败蔡师于莘,以蔡侯献舞归。 +齐侯之出也,过谭,谭不礼焉。及其入也,诸侯皆贺,谭又不至。冬,齐师灭谭,谭无礼也。谭子奔莒,同盟故也。 +译文 +十年春季,齐国的军队攻打我鲁国。庄公准备迎战。曹刿请求接见。他的同乡人说:“那些每天都吃肉的人在那里谋划,你又去参与什么!”曹刿说:“吃肉的人鄙陋不灵活,不能作长远考虑。”于是入宫进见庄公。曹刿问庄公:“凭什么来作战?”庄公说:“有吃有穿,不敢独自享受,一定分给别人。”曹刿回答说:“小恩小惠不能周遍,百姓不会服从的。”庄公说:“祭祀用的牛羊玉帛,不敢擅自增加,祝史的祷告一定反映真实情况。”曹刿回答说:“一点诚心也不能代表一切,神明不会降福的。”庄公说:“大大小小的案件,虽然不能完全探明底细,但必定合情合理去办。”曹刿回答说:“这是为百姓尽力的一种表现,凭这个可以打一下。打起来,请让我跟着去。” +庄公和曹刿同乘一辆兵车,与齐军在长勺展开战斗,庄公准备击鼓。曹刿说:“还不行。”齐国人打了三通鼓。曹刿说:“可以了。”齐军大败,庄公准备追上去。曹刿说:“还不行。”下车,细看齐军的车辙,然后登上车前横木远望,说:“行了。”就追击齐军。 +战胜以后,庄公问曹刿取胜的缘故。曹刿回答说:“作战全凭勇气。第一通鼓振奋勇气,第二通鼓勇气就少了一些,第三通鼓勇气就没有了。他们的勇气没有了,而我们的勇气刚刚振奋,所以战胜了他们。大国的情况难于捉摸,还恐怕有埋伏。我细看他们的车辙已经乱了,远望他们的旗子已经倒下,所以才追逐他们。” +夏季,六月,齐国和宋国的军队驻扎在郎地。公子偃说:“宋军的军容不整齐,可以打败他。宋军败了,齐军必然回国。请您攻击宋军。”庄公不同意。公子偃从雩门私自出击,把马蒙上老虎皮先攻宋军,庄公领兵跟着进击,在乘丘把宋军打得大败。齐军也就回国了。 +蔡哀侯在陈国娶妻,息侯也在陈国娶妻。息妫出嫁时路过蔡国。蔡侯说:“她是我妻子的姊妹。”留下来见面,不很礼貌。息侯听到这件事,发怒,派人对楚文王说:“请您假装进攻我国,我向蔡国求援,您就可以攻打它。” +楚文王同意。秋季九月,楚国在莘地击败蔡军,俘虏了蔡侯献舞回国。 +齐侯逃亡在外的时候,经过谭国,谭国人对他很不礼貌。等到他回国,诸侯都去祝贺,谭国又没有人去。冬季,齐军就灭亡了谭国,这是由于谭国没有礼貌。谭子逃亡到莒国,这是因为两国同盟的缘故。 + +庄公十一年 +【经】十有一年春王正月。夏五月,戊寅,公败宋师于鄑。秋,宋大水。冬,王姬归于齐。 +【传】十一年夏,宋为乘丘之役故侵我。公御之,宋师未陈而薄之,败诸鄑。 +凡师,敌未陈曰败某师,皆陈曰战,大崩曰败绩,得人隽曰克,覆而败之曰取某师,京师败曰王师败绩于某。 +秋,宋大水。公使吊焉,曰:“天作淫雨,害于粢盛,若之何不吊?”对曰:“孤实不敬,天降之灾,又以为君忧,拜命之辱。”臧文仲曰:“宋其兴乎。禹、汤罪己,其兴也悖焉、桀、纣罪人,其亡也忽焉。且列国有凶称孤,礼也。言惧而名礼,其庶乎。”既而闻之曰公子御说之辞也。臧孙达曰:“是宜为君,有恤民之心。” +冬,齐侯来逆共姬。 +乘丘之役,公之金仆姑射南宫长万,公右遄孙生搏之。宋人请之,宋公靳之,曰:“始吾敬子,今子,鲁囚也。吾弗敬子矣。”病之。 +译文 +十一年夏季,宋国为了乘丘那次战役的缘故而入侵我国。庄公出兵迎战。 +宋国的军队还没有摆开阵势,我军就逼近压过去,在戬地打败宋军。 +凡是作战,敌方没有摆开阵势叫做“败某师”,都摆开了阵势叫做“战”,大崩溃叫做“败绩”,俘虏敌方的勇士叫做“克”,伏兵而击败敌军叫做“取某师”,周天子的军队被打败叫做“王师败绩于某”。 +秋季,宋国发大水。庄公派使者去慰问,说:“上天降下大雨,危害了庄稼,为什么不慰问呢?”宋闵公回答说:“我对于上天不诚敬,上天降灾,还使贵国国君担忧,承蒙关注,实不敢当。”臧文仲说:“宋国恐怕要兴盛了吧!禹、汤责罚自己,他们勃然兴起;桀、纣责罚别人,他们马上灭亡。 +而且别国发生灾荒,国君称孤,这是合于礼的。言语有所戒惧而名称合于礼制,这就差不多了吧!”不久,又听说上面那番话是公子御说所说的,臧孙达说:“这个人适合当国君,因为他有体恤百姓的心思。” +冬季,齐桓公来鲁国迎娶共姬。 +在乘丘战役中,庄公用叫金仆姑的箭射中南宫长万,庄公的车右歂孙活捉了长万。宋国人请求把南宫长万释放回国。长万是力气极大的人,宋闵公开玩笑说:“原来我尊敬你,如今你成了鲁国的囚犯,所以我便不敬重你了。” +南宫长万因此而怀恨他。 + +庄公十二年 +【经】十有二年春王三月,纪叔姬归于酅。夏四月。秋八月甲午,宋万弑其君捷及其大夫仇牧。十月,宋万出奔陈。 +【传】十二年秋,宋万弑闵公于蒙泽。遇仇牧于门,批而杀之。遇大宰督于东宫之西,又杀之。立子游。群公子奔萧。公子御说奔亳。南宫牛、猛获帅师围亳。 +冬十月,萧叔大心及戴、武、宣、穆、庄之族以曹师伐之。杀南宫牛于师,杀子游于宋,立桓公。猛获奔卫。南宫万奔陈,以乘车辇其母,一日而至。 +宋人请猛获于卫,卫人欲勿与,石祁子曰:“不可。天下之恶一也,恶于宋而保于我,保之何补?得一夫而失一国,与恶而弃好,非谋也。”卫人归之。亦请南宫万于陈,以赂。陈人使妇人饮之酒,而以犀革裹之。比及宋手足皆见。宋人皆醢之。 +译文 +十二年秋季,宋国的南宫长万在蒙泽杀死了宋闵公。他在城门口遇到仇牧,反手便打死了他。在东宫的西面遇到太宰华督,又杀了他。拥立子游为国君。公子们都逃亡到萧邑,而公子御说逃亡到亳地,南宫牛、猛获率领军队包围了亳地。 +冬季,十月,萧叔大心和宋戴公、武公、宣公、穆公、庄公的族人借调曹国的军队付伐南宫牛和猛获。在阵前杀死了南宫牛,在宋国都城杀死了子游,拥立宋桓公为国君。猛获逃亡到卫国,南宫长万逃亡到陈国,长万自己驾车拉着他母亲,一天就到达了。 +宋国人到卫国请求归还猛获。卫国人想不给他们。石祁子说:“不行。 +普天下的邪恶都是一样可恶的,在宋国作恶而在我国受到保护,保护了他有什么好处?得到一个人而失去一个国家,结交邪恶的人而丢掉友好的国家,这不是好主意。”卫国人把猛获归还给了宋国。宋国又到陈国请求归还南宫长万,并且施以贿赂。陈国人让女人劝南宫长万饮酒,灌醉了他就用犀牛皮把他包了起来。等到达宋国时,南宫长万的手脚都露出来了。宋国人把猛获和南宫长万剁成了肉酱。 + + +庄公十三年 +【经】十有三年春,齐侯、宋人、陈人、蔡人、邾人会于北杏。夏六月,齐人灭遂。秋七月。冬,公会齐侯盟于柯。 +【传】十三年春,会于北杏,以平宋乱。遂人不至。 +夏,齐人灭遂而戍之。 +冬,盟于柯,始及齐平也。 +宋人背北杏之会。 +译文 +十三年春季,鲁庄公和齐、宋、陈、蔡、邾各国国君在北杏会见,是为了平定宋国的动乱。遂国人没有来。夏季,齐国人灭亡遂国并派人戍守。 +冬季,宋桓公和齐桓公在柯地结盟,开始和齐国讲和。 +宋国人违背了北杏的盟约。 + +庄公十四年 +【经】十有四年春,齐人、陈人、曹人伐宋。夏,单伯会伐宋。秋七月,荆入蔡。冬,单伯会齐侯、宋公、卫侯、郑伯于鄄。 +【传】十四年春,诸侯伐宋,齐请师于周。夏,单伯会之,取成于宋而还。 +郑厉公自栎侵郑,及大陵,获傅瑕。傅瑕曰:“苟舍我,吾请纳君。”与之盟而赦之。六月甲子,傅瑕杀郑子及其二子而纳厉公。 +初,内蛇与外蛇斗于郑南门中,内蛇死。六年而厉公入。公闻之,问于申繻曰:“犹有妖乎?”对曰:“人之所忌,其气焰以取之,妖由人兴也。人无衅焉,妖不自作。人弃常则妖兴,故有妖。”   厉公入,遂杀傅瑕。使谓原繁曰:“傅瑕贰,周有常刑,既伏其罪矣。纳我而无二心者,吾皆许之上大夫之事,吾愿与伯父图之。且寡人出,伯父无里言,入,又不念寡人,寡人憾焉。”对曰:“先君桓公命我先人典司宗祏。社稷有主而外其心,其何贰如之?苟主社稷,国内之民其谁不为臣?臣无二心,天之制也。子仪在位十四年矣,而谋召君者,庸非二乎。庄公之子犹有八人,若皆以官爵行赂劝贰而可以济事,君其若之何?臣闻命矣。”乃缢而死。 +蔡哀侯为莘故,绳息妫以语楚子。楚子如息,以食入享,遂灭息。以息妫归,生堵敖及成王焉,未言。楚子问之,对曰:“吾一妇人而事二夫,纵弗能死,其又奚言?”楚子以蔡侯灭息,遂伐蔡。秋七月,楚入蔡。 +君子曰:“《商书》所谓‘恶之易也,如火之燎于原,不可乡迩,其犹可扑灭’者,其如蔡哀侯乎。” +冬,会于鄄,宋服故也。 +译文 +十四年春季,齐国、陈国、曹国联军进攻宋国。齐国请求成周出兵。夏季,单伯带兵同诸侯相会。同宋国讲和后回国。 +郑厉公从栎地带兵入侵郑国国都,到达大陵,俘虏了傅瑕。傅瑕说:“如果放了我,我可以使君王回国再登君位。”郑厉公和他盟誓,便把他释放了。 +六月二十日,傅瑕杀死郑子子仪和他的两个儿子,接纳厉公回国。 +当初,在郑国国都的南门下面,一条在门里的蛇和一条在门外的蛇相斗,门里的蛇被咬死。过了六年而郑厉公回国。鲁庄公听说这件事,向申繻询问说:“厉公的回国难道与妖蛇有关系吗?”申繻回答说:“一个人是否会遇到他所顾忌的事,是由于他自己的气焰所招致的。妖孽是由于人才起来的。 +人没有毛病,妖孽自己不能起来。人丢弃正道,妖孽就自己来了,所以才有妖孽。” +郑厉公回国,就杀死了傅瑕。派人对原繁说:“傅瑕对国君有二心,周朝定有惩处这类奸臣的刑罚,现在傅瑕已经得到惩处了。帮助我回国而没有二心的人,我都答应给他上大夫的职位,我愿意跟伯父一起商量。而且我离开国家在外,伯父没有告诉我国内的情况。回国以后,又并不亲附我,我对此感到遗憾。”原繁回答说:“先君桓公命令我的先人管理宗庙列祖列宗的主位,国家有君主而自己的心却在国外,还有比这更大的二心吗?如果主持国家,国内的百姓,又谁不是他的臣下呢?臣下不应该有二心,这是上天的规定。子仪居于君位,十四年了,现在策划召请君王回国的,难道不是二心吗?庄公的儿子还有八个人,如果都用官爵做贿赂以劝说别人三心二意而又可能成功,君王又怎么办?下臣知道君王的意思了。”原繁说完,就上吊死了。 +蔡哀侯由于莘地战役被俘,在楚文王面前赞美息妫。楚文王到息国,设宴招待息侯而加以袭杀,就灭亡了息国。他把息妫带回楚国,生了堵敖和成王。息妫没有主动说过话,楚文王问她,她回答说:“我一个女人,伺候两个丈夫,即使不能死,又能说什么?”楚文王由于蔡侯的缘故才灭亡了息国,于是再进攻蔡国。秋季,七月,楚军进入蔡国。 +君子说:“《商书》所说的‘恶的蔓延,如同大火在草原上燃烧,不可以接近,难道还可以扑灭?’恐怕就像蔡哀侯吧!” +冬季,单伯和齐桓公、宋桓公、卫惠公、郑厉公在鄄地会见,这是由于宋国顺服的缘故。 + + +庄公十五年 +【经】十有五年春,齐侯、宋公、陈侯、卫侯、郑伯会于鄄。夏,夫人姜氏如齐。秋,宋人、齐人、邾人伐郳。郑人侵宋。冬十月。 +【传】十五年春,复会焉,齐始霸也。 +秋,诸侯为宋伐郳。郑人间之而侵宋。 +译文 +十五年春季,齐桓公、宋桓公、陈宣公、卫惠公、郑厉公再次在鄄地会见,齐国开始称霸。 +秋季,各诸侯为宋国而共同攻打郳国。郑国人便乘机入侵宋国。 + +庄公十六年 +【经】十有六年春王正月。夏,宋人、齐人、卫人伐郑。秋,荆伐郑。冬十有二月,会齐侯、宋公、陈侯、卫侯、郑伯、许男、滑伯、滕子同盟于幽。邾子克卒。 +【传】十六年夏,诸侯伐郑,宋故也。 +郑伯自栎入,缓告于楚。秋,楚伐郑,及栎,为不礼故也。 +郑伯治与于雍纠之乱者。九月,杀公子阏,刖强鉏。公父定叔出奔卫。三年而复之,曰:“不可使共叔无后于郑。”使以十月入,曰:“良月也,就盈数焉。” +君子谓:“强鉏不能卫其足。” +冬,同盟于幽,郑成也。 +王使虢公命曲沃伯以一军为晋侯。 +初,晋武公伐夷,执夷诡诸。蒍国请而免之。既而弗报。故子国作乱,谓晋人曰:“与我伐夷而取其地。”遂以晋师伐夷,杀夷诡诸。周公忌父出奔虢。惠王立而复之。 +译文 +十六年夏季,各诸侯联军进攻郑国,这是由于郑国入侵宋国的缘故。 +郑厉公从栎地回到国都,没有及时通知楚国。秋季,楚国进攻郑国,到达栎地,这是为了报复郑厉公对楚国不恭敬没有及时通知的缘故。 +郑厉公惩罚参与雍纠之乱的人。九月,杀死了公子阏,砍去强鉏的两脚。 +公父定叔逃亡到卫国。过了三年,郑厉公又让他回国了,说:“不能让共叔在郑国的后代没有禄位。”让他在十月回到国内,说:“这是好月份,十月是个满数呢。” +君子认为,“强鉏不能保住他的两脚”。 +冬季,鲁庄公和齐桓公、宋桓公、陈宣公、卫惠公、郑厉公、许穆公、滑伯、滕子在幽地一起结盟,这是为了对郑国讲和。 +周僖王派虢公命令曲沃伯建立一军,做晋国国君。 +当初,晋武公进攻夷地,俘虏了夷诡诸。..国为他请求因而释放了他。 +后来夷诡诸并不报答,所以子国(即..国)作乱,对晋国人说:“和我一起进攻夷地而夺取它的土地。”就带着晋国军队进攻夷地,杀死了夷诡诸。周公忌父逃亡到虢国。到周惠王时便又立他为君而恢复夷地。 + + +庄公十七年 +【经】十有七年春,齐人执郑詹。夏,齐人歼于遂。秋,郑詹自齐逃来。冬,多麋。 +【传】十七年春,齐人执郑詹,郑不朝也。 +夏,遂因氏,颌氏、工娄氏、须遂氏飨齐戍,醉而杀之,齐人歼焉。 +译文 +十七年春季,齐国人抓住郑詹,这是由于郑国不去朝见齐国。 +夏季,遂国的因氏、颌氏、工娄氏、须遂氏用酒食招待在遂国戍守的齐军,灌醉以后杀了他们。齐国戍守者被因氏四族全部杀尽。 + + +庄公十八年 +【经】十有八年春王三月,日有食之。夏,公追戎于济西。秋,有《或虫》。冬十月。 +【传】十八年春,虢公、晋侯朝王,王飨醴,命之宥,皆赐玉五珏,马三匹。非礼也。王命诸侯,名位不同,礼亦异数,不以礼假人。 +虢公、晋侯、郑伯使原庄公逆王后于陈。陈妫归于京师,实惠后。 +夏,公追戎于济西。不言其来,讳之也。 +秋,有蜮,为灾也。 +初,楚武王克权,使斗缗尹之。以叛,围而杀之。迁权于那处,使阎敖尹之。及文王即位,与巴人伐申而惊其师。巴人叛楚而伐那处,取之,遂门于楚。阎敖游涌而逸。楚子杀之,其族为乱。冬,巴人因之以伐楚。 +译文 +十八年春季,虢公、晋献公朝觐周惠王。周惠王用甜酒招待,又允许他们向自己敬酒。同时各赐给他们玉五对,马四匹。这是不合于礼的。周天子对诸侯有所策命,封爵地位不一样,礼仪的等级也不一样,不能把礼仪随便给人。 +虢公、晋献公、郑厉公派原庄公去陈国迎接王后。陈妫嫁到京城,就是惠后。 +夏季,庄公在济水的西边追逐戎人。《春秋》没有记载戎人来攻,这是由于避讳提起这件事。 +秋季,有蜮虫,《春秋》所以记载,是由于造成了灾害。 +当初,楚武王攻克权国,派鬬缗做这里的长官,鬬缗据有权地而叛变楚国。楚国包围权地而杀掉了鬬缗,又把权地的百姓迁到那处,改派阎敖治理这个地方。等到文王即位,和巴国人一起进攻申国,楚军使巴军受到惊恐。巴国人背叛楚国而进攻那处,加以占领,于是又攻打楚国都城的城门。阎敖在涌水里游泳逃走,楚文王杀了阎敖,他的族人作乱。冬季,巴国人因此进攻楚国。 + +庄公十九年 +【经】十有九年春王正月。夏四月。秋,公子结媵陈人之妇于鄄,遂及齐侯、宋公盟。夫人姜氏如莒。冬,齐人、宋人、陈人伐我西鄙。 +【传】十九年春,楚子御之,大败于津。还,鬻拳弗纳。送伐黄,败黄师于碏陵。还,及湫,有疾。夏六月庚申卒,鬻拳葬诸夕室,亦自杀也,而葬于絰 +初,鬻拳强谏楚子,楚子弗从,临之以兵,惧而从之。鬻拳曰:“吾惧君以皇。兵,罪莫大焉。”遂自刖也。楚人以为大阍,谓之大伯,使其后掌之。君子“鬻拳可谓爱君矣,谏以自纳于刑,刑犹不忘纳君于善。” +初,王姚嬖于庄王,生子颓。子颓有宠,蒍国为之师。及惠王即位。取蒍国之圃以为囿,边伯之宫近于王宫,王取之。王夺子禽祝跪与詹父田,而收膳夫之秩。故蒍国、边伯、石速、詹父、子禽祝跪作乱,因苏氏。秋,五大夫奉子颓以伐王,不克,出奔温。苏子奉子颓以奔卫。卫师、燕师伐周。冬,立子颓。 +译文 +十九年春季,楚文王发兵抵御巴军,在津地被巴军打得大败。回国,鬻拳不开城门接纳,楚文王就转而进攻黄国,在踖陵打败了黄国的军队。楚文王回国,到达湫地时得了病。夏季,六月十五日,楚文王死去。鬻拳把他安葬在夕室,然后自己也自杀身亡,死后被安葬在地下宫殿的前院里。 +当初,鬻拳坚决劝阻楚文王,楚文王不听从。鬻拳拿起武器对准楚文王,楚文王害怕而被迫听从。鬻拳说:“我用武器威胁国君,没有比这再大的罪过了。”于是就自己砍去两脚。楚国人让他担任卫戍楚都城门的官职,称之为太伯,并且让他的后代执掌这个官职。 +君子说:“鬻拳可以说是爱护国君了,由于劝阻而自己使自己受刑,受了刑还不忘记使国君归于正道。” +当初,王姚受到周庄王的宠爱,生了子穨。子穨也受到宠爱,..国做他的师傅。等惠王继承王位,夺取了..国的菜园来畜养野兽。边伯的房子,近在王宫的旁边,蕙王也占取了。惠王又夺取了子禽祝跪和詹父的田地,收回了膳夫石速的俸禄。所以..国、边伯、石速、詹父、子禽祝跪发动叛乱,依靠苏氏。秋季,五位大夫拥戴子穨攻打惠王,没有得胜,逃亡到温地。苏子拥着子穨逃亡到卫国。卫国、燕国的军队进攻成周。冬季,立王子穨为周天子。 + +庄公二十年 +【经】二十年春王二月,夫人姜氏如莒。夏,齐大灾。秋七月。冬,齐人伐戎。 +【传】二十年春,郑伯和王室,不克。执燕仲父。夏,郑伯遂以王归,王处于栎。秋,王及郑伯入于邬。遂入成周,取其宝器而还。 +冬,王子颓享五大夫,乐及遍舞。郑伯闻之,见虢叔,曰:“寡人闻之,哀乐失时,殃咎必至。今王子颓歌舞不倦,乐祸也。夫司寇行戮,君为之不举,而况敢乐祸乎!奸王之位,祸孰大焉?临祸忘忧,忧必及之。盍纳王乎?”虢公曰:“寡人之愿也。” +译文 +二十年春季,郑厉公调解周惠王和子穨之间的纠纷,没有成功。逮捕了燕仲父。夏季,郑厉公就带了周惠王回国。惠王住在栎地。秋季,惠王和郑厉公到了邬地,于是就进入成周,取得了成周的宝器而回。 +冬季,王子穨设享礼招待五位大夫,奏乐及于各个时代所有的舞蹈。郑厉公听到这件事,见到虢叔说:“我听说,悲哀或者高兴,若不是时候,灾祸一定会到来。现在王子穨观赏歌舞而不知疲倦,这是以祸患为高兴。司寇杀人,国君为此而减膳撤乐,何况敢以祸患而高兴呢?篡夺天子的职位,祸患还有比这更大的吗?面临祸患而忘记忧愁,忧愁一定到来。何不让天子复位呢?”虢公说:“这是我的愿望。” + +庄公二十一年 +【经】二十有一年春,王正月。夏五月辛酉,郑伯突卒。秋七月戊戌,夫人姜氏薨。冬十有二月,葬郑厉公。 +【传】二十一年春,胥命于弭。夏,同伐王城。郑伯将王,自圉门入,虢叔自北门入,杀王子颓及五大夫。郑伯享王于阙西辟,乐备。王与之武公之略,自虎牢以东。原伯曰:“郑伯效尤,其亦将有咎。”五月,郑厉公卒。 +王巡虢守。虢公为王宫于玤,王与之酒泉。郑伯之享王也,王以后之鞶鉴予之。虢公请器,王予之爵。郑伯由是始恶于王。 +冬,王归自虢。 +译文 +二十一年春季,郑厉公和虢公在弭地会谈。夏季,一起进攻王城。郑厉公拥着惠王从圉门入城,虢叔从北门入城。杀了王子穨和五个大夫。郑厉公在宫门口西阙设宴招待惠王,全套乐舞齐备。惠王赐给他郑武公时代从虎牢以东的土地。原伯说:“郑伯学了做坏事,恐怕也会招来灾祸。”五月,郑厉公去世。 +周惠王巡视虢公防守的土地,虢公为惠王在玤地建造了行宫,惠王就把酒泉赐给他。 +以前当郑厉公设宴招待惠王的时候,惠王把王后的鞶鉴赐给他。虢公也请求赏赐器物,惠王把青铜酒杯赐给他。由于鞶鉴没有青铜酒杯贵重,郑厉公从此怨恨周惠王。 +冬季,周惠王从虢国回到成周。 + + +庄公二十二年 +【经】二十二年春王正月,肆大眚。癸丑,葬我小君文姜。陈人杀其公子御寇。夏五月。秋七月丙申,及齐高傒盟于防。冬,公如齐纳币。 +【传】二十二年春,陈人杀其大子御寇,陈公子完与颛孙奔齐。颛孙自齐来奔。 +齐侯使敬仲为卿。辞曰:“羁旅之臣,幸若获宥,及于宽政,赦其不闲于教训而免于罪戾,弛于负担,君之惠也,所获多矣。敢辱高位,以速官谤。请以死告。《诗》云:‘翘翘车乘,招我以弓,岂不欲往,畏我友朋。’”使为工正。 +饮桓公酒,乐。公曰:“以火继之。”辞曰:“臣卜其昼,未卜其夜,不敢。”君子曰:“酒以成礼,不继以淫,义也。以君成礼,弗纳于淫,仁也。” +初,懿氏卜妻敬仲,其妻占之,曰:“吉,是谓‘凤皇于飞,和鸣锵锵,有妫之后,将育于姜。五世其昌,并于正卿。八世之后,莫之与京。’”陈厉公,蔡出也。故蔡人杀五父而立之,生敬仲。其少也。周史有以《周易》见陈侯者,陈侯使筮之,遇《观》之《否》。曰:“是谓‘观国之光,利用宾于王。’代陈有国乎。不在此,其在异国;非此其身,在其子孙。光,远而自他有耀者也。《坤》,土也。《巽》,风也。《乾》,天也。风为天于土上,山也。有山之材而照之以天光,于是乎居土上,故曰:‘观国之光,利用宾于王。’庭实旅百,奉之以玉帛,天地之美具焉,故曰:‘利用宾于王。’犹有观焉,故曰其在后乎。风行而着于土,故曰其在异国乎。若在异国,必姜姓也。姜,大岳之后也。山岳则配天,物莫能两大。陈衰,此其昌乎。” +及陈之初亡也,陈桓子始大于齐。其后亡成,成子得政。 +译文 +二十二年春季,陈国人杀了他们的太子御寇。陈国的敬仲和颛孙逃亡到齐国。颛孙又从齐国逃亡到鲁国来。 +齐桓公想任命敬仲做卿,他辞谢说:“寄居在外的小臣如果有幸获得宽恕,能在宽厚的政治之下,赦免我的缺乏教训,而得以免除罪过,放下恐惧,这是君王的恩惠。我所得的已经很多了,哪里敢接受这样的高位而很快地招来官员们的指责?谨昧死上告。《诗》说:‘高高的车子,招呼我用的是弓。 +难道我不想前去?怕的是我的友朋。’”齐桓公就让他担任了工正官。 +敬仲招待齐桓公饮酒,桓公很高兴。天晚了,桓公说:“点上烛继续喝酒。”敬仲辞谢说:“臣只知道白天招待君主,不知道晚上陪饮。不敢遵命。” +君子说:“酒用来完成礼仪,不能没有节制,这是义;由于和国君饮酒完成了礼仪,不使他过度,这是仁。” +当初,懿氏要把女儿嫁给敬仲而占卜吉凶。他的妻子占卜,说:“吉利。这叫做‘凤凰飞翔,唱和的声音嘹亮。妫氏的后代,养育于齐姜。第五代就要昌盛,官位和正卿一样。第八代以后,没有人可以和他争强。’” +陈厉公是蔡国女人所生,所以蔡国人杀了五父而立他为君,生了敬仲。 +在敬仲年幼的时候,有一个成周的太史用《周易》去见陈厉公,陈厉公让他占筮,占得的《观》卦变成《否》卦。周太史说:“这就叫做‘出聘观光,利于作上宾于君王’。这个人恐怕要代替陈而享有国家了吧!但不在这里,而在别国,不在这个人身上,而在他的子孙。光,是从另外地方照耀而来的。《坤》是土,《巽》是风,《乾》是天。风起于天而行于土上,这就是山。有了山上的物产,又有天光照射,这就居于地土上,所以说‘出聘观光,利于作上宾于君王’,庭中陈列的礼物上百件,另外进奉束帛玉璧,天上地下美好的东西都具备了,所以说‘利于作上宾于君王’。还有等着观看,所以说他的昌盛在于后代吧!风行走最后落在土地上,所以说他的昌盛在于别国吧!如果在别国,必定是姜姓之国。姜是太岳的后代。山岳高大可以与天相配。但事物不可能两者一样大,陈国衰亡,这个氏族就要昌盛吧!” +等到陈国第一次灭亡,陈桓子才在齐国有强大的势力,后来楚国再次灭亡陈国,陈成子取得了齐国政权。 + +庄公二十三年 +【经】二十有三年春,公至自齐。祭叔来聘。夏,公如齐观社。公至自齐。荆人来聘。公及齐侯遇于谷。萧叔朝公。秋,丹桓宫楹。冬十有一月,曹伯射姑卒。十有二月甲寅,公会齐侯盟于扈。 +【传】二十三年夏,公如齐观社,非礼也。曹刿谏曰:“不可。夫礼,所以整民也。故会以训上下之则,制财用之节;朝以正班爵之义,帅长幼之序;征伐以讨其不然。诸侯有王,王有巡守,以大习之。非是,君不举矣。君举必书,书而不法,后嗣何观?” +晋桓、庄之族逼,献公患之。士蒍曰:“去富子,则群公子可谋也已。”公曰:“尔试其事。”士蒍与群公子谋,谮富子而去之。 +秋,丹桓宫之楹。 +译文 +二十三年夏季,鲁庄公到齐国去观看祭祀社神,这是不合于礼的。曹刿劝谏说:“不行。礼,是用来整饬百姓的。所以会见是用以训示上下之间的法则,制订节用财赋的标准;朝觐是用以排列爵位的仪式,遵循老少的次序;征伐是用以攻打对上的不尊敬。诸侯朝聘天子,天子视察四方,以熟悉会见和朝觐的制度。如果不是这样,国君是不会有举动的。国君的举动史官一定要加以记载。记载而不合于法度,后代子孙看到的是什么?” +晋国桓叔、庄伯的家族势力强盛而威逼公族,晋献公担心这种情况。士说:“去掉富子,对公子们就好办了。”晋献公说:“你试着办这件事。” +士就在公子们中间讲富子的坏话,然后和公子们设法去掉了富子。秋季,在桓公庙的梁柱上涂上红漆。 + +庄公二十四年 +【经】二十有四年春王三月,刻桓宫桷。葬曹庄公。夏,公如齐逆女。秋,公至自齐。八月丁丑,夫人姜氏入。戊寅,大夫宗妇觌,用币。大水。冬,戎侵曹。曹羁出奔陈。赤归于曹。郭公。 +【传】二十四年春,刻其桷,皆非礼也。御孙谏曰:“臣闻之:‘俭,德之共也;侈,恶之大也。’先君有共德而君纳诸大恶,无乃不可乎!” +秋,哀姜至。公使宗妇觌,用币,非礼也。御孙曰:“男贽大者玉帛,小者禽鸟,以章物也。女贽不过榛栗枣修,以告虔也。今男女同贽,是无别也。男女之别,国之大节也。而由夫人乱之,无乃不可乎!” +晋士蒍又与群公子谋,使杀游氏之二子。士蒍告晋侯曰:“可矣。不过二年,君必无患。” +译文 +二十四年春季,又在桓公庙的椽子上雕花,这件事与去年庙柱上涂红漆都是不合礼制的。御孙劝阻说:“下臣听说:‘节俭,是善行中的大德;奢侈,是邪恶中的大恶。’先君具有大德,而君王却把它放到大恶里去,恐怕不可以吧?” +秋季,哀姜来到鲁国,庄公让同姓大夫的夫人相见,相见时用玉帛作为见面礼,这是不合于礼的。御孙说:“男人相见的礼物,大的是玉帛,小的是禽鸟,用东西来表明等级。女人相见的礼物,不超过榛子、栗子、枣子、干肉,以表示诚敬而已。现在男女用相同的相见礼,这是没有区别了。男女的区别,是国家的大法,由于夫人而搞乱了,恐怕不可以吧!” +晋国的士..又和公子们策划,让他们杀了游氏的两个儿子。士..告诉晋献公说:“行了。不超过两年,君王就不必担心了。” + +庄公二十五年 +【经】二十有五年春,陈侯使女叔来聘。夏五月癸丑,卫侯朔卒。六月辛未,朔,日有食之,鼓、用牲于社。伯姬归于杞。秋,大水,鼓、用牲于社、于门。冬,公子友如陈。 +【传】二十五年春,陈女叔来聘,始结陈好也。嘉之,故不名。 +夏六月辛未,朔,日有食之。鼓,用牲于社,非常也。唯正月之朔,慝未作,日有食之,于是乎用币于社,伐鼓于朝。 +秋,大水。鼓,用牲于社、于门,亦非常也。凡天灾,有币无牲。非日月之眚,不鼓。 +晋士蒍使群公子尽杀游氏之族,乃城聚而处之。 +冬,晋侯围聚,尽杀群公子。 +译文 +二十五年春季,陈国的女叔来鲁国聘问,这是开始和陈国友好。《春秋》赞美这件事,所以不记载女叔的名字。 +夏季六月初一日,发生了日食。击鼓,用牺牲祭祀土地神庙,这是不合于常礼的。只有夏历四月的初一,阴气没有发作,如果发生日食,才用玉帛祭祀土地之神,在朝廷之上击鼓。 +秋季,有大水,击鼓,用牺牲祭祀土地神庙和城门门神,也不合于常礼。 +凡是天灾,祭祀时只能用玉帛而不用牺牲。不是日食、月蚀,不击鼓。 +晋国的士..让公子们杀尽了游氏家族,于是在聚地筑城而让公子们去住。冬季,晋献公包围了聚城,把公子们全部杀光。 + +庄公二十六年 +【经】二十有六年春,公伐戎。夏,公至自伐戎。曹杀其大夫。秋,公会宋人、齐人,伐徐。冬十有二月癸亥,朔,日有食之。 +【传】二十六年春,晋士蒍为大司空。 +夏,士蒍城绛,以深其宫。 +秋,虢人侵晋。冬,虢人又侵晋。 +译文 +二十六年春季,晋国的士..做了大司空。 +夏季,士..加高并加大绛都城垣,同时也加高宫墙。 +秋季,虢国人入侵晋国。 +冬季,虢国人又入侵晋国。 + +庄公二十七年 +【经】二十有七年春,公会杞伯姬于洮。夏六月,公会齐侯、宋公、陈侯、郑伯同盟于幽。秋,公子友如陈,葬原仲。冬,杞伯姬来。莒庆来逆叔姬。杞伯来朝。公会齐侯于城濮。 +【传】二十七年春,公会杞伯姬于洮,非事也。天子非展义不巡守,诸侯非民事不举,卿非君命不越竟。 +夏,同盟于幽,陈,郑服也。 +秋,公子友如陈,葬原仲,非礼也。原仲,季友之旧也。 +冬,杞伯姬来,归宁也。凡诸侯之女,归宁曰来,出曰来归。夫人归宁曰如某,出曰归于某。 +晋侯将伐虢,士蒍曰:“不可,虢公骄,若骤得胜于我,必弃其民。无众而后伐之,欲御我谁与?夫礼乐慈爱,战所畜也。夫民让事乐和,爱亲哀丧而后可用也。虢弗畜也,亟战将饥。” +王使召伯廖赐齐侯命,且请伐卫,以其立子颓也。 +译文 +二十七年春季,鲁庄公和杞伯姬在洮地会见,与国家大事无关。天子不是为了宣扬德义不出去视察,诸侯不是为了百姓的事情不能出行,卿没有国君的命令不能越过国境。 +夏季,鲁庄公和齐桓公、宋桓公、陈宣公、郑文公在幽地一起结盟,由于陈国和郑国都顺服了。 +秋季,公子友到陈国安葬原仲,这不合于礼。原仲,只是季友私人的老朋友。 +冬季,杞伯姬来,这是回娘家。凡是诸侯的女儿,回娘家叫做“来”,被夫家休弃叫做“来归”,本国国君的夫人回娘家叫做“如某”,被休弃叫做“归于某”。 +晋献公准备进攻虢国。士..说:“不行。虢公骄傲,如果突然和我国交战而得胜,就必定会丢弃他的百姓。他失去群众然后我们再去进攻,即使要抗拒,有谁会跟他呢?礼、乐、慈、爱,这是作战所应当事先具备的。百姓谦让、和协、对亲属爱护,对丧事哀痛,这才可以使用。现在虢国不具备这些,多次对外作战,百姓会气馁的。” +周惠王派遣召伯廖赐命齐桓公,并要求他进攻卫国,因为卫国曾拥立子穨做周天子。 + +庄公二十八年 +【经】二十有八年春,王三月甲寅,齐人伐卫。卫人及齐人战,卫人败绩。夏四月丁未,邾子琐卒。秋,荆伐郑,公会齐人、宋人救郑。冬,筑郿。大无麦、禾,臧孙辰告籴于齐。 +【传】二十八年春,齐侯伐卫。战,败卫师。数之以王命,取赂而还。 +晋献公娶于贾,无子。烝于齐姜,生秦穆夫人及大子申生。又娶二女于戎,大戎狐姬生重耳,小戎子生夷吾。晋伐骊戎,骊戎男女以骊姬。归生奚齐。其娣生卓子。骊姬嬖,欲立其子,赂外嬖梁五,与东关嬖五,使言于公曰:“曲沃,君之宗也。蒲与二屈,君之疆也。不可以无主。宗邑无主则民不威,疆埸无主则启戎心。戎之生心,民慢其政,国之患也。若使大子主曲沃,而重耳、夷吾主蒲与屈,则可以威民而惧戎,且旌君伐。”使俱曰:“狄之广莫,于晋为都。晋之启土,不亦宜乎?”晋侯说之。夏,使大子居曲沃,重耳居蒲城,夷吾居屈。群公子皆鄙,唯二姬之子在绛。二五卒与骊姬谮群公子而立奚齐,晋人谓之二耦。 +楚令尹子元欲蛊文夫人,为馆于其宫侧,而振万焉。夫人闻之,泣曰:“先君以是舞也,习戎备也。今令尹不寻诸仇雠,而于未亡人之侧,不亦异乎!”御人以告子元。子元曰:“妇人不忘袭仇,我反忘之!” +秋,子元以车六百乘伐郑,入于桔柣之门。子元、斗御疆、斗梧、耿之不比为旆,斗班、王孙游、王孙喜殿。众车入自纯门,及逵市。县门不发,楚言而出。子元曰:“郑有人焉。”诸侯救郑,楚师夜遁。郑人将奔桐丘,谍告曰:“楚幕有乌。”乃止。 +冬,饥。臧孙辰告籴于齐,礼也。 +筑郿,非都也。凡邑有宗庙先君之主曰都,无曰邑。邑曰筑,都曰城。 +译文 +二十八年春季,齐桓公讨伐卫国,作战,打败了卫军,用周天子的名义责备卫国,取得了财货回国。 +晋献公从贾国娶了妻子,没生儿子。他和齐姜私通,生了秦穆夫人和太子申生。又在戎娶了两个女人,大戎狐姬生了重耳,小戎子生了夷吾。晋国攻打骊戎,骊戎男把骊姬献给晋献公,回国后生了奚齐,她的妹妹生了卓子。 +骊姬受到宠爱,想立自己的儿子为太子,贿赂男宠梁五和东关嬖五,让他们对晋献公说:“曲沃是君王的宗邑,蒲地和二屈是君王的边疆,不可以没有强大的地方官。宗邑缺乏有力的主管,百姓就不会畏惧;边疆没有有力的主管,就会勾引戎狄侵犯的念头。戎狄有侵犯的念头,百姓就会轻视政令,这是国家的祸患。如果让太子主管曲沃,又让重耳、夷吾主管蒲地和二屈,就可以使百姓畏惧、戎狄害怕,而且可以表彰君王的功绩。”又让这两个人一起对晋献公说:“狄人广漠的土地,如果归属晋国,可以在那里开疆辟土。 +晋国开疆辟土,不也恰当吗?”晋侯很高兴。夏季,让太子住在曲沃,重耳住在蒲地,夷吾住在屈地。别的公子也都住在边境上,只有骊姬和她妹妹的儿子在绛城。两个五梁五和东关嬖五最终和骊姬诬陷了公子们而立了奚齐为太子,晋国人称他们为“两个名叫五的狼狈朋比”。 +楚国的令尹子元想诱惑文王夫人,在她的宫旁造了房舍,在里边摇铃铎跳万舞。夫人听到了,哭着说:“先君让人跳这个舞蹈,是用来演习战备的。 +现在令尹不用于仇敌而用于一个寡妇的旁边,不也是奇怪吗?”侍者告诉了子元。子元说:“女人不忘记袭击仇敌,我反倒忘了。” +秋季,子元带领六百辆战车进攻郑国,进入桔柣之门。子元、鬬御彊、鬬梧、耿之不比率领前军,鬬班、王孙游、王孙喜在后面。车队从纯门进去,到达大路上的市场。内城的闸门没有放下。楚国人用楚国方言说了一阵就退出去了。子元说:“郑国有人才。”诸侯救援郑国,楚军就夜里溜走了。郑国人已经准备逃往桐丘,间谍报告说:“楚国的帐篷上有乌鸦。”于是就停止逃跑。 +冬季,发生饥荒。鲁国的大夫臧孙辰向齐国购买粮食,这是合于礼的。 +鲁国筑郿邑,因为郿不是都市。凡是城邑,有宗庙和先君神主的叫做“都”,没有的叫做“邑”。建造邑叫做“筑”,建造都叫做“城”。 + + +庄公二十九年 +【经】二十有九年春,新延既。夏,郑人侵许。秋,有蜚。冬十有二月,纪叔卒。城诸及防。 +【传】二十九年春,新作延。书,不时也。凡马日中而出,日中而入。 +夏,郑人侵许。凡师有钟鼓曰伐,无曰侵,轻曰袭。 +秋,有蜚,为灾也。凡物不为灾不书。 +冬十二月,城诸及防,书,时也。凡土功,龙见而毕务,戒事也。火见而致用,水昏正而栽,日至而毕。 +樊皮叛王。 +译文 +二十九年春季,新造延厩。《春秋》所以记载这件事,是由于不合时令。 +凡是马,春分时节放牧,秋分时节入马圈。 +夏季,郑国人入侵许国。凡是出兵,有钟鼓之声叫做“伐”,没有叫做“侵”,轻装部队快速突击叫做“袭”。 +秋季,发现蜚盘虫,成了灾。凡是事物不成灾,《春秋》就不加记载。 +冬季十二月,在诸地和防地筑城。《春秋》记载这件事,是因为合于时令。凡是土木工程,苍龙星出现,此时农事完毕,就要做准备了;大火星出现,就要把用具放到工场上,黄昏,营室星在南方出现,就要筑墙立板,冬至以后不再施工。 +周大夫樊皮背叛周惠王。 + +庄公三十年 +【经】三十年春王正月。夏,次于成。秋七月,齐人降鄣。八月癸亥,葬纪叔。九月庚午朔,日有食之,鼓、用牲于社。冬,公及齐侯遇于鲁济。齐人伐山戎。 +【传】三十年春,王命虢公讨樊皮。夏四月丙辰,虢公入樊,执樊仲皮,归于京师。 +楚公子元归自伐郑,而处王宫,斗射师谏,则执而梏之。 +秋,申公斗班杀子元,斗谷于菟为令尹,自毁其家以纾楚国之难。 +冬,遇于鲁济,谋山戎也,以其病燕故也。 +译文 +三十年春季,周惠王命令虢公讨伐樊皮。夏季,四月十四日,虢公进入樊国,俘虏了樊皮,带到京城。 +楚国的公子元攻打郑国回来,住在王宫里。鬬射师劝阻,就把他抓起来带上手铐。秋季,申公鬬班杀死子元。鬬穀於菟做令尹,自己捐献家财,来缓和楚国的危难。 +冬季,鲁庄公和齐桓公在鲁国济水非正式会见,策划攻打山戎,因为山戎危害燕国的缘故。 + +庄公三十一年 +【经】三十有一年春,筑台于郎。夏四月,薛伯卒。筑台于薛。六月,齐侯来献戎捷。秋,筑台于秦。冬,不雨。 +【传】三十一年夏六月,齐侯来献戎捷,非礼也。凡诸侯有四夷之功,则献于王,王以警于夷。中国则否。诸侯不相遗俘。 +译文 +  三十一年夏季,六月,齐桓公来鲁国奉献讨伐山戎的战利品,这是不合于礼的。凡是诸侯讨伐四方夷狄有功,就要奉献给周天子,周天子用来警戒四方夷狄;在中原作战就不这样。诸侯之间不能互相赠送俘虏。 + +庄公三十二年 +【经】三十有二年春,城小谷。夏,宋公、齐侯遇于梁丘。秋七月癸巳,公子牙卒。八月癸亥,公薨于路寝。冬十月己未,子般卒。公子庆父如齐。狄伐邢。 +【传】三十二年春,城小谷,为管仲也。 +齐侯为楚伐郑之故,请会于诸侯。宋公请先见于齐侯。夏,遇于梁丘。 +秋七月,有神降于莘。 +惠王问诸内史过曰:“是何故也?”对曰:“国之将兴,明神降之,监其德也;将亡,神又降之,观其恶也。故有得神以兴,亦有以亡,虞、夏、商、周皆有之。”王曰:“若之何?”对曰:“以其物享焉,其至之日,亦其物也。”王从之。内史过往,闻虢请命,反曰:“虢必亡矣,虐而听于神。” +神居莘六月。虢公使祝应、宗区、史嚚享焉。神赐之土田。史嚚曰:“虢其亡乎!吾闻之:国将兴,听于民;将亡,听于神。神,聪明正直而一者也,依人而行。虢多凉德,其何土之能得!” +初,公筑台临党氏,见孟任,从之。閟,而以夫人言许之。割臂盟公,生子般焉。雩,讲于梁氏,女公子观之。圉人荦自墙外与之戏。子般怒,使鞭之。公曰:“不如杀之,是不可鞭。荦有力焉,能投盖于稷门。” +公疾,问后于叔牙。对曰:“庆父材。”问于季友,对曰:“臣以死奉般。”公曰:“乡者牙曰庆父材。”成季使以君命命僖叔待于金咸巫氏,使金咸季鸩之,曰:“饮此则有后于鲁国,不然,死且无后。”饮之,归及逵泉而卒,立叔孙氏。 +八月癸亥,公薨于路寝。子般即位,次于党氏。冬十月己未,共仲使圉人荦贼子般于党氏。成季奔陈。立闵公。 +译文 +三十二年春季,齐国在小穀筑了一座城,这是为管仲而筑的。 +齐桓公由于楚国进攻郑国的缘故,请求和诸侯会见。宋桓公请求和齐桓公先行会见。夏季,在梁丘非正式会见。 +秋季,七月,有神明在莘地下降。周惠王向内史过询问说:“这是什么原因?”内史过回答说:“国家将要兴起,神明下降,观察它的德行;将要灭亡,神明也会下降,观察它的邪恶。所以有的得到神明而兴起,也有的得到神明而灭亡,虞、夏、商、周都有过这种情况。”周惠王说:“怎么办呢?” +内史过回答说:“用相应的物品来祭祀。他来到的日子,按规定,这个日子的祭祀该是什么,也就是他的祭品。”周惠王听从了。内史过前去祭祀,听到虢国请求神明赐予,回来说:“虢国必定要灭亡了,暴虐而听命于神明。” +神明在莘地住了六个月,虢公派遣祝应、宗区、史嚚去祭祀。神明答应赐给他疆土田地。史嚚说:“虢国恐怕要灭亡了吧!我听说:‘国家将要兴起,听百姓的;将要灭亡,听神明的。’神明,是聪明正直而一心一意的,按照不同的人而行事。虢国多的是恶德坏事,又有什么土地能够得到?” +当初,庄公建造高台,可以看到党家。在台上望见党氏的女儿孟任,就跟着她走。孟任闭门拒绝。庄公答应立她为夫人。她答应了,割破手臂和庄公盟誓,后来就生了子般。一次正当雩祭,事先在梁家演习,庄公的女公子观看演习,圉人荦从墙外对她调戏。子般发怒,让人鞭打荦。庄公说:“不如杀掉他,这个人不能鞭打。他很有力气,可以举起稷门的城门,能将门扇远远地扔出去。” +庄公得了重病,向叔牙询问继承人的事。叔牙回答说:“庆父有才能。”向季友询问,季友回答说:“臣用死来事奉子般。”庄公说:“刚才叔牙说‘庆父有才能’。”季友就派人用国君的名义让僖叔(叔牙)等待在鍼巫家里,让鍼巫用毒酒毒死叔牙,说:“喝了这个,你的后代在鲁国还可以享有禄位;不这样,你死了,后代还没有禄位。”叔牙喝了毒酒,回去,到达逵泉就死去了。鲁国立他的后人为叔孙氏。 +八月初五日,鲁庄公死在正寝里。子般即位,住在党氏家里。冬季,十月初二日,共仲派圉人荦在党家刺死了子般。成季逃亡到陈国。立闵公为国君。 + + +闵公 + +闵公元年 +【经】元年春王正月。齐人救邢。夏六月辛酉,葬我君庄公。秋八月,公及齐侯盟于落姑。季子来归。冬,齐仲孙来。 +【传】元年春,不书即位,乱故也。 +狄人伐邢。管敬仲言于齐侯曰:“戎狄豺狼,不可厌也。诸夏亲昵,不可弃也。宴安鸩毒,不可怀也。《诗》云:‘岂不怀归,畏此简书。’简书,同恶相恤之谓也。请救邢以从简书。”齐人救邢。 +夏六月,葬庄公,乱故,是以缓。 +秋八月,公及齐侯盟于落姑,请复季友也。齐侯许之,使召诸陈,公次于郎以待之。“季子来归”,嘉之也。 +冬,齐仲孙湫来省难。书曰“仲孙”,亦嘉之也。 +仲孙归曰:“不去庆父,鲁难未已。”公曰:“若之何而去之?”对曰:“难不已,将自毙,君其待之。”公曰:“鲁可取乎?”对曰:“不可,犹秉周礼。周礼,所以本也。臣闻之,国将亡,本必先颠,而后枝叶从之。鲁不弃周礼,未可动也。君其务宁鲁难而亲之。亲有礼,因重固,间携贰,覆□乱,霸王之器也。” +晋侯作二军,公将上军,大子申生将下军。赵夙御戎,毕万为右,以灭耿、灭霍、灭魏。还,为大子城曲沃。赐赵夙耿,赐毕万魏,以为大夫。 +士蒍曰:“大子不得立矣,分之都城而位以卿,先为之极,又焉得立。不如逃之,无使罪至。为吴大伯,不亦可乎?犹有令名,与其及也。且谚曰:‘心苟无瑕,何恤乎无家。’天若祚大子,其无晋乎。” +卜偃曰:“毕万之后必大。万,盈数也;魏,大名也;以是始赏,天启之矣。天子曰兆民,诸侯曰万民。今名之大,以从盈数,其必有众。” +初,毕万筮仕于晋,遇《屯》ⅴⅲ之《比》ⅴⅰ。辛廖占之,曰:“吉。《屯》固《比》入,吉孰大焉?其必蕃昌。《震》为土,车从马,足居之,兄长之,母覆之,众归之,六体不易,合而能固,安而能杀。公侯之卦也。公侯之子孙,必复其始。” +译文 +元年春季,《春秋》没有记载即位,是由于动乱不能举行即位仪式。 +狄人进攻邢国。管仲对齐桓公说:“戎狄好像豺狼,是不会满足的;中原各国互相亲近,是不能抛弃的。安逸等于毒药,是不能怀恋的。《诗》说:‘难道不想着回去,怕的是这个竹简上的军事文字。’竹简上的军事文字,就是同仇敌忾而忧患与共的意思,所以请按照简书而救援邢国。”于是齐国人出兵救援邢国。 +夏季,六月,安葬庄公。由于发生动乱,所以推迟了,过了十一个月才安葬。 +秋季,八月,闵公和齐桓公在落姑结盟,请求齐桓公帮助季友回国。齐桓公同意,派人从陈国召回季友,闵公住在郎地等候他。《春秋》记载说“季子来归”,这是赞美季友。 +冬季,齐国的仲孙湫前来对祸难表示慰问,《春秋》称之为“仲孙”,也是赞美他。仲孙回国说:“不除掉庆父,鲁国的祸难没完没了。”齐桓公说:“怎么样才能除掉他?”仲孙回答说:“祸难不止,将会自取灭亡,您就等着吧!”齐桓公说:“鲁国可以取得吗?”仲孙说:“不行。他们还遵行周礼。周礼,是立国的根本。下臣听说:‘国家将要灭亡,如同大树,躯干必然先行仆倒,然后枝叶随着落下。’鲁国不抛弃周礼,是不能动它的。您应当从事于安定鲁国的祸难并且亲近它。亲近有礼仪的国家,依靠稳定坚固的国家,离间内部涣散的国家,灭亡昏暗动乱的国家,这是称霸称王的方法。” +晋献公建立两个军,自己率领上军,太子申生率领下军。赵夙为晋献公驾御战车,毕万作为车右。出兵灭掉耿国、灭掉霍国、灭掉魏国。回国来,晋献公为太子在曲沃建造城墙,把耿地赐给赵夙,把魏地赐给毕万,派他们做大夫。 +士..说:“太子不能做继承者了,把都城分给他,而给他以卿的地位,先让他达到顶点,又哪里能够立为国君?与其得到罪过,不如逃走,不要让罪过到来。做一个吴太伯,不也是可以的吗?这样还可以保有好名声。而且俗话说:‘心里如果没有毛病,又何必担心没有家?’上天如果保佑您,您就不要在晋国了吧!” +卜偃说:“毕万的后代必定昌大。万,是满数;魏,是巍巍高大的名称。 +开始赏赐就这样,上天已经启示了。天子统治兆民,所以称为‘兆民’,诸侯统治万民,所以称为‘万民’。现在名称的高大跟着满数,他就必然会得到群众。” +当初,毕万占卜在晋国做官的吉凶,得到《屯》卦变成《比》卦。 +辛廖预测说:“吉利。《屯》坚固,《比》进入,还有比这更大的吉利吗? +所以他必定蕃衍昌盛。《震》卦变成了土,车跟随着马,两脚踏在这里,哥哥抚育他,母亲保护他,群众归附他,这六条不变,集合而能坚固,安定而有威武,这是公侯的封象。公侯的子孙,必定能回复到他开始的地位。” + +闵公二年 +【经】二年春王正月,齐人迁阳。夏五月乙酉,吉禘于庄公。秋八月辛丑,公薨。九月,夫人姜氏孙于邾。公子庆父出奔莒。冬,齐高子来盟。十有二月,狄入卫。郑弃其师。 +【传】二年春,虢公败犬戎于渭汭。舟之侨曰:“无德而禄,殃也。殃将至矣。”遂奔晋。 +夏,吉禘于庄公,速也。 +初,公傅夺卜齮田,公不禁。 +秋八月辛丑,共仲使卜齮贼公于武闱。成季以僖公适邾。共仲奔莒,乃入,立之。以赂求共仲于莒,莒人归之。及密,使公子鱼请,不许。哭而往,共仲曰:“奚斯之声也。”乃缢。 +闵公,哀姜之娣叔姜之子也,故齐人立之。共仲通于哀姜,哀姜欲立之。闵公之死也,哀姜与知之,故孙于邾。齐人取而杀之于夷,以其尸归,僖公请而葬之。 +成季之将生也,桓公使卜楚丘之父卜之。曰:“男也。其名曰友,在公之右。间于两社,为公室辅。季氏亡,则鲁不昌。”又筮之,遇《大有》ⅵⅰ之《乾》ⅰⅰ,曰:“同复于父,敬如君所。”及生,有文在其手曰“友”,遂以命之。 +冬十二月,狄人伐卫。卫懿公好鹤,鹤有乘轩者。将战,国人受甲者皆曰:“使鹤,鹤实有禄位,余焉能战!”公与石祁子玦,与宁庄子矢,使守,曰:“以此赞国,择利而为之。”与夫人绣衣,曰:“听于二子。”渠孔御戎,子伯为右,黄夷前驱,孔婴齐殿。及狄人战于荧泽,卫师败绩,遂灭卫。卫侯不去其旗,是以甚败。狄人囚史华龙滑与礼孔以逐卫人。二人曰:“我,大史也,实掌其祭。不先,国不可得也。”乃先之。至则告守曰:“不可待也。”夜与国人出。狄入卫,遂从之,又败诸河。 +初,惠公之即位也少,齐人使昭伯烝于宣姜,不可,强之。生齐子、戴公、文公、宋桓夫人、许穆夫人。文公为卫之多患也,先适齐。及败,宋桓公逆诸河,宵济。卫之遗民男女七百有三十人,益之以共,滕之民为五千人,立戴公以庐于曹。许穆夫人赋《载驰》。齐侯使公子无亏帅车三百乘、甲士三千人以戍曹。归公乘马,祭服五称,牛羊豕鸡狗皆三百,与门材。归夫人鱼轩,重锦三十两。 +郑人恶高克,使帅师次于河上,久而弗召。师溃而归,高克奔陈。郑人为之赋《清人》。 +晋侯使大子申生伐东山皋落氏。里克谏曰:“大子奉冢祀,社稷之粢盛,以朝夕视君膳者也,故曰冢子。君行则守,有守则从。从曰抚军,守曰监国,古之制也。夫帅师,专行谋,誓车旅,君与国政之所图也,非大子之事也。师在制命而已。禀命则不威,专命则不孝。故君之嗣适不可以帅师。君失其官,帅师不威,将焉用之。且臣闻皋落氏将战,君其舍之。”公曰:“寡人有子,未知其谁立焉。”不对而退。 +见大子,大子曰:“吾其废乎?”对曰:“告之以临民,教之以军旅,不共是惧,何故废乎?且子惧不孝,无惧弗得立,修己而不责人,则免于难。” +大子帅师,公衣之偏衣,佩之金玦。狐突御戎,先友为右,梁余子养御罕夷,先丹木为右。羊舌大夫为尉。光友曰:“衣身之偏,握兵之要,在此行也,子其勉之。偏躬无慝,兵要远灾,亲以无灾,又何患焉!”狐突叹曰:“时,事之征也;衣,身之章也;佩,衷之旗也。故敬其事则命以始,服其身则衣之纯,用期衷则佩之度。今命以时卒,閟其事也;衣之龙服,远其躬也;佩以金玦,弃其衷也。服以远之,时以閟之,龙凉冬杀,金寒玦离,胡可恃也?虽欲勉之,狄可尽乎?”梁余子养曰:“帅师者受命于庙,受脤于社,有常服矣。不获而龙,命可知也。死而不孝,不如逃之。”罕夷曰:“龙奇无常,金玦不复,虽复何为,君有心矣。”先丹木曰:“是服也。狂夫阻之。曰‘尽敌而反’,敌可尽乎!虽尽敌,犹有内谗,不如违之。”狐突欲行。羊舌大夫曰:“不可。违命不孝,弃事不忠。虽知其寒,恶不可取,子其死之。” +大子将战,狐突谏曰:“不可,昔辛伯谂周桓公云:‘内宠并后,外宠二政,嬖子配适,大都耦国,乱之本也。’周公弗从,故及于难。今乱本成矣,立可必乎?孝而安民,子其图之,与其危身以速罪也。” +成风闻成季之繇,乃事之,而属僖公焉,故成季立之。 +僖之元年,齐桓公迁邢于夷仪。二年,封卫于楚丘。邢迁如归,卫国忘亡。 +卫文公大布之衣,大帛之冠,务材训农,通商惠工,敬教劝学,授方任能。元年革车三十乘,季年乃三百乘。 +译文 +二年春季,虢公在渭水入河的地方打败犬戎。舟之侨说:“没有德行受到宠禄,这是灾祸。灾祸将要来到了。”就逃亡到晋国。 +夏季,为庄公举行大祭。未免太快了。 +当初,闵公的保傅夺取卜齮的田地,闵公不加禁止。秋季,八月二十四日,共仲指使卜齮在武闱杀害闵公。成季带着僖公跑到邾国。共仲逃亡到莒国,季友和僖公就回到鲁国,拥立僖公为国君。用财货到莒国求取共仲,莒国人把他送了回来。共仲到达密地,让公子鱼请求赦免。没有得到同意,公子鱼哭着回去。共仲说:“这是公子鱼的哭声啊!”于是上吊死了。 +闵公是哀姜的妹妹叔姜的儿子,所以齐人立他为国君。共仲和哀姜私通,哀姜想立他为国君。闵公的被害,哀姜事先知道内情,所以逃到邾国。齐人向邾人索取哀姜,在夷地杀了她,把她的尸首带回去,僖公请求归还尸首安葬。 +成季将要出生的时候,鲁桓公让掌卜官楚丘的父亲占卜。他说:“是男孩子。他名叫友,是您的右手;处于周社和亳社之间,作为公室的辅助。季氏灭亡,鲁国不能盛昌。”又占筮,得到《大有》变成《乾》,说:“尊贵如同父亲,敬重如同国君。”等到生下来,在手掌心有个“友”字,就以友命名。 +冬季,十二月,狄人进攻卫国。卫懿公喜欢鹤,鹤有坐车子的。将要作战时,接受甲胄的人们都说:“让鹤去,鹤实际上享有官禄官位,我们哪里能打仗!”懿公把玉佩给了石祁子,把箭给了甯庄子,让他们防守,说:“用这个来赞助国家,选择有利的去做。”把绣衣给了夫人,说:“听他们二人的!”渠孔为卫懿公驾御战车,子伯作为车右;黄夷打冲锋,孔婴齐指挥后军。和狄人在荧泽作战,卫军大败,狄人就灭亡了卫国。卫侯不肯去掉自己的旗帜,所以惨败。狄人囚禁了史官华龙滑和礼孔以追赶卫国人。这两个人说:“我们,是太史之官,执掌祭祀。如果不先回去,你们是不能得到国都的。”于是就让他们先回去。他们到达,就告诉守卫的人说:“不能抵御了。”夜里和国都的人一起退走。狄人进入卫国国都,跟着追上去,又在黄河边上打败了卫国人。 +当初,卫惠公即位的时候还很年轻,齐人让昭伯和宣姜私通,昭伯不同意,就逼迫他干。生了齐子、戴公、文公、宋桓夫人、许穆夫人。文公由于卫国祸患太多,先到了齐国。等到卫国这次大败,宋桓公在黄河边上迎接,夜里渡河。卫国的遗民男女共计七百三十人,加上共地、滕地的百姓共五千人。立戴公为国君。暂时寄居在曹邑,许穆夫人作了《载驰》这首诗。齐桓公派遣公子无亏率领战车三百辆、披甲战士三千人守卫曹邑,赠送给戴公驾车的马匹,祭服五套,牛、羊、猪、鸡、狗都是三百头,还有做门户的木材。 +赠送给夫人用鱼皮装饰的车子,上等的绸缎三十匹。 +郑国人讨厌高克,派他率领军队住在黄河边,很久也不召他回来,军队溃散逃回,高克逃亡到陈国。郑国人为高克作了《清人》这首诗。 +晋献公派遣太子申生进攻东山的皋落氏。里克进谏说:“太子,是奉事宗庙祭祀、社稷大祭和早晚照看国君饮食的人,所以叫做冢子。国君外出就守护国家,如果有别人守护就跟随国君。跟随在外叫做抚军,守护在内叫做监国,这是古代的制度。说到带兵一事,对各种策略作出决断,对军队发号施令,这是国君和正卿所应该策划的,不是太子的事情。率领大军在于控制命令,太子领兵,如果遇事都要请示就失去威严,擅自发令而不请示就是不孝,所以国君的大儿子不能带领军队。国君失去了任命职官的准则,太子统率军队也没有威严,何必如此呢?而且下臣听说皋落氏准备出兵迎战,君王还是不要太子去为好。”晋献公说:“我有好几个儿子,还不知道立谁为嗣君呢!”里克不回答,退了下去。里克进见太子。太子说:“我恐怕要被废了吧!”里克回答说:“命令您在曲沃治理百姓,教导您熟悉军事,害怕的是不能完成任务,为什么会废立呢?而且做儿子的应该害怕不孝,不应该害怕不能立为嗣君。修养自己而不要去责备别人,就可以免于祸难。” +太子申生带领军队,晋献公让他穿左右两色的衣服,佩带有缺口的青铜环形佩器。狐突驾御战车,先友作为车右。梁馀子养为罕夷驾御战车,先丹木作为车右。羊舌大夫作为军尉。先友说:“穿着国君衣服的一半,掌握着军事的机要,成败全在这一回了,您要自己勉励啊!分出一半衣服没有恶意,兵权在手可以远离灾祸,与国君亲近又远离灾祸,又担心什么!”狐突叹息说:“时令,是事情的象征,衣服,是身分的标识,佩饰,是心志的旗帜。 +所以如果看重这件事,就应该在春、夏季发布命令;赐予衣服,就不要用杂色;使人衷心为自己所用,就要让他佩带合于礼度的装饰品。如今在年终发布命令,那是要让事情不能顺利进行;赐给他穿杂色衣服,那是要使他疏远;让他佩带缺口青铜环佩器,那是表示出丢弃太子的内心。现在是用衣服疏远他,用时令使他不能顺利进行;杂色,意味凉薄;冬天,意味肃杀;金,意味寒冷;玦,意味决绝,这怎么可以依靠呢?虽然要勉力而为,狄人难道可以消灭得一人不剩吗?”梁馀子养说:“领兵的人,在太庙里接受命令,在祭祀土神的地方接受祭肉,还应该有一定的服饰。现在得不到规定的服饰而得到杂色衣服,命令不怀好意可想而知。死了以后还要落个不孝的罪名,不如逃了吧!”罕夷说:“杂色的奇装异服不合规定,青铜环形佩器表示不再回来。这样,即使是回来还有什么用?国君已经有别的心思了。”先丹木说:“这样的衣服,狂人也不会去穿的。国君说:‘将敌人消灭光了再回来’,敌人难道可以消灭得一干二净吗?即使把敌人消灭干净了,还有内部谗言,不如离开这里。”狐突要走,羊舌大夫说:“不行。违背命令是不孝,抛弃责任是不忠。虽然已经感到了国君的心里冷酷,不孝不忠这样的邪恶是不可取的。您还是为此而死吧!” +太子准备作战,狐突劝阻说:“不行。从前辛伯劝阻周桓公说:‘妾媵并同于王后,宠臣相等于正卿,庶子和嫡子同等,大城和国都相同,这就是祸乱的根本。’周桓公不听,所以遭到祸难。现在祸乱的根本已经形成,您还能肯定会立您为嗣君吗?您就考虑一下吧!与其危害自身而加快罪过的到来,何如尽孝道而安定百姓!” +成风听到成季出生时占卜的卦辞,就和他结交,并且把僖公嘱托给他,所以成季立僖公为国君。 +僖公元年,齐桓公把邢国迁到夷仪。二年,把卫国封在楚丘。邢国迁居,好像回到原来的国土;卫国重建,却忘记了亡国之痛。 +卫文公穿着粗布衣服,戴着粗帛帽子,努力生产,教导农耕,便利商贩,加惠各种手工业,重视教化,奖励求学,向臣下传授为官之道,任用有能力的人。头一年,战车只有三十辆,到末年,就有了三百辆。 + +僖公 + + +僖公元年 +【经】元年春王正月。齐师、宋师、曹伯次于聂北,救邢。夏六月,邢迁于夷仪。齐师、宋师、曹师城邢。秋七月戊辰,夫人姜氏薨于夷,齐人以归。楚人伐郑。八月,公会齐侯、宋公、郑伯、曹伯、邾人于柽。九月,公败邾师于偃。冬十月壬午,公子友帅师败莒于郦。获莒拏。十有二月丁巳,夫人氏之丧至自齐。 +【传】元年春,不称即位,公出故也。公出复入,不书,讳之也。讳国恶,礼也。 +诸侯救邢。邢人溃,出奔师。师遂逐狄人,具邢器用而迁之,师无私焉。 +夏,邢迁夷仪,诸侯城之,救患也。凡侯伯救患分灾讨罪,礼也。 +秋,楚人伐郑,郑即齐故也。盟于荦,谋救郑也。 +九月,公败邾师于偃,虚丘之戍将归者也。 +冬,莒人来求赂。公子友败诸郦,获莒子之弟拏。非卿也,嘉获之也。公赐季友汶阳之田及费。 +夫人氏之丧至自齐。君子以齐人杀哀姜也为已甚矣,女子,从人者也。 +译文 +元年春季,《春秋》没有记载即位,这是由于僖公出奔在外的缘故。僖公出奔而又回到国内,《春秋》不加记载,这是由于避讳。不记国家的坏事,这是合于礼的。 +齐桓公、宋桓公、曹昭公率领军队驻扎在聂北,诸侯联军救援邢国。邢军已经溃散,逃到诸侯的军队里。军队便赶走了狄人,装载了邢国的器物财货而让邢军搬走,各国军队没有私自占有。 +夏季,邢国把都城迁到夷仪,诸侯替它筑城,为的是救援患难。凡是诸侯领袖,救援患难、分担灾害、讨伐罪人,都是合于礼的。 +秋季,楚国人进攻郑国,这是由于郑国亲近齐国的缘故。鲁僖公和齐桓公、宋桓公、郑文公、邾子在荦地结盟,策划救援郑国。九月,僖公在偃地打败了邾国的军队,这支队伍是戍守在虚丘将要回国的军队。 +冬季,莒国人来求取财货,公子友在郦地打败了他们,俘虏了莒子的弟弟挐。挐并不是卿,《春秋》这样记载,是为了称赞公子友俘获的功劳。僖公把汶阳的田地和费地赐给季友。 +鲁庄公夫人姜氏的尸体从齐国运来。君子认为齐国人杀死哀姜是太过分了,妇女,本来应该听从丈夫的。 + +僖公二年 +【经】二年春王正月,城楚丘。夏五月辛巳,葬我小君哀姜。虞师、晋师灭下阳。秋九月,齐侯、宋公、江人、黄人盟于贯。冬十月,不雨。楚人侵郑。 +【传】二年春,诸侯城楚丘而封卫焉。不书所会,后也。 +晋荀息请以屈产之乘与垂棘之璧,假道于虞以伐虢。公曰:“是吾宝也。”对曰:“若得道于虞,犹外府也。”公曰:“宫之奇存焉。”对曰:“宫之奇之为人也,懦而不能强谏,且少长于君,君昵之,虽谏,将不听。”乃使荀息假道于虞,曰:“冀为不道,入自颠軨,伐鄍三门。冀之既病。则亦唯君故。今虢为不道,保于逆旅,以侵敝邑之南鄙。敢请假道以请罪于虢。”虞公许之,且请先伐虢。宫之奇谏,不听,遂起师。夏,晋里克、荀息帅师会虞师伐虢,灭下阳。先书虞,贿故也。 +秋,盟于贯,服江、黄也。 +齐寺人貂始漏师于多鱼。 +虢公败戎于桑田。晋卜偃曰:“虢必亡矣。亡下阳不惧,而又有功,是天夺之鉴,而益其疾也。必易晋而不抚其民矣,不可以五稔。” +冬,楚人伐郑,斗章囚郑聃伯。 +译文 +二年春季,诸侯在楚丘筑城,而将由周天子封给卫国。《春秋》没有记载诸侯会见,是由于僖公到会晚了。 +晋国的荀息请求用屈地出产的马和垂棘出产的璧玉向虞国借路来进攻虢国。晋献公说:“这是我的宝物啊!”荀息回答说:“如果向虞国借到了路,东西放在虞国,就像放在宫外的库房里一样。”晋献公说:“宫之奇还在那里。”荀息回答说:“宫之奇的为人,懦弱而不能坚决进谏,而且从小就和虞君在宫里一起长大,虞君对他亲昵,虽然进谏,虞君不会听从的。”于是晋献公就派荀息到虞国去借路,说:“冀国无道,从颠軨入侵,围攻虞国鄍邑的三面城门。敝国伐冀而使冀国受到损失,也是为了君王的缘故。现在虢国无道,在客舍里筑起堡垒,来攻打敝国的南部边境。谨大胆地请求贵国借路,以便到虢国去问罪。”虞公答应了,而且自己请求先去进攻虢国。宫之奇劝阻,虞公不听,就带兵进攻虢国。夏季,晋国的里克、荀息领兵会合虞军,进攻虢国,灭亡了下阳。《春秋》把虞国写在前面,因为虞国接受了贿赂。 +秋季,齐桓公、宋桓公、江、黄两地的头目在贯地结盟,这是为了江、黄两国归服于齐。 +齐国的寺人貂开始在多鱼地方泄漏了军事机密。 +虢公在桑田打败了戎人。晋国的卜偃说:“虢国必将被灭亡。被灭掉了下阳不知戒惧,反而又建立了武功,这是上天夺去了虢国的镜子,而加重它的作恶啊!虢国必定轻视晋国又不爱抚百姓,过不了五年,必然灭亡。” +冬季,楚国人进攻郑国,鬬章囚禁了郑国的聃伯。 + +僖公三年 +【经】三年春王正月,不雨。夏四月不雨。徐人取舒。六月雨。秋,齐侯、宋公、江人、黄人会于阳谷。冬,公子友如齐位盟。楚人伐郑。 +【传】三年春,不雨。夏六月,雨。自十月不雨至于五月,不曰旱,不为灾也。 +秋,会于阳谷,谋伐楚也。 +齐侯为阳谷之会,来寻盟。冬,公子友如齐位盟。 +楚人伐郑,郑伯欲成。孔叔不可,曰:“齐方勤我,弃德不祥。” +齐侯与蔡姬乘舟于囿,荡公。公惧,变色。禁之,不可。公怒,归之,未绝之也。蔡人嫁之。 +译文 +三年春季,不下雨,到六月才下雨。从去年十月不下雨一直到五月,《春秋》没有记载说旱,因为没有造成灾害。 +秋季,齐桓公、宋桓公、江人、黄人在阳穀会见,这是由于预谋进攻楚国。 +齐桓公为了阳穀的盟会而来重温旧好。冬季,公子友到齐国参加盟会。 +楚军进攻郑国,郑文公想求和。孔叔不同意,说:“齐国正为我国忙着,丢弃他们的恩德而向楚国讲和,不会有好结果。” +齐桓公和蔡姬在园子里坐船游览,蔡姬故意摇动游船,使齐桓公摇来晃去。齐桓公害怕,脸色都变了,叫她别摇,蔡姬不听。齐桓公很生气,把她送回蔡国,但并不是断绝婚姻关系。蔡国人却把蔡姬改嫁了。 + +僖公四年 +【经】四年春王正月,公会齐侯、宋公、陈侯、卫侯、郑伯,许男、曹伯侵蔡。蔡溃,遂伐楚,次于陉。夏,许男新臣卒。楚屈完来盟于师,盟于召陵。齐人执陈辕涛涂。秋,及江人、黄人伐陈。八月,公至自伐楚。葬许穆公。冬十有二月,公孙兹帅师会齐人、宋人、卫人、郑人、许人、曹人侵陈。 +【传】四年春,齐侯以诸侯之师侵蔡。蔡溃。遂伐楚。楚子使与师言曰:“君处北海,寡人处南海,唯是风马牛不相及也。不虞君之涉吾地也,何故?”管仲对曰:“昔召康公命我先君大公曰:‘五侯九伯,女实征之,以夹辅周室。’赐我先君履,东至于海,西至于河,南至于穆陵,北至于无棣。尔贡包茅不入,王祭不共,无以缩酒,寡人是征。昭王南征而不复,寡人是问。”对曰:“贡之不入,寡君之罪也,敢不共给。昭王之不复,君其问诸水滨。”师进,次于陉。 +夏,楚子使屈完如师。师退,次于召陵。 +齐侯陈诸侯之师,与屈完乘而观之。齐侯曰:“岂不谷是为?先君之好是继。与不谷同好,如何?”对曰:“君惠徼福于敝邑之社稷,辱收寡君,寡君之愿也。”齐侯曰:“以此众战,谁能御之?以此攻城,何城不克?”对曰:“君若以德绥诸侯,谁敢不服?君若以力,楚国方城以为城,汉水以为池,虽众,无所用之。” +屈完及诸侯盟。 +陈辕涛涂谓郑申侯曰:“师出于陈、郑之间,国必甚病。若出于东方,观兵于东夷,循海而归,其可也。”申侯曰:“善。”涛涂以告,齐侯许之。申侯见,曰:“师老矣,若出于东方而遇敌,惧不可用也。若出于陈、郑之间,共其资粮悱屦,其可也。”齐侯说,与之虎牢。执辕涛涂。 +秋,伐陈,讨不忠也。 +许穆公卒于师,葬之以侯,礼也。凡诸侯薨于朝会,加一等;死王事,加二等。于是有以衮敛。 +冬,叔孙戴伯帅师,会诸侯之师侵陈。陈成,归辕涛涂。 +初,晋献公欲以骊姬为夫人,卜之,不吉;筮之,吉。公曰:“从筮。”卜人曰:“筮短龟长,不如从长。且其繇曰:‘专之渝,攘公之羭。一薰一莸,十年尚犹有臭。’必不可。”弗听,立之。生奚齐,其娣生卓子。及将立奚齐,既与中大夫成谋,姬谓大子曰:“君梦齐姜,必速祭之。”大子祭于曲沃,归胙于公。公田,姬置诸宫六日。公至,毒而献之。公祭之地,地坟。与犬,犬毙。与小臣,小臣亦毙。姬泣曰:“贼由大子。”大子奔新城。公杀其傅杜原款。或谓大子:“子辞,君必辩焉。”大子曰:“君非姬氏,居不安,食不饱。我辞,姬必有罪。君老矣,吾又不乐。”曰:“子其行乎!”大子曰:“君实不察其罪,被此名也以出,人谁纳我?” +十二月戊申,缢于新城。姬遂谮二公子曰:“皆知之。”重耳奔蒲。夷吾奔屈。 +译文 +四年春季,齐桓公率领鲁僖公、宋桓公、陈宣公、卫文公、郑文公、许穆公、曹昭公各诸侯的联军入侵蔡国。蔡军溃败,齐桓公就接着进攻楚国。 +楚成王派遣使者来到军中,说:“君王住在北方,我住在南方,即使是牛马发情狂奔彼此也不会相关。没有想到君王竟不顾路远来到我国的土地上,这是什么缘故?”管仲回答说:“以前召康公命令我们的先君太公说:‘五侯九伯,你都可以征伐他们,以便辅助王室。’赐给我们的先君征伐的范围,东边到大海,西边到黄河,南边到穆陵,北边到无棣。你不进贡王室的包茅,使天子的祭祀缺乏应有的物资,不能漉酒请神,我为此而来问罪。昭王南征到楚国而没有回去,我为此而来责问。”使者回答说:“贡品没有送来,这确是我君的罪过,今后岂敢不供给?至于昭王没有回去,君王还是问水边上的人吧!”诸侯的军队前进,驻扎在陉地。 +夏季,楚成王派遣屈完带兵到诸侯军驻地。诸侯军队撤退,驻扎在召陵。齐桓公把所率领的军队列成战阵,和屈完坐一辆战车检阅队伍。齐桓公说:“我们出兵,难道是为了我一个人吗?为的是继续先君建立的友好关系。我们两国共同友好怎么样?”屈完回答说:“君王惠临敝国求福,承蒙君王安抚我君,这正是我君的愿望!”齐桓公说:“用这样的军队来作战,谁能够抵御他们?用这样的军队来攻城,哪个城不被攻破?”屈完回答说:“君王如果用德行安抚诸侯,谁敢不服?君王如果用武力,楚国有方城山作为城墙,汉水作为护城河,君王的军队即使很多,也没有什么用处。”屈完与各诸侯订立了盟约。 +陈国的辕涛涂对郑国的申侯说:“军队取道陈国和郑国之间,两国供应必然发生困难。如果向东走,向东夷炫耀武力,沿着海道回国,这就很好了。”申侯说:“好。”辕涛涂就把这个意见告诉齐桓公,齐桓公同意了。申侯进见齐桓公说:“军队在外头久了,如果往东走而遇到敌人,恐怕是不能打硬仗了。如果取道陈国和郑国之间,由两国供给军队的粮食、军鞋,这就可以了。”齐桓公很高兴,将虎牢赏给他,而把辕涛涂抓了起来。 +秋季,齐国和江国、黄国进攻陈国,这是为了讨伐陈国对齐国的不忠。 +许穆公死在军中,用安葬侯的制度安葬他,这是合于礼的。凡是诸侯在朝会时死去,葬礼加一等;为天子作战而死的,加二等。在这种情况下才可以用天子的礼服入殓。 +冬季,叔孙戴伯带兵会合诸侯的军队侵犯陈国。陈国求和,便把辕涛涂放回去了。 +当初,晋献公想立骊姬做夫人,用龟来占卜,不吉利;用草占卜,吉利。献公说:“听从蓍草所占卜的结果。”占卜的人说:“蓍草之数短而龟象却长,不如按照龟卜。而且它的繇辞说:‘专宠会使人心生不良,将要偷走您的公羊。香草和臭草放在一起,十年以后还会有臭气。’一定不可以。”晋献公不听,立了骊姬。骊姬生了奚齐,她的妹妹生了卓子。等到打算立奚齐做太子,骊姬已经和中大夫定了计谋。骊姬对太子说:“国君梦见你母亲齐姜,你一定要赶快祭祀她。”太子到曲沃祭祀,把祭酒祭肉带回来给献公吃。献公刚好出外打猎,骊姬把酒肉放在宫里过了六天。献公回来,骊姬在酒肉里下毒药而献上去。献公以酒祭地,地土突起像坟堆。把肉给狗吃,狗就死掉;给宦官吃,宦官也死了。骊姬哭着说:“阴谋来自太子那里。”太子逃亡到新城,献公杀了他的保傅杜原款。有人对太子说:“您如果声辩,国君是必定能弄清楚的。”太子说:“国君没有骊姬,居不安,食不饱。我如果声辩,骊姬必定有罪。国君年纪老了,骊姬有罪会使国君不高兴,我也会忧郁不乐的。”说:“那么您逃走吧!”太子说:“国君还没有查清我的罪过,带着这个名义出去,别人谁会接纳我?”十二月二十七日,太子吊死在新城。骊姬就诬陷两位公子说:“太子的阴谋他们都参预了。”于是重耳逃亡到蒲城,夷吾逃亡到屈地。 + + +僖公五年 +【经】五年春,晋侯杀其世子申生。杞伯姬来朝其子。夏,公孙兹如牟。公及齐侯、宋公、陈侯、卫侯、郑伯、许男、曹伯会王世子于首止。秋八月,诸侯盟于首止。郑伯逃归不盟。楚人灭弦,弦子奔黄。九月戊申朔,日有食之。冬,晋人执虞公。 +【传】五年春,王正月辛亥朔,日南至。公既视朔,遂登观台以望。而书,礼也。凡分、至、启、闭,必书云物,为备故也。 +晋侯使以杀大子申生之故来告。 +初,晋侯使士蒍为二公子筑蒲与屈,不慎,置薪焉。夷吾诉之。公使让之。士蒍□稽首而对曰:“臣闻之,无丧而戚,忧必仇焉。无戎而城,仇必保焉。寇仇之保,又何慎焉!守官废命不敬,固仇之保不忠,失忠与敬,何以事君?《诗》云:‘怀德惟宁,宗子惟城。’君其修德而固宗子,何城如之?三年将寻师焉,焉用慎?”退而赋曰:“狐裘龙茸,一国三公,吾谁适从?”及难,公使寺人披伐蒲。重耳曰:“君父之命不校。”乃徇曰:“校者吾仇也。”逾垣而走。披斩其祛,遂出奔翟。 +夏,公孙兹如牟,娶焉。 +会于首止,会王大子郑,谋宁周也。 +陈辕宣仲怨郑申侯之反己于召陵,故劝之城其赐邑,曰:“美城之,大名也,子孙不忘。吾助子请。”乃为之请于诸侯而城之,美。遂谮诸郑伯,曰:“美城其赐邑,将以叛也。”申侯由是得罪。 +秋,诸侯盟。王使周公召郑伯,曰:“吾抚女以从楚,辅之以晋,可以少安。”郑伯喜于王命而惧其不朝于齐也,故逃归不盟,孔叔止之曰:“国君不可以轻,轻则失亲。失亲患必至,病而乞盟,所丧多矣,君必悔之。”弗听,逃其师而归。 +楚斗谷于菟灭弦,弦子奔黄。 +于是江、黄、道、柏方睦于齐,皆弦姻也。弦子恃之而不事楚,又不设备,故亡。 +晋侯复假道于虞以伐虢。宫之奇谏曰:“虢,虞之表也。虢亡,虞必从之。晋不可启,寇不可玩,一之谓甚,其可再乎?谚所谓‘辅车相依,唇亡齿寒’者,其虞、虢之谓也。”公曰:“晋,吾宗也,岂害我哉?”对曰:“大伯、虞仲,大王之昭也。大伯不从,是以不嗣。虢仲、虢叔,王季之穆也,为文王卿士,勋在王室,藏于盟府。将虢是灭,何爱于虞?且虞能亲于桓,庄乎,其爱之也?桓、庄之族何罪,而以为戮,不唯逼乎?亲以宠逼,犹尚害之,况以国乎?”公曰:“吾享祀丰洁,神必据我。”对曰:“臣闻之,鬼神非人实亲,惟德是依。故《周书》曰:‘皇天无亲,惟德是辅。’又曰:‘黍稷非馨,明德惟馨。’又曰:‘民不易物,惟德繄物。’如是,则非德,民不和,神不享矣。神所冯依,将在德矣。若晋取虞而明德以荐馨香,神其吐之乎?”弗听,许晋使。宫之奇以其族行,曰:“虞不腊矣,在此行也,晋不更举矣。” +八月甲午,晋侯围上阳。问于卜偃曰:“吾其济乎”?对曰:“克之。”公曰:“何时?”对曰:“童谣云:‘丙之晨,龙尾伏辰,均服振振,取虢之旂。鹑之贲贲,天策焞焞,火中成军,虢公其奔。’其九月、十月之交乎。丙子旦,日在尾,月在策,鹑火中,必是时也。” +冬十二月丙子朔,晋灭虢,虢公丑奔京师。师还,馆于虞,遂袭虞,灭之,执虞公及其大夫井伯,以媵秦穆姬。而修虞祀,且归其职贡于王。 +故书曰:“晋人执虞公。”罪虞,且言易也。 +译文 +五年春季,周王朝历法的正月初一日,冬至。鲁僖公在太庙听政以后,就登上观台望云物,加以记载,这是合于礼的。凡是春分秋分、夏至冬至、立春立夏、立秋立冬,必定要记载云物,这是由于要为灾荒作准备的缘故。 +晋献公派遣使者来报告杀害太子申生的原因。 +当初,晋献公派士蔿为两位公子在蒲地和屈地筑城,不小心,城墙里放进了木柴。夷吾告诉晋献公。晋献公派人责备士蔿。士蔿叩头回答说:“臣听说:‘没有丧事而悲伤,忧愁必然跟着来到;没有兵患而筑城,国内的敌人必然据作守卫之用。’敌人既然可以占据,哪里用得着谨慎?担任官职而不接受命令,这是不敬;巩固敌人可以占据的地方,这是不忠。没有忠和敬,怎么能奉事国君?《诗经》说:‘心存德行就是安宁,宗室子弟就是城池。’君王只要修养德行而使同宗子弟的地位巩固,哪个城池能比得上?三年以后就要用兵,哪里用得着谨慎?”退出去赋诗说:“狐皮袍子蓬蓬松松,一个国家有了三个主人翁,究竟是谁我该一心跟从?”等到发生祸难,晋献公派遣寺人披攻打蒲城。重耳说:“国君和父亲的命令不能违抗。”并通告说:“抵抗的就是我的敌人。”重耳越墙逃走,寺人披砍掉了他的袖口,最后他逃亡到翟国。 +夏季,公孙兹到牟国,在那里娶了亲。 +鲁僖公和齐桓公、宋桓公、陈宣公、卫文公、郑文公、许僖公、曹昭公在首止相会,会见周王的太子郑,为的是安定成周。 +陈国的辕宣仲(涛涂)怨恨郑国的申侯在召陵出卖了他,所以故意劝申侯在所赐的封邑筑城,说:“把城筑得美观,名声就大些,子孙不会忘记。我帮助您请求。”就为申侯向诸侯请求而筑起城墙,筑得很美观。辕宣仲就在郑文公面前进谗言说:“把所赐封邑的城墙筑得那么美观,是准备将来用这城墙叛乱的。”申侯因此而获罪。 +秋季,诸侯会盟。周惠王派周公召见郑文公,说:“我安抚你去跟随楚国,又让晋国辅助你,这就可以稍稍安定了。”郑文公对周惠王的命令感到高兴,又对没有朝见齐国感到惧怕,所以打算逃走回国而不参加盟誓。孔叔不让他走,说:“国君举动不能轻率,轻率就失掉了能亲近的人。失掉了能亲近的人,祸患必然来到。国家困难而去乞求结盟,所失掉的东西就多了。您一定会后悔。”郑文公不听,离开了军队潜逃回国。 +楚国的鬬穀於菟灭亡弦国,弦子逃亡到黄国。这时江、黄、道、柏四国和齐国友好,这些国家都和弦国有婚姻关系。弦子仗着这些关系而不去事奉楚国,又不设置防备,所以被灭亡。 +晋献公再次向虞国借路进攻虢国。宫之奇劝阻说:“虢国是虞国的外围,虢国灭亡,虞国必定跟着完蛋。晋国的野心不能让他打开,引进外国军队不能忽视。一次已经够了,难道还可以来第二次吗?俗话说的‘大车的板和车子互相依存,嘴唇缺了,牙齿便受冷寒’,这说的就是虞国和虢国的关系。”虞公说:“晋国是我的宗族,难道会害我吗?”宫之奇回答说:“太伯、虞仲,是太王的儿子。太伯没有随侍在侧,所以没有继位。虢仲、虢叔,是王季的儿子,做过文王卿士,功勋在于王室,受勋的记录还藏在盟府。晋国准备灭掉虢国,对虞国又有什么可爱惜的?况且虞国能比晋国的桓叔、庄伯更加亲近吗?如果他们爱惜桓叔、庄伯,这两个家族有什么罪过,但是却被杀戮,不就是因为使他们感到受到威胁吗?亲近的人由于受宠就威胁公室,尚且被无辜杀害,何况对一个国家呢?”虞公说:“我祭祀的祭品丰盛又清洁,神明必定保佑我。”宫之奇回答说:“下臣听说,鬼神并不是亲近哪一个人,而只是依从有德行的人,所以《周书》说:‘上天没有私亲,只对有德行的才加以辅助。’又说:‘祭祀的黍稷不芳香,美德才芳香。’又说:‘百姓不能变更祭祀的物品,只有德行才可以充当祭祀的物品。’这样看来,那么不是道德,百姓就不和,神明也就不来享用祭物了。神明所凭依的,就在于德行了。如果晋国占取了虞国,发扬美德作为芳香的祭品奉献于神明,神明难道会吐出来吗?”虞公不听,答应了晋国使者的要求。宫之奇带领了他的族人出走,说:“虞国过不了今年的腊祭了。就是这一次,晋国不必再次出兵了。” +八月某一天,晋献公包围上阳。问卜偃说:“我能够成功吗?”卜偃回答说:“能攻下。”晋献公说:“什么时候?”卜偃回答说:“童谣说:‘丙子日的清早,龙尾星为日光所照;军服威武美好,夺取虢国的旗号。鹑火星像只大鸟,天策星没有光耀,鹑火星下整理军队,虢公将要逃跑。’这日子恐怕在九月底十月初吧!丙子日的清晨,日在尾星之上,月在天策星之上,鹑火星在日月的中间,一定是这个时候。” +冬季,十二月初一日,晋国灭掉了虢国。虢公丑逃亡到京城。晋军回国,住在虞国,乘机袭击虞国,灭亡了它。晋国人抓住了虞公和他的大夫井伯,把井伯作为秦穆姬的陪嫁随员,但并不废弃虞国的祭祀,而且把虞国的赋税归于周王。 +所以《春秋》记载说“晋人执虞公”,这是归罪于虞国,而且说事情进行得太容易。 + + +僖公六年 +【经】六年春王正月。夏,公会齐侯、宋公、陈侯、卫侯、曹伯伐郑,围新城。秋,楚人围许,诸侯遂救许。冬,公至自伐郑。 +【传】六年春,晋侯使贾华伐屈。夷吾不能守,盟而行。将奔狄郤芮曰:“后出同走,罪也。不如之梁。梁近秦而幸焉。”乃之梁。 +夏,诸侯伐郑,以其逃首止之盟故也。围新密,郑所以不时城也。 +秋,楚子围许以救郑,诸侯救许,乃还。 +冬,蔡穆侯将许僖公以见楚子于武城。许男面缚,衔璧,大夫衰絰,士舆榇。楚子问诸逢伯,对曰:“昔武王克殷,微子启如是。武王亲释其缚,受其璧而祓之。焚其榇,礼而命之,使复其所。”楚子从之。 +译文 +六年春季,晋献公派遣贾华率军进攻屈地。夷吾守不住,和屈人订立盟约然后出走。准备逃亡到狄。郤芮说:“在重耳之后离开而且同样逃到狄,这就表明你有同谋的罪过。不如去梁国。梁国接近秦国而又得到它的信任。”于是夷吾就到了梁国。 +夏季,诸侯进攻郑国,因为郑国逃避首止那次结盟的缘故。诸侯军包围了新密,这就是郑国在不宜动土筑城的时令而筑城的缘故。 +秋季,楚成王出兵包围许国来救援郑国。诸侯出兵救援许国,楚军于是回国。 +冬季,蔡穆侯带领许僖公到武城去见楚成王。许男两手反绑,嘴里衔着璧玉,大夫穿着孝服,士抬着棺材。楚成王询问逢伯。逢伯回答说:“从前武王打胜殷朝,微子启就是这样做的。武王亲自解开他的捆绑,接受他的璧玉而举行扫除凶恶之礼,烧掉他的棺材,给以礼遇而命令他,让他回到原地原位去。”楚成王接受了逢伯的建议。 + + +僖公七年 +【经】七年春,齐人伐郑。夏,小邾子来朝。郑杀其大夫申侯。秋七月,公会齐侯、宋公、陈世子款、郑世子华盟于宁母。曹伯班卒。公子友如齐。冬葬曹昭公。 +【传】七年春,齐人伐郑。孔叔言于郑伯曰:“谚有之曰:‘心则不竞,何惮于病。’既不能强,又不能弱,所以毙也。国危矣,请下齐以救国。”公曰:“吾知其所由来矣。姑少待我。”对曰:“朝不及夕,何以待君?” +夏,郑杀申侯以说于齐,且用陈辕涛涂之谮也。 +初,申侯,申出也,有宠于楚文王。文王将死,与之璧,使行,曰,“唯我知女,女专利而不厌,予取予求,不女疵瑕也。后之人将求多于女,女必不免。我死,女必速行。无适小国,将不女容焉。”既葬,出奔郑,又有宠于厉公。子文闻其死也,曰:“古人有言曰‘知臣莫若君。’弗可改也已。” +秋,盟于宁母,谋郑故也。 +管仲言于齐侯曰:“臣闻之,招携以礼,怀远以德,德礼不易,无人不怀。”齐侯修礼于诸侯,诸侯官受方物。 +郑伯使大子华听命于会,言于齐侯曰:“泄氏、孔氏、子人氏三族,实违君命。若君去之以为成。我以郑为内臣,君亦无所不利焉。”齐侯将许之。管仲曰:“君以礼与信属诸侯,而以奸终之,无乃不可乎?子父不奸之谓礼,守命共时之谓信。违此二者,奸莫大焉。”公曰:“诸侯有讨于郑,未捷。今苟有衅。从之,不亦可乎?”对曰:“君若绥之以德,加之以训辞,而帅诸侯以讨郑,郑将覆亡之不暇,岂敢不惧?若总其罪人以临之,郑有辞矣,何惧?且夫合诸侯以崇德也,会而列奸,何以示后嗣?夫诸侯之会,其德刑礼义,无国不记。记奸之位,君盟替矣。作而不记,非盛德也。君其勿许,郑必受盟。夫子华既为大子而求介于大国,以弱其国,亦必不免。郑有叔詹、堵叔、师叔三良为政,未可间也。”齐侯辞焉。子华由是得罪于郑。 +冬,郑伯请盟于齐。 +闰月,惠王崩。襄王恶大叔带之难,惧不立,不发丧而告难于齐。 +译文 +七年春季,齐国人进攻郑国。孔叔对郑文公说:“俗语有这样的话:‘心志假若不坚强,怎么能又怕屈辱?’既然不能强硬,又不能软弱,因此只有死路一条。国家危险了,请您向齐国屈服以挽救国家。”郑文公说:“我知道他们是为什么来的了,姑且稍稍等我一下。”孔叔回答说:“情况危急,早晨到不了晚上,怎么等待君王呢?” +夏季,郑文公杀死申侯以讨好齐国,同时也是由于陈国辕涛涂的诬陷。当初,因为申侯是申氏所生,受到楚文王的宠信。文王将要死的时候,把璧玉给他,让他走,说:“只有我了解你,你垄断财货而永不满足,从我这里取,从我这里求,我不加罪于你。后来的人将会向你索取大量财货,你必然不免于罪。我死,你一定要赶快走,不要到小国去,他们不会容纳你的。”安葬楚文王后,申侯逃到郑国,又受到厉公的宠信。子文听到他的死讯,说:“古人有这样的话说:‘了解臣子没有像国君那样清楚的。’这句话是不能改变的啊!” +秋季,鲁僖公和齐桓公、宋桓公、陈国的世子款、郑国的世子华在宁母结盟,策划进攻郑国。 +管仲对齐桓公说:“臣听说:招抚有二心的国家,用礼;怀念疏远的国家,用德。凡事不违背德和礼,没有人不归附的。”齐桓公就以礼对待诸侯,诸侯的官员接受了齐国赏的土特产。 +郑文公派遣太子华接受会议的命令,对齐桓公说:“泄氏、孔氏、子人氏三族,违背您的命令。您如果除掉他们而和敝国讲和,我国作为您的内臣,这对您也没有什么不利。”齐桓公准备答应他。管仲说:“君王用礼和信会合诸侯,而用邪恶来结束,未免不行吧。儿子和父亲不相违背叫做礼,见机行事完成君命叫做信。违背这两点,没有比这再大的邪恶了。”齐桓公说:“诸侯进攻郑国,没有得胜;现在幸而有机可乘,利用这点,不也行吗?”管仲回答说:“君王如果用德来安抚,加上教训,他们不接受,然后率领诸侯讨伐郑国;郑国挽救危亡还来不及,哪敢不害怕?如果领着他的罪人以兵进攻郑国,郑国就有理了,还害怕什么?而且会合诸侯,这是为了尊崇德行。会合而让奸邪之人列于国君,怎么能向后代交代?诸侯的会见,他们的德行、刑罚、礼仪、道义,没有一个国家不加以记载。如果记载了让邪恶的人居于君位,君王的盟约就要废弃了。事情做了而不能见于记载,这就不是崇高的道德。君王还是同意为好!郑国一定会接受盟约的。子华既然做了太子,而要求凭借大国来削弱他的国家,也一定不能免于祸患。郑国有叔詹、堵叔、师叔三个贤明的人执政,还不能去钻它的空子。”齐桓公于是向子华辞谢。子华因此得罪了郑国。 +冬季,郑文公派遣使者到齐国请求订立盟约。 +闰十二月,周惠王去世。襄王担心大叔王子带作乱,又害怕不能立为国君,所以不发布丧事的消息,却把将要发生内乱的事向齐国报告。 + + +僖公八年 +【经】八年春王正月,公会王人、齐侯、宋公、卫侯、许男、曹伯、陈世子款盟于洮。郑伯乞盟。夏,狄伐晋。秋七月,禘于大庙,用致夫人。冬十有二月丁未,天王崩。 +【传】八年春,盟于洮,谋王室也。郑伯乞盟,请服也。襄王定位而后发丧。 +晋里克帅师,梁由靡御。虢射为右,以败狄于采桑。梁由靡曰:“狄无耻,从之必大克。”里克曰:“拒之而已,无速众狄。”虢射曰:“期年,狄必至,示之弱矣。” +夏,狄伐晋,报采桑之役也。复期月。 +秋,禘而致哀姜焉,非礼也。凡夫人不薨于寝,不殡于庙,不赴于同,不祔于姑,则弗致也。 +冬,王人来告丧,难故也,是以缓。 +宋公疾,大子兹父固请曰:“目夷长,且仁,君其立之。”公命子鱼,子鱼辞,曰:“能以国让,仁孰大焉?臣不及也,且又不顺。”遂走而退。 +译文 +八年春季,鲁僖公和周王室的使者、齐桓公、宋桓公、卫文公、许僖公、曹共公、郑世子款在洮地会盟,商谈安定王室。郑文公请求参加盟会,表示顺服。襄王的君位安定后,才举行丧礼。 +晋国的里克率领军队,梁由靡驾御战车,虢射作为车右,在采桑打败了狄人。梁由靡说:“狄人不以逃走为耻,如果追击,必然大胜。”里克说:“吓唬一下就行了,不要因为追击招来更多的狄人。”虢射说:“只要一年,狄人必然再来,不去追击,就是向他们示弱了。” +夏季,狄人进攻晋国,这是为了报复采桑这一战役,应验了,虢射所说一年的预言。 +秋季,举行宗庙合祭,把哀姜的神主放在太庙里,这是不合于礼的。凡是夫人,如果不死在正房里,不在祖庙里停棺,不向同盟国家发讣告,不陪祀祖姑,就不能把神主放进太庙里去。 +冬季,周王室的使者来鲁国讣告丧事,由于发生祸难,所以讣告迟了。 +宋桓公得了重病,太子兹父再三请求说:“目夷年长而且仁爱,君王应该立他为国君。”宋桓公就下令要目夷继位。目夷推谢说:“能够把国家辞让给别人,还有比这更大的仁爱吗?下臣不如他!而且又不符合立君的顺序。”于是就退了出去。 + + +僖公九年 +【经】九年春王三月丁丑,宋公御说卒。夏,公会宰周公、齐侯、宋子、卫侯、郑伯、许男、曹伯于葵丘。秋七月乙酉,伯姬卒。九月戊辰,诸侯盟于葵丘。甲子,晋侯佹诸卒。冬,晋里奚克杀其君之子奚齐。 +【传】九年春,宋桓公卒,未葬而襄公会诸侯,故曰子。凡在丧,王曰小童,公侯曰子。 +夏,会于葵丘,寻盟,且修好,礼也。 +王使宰孔赐齐侯胙,曰:“天子有事于文武,使孔赐伯舅胙。”齐侯将下拜。孔曰:“且有后命。天子使孔曰:‘以伯舅耋老,加劳,赐一级,无下拜’”。对曰:“天威不违颜咫尺,小白余敢贪天子之命无下拜?恐陨越于下,以遗天子羞。敢不下拜?”下,拜;登,受。 +秋,齐侯盟诸侯于葵丘,曰:“凡我同盟之人,既盟之后,言归于好。”宰孔先归,遇晋侯曰:“可无会也。齐侯不务德而勤远略,故北伐山戎,南伐楚,西为此会也。东略之不知,西则否矣。其在乱乎。君务靖乱,无勤于行。”晋侯乃还。 +九月,晋献公卒,里克、ぶ郑欲纳文公,故以三公子之徒作乱。 +初,献公使荀息傅奚齐,公疾,召之,曰:“以是藐诸孤,辱在大夫,其若之何?”稽首而对曰:“臣竭其股肱之力,加之以忠贞。其济,君之灵也;不济,则以死继之。”公曰:“何谓忠贞?”对曰:“公家之利,知无不为,忠也。送往事居,耦俱无猜。贞也。”及里克将杀奚齐,先告荀息曰:“三怨将作,秦、晋辅之,子将何如?”荀息曰:“将死之。”里克曰:“无益也。”荀叔曰:“吾与先君言矣,不可以贰。能欲复言而爱身乎?虽无益也,将焉辟之?且人之欲善,谁不如我?我欲无贰而能谓人已乎?” +冬十月,里克杀奚齐于次。书曰:“杀其君之子。”未葬也。荀息将死之,人曰:“不如立卓子而辅之。”荀息立公子卓以葬。十一月,里克杀公子卓于朝,荀息死之。君子曰:“诗所谓‘白圭之玷,尚可磨也;斯言之玷,不可为也,’荀息有焉。” +齐侯以诸侯之师伐晋,及高梁而还,讨晋乱也。令不及鲁,故不书。 +晋郤芮使夷吾重赂秦以求入,曰:“人实有国,我何爱焉。入而能民,土于何有。”从之。齐隰朋帅师会秦师,纳晋惠公。秦伯谓郤芮曰:“公子谁恃?”对曰:“臣闻亡人无党,有党必有仇。夷吾弱不好弄,能斗不过,长亦不改,不识其他。”公谓公孙枝曰:“夷吾其定乎?”对曰:“臣闻之,唯则定国。《诗》曰:‘不识不知,顺帝之则。’文王之谓也。又曰:‘不僭不贼,鲜不为则。’无好无恶,不忌不克之谓也。今其言多忌克,难哉!”公曰:“忌则多怨,又焉能克?是吾利也。” +宋襄公即位,以公子目夷为仁,使为左师以听政,于是宋治。故鱼氏世为左师。 +译文 +九年春季,宋桓公去世。还没有下葬,宋襄公就会见诸侯,所以《春秋》称他为“子”。凡是在丧事期间,天子称为“小童”,公侯称为“子”。 +夏季,鲁僖公和宰周公、齐桓公、宋桓公、卫文公、郑文公、许僖公、曹共公在葵丘会见,重温过去的盟约,同时发展友好关系,这是合于礼的。 +周襄王派宰孔把祭肉赐给齐桓公,说:“周天子祭祀文王、武王,派遣我把祭肉赐给伯舅。”齐桓公准备下阶拜谢。宰孔说:“还有以后的命令,天子派我说:‘因为伯舅年纪大了,加上功劳,奖赐一级,不用下阶拜谢。’”齐桓公回答说:“天子的威严就在前面,小白我岂敢受天子的命令而不下阶拜谢?不下拜,我惟恐在诸侯位上摔下来,给天子留下羞辱。岂敢不下阶拜谢?”齐桓公下阶拜谢,登上台阶接受祭肉。 +秋季,齐桓公和诸侯在葵丘会盟,说:“凡是我们一起结盟的人,既已盟誓之后,就回复到过去那样友好。”宰孔先行回国,遇到晋献公,说:“可以不去参加会盟了。齐桓公不致力于德行,而忙于远征,所以向北边攻打山戎,向南边攻打楚国,在西边就举行了这次会盟,向东边是否要有所举动,还不知道,攻打西边是不可能的。晋国恐怕会有祸乱吧!君王应该从事于安定国内的祸乱,不要急于前去。”晋献公听了这话,就回国了。 +九月,晋献公去世。里克邳(原为上不下十,下同)郑想要接纳文公为国君,所以就发动三位公子的党羽起来作乱。 +当初,晋献公曾让荀息辅助奚齐。当献公重病时,召见荀息说:“把这个弱小的孤儿付托给您,怎么样?”荀息叩头说:“下臣愿意竭尽力量,再加上忠贞。事情成功,那是君主在天的威灵;不成功,我就继之以死。”献公说:“什么叫忠贞?”荀息回答说:“国家的利益,知道了没有不做的,这是忠;送走过去的,奉事活着的,两方面都互不猜疑,这是贞。”等到里克将要杀掉奚齐,先期告诉荀息说:“三方面的怨恨都要发作了,秦国和晋国帮助他们,您打算怎么办?”荀息说:“打算死。”里克说:“没有好处!”荀息说:“我和先君说过了,不能改变。难道既想要实践诺言而又要爱惜己身吗?虽然没有好处,又能躲到哪里去呢?而且人们要求上进,谁不像我一样?我不想改变诺言,难道能够对别人说不要这样做吗?” +冬季,十月,里克在居丧的茅屋里杀了奚齐。《春秋》记载说:“杀其君之子”,称奚齐为“君之子”,是由于晋献公还没有下葬。荀息准备自杀,有人说:“不如立卓子为国君而辅助他。”荀息立了公子卓为国君而安葬了献公。十一月,里克又在朝廷上杀了公子卓。荀息就自杀了。君子说:“《诗》所说的‘白玉圭上的斑点,还可以磨掉;说话有了毛病,就不可以追回了。’荀息就是这样的啊!” +齐桓公带领诸侯的军队进攻晋国,到达高梁就回国。这是为了讨伐晋国发生的祸乱。命令没有到达鲁国,所以《春秋》没有记载。 +晋国的郤芮要夷吾给秦国馈送重礼,以请求秦国帮助他回国,并对夷吾说:“真要使别人占据了国家,我们有什么可爱惜的?回国而得到百姓,土地有什么了不起?”夷吾听从了。 +齐国的隰朋率领军队会合秦军而使晋惠公回国即位。 +秦穆公对郤芮说:“公子依靠谁?”郤芮回答说:“臣听说逃亡在外的人没有党羽,有了党羽必定就有仇敌。夷吾小时候不喜欢玩耍,能够争斗而不过分,年纪大了也不改变,其他我就不知道了。”秦穆公对公孙枝说:“夷吾可以安定国家吗?”公孙枝说:“臣听说:只有行为合乎准则,才能安定国家。《诗》说:‘无知无识,顺应了上帝的法则’,文王就是这样的。又说,‘不弄假,不伤残,很少不能做典范’,没有爱好,也没有厌恶,这就是说既不猜忌也不好强。现在他的话里边既猜忌又好强,要夷吾安定晋国,难呀!”秦穆公说:“猜忌就多怨恨,又哪里能够取胜?这是我国的利益啊。” +宋襄公做了国君,认为公子目夷仁爱,让他做左师来处理政事,宋国由此安定太平。所以目夷的后人鱼氏世世代代承袭左师的官。 + + +僖公十年 +【经】十年春王正月,公如齐。狄灭温,温子奔卫。晋里克弑其君卓及其大夫荀息。夏,齐侯、许男伐北戎。晋杀其大夫里克。秋七月。冬,大雨雪。 +【传】十年春,狄灭温,苏子无信也。苏子叛王即狄,又不能于狄,狄人伐之,王不救,故灭。苏子奔卫。 +夏四月,周公忌父、王子党会齐隰朋立晋侯。晋侯杀里克以说。将杀里克,公使谓之曰:“微子则不及此。虽然,子弑二君与一大夫,为子君者不亦难乎?”对曰:“不有废也,君何以兴?欲加之罪,其无辞乎?臣闻命矣。”伏剑而死。于是ぶ郑聘于秦,且谢缓赂,故不及。 +晋侯改葬共大子。 +秋,狐突适下国,遇大子,大子使登,仆,而告之曰:“夷吾无礼,余得请于帝矣。将以晋畀秦,秦将祀余。”对曰:“臣闻之,神不歆非类,民不祀非族。君祀无乃殄乎?且民何罪?失刑乏祀,君其图之。”君曰:“诺。吾将复请。七日新城西偏,将有巫者而见我焉。”许之,遂不见。及期而往,告之曰:“帝许我罚有罪矣,敝于韩。” +ぶ郑之如秦也,言于秦伯曰:“吕甥、郤称、冀芮实为不从,若重问以召之,臣出晋君,君纳重耳,蔑不济矣。” +冬,秦伯使冷至报问,且召三子。郤芮曰:“币重而言甘,诱我也。”遂杀ぶ郑、祁举及七舆大夫:左行共华、右行贾华、叔坚、骓颛、累虎、特宫、山祁,皆里、ぶ之党也。ぶ豹奔秦,言于秦伯曰:“晋侯背大主而忌小怨,民弗与也,伐之必出。”公曰:“失众,焉能杀。违祸,谁能出君。” +译文 +十年春季,狄人灭亡温国,这是由于苏子不讲信义。苏子背叛周襄王而投奔狄人,又和狄人处不来,狄人进攻他,周襄王不去救援,因此灭亡。苏子逃亡到卫国。 +夏季,四月,周公忌父、王子党会合齐国的隰朋立了晋惠公。晋惠公杀死里克表示讨好。将要杀掉里克以前,晋惠公派人对他说:“如果没有您,我就做不了晋君。尽管如此,您杀了两个国君一个大夫,做您国君的人,不也太难了吗?”里克回答说:“没有奚齐、卓子的被废,君王怎么能兴起?要给人加上罪名,还怕没有话说吗?下臣知道国君的意思了。”说完,用剑自杀而死。当时邳郑正在秦国聘问,也是为了推迟割让国土而去致歉,所以没有碰上这场灾祸。 +晋惠公改葬恭太子。 +秋季,狐突到陪都曲沃去,遇到太子申生。太子让他登车作为驾车的人,告诉他说:“公子夷吾无礼,我已经请求上帝并且得到同意,准备把晋国给予秦国,秦国将会祭祀我。”狐突回答说:“臣听说,神明不享受别的族的祭品,百姓也不祭祀别的族,您的祭祀恐怕会断绝了吧?而且百姓有什么罪?处罚不当而又祭祀断绝,请您考虑一下!”太子申生说:“好,我打算重新请求。过七天,新城西边将要有一个巫人表达我的意见。”狐突同意去见巫人,申生就一下子不见了。到时候前去,巫人告诉他说:“天帝允许我惩罚有罪的人,他将在韩地大败。” +邳郑去秦国的时候,对秦伯说:“吕甥、郤称、冀芮是不同意给秦国土地的。如果用重礼对他们表示问候而后召请他们,下臣赶走晋国国君,国王让重耳回国即位,这就没有不成功的。” +冬季,秦穆公派遣泠至到晋国回聘,并且召请吕甥、郤称、冀芮三人。郤芮说:“财礼重而说话好听,这是在引诱我们。”就杀了邳郑、祁举和七个舆大夫:左行共华、右行贾华、叔坚、骓歂、纍虎、特宫、山祁,都是里克邳郑的党羽。 +邳豹逃亡到秦国,对秦穆公说:“晋侯背叛大主而忌恨小怨,百姓不拥护他。如果进攻,百姓一定赶走他。”秦穆公说:“如果夷吾失去群众,哪里还能杀掉大臣?百姓都要逃难,谁能赶走国君?” + +僖公十一年 +【经】十有一年春。晋杀其大夫ぶ郑父。夏,公及夫人姜氏会齐侯于阳谷。秋八月,大雩。冬,楚人伐黄。 +【传】十一年春,晋侯使以ぶ郑之乱来告。 +天王使召武公、内史过赐晋侯命。受玉惰。过归,告王曰:“晋侯其无后乎。王赐之命而惰于受瑞,先自弃也已,其何继之有?礼,国之干也。敬,礼之舆也。不敬则礼不行,礼不行则上下昏,何以长世?” +夏,扬、拒、泉、皋、伊、洛之戎同伐京师,入王城,焚东门,王子带召之也。秦、晋、伐戎以救周。秋,晋侯平戎于王。 +黄人不归楚贡。冬,楚人伐黄。 +译文 +十一年春季,晋惠公派遣使者报告邳郑发动的叛乱。 +周襄王派遣召武公、内史过以荣宠赐给晋惠公。晋惠公接受瑞玉的时候精神不振作。内史过回去,向周襄王报告说:“晋侯的后代恐怕不能享有禄位了吧!天子以荣宠赐给他,他反而懒散地接受瑞玉,这就是先自暴自弃了,他还会有什么继承人?礼,是国家的躯干;敬,是载礼的车箱。不恭敬,礼就不能实施;礼不能实施,上下就昏乱,如何能长久?”夏季,扬、拒、泉、皋和伊洛的戎人一起进攻京城,进了王城,烧了东门,这是王子带召引来的。 +秦军、晋军攻打戎军来救援周朝。秋季,晋惠公让戎人和周襄王讲和。 +黄国人不向楚国进贡品。冬季,楚国人进攻黄国。 + +僖公十二年 +【经】十有二年春王三月庚午,日有食之。夏,楚人灭黄。秋七月。冬十有二月丁丑,陈侯杵臼卒。 +【传】十二年春,诸侯城卫楚丘之郛,惧狄难也。 +黄人恃诸侯之睦于齐也,不共楚职,曰:“自郢及我九百里,焉能害我?”夏,楚灭黄。   王以戎难故,讨王子带。秋,王子带奔齐。 +冬,齐侯使管夷吾平戎于王,使隰朋平戎于晋。 +王以上卿之礼飨管仲,管仲辞曰:“臣,贱有司也,有天子之二守国、高在。若节春秋来承王命,何以礼焉?陪臣敢辞。”王曰:“舅氏,余嘉乃勋,应乃懿德,谓督不忘。往践乃职,无逆朕命。”管仲受下卿之礼而还。君子曰:“管氏之世祀也宜哉!让不忘其上。《诗》曰:‘恺悌君子,神所劳矣。’” +译文 +十二年春季,诸侯在卫国的楚丘建筑外城,这是因为担心狄人来犯。黄人依靠诸侯和齐国和睦,不向楚国进贡,说:“从郢都到我国有九百里,楚国哪能危害我国?”夏季,楚国就灭亡了黄国。 +周襄王由于戎人骚扰的缘故,讨伐王子带。秋季,王子带逃亡到齐国。冬季,齐桓公派遣管仲让戎人和周襄王讲和,派隰朋让戎人和晋国讲和。 +周襄王以上卿的礼节设宴招待管仲。管仲辞谢说:“陪臣是低贱的官员。现在有天子所任命的国氏、高氏在那里,如果他们按春秋两季接受天子的命令,又用什么礼节来待他们呢?陪臣谨请辞谢。”天子说:“舅父,我赞美你的功勋,接受你的美德,这可以说是深厚而不能忘记的。去执行你的职务吧,不要违抗我的命令!”管仲最终还是接受了下卿的礼节而回国。君子说:“管氏世世代代受到祭祀是多么恰当啊!谦让而不忘记爵位比他高的上卿。《诗》说:‘和蔼平易的君子,就是神明所保佑的了。’” + +僖公十三年 +【经】十有三年春,狄侵卫。夏四月,葬陈宣公。公会齐侯、宋公、陈侯、郑伯、许男、曹伯于咸。秋九月,大雩。冬,公子友如齐。 +【传】十三年春,齐侯使仲孙湫聘于周,且言王子带。事毕,不与王言。归,覆命曰:“未可。王怒未怠,其十年乎。不十年,王弗召也。” +夏,会于咸,淮夷病杞故,且谋王室也。 +秋,为戎难故,诸侯戍周,齐仲孙湫致之。 +冬,晋荐饥,使乞籴于秦。秦伯谓子桑:“与诸乎?”对曰:“重施而报,君将何求?重施而不报,其民必携,携而讨焉,无众必败。”谓百里:“与诸乎?”对曰:“天灾流行,国家代有,救灾恤邻,道也。行道有福。” +ぶ郑之子豹在秦,请伐晋。秦伯曰:“其君是恶,其民何罪?”秦于是乎输粟于晋,自雍及绛相继,命之曰泛舟之役。 +译文 +十三年春季,齐桓公派遣仲孙湫到成周聘问,同时要他说起王子带的事情。聘问完了,仲孙湫不和周襄王谈起王子带。回国,向齐桓公汇报说:“还不行。周襄王的怒气没有消除,恐怕要等十年了。不到十年周王是不会召他回去的。” +夏季,鲁僖公和齐桓公、宋襄公、陈穆公、卫文公、郑文公、许僖公、曹共公在咸地会见,一则由于淮夷让杞国感到担心,同时也由于商量使周王朝安定。 +秋季,为了戎人造成的祸难,诸侯派兵防守成周。齐国的仲孙湫也带领军队前去。 +冬季,晋国再次发生饥荒,派人到秦国请求购买粮食。秦穆公对子桑说:“给他们吗?”子桑回答说:“再一次给他们恩惠而报答我们,君王还要求什么?再一次给他们恩惠而不报答我们,他们的老百姓必然离心;离心以后再去讨伐,他没有群众就必然失败。”秦穆公对百里说:“给他们吗?”百里回答说:“天灾流行,总会在各国交替发生的。救援灾荒,周济邻国,这是正道。按正道办事会有福禄。”邳郑的儿子豹在秦国,请求进攻晋国。秦穆公说:“厌恶他们的国君,百姓有什么罪?”秦国就这样把粟米运送到晋国,船队从雍城到绛城接连不断,人们把这次运粮称为“泛舟之役”。 + + +僖公十四年 +【经】十有四年春,诸侯城缘陵。夏六月,季姬及鄫子遇于防。使鄫子来朝。秋八月辛卯,沙鹿崩。狄侵郑。冬,蔡侯肝卒。 +【传】十四年春,诸侯城缘陵而迁杞焉。不书其人,有阙也。 +鄫季姬来宁,公怒,止之,以鄫子之不朝也。夏,遇于防,而使来朝。 +秋八月辛卯,沙鹿崩。晋卜偃曰:“期年将有大咎,几亡国。” +冬,秦饥,使乞籴于晋,晋人弗与。庆郑曰:“背施无亲,幸灾不仁,贪爱不祥,怒邻不义。四德皆失,何以守国?”虢射曰:“皮之不存,毛将安傅?”庆郑曰:“弃信背邻,患孰恤之?无信患作,失授必毙,是则然矣。”虢射曰:“无损于怨而厚于寇,不如勿与。”庆郑曰:“背施幸灾,民所弃也。近犹仇之,况怨敌乎?”弗听。退曰:“君其悔是哉!” +译文 +十四年春季,诸侯在缘陵筑城而把杞都迁去。《春秋》没有记载筑城的是哪些国家,是由于文字有缺。 +鄫季姬回鲁国娘家,僖公发怒,留住她不准回去,这是因为鄫子不来朝见的缘故。夏季,鄫季姬和鄫子在防地见面,要鄫子前来朝见。 +秋季,八月初五日,沙鹿山崩塌。晋国的卜偃说:“一周年将会有大灾难,几乎要亡国。” +冬季,秦国发生饥荒,派人到晋国请求购买粮食。晋国人不给。庆郑说:“背弃恩惠就没有亲人,幸灾乐祸就是不仁,贪图所爱惜的东西就是不祥,使邻国愤怒就是不义。这四种道德都丢掉了,用什么来保卫国家?”虢射说:“皮已经不存在,毛又依附在哪里?”庆郑说:“丢弃信用,背弃邻国,患难谁来周济?没有信用就会发生患难,失掉了救援,必定灭亡。这就是那样的。”虢射说:“即使给粮食,对怨恨不会有所减少,反而使敌人增加实力,不如不给。”庆郑说:“背弃恩惠,幸灾乐祸,是百姓所唾弃的。亲近的人还会因此结仇,何况是敌人呢?”晋惠公不听。庆郑退下来说:“国君要后悔的!” + +僖公十五年 +【经】十有五年春王正月,公如齐。楚人伐徐。三月,公会齐侯、宋公、陈侯、卫候、郑伯、许男、曹伯盟于牡丘,遂次于匡。公孙敖帅师及诸侯之大夫救徐。夏五月,日有食之。秋七月,齐师、曹师伐厉。八月,螽。九月,公至自会。季姬归于鄫。己卯晦,震夷伯之庙。冬,宋人伐曹。楚人败徐于娄林。十有一月壬戌,晋侯及秦伯战于韩,获晋侯。 +【传】十五年春,楚人伐徐,徐即诸夏故也。三月,盟于牡丘,寻蔡丘之盟,且救徐也。孟穆伯帅师及诸侯之师救徐,诸侯次于匡以待之。 +夏五月,日有食之。不书朔与日,官失之也。 +秋,伐,厉,以救徐也。 +晋侯之入也,秦穆姬属贾君焉,且曰:“尽纳群公子。”晋侯烝于贾君,又不纳群公子,是以穆姬怨之。晋侯许赂中大夫,既而皆背之。赂秦伯以河外列城五,东尽虢略,南及华山,内及解梁城,既而不与。晋饥,秦输之粟;秦饥,晋闭之籴,故秦伯伐晋。 +卜徒父筮之,吉。涉河,侯车败。诘之,对曰:“乃大吉也,三败必获晋君。其卦遇《蛊》,曰:‘千乘三去,三去之馀,获其雄狐。’夫狐蛊,必其君也。《蛊》之贞,风也;其悔,山也。岁云秋矣,我落其实而取其材,所以克也。实落材亡,不败何待?” +三败及韩。晋侯谓庆郑曰:“寇深矣,若之何?”对曰:“君实深之,可若何?”公曰:“不孙。”卜右,庆郑吉,弗使。步扬御戎,家仆徒为右,乘小驷,郑入也。庆郑曰:“古者大事,必乘其产,生其水土而知其人心,安其教训而服习其道,唯所纳之,无不如志。今乘异产,以从戎事,及惧而变,将与人易。乱气狡愤,阴血周作,张脉偾兴,外强中乾。进退不可,周旋不能,君必悔之。”弗听。 +九月,晋侯逆秦师,使韩简视师,复曰:“师少于我,斗士倍我。”公曰:“何故?”对曰:“出因其资,入用其宠,饥食其粟,三施而无报,是以来也。今又击之,我怠秦奋,倍犹未也。”公曰:“一夫不可狃,况国乎。”遂使请战,曰:“寡人不佞,能合其众而不能离也,君若不还,无所逃命。”秦伯使公孙枝对曰:“君之未入,寡人惧之,入而未定列,犹吾忧也。苟列定矣,敢不承命。”韩简退曰:“吾幸而得囚。” +壬戌,战于韩原,晋戎马还泞而止。公号庆郑。庆郑曰:“愎谏违卜,固败是求,又何逃焉?”遂去之。梁由靡御韩简,虢射为右,辂秦伯,将止之。郑以救公误之,遂失秦伯。秦获晋侯以归。晋大夫反首拔舍从之。秦伯使辞焉,曰:“二三子何其戚也?寡人之从君而西也,亦晋之妖梦是践,岂敢以至。”晋大夫三拜稽首曰:“君履后土而戴皇天,皇天后土实闻君之言,群臣敢在下风。” +穆姬闻晋侯将至,以大子荦、弘与女简、璧登台而履薪焉,使以免服衰絰逆,且告曰:“上天降灾,使我两君匪以玉帛相见,而以兴戎。若晋君朝以入,则婢子夕以死;夕以入,则朝以死。唯君裁之。”乃舍诸灵台。 +大夫请以入。公曰:“获晋侯,以厚归也。既而丧归,焉用之?大夫其何有焉?且晋人戚忧以重我,天地以要我。不图晋忧,重其怒也;我食吾言,背天地也。重怒难任,背天不祥,必归晋君。”公子絷曰:“不如杀之,无聚慝焉。”子桑曰:“归之而质其大子,必得大成。晋未可灭而杀其君,只以成恶。且史佚有言曰:‘无始祸,无怙乱,无重怒。’重怒难任,陵人不祥。”乃许晋平。 +晋侯使郤乞告瑕吕饴甥,且召之。子金教之言曰:“朝国人而以君命赏,且告之曰:‘孤虽归,辱社稷矣。其卜贰圉也。’”众皆哭。晋于是乎作爰田。吕甥曰:“君亡之不恤,而群臣是忧,惠之至也。将若君何?”众曰:“何为而可?”对曰:“征缮以辅孺子,诸侯闻之,丧君有君,群臣辑睦,甲兵益多,好我者劝,恶我者惧,庶有益乎!”众说。晋于是乎作州兵。 +初,晋献公筮嫁伯姬于秦,遇《归妹》三之《睽》三。史苏占之曰:“不吉。其繇曰:‘士刲羊,亦无亡也。女承筐,亦无贶也。西邻责言,不可偿也。《归妹》之《睽》,犹无相也。’《震》之《离》,亦《离》之《震》,为雷为火。为嬴败姬,车说问其輹,火焚其旗,不利行师,败于宗丘。《归妹》《睽》孤,寇张之弧,侄其从姑,六年其逋,逃归其国,而弃其家,明年其死于高梁之虚。”及惠公在秦,曰:“先君若从史苏之占,吾不及此夫。”韩简侍,曰:“龟,像也;筮,数也。物生而后有象,像而后有滋,滋而后有数。先君之败德,乃可数乎?史苏是占,勿从何益?《诗》曰:‘下民之孽,匪降自天,僔沓背憎,职竞由人。’” +震夷伯之庙,罪之也,于是展氏有隐慝焉。 +冬,宋人伐曹,讨旧怨也。 +楚败徐于娄林,徐恃救也。 +十月,晋阴饴甥会秦伯,盟于王城。 +秦伯曰:“晋国和乎?”对曰:“不和。小人耻失其君而悼丧其亲,不惮征缮以立圉也,曰:‘必报仇,宁事戎狄。’君子爱其君而知其罪,不惮征缮以待秦命,曰:‘必报德,有死无二。’以此不和。”秦伯曰:“国谓君何?”对曰:“小人戚,谓之不免。君子恕,以为必归。小人曰:‘我毒秦,秦岂归君?’君子曰:‘我知罪矣,秦必归君。贰而执之,服而舍之,德莫厚焉,刑莫威焉。服者怀德,贰者畏刑。此一役也,秦可以霸。纳而不定,废而不立,以德为怨,秦不其然。’”秦伯曰:“是吾心也。”改馆晋侯,馈七牢焉。 +蛾析谓庆郑曰:“盍行乎?”对曰:“陷君于败,败而不死,又使失刑,非人臣也。臣而不臣,行将焉入?”十一月,晋侯归。丁丑,杀庆郑而后入。   是岁,晋又饥,秦伯又饩之粟,曰:“吾怨其君而矜其民。且吾闻唐叔之封也,箕子曰:‘其后必大。’晋其庸可冀乎!姑树德焉以待能者。”于是秦始征晋河东,置官司焉。 +译文 +十五年春季,楚国人进攻徐国,由于徐国依靠中原诸侯的缘故。三月,鲁僖公和齐桓公、宋襄公、陈穆公、卫文公、郑文公、许僖公、曹共公在牡丘结盟,重温葵丘的盟约,同时为了救援徐国。孟穆伯率领鲁军和诸侯的军队救援徐国,诸侯住在匡地等待他。 +夏季,五月,发生日食。《春秋》没有记载朔日和日期,由于史官的漏记。 +秋季,进攻厉国,以此来救援徐国。 +晋惠公回国继承君位的时候,秦穆姬把贾君嘱托给他,而且说:“把公子们都接回国内。”晋惠公和贾君通奸,又不接纳公子们回国,由此穆姬就怨恨他。晋惠公曾经答应给中大夫送礼,后来也都不给了。还答应给秦穆公黄河以西和以南的五座城,东边到虢略镇,南边到华山,还有黄河之内的解梁城,后来都不兑现。晋国有饥荒,秦国给它运送粟米;秦国有饥荒,晋国却拒绝秦国买粮,所以秦穆公攻打晋国。 +卜徒父用筮草占卜,吉利:“渡过黄河,毁坏侯的车子。”秦穆公仔细追问,卜徒父回答说:“这是大吉大利。晋军连败三次,晋国国君必然被俘获。这一卦得到《蛊》,繇辞说:‘三次驱除一千辆兵车,三次驱除之余,获得了那条雄狐。’雄狐指的一定是他们的国君。《蛊》的内卦是风,外卦是山。时令到了秋天了,我们的风吹过他们山上,吹落了他们的果实,还取得他们的木材,所以能战胜。果实落地而木材丢失,不打败仗还等待什么?”晋军三次战败,退到韩地。晋惠公对庆郑说:“敌人深入了,怎么办?”庆郑回答说:“君王让他们深入的,能够怎么办?”晋惠公说:“答话放肆无礼!”占卜车右的人选,庆郑得吉卦。但是晋惠公不用他,让步扬驾御战车,家仆徒作为车右。以小驷马驾车,是从郑国来的。庆郑说:“古代发生战争,一定要用本国的马驾车。出生在自己的水土上,知道主人的心意;安于受主人的调教,熟悉这里的道路;随你放在哪里,没有不如意的。现在用外国出产的马来驾车,从事战斗,等到一害怕而失去正常状态,就会不听指挥了。鼻子里乱喷粗气表示狡猾和愤怒,血液在全身奔流,使血管扩张突起,外表强壮而内部枯竭。进也不能,退也不是,旋转也不能,君王必然要后悔。”晋惠公不听。 +九月,晋惠公将要迎战秦军,派韩简视察军队。韩简回来说:“军队比我们少,能奋力作战的人却倍于我们。”晋惠公说:“什么原因?”韩简回答说:“君王逃离晋国是由于他的资助,回国是由于他的宠信,有了饥荒吃他的粟米,三次给我们恩惠而没有报答,由于这样他们才来的。现在又将迎击他们,我方懈怠,秦国奋发,斗志岂止相差一倍啊!”晋惠公说:“一个人还不能轻侮,何况是国家呢?”于是就派韩简去约战,说:“寡人不才,能集合我的部下而不能让他们离散。君王如果不回去,我们将没有地方逃避命令。”秦穆公派公孙枝回答说:“晋君没有回国,我为他忧惧;回国后没有安定位置,还是我所担心的。如果君位已定,寡人敢不接受作战的命令?”韩简退下去说:“我如果能被俘囚禁就是幸运的。” +十四日,秦、晋两军在韩原作战。晋惠公的小驷马陷在烂泥中盘旋不出。晋惠公向庆郑呼喊求救。庆郑说:“不听劝谏,违抗占卜,本来就是自取失败,为什么又要逃走呢?”于是就离开了。梁由靡驾韩简的战车,虢射作为车右,迎战秦穆公的战车,将要俘虏他。庆郑因为叫他们救援晋惠公而耽误,就使秦穆公走脱了。秦国俘虏了晋惠公。晋国的大夫披头散发,拔出帐篷,跟随晋惠公。秦穆公派使者辞谢说:“你们几位为什么那样忧愁啊!寡人跟随晋国国君往西去,只不过实现晋国的妖梦罢了,难道敢做得太过分吗?”晋国的大夫三拜叩头说:“君王踩着后土,而顶着皇天,皇天后土都听到了您的话,下臣们谨在下边听候吩咐。” +秦穆姬听说晋惠公将要来到,领着太子莹、儿子弘和女儿简璧登上高台,踩着柴草。她派遣使者捧着遭丧所着丧服前去迎接秦穆公,说:“上天降下灾祸,让我两国国君不是用礼品相见而是兴动甲兵。如果晋国国君早晨进入国都,那么我就晚上自焚;晚上进入,那么我就早晨自焚。请君王裁夺。” +于是秦穆公把晋惠公拘留在灵台。大夫请求把晋惠公带回国都。秦穆公说:“俘获晋侯,本来是带着丰厚的收获回来的,但一回来就要发生丧事,这有什么用?大夫又能得到什么呢?而且晋国人用忧愁来感动我,用天地来约束我,如果不考虑晋国人的忧愁,就会加深他们对秦国的愤怒。我如果不履行自己的诺言,就是违背天地,加深愤怒会使我担当不起,违背天地会不吉利,一定要放晋君回国。”公子絷说:“不如杀了他,不要积聚邪恶。”子桑说:“放他回国而用他的太子作为人质,必然会得到很有利的讲和条件。晋国还不会灭亡,而杀掉它的国君,只能造成很坏的后果。而且史佚有话说:‘不要发动祸患,不要依靠动乱,不要增加愤怒。’增加愤怒会使人难于担当,欺凌别人会不吉利。”于是就允许晋国讲和。 +晋惠公派遣郤乞告诉瑕吕饴甥,同时召他前来,饴甥教郤乞该怎么说话,说:“把都城里的人都召到宫门前而用国君的名义给予赏赐。而且告诉他们说:“我虽然回国了,但已经给国家带来了耻辱,还是占卜一个吉日,让我的继承人圉就国君之位吧。’”郤乞回去照办,大家一齐号哭。晋国就在这时开始改易田制,开阡陌从新规定田界。吕饴甥说:“国君不为自己在外而担忧,反而为群臣担忧,这是最大的恩惠了,我们准备怎样对待国君?”大家说:“怎么办才行呢?”吕饴甥回答说:“征收赋税,修理装备武器,以辅助继承人。诸侯听到我国失去了国君,又有新的国君,群臣和睦,装备武器比以前更多。喜欢我们的就会勉励我们,讨厌我们的就会有所害怕,也许会有好处吧!”大家很高兴,晋国因为这样而开始兵制改革。 +当初,晋献公为嫁伯姬给秦国而占筮,得到《归妹》变成《睽》卦。史苏预测说:“不吉利。卦辞说:‘男人宰羊,不见血浆;女人拿筐,白忙一场。西邻责备,不可补偿。《归妹》变《睽》,没人相帮。’《震》卦变成《离》卦,也就是《离》卦变成《震》卦。‘又是雷,又是火,胜者姓嬴,败者姓姬。车子脱离车轴,大火烧掉军旗,不利于出师,在宗丘打得大败。《归妹》嫁女,《睽》离单孤,敌人的木弓将要张舒。侄子跟着姑姑,六年之后,逃回自己所居,抛弃了他的家,明年死在高梁的废墟。’”等到惠公在秦国,说:“先君如果听从了史苏的占卜,我不会到这个地步!”韩简随侍在侧,说:“龟甲,是形象;筮草,是数字。事物生长以后才有形象,有形象以后才能滋长,滋长以后才有数字。先君败坏的道德,难道可以数得完吗?史苏的占卜,即使听从了,又有什么好处?《诗》说:‘百姓的灾祸,不是从天下降。当面附和,背后毁谤,主要都由于人的无状。’” +雷击夷伯的庙宇,这是降罪于他,由于可以看到展氏有别人不知道的隐恶。 +冬季,宋国人进攻曹国,为了报复以前结下的怨恨。楚国在娄林打败徐国,徐国所以失败,是由于专靠别国去救援。十月,晋国的阴饴甥会见秦穆公,在王城订立盟约。 +秦穆公说:“晋国和睦吗?”阴饴甥回答悦:“不和睦。小人以失掉国君为耻辱,而哀悼失去了的亲属,不怕筹集资金,重整军队而立圉为国君,说:“一定报仇,宁可因此而事奉戎狄。’君子爱护国君而知道他的罪过,不怕筹集资金,重整军队来等待秦国的命令,说:‘一定要报答恩德,有必死之志而无二心。’因为这样才不和睦。”秦穆公说:“全国认为国君的前途会怎么样?”阴饴甥回答说:“小人忧愁,认为他不会被赦免;君子宽恕,以为他一定会回来。小人说:‘我们得罪了秦国,秦国怎么能让国君回来?’君子说:‘我们已经认罪了,秦国一定让国君回来。有三心二意,就抓起来;服了罪,就释放他。德行没有比这再宽厚的了,刑罚没有比这再威严的了。服罪的怀念德行,有三心二意的害怕刑罚,这一战役,秦国可以称霸诸侯。让他回国而不使之安定,甚至废掉他而不立他为国君,使恩惠变为怨恨,秦国不会这样做的吧!’”秦穆公说:“我正是这样想的。”于是改变对晋惠公的待遇,让他住在宾馆里,馈送了七副牛、羊、猪等食用物品。蛾析对庆郑说:“何不逃走呢?”庆郑回答说:“使国君陷于失败,失败了不死反而逃亡,又让国君失去刑罚,这就不是做臣下的样子。臣下而不合于臣道,又能逃到哪里去?”十一月,晋惠公回国。二十九日,杀了庆郑,然后进入国都。 +这一年,晋国又发生饥荒,秦穆公赠送给他们粟米,说:“我怨恨他们的国君,而怜悯他们的百姓。而且我听说唐叔受封的时候,箕子说:‘他的后代一定昌大。’晋国是可以图谋的吗!我们姑且树立恩惠,来等待有才能的人。”于是,秦国就开始在晋国黄河东部征收赋税,设置官员。 + + +僖公十六年 +【经】十有六年春王正月戊申朔,陨石于宋五。是月,六鷁退飞,过宋都。三月壬申,公子季友卒。夏四月丙申,鄫季姬卒。秋七月甲子,公孙兹卒。冬十有二月,公会齐侯、宋公、陈侯、卫侯、郑伯、许男、邢侯、曹伯于淮。 +【传】十六年春,陨石于宋五,陨星也。六鷁退飞过宋都,风也。周内史叔兴聘于宋,宋襄公问焉,曰;“是何祥也?吉凶焉在?”对曰:“今兹鲁多大丧,明年齐有乱,君将得诸侯而不终。”退而告人曰:“君失问。是阴阳之事,非吉凶所生也。吉凶由人,吾不敢逆君故也。” +夏,齐伐厉不克,救徐而还。 +秋,狄侵晋,取狐、厨、受铎,涉汾,及昆都,因晋败也。 +王以戎难告于齐,齐征诸侯而戍周。 +冬,十一月乙卯,郑杀子华。 +十二月会于淮,谋郐,且东略也。城鄫,役人病。有夜登丘而呼曰:“齐有乱。”不果城而还。 +译文 +十六年春季,在宋国上空坠落五块石头,这是坠落的星星。六只鹢鸟后退着飞,经过宋国国都,这是由于风太大的缘故。成周的内使叔兴在宋国聘问,宋襄公询问这两件事,说:“这是什么预兆?吉凶在于哪里?”叔兴回答说:“今年鲁国多有大的丧事,明年齐国有动乱,君王将会得到诸侯拥护却不能保持到最后。”退下来告诉别人说:“国君询问得不恰当,这是有关阴阳的事情,人事吉凶与此无关。吉凶由人的行为所决定。我这样回答是由于不敢违背国君的缘故。” +夏季,齐国进攻厉国,没有得胜,救援了徐国而后回国。 +秋季,狄人攻打晋国,占取了狐、厨、受铎,渡过汾水,到达昆都,因为晋国战败了。 +周襄王把戎人造成的祸难告诉齐国。齐国调集诸侯的军队到成周去防守。 +冬季,十一月十二日,郑国杀了子华。十二月,鲁僖公和齐桓公、宋襄公、陈穆公、卫文公、郑文公、许僖公、邢侯、曹共公在淮地会见,是为了商量救援鄫国免被淮夷所侵。并且商量向东方用兵。替鄫国筑城,服劳役的人困乏,有人夜里登上小山头喊叫说:“齐国发生动乱!”诸侯没有等到筑完城就各自回国了。 + +僖公十七年 +【经】十有七年春,齐人、徐人伐英氏。夏,灭项。秋,夫人姜氏会齐侯于卞。九月,会至自会。冬十有二月乙亥,齐侯小白卒。 +【传】十七年春,齐人为徐伐英氏,以报娄林之役也。 +夏,晋大子圉为质于秦,秦归河东而妻之。惠公之在梁也,梁伯妻之。梁赢孕,过期,卜招父与其子卜之。其子曰:“将生一男一女。”招曰:“然。男为人臣,女为人妾。”故名男曰圉,女曰妾。及子圉西质,妾为宦女焉。 +师灭项。淮之会,公有诸侯之事未归而取项。齐人以为讨,而止公。 +秋,声姜以公故,会齐侯于卞。九月,公至。书曰:“至自会。”犹有诸侯之事焉,且讳之也。 +齐侯之夫人三:王姬,徐嬴,蔡姬,皆无子。齐侯好内,多内宠,内嬖如夫人者六人:长卫姬,生武孟;少卫姬,生惠公;郑姬,生孝公;葛嬴,生昭公;密姬,生懿公,宋华子,生公子雍。公与管仲属孝公于宋襄公,以为太子。雍巫有宠于卫共姬,因寺人貂以荐羞于公,亦有宠,公许之立武孟。 +管仲卒,五公子皆求立。冬十月乙亥,齐桓公卒。易牙入,与寺人貂因内宠以杀群吏,而立公子无亏。孝公奔宋。十二月乙亥赴。辛巳夜殡。 +译文 +十七年春季,齐国人为徐国攻打英氏,以报复前二年楚击败徐于娄林那一次战役。 +夏季,晋国的太子圉在秦国作人质,秦国把河东土地归还晋国并把女儿嫁给圉。晋惠公在梁国的时候,梁伯把女儿嫁给他。梁嬴怀孕,过了预产期。卜招父和他的儿子占卜,他的儿子说:“将要生一男一女。”卜招父说:“对。男的做别人的奴仆,女的做别人的奴婢。”所以把男的叫做圉,女的取名叫做妾。等到子圉到西方作人质,妾就在秦国作了侍女。 +鲁国军队灭亡项国。在淮地的会见,僖公正有和各国诸侯相会的大事,没有回国,鲁军就占取了项国。齐国人认为这是由僖公下令进攻,因此把僖公拘留,不让他回国。 +秋季,声姜由于僖公的缘故,在卞地会见齐桓公。九月,僖公到达。《春秋》记载说“至自会”,这是由于国家大事还没有处理完,而且不愿说出被拘留这件事。 +齐桓公的三位夫人,王姬、徐嬴、蔡姬,都没有儿子。齐桓公喜欢女色,宠爱的姬妾不少,宫内受宠的女人待遇如同夫人一样的有六人:大卫姬,生了武孟;小卫姬,生了惠公;郑姬,生了孝公;葛嬴,生了昭公;密姬,生了懿公;宋华子,生了公子雍。桓公和管仲把孝公托付给宋襄公,以他为太子。雍巫受到卫共姬的宠信,由于寺人貂的关系把美味的食品进献给齐桓公,又受到齐桓公的宠信。齐桓公答应他们立武孟为继承人。管仲死,五个公子都谋求立为嗣君。 +冬季,十月初七日,齐桓公死。易牙进宫,和寺人貂依靠那些内宠的权贵而杀死一批官吏,立公子无亏为国君。孝公逃亡到宋国。十二月初八日,发出讣告。十四日夜间,将桓公尸体大殓入棺。 + + +僖公十八年 +【经】十有八年春王正月,宋公、曹伯、卫人、邾人伐齐。夏,师救齐。五月戊寅,宋师及齐师战于甗。齐师败绩。狄救齐。秋八月丁亥,葬齐桓公。冬,邢人,狄人伐卫。 +【传】十八年春,宋襄公以诸侯伐齐。三月,齐人杀无亏。 +郑伯始朝于楚,楚子赐之金,既而悔之,与之盟曰:“无以铸兵。”故以铸三钟。 +齐人将立孝公,不胜,四公子之徒遂与宋人战。夏五月,宋败齐师于,立孝公而还。 +秋八月,葬齐桓公。 +冬,邢人、狄人伐卫,围菟圃。卫侯以国让父兄子弟及朝众曰:“苟能治之,毁请从焉。”众不可,而后师于訾娄。狄师还。 +梁伯益其国而不能实也,命曰新里,秦取之。 +译文 +十八年春季,宋襄公率领曹共公等攻打齐国。三月,齐国人杀了无亏。 +郑文公开始到楚国朝见。楚成王把铜赐给他,不久又后悔,和他盟誓说:“不要拿来铸造武器。”所以郑文公用它铸造了三座钟。 +齐国人准备立孝公为国君,挡不住四公子一伙的反对,孝公逃亡到宋国,四公子一伙就和宋军作战。夏季,五月,宋国在甗地打败了齐国,立了孝公,然后回国。 +秋季,八月,安葬齐桓公。 +冬季,邢人、狄人进攻卫国,包围了菟圃。卫文公把国君的地位推让给父兄子弟和朝廷上的其他人,说:“谁如果能治理国家,我就跟从他。”大家不同意,而后在訾娄摆开阵势。狄军就退回去了。梁伯扩充了疆土,筑了很多城邑,却不能把百姓迁往那里,把那地方命名为新里,但被秦国占取了。 + +僖公十九年 +【经】十有九年春王三月,宋人执滕子婴齐。夏六月,宋公、曹人、邾人盟于曹南。鄫子会盟于邾。己酉,邾人执郐子,用之。秋,宋人围曹。卫人伐邢。冬,会陈人、蔡人、楚人、郑人盟于齐。梁亡。 +【传】十九年春,遂城而居之。 +宋人执滕宣公。 +夏,宋公使邾文公用鄫子于次睢之社,欲以属东夷。司马子鱼曰:“古者六畜不相为用,小事不用大牲,而况敢用人乎?祭祀以为人也。民,神之主也。用人,其谁飨之?齐桓公存三亡国以属诸侯,义士犹曰薄德。今一会而虐二国之君,又用诸淫昏之鬼,将以求霸,不亦难乎?得死为幸!” +秋,卫人伐邢,以报菟圃之役。于是卫大旱,卜有事于山川,不吉。宁庄子曰:“昔周饥,克殷而年丰。今邢方无道,诸侯无伯,天其或者欲使卫讨邢乎?”从之,师兴而雨。 +宋人围曹,讨不服也。子鱼言于宋公曰:“文王闻崇德乱而伐之,军三旬而不降,退修教而复伐之,因垒而降。《诗》曰:‘刑于寡妻,至于兄弟,以御于家邦。’今君德无乃犹有所阙,而以伐人,若之何?盍姑内省德乎?无阙而后动。” +陈穆公请修好于诸侯,以无忘齐桓之德。冬,盟于齐,修桓公之好也。 +梁亡,不书其主,自取之也。初,梁伯好土功,亟城而弗处,民罢而弗堪,则曰:“某寇将至。”乃沟公宫,曰:“秦将袭我。”民惧而溃,秦遂取梁。 +译文 +十九年春季,秦国人就筑了城而移民居住在新里。宋人抓住了滕宣公。 +夏季,宋襄公让邾文公杀死鄫子来祭祀次睢的土地神,想因此使东夷来降附。司马子鱼说:“古时候六种畜牲不能相互用来祭祀,小的祭祀不杀大牲口,何况敢于用人作牺牲呢?祭祀是为了人。百姓,是神的主人。杀人祭祀,有什么神来享用?齐桓公恢复了三个被灭亡的国家以使诸侯归附,义士还说他薄德,现在一次会盟而侵害两个国家的国君,又用来祭祀邪恶昏乱的鬼神,要拿这个来求取霸业,不也是很难吗?得以善终就算幸运了。” +秋季,卫军进攻邢国,以报复菟圃这一役。这时卫国大旱,为祭祀山川而占卜,不吉利。甯庄子说:“从前周室发生饥荒,打败了商朝就丰收。现在正当邢国无道,诸侯没有领袖,上天或者是要让卫国进攻邢国吧!”听从了他的话,征集军队就下了雨。 +宋军包围曹国,为了讨伐曹国的不肯顺服。子鱼对宋公说:“文王听到崇国德行昏乱而去攻打,打了三十天,崇国不投降。退兵回国,修明教化,再去攻打,文王就驻扎在过去所筑的营垒里,崇国就投降了。《诗》说:‘在嫡妻面前作出示范,由此而作为兄弟们的表率,以此来治理一家一国。’现在君王的德行恐怕还有所欠缺,而以此攻打曹国,能把它怎么办?何不姑且退回去自己检查一下德行,等到没有欠缺了再采取行动。” +陈穆公请求在诸侯间重新建立友好关系,表示不忘齐桓公的德行。冬季,在齐国会盟,重新建立齐桓公时代的友好关系。 +梁国灭亡了,《春秋》没有记载灭亡梁国的是谁,是因为祸害是梁国自己找取的。当初,梁伯喜好大兴土木,屡次筑城而无人居住,百姓疲倦得不能忍受,就说:“某某敌人要来了。”于是在国君的宫室外挖沟,说:“秦国将要袭击我国。”百姓害怕而溃散,秦国就趁机占取了梁国。 + +僖公二十年 +【经】二十年春,新作南门。夏,郜子来朝。五月乙巳,西宫灾。郑人入滑。秋,齐人、狄人盟于邢。冬,楚人伐随。 +【传】二十年春,新作南门。书,不时也。凡启塞从时。 +滑人叛郑而服于卫。夏,郑公子士、泄堵寇帅师入滑。 +秋,齐、狄盟于邢,为邢谋卫难也。于是卫方病邢。 +随以汉东诸侯叛楚。冬,楚斗谷于菟帅师伐随,取成而还。君子曰:“随之见伐,不量力也。量力而动,其过鲜矣。善败由己,而由人乎哉?《诗》曰:‘岂不夙夜,谓行多露。’” +宋襄公欲合诸侯,臧文仲闻之,曰:“以欲从人,则可;以人从欲,鲜济。” +译文 +二十年春季,重新建造南门。《春秋》记载这件事,是由于妨碍农时。凡是修筑城门和制作门闩,应该不妨碍农时。 +滑国人背叛郑国而顺服于卫国。夏季,郑国的公子士、泄堵寇率领军队攻入滑国。 +秋季,齐国和狄人在邢国相会并订立盟约,为邢国策划对付卫国的侵袭。这时候卫国才担心邢国。 +随国依靠汉水东边各诸侯的力量背叛楚国。冬季,楚国的鬬穀於菟率领军队进攻随国,讲和以后回国。君子说:“随国被攻打,是由于不估量自己的国力。估量自己的力量然后动作,祸害就少了。成败在于自己,难道在于别人?《诗》说:‘难道不想早晚奔波,无奈路上露水太多。’” +宋襄公想要会合诸侯。臧文仲听到了,说:“拿自己的愿望服从别人就可以,要使别人服从自己的愿望就很少有成功的。” + +僖公二十一年 +【经】二十有一年春,狄侵卫。宋人、齐人、楚人盟于鹿上。夏,大旱。秋,宋公、楚子、陈侯、蔡侯、郑伯、许男、曹伯会于盂。执宋公以伐宋。冬,公伐邾。楚人使宜申来献捷。十有二月癸丑,公会诸侯盟于薄。释宋公。 +【传】二十一年春,宋人为鹿上之盟,以求诸侯于楚。楚人许之。公子目夷曰:“小国争盟,祸也。宋其亡乎,幸而后败。” +夏,大旱。公欲焚巫兀。臧文仲曰:“非旱备也。修城郭,贬食省用,务穑劝分,此其务也。巫兀何为?天欲杀之,则如勿生;若能为旱,焚之滋甚。”公从之。是岁也,饥而不害。 +秋,诸侯会宋公于盂。子鱼曰:“祸其在此乎!君欲已甚,其何以堪之?”于是楚执宋公以伐宋。 +冬,会于薄以释之。子鱼曰:“祸犹未也,未足以惩君。” +任、宿、须句、颛臾,风姓也。实司大皞与有济之祀,以服事诸夏。邾人灭须句,须句子来奔,因成风也。成风为之言于公曰:“崇明祀,保小寡,周礼也;蛮夷猾夏,周祸也。若封须句,是崇皞、济而修祀,纾祸也。” +译文 +二十一年春季,宋国和齐国人、楚国人在鹿上举行了会盟,便向楚国要求当时归附楚国的中原诸侯奉自己为盟主,楚国人答应了。公子目夷说:“小国争当盟主,这是灾祸。宋国或许会被灭亡吧!失败得晚一点,就算运气了。” +夏季,很久没有下雨,干旱得很。僖公要烧死巫人和仰面朝天的怪人。臧文仲说:“这不是解决旱灾的办法。修理城墙、节用饮食、节省开支、致力农事、劝人施舍,这是应该做的。巫人、仰面朝天的怪人能做什么?上天要杀他们,就应当不生他们;如果他们能造成旱灾,烧死他们会更厉害。”僖公听从了。这一年,虽有饥荒,却没有伤害百姓。 +秋季,楚成王、陈穆公、蔡庄公、郑文公、许僖公、曹共公在盂地会见宋襄公。子鱼说:“祸根子就在这里吧!国君的欲望太过分,那怎能忍受得了?”在会上楚国抓住了宋襄公来攻打宋国。 +冬季,诸侯在薄地会盟,释放了宋襄公。子鱼说:“祸殃还没有完,这点够不上惩罚国君。” +任国、宿国、须句、颛臾,都姓风,主管太皞和济水神的祭祀,而服从中原各国。邾国人灭亡了须句,须句君逃亡到鲁国来,这是由于须句是成风的娘家。成风对僖公说:“尊崇明祀,保护弱小,这是周的礼仪;蛮夷扰乱中原,这是周的祸患。如果封了须句国的爵位,这是尊崇太皞、济水神而修明祭祀和缓解祸患啊。” + + +僖公二十二年 +【经】二十有二年春,公伐邾,取须句。夏,宋公、卫侯、许男、滕子伐郑。秋八月丁未,及邾人战于升陉。冬十有一月己巳朔,宋公及楚人战于泓,宋师败绩。 +【传】二十二年春,伐邾,取须句,反其君焉,礼也。 +三月,郑伯如楚。 +夏,宋公伐郑。子鱼曰:“所谓祸在此矣。” +初,平王之东迁也,辛有适伊川,见被发而祭于野者,曰:“不及百年,此其戎乎!其礼先亡矣。”秋,秦、晋迁陆浑之戎于伊川。 +晋大子圉为质于秦,将逃归,谓嬴氏曰:“与子归乎?”对曰:“子,晋大子,而辱于秦,子之欲归,不亦宜乎?寡君之使婢子侍执巾栉,以固子也。从子而归,弃君命也。不敢从,亦不敢言。”遂逃归。 +富辰言于王曰:“请召大叔。《诗》曰:‘协比其邻,昏姻孔云。’吾兄弟之不协,焉能怨诸侯之不睦?”王说。王子带自齐复归于京师,王召之也。 +邾人以须句故出师。公卑邾,不设备而御之。臧文仲曰:“国无小,不可易也。无备,虽众不可恃也。《诗》曰:‘战战兢兢,如临深渊,如履薄冰。’又曰:‘敬之敬之,天惟显思,命不易哉!’先王之明德,犹无不难也,无不惧也,况我小国乎!君其无谓邾小。蜂虿有毒,而况国乎?”弗听。 +八月丁未,公及邾师战于升陉,我师败绩。邾人获公胄,县诸鱼门。 +楚人伐宋以救郑。宋公将战,大司马固谏曰:“天之弃商久矣,君将兴之,弗可赦也已。”弗听, +冬十一月己巳朔,宋公及楚人战于泓。宋人既成列,楚人未既济。司马曰:“彼众我寡,及其未既济也请击之。”公曰:“不可。”既济而未成列,又以告。公曰:“未可。”既陈而后击之,宋师败绩。公伤股,门官歼焉。 +国人皆咎公。公曰:“君子不重伤,不禽二毛。古之为军也,不以阻隘也。寡人虽亡国之馀,不鼓不成列。”子鱼曰:“君未知战。勍敌之人隘而不列,天赞我也。阻而鼓之,不亦可乎?犹有惧焉。且今之勍者,皆吾敌也。虽及胡《老司》,获则取之,何有于二毛?明耻教战,求杀敌也,伤未及死,如何勿重?若受重伤,则如勿伤;爱其二毛,则如服焉。三军以利用也,金鼓以声气也。利而用之,阻隘可也;声盛致志,鼓儳可也。” +丙子晨,郑文夫人芈氏、姜氏劳楚子于柯泽。楚子使师缙示之俘馘。君子曰:“非礼也。妇人送迎不出门,见兄弟不逾阈,戎事不迩女器。” +丁丑,楚子入飨于郑,九献,庭实旅百,加笾豆六品。飨毕,夜出,文芈送于军,取郑二姬以归。叔詹曰:“楚王其不没乎!为礼卒于无别,无别不可谓礼,将何以没?”诸侯是以知其不遂霸也。 +译文 +二十二年春季,鲁国讨伐邾国,占领须句,护送须句的国君回国,这是符合礼的。 +三月,郑文公到楚国去。 +夏季,宋襄公进攻郑国。子鱼说:“所说的祸乱就在这里了。” +当初,周平王向东迁都洛阳的时候,辛有到了伊川,见到披着头发在野外祭祀的人,说:“不到一百年,这里就要变成戎人居住的地方了!它的礼仪先就消失了。”秋季,秦国和晋国把陆浑之戎迁到伊川。 +晋国的太子圉在秦国作人质,准备逃回晋国,对嬴氏说:“跟你一起回去么?”嬴氏说:“你是晋国的太子而屈居在秦国。你想回去,不也很应该吗?我国君主让婢子侍候你,为你捧着手巾梳子,是为了使你安心,跟你回去,就丢弃了国君的命令。我不敢跟从,也不敢泄露。”太子圉就逃回晋国。富辰对周襄王说:“请您把太叔召回来。《诗》说:‘和他的邻居融洽,姻亲才能友好。’我国兄弟都不融洽,哪里能埋怨诸侯的不顺服?”周襄王听了很高兴。王子带从齐国回到京师,这是周襄王把他召回来的。 +邾人由于鲁国帮助须句的缘故出兵攻打鲁国。僖公轻视邾国,不作准备便去抵御。臧文仲说:“国家无所谓弱小,不能轻视。没有准备,人虽然众多,还是不足依靠的。《诗》说:‘战战兢兢,如同面向深渊,如同踩着薄冰。’又说:‘谨慎又谨慎,上天光明普照,得到上天保佑不容易啊!’以先王的美德,还没有不困难、没有不戒惧的,何况我们小国呢?君王不要认为邾国弱小,黄蜂、蝎子都有毒,何况一个国家呢?”僖公不听。八月初八日,僖公率军与邾军在升陉作战,我军大败。邾军获得僖公的头盔,挂在鱼门上。 +楚人进攻宋国以救援郑国。宋襄公准备应战,大司马固劝阻说:“上天丢弃我们商朝后代已经很久了,您想复兴它,这是违背上天而不能被赦免的。”宋襄公不听。 +冬季,十一月初一日,宋襄公与楚国人在泓水边上作战。宋军已经排成队列,楚军还没有全部渡过河。司马说:“他们兵多,我们兵少,趁他们没有全部渡过河的时候,请君王下令攻击他们。”宋襄公说:“不行。”楚军渡过河以后还没有排开阵势,司马又把刚才的情况报告宋襄公。宋襄公说:“还不行。”等楚军摆开阵势然后才攻击他们,宋军被打得大败,宋襄公大腿后受箭伤,跟随宋襄公的卿大夫子弟任护卫的被歼灭。都城里的人都责怪宋襄公。宋襄公说:“君子不两次伤害敌人,不擒捉头发花白的敌人。古代的作战,不靠关塞险阻取胜。寡人虽然是殷商亡国的后裔,不攻击没有摆开阵势的敌人。”子鱼说:“国君不懂战争。强大的敌人,由于地形狭隘而没有摆开阵势,这是上天在帮助我,把他们拦截而攻击,不也是可以的吗?可是还害怕不能取胜。现在强大的国家,都是我们的敌人,虽然是老头子,捉了也不能放,管什么头发花白不花白。说明国家耻辱是什么,以此教导士兵作战,目的就是为了多杀敌人。敌人受伤而没有死,为什么不可以再次打击他一次?如果爱惜敌人伤员而不再打击,就应该一开始就不伤害他;爱惜那些头发花白的人,就不如向他们投降。军队,由于有利才加以使用;战鼓雷鸣,是用声音来激励士气。有利而使用,在狭路攻击是可以的;鼓声大作鼓舞了士气,攻击没有摆开阵势的敌人也是可以的。” +十一月初八日早晨,郑文公夫人芈氏、姜氏在柯泽慰劳楚成王。楚成王派师缙把俘虏和被杀死的敌人的左耳给他们看。君子说:“这是不合于礼的。女人送迎不出房门,和兄弟相见不出门槛,打仗时不接近女人的用具。”初九日,楚成王进入郑国接受享礼,主人敬酒九次,庭院里陈列的礼品有一百件,另外再加笾豆礼品六件。宴请完毕,夜里出来,文芈送他到军营里。楚成王带了郑国的两个侍妾回去。叔詹说:“楚成王恐怕不得寿终正寝吧!执行礼节而最后至于男女混杂。男女混杂不能认为合于礼,他将怎么能得到好死?”所以诸侯知道楚成王不能完成霸业。 + + +僖公二十三年 +【经】二十有三年春,齐侯伐宋,围婚。夏五月庚寅,宋公兹父卒。秋,楚人伐陈。冬十有一月,杞子卒。 +【传】二十三年春,齐侯伐宋,围缗,以讨其不与盟于齐也。 +夏五月,宋襄公卒,伤于泓故也。 +秋,楚成得臣帅师伐陈,讨其贰于宋也。遂取焦、夷,城顿而还。子文以为之功,使为令尹。叔伯曰:“子若国何?”对曰:“吾以靖国也。夫有大功而无贵仕,其人能靖者与有几?” +九月,晋惠公卒。怀公命无从亡人。期,期而不至,无赦。狐突之子毛及偃从重耳在秦,弗召。冬,怀公执狐突曰:“子来则免。”对曰:“子之能仕,父教之忠,古之制也。策名委质,贰乃辟也。今臣之子,名在重耳,有年数矣。若又召之,教之贰也。父教子贰,何以事君?刑之不滥,君之明也,臣之愿也。淫刑以逞,谁则无罪?臣闻命矣。”乃杀之。 +卜偃称疾不出,曰:“《周书》有之:‘乃大明服。’己则不明而杀人以逞,不亦难乎?民不见德而唯戮是闻,其何后之有?” +十一月,杞成公卒。书曰“子”,杞,夷也。不书名,未同盟也。凡诸侯同盟,死则赴以名,礼也。赴以名,则亦书之,不然则否,辟不敏也。 +晋公子重耳之及于难也,晋人伐诸蒲城。蒲城人欲战。重耳不可,曰:“保君父之命而享其生禄,于是乎得人。有人而校,罪莫大焉。吾其奔也。”遂奔狄。从者狐偃、赵衰、颠颉、魏武子、司空季子。狄人伐啬咎如,获其二女:叔隗、季隗,纳诸公子。公子取季隗,生伯儵、叔刘,以叔隗妻赵衰,生盾。将适齐,谓季隗曰:“待我二十五年,不来而后嫁。”对曰:“我二十五年矣,又如是而嫁,则就木焉。请待子。”处狄十二年而行。 +过卫。卫文公不礼焉。出于五鹿,乞食于野人,野人与之块,公子怒,欲鞭之。子犯曰:“天赐也。”稽首,受而载之。 +及齐,齐桓公妻之,有马二十乘,公子安之。从者以为不可。将行,谋于桑下。蚕妾在其上,以告姜氏。姜氏杀之,而谓公子曰:“子有四方之志,其闻之者吾杀之矣。”公子曰:“无之。”姜曰:“行也。怀与安,实败名。”公子不可。姜与子犯谋,醉而遣之。醒,以戈逐子犯。 +及曹,曹共公闻其骈胁。欲观其裸。浴,薄而观之。僖负羁之妻曰:“吾观晋公子之从者,皆足以相国。若以相,夫子必反其国。反其国,必得志于诸侯。得志于诸侯而诛无礼,曹其首也。子盍蚤自贰焉。”乃馈盘飨,置璧焉。公子受飨反璧。 +及宋,宋襄公赠之以马二十乘。 +及郑,郑文公亦不礼焉。叔詹谏曰:“臣闻天之所启,人弗及也。晋公子有三焉,天其或者将建诸,君其礼焉。男女同姓,其生不蕃。晋公子,姬出也,而至于今,一也。离外之患,而天不靖晋国,殆将启之,二也。有三士足以上人而从之,三也。晋、郑同侪,其过子弟,固将礼焉,况天之所启乎?”弗听。 +及楚,楚之飨之,曰:“公子若反晋国,则何以报不谷?”对曰:“子女玉帛则君有之,羽毛齿革则君地生焉。其波及晋国者,君之馀也,其何以报君?”曰:“虽然,何以报我?”对曰:“若以君之灵,得反晋国,晋、楚治兵,遇于中原,其辟君三舍。若不获命,其左执鞭弭、右属櫜健,以与君周旋。”子玉请杀之。楚子曰:“晋公子广而俭,文而有礼。其从者肃而宽,忠而能力。晋侯无亲,外内恶之。吾闻姬姓,唐叔之后,其后衰者也,其将由晋公子乎。天将兴之,谁能废之。违天必有大咎。”乃送诸秦。秦伯纳女五人,怀嬴与焉。奉也活盥,既而挥之。怒曰:“秦、晋匹也,何以卑我!”公子惧,降服而囚。 +他日,公享之。子犯曰:“吾不如衰之文也。请使衰从。”公子赋《河水》,公赋《六月》。赵衰曰:“重耳拜赐。”公子降,拜,稽首,公降一级而辞焉。衰曰:“君称所以佐天子者命重耳,重耳敢不拜。” +译文 +二十三年春季,齐孝公发兵进攻宋国,包围缗地,讨伐宋国不到齐国参加会盟。 +夏季,五月,宋襄公死,这是由于在泓地战役中受伤的缘故。 +秋季,楚国的成得臣领兵进攻陈国,讨伐陈国倾向宋国。于是占领了焦、夷两地,在顿地筑城后回国。子文把这些作为他的功劳,让他做令尹。叔伯说:“您打算把国家怎么办?”子文回答说:“我是用这个来安定国家的。有了大功而不居高位,这样的人能够安定国家的有几个?” +九月,晋惠公死了。怀公即位,命令臣民不准跟随逃亡在外的人。规定了期限,不回来的不赦免。狐突的儿子毛和偃跟随重耳在秦国,不肯召他们回国。怀公抓住狐突,说:“儿子回来就赦免。”狐突回答说:“当儿子能够做官,父亲教他懂得忠诚的道理,这是古代的制度。名字写在简策上,给主子送了进见的礼物,如果三心二意就是罪过。现在下臣的儿子,名字在重耳那里已经有年头了,如果又召他回来,这是教他三心二意。父亲教儿子三心二意,用什么来事奉国君?刑罚的不滥用,这是君主的贤明,下臣的愿望。滥用刑罚以图快意,谁能没有罪?下臣知道您的意思了。”晋怀公于是杀了狐突。卜偃推说有病不出门,说:“《周书》上有这样的话:‘君主伟大贤明臣民然后顺服。’自己如果不贤明,反而杀人以图快意,不也很难办事吗?百姓看不到德行,反而只听到杀戮,哪里还能有什么后代?” +十一月,杞成公去世。《春秋》记载称“子”,因为杞是夷人。不记载名字,是由于没有和鲁国结过盟的缘故。凡是同盟的诸侯,死后就在讣告上写上名字,这是合于礼的。讣告上写上名字,《春秋》就加以记载,否则就不记载,这是为了避免弄不清楚而误记。 +晋公子重耳遭到祸难的时候,晋献公的军队在蒲城攻打他。蒲城人想要迎战,重耳不肯,说:“仰仗着国君父亲的恩宠而享有奉养自己的俸禄,因此才得到百姓的拥护。有百姓的拥护而反抗,没有比这再大的罪过了。我还是逃亡吧。”于是就逃亡到狄人那里,跟随的有狐偃、赵衰、颠颉、魏武子、司空季子。狄人攻打廧咎如,俘虏了他两个女儿叔隗、季隗,送给公子。公子娶了季隗,生了伯儵、叔刘。把叔隗嫁给赵衰,生了盾。公子要到齐国去,对季隗说:“等我二十五年,不回来再改嫁。”季隗回答说:“我已经二十五岁了,又再过二十五年改嫁,我就要进棺材了。我等您。”公子在狄一共住了十二年,然后离开。经过卫国,卫文公不以礼来待他。 +经过五鹿时,向乡下人要饭。乡下人给他一块泥土。公子发怒,要鞭打他。子犯说:“这是上天赐与的啊!”公子叩着头接受,把泥土装上车子。 +重耳到达齐国,齐桓公也给他娶妻,有马八十匹。公子安于齐国的生活。跟随的人认为这样不行,准备离去,在桑树下商量。养蚕的侍妾正好在树上听到,把这事告诉姜氏。姜氏杀了她,告诉公子说:“您有远大的志向,听到的人,我已经杀了。”公子说:“没有这回事。”姜氏说:“走吧!留恋妻子和贪图安逸,实在会有损前途。”公子不肯。姜氏和子犯商量,灌醉了公子,然后打发他走。公子酒醒,拿起长戈追逐子犯。 +重耳到达曹国,曹共公听说他的肋骨排比很密,似乎并成一整块,想从他裸体中看个真相。乘重耳洗澡,他就在帘子外观看。僖负羁的妻子对负羁说:“我看晋公子的随从人员,都足以辅助国家。如果用他们作辅助,晋公子必定能回晋国做国君。回到晋国,肯定在诸侯中称霸。在诸侯中称霸而惩罚对他无礼的国家,曹国就是第一个。您何不早一点向他表示好感呢!”僖负羁于是就向晋公子馈送一盘食品,里边藏着璧玉。公子接受食品,退回璧玉。 +重耳到达宋国,宋襄公把马八十匹送给他。到达郑国,郑文公也不加礼遇。叔詹劝谏说:“臣听说上天所赞助的人,别人就赶不上了。晋公子具有三条,上天或者将要立他为国君吧,您最好还是以礼相待。父母同姓,子孙不能昌盛。晋公子是姬姓女子生的,所以能活到今天,这是一。经受逃亡在外的忧患,而上天使晋国不安定,大概是将要赞助他了,这是二。有三个人足以居于别人之上,却一直跟随着他,这是三。晋国和郑国地位平等,他们的子弟路过还应当以礼相待,何况是上天所赞助的呢?”郑文公没有听叔詹的劝谏。 +重耳到达楚国,楚成王设宴会招待他,说:“公子如果回到晋国,用什么报答我?”公子回答说:“子、女、玉、帛都是君王所拥有的,鸟羽、皮毛、象牙、犀革都是君王土地上所生长的。那些波及晋国的,已经是君王剩馀的了,我能用什么来报答君王呢?”楚成王说:“尽管这样,究竟用什么报答我?”公子回答说:“如果托君王的福,能够回到晋国,一旦晋、楚两国演习军事,在中原相遇,那就后退九十里。如果还得不到君王的宽大,那就左手执鞭执弓,右边挂着弓袋箭袋,跟君王较量一下。”子玉请求楚王杀掉他。楚成王说:“晋公子志向远大而生活俭约,文辞华美而合乎礼仪。他的随从严肃而宽大,忠诚又有能力。晋侯没有亲近的人,国内国外都讨厌他。我听说姬姓是唐叔后代,将会最后衰亡,这恐怕是从晋公子为君以后的缘故吧!上天将要使他兴起,谁能够废掉他?违背上天,必然有大灾。”于是就把他送回秦国。 +秦穆公送给重耳五个女子,怀嬴也在内。怀嬴捧着盛水的器皿伺候重耳洗脸,他洗了手不用手巾擦手,而挥挥手把手上的水甩干。怀嬴很生气,说:“秦、晋两国地位平等,为什么轻视我?”公子害怕,脱去上衣自囚表示谢罪。有一天,秦穆公设宴席招待重耳,子犯说:“我不如赵衰那样有文采,请您让赵衰跟随赴宴。”公子在宴会上赋《河水》这首诗,秦穆公赋《六月》这首诗。赵衰说:“重耳拜谢恩赐!”公子退到阶下,拜,叩头,秦穆公走下一级台阶辞谢。赵衰说:“君王把所以辅助天子的事命令重耳,重耳岂敢不拜?” + +僖公二十四年 +【经】二十有四年春王正月。夏,狄伐郑。秋七月。冬,天王出居于郑。晋侯夷吾卒。 +【传】二十四年春,王正月,秦伯纳之,不书,不告入也。 +及河,子犯以璧授公子,曰:“臣负羁绁从君巡于天下,臣之罪甚多矣。臣犹知之,而况君乎?请由此亡。”公子曰:“所不与舅氏同心者,有如白水。”投其璧于河。济河,围令狐,入桑泉,取臼衰。二月甲午,晋师军于庐柳。秦伯使公子絷如晋师,师退,军于郇。辛丑,狐偃及秦、晋之大夫盟于郇。壬寅,公子入于晋师。丙午,入于曲沃。丁未,朝于武宫。戊申,使杀怀公于高梁。不书,亦不告也。吕、郤畏逼,将焚公宫而弑晋侯。寺人披请见,公使让之,且辞焉,曰:“蒲城之役,君命一宿,女即至。其后余从狄君以田渭滨,女为惠公来求杀余,命女三宿,女中宿至。虽有君命,何其速也。夫祛犹在,女其行乎。”对曰:“臣谓君之入也,其知之矣。若犹未也,又将及难。君命无二,古之制也。除君之恶,唯力是视。蒲人、狄人,余何有焉。今君即位,其无蒲、狄乎?齐桓公置射钩而使管仲相,君若易之,何辱命焉?行者甚众,岂唯刑臣。”公见之,以难告。三月,晋侯潜会秦伯于王城。己丑晦,公宫火,瑕甥、郤芮不获公,乃如河上,秦伯诱而杀之。晋侯逆夫人嬴氏以归。秦伯送卫于晋三千人,实纪纲之仆。 +初,晋侯之竖头须,守藏者也。其出也,窃藏以逃,尽用以求纳之。及入,求见,公辞焉以沐。谓仆人曰:“沐则心覆,心覆则图反,宜吾不得见也。居者为社稷之守,行者为羁绁之仆,其亦可也,何必罪居者?国君而仇匹夫,惧者甚众矣。”仆人以告,公遽见之。 +狄人归季隗于晋而请其二子。文公妻赵衰,生原同、屏括、搂婴。赵姬请逆盾与其母,子余辞。姬曰:“得宠而忘旧,何以使人?必逆之!”固请,许之,来,以盾为才,固请于公以为嫡子,而使其三子下之,以叔隗为内子而己下之。 +晋侯赏从亡者,介之推不言禄,禄亦弗及。推曰“献公之子九人,唯君在矣。惠、怀无亲,外内弃之。天未绝晋,必将有主。主晋祀者,非君而谁?天实置之,而二三子以为己力,不亦诬乎?窃人之财,犹谓之盗,况贪天之功以为己力乎?下义其罪,上赏其奸,上下相蒙,难与处矣!”其母曰:“盍亦求之,以死谁怼?”对曰:“尤而效之,罪又甚焉,且出怨言,不食其食。”其母曰:“亦使知之若何?”对曰:“言,身之文也。身将隐,焉用文之?是求显也。”其母曰:“能如是乎?与女偕隐。”遂隐而死。晋侯求之,不获,以绵上为之田,曰:“以志吾过,且旌善人。” +郑之入滑也,滑人听命。师还,又即卫。郑公子士、泄堵俞弥帅师伐滑。王使伯服、游孙伯如郑请滑。郑伯怨惠王之入而不与厉公爵也,又怨襄王之与卫、滑也,故不听王命而执二子。王怒,将以狄伐郑。富辰谏曰:“不可。臣闻之,大上以德抚民,其次亲亲以相及也。昔周公吊二叔之不咸,故封建亲戚以蕃屏周。管蔡郕霍,鲁卫毛聃,郜雍曹滕,毕原酆郇,文之昭也。邗晋应韩,武之穆也。凡蒋刑茅胙祭,周公之胤也。召穆公思周德之不类,故纠合宗族于成周而作诗,曰:‘常棣之华,鄂不□韦□韦,凡今之人,莫如兄弟。’其四章曰:‘兄弟阋于墙,外御其侮。’如是,则兄弟虽有小忿,不废懿亲。今天子不忍小忿以弃郑亲,其若之何?庸勋亲亲,昵近尊贤,德之大者也。即聋从昧,与顽用嚚,奸也大者也。弃德崇奸,祸之大者也。郑有平、惠之勋,又有厉、宣之亲,弃嬖宠而用三良,于诸姬为近,四德具矣。耳不听五声之和为聋,目不别五色之章为昧,心不则德义之经为顽,口不道忠信之言为嚚,狄皆则之,四奸具矣。周之有懿德也,犹曰‘莫如兄弟’,故封建之。其怀柔天下也,犹惧有外侮,扞御侮者莫如亲亲,故以亲屏周。召穆公亦云。今周德既衰,于是乎又渝周、召以从诸奸,无乃不可乎?民未忘祸,王又兴之,其若文、武何?”王弗听,使颓叔、桃子出狄师。夏,狄伐郑,取栎。 +王德狄人,将以其女为后。富辰谏曰:“不可。臣闻之曰:‘报者倦矣,施者未厌。’狄固贪淋,王又启之,女德无极,妇怨无终,狄必为患。”王又弗听。 +初,甘昭公有宠于惠后,惠后将立之,未及而卒。昭公奔齐,王复之,又通于隗氏。王替隗氏。颓叔、桃子曰:“我实使狄,狄其怨我。”遂奉大叔,以狄师攻王。王御士将御之。王曰:“先后其谓我何?宁使诸。侯图之。”璲出。及坎□,国人纳之。 +秋,颓叔、桃子奉大叔,以狄师伐周,大败周师,获周公忌父、原伯、毛伯、富辰。王出适郑,处于汜。大叔以隗氏居于温。 +郑子华之弟子臧出奔宋,好聚鹬冠。郑伯闻而恶之,使盗诱之。八月,盗杀之于陈、宋之间。君子曰:“服之不衷,身之灾也。《诗》曰:‘彼己之子,不称其服。’子臧之服,不称也夫。《诗》曰,‘自诒伊戚’,其子臧之谓矣。《夏书》曰,‘地平天成’,称也。” +宋及楚平。宋成公如楚,还入于郑。郑伯将享之,问礼于皇武子。对曰:“宋,先代之后也,于周为客,天子有事膰焉,有丧拜焉,丰厚可也。”郑伯从之,享宋公有加,礼也。 +冬,王使来告难曰:“不谷不德,得罪于母弟之宠子带,鄙在郑地汜,敢告叔父。”臧文仲对曰:“天子蒙尘于外,敢不奔问官守。”王使简师父告于晋,使左鄢父告于秦。天子无出,书曰“天王出居于郑”,辟母弟之难也。天子凶服降名,礼也。郑伯与孔将鉏、石甲父、侯宣多省视官具于汜,而后听其私政,礼也。 +卫人将伐邢,礼至曰:“不得其守,国不可得也。我请昆弟仕焉。”乃往,得仕。 +译文 +二十四年春季,周王朝历法的正月,秦穆公把公子重耳送回晋国。《春秋》没有记载这件事,因为晋国没有向鲁国报告重耳回晋国的事。到达黄河岸边,子犯把玉璧还给公子,说:“下臣背着马笼头马缰绳跟随您在天下巡行,下臣的罪过很多,下臣自己尚且知道,何况您呢?请您让我从这里走开吧。”公子说:“如果不和舅父同一条心,有河神作证。”把他的璧玉扔到了黄河里。 +重耳等一行渡过黄河,包围了令狐,进入桑泉,占取了臼衰。二月的一天, 晋国的军队驻扎在庐柳。秦穆公派遣公子絷到晋国军队里去交涉。晋军退走,驻扎在郇地。又一天,狐偃和秦国、晋国的大夫在郇地结盟。又一天,公子重耳到达晋国军队里。又一天,重耳进入曲沃。又一天,重耳在晋武公的庙宇中朝见群臣。又一天,重耳派人在高梁杀死了晋怀公。《春秋》没有记载这件事,也是由于晋国没有来鲁国报告的缘故。 +吕、郤两家害怕祸难逼近,准备焚烧宫室而杀死晋文公。寺人披请求进见。晋文公派人责备他,而且拒绝接见,说:“蒲城那一次战役,国君命令你一个晚上到达,你马上就来了。后来我跟随狄君在渭水边上打猎,你为惠公来杀我,惠公命令你过三个晚上再来,你过两个晚上就来了。虽然有国君的命令,为什么那么快呢?那只被割断的袖子还在,你还是走开吧!”寺人披回答说:“小臣原来认为国君回国以后,已经了解情况了。如果还没有,就会又一次遇到祸难。执行国君的命令只有一心一意,这是古代的制度。除去国君所厌恶的人,只看自己有多大力量。蒲人、狄人,对我来说算什么呢?现在您即位做国君,也会同我心目中一样没有蒲、狄吧!齐桓公把射钩的事故在一边,而让管仲辅助他。君王如果改变这种做法,我会自己走的,哪里需要君王的命令呢?离开的人很多,岂独是我受过宫刑的小臣?”晋文公接见了寺人披,寺人披就把祸乱告诉了晋文公。三月,晋文公秘密地和秦穆公在王城会见。三十日,文公的宫殿起火。瑕甥、郤芮找不到晋文公,于是就到黄河边上去找,秦穆公把他们诱去杀死了。晋文公迎接夫人嬴氏回国。秦穆公赠送给晋国卫士三千人,都是一些得力的臣仆。 +当初,晋文公有个侍臣名叫头须,是专门管理财物的。当晋文公在国外的时候,头须偷盗了财物潜逃,把这些财物都用来设法让晋文公回国。没有成功,只好留在国内。等到晋文公回来,头须请求进见。晋文公推托说正在洗头。头须对仆人说:“洗头的时候心就倒过来,心倒了意图就反过来,无怪我不能被接见了。留在国内的人是国家的守卫者,跟随在外的是背着马笼头马缰绳的仆人,这也都是可以的,何必要怪罪留在国内的人?身为国君而仇视普通人,害怕的人就多了。”仆人把这些话告诉晋文公,晋文公立即接见了他。 +狄人把季隗送回到晋国,而请求留下她的两个儿子。晋文公把女儿嫁给赵衰,生了原同、屏括、楼婴。赵姬请求迎接盾和他的母亲。赵衰辞谢不肯。赵姬说:“得到新宠而忘记旧好,以后还怎样使用别人?一定要把他们接回来。”坚决请求,赵衰同意了。叔隗和赵盾回来以后,赵姬认为赵盾有才,坚决向赵衰请求,把赵盾作为嫡子,而让她自己生的三个儿子居于赵盾之下,让叔隗作为正妻,而自己居于她之下。 +晋文公赏赐跟随他逃亡的人,介之推没有提及禄位,禄位也没有赐到他身上。介之推说:“献公的儿子有九个,只有公子在世了。惠公、怀公没有亲近的人,国内国外都抛弃了他们。上天不使晋国绝后,必定会有君主。主持晋国祭祀的人,不是公子又会是谁?这实在是上天立他为君,而他们这些人却以为是自己的力量,这不是欺骗吗?偷别人的财物,尚且叫做盗,何况贪上天的功劳以为自己的力量呢?下面的人把贪功的罪过当成合理,上面的人对欺骗加以赏赐,上下相互欺骗,这就难和他们相处了。”介之推的母亲说:“为什么不也去求赏?这样的死,又能怨谁?”介之推回答说:“明知错误而去效法,罪就更大了。而且我口出怨言,不能吃他的俸禄。”他母亲说:“也让他知道一下,怎么样?”介之推回答说:“说话,是身体的文饰。身体将要隐藏,哪里用得着文饰?这只不过是去求显露罢了。”他母亲说:“你能够这样吗?我和你一起隐居起来。”于是就隐居而死。晋文公派人寻找介之推,找不到,就把绵上的田封给他,说:“用这来记载我的过失,来表扬好人。” +郑军进入滑国的时候,滑人听从命令。军队回去,滑国又亲附卫国。郑国的公子士、洩堵俞弥带兵进攻滑国。周襄王派伯服、游孙伯到郑国请求不要进攻滑国。郑文公怨恨周惠王回到成周而不给厉公饮酒礼器杯子,又怨恨周襄王偏袒卫、滑两国,所以不听周襄王的命令而逮捕了伯服和游孙伯。周襄王发怒,准备领着狄人进攻郑国。富辰劝谏说:“不行。下臣听说,最高的人用德行来安抚百姓,其次的亲近亲属,由近到远。从前周公叹息管叔、蔡叔不得善终,所以把土地分封给亲戚作为周朝的屏障。管、蔡、郕、霍、鲁、卫、毛、聃、郜、雍、曹、滕、毕、原、酆、郇各国,是文王的儿子。邢、晋、应、韩各国,是武王的儿子。凡、蒋、邢、茅、胙、祭各国,是周公的后代。召穆公忧虑周德衰微,所以集合了宗族在成周而做诗,说:‘小叶杨的花儿,花朵是那样漂亮艳丽,现在的人们,总不能亲近得像兄弟。’诗的第四章说:‘兄弟们在墙里争吵,一到墙外就共同对敌。’像这样,那么兄弟之间虽然有小不和睦,也不能废弃好亲属。现在您不忍耐小怨而丢弃郑国这门亲属,又能把它怎么办?酬答勋劳,亲近亲属,接近近臣,尊敬贤人,这是德行中的大德。靠拢耳背的人,跟从昏暗的人,赞成固陋的人,使用奸诈的人,这是邪恶中的大恶,抛弃德行,崇尚邪恶,这是祸患中的大祸。郑国有过辅助平王、惠王的勋劳,又有厉王、宣王的亲属关系,郑国国君舍弃宠臣而任用三个好人,在姬姓诸姓中属于近亲,四种德行都具备了。耳朵不能听到五声的唱和是耳聋,眼睛不能辨别五色的文饰是昏暗,心里不学德义的准则是顽固,嘴里不说忠信的话是奸诈。狄人效法这些,四种邪恶都具备了。周室具有美德的时候,尚且说‘总不能亲近得像兄弟’,所以分封建制。当它笼络天下的时候,尚且害怕有外界的侵犯;抵御外界侵犯的措施,没有比亲近亲属再好的了,所以用亲属作为周室的屏障。召穆公也是这样说的。现在周室的德行已经衰败,而这时又改变周公、召公的措施以跟从各种邪恶,恐怕不可以吧!百姓没有忘记祸乱,君王又把它挑起来,怎么来对待文王、武王呢?”周襄王不听,派遣颓叔、桃子出动狄军。 +夏季,狄军进攻郑国,占领了栎地。 +周襄王感谢狄人,准备把狄君的女儿做王后。富辰劝阻说:“不行。臣听说:‘报答的人已经厌倦了,施恩的人还没有满足。’狄人本来贪婪,而您又启发他们。女子的行为没有准则,妇人的怨恨没有终结,狄人必然成为祸患。”周襄王又不听。 +当初,甘昭公受到惠后的宠爱,惠后打算立他为嗣君,没有来得及惠后就死去了。昭公逃亡到齐国,周天子让他回来,他又和隗氏私通。周天子废了隗氏。颓叔、桃子说:“狄人这样,是我们指使的,狄人可能会怨恨我们。”就奉戴大叔攻打周天子,周王的侍卫人员准备抵御,周王说:“如果杀死太叔,先王后将会说我什么?宁可让诸侯来商量一下。”周王于是就离开成周,到达坎欿,都城里的人又把周王接回都城。秋季,颓叔、桃子奉事太叔领了狄人的军队进攻成周,把周军打得大败,俘虏了周公忌父、原伯、毛伯、富辰。周襄王离开成周去郑国,住在汜地。太叔和隗氏住在温地。 +郑国子华的兄弟子臧逃亡到宋国,喜欢收集鹬毛帽子。郑文公听说后很讨厌他,指使杀手骗他出来。八月,杀手将子臧杀死在陈国和宋国交界的地方。君子说:“衣服的不合适,这是身体的灾祸。《诗》说:‘那一个人啊,和他的服饰不能相称。’子臧的服饰,就是不相称啊!《诗》说:‘自己给自己找来祸害。’子臧就是这样。《夏书》说:‘大地平静,上天成全。’这就是上下相称了。” +宋国和楚国讲和,宋成公到楚国。回国时,进入郑国。郑文公准备设宴招待他,向皇武子询问礼仪。皇武子回答说:“宋国是先朝的后代,在周朝来说是客人。周天子祭祀宗庙,要送给他祭肉;有了丧事,宋国国君来吊唁,周天子是要答拜的。丰盛地招待他是可以的。”郑文公听从皇武子的话,设享礼招待宋公,比常礼有所增加。这是合于礼的。 +冬季,周襄王的使者前来报告发生的祸难,说:“不穀缺乏德行,得罪了母亲所宠爱的儿子带,现在僻处在郑国的汜地,谨敢将这件事情报告叔父。”臧文仲回答说:“天子在外边蒙受尘土,岂敢不赶紧去问候左右。” +周襄王派简师父向晋国报告,派左鄢父到秦国报告。天子无所谓出国,《春秋》记载说“天王出居于郑”,意思是由于躲避兄弟所造成的祸难。天子穿着素服,自称“不穀”,这是合于礼的。 +郑文公和孔将鉏、石甲父、侯宣多到汜地问候天子的官员和检查供应天子的用品,然后听取关于郑国的政事,这是合于礼的。 +卫国人准备攻打邢国,卫大夫礼至说:“不和他们的大官接近,是难以得到他们的国家的。我请求让我的兄弟去邢国做官。”他们就前去邢国,并做了官。 + +僖公二十五年 +【经】二十有五年春王正月,丙午,卫侯毁灭邢。夏四月癸酉,卫侯毁卒。宋荡伯来逆妇。宋杀其大夫。秋,楚人围陈,纳顿子于顿。葬卫文公。冬十有二月癸亥,公会卫子、莒庆盟于洮。 +【传】二十五年春,卫人伐邢,二礼从国子巡城,掖以赴外,杀之。正月丙午,卫侯毁灭邢,同姓也,故名。礼至为铭曰:“余掖杀国子,莫余敢止。” +秦伯师于河上,将纳王。狐偃言于晋侯曰:“求诸侯,莫如勤王。诸侯信之,且大义也。继文之业而信宣于诸侯,今为可矣。”使卜偃卜之,曰:“吉。遇黄帝战于阪泉之兆。”公曰:“吾不堪也。”对曰:“周礼未改。今之王,古之帝也。”公曰:“筮之。”筮之,遇《大有》ⅵⅰ之《睽》ⅵⅷ,曰:“吉。遇‘公用享于天子’之卦也。战克而王飨,吉孰大焉,且是卦也,天为泽以当日,天子降心以逆公,不亦可乎?《大有》去《睽》而复,亦其所也。”晋侯辞秦师而下。三月甲辰,次于阳樊。右师围温,左师逆王。夏四月丁巳,王入于王城,取大叔于温,杀之于隰城。 +戊午,晋侯朝王,王飨醴,命之宥。请隧,弗许,曰:“王章也。未有代德而有二王,亦叔父之所恶也。”与之阳樊、温、原、欑茅之田。晋于是始启南阳。 +阳樊不服,围之。苍葛呼曰:“德以柔中国,邢以威四夷,宜吾不敢服也。此谁非王之亲姻,其俘之也!”乃出其民。 +秋,秦、晋伐鄀。楚斗克、屈御寇以申、息之师戍商密。秦人过析隈,入而系舆人以围商密,昏而傅焉。宵,坎血加书,伪与子仪、子边盟者。商密人惧曰:“秦取析矣,戍人反矣。”乃降秦师。囚申公子仪、息公子边以归。楚令尹子玉追秦师,弗及,遂围陈,纳顿子于顿。 +冬,晋侯围原,命三日之粮。原不降,命去之。谍出,曰:“原将降矣。”军吏曰:“请待之。”公曰:“信,国之宝也,民之所庇也,得原失信,何以庇之?所亡滋多。”退一舍而原降。迁原伯贯于冀。赵衰为原大夫,狐溱为温大夫。 +卫人平莒于我,十二月,盟于洮,修卫文公之好,且及莒平也。 +晋侯问原守于寺人勃鞮,对曰:“昔赵衰以壶□食从径,馁而弗食。”故使处原。 +译文 +二十五年春季,卫军进攻邢国,礼氏两兄弟跟随邢国大官国子在城上巡察,两人左右挟持国子把他扔到城外,使他摔死。正月二十日,卫侯燬灭亡邢国。由于卫国和邢国同姓,所以记载卫侯的名字。礼至在铜器上作铭文说:“我挟持杀死国子,没有人敢来阻止我。” +秦穆公把军队驻扎在黄河边上,准备送周襄王回朝。狐偃对晋文公说:“求得诸侯的拥护,没有像为天子的事情尽力这样有效。可以得到诸侯信任,而且合于大义。继续文侯的事业,同时信用宣扬在诸侯之中,现在是机会了。”让卜偃占卜,说:“大吉。得到黄帝在阪泉作战的预兆。”晋文公说:“我当不起啊。”卜偃回答说:“周室的礼制没有改变,现在的王,就是古代的帝。”晋文公说:“占筮!”又占筮,得到《大有》变成《睽》,说:“吉利。得到‘公被天子设享礼招待’这个卦,战胜以后天子设享礼招待,还有比这更大的吉利吗?而且这一卦,天变成水泽来承受太阳的照耀,象征天子自己降格来迎接您,不也是可以吗?《大有》变成《睽》而又回到《大有》,天子也就回到他的处所。” +晋文公辞退秦军,顺流而下。三月十九日,军队驻扎在阳樊,右翼部队包围温地,左翼部队迎接周襄王。夏季四月初三日,襄王进入王城。在温地抓了太叔,把他杀死在隰城。初四日,晋文公朝觐周襄王。周襄王用甜酒招待晋文公,又让晋文公向自己回敬酒。晋文公请求死后能用隧道葬他,周襄王没有允许,说:“这是王室的规章。还没有取代周室的行为而有两个天子,这也是叔父所厌恶的。”赐给晋文公阳樊、温、原、攒茅的田地。晋国在这时候才开辟了南阳的疆土。 +阳樊人不服,晋国军队包围了阳樊。仓葛大喊说:“德行用来安抚中原国家,刑罚用来威慑四方夷狄,你们这样干,无怪我们不敢降服了。这里谁不是天子的亲戚,难道能俘虏他们吗?”于是就放百姓出城了。 +秋季,秦国和晋国进攻鄀国。楚国的鬬克、屈御寇带领申、息两地的军队戍守商密。秦军经过析地,绕道丹江水湾子,同时捆绑着自己的士兵假装俘虏,以包围商密,黄昏的时候逼近城下。夜里,掘地歃血,把盟书放在上面,假装和鬬克、御寇盟誓的样子。商密的人害怕,说:“秦军已经占领析地了!戍守的人背叛了!”于是就向秦军投降。秦国军队囚禁了申公鬬克、息公屈御寇而回国。楚国的令尹子玉追赶秦军,没有赶上。楚军就包围陈国,把顿子送回顿国。 +冬季,晋文公率军包围原国,命令携带三天的粮食。到了三天原国不投降,就下令离开。间谍从城里出来,说:“原国准备投降了。”军官说:“请等待一下。”晋文公说:“信用,是国家的宝贝,百姓靠它庇护。得到原国而失去信用,用什么庇护百姓?所损失的东西更多。”退兵三十里,原国投降。晋文公把原伯贯迁到冀地。任命赵衰作为原地的地方官,狐溱作为温地的地方官。 +卫国人调停莒国和我国的关系。十二月,鲁僖公和卫成公、莒庆在洮地结盟,重温卫文公时代的旧好,同时和莒国讲和。 +晋文公向寺人勃鞮询问镇守原地的人选。勃鞮回答说:“以前赵衰用壶盛饮料并携带了食物跟随您,他一个人走在小道上,饿了也不去吃它。”所以晋文公让赵衰作为原地的地方官。 + +僖公二十六年 +【经】二十有六年春王正月,己未,公会莒子、卫宁速盟于向。齐人侵我西鄙,公追齐师,至酅,不及。夏,齐人伐我北鄙。卫人伐齐。公子遂如楚乞师。秋,楚人灭夔,以夔子归。冬,楚人伐宋,围婚。公以楚师伐齐,取谷。公至自伐齐。 +【传】二十六年春,王正月,公会莒兹ぶ宁庄子盟于向,寻洮之盟也。齐师侵我西鄙,讨是二盟也。夏,齐孝公伐我北鄙。卫人伐齐,洮之盟故也。公使展喜犒师,使受命于展禽。 +齐侯未入竟,展喜从之,曰:“寡君闻君亲举玉趾,将辱于敝邑,使下臣犒执事。”齐侯曰:“鲁人恐乎?”对曰:“小人恐矣,君子则否。”齐侯曰:“室如县罄,野无青草,何恃而不恐?”对曰:“恃先王之命。昔周公、大公股肱周室,夹辅成王。成王劳之而赐之盟,曰:‘世世子孙,无相害也。’载在盟府,大师职之。桓公是以纠合诸侯而谋其不协,弥缝其阙而匡救其灾,昭旧职也。及君即位,诸侯之望曰:‘其率桓之功。’我敝邑用不敢保聚,曰:‘岂其嗣世九年而弃命废职,其若先君何?’君必不然。恃此以不恐。”齐侯乃还。 +东门襄仲、臧文仲如楚乞师,臧孙见子玉而道之伐齐、宋,以其不臣也。 +夔子不祀祝融与鬻熊,楚人让之,对曰:“我先王熊挚有疾,鬼神弗赦而自窜于夔。吾是以失楚,又何祀焉?”秋,楚成得臣、斗宜申帅师灭夔,以夔子归。 +宋以其善于晋侯也,叛楚即晋。冬,楚令尹子玉、司马子西帅师伐宋,围缗。 +公以楚师伐齐,取谷。凡师能左右之曰以。置桓公子雍于谷,易牙奉之以为鲁援。楚申公叔侯戍之。桓公之子七人,为七大夫于楚。 +译文 +二十六年春季,周王朝历法的正月,鲁僖公会见莒兹邳公、甯庄子,在向地结盟。重温洮地盟会的旧好。 +齐国军队进攻我国西部边境,表示对洮、向两次会盟的不满。 +夏季,齐孝公进攻我国北部边境,卫军便攻打齐国,这是卫国履行洮地的盟约。 +僖公派遣展喜犒劳军队,派他向展禽请教如何措辞。齐孝公尚未进入我国国境,展喜出境见他,说:“我的君主听说君王亲自出动大驾,将要光临敝邑,所以派遣下臣来慰劳您的左右侍从。”齐孝公说:“鲁国人害怕吗?”展喜回答说:“小人害怕了,君子不怕。”齐孝公说:“房屋中像挂起的磬一样的空,四野里连青草都没有,靠什么不害怕?”展喜回答说:“靠着先王的命令。从前周公、太公辅助周王朝,在左右协助成王。成王慰劳他们,赐给他们盟约,说:‘世世代代的子孙不要互相侵犯。’这个盟约藏在盟府之中,由太史掌管。桓公因此联合诸侯,而商讨解决他们之间的纠纷,弥补他们的过失,而救援他们的灾难,这都是显扬过去的职责。等君王即位,各国诸侯盼望说:‘他会继续桓公的功业吧!’我敝邑因此不敢保护城郭纠聚民众,说:‘难道他即位九年,就背弃王命、废弃职责?他怎么对得住先君?他一定不会这样做的。’靠着这个,所以不害怕。”齐孝公就收兵回国了。 +东门襄仲、臧文仲到楚国请求出兵。臧孙进见楚国的大臣子玉而引导他攻打齐、宋两国,因为齐、宋两国不肯尊事楚国。 +夔君不祭祀祝融和鬻熊,楚国人责备他。夔君回答说:“我们的先王熊挚有病,鬼神不肯赦免他,使他死去,所以自己流窜到夔,我国因此失去楚国的救助,又祭祀什么?”秋季,楚国的成得臣、鬬宜申领兵灭亡夔国,抓了夔君回国。 +宋国因为他们曾经对晋侯表示友善,所以背叛楚国而靠拢晋国。冬季,楚国的令尹子玉、司马子西领兵攻打宋国,包围缗地。 +僖公指挥楚国军队攻打齐国,占领了穀地。凡是出兵,能够随意指挥别国军队叫做“以”。把齐桓公的儿子雍安置在穀地,易牙奉事他作为鲁国的后援。齐桓公的儿子有七个人,都在楚国做了大夫。 + +僖公二十七年 +【经】二十有七年春,杞子来朝。夏六月庚寅,齐侯昭卒。秋八月乙未,葬齐孝公。乙巳,公子遂帅师入杞。冬,楚人、陈侯、蔡侯、郑伯、许男围宋。十有二月甲戌,公会诸侯,盟于宋。 +【传】二十七年春,杞桓公来朝,用夷礼,故曰子。公卑杞,杞不共也。 +夏,齐孝公卒。有齐怨,不废丧纪,礼也。 +秋,入杞,责无礼也。 +楚子将围宋,使子文治兵于睽,终朝而毕,不戮一人。子玉复治兵于蒍,终日而毕,鞭七人,贯三人耳。国老皆贺子文,子文饮之酒。蒍贾尚幼,后至,不贺。子文问之,对曰:“不知所贺。子之传政于子玉,曰:‘以靖国也。’靖诸内而败诸外,所获几何?子玉之败,子之举也。举以败国,将何贺焉?子玉刚而无礼,不可以治民。过三百乘,其不能以入矣。苟入而贺,何后之有?” +冬,楚子及诸侯围宋,宋公孙固如晋告急。先轸曰:“报施救患,取威定霸,于是乎在矣。”狐偃曰:“楚始得曹而新昏于卫,若伐曹、卫,楚必救之,则齐、宋免矣。”于是乎蒐于被庐,作三军。谋元帅。赵衰曰:“郤縠可。臣亟闻其言矣,说礼乐而敦《诗》《书》。《诗》、《书》,义之府也。礼乐,德之则也。德义,利之本也。《夏书》曰:‘赋纳以言,明试以功,车服以庸。’君其试之。”及使郤縠将中军,郤溱佐之;使狐偃将上军,让于狐毛,而佐之;命赵衰为卿,让于栾枝、先轸。使栾枝将下军,先轸佐之。荀林父御戎,魏准为右。 +晋侯始入而教其民,二年,欲用之。子犯曰:“民未知义,未安其居。”于是乎出定襄王,入务利民,民怀生矣,将用之。子犯曰:“民未知信,未宣其用。”于是乎伐原以示之信。民易资者不求丰焉,明征其辞。公曰:“可矣乎?”子犯曰:“民未知礼,未生其共。”于是乎大蒐以示之礼,作执秩以正其官,民听不惑而后用之。出谷戍,释宋围,一战而霸,文之教也。 +译文 +二十七年春季,杞桓公来鲁国朝见。因为他用的是夷人的礼节,所以《春秋》称他为“子”。僖公看不起杞子,由于他认为杞子不恭敬。 +夏季,齐孝公去世。鲁国虽然对齐国有怨恨,但是仍然没有废弃对邻国君主的吊唁,这是合于礼的。 +秋季,公子遂领兵攻入杞国,这是为了责备杞桓公的无礼。 +楚成王准备包围宋国,派遣子文在睽地演习作战,一早上就完事,没有杀一个人。子玉又在?地演习作战,一天才完事,鞭打七个人,用箭穿三个人的耳朵。元老们都祝贺子文。子文招待他们喝酒。?贾年纪还小,迟到了,不祝贺。子文问他,回答说:“不知道要祝贺什么。您把政权传给子玉,说‘为了安定国家’,安定于内而失败于外,所得到的有多少?子玉的对外作战失败,是由于您的推举。推举而使国家失败,有什么可贺的呢?子玉刚愎无礼,不能让他治理军民,率领的兵车超过三百辆,恐怕就不能回来了。如果回来,再祝贺,有什么晚呢?” +冬季,楚成王和诸侯包围宋国。宋国的公孙固到晋国报告紧急情况。先轸说:“报答施舍,救援患难,取得威望,成就霸业,就在这里了。”狐偃说:“楚国刚刚得到曹国,又新近和卫国结为婚姻之国,如果攻打曹、卫两国,楚国必定救援,那么齐国和宋国就可以免于被攻了。”晋国因此而在被庐阅兵,建立三个军,商量元帅的人选。赵衰说:“郤縠可以。我屡次听到他的话,喜爱礼乐而重视《诗》、《书》。《诗》、《书》,是道义的府库;礼乐,是道德的表率;道德礼义,是利益的基础。《夏书》说:‘有益的话全部采纳,考察效果加以试验,如果成功,用车马衣服作为酬劳。’您不妨试一下!”于是晋国派郤縠率领中军,郤溱辅助他。派狐偃率领上军,狐偃让给狐毛而自己辅助他。任命赵衰为卿,赵衰让给栾枝、先轸。命栾枝率领下军,先轸辅助他。荀林父驾御战车,魏犫作为车右。 +晋文公一回国,就训练百姓,过了两年,就想使用他们。子犯说:“百姓还不知道道义,还没能各安其位。”晋文公就离开晋国去安定周襄王的君位,回国后致力于便利百姓,百姓就各安于他们的生活了。又打算使用他们,子犯说:“百姓还不知道93 信用,还不能十分明白信用的作用。”就攻打原国来让百姓看到信用,百姓做买卖不求暴利,明码实价,各无贪心。晋文公说:“行了吗?”子犯说:“百姓还不知道礼仪,没有产生他们的恭敬。”由此举行盛大阅兵来让百姓看到礼仪,建立执秩的官职来规定主管官员的职责。等到百姓看到事情就能明辨是非,然后才使用他们。赶走穀地的驻军,解除宋国的包围,一次战争就称霸诸侯,这都是文公的教化。 + + +僖公二十八年 +【经】二十有八年春,晋侯侵曹,晋侯伐卫。公子买戍卫,不卒戍,刺之。楚人救卫。三月丙午,晋侯入曹,执曹伯。畀宋人。夏四月己巳,晋侯、齐师、宋师、秦师及楚人战于城濮,楚师败绩。楚杀其大夫得臣。卫侯出奔楚。五月癸丑,公会晋侯、齐侯、宋公、蔡侯、郑伯、卫子、莒子,盟于践土。陈侯如会。公朝于王所。六月,卫侯郑自楚复归于卫。卫元咺出奔晋。陈侯款卒。秋,杞伯姬来。公子遂如齐。冬,公会晋侯、齐侯、宋公、蔡侯、郑伯、陈子、莒子、邾人、秦人于温。天王狩于河阳。壬申,公朝于王所。晋人执卫侯,归之于京师。卫元咺自晋复归于卫。诸侯遂围许。曹伯襄复归于曹,遂会诸侯围许。 +【传】二十八年春,晋侯将伐曹,假道于卫,卫人弗许。还,自南河济。侵曹伐卫。正月戊申,取五鹿。二月,晋郤縠卒。原轸将中军,胥臣佐下军,上德也。晋侯、齐侯盟于敛盂。卫侯请盟,晋人弗许。卫侯欲与楚,国人不欲,故出其君以说于晋。卫侯出居于襄牛。 +公子买戍卫,楚人救卫,不克。公惧于晋,杀子丛以说焉。谓楚人曰:“不卒戍也。” +晋侯围曹,门焉,多死,曹人尸诸城上,晋侯患之,听舆人之谋曰称:“舍于墓。”师迁焉,曹人凶惧,为其所得者棺而出之,因其凶也而攻之。三月丙午,入曹。数之,以其不用僖负羁而乘轩者三百人也。且曰:“献状。”令无入僖负羁之宫而免其族,报施也。魏准、颠颉怒曰:“劳之不图,报于何有!”蓺僖负羁氏。魏准伤于胸,公欲杀之而爱其材,使问,且视之。病,将杀之。魏准束胸见使者曰:“以君之灵,不有宁也。”距跃三百,曲踊三百。乃舍之。杀颠颉以徇于师,立舟之侨以为戎右。 +宋人使门尹般如晋师告急。公曰:“宋人告急,舍之则绝,告楚不许。我欲战矣,齐、秦未可,若之何?”先轸曰:“使宋舍我而赂齐、秦,藉之告楚。我执曹君而分曹、卫之田以赐宋人。楚爱曹、卫,必不许也。喜赂怒顽,能无战乎?”公说,执曹伯,分曹、卫之田以畀宋人。 +楚子入居于申,使申叔去谷,使子玉去宋,曰:“无从晋师。晋侯在外十九年矣,而果得晋国。险阻艰难,备尝之矣;民之情伪,尽知之矣。天假之年,而除其害。天之所置,其可废乎?《军志》曰:‘允当则归。’又曰:‘知难而退。’又曰:‘有德不可敌。’此三志者,晋之谓矣。”子玉使伯棼请战,曰:“非敢必有功也,愿以间执谗慝之口。”王怒,少与之师,唯西广、东宫与若敖之六卒实从之。 +子玉使宛春告于晋师曰:“请复卫侯而封曹,臣亦释宋之围。”子犯曰:“子玉无礼哉!君取一,臣取二,不可失矣。”先轸曰:“子与之。定人之谓礼,楚一言而定三国,我一言而亡之。我则无礼,何以战乎?不许楚言,是弃宋也。救而弃之,谓诸侯何?楚有三施,我有三怨,怨仇已多,将何以战?不如私许复曹、卫以携之,执宛春以怒楚,既战而后图之。”公说,乃拘宛春于卫,且私许复曹、卫。曹、卫告绝于楚。 +子玉怒,从晋师。晋师退。军吏曰:“以君辟臣,辱也。且楚师老矣,何故退?”子犯曰:“师直为壮,曲为老。岂在久乎?微楚之惠不及此,退三舍辟之,所以报也。背惠食言,以亢其仇,我曲楚直。其众素饱,不可谓老。我退而楚还,我将何求?若其不还,君退臣犯,曲在彼矣。”退三舍。楚众欲止,子玉不可。 +夏四月戊辰,晋侯、宋公、齐国归父、崔夭、秦小子憖次于城濮。楚师背酅而舍,晋侯患之,听舆人之诵,曰:“原田每每,舍其旧而新是谋。”公疑焉。子犯曰:“战也。战而捷,必得诸侯。若其不捷,表里山河,必无害也。”公曰:“若楚惠何?”栾贞子曰:“汉阳诸姬,楚实尽之,思小惠而忘大耻,不如战也。”晋侯梦与楚子搏,楚子伏己而监其脑,是以惧。子犯曰:“吉。我得天,楚伏其罪,吾且柔之矣。” +子玉使斗勃请战,曰:“请与君之士戏,君冯轼而观之,得臣与寓目焉。”晋侯使栾枝对曰:“寡君闻命矣。楚君之惠未之敢忘,是以在此。为大夫退,其敢当君乎?既不获命矣,敢烦大夫谓二三子,戒尔车乘,敬尔君事,诘朝将见。” +晋车七百乘,革显、革引、鞅、革半。晋侯登有莘之虚以观师,曰:“少长有礼,其可用也。”遂伐其木以益其兵。鲁巳,晋师陈于莘北,胥臣以下军之佐当陈、蔡。子玉以若敖六卒将中军,曰:“今日必无晋矣。”子西将左,子上将右。胥臣蒙马以虎皮,先犯陈、蔡。陈、蔡奔,楚右师溃。狐毛设二旆而退之。栾枝使舆曳柴而伪遁,楚师驰之。原轸、郤溱以中军公族横击之。狐毛、狐偃以上军夹攻子西,楚左师溃。楚师败绩。子玉收其卒而止,故不败。 +晋师三日馆谷,及癸酉而还。甲午,至于衡雍,作王宫于践土。 +乡役之三月,郑伯如楚致其师,为楚师既败而惧,使子人九行成于晋。晋栾枝入盟郑伯。五月丙午,晋侯及郑伯盟于衡雍。丁未,献楚俘于王,驷介百乘,徒兵千。郑伯傅王,用平礼也。己酉,王享醴,命晋侯宥。王命尹氏及王子虎、内史叔兴父策命晋侯为侯伯,赐之大辂之服,戎辂之服,彤弓一,彤矢百,玈弓矢千,秬鬯一卣,虎贲三百人。曰:“王谓叔父,敬服王命,以绥四国。纠逖王慝。”晋侯三辞,从命。曰:“重耳敢再拜稽首,奉扬天子之丕显休命。”受策以出,出入三觐。 +卫侯闻楚师败,惧,出奔楚,遂适陈,使元咺奉叔武以受盟。癸亥,王子虎盟诸侯于王庭,要言曰:“皆奖王室,无相害也。有渝此盟,明神殛之,俾队其师,无克祚国,及而玄孙,无有老幼。”君子谓是盟也信,谓晋于是役也能以德攻。 +初,楚子玉自为琼弁玉缨,未之服也。先战,梦河神谓己曰:“畀余,余赐女孟诸之麋。”弗致也。大心与子西使荣黄谏,弗听。荣季曰:“死而利国。犹或为之,况琼玉乎?是粪土也,而可以济师,将何爱焉?”弗听。出,告二子曰:“非神败令尹,令尹其不勤民,实自败也。”既败,王使谓之曰:“大夫若入,其若申、息之老何?”子西、孙伯曰:“得臣将死,二臣止之曰:‘君其将以为戮。’”及连谷而死。晋侯闻之而后喜可知也,曰:“莫馀毒也已!蒍吕臣实为令尹,奉己而已,不在民矣。” +或诉元咺于卫侯曰:“立叔武矣。”其子角从公,公使杀之。咺不废命,奉夷叔以入守。 +六月,晋人复卫侯。宁武子与卫人盟于宛濮,曰:“天祸卫国,君君臣不协,以及此忧也。今天诱其衷,使皆降心以相从也。不有居者,谁守社稷?不有行者,谁扞牧圉?不协之故,用昭乞盟于尔大神以诱天衷。自今日以往,既盟之后,行者无保其力,居者无惧其罪。有渝此盟,以相及也。明神先君,是纠是殛。”国人闻此盟也,而后不贰。卫侯先期入,宁子先,长佯守门以为使也,与之乘而入。公子颛犬、华仲前驱。叔孙将沐,闻君至,喜,捉发走出,前驱射而杀之。公知其无罪也,枕之股而哭之。颛犬走出,公使杀之。元咺出奔晋。 +城濮之战,晋中军风于泽,亡大旆之左旃。祁瞒奸命,司马杀之,以徇于诸侯,使茅伐代之。师还。壬午,济河。舟之侨先归,士会摄右。秋七月丙申,振旅,恺以入于晋。献俘授馘,饮至大赏,征会讨贰。杀舟之侨以徇于国,民于是大服。 +君子谓:“文公其能刑矣,三罪而民服。《诗》云:‘惠此中国,以绥四方。’不失赏刑之谓也。” +冬,会于温,讨不服也。 +卫侯与元咺讼,宁武子为辅,金咸庄子为坐,士荣为大士。卫侯不胜。杀士荣,刖金咸庄子,谓宁俞忠而免之。执卫侯,归之于京师,置诸深室。宁子职纳橐饘焉。元咺归于卫,立公子瑕。 +是会也,晋侯召王,以诸侯见,且使王狩。仲尼曰:“以臣召君,不可以训。”故书曰:“天王狩于河阳。”言非其地也,且明德也。 +壬申,公朝于王所。 +丁丑,诸侯围许。 +晋侯有疾,曹伯之竖侯孺货筮史,使曰:“以曹为解。齐桓公为会而封异姓,今君为会而灭同姓。曹叔振铎,文之昭也。先君唐叔,武之穆也。且合诸侯而灭兄弟,非礼也。与卫偕命,而不与偕复,非信也。同罪异罚,非刑也。礼以行义,信以守礼,刑以正邪,舍此三者,君将若之何?”公说,复曹伯,遂会诸侯于许。 +晋侯作三行以御狄,荀林父将中行,屠击将右行,先蔑将左行。 +译文 +二十八年春季,晋文公准备攻打曹国,向卫国借路。卫国不答应。回来,从南河渡过黄河,入侵曹国,攻打卫国。正月初九日,占取了五鹿。二月,郤縠死。原轸率领中军,胥臣辅助下军,把原轸提升,是为了重视才德。晋文公和齐昭公在敛盂结盟。卫成公请求参加盟约,晋国人不答应。卫成公想亲附楚国,国内的人们不愿意,所以赶走了他们的国君,来讨好晋国。卫成公离开国都住在襄牛。 +公子买驻守在卫国,楚国人救援卫国,没有得胜。鲁僖公害怕晋国,杀了公子买来讨好晋国。骗楚国人说:“他驻守没到期就想回来,所以杀了他。” +晋文公发兵包围曹国,攻城,战死的人很多。曹军把晋军的尸体陈列在城上,晋文公很担心。听了士兵们的主意,声称“在曹国人的墓地宿营”。军队转移。曹国人恐惧,把他们得到的晋军的尸体装进棺材运出来,晋军由于曹军恐惧而攻城。三月初八日,进入曹国,责备曹国不任用僖负羁,做官坐车的反倒有三百人,并且说当年观看自己洗澡,现在罪有应得。下令不许进入僖负羁的家里,同时赦免他的族人,这是为了报答恩惠。魏犫、颠颉发怒说:“不替有功劳或者苦劳的人着想,还报答个什么恩惠?”放火烧了僖负羁的家。魏犫胸部受伤,晋文公想杀死他,但又爱惜他的才能,派人去慰问,同时观察病情。如果伤势很重,就准备杀了他。魏犫捆紧胸膛出见使者,说:“由于国君的威灵,难道我敢图安逸吗!”说着就向上跳了很多次,又向前跳了很多次。晋文公于是就饶恕了他,而杀死颠颉通报全军,立舟之侨作为车右。 +宋国派门尹般到晋军中报告危急情况。晋文公说:“宋国来报告危急情况,不去救他就断绝了交往,请求楚国解围,他们又不答应。我们想作战,齐国和秦国又不同意。怎么办?”先轸说:“让宋国丢开我国而去给齐国、秦国赠送财礼。假借他们两国去请求楚国。我们逮住曹国国君,把曹国、卫国的田地分给宋国。楚国喜欢曹国、卫国,一定不答应齐国和秦国的请求。齐国和秦国对宋国的财礼喜欢,而对楚国的固执很生气,能够不打仗吗?”晋文公很高兴,拘捕了曹共公,把曹国和卫国的田地分给了宋国人。楚成王进入申城并住下来,让申叔离开穀地,让子玉离开宋国,说:“不要去追逐晋国军队!晋文公在外边,十九年了,而果然得到了晋国。险阻艰难,都尝过了;民情真假,也都知道了。上天给予他年寿,同时除去了他的祸害,上天所设置的,难道可以废除吗?《军志》说:‘适可而止。’又说:‘知难而退。’又说:‘有德的人不能抵挡。’这三条记载,适用于晋国。” +子玉派遣伯棼向成王请战,说:“不敢说一定有功劳,愿意借此堵塞奸邪小人的口。”楚成王发怒,少给他军队,只有西广、东宫和若敖的一百八十辆战车跟去。 +子玉派宛春到晋军中报告说:“请恢复卫侯的君位,同时把土地退还曹国,我也解除对宋国的包围。”子犯说:“子玉无礼啊!给君王的,只是解除对宋国的包围一项,而要求君王给出的,却是复卫封曹两项。这次打仗的机会不可失掉了。”先轸说:“君王应该答应他的请求。安定别人叫做礼,楚国人一句话安定三国,我们一句话而使它们灭亡。我们就无礼,拿什么来作战呢?不答应楚国的请求,这是抛弃宋国;救援了又抛弃他,将对诸侯说什么?楚国有三项恩惠,我们有三项怨仇,怨仇已经太多了,准备拿什么作战?不如私下里答应恢复曹国和卫国来离间他们,逮了宛春来激怒楚国,等打起仗再说。”晋文公很高兴。于是把宛春囚禁在卫国,同时私下里允诺恢复曹、卫。曹、卫就与楚国断绝邦交。 +子玉发怒,追逐晋军。晋军撤退。军吏说:“以国君而躲避臣下,这是耻辱;而且楚军已经疲劳不堪,为什么退走?”子犯说:“出兵作战,有理就气壮,无理就气衰,哪里在于在外边时间的长短呢?如果没有楚国的恩惠,我们到不了这里。退三舍躲避他们,就是作为报答。背弃恩惠而说话不算数,要用这个来蔽护他们的敌人,我们缺理而楚国有理,加上他们的士气一向饱满,不能认为是衰疲。我们退走而楚军回去,我们还要求什么?如果他们不回去,国君退走,而臣下进犯,他们就缺理了。”晋军退走三舍。楚国骑士要停下来,子玉不同意。 +夏季,四月初一日,晋文公、宋成公、齐国的国归父、崔夭、秦国的小子慭驻在城催。楚军背靠着险要的地方扎营,晋文公担心这件事。听到士兵念诵说:“休耕田里的绿草繁茂,丢开旧草而对新的加以犁锄。”晋文公很疑惑。子犯说:“出战吧!战而得胜,一定得到诸侯;如果不胜,我国外有大河,内有高山,一定没有什么害处。”晋文公说:“对楚国的恩惠怎么办?”栾枝说:“汉水以北的姬姓诸国,楚国都把它们吞并完了。想着小恩惠,而忘记大耻大辱,不如出战。”晋文公梦中和楚王搏斗,楚王伏在自己身上咀嚼自己的脑浆,因而害怕。子犯说:“吉利。我得到上天,楚国伏罪,而且我们已经安抚他们了。” +子玉派遣鬬勃向晋国挑战,说:“请和君王的斗士作一次角力游戏,君王靠在车横板上观看,得臣可以陪同君王一起观看了。”晋文公派遣栾枝回答说:“我们国君知道您的意思了。楚君的恩惠,没有敢忘记,所以待在这里。我们以为大夫已经退兵了,臣下难道敢抵挡国君吗?既然大夫不肯退兵,那就烦大夫对贵部将士们说:‘准备好你们的战车,忠于你们的国事,明天早晨将再见面。’”晋国战车七百辆,装备齐全。晋文公登上有莘的废城观看军容,说:“年少的和年长的,排列有序,合于礼,可以使用了。”就命令砍伐山上的树木,以增加武器。 +初二日,晋军在莘北摆开阵势,胥臣让下军分别抵挡陈、蔡军队。子玉用若敖的一百八十乘率领中军,说:“今天一定灭掉晋国了。”子西率领左军,子上率领右军。胥臣把马蒙上老虎皮,先攻陈、蔡两军。陈、蔡两军奔逃,楚军的右翼部队溃散。狐毛派出前军两队击退楚军的溃兵。栾枝让车子拖着木柴假装逃走,楚军追击,原轸、郤溱率领中军的公族拦腰袭击。狐毛、狐偃率领上军夹攻子西,楚国的左翼部队溃散。楚军大败。子玉及时下令收兵,得以不败。 +晋军休整三天,吃楚军留下的粮食,到初六日起程回国。二十七日,到达衡雍,为天子在践土建造了一座王宫。 +这一战役之前的三个月,郑文公派军队到楚国助战,因为楚军已经失败而害怕了,派遣子人九和晋国讲和。晋国的栾枝进入郑国和郑文公订立盟约。 +五月初九日,晋文公和郑文公在衡雍结盟。初十日,把楚国的战俘献给周襄王:驷马披甲的战车一百辆,步兵一千人。郑文公作为相礼,用的是周平王时的礼仪。十二日,周襄王设享礼用甜酒招待晋文公,又允许他向自己回敬酒。周襄王命令尹氏和王子虎、内史叔兴父用策书任命晋文公为诸侯的领袖,赐给他大辂车、戎辂车以及相应的服装仪仗,红色的弓一把、红色的箭一百枝,黑色的弓十把和箭一千枝,黑黍加香草酿造的酒一卣,勇士三百人,说:“天子对叔父说:‘恭敬地服从天子的命令,以安抚四方诸侯,惩治王朝的邪恶。’”晋文公辞谢三次,然后接受命令,说:“重耳谨再拜叩头,接受和宣扬天子的重大赏赐和命令。”接受了策书就离开成周。从进入成周到离开,三次朝见周王。 +卫成公听说楚军失败,害怕,逃亡到楚国,又到了陈国,派遣元咺奉事叔武去接受盟约。二十六日,王子虎和诸侯在天子的庭院里盟誓,约定说:“全部辅助王室,不要互相伤害!谁要违背盟约,就要受到神的诛杀,使他军队颠覆,不能享有国家,直到你的玄孙,不论老小。”君子认为这次结盟是守信用的,认为晋国在这次战役中能够用道德来进攻。 +当初,楚国的子玉自己制作了镶玉的马冠马鞅,还没有使用。作战之前,梦见黄河河神对他说:“送给我,我赐给你孟诸的水草地。”子玉没有送去。他儿子大心和子西派荣黄劝谏,子玉不听。荣黄说:“死而有利于国家,尚且还要去做,何况是美玉呢?和国家比起来这不过是粪土罢了。如果可以使军队成功,有什么可惜的?”子玉仍然不肯。荣黄出来告诉两个人说:“不是神明让令尹失败,令尹不以百姓的事情为重,实在是自取失败啊。”子玉失败之后,楚成王派使臣对子玉说:“申、息的子弟大多伤亡了,大夫如果回来,怎么向申、息两地的父老交代呢?”子西、大心对使臣说:“子玉本来要自杀的,我们两个阻拦他说:‘不要自杀,国君还准备杀你呢。’”到达连穀,子玉就自杀了。 +晋文公听说子玉自杀的消息以后,喜形于色,说:“没有人再来为害于我了。蔿吕臣做令尹,不过是维护自己罢了,并不是为了百姓。” +有人在卫成公面前毁谤元咺说:“他已立了叔武做国君了。”元咺的儿子角跟随卫成公,卫成公派人杀了他。元咺并没有因此而废弃卫成公的命令,还是奉事叔武回国摄政。六月,晋国人听任卫侯回国。甯武子和卫国官吏、大族等在宛濮结盟,说:“上天降祸卫国,君臣不和谐,所以才遭到这样的忧患。现在天意保佑我国,让大家放弃成见而互相听从。没有留下的人,谁来守卫国家?没有跟随君王的人,谁去保卫那些牧牛养马的人?由于不和协,因此乞求在大神面前明白宣誓,以求天意保佑。从今天订立盟约之后,在外的人不要仗恃自己的功劳,留下的人不要害怕有罪。谁要违背盟约,祸害就降临到他头上。神明和先君在上,加以惩罚诛杀。”国内的人们知道了这盟约,才没有二心。 +卫成公比约定的日期先进入卫国,甯武子在卫成公之前,长牂把守城门,以为他是国君的使者,和他同乘一辆车进入。公子歂犬、华仲作为前驱,叔武正要洗发,听说国君来到,很高兴,用手抓着头发跑出来,前驱却把他射死了。卫成公知道他没有罪,把头枕在尸体的大腿上而哭他。歂犬逃跑,卫成公派人把他杀死了。元咺逃亡到晋国。 +在城濮的战役中,晋军的中军在沼泽地遇到大风,丢掉了前军左边的大旗。祁瞒犯了军令,司马把他杀了,并通报诸侯,派茅茷代替他。军队回来,六月十六日,渡过黄河,舟之侨擅自先行回国,士会代理车右。秋季,七月某一天,胜利归来,高唱凯歌进入晋国,在太庙报告俘获和杀死敌人的数字,饮酒犒赏,召集诸侯会盟和攻打有二心的国家。杀舟之侨并通报全国,百姓因此而大为顺服。君子认为:“晋文公能够严明刑罚,杀了颠颉、祁瞒、舟之侨三个罪人而百姓顺服。《诗》说:‘施惠于中原国家,安定四方的诸侯’,说的就是没有失去公正的赏赐和刑罚。” +冬季,僖公和晋文公、齐昭公、宋成公、蔡庄公、郑文公、陈子、莒子、邾子、秦同人在温地会见,商量出兵攻打不顺服的国家。 +卫成公和元咺争讼,甯武子作为卫成公的诉讼人,鍼庄子作为卫成公的代理人,士荣作为卫成公的答辩人。卫成公没有胜诉。作为诸侯领袖的晋国杀了士荣,砍了鍼庄子的脚,认为甯武子忠诚而赦免了他。逮捕卫成公,把他送到京师,关在牢房里。甯武子负责给卫成公送衣食。元咺回到卫国,立公子瑕为国君。 +这次温地的会盟,晋文公召请周襄王前来,并且带领诸侯朝见他,又让周襄王打猎。孔子说:“以臣下而召请君主,是不能作为榜样的。”所以《春秋》记载说“天王狩于河阳”,天下本都是周王朝的地方,而这里却不是周襄王的地方了,而且是为了表明晋国的功德而避讳的说法。 +十月初七日,僖公到周襄王的住处朝觐。 +十一月十二日,诸侯包围许国。 +晋文公有重病,曹共公的侍从侯獳贿赂晋文公的筮史,让他把得病的原因说成是由于灭了曹国。他就对晋文公说:“齐桓公主持会盟而封异姓的国家,现在君王主持会盟而灭同姓的国家。曹国的叔振铎,是文王的儿子;先君唐叔,是武王的儿子。而且会合诸侯而灭掉兄弟之国,这是不符合礼仪的;曹国和卫国一样得到君王的诺言,但是不能一同复国,这是不讲信用的;罪过相同而惩罚不同,这是不符合刑律的。礼仪用来推动道义,信用用来保护礼仪,刑律用来纠正邪恶。丢开了这三项,君王准备怎么办?”晋文公很高兴,恢复了曹共公的君位,曹共公就在许国和诸侯会盟。 +晋文公建立三个步兵师来抵抗狄人,荀林父将领中行,屠击将领右行,先蔑将领左行。 + + +僖公二十九年 +【经】二十有九年春,介葛卢来。公至自围许。夏六月,会王人、晋人、宋人、齐人、陈人、蔡人、秦人盟于翟泉。秋,大雨雹。冬,介葛卢来。 +【传】二十九年春,葛卢来朝,舍于昌衍之上。公在会,馈之刍米,礼也。 +夏,公会王子虎、晋狐偃、宋公孙固、齐国归父、陈辕涛涂、秦小子憖,盟于翟泉,寻践土之盟,且谋伐郑也。卿不书,罪之也。在礼,卿不会公、侯,会伯、子、男可也。 +秋,大雨雹,为灾也。 +冬,介葛卢来,以未见公,故复来朝,礼之,加燕好。 +介葛卢闻牛鸣,曰:“是生三牺,皆用之矣,其音云。”问之而信。 +译文 +二十九年春季,介葛卢前来朝见,让他住在昌衍山上。当时鲁僖公正在参加许国翟泉的会见,赠送给他草料、粮食等物,这是合于礼的。 +夏季,僖公和王子虎、晋国狐偃、宋国公孙固、齐国国归父、陈国辕涛涂、秦国小子?在翟泉结盟,重温践土的盟约,同时策划进攻郑国。参加结盟的卿没有记载,这是表示谴责他们。按照礼制,诸侯的卿不能参加公、侯的会见,参加伯、子、男的会见是可以的。 +秋季,有大雨和雹子,成了灾害,《春秋》才加以记载。 +冬季,介葛卢前来,由于前次没有见到僖公,再次来朝。对他加以礼遇,再加上燕礼和赠送上等财礼。 +介葛卢听到牛叫,说:“这头牛生了三头小牛,都用来祭祀了,所以它的声音如此。”加以询问,果然这样。 + +僖公三十年 +【经】三十年春王正月。夏,狄侵齐。秋,卫杀其大夫元咺及公子瑕。卫侯郑归于卫。晋人、秦人围郑。介人侵萧。冬,天王使宰周公来聘。公子遂如京师。遂如晋。 +【传】三十年春,晋人侵郑,以观其可攻与否。狄间晋之有郑虞也,夏,狄侵齐。 +晋侯使医衍鸩卫侯。宁俞货医,使薄其鸩,不死。公为之请,纳玉于王与晋侯。皆十□王许之。秋,乃释卫侯。卫侯使赂周颛、治廑,曰:“苟能纳我,吾使尔为卿。”周、冶杀元咺及子适、子仪。公入祀先君。周、冶既服将命,周颛先入,及门,遇疾而死。冶廑辞卿。 +九月甲午,晋侯、秦伯围郑,以其无礼于晋,且贰于楚也。晋军函陵,秦军汜南。佚之狐言于郑伯曰:“国危矣,若使烛之武见秦君,师必退。”公从之。辞曰:“臣之壮也,犹不如人,今老矣,无能为也已。”公曰:“吾不能早用子,今急而求子,是寡人之过也。然郑亡,子亦有不利焉。”许之,夜缒而出,见秦伯,曰:“秦、晋围郑,郑既知亡矣。若亡郑而有益于君,敢以烦执事。越国以鄙远,君知其难也,焉用亡郑以陪邻。邻之厚,君之薄也。若舍郑以为东道主,行李之往来,共其乏困,君亦无所害。且君尝为晋君赐矣,许君焦、瑕,朝济而夕设版焉,君之所知也。夫晋何厌之有?既东封郑,又欲肆其西封,不阙秦,将焉取之?阙秦以利晋,唯君图之。”秦伯说,与郑人盟,使杞子、逢孙、扬孙戍之,乃还。 +子犯请击之,公曰:“不可。微夫人力不及此。因人之力而敝之,不仁。失其所与,不知。以乱易整,不武。吾其还也。”亦去之。 +初,郑公子兰出奔晋,从于晋侯。伐郑,请无与围郑。许之,使待命于东。郑石甲父、侯宣多逆以为大子,以求成于晋,晋人许之。 +冬,王使周公阅来聘,飨有昌蜀、白、黑、形盐。辞曰:“国君,文足昭也,武可畏也,则有备物之飨以象其德。荐五味,羞嘉谷,盐虎形,以献其功。吾何以堪之?” +东门襄仲将聘于周,遂初聘于晋。 +译文 +三十年春季,晋国人入侵郑国,以此来试探郑国是否可以攻打。狄人钻了晋国侵犯郑国这个空子,夏季,狄人入侵齐国。 +晋文公派了医生衍毒死卫成公。甯俞贿赂医生,让他少放点毒药,所以卫成公没有被毒死。僖公为卫成公请求,把玉献给周襄王和晋文公,都是十对。周襄王允许了。秋季,卫成公被释放了。 +卫成公派人贿赂周歂、冶廑说:“如果能接纳我当国君,我让你们当卿。”周、冶两人杀了元咺和子适、子仪。卫成公回国,在太庙祭祀先君,周、冶两人已经穿好卿的礼服,准备接受任命,周歂先进太庙,到门口,发病而死。冶廑骇怕了,便辞去卿位。 +九月初十日,晋文公、秦穆公包围郑国,因为郑国对晋国无礼,而且心向着楚国。晋军驻扎在函陵,秦军驻扎在汜南。佚之狐对郑文公说:“国家危急了。假若派遣烛之武去进见秦君,军队必然退走。”郑文公采纳了这个建议,便请烛之武去进见秦君,烛之武推辞说:“下臣年壮的时候,尚且不如别人;现在老了,无能为力了。”郑文公说:“我没有能及早任用您,现在形势危急而来求您,这是我的过错。然而郑国被灭亡,您也不好啊。”烛之武答应了,夜里用绳子把自己从城上吊到城外,进见秦穆公,说:“秦、晋两国包围郑国,郑国已经知道自己要灭亡了。如果灭亡郑国而对君王有好处,那是值得劳动君王左右随从的。越过别国而以远方的土地作为边邑,君王知道是不容易的,哪里用得着灭亡郑国来增加邻国的土地?邻国实力加强,就是君王的削弱。如果赦免郑国,让他做东路上的主人,使者的往来,供应他所缺少的一切东西,对君王也没有害处。而且君王曾经把好处赐给晋国国君了,他答应给君王焦、瑕两地,早晨过河回国,晚上就设版筑城,这是君王所知道的。晋国哪有满足的时候,已经在东边向郑国开拓土地,又要肆意扩大它西边的土地。如果不损害秦国,还能到哪里去取得土地呢?损害秦国来有利于晋国的事,请君王考虑。”秦穆公很高兴,和郑国人结盟,派遣杞子、逢孙、杨孙在郑国戍守,就撤退了。 +子犯请求追击秦军。晋文公说:“不行。如果没有他们的力量,我们不会有今天这个地位。靠了别人的力量,反而损害他,这是不讲仁德;失掉了同盟国家,这是不明智;用动乱代替整齐,这是不勇敢。我还是回去吧。”晋文公也就撤军回国。 +当初,郑国的公子兰逃亡到晋国,跟随晋文公攻打郑国,请求不要参加对郑都的包围。晋文公答应了,让他在东部边境等候命令。郑国的石甲父、侯宣多把他接回来做太子,向晋国讲和,晋国允许了。 +冬季,周襄王派遣周公阅来鲁国聘问,宴请他的食物有昌蒲菹、白米糕、黑黍糕和虎形块盐。周公阅推辞说:“国家的君主,文治足以显扬四方,武功可以使人畏惧,就备有各种物品宴请,以像征他的德行;进五味的调和,献美好的粮食,有虎形的盐,以像征他的功业。我怎么当得起这个?” +东门襄仲将要到成周聘问,就顺路到晋国作初次聘问。 + +僖公三十一年 +【经】三十有一年春,取济西田。公子遂如晋。夏四月,四卜郊,不从,乃免牲。犹三望。秋七月。冬,杞伯姬来求妇。狄围卫。十有二月,卫迁于帝丘。 +【传】三十一年春,取济西田,分曹地也。使臧文仲往,宿于重馆。重馆人告曰:“晋新得诸侯,必亲其共,不速行,将无及也。”从之,分曹地,自洮以南,东傅于济,尽曹地也。 +襄仲如晋,拜曹田也。 +夏四月,四卜郊,不从,乃免牲,非礼也。犹三望,亦非礼也。礼不卜常祀,而卜其牲、日,牛卜日曰牲。牲成而卜郊,上怠慢也。望,郊之细也。不郊,亦无望可也。 +秋,晋搜于清原,作五军御狄。赵衰为卿。 +冬,狄围卫,卫迁于帝丘。卜曰三百年。卫成公梦康叔曰:“相夺予享。”公命祀相。宁武子不可,曰:“鬼神非其族类,不歆其祀。杞、鄫何事?相之不享于此。久矣,非卫之罪也,不可以间成王、周公之命祀。请改祀命。” +郑泄驾恶公子瑕,郑伯亦恶之,故公子瑕出奔楚。 +译文 +三十一年春季,取得济水以西的田土,这本是分割给曹国的土地。派臧文仲前去,住在重地的宾馆里。重地宾馆里的人告诉他说:“晋国新近得到许多诸侯国家为盟邦,必定亲近恭顺他的人,你不快点走,怕会赶不上。”臧文仲听从了。分割曹国的土地,从洮水以南,东边挨着济水,都是曹国的土地。 +襄仲到晋国去,拜谢取得曹国的田地。 +夏季,四月,四次占卜郊祭,都不吉利,就不举行郊祭,不杀牛,这是不合于礼的。仍旧祭祀名山大川泰山、淮水、东海三处,这也是不合于礼的。按礼制,不占卜常规的祭祀,而只是占卜使用的牺牲和日期。牛,在占卜到好日子以后就改称牲,已经成为牲而还要占卜郊祭的吉凶,这是在上者侮慢大典、亵渎龟甲。望祭,是郊祭的细节,不举行郊祭,更不必举行对山川的望祭。 +秋季,晋国在清原检阅军队,建立五个军来抵抗狄人。赵衰被任命为卿。 +冬季,狄人包围卫国,卫国迁移到帝丘,占卜的结果是立国三百年。卫成公梦见康叔说:“相夺走了我的祭献。”成公命令祭祀相。甯武子不同意,说:“不是同族人的祭祀,鬼神就不享用那种祭品。杞国和鄫国为什么不祭祀?相在杞国和卫国没有受到祭献很久了,这不是卫国的罪过,不能违反成王、周公所规定的祭祀,请求您改变祭祀相的命令。”郑国的洩驾讨厌公子瑕,郑文公也很讨厌他,所以公子瑕逃亡到楚国。 + + +僖公三十二年 +【经】三十有二年春王正月。夏四月己丑,郑伯捷卒。卫人侵狄。秋,卫人及狄盟。冬十有二月己卯,晋侯重耳卒。 +【传】三十二年春,楚斗章请平于晋,晋阳处父报之。晋、楚始通。 +夏,狄有乱。卫人侵狄,狄请平焉。秋,卫人及狄盟。 +冬,晋文公卒。庚辰,将殡于曲沃,出绛,柩有声如牛。卜偃使大夫拜。曰:“君命大事。将有西师过轶我,击之,必大捷焉。”杞子自郑使告于秦,曰:“郑人使我掌其北门之管,若潜师以来,国可得也。”穆公访诸蹇叔,蹇叔曰:“劳师以袭远,非所闻也。师劳力竭,远主备之,无乃不可乎!师之所为,郑必知之。勤而无所,必有悖心。且行千里,其谁不知?”公辞焉。召孟明、西乞、白乙,使出师于东门之外。蹇叔哭之,曰:“孟子,吾见师之出而不见其入也。”公使谓之曰:“尔何知?中寿,尔墓之木拱矣。”蹇叔之子与师,哭而送之,曰:“晋人御师必于殽。殽有二陵焉。其南陵,夏后皋之墓也;其北陵,文王之所辟风雨也。必死是间,余收尔骨焉。”秦师遂东。 +译文 +三十二年春季,楚国的鬬章到晋国请求讲和,晋国的阳处父到楚国回聘,晋国和楚国从此开始正式交往。 +夏季,狄人发生动乱,卫军侵袭狄人,狄人请求讲和。秋季,卫国和狄结盟。 +冬季,晋文公死。十二月初十日,准备把棺材送在曲沃停放。离开绛城,棺材里有声音像牛叫。卜偃请大夫跪拜,说:“国君发布军事命令:将要有西边的军队过境袭击我国,如果攻击他们,必定大胜。”杞子从郑国派人告诉秦国说:“郑国人让我掌管他们北门的钥匙,如果偷偷地把兵开来,可以占领他们的国都。”秦穆公去问蹇叔。蹇叔说:“使军队疲劳而去侵袭相距遥远的地方,我没有听说过。军队疲劳,力量衰竭,远地的国家有防备,恐怕不行吧!我们军队的行动,郑国一定知道,费了力气不讨好,士兵一定有抵触情绪。而且行军走一千里,谁会不知道?”秦穆公不接受他的意见。召见盂明、西乞、白乙,让他们在东门外出兵。蹇叔哭着送他们说:“孟子,我看到军队出去而看不到回来了!”秦穆公派人对他说:“你知道什么?如果你六七十岁死了,你坟上的树木已经合抱了。”蹇叔的儿子在军队里,蹇叔哭着送他,说:“晋国人必定在殽山抵御我军,殽山有两座山陵。它的南陵,是夏后皋的坟墓;它的北陵,是文王在那里避过风雨的地方。你必定死在两座山陵之间,我去那里收你的尸骨吧!”秦国军队就向东进发。 + +僖公三十三年 +【经】三十有三年春王二月,秦人入滑。齐侯使国归父来聘。夏四月辛巳,晋人及姜戎败秦师于殽。癸巳,葬晋文公。狄侵齐。公伐邾,取訾娄。秋,公子遂帅师伐邾。晋人败狄于箕。冬十月,公如齐。十有二月,公至自齐。乙巳,公薨于小寝。陨霜不杀草。李梅实。晋人、陈人、郑人伐许。 +【传】三十三年春,秦师过周北门,左右免胄而下。超乘者三百乘。王孙满尚幼,观之,言于王曰:“秦师轻而无礼,必败。轻则寡谋,无礼则脱。入险而脱。又不能谋,能无败乎?”及滑,郑商人弦高将市于周,遇之。以乘韦先,牛十二犒师,曰:“寡君闻吾子将步师出于敝邑,敢犒从者,不腆敝邑,为从者之淹,居则具一日之积,行则备一夕之卫。”且使遽告于郑。 +则束载、厉兵、秣马矣。使皇武子辞焉,曰:“吾子淹久于敝邑,唯是脯资饩牵竭矣。为吾子之将行也,郑之有原圃,犹秦之有具囿也。吾子取其麋鹿以闲敝邑,若何?”杞子奔齐,逢孙、扬孙奔宋。孟明曰:“郑有备矣,不可冀也。攻之不克,围之不继,吾其还也。”灭滑而还。 +齐国庄子来聘,自郊劳至于赠贿,礼成而加之以敏。臧文仲言于公曰:“国子为政,齐犹有礼,君其朝焉。臣闻之,服于有礼,社稷之卫也。” +晋原轸曰:“秦违蹇叔,而以贪勤民,天奉我也。奉不可失,敌不可纵。纵敌患生,违天不祥。必伐秦师。”栾枝曰:“未报秦施而伐其师,其为死君乎?”先轸曰:“秦不哀吾丧而伐吾同姓,秦则无礼,何施之为?吾闻之,一日纵敌,数世之患也。谋及子孙,可谓死君乎?”遂发命,遽兴姜戎。子墨衰絰,梁弘御戎,莱驹为右。 +夏四月辛巳,败秦师于殽,获百里孟明视、西乞术、白乙丙以归,遂墨以葬文公。晋于是始墨。 +文嬴请三帅,曰:“彼实构吾二君,寡君若得而食之,不厌,君何辱讨焉!使归就戮于秦,以逞寡君之志,若何?”公许之,先轸朝。问秦囚。公曰:“夫人请之,吾舍之矣。”先轸怒曰:“武夫力而拘诸原,妇人暂而免诸国。堕军实而长寇仇,亡无日矣。”不顾而唾。公使阳处父追之,及诸河,则在舟中矣。释左骖,以公命赠孟明。孟明稽首曰:“君之惠,不以累臣衅鼓,使归就戮于秦,寡君之以为戮,死且不朽。若从君惠而免之,三年将拜君赐。” +秦伯素服郊次,乡师而哭曰:“孤违蹇叔以辱二三子,孤之罪也。不替孟明,孤之过也。大夫何罪?且吾不以一眚掩大德。” +狄侵齐,因晋丧也。 +公伐邾,取訾娄,以报升陉之役。邾人不设备。秋,襄仲复伐邾。 +狄伐晋,及箕。八月戊子,晋侯败狄于箕。郤缺获白狄子。先轸曰:“匹夫逞志于君而无讨,敢不自讨乎?”免胄入狄师,死焉。狄人归其元,面如生。 +初,臼季使过冀,见冀缺耨,其妻盍之。敬,相待如宾。与之归,言诸文公曰:“敬,德之聚也。能敬必有德,德以治民,君请用之。臣闻之,出门如宾,承事如祭,仁之则也。”公曰:“其父有罪,可乎?”对曰:“舜之罪也殛鲧,其举也兴禹。管敬仲,桓之贼也,实相以济。《康诰》曰:‘父不慈,子不祗,兄不友,弟不共,不相及也。’《诗》曰:‘采葑采菲,无以下体。’君取节焉可也。”文公以为下军大夫。反自箕,襄公以三命命先且居将中军,以再命命先茅之县赏胥臣曰:“举郤缺,子之功也。”以一命命郤缺为卿,复与之冀,亦未有军行。 +冬,公如齐,朝,且吊有狄师也。反,薨于小寝,即安也。 +晋、陈、郑伐许,讨其贰于楚也。 +楚令尹子上侵陈、蔡。陈、蔡成,遂伐郑,将纳公子瑕,门于桔柣之门。瑕覆于周氏之汪,外仆髡屯禽之以献。文夫人敛而葬之郐城之下。 +晋阳处父侵蔡,楚子上救之,与晋师夹泜而军。阳子患之,使谓子上曰:“吾闻之,文不犯顺,武不违敌。子若欲战,则吾退舍,子济而陈,迟速唯命,不然纾我。老师费财,亦无益也。”乃驾以待。子上欲涉,大孙伯曰:“不可。晋人无信,半涉而薄我,悔败何及,不如纾之。”乃退舍。阳子宣言曰:“楚师遁矣。”遂归。楚师亦归。大子商臣谮子上曰:“受晋赂而辟之,楚之耻也,罪莫大焉。”王杀子上。 +葬僖公,缓作主,非礼也。凡君薨,卒哭而祔,祔而作主,特祀于主,烝尝禘于庙。 +译文 +三十三年春季,秦国军队经过成周王城的北门,战车上除御者以外,车左、车右都脱去头盔下车致敬,随即跳上车去的有三百辆战车的将士。王孙满年纪还小,看到了,对周襄王说:“秦国军队不庄重又没有礼貌,一定失败。不庄重就缺少计谋,无礼貌就不严肃。进入险地而满不在乎,又不能出主意,能够不打败仗吗?” +秦军到达滑国,郑国的商人弦高准备到成周做买卖,碰到秦军,先送秦军四张熟牛皮作引礼,再送十二头牛犒劳军队,说:“寡君听说您准备行军经过敝邑,谨来犒赏您的随从。敝邑贫乏,为了您的随从在这里停留,住下就预备一天的供应,离开就准备一夜的保卫。”弦高同时又派传车紧急地向郑国报告。郑穆公派人去探看杞子等人的馆舍,发现他们已经装束完毕、磨利武器、喂饱马匹了。派皇武子辞谢他们,说:“大夫们久住在这里,敝邑的干肉、粮食、牲口都竭尽了。为了大夫们将要离开,郑国的有原圃,就如同秦国的有具圃,大夫们自己猎取麋鹿,使敝邑得有闲空,怎么样?”于是杞子逃到齐国,逢孙、杨孙逃到宋国。孟明说:“郑国有准备了,不能存有希望了。攻打郑国不能取胜,包围它又没有后援,我还是回去吧。”灭亡了滑国就回去。 +齐国的国庄子前来聘问,从郊外迎接一直到赠礼送行,礼节周到,仪容又好。臧文仲对僖公说:“国子执政,齐国还是有礼的,君王去朝见吧!下臣听说:对有礼之邦顺服,这是国家的保障。” +晋国的先轸说:“秦君违背蹇叔的话,由于贪婪而劳动百姓,这是上天给予我们的机会。给予的不能丢失,敌人不能放走。放走敌人,就会发生祸患;违背天意,就不吉利。一定要进攻秦国军队。”栾枝说:“没有报答秦国的恩惠而进攻它的军队,心目中还有死去的国君吗?”先轸说:“我们有丧事秦国不悲伤,反而攻打我们的同姓国家,他们就是无礼,还讲什么恩惠?我听说:‘一天放走敌人,这是几代的祸患。’为子孙后代打算,这可以有话对死去的国君说了吧!”于是就发布起兵的命令,立即动员姜戎的军队。晋襄公把丧服染成黑色,梁弘驾御战车,莱驹作为车右。 +夏季,四月十三日,在殽山把秦国军队打得一个人不留,并且俘虏了三个指挥官百里孟明视、西乞术、白乙丙而回去。于是就穿着黑色的丧服来安葬晋文公。晋国从此开始使用黑色丧服。 +文嬴请求把三位指挥官释放回国,说:“他们挑拨我们两国国君,寡君如果抓到他们,吃他们的肉还不能满足,何必劳君王去讨伐呢?让他们回到秦国受诛杀,以使寡君快意,怎么样?”晋襄公答应了。先轸上朝,问起秦国的囚犯,晋襄公说:“母亲代他们提出请求,我就放走他们了。”先轸生气地说:“武人花力气在战场上逮住他们,女人说几句谎话就把他们在国内放了,毁弃了战果而长了敌人的志气,晋国快要灭亡了!”先轸不顾襄公在面前就在地上吐唾沫。晋襄公派阳处父追赶放走的三个人,追到黄河边上,他们已经上船了。阳处父解下车左边的骖马,用晋襄公的名义赠送给他们。孟明叩头说:“承蒙君王的恩惠,不用被囚之臣来祭鼓,让我们回到秦国去受诛戮,寡君如果杀了我们,死了以后名声不朽,如果依从君王的恩惠而赦免了我们,三年之后将要拜谢君王恩赐。” +秦穆公穿着素服住在郊外,对着被释放回来的将士号哭,说:“我没有听蹇叔的话,使你们几位受到侮辱,这是我的罪过。不撤回孟明的驻军,这也是我的过错,你们三位有什么罪?而且我不能用一次的过错来掩盖大德。” +狄人入侵齐国,因为晋国有丧事,不能顾及派兵支援齐国。僖公进攻邾国,占取了訾娄,以报复升陉这一战役。邾国没有设防,秋季,襄仲再一次攻打邾国。 +狄军攻打晋国,到达箕地。八月二十二日,晋襄公在箕地打败狄军。郤缺俘虏了白狄子。先轸说:“一个普通人在国君面前放肆而没有受惩罚,哪里敢不自己惩罚自己?”先轸脱下头盔冲入狄军中,死在战阵上。狄人送回他的脑袋,面色像活着一样。 +当初,臼季出使,经过冀国,看到冀缺在锄田除草,他妻子给他送饭,很恭敬,彼此像待客人一样。臼季和冀缺一起回到国都,对文公说:“恭敬,是德行的集中表现。能够恭敬,就必定有德行。德行用来治理百姓,请君王任用他。臣听说:‘出门好像会见宾客,承担事情好像参加祭祀,这是仁爱的准则。’”晋文公说:“他的父亲冀芮有罪,可以吗?”臼季回答:“舜惩办罪人,流放了鲧,他举拔人材却起用鲧的儿子禹。管敬仲是桓公的敌人,任命他为相而得到成功。《康诰》说:‘父亲不慈爱,儿子不诚敬,哥哥不友爱,弟弟不恭敬,这是与别人无关的。’《诗》说:‘采蔓菁,采萝卜,不要把它下部当废料。’您挑用他的好的地方就可以了。”晋文公让冀缺担任下军大夫。从箕地回来,晋襄公用诸侯大臣中的最高级别命令先且居率领中军,用次等级别命令把先茅的县赏给胥臣,说:“推举郤缺,是你的功劳。”用三等级别命令郤缺做卿,再给他冀地,但是没有军职。 +冬季,僖公到齐国朝见,同时对狄人进攻这件事表示慰问。回国,死在路寝里,是因为贪图安逸的缘故。 +晋国、陈国、郑国进攻许国,惩罚它倾向楚国。 +楚国令尹子上攻打陈国、蔡国。陈国、蔡国和楚国讲和,又进攻郑国,准备把公子瑕送回去做国君。在桔秩之门攻城,公子瑕的战车翻倒在周氏的池塘中,外边的仆人髠抓住了他献给郑文公。文公夫人为他殡敛而安葬在郐城下。 +晋国的阳处父入侵蔡国,楚国的子上前去救援,和晋军夹着泜水对峙。阳处父担心,派人对子上说:“我听说:‘文的不能触犯顺理的人,武的不能躲避仇敌之辈。’您如果想打,那么我就后退三十里,您渡河再摆开阵势,早打晚打听您的。不这样,让我缓口气,军士劳累,费钱财,也没有什么好处。”于是就驾上马车等着他。子上想要渡河,大孙伯说:“不行。晋国人不讲信用,如果乘我们渡过一半而迫击我们,那时战败而后悔,哪里还来得及?不如让他们缓口气。”于是就后退三十里。阳子宣布说:“楚国军队逃走了。”就回国去了。楚国军队也就回国。太子商臣诬告子上说:“子上接受了晋国的贿赂而躲避他们,这是楚国的耻辱。罪没有比这再大的了。”楚成王杀死了子上。 +安葬僖公,没有及时制作神主牌位,这是不合于礼的。凡国君死去,安葬后十多天停止了不定时的号哭,就把死者的神主附祭于祖庙,附祭就要制作神主牌位,单独向新死者的神主祭祀,烝祭、尝祭、禘祭就在祖庙中连同其他祖先一起祭祀。 + +文公 + +文公元年 +【经】元年春王正月,公即位。二月癸亥,日有食之。天王使叔服来会葬。夏四月丁巳,葬我君僖公。天王使毛伯来锡公命。晋侯伐卫。叔孙得臣如京师。卫人伐晋。秋,公孙敖会晋侯于戚。冬十月丁未,楚世子商臣弑其君頵。公孙敖如齐。 +【传】元年春,王使内史叔服来会葬。公孙敖闻其能相人也,见其二子焉。叔服曰:“谷也食子,难也收子。谷也丰下,必有后于鲁国。” +于是闰三月,非礼也。先王之正时也,履端于始,举正于中,归余于终。履端于始,序则不愆。举正于中,民则不惑。归余于终,事则不悖。 +夏四月丁巳,葬僖公。 +王使毛伯卫来锡公命。叔孙得臣如周拜。 +晋文公之季年,诸侯朝晋。卫成公不朝,使孔达侵郑,伐绵、訾,及匡。晋襄公既祥,使告于诸侯而伐卫,及南阳。先且居曰:“效尤,祸也。请君朝王,臣从师。”晋侯朝王于温,先且居、胥臣伐卫。五月辛酉朔,晋师围戚。六月戊戌,取之,获孙昭子。 +卫人使告于陈。陈共公曰:“更伐之,我辞之。”卫孔达帅师伐晋,君子以为古。古者越国而谋。 +秋,晋侯疆戚田,故公孙敖会之。 +初,楚子将以商臣为大子,访诸令尹子上。子上曰:“君之齿未也。而又多爱,黜乃乱也。楚国之举。恒在少者。且是人也。蜂目而豺声,忍人也,不可立也。”弗听。既又欲立王子职而黜大子商臣。商臣闻之而未察,告其师潘崇曰:“若之何而察之?”潘崇曰:“享江问而勿敬也。”从之。江芈怒曰:“呼,役夫!宜君王之欲杀女而立职也。”告潘崇曰:“信矣。”潘崇曰:“能事诸乎?”曰:“不能。”“能行乎?”曰:“不能。”“能行大事乎?”曰:“能。” +冬十月,以宫甲围成王。王请食熊蹯而死。弗听。丁未,王缢。谥之曰:“灵”,不瞑;曰:“成”,乃瞑。穆王立,以其为大子之室与潘崇,使为大师,且掌环列之尹。 +穆伯如齐,始聘焉,礼也。凡君即位,卿出并聘,践修旧好,要结外授,好事邻国,以卫社稷,忠信卑让之道也。忠,德之正也;信,德之固也;卑让,德之基也。 +殽之役,晋人既归秦帅,秦大夫及左右皆言于秦伯曰:“是败也,孟明之罪也,必杀之。”秦伯曰:“是孤之罪也。周芮良夫之诗曰;‘大风有隧,贪人败类,听言则对,诵言如醉,匪用其良,覆俾我悖。’是贪故也,孤之谓矣。孤实贪以祸夫子,夫子何罪?”复使为政。 +译文 +元年春季,周襄王派遣内史叔服来鲁国参加僖公的葬礼。公孙敖听说叔服能给人看相,便引出自己两个儿子穀和难来见他。叔服说:“穀可以祭祀供养您,难可以安葬您。穀的下颔丰满,后代在鲁国必然昌大。” +今年闰三月,这是不合传统习惯的。先王端正时令,年历的推算以冬至作为开始,测定春分、秋分、夏至、冬至的月份作为四季的中月,把剩余的日子归在一年的末尾。年历的推算以冬至作为开始,四季的次序就不会错乱;以正朔的月份作为标准,百姓就不会迷惑;把剩余的月份归总在一年的终了置闰月,事情就不会差误。 +夏季,四月二十六日,安葬僖公。周襄王派遣毛伯卫来鲁国赐给鲁文公写在竹简上的奖状。叔孙得臣到成周答谢。 +晋文公的晚年,诸侯朝见晋国,卫成公不去朝见,反而派遣孔达侵袭郑国,攻打绵、訾和匡地。晋襄公在举行小祥祭祀以后,派人通告诸侯而讨伐卫国,到达南阳。先且居说:“学坏样子,这是祸害。请您朝觐周天子,下臣跟随军队。”晋襄公在温地朝觐了周襄王。先且居、胥臣进攻卫国。五月初一日,晋军包围戚地。六月初八日,占取戚地,俘虏了孙昭子。 +卫国人派人报告陈国。陈共公说:“转过去进攻他们。我去对他们说。”卫国的孔达就率兵进攻晋国。君子认为,这样做属于过于粗心。粗心,指的是让别国给自己出主意。 +秋季,晋襄公划定戚地田土的疆界,所以公孙敖参加了。 +当初,楚成王打算立商臣为太子,征求令尹子上的意见。子上说:“君王的年纪还不算大,而且内宠又多,立了商臣再加以废黜,就会有祸乱。楚国立太子,常常选择年轻的。而且商臣这个人,眼睛像胡蜂,声音像豺狼,是一个残忍的人,不能立为太子。”楚成王没有听从。立了商臣以后,又想立王子职而废掉太子商臣。商臣听到消息但还没有弄准确,告诉他老师潘崇说:“怎么样能弄准确?”潘崇说:“你设宴招待江芈而故意表示不尊敬。”商臣这样做了。江芈发怒说:“啊!贱东西!难怪君王要杀掉你而立职做太子。”商臣告诉潘崇说:“事情确实了。”潘崇说:“你能事奉公子职吗?”商臣说:“不能。”潘崇说:“能逃亡出国吗?”商臣说:“不能。”潘崇说:“能够办大事吗?”商臣说:“能。” +冬季,十月,商臣率领宫中的警卫军包围楚成王,并且逼成王自杀。成王请求吃了熊掌以后去死,商臣不答应。十八日,楚成王上吊而死。给他上谥号称为“灵”,尸体不闭眼睛;谥为“成”,才闭上眼睛。楚穆王即位,把他做太子时的房屋财物给了潘崇,让潘崇做太师,而且作为掌管宫中警卫军的长官。 +穆伯到齐国去,开始聘问,这是合于礼的。凡是国君即位,卿出国普遍聘问,继续重温过去的友好,团结外援,善待邻国,来保卫国家,这是合于忠、信、卑让的。忠,意味政治道德的纯正;信,意味政治道德的巩固;卑让,意味政治道德有基础。 +殽地这次战役,晋国放回了秦国的主将,秦国的大夫和左右待臣都对秦穆公说:“这次战败,是孟明的罪过,一定要杀死他。”秦穆公说:“这是我的罪过。周朝芮良夫的诗说:‘大风迅猛把一切摧毁,贪婪的人把善良败坏。听到不相干的就喜欢插嘴,听到《诗》、《书》就打瞌睡,不能任用有才能的人,反而使我和道义相背。’这是由于贪婪的缘故,说的就是我啊。我由于贪婪而使孟明受祸,孟明有什么罪?”重新让孟明执政。 + +文公二年 +【经】二年春王二月甲子,晋侯及秦师战于彭衙,秦师败绩。丁丑,作僖公主。三月乙巳,及晋处父盟。夏六月,公孙敖会宋公、陈侯、郑伯、晋士縠盟于垂陇。自十有二月不雨,至于秋七月。八月丁卯,大事于大庙,跻僖公。冬,晋人、宋人、陈人、郑人伐秦。公子遂如齐纳币。 +【传】二年春,秦孟明视帅师伐晋,以报殽之役。二月晋侯御之。先且居将中军,赵衰佐之。王官无地御戎,狐鞫居为右。甲子,及秦师战于彭衙。秦师败绩。晋人谓秦“拜赐之师”。 +战于殽也,晋梁弘御戎,莱驹为右。战之明日,晋襄公缚秦囚,使莱驹以戈斩之。囚呼,莱驹失戈,狼瞫取戈以斩囚,禽之以从公乘,遂以为右。箕之役,先轸黜之而立续简伯。狼瞫怒。其友曰:“盍死之?”瞫曰:“吾未获死所。”其友曰:“吾与女为难。”瞫曰;“《周志》有之,‘勇则害上,不登于明堂。’死而不义,非勇也。共用之谓勇。吾以勇求右,无勇而黜,亦其所也。谓上不我知,黜而宜,乃知我矣。子姑待之。”及彭衙,既陈,以其属驰秦师,死焉。晋师从之,大败秦师。君子谓:“狼瞫于是乎君子。诗曰:‘君子如怒,乱庶遄沮。’又曰:‘王赫斯怒,爰整其旅。’怒不作乱而以从师,可谓君子矣。” +秦伯犹用孟明。孟明增修国政,重施于民。赵成子言于诸大夫曰:“秦师又至,将必辟之,惧而增德,不可当也。诗曰:‘毋念尔祖,聿修厥德。’孟明念之矣,念德不怠,其可敌乎?” +丁丑,作僖公主,书,不时也。 +晋人以公不朝来讨,公如晋。夏四月己巳,晋人使阳处父盟公以耻之。书曰:“及晋处父盟。”以厌之也。适晋不书,讳之也。公未至,六月,穆伯会诸侯及晋司空士縠盟于垂陇,晋讨卫故也。书士縠,堪其事也。 +陈侯为卫请成于晋,执孔达以说。 +秋八月丁卯,大事于大庙,跻僖公,逆祀也。于是夏父弗忌为宗伯,尊僖公,且明见曰:“吾见新鬼大,故鬼小。先大后小,顺也。跻圣贤,明也。明、顺,礼也。” +君子以为失礼。礼无不顺。祀,国之大事也,而逆之,可谓礼乎?子虽齐圣,不先父食久矣。故禹不先鲧,汤不先契,文、武不先不窋。宋祖帝乙,郑祖厉王,犹上祖也。是以《鲁颂》曰:“春秋匪解,享祀不忒,皇皇后帝,皇祖后稷。”君子曰礼,谓其后稷亲而先帝也。《诗》曰:“问我诸姑,遂及伯姊。”君子曰礼,谓其姊亲而先姑也。仲尼曰:“臧文仲,其不仁者三,不知者三。下展禽,废六关,妾织蒲,三不仁也。作虚器,纵逆祀,祀爰居,三不知也。” +冬,晋先且居、宋公子成、陈辕选、郑公子归生伐秦,取汪,及彭衙而还,以报彭衙之役。卿不书,为穆公故,尊秦也,谓之崇德。 +襄仲如齐纳币,礼也。凡君即位,好舅甥,修昏姻,娶元妃以奉粢盛,孝也。孝,礼之始也。 +译文 +二年春季,秦国的孟明视领兵攻打晋国,以报复殽地这次战役。二月,晋襄公抵抗秦军,先且居率领中军,赵衰辅助他。王官无地为先且居驾御战车,狐鞫居作为车右。二月七日,和秦军在彭衙作战,秦军大败。晋国人说这是秦国“拜谢恩赐的战役”。 +在殽地作战的时候,晋国的梁弘为晋襄公驾御战车,莱驹作为车右。作战的第二天,晋襄公捆绑了秦国的俘虏,派莱驹用戈去杀他们,俘虏大声喊叫,莱驹把戈掉在地上,狼瞫拿起戈砍了俘虏的头,抓起莱驹追上了晋襄公的战车,晋襄公就让他作为车右。箕地这一战役,先轸废掉了狼瞫,而以续简伯作为车右。狼瞫发怒。他的朋友说:“为什么不去死?”狼瞫说:“我没有找到死的地方。”他的朋友说:“我跟你一起发难杀死先轸。”狼瞫说:“《周志》有这样的话:‘勇敢如果杀害在上的人,死后不能进入明堂。’死而不合于道义,这不是勇敢。为国家所用叫做勇敢,我用勇敢得到了车右,没有勇敢而被废黜,也是合适的。如果说上面的人不了解我,废黜得得当,就是了解我了。您姑且等着吧!”到达彭衙,摆开阵势以后,狼瞫率领部下冲进秦军的队伍,死在阵地上。晋军跟着上去,把秦军打得大败。君子认为:“狼瞫由于这样可以算得君子了。《诗》说:‘君子如果发怒,动乱就可以很快阻止。’又说:‘文王勃然大怒,于是就整顿军队。’发怒不去作乱,反而上去打仗,可以说是君子了。” +秦穆公还是任用孟明。孟明进一步修明政事,给百姓以优厚的待遇。赵成子对大夫们说:“秦军如果再一次前来,必定要避开它。由于畏惧而进一步修明了德行,那是不能抵挡的。《诗》说:‘怀念着你的祖先,修明你的德行。’孟明想到这两句诗了。想到德行而努力不懈,难道可以抵挡吗?” +二十日,制作僖公的神主牌位。《春秋》之所以记载,是由于制作不及时。 +晋国人由于鲁文公不去朝见而前来讨伐。文公去了晋国。夏季,四月十三日,晋国派阳处父和文公结盟来羞辱他。《春秋》记载说“及晋处父盟”,这是表示厌恶的意思。到晋国去而不加记载,这是出于隐讳。 +鲁文公没有到达鲁国,六月,穆伯在垂陇和诸侯以及晋国司空士縠结盟,这是由于晋国攻打卫国的缘故。《春秋》记载称为“士縠”,是由于认为他能够胜任。陈共公为卫国向晋国求和,拘捕了孔达以向晋国解说。 +秋季,八月十三日,在太庙祭祀,升僖公的神位在闵公之上,这是不按顺序的祭祀。当时夏父弗忌担任宗伯,尊崇僖公,而且宣布他所见到的说:“我见到新鬼大,旧鬼小,先大后小,这是顺序。使圣上升位,这是明智。明智、顺序,这是合于礼的。”君子认为,这样做是失礼。礼没有不合顺序的。祭祀是国家的大事,不按顺序,难道能说合于礼吗?儿子虽然聪明圣哲,不能在父亲之前享受祭品,由来己久。所以禹不能在鲧之前,汤不能在契之前,文王、武王不能在窋之前。宋国以帝乙为祖宗,郑国以厉王为祖宗,这还是对祖宗的尊崇。所以《鲁颂》说:“一年四季的祭祀不懈怠,没有差错,致祭于上帝,又致祭于伟大的祖先后稷。”君子说这合于礼,说的是后稷虽然亲近,然而却先称上帝。《诗》说:“问候我的姑母们,再问候到各位姐姐。”君子说这合于礼,说的是姐姐虽然亲近,然而却先称姑姑。孔子说:“臧文仲,他不仁爱的事情有三件,不聪明的事情有三件。使展禽居于下位,设立六个关口,小老婆织席贩卖,这是三件不仁爱的事情。养一个大乌龟、迷信卜卦,纵容不合顺序的祭祀,祭祀海鸟爰居,这是三件不聪明的事情。” +冬季,晋国先且居、宋国公子成、陈国辕选、郑国公子归生攻打秦国,占取了汪地和彭衙,然后回国,以报复上次彭衙的战役。卿的名字不加记载,这是为了穆公的缘故。尊重秦国,叫做尊重德行。襄仲到齐国致送玉帛财礼,这是合于礼的。凡是国君即位,加强舅甥国家间的友好,办理婚姻的事,娶元配夫人来主持祭祀,这是孝道。孝道,是礼的开始。 + +文公三年 +【经】三年春王正月,叔孙得臣会晋人、宋人、陈人、卫人、郑人伐沈。沈溃。夏五月,王子虎卒。秦人伐晋。秋,楚人围江。雨螽于宋。冬,公如晋。十有二月己巳,公及晋侯盟。晋阳处父帅师伐楚以救江。 +【传】三年春,庄叔会诸侯之师伐沈,以其服于楚也。沈溃。凡民逃其上曰溃,在上曰逃。 +卫侯如陈,拜晋成也。 +夏四月乙亥,王叔文公卒,来赴吊如同盟,礼也。 +秦伯伐晋,济河焚舟,取王官,及郊。晋人不出,遂自茅津济,封殽尸而还。遂霸西戎,用孟明也。君子是以知“秦穆公之为君也,举人之周也,与人之壹也;孟明之臣也,其不解也,能惧思也;子桑之忠也,其知人也,能举善也。《诗》曰:‘于以采蘩,于沼于沚,于以用之公侯之事’,秦穆有焉。‘夙夜匪解,以事一人’,孟明有焉。‘诒阙孙谋,以燕翼子’,子桑有焉。” +秋,雨螽于宋,队而死也。 +楚师围江。晋先仆伐楚以救江。 +冬,晋以江故告于周。王叔桓公、晋阳处父伐楚以救江,门于方城,遇息公子朱而还。 +晋人惧其无礼于公也,请改盟。公如晋,及晋侯盟。晋侯飨公,赋《菁菁者莪》。庄叔以公降,拜,曰:“小国受命于大国,敢不慎仪。君贶之以大礼,何乐如之。抑小国之乐,大国之惠也。”晋侯降,辞。登,成拜。公赋《嘉乐》。 +译文 +三年春季,庄叔会合诸侯的军队攻打沈国,因为沈国向楚国顺服,沈国百姓溃散。凡是百姓逃避他们上级叫做“溃”,上级逃走叫做“逃”。卫成公到陈国去,这是为了拜谢陈国促成的卫、晋和议。 +夏季,四月二十四日,王叔文公死,发来讣告,像对同盟国一样去吊唁,这是合于礼仪的。 +秦穆公攻打晋国,渡过黄河,烧掉渡船,占取了王官和郊地。晋军不出战。秦军就从茅津渡黄河,在殽地为死亡的将士筑一个大坟墓,然后回国。秦穆公就此称霸于西方少数民族诸国,这是由于任用了孟明。君子因此知道,秦穆公作为国君,提拔人才考虑全面,任用人才专一无二;孟明作为臣子,努力不懈,能够因为畏惧而思考;子桑忠诚,他了解别人,能够推举好人。《诗》说:“在哪里去采蒿子?在池塘里、在小洲上。在哪里使用它?在公侯的祭祀典礼上。”秦穆公就是这样的。“早晚努力不懈,以事奉在最上层的一个人”,孟明就是这样的。“把谋略留给子孙,以安定和辅佐他们”,子桑就是这样的。 +秋季,在宋国有大批螽斯像雨点一样落下来,这是死了以后掉下来的。 +楚国的军队包围江国,晋国的先仆攻打楚国去救援江国。 +冬季,晋国把江国的事情报告周襄王,王叔桓公、晋国的阳处父攻打楚国以救援江国。攻打方城山关口,并看到了楚国的息公子朱才回国。晋国人为曾经对鲁文公的失礼而感到恐惧,请求改订盟约。文公到了晋国,和晋襄公结盟。晋襄公设享礼招待文公,赋《菁菁者莪》这首诗。庄叔让文公降阶下拜,说:“小国在大国接受命令,岂敢对礼仪有所不谨慎?君王赐我们以重大典礼,还有什么比这再高兴的呢?小国的高兴,是大国的恩赐。”晋襄公走下台阶辞谢,再登上台阶,完成拜礼。文公赋《嘉乐》这首诗。 + +文公四年 +【经】四年春,公至自晋。夏,逆妇姜于齐。狄侵齐。秋,楚人灭江。晋侯伐秦。卫侯使宁俞来聘。冬十有一月壬寅,夫人风氏薨。 +【传】四年春,晋人归孔达于卫,以为卫之良也,故免之。 +夏,卫侯如晋拜。曹伯如晋,会正。 +逆妇姜于齐,卿不行,非礼也。君子是以知出姜之不允于鲁也。曰:“贵聘而贱逆之,君而卑之,立而废之,弃信而坏其主,在国必乱,在家必亡。不允宜哉?《诗》曰:‘畏天之威,于时保之。’敬主之谓也。” +秋,晋侯伐秦,围刓、新城,以报王官之役。 +楚人灭江,秦伯为之降服、出次、不举、过数。大夫谏,公曰:“同盟灭,虽不能救,敢不矜乎!吾自惧也。”君子曰:“《诗》云:‘惟彼二国,其政不获,惟此四国,爰究爰度。’其秦穆之谓矣。” +卫宁武子来聘,公与之宴,为赋《湛露》及《彤弓》。不辞,又不答赋。使行人私焉。对曰:“臣以为肄业及之也。昔诸侯朝正于王,王宴乐之,于是乎赋《湛露》,则天子当阳,诸侯用命也。诸侯敌王所忾而献其功,王于是乎赐之彤弓一,彤矢百,玈弓矢千,以觉报宴。今陪臣来继旧好,君辱贶之,其敢干大礼以自取戾。” +冬,成风薨。 +译文 +四年春季,晋国人释放孔达回到卫国,这是由于把他作为卫国的好人材,所以赦免了他。 +夏季,卫成公到晋国拜谢释放孔达。曹共公到晋国商谈纳贡的事情。 +在齐国迎接姜氏,鲁国的卿没有去迎接,这是不合于礼的。君子因此知道出姜在鲁国不会有好结果,说:“用尊贵的礼节行聘而用低贱的礼节迎接她,身分是国家的第一夫人而轻待她,立为第一夫人而废弃她,丢掉信用而损害妇女之首的身分,这样的事情发生在国家中必然使国家动乱,在家族中必然使家族灭亡。没有好下场是应该的了。《诗》说:‘畏惧上天的威灵,因此就能保有福禄。’这就是说要看重妇女之首这样的身分。” +秋季,晋襄公攻打秦国,包围邧地、新成,以报复王官那次战役。楚国人灭亡了江国,秦穆公为这件事穿上素服,出居别室,减膳撤乐,超过了应有的礼数。大夫劝谏。秦穆公说:“同盟的国家被灭,虽然没有救援,岂敢不哀怜呢?我是自己警惕呀。”君子说:“《诗》说:‘他们两个国家,政事不合法度;四方的国家,只好设法自谋。’秦穆公就是这样的。”卫国的甯武子来鲁国聘问,文公设宴招待他,为他赋《湛露》和《彤弓》两首诗。甯武子没有辞谢,又不赋诗回答。文公派使者私下探问。甯武子回答说:“下臣以为是在练习演奏的。从前诸侯正月去京师向天子朝贺,天子设宴奏乐,在这个时候赋《湛露》这首诗,那就表示天子对着太阳,诸侯听候命令。诸侯把天子所痛恨的人作为敌人,而且献上自己的功劳。天子因为这样而赐给他们红色的弓一把、红色的箭一百枝、黑色的弓十把和箭一千枝,以表彰功劳而用宴乐来报答。现在陪臣前来继续过去的友好,承君王赐宴,哪里敢触犯大礼来自取罪过?” +冬季,成风去世。 + +文公五年 +【经】五年春王正月,王使荣叔归含,且賵。三月辛亥,葬我小君成风。王使召伯来会葬。夏,公孙敖如晋。秦人入鄀。秋,楚人灭六。冬十月甲申,许男业卒。 +【传】五年春,王使荣叔来含且賵,召昭公来会葬,礼也。 +初,鄀叛楚即秦,又贰于楚。夏,秦人入鄀。 +六人叛楚即东夷。秋,楚成大心、仲归帅师灭六。 +冬,楚公子燮灭蓼,臧文仲闻六与蓼灭,曰:“皋陶庭坚不祀忽诸。德之不建,民之无援,哀哉!” +晋阳处父聘于卫,反过宁,宁嬴从之,及温而还。其妻问之,嬴曰;“以刚。《商书》曰:‘沈渐刚克,高明柔克。’夫子壹之,其不没乎。天为刚德,犹不干时,况在人乎?且华而不实,怨之所聚也,犯而聚怨,不可以定身。余惧不获其利而离其难,是以去之。” +晋赵成子,栾贞子、霍伯、臼季皆卒。 +译文 +五年春季,周襄王派遣荣叔前来致送含在死者口中的玉和丧仪,召昭公来参加葬礼,这是符合礼仪的。 +当初,鄀国背叛楚国亲近秦国,后来又倾向楚国。夏季,秦国进入鄀国。六国人背叛楚国亲近东夷。秋季,楚国的成大心、仲归带兵灭亡了六国。 +冬季,楚国的公子燮灭亡蓼国。臧文仲听到六国和蓼国灭亡,说:“皋陶、庭坚没有人祭祀了。德行不建立,百姓没有人救援,可悲啊!” +晋国的阳处父到卫国聘问,回国时路过甯地,甯嬴愿意跟着他。甯嬴到达温地又回来了,他妻子问他,甯嬴说:“太刚强了。《商书》说:‘深沉的人要用刚强来克服,爽朗的人要用柔弱来克服。’那个人只具备其中之一,恐怕不得善终吧!上天纯阳,属于刚强的德行,尚且不触犯寒暑四时运行的次序,何况人呢?而且华而不实,就会聚集怨恨。触犯别人而聚集怨恨,不能够安定自身。我是害怕不能得到利益反而遭到祸害,因此才离开他。” +晋国的赵成子、栾贞子、霍伯、臼季都已经去世了。 + + +文公六年 +【经】六年春,葬许僖公。夏,季孙行父如陈。秋,季孙行父如晋。八月乙亥,晋侯欢卒。冬十月,公子遂如晋。葬晋襄公。晋杀其大夫阳处父。晋狐射姑出奔狄。闰月不告月,犹朝于庙。 +【传】六年春,晋蒐于夷,舍二军。使狐射姑将中军,赵盾佐之。阳处父至自温,改蒐于董,易中军。阳子,成季之属也,故党于赵氏,且谓赵盾能,曰:“使能,国之利也。”是以上之。宣子于是乎始为国政,制事典,正法罪。辟狱刑,董逋逃。由质要,治旧污,本秩礼,续常职,出滞淹。既成,以授大傅阳子与大师贾佗,使行诸晋国,以为常法。 +臧文仲以陈、卫之睦也,欲求好于陈。夏,季文子聘于陈,且娶焉。 +秦伯任好卒。以子车氏之三子奄息、仲行、金咸虎为殉。皆秦之良也。国人哀之,为之赋《黄鸟》。君子曰:“秦穆之不为盟主也,宜哉。死而弃民。先王违世,犹诒之法,而况夺之善人乎!《诗》曰:‘人之云亡,邦国殄瘁。’无善人之谓。若之何夺之?”古之王者知命之不长,是以并建圣哲,树之风声,分之采物,着之话言,为之律度,陈之艺极,引之表仪,予之法制,告之训典,教之防利,委之常秩,道之礼则,使毋失其土宜,众隶赖之,而后即命。圣王同之。今纵无法以遗后嗣,而又收其良以死,难以在上矣。君子是以知秦之不复东征也。 +秋,季文子将聘于晋,使求遭丧之礼以行。其人曰:“将焉用之?”文子曰:“备豫不虞,古之善教也。求而无之,实难,过求何害?” +八月乙亥,晋襄公卒。灵公少,晋人以难故,欲立长君。赵孟曰:“立公子雍。好善而长,先君爱之,且近于秦。秦,旧好也。置善则固,事长则顺,立爱则孝,结旧则安。为难故,故欲立长君,有此四德者,难必抒矣。”贾季曰:“不如立公子乐。辰嬴嬖于二君,立其子,民必安之。”赵孟曰:“辰嬴贱,班在九人,其子何震之有?且为二嬖,淫也。为先君子,不能求大而出在小国,辟也。母淫子辟,无威。陈小而远,无援。将何安焉?杜祁以君故,让逼姞而上之,以狄故,让季隗而己次之,故班在四。先君是以爱其子而仕诸秦,为亚卿焉。秦大而近,足以为援,母义子爱,足以威民,立之不亦可乎?”使先蔑、士会如秦,逆公子雍。贾季亦使召公子乐于陈。赵孟使杀诸郫。贾季怨阳子之易其班也,而知其无援于晋也。九月,贾季使续鞫居杀阳处父。书曰:“晋杀其大夫。”侵官也。 +冬十月,襄仲如晋。葬襄公。 +十一月丙寅,晋杀续简伯。贾季奔狄。宣子使臾骈送其帑。夷之蒐,贾季戮臾骈,臾骈之人欲尽杀贾氏以报焉。臾骈曰:“不可。吾闻《前志》有之曰:‘敌惠敌怨,不在后嗣’,忠之道也。夫子礼于贾季,我以其宠报私怨,无乃不可乎?介人之宠,非勇也。损怨益仇,非知也。以私害公,非忠也。释此三者,何以事夫子?”尽具其帑,与其器用财贿,亲帅扞之,送致诸竟。 +闰月不告朔,非礼也。闰以正时,时以作事,事以厚生,生民之道,于是乎在矣。不告闰朔,弃时政也,何以为民? +译文 +六年春季,晋国在夷地检阅军队,撤去两个军。让狐姑射率领中军,赵盾辅助他。阳处父从温地来,改在董地检阅军队,调换了中军主将。阳子,原是成季(赵衰)的下属,所以偏向赵氏,而且认为赵盾富有才能,说:“任用能干的人,这是国家的利益。”所以使赵盾居于上位。赵宣子从这时开始掌握国家的政权,制定章程,修订法令,清理诉讼,督察逃亡,使用契约,清除政治上的污垢,恢复被破坏的次序,重建已经废弃的官职,提拔被压抑的贤能。政令法规完成以后,交给太傅阳子和太师贾佗,使之在晋国推行,作为经常的法则。 +臧文仲由于陈、卫两国和睦,想要讨好陈国。夏季,季文子到陈国聘问,同时娶了家室。 +秦穆公任好死了,用子车氏的三个儿子奄息、仲行、鍼虎殉葬,这三个人都是秦国的杰出人物。国都的人哀悼他们,为他们赋了《黄鸟》这首诗。君子说:“秦穆公没有当上盟主,活该!死了以后还抛弃百姓。以前的国君离世,还留下了法度,而何况夺百姓的好人呢?《诗》说:‘贤人的死亡,国家就困乏损伤。’这就是说没有好人。为什么还去夺走好人呢?古代身居王位的人知道寿命不能长久,因此就普遍选出贤能,给他们树立风气教化,分给他们旗帜服装,把对他们有益的话记录在典册上,为他们制订法度,对他们公布准则,设立表率来引导他们,给予规章让他们使用,告诉他们先王遗留下来的训导,教育他们防止谋求私利,委任他们一定的职务,开导他们使之合于礼仪,让他们不要违背了因地制宜,让大家都信赖他们,然后到死为止。这样的做法,圣人和先王都是相同的。现在即使没有法则留给后代,反而将杰出人物作为殉葬,这就难于处在上面了。”君子因此而知道秦国再也无法向东征伐了。 +秋季,季文子准备到晋国聘问,让人代他请求如果遭到丧事以后应得的礼仪然后才动身。随行的人说:“准备了做什么用?”文子说:“预备好意外的事,这是古代的好教训。临时去请求而没有得到,这会遇到困难。所得虽然一时用不着,有什么害处?” +八月十四日,晋襄公死了。晋灵公年幼,晋国人由于发生祸难的缘故,要立年长的国君。赵孟说:“立公子雍为君。他乐于行善而且年长,先君宠爱他,而且为秦国所亲近。秦国,是老朋友了。能安排好人就巩固,立年长的人就名正言顺,立先君所爱就合于孝道,结交老朋友就安定。因为祸难的缘故,所以要立年长的国君。有了这四项德行的人,祸难就必定可以缓和了。”贾季说:“不如立公子乐。辰嬴受到两位国君的宠爱,立她的儿子,百姓必然安定。”赵孟说:“辰嬴低贱,位次第九,她的儿子有什么威严呢?而且为两位国君所宠幸,这是淫荡。作为先君的儿子,不能求得大国而出居小国,这是鄙陋。母亲淫荡,儿子鄙陋,就没有威严;陈国小而且远,有事不能救援,怎么能安定呢?杜祁由于国君的缘故,让位给偪姞而使她在上;由于狄人的缘故,让位给季隗而自己居她之下,所以位次第四。先君因此喜欢她的儿子,让他在秦国做官,做到亚卿。秦国大而且近,有事足以救援;母亲具有道义,儿子受到喜欢,足以威临百姓。立公子雍,不也可以吗?”派先蔑、士会到秦国迎接公子雍。贾季也派人到陈国召回公子乐。赵孟派人在郫地杀了公子乐。贾季怨恨阳子改变他的地位,又知道他在晋国没有人援助。九月,贾季派续鞠居杀死阳处父。《春秋》记载说“晋杀其大夫”,这是由于阳处父侵夺了官职的缘故。 +冬季十月,襄仲到晋国参加晋襄公的葬礼。 +十一月某一天,晋国杀了续简伯。贾季逃亡到狄。宣子派臾骈把他的妻子儿女送到他那里去。在夷地阅兵的时侯,贾季曾经侮辱过臾骈。臾骈手下的人因此要杀尽贾氏来图报复。臾骈说:“不行。我听说《前志》上有这样的话:‘有惠于人或有怨于人,和他的后代无关,这合于忠诚之道。’他老人家对贾季表示礼貌,我因为受到他的宠信而报复自己的私怨,恐怕不可以吧!因为别人的宠信而去报复,这不是勇敢。消减怨气而增加仇恨,这不是明智。以私害公,这不是忠诚。舍弃了这三条,用什么去事奉他老人家?”所以就把贾季的妻儿以及他们的器用财货准备齐全,亲自领头保卫,把他们送到边境上。 +闰月不举行告朔的仪式,这是不合于礼仪的。闰用来补正四时,根据四时来安排农事,农事合于时令可以使百姓富裕,养活百姓的方法就在于此了。不举行闰月告朔仪式,这是放弃了施政的时令,怎么能治理百姓? + +文公七年 +【经】七年春,公伐邾。三月甲戌,取须句。遂城郚。夏四月,宋公王臣卒。宋人杀其大夫。戊子,晋人及秦人战于令狐。晋先蔑奔秦。狄侵我西鄙。秋八月,公会诸侯、晋大夫盟于扈。冬,徐伐莒。公孙敖如莒莅盟。 +【传】七年春,公伐邾。间晋难也。 +三月甲戌,取须句,置文公子焉,非礼也。 +夏四月,宋成公卒。于是公子成为右师,公孙友左师,乐豫为司马,鳞矔为司徒,公子荡为司城,华御事为司寇。 +昭公将去群公子,乐豫曰:“不可。公族,公室之枝叶也,若去之则本根无所庇荫矣。葛藟犹能庇其本根,故君子以为比,况国君乎?此谚所谓庇焉而纵寻斧焉者也。必不可,君其图之。亲之以德,皆股肱也,谁敢携贰?若之何去之?”不听。穆、襄之族率国人以攻公,杀公孙固、公孙郑于公宫。六卿和公室,乐豫舍司马以让公子卬,昭公即位而葬。书曰:“宋人杀其大夫。”不称名,众也,且言非其罪也。 +秦康公送公子雍于晋,曰:“文公之入也无卫,故有吕、郤之难。”乃多与之徒卫。穆赢日抱大子以啼于朝,曰:“先君何罪?其嗣亦何罪?舍适嗣不立而外求君,将焉置此?”出朝,则抱以适赵氏,顿首于宣子曰:“先君奉此子也而属诸子,曰:‘此子也才,吾受子之赐;不才,吾唯子之怨。’今君虽终,言犹在耳,而弃之,若何?”宣子与诸大夫皆患穆嬴,且畏逼,乃背先蔑而立灵公,以御秦师。箕郑居守。赵盾将中军,先克佐之。荀林父佐上军。先蔑将下军,先都佐之,步招御戎,戎津为右。及堇阴,宣子曰:“我若受秦,秦则宾也;不受,寇也。既不受矣,而复缓师,秦将生心。先人有夺人之心,军之善谋也。逐寇如追逃,军之善政也。”训卒利兵,秣马蓐食,潜师夜起。戊子,败秦师于令狐,至于刳首。己丑,先蔑奔秦。士会从之。 +先蔑之使也,荀林父止之,曰:“夫人、大子犹在,而外求君,此必不行。子以疾辞,若何?不然,将及。摄卿以往可也,何必子?同官为寮,吾尝同寮,敢不尽心乎!”弗听。为赋《板》之三章。又弗听。及亡,荀伯尽送其帑及其器用财贿于秦,曰:“为同寮故也。” +士会在秦三年,不见士伯。其人曰:“能亡人于国,不能见于此,焉用之?”士季曰:“吾与之同罪,非义之也,将何见焉?”及归,遂不见。 +狄侵我西鄙,公使告于晋。赵宣子使因贾季问酆舒。且让之。酆舒问于贾季曰:“赵衰、赵盾孰贤?”对曰:“赵衰,冬日之日也。赵盾,夏日之日也。” +秋八月,齐侯、宋公、卫侯、郑伯、许男、曹伯会晋赵盾盟于扈,晋侯立故也。公后至,故不书所会。凡会诸侯,不书所会,后也。后至,不书其国,辟不敏也。 +穆伯娶于莒,曰戴己,生文伯,其娣声己生惠叔。戴己卒,又聘于莒,莒人以声己辞,则为襄仲聘焉。 +冬,徐伐莒。莒人来请盟。穆伯如莒莅盟,且为仲逆。及鄢陵。登城见之,美,自为娶之。仲请攻之,公将许之。叔仲惠伯谏曰:“臣闻之,兵作于内为乱,于外为寇,寇犹及人,乱自及也。今臣作乱而君不禁,以启寇仇,若之何?”公止之,惠伯成之。使仲舍之,公孙敖反之,复为兄弟如初。从之。 +晋郤缺言于赵宣子曰:“日卫不睦,故取其地,今已睦矣,可以归之。叛而不讨,何以示威?服而不柔,何以示怀?非威非怀,何以示德?无德,何以主盟?子为正卿,以主诸侯,而不务德,将若之何?《夏书》曰:‘戒之用休,董之用威,劝之以《九歌》,勿使坏。’九功之德皆可歌也,谓之九歌。六府、三事,谓之九功。水、火、金、木、土、谷,谓之六府。正德、利用、厚生,谓之三事。义而行之,谓之德、礼。无礼不乐,所由叛也。若吾子之德莫可歌也,其谁来之?盍使睦者歌吾子乎?”宣子说之。 +译文 +七年春季,鲁文公发兵攻打邾国,这是鲁国利用晋国内乱的空子。三月十七日,占取须句,让邾文公的儿子当守官,这是不合于礼仪的。 +夏季,四月,宋成公死了。这时候公子成做右师,公孙友做左师,乐豫做司马,鳞矔做司徒,公子荡做司城,华御事做司寇。宋昭公准备杀死公子们。乐豫说:“不行。公族,是公室的枝叶,如果去掉它,那么树干树根就没有遮盖了。葛藟还能遮蔽它的躯干和根子,所以君子以它作为比喻,何况是国君呢?这就是俗话所说‘树阴遮蔽,偏偏使用斧子’,一定不可以。君王要考虑一下,如果用德行去亲近他们,那就都是左右辅弼的臣子,谁敢有二心?怎么要杀他们呢?”宋昭公不听。穆公、襄公的族人率领国内的人们攻打昭公,在宫里杀了公孙固和公孙郑。六卿和公室讲和,乐豫放弃了司马的官职来让给公子卬。昭公即位后安葬被杀的人。《春秋》记载说:“宋人杀其大夫”,不记载名字,这是由于人多而且他们没有罪。 +秦康公送公子雍到晋国,说:“晋文公回国的时候没有卫士,所以有吕、郤发动的祸难。”于是就多给他步兵卫士。穆嬴每天抱着太子在朝廷上啼哭,说:“先君有什么罪?他的合法继承人有什么罪?丢开嫡子不立,反而到外边去求国君,你们准备怎样安置这个孩子?”出了朝廷,就抱着孩子到赵氏家去,向赵盾叩头,说:“先君捧着这个孩子嘱托给您,说:‘这个孩子如果成材,我就是受了您的赐予;如果不成材,我就要怨您。’现在国君虽然去世,话音还在耳边,现在反而丢掉它,怎么办?”赵盾和大夫们都怕穆嬴,而且害怕威逼,就背弃了先蔑而立灵公为君,并且发兵抵御秦国军队。箕郑留守。赵盾率领中军,先克辅助他;荀林父辅助上军;先蔑率领下军,先都辅助他。步招为赵盾驾御战车,戎津作为车右。到达堇阴。赵盾说:“我们如果接受秦国送公子雍回来,他们就是客人;不接受,他们就是敌人。已经不接受了,而又慢慢地出兵,秦国将会动别的念头。争取主动而有夺取敌人的决心,这是作战的好谋略。驱逐敌人好像追赶逃亡者,这是作战的好战术。”于是就训练士兵,磨砺武器,把马喂饱,让部队吃饱,隐蔽行动,夜里出兵。四月初一日,在令狐打败秦军,一直追到刳首。初二日,先蔑逃亡到秦国,士会跟着他。 +先蔑出使秦国的时候,荀林父劝阻他,说:“夫人和太子还在,反而到外边去求国君,这一定是行不通的。您以生病作借口,行吗?不这样,祸患将会惹到您身上。派一个代理卿前去就可以了,为什么一定要您去?在一起做官就是‘寮’,我曾经和您同寮,岂敢不尽我的心意呢?”先蔑没有听从。荀林父为他赋《板》这首诗的第三章,又没有听从。等到逃亡出国,荀林父把他的妻子儿女和财货全部送到秦国,说:“这是为了同寮的缘故。” +士会在秦国三年,没有和先蔑见面。随行的人说:“能和别人一起逃亡到这个国家,而不能在这里见面,那有什么用处?”士会说:“我和他罪过相同,并不是认为他有道义才跟他来的,见面干什么?”一直到回国,没有见过面。 +狄人侵袭我国西部边境,鲁文公派使者向晋国报告。赵宣子派贾季去问酆舒,同时责备他。酆舒问贾季说:“赵衰、赵盾哪一个贤明?”贾季回答说:“赵衰,是冬天的太阳;赵盾,是夏天的太阳。” +秋季,八月,齐昭公、宋昭公、卫成公、陈共公、郑穆公、许昭公、曹共公和晋国的赵盾在扈地结盟,这是由于晋灵公即位的缘故。鲁文公晚到,所以《春秋》没有记载他参加会议。凡是和诸侯会盟,如果不记载参加会的国家,就是因为晚到的缘故。晚到,不记载这些国家,这是为了避免弄不清而误记。 +穆伯在莒国娶妻,名叫戴己,生了文伯;她的妹妹声己,生了惠叔。戴己死,穆伯又到莒国行聘,莒国人由于有声己而辞谢,所以就为襄仲行聘。冬季,徐国攻打莒国,莒国人前来请求结盟,穆伯到莒国参加盟会,同时为襄仲迎接莒女。到达鄢陵,登上城见到莒女,很美丽,就自己娶了她。襄仲请求攻打穆伯,文公准备答应。叔仲惠伯劝谏说:“下臣听说:‘战争起于内部叫做乱,起于外部叫做寇。寇尚且伤人,乱就是自己打自己了。’现在臣下作乱而国君不加禁止,如果因此而引起外部敌人的进攻,怎么办?”文公就阻止襄仲的进攻。惠伯给他们调解:让襄仲丢开莒女不娶,公孙敖就把莒女送回莒国,重新作为兄弟像起初一样。襄仲和公孙敖听从了。 +晋国的郤缺对赵宣子说:“过去卫国不顺服,所以占取它的土地,现在已经顺服,可以还给它了。背叛了不加讨伐,用什么显示声威?顺服了不加抚慰,用什么表示关怀?不显示声威和不表示关怀,用什么显示德行?没有德行,如何主持盟会?您作为正卿,主持诸侯之事而不致力于德行,打算怎么办?《夏书》说:‘把喜事告诉他,用威严督察他,用《九歌》勉励他,不要让他学坏。’有关九功的德行都可以歌唱,叫做《九歌》。六府、三事,叫做九功。水、火、金、木、土、谷,叫做六府;端正德行、利于使用、富裕民生,叫做三事。合于道义而推行这些,叫做德、礼。没有礼就不快乐,这是叛变之所由来。像您的德行,没有可以歌唱的,有谁肯来归服?何不使归服的人歌颂您呢?”赵宣子听了这番话很高兴。 + +文公八年 +【经】八年春王正月。夏四月。秋八月戊申,天王崩。冬十月壬午,公子遂会晋赵盾盟于衡雍。乙酉,公子遂会洛戎盟于暴。公孙敖如京师,不至而复。丙戌,奔莒。螽。宋人杀其大夫司马。宋司城来奔。 +【传】八年春,晋侯使解扬归匡、戚之田于卫,且复致公婿池之封,自申至于虎牢之竟。 +夏,秦人伐晋,取武城,以报令狐之役。 +秋,襄王崩。 +晋人以扈之盟来讨。冬,襄仲会晋赵孟,盟于衡雍,报扈之盟也,遂会伊洛之戎。书曰“公子遂”,珍之也。 +穆伯如周吊丧,不至,以币奔莒,从己氏焉。 +宋襄夫人,襄王之姊也,昭公不礼焉。夫人因戴氏之族,以杀襄公之孙孔叔、公孙钟离及大司马公子卬,皆昭公之党也。司马握节以死,故书以官。司城荡意诸来奔,效节于府人而出。公以其官逆之,皆复之,亦书以官,皆贵之也。 +夷之蒐,晋侯将登箕郑父、先都,而使士縠、梁益耳将中军。先克曰:“狐、赵之勋,不可废也。”从之。先克夺蒯得田于堇阴。故箕郑父、先都、士縠、梁益耳、蒯得作乱。 +译文 +八年春季,晋灵公派遣解扬把匡地、戚地的土田归还给卫国,而且再送公婿池的封地,从申地到虎牢边境。 +夏季,秦军攻打晋国,占领了武城,以报复令狐那一次战役。 +秋季,周襄王逝世。 +晋国人由于扈地的结盟文公晚去而来攻打鲁国。冬季,襄仲和晋国的赵孟在衡雍会见,这是为了补偿扈地那次结盟,并因此而和伊、雒的戎人会见。《春秋》称他为“公子遂”,这是表示重视他。 +穆伯去成周吊丧,没有到成周,带了礼物逃亡到莒国,跟随己氏去了。宋襄夫人是周襄王的姐姐,宋昭公对她不加礼遇。宋襄夫人依靠戴氏的族人杀了襄公的孙子孔叔、公孙钟离和大司马公子卬,都是宋昭公的党羽。司马手里拿着符节死去,所以《春秋》记载他的官职而不写名字。司城荡意诸逃亡前来,把符节还给府人然后出去。文公按照他原来的官职接待他,而且都恢复了他们原来的官职。《春秋》也记载他的官职而不写名字。所有这些都是表示尊重他们。 +在夷地阅兵的时候,晋襄公准备提升箕郑父、先都,而让士縠、梁益耳率领中军。先克说:“狐、赵两人的功劳,不能废弃。”晋襄公听从了这个意见。先克在堇阴夺取了蒯得的田地,因此箕郑父、先都、士縠、梁益耳、蒯得发动叛乱。 + + +文公九年 +【经】九年春,毛伯来求金。夫人姜氏如齐。二月,叔孙得臣如京师。辛丑,葬襄王。晋人杀其大夫先都。三月,夫人姜氏至自齐。晋人杀其大夫士縠及箕郑父。楚人伐郑。公子遂会晋人、宋人、卫人、许人救郑。夏,狄侵齐。秋八月,曹伯襄卒。九月癸西,地震。冬,楚子使椒来聘。秦人来归僖公、成风之襚。葬曹共公。 +【传】九年春,王正月己酉,使贼杀先克。乙丑,晋人杀先都,梁益耳。 +毛伯卫来求金,非礼也。不书王命,未葬也。 +二月庄叔如周。葬襄王。 +三月甲戌,晋人杀箕郑父、士縠、蒯得。 +范山言于楚子曰:“晋君少,不在诸侯,北方可图也。”楚子师于狼渊以伐郑。囚公子坚、公子龙及乐耳。郑及楚平。公子遂会晋赵盾、宋华耦、卫孔达、许大夫救郑,不及楚师。卿不书,缓也,以惩不恪。 +夏,楚侵陈,克壶丘,以其服于晋也。 +秋,楚公子朱自东夷伐陈,陈人败之,获公子伐。陈惧,乃及楚平。 +冬,楚子越椒来聘,执币傲。叔仲惠伯曰:“是必灭若敖氏之宗。傲其先君,神弗福也。” +秦人来归僖公、成风之襚,礼也。诸侯相吊贺也,虽不当事,苟有礼焉,书也,以无忘旧好。 +译文 +九年春季,周王朝历法的正月初二日,晋灵公派遣凶手杀死了先克。十八日,晋国人杀死了先都、梁益耳。 +毛伯卫前来求取丧仪,这不合于礼。没有记载说这是天子的命令,这是由于周襄王还没有安葬。 +二月,庄叔去成周参加襄王的葬礼。 +三月二十八日,晋国人杀死了箕郑父、士縠、蒯得。 +范山对楚穆王说:“晋国国君年少,心意不在于称霸诸侯,北方是可以打主意的。”楚王在狼渊出兵来攻打郑国。囚禁了公子坚、公子尨和乐耳。郑国和楚国讲和。 +公子遂会合晋国赵盾、宋国华耦、卫国孔达、许国大夫,救援郑国,没有碰上楚军。《春秋》没有记载卿的名字,由于他们出兵迟缓,以此惩戒他们的办事不严肃认真。 +夏季,楚国入侵陈国,攻下壶丘,因为陈国归服了晋国。 +秋季,楚国公子朱从东夷进攻陈国,陈国军队打败了他,俘虏了公子茷。陈国害怕楚国报复,就和楚国讲和。 +冬季,楚国子越椒前来聘问,手拿着礼物显出傲慢的样子。叔仲惠伯说:“这个人必然会使若敖氏的宗族灭亡。向他的先君表示傲慢,神灵不会降福给他。” +秦国人前来向死去的僖公和成风赠送衣衾,这是合于礼的。诸侯之间互相吊丧贺喜,虽然不及时,如果符合礼仪,《春秋》就要加以记载,以表示不忘记过去的友好。 + +文公十年 +【经】十年春王三月辛卯,臧孙辰卒。夏,秦伐晋。楚杀其大夫宜申。自正月不雨,至于秋七月。及苏子盟于女栗。冬,狄侵宋。楚子、蔡侯次于厥貉。 +【传】十年春,晋人伐秦,取少梁。 +夏,秦伯伐晋,取北征。 +初,楚范巫矞似谓成王与子玉、子西曰:“三君皆将强死。”城濮之役,王思之,故使止子玉曰:“毋死。”不及。止子西,子西缢而县绝,王使适至,遂止之,使为商公。沿汉溯江,将入郢。王在渚宫,下,见之。惧而辞曰:“臣免于死,又有谗言,谓臣将逃,臣归死于司败也。”王使为工尹,又与子家谋弑穆王。穆王闻之。五月杀斗宜申及仲归。 +秋七月,及苏子盟于女栗,顷王立故也。 +陈侯、郑伯会楚子于息。冬,遂及蔡侯次于厥貉。将以伐宋。宋华御事曰:“楚欲弱我也。先为之弱乎,何必使诱我?我实不能,民何罪?”乃逆楚子,劳,且听命。遂道以田孟诸。宋公为右盂,郑伯为左盂。期思公复遂为右司马,子朱及文之无畏为左司马。命夙驾载燧,宋公违命,无畏抶其仆以徇。 +或谓子舟曰:“国君不可戮也。”子舟曰:“当官而行,何强之有?《诗》曰:‘刚亦不吐,柔亦不茹。’‘毋从诡随,以谨罔极。’是亦非辟强也,敢爱死以乱官乎!” +厥貉之会,麇子逃归。 +译文 +十年春季,晋国人攻打秦国,占领了少梁。 +夏季,秦国攻打晋国,占领了北征。 +当初,楚国范地的巫人矞似预言成王和子玉、子西说:“这三位都将被杀死。”城濮那次战役,楚王想起了这句话,所以阻止子玉说:“不要自杀。”但是没有来得及。去阻止子西,子西正在上吊而绳子断了,楚王的使者刚刚来到,就阻止了他自杀,让他做了商公。子西沿汉江而下,逆长江而上,将要进入郢都。楚王正在渚宫,下来接见他,子西害怕,就解释说:“下臣幸而免于一死,但又有人诬陷,说下臣准备逃走,下臣现在回来请求死在司败那里。”楚王让他做了工尹,他又和子家策划杀死穆王。穆王听到后,在五月间杀了子西和子家。 +秋季,七月,文公和苏子在女栗结盟,这是由于周顷王即位的缘故。 +陈恭公、郑穆公在息地会见楚穆王。冬季,就和蔡庄侯一起领兵驻扎在厥貉,准备攻打宋国。宋国的华御事说:“楚国想要让我们归服,是不是我们先主动表示顺服?他们何必摆出这副架势来逼迫我们?我们实在没有能耐,但是百姓有什么罪?”于是就亲自去迎接楚穆王,向他表示慰劳,同时听候命令。于是就引导楚穆王在孟诸打猎。宋昭公率领右边圆阵,郑穆公率领左边圆阵。期思公复遂作为右司马,子朱和文之无畏作为左司马,下令早晨在车上装载取火工具出发。宋昭公违背命令,无畏笞打他的仆人并在全军示众。有人对文之无畏说:“国君是不能够侮辱的。”文之无畏说:“按照职责办事,有什么强横?《诗》说:‘硬的不吐出来,软的不吞下去。’又说:‘不要放纵狡诈的人,以使放荡的行为得以检点。’这也是不避强横的意思。我哪里敢爱惜生命而放弃职守呢!” +在厥貉会见的时候,麇子逃走回国。 + +文公十一年 +【经】十有一年春,楚子伐麋。夏,叔仲彭生会晋郤缺于承筐。秋,曹伯来朝。公子遂如宋。狄侵齐。冬十月甲午,叔孙得臣败狄于咸。 +【传】十一年春,楚子伐麇,成大心败麇师于防渚。潘崇复伐麇,至于锡穴。 +夏,叔仲惠伯会晋郤缺于承筐,谋诸侯之从于楚者。 +秋,曹文公来朝,即位而来见也。 +襄仲聘于宋,且言司城荡意诸而复之,因贺楚师之不害也。 +鄋瞒侵齐。遂伐我。公卜使叔孙得臣追之,吉。侯叔夏御庄叔,绵房甥为右,富父终甥驷乘。冬十月甲午,败狄于咸,获长狄侨如。富父终甥舂其喉以戈,杀之,埋其首于子驹之门,以命宣伯。 +初,宋武公之世,鄋瞒伐宋,司徒皇父帅师御之,耏班御皇父充石,公子谷甥为右,司寇牛父驷乘,以败狄于长丘,获长狄缘斯,皇父之二子死焉。宋公于是以门赏耏班,使食其征,谓之耏门。晋之灭潞也,获侨如之弟焚如。齐襄公之二年,鄋瞒伐齐,齐王子成父获其弟荣如,埋其首于周首之北门。卫人获其季简如,鄋瞒由是遂亡。 +郕大子朱儒自安于夫钟,国人弗徇。 +译文 +十一年春季,楚穆王攻打麇国。成大心在防渚打败麇军。潘崇再次攻打麇国,到达锡穴。 +夏季,叔仲惠伯在承筐会见晋国郤缺,这是为了商量对付追随楚国的诸侯。 +秋季,曹文公前来朝见,这是由于他刚即位而来朝见的。 +襄仲到宋国聘问,同时又替司城荡意诸说话而让他回国。这次聘问并且为了祝贺宋军没有遭到楚军兵害。 +鄋瞒侵袭齐国,并因此攻打我国。文公占了一个卦,卜派遣叔孙得臣追赶敌人,吉利。侯叔夏驾御叔孙得臣的战车,绵房甥作为车右,富父终甥作为驷乘。冬季,十月初三日,在咸地打败狄人,俘虏了长狄侨如。富父终甥用戈抵住他的咽喉,杀死了他,把他的脑袋埋在子驹之门下边。就把宣伯名叫侨如。 +当初,在宋武公时代,鄋瞒进攻宋国,司徒皇父带兵抵御。耏班驾御皇父充石的战车,公子穀甥为车右,司寇牛父作驷乘,在长丘打败狄人,俘虏了长狄缘斯。皇父的两个儿子战死,宋公因此就把城门赏给耏班,让他征收城门税,把城门称为耏门。 +晋国灭亡潞国的时候,俘虏了侨如的弟弟焚如。齐襄公二年,鄋瞒进攻齐国,齐国的王子成父俘虏了侨如的弟弟荣如,把他的脑袋埋在周首的北门下边。卫国人又俘虏了侨如的弟弟简如,鄋瞒由此就被灭亡。 +郕国的太子朱儒自己安逸地居住在夫钟,国内的人们不肯顺服他。 + +文公十二年 +【经】十有二年春王正月,郕伯来奔。杞伯来朝。二月庚子,子叔姬卒。夏,楚人围巢。秋,滕子来朝。秦伯使术来聘。冬十有二戊午,晋人、秦人战于河曲。季孙行父帅师城诸及郓。 +【传】十二年春,郕伯卒,郕人立君。大子以夫钟与郕邽来奔。公以诸侯逆之,非礼也。故书曰:“郕伯来奔。”不书地,尊诸侯也。 +杞桓公来朝,始朝公也。且请绝叔姬而无绝昏,公许之。 +二月,叔姬卒,不言杞,绝也。书叔姬,言非女也。 +楚令尹大孙伯卒,成嘉为令尹。群舒叛楚。夏,子孔执舒子平及宗子,遂围巢。 +秋,滕昭公来朝,亦始朝公也。 +秦伯使西乞术来聘,且言将伐晋。襄仲辞玉曰:“君不忘先君之好,照临鲁国,镇抚其社稷,重之以大器,寡君敢辞玉。”对曰:“不腆敝器,不足辞也。”主人三辞。宾客曰:“寡君愿徼福于周公、鲁公以事君,不腆先君之敝器,使下臣致诸执事以为瑞节,要结好命,所以藉寡君之命,结二国之好,是以敢致之。”襄仲曰:“不有君子,其能国乎?国无陋矣。”厚贿之。 +秦为令狐之役故,冬,秦伯伐晋,取羁马。晋人御之。赵盾将中军,荀林父佐之。郤缺上军,臾骈佐之。栾盾将下军,胥甲佐之。范无恤御戎,以从秦师于河曲。臾骈曰:“秦不能久,请深垒固军以待之。”从之。 +秦人欲战,秦伯谓士会曰:“若何而战?”对曰:“赵氏新出其属曰臾骈,必实为此谋,将以老我师也。赵有侧室曰穿,晋君之婿也,有宠而弱,不在军事,好勇而狂,且恶臾骈之佐上军也,若使轻者肆焉,其可。”秦伯以璧祈战于河。 +十二月戊午,秦军掩晋上军,赵穿追之,不及。反,怒曰:“裹粮坐甲,固敌是求,敌至不击,将何俟焉?”军吏曰:“将有待也。”穿曰:“我不知谋,将独出。”乃以其属出。宣子曰:“秦获穿也,获一卿矣。秦以胜归,我何以报?”乃皆出战,交绥。秦行人夜戒晋师曰:“两君之士皆未憖也,明日请相见也。”臾骈曰:“使者目动而言肆,惧我也,将遁矣。薄诸河,必败之。”胥甲、赵穿当军门呼曰:“死伤未收而弃之,不惠也;不待期而薄人于险,无勇也。”乃止。秦师夜遁。复侵晋,入瑕。 +城诸及郓,书,时也。 +译文 +十二年春季,郕伯死了,郕国人又立了国君。太子把夫钟和郕国的宝圭作为奉献而逃亡到鲁国来。文公把他作为诸侯迎接,这不合于礼。所以《春秋》记载说“郕伯来奔”,不记载关于奉献土地的事情,把郕伯作为诸侯来尊重。 +杞桓公来鲁国朝见,这是第一次前来朝见鲁文公。同时又请求和叔姬离婚,但不断绝两国的婚姻关系,文公答应了。二月,叔姬死了。《春秋》不记载“杞”字,是由于杞国和她断绝了关系。写明“叔姬”,是说她已经出过嫁。 +楚国的令尹大孙伯去世,成嘉做了令尹。舒氏的一批人背叛楚国。夏季,子孔逮捕了舒子平和宗子,就乘机包围巢地。 +秋季,滕昭公来鲁国朝见,也是第一次前来朝见文公。 +秦康公派遣西乞术前来聘问,而且说将要攻打晋国。襄仲不肯受玉,说:“贵国国君没有忘记和先君的友好,光临鲁国,镇定安抚我们这个国家,十分厚重地赠给我们大器,寡君不敢受玉。”西乞术回答说:“不丰厚的器物,不值得辞谢。”主人辞谢了三次,客人回答说:“寡君愿意在周公、鲁公这里求取福禄来事奉贵国国君,一点微薄的礼物,派遣下臣致送给执事,以作为祥瑞的信物,相约友好,把它用来表示寡君的命令,缔结两国之间的友好,因此才敢致送。”襄仲说:“若没有这样的外交人才,难道能治理国家吗?秦国不是鄙陋的国家。”就用重礼赠送给西乞术。 +秦国为了令狐那次战役的缘故,冬季,秦康公发兵攻打晋国,占取了羁马。晋国发兵抵御。赵盾率领中军,荀林父作为辅佐。郤缺率领上军,臾骈作为辅佐。栾盾率领下军,胥甲作为辅佐。范无恤为赵盾驾御战车,在河曲迎战秦军。臾骈说:“秦军不能持久,请高筑军垒巩固军营等着他们。”赵盾听从了他的意见。 +秦军准备出战。秦康公对士会说:“用什么办法作战?”士会回答说:“赵盾新近提拔他的部下名叫臾骈,必定是他出的这个主意,打算使我军久驻在外面感到疲乏。赵氏有一个旁支的子弟名叫穿,是晋国国君的女婿,受到宠信而年少,不懂得作战,喜好勇猛而又狂妄,又讨厌臾骈作为上军的辅佐。如果派出一些勇敢而不刚强的人对上军加以袭击,或许还有可能战胜赵穿。”秦康公把玉璧丢在黄河里,向河神祈求战争胜利。 +十二月初四日,秦国袭击晋军的上军,赵穿追赶秦军,没有追上。回来,发怒说:“装着粮食披着甲胄,就是要寻求敌人。敌人来了不去攻击,打算等待什么呢?”军官说:“将要有所等待啊。”赵穿说:“我不懂得计谋,我打算自己出战。”就带领他的士兵出战。赵盾说:“秦军要是俘虏了赵穿,就是俘虏了一位卿了。秦国带着胜利回去,我用什么回报晋国的父老?”于是全部出战,双方刚一交战就彼此退兵。秦军的使者夜里告诉晋国军队说:“我们两国国君的将士都还没有痛快地打一仗,明天请再相见。”臾骈说:“使者眼神不安而声音失常,这是害怕我们,秦军将要逃走了。我军把他们逼到黄河边上,一定可以打败他们。”胥甲、赵穿挡住营门大喊说:“死伤的人还没有收集就把他们丢弃,这是不仁慈。不等到约定的日期而把人逼到险地,这是没有勇气。”于是晋军就停止出击。秦军夜里逃走了。后来又入侵晋国,进入瑕地。 +鲁国在诸地和郓地筑城,《春秋》记载这件事,是由于合于时令。 + +文公十三年 +【经】十有三春王正月。夏五月壬午,陈侯朔卒。邾子蘧蒢卒。自正月不雨,至于秋七月。大室屋坏。冬,公如晋。卫侯会公于沓。狄侵卫。十有二月己丑,公及晋侯盟。公还自晋,郑伯会公于棐。 +【传】十三年春,晋侯使詹嘉处瑕,以守桃林之塞。 +晋人患秦之用士会也,夏,六卿相见于诸浮,赵宣子曰;“随会在秦,贾季在狄,难日至矣,若之何?”中行桓子曰:“请复贾季,能外事,且由旧勋。”郤成子曰:“贾季乱,且罪大,不如随会,能贱而有耻,柔而不犯,其知足使也,且无罪。” +乃使魏寿余伪以魏叛者以诱士会,执其帑于晋,使夜逸。请自归于秦,秦伯许之。履士会之足于朝。秦伯师于河西,魏人在东。寿余曰:“请东人之能与夫二三有司言者,吾与之先。”使士会。士会辞曰:“晋人,虎狼也,若背其言,臣死,妻子为戮,无益于君,不可悔也。”秦伯曰:“若背其言,所不归尔帑者,有如河。”乃行。绕朝赠之以策,曰:“子无谓秦无人,吾谋适不用也。”既济,魏人噪而还。秦人归其帑。其处者为刘氏。 +邾文公卜迁于绎。史曰:“利于民而不利于君。”邾子曰:“苟利于民,孤之利也。天生民而树之君,以利之也。民既利矣,孤必与焉。”左右曰:“命可长也,君何弗为?”邾子曰:“命在养民。死之短长,时也。民苟利矣,迁也,吉莫如之!”遂迁于绎。 +五月,邾文公卒。君子曰:“知命。” +秋七月,大室之屋坏,书,不共也。 +冬,公如晋,朝,且寻盟。卫侯会公于沓,请平于晋。公还,郑伯会公于棐,亦请平于晋。公皆成之。郑伯与公宴于棐。子家赋《鸿雁》。季文子曰:“寡君未免于此。”文子赋《四月》。子家赋《载驰》之四章。文子赋《采薇》之四章。郑伯拜。公答拜。 +译文 +十三年春季,晋灵公派詹嘉住在瑕地,以防守桃林这个险要的地方。晋国人担心秦国任用士会,夏季,六卿在诸浮相见。赵宣子说:“士会在秦国,贾季在狄人那里,祸患每天都可能发生,怎么办?”中行桓子说:“请让贾季回来,他了解外界的事情,而且因为有过去的功劳。”郤成子说:“贾季喜欢作乱,而且罪过大,不如让士会回来。士会能够做到卑贱而知道耻辱,柔弱而不受侵犯,他的智谋足以使用,而且没有罪过。”于是晋国就让魏寿馀假装率领魏地的人叛乱,以引诱士会。把魏寿馀的妻子儿女抓在晋国,让他夜里逃走。魏寿馀请求把魏地归入秦国,秦康公答应了。魏寿馀在朝廷上踩一下士会的脚,示意士会与他一起回晋国。秦康公驻军在河西,魏地人在河东。魏寿馀说:“请派一位东边人而能够跟魏地几位官员说话的,我跟他一起先去。”秦康公派遣士会。士会辞谢说:“晋国人,是老虎豺狼。如果违背原来的话不让下臣回来,下臣死,妻子儿女也将被诛戮,这对君王没有好处,而且后悔不及。”秦康公说:“如果晋国违背原来的话不让你回来,我若不送还你的妻子儿女,有河神作证!”这样士会才敢去。绕朝把马鞭送给士会,说:“您别说秦国没有人才,我的计谋正好不被采用罢了。”渡过黄河以后,魏地人因得到士会而欢呼,熙熙嚷嚷地回去了。秦国人送还了士会的妻子儿女。士会留在秦国的家人都改姓为刘氏。 +邾文公为了迁都到绎地而占了卦问吉凶。史官说:“对百姓有利而对国不利。”邾文公说:“如果对百姓有利,也就是我的利益。上天生育了百姓而为他们设置君主,就是用来给他们利益的。百姓得到利益,我就必然也在其中了。”左右随从说:“生命是可以延长的,君王为什么不这样做?”邾文公说:“活着就是为了抚养百姓。而死的或早或晚,那是由于偶然因素的缘故。百姓如果有利,迁都就是了,没有比这再吉利的了。”于是就迁都到绎地。五月,邾文公死了。君子说:“邾文公真正懂得天命。” +秋季,七月,太庙正屋屋顶损坏,《春秋》所以记载,是为了表示臣下的不恭敬。 +冬季,文公到晋国朝见,同时重温过去的友好关系。卫成公在沓地会见文公,请求和晋国讲和。文公回国时,郑穆公在棐地会见文公,也请求和晋国讲和。鲁文公都一一帮助他们达成和议。 +郑穆公和鲁文公在棐地举行宴会,子家赋了《鸿雁》这首诗。季文子说:“寡君也不能免于这种处境。”就赋了《四月》这首诗,子家又赋了《载驰》这首诗的第四章,季文子赋了《采薇》这首诗的第四章。郑穆公拜谢,鲁文公答谢。 + + +文公十四年 +【经】十有四年春王正月,公至自晋。邾人伐我南鄙,叔彭生帅师伐邾。夏五月乙亥,齐侯潘卒。六月,公会宋公、陈侯、卫侯、郑伯、许男、曹伯、晋赵盾。癸酉,同盟于新城。秋七月,有星孛入于北斗。公至自会。晋人纳捷菑于邾。弗克纳。九月甲申,公孙敖卒于齐。齐公子商人弑其君舍。宋子哀来奔。冬,单伯如齐。齐人执单伯。齐人执子叔姬。 +【传】十四年春,顷王崩。周公阅与王孙苏争政,故不赴。凡崩、薨,不赴,则不书。祸、福,不告亦不书,惩不敬也。 +邾文公之卒也,公使吊焉,不敬。邾人来讨,伐我南鄙,故惠伯伐邾。 +子叔姬齐昭公,生舍。叔姬无宠,舍无威。公子商人骤施于国,而多聚士,尽其家,贷于公,有司以继之。夏五月,昭公卒,舍即位。 +邾文公妃元齐姜生定公,二妃晋姬生捷菑。文公卒,邾人立定公,捷菑奔晋。 +六月,同盟于新城,从于楚者服,且谋邾也。 +秋七月乙卯夜,齐商人弑舍而让元。元曰:“尔求之久矣。我能事尔,尔不可使多蓄憾。将免我乎?尔为之!” +有星孛入于北斗,周内史叔服曰:“不出七年,宋、齐、晋之君皆将死乱。” +晋赵盾以诸侯之师八百乘纳捷菑于邾。邾人辞曰:“齐出玃且长。”宣子曰:“辞顺而弗从,不祥。”乃还。 +周公将与王孙苏讼于晋,王叛王孙苏,而使尹氏与聃启讼周公于晋。赵宣子平王室而复之。 +楚庄王立,子孔、潘崇将袭群舒,使公子燮与子仪守而伐舒蓼。二子作乱,城郢而使贼杀子孔,不克而还。八月,二子以楚子出,将如商密。庐戢梨及叔麋诱之,遂杀斗克及公子燮。 +初,斗克囚于秦,秦有殽之败,而使归求成,成而不得志。公子燮求令尹而不得。故二子作乱。 +穆伯之从己氏也,鲁人立文伯。穆伯生二子于莒而求复,文伯以为请。襄仲使无朝。听命,复而不出,二年而尽室以复适莒。文伯疾而请曰:“谷之子弱,请立难也。”许之。文伯卒,立惠叔。穆伯请重赂以求复,惠叔以为请,许之。将来,九月卒于齐,告丧,请葬,弗许。 +宋高哀为萧封人,以为卿,不义宋公而出,遂来奔。书曰:“宋子哀来奔去贵之也。” +齐人定懿公,使来告难,故书以九月。齐公子元不顺懿公之为政也,终不曰“公”,曰“夫己氏”。 +襄仲使告于王,请以王宠求昭姬于齐。曰:“杀其子,焉用其母?请受而罪之。” +冬,单伯如齐,请子叔姬,齐人执之。又执子叔姬。 +译文 +十四年春季,周顷王逝世。周公阅和王孙苏争夺政权,所以没有发布讣告。凡是天子“逝世”,诸侯“去世”,没有发来讣告,《春秋》就不加记载。灾祸、喜庆,如果没有前来报告,也不加记载。那是为了惩诫那些不认真负责的人。 +邾文公死的时候,鲁文公派遣使者前去吊丧,礼仪不周到。邾国兴师问罪,攻打我国南部边境,所以惠伯领兵攻打邾国。 +子叔姬嫁给齐昭公为夫人,生了儿子舍。叔姬不受宠爱,舍没有威信。公子商人却多次在国内施舍财物,养着许多门客,把家产都用光了,又向掌管公室财物的官员借贷而继续施舍。夏季,五月,齐昭公去世,舍即国君位。邾文公的第一夫人齐姜,生了定公;第二夫人晋姬,生了捷菑。邾文公去世后,邾国人立定公为君,捷菑逃亡到晋国。 +六月,鲁文公和宋昭公、陈灵公、卫成公、郑穆公、许男、曹文公、晋国赵盾一起在新城会盟,这是由于以前跟随楚国的国家都顺服,同时谋划攻打邾国。 +秋季,七月某一天,夜里,齐公子商人杀死舍而让位给元。元说:“你谋求这个君位已经很久了。我能够事奉你,你不能积下许多怨恨,要是这样,你会让我免于被杀吗?你去做国君吧!” +有彗星进入北斗。成周的内史叔服说:“不出七年,宋国、齐国、晋国的国君,都将死于叛乱。” +晋国的赵盾率领诸侯联军的八百辆战车,把捷菑送回邾国。邾国人辞谢说:“齐女生的貜且年长。”赵宣子说:“说话合于情理而不听从,不吉祥。”于是就回去了。 +周公阅打算和王孙苏在晋国争讼,周顷王违背了对王孙苏的诺言,而让尹氏和聃启在晋国替周公阅争讼。赵宣子调停了王室之间的纠纷而使各人恢复了原来的职位。 +楚庄王即位,子孔、潘崇准备袭击舒族的那些部落或国家,派公子燮和子仪留守而进攻舒蓼。这两个人发动叛乱,加筑郢都城墙,又派贼人去刺死子孔,没有成功而返回郢城。八月,两个人挟持了楚庄王离开郢都,准备去商密,庐戢梨和叔麇设计引诱他们;于是就杀死了子仪和公子燮。 +当初,子仪囚禁在秦国,秦国在殽地战败,派他回国求和。媾和以后,子仪的愿望没有得到满足,公子燮要求做令尹也没有得到手,所以两人就发动叛乱。 +穆伯跟随己氏的时候,鲁国人立了文伯做继承人。穆伯在莒国生了两个儿子,要求回国。文伯代替他申请。襄仲不让穆伯上朝参与政事。穆伯听从命令,回来以后也不外出,过了三年又将全家再次搬到莒国去。文伯生重病,请求说:“穀的儿子年纪太小,请立难吧。”大家同意了。文伯去世,立了惠叔。穆伯让惠叔给大家送重礼再次要求回国,惠叔代他请求,得到允许。穆伯将要回来,九月间,死在齐国。向鲁国报丧,请求归葬于鲁,没有得到允许。 +宋国的高哀担任萧地的守将,让他做卿,他认为宋公不义而离去,于是就逃亡到鲁国来。《春秋》记载“宋子哀来奔”,这是表示对他的尊重。 +齐国人安定了齐懿公的地位,才派人前来报告祸难,所以《春秋》把商人杀死舍这件事记为“九月”。齐国的公子元不服懿公执政,始终不称他做“公”,而称他做“那个人”。 +襄仲派人报告周顷王,请用周天子的尊荣在齐国求取子叔姬,说:“杀了她的儿子,哪里还用得着他的母亲?请求接纳她而惩办她。”冬季,单伯到齐国请求送回子叔姬,齐国人逮捕了他,同时又逮捕了子叔姬。 + +文公十五年 +【经】十有五年春,季孙行父如晋。三月,宋司马华孙来盟。夏,曹伯来朝。齐人归公孙敖之丧。六月辛丑朔,日有食之。鼓、用牲于社。单伯至自齐。晋郤缺帅师伐蔡。戊申,入蔡。齐人侵我西鄙。季孙行父如晋。冬十有一月,诸侯盟于扈。十有二月,齐人来归子叔姬。齐侯侵我西鄙,遂伐曹入期郛。 +【传】十五年春,季文子如晋,为单伯与子叔姬故也。 +三月,宋华耦来盟,其官皆从之。书曰“宋司马华孙”,贵之也。 +公与之宴,辞曰:“君之先臣督,得罪于宋殇公,名在诸侯之策。臣承其祀,其敢辱君,请承命于亚旅。”鲁人以为敏。 +夏,曹伯来朝,礼也。诸侯五年再相朝,以修王命,古之制也。 +齐人或为孟氏谋,曰:“鲁,尔亲也。饰棺置诸堂阜,鲁必取之。”从之。卞人以告。惠叔犹毁以为请。立于朝以待命。许之,取而殡之。齐人送之。书曰:“齐人归公孙敖之丧。”为孟氏,且国故也。葬视共仲。 +声己不视,帷堂而哭。襄仲欲勿哭,惠伯曰:“丧,亲之终也。虽不能始,善终可也。史佚有言曰:‘兄弟致美。’救乏、贺善、吊灾、祭敬、丧哀,情虽不同,毋绝其爱,亲之道也。子无失道,何怨于人?”襄仲说,帅兄弟以哭之。他年,其二子来,孟献子爱之,闻于国。或谮之曰:“将杀子。”献子以告季文子。二子曰:“夫子以爱我闻,我以将杀子闻,不亦远于礼乎?远礼不如死。”一人门于句鼆,一人门于戾丘,皆死。 +六月辛丑朔,日有食之,鼓、用牲于社,非礼也。日有食之,天子不举,伐鼓于社,诸侯用币于社,伐鼓于朝,以昭事神、训民、事君,示有等威。古之道也。 +齐人许单伯请而赦之,使来致命。书曰:“单伯至自齐。”贵之也。 +新城之盟,蔡人不与。晋郤缺以上军、下军伐蔡,曰:“君弱,不可以怠。”戊申,入蔡,以城下之盟而还。凡胜国,曰灭之;获大城焉,曰入之。 +秋,齐人侵我西鄙,故季文子告于晋。 +冬十一月,晋侯、宋公、卫侯、蔡侯、郑伯、许男、曹伯盟于扈,寻新城之盟,且谋伐齐也。齐人赂晋侯,故不克而还。于是有齐难,是以公不会。书曰:“诸侯盟于扈。”无能为故也。凡诸侯会,公不与,不书,讳君恶也。与而不书,后也。 +齐人来归子叔姬,王故也。 +齐侯侵我西鄙,谓诸侯不能也。遂伐曹,入其郛,讨其来朝也。季文子曰:“齐侯其不免乎。己则无礼,而讨于有礼者,曰:‘女何故行礼!’礼以顺天,天之道也,己则反天,而又以讨人,难以免矣。诗曰:‘胡不相畏,不畏于天?’君子之不虐幼贱,畏于天也。在周颂曰:‘畏天之威,于时保之。’不畏于天,将何能保?以乱取国,奉礼以守,犹惧不终,多行无礼,弗能在矣!” +译文 +十五年春季,季文子去晋国,为了单伯和子叔姬的缘故。 +三月,宋国的华耦前来会盟,他的部属都跟随前来。《春秋》称他为“宋司马华孙”,这是表示尊重他。鲁文公要和他同席宴会。华耦婉辞谢绝说:“君王的先臣督得罪了宋殇公,名字记载在诸侯的简册上。下臣承继他的祭祀,怎么敢使君王蒙受耻辱?请在亚旅那里接受命令。”鲁国人认为华耦措辞得体。 +夏季,曹文公前来朝见,这合于礼。诸侯每五年再一次互相朝见,以重温天子的命令,这是古代的制度。 +齐国有人为孟氏策划,说:“鲁国,是你的亲戚,把公孙敖的饰棺放在堂阜,鲁国必定会取去的。”孟氏听从了。卞邑大夫把这件事作了报告。惠叔仍然很悲哀,容颜消瘦,请求取回饰棺,立在朝廷上以等待命令。鲁国答应了这项请求,于是取回了饰棺停放。齐国人也来送丧,《春秋》记载说:“齐人归公孙敖之丧”,这是为了孟氏,同时又为了国家的缘故。依照安葬共仲的葬礼安葬了公孙敖。声己不肯去看棺材,在帷堂里哭泣。襄仲不想去哭丧,惠伯说:“办丧事,是对待亲人的最后大事。虽不能有一个好的开始,有一个好的终结是可以的。史佚有这样的话,说:‘兄弟之间各自尽力做到完美。救济困乏,祝贺喜庆,吊唁灾祸,祭祀恭敬,丧事悲哀,感情虽然不一样,不要断绝他们之间的友爱,这就是对待亲人的道义。’您自己只要不丧失道义,怨恨别人干什么呢?”襄仲听了很高兴,带领了兄弟们前去哭丧。后来,穆伯的两个儿子回来,孟献子喜爱他们,闻名于全国。有人诬陷他们,对孟献子说:“这两个人准备杀死你。”孟献子把这话告诉季文子。这两个人说:“他老人家因为爱我们,全国都知道,我们以准备杀死他而臭名在外,这不是远离于礼了吗?远离于礼还不如死。”后来,两兄弟一人在句鼆守门,一人在戾丘守门,都战死了。 +六月初一日,发生日食。击鼓,用牺牲在土地神庙里祭祀,这是合于礼的。发生日食,天子减膳撤乐,在土地神庙里击鼓。诸侯用玉帛在土地神庙里祭祀,在朝廷上击鼓,以表明事奉神灵、教训百姓、事奉国君。表示威仪有等级,这是古代的制度。 +齐国人允许了单伯要子叔姬回国的请求而赦免了他,派遣他来鲁国传达命令。《春秋》记载说“单伯至自齐”,这是表示尊重他。 +在新城的盟会,蔡国人不参加。晋国的郤缺率领上军、下军攻打蔡国,说:“国君年少,不能因此懈怠。”六月初八日,进入蔡国,订立了城下之盟,然后回国。凡是战胜别的国家,叫做“灭之”;得到大城,叫做“入之”。 +秋季,齐军侵犯我国西部边境,所以季文子向晋国报告。 +冬季,十一月,晋灵公、宋昭公、卫成公、蔡庄侯、陈灵公、郑穆公、许昭公、曹文公在扈地结盟,重温新城盟会的友好,同时策划攻打齐国。齐国人给晋灵公馈送财礼,所以没有战胜就回来了。在这时候发生了齐国进攻我国的灾难,所以文公没有参加盟会。《春秋》记载说“诸侯盟于扈”,这是由于没有救援我国的缘故。凡是诸侯会见,鲁公不参加,《春秋》就不加记载,这是由于隐讳国君的过失。参加了而不记载,这是由于迟到。齐国人前来送回子叔姬,这是由于天子有命令的缘故。 +齐懿公发兵进攻我国西部边境,他认为诸侯不能救援。并因此而攻打曹国,进入外城,讨伐曹国曾经前来朝见过鲁国。季文子说:“齐侯恐怕不能免于患难吧?自己就不合于礼,反而讨伐合于礼的国家,说:‘你为什么实行礼?’礼用来顺服上天,这是上天的常道。自己就违反上天,反而又因此付伐别人,这就难免有祸难了。《诗》说:‘为什么不互相敬畏?因为不敬畏上天。’君子不虐待幼小和卑贱,这是由于畏惧上天。在《周颂》里说:‘畏敬上天的威灵,因此就能保有福禄。’不畏敬上天,如何能保得住?用动乱取得国家,奉行礼仪来保持国君的地位,还害怕不得善终,多做不合于礼的事情,这就不得善终了。” + + +文公十六年 +【经】十有六年春,季孙行父会齐侯于阳谷,齐侯弗及盟。夏五月,公四不视朔。六月戊辰,公子遂及齐侯盟于郪丘。秋八月辛未,夫人姜氏薨。毁泉台。楚人、秦人、巴人灭庸。冬十有一月,宋人弑其君杵臼。 +【传】十六年春,王正月,及齐平。公有疾,使季文子会齐侯于阳谷。请盟,齐侯不肯,曰:“请俟君间。” +夏五月,公四不视朔,疾也。公使襄仲纳赂于齐侯,故盟于郪丘。 +有蛇自泉宫出,入于国,如先君之数秋八月辛未,声姜薨,毁泉台。 +楚大饥,戎伐其西南,至于阜山,师于大林。又伐其东南,至于阳丘,以侵訾枝。庸人帅群蛮以叛楚。麇人率百濮聚于选,将伐楚。于是申、息之北门不启。 +楚人谋徙于阪高。蒍贾曰:“不可。我能往,寇亦能住。不如伐庸。夫麇与百濮,谓我饥不能师,故伐我也。若我出师,必惧而归。百濮离居,将各走其邑,谁暇谋人?”乃出师。旬有五日,百濮乃罢。自庐以往,振廪同食。次于句澨。使庐戢黎侵庸,及庸方城。庸人逐之,囚子扬窗。三宿而逸,曰:“庸师众,群蛮聚焉,不如复大师,且起王卒,合而后进。”师叔曰:“不可。姑又与之遇以骄之。彼骄我怒,而后可克,先君蚡冒所以服陉隰也。”又与之遇,七遇皆北,唯裨、鯈、鱼人实逐之。 +庸人曰:“楚不足与战矣。”遂不设备。楚子乘馹,会师于临品,分为二队,子越自石溪,子贝自仞,以伐庸。秦人、巴人从楚师,群蛮从楚子盟。遂灭庸。 +宋公子鲍礼于国人,宋饥,竭其粟而贷之。年自七十以上,无不馈诒也,时加羞珍异。无日不数于六卿之门,国之才人,无不事也,亲自桓以下,无不恤也。公子鲍美而艳,襄夫人欲通之,而不可,夫人助之施。昭公无道,国人奉公子鲍以因夫人。 +于是华元为右师,公孙友为左师,华耦为司马,鳞鱼雚为司徒,荡意诸为司城,公子朝为司寇。初,司城荡卒,公孙寿辞司城,请使意诸为之。既而告人曰:“君无道,吾官近,惧及焉。弃官则族无所庇。子,身之贰也,姑纾死焉。虽亡子,犹不亡族。”既,夫人将使公田孟诸而杀之。公知之,尽以宝行。荡意诸曰:“盍适诸侯?”公曰:“不能其大夫至于君祖母以及国人,诸侯谁纳我?且既为人君,而又为人臣,不如死。”尽以其宝赐左右以使行。夫人使谓司城去公,对曰:“臣之而逃其难,若后君何?” +冬十一月甲寅,宋昭公将田孟诸,未至,夫人王姬使帅甸攻而杀之。荡意诸死之。书曰:“宋人弑其君杵臼。”君无道也。 +文公即位,使母弟须为司城。华耦卒,而使荡虺为司马。 +译文 +十六年春季,周王朝历法的正月,鲁国与齐国议和。文公生病,派季文子和齐懿公在阳穀会见。季文子请求盟誓,齐懿公不肯,说:“请等贵国国君病好了再说吧。” +夏季,五月,文公四次没有在朔日听政,这是由于生重病的缘故。文公派襄仲向齐懿公馈送财礼,所以就在郪丘结盟。 +有蛇从泉宫出来,进入国都,共十七条,和先君的数目一样。秋季,八月初八日,声姜死,因此拆毁了泉台。 +楚国发生大饥荒,戎人攻打它的西南部,到达阜山,军队驻扎在大林。又进攻它的东南部,到达阳丘,以进攻訾枝。庸国人率领蛮人们背叛楚国,麇国人率领百濮聚集在选地,准备攻打楚国。在这时候,申地、息地的北门不敢打开。 +楚国人商量迁到阪高去。蒍贾说:“不行。我们能去,敌人也能去,不如攻打庸国。麇国和百濮,认为我们遭受饥荒而不能出兵,所以攻打我们。如果我们出兵,他们必然害怕而回去。百濮散居各处,将会各回各的地方,谁还有空来打别人的主意?”于是楚国就出兵,过了十五天,百濮就罢兵回去了。 +楚军从庐地出发以后,每到一地就打开仓库让将士一起食用。军队驻扎在句澨。派庐戢梨进攻庸国,到达庸国的方城。庸国人赶走楚军,囚禁了子扬窗。过了三个晚上,子扬窗逃跑回来,说:“庸国的军队人数众多,蛮人们聚在那里,不如再发大兵,同时出动国君的直属部队,合兵以后再进攻。”师叔说:“不行。姑且再跟他们交战使他们骄傲。他们骄傲,我们奋发,然后就可以战胜,先君蚡冒就是这样使陉隰归服的。”楚军又和他们接战,七次接战都败走,蛮人中只有裨、鯈、鱼人追赶楚军。庸国人说:“楚国不足以一战了。”就不再设防。 +楚庄王乘坐驿站的传车,在临品和前方部队会师,把军队分做两队:子越从石溪出发,子贝从仞地出发,以进攻庸国。秦军、巴军跟随着楚军,蛮人们服从楚王,和他结盟,就把庸国灭亡了。 +宋国的公子鲍对国人加以优礼,宋国发生饥荒,把粮食全部拿出来施舍。对年纪在七十岁以上的,没有不送东西的,还按时令加送珍贵食品。没有一天不进出六卿的大门。对国内有才能的人,没有不加事奉的;对亲属中从桓公以下的子孙,没有不加周济的。公子鲍漂亮而且艳丽,宋襄公夫人想和他私通,公子鲍不肯,襄公夫人就帮助他施舍。宋昭公无道,国内的人们都由于襄公夫人的关系而拥护公子鲍。 +当时,华元做右师,公子友做左师,华耦做司马、鳞鱹做司徒,荡意诸做司城,公子朝做司寇。当初,司城荡死了,公子寿辞掉司城的官职,请求让荡意诸担任。后来告诉别人说:“国君无道,我的官位接近国君,很怕祸患引到身上。如果丢掉官职不干,家族就无所庇护。儿子,是我的代表,姑且让我晚点死去。这样,虽然丧失儿子,还不致于丧失家族。”不久以后,襄公夫人准备让宋昭公在孟诸打猎而乘机杀死他。宋昭公知道以后,带上了全部珍宝而出行。荡意诸说:“何不到诸侯那里去?”宋昭公说:“得不到自己的大夫至于君祖母以及人们的信任,诸侯谁肯接纳我?而且已经做了别人的君主,再做别人的臣下,不如死了好。”昭公把他的珍宝全部赐给左右随行人员,而让他们离去。襄公夫人派人告诉司城荡意诸离开宋昭公,司城回答说:“做他的臣下,而又逃避他的祸难,怎么能事奉以后的国君呢?” +冬季,十一月二十二日,宋昭公准备去孟诸打猎,没有到达,襄公夫人王姬派遣帅甸进攻并杀死了他,荡意诸为此死了。《春秋》记载说“宋人弑其君杵臼”,这是由于国君无道。宋文公即位,派同母弟做了司城。华耦死后,派荡虺担任司马。 + +文公十七年 +【经】十有七年春,晋人、卫人、陈人、郑人伐宋。夏四月癸亥,葬我小君声姜。齐侯伐我西鄙。六月癸未,公及齐侯盟于谷。诸侯会于扈。秋,公至自谷。冬,公子遂如齐。 +【传】十七年春,晋荀林父、卫孔达、陈公孙宁、郑石楚伐宋。讨曰:“何故弑君!”犹立文公而还,卿不书,失其所也。 +夏四月癸亥,葬声姜。有齐难,是以缓。 +齐侯伐我北鄙,襄仲请盟。六月,盟于谷。 +晋侯蒐于黄父,遂复合诸侯于扈,平宋也。公不与会,齐难故也。书曰“诸侯”,无功也。 +于是,晋侯不见郑伯,以为贰于楚也。 +郑子家使执讯而与之书,以告赵宣子,曰:“寡君即位三年,召蔡侯而与之事君。九月,蔡侯入于敝邑以行。敝邑以侯宣多之难,寡君是以不得与蔡侯偕。十一月,克灭侯宣多而随蔡侯以朝于执事。十二年六月,归生佐寡君之嫡夷,以请陈侯于楚而朝诸君。十四年七月,寡君又朝,以蒇陈事。十五年五月,陈侯自敝邑往朝于君。往年正月,烛之武往朝夷也。八月,寡君又往朝。以陈、蔡之密迩于楚而不敢贰焉,则敝邑之故也。虽敝邑之事君,何以不免?在位之中,一朝于襄,而再见于君。夷与孤之二三臣相及于绛,虽我小国,则蔑以过之矣。今大国曰:‘尔未逞吾志。’敝邑有亡,无以加焉。古人有言曰:‘畏首畏尾,身其馀几。’又曰:‘鹿死不择音。’小国之事大国也,德,则其人也;不德,则其鹿也,铤而走险,急何能择?命之罔极,亦知亡矣。将悉敝赋以待于鯈,唯执事命之。 +文公二年六月壬申,朝于齐。四年二月壬戌,为齐侵蔡,亦获成于楚。居大国之间而从于强令,岂其罪也。大国若弗图,无所逃命。” +晋巩朔行成于郑,赵穿、公婿池为质焉。 +秋,周甘蜀败戎于垂,乘其饮酒也。 +冬十月,郑大子夷、石楚为质于晋。 +襄仲如齐,拜谷之盟。复曰:“臣闻齐人将食鲁之麦。以臣观之,将不能。齐君之语偷。臧文仲有言曰:‘民主偷必死’。” +译文 +十七年春季,晋国荀林父、卫国孔达、陈国公孙宁、郑国石楚联军攻打宋国,质问说:“为什么杀死你们国君?”还是立了宋文公而回国。《春秋》没有记载卿的姓名,这是由于他们改变初衷。 +夏季,四月初四日,安葬声姜。由于有齐国攻战造成的困难,因此推迟。 +齐懿公攻打我国北部边境,襄仲请求结盟。六月,在穀地结盟。 +晋灵公在黄父阅兵,就因此再次在扈地会合诸侯,这是为了和宋国讲和。鲁文公没有参加会合,这是由于发生了齐国征战造成的困难的缘故。《春秋》记载说“诸侯”而不记名字,这是讥讽他们并没有取得成效。 +当时,晋灵公拒绝会见郑穆公,以为他背晋而亲楚。郑国的子家派通信使者去晋国,并且给他一封信,告诉赵宣子,说:我郑国国君即位三年,召了蔡侯和他一起事奉贵国君主。九月,蔡侯来到敝邑前去贵国。敝邑由于侯宣多造成的祸难,我君因此而不能和蔡侯一同前来。十一月,消灭了侯宣多,就随同蔡侯而向执事朝觐。十二年六月,归生辅佐我君的长子夷,到楚国请求陈侯一同朝见贵国君主。十四年七月,我君又向贵国君主朝见,以完成关于陈国的事情。十五年五月,陈侯从我国前去朝见贵国君主。去年正月,烛之武前去贵国,这是为了使夷前往朝见贵国君主。八月,我君又前去朝见。因陈、蔡两国紧紧挨着楚国而不敢对晋有二心,那是由于我们的缘故。为什么唯独我们这样事奉贵国君主,反而不能免于祸患呢? +我郑君在位期间,一次朝见贵国先君襄公,两次朝见现在的君主。夷和我的几个臣下紧接着到绛城来。我郑国虽然是个小国,却没有谁能比我国对贵国更有诚意了。如今大国说:“你没有能让我称心如意。”敝邑只有等待灭亡,也不能再增加一点什么了。古人有话说:“怕头怕尾,剩下来的身子还有多少?”又说:“鹿在临死前,顾不上选择庇护的地方。”小国事奉大国,如果大国以德相待,小国就会以人道相事奉;如果不是以德相待,那就会像鹿一样,狂奔走险,急迫的时候,哪里还能选择地方?贵国的命令没有止境,我们也知道面临灭亡了,只好准备派出敝邑全部的士兵在鯈地等待。该怎么办,就听凭您的命令吧! +我郑文公二年六月二十日,曾到齐国朝见。四年二月某一天,为齐国进攻蔡国,也和楚国取得讲和。处于齐、楚两个大国之间而屈从于强国的命令,这难道是我们的罪过吗?大国如果不加谅解,我们是没有地方可以逃避你们的命令了。晋国的巩朔到郑国讲和修好,赵穿,公婿池作为人质。 +秋季,周朝的甘歜在邥垂打败戎人,一战取胜是由于趁着戎人正在喝酒而用兵。 +冬季,十一月,郑国的太子夷、大夫石楚到晋国作为人质。 +襄仲到齐国去,拜谢穀地的结盟。回来说:“下臣听说齐国人将要吃鲁国的麦子。据下臣看来,恐怕做不到。齐国国君的话极不严肃。臧文仲曾说过:‘百姓的主人说话不严肃,必然很快就会死。’” + +文公十八年 +【经】十有八年春王二月丁丑,公薨于台下。秦伯荦卒。夏五月戊戌,齐人弑其君商人。六月癸酉,葬我君文公。秋,公子遂、叔孙得臣如齐。冬十月,子卒。夫人姜氏归于齐。季孙行父如齐。莒弑其君庶其。 +【传】十八年春,齐侯戒师期,而有疾,医曰:“不及秋,将死。”公闻之,卜曰:“尚无及期。”惠伯令龟,卜楚丘占之曰:“齐侯不及期,非疾也。君亦不闻。令龟有咎。”二月丁丑,公薨。 +齐懿公之为公子也,与邴蜀之父争田,弗胜。及即位,乃掘而刖之,而使蜀仆。纳阎职之妻,而使职骖乘。 +夏五月,公游于申池。二人浴于池,蜀以扑抶职。职怒。曰:“人夺女妻而不怒,一抶女庸何伤!”职曰:“与刖其父而弗能病者何如?”乃谋弑懿公,纳诸竹中。归,舍爵而行。齐人立公子元。 +六月,葬文公。 +秋,襄仲、庄叔如齐,惠公立故,且拜葬也。 +文公二妃敬赢生宣公。敬赢嬖而私事襄仲。宣公长而属诸襄仲,襄仲欲立之,叔仲不可。仲见于齐侯而请之。齐侯新立而欲亲鲁,许之。 +冬十月,仲杀恶及视而立宣公。书曰“子卒”,讳之也。仲以君命召惠伯。其宰公冉务人止之,曰:“入必死。”叔仲曰:“死君命可也。”公冉务人曰:“若君命可死,非君命何听?”弗听,乃入,杀而埋之马矢之中。公冉务人奉其帑以奔蔡,既而复叔仲氏。 +夫人姜氏归于齐,大归也。将行,哭而过市曰:“天乎,仲为不道,杀适立庶。”市人皆哭,鲁人谓之哀姜。 +莒纪公生大子仆,又生季佗,爱季佗而黜仆,且多行无礼于国。仆因国人以弑纪公,以其宝玉来奔,纳诸宣公。公命与之邑,曰:“今日必授。”季文子使司寇出诸竟,曰:“今日必达。”公问其故。季文子使大史克对曰:“先大夫臧文仲教行父事君之礼,行父奉以周旋,弗敢失队。”曰:‘见有礼于其君者,事之如孝子之养父母也。见无礼于其君者,诛之如鹰鸇之逐鸟雀也。’先君周公制《周礼》曰:‘则以观德,德以处事,事以度功,功以食民。’作《誓命》曰:‘毁则为贼,掩贼为藏,窃贿为盗,盗器为奸。主藏之名,赖奸之用,为大凶德,有常无赦,在《九刑》不忘。’行父还观莒仆,莫可则也。孝敬忠信为吉德,盗贼藏奸为凶德。夫莒仆,则其孝敬,则弑君父矣;则其忠信,则窃宝玉矣。其人,则盗贼也;其器,则奸兆也,保而利之,则主藏也。以训则昏,民无则焉。不度于善,而皆在于凶德,是以去之。 +“昔高阳氏有才子八人,苍舒、隤岂、檮寅、大临、龙降、庭坚、仲容、叔达,齐圣广渊,明允笃诚,天下之民谓之八恺。高辛氏有才子八人,伯奋、仲堪、叔献、季仲、伯虎、仲熊、叔豹、季狸,忠肃共懿,宣慈惠和,天下之民谓之八元。此十六族也,世济其美,不陨其名,以至于尧,尧不能举。舜臣尧,举八恺,使主后土,以揆百事,莫不时序,地平天成。举八元,使布五教于四方,父义、母慈、兄友、弟共、子孝,内平外成。昔帝鸿氏有不才子,掩义隐贼,好行凶德,丑类恶物,顽嚚不友,是与比周,天下之民谓之浑敦。少嗥氏有不才子,毁信废忠,崇饰恶言,靖谮庸回,服谗蒐慝,以诬盛德,天下之民谓之穷奇。颛顼有不才子,不可教训,不知话言,告之则顽,舍之则嚚,傲很明德,以乱天常,天下之民谓之檮杌。此三族也,世济其凶,增其恶名,以至于尧,尧不能去。缙云氏有不才子,贪于饮食,冒于货贿,侵欲崇侈,不可盈厌,聚敛积实,不知纪极,不分孤寡,不恤穷匮,天下之民以比三凶,谓之饕餮。舜臣尧,宾于四门,流四凶族浑敦、穷奇、檮杌、饕餮,投诸四裔,以御魑魅。是以尧崩而天下如一,同心戴舜以为天子,以其举十六相,去四凶也。故《虞书》数舜之功,曰‘慎徽五典,五典克从’,无违教也。曰‘纳于百揆,百揆时序’,无废事也。曰‘宾于四门,四门穆穆’,无凶人也。 +舜有大功二十而为天子,今行父虽未获一吉人,去一凶矣,于舜之功,二十之一也,庶几免于戾乎!” +宋武氏之族道昭公子,将奉司城须以作乱。十二月,宋公杀母弟须及昭公子,使戴、庄、桓之族攻武氏于司马子伯之馆。遂出武、穆之族,使公孙师为司城,公子朝卒,使乐吕为司寇,以靖国人。 +译文 +十八年春季,齐懿公下达了出兵日期,不久就得了病。医生说:“过不了秋天就会死去。”鲁文公听说以后,占了个卜,说:“希望他不到发兵日期就死!”惠伯在占卜前把所要占卜的事情致告龟甲,卜楚丘占了个卜说:“齐懿公不到期而死,但不是由于生病;国君也听不到这件事了。致告龟甲的人有灾祸。”二月二十三日,鲁文公逝世。 +齐懿公在做公子的时候,和邴歜的父亲争夺田地,没有得胜。等到即位以后,就掘出尸体而砍去他的脚,但又让邴歜为他驾车。夺取了阎职的妻子而又让阎职作他的骖乘。 +夏季,五月,齐懿公在申池游玩。邴歜、阎职两个人在池子里洗澡,邴歜用马鞭打阎职。阎职发怒。邴歜说:“别人夺了你的妻子你不生气,打你一下,有什么妨碍?”阎职说:“比砍了他父亲的脚而不敢怨恨的人怎么样?”于是二人就一起策划,杀死了齐懿公,把尸体放在竹林里。回去,在宗庙里祭祀,摆好酒杯然后公然出走。齐国人立了公子元为国君。 +六月,安葬鲁文公。 +秋季,襄仲、庄叔去齐国,这是由于齐惠公即位,同时拜谢齐国前来参加葬礼。 +鲁文公的第二个妃子敬嬴生了宣公。敬嬴受到宠爱,而私下结交襄仲。宣公年长,敬嬴把他嘱托给襄仲。襄仲要立他为国君,仲叔不同意,仲叔进见齐惠公。请求不要立宣公为国君。齐惠公新即位,想要亲近鲁国,同意了仲叔的请求。 +冬季,十月,襄仲杀死了太子恶和他的弟弟视,拥立宣公为国君。《春秋》记载说“子卒”,这是为了隐讳真象。襄仲用国君的名义召见叔仲惠伯,惠伯的家臣头子公冉务人劝止他,说:“进去必定死。”叔仲说:“死于国君的命令是可以的。”公冉务人说:“如果是国君的命令,可以死;不是国君的命令,为什么听从?”叔仲不听,就进去了,襄仲把他杀死了而埋在马粪中间。公冉务人事奉叔仲的妻子儿女逃亡到蔡国,不久以后重新立了叔仲氏。 +鲁文公夫人姜氏回到齐国,这是回娘家而不再回来了。她将要离开的时候,哭着经过集市,说:“天哪!襄仲无道,杀死了嫡子立庶子。”集市上的人都随着她哭泣,鲁国人称她为哀姜。 +莒纪公生了太子仆,又生了季佗,喜爱季佗而废黜太子仆,而且在国内办了许多不合礼仪的事情。太子仆依靠国内人们的力量杀了纪公,拿了他的宝玉逃亡前来,送给鲁宣公。宣公命令给他城邑,说:“今天一定得给。”季文子让司寇把他赶出国境,说:“今天一定得彻底执行。”鲁宣公询问这样做的缘故。季文子让太史克回答说:先大夫臧文仲教导行父事奉国君的礼仪,行父根据它而应酬对答,不敢丢失。先大夫说:“见到对他的国君有礼的,事奉他,如同孝子奉养父母一样;见到对他的国君无礼的,诛戮他,如同鹰鹯追逐鸟雀一样。”先君周公制作《周礼》说:“礼仪用来观察德行,德行用来处置事情,事情用来衡量功劳,功劳用来取食于民。”又制作《誓命》说:“毁弃礼仪就是贼,窝藏贼人就是赃,偷窃财物就是盗,偷盗宝器就是奸。有窝赃的名声,利用奸人的宝器,这是很大的凶德,国家对此有规定的刑罚,不能赦免,记载在《九刑》之中,不能忘记。”行父仔细观察莒仆,没有可以效法的。孝敬、忠信是吉德,盗贼、赃奸,是凶德。这个莒仆,如果取法他的孝敬吧,那么他是杀了国君父亲的;取法他的忠信吧,那么他是偷窃了宝玉的。他这个人,就是盗贼;他的器物,就是赃证。如果保护这个人而用他的器物,那就是窝赃。以此来教育百姓,百姓就昏乱无所取法了。莒仆的这些表现都不能算好事,而都属于凶德,所以才把他赶走。 +从前高阳氏有才能强的子孙八位:苍舒、隤??、梼戭、大临、尨降、庭坚、仲容、叔达,他们中正、通达、宽宏、深远、明智、守信、厚道、诚实,天下的百姓称之为八恺。高辛氏有才能强的子孙八位:伯奋、仲堪、叔献、季仲、伯虎、仲熊、叔豹、季狸,他们忠诚、恭敬、勤谨、端美、周密、慈祥、仁爱、宽和,天下的百姓称之为八元。这十六个家族,世世代代继承他们的美德,没有丧失前世的声名,一直到尧的时代,但是尧没有能举拔他们。舜做了尧的臣下以后,举拔八恺,让他们担任管理土地的官职,处理各种事务,没有不顺当的,地上和天上都平和无事。又举拔八元,让他们在四方之国宣扬五种教化,父亲讲道义,母亲慈爱,哥哥友爱,弟弟恭敬,儿子孝顺,里里外外都平安无事。从前帝鸿氏有一个没有才能的儿子,掩蔽道义,包庇奸贼,喜欢办那些属于凶德的事情,把坏东西引为同类,那些愚昧奸诈的人,和他混在一起,天下的百姓称他为浑敦。少皞氏有一个没有才能的儿子,毁坏信义,废弃忠诚,花言巧语,惯听谗言,任用奸邪,造谣中伤,掩盖罪恶,诬陷盛德的人,天下的百姓称他为穷奇。颛顼氏有一个没有才能的儿子,没办法教训,不知道好话,他愚顽不灵,丢开他,他又刁恶奸诈,鄙视美德,搅乱上天的常道,天下的百姓称他为梼杌。这三个家族,世世代代继承他们的凶恶,加重了他们的坏名声,一直到尧的时代,但是尧没有能赶走他们。缙云氏有一个没有才能的儿子,追求吃喝,贪图财货,任性奢侈,不能满足,聚财积谷,没有限度,不分给孤儿寡妇,不周济穷人,天下的百姓把他和三凶相比,称他为饕餮。舜做了尧的臣下以后,开辟四方的城门,流放四个凶恶的家族,把浑敦、穷奇、梼杌、饕餮赶到四边荒远的地方,让他们去抵御妖怪。由于这样,尧死后而天下就像一个人一样,同心拥戴舜做天子,因为他举拔了十六相而去掉了四凶的缘故。所以《虞书》举出舜的功业,说“谨慎地发扬五典,五典就能服从他”,这是说没有错误的教导。说“放在许多事务之中,事务都能顺利”,这是说没有荒废的事务。说“开辟四方的城门,从远方来的宾客都恭敬肃穆”,这是说没有凶顽的人物。舜建立了二十种大功才成为天子,现在行父没有得到一个好人,但已经赶走一个凶顽的人了。与舜的功业相比,已是二十分之一,差不多可以免于罪过了吧! +宋国武氏的族人领着昭公的儿子,准备事奉司城须来发动叛乱。十二月,宋文公杀死了同胞兄弟须和昭公的儿子,让戴公、庄公、桓公的族人在司马子伯的宾馆里攻打武氏,于是就把武公、穆公的族人驱逐出境,派遣公孙师做司城。公子朝去世,派了乐吕做司寇,来安定国内的人心。 + +宣公 + + +宣公元年 +【经】元年春王正月,公即位。公子遂如齐逆女。三月,遂以夫人妇姜至自齐。夏,季孙行父如齐。晋放其大夫胥甲父于卫。公会齐侯于平州。公子遂如齐。六月,齐人取济西田。秋,邾子来朝。楚子、郑人侵陈,遂侵宋。晋赵盾帅师救陈。宋公、陈侯、卫侯、曹伯会晋师于棐林,伐郑。冬,晋赵穿帅师侵崇。晋人、宋人伐郑。 +【传】元年春,王正月,公子遂如齐逆女,尊君命也。三月,遂以夫人妇姜至自齐,尊夫人也。 +夏,季文子如齐,纳赂以请会。 +晋人讨不用命者,放胥甲父于卫,而立胥克。先辛奔齐。 +会于平州,以定公位。东门襄仲如齐拜成。 +六月,齐人取济西之田,为立公故,以赂齐也。 +宋人之弑昭公也,晋荀林父以诸侯之师伐宋,宋及晋平,宋文公受盟于晋。又会诸侯于扈,将为鲁讨齐,皆取赂而还。郑穆公曰:“晋不足与也。”遂受盟于楚。陈共公之卒,楚人不礼焉。陈灵公受盟于晋。 +秋,楚子侵陈,遂侵宋。晋赵盾帅师救陈、宋。会于棐林,以伐郑也。楚蒍贾救郑,遇于北林。囚晋解扬,晋人乃还。 +晋欲求成于秦,赵穿曰:“我侵崇,秦急崇,必救之。吾以求成焉。”冬,赵穿侵崇,秦弗与成。 +晋人伐郑,以报北林之役。于是,晋侯侈,赵宣子为政,骤谏而不入,故不竞于楚。 +译文 +元年春,周王朝历法的正月,公子遂到齐国迎接齐女。《春秋》所以称之为“公子遂”,是由于尊重国君的命令。 +三月,遂和夫人妇姜从齐国来到,《春秋》所以又称之为“遂”,是由于尊重夫人。 +夏季,季文子到齐国,进献财礼。以请求参加盟会。 +晋国人惩罚不听命令的人,把胥甲父放逐到卫国,而立了胥克。先辛逃亡到齐国。 +宣公和齐惠公在平州会见,以稳定宣公的君位。东门襄仲去齐国,拜谢宣公能够参加盟会。 +六月,齐国人取得了济水以西的土田,这是由于齐国帮助宣公得为国君的缘故,用此作为对齐国的谢礼。 +宋国人杀死昭公的时候,晋国的荀林父带领诸侯的军队攻打宋国,宋国和晋国讲和,宋文公在晋国接受盟约。又在扈地会合诸侯,准备为鲁国讨伐齐国。两次都取得了财货而回国。 +郑穆公说:“晋国是不值得亲附的。”就在楚国接受盟约。陈共公死的时候,楚国不行诸侯吊丧的礼仪,陈灵公在晋国接受盟约。 +秋季,楚庄王侵袭陈国,乘机又侵袭宋国。晋国赵盾带兵救陈、宋。宋文公、陈灵公、卫成公、曹文公和晋军在棐林会合,讨伐郑国。楚国..贾去救援郑国,在北林和晋军相遇,囚禁了晋国的解扬,晋军就回国了。 +晋国想要和秦国讲和。赵穿说:“我们侵袭崇国,秦国为崇国着急,一定会去救崇国,我们就以此向秦国要求讲和。”冬季。赵穿侵袭崇国。秦国不肯和晋国讲和。晋军攻打郑国,以报复北林的那次战役。当时,晋灵公奢侈,赵宣子执政,多次劝谏都不听,所以不能和楚国竞争。 + +宣公二年 +【经】二年春王二月壬子,宋华元帅师及郑公子归生帅师,战于大棘。宋师败绩,获宋华元。秦师伐晋。夏,晋人、宋人、卫人、陈人侵郑。秋九月乙丑,晋赵盾弑其君夷皋。冬十月乙亥,天王崩。 +【传】二年春,郑公子归生受命于楚,伐宋。宋华元、乐吕御之。二月壬子,战于大棘,宋师败绩,囚华元,获乐吕,及甲车四百六十乘,俘二百五十人,馘百人。狂狡辂郑人,郑人入于井,倒戟而出之,获狂狡。君子曰:“失礼违命,宜其为禽也。戎,昭果毅以听之之谓礼,杀敌为果,致果为毅。易之,戮也。” +将战,华元杀羊食士,其御羊斟不与。及战,曰:“畴昔之羊,子为政,今日之事,我为政。”与人郑师,故败。君子谓:“羊斟非人也,以其私憾,败国殄民。于是刑孰大焉。《诗》所谓‘人之无良’者,其羊斟之谓乎,残民以逞。” +宋人以兵车百乘、文马百驷以赎华元于郑。半入,华元逃归,立于门外,告而入。见叔佯,曰:“子之马然也。”对曰:“非马也,其人也。”既合而来奔。 +宋城,华元为植,巡功。城者讴曰:“睅其目,皤其腹,弃甲而复。于思于思,弃甲复来。”使其骖乘谓之曰:“牛则有皮,犀兕尚多,弃甲则那?”役人曰:“从其有皮,丹漆若何?”华元曰:“去之,夫其口众我寡。” +秦师伐晋,以报崇也,遂围焦。夏,晋赵盾救焦,遂自阴地,及诸侯之师侵郑,以报大棘之役。楚斗椒救郑,曰:“能欲诸侯而恶其难乎?”遂次于郑以待晋师。赵盾曰:“彼宗竞于楚,殆将毙矣。姑益其疾。”乃去之。 +晋灵公不君:厚敛以雕墙;从台上弹人,而观其辟丸也;宰夫肠熊蹯不熟,杀之,置诸畚,使妇人载以过朝。赵盾、士季见其手,问其故,而患之。将谏,士季曰:“谏而不入,则莫之继也。会请先,不入则子继之。”三进,及溜,而后视之。曰:“吾知所过矣,将改之。”稽首而对曰:“人谁无过?过而能改,善莫大焉。《诗》曰:‘靡不有初,鲜克有终。’夫如是,则能补过者鲜矣。君能有终,则社稷之固也,岂唯群臣赖之。又曰:‘衮职有阙,惟仲山甫补之。’能补过也。君能补过,兖不废矣。”犹不改。宣子骤谏,公患之,使锄麑贼之。晨往,寝门辟矣,盛服将朝,尚早,坐而假寐。麑退,叹而言曰:“不忘恭敬,民之主也。贼民之主,不忠。弃君之命,不信。有一于此,不如死也。”触槐而死。 +秋九月,晋侯饮赵盾酒,伏甲将攻之。其右提弥明知之,趋登曰:“臣侍君宴,过三爵,非礼也。”遂扶以下,公嗾夫獒焉。明搏而杀之。盾曰:“弃人用犬,虽猛何为。”斗且出,提弥明死之。 +初,宣子田于首山,舍于翳桑,见灵辄饿,问其病。曰:“不食三日矣。”食之,舍其半。问之,曰:“宦三年矣,未知母之存否,今近焉,请以遗之。”使尽之,而为之箪食与肉,置诸橐以与之。既而与为公介,倒戟以御公徒,而免之。问何故。对曰:“翳桑之饿人也。”问其名居,不告而退,遂自亡也。 +乙丑,赵穿攻灵公于桃园。宣子未出山而复。大史书曰:“赵盾弑其君。”以示于朝。宣子曰:“不然。”对曰:“子为正卿,亡不越竟,反不讨贼,非子而谁?”宣子曰:“乌呼,‘我之怀矣,自诒伊戚’,其我之谓矣!”孔子曰:“董孤,古之良史也,书法不隐。赵宣子,古之良大夫也,为法受恶。惜也,越竟乃免。” +宣子使赵穿逆公子黑臀于周而立之。壬申,朝于武宫。 +初,丽姬之乱,诅无畜群公子,自是晋无公族。及成公即位,乃宦卿之适子而为之田,以为公族,又宦其馀子亦为余子,其庶子为公行。晋于是有公族、余子、公行。赵盾请以括为公族,曰:“君姬氏之爱子也。微君姬氏,则臣狄人也。”公许之。 +冬,赵盾为旄车之族。使屏季以其故族为公族大夫。 +译文 +二年春季,郑国公子归生接受楚国命令攻打宋国。宋国华元、乐吕带兵抵御。二月十日,在大棘地方开战,宋军大败。郑国囚禁了华元,得到乐吕的尸首,缴获战车四百六十辆,俘虏二百五十人,割了一百个被打死的敌人的耳朵。 +狂狡迎战郑国人,那个郑国人逃进井里。狂狡把戟柄放下井去拉他上来。那个人出井以后反而俘虏了狂狡。君子说:“丢掉礼而违背命令,他活该被俘。战争,发扬果敢刚毅的精神以服从命令叫做礼。杀死敌人就是果敢,达到果敢就是刚毅。如果反过来,就要被杀戮。” +准备开战的时候,华元杀羊犒赏士兵,他的车夫羊斟没有吃到。等到打起仗来,羊斟说:“前天的羊,是你作主;今天的打仗,是我作主。”就驱车进入郑军,所以宋军失败。君子认为:“羊斟不像个人,由于私怨,使国家战败、百姓受害,还有比这应当受到更重的刑罚吗?《诗》所谓‘存心不良’,羊斟就是这种人吧!他残害百姓以使自己快意。” +宋国人用兵车一百辆、毛色漂亮的马四百匹,从郑国赎取华元。仅送去一半,华元就逃回来了。华元站在城门外,告诉守门人自己的身分,然后进城。见到羊斟说:“您的马不受驾御才会这样吧?”羊斟回答说:“不是马,是人。”回答完就逃到鲁国来。 +宋国筑城,华元作为主持者,巡视工作。筑城的人唱歌说:“鼓着眼,挺着肚,丢了皮甲往回走。连鬓胡,长满腮,丢盔卸甲逃回来。”华元使他的骖乘对他们说:“有牛就有皮,犀牛兕牛多的是,丢了皮甲又有什么了不起?”做工的人说:“即使有牛皮,又去哪里找红漆?”华元说:“走吧!他们的嘴多,我们的嘴少。” +秦国军队攻打晋国,以报复晋军侵入崇地的那次战役,因此而包围焦地。夏季,晋国赵盾救援焦地,于是从阴地会同诸侯的军队袭击郑国,以报复郑国攻打大棘的那次战役。楚国鬬椒救援郑国,说:“难道想得到诸侯的拥护,而又害怕困难吗?”楚军就驻扎在郑国,等待晋军。赵盾说:“他那个宗族在楚国争权夺利,差不多要完蛋了。暂且让他加重弊病。”于是就离开郑国。 +晋灵公做事不合为君之道:重重地收税用来彩画墙壁,从高台上用弹丸打人而看他们躲避弹丸的形状。有一次,厨子烧煮熊掌不熟,灵公杀死他,放在畚箕里,让女人用头顶着走过朝庭。赵盾和士会看到死人的手,问起杀人的缘故,感到担心,准备进谏。士会对赵盾说:“你劝谏如果听不进去,就没有人继续劝谏了。请让士会先去,不听,你再接着劝谏。”士会前去三次,到达屋檐下,晋灵公才转眼看他,说:“我知道错了,打算改正。”士会叩头回答说:“一个人谁没有错,有了过错能够改正,就没有比这再好的事情了。《诗》说:‘事情不难有个好开始,很少能有个好结果。’如果像这样,能够弥补过错的人就很少了。君王能够有好结果,那就是国家的保障了,岂只仅仅臣下们依靠它。《诗》又说:‘周宣王有了过失,只有仲山甫来弥补。’这说的是能够弥补错误。君王能够弥补错误,礼服就不会丢弃了。”晋灵公尽管口头上说要改错,行动上还是不改正。赵盾屡次进谏,晋灵公很讨厌,派遣鉏麑去刺杀他。一天清早,赵盾的卧室门已经打开了,穿得整整齐齐,准备入朝。时间还早,赵盾正坐着打瞌睡。鉏麑退出来,叹气说:“不忘记恭敬,真是百姓的主人。刺杀百姓的主人,就是不忠;放弃国君的使命, +就是不信。两件事情有了一件,不如死了好。”撞在槐树上死去了。 +就是不信。两件事情有了一件,不如死了好。”撞在槐树上死去了。 +当初,赵盾在首阳山打猎,住在翳桑,看见灵辄饿倒在地上,问他有什么病。灵辄说:“已经三天没吃东西了。”赵盾给他食物,他留下一半。问他为什么,他说:“在外学习做官已经三年了,不知道母亲还在不在,现在快到家了,请让我把这个留给她。”赵盾让他吃完,并且又给他准备了一筐饭和一些肉,放在袋子里给了他。后来灵辄做了晋灵公的卫兵,在这次事件中,倒过戟来抵御晋灵公的其他卫兵,使赵盾免于祸难。赵盾问他为什么这样做,他回答说:“我就是翳桑那个饿倒的人。”问他的姓名住处,他不回答而退了出去,就自己逃亡了。 +九月二十六日,赵穿在桃园杀死了晋灵公。赵盾没有走出晋国国境就回来再度做卿。太史记载说:“赵盾弑其君”,在朝廷上公布。赵盾说:“不是这样。”太史回答说:“您是正卿,逃亡而没有走出国境,回来不惩罚凶手,弑君的人不是您还是谁?”赵盾说:“哎呀!《诗》说:‘因为我的怀恋,给自己带来了忧戚。’恐怕就是说的我了。”孔子说:“董狐,是古代的好史官,据事直书而不加隐讳。赵宣子,是古代的好大夫,因为法度而蒙受恶名。太可惜了,要是走出了国境,就可以避免背上弑君的罪名了。” +赵盾派遣赵穿到成周迎接公子黑臀而立他为国君。十月初三日,公子黑臀到武官庙朝祭。 +当初,丽姬作乱的时候,在神前诅咒,不许收容公子们,从此晋国没有公族这个官职。等到晋成公即位,就把官职授给卿的嫡长子,并且给他们土田,让他们做公族大夫。又把官职授给卿的其他儿子,也让他们担任馀子的官,让他们的庶子担任公行的官。晋国从此开始有了公族、馀子、公行三种官职。 +赵盾请求让赵括担任公族大夫,说:“他是君姬氏的爱子。如果没有君姬氏,那么下臣就是狄人了。”晋成公同意了。冬季,赵盾掌管旄车之族,让赵括统率他的旧族,做公族大夫。 + +宣公三年 +【经】三年春王正月,郊牛之口伤,改卜牛。牛死,乃不郊。犹三望。葬匡王。楚子伐陆浑之戎。夏,楚人侵郑。秋,赤狄侵齐。宋师围曹。冬十月丙戌。郑伯兰卒。葬郑穆公。 +【传】三年春,不郊而望,皆非礼也。望,郊之属也。不郊亦无望,可也。 +晋侯伐郑,及郔。郑及晋平,士会入盟。 +楚子伐陆浑之戎,遂至于洛,观兵于周疆。定王使王孙满劳楚子。楚子问鼎之大小轻重焉。对曰:“在德不在鼎。昔夏之方有德也,远方图物,贡金九牧,铸鼎象物,百物而为之备,使民知神、奸。故民入川泽山林,不逢不若。螭魅罔两,莫能逢之,用能协于上下以承天休。桀有昏德,鼎迁于商,载祀六百。商纣暴虐,鼎迁于周。德之休明,虽小,重也。其建回昏乱,虽大,轻也。天祚明德,有所底止。成王定鼎于郏鄏,卜世三十,卜年七百,天所命也。周德虽衰,天命未改,鼎之轻重,未可问也。” +夏,楚人侵郑,郑即晋故也。 +宋文公即位三年,杀母弟须及昭公子。武氏之谋也,使戴、桓之族攻武氏于司马子伯之馆。尽逐武、穆之族。武、穆之族以曹师伐宋。秋,宋师围曹,报武氏之乱也。 +冬,郑穆公卒。 +初,郑文公有贱妾曰燕姞,梦天使与己兰,曰:“余为伯鯈。余,而祖也,以是为而子。以兰有国香,人服媚之如是。”既而文公见之,与之兰而御之。辞曰:“妾不才,幸而有子,将不信,敢征兰乎。”公曰:“诺。”生穆公,名之曰兰。 +文公报郑子之妃,曰陈妫,生子华、子臧。子臧得罪而出。诱子华而杀之南里,使盗杀子臧于陈、宋之间。又娶于江,生公子士。朝于楚,楚人鸩之,及叶而死。又娶于苏,生子瑕、子俞弥。俞弥早卒。泄驾恶瑕,文公亦恶之,故不立也。公逐群公子,公子兰奔晋,从晋文公伐郑。石癸曰:“吾闻姬、姞耦,其子孙必蕃。姞,吉人也,后稷之元妃也,今公子兰,姞甥也。天或启之,必将为君,其后必蕃,先纳之可以亢宠。”与孔将锄、侯宣多纳之,盟于大宫而立之。以与晋平。 +穆公有疾,曰:“兰死,吾其死乎,吾所以生也。”刈兰而卒。 +译文 +三年春季,没有举行郊祭却举行望祭,这都不合于礼。望祭,是属于郊祭的一种,不举行郊祭,也不必举行望祭了。晋成公发兵攻打郑国,到达郔地。郑国和晋国讲和,士会到郑国缔结盟约。 +楚庄王发兵攻打陆浑的戎人,到达雒水,在周朝的直辖地域陈兵示威。周定王派遣王孙满慰劳楚庄王。楚庄王问起九鼎的大小轻重如何。王孙满回答说:“鼎的大小轻重在于德而不在于鼎本身。从前夏朝正是有德的时候,把远方的东西画成图像,让九州的长官进贡铜器,铸造九鼎并且把图像铸在鼎上,所有物像都具备在上面了,让百姓知道神物和怪物。所以百姓进入川泽山林,就不会碰上不利于自己的东西。螭魅魍魉这些鬼怪都不会遇上,因而能够使上下和谐,以承受上天的福佑。夏桀昏乱,把鼎迁到了商朝,前后六百年。商纣暴虐,鼎又迁到了周朝,德行如果美善光明,鼎虽然小,也是重的。如果奸邪昏乱,鼎虽然大,也是轻的。上天赐福给明德的人,是有一定期限的。成王把九鼎固定在郏鄏,占卜的结果是传世三十代,享国七百年,这是上天所命令的。周朝的德行虽然衰微,天命并没有改变。鼎的轻重,是不能询问的。” +夏季,楚国人入侵郑国,这是由于郑国倾向晋国的缘故。 +宋文公即位的第三年,杀了同胞弟弟须和昭公的儿子,这是出于武氏的谋划。于是就让戴公、桓公的族人在司马子伯的客馆里攻打武氏,把武公、穆公的族人全部驱赶出国。武公、穆公的族人用曹国的军队攻打宋国。秋季,宋国军队包围曹国,以报复武氏的叛乱。 +冬季,郑穆公去世。当初,郑文公有一个贱妾名叫燕姞,梦见天使给她一支兰花,说:“我是伯鯈。我,是你的祖先,把兰作为你的儿子。因为兰花的香味在全国数第一,佩带着它,别人就会像爱它一样地爱你。”不久以后,文公见到燕姞,给她一支兰花而让她侍寝。燕姞告诉文公说:“我的地位低贱,侥幸怀了孩子。如果别人不相信,敢请把兰花用来作为信物。”文公说:“好。”生了穆公,取名叫兰。 +郑文公奸淫了郑子的妃子叫做陈妫的,生了子华、子臧。子臧得了罪而离开了郑国。郑文公将子华诱骗到南里并杀死了他,又派坏人把子臧杀死在陈、宋两国之间。又在江国娶妻,生了公子士。公子士到楚国朝见,楚国人给他喝了毒酒,到叶地就死了。又在苏国娶妻,生了子瑕、子俞弥。俞弥早死。泄驾讨厌子瑕,郑文公也讨厌他,所以没有立为太子。郑文公赶走公子们,公子兰逃亡到晋国,跟随晋文公攻打郑国。石癸说:“我听说姬、姞两姓适合于成为配偶,他们的子孙必定蕃衍。姞,就是吉人的意思,是后稷的嫡妻。现在公子兰是姞氏的外甥,上天或许要使他光大,必然会做国君,他的后代必然蕃盛。如果先接纳他为国君,就可以保持他的宠信。”于是石癸就和孔将鉏、侯宣多收纳了公子兰,在大宫里盟誓以后而立了公子兰为国君,以此与晋国讲和。 +郑穆公有病,说:“兰花死了,我也许要死了吧!我是靠着它出生的。”割掉了兰花,郑穆公就死了。 + +宣公四年 +【经】四年春王正月,公及齐侯平莒及郯。莒人不肯。公伐莒,取向。秦伯稻卒。夏六月乙酉,郑公子归生弑其君夷。赤狄侵齐。秋,公如齐。公至自齐。冬,楚子伐郑。 +【传】四年春,公及齐侯平莒及郯,莒人不肯。公伐莒,取向,非礼也。平国以礼不以乱,伐而不治,乱也。以乱平乱,何治之有?无治,何以行礼? +楚人献鼋于郑灵公。公子宋与子家将见。子公之食指动,以示子家,曰:“他日我如此,必尝异味。”及入,宰夫将解鼋,相视而笑。公问之,子家以告,及食大夫鼋,召子公而弗与也。子公怒,染指于鼎,尝之而出。公怒,欲杀子公。子公与子家谋先。子家曰:“畜老,犹惮杀之,而况君乎?”反谮子家,子家惧而从之。夏,弑灵公。书曰:“郑公子归生弑其君夷。”权不足也。君子曰:“仁而不武,无能达也。”凡弑君,称君,君无道也;称臣,臣之罪也。 +郑人立子良,辞曰:“以贤则去疾不足,以顺则公子坚长。”乃立襄公。襄公将去穆氏,而舍子良。子良不可,曰:“穆氏宜存,则固愿也。若将亡之,则亦皆亡,去疾何为?”乃舍之,皆为大夫。 +初,楚司马子良生子越椒,子文曰:“必杀之。是子也,熊虎之状,而豺狼之声,弗杀,必灭若敖氏矣。谚曰:‘狼子野心。’是乃狼也,其可畜乎?”子良不可。子文以为大戚,及将死,聚其族,曰:“椒也知政,乃速行矣,无及于难。”且泣曰:“鬼犹求食,若敖氏之鬼,不其馁而?”及令尹子文卒,斗般为令尹,子越为司马。蒍贾为工正,谮子扬而杀之,子越为令尹,己为司马。子越又恶之,乃以若敖氏之族圄伯嬴于□□阳而杀之,遂处烝野,将攻王。王以三王之子为质焉,弗受,师于漳澨。秋七月戊戌,楚子与若敖氏战于皋浒。伯棼射王,汰輈,及鼓跗,着于丁宁。又射汰輈,以贯笠毂。师惧,退。王使巡师曰:“吾先君文王克息,获三矢焉。伯棼窃其二,尽于是矣。”鼓而进之,遂灭若敖氏。 +初,若敖娶于云阜,生斗伯比。若敖卒,从其母畜于云阜,淫于云阜子之女,生子文焉云阜夫人使弃诸梦中,虎乳之。云阜子田,见之,惧而归,以告,遂使收之。楚人谓乳谷,谓虎于菟,故命之曰斗谷于菟。以其女妻伯比,实为令尹子文。其孙箴尹克黄使于齐,还,及宋,闻乱。其人曰,“不可以入矣。”箴尹曰:“弃君之命,独谁受之?尹,天也,天可逃乎?”遂归,覆命而自拘于司败。王思子文之治楚国也,曰:“子文无后,何以劝善?”使复其所,改命曰生。 +冬,楚子伐郑,郑未服也。 +译文 +四年春季,鲁宣公和齐惠公使莒国和郯国讲和,莒人不肯。宣公攻打莒国,占领了向地,这是不合于礼的。和别国讲和应该用礼,不应该用动乱。讨伐就不能安定,就是动乱。用动乱去平定动乱,还有什么安定?没有安定,用什么来实行礼? +楚国人献给郑灵公一只大甲鱼。公子宋和子家将要进见,走在路上,公子宋的食指忽然自己动了起来,就把它给子家看,说:“以往我遇到这种情况,一定可以尝到美味。”等到进去以后,厨师正准备切甲鱼,两人互相看着而笑起来。郑灵公问他们为什么笑,子家就把刚才的情况告诉郑灵公。等到郑灵公把甲鱼赐给大夫们吃的时候,也把公子宋召来但偏不给他吃。公子宋发怒,用手指头在鼎里蘸了蘸,尝到味道后才退出去。郑灵公发怒,要杀死公子宋。公子宋和子家策划先下手。子家说:“牲口老了,尚且怕杀,何况国君?”公子宋就反过来诬陷子家。子家害怕,只好跟着他干,夏季,杀死了郑灵公。《春秋》记载说:“郑公子归生弑其君夷。”这是由于子家的权力不足的缘故。君子说:“仁爱而没有勇武,总是达不到目的。”凡是杀死国君,如果只记载国君的名字,这是由于国君无道;记载臣下的名字,这就是臣下有罪过。 +郑国人要立子良为国君,子良辞谢说:“以贤明而论,去疾是不够的,以顺序而论,公子坚年长。”就立了郑襄公。襄公准备驱逐他的兄弟们,而赦免了子良。子良不同意,说:“穆公的儿子如果适合留下来,去疾本来就有这样的愿望。如果要离开郑国,那就都离开,为什么单独留下去疾?”于是赦免了他们,让他们都做大夫。 +当初,楚国的司马子良生了子越椒。子文说:“一定要杀死他!这个孩子,有熊虎的形状、豺狼的声音,不杀,必然会灭亡若敖氏了。俗话说:‘狼子野心。’这孩子是一条狼,难道能够养着吗?”子良不同意,子文把这件事当成一件很大的忧心事,到他临死的时候,聚集了他的族人,说:“如果越椒一旦执政,就快点走吧,不要遭到祸难。”同时哭着说:“鬼尚且要求吃东西,若敖氏的鬼不是要挨饿了吗!”等到令尹子文死去,鬬般担任令尹,子越担任司马。..贾出任工正,诬陷子扬并且杀了他,子越就做了令尹,他自己做了司马。子越又讨厌他,就带领了若敖氏的族人把伯嬴囚禁在轑阳并且杀死了他,于是就住在烝野地方,准备进攻楚庄王。楚庄王用三代国王的子孙作为人质,子越不接受。楚庄王在漳澨用兵。秋季,七月初九日,楚庄王和若敖氏在皋浒作战。子越椒用箭射楚庄王,力量强而箭镞锋利,箭飞过车辕,穿过鼓架,射在铜钲上。又射一箭,飞过车辕,透过车盖。士兵害怕,开始退却。楚庄王派人在军队里到处喊着说:“我们的先君文王攻克息国,得到三枝箭,子越椒偷去两枝,已经全用完了。”于是楚王下令击鼓进军,就消灭了若敖氏。 +当初,若敖在..国娶妻,生了鬬伯比。若敖死后,跟着他的母亲养在..国,和..子的女儿私通,生了子文。..夫人让人把子文丢在云梦泽里,有老虎给他喂奶,..子打猎,看到这场面,害怕而回来。夫人把女儿私生子的情况告诉..子,..子就让人收养了子文。楚国人把奶叫做“穀”,把老虎叫做“於菟”,所以就把这个孩子叫做鬬穀於菟。..子把他的女儿嫁给鬬伯比做妻子。鬬穀於菟就是令尹子文。 +子文的孙子箴尹克黄出使齐国,回来时到达宋国,听到叛乱消息。有人说:“不能回去了。”箴尹说“丢掉国君的命令,还有谁来接受我?国君,就是上天,难道可以逃避上天吗?”就回到楚国复命,并且自动到法官那里请求囚禁。楚庄王想起子文治理楚国的功绩,说:“子文如果没有后代,如何劝人为善?”就让克黄恢复原来的官职,把他的名字改为“生”。 +子文的孙子箴尹克黄出使齐国,回来时到达宋国,听到叛乱消息。有人说:“不能回去了。”箴尹说“丢掉国君的命令,还有谁来接受我?国君,就是上天,难道可以逃避上天吗?”就回到楚国复命,并且自动到法官那里请求囚禁。楚庄王想起子文治理楚国的功绩,说:“子文如果没有后代,如何劝人为善?”就让克黄恢复原来的官职,把他的名字改为“生”。 + +宣公五年 +【经】五年春,公如齐。夏,公至自齐。秋九月,齐高固来逆叔姬。叔孙得臣卒。冬,齐高固及子叔姬来。楚人伐郑。 +【传】五年春,公如齐,高固使齐侯止公,请叔姬焉。 +夏,公至自齐,书,过也。 +秋九月,齐高固来逆女,自为也。故书曰:“逆叔姬。”即自逆也。 +冬,来,反马也。 +楚子伐郑,陈及楚平。晋荀林父救郑,伐陈。 +译文 +楚国人献给郑灵公一只大甲鱼。公子宋和子的妻子。 +夏季,宣公从齐国回来,《春秋》记载这件事,这是因为他有过失。 +秋季,九月,齐国的高固前来迎接叔姬,这是为了自己。所以《春秋》记载说“逆叔姬”,这是由于卿亲自迎娶的缘故。 +冬季,高固和子叔姬来鲁国,这是为了履行“返马”这一古代婚姻礼节。 +楚庄王进攻郑国。陈国和楚国讲和。晋国的荀林父救援郑国,进攻陈国。 + + +宣公六年 +【经】六年春,晋赵盾、卫孙免侵陈。夏四月。秋八月,螽。冬十月。 +【传】六年春,晋、卫侵陈,陈即楚故也。 +夏,定王使子服求后于齐。 +秋,赤狄伐晋。围怀,及邢丘。晋侯欲伐之。中行桓子曰:“使疾其民,以盈其贯,将可殪也。《周书》曰:‘殪戎殷。’此类之谓也。” +冬,召桓公逆王后于齐。 +楚人伐郑,取成而还。 +郑公子曼满与王子伯廖语,欲为卿。伯廖告人曰:“无德而贪,其在《周易》《丰》三之《离》三,弗过之矣。”间一岁,郑人杀之。 +译文 +六年春季,晋国、卫国入侵陈国,这是由于陈国偏向楚国的缘故。 +夏季,周定王派遣子服到齐国求娶齐女为王后。 +秋季,赤狄进攻晋国,包围了怀地和邢丘。晋成公打算反攻。中行桓子说:“让他危害他自己的百姓,以使他恶贯满盈,到时候大概就可以歼灭了。《周书》说:‘歼灭大国殷朝’,说的就是这一类的事情。” +冬季,周卿士召桓公到齐国迎接王后。 +楚军攻打郑国,讲和以后就回去了。 +郑国的公子曼满对王子伯廖说,他想要做卿。伯廖告诉别人说:“没有德行而又贪婪,他是应在《周易》《丰》卦变成《离》卦这样的卦象上,不会超过三年,必然灭亡。”隔了一年,郑国人杀死了公子曼满。 + +宣公七年 +【经】七年春,卫侯使孙良夫来盟。夏,公会齐侯伐莱。秋,公至自伐莱。大旱。冬,公会晋侯、宋公、卫侯、郑伯、曹伯于黑壤。 +【传】七年春,卫孙桓子来盟,始通,且谋会晋也。 +夏,公会齐侯伐莱,不与谋也。凡师出,与谋曰及,不与某曰会。 +赤狄侵晋,取向阴之禾。 +郑及晋平,公子宋之谋也,故相郑伯以会。冬,盟于黑壤,王叔桓公临之,以谋不睦。 +晋侯之立也,公不朝焉,又不使大夫聘,晋人止公于会,盟于黄父。公不与盟,以赂免。故黑壤之盟不书,讳之也。 +译文 +七年春季,卫国的孙桓子来鲁国缔结盟约,两国开始修好,同时商量和晋国会见。 +夏季,鲁宣公会合齐惠公联兵进攻莱国,这是由于事先并没有让我国参与策划。凡是出兵,事先参与策划叫做“及”,没有参与策划叫做“会”。 +赤狄入侵晋国,割取了向阴的谷子。 +郑国和晋国讲和,这是出于公子宋的谋划,所以公子宋作为郑君的赞助行礼者来参加盟会。冬季,在黑壤结盟。周卿士王叔桓公到会监临,以促成不和睦的诸侯重建邦交。 +晋成公即位的时候,鲁宣公没有去朝见,又不派大夫访问,晋国人因此在会上拘留了他。在黄父结盟,宣公没有参加,由于向晋国送了一些财物才得以被释放回国。所以《春秋》不记载黑壤的结盟,这是由于隐讳国君受辱。 + + +宣公八年 +【经】八年春,公至自会。夏六月,公子遂如齐,至黄乃复。辛巳,有事于大庙,仲遂卒于垂。壬午,犹绎。万入,去籥。戊子,夫人赢氏薨。晋师、白狄伐秦。楚人灭舒蓼。秋七月甲子,日有食之,既。冬十月己丑,葬我小君敬赢。雨,不克葬。庚寅,日中而克葬。城平阳。楚师伐陈。 +【传】八年春,白狄及晋平。夏,会晋伐秦。晋人获秦谍,杀诸绛市,六日而苏。 +有事于大庙,襄仲卒而绎,非礼也。 +楚为众舒叛,故伐舒蓼,灭之。楚子疆之,及滑汭。盟吴、越而还。 +晋胥克有蛊疾,郤缺为政。秋,废胥克。使赵朔佐下军。 +冬,葬敬赢。旱,无麻,始用葛茀。雨,不克葬,礼也。礼,卜葬,先远日,辟不怀也。 +城平阳,书,时也。 +陈及晋平。楚师伐陈,取成而还。 +译文 +八年春季,白狄和晋国讲和。夏季,会合晋国进攻秦国。晋国人抓住秦国的一个间谍,把他杀死在绛城的街市上,过了六天又复活了。 +在太庙举行祭祀,襄仲死后接连两天举行祭祀,这是不合于礼的。 +楚国因为舒姓诸侯背叛,所以进攻舒、蓼,灭亡了舒、蓼两国。楚庄王给它们划定疆界,到达滑水的转折处,同时和吴国、越国结盟而回去。 +晋国胥克得了食物中毒的病,郤缺主持国政。秋季,废了胥克,任命赵朔做下军的副帅。 +冬季,安葬敬嬴。由于旱灾,没有麻,开始用葛做牵引棺材的绳子。由于下雨,不能如期下葬,这是符合礼的。按礼的一般的规定,占卜安葬的日期,先占卜较远的日期,以避免别人认为对死者不加怀念。 +鲁国在平阳筑城,《春秋》记载这件事,是因为合于时令。 +陈国和晋国讲和。楚国的军队进攻陈国,讲和以后回国。 + +宣公九年 +【经】九年春王正月,公如齐。公至自齐。夏,仲孙蔑如京师。齐侯伐莱。秋,取根牟。八月,滕子卒。九月,晋侯、宋公、卫侯、郑伯、曹伯会于扈。晋荀林父帅师伐陈。辛酉,晋侯黑臀卒于扈。冬十月癸酉,卫侯郑卒。宋人围滕。楚子伐郑。晋郤缺帅师救郑。陈杀其大夫泄冶。 +【传】九年春,王使来徵聘。夏,孟献于聘于周,王以为有礼,厚贿之。 +秋,取根牟,言易也。 +滕昭公卒。 +会于扈,讨不睦也。陈侯不会。晋荀林父以诸侯之师伐陈。晋侯卒于扈,乃还。 +冬,宋人围滕,因其丧也。 +陈灵公与孔宁、仪行父通于夏姬,皆衷其示日服以戏于朝。泄冶谏曰:“公卿宣淫,民无效焉,且闻不令,君其纳之。”公曰:“吾能改矣。”公告二子,二子请杀之,公弗禁,遂杀泄冶。孔子曰:“《诗》云:‘民之多辟,无自立辟。’其泄冶之谓乎。” +楚子为厉之役故,伐郑。 +晋郤缺救郑,郑伯败楚师于柳棼。国人皆喜,唯子良忧曰:“是国之灾也,吾死无日矣。” +译文 +九年春季,周定王的使者来鲁国要求派人去聘问。夏季,孟献子去成周聘问。周定王认为有礼,赠给他丰厚的财礼。 +秋季,占领了根牟,《春秋》记载是说很容易。 +滕昭公死。 +晋成公、宋文公、卫成公、郑襄公、曹文公在扈地会见,这是由于准备攻打不听从晋国的国家。陈灵公没有参加会见,晋国的荀林父率领诸侯的军队进攻陈国。晋成公死在扈地,荀林父便率兵回国。 +冬季,宋军包围滕国,这是乘滕国有丧事。 +陈灵公和孔宁、仪行父与夏姬通奸,都把夏姬的汗衣贴身穿着,而且在朝廷上开玩笑。泄冶进谏说:“国君和卿宣扬淫乱,百姓就无所效法,而且名声不好。君王还是把那件汗衫收藏起来吧!”陈灵公说:“我能够改过了。”陈灵公把泄冶的话告诉孔宁、仪行父两个人,这两个人请求杀死泄冶,陈灵公不加禁止,于是就杀了泄冶。孔子说:“《诗》说:‘百姓多行邪恶,就不要再去自立法度。’这说的就是泄冶吧!” +楚庄王为了厉地战役的缘故,进攻郑国。 +晋国的郤缺率兵去救援郑国,郑襄公在柳棼打败了楚军。国内的人们都很欢喜,只有子良担心说:“这是国家的灾难,我离死期不远了。” + +宣公十年 +【经】十年春,公如齐。公至自齐。齐人归我济西田。夏四月丙辰,日有食之。己巳,齐侯元卒。齐崔氏出奔卫。公如齐。五月,公至自齐。癸巳,陈夏征舒弑其君平国。六月,宋师伐滕。公孙归父如齐,葬齐惠公。晋人、宋人、卫人、曹人伐郑。秋,天王使王季子来聘。公孙归父帅师伐邾,取绎。大水。季孙行父如齐。冬,公孙归父如齐。齐侯使国佐来聘。饥。楚子伐郑。 +【传】十年春,公如齐。齐侯以我服故,归济西之田。 +夏,齐惠公卒。崔杼有宠于惠公,高、国畏其逼也,公卒而逐之,奔卫。书曰“崔氏”,非其罪也,且告以族,不以名。凡诸侯之大夫违,告于诸侯曰:“某氏之守臣某,失守宗庙,敢告。”所有玉帛之使者,则告,不然,则否。 +公如齐奔丧。 +陈灵公与孔宁、仪行父饮酒于夏氏。公谓行父曰:“征舒似女。”对曰:“亦似君。”征舒病之。公出,自其厩射而杀之。二子奔楚。 +滕人恃晋而不事宋,六月,宋师伐滕。 +郑及楚平。诸侯之师伐郑,取成而还。 +秋,刘康公来报聘。 +师伐邾,取绎。 +季文子初聘于齐。 +冬,子家如齐,伐邾故也。 +国武子来报聘。 +楚子伐郑。晋士会救郑,逐楚师于颖北。诸侯之师戍郑。郑子家卒。郑人讨幽公之乱,斫子家之棺而逐其族。改葬幽公,谥之曰灵。 +译文 +十年春季,鲁宣公到了齐国。齐惠公因为我国顺服的缘故,把济水以西的土田归还给我国。 +夏季,齐惠公去世。崔杼受到齐惠公的宠信,高、国两族惧怕他威逼,惠公死后就赶走了崔杼,崔杼逃亡到卫国。《春秋》记载说“崔氏”,是说这不是他的罪过,而且把这件事通告诸侯时,也称族而不称名。凡是诸侯的大夫离开本国,通告诸侯说:“某氏的守臣某,不能守宗庙了,谨此通告。”凡是有友好往来的国家就发给通告,不是,就不发通告。 +宣公奔赴齐国参加丧礼。 +陈灵公和孔宁、仪行父在夏征舒家喝酒。灵公对仪行父说:“征舒长得像你。”仪行父回答说:“也像君王。”夏征舒对此感到愤恨。灵公出去,夏征舒从马房里用箭射死灵公。孔宁、仪行父逃亡到楚国。 +滕国人依靠晋国而不事奉宋国,六月,宋国的军队进攻滕国。 +郑国和楚国讲和,诸侯的军队进攻郑国,讲和以后回国。 +秋季,刘康公前来回聘。 +鲁国出兵进攻邾国,占领了绎地。 +季文子第一次到齐国聘问。 +冬季,子家到了齐国,这是为了向齐国解释鲁国进攻了邾国的缘故。 +国武子前来回聘。 +楚庄王进攻郑国。晋国的士会去救郑国,在颍水北面赶走了楚军。诸侯的军队在郑国留守。郑国的子家死。郑国人为了讨伐杀害幽公的那次动乱,打开了子家的棺材,并赶走了他的族人。改葬幽公,把他的谥号改为“灵”。 + +宣公十一年 +【经】十有一年春王正月。夏,楚子、陈侯、郑伯盟于辰陵。公孙归父会齐人伐莒。秋,晋侯会狄于欑函。冬十月,楚人杀陈夏征舒。丁亥,楚子入陈。纳公孙宁、仪行父于陈。 +【传】十一年春,楚子伐郑,及栎。子良曰:“晋、楚不务德而兵争,与其来者可也。晋、楚无信,我焉得有信。”乃从楚。夏,楚盟于辰陵,陈、郑服也。 +楚左尹子重侵宋,王待诸郔。令尹蒍艾猎城沂,使封人虑事,以授司徒。量功命日,分财用,平板干,称畚筑,程土物,议远迩,略基趾,具□粮,度有司,事三旬而成,不愆于素。 +晋郤成子求成于众狄,众狄疾赤狄之役,遂服于晋。秋,会于欑函,众狄服也。是行也。诸大夫欲召狄。郤成子曰:“吾闻之,非德,莫如勤,非勤,何以求人?能勤有继,其从之也。《诗》曰:‘文王既勤止。’文王犹勤,况寡德乎?” +冬,楚子为陈夏氏乱故,伐陈。谓陈人无动,将讨于少西氏。遂入陈,杀夏征舒,轘诸栗门,因县陈。陈侯在晋。 +申叔时使于齐,反,覆命而退。王使让之曰:“夏征舒为不道,弑其君,寡人以诸侯讨而戮之,诸侯、县公皆庆寡人,女独不庆寡人,何故”对曰:“犹可辞乎?”王曰:“可哉”曰:夏征舒弑其君,其罪大矣,讨而戮之,君之义也。抑人亦有言曰:‘牵牛以蹊人之田,而夺之牛。’牵牛以蹊者,信有罪矣;而夺之牛,罚已重矣。诸侯之从也,曰讨有罪也。今县陈,贪其富也。以讨召诸侯,而以贪归之,无乃不可乎?王曰:“善哉!”吾未之闻也。反之,可乎?对曰:“可哉!吾侪小人所谓取诸其怀而与之也。”乃复封陈,乡取一人焉以归,谓之夏州。故书曰:“楚子入陈,纳公孙宁、仪行父于陈。”书有礼也。 +厉之役,郑伯逃归,自是楚未得志焉。郑既受盟于辰陵,又徼事于晋。 +译文 +十一年春季,楚庄王发兵进攻郑国,到达栎地。子良说:“晋国、楚国不讲德行,而用武力争夺,谁来我们就接近他。晋国、楚国没有信用,我们哪里能够有信用?”于是就跟从楚国。夏季,楚国在辰陵会盟,这是由于陈、郑两国都顺服了。 +楚国的左尹子重袭击宋国,楚庄王住在郔地等待。令尹蒍艾猎在沂地筑城,派遣主持人考虑工程计划,将情况报告给司徒。计量工程,规定日期,分配材料和用具,放平夹板和支柱,规定土方和器材劳力的多少,研究取材和工作的远近,巡视城基各处,准备粮食,审查监工的人选,工程三十天就完成,没有超过原定的计划。 +晋国的郤成子向狄人各部族谋求友好。狄人各部族憎恨赤狄对他们的役使,于是顺服晋国。秋季,在欑函会见,狄人各部族都来顺服。在这次欑函之行以前,大夫们要召集狄人前来。郤成子说:“我听说,没有德行,就只能勤劳;没有勤劳,如何能要求别人服从我?能够勤劳,就有成果,还是到狄人那里去吧。《诗》说:‘文王已经做到勤劳。’文王尚且勤劳,何况缺少德行的人呢?” +冬季,楚庄王由于陈国夏氏作乱的缘故,进攻陈国。对陈国人说:“不要惊俱,我将要讨伐少西氏。”就进入陈国,杀了夏征舒,把他五马分尸在栗门。因而就把陈国设置为县。这时陈成公正在晋国。 +申叔时在齐国出使,回国,向楚庄王复了命以后就退下去。楚庄王派人责备他说:“夏征舒无道,杀死他的国君。我带领诸侯讨伐而杀了他,诸侯、县公都庆贺我,你独独不庆贺我,什么缘故?”申叔时回答说:“还可以申述理由吗?”楚庄王说:“可以呀!”申叔时说:“夏征舒杀死他的国君,他的罪恶是是很大了;讨伐而杀了他,这是君王所应当做的事。不过人们也有话说:‘牵牛践踏别人的田地,就把他的牛夺过来。’牵牛践踏田地的人,肯定是有过错的了;但夺走他的牛,惩罚就太重了。诸侯跟从君王,说是讨伐有罪的人。现在把陈国设置为县,这就是贪图一国的富有。用伐罪号召诸侯,而以贪婪来告终,恐怕不可以吧?”楚庄王说:“好啊!我没有听说过这些话。归还陈国的土地,可以吗?”申叔时回答说:“这就是我们这一班小人所说的‘从怀里拿出来给他’呀。”楚庄王就重新封立陈国,从每个乡带一个人回楚国,集中住在一地,称为夏州。所以《春秋》记载说“楚子入陈,纳公孙宁、仪行父于陈”,这是表扬这一举动合于礼。 +厉地这一战役,郑襄公逃走回国。从这时候以来,楚国就没有得志。郑国既然在辰陵接受盟约,又要求事奉晋国。 + +宣公十二年 +【经】十有二年春,葬陈灵公。楚子围郑。夏六月乙卯,晋荀林父帅师及楚子战于邲,晋师败绩。秋七月。冬十有二月戊寅,楚子灭萧。晋人、宋人、卫人、曹人同盟于清丘。宋师伐陈。卫人救陈。 +【传】十二年春,楚子围郑。旬有七日,郑人卜行成,不吉。卜临于大宫,且巷出车,吉。国人大临,守陴者皆哭。楚子退师,郑人修城,进复围之,三月克之。入自皇门,至于逵路。郑伯肉袒牵羊以逆,曰:“孤不天,不能事君,使君怀怒以及敝邑,孤之罪也。敢不唯命是听。其俘诸江南以实海滨,亦唯命。其翦以赐诸侯,使臣妾之,亦唯命。若惠顾前好,徼福于厉、宣、桓、武,不泯其社稷,使改事君,夷于九县,君之惠也,孤之愿之,非所敢望也。敢布腹心,君实图之。”左右曰:“不可许也,得国无赦。”王曰:“其君能下人,必能信用其民矣,庸可几乎?”退三十里而许之平。潘□入盟,子良出质。 +夏六月,晋师救郑。荀林父将中军,先縠佐之。士会将上军,郤克佐之。赵朔将下军,栾书佐之。赵括、赵婴齐为中军大夫。巩朔、韩穿为上军大夫。荀首、赵同为下军大夫。韩厥为司马。及河,闻郑既及楚平,桓子欲还,曰:“无及于郑而剿民,焉用之?楚归而动,不后。”随武子曰:“善。会闻用师,观衅而动。德刑政事典礼不易,不可敌也,不为是征。楚军讨郑,怒其贰而哀其卑,叛而伐之,服而舍之,德刑成矣。伐叛,刑也;柔服,德也。二者立矣。昔岁入陈,今兹入郑,民不罢劳,君无怨讟,政有经矣。荆尸而举,商农工贾不败其业,而卒乘辑睦,事不奸矣。蒍敖为宰,择楚国之令典,军行,右辕,左追蓐,前茅虑无,中权,后劲,百官象物而动,军政不戒而备,能用典矣。其君之举也,内娃选于亲,外姓选于旧;举不失德,赏不失劳;老有加惠,旅有施舍;君子小人,物有服章,贵有常尊,贱有等威;礼不逆矣。德立,刑行,政成,事时,典从,礼顺,若之何敌之?见可而进,知难而退,军之善政也。兼弱攻昧,武之善经也。子姑整军而经武乎,犹有弱而昧者,何必楚?仲虺有言曰:‘取乱侮亡。’兼弱也。《汋》曰:‘于铄王师,遵养时晦。’耆昧也。《武》曰:‘无竞惟烈。’抚弱耆昧以务烈所,可也。”彘子曰:“不可。晋所以霸,师武臣力也。今失诸侯,不可谓力。有敌而不从,不可谓武。由我失霸,不如死。且成师以出,闻敌强而退,非夫也。命为军师,而卒以非夫,唯群子能,我弗为也。”以中军佐济。 +知庄子曰:“此师殆哉。《周易》有之,在《师》三之《临》三,曰:‘师出以律,否臧凶。’执事顺成为臧,逆为否,众散为弱,川壅为泽,有律以如己也,故曰律。否臧,且律竭也。盈而以竭,夭且不整,所以凶也。不行谓之《临》,有帅而不从,临孰甚焉!此之谓矣。果遇,必败,彘子尸之。虽免而归,必有大咎。”韩献子谓桓子曰:“彘子以偏师陷,子罪大矣。子为元师,师不用命,谁之罪也?失属亡师,为罪已重,不如进也。事之不捷,恶有所分,与其专罪,六人同之,不犹愈乎?”师遂济。 +楚子北师次于郔,沈尹将中军,子重将左,子反将右,将饮马于河而归。闻晋师既济,王欲还,嬖人伍参欲战。令尹孙叔敖弗欲,曰:“昔岁入陈,今兹入郑,不无事矣。战而不捷,参之肉其足食乎?”参曰:“若事之捷,孙叔为无谋矣。不捷,参之肉将在晋军,可得食乎?”令尹南辕反旆,伍参言于王曰:“晋之从政者新,未能行令。其佐先縠刚愎不仁,未肯用命。其三帅者专行不获,听而无上,众谁适从?此行也,晋师必败。且君而逃臣,若社稷何?”王病之,告令尹,改乘辕而北之,次于管以待之。 +晋师在敖、鄗之间。郑皇戌使如晋师,曰:“郑之从楚,社稷之故也,未有贰心。楚师骤胜而骄,其师老矣,而不设备,子击之,郑师为承,楚师必败。”彘子曰:“败楚服郑,于此在矣,必许之。”栾武子曰:“楚自克庸以来,其君无日不讨国人而训之于民生之不易,祸至之无日,戒惧之不可以怠。在军,无日不讨军实而申儆之于胜之不可保,纣之百克,而卒无后。训以若敖、蚡冒,筚路蓝缕,以启山林。箴之曰:‘民生在勤,勤则不匮。’不可谓骄。先大夫子犯有言曰:‘师直为壮,曲为老。’我则不德,而徼怨于楚,我曲楚直,不可谓老。其君之戎,分为二广,广有一卒,卒偏之两。右广初驾,数及日中;左则受之,以至于昏。内官序当其夜,以待不虞,不可谓无备。子良,郑之良也。师叔,楚之崇也。师叔入盟,子良在楚,楚、郑亲矣。来劝我战,我克则来,不克遂往,以我卜也,郑不可从。”赵括、赵同曰:“率师以来,唯敌是求。克敌得属,又何矣?必从彘子。”知季曰:“原、屏,咎之徒也。”赵庄子曰:“栾伯善哉,实其言,必长晋国。” +楚少宰如晋师,曰:“寡君少遭闵凶,不能文。闻二先君之出入此行也,将郑是训定,岂敢求罪于晋。二三子无淹久。”随季对曰:“昔平王命我先君文侯曰:‘与郑夹辅周室,毋废王命。’今郑不率,寡君使群臣问诸郑,岂敢辱候人?敢拜君命之辱。”彘子以为谄,使赵括从而更之,曰:“行人失辞。寡君使群臣迁大国之迹于郑,曰:‘无辟敌。’群臣无所逃命。” +楚子又使求成于晋,晋人许之,盟有日矣。楚许伯御乐伯,摄叔为右,以致晋师,许伯曰:“吾闻致师者,御靡旌摩垒而还。”乐伯曰:“吾闻致师者,左射以菆,代御执辔,御下两马,掉鞅而还。”摄叔曰:“吾闻致师者,右入垒,折馘,执俘而还。”皆行其所闻而复。晋人逐之,左右角之。乐伯左射马而右射人,角不能进,矢一而已。麋兴于前,射麋丽龟。晋鲍癸当其后,使摄叔奉麋献焉,曰:“以岁之非时,献禽之未至,敢膳诸从者。”鲍癸止之,曰:“其左善射,其右有辞,君子也。”既免。 +晋魏錡求公族未得,而怒,欲败晋师。请致师,弗许。请使,许之。遂往,请战而还。楚潘党逐之,及荧泽,见六麋,射一麋以顾献曰:“子有军事,兽人无乃不给于鲜,敢献于从者。”叔党命去之。赵旃求卿未得,且怒于失楚之致师者。请挑战,弗许。请召盟。许之。与魏錡皆命而往。郤献子曰:“二憾往矣,弗备必败。”彘子曰:“郑人劝战,弗敢从也。楚人求成,弗能好也。师无成命,多备何为。”士季曰:“备之善。若二子怒楚,楚人乘我,丧师无日矣。不如备之。楚之无恶,除备而盟,何损于好?若以恶来,有备不败。且虽诸侯相见,军卫不彻,警也。”彘子不可。 +士季使巩朔、韩穿帅七覆于敖前,故上军不败。赵婴齐使其徒先具舟于河,故败而先济。 +潘党既逐魏錡,赵旃夜至于楚军,席于军门之外,使其徒入之。楚子为乘广三十乘,分为左右。右广鸡鸣而驾,日中而说。左则受之,日入而说。许偃御右广,养由基为右。彭名御左广,屈荡为右。乙卯,王乘左广以逐赵旃。赵旃弃车而走林,屈荡搏之,得其甲裳。晋人惧二子之怒楚师也,使軘车逆之。潘党望其尘,使聘而告曰:“晋师至矣。”楚人亦惧王之入晋军也,遂出陈。孙叔曰:“进之。宁我薄人,无人薄我。《诗》云:‘元戎十乘,以先启行。’先人也。《军志》曰:‘先人有夺人之心’。薄之也。”遂疾进师,车驰卒奔,乘晋军。桓子不知所为,鼓于军中曰:“先济者有赏。”中军、下军争舟,舟中之指可掬也。 +晋师右移,上军未动。工尹齐将右拒卒以逐下军。楚子使唐狡与蔡鸠居告唐惠侯曰:“不谷不德而贪,以遇大敌,不谷之罪也。然楚不克,君之羞也,敢藉君灵以济楚师。”使潘党率游阙四十乘,从唐侯以为左拒,以从上军。驹伯曰:“待诸乎?”随季曰:“楚师方壮,若萃于我,吾师必尽,不如收而去之。分谤生民,不亦可乎?”殿其卒而退,不败。 +王见右广,将从之乘。屈荡尸之,曰:“君以此始,亦必以终。”自是楚之乘广先左。 +晋人或以广队不能进,楚人惎之脱扃,少进,马还,又惎之拔旆投衡,乃出。顾曰:“吾不如大国之数奔也。” +赵旃以其良马二,济其兄与叔父,以他马反,遇敌不能去,弃车而走林。逢大夫与其二子乘,谓其二子无顾。顾曰:“赵叟在后。”怒之,使下,指木曰:“尸女于是。”授赵旃绥,以免。明日以表尸之,皆重获在木下。 +楚熊负羁囚知荦。知庄子以其族反之,厨武子御,下军之士多从之。每射,抽矢,菆,纳诸厨子之房。厨子怒曰:“非子之求而蒲之爱,董泽之蒲,可胜既乎?”知季曰:“不以人子,吾子其可得乎?吾不可以苟射故也。”射连尹襄老,获之,遂载其尸。射公子谷臣,囚之。以二者还。 +及昏,楚师军于邲,晋之馀师不能军,宵济,亦终夜有声。 +丙辰,楚重至于邲,遂次于衡雍。潘党曰:“君盍筑武军,而收晋尸以为京观。臣闻克敌必示子孙,以无忘武功。”楚子曰:“非尔所知也。夫文,止戈为武。武王克商。作《颂》曰:‘载戢干戈,载櫜弓矢。我求懿德,肆于时夏,允王保之。’又作《武》,其卒章曰‘耆定尔功’。其三曰:‘铺时绎思,我徂求定。’其六曰:‘绥万邦,屡丰年。’夫武,禁暴、戢兵、保大、定功、安民、和众、丰财者也。故使子孙无忘其章。今我使二国暴骨,暴矣;观兵以威诸侯,兵不戢矣。暴而不戢,安能保大?犹有晋在,焉得定功?所违民欲犹多,民何安焉?无德而强争诸侯,何以和众?利人之几,而安人之乱,以为己荣,何以丰财?武有七德,我无一焉,何以示子孙?其为先君宫,告成事而已。武非吾功也。古者明王伐不敬,取其鲸鲵而封之,以为大戮,于是乎有京观,以惩淫慝。今罪无所,而民皆尽忠以死君命,又可以为京观乎?”祀于河,作先君宫,告成事而还。 +是役也,郑石制实入楚师,将以分郑而立公子鱼臣。辛未,郑杀仆叔子服。君子曰:“史佚所谓毋怙乱者,谓是类也。《诗》曰:‘乱离瘼矣,爰其适归?’归于怙乱者也夫。” +郑伯、许男如楚。 +秋,晋师归,桓子请死,晋侯欲许之。士贞子谏曰:“不可。城濮之役,晋师三日谷,文公犹有忧色。左右曰:‘有喜而忧,如有忧而喜乎?’公曰:‘得臣犹在,忧未歇也。困兽犹斗,况国相乎!’及楚杀子玉,公喜而后可知也,曰:‘莫馀毒也已。’是晋再克而楚再败也。楚是以再世不竞。今天或者大警晋也,而又杀林父以重楚胜,其无乃久不竞乎?林父之事君也,进思尽忠,退思补过,社稷之卫也,若之何杀之?夫其败也,如日月之食焉,何损于明?”晋侯使复其位。 +冬,楚子伐萧,宋华椒以蔡人救萧。萧人囚熊相宜僚及公子丙。王曰:“勿杀,吾退。”萧人杀之。王怒,遂围萧。萧溃。申公巫臣曰:“师人多寒。”王巡三军,拊而勉之。三军之士,皆如挟纩。遂傅于萧。还无社与司马卯言,号申叔展。叔展曰:“有麦曲乎?”曰:“无”。“有山鞠穷乎?”曰:“无”。“河鱼腹疾奈何?”曰:“目于眢井而拯之。”“若为茅絰,哭井则己。”明日萧溃,申叔视其井,则茅絰存焉,号而出之。 +晋原縠、宋华椒、卫孔达、曹人同盟于清丘。曰:“恤病讨贰。”于是卿不书,不实其言也。宋为盟故,伐陈。卫人救之。孔达曰:“先君有约言焉,若大国讨,我则死之。” +译文 +十二年春季,楚庄王包围郑国十七天。郑国人占卜以求和,不吉利;为在太庙号哭和出车于街巷去占卜,吉利。城里的人们在太庙大哭,守城的将士在城上大哭。楚庄王退兵。郑国人修筑城墙,楚国又进军,再次包围郑国,经三个月,攻克了郑国。楚军从皇门进入,到达京城的大路上。郑襄公脱去衣服,牵着羊迎接楚庄王,说:“我不能承奉天意,不能事奉君王,使君王带着怒气来到敝邑,这是我的罪过,岂敢不唯命是听?要把我俘虏到江南,放到海边,也听君王吩咐;要灭亡郑国,把郑地赐给诸侯,让郑国人作为奴隶,也听君王吩咐。如果承君王顾念从前的友好,向周厉王、宣王、郑桓公、武公求福,而不灭绝我国,让我国重新事奉君王,等同于楚国的诸县,这是君王的恩惠,我的心愿,但又不是我所敢于指望的了。谨坦露心里的话,请君王考虑。”左右随从说:“不能允许他,得到了国家没有赦免的。”楚庄王说:“他的国君能够屈居他人之下,必然能够取信和使用他的百姓,恐怕还是很有希望的吧!”楚军退兵三十里而允许郑国讲和。潘尪入郑国结盟,子良到楚国作为人质。 +夏季,六月,晋国的军队去救郑国。荀林父率领中军,先縠为辅佐;士会率领上军,郤作辅佐;赵朔率领下军,栾书作为辅佐。赵括、赵婴齐担任中军大夫,巩朔、韩穿担任上军大夫,荀首、赵同担任下军大夫。韩厥担任司马。到达黄河,听到郑国已经和楚国讲和,荀林父想要回去,说:“没有赶到郑国,又劳动百姓,出兵有什么用?等楚军回去以后我军再出兵进攻郑国,还不算晚。”士会说:“好。会听说用兵之道,观察敌人的间隙而后行动,德行、刑罚、政令、事务、典则、礼仪合乎常道,就是不可抵挡的,不能进攻这样的国家。楚国的军队讨伐郑国,讨厌郑国有二心,又可怜郑国的卑下,郑国背叛就讨伐他,郑国顺服就赦免他,德行、刑罚都完成了。讨伐背叛,这是刑罚;安抚顺服,这是德行,这二者树立起来了。往年进入陈国,如今进入郑国,百姓并不感到疲劳,国君没有受到怨恨,政令就合于常道了,楚军摆成荆尸之阵而后发兵,井井有条,商贩、农民、工匠、店主都不废时失业,步兵车兵关系和睦,事务就互不相犯了。蒍敖做令尹,选择实行楚国好的法典,军队出动,右军跟随主将的车辕,左军打草作为歇息的准备,前军以旄旌开路以防意外,中军斟酌谋划,后军以精兵押阵。各级军官根据象征自己的旌旗的指示而采取行动,军事政务不必等待命令而完备,这就是能够运用典则了。他们国君选拔人材,同姓中选择亲近的支系,异姓中选择世代旧臣,提拔不遗漏有德行的人,赏赐不遣漏有功劳的人。对老人有优待,对旅客有赐予。君子和小人,各有规定的服饰。对尊贵的有一定的礼节示以尊重,对低贱的有一定的等级示以威严。这就是礼节没有不顺的了。德行树立,刑罚施行,政事成就,事务合时,典则执行,礼节顺当,怎么能抵挡楚国?看到可能就前进,遇到困难就后退,这是治军的好办法。兼并衰弱进攻昏暗,这是用兵的好规则。您姑且整顿军队、筹划武备吧!还有弱小而昏暗的国家,为什么一定要进攻楚军?仲虺说:‘占取动乱之国,欺侮可以灭亡之国。’说的就是兼并衰弱。《诗经·周倾·酌》篇说:‘天子的军队多么神气,率领他们把昏昧的国家占取。’说的就是进攻昏昧。《武》篇说:‘武王的功业无比伟大强盛。’安抚衰弱进攻昏暗,以致力于功业所在,这就可以了。”先縠说:“不行。晋国所以能称霸诸侯,是由于军队勇敢、臣下得力。现在失去了诸侯,不能说是得力;有了敌人不去追逐,不能说是勇敢。由于我们而丢掉霸主的地位,不如去死。而且晋国整顿军队不出动,听到敌人强大就退却,这不是大丈夫。任命为军队的统帅,而做出了不是大丈夫所做的事,这只有你们能办到,我是不会干的。”说完,就带领中军副帅所属军队渡过黄河。 +荀首说:“先縠这些军队危险了。《周易》上有这样的卦象,从《师》卦变成《临》卦,爻辞说:‘出兵用法令治理,法令不严明,结果必凶。’执行顺当而成功就是‘臧’,反其道就是‘否’。大众离散是柔弱,流水壅塞就成为沼泽。有法制指挥三军如同指挥自己一样,所以叫做律。执行不顺当,法制治理就穷尽而无用。从充满到穷尽,阻塞而且不整齐,就是凶险的征兆了。不能流动叫做‘临’,有统帅而不服从,还有比这更严重的‘临’吗?说的就是先縠的这个行为了。果真和敌人相遇,一定失败,彘子将会是主要罪魁,即使免于战死而回国,一定有大的灾祸。”韩厥对荀林父说:“彘子率领一部分军队失陷,您的罪过大了。您作为最高统帅,军队不听命令,这是谁的罪过?失去属国,丢掉军队,构成的罪过已经太重,不如干脆进军。作战如果不能得胜,失败的罪过可以共分担,与其一个人承担罪责,六个人共同承担,不还好一点吗?”于是晋国的军队就渡过了黄河。 +楚庄王率军北上,军队驻扎在郔地。沈尹率领中军,子重率领左军,子反率领右军,准备在黄河饮马以后就回国。听到晋国军队已经渡过黄河,楚庄王想要回去,宠臣伍参想打仗,令尹孙叔敖不想干,说:“往年进入陈国,今年进入郑国,不是没有战争。打起来以后不能得胜,吃了伍参的肉难道就够了吗?”伍参说:“如果作战得胜,孙叔就是没有谋略。不能得胜,参的肉将会在晋军那里,哪里还能吃得上呢?”令尹回车向南,倒转旌旗。伍参对楚庄王说:“晋国参政的是新人,不能行使命令。他的副手先縠刚愎不仁,不肯听从命令。他们的三个统帅,想要专权行事而不能办到。想要听从命令而没有上级,大军听从谁的命令?这一次,晋军一定失败。而且国君逃避臣下,国君怎能蒙受这耻辱?”楚庄王听了不高兴,告诉令尹把战车改而向北,楚军驻扎在管地等待晋军。 +晋国军队驻在敖、鄗两山之间。郑国的皇戌出使到晋军中,说:“郑国跟从楚国,是为了保存国家的缘故,对晋国并没有二心。楚军屡次得胜而骄傲,他们在外面已经很久了,又不设防御。您攻击他们,郑国的军队作为后继,楚军一定失败。”先縠说:“打败楚军,降服郑国,就在此一举了,一定要答应皇戌的请求。”栾书说:“楚国自从战胜庸国以来,楚国的国君没有一天不用不列的方式治理国内的人们:教训百姓生计的不容易、祸患不知哪天就会到来、戒备警惕不能放松。在军队里,没有一天不用这样的方式管理军官士兵,告诫军队:胜利的不能永远保有、纣得到一百次胜利而终究没有好结果。用若敖、蚡冒乘柴车、穿破衣开辟山林的事迹来教训他们。告诫说:‘百姓的生计在于勤劳,勤劳就不会匮乏。’这就不能说他们骄傲。先大夫子犯说过:‘出兵作战,理直就气壮,理亏就气衰。’我们所做的事情不合于道德,又和楚国结怨,我们理曲,楚国理直,这就不能说他们气衰。他们国君的战车分为左右二广,每广有战车一卒三十辆,每卒又分左右两偏。右广先套车,计算时间等到中午,左广就接替它,一直到晚上。左右近臣按次序值夜,以防备发生意外,这就不能说没有防备。子良,是郑国的杰出人物;师叔,是楚国地位崇高的人物。师叔进入郑国结盟,子良作为人质住在楚国,楚国和郑国是亲近的。他们来劝我们作战,我们战胜就来归服,不胜就去依靠楚国,这是用我们作为占卜!郑国的话不能听从。”赵括、赵同说:“领兵而来,就是为了寻找敌人。战胜敌人,得到属国,又等待什么?一定要听从彘子的话。”荀首说:“赵同、赵括的主意,是一条自取祸乱之道。”赵庄子说:“栾伯好啊!实践他的话,一定能使晋国长久。” +楚国的少宰到晋军中去,说:“寡君年轻时就遭到忧患,不善于辞令。听到两位先君来往在这条道路上,就是打算教导和安定郑国,岂敢得罪晋国?您几位不要呆得太久了!”士会回答说:“以前周平王命令我们的先君晋文侯说:‘和郑国共同辅佐周王室,不要废弃天子的命令。’现在郑国不遵循天子的命令,寡君派遣下臣们质问郑国,岂敢劳动楚国官吏来迎送?恭敬地拜谢君王的命令。”先穀认为这是奉承楚国,派遣赵括跟上去更正说:“我们的临时代表的说法不恰当。寡君使臣下们把楚国从郑国迁出去,说:‘不要躲避敌人!’臣下们没有地方可以逃避命令。” +楚庄王又派使者向晋国求和,晋国人答应了,已约定了结盟的日期。楚国的许伯替乐伯驾御战车,摄叔作为车右,向晋军单车挑战。许伯说:“我听说单车挑战,驾车人疾驰而使旌旗斜倒,迫近敌营,然后回来。”乐伯说:“我听说单车挑战,车左用利箭射敌,代替御者执掌马缰,驾车人下车,整齐马匹,整理好马脖子上的皮带,然后回来。”摄叔说:“我听说单车挑战,车右进入敌营,杀死敌人割取左耳、抓住俘虏,然后回来。”这三个人都按照自己所听到的完成了任务,而后回来。晋国人追赶他们,左右两面夹攻。乐伯左边射马,右边射人,使晋军左右翼不能前进。箭只剩下一枝。有麋鹿出现在前面,乐伯射麋鹿正中背部。晋国的鲍癸正在后面,乐伯让摄叔拿着麋鹿献给他,说:“由于今年还不到时令,应当奉献的禽兽没有来,谨把它奉献给您的随从作为膳食。”鲍癸阻止部下,不再追赶,说:“他们的车左善于射箭,车右善于辞令,都是君子啊。”因此许伯等三人都免于被俘。 +晋国的魏锜请求做公族大夫,没有达到目的,因而发怒,想要使晋军失败。请求单车挑战,没有得到允许。请求出使,允许了。于是就去到楚军中,请战以后而回国。楚国的潘党追赶他,到达荧泽,魏锜看到六只麋鹿,就射死一只,回车献给潘党,说:“您有军事在身,打猎的人恐怕不能供给新鲜的野兽吧?谨以此奉献给您的随从人员。”潘党下令不再追赶魏锜。赵旃请求做卿没有达到目的,而且对于失掉楚国单车挑战的人很生气,就请求挑战,没有得到允许。请求召请楚国人前来结盟,允许了。赵旃和魏锜都接受命令而前去。郤克说:“这两个心怀不满的人去了,不加防备,必然失败。”先縠说:“郑国人劝我们作战,不敢听从;楚国人求和,又不能实行友好。带兵没有固定的策略,多加防备做什么?”士会说:“防备他们为好。如果这两位激怒了楚国,楚国人乘机掩袭,马上可以丧失军队。不如防备他们,楚国人没有恶意,撤除戒备而结盟,哪里会损害友好?如果带着恶意而来,有了防备,不会失败。而且即使是诸侯相见,军队的守备也不加撤除,这就是警惕。”先縠不同意。 +士会派遣巩朔、韩穿率领七队伏兵埋伏在敖山之前,所以上军不败。赵婴齐派遣他的部下先在黄河准备了船只,所以战败以后就渡过河去了。 +潘党已经赶走了魏锜,赵旃在夜里达到楚军驻地,铺开席子坐在军门的外面,派遣他的部下先进军门。楚庄王的战车一广三十辆,共分为左右两广。右广在早晨鸡叫的时候套车,太阳到了中天才卸车;左广就接替右广,太阳落山才卸车。许偃驾御右广的指挥车,养由基作为车右;彭名驾御左广的指挥车,屈荡作为车右。六月十四日,楚庄王乘坐左广的指挥车,以追赶赵旃。赵旃丢掉车子跑进树林里,屈荡和他搏斗,获得了他的铠甲和下衣。晋国人害怕这两个人激怒楚军,让驻守的兵车前来接他们。潘党远望飞起来的尘土,派战车奔驰报告说:“晋国的军队来了。”楚国人也害怕楚庄王陷入晋军中,就出兵迎战。孙叔敖说:“前进!宁可我们迫近敌人,不要让敌人迫近我们。《诗》说:‘大兵车十辆,冲在前面开道’,这是要抢在敌人的前面。《军志》说:‘抢在敌人前面,可以夺去敌人的斗志。’这是要主动迫近敌人。”于是就很快地进军,战车奔驰、士卒奔跑,围攻晋军。荀林父不知所措,在军中击鼓宣布说:“先过河的有赏。”中军、下军互相争夺船只,争先恐后,先上船的人用刀砍断后来者攀着船舷的手指,船中砍断的指头多得可以用手捧起来。 +晋军向右转移,上军没有动。工尹齐率领右方阵的士兵,以追逐晋国的下军。楚庄王派唐狡和蔡鸠居报告唐惠侯说:“我无德而贪功,而又遭遇强大的敌人,这是我的罪过。楚国如果不能得胜,这也是君王的羞耻。谨借重君王的福佑,以帮助楚军成功。”派遣潘党率领后备的战车四十辆,跟随唐侯作为左方阵,以迎战晋国的上军。驹伯说:“抵御他们吗?”士会说:“楚军的士气正旺盛,如果楚军集中兵力对付我们的上军,我们的军队必然被消灭,不如收兵离开。分担战败的指责,保全士兵的生命,不也是可以的吗?”就亲自作为上军的后殿而退兵,因此没有被打败。 +楚庄王见到右广,准备乘坐。屈荡阻止说:“君王乘坐左广开始作战,也一定要乘坐它结束战争。”从此楚国的乘广改以左广为先。 +晋国人有战车陷在坑里不能前进,楚国人教他们抽出车前横木,没走多远,马盘旋不能前进,楚国人又教他们拔掉大旗,扔掉车辕头上的横木,这样才逃了出去。晋军转过头来说:“我们可不像大国的人有多次逃跑的经验。” +赵旃用他的好马两匹帮助他的哥哥和叔父逃跑,而用其他的马驾车回来。碰上敌人不能逃脱,就丢弃车子跑到树林里。逢大夫和他两个儿子坐在车上,对他两个儿子说:“不要回头去望。”儿子回头去望说:“赵老头在后边。”逢大夫发怒,让他们下车,指着树木说:“在这里收你们的尸首。”逢大夫就把缰绳交给了赵旃,赵旃登上战车得以逃脱。第二天,按照标志前去收尸,在树下得到了两个叠压的尸首。 +楚国的熊负羁囚禁了知罃,荀首率领他的部属回来战斗,魏锜驾御战车,下军的士兵大多跟着回来。荀首每次发射,抽箭,如果是利箭,就放在魏锜的箭袋里。魏锜发怒说:“不去寻找儿子,反而爱惜蒲柳,董泽的蒲柳,难道可以用得完吗?”荀首说:“不得到别人的儿子,我的儿子难道可以得到吗?利箭我是不能随便射出去的。”荀首射中了连尹襄老,得到他的尸首,就用战车装上;射中公子谷臣,把他囚禁起来。荀首带了这两个人回去。 +到黄昏时,楚军驻扎在邲地,晋国剩余的士兵已经溃不成军,夜里渡河,喧吵了一整夜。 +六月十五日,楚军的辎重到达邲地,军队就驻扎在衡雍。潘党说:“君王何不建筑起军营显示武功,收集晋国人的尸首建立一个大坟堆?下臣听说战胜了敌人一定要有纪念物给子孙看,表示不忘记武功。”楚庄王说:这不是你所知道的。说到文字,止戈二字合起来是个武字。武王战胜商朝,作《周颂》说:“收拾干戈,包藏弓箭。我追求那美德,陈于这《夏》乐之中,成就王业而保有天下。”又作《武》篇,它的最后一章说:“得以巩固你的功业。”《周颂》的第三章说:“布陈先王的美德而加以发扬,我前去征讨只是为了求得安定。”它的第六章说:“安定万邦,常有丰年。”武功,是用来禁止强暴、消灭战争、保持强大、巩固功业、安定百姓、调和大众、丰富财物的,所以要让子孙不要忘记他的大功。现在我让两国士兵暴露尸骨,这是强暴了;显耀武力以使诸侯畏惧,战争不能消灭了;强暴而不消灭战争,哪里能够保持强大?还有晋国存在,如何能够巩固功业?所违背百姓的愿望还很多,百姓如何能够安定?没有德行而勉强和诸侯相争,用什么调和大众?乘别人之危作为自己的利益,趁人之乱作为自己的安定,如何能丰富财物?武功具有七种美德,我对晋国用兵却没有一项美德,用什么来昭示子孙后代?还是为楚国的先君修建宗庙,把成功的事祭告先君罢了。用武不是我追求的功业。古代圣明的君王征伐对上不恭敬的国家,抓住它的罪魁祸首杀掉埋葬,作为一次大杀戮,这样才有了京观以惩戒罪恶。现在并不能明确指出晋国的罪恶在哪里,士卒都尽忠为执行国君的命令而死,又难道能建造京观来惩戒吗?楚庄王说完,就在黄河边上祭祀了河神,修建了先君的神庙,报告战争胜利,然后回国。 +这次战役,是郑国的石制把楚国军队引进来的,企图分割郑国,并且立公子鱼臣为国君。七月二十九日,郑国人杀死了鱼臣和石制。君子说:“史佚所谓‘不要依仗动乱’,说的就是这一类人,《诗》说:‘动乱离散是那么厉害,有哪里可以归宿’?这是归罪于靠动乱来谋私利的人吧!” +郑襄公、许昭公去到楚国。 +秋季,晋国军队回国,荀林父自己请求处以死罪,晋景公打算答应他。士贞子劝谏说:“不行,城濮那一次战役,晋军三天吃着楚军留下的粮食,文公还面带忧色。左右的人说:‘有了喜事而忧愁,如果有了忧事反倒喜悦吗?’文公说:‘得臣还在,忧愁还不能算完结。被困的野兽还要争斗一下,何况是一国的宰相呢?’等到楚国杀了得臣,文公便喜形于色,说:‘没有人来同我作对了。’这是晋国的再次胜利,也是楚国的再次失败,楚国由此两世都不能强盛。现在上天或者是要大大地警戒晋国,但又杀了荀林父以增加楚国的胜利,这恐怕会使晋国好久还不能强盛的吧?荀林父的事奉国君,进,想着竭尽忠诚,退,想着弥补过错,是捍卫国家的人,怎么能杀他?他的失败,如同日蚀月蚀,怎么会损害日月的光明?”晋景公就命令荀林父官复原位。 +冬季,楚庄王攻打萧国。宋国华椒率领蔡军去救萧国。萧军囚禁了熊相宜僚和公子丙。楚庄王说:“不要杀,我退兵。”萧国人杀了他们。楚庄王发怒,就包围了萧国。萧国崩溃,申公巫臣说:“军队里的人大多很冷。”楚庄王巡视三军,安抚慰勉士兵们,三军的战士感到温暖,都好像披上了丝棉一样。军队就前进而逼近萧城。还无社告诉司马卯,把申叔展喊出来。申叔展说:“你有酒药吗?”还无社说:“没有。”“有川芎吗?”还无社说:“没有。”“得了风湿病怎么办?”还无社说:“注意看枯井就可以拯救我。”申叔展说:“你在井上放一条草绳子,有向井里哭的人就是我。”第二天,萧国崩溃。申叔展看到井上有草绳子在那里,就放声号哭,把还无社救出枯井。 +晋国的原縠、宋国的华椒、卫国的孔达、曹国人在清丘结盟,说:“周济有困难的国家,讨伐三心二意的国家。”对这次盟会,《春秋》没有记载卿的姓名,这是由于没有实行盟约。宋国为了盟约的缘故,进攻陈国。卫军救援陈国,孔达说:“先君有约定,如果大国进攻我们,我愿意为此去死。” + +宣公十三年 +【经】十有三年春,齐师伐莒。夏,楚子伐宋。秋,螽。冬,晋杀其大夫先縠。 +【传】十三年春,齐师伐莒,莒恃晋而不事齐故也。 +夏,楚子伐宋,以其救萧也。君子曰:“清丘之盟,唯宋可以免焉。” +秋,赤狄伐晋,及清,先縠召之也。 +冬,晋人讨邲之败,与清之师,归罪于先縠而杀之,尽灭其族。君子曰:“恶之来也,己则取之,其先縠之谓乎。” +清丘之盟,晋以卫之救陈也讨焉。使人弗去,曰:“罪无所归,将加而师。”孔达曰:“苟利社稷,请以我说。罪我之由。我则为政而亢大国之讨,将以谁任?我则死之。” +译文 +十三年春季,齐国军队进攻莒国,由于莒国依仗晋国而不奉事齐国的缘故。 +夏季,楚庄王进攻宋国,因为宋国曾救援萧国。君子说:“清丘的结盟,只有宋国可以免去被讥议。” +秋季,赤狄进攻晋国,到达清地,这是先縠把他们召来的。 +冬季,晋国人追究邲地失败和清地战争的责任,归罪于先穀而杀死了他,把他的族人也全部杀掉了。君子说“‘刑戮来到,那是自找’,先縠就是这样的吧?” +清丘的盟约,晋国由于卫国救援陈国,就加以责备。晋国使者不肯离去,说:“罪责如果无所归属,将要把战争加在你们头上。”孔达说:“如果有利于社稷,就请用我的死来作为解说吧,罪过由于我。我在执政,而面对大国的责备,这个罪责还能推给谁?我愿意为此而死。” + +宣公十四年 +【经】十有四年春,卫杀其大夫孔达。夏五月壬申,曹伯寿卒。晋侯伐郑。秋九月,楚子围宋。葬曹文公。冬,公孙归父会齐侯于谷。 +【传】十四年春,孔达缢而死。卫人以说于晋而免。遂告于诸侯曰:“寡君有不令之臣达,构我敝邑于大国,既伏其罪矣,敢告。”卫人以为成劳,复室其子,使复其位。 +夏,晋侯伐郑,为邲故也。告于诸侯,搜焉而还。中行桓子之谋也。曰:“示之以整,使谋而来。”郑人惧,使子张代子良于楚。郑伯如楚,谋晋故也。郑以子良为有礼,故召之。 +楚子使申舟聘于齐,曰:“无假道于宋。”亦使公子冯聘于晋,不假道于郑。申舟以孟诸之役恶宋,曰:“郑昭宋聋,晋使不害,我则必死。”王曰:“杀女,我伐之。”见犀而行。及宋,宋人止之,华元曰:“过我而不假道,鄙我也。鄙我,亡也。杀其使者必伐我,伐我亦亡也。亡一也。”乃杀之。楚子闻之,投袂而起,屦及于窒皇,剑及于寝门之外,车及于蒲胥之市。秋九月,楚子围宋。 +冬,公孙归父会齐侯于谷。见晏桓子,与之言鲁乐。桓子告高宣子曰:“子家其亡乎,怀于鲁矣。怀必贪,贪必谋人。谋人,人亦谋己。一国谋之,何以不亡?” +孟献子言于公曰:“臣闻小国之免于大国也,聘而献物,于是有庭实旅百。朝而献功,于是有容貌采章嘉淑,而有加货。谋其不免也。诛而荐贿,则无及也。今楚在宋,君其图之。”公说。 +译文 +十四年春季,卫国的孔达上吊死了,卫国人以此向晋国解说而免于被讨伐。于是就通告诸侯说:“寡君有一个不好的臣子孔达,在敝邑和大国之间进行挑拨,已经伏罪了,谨此通告。”卫国人因为孔达过去有不少劳绩并辅助成公,便为他的儿子娶妻,而且让他的儿子接任了父亲的官位。 +夏季,晋景公进攻郑国,这是为了邲地战役郑国帮助过楚国的缘故。通告诸侯,阅兵以后回国。这是中行桓子的计谋,他说:“给他们看到我军队伍严整,让他们自己谋划前来归服我们。”郑国害怕、派子张到楚国代替子良。郑襄公前去楚国,这是由于策划对付晋国的缘故。郑国认为子良合于礼,所以召他回国。 +楚庄王派遣申舟到齐国聘问,说:“不要向宋国请求借路。”同时还派公子冯到晋国聘问,也不许公子冯向郑国请求借路。申舟由于孟诸这一役得罪了宋国,说:“郑国明白、宋国糊涂,去晋国的使者没有危险,我就必然会死。”楚庄王说:“要是杀死了你,我就攻打宋国。”申舟把儿子申犀引见给楚庄王然后出使。到达宋国,宋国人不让他走。华元说:“经过我国而不请求借路,这是把我国作为楚国边境内的县城。把我们当作县城,这是视我为被灭亡之国。杀了楚国的使者,楚国必然会进攻我国,进攻我国也不过是被灭亡。反正一样是灭亡。”就杀死了申舟。楚庄王听到申舟被杀的消息,一甩袖子就站起来,随从赶上去到前院才送上鞋子,追到寝宫门外才送上佩剑,追到蒲胥街市才让他坐上车子。秋季,九月,楚庄王进攻宋国。 +冬季,公孙归父在穀地会见齐襄公、见到晏桓子,跟他谈到鲁国,很高兴。晏桓子告诉高宣子说:“归父恐怕会逃亡吧!他留恋鲁国。留恋必然贪婪,贪婪必然算计别人。算计别人,别人也算计他自己。一个国家里的人算计他,怎么会不逃亡?” +孟献子对鲁宣公说:“臣听说小国能免罪于大国,是去聘问又进献财物,因此就有庭中陈列的礼物上百件;去朝见并进献功劳,因此就有各色各样的装饰品,美好而且加之以额外礼物,这是为了谋求免除不能赦免的罪过。当大国加以责罚后再进奉财货,就来不及了。现在楚国正屯兵在宋国,君王应该考虑一下!”鲁宣公很高兴。 + +宣公十五年 +【经】十有五年春,公孙归父会楚子于宋。夏五月,宋人及楚人平。六月癸卯,晋师灭赤狄潞氏,以潞子婴儿归。秦人伐晋。王札子杀召伯、毛伯。秋,螽。仲孙蔑会齐高固于无娄。初,税亩。冬,蝝生。饥。 +【传】十五年春,公孙归父会楚子于宋。 +宋人使乐婴齐告急于晋。晋侯欲救之。伯宗曰:“不可。古人有言曰:‘虽鞭之长,不及马腹。’天方授楚,未可与争。虽晋之强,能违天乎?谚曰:‘高下在心。’川泽纳污,山薮藏疾,瑾瑜匿瑕,国君含垢,天之道也,君其待之。”乃止。使解扬如宋,使无降楚,曰:“晋师悉起,将至矣。”郑人囚而献诸楚,楚子厚赂之,使反其言,不许,三而许之。登诸楼车,使呼宋人而告之。遂致其君命。楚子将杀之,使与之言曰:“尔既许不谷而反之,何故?非我无信,女则弃之,速即尔刑。”对曰:“臣闻之,君能制命为义,臣能承命为信,信载义而行之为利。谋不失利,以卫社稷,民之主也。义无二信,信无二命。君之赂臣,不知命也。受命以出,有死无《员雨》,又可赂乎?臣之许君,以成命也。死而成命,臣之禄也。寡君有信臣,下臣获考死,又何求?”楚子舍之以归。 +夏五月,楚师将去宋。申犀稽首于王之马前,曰:“毋畏知死而不敢废王命,王弃言焉。”王不能答。申叔时仆,曰:“筑室反耕者,宋必听命。”从之。宋人惧,使华元夜入楚师,登子反之床,起之曰:“寡君使元以病告,曰:‘敝邑易子而食,析骸以爨。虽然,城下之盟,有以国毙,不能从也。去我三十里,唯命是听。’”子反惧,与之盟而告王。退三十里。宋及楚平,华元为质。盟曰:“我无尔诈,尔无我虞。” +潞子婴儿之夫人,晋景公之姊也。酆舒为政而杀之,又伤潞子之目。晋侯将伐之,诸大夫皆曰:“不可。酆舒有三俊才,不如待后之人。”伯宗曰:“必伐之。狄有五罪,俊才虽多,何补焉?不祀,一也。耆酒,二也。弃仲章而夺黎氏地,三也。虐我伯姬,四也。伤其君目,五也。怙其俊才,而不以茂德,兹益罪也。后之人或者将敬奉德义以事神人,而申固其命,若之何待之?不讨有罪,曰将待后,后有辞而讨焉,毋乃不可乎?夫恃才与众,亡之道也。商纣由之,故灭。天反时为灾,地反物为妖,民反德为乱,乱则妖灾生。故文反正为乏。尽在狄矣。”晋侯从之。六月癸卯,晋荀林父败赤狄于曲梁。辛亥,灭潞。酆舒奔卫,卫人归诸晋,晋人杀之。 +王孙苏与召氏、毛氏争政,使王子捷杀召戴公及毛伯卫。卒立召襄。 +秋七月,秦桓公伐晋,次于辅氏。壬午,晋侯治兵于稷以略狄土,立黎侯而还。及洛,魏颗败秦师于辅氏。获杜回,秦之力人也。 +初,魏武子有嬖妾,无子。武子疾,命颗曰:“必嫁是。”疾病,则曰:“必以为殉。”及卒,颗嫁之,曰:“疾病则乱,吾从其治也。”及辅氏之役,颗见老人结草以亢杜回,杜回踬而颠,故获之。夜梦之曰:“余,而所嫁妇人之父也。尔用先人之治命,余是以报。” +晋侯赏桓子狄臣千室,亦赏士伯以瓜衍之县。曰:“吾获狄土,子之功也。微子,吾丧伯氏矣。”羊舌职说是赏也,曰:“《周书》所谓‘庸庸祗祗’者,谓此物也夫。士伯庸中行伯,君信之,亦庸士伯,此之谓明德矣。文王所以造周,不是过也。故《诗》曰:‘陈锡哉周。’能施也。率是道也,其何不济?” +晋侯使赵同献狄俘于周,不敬。刘康公曰:“不及十年,原叔必有大咎,天夺之魄矣。” +初税亩,非礼也。谷出不过藉,以丰财也。 +冬,蝝生,饥。幸之也。 +译文 +十五年春季,鲁国的公孙归父在宋国会见楚庄王。 +宋国人派乐婴齐到晋国报告急难,晋景公想要救援宋国。伯宗说:“不行。古人有话说:‘鞭子虽然长,达不到马肚子。’上天正在保佑楚国,不能和他竞争。晋国虽然强盛,能够违背上天吗?俗话说:‘高高下下,都在心里。’河流湖泊里容纳污泥浊水,山林草野里暗藏毒虫猛兽,美玉也藏匿着斑痕,国君也得忍受点耻辱,这是上天的常道。君王还是等着吧!”于是,晋景公就停止发兵救宋,派遣解扬到宋国去,让宋国不要投降楚国,解扬对宋国说:“晋国的军队都已经出发,将要到达了。”解扬路过郑国时,郑国人把他囚禁起来献给楚国。楚庄王重重地贿赂他,让他把话反过来说。解扬不答应。经过三次劝说以后才答应了。楚国人让解扬登上楼车,向宋国人喊话,而将楚国人要说的话告诉他们。解扬就乘机传达晋君的命令。楚庄王准备杀死他,派人对他说:“你既已答应了我,现在又反过来,是什么缘故?不是我没有信用,而是你丢失了它。快去受你的刑罚吧!”解扬回答说:“臣听说,国君能制订命令就是道义,臣下能接受命令就是信用,信用贯彻了道义然后去做就是利益。谋划不失去利益,以保卫国家,才是百姓的主人。道义不能有两种信用,信用不能接受两种命令。君王的贿赂下臣,就是不懂得命令的意义。接受了国君的命令而出国,宁可一死而不能废弃命令,难道又可以贿赂的吗?下臣所以答应您,那是为了借机会完成国君的使命。死而能完成使命,这是下臣的福气。寡君有守信的下臣,下臣死得其所,又有什么可以追求的?”楚庄王赦免了解扬放他回去。 +夏季,五月,楚军准备离开宋国,申犀在楚庄王马前叩头说:“无畏知道死而不敢废弃君王的命令,君王丢掉自己的话了。”楚庄王不能回答。申叔时正为楚庄王驾车,说:“造起房子,让种田的人回来,宋国必然听从命令。”楚庄王听从了。宋国人害怕,派华元在夜里进入楚军营,登上子反的床,叫他起来,说:“寡君派元把困难情况告诉你,说:‘敝邑交换着儿子杀了吃掉,把尸骨拆开来烧着做饭。尽管如此,无条件投降,宁可让国家灭亡,也是不能这样做的。你们退兵三十里,宋国将唯命是听。’”子反害怕,就和华元私自订盟誓然后报告楚庄王。楚军退兵三十里,宋国和楚国讲和。华元作为人质。盟誓说:“我不骗你,你不欺我。” +潞子婴儿的夫人,是晋景公的姐姐。鄷舒执政以后杀了她,又伤了潞子的眼睛。晋景公准备进攻他。大夫们都说:“不行。鄷舒有三项显著的才能,不如等待他的后任。”伯宗说:“一定要进攻他。狄人有五条罪状,突出的才能虽然多,有什么补益?不祭祀,这是一。喜欢喝酒,这是二。废弃仲章而夺取黎氏的土地,这是三。杀害我们伯姬,这是四。伤了他国君的眼睛,这是五。依仗他自己的显著才能,而不用美德,这就更增加了罪过。继任的人或者将会敬奉德义以奉事神明,而巩固国家的命运,到时又怎么对待他?不进攻有罪的人,说‘将等待后继人’,以后有了理由再去进攻,恐怕不可以吧!依仗才能和人多,这是亡国之道。商纣按这样去做,所以被灭亡。天违反时令就是灾难,地违反物性就是妖异,百姓违反道德就是祸乱。有了祸乱就有妖异和灾祸发生。所以在文字上,正字反过来就是乏字。上面这些反常的事在狄人那里都是存在的。”晋景公听从了。六月十八日,晋国荀林父在曲梁打败赤狄。二十六日,灭潞国。鄷舒逃亡到卫国,卫国人把他送还到晋国,晋国人杀死了他。 +王孙苏与召氏、毛氏争夺政权,指使王子捷杀死了召戴公和毛伯卫,最后立了召襄为执政卿士。 +秋季,七月,秦桓公进攻晋国,驻扎在辅氏。二十七日,晋景公在稷地进行武装演习,来占领狄人的土地,立了黎侯然后回来。到达洛水,魏颗在辅氏击败秦军,俘获了杜回这个秦国的大力士。 +当初,魏武子有一个爱妾,没有生儿子。魏武子生病,分咐魏颗说:“等我死去以后,一定要嫁了她”病危时,又说:“一定要让她殉葬!”等到魏武子死后,魏颗把她嫁了,说:“病重了就神志不清,我听从他清醒时候的话。”等到辅氏这一役,魏颗看到一个老人把草打成结来遮拦杜回。杜回绊倒在地,所以俘虏了他。夜里梦见老人说:“我,是你所嫁女人的父亲。你执行你先人清醒时候的话,我以此作为报答。” +晋景公赏给桓子狄国的臣民一千家,也把瓜衍的县城赏给士伯,说:“我得到狄国的土地,是您的功劳。如果没有您,我就丧失伯氏了。”羊舌职对这些赏赐感到高兴,说:“《周书》所谓‘能用可用的、能敬可敬的’,说的就是这一类吧。士伯认为中行伯为可以任用,国君相信他,就任用他,这就叫做明德了。文王所以能创立周朝,也不超过这些了。所以《诗》说‘把利益布施给天下,创立了周朝’,这是说文王能够施恩于百姓。遵循这个道理去做,还有什么不能成功的?” +晋景公派遣赵同到成周进献俘虏的狄人,表现得不恭敬。刘康公说:“不到十年,原叔一定有大灾难。上天已经夺走了他的魂魄了。” +鲁国开始按田亩征税,这是不合于礼的。过去的征税方法是所征的稻谷不超过“藉”的规定,这是用以增加财货的办法。 +冬季,蝗的幼虫蜉化,造成饥荒。《春秋》所以记载这件事,是由于庆幸没有造成严重灾害。 + +宣公十六年 +【经】十有六年春王正月。晋人灭赤狄甲氏及留吁。夏,成周宣榭火。秋,郯伯姬来归。冬,大有年。 +【传】十六年春,晋士会帅师灭赤狄甲氏及留吁、铎辰。 +三月,献狄俘。晋侯请于王。戊申,以黻冕命士会将中军,且为大傅。于是晋国之盗逃奔于秦。羊舌职曰:“吾闻之,‘禹称善人,不善人远’,此之谓也夫。《诗》曰:‘战战兢兢,如临深渊,如履薄冰。’善人在上也。善人在上,则国无幸民。谚曰:‘民之多幸,国之不幸也。’是无善人之谓也。” +夏,成周宣榭火,人火之也。凡火,人火曰火,天火曰灾。 +秋,郯伯姬来归,出也。 +为毛、召之难故,王室复乱。王孙苏奔晋,晋人复之。 +冬,晋侯使士会平王室,定王享之,原襄公相礼,殽烝。武子私问其故。王闻之,召武子曰:“季氏,而弗闻乎?王享有体荐,宴有折俎。公当享,卿当宴,王室之礼也。”武子归而讲求典礼,以修晋国之法。 +译文 +十六年春季,晋国的士会率领军队灭亡了赤狄的甲氏和留吁、铎辰。 +三月,晋国向周定王进献俘虏的狄人。晋景公向周定王请求,二十七日,把礼服赐给士会命令他率领中军,并且担任太傅。在这种情况下,晋国的盗贼逃奔到秦国。羊舌职说:“我听说,‘禹提拔好人,不好的人因此远离’,说的就是这样的事情吧!《诗》说,‘战战兢兢,如同面临深渊,如同踩着薄冰’,这是因为有好人在上面执政。有好人在上面,国家中就没有心存侥幸的百姓。俗话说,‘百姓多存侥幸,就是国家不幸’,这就是没有好人在位的说法。” +夏季,成周的宣榭失火,这是由于人放火烧着的。凡是失火,人为的火叫做火。天降的火叫做灾。 +秋季,郯伯姬回来,这是由于被遗弃送回娘家。 +由于毛氏、召氏祸难的缘故,周王室又发生动乱,王孙苏逃亡到晋国。晋国人让他重新恢复了卿士。 +冬季,晋景公派遣士会调解王室的纠纷,周定王设享礼招待他。周大夫原襄公主持典礼,把切开的带骨的肉放在盛肉的器具里。士会暗中问这是什么缘故。周定王听到,召见士会说:“季氏,你没有听说过吗?天子设享礼有摆而不食的‘体荐’,设宴礼有把肉切成块的‘折俎’。诸侯应当设享礼招待,卿、大夫应当设宴会招待。这是王室的礼节。”士会回国以后就讲求典礼,以修明晋国的法度。 + + +宣公十七年 +【经】十有七年春王正月庚子,许男锡我卒。丁未,蔡侯申卒。夏,葬许昭公。葬蔡文公。六月癸卯,日有食之。己未,公会晋侯、卫侯、曹伯、邾子同盟于断道。秋,公至自会。冬十有一月壬午,公弟叔肸卒。 +【传】十七年春,晋侯使郤克征会于齐。齐顷公帷妇人,使观之。郤子登,妇人笑于房。献子怒,出而誓曰:“所不此报,无能涉河。”献子先归,使栾京庐待命于齐,曰:“不得齐事,无覆命矣。”郤子至,请伐齐,晋侯弗许。请以其私属,又弗许。 +齐侯使高固、晏弱、蔡朝、南郭偃会。及敛孟,高固逃归。夏,会于断道,讨贰也。盟于卷楚,辞齐人。晋人执晏弱于野王,执蔡朝于原,执南郭偃于温。苗贲皇使,见晏桓子,归言于晋侯曰:“夫晏子何罪?昔者诸侯事吾先君,皆如不逮,举言群臣不信,诸侯皆有贰志。齐君恐不得礼,故不出,而使四子来。左右或沮之,曰:‘君不出,必执吾使。’故高子及敛盂而逃。夫三子者曰:‘若绝君好,宁归死焉。’为是犯难而来,吾若善逆彼以怀来者。吾又执之,以信齐沮,吾不既过矣乎?过而不改,而又久之,以成其悔,何利之有焉?使反者得辞,而害来者,以惧诸侯,将焉用之?”晋人缓之,逸。 +秋八月,晋师还。 +范武子将老,召文子曰:“燮乎!吾闻之,喜怒以类者鲜,易者实多。《诗》曰:‘君子如怒,乱庶遄沮;君子如祉,乱庶遄已。’君子之喜怒,以已乱也。弗已者,必益之。郤子其或者欲已乱于齐乎?不然,余惧其益之也。余将老,使郤子逞其志,庶有豸乎?尔从二三子唯敬。”乃请老,郤献子为政。 +冬,公弟叔肸卒。公母弟也。凡大子之母弟,公在曰公子,不在曰弟。凡称弟,皆母弟也。 +译文 +十七年春季,晋景公派遣郤克到齐国征召齐顷公参加盟会。齐顷公用帷幕遮住妇人让她观看。郤克登上台阶,那妇人在房里笑起来。郤克生气,出来发誓说:“不报复这次耻辱,就不能渡过黄河!”郤克先回国,让栾京庐在齐国等候命令,说:“不能完成在齐国的使命,就不要回国复命。”郤克到达晋国,请求进攻齐国,晋景公不答应,请求带领家族去进攻齐国,晋景公也不答应。 +齐顷公派遣高固、晏弱、蔡朝、南郭偃参加会盟。到达敛盂,高固逃回来。夏季,在断道会盟,这是为了讨伐有二心的国家。又在卷楚结盟,拒绝齐国人参加。晋国人在野王逮捕了晏弱,在原地逮捕了蔡朝,在温地逮捕了南郭偃。苗贲皇出使路过,见到晏弱。回去,对晋景公说:“晏子有什么罪?从前诸侯奉事我们的先君,都急得像赶不上的样子,都说是因为晋国君臣不讲信用,所以诸侯都有二心。齐国的国君恐怕不能得到礼遇,所以不出国而派这四个人来。齐顷公左右的随从有人阻止,说:‘您不出国,一定会抓住我国的使者。’所以高子到达敛盂就逃走了。这三个人说:‘如果因为我们断绝了国君的友好,宁可回国被处死。’为此他们甘冒危险而来。我们应该好好迎接他们,以使前来的人对我们怀念,但是我们偏偏逮捕了他们,以证明齐国人的劝阻是对的,我们不是已经做错了吗?做错了而不加以改正,而又久久不肯释放,以造成他们的后悔,这有什么好处?让回去的人有了逃走的理由,而伤害前来的人,以使诸侯害怕,这有什么用?”于是晋国人放松了看管,齐国的三名使者就逃走了。 +秋季,八月,晋军回国。 +范武子打算告老还乡,把儿子范文子喊过来,说:“燮儿啊!我听说,喜怒合于礼法的是很少的,和它相反的倒是很多。《诗》说:‘君子如果发怒,祸乱或许可以很快阻住。君子如果喜悦,祸乱或许可以很快停歇。’君子的喜怒是用来阻止祸乱的。如果不是阻止,就一定会增加祸乱。郤子或者是想要在齐国阻止祸乱吧。如果不是这样,我怕他会增加祸乱呢!我打算告老还乡了,让郤子能够心满意足,祸乱或许可以解除。你跟随几位大夫,唯有恭敬从事。”于是就请求告老。郤克执政。 +冬季,鲁宣公的弟弟叔肸死,他是宣公的同母兄弟。凡是太子的同母兄弟,国君在世叫做公子,不在世叫做弟。凡称为弟的,都是同母兄弟。 + +宣公十八年 +【经】十有八年春,晋侯、卫世子臧伐齐。公伐杞。夏四月。秋七月,邾人伐鄫子于鄫。甲戌,楚子旅卒。公孙归父如晋。冬十月壬戌,公薨于路寝。归父还自晋,至笙。遂奔齐, +【传】十八年春,晋侯、卫大子臧伐齐,至于阳谷。齐侯会晋侯盟于缯,以公子强为质于晋。晋师还,蔡朝、南郭偃逃归。 +夏,公使如楚乞师,欲以伐齐。 +秋,邾人戕鄫子于鄫。凡自虐其君曰弑,自外曰戕。 +楚庄王卒。楚师不出,既而用晋师,楚于是乎有蜀之役。 +公孙归父以襄仲之立公也,有宠,欲去三桓以张公室。与公谋而聘于晋,欲以晋人去之。冬,公薨。季文子言于朝曰:“使我杀适立庶以失大援者,仲也夫。”臧宣叔怒曰:“当其时不能治也,后之人何罪?子欲去之,许请去之。”遂逐东门氏。子家还,及笙,坛帷,覆命于介。既覆命,袒、括发,即位哭,三踊而出。遂奔齐。书曰“归父还自晋。”善之也。 +译文 +十八年春季,晋景公、卫国的太子臧共同发兵进攻齐国,到达阳穀,齐顷公与晋景公在缯地会见订立盟约,齐国派公子彊在晋国作为人质。晋军回国。蔡朝、南郭偃逃回国内。 +夏季,鲁宣公的使者到楚国请求出兵,想要进攻齐国。 +秋季,邾国人在鄫国戕杀鄫子。凡从国内杀死他们国君叫做“弑”,从国外来人杀的叫做“戕”。 +楚庄王去世,楚军不能出兵。不久鲁国就利用晋军攻打齐国,楚国因此而有蜀地的战役。 +公孙归父由于他父亲襄仲立了鲁宣公,而受到宣公宠信,他想要去掉孟孙、叔孙、季孙这“三桓”,以伸张公室的权力。他和宣公策划以后就到晋国去聘问,想要用晋国人的力量来去掉三桓。冬季,宣公逝世。季文子在朝廷上说:“让我杀死嫡子立了庶子以失掉强大的援助的,就是襄仲啊!”臧宣叔发怒说:“当时不能治罪,他的后人有什么罪?您要去掉他,许就请求去掉他。”于是就把襄仲的家族东门氏驱逐出国。 +公孙归父回国,到达笙地,用帷幕遮住土坛,向他的副手举行复命的礼节。复命完了,脱去外衣,以麻束发,回到自己的位置痛哭,顿脚三次退出。于是就逃亡到齐国。《春秋》记载说“归父还自晋”,是对他表示赞许。 + +成公 + +成公元年 +【经】元年春王正月,公即位。二月辛酉,葬我君宣公。无冰。三月,作丘甲。夏,臧孙许及晋侯盟于赤棘。秋,王师败绩于茅戎。冬十月。 +【传】元年春,晋侯使瑕嘉平戎于王,单襄公如晋拜成。刘康公徼戎,将遂伐之。叔服曰:“背盟而欺大国,此必败。背盟,不祥;欺大国,不义;神人弗助,将何以胜?”不听,遂伐茅戎。三月癸未,败绩于徐吾氏。 +为齐难故,作丘甲。 +闻齐将出楚师,夏,盟于赤棘。 +秋,王人来告败。 +冬,臧宣叔令修赋、缮完、具守备,曰:“齐、楚结好,我新与晋盟,晋、楚争盟,齐师必至。虽晋人伐齐,楚必救之,是齐、楚同我也。知难而有备,乃可以逞。” +译文 +元年春季,晋景公派遣瑕嘉调解周天子和戎人的冲突,单襄公到晋国拜谢调解成功。刘康公对戎人心存侥幸,打算乘此进攻他们。叔服说:“背弃盟约而又欺骗大国,这一定失败。背弃盟约就是不吉祥,欺骗大国就是不义,神明、百姓都不会帮助,将要如何去取胜利?”刘康公没有听从,于是就进攻茅戎。三月十九日,在徐吾氏地方被打得大败。 +鲁国为了防备齐国入侵,定出“丘甲”的制度。 +鲁国听说齐国将要率同楚军前来进攻,夏季,(臧孙许和晋景公)在赤棘结盟。 +秋季,周定王的使者来鲁国报告战败。 +冬季,臧宣叔命令整顿军赋、修治城郭,完成防御设施,说:“齐国和楚国结成友好,我国最近和晋国订了盟约。晋国和楚国争夺盟主,齐国的军队一定会来攻打我国。虽然晋国进攻齐国,楚国必然去救它,这就是齐、楚两国一起与我为敌。预计到祸难而有所防备,祸难就得以解除。” + +成公二年 +【经】二年春,齐侯伐我北鄙。夏四月丙戌,卫孙良夫帅师及齐师战于新筑,卫师败绩。六月癸酉,季孙行父、臧孙许、叔孙侨如、公孙婴齐帅师会晋郤克、卫孙良夫、曹公子首及齐侯战于鞍,齐师败绩。秋七月,齐侯使国佐如师。己酉,及国佐盟于袁娄。八月壬卒。宋公鲍卒。庚寅,卫侯速卒。取汶阳田。冬,楚师、郑师侵卫。十有一月,公会楚公子婴齐于蜀。丙申,公及楚人、秦人、宋人、陈人、卫人、郑人、齐人、曹人、邾人、薛人、鄫人盟于蜀。 +【传】二年春,齐侯伐我北鄙,围龙。顷公之嬖人卢蒲就魁门焉,龙人囚之。齐侯曰:“勿杀!吾与而盟,无入而封。”弗听,杀而膊诸城上。齐侯亲鼓,士陵城,三日,取龙,遂南侵及巢丘。 +卫侯使孙良夫、石稷、宁相、向禽将侵齐,与齐师遇。石子欲还,孙子曰:“不可。以师伐人,遇其师而还,将谓君何?若知不能,则如无出。今既遇矣,不如战也。” +夏,有。 +石成子曰:“师败矣。子不少须,众惧尽。子丧师徒,何以覆命?”皆不对。又曰:“子,国卿也。陨子,辱矣。子以众退,我此乃止。”且告车来甚众。齐师乃止,次于鞫居。新筑人仲叔于奚救孙桓子,桓子是以免。 +既,卫人赏之以邑,辞。请曲县、繁缨以朝,许之。仲尼闻之曰:“惜也,不如多与之邑。唯器与名,不可以假人,君之所司也。名以出信,信以守器,器以藏礼,礼以行义,义以生利,利以平民,政之大节也。若以假人,与人政也。政亡,则国家从之,弗可止也已。” +孙桓子还于新筑,不入,遂如晋乞师。臧宣叔亦如晋乞师。皆主郤献子。晋侯许之七百乘。郤子曰:“此城濮之赋也。有先君之明与先大夫之肃,故捷。克于先大夫,无能为役,请八百乘。”许之。郤克将中军,士燮佐上军,栾书将下军,韩厥为司马,以救鲁、卫。臧宣叔逆晋师,且道之。季文子帅师会之。及卫地,韩献子将斩人,郤献子驰,将救之,至则既斩之矣。郤子使速以徇,告其仆曰:“吾以分谤也。” +师从齐师于莘。六月壬申,师至于靡笄之下。齐侯使请战,曰:“子以君师,辱于敝邑,不腆敝赋,诘朝请见。”对曰:“晋与鲁、卫,兄弟也。来告曰:‘大国朝夕释憾于敝邑之地。’寡君不忍,使群臣请于大国,无令舆师淹于君地。能进不能退,君无所辱命。”齐侯曰:“大夫之许,寡人之愿也;若其不许,亦将见也。”齐高固入晋师,桀石以投人,禽之而乘其车,系桑本焉,以徇齐垒,曰:“欲勇者贾余馀勇。” +癸酉,师陈于□安。邴夏御齐侯,逢丑父为右。晋解张御郤克,郑丘缓为右。齐侯曰:“余姑翦灭此而朝食。”不介马而驰之。郤克伤于矢,流血及屦,未绝鼓音,曰:“余病矣!”张侯曰:“自始合,而矢贯余手及肘,余折以御,左轮朱殷,岂敢言病。吾子忍之!”缓曰:“自始合,苟有险,余必下推车,子岂识之?然子病矣!”张侯曰:“师之耳目,在吾旗鼓,进退从之。此车一人殿之,可以集事,若之何其以病败君之大事也?擐甲执兵,固即死也。病未及死,吾子勉之!”左并辔,右援枹而鼓,马逸不能止,师从之。齐师败绩。逐之,三周华不注。 +韩厥梦子舆谓己曰:“旦辟左右。”故中御而从齐侯。邴夏曰:“射其御者,君子也。”公曰:“谓之君子而射之,非礼也。”射其左,越于车下。射其右,毙于车中,綦毋张丧车,从韩厥,曰:“请寓乘。”从左右,皆肘之,使立于后。韩厥俛,定其右。逢丑父与公易位。将及华泉,骖絓于木而止。丑父寝于轏中,蛇出于其下,以肱击之,伤而匿之,故不能推车而及。韩厥执絷马前,再拜稽首,奉觞加璧以进,曰:“寡君使群臣为鲁、卫请,曰:‘无令舆师陷入君地。’下臣不幸,属当戎行,无所逃隐。且惧奔辟而忝两君,臣辱戎士,敢告不敏,摄官承乏。”丑父使公下,如华泉取饮。郑周父御佐车,宛伐为右,载齐侯以免。韩厥献丑父,郤献子将戮之。呼曰:“自今无有代其君任患者,有一于此,将为戮乎!”郤子曰:“人不难以死免其君。我戮之不祥,赦之以劝事君者。”乃免之。 +齐侯免,求丑父,三入三出。每出,齐师以帅退。入于狄卒,狄卒皆抽戈楯冒之。以入于卫师,卫师免之。遂自徐关入。齐侯见保者,曰:“勉之!齐师败矣。”辟女子,女子曰:“君免乎?”曰:“免矣。”曰:“锐司徒免乎?”曰:“免矣。”曰:“苟君与吾父免矣,可若何!”乃奔。齐侯以为有礼,既而问之,辟司徒之妻也。予之石窌。 +晋师从齐师,入自丘舆,击马陉。齐侯使宾媚人赂以纪甗、玉磬与地。不可,则听客之所为。宾媚人致赂,晋人不可,曰:“必以萧同叔子为质,而使齐之封内尽东其亩。”对曰:“萧同叔子非他,寡君之母也。若以匹敌,则亦晋君之母也。吾子布大命于诸侯,而曰:‘必质其母以为信。’其若王命何?且是以不孝令也。《诗》曰:‘孝子不匮,永锡尔类。’若以不孝令于诸侯,其无乃非德类也乎?先王疆理天下物土之宜,而布其利,故《诗》曰:‘我疆我理,南东其亩。’今吾子疆理诸侯,而曰‘尽东其亩’而已,唯吾子戎车是利,无顾土宜,其无乃非先王之命也乎?反先王则不义,何以为盟主?其晋实有阙。四王之王也,树德而济同欲焉。五伯之霸也,勤而抚之,以役王命。今吾子求合诸侯,以逞无疆之欲。《诗》曰‘布政优优,百禄是遒。’子实不优,而弃百禄,诸侯何害焉!不然,寡君之命使臣则有辞矣,曰:‘子以君师辱于敝邑,不腆敝赋以,犒从者。畏君之震,师徒□尧败,吾子惠徼齐国之福,不泯其社稷,使继旧好,唯是先君之敝器、土地不敢爱。子又不许,请收合馀烬,背城借一。敝邑之幸,亦云从也。况其不幸,敢不唯命是听。’”鲁、卫谏曰:“齐疾我矣!其死亡者,皆亲昵也。子若不许,仇我必甚。唯子则又何求?子得其国宝,我亦得地,而纾于难,其荣多矣!齐、晋亦唯天所授,岂必晋?”晋人许之,对曰:“群臣帅赋舆以为鲁、卫请,若苟有以藉口而复于寡君,君之惠也。敢不唯命是听。” +禽郑自师逆公。 +秋七月,晋师及齐国佐盟于爰娄,使齐人归我汶阳之田。公会晋师于上鄍,赐三帅先路三命之服,司马、司空、舆帅、候正、亚旅,皆受一命之服。 +八月,宋文公卒。始厚葬,用蜃炭,益车马,始用殉。重器备,椁有四阿,棺有翰桧。 +君子谓:“华元、乐举,于是乎不臣。臣治烦去惑者也,是以伏死而争。今二子者,君生则纵其惑,死又益其侈,是弃君于恶也。何臣之为?” +九月,卫穆公卒,晋二子自役吊焉,哭于大门之外。卫人逆之,妇人哭于门内,送亦如之。遂常以葬。 +楚之讨陈夏氏也,庄王欲纳夏姬,申公巫臣曰:“不可。君召诸侯,以讨罪也。今纳夏姬,贪其色也。贪色为淫,淫为大罚。《周书》曰:‘明德慎罚。’文王所以造周也。明德,务崇之之谓也;慎罚,务去之之谓也。若兴诸侯,以取大罚,非慎之也。君其图之!”王乃止。子反欲取之,巫臣曰:“是不祥人也!是夭子蛮,杀御叔,弑灵侯,戮夏南,出孔、仪,丧陈国,何不祥如是?人生实难,其有不获死乎?天下多美妇人,何必是?”子反乃止。王以予连尹襄老。襄老死于邲,不获其尸,其子黑要烝焉。巫臣使道焉,曰:“归!吾聘女。”又使自郑召之,曰:“尸可得也,必来逆之。”姬以告王,王问诸屈巫。对曰:“其信!知荦之父,成公之嬖也,而中行伯之季弟也,新佐中军,而善郑皇戌,甚爱此子。其必因郑而归王子与襄老之尸以求之。郑人惧于邲之役而欲求媚于晋,其必许之。”王遣夏姬归。将行,谓送者曰:“不得尸,吾不反矣。”巫臣聘诸郑,郑伯许之。及共王即位,将为阳桥之役,使屈巫聘于齐,且告师期。巫臣尽室以行。申叔跪从其父将适郢,遇之,曰:“异哉!夫子有三军之惧,而又有《桑中之喜,宜将窃妻以逃者也。”及郑,使介反币,而以夏姬行。将奔齐,齐师新败曰:“吾不处不胜之国。”遂奔晋,而因郤至,以臣于晋。晋人使为邢大夫。子反请以重币锢之,王曰:“止!其自为谋也,则过矣。其为吾先君谋也,则忠。忠,社稷之固也,所盖多矣。且彼若能利国家,虽重币,晋将可乎?若无益于晋,晋将弃之,何劳锢焉。” +晋师归,范文子后入。武子曰:“无为吾望尔也乎?”对曰:“师有功,国人喜以逆之,先入,必属耳目焉,是代帅受名也,故不敢。”武子曰:“吾知免矣。” +郤伯见,公曰:“子之力也夫!”对曰:“君之训也,二三子之力也,臣何力之有焉!”范叔见,劳之如郤伯,对曰:“庚所命也,克之制也,燮何力之有焉!”栾伯见,公亦如之,对曰:“燮之诏也,士用命也,书何力之有焉!” +宣公使求好于楚。庄王卒,宣公薨,不克作好。公即位,受盟于晋,会晋伐齐。卫人不行使于楚,而亦受盟于晋,从于伐齐。故楚令尹子重为阳桥之役以求齐。将起师,子重曰:“君弱,群臣不如先大夫,师众而后可。《诗》曰:‘济济多士,文王以宁。’夫文王犹用众,况吾侪乎?且先君庄王属之曰:‘无德以及远方,莫如惠恤其民,而善用之。’”乃大户,已责,逮鳏,救乏,赦罪,悉师,王卒尽行。彭名御戎,蔡景公为左,许灵公为右。二君弱,皆强冠之。 +冬,楚师侵卫,遂侵我,师于蜀。使臧孙往,辞曰:“楚远而久,固将退矣。无功而受名,臣不敢。”楚侵及阳桥,孟孙请往,赂之以执斫、执针、织紝,皆百人。公衡为质,以请盟,楚人许平。 +十一月,公及楚公子婴齐、蔡侯、许男、秦右大夫说、宋华元、陈公孙宁、卫孙良夫、郑公子去疾及齐国之大夫盟于蜀。卿不书,匮盟也。于是乎畏晋而窃与楚盟,故曰匮盟。蔡侯、许男不书,乘楚车也,谓之失位。君子曰:“位其不可不慎也乎!蔡、许之君,一失其位,不得列于诸侯,况其下乎?《诗》曰:‘不解于位,民之攸塈。’其是之谓矣。” +楚师及宋,公衡逃归。臧宣叔曰:“衡父不忍数年之不宴,以弃鲁国,国将若之何?谁居?后之人必有任是夫!国弃矣。” +是行也,晋辟楚,畏其众也。君子曰:“众之不可以已也。大夫为政,犹以众克,况明君而善用其众乎?《大誓》所谓商兆民离,周十人同者众也。” +晋侯使巩朔献齐捷于周,王弗见,使单襄公辞焉,曰:“蛮夷戎狄,不式王命,淫湎毁常,王命伐之,则有献捷,王亲受而劳之,所以惩不敬,劝有功也。兄弟甥舅,侵败王略,王命伐之,告事而已,不献其功,所以敬亲昵,禁淫慝也。今叔父克遂,有功于齐,而不使命卿镇抚王室,所使来抚余一人,而巩伯实来,未有职司于王室,又奸先王之礼,余虽欲于巩伯、其敢废旧典以忝叔父?夫齐,甥舅之国也,而大师之后也,宁不亦淫从其欲以怒叔父,抑岂不可谏诲?”士庄伯不能对。王使委于三吏,礼之如侯伯克敌使大夫告庆之礼,降于卿礼一等。王以巩伯宴,而私贿之。使相告之曰:“非礼也,勿籍。” +译文 +二年春季,齐顷公进攻我国北部边境,包围龙地。齐顷公的宠臣卢蒲就魁攻打城门,龙地的人把他逮住囚禁。齐顷公说:“不要杀,我和你们盟誓,不进入你们的境内。”龙地的人不听,把他杀了,暴尸城上。齐顷公亲自击鼓,兵士爬上城墙。三天,占领了龙地。于是就向南入侵,到达巢丘。 +卫穆公派遣孙良夫、石稷、宁相、向禽率兵入侵齐国,和齐军相遇。石稷想要回去,孙良夫说:“不行。用军队攻打别人,遇上敌人就回去,将怎样对国君说呢?如果知道不能作戕,就应当不出兵。现在既然和敌军相遇,不如打一仗。” +夏季,有。 +石稷说:“军队战败了,您如果不稍稍等待,顶住敌军,将会全军覆灭。您丧失了军队,如何回报君命?”大家都不回答。石稷又说:“您,是国家的卿。损失了您,就是一种羞耻了。您带着大家撤退,我就留在这里。”同时通告军中,说援军的战车来了不少。齐国的军队就停止前进,驻扎在鞠居。 +新筑大夫仲叔于奚援救了孙良夫,孙良夫因此得免于难。不久,卫国人把城邑赏给仲叔于奚。仲叔于奚辞谢,而请求得到诸侯所用三面悬挂的乐器,并用繁缨装饰马匹来朝见,卫君允许了。孔子听说这件事,说:“可惜啊,还不如多给他城邑。惟有器物和名号,不能假借给别人,这是国君掌握的。名号用来赋予威信,威信用来保持器物,器物用来体现礼制,礼制用来推行道义,道义用来产生利益,利益用来治理百姓,这是政权中的大节。如果把名位、礼器假借给别人,这就是把政权给了别人。失去政权,国家也就跟着失去,这是不能阻止的。” +孙桓子回到新筑,不进国都,就到晋国请求出兵。臧宣叔也到晋国请求出兵。两人都投奔郤克。晋景公答应派出七百辆战车。郤克说:“这是城濮之战的战年数。当时有先君的明察和先大夫的敏捷,所以得胜。克和先大夫相比,还不足以做他们的仆人。请发八百乘战车。”晋景公答应了。郤克率领中军,士燮辅佐上军,栾书率领下军,韩厥做司马,以救援鲁国和卫国,臧宣叔迎接晋军,同时向导开路。季文子率领军队和他们会合。到达卫国境内,韩厥要杀人,郤克驾车疾驰赶去,打算救下那个人。等赶到,已经杀了。郤克派人把尸体在军中示众,还告诉他的御者说:“我用这样的做法来分担指责。” +晋、鲁、卫联军在莘地追上齐军。六月十六日,军队到达靡笄山下。齐顷公派人请战,说:“您带领国君的军队光临敝邑,敝国的士兵不强,也请在明天早晨相见决战。”郤克回答说:“晋和鲁、卫是兄弟国家,他们前来告诉我们说:‘大国不分早晚都在敝邑的土地上发泄气愤。’寡君不忍,派下臣们前来向大国请求,同时又不让我军长久留在贵国。我们只能前进不能后退,您的命令是不会不照办的。”齐顷公说:“大夫允许,正是齐国的愿望;如果不允许,也要兵戎相见的。”齐国的高固攻打晋军,拿起石头扔向晋军,抓住晋军战俘,然后坐上他的战车,把桑树根子系在车上,巡行到齐营说:“想要勇气的人可以来买我剩下的勇气!” +十七日,齐、晋两军在鞌地摆开阵势。邴夏为齐顷公驾车,逢丑父作为车右。晋国的解张为郤克驾车,郑丘缓作为车右。齐顷公说:“我暂且消灭了这些人再吃早饭。”马不披甲,驰向晋军。郤克受了箭伤,血流到鞋子上,但是鼓声不断,说:“我受伤了!”解张说:“从一开始交战,箭就射穿了我的手和肘,我折断了箭杆仍驾车,左边的车轮都染成黑红色,哪里敢说受伤?您忍着点吧!”郑丘缓说:“从一开始交战,如果遇到危险,我必定下车推车,您难道了解吗?不过您真是受伤了!”解张说:“军队的耳目,在于我的旗子和鼓声,前进后退都要听从它。这辆车子由一个人镇守,战事就可以完成。为什么要为了一点痛苦而败坏国君的大事呢?身披盔甲,手执武器,本来就抱定必死的决心,受伤还没有到死的程度,你还是尽力而为吧!”于是就左手一把握着马缰,右手拿着鼓槌击鼓。马奔跑不能停止,全军就跟着上去。齐军大败,晋国追赶齐军,绕了华不注山三圈。 +韩厥梦见他父亲子舆对他说:“明天不要站在战车左右两侧。”因此韩厥就在中间驾战车而追赶齐顷公。邴夏说:“射那位驾车人,他是君子。”齐顷公说:“认为他是君子而射他,这不合于礼。”射车左,车左死在车下。射车右,车右死在车中。綦毋张丢失了战车,跟上韩厥说:“请允许我搭乘您的战车。”上车,准备站在左边或右边,韩厥用肘推他,使他站在身后。韩厥弯下身子,放稳车右的尸体。逢丑父和齐顷公乘机互换位置。将要到达华泉,骖马被树木绊住了。头几天,逢丑父睡在栈车里,有一条蛇爬到他身边,他用小臂去打蛇,小臂受伤,但隐瞒了这件事,由于这样,他不能用臂推车前进,这样才被韩厥追上。韩厥拿着马缰走向马前,跪下叩头,捧着酒杯加上玉璧献上,说:“寡君派臣下们替鲁、卫两国请求,说:‘不要让军队进入齐国的土地。’下臣不幸,正好在军队服役,不能逃避服役。而且也害怕奔走逃避成为两国国君的耻辱。下臣身为一名战士,谨向君王报告我的无能,但由于人手缺乏,只好承当这个官职。”逢丑父要齐顷公下车,到华泉去取水。郑周父驾御副车,宛茷作为车右,带着齐顷公逃走而免于被俘。韩厥献上逢丑父,郤克要杀死逢丑父。逢丑父喊叫说:“从今以后再没有代替他国君受难的人了,有一个在这里,还要被杀死吗?”郤克说:“一个人不畏惧用死来使他的国君免于祸患,我杀了他,不吉利。赦免了他,用来勉励事奉国君的人。”于是就释放了逢丑父。 +齐顷公免于被俘以后,寻找逢丑父,在晋军中三进三出。每次出来的时候,齐军都簇拥着护卫他。进入狄人军队中,狄人的士兵都抽出戈和盾以保护齐顷公。进入卫国的军队中,卫军也对他们不加伤害。于是,齐顷公就从徐关进入齐国临淄。齐顷公看到守军,说:“你们努力吧!齐军战败了!”齐顷公的车前进时使一个女子让路,这个女子说:“国君免于祸难了吗?”说:“免了。”她说:“锐司徒免于祸难了吗?”说:“免了。”她说:“如果国君和我父亲免于祸难了,还要怎么样?”就跑开了。齐顷公认为她知礼,不久查询,才知道是辟司徒的妻子,就赐给她石窌地方作为封邑。 +晋军追赶齐军,从丘舆进入齐国,进攻马陉。齐顷公派遣宾媚人把纪甗、玉磬和土地送给战胜诸国,说:“如果他们不同意讲和,就随他们怎么办吧。”宾媚人送去财礼,晋国人不同意,说:“一定要让萧同叔子作为人质,同时使齐国境内的田陇全部东向。”宾媚人回答说:萧同叔子不是别人,是寡君的母亲,如果从对等地位来说,那也就是晋军的母亲。您在诸侯中发布重大的命令,反而说一定要把人家的母亲作为人质以取信,您又将要怎样对待周天子的命令呢?而且这样做,就是用不孝来命令诸侯。《诗》说:“孝子的孝心没有竭尽,永远可以感染你的同类。”如果用不孝号令诸侯,这恐怕不是道德的准则吧!先王对天下的土地,定疆界、分地理,因地制宜,以获取应得的利益。所以《诗》说:“我划定疆界、分别地理,南向东向开辟田亩。”现在您让诸侯定疆界、分地理,反而只说什么“田垄全部东向”,不顾地势是否适宜,只管自己兵车进出的有利,恐怕不是先王的政令吧!违反先王的遗命就是不合道义,怎么能做盟主?晋国确实是有缺点的。四王能统一天下,主要是能树立德行而满足诸侯的共同愿望;五伯能领导诸侯,主要是能自己勤劳而安抚诸侯,使大家服从天子的命令。现在您要求会合诸侯,来满足没有止境的欲望。《诗》说:“政事的推行宽大和缓,各种福禄都将积聚。”您确实不能宽大,丢弃了各种福禄,这对诸侯有什么害处呢?如果您不肯答应,寡君命令我使臣,就有话可说了:“您带领国君的军队光临敝邑,敝邑用很少的财富,来犒劳您的左右随员。害怕贵国国君的愤怒,我军战败。您惠临而肯赐齐国的福,不灭亡我们的国家,让齐、晋两国继续过去的友好,那么先君的破旧器物和土地我们是不敢爱惜的。您如果又不肯允许,我们就请求收集残兵败将,背靠自己的城下再决最后一战。敝邑有幸而战胜,也会依从贵国的;何况不幸而败,哪敢不听从您的命令?” +鲁、卫两国劝谏郤克说:“齐国怨恨我们了。齐国死去和溃散的,都是齐侯亲近的人。您如果不肯答应,必然更加仇恨我们。即使是您,还有什么可追求的?如果您得到齐国的国室,我们也得到失地,而缓和了祸难,这荣耀也就很多了。齐国和晋国都是由上天授与的,难道一定只有晋国永久胜利吗?”晋国人答应了鲁、卫的意见,回答说:“下臣们率领兵车,来为鲁、卫两国请求。如果有话可以向寡君复命,这就是君王的恩惠了。岂敢不遵命?” +禽郑从军中去迎接鲁成公。 +秋季,七月,晋军和齐国宾媚人在爰娄结盟,让齐国归还我国汶阳的土田。成公在上鄍会见晋军,把先路和三命的车赐给三位高级将领,司马、司空、舆帅、候正、亚旅都接受了一命的车服。 +八月,宋文公去世。开始厚葬:用蚌蛤和木炭,增加陪葬的车马,开始用活人殉葬,用很多器物陪葬。椁有四面呈坡形,棺有翰、桧等装饰。 +君子认为:“华元、乐举,在这里有失为臣之道。臣子,是为国君去掉烦乱解除迷惑的,因此要冒死去谏诤。现在这两个人,国君活着的时候就由他去放纵作恶,死了以后又增加他的奢侈,这是把国君推入邪恶里去,这算是什么臣子?” +九月,卫穆公去世,晋国的三位将领从战地率兵返国途中顺便去吊唁,在大门之外哭吊。卫国人迎接他们,女人在门内哭。送他们的时候也是这样。以后别国官员来吊唁就是以此为常,直到下葬。 +楚国在攻打陈国夏氏的时候,楚庄王想收纳夏姬。申公巫臣说:“不行。君王召集诸侯,是为了讨伐有罪;现在收纳夏姬,就是贪恋她的美色了。贪恋美色叫做淫,淫就会受到重大处罚。《周书》说:‘宣扬道德,谨慎惩罚’,文王因此而创立周朝。宣扬道德,就是致力于提倡它,谨慎惩罚,就是致力于不用它。如果出动诸侯的军队反而得到重大处罚,就是不谨慎了。君王还是考虑一下吧!”楚庄王就不要夏姬了。子反想要娶夏姬,巫臣说:“这是个不吉利的人。她使子蛮早死,杀了御叔,弑了灵侯,诛了夏南,使孔宁、仪行父逃亡在外,陈国因此被灭亡,为什么不吉利到这个样子!人生在世实在很不容易,如果娶了夏姬,恐怕不得好死吧!天下多的是漂亮的女人,为什么一定要她?”子反也就不要她了。楚庄王把夏姬给了连尹襄老。襄老在邲地战役中死去,没有找到尸首。他的儿子黑要和夏姬私通。巫臣派人向夏姬示意,说:“回娘家去,我娶你。”又派人从郑国召唤她说:“襄老尸首可以得到,一定要亲自来接。”夏姬把这话报告楚庄王。楚庄王就问巫臣。巫臣回答说:“恐怕是靠得住的。知罃的父亲,是成公的宠臣,又是中行伯的小兄弟,新近做了中军佐,和郑国的皇戌交情很好,非常喜爱这个儿子,他一定是想通过郑国而归还王子和襄老尸首而来要求交换知罃。郑国人对邲地战役感到害怕,同时要讨好于晋国,他们一定会答应。”楚庄王就打发夏姬回去。将要动身的时候,夏姬对送行的人说:“不能得到尸首,我就不回来了。”巫臣在郑国聘她为妻,郑襄公允许了。等到楚共王即位,将要发动阳桥战役,派巫臣到齐国聘问,同时把出兵的日期告诉齐国。巫臣把一切家财全部带走。申叔跪跟着他的父亲将要到郢都去,碰上巫臣,说:“怪哉!这个人有肩负军事重任的戒惧之心,却又有‘桑中’幽会的喜悦之色,可能是将要带着别人的妻子私奔吧!”到了郑国,巫臣派副使带回财礼,就带着夏姬走了。准备逃亡到齐国,齐国又被战败,巫臣说:“我不住在不打胜仗的国家。”就逃亡到晋国,并且由于郤至的关系在晋国做臣下。晋国人让他做邢地的大夫。子反请求把巨款送给晋国,而要求晋国对巫臣永不录用,楚共王说:“别那样做!他为自己打算是错误的,他为我的先君打算则是忠诚的。忠诚,国家靠着它来巩固,所能保护的东西就多了。而且他如果能有利于晋国,虽然送去重礼,晋国会同意永不录用吗?如果对晋国没有好处,晋国将会不要他,何必求其永不录用呢?” +晋国军队回国,范文子最后回来。他的父亲范武子说“你不也知道我在盼望你吗?”范文子回答说:“出兵有功劳,国内的人们高兴地迎接他们。先回来,一定受到人们的注意,这是代替统帅接受荣誉,所以我不敢。”武子说:“你这样谦让,我认为可以免于祸害了。” +郤伯入见,晋景公说:“这是您的功劳啊!”郤伯回答说:“这是君王的教导,诸位将帅的功劳,下臣有什么功劳呢?”范文子入见,晋景公像对郤伯一样慰劳他。范文子回答说:“这是范庚的命令,郤克的节制,小臣士燮有什么功劳呢?”栾伯进见,晋景公也如同慰劳郤伯他们一样慰劳他。栾伯回答说:“这是士燮的指示,士兵服从命令,小臣栾书有什么功劳呢?” +鲁宣公曾派遣使者到楚国要求建立友好关系,由于楚庄王死了,不久鲁宣公也死去,没有能够建立友好关系。鲁成公即位,在晋国接受盟约,会合晋国进攻齐国。卫国人不派使者去楚国聘问,也在晋国接受盟约,跟从着进攻齐国。因此楚国的令尹子重发动阳桥战役来救齐国。将要发兵,子重说:“国君年幼,臣下们又比不上先大夫,军队人数众多然后才可以取胜。《诗》说:‘众多的人士,文王借以安宁。’文王尚且使用大众,何况是我们这些人呢?而且先君庄王把国君嘱托给我们说:‘如果没有德行到达边远的地方,还不如加恩体恤百姓而很好地使用他们。’”于是楚国就大事清查户口,免除税收的拖欠,施舍鳏夫,救济困乏,赦免罪人。动员全部军队,楚王的警卫军也全部出动。彭名驾御战车,蔡景公作为车左,许灵公作为车右。两位国君还没有成年,都勉强行了冠礼。 +冬季,楚军入侵卫国,就乘机在蜀地进攻我国。派臧孙去到楚军中求和。臧孙辞谢说:“楚军远离本国为时很久,本来就要退兵了。没有功劳而接受荣誉,下臣不敢。”楚军进攻到达阳桥,孟孙请求前去送给楚军木工、缝工、织工各一百人,公衡作为人质,请求结盟。楚国人答应讲和。 +十一月,鲁成公和楚国公子婴齐、蔡景侯、许灵公、秦国右大夫说、宋国华元、陈国公孙宁、卫国孙良夫、郑国公子去疾和齐国大夫在蜀地结盟。《春秋》没有记载卿的名字,这是由于结盟缺乏诚意。在这种情况下又因为鲁国畏惧晋国而偷偷和楚国结盟,所以说“结盟缺乏诚意”。《春秋》没有记载蔡景侯、许灵公,这是由于他们乘坐了楚国的战车,叫做失去了身份。君子说:“身份是不可以不慎重的啊!蔡、许两国国君,一旦失去身份,就不能列在诸侯之中,何况在他们之下的人呢!《诗》说:‘在高位的人不懈怠,百姓就能得到休息。’说的就是这种情况了。” +楚军到达宋国,公衡逃了回来。臧孙说:“衡父不能忍耐几年的不安宁,抛弃鲁国,国家将怎么办?谁来受祸?他的后代一定会有受到祸患的!国家被抛弃了” +在这次军事行动中,晋军避开楚军,由于害怕他们人数过多。君子说:“大众是不可以不用的。大夫当政,尚且可以利用大众来战胜敌人,何况是贤明的国君而且又能善于使用大众呢?《大誓》所说商朝亿万人离心离德,周朝十个人同心同德,都是说的大众啊。” +晋景公派遣巩朔到成周进献战胜齐国的战利品,周定王不接见,派遣单襄公辞谢,说:“蛮夷戎狄,不遵奉天子的命令,迷恋酒色,败坏了天子的制度,天子命令讨伐他,就有了进献战利品的礼仪。天子亲自接受而加以慰劳,用这来惩罚不敬,勉励有功。如果是兄弟甥舅的国家侵犯败坏天子的法度,天子命令讨伐他,只向天子报告一下情况罢了,不用进献俘虏,用这来尊敬亲近、禁止邪恶。现在叔父能够顺利成功,在齐国建立了功勋,而不派遣曾受天子任命的卿来安抚王室,所派遣来安抚我的使者,仅仅是巩伯,他在王室中没有担任职务,又违反了先王的礼制。我虽然喜爱巩伯,岂敢废弃旧的典章制度以羞辱叔父?齐国和周室是甥舅之国,而且是姜太公的后代,叔父攻打齐国,难道是齐国放纵了私欲以激怒了叔父?或是齐国已经不可谏诤和教诲了呢?”巩朔不能回答。周定王把接待的事情交给三公,让他们用侯、伯战胜敌人派大夫告捷的礼节接待巩朔,比接待卿的礼节低一等。周定王和巩伯饮宴,私下送给他财礼,让相礼者告诉他说:“这是不合于礼制的,不要记载在史册上。” + +成公三年 +【经】三年春王正月,公会晋侯、宋公、卫侯、曹伯伐郑。辛亥,葬卫穆公。二月,公至自伐郑。甲子,新宫灾。三日哭。乙亥,葬宋文公。夏,公如晋。郑公子去疾帅师伐许。公至自晋。秋,叔孙侨如帅师围棘。大雩。晋郤克、卫孙良夫伐啬咎如。冬十有一月,晋侯使荀庚来聘。卫侯使孙良夫来聘。丙午,及荀庚盟。丁未,及孙良夫盟。郑伐许。 +【传】三年春,诸侯伐郑,次于伯牛,讨邲之役也,遂东侵郑。郑公子偃帅师御之,使东鄙覆诸鄤,败诸丘舆。皇戌如楚献捷。 +夏,公如晋,拜汶阳之田。 +许恃楚而不事郑,郑子良伐许。 +晋人归公子谷臣与连尹襄老之尸于楚,以求知荦。于是荀首佐中军矣,故楚人许之。王送知荦,曰:“子其怨我乎?”对曰:“二国治戎,臣不才,不胜其任,以为俘馘。执事不以衅鼓,使归即戮,君之惠也。臣实不才,又谁敢怨?”王曰:“然则德我乎?”对曰:“二国图其社稷,而求纾其民,各惩其忿以相宥也,两释累囚以成其好。二国有好,臣不与及,其谁敢德?”王曰:“子归,何以报我?”对曰:“臣不任受怨,君亦不任受德,无怨无德,不知所报。”王曰:“虽然,必告不谷。”对曰:“以君之灵,累臣得归骨于晋,寡君之以为戮,死且不朽。若从君之惠而免之,以赐君之外臣首;首其请于寡君而以戮于宗,亦死且不朽。若不获命,而使嗣宗职,次及于事,而帅偏师以修封疆,虽遇执事,其弗敢违。其竭力致死,无有二心,以尽臣礼,所以报也。”王曰:“晋未可与争。”重为之礼而归之。 +秋,叔孙侨如围棘,取汶阳之田。棘有服,故围之。 +晋郤克、卫孙良夫伐啬咎如,讨赤狄之馀焉。啬咎如溃,上失民也。 +冬十一月,晋侯使荀庚来聘,且寻盟。卫侯使孙良夫来聘,且寻盟。公问诸臧宣叔曰:“中行伯之于晋也,其位在三。孙子之于卫也,位为上卿,将谁先?”对曰:“次国之上卿当大国之中,中当其下,下当其上大夫。小国之上卿当大国之下卿,中当其上大夫,下当其下大夫。上下如是,古之制也。卫在晋,不得为次国。晋为盟主,其将先之。”丙午,盟晋,丁未,盟卫,礼也。 +十二月甲戌,晋作六军。韩厥、赵括、巩朔、韩穿、荀骓、赵旃皆为卿,赏鞍之功也。 +齐侯朝于晋,将授玉。郤克趋进曰:“此行也,君为妇人之笑辱也,寡君未之敢任。”晋侯享齐侯。齐侯视韩厥,韩厥曰:“君知厥也乎?”齐侯曰:“服改矣。”韩厥登,举爵曰:“臣之不敢爱死,为两君之在此堂也。” +荀荦之在楚也,郑贾人有将置诸褚中以出。既谋之,未行,而楚人归之。贾人如晋,荀荦善视之,如实出己,贾人曰:“吾无其功,敢有其实乎?吾小人,不可以厚诬君子。”遂适齐。 +译文 +三年春季,诸侯联军进攻郑国,联军驻扎在伯牛,这是讨伐邲地战役郑国对晋国有二心,于是就从东边入侵郑国。郑国的公子偃领兵抵御,命令东部边境地方部队在鄤地设下埋伏,把敌军在丘舆击败。皇戌到楚国进献战利品。 +夏季,鲁成公到晋国,拜谢晋国让齐国退还汶阳的土田。 +许国依仗楚国而不事奉郑国,郑国的子良进攻许国。 +晋国人把楚国公子穀臣和连尹襄老尸首归还给楚国,以此要求换回知罃。当时荀首已经是中军副帅,所以楚国人答应了。楚共王送别知罃,说:“您恐怕怨恨我吧!”知罃回答说:“两国交战,下臣没有才能,不能胜任所当职务,所以做了俘虏。君王的左右的人没有用我的血来祭鼓,而让我回国去接受杀戮,这是君王的恩惠啊。下臣实在没有才能,又敢怨恨谁?”楚共王说:“那么感激我吗?”知罃回答说:“两国为自己的国家打算,希望让百姓得到安宁,各自抑止自己的愤怒,求得互相原谅,两边都释放被俘的囚犯,以结成友好。两国友好,下臣不曾与谋,又敢感激谁?”楚共王说:“您回去,用什么报答我?”知罃回答说:“下臣既不怨恨,君王也不值得感恩,没有怨恨,没有恩德,就不知道该报答什么。”楚共王说:“尽管这样,也一定把您的想法告诉我。”知罃回答说:“承君王的福佑,被囚的下臣能够带着这把骨头回晋国,寡君如果加以诛戮,死得幸运。如果由于君王的恩惠而赦免下臣,把下臣赐给您的外臣荀首,荀首向我君请求,而把下臣杀戮在自己的宗庙中,也死得幸运。如果得不到寡君诛戮的命令,而让下臣继承宗子的地位,按次序承担晋国的大事,率领一部分军队以保卫边疆,虽然碰到君王的左右,我也不敢违背礼义回避,要竭尽全力以至于死,没有二心,以尽到为臣的职责,这就是所报答于君王的。”楚共王说:“晋国是不可以和它相争的。”于是就对知罃重加礼遇而放他回晋国去。 +秋季,叔孙侨如包围棘地,占取了汶阳的土田。由于棘地人不服从,所以包围了棘。 +晋国的郤克、卫国的孙良夫进攻廧咎如,讨伐赤狄的残余。廧咎如溃败,这是由于他们的上级失去了民心。 +冬季,十一月,晋景公派遣荀庚前来聘问,同时重温过去的盟约。卫定公派遣孙良夫前来聘问,并且重温过去的盟约。鲁成公向臧宣叔询问说:“中行伯在晋国,位次排列第三;孙子在卫国,位次是上卿,应该让谁在前?”臧宣叔回答说:“次国的上卿,相当于大国的中卿,中卿相当于它的下卿,下卿相当于它的上大夫。小国的上卿,相当于大国的下卿,中卿相当于它的上大夫,下卿相当于它的下大夫。位次的上下如此,这是古代的制度。卫国对晋国来说,不能算是次国。晋国是盟主,晋国应该先行礼。”二十八日,和晋国结盟。二十九日,和卫国结盟。这是合于礼的。 +十二月二十六日,晋国编成六个军。韩厥、赵括、巩朔、韩穿、荀骓、赵旃都做了卿,这是为了赏赐在鞌地战役中的功劳。 +齐顷公到晋国朝见,将要举行授玉的仪式。郤克快步走进来,说:“这一趟,君王是为女人的取笑而受到了羞辱,寡君不敢当。”晋景公设宴招待齐顷公。齐顷公注视着韩厥。韩厥说:“君王认识厥吗?”齐顷公说:“服装换了。”韩厥登阶,举起酒杯说:“下臣所以不惜一死,当时就是为了两位国君现在在这个堂上饮宴啊。” +荀罃在楚国的时侯,郑国的商人准备把他藏在袋子里逃出楚国。已经商量好,还没有动身,楚国人就把他送回来了。这个商人到晋国,荀罃待他很好,好像确实救了自己一样。商人说:“我没有那样的功劳,敢有这样的实惠吗?我是小人,不能够这样来欺骗君子。”商人于是就到齐国去了。 + + +成公四年 +【经】四年春,宋公使华元来聘。三月壬申,郑伯坚卒。杞伯来朝。夏四月甲寅,臧孙许卒。公如晋。葬郑襄公。秋,公至自晋。冬,城郓。郑伯伐许。 +【传】四年春,宋华元来聘,通嗣君也。 +杞伯来朝,归叔姬故也。 +夏,公如晋,晋侯见公,不敬。季文子曰:“晋侯必不免。《诗》曰:‘敬之敬之!天惟显思,命不易哉!’夫晋侯之命在诸侯矣,可不敬乎?” +秋,公至自晋,欲求成于楚而叛晋,季文子曰:“不可。晋虽无道,未可叛也。国大臣睦,而迩于我,诸侯听焉,未可以贰。史佚之《志》有之,曰:‘非我族类,其心必异。’楚虽大,非吾族也,其肯字我乎?”公乃止。 +冬十一月,郑公孙申帅师疆许田,许人败诸展陂。郑伯伐许,鉏任、泠敦之田。 +晋栾书将中军,荀首佐之,士燮佐上军,以救许伐郑,取汜、祭。楚子反救郑,郑伯与许男讼焉。皇戌摄郑伯之辞,子反不能决也,曰:“君若辱在寡君,寡君与其二三臣共听两君之所欲,成其可知也。不然,侧不足以知二国之成。” +晋赵婴通于赵庄姬。 +译文 +四年春季,宋国的华元前来聘问,这是为继位的国君通好。 +杞桓公来鲁国朝见,这是由于要将叔姬送回鲁国。 +夏季,鲁成公去到晋国。晋景公会见成公,不恭敬。季文子说:“晋景公一定不免于祸难。《诗》说:‘谨慎又谨慎,上天光明普照,得到天命不容易啊!’晋景公的命运决定于诸侯,可以不恭敬吗?” +秋季,成公从晋国到达鲁国,想要向楚国要求友好而背叛晋国。季文子说:“不行。晋国虽然无道,尚不能背叛。国家广大、群臣和睦,而且靠近我国,诸侯听他的命令,不能有二心。史佚的《志》有这样的话:‘不是我们同族,他的心思必然不同。’楚国虽然土地广大,不是我们同族,难道肯爱我们吗?”成公就没有那样做。 +冬季,十一月,郑国的公孙申带兵去划定所得许国土田的疆界。许国人在展陂打败了他们。郑伯进攻许国,占领了鉏任、冷敦的土田。 +晋将栾书率领中军,荀首作为副帅,士燮为上军副帅,救援许国,进攻郑国,占领了汜地、祭地。 +楚国的子反救援郑国,郑襄公和许灵公在子反那里争论是非,皇戌代表郑襄公发言。子反不能判断,说:“您二位如果屈驾去问候寡君,寡君和他几个臣子共同听取两位君王的意见才可以判断出是非。否则,侧不大了解两国之间的是非。” +晋国的赵婴和赵庄姬私通。 + + +成公五年 +【经】五年春王正月,杞叔姬来归。仲孙蔑如宋。夏,叔孙侨如会晋荀首于谷。梁山崩。秋,大水。冬十有一月己酉,天王崩。十有二月己丑,公会晋侯、齐侯、宋公、卫侯、郑伯、曹伯、邾子、杞伯同盟于虫牢。 +【传】五年春,原、屏放诸齐。婴曰:“我在,故栾氏不作。我亡,吾二昆其忧哉!且人各有能有不能,舍我何害?”弗听。婴梦天使谓己:“祭余,余福女。”使问诸士贞伯,贞伯曰:“不识也。”既而告其人曰:“神福仁而祸淫,淫而无罚,福也。祭,其得亡乎?”祭之,之明日而亡。、孟献子如宋,报华元也。 +孟献子如宋,报华元也。 +夏,晋荀首如齐逆女,故宣伯餫诸谷。 +梁山崩,晋侯以传召伯宗。伯宗辟重,曰:“辟传!”重人曰:“待我,不如捷之速也。”问其所,曰:“绛人也。”问绛事焉,曰:“梁山崩,将召伯宗谋之。”问:“将若之何?”曰:“山有朽壤而崩,可若何?国主山川。故山崩川竭,君为之不举,降服,乘缦,彻乐,出次,祝币,史辞以礼焉。其如此而已,虽伯宗若之何?”伯宗请见之,不可。遂以告而从之。 +许灵公愬郑伯于楚。六月,郑悼公如楚,讼,不胜。楚人执皇戌及子国。故郑伯归,使公子偃请成于晋。秋八月,郑伯及晋赵同盟于垂棘。 +宋公子围龟为质于楚而还,华元享之。请鼓噪以出,鼓噪以复入,曰:“习功华氏。”宋公杀之。 +冬,同盟于虫牢,郑服也。诸侯谋复会,宋公使向为人辞以子灵之难。 +十一月己酉,定王崩。 +译文 +五年春季,赵同、赵括把赵婴放逐到齐国。赵婴说:“有我在,所以栾氏不敢作乱。我逃亡,两位兄长恐怕就有忧患了。而且人们各有所能,也有所不能,赦免我又有什么坏处?”赵同、赵括不听。赵婴梦见天使对自己说:“祭祀我,我降福给你。”派人向士贞伯询问。士贞伯说:“不知道。”不久士贞伯就告诉别人说:“神灵降福给仁爱的人,而降祸给淫乱的人。淫乱而没有受到惩罚,这就是福了。祭祀了,难道无祸?”赵婴祭祀了神灵,第二天就逃亡了。 +孟献子到了宋国,这是回报华元的聘问。 +夏季,晋国的荀首去到齐国迎接齐女,所以宣伯在穀地给他馈送食物。 +梁山崩塌,晋景公用传车召见伯宗。伯宗在路上叫一辆载重车避开,说:“为传车让路。”押送重车的人说:“与其等我,不如走小路要快一些。”伯宗问他是哪里人,押车人说:“绛城人。”伯宗问起绛城的事情。押车人说:“梁山崩塌,打算召见伯宗商量。”伯宗问:“准备怎么办?”押车人说:“山有了腐朽的土壤而崩塌。又能怎么办?国家以山川为主,所以遇到山崩川竭,国君就要为它减膳撤乐、穿素服、乘坐没有彩画的车子、不奏音乐、离开寝宫、陈列献神的礼物。太史宣读祭文,以礼祭祀山川之神。就是这样罢了,即使是伯宗,还能怎么样?”伯宗要求带押车人去见晋景公,他不答应。于是伯宗就把押车人的话告诉了晋景公,晋景公听从了。 +许灵公在楚国控告郑悼公。六月,郑悼公去到楚国争讼,没有取得胜利,楚国人抓住了皇戌和子国。所以郑悼公回国以后,派遣公子偃到晋国要求讲和。秋季,八月,郑悼公和晋国的赵同在垂棘结盟。 +宋国的公子围龟在楚国当人质以后回到宋国,华元设享礼招待他。围龟请求打鼓呼叫而出华元的大门,又打鼓呼叫而进去,说:“这就是演习进攻华氏。”宋共公把他杀了。 +冬季,鲁成公和晋景公、齐顷公、宋共公、卫定公、郑悼公、曹宣公、邾子、杞桓公在虫牢结盟,这是由于郑国顺服。 +诸侯商量再次会见,宋共公派向为人以子灵事件为理由而辞谢了,不参加会见。 +十一月十二日,周定王逝世。 + +成公六年 +【经】六年春王正月,公至自会。二月辛巳,立武宫。取鄟卫孙良夫帅师侵宋。夏六月,邾子来朝。公孙婴齐如晋。壬申,郑伯费卒。秋,仲孙蔑、叔孙侨如帅师侵宋。楚公子婴齐帅师伐郑。冬,季孙行父如晋。晋栾书帅师救郑。 +【传】六年春,郑伯如晋拜成,子游相,授玉于东楹之东。士贞伯曰:“郑伯其死乎?自弃也已!视流而行速,不安其位,宜不能久。” +二月,季文子以鞍之功立武宫,非礼也。听于人以救其难,不可以立武。立武由己,非由人也。 +取鄟,言易也。 +三月,晋伯宗、夏阳说,卫孙良夫、宁相,郑人,伊、洛之戎,陆浑,蛮氏侵宋,以其辞会也。师于金咸,卫人不保。说欲袭卫,曰:“虽不可入,多俘而归,有罪不及死。”伯宗曰:“不可。卫唯信晋,故师在其郊而不设备。若袭之,是弃信也。虽多卫俘,而晋无信,何以求诸侯?”乃止,师还,卫人登陴。 +晋人谋去故绛。诸大夫皆曰:“必居郇瑕氏之地,沃饶而近盬,国利君乐,不可失也。”韩献子将新中军,且为仆大夫。公揖而入。献子从。公立于寝庭,谓献子曰:“何如?”对曰:“不可。郇瑕氏土薄水浅,其恶易觏。易觏则民愁,民愁则垫隘,于是乎有沉溺重膇之疾。不如新田,土厚水深,居之不疾,有汾、浍以流其恶,且民从教,十世之利也。夫山、泽、林、盬,国之宝也。国饶,则民骄佚。近宝,公室乃贫,不可谓乐。”公说,从之。夏四月丁丑,晋迁于新田。 +六月,郑悼公卒。 +子叔声伯如晋。命伐宋。 +秋,孟献子、叔孙宣伯侵宋,晋命也。 +楚子重伐郑,郑从晋故也。 +冬,季文子如晋,贺迁也。 +晋栾书救郑,与楚师遇于绕角。楚师还,晋师遂侵蔡。楚公子申、公子成以申、息之师救蔡,御诸桑隧。赵同、赵括欲战,请于武子,武子将许之。知庄子、范文子、韩献子谏曰:“不可。吾来救郑,楚师去我,吾遂至于此,是迁戮也。戮而不已,又怒楚师,战必不克。虽克,不令。成师以出,而败楚之二县,何荣之有焉?若不能败,为辱已甚,不如还也。”乃遂还。 +于是,军帅之欲战者众,或谓栾武子曰:“圣人与众同欲,是以济事。子盍从众?子为大政,将酌于民者也。子之佐十一人,其不欲战者,三人而已。欲战者可谓众矣。《商书》曰:‘三人占,从二人。’众故也。”武子曰:“善钧,从众。夫善,众之主也。三卿为主,可谓众矣。从之,不亦可乎?” +译文 +六年春季,郑悼公到晋国去拜谢讲和,子游辅助行礼,在东楹的东边举行授玉的仪式。士贞伯说:“郑悼公恐怕要死了!自己不尊重自己。目光流动东张西望而走路又快,很不安地坐在自己的位子上,大概不能活多久了。” +二月,鲁大夫季文子由于鞌地战役的武功建立了武宫,这是不合于礼的。听从别人的话来解救鲁国的灾难,不能标榜武功。建立武功应该在于自己,而不是由于别人的功劳。 +占领鄟地,《春秋》记载说事情完成得很容易。 +三月,晋国伯宗、夏阳说、卫国孙良夫、宁相、郑人、伊洛戎人、陆浑、蛮氏入侵宋国,这是由于宋国拒绝参加盟会。军队驻扎在鍼地。卫国人不加防守。夏阳说要袭击卫国,说:“虽然不能进入,多抓一些俘虏回去,有罪也不至于死。”伯宗说:“不行。卫国因为相信晋国,所以军队驻扎在他们郊外而不加防守,如果袭击他们,这是丢弃信用。虽然多抓了卫国俘虏,而晋国没有信义,用什么去获得诸侯的拥戴?”于是就停止了行动。军队回国,卫国人却登上了城墙。 +晋国人计划离开故都绛城,大夫们都说:“一定要住在郇瑕氏的地方,那里肥沃富饶而靠近盐池,国家有利,国君欢乐,不可以失掉它。”韩献子正率领新中军,同时掌管宫中的事。晋景公朝罢向群臣作揖而后退入路门,韩献子跟着。晋景公站在正寝外边的庭院里,对韩献子说:“怎么样?”韩献子回答说:“不行。郇瑕氏土薄水浅,污秽肮脏的东西容易积聚。污秽的东西容易积聚,百姓就发愁,百姓发愁,身体就瘦弱,在这种情况下就会有风湿脚肿的疾病,不如新田,土厚水深,住在那里不生疾病,有汾水、浍水以冲走污秽,而且百姓习惯服从,这是子孙十代的利益。深山、大泽、森林、盐池,是国家的宝藏,国家富饶,百姓就骄傲放荡。靠近宝藏,大家争利,国家财富就少。不能说是欢乐。”晋景公很高兴,听从了他的话。夏季,四月十三日,晋国迁都到新田。 +六月,郑悼公去世。 +子叔声伯去到晋国,晋国命令鲁国进攻宋国。 +秋季,孟献子、叔孙宣伯率兵入侵宋国,奉了晋国的命令。楚国的子重进攻郑国,这是由于郑国跟随晋国的缘故。 +冬季,季文子去到晋国,为了祝贺晋国迁都。 +晋国栾书救援郑国,和楚军在绕角相遇。楚军回国,晋军就侵袭蔡国。楚国公子申、公子成带领申地、息地的军队去救援蔡国,在桑隧抵抗晋军。赵同、赵括想要出战,向栾武子请求,栾武子打算答应。知庄子、范文子、韩献子劝谏说:“不行。我们来救援郑国,楚军离开我们,我们就到了这里,这是把杀戮转移到别人头上。杀戮而不停止,又激怒楚军,战争一定不能得胜。即便战胜,也不是好事。整顿军队出国,仅仅打败楚国两个县的军队,有什么光荣呢?如果不打败他们,受到的耻辱就太过分了。不如回去。”于是晋军就回去了。 +当时军官中要作战的很多,有人对栾武子说:“圣人的愿望和大众相同,所以能成功。您何不听从大家的意见?您是执政大臣,应当斟酌百姓的意见。您的辅佐者十一个人,不想作战的仅仅三个人。想要作战的人可以说是大多数。《商书》说:‘三个人占卜,听从两个人的。’因为是多数的缘故。”栾武子说:“同样是好事,才服从多数,好事是大众的主张。现在有三位大臣主张,可以说是大众了。依从他们,不也是可以的吗?” + +成公七年 +【经】七年春王正月,鼷鼠食郊牛角,改卜牛。鼷鼠又食其角,乃免牛。吴伐郯。夏五月,曹伯来朝。不郊,犹三望。秋,楚公子婴齐帅师伐郑。公会晋侯、齐侯、宋公、卫侯、曹伯、莒子、邾子、杞伯救郑。八月戊辰,同盟于马陵。公至自会。吴入州来。冬,大雩。卫孙林父出奔晋。 +【传】七年春,吴伐郯,郯成。季文子曰:“中国不振旅,蛮夷入伐,而莫之或恤,无吊者也夫!《诗》曰:‘不吊昊天,乱靡有定。’其此之谓乎!有上不吊,其谁不受乱?吾亡无日矣!”君子曰:“如惧如是,斯不亡矣。” +郑子良相成公以如晋,见,且拜师。 +夏,曹宣公来朝。 +秋,楚子重伐郑,师于汜。诸侯救郑。郑共仲、侯羽军楚师,囚郧公钟仪,献诸晋。 +八月,同盟于马陵,寻虫牢之盟,且莒服故也。 +晋人以钟仪归,囚诸军府。 +楚围宋之役,师还,子重请取于申、吕以为赏田,王许之。申公巫臣曰:“不可。此申、吕所以邑也,是以为赋,以御北方。若取之,是无申、吕也。晋、郑必至于汉。”王乃止。子重是以怨巫臣。子反欲取夏姬,巫臣止之,遂取以行,子反亦怨之。及共王即位,子重、子反杀巫臣之族子阎、子荡及清尹弗忌及襄老之子黑要,而分其室。子重取子阎之室,使沈尹与王子罢分子荡之室,子反取黑要与清尹之室。巫臣自晋遗二子书,曰:“尔以谗慝贪婪事君,而多杀不辜。余必使尔罢于奔命以死。” +巫臣请使于吴,晋侯许之。吴子寿梦说之。乃通吴于晋。以两之一卒适吴,舍偏两之一焉。与其射御,教吴乘车,教之战陈,教之叛楚。置其子狐庸焉,使为行人于吴。吴始伐楚,伐巢、伐徐。子重奔命。马陵之会,吴入州来。子重自郑奔命。子重、子反于是乎一岁七奔命。蛮夷属于楚者,吴尽取之,是以始大,通吴于上国。 +卫定公恶孙林父。冬,孙林父出奔晋。卫侯如晋,晋反戚焉。 +译文 +七年春季,吴国进攻郯国,郯国和吴国讲和。季文子说:“中原诸国不能镇慑蛮夷,蛮夷却来进攻,而没有人对此担忧,这是因为没有好国君的缘故啊!《诗》说:‘上天不善,动乱没有个安定的时候。’说的就是这种情况吧!有了上面的人但是不善,还有谁不受到动乱?我们很快就会灭亡了。”君子说:“像这样知道戒惧,这就不会灭亡了。” +郑国的子良作为郑成公的相礼到了晋国,进见晋景公,同时拜谢出兵救郑。 +夏季,曹宣公前来朝见。 +秋季,楚国的子重进攻郑国,军队驻扎在汜地。诸侯救援郑国。郑国的共仲、侯羽包围楚军,囚禁郧公钟仪,把他献给晋国。 +八月,鲁成公和晋景公、齐顷公、宋共公、卫定公、曹宣公、莒子、邾子、杞桓公在马陵结盟,这是由于重温虫牢的盟约,同时又因莒国顺服的缘故。 +晋国人带着钟仪回去,把他囚禁在军用储藏室里。 +楚国包围宋国那一次战役,楚军回国,子重请求取得申邑、吕邑土地作为赏田。楚共王答应了。申公巫臣说:“不行。申、吕两地之所赖以成为城邑的,是因为从这里征发兵赋,以抵御北方。如果私人占有它,这就不能成为申邑和吕邑了。晋国和郑国一定可以到达汉水。”楚庄王就不给了。子重因此怨恨巫臣。子反想娶夏姬。巫臣阻止他,自己反而娶了夏姬逃到晋国,子反因此也很怨恨巫臣。等到楚共王即位,子重,子反杀了巫臣的族人子阎、子荡和清尹弗忌以及襄老的儿子黑要,并且瓜分他们的家产。子重取得了子阎的家产,让沈尹和王子罢瓜分子荡的家产,子反取得黑要和清尹弗忌的家产。巫臣从晋国写信给子反、子重两个人,说:“你们用邪恶贪婪事奉国君,杀了很多无罪的人,我一定要让你们疲于奔命而死。” +巫臣请求出使到吴国去,晋景公允许了。吴子寿梦喜欢他。于是巫臣就使吴国和晋国通好,带领了楚国的三十辆兵车到吴国做教练,留下十五辆给吴国。送给吴国射手和御者,教吴国人使用兵车,教他们安排战阵,教他们背叛楚国。巫臣又把自己的儿子狐庸留在那里,让他在吴国做外交官。吴国开始进攻楚国、进攻巢国、进攻徐国,子重奉命奔驰。在马陵会见的时候,吴军进入州来,子重从郑国奉命赶去救援。子重、子反在这种情况下,一年之中七次奉命奔驰以抵御吴军。蛮夷属于楚国的,吴国全部加以占取,因此吴国开始强大,吴国才得以和中原诸国往来。 +卫定公讨厌孙林父。冬季,孙林父逃亡到晋国。卫定公去到晋国,晋国把孙林父的封邑戚地归还给了卫国。 + + +成公八年 +【经】八年春,晋侯使韩穿来言汶阳之田,归之于齐。晋栾书帅师侵蔡。公孙婴齐如莒。宋公使华元来聘。夏,宋公使公孙寿来纳币。晋杀其大夫赵同、赵括。秋七月,天子使召伯来赐公命。冬十月癸卯,杞叔姬卒。晋侯使士燮来聘。叔孙侨如会晋士燮、齐人、邾人代郯。卫人来媵。 +【传】八年春,晋侯使韩穿来言汶阳之田,归之于齐。季文子饯之,私焉,曰:“大国制义以为盟主,是以诸侯怀德畏讨,无有贰心。谓汶阳之田,敝邑之旧也,而用师于齐,使归诸敝邑。今有二命曰:‘归诸齐。’信以行义,义以成命,小国所望而怀也。信不可知,义无所立,四方诸侯,其谁不解体?《诗》曰:‘女也不爽,士贰其行。士也罔极,二三其德。’七年之中,一与一夺,二三孰甚焉!士之二三,犹丧妃耦,而况霸主?霸主将德是以,而二三之,其何以长有诸侯乎?《诗》曰:‘犹之未远,是用大简。’行父惧晋之不远犹而失诸侯也,是以敢私言之。” +晋栾书侵蔡,遂侵楚获申骊。楚师之还也,晋侵沈,获沈子揖初,从知、范、韩也。君子曰:“从善如流,宜哉!《诗》曰:‘恺悌君子,遐不作人。’求善也夫!作人,斯有功绩矣。”是行也,郑伯将会晋师,门于许东门,大获焉。 +声伯如莒,逆也。 +宋华元来聘,聘共姬也。 +夏,宋公使公孙寿来纳币,礼也。 +晋赵庄姬为赵婴之亡故,谮之于晋侯,曰:“原、屏将为乱。”栾、郤为征。六月,晋讨赵同、赵括。武从姬氏畜于公宫。以其田与祁奚。韩厥言于晋侯曰:“成季之勋,宣孟之忠,而无后,为善者其惧矣。三代之令王,皆数百年保天之禄。夫岂无辟王,赖前哲以免也。《周书》曰:‘不敢侮鳏寡。’所以明德也。”乃立武,而反其田焉。 +秋,召桓公来赐公命。 +晋侯使申公巫臣如吴,假道于莒。与渠丘公立于池上,曰:“城已恶!”莒子曰:“辟陋在夷,其孰以我为虞?”对曰:“夫狡焉思启封疆以利社稷者,何国蔑有?唯然,故多大国矣,唯或思或纵也。勇夫重闭,况国乎?” +冬,杞叔姬卒。来归自杞,故书。 +晋士燮来聘,言伐郯也,以其事吴故。公赂之,请缓师,文子不可,曰:“君命无贰,失信不立。礼无加货,事无二成。君后诸侯,是寡君不得事君也。燮将复之。”季孙惧,使宣伯帅师会伐郯。 +卫人来媵共姬,礼也。凡诸侯嫁女,同姓媵之,异姓则否。 +译文 +八年春季,晋景公派遣韩穿来鲁国谈到关于汶阳土田的事,要把汶阳之田归还给齐国。季文子设酒给他饯行,和他私下交谈,说:“大国处理事务合理适宜,凭这个作为盟主,因此诸侯怀念德行而害怕讨伐,没有二心。说到汶阳的土田,那原是敝邑所有,后来对齐国用兵,晋国命令齐国把它还给敝邑。现在又有不同的命令,说‘归还给齐国’。信用用来推行道义,道义用来完成命令,这是小国所盼望而怀念的。信用不能得知,道义无所树立,四方的诸侯,谁能不涣散瓦解?《诗》说:‘女子毫无过失,男人却有过错。男人没有标准,他的行为前后不一。’七年当中,忽而给予忽而夺走,前后不一还有比这更甚的吗?一个男人前后不一,尚且丧失配偶,何况是霸主?霸主应该用德,但却前后不一,他怎么能长久得到诸侯的拥护呢?《诗》说:‘谋略缺乏远见,因此极力劝谏。’行父害怕晋国不能深谋远虑而失去诸侯,因此敢于和您作私下的交谈。” +晋国栾书率军侵袭蔡国,接着又侵袭楚国,俘虏了申骊。楚军回去的时候,晋军侵袭沈国,俘虏了沈子揖初,这是听从了知庄子、范文子、韩献子等人的意见。君子说:“听从好主意好像流水一样,这是多么恰当啊!《诗》说:‘恭敬随和的君子,为什么不起用人材?’这就是求取善人啊!起用人材,这就有功绩了。” 这次行动,郑成公准备会合晋军,经过许国,攻打许国的东门,俘获很多。 +声伯去到莒国,这是去迎接妻子。 +宋国华元来鲁国聘问,为宋共公聘共姬为夫人。 +夏季,宋共公派公孙寿前来代宋共公订婚,这是合于礼的。 +晋国的赵庄姬为了赵婴逃亡的缘故,向晋景公诬陷说:“原(赵同)、屏(赵括)将要作乱。栾氏、郤氏可作证。”六月,晋国讨伐赵同、赵括。赵武跟随庄姬寄住在晋景公宫里。晋景公把赵氏的土田赐给祁奚。韩厥对晋景公说:“成季的功勋,宣孟的忠诚,但他们却没有后代来继承,做好事的人就要害怕了。三代的贤明君王,都能够几百年保持上天的禄位。难道就没有邪恶的君王?这是靠着他祖先的贤明才得以免于亡国。《周书》说:‘不敢欺侮鳏夫寡妇’,就是用这样的做法来发扬道德。”于是就立赵武为赵氏的继承人,归还了赵氏的土田。 +秋季,周卿士召桓公前来向鲁成公颁赐袭爵的命令。 +晋景公派遣申公巫臣去吴国,向莒国借路。巫臣和渠丘公站在护城河上,说:“城太坏了。”渠丘公说:“敝国偏僻简陋,处在蛮夷之地,有谁会把敝国作为觊觎的目的呢?”巫臣说:“狡猾的人想开辟疆土以利国家的,哪个国家没有?惟其如此,所以大国就多了。不过受觊觎的小国有的思虑有备,也有的放纵不备。勇敢的人还要层层关闭好内外门户,何况国家?” +冬季,杞国的叔姬死了。由于她从杞国被休了回到鲁国来,所以《春秋》加以记载。 +晋国的士燮来鲁国聘问,声称要进攻郯国,因为郯国奉事吴国的缘故。鲁成公送给他财礼,请求从缓进兵。士燮不答应,说:“国君的命令说一不二,失去信义难以自立。除规定的礼物外,不应该增加财币,公事私事不能两全其美。君王后于诸侯出兵,这样寡君就不能事奉君王了。燮打算就这样向寡君回报。”季孙听了这话很害怕,派宣伯率兵会合进攻郯国。 +卫国人送女子前来鲁国作为共姬的陪嫁,这是合于礼的。凡是诸侯女儿出嫁,同姓的国家送女作为陪嫁,异姓就不送。 + +成公九年 +【经】九年春王正月,杞伯来逆叔姬之丧以归。公会晋侯、齐侯、宋公、卫侯、郑伯、曹伯、莒子、杞伯,同盟于蒲。公至自会。二月伯姬归于宋。夏,季孙行父如宋致女。晋人来媵。秋七月丙子,齐侯无野卒。晋人执郑伯。晋栾书帅师伐郑。冬十有一月,葬齐顷公。楚公子婴齐帅师伐莒。庚申,莒溃。楚人入郓。秦人、白狄伐晋。郑人围许。城中城。 +【传】九年春,杞桓公来逆叔姬之丧,请之也。杞叔姬卒,为杞故也。逆叔姬,为我也。 +为归汶阳之田故,诸侯贰于晋。晋人惧,会于蒲,以寻马陵之盟。季文子谓范文子曰:“德则不竞,寻盟何为?”范文子曰:“勤以抚之,宽以待之,坚强以御之,明神以要之,柔服而伐贰,德之次也。”是行也,将始会吴,吴人不至。 +二月,伯姬归于宋。 +楚人以重赂求郑,郑伯会楚公子成于邓。 +夏,季文子如宋致女,覆命,公享之。赋《韩奕》之五章,穆姜出于房,再拜,曰:“大夫勤辱,不忘先君以及嗣君,施及未亡人。先君犹有望也!敢拜大夫之重勤。”又赋《绿衣》之卒章而入。 +晋人来媵,礼也。 +秋,郑伯如晋。晋人讨其贰于楚也,执诸铜鞮。 +栾书伐郑,郑人使伯蠲行成,晋人杀之,非礼也。兵交,使在其间可也。楚子重侵陈以救郑。 +晋侯观于军府,见钟仪,问之曰:“南冠而絷者,谁也?”有司对曰:“郑人所献楚囚也。”使税之,召而吊之。再拜稽首。问其族,对曰:“泠人也。”公曰:“能乐乎?”对曰:“先父之职官也,敢有二事?”使与之琴,操南音。公曰:“君王何如?”对曰:“非小人之所得知也。”固问之,对曰:“其为大子也,师保奉之,以朝于婴齐而夕于侧也。不知其他。”公语范文子,文子曰:“楚囚,君子也。言称先职,不背本也。乐操土风,不忘旧也。称大子,抑无私也。名其二卿,尊君也。不背本,仁也。不忘旧,信也。无私,忠也。尊君。敏也。仁以接事,信以守之,忠以成之,敏以行之。事虽大,必济。君盍归之,使合晋、楚之成。”公从之,重为之礼,使归求成。 +冬十一月,楚子重自陈伐莒,围渠丘。渠丘城恶,众溃,奔莒。戊申,楚入渠丘。莒人囚楚公子平,楚人曰:“勿杀!吾归而俘。”莒人杀之。楚师围莒。莒城亦恶,庚申,莒溃。楚遂入郓,莒无备故也。 +君子曰:“恃陋而不备,罪之大者也;备豫不虞,善之大者也。莒恃其陋,而不修城郭,浃辰之间,而楚克其三都,无备也夫!《诗》曰:‘虽有丝、麻,无弃菅、蒯;虽有姬、姜,无弃蕉萃。凡百君子,莫不代匮。’言备之不可以已也。” +秦人、白狄伐晋,诸侯贰故也。 +郑人围许,示晋不急君也。是则公孙申谋之,曰:“我出师以围许,为将改立君者,而纾晋使,晋必归君。” +城中城,书,时也。 +十二月,楚子使公子辰如晋,报钟仪之使,请修好结成。 +译文 +九年春季,杞桓公来鲁国迎接叔姬的灵柩,这是由于鲁国的请求。杞叔姬的死,是由于被杞国遗弃的缘故。迎接叔姬的灵柩,是为了我国的颜面。 +由于晋国让鲁国把汶阳的土田归还给齐国的缘故,诸侯对晋国有了二心。晋国人畏惧,在蒲地和诸侯会见,重温马陵的盟会。鲁大夫季文子对晋大夫范文子说:“晋国德行已经不强,重温旧盟做什么?”范文子说:“用勤勉来安抚诸侯,用宽厚来对待诸侯,用坚强来驾御诸侯,用盟誓来约束诸侯,笼络顺服的而讨伐有二心的,这也是次等的德行了。”晋国召集的这一次会议,是首次邀请吴国,吴国人没有来。 +二月,伯姬出嫁到宋国。 +楚国人用很重的礼物求取郑国,郑成公和楚国公子成在邓地相会。 +夏季,季文子去到宋国慰问伯姬,回国复命,鲁成公设宴招待他。季文子赋《韩弈》的第五章。穆姜从房里出来,两次下拜,说:“大夫辛勤,不忘记先君以及于嗣君,延及于未亡人,先君也是这样来期望您的。谨拜谢大夫加倍的辛勤。”穆姜又赋《绿衣》的最后一章然后才进去。 +晋国人来鲁国送女陪嫁,这是合于礼的。 +秋季,郑成公去到晋国,晋国人为了惩罚他倾向楚国,在铜鞮逮住了他。 +晋将栾书率兵进攻郑国,郑国人派遣伯蠲求和,晋国人杀死了伯蠲,这是不合于礼的。两国交兵,使者可以来往两国之间。 +楚国的子重入侵陈国以救郑国。 +晋景公视察军用仓库,见到钟仪,问人说:“戴着南方的帽子而被囚禁的人是谁?”官吏回答说:“是郑国人所献的楚国俘虏。”晋景公让人把他释放出来,召见并且慰问他。钟仪再拜,叩头。晋景公问他在楚国的族人,他回答说:“是乐人。”晋景公说:“能够奏乐吗?”钟仪回答说:“这是先人的职责,岂敢从事于其他工作呢?”晋景公命令把琴给钟仪,他弹奏的是南方乐调。晋景公说:“你们的君王怎样?”钟仪回答说:“这不是小人能知道的。”晋景公再三问他,他回答说:“当他做太子的时候,师保奉事着他,每天早晨向婴齐请教,晚上向侧去请教。我不知道别的事。”晋景公把这些告诉了范文子。文子说:“这个楚囚,是君子啊。说话中举出先人的职官,这是不忘记根本;奏乐奏家乡的乐调,这是不忘记故旧;举出楚君做太子时候的事,这是没有私心;称二卿的名字,这是尊崇君王。不背弃根本,这是仁;不忘记故旧,这是守信;没有私心,这是忠诚;尊崇君王,这是敏达。用仁来办理事情,用信来守护,用忠来成就,用敏来执行。事情虽然大,必然会成功。君王何不放他回去,让他结成晋、楚的友好。”晋景公听从了,对钟仪重加礼遇,让他回国去替晋国求和。 +冬季,十一月,楚国子重从陈国进攻莒国,包围了渠丘。渠丘城池破败,大众溃散而逃亡到莒城。初五日,楚国进入渠丘。莒国人抓住了楚国的公子平。楚国人说:“不要杀他,我们归还你们俘虏。”莒国人杀了公子平,楚国的军队包围了莒城。莒城的城墙也不好,十七日,莒国溃败。楚军就进入郓城,这是由于莒国没有防备的缘故。 +君子说:“依仗简陋而不设防备,这是罪中的大罪;防备意外,这是善中的大善。莒国依仗它的简陋而不修城郭,十二天之间而楚军攻克它的三个城市,这是由于没有防备的缘故啊!《诗》说:‘虽然有了丝麻,不要丢掉杂草;虽然有了美人儿,不要丢掉不美的。凡是君子们,没有不缺此少彼的时候。’说的就是防备不能停止。” +秦军、白狄进攻晋国,由于诸侯对晋国有了二心的缘故。 +郑国人包围许国,这是为了向晋国表示他们并不急于救出郑成公。这是公孙申出的计谋,他说:“我们出兵包围许国,假装打算另立国君的样子,而暂时不派使者去晋国,晋国必然放我们国君回来。” +鲁国在内城筑城,《春秋》记载这件事,因为合于时令。 +十二月,楚共王派公子辰去晋国,以回报钟仪的使命,请求重温友好,缔结和约。 + +成公十年 +【经】十年春,卫侯之弟黑背帅师侵郑。夏四月,五卜郊,不从,乃不郊。五月,公会晋侯、齐侯、宋公、卫侯、曹伯伐郑。齐人来媵。丙午,晋侯獳卒。秋七月,公如晋。冬十月。 +【传】十年春,晋侯使籴伐如楚,报大宰子商之使也。 +卫子叔黑背侵郑,晋命也。 +郑公子班闻叔申之谋。三月,子如立公子繻。夏四月,郑人杀繻,立髡顽。子如奔许。栾武子曰:“郑人立君,我执一人焉,何益?不如伐郑而归其君,以求成焉。”晋侯有疾。五月,晋立大子州蒲以为君,而会诸侯伐郑。郑子罕赂以襄钟,子然盟于修泽,子驷为质。辛巳,郑伯归。 +晋侯梦大厉,被发及地,搏膺而踊,曰:“杀余孙,不义。余得请于帝矣!”坏大门及寝门而入。公惧,入于室。又坏户。公觉,召桑田巫。巫言如梦。公曰:“何如?”曰:“不食新矣。”公疾病,求医于秦。秦伯使医缓为之。未至,公梦疾为二竖子,曰:“彼,良医也。惧伤我,焉逃之?”其一曰:“居肓之上,膏之下,若我何?”医至,曰:“疾不可为也。在肓之上,膏之下,攻之不可,达之不及,药不至焉,不可为也。”公曰:“良医也。”厚为之礼而归之。六月丙午,晋侯欲麦,使甸人献麦,馈人为之。召桑田巫,示而杀之。将食,张,如厕,陷而卒。小臣有晨梦负公以登天,及日中,负晋侯出诸厕,遂以为殉。 +郑伯讨立君者,戊申,杀叔申、叔禽。君子曰:“忠为令德,非其人犹不可,况不令乎?” +秋,公如晋。晋人止公,使送葬。于是籴伐未反。 +冬,葬晋景公。公送葬,诸侯莫在。鲁人辱之,故不书,讳之也。 +译文 +十年春季,晋景公派遣籴茷去楚国,这是回报太宰子商的出使。 +卫国子叔黑背侵袭郑国,这是执行晋国的命令。 +郑国的公子班听到了叔申的策划。三月,公子班立公子繻为国君。夏季四月,郑国人杀了公子繻,立了髡顽,公子班逃亡到许国。栾武子说:“郑国人立了国君,我们抓的就是一个普通人,有什么好处?不如进攻郑国,把他们的国君送回国,以此求和。”晋景公有病,五月,晋国立太子州蒲为国君,会合诸侯进攻郑国。郑国的子罕把襄公宗庙中的钟赠送给晋国,子然和诸侯在脩泽结盟,子驷作为人质。十一日,郑成公回国。 +晋景公梦见一个厉鬼,披的长发拖到地上,捶胸跳跃,说:“你杀了我的子孙,这是不义。我请求为子孙复仇,已经得到上帝的允许了!”厉鬼毁掉宫门、寝门走了进来。晋景公害怕,躲进内室,厉鬼又毁掉内室的门。晋景公醒来,召见桑田的巫人。巫人所说的和晋景公梦见的情况一样。晋景公说:“怎么样?”巫人说:“君王吃不到新收的麦子了!”晋景公病重,到秦国请医生。秦桓公派医缓给晋景公诊病。医缓还没有到达,晋景公又梦见疾病变成两个小儿童,一个说:“他是个好医生,恐怕会伤害我们,往哪儿逃好?”另一个说:“我们待在肓的上边,膏的下边,拿我们怎么办?”医生来了,说:“病不能治了,病在肓的上边,膏的下边,灸不能用,针达不到,药物的力量也达不到了,不能治了。”晋景公说:“真是好医生啊。”于是馈送给他丰厚的礼物让他回去。六月初六日,晋景公想吃新麦子,让管食物的人献麦,厨师烹煮。景公召见桑田巫人来,把煮好的新麦给他看,然后杀了他。景公将要进食,突然肚子发胀,上厕所,跌进厕所里死去。有一个宦官早晨梦见背着晋景公登天,等到中午,他背着晋景公从厕所出来,于是就以他为景公殉葬了。 +郑成公讨伐立国君的人,六月初八日,杀了叔申、叔禽。君子说:“忠诚是美德,所忠的人不合式尚且不可以,何况本人又不好呢?” +秋季,鲁成公到晋国。晋国人留下成公,让他送葬。当时籴茷还没有回来。 +冬季,安葬晋景公。鲁成公送葬,诸侯都不在场。鲁国人认为这是耻辱,所以《春秋》不加记载,这是隐讳国耻。 + +成公十一年 +【经】十有一年春王三月,公至自晋。晋侯使郤犨来聘,己丑,及郤犨盟。夏,季孙行父如晋。秋,叔孙侨如如齐。冬十月。 +【传】十一年春,王三月,公至自晋。晋人以公为贰于楚,故止公。公请受盟,而后使归。 +郤犨来聘,且莅盟。 +声伯之母不聘,穆姜曰:“吾不以妾为姒。”生声伯而出之,嫁于齐管于奚。生二子而寡,以归声伯。声伯以其外弟为大夫,而嫁其外妹于施孝叔。郤犨来聘,求妇于声伯。声伯夺施氏妇以与之。妇人曰:“鸟兽犹不失俪,子将若何?”曰:“吾不能死亡。”妇人遂行,生二子于郤氏。郤氏亡,晋人归之施氏,施氏逆诸河,沉其二子。妇人怒曰:“己不能庇其伉俪而亡之,又不能字人之孤而杀之,将何以终?”遂誓施氏。 +夏,季文子如晋报聘,且莅盟也。 +周公楚恶惠、襄之逼也,且与伯与争政,不胜,怒而出。及阳樊,王使刘子复之,盟于鄄而入。三日,复出奔晋。 +秋,宣伯聘于齐,以修前好。 +晋郤至与周争鄇田,王命刘康公、单襄公讼诸晋。郤至曰:“温,吾故也,故不敢失。”刘子、单子曰:“昔周克商,使诸侯抚封,苏忿生以温为司寇,与檀伯达封于河。苏氏即狄,又不能于狄而奔卫。襄王劳文公而赐之温,狐氏、阳氏先处之,而后及子。若治其故,则王官之邑也,子安得之?”晋侯使郤至勿敢争。 +宋华元善于令尹子重,又善于栾武子。闻楚人既许晋籴伐成,而使归覆命矣。冬,华元如楚,遂如晋,合晋、楚之成。 +秦、晋为成,将会于令狐。晋侯先至焉,秦伯不肯涉河,次于王城,使史颗盟晋侯于河东。晋郤犨盟秦伯于河西。范文子曰:“是盟也何益?齐盟,所以质信也。会所,信之始也。始之不从,其何质乎?”秦伯归而背晋成。 +译文 +十一年,春季,周王朝历法的三月,鲁成公从晋国回来。晋国人认为成公倾向楚国,所以扣留了他。成公请求接受盟约,然后让他回国。 +郤犫来鲁国聘问,而且参加结盟。 +声伯的母亲没有举行媒聘之礼就和叔肸同居,穆姜说:“我不能把姘妇当成嫂嫂。”声伯的母亲生了声伯,就被遗弃了,嫁给齐国的管于奚,生了两个孩子以后又守寡,就把两个孩子给了声伯。声伯让他的异父兄弟做了大夫,又把异父妹妹嫁给施孝叔。郤犫前来聘问,向声伯求取妻子。声伯把施氏的妻子夺过来给了郤犫。这个女人对丈夫说:“鸟兽还不肯失掉配偶,您打算怎么办?”她的丈夫说:“我不能够因此死去或者逃亡。”这个女人就随郤犫走了。在郤氏那里生了两个孩子,郤氏被灭,晋国人又把她还给施氏。施氏在黄河边迎接她,把她的两个孩子沉进黄河里。这个妇女发怒说:“自己不能保护自己的配偶而让她离开,又不能爱护别人的孤儿而杀死他们,这怎么能有好结果?”就发誓不再做施氏的妻子。 +夏季,季文子去到晋国,回报聘问,同时也参加结盟。 +周公楚讨厌周惠王、周襄王族人的逼迫,同时又和伯舆争夺政权,没有得胜,就生气而离开。到达阳樊,周简王派刘子让周公楚回来,在鄄地结盟然后进入国内。三天后,周公楚再次离去,逃亡到晋国。 +秋季,宣伯到齐国聘问,重修过去的友好。 +晋国的郤至和周室争夺鄇地的土地,周简王命令刘康公、单襄公到晋国争讼。郤至说:“温地,过去就是我的封邑,所以不敢丢失。”刘康公、单襄公说:“以前周朝战胜商朝,让诸侯据有封地。苏忿生据有温地,做了司寇,和檀伯达封在黄河边上。苏氏投奔狄人,又和狄人不合式而逃到卫国。襄王为了慰劳文公,将温地赐给了他,狐氏、阳氏先住在这里,然后才轮到您。如果要追查过去的原因,那么它是周天子属官的封邑,您怎么能得到它?”晋厉公下令要郤至不要争夺。 +宋国大夫华元和楚令尹子重友好,又和晋大夫栾武子友好,听到楚人已经允许晋国的籴茷求和,而让他回国复命了。冬季,华元到楚国,又到晋国,促成晋、楚的和好。 +秦、晋两国和好,准备在令狐会见。晋厉公先到达。秦桓公不肯渡过黄河,住在王城,派遣史颗和晋厉公在河东会盟。晋国的郤犫和秦桓公在河西结盟。范文子说:“这样的结盟有什么好处?斋戒盟誓,是用来表示信用的。约定会见地点,这是信用的开始。开始都不顺从,难道可以相信吗?”秦桓公回去就背弃了和晋国的友好盟约。 + + +成公十二年 +【经】十有二年春,周公出奔晋。夏,公会晋侯、卫侯于琐泽。秋,晋人败狄于交刚。冬十月。 +【传】十二年春,王使以周公之难来告。书曰:“周公出奔晋。”凡自周无出,周公自出故也。 +宋华元克合晋、楚之成。夏五月,晋士燮会楚公子罢、许偃。癸亥,盟于宋西门之外,曰:“凡晋、楚无相加戎,好恶同之,同恤菑危,备救凶患。若有害楚,则晋伐之。在晋,楚亦如之。交贽往来,道路无壅,谋其不协,而讨不庭有渝此盟,明神殛之,俾队其师,无克胙国。”郑伯如晋听成,会于琐泽,成故也。 +狄人间宋之盟以侵晋,而不设备。秋,晋人败狄于交刚。 +晋郤至如楚聘,且莅盟。楚子享之,子反相,为地室而县焉。郤至将登,金奏作于下,惊而走出。子反曰:“日云莫矣,寡君须矣,吾子其入也!”宾曰:“君不忘先君之好,施及下臣,贶之以大礼,重之以备乐。如天之福,两君相见,何以代此。下臣不敢。”子反曰:“如天之福,两君相见,无亦唯是一矢以相加遗,焉用乐?寡君须矣,吾子其入也!”宾曰:“若让之以一矢,祸之大者,其何福之为?世之治也,诸侯间于天子之事,则相朝也,于是乎有享宴之礼。享以训共俭,宴以示慈惠。共俭以行礼,而慈惠以布政。政以礼成,民是以息。百官承事,朝而不夕,此公侯之所以扞城其民也。故《诗》曰:‘赳赳武夫,公侯干城。’及其乱也,诸侯贪冒,侵欲不忌,争寻常以尽其民,略其武夫,以为己腹心股肱爪牙。故《诗》曰:‘赳赳武夫,公侯腹心。’天下有道,则公侯能为民干城,而制其腹心。乱则反之。今吾子之言,乱之道也,不可以为法。然吾子,主也,至敢不从?”遂入,卒事。归,以语范文子。文子曰:“无礼必食言,吾死无日矣夫!” +冬,楚公子罢如晋聘,且莅盟。十二月,晋侯及楚公子罢盟于赤棘。 +译文 +十二年春季,周简王的使者来鲁国通告周公楚的祸难事件。《春秋》记载说“周公出奔晋”。凡是从周朝外逃的不能叫做“出”,周公楚自己出逃,所以才用“出”字。 +宋国华元完成了晋、楚两国的和好。夏季,五月,晋国士燮会见楚国公子罢、许偃。初四日,在宋国西门之外结盟,说:“凡是晋、楚两国,不要互相以兵戎相见,要好恶相同,一起救济灾难危亡,救援饥荒祸患。如果有危害楚国的,晋国就攻打它;对晋国,楚国也是这样做。两国使者往来,道路不要阻塞,协商不和,讨伐背叛。谁要违背盟约,神灵就要诛杀,使他军队颠覆,不能保佑国家。”郑成公去到晋国听受和约,和诸侯在琐泽会见,这是由于晋、楚和好的缘故。 +狄人乘宋国促成的结盟会这一空隙攻打晋国,但又不设防备。秋季,晋国人在交刚打败了狄人。 +晋国郤至到楚国聘问,同时参加盟约。楚共王设享礼招待他,子反作为相礼者,在地下室悬挂乐器。郤至将要登堂,下面击钟又击鼓,惊慌地退了出来。子反说:“时间不早了,寡君等着呢,您还是进去吧!”客人说:“贵国君王不忘记先君的友好,加之于下臣,赐给下臣以重大的礼仪,又加上钟鼓音乐,如果上天降福,两国国君相见,还能用什么礼节来代替这个呢?下臣不敢当。”子反说:“如果上天降福,两国国君相见,也只能用一支箭彼此相赠,哪里还用奏乐?寡君等着呢,您还是进去吧!”客人说:“如果用一支箭来款待,这是祸中的大祸,还有什么福可说?当天下大治的时候,诸侯在完成天子使命的闲暇之时,就互相朝见,在这时就有享、宴的礼仪。享礼用来教导恭敬节俭,宴礼用来表示慈爱恩惠。恭敬节俭用来推行礼仪,而慈爱恩惠则用来施行政教。政教用礼仪来完成,百姓因此得到休息。百官承受政事,白天朝见晚上就不再朝见,这就是公侯所用来捍卫他们百姓的措施,所以《诗》说:‘雄赳赳的武士,是公侯的捍卫。’等到它动乱的时候,诸侯贪婪,侵占欲望已无所顾忌,为争夺尺寸之地而驱使百姓致于死亡,收取他的武士,作为自己的心腹、股肱、爪牙。所以《诗》说:‘雄赳赳的武士,是公侯的心腹。’天下有道,那么公侯就能做百姓的捍卫,而控制他的心腹。动乱时,就反过来。现在您的话,是动乱之道,不能用来作为法则。然而您,是主人,至岂敢不听从?”于是就进去,把事情办完。郤至回去把情况告诉范文子。文子说:“无礼,必然说话不算话,我们离开死日不远了。” +冬季,楚国公子罢去到晋国聘问,同时参加结盟,十二月,晋厉公和楚公子罢在赤棘结盟。 + +成公十三年 +【经】十有三年春,晋侯使郤錡来乞师。三月,公如京师。夏五月,公自京师,遂会晋侯、齐侯、宋公、卫侯、郑伯、曹伯、邾人、滕人伐秦。曹伯卢卒于师。秋七月,公至自伐秦。冬,葬曹宣公。 +【传】十三年春,晋侯使郤錡来乞师,将事不敬。孟献子曰:“郤氏其亡乎!礼,身之干也。敬,身之基也。郤子无基。且先君之嗣卿也,受命以求师,将社稷是卫,而惰,弃君命也。不亡何为?” +三月,公如京师。宣伯欲赐,请先使,王以行人之礼礼焉。孟献子从。王以为介,而重贿之。 +公及诸侯朝王,遂从刘康公、成肃公会晋侯伐秦。成子受脤于社,不敬。刘子曰:“吾闻之,民受天地之中以生,所谓命也。是以有动作礼义威仪之则,以定命也。能者养以之福,不能者败以取祸。是故君子勤礼,小人尽力,勤礼莫如致敬,尽力莫如敦笃。敬在养神,笃在守业。国之大事,在祀与戎,祀有执膰,戎有受脤,神之大节也。今成子惰,弃其命矣,其不反乎?” +夏四月戊午,晋侯使吕相绝秦,曰:“昔逮我献公,及穆公相好,戮力同心,申之以盟誓,重之以昏姻。天祸晋国,文公如齐,惠公如秦。无禄,献公即世,穆公不忘旧德,俾我惠公用能奉祀于晋。又不能成大勋,而为韩之师。亦悔于厥心,用集我文公,是穆之成也。文公躬擐甲胄,跋履山川,逾越险阻,征东之诸侯,虞、夏、商、周之胤,而朝诸秦,则亦既报旧德矣。郑人怒君之疆埸,我文公帅诸侯及秦围郑。秦大夫不询于我寡君,擅及郑盟。诸侯疾之,将致命于秦。文公恐惧,绥静诸侯,秦师克还无害,则是我有大造于西也。无禄,文公即世,穆为不吊,蔑死我君,寡我襄公,迭我淆地,奸绝我好,伐我保城,殄灭我费滑,散离我兄弟,挠乱我同盟,倾覆我国家。我襄公未忘君之旧勋,而惧社稷之陨,是以有淆之师。犹愿赦罪于穆公,穆公弗听,而即楚谋我。天诱其衷,成王殒命,穆公是以不克逞志于我。穆、襄即世,康、灵即位。康公,我之自出,又欲阙翦我公室,倾覆我社稷,帅我蝥贼,以来荡摇我边疆。我是以有令狐之役。康犹不悛,入我河曲,伐我涷川,俘我王官,翦我羁马,我是以有河曲之战。东道之不通,则是康公绝我好也。 +及君之嗣也,我君景公引领西望曰:‘庶抚我乎!’君亦不惠称盟,利吾有狄难,入我河县,焚我箕、郜,芟夷我农功,虔刘我边陲。我是以有辅氏之聚。“君亦悔祸之延,而欲徼福于先君献、穆,使伯车来,命我景公曰:‘吾与女同好弃恶,复修旧德,以追念前勋,’言誓未就,景公即世,我寡君是以有令狐之会。君又不祥,背弃盟誓。白狄及君同州,君之仇仇,而我之昏姻也。君来赐命曰:‘吾与女伐狄。’寡君不敢顾昏姻,畏君之威,而受命于吏。君有二心于狄,曰:‘晋将伐女。’狄应且憎,是用告我。楚人恶君之二三其德也,亦来告我曰:‘秦背令狐之盟,而来求盟于我:“昭告昊天上帝、秦三公、楚三王曰:‘余虽与晋出入,余唯利是视。’不谷恶其无成德,是用宣之,以惩不壹。”诸侯备闻此言,斯是用痛心疾首,昵就寡人。寡人帅以听命,唯好是求。君若惠顾诸侯,矜哀寡人,而赐之盟,则寡人之愿也。其承宁诸侯以退,岂敢徼乱。君若不施大惠,寡人不佞,其不能以诸侯退矣。敢尽布之执事,俾执事实图利之!” +秦桓公既与晋厉公为令狐之盟,而又召狄与楚,欲道以伐晋,诸侯是以睦于晋。晋栾书将中军,荀庚佐之。士燮将上军,郤錡佐之。韩厥将下军,荀罃佐之。赵旃将新军,郤至佐之。郤毅御戎,栾金咸为右。孟献子曰:“晋帅乘和,师必有大功。”五月丁亥,晋师以诸侯之师及秦师战于麻隧。秦师败绩,获秦成差及不更女父。曹宣公卒于师。师遂济泾,及侯丽而还。迓晋侯于新楚。 +成肃公卒于瑕。 +六月丁卯夜,郑公子班自訾求入于大宫,不能,杀子印、子羽。反军于市,己巳,予驷帅国人盟于大宫,遂从而尽焚之,杀子如、子□龙、孙叔、孙知。 +曹人使公子负刍守,使公子欣时逆曹伯之丧。秋,负刍杀其大子而自立也。诸侯乃请讨之,晋人以其役之劳,请俟他年。冬,葬曹宣公。既葬,子臧将亡,国人皆将从之。成公乃惧,告罪,且请焉,乃反,而致其邑。 +译文 +十三年春季,晋厉公派遣郤犫来鲁国请求援兵,处理事情态度不严肃。孟献子说:“郤氏恐怕要灭亡了吧!礼仪,是身体的躯干;恭敬,是身体的基础。郤子却没有基础。而且作为先君的嗣卿,接受命令而来请求出兵,想保卫国家,但却怠惰,这是不顾国君的命令,不灭亡还做什么?” +三月,鲁成公到京师。宣伯想要得到赏赐,请求先行出使。周简王用对普通外交官的礼仪来接待他。孟献子跟从成公,周简王把他作为成公的第一位外交官,而重重地赠给他财礼。 +成公和诸侯朝觐周简王,接着就跟从刘康公、成肃公会合晋厉公进攻秦国。成肃公在社神庙接受祭肉的时候,不恭敬。刘康公说:“我听说:百姓得到天地的中和之气而降生,这就是所谓生命。因此就有动作、礼义、威仪的准则,用来固定天命。有能力的人保持这些可以得福,没有能力的人败坏这些足以取祸。所以君子勤于礼法,小人竭尽力量。勤于礼法莫过于恭敬,竭尽力量莫过于敦厚笃实。恭敬在于供奉神灵,笃实在于各安本分。国家的大事情,在于祭祀和战争。祭祀有分祭肉之礼,战争有受祭肉之礼,这是和神灵交往的大节。现在成子表现出懒惰不恭,丢弃天命了,恐怕回不来了吧!” +夏季,四月初五日,晋厉公派遣吕相去和秦国断绝外交关系,说: +从前我先君晋献公和贵国先君秦穆公互相友好,合力同心,用盟誓来表明,再用婚姻加深两国关系。上天降祸于晋国,文公到了齐国,惠公到了秦国。不幸,献公去世。穆公不忘记过去的恩德,使我们惠公因此能在晋国主持祭祀,但又不能完成重大的勋劳,却和我国有了韩地之战。后来心里又有些懊悔,因此成就了我们文公回国为君,这都是秦穆公的功劳。文公亲自身披甲胄,登山涉水,经历艰难险阻,征服东方的诸侯,虞、夏、商、周的后代都向秦国朝见,也就已经报答过去的恩德了。郑国人侵犯君王的边界,我们文公率领诸侯和秦国共同包围郑国,秦国的大夫不和我们国君商量,擅自和郑国订立了盟约。诸侯痛恨这件事,打算和秦国拚命,文公恐惧,安抚诸侯,使秦军得以平安回国而没有受到损害,这就是我国有大功劳于西方秦国之处。 +“不幸,文公去世,穆公不善,蔑视我们故去的国君,以我们晋襄公为软弱可欺,突然侵犯我们的殽地,断绝我们同友好国家的往来,攻打我们的城堡,绝灭我们的滑国,离散我们的兄弟之邦,扰乱我们的同盟之国,颠覆我们的国家。我们襄公没有忘记君王过去的勋劳,而又害怕国家的颠覆,这样才有殽地的这一战役,但还是愿意在穆公那里解释以求赦免罪过。穆公不听,反而亲近楚国来谋害我们。天意保佑我国,楚成王丧命,穆公因此不能在我国称心如意。穆公、襄公去世,康公、灵公即位。康公,是我国穆姬所生的,但又想损害我们的公室,颠覆我们的国家,率领我国的内奸,以动摇我们的边疆,因此我国才有了令狐这一战役。秦康公还是不肯改悔,又进入我国河曲,攻打我国涑川,掠取我国王官,割断我国的羁马,因此我国才有了河曲这一战役。东边的道路不通,那是由于康公同我们断绝友好所造成的。 +“等到君王继位以后,我们的国君晋景公伸着脖子望着西边说:‘也许要安抚我们了吧!’但君王也不考虑和我们结盟,却利用我国有狄人的祸难,侵入我国的河县,焚烧我国的箕地、郜地,抢割我国的庄稼,骚扰我国边境,我国因此而有辅氏的战役。君王也后悔战祸的蔓延,而想求福于先君晋献公和秦穆公,派遣伯车前来命令我们景公说:‘我跟你重修旧好、丢弃怨恨,恢复以往的关系,以追念以前的勋劳。’盟誓还没有完成,我晋景公就去世了,因此我们国君才和秦国有令狐的会见。君王又不善,背弃了盟誓。白狄和君王同在雍州境内,他们是君王的仇敌,却是我们的亲戚。君王前来命令说:‘我跟你攻打狄人。’寡君不敢顾及亲戚,畏惧君王的威严,就给官吏下令攻打狄人。但君王又对狄人有了别的念头,告诉他们说:‘晋国将要攻打你们。’对君王的做法,狄人接受而又厌恶,因此就告诉了我们。楚国人讨厌君王的反复无常,也来告诉我们说:‘秦国背弃了令狐的盟约,而来向我国请求结盟:‘对着皇天上帝、秦国的三位先公、楚国的三位先王发誓:我虽然和晋国有往来,我只是唯利是图。’楚国人讨厌秦君反复无常,因此把事情公布出来,以惩戒言行不一的人。’” +秦桓公已经和晋厉公在令狐结盟,而又召来狄人和楚人,要引导他们进攻晋国,诸侯因此跟晋国和睦。晋国的栾书率领中军,荀庚作为辅佐;士燮率领上军,郤锜作为辅佐;韩厥率领下军,荀罃作为辅佐;赵旃率领新军,郤至作为辅佐。郤毅驾御战车,栾鍼作为车右。孟献子说:“晋国的将领和甲士上下一致,军队必然建立大功。”五月初四日,晋军率领诸侯的军队和秦军在麻隧作战。秦军大败,俘虏了秦国的成差和不更女父。曹宣公死在军中。军队就渡过泾水,到达侯丽然后回去。军队在新楚迎接晋厉公。 +成肃公死在瑕地。 +六月十五日夜里,郑国公子班从訾地请求进入祖庙,没有做到,就杀了子印、子羽,回来驻扎在市上。十七日,子驷率领国内的人们在祖庙结盟,跟着就全部烧了它,杀了公子班、子駹、孙叔、孙知。 +曹国人派公子负刍留守,派公子欣时去迎接曹宣公尸体。秋季,公子负刍杀了曹宣公的太子而自立为国君,诸侯就请求讨伐他。晋国人由于他在和秦国作战中有功劳,请求等到以后再讨伐。冬季,安葬曹宣公。安葬以后,子臧准备逃亡,国内的人都要跟着他逃亡。曹成公负刍才感到恐惧,承认罪过,而且请求子臧留下来不要出走。子臧这才返回来,然后把采邑还给曹成公。 + +成公十四年 +【经】十有四年春王正月,莒子朱卒。夏,卫孙林父自晋归于卫。秋,叔孙侨如如齐逆女。郑公子喜帅师伐许。九月,侨如以夫人妇姜氏至自齐。冬十月庚寅,卫侯臧卒。秦伯卒。 +【传】十四年春,卫侯如晋,晋侯强见孙林父焉,定公不可。夏,卫侯既归,晋侯使郤犨送孙林父而见之。卫侯欲辞,定姜曰:“不可。是先君宗卿之嗣也,大国又以为请,不许,将亡。虽恶之,不犹愈于亡乎?君其忍之!安民而宥宗卿,不亦可乎?”卫侯见而复之。 +卫侯飨苦成叔,宁惠子相。苦成叔傲。宁子曰:“苦成家其亡乎!古之为享食也,以观威仪、省祸福也。故《诗》曰:‘兕觥其觩,旨酒思柔,彼交匪傲,万福来求。’今夫子傲,取祸之道也。” +秋,宣伯如齐逆女。称族,尊君命也。 +八月,郑子罕伐许,败焉。戊戌,郑伯复伐许。庚子,入其郛。许人平以叔申之封。 +九月,侨如以夫人妇姜氏至自齐。舍族,尊夫人也。故君子曰:“《春秋》之称,微而显,志而晦,婉而成章,尽而不污,惩恶而劝善。非圣人谁能修之?” +卫侯有疾,使孔成子、宁惠子立敬姒之子衎以为大子。冬十月,卫定公卒。夫人姜氏既哭而息,见大子之不哀也,不内酌饮。叹曰:“是夫也,将不唯卫国之败,其必始于未亡人!乌呼!天祸卫国也夫!吾不获鱄也使主社稷。”大夫闻之,无不耸惧。孙文子自是不敢舍其重器于卫,尽置诸戚,而甚善晋大夫。 +译文 +十四年春季,卫定公去到晋国,晋厉公强请卫定公接见孙林父,卫定公不同意。夏季,卫定公回国以后,晋厉公派郤犫送孙林父去见他。卫定公想要推辞。定姜说:“不行。他是先君宗卿的后代,大国又以此作为请求,如果不答应,我国将要灭亡。虽然讨厌他,总比亡国强些吧?君王还是忍耐一下吧!安定百姓而赦免宗卿,不也是可行的吗?”卫定公接见了孙林父,并且恢复了他的职位和采邑。 +卫定公设享礼招待苦成叔,宁惠子作陪,苦成叔表现出傲慢的样子。宁惠子说:“苦成叔恐怕要被灭亡了吧!古代举行享礼,是用来观察威仪,省察祸福的,所以《诗》说:‘弯弯角杯,柔和甜酒。不骄不傲,聚集万福。’现在他老人家表现傲慢,是取祸之道啊!” +秋季,鲁大夫宣伯到齐国迎接齐女。《春秋》称他的族名,这是由于尊重国君的命令。 +八月,郑国的子罕进攻许国,战败。二十三日,郑成公再次进攻许国。二十五日,进入许国的外城。许国人把叔申的封地交还郑国以此与郑国讲和。 +九月,侨如带着夫人姜氏从齐国来到。《春秋》不称族名,这是由于尊重夫人。所以君子说:《春秋》的记载,言词不多而意义显明,记载史实而意义深远,婉转而顺理成章,穷尽而不歪曲,警戒邪恶而奖励善良。如果不是圣人,谁能够编写?” +卫定公有病,让孔成子、宁惠子立敬姒的儿子衎作为太子。冬季,十一月,卫定公去世。夫人姜氏哭丧以后休息,看到太子并不悲哀,就连水也不喝,叹气说:“这个人啊,将要不仅会使卫国遭致败亡,而且必然从我这个未亡人身上开始动手。唉呀!这是上天降祸给卫国吧!我不能得到鱄来主持国家。”大夫们听到以后,无不感到十分恐惧。孙文子从此不敢把他的宝器藏在卫国,而都放在采邑戚地,同时尽量和晋国的大夫友好。 + +成公十五年 +【经】十有五年春王二月,葬卫定公。三月乙巳,仲婴齐卒。癸丑,公会晋侯、卫侯、郑伯、曹伯、宋世子成、齐国佐,邾人同盟于戚。晋侯执曹伯归于京师。公至自会。夏六月,宁公固卒。楚子伐郑。秋八月庚辰,葬宋共公。宋华元出奔晋。宋华元自晋归于宋。宋杀其大夫山。宋鱼石出奔楚。冬十有一月,叔孙侨如会晋士燮、齐高无咎、宋华元、卫孙林父、郑公子酉、邾人会吴于钟离。许迁于叶。 +【传】十五年春,会于戚,讨曹成公也。执而归诸京师。书曰:“晋侯执曹伯。”不及其民也。凡君不道于其民,诸侯讨而执之,则曰某人执某侯。不然,则否。 +诸侯将见子臧于王而立之,子臧辞曰:“《前志》有之,曰:‘圣达节,次守节,下失节。’为君,非吾节也。虽不能圣,敢失守乎?”遂逃,奔宋。 +夏六月,宋共公卒。 +楚将北师。子囊曰:“新与晋盟而背之,无乃不可乎?”子反曰:“敌利则进,何盟之有?”申叔时老矣,在申,闻之,曰:“子反必不免。信以守礼,礼以庇身,信礼之亡,欲免得乎?”楚子侵郑,及暴隧,遂侵卫,及首止。郑子罕侵楚,取新石。栾武子欲报楚,韩献子曰:“无庸,使重其罪,民将叛之。无民,孰战?” +秋八月,葬宋共公。于是华元为右师,鱼石为左师,荡泽为司马,华喜为司徒,公孙师为司城,向为人为大司寇,鳞朱为少司寇,向带为大宰,鱼府为少宰。荡泽弱公室,杀公子肥。华元曰:“我为右师,君臣之训,师所司也。今公室卑而不能正,吾罪大矣。不能治官,敢赖宠乎?”乃出奔晋。 +二华,戴族也;司城,庄族也;六官者,皆桓族也。鱼石将止华元,鱼府曰:“右师反,必讨,是无桓氏也。”鱼石曰:“右师苟获反,虽许之讨,必不敢。且多大功,国人与之,不反,惧桓氏之无祀于宋也。右师讨,犹有戌在,桓氏虽亡,必偏。”鱼石自止华元于河上。请讨,许之,乃反。使华喜、公孙师帅国人攻荡氏,杀子山。书曰:“宋杀大夫山。”言背其族也。 +鱼石、向为人、鳞朱、向带、鱼府出舍于睢上。华元使止之,不可。冬十月,华元自止之,不可。乃反。鱼府曰:“今不从,不得入矣。右师视速而言疾,有异志焉。若不我纳,今将驰矣。”登丘而望之,则驰。聘而从之,则决睢澨,闭门登陴矣。左师、二司寇、二宰遂出奔楚。华元使向戌为左师,老佐为司马,乐裔为司寇,以靖国人。 +晋三郤害伯宗,谮而杀之,及栾弗忌。伯州犁奔楚。韩献子曰:“郤氏其不免乎!善人,天地之纪也,而骤绝之,不亡何待?” +初,伯宗每朝,其妻必戒之曰:“‘盗憎主人,民恶其上。’子好直言,必及于难。” +十一月,会吴于钟离,始通吴也。 +许灵公畏逼于郑,请迁于楚。辛丑,楚公子申迁许于叶。 +译文 +十五年春季,鲁成公和晋厉公、卫献公、郑成公、曹成公、宋国世子成、齐国国佐、邾人在戚地会盟,这是为了讨伐曹成公。逮捕了曹成公送到京师。《春秋》记载说“晋侯执曹伯”,这是由于曹成公的罪过不及于百姓。凡是国君对百姓无道,诸侯讨伐而且逮捕了他,就说“某人执某侯”,否则就不这样记载。 +诸侯要让子臧进见周王而立他为曹国国君。子臧辞谢说:“古书上有这样的话:‘圣人通达节义,其次保守节义,最下失去节义’。做国君这件事不合于我的节义。虽然不能像圣人那样,岂敢失节呢?”于是逃亡到宋国。 +夏季,六月,宋共公去世。 +楚国准备向北方出兵,子囊说:“新近和晋国结盟而背弃它,恐怕不可吧!”子反说:“敌情有利于我就前进,结什么盟?”申叔时已经老了,住在采邑申地,听到这话,说:“子反必然不能免于祸难。信用用来保持礼义,礼义用来保护生存,信用、礼义都没有了,想要免于祸难,行吗?” +楚子入侵郑国,到达暴隧,因此入侵卫国,到达首止。郑国子罕入侵楚国,战领了新石。 +晋将栾武子想要报复楚国,韩献子说:“不用,让他自己加重罪过,百姓将会背叛他。失了人心,谁去替他打仗。” +秋季,八月,安葬宋共公。在这时,华元做右师,鱼石做左师,荡泽做司马,华喜做司徒,公孙师做司城,向为人做大司寇,鳞朱做少师寇,向带做太宰,鱼府做少宰。荡泽要削弱公室,杀了公子肥。华元说:“我做右师,国君和臣下的教导,这是师所掌管的。现在公室的地位低下,却不能拨正,我的罪过大了。不能尽到职责,岂敢以得到宠信为利呢?”于是出奔晋国。 +二位华氏,是戴公的后代;司城,是庄公的后代;其他六大臣都是桓公的后代。鱼石准备阻止华元逃亡。鱼府说:“右师如果回来,必然要讨伐荡泽,这就会没有桓氏这一族了。”鱼石说:“右师如果能够回来,虽然允许他讨伐,他必然不敢。而且他建立了大功,国内的人们亲附他,如果他不回来,恐怕桓氏在宋国没有人祭祀了。右师如果讨伐,还有向戌在那里。桓氏虽然灭亡,必然只是亡掉一部分而已。”鱼石自己在黄河岸上阻止华元。华元请求讨伐荡泽,鱼石答应了。华元这才回来,派遣华喜、公孙师率领国内的人们进攻荡氏,杀了荡泽,《春秋》记载说“宋杀其大夫山”,就是说荡泽背弃了自己的宗族。 +鱼石、向为人、鳞朱、向带、鱼府离开都城住在睢水旁边,华元派人劝阻他们,他们不同意。冬季,十月,华元亲自去劝阻,他们又不同意,华元就回来了。鱼府说:“现在不听从华元的话,以后就不能进入国都了。右师眼睛转动很快而说话很急,有别的想法呀。如果不接纳我们,现在就要疾驰而去了。”他们登上山头一看,就看到华元疾驰而去。这五个人驱车跟随华元,华元已经掘开睢水堤防,关闭城门登上城墙了。左师、两个司寇、两个宰就逃亡到楚国。华元派向戌做左师、老佐做司马、乐裔做司寇,来安定国内的人。 +晋国三郤陷害伯宗,诬陷以后再杀了他,并且连累及于栾弗忌。伯州犁逃亡到楚国。韩献子说:“郤氏恐怕不能免于祸难吧!善人,是天地的纲纪,而多次加以杀害,不灭亡还等什么?” +当初,伯宗每次朝见,他的妻子一定劝戒他说:“盗贼憎恨主人,百姓讨厌统治者,您喜欢说直话,必然遭到祸难。” +十一月,叔孙侨如会合晋国士燮、齐国高无咎、宋国华元、卫国孙林父、郑国公子?和吴国在钟离会见,这是开始和吴国友好往来。 +许灵公害怕郑国逼迫,请求迁到楚国。十一月初三日,楚国公子申把许国迁到叶地。 + +成公十六年 +【经】十有六年春王正月,雨,木冰。夏四月辛未,滕子卒。郑公子喜帅师侵宋。六月丙寅朔,日有食之。晋侯使栾□来乞师。甲午晦,晋侯及楚子、郑伯战于鄢陵。楚子、郑师败绩。楚杀其大夫公子侧。秋,公会晋侯、齐侯、卫侯、宋华元、邾人于沙随,不见公。公至自会。公会尹子,晋侯、齐国佐、邾人伐郑。曹伯归自京师。九月,晋人执季孙行父,舍之于苕丘。冬十月乙亥,叔孙侨如出奔齐。十有二月乙丑,季孙行父及晋郤犨盟于扈。公至自会。乙酉,刺公子偃。 +【传】十六年春,楚子自武城使公子成以汝阴之田求成于郑。郑叛晋,子驷从楚子盟于武城。 +夏四月,滕文公卒。 +郑子罕伐宋,宋将鉏、乐惧败诸汋陂。退,舍于夫渠,不儆,郑人覆之,败诸汋陵,获将鉏、乐惧。宋恃胜也。 +卫侯伐郑,至于鸣雁,为晋故也。 +晋侯将伐郑,范文子曰:“若逞吾愿,诸侯皆叛,晋可以逞。若唯郑叛,晋国之忧,可立俟也。”栾武子曰:“不可以当吾世而失诸侯,必伐郑。”乃兴师。栾书将中军,士燮佐之。郤錡将上军,荀偃佐之。韩厥将下军,郤至佐新军,荀罃居守。郤犨如卫,遂如齐,皆乞师焉。栾□来乞师,孟献子曰:“有胜矣。”戊寅,晋师起。 +郑人闻有晋师,使告于楚,姚句耳与往。楚子救郑,司马将中军,令尹将左,右尹子辛将右。过申,子反入见申叔时,曰:“师其何如?”对曰:“德、刑、详、义、礼、信,战之器也。德以施惠,刑以正邪,详以事神,义以建利,礼以顺时,信以守物。民生厚而德正,用利而事节,时顺而物成。上下和睦,周旋不逆,求无不具,各知其极。故《诗》曰:‘立我烝民,莫匪尔极。’是以神降之福,时无灾害,民生敦庞,和同以听,莫不尽力以从上命,致死以补其阙。此战之所由克也。今楚内弃其民,而外绝其好,渎齐盟,而食话言,奸时以动,而疲民以逞。民不知信,进退罪也。人恤所底,其谁致死?子其勉之!吾不复见子矣。”姚句耳先归,子驷问焉,对曰:“其行速,过险而不整。速则失志,不整丧列。志失列丧,将何以战?楚惧不可用也。” +五月,晋师济河。闻楚师将至,范文子欲反,曰:“我伪逃楚,可以纾忧。夫合诸侯,非吾所能也,以遗能者。我若群臣辑睦以事君,多矣。”武子曰:“不可。” +六月,晋、楚遇于鄢陵。范文子不欲战,郤至曰:“韩之战,惠公不振旅。箕之役,先轸不反命,邲之师,荀伯不复从。皆晋之耻也。子亦见先君之事矣。今我辟楚,又益耻也。”文子曰:“吾先君之亟战也,有故。秦、狄、齐、楚皆强,不尽力,子孙将弱。今三强服矣,敌楚而已。唯圣人能外内无患,自非圣人,外宁必有内忧。盍释楚以为外惧乎?” +甲午晦,楚晨压晋军而陈。军吏患之。范□趋进,曰:“塞井夷灶,陈于军中,而疏行首。晋、楚唯天所授,何患焉?”文子执戈逐之,曰:“国之存亡,天也。童子何知焉?”栾书曰:“楚师轻窕,固垒而待之,三日必退。退而击之,必获胜焉。”郤至曰:“楚有六间,不可失也。其二卿相恶。王卒以旧。郑陈而不整。蛮军而不陈。陈不违晦,在陈而嚣,合而加嚣,各顾其后,莫有斗心。旧不必良,以犯天忌。我必克之。” +楚子登巢车以望晋军,子重使大宰伯州犁侍于王后。王曰:“骋而左右,何也?”曰:“召军吏也。”“皆聚于军中矣!”曰:“合谋也。”“张幕矣。”曰:“虔卜于先君也。”“彻幕矣!”曰:“将发命也。”“甚嚣,且尘上矣!”曰:“将塞井夷灶而为行也。”“皆乘矣,左右执兵而下矣!”曰:“听誓也。”“战乎?”曰:“未可知也。”“乘而左右皆下矣!”曰:“战祷也。”伯州犁以公卒告王。苗贲皇在晋侯之侧,亦以王卒告。皆曰:“国士在,且厚,不可当也。”苗贲皇言于晋侯曰:“楚之良,在其中军王族而已。请分良以击其左右,而三军萃于王卒,必大败之。”公筮之,史曰:“吉。其卦遇《复》三,曰:‘南国戚,射其元王中厥目。’国戚王伤,不败何待?”公从之。有淖于前,乃皆左右相违于淖。步毅御晋厉公,栾金咸为右。彭名御楚共王,潘党为右。石首御郑成公,唐苟为右。栾、范以其族夹公行,陷于淖。栾书将载晋侯,金咸曰:“书退!国有大任,焉得专之?且侵官,冒也;失官,慢也;离局,奸也。有三不罪焉,可犯也。”乃掀公以出于淖。 +癸巳,潘□之党与养由基蹲甲而射之,彻七札焉。以示王,曰:“君有二臣如此,何忧于战?”王怒曰:“大辱国。诘朝,尔射,死艺。”吕錡梦射月,中之,退入于泥。占之,曰:“姬姓,日也。异姓,月也,必楚王也。射而中之,退入于泥,亦必死矣。”及战,射共王,中目。王召养由基,与之两矢,使射吕錡,中项,伏弢。以一矢覆命。 +郤至三遇楚子之卒,见楚子,必下,免胄而趋风。楚子使工尹襄问之以弓,曰:“方事之殷也,有韎韦之跗注,君子也。识见不谷而趋,无乃伤乎?”郤至见客,免胄承命,曰:“君之外臣至,从寡君之戎事,以君之灵,间蒙甲胄,不敢拜命,敢告不宁君命之辱,为事之故,敢肃使者。”三肃使者而退。 +晋韩厥从郑伯,其御杜溷罗曰:“速从之!其御屡顾,不在马,可及也。”韩厥曰:“不可以再辱国君。”乃止。郤至从郑伯,其右茀翰胡曰:“谍辂之,余从之乘而俘以下。”郤至曰:“伤国君有刑。”亦止。石首曰:“卫懿公唯不去其旗,是以败于荧。”乃旌于弢中。唐苟谓石首曰:“子在君侧,败者壹大。我不如子,子以君免,我请止。”乃死。 +楚师薄于险,叔山冉谓养由基曰:“虽君有命,为国故,子必射!”乃射。再发,尽殪。叔山冉搏人以投,中车,折轼。晋师乃止。囚楚公子伐。 +栾金咸见子重之旌,请曰:“楚人谓夫旌,子重之麾也。彼其子重也。日臣之使于楚也,子重问晋国之勇。臣对曰:‘好以众整。’曰:‘又何如?’臣对曰:‘好以暇。’今两国治戎,行人不使,不可谓整。临事而食言,不可谓暇。请摄饮焉。”公许之。使行人执榼承饮,造于子重,曰:“寡君乏使,使金咸御持矛。是以不得犒从者,使某摄饮。”子重曰:“夫子尝与吾言于楚,必是故也,不亦识乎!”受而饮之。免使者而复鼓。 +旦而战,见星未已。子反命军吏察夷伤,补卒乘,缮甲兵,展车马,鸡鸣而食,唯命是听。晋人患之。苗贲皇徇曰:“搜乘补卒,秣马利兵,修陈固列,蓐食申祷,明日复战。”乃逸楚囚。王闻之,召子反谋。谷阳竖献饮于子反,子反醉而不能见。王曰:“天败楚也夫!余不可以待。”乃宵遁。晋入楚军,三日谷。范文子立于戎马之前,曰:“君幼,诸臣不佞,何以及此?君其戒之!《周书》曰‘唯命不于常’,有德之谓。” +楚师还,及瑕,王使谓子反曰:“先大夫之覆师徒者,君不在。子无以为过,不谷之罪也。”子反再拜稽首曰:“君赐臣死,死且不朽。臣之卒实奔,臣之罪也。”子重复谓子反曰:“初陨师徒者,而亦闻之矣!盍图之?”对曰:“虽微先大夫有之,大夫命侧,侧敢不义?侧亡君师,敢忘其死。”王使止之,弗及而卒。 +战之日,齐国佐、高无咎至于师。卫侯出于卫,公出于坏隤。宣伯通于穆姜,欲去季、孟,而取其室。将行,穆姜送公,而使逐二子。公以晋难告,曰:“请反而听命。”姜怒,公子偃、公子鉏趋过,指之曰:“女不可,是皆君也。”公待于坏隤,申宫儆备,设守而后行,是以后。使孟献子守于公宫。 +秋,会于沙随,谋伐郑也。宣伯使告郤犨曰:“鲁侯待于坏隤以待胜者。”郤犨将新军,且为公族大夫,以主东诸侯。取货于宣伯而诉公于晋侯,晋侯不见公。 +曹人请于晋曰:“自我先君宣公即位,国人曰:‘若之何忧犹未弭?’而又讨我寡君,以亡曹国社稷之镇公子,是大泯曹也。先君无乃有罪乎?若有罪,则君列诸会矣。君唯不遗德刑,以伯诸侯。岂独遗诸敝邑?取私布之。” +七月,公会尹武公及诸侯伐郑。将行,姜又命公如初。公又申守而行。诸侯之师次于郑西。我师次于督扬,不敢过郑。子叔声伯使叔孙豹请逆于晋师。为食于郑郊。师逆以至。声伯四日不食以待之,食使者而后食。 +诸侯迁于制田。知武子佐下军,以诸侯之师侵陈,至于鸣鹿。遂侵蔡。未反,诸侯迁于颖上。戊午,郑子罕宵军之,宋、齐、卫皆失军。 +曹人复请于晋,晋侯谓子臧:“反,吾归而君。”子臧反,曹伯归。子臧尽致其邑与卿而不出。 +宣伯使告郤犨曰:“鲁之有季、孟,犹晋之有栾、范也,政令于是乎成。今其谋曰:‘晋政多门,不可从也。宁事齐、楚,有亡而已,蔑从晋矣。’若欲得志于鲁,请止行父而杀之,我毙蔑也而事晋,蔑有贰矣。鲁不贰,小国必睦。不然,归必叛矣。” +九月,晋人执季文子于苕丘。公还,待于郓。使子叔声伯请季孙于晋,郤犨曰:“苟去仲孙蔑而止季孙行父,吾与子国,亲于公室。”对曰:“侨如之情,子必闻之矣。若去蔑与行父,是大弃鲁国而罪寡君也。若犹不弃,而惠徼周公之福,使寡君得事晋君。则夫二人者,鲁国社稷之臣也。若朝亡之,鲁必夕亡。以鲁之密迩仇雠,亡而为仇,治之何及?”郤犨曰:“吾为子请邑。”对曰:“婴齐,鲁之常隶也,敢介大国以求厚焉!承寡君之命以请,若得所请,吾子之赐多矣。又何求?”范文子谓栾武子曰:“季孙于鲁,相二君矣。妾不衣帛,马不食粟,可不谓忠乎?信谗慝而弃忠良,若诸侯何?子叔婴齐奉君命无私,谋国家不贰,图其身不忘其君。若虚其请,是弃善人也。子其图之!”乃许鲁平,赦季孙。 +冬十月,出叔孙侨如而盟之,侨如奔齐。 +十二月,季孙及郤犨盟于扈。归,刺公子偃,召叔孙豹于齐而立之。 +齐声孟子通侨如,使立于高、国之间。侨如曰:“不可以再罪。”奔卫,亦间于卿。 +晋侯使郤至献楚捷于周,与单襄公语,骤称其伐。单子语诸大夫曰:“温季其亡乎!位于七人之下,而求掩其上。怨之所聚,乱之本也。多怨而阶乱,何以在位?《夏书》曰:‘怨岂在明?不见是图。’将慎其细也。今而明之,其可乎?” +译文 +十六年春季,楚共王从武城派公子成用汝阴的土田向郑国求和。郑国背叛晋国,子驷跟随楚子在武城结盟。 +夏季,四月,滕文公去世。 +郑国的子罕进攻宋国,宋国将鉏、乐惧在汋陂打败了他。宋军退兵,驻扎在夫渠,不加警备。郑军伏兵袭击,在汋陵打败了他们,俘虏了将鉏、乐惧。这是由宋国仗恃打了胜仗而不加戒备。 +卫献公发兵攻打郑国,到达鸣雁,这是为了晋国的缘故。 +晋厉公打算讨伐郑国,范文子说:“如果按照我的愿望,诸侯都背叛,晋国的危机可以得到缓和。如果只是一个郑国背叛,晋国的忧患,可能马上就会来了。”栾武子说:“不能在我们这一辈执政的时候失去诸侯,一定要进攻郑国。”于是就发兵。栾书率领中军,士燮作为辅佐;郤锜率领上军,荀偃作为辅佐;韩厥率领下军,郤至作为新军辅佐。荀罃留守。郤犫去到卫国,乘机到齐国,请求两国出兵。栾黡前来请求出兵,孟献子说:“晋国可能得胜了。”四月十二日,晋军出兵。 +郑国人听说晋国出兵,就派使者报告楚国,姚句耳同行。楚共王救援郑国。司马子反率领中军,令尹子重率领左军,右尹子辛率领右军。路过申地,子反进见申叔时,说:“这次出兵会怎么样?”申叔时回答说:“德行、刑罚、和顺、道义、礼法、信用,这是战争的手段。德行用来施予恩惠,刑罚用来纠正邪恶,和顺用来事奉神灵,道义用来建立利益,礼法用来适合时宜,信用用来护守事物。人民生活优厚,道德就端正;举动有利,事情就合于节度,时宜合适,生产就有所成就;这样就能上下和睦,相处没有矛盾,有所需求无不具备,各人都知道行动的准则。所以《诗》说:‘安置百姓,没有不合乎准则。’这样,神灵就降福于他,四时没有灾害,百姓生活优厚,齐心一致地听命,没有不尽力以服从上面命令的,不顾性命来弥补死去的战士的空缺,这样就是战争所以能够胜利的原因。现在楚国内部丢弃他的百姓,外部断绝他的友好,亵渎神圣的盟约而说话不讲信用,违反时令发动战争,使百姓疲劳以求快意。人们不知道什么是信用,进退都是罪过。人们为他们的结局在担忧,还有谁肯去送命?您还是尽力做吧!我不会再看到您了。”姚句耳先回来,子驷询问情况,他回答说:“楚军行军迅速,经过险要的地方行列不整齐。动作太快就会考虑不周,军容不整齐就丧失了行列。考虑不周、行列丧失,怎么能打仗?楚国恐怕不能依靠了。” +五月,晋军渡过黄河。他们听说楚军将要到达,范文子想要回去,说:“我们假装逃避楚国,这样就能够缓和忧患。会合诸侯,不是我所能做到的,还是遗留给有能力的人吧。我们如果群臣和睦以奉事国君,这就够了。”栾武子说:“不可以。” +六月,晋、楚两军在鄢陵相遇。范文子不想作战。郤至说:“韩地这一战,惠公失败归来;箕地这一役,先轸不能回国复命;邲地这一仗,荀伯又失败,这都是晋国的耻辱。您也了解先君时代的情况了。现在我们逃避楚国,这又是增加耻辱。”范文子说:“我们先君的屡次作战,是有原因的。秦国、狄人、齐国、楚国都很强大,如果我们不尽自己的力量,子孙将会被削弱。现在三强已经顺服,敌人仅楚国而已。只有圣人才能够外部内部都没有祸患。如果不是圣人,外部安定,内部必然还有忧患,何不放掉楚国把它作为外部的戒惧呢?” +二十九日(阴历月终),楚军在清早逼近晋军而摆开阵势。晋国的军吏担心这种情况。范匄快步向前,说:“填井平灶,就在军营摆开阵势,把行列间的距离放宽。晋、楚两国都是上天的赐予,有什么可担心的?”范文子拿起戈来驱逐他,说:“国家的存亡,这是天意,小孩子知道什么?”栾书说:“楚军轻佻,加固营垒而等待他们,三天一定退军。乘他们退走而加以追击,一定可以得胜。”郤至说:“楚国有六个空子,我们不可失掉时机:楚国的两个卿不和;楚共王的亲兵们从旧家中选拔,都已衰老;郑国虽然摆开阵势却不整齐;蛮人虽有军队却没有阵容;楚军摆阵不避讳月底;士兵在阵中就喧闹,各阵式相联合后就更加喧闹,各军彼此观望依赖,没有战斗意志。旧家子弟的士兵不一定是强兵,所以这些都触犯了天意和兵家大忌。我们一定能战胜他们。” +楚共王登上楼车了望晋军。子重让大宰伯州犁侍立在楚共王身后。楚共王说:“车子向左右驰骋,干什么?”伯州犁说:“这是召集军官们。”楚共王说:“那些人都集合在中军了。”伯州犁说:“这是一起谋议。”楚共王说:“帐幕张开了。”伯州犁说:“这是在先君的神主前占卜。”楚共王说:“帐幕撤除了。”伯州犁说:“这是将要发布命令了。”楚共王说:“喧闹得厉害。而且尘土飞扬起来了。”伯州犁说:“这是准备填井平灶摆开阵势。”楚共王说:“都登上战车了,将帅和车右都拿着武器下车了。”伯州犁说:“这是宣布号令。”楚共王说:“他们要作战吗?”伯州犁说:“还不能知道。”楚共王说:“晋军上了战车,将帅和车右又下来了。”伯州犁说:“这是战前的祈祷。”伯州犁把晋厉公亲兵的情况向楚共王报告。苗贲皇在晋厉公的旁边,也把楚共王亲兵的情况向晋厉公报告。晋厉公左右的将士们都说:“有国家中杰出的人物在那里,而且军阵厚实,不能抵挡。”苗贲皇对晋厉公说:“楚国的精兵在于他们中军的王族而已。请求把我们的精兵分开去攻击他们的左右军,再集中三军攻打楚王的亲兵,一定可以把他们打得大败。”晋厉公让太史占筮。太史说:“吉利。得到《复》。卦辞说:‘南方的国家局促,射它的国王,箭头中目。’国家局促,国王受伤,不失败,还等待什么?”晋厉公听从了。晋军营前头有泥沼,于是晋军都或左或右地避开泥沼而行。步毅驾御晋厉公的战车,栾鍼作为车右。彭名驾御楚共王的战车,潘党作为车右。石首驾御郑成公的战车,唐苟作为车右。栾、范领着他们私族部队左右护卫着晋厉公前进。战车陷在泥沼里。栾书打算将晋厉公装载在自己车上。他儿子栾鍼说:“书退下去!国家有大事,你哪能一人揽了?而且侵犯别人的职权,这是冒犯;丢弃自己的职责,这是怠慢;离开自己的部下,这是扰乱。有三件罪名,不能违犯啊。”于是就掀起晋厉公的战车离开泥沼。 +六月二十八日,潘尫的儿子党和养由基把皮甲重叠而射它,穿透了七层。拿去给楚共王看,说:“君王有这样两个臣下在这里,还有什么可怕的?”楚共王发怒说:“真丢人!明早作战,你们射箭,将会死在这武艺上。”吕锜梦见自己射月亮,射中,自己却退进了泥塘里。占卜,说:“姬姓,是太阳;异姓,是月亮,这一定是楚共王了。射中了他,自己又退进泥里,就一定会战死。”等到作战时,吕锜射中了楚共王的眼睛。楚王召唤养由基,给他两支箭,让他射吕锜。结果射中吕锜的脖子,伏在弓套上死了。养由基拿了剩下的一支向楚共王复命。 +郤至三次碰到楚共王的士兵,见到楚共王时,一定下车,脱下头盔,快步向前而走。楚共王派工尹襄送上一张弓去问候,说:“正当战事激烈的时候,有一位身穿浅红色牛皮军服的人,是君了啊!刚才见到我而快走,恐怕是受伤了吧!”郤至见到客人,脱下头盔接受命令,说:“贵国君王的外臣郤至跟随寡君作战,托君王的福,参与了披甲的行列,不敢拜谢命令。谨向君王报告没有受伤,感谢君王惠赐给我的命令。由于战事的缘故,谨向使者敬礼。”于是,三次向使者肃拜以后才退走。 +晋国的韩厥追赶郑成公,他的车夫杜溷罗说:“是否赶快追上去?他们的御者屡屡回头看,注意力不在马上,可以赶上。”韩厥说:“不能再次羞辱国君。”于是就停止追赶。郤至追赶郑成公,他的车右茀翰胡说:“另外派轻车从小道迎击,我追上他的战车而把他俘虏下来。”郤至说:“伤害国君要受到刑罚。”也停止了追赶。石首说:“从前卫懿公由于不去掉他的旗子,所以才在荧地战败。”于是就把旗子放进弓袋里。唐苟对石首说:“您在国君旁边,战败者应该一心保护国君。我不如您,您带着国君逃走,我请求留下。”于是唐苟就战死了。 +楚军被逼在险阻的地带,叔山冉对养由基说:“虽然国君有命令,为了国家的缘故,您一定要射箭。”养由基就射晋军,再射,被射的人都被射死。叔山冉举起晋国人投掷过去,掷中战车,折断了车前的横木。晋军于是停下来。囚禁了楚国的公子茷。 +栾鍼见到子重的旌旗,请求说:“楚国人说那面旌旗是子重的旗号,他恐怕就是子重吧。当初下臣出使到楚国,子重问起晋国的勇武表现在哪里,下臣回答说:‘喜好整齐,按部就班。’子重说:‘还有什么?’下臣回答说:‘喜好从容不迫。’现在两国兴兵,不派遣使者,不能说是按部就班;临到事情而不讲信用,不能说是从容不迫。请君王派人替我给子重进酒。”晋厉公答应了,派遣使者拿着酒器奉酒,到了子重那里,说:“寡君缺乏使者,让栾鍼执矛侍立在他左右,因此不能犒赏您的从者,派我前来代他送酒。”子重说:“他老人家曾经跟我在楚国说过一番话,送酒来一定是这个原因。他的记忆力不也是很强吗?”受酒而饮,不留难使者而重新击鼓。 +早晨开始作战,直到黄昏还没有结束战争。子反命令军官视察伤情,补充步兵车兵,修理盔甲武器,陈列战车马匹,鸡叫的时候吃饭,唯主帅的命令是听。晋国因此担心。苗贲皇通告全军说:“检阅战车、补充士卒,喂好马匹,磨快武器,整顿军阵、巩固行列,饱吃一顿、再次祷告,明天再战!”就故意放松楚国的俘虏让他们逃走。楚共王听到这些情况,召子反一起商量。穀阳竖献酒给子反,子反喝醉了不能进见。楚共王说:“这是上天要让楚国失败啊!我不能等待了。”于是就夜里逃走了。晋军进入楚国军营,吃了三天楚军留下的粮食。范文子站在兵马前面,说:“君王年幼,下臣们不才,怎么能得到这个地步?君王还是要警惕啊!《周书》说,‘天命不能常在不变’,说的是有德的人就可以享有天命。” +楚军回去,到达瑕地,楚共王派人对子反说:“先大夫让军队覆没,当时国君不在军中。现在您没有过错,这是我的罪过。”子反再拜叩头说:“君王赐下臣去死,死而不朽。下臣的士兵的确败逃了,这是下臣的罪过。”子重也派人对子反说:“当初让军队覆没的人,他的结果你也听到过了。何不自己打算一下!”子反回答说:“即使没有先大夫自杀谢罪的事,大夫命令侧死去,侧岂敢贪生而陷于不义?侧使国君的军队败亡,岂敢忘记一死?”楚共王派人阻止他,没来得及,子反就自杀了。 +作战的第二天,齐国国佐、高无咎到达军中,卫献公从卫国出来,鲁成公从坏隤出来。宣伯和穆姜私通,想要去掉季、孟两人而占取他们的家财。成公将要出行,穆姜送他,让他驱逐这两个人。成公把晋国的危难告诉她,说:“请等我回来再听取您的命令。”穆姜生气,公子偃、公子鉏快步走过,穆姜指着他们说:“你要不同意,他们都可以是国君!”鲁成公在坏隤等待,防护宫室、加强戒备、设置守卫,然后出行,所以去晚了。让孟献子在公宫留守。 +秋季,鲁成公和晋厉公、齐灵公、卫献公、宋国华元、邾国人在沙随会见,商量进攻郑国。宣伯派人告诉郤犫说:“鲁侯在坏隤等着,以等待胜利者。”郤犫率领新军,同时做公族大夫,主持东方诸侯的事务。他从宣伯那里拿了财物,而在晋厉公那里毁谤鲁成公。晋厉公就不和鲁成公见面。 +曹国人向晋国请求说:“自从我先君宣公去世,国内的人们说:‘怎么办?忧患还没有消除。’而贵国又讨伐我寡君,因而使镇抚曹国国家的公子子臧逃亡,这是在大举灭曹,莫非由于先君有罪吧!可是如果有罪,那么君王又使他参加会盟。君王不丢失德行和刑罚,所以才能称霸诸侯,岂独丢弃敝邑?谨在私下向贵国表达真情。” +七月,鲁成公会合尹武公和诸侯进攻郑国。成公将要出行,穆姜又像以前一样命令成公。成公又在宫中设了防备以后才出行。诸侯的军队驻扎在郑国西部,我国的军队驻扎在督扬,不敢经过郑国。子叔声伯派叔孙豹请求晋军前来迎接我军,又在郑国郊外为晋军准备饭食。晋军为迎接我军而来到。声伯四天没有吃饭等着他们,直到让晋国的使者吃了饭以后自己才吃。 +诸侯迁移到制田,知武子作为下军副帅,率领诸侯的军队入侵陈国,到达鸣鹿,因此入侵蔡国。还没有回来,诸侯又迁移到颍上。七月二十四日,郑国的子罕发动夜袭,宋国、齐国、卫国都溃不成军。 +曹国人再次向晋国请求。晋厉公对子臧说:“你回去,我送回你们国君。”子臧回国,曹成公也回来了,子臧把他的封邑和卿的职位全部交出去而不再做官。 +叔孙侨如派人告诉郤犫说:“鲁国有季氏、孟氏,就好像晋国有栾氏、范氏,政令就是在那里制订的。现在他们商量说:‘晋国的政令出于不同的家族,不能统一,这是不能服从的。宁可事奉齐国和楚国,哪怕亡国,也不要跟从晋国了。’晋国如果要在鲁国行使自己的意志,请留下行父而杀了他,我把蔑杀死,事奉晋国,就没有二心了。鲁国没有二心,其他小国一定服从晋国。不这样,行父回国就必然背叛晋国。” +九月,晋国人在苕丘逮捕了季孙行父。成公回来。在郓地等待,派子叔声伯向晋国请求放回季孙。郤犫说:“如果去掉仲孙蔑而留下季孙行父,我给您鲁国的政权,对待您比对公室还亲。”声伯回答说:“侨如的情况,您一定听到了。如果去掉蔑和行父,这是大大地丢弃鲁国而加罪寡君。如果还不丢弃鲁国,而承您向周公求福,让寡君能够事奉晋国国君,那么这两个人,是鲁国的社稷之臣。如果早晨去掉他们,鲁国必然晚上灭亡。鲁国靠近晋国的仇敌,灭亡了以后就会变成仇敌,还来得及补救吗?”郤犫说:“我为您请求封邑。”声伯回答说:“婴齐,是鲁国的小臣,岂敢仗恃大国以求取丰厚的官禄?我奉了寡君的命令前来请求,如果得到所请求的,您的恩赐就很多了,还有什么请求?”范文子对栾武子说:“季孙在鲁国,辅助过两个国君。妾不穿丝绸,马不吃粮食,难道他不是忠诚吗?相信奸邪而丢弃忠良,怎么对付诸侯?子叔婴齐接受国君的命令没有私心,为国家谋划也没有二心,为自己打算而不忘国君。如果拒绝他的请求,这是丢弃善人啊!您还是考虑一下吧!”于是允许鲁国讲和,赦免了季孙行父。 +冬季,十月,放逐叔孙侨如并且和大夫们结盟。侨如逃亡到齐国。 +十二月,季孙和郤犫在扈地结盟。回国,暗杀了公子偃,把叔孙豹从齐国召回而立了他。 +齐国的声孟子和侨如私通,让他位于高氏、国氏之间。侨如说:“不能再犯罪了。”便逃亡到卫国,也位于各卿之间。 +晋厉公派遣郤至到成周去献对楚国作战的战利品,郤至和单襄公说话,屡次夸耀自己的功劳。单襄公对大夫们说:“郤至恐怕要被杀吧!他的地位在七个人之下,而想要盖过他的上级。聚集怨恨,这是祸乱的根本。多招怨恨,是自造祸乱的阶梯,怎么还能据有官位?《夏书》说:‘怨恨难道只是在看得到的地方?看不到的倒是应该考虑。’这是说在细微之处也要谨慎。现在郤至把看不到的怨恨都变得明显了,这样可以吗?” + +成公十七年 +【经】十有七年春,卫北宫括帅师侵郑。夏,公会尹子、单子、晋侯、齐侯、宋公、卫侯、曹伯、邾人伐郑。六月乙酋,同盟于柯陵。秋,公至自会。齐高无咎出奔莒。九月辛丑,用郊。晋侯使荀罃来乞师。冬,公会单子、晋侯、宋公、卫侯、曹伯、齐人、邾人伐郑。十有一月,公至自伐郑。壬申,公孙婴卒于貍脤。十有二月丁巳朔,日有食之。邾子玃且卒。晋杀其大夫郤錡、郤犨、郤至。楚人灭舒庸。 +【传】十七年春,王正月,郑子驷侵晋虚、滑。卫北宫括救晋,侵郑,至于高氏。 +夏五月,郑大子髡顽、侯孺为质于楚,楚公子成、公子寅戍郑。公会尹武公、单襄公及诸侯伐郑,自戏童至于曲洧。 +晋范文子反自鄢陵,使其祝宗祈死,曰:“君骄侈而克敌,是天益其疾也。难将作矣!爱我者惟祝我,使我速死,无及于难,范氏之福也。”六月戊辰,士燮卒。 +乙酉同盟于柯陵,寻戚之盟也。 +楚子重救郑,师于首止。诸侯还。 +齐庆克通于声孟子,与妇人蒙衣乘辇而入于闳。鲍牵见之,以告国武子,武子召庆克而谓之。庆克久不出,而告夫人曰:“国子谪我!”夫人怒。国子相灵公以会,高、鲍处守。及还,将至,闭门而索客。孟子诉之曰:“高、鲍将不纳君,而立公子角。国子知之。”秋七月壬寅,刖鲍牵而逐高无咎。无咎奔莒,高弱以卢叛。齐人来召鲍国而立之。 +初,鲍国去鲍氏而来为施孝叔臣。施氏卜宰,匡句须吉。施氏之宰,有百室之邑。与匡句须邑,使为宰。以让鲍国,而致邑焉。施孝叔曰:“子实吉。”对曰:“能与忠良,吉孰大焉!”鲍国相施氏忠,故齐人取以为鲍氏后。仲尼曰:“鲍庄子之知不如葵,葵犹能卫其足。” +冬,诸侯伐郑。十月庚午,围郑。楚公子申救郑,师于汝上。十一月,诸侯还。 +初,声伯梦涉洹,或与己琼瑰,食之,泣而为琼瑰,盈其怀。从而歌之曰:“济洹之水,赠我以琼瑰。归乎!归乎!琼瑰盈吾怀乎!”惧不敢占也。还自郑,壬申,至于狸脤而占之,曰:“余恐死,故不敢占也。今众繁而从余三年矣,无伤也。”言之,之莫而卒。 +齐侯使崔杼为大夫,使庆克佐之,帅师围卢。国佐从诸侯围郑,以难请而归。遂如卢师,杀庆克,以谷叛。齐侯与之盟于徐关而复之。十二月,卢降。使国胜告难于晋,待命于清。 +晋厉公侈,多外嬖。反自鄢陵,欲尽去群大夫,而立其左右。胥童以胥克之废也,怨郤氏,而嬖于厉公。郤錡夺夷阳五田,五亦嬖于厉公。郤犨与长鱼矫争田,执而梏之,与其父母妻子同一辕。既,矫亦嬖于厉公。栾书怨郤至,以其不从己而败楚师也,欲废之。使楚公子伐告公曰:“此战也,郤至实召寡君。以东师之未至也,与军帅之不具也,曰:‘此必败!吾因奉孙周以事君。’”公告栾书,书曰:“其有焉!不然,岂其死之不恤,而受敌使乎?君盍尝使诸周而察之?”郤至聘于周,栾书使孙周见之。公使觇之,信。遂怨郤至。 +厉公田,与妇人先杀而饮酒,后使大夫杀。郤至奉豕,寺人孟张夺之,郤至射而杀之。公曰:“季子欺余。” +厉公将作难,胥童曰:“必先三郤,族大多怨。去大族不逼,敌多怨有庸。”公曰:“然。”郤氏闻之,郤錡欲攻公,曰:“虽死,君必危。”郤至曰:“人所以立,信、知、勇也。信不叛君,知不害民,勇不作乱。失兹三者,其谁与我?死而多怨,将安用之?君实有臣而杀之,其谓君何?我之有罪,吾死后矣!若杀不辜,将失其民,欲安,得乎?待命而已!受君之禄是以聚党。有党而争命,罪孰大焉!” +壬午,胥童、夷羊五帅甲八百,将攻郤氏。长鱼矫请无用众,公使清沸魋助之,抽戈结衽,而伪讼者。三郤将谋于榭。矫以戈杀驹伯、苦成叔于其位。温季曰:“逃威也!”遂趋。矫及诸其车,以戈杀之,皆尸诸朝。 +胥童以甲劫栾书、中行偃于朝。矫曰:“不杀二子,忧必及君。”公曰:“一朝而尸三卿,余不忍益也。”对曰:“人将忍君。臣闻乱在外为奸,在内为轨。御奸以德,御轨以刑。不施而杀,不可谓德。臣逼而不讨,不可谓刑。德刑不立,奸轨并至。臣请行。”遂出奔狄。公使辞于二子,曰:“寡人有讨于郤氏,既伏其辜矣。大夫无辱,其复职位。”皆再拜稽首曰:“君讨有罪,而免臣于死,君之惠也。二臣虽死,敢忘君德。”乃皆归。公使胥童为卿。 +公游于匠丽氏,栾书、中行偃遂执公焉。召士□,士□辞。召韩厥,韩厥辞,曰:“昔吾畜于赵氏,孟姬之谗,吾能违兵。古人有言曰:‘杀老牛莫之敢尸。’而况君乎?二三子不能事君,焉用厥也!” +舒庸人以楚师之败也,道吴人围巢,伐驾,围厘、虺,遂恃吴而不设备。楚公子櫜师袭舒庸,灭之。 +闰月乙卯晦,栾书、中行偃杀胥童。民不与郤氏,胥童道君为乱,故皆书曰:“晋杀其大夫。” +译文 +十七年春季,周王朝历法的正月,郑国子驷进攻晋国的虚、滑两地。卫国的北宫括救援晋国,侵袭郑国,到达高氏。 +夏季,五月,郑国太子髡顽和侯卻獳到楚国作为人质,楚国公子成、公子寅戍守在郑国。鲁成公会合尹武公、单襄公以及诸侯进攻郑国,从戏童到达曲洧。 +晋国的范文子从鄢陵回国,让他的祝宗祈求早点死去,说:“国君骄横奢侈而又战胜敌人,这是上天增加他的毛病,祸难将要起来了。爱我的人只有诅咒我,让我快点死去,不要及于祸难,这就是范氏的福气。”六月初九日,”范文子死。 +六月二十六日,鲁成公和尹子、单子、晋厉公、齐灵公、宋平公、卫献公、曹成公、邾国人在柯陵结盟,这是为了重温戚地的盟会。 +楚国的子重援救郑国,军队驻扎在首止。诸侯就退兵回国。 +齐国的庆克和声孟子私通,穿着女人衣服和女人一起坐辇进入宫中的夹道门。鲍牵见到了,报告国武子。武子把庆克召来告诉他。庆克躲在家里很久不出门,报告声孟子说:“国子责备我。”声孟子发怒。国武子作为齐灵公的相礼参加会见,高无咎、鲍牵留守。等到回国,将要到达的时候,关闭城门,检查旅客。声孟子诬陷说:“高、鲍两人打算不接纳国君而立公子角,国子参与这件事。”秋季,七月十三日,砍去了鲍牵的双脚而驱逐了高无咎。高无咎逃亡到莒国。高弱据有卢地而发动叛乱。齐国人来鲁国召回鲍国而立了他。 +当初,鲍国离开鲍氏来鲁国做施孝叔的家臣。施氏占卜总管的人选,匡句须吉利。施氏的总管拥有一百家的采邑。施氏给了匡句须采邑,让他做总管,他却让给鲍国而且把采邑也给了鲍国。施孝叔说:“你是占卜认为吉利的。”匡句须回答说:“能够给忠良,还有比这再大的吉利吗?”鲍国辅助施氏很忠诚,所以齐国人把他召回去作为鲍氏的后嗣。孔子说:“鲍牵的聪明不如葵菜,葵菜还能保护自己的脚。” +冬季,诸侯进攻郑国。十月十二日,包围郑国。楚国公子申救援郑国,军队驻扎在汝水边上。十一月,诸侯退兵回国。 +当初,声伯梦见步行渡过洹水,有人将琼瑰给他吃了,哭出来的眼泪都成了琼瑰装满怀抱,跟着唱歌说:“渡过洹水,赠给我琼瑰。回去吧回去吧,琼瑰装满我的怀内!”醒来由于害怕而不敢占卜。从郑国回来,十一月某一天,到达狸脤,而占卜这件事,说:“我害怕死,所以不敢占卜。现在大家跟随我已经三年了,没有妨碍了。”说了这件事,到晚上就死了。 +齐灵公派崔杼做大夫,派庆克辅佐他,率领军队包围卢地。国佐跟从诸侯包围郑国,由于齐国发生祸难请求回国。国佐于是就到了包围卢地的军队里,杀了庆克,据有穀地而发动叛乱。齐灵公和国佐在徐关结盟以后,恢复了他的官位。十二月,卢地人投降。齐灵公派遣国胜向晋国报告祸难,并且让他在清地等候命令。 +晋厉公奢侈,有很多宠信的大夫。从鄢陵回来,想要全部去掉其他的大夫,而立左右宠信的人。胥童因为胥克的被废,怨恨郤氏而成为厉公宠臣。郤犫夺走了夷阳五的土田,夷阳五也为厉公所宠信。郤犫和长鱼矫争夺土田,把长鱼矫逮捕囚禁,和他的父母妻子同系在一个车辕上。不久以后,长鱼矫也受到厉公的宠信。栾书怨恨郤至,因为他不听自己的主意而又打败了楚军,想要废掉他。栾书让楚国的公子茷告诉厉公说:“这次战役,郤至实在是召来我寡君的,因为东方的军队没有到达和晋军统帅没有完全出动,他说:‘这一战晋国必然失败,我就乘机拥立孙周来事奉君王。’”厉公告诉栾书。栾书说:“恐怕有这回事。否则,难道他会不顾虑死,而接受敌人的使者吗?君王何不试着派他到成周而考察他一下呢?”郤至到成周聘问,栾书让孙周接见他,晋厉公派人窥探,证实了。于是厉公就怨恨郤至。 +晋厉公打猎,和女人一起首先射猎,并且喝酒,然后让大夫射猎。郤至奉献野猪,寺人孟张夺走野猪,郤至射死了孟张。厉公说:“郤至欺负我!” +厉公准备发动群臣讨伐郤至,胥童说:“一定要先从三郤开刀。他们族大,怨恨多。去掉大族,公室就不受逼迫;讨伐怨恨多的,容易有功。”厉公说:“对。”郤氏听到这件事,郤锜想要攻打厉公,说:“虽然我们一族就要死了,国君也必定危险了。”郤至说:“人能站得住,是由于有信用、明智、勇敢。有信用不能背叛国君,明智不能残害百姓,勇敢不能发动祸难。没有这三样,还有谁亲近我们?死了又增多怨恨,还有什么用?国君有了臣下而杀了他们,能把国君怎么办?我若有罪,死得已经晚了。如果国君杀害的是无罪的人,他将要失掉百姓,想要安定,行吗?还是听候命令吧。受了国君的禄位,因此才能聚集亲族。有了亲族而和国君相争,还有比这更大的罪过吗?” +十二月二十六日,胥童、夷羊五率领甲士八百人准备进攻郤氏,长鱼矫请求不要兴师动众,晋厉公派清沸魋去帮助他们。长鱼矫和清沸魋抽出戈来,衣襟相结,装成打架争讼的样子。三郤准备在台榭里和他们计议,长鱼矫乘机用戈在座位上刺死了郤锜和郤犫。郤至说:“无罪被杀,不如逃走。”于是赶快逃走。长鱼矫追上郤至的车子,用戈刺死了他。都陈尸在朝廷上。 +胥童带领甲士在朝廷上劫持了栾书、中行偃。长鱼矫说:“不杀这两个人,忧患必然会到国君身上。”晋厉公说:“一天之中而把三个卿的尸摆在朝上,我不忍心增加了。”长鱼矫回答说:“别人对君王会忍心的。下臣听说祸乱在外就是奸,在内就是轨。用德行来对待奸,用刑罚来对待轨。不施教化就加以杀戮,不能叫做德行;臣下逼迫国君而不加讨伐,不能叫做刑罚。德行和刑罚不加树立,奸、轨就一起来了,下臣请求离去。”于是就逃亡到狄人那里。厉公派人向栾书和中行偃辞谢说:“寡人讨伐郤氏,郤氏已经伏罪,大夫不要把劫持的事作为耻辱,还是各复其位吧!”他们都再拜叩头说:“君王讨伐有罪的人,而赦免下臣一死,这是君王的恩惠。我们两个人即使死了,哪里敢忘记君王的恩德?”于是都回去了。晋厉公派胥童做卿。 +晋厉公在匠丽氏那里游玩,栾书、中行偃就乘机抓住了他。召唤士匄,士匄辞谢。召唤韩厥,韩厥辞谢说:“从前我在赵氏家里养大,孟姬诬陷赵氏,我能顶住不出兵。古人有话说,‘杀老牛没有人敢作主’,何况是国君呢?您几位不能事奉国君,又哪里用得到厥呢?” +舒庸人由于楚军的战败,引导吴国人包围巢地,进攻驾地,包围厘地和虺地,因此就依仗着吴国而不设防。楚国公子槖师入侵舒庸,灭亡了舒庸。 +闰月二十九日,栾书、中行偃杀了胥童。百姓不亲附郤氏,胥童引导国君作乱,所以《春秋》都记载说“晋杀其大夫”。 + +成公十八年 +【经】十有八年春王正月,晋杀其大夫胥童。庚申,晋弑其君州蒲。齐杀其大夫国佐。公如晋。夏,楚子、郑伯伐宋。宋鱼石复入于彭城。公至自晋。晋侯使士□来聘。秋,杞伯来朝。八月,邾子来朝,筑鹿囿。己丑,公薨于路寝。冬,楚人、郑人侵宋。晋侯使士鲂来乞师。十有二月,仲孙蔑会晋侯、宋公、卫侯、邾子、齐崔杼同盟于虚朾。丁未,葬我君成公。 +【传】十八年春,王正月庚申,晋栾书、中行偃使程滑弑厉公,葬之于翼东门之外,以车一乘。使荀罃、士鲂逆周子于京师而立之,生十四年矣。大夫逆于清原,周子曰:“孤始愿不及此。虽及此,岂非天乎!抑人之求君,使出命也,立而不从,将安用君?二三子用我今日,否亦今日,共而从君,神之所福也。”对曰:“群臣之愿也,敢不唯命是听。”庚午,盟而入,馆于伯子同氏。辛巳,朝于武宫,逐不臣者七人。周子有兄而无慧,不能辨菽麦,故不可立。 +齐为庆氏之难故,甲申晦,齐侯使士华免以戈杀国佐于内宫之朝。师逃于夫人之宫。书曰:“齐杀其大夫国佐。”弃命,专杀,以谷叛故也。使清人杀国胜。国弱来奔,王湫奔莱。庆封为大夫,庆佐为司寇。既,齐侯反国弱,使嗣国氏,礼也。 +二月乙酉朔,晋侯悼公即位于朝。始命百官,施舍、己责,逮鳏寡,振废滞,匡乏困,救灾患,禁淫慝,薄赋敛,宥罪戾,节器用,时用民,欲无犯时。使魏相、士鲂、魏颉、赵武为卿。荀家、荀会、栾□、韩无忌为公族大夫,使训卿之子弟共俭孝弟。使士渥浊为大傅,使修范武子之法。右行辛为司空,使修士蒍之法。弁纠御戎,校正属焉,使训诸御知义。荀宾为右,司士属焉,使训勇力之士时使。卿无共御,立军尉以摄之。祁奚为中军尉,羊舌职佐之,魏绛为司马,张老为候奄。铎遏寇为上军尉,籍偃为之司马,使训卒乘亲以听命。程郑为乘马御,六驺属焉,使训群驺知礼。凡六官之长,皆民誉也。举不失职,官不易方,爵不逾德,师不陵正,旅不逼师,民无谤言,所以复霸也。 +公如晋,朝嗣君也。 +夏六月,郑伯侵宋,及曹门外。遂会楚子伐宋,取朝郏。楚子辛、郑皇辰侵城郜,取幽丘,同伐彭城,纳宋鱼石、向为人、鳞朱、向带、鱼府焉,以三百乘戍之而还。书曰“复入”,凡去其国,国逆而立之,曰“入”;复其位,曰“复归”;诸侯纳之,曰“归”。以恶曰复入。宋人患之。西鉏吾曰:“何也?若楚人与吾同恶,以德于我,吾固事之也,不敢贰矣。大国无厌,鄙我犹憾。不然,而收吾憎,使赞其政,以间吾衅,亦吾患也。今将崇诸侯之奸,而披其地,以塞夷庚。逞奸而携服,毒诸侯而惧吴、晋。吾庸多矣,非吾忧也。且事晋何为?晋必恤之。” +公至自晋。晋范宣子来聘,且拜朝也。君子谓:“晋于是乎有礼。” +秋,杞桓公来朝,劳公,且问晋故。公以晋君语之。杞伯于是骤朝于晋而请为昏。 +七月,宋老佐、华喜围彭城,老佐卒焉。 +八月,邾宣公来朝,即位而来见也。 +筑鹿囿,书,不时也。 +己丑,公薨于路寝,言道也。 +冬十一月,楚子重救彭城,伐宋,宋华元如晋告急。韩献子为政,曰:“欲求得人,必先勤之,成霸安强,自宋始矣。”晋侯师于台谷以救宋,遇楚师于靡角之谷。楚师还。 +晋士鲂来乞师。季文子问师数于臧武仲,对曰:“伐郑之役,知伯实来,下军之佐也。今彘季亦佐下军,如伐郑可也。事大国,无失班爵而加敬焉,礼也。”从之。 +十二月,孟献子会于虚朾,谋救宋也。宋人辞诸侯而请师以围彭城。孟献子请于诸侯,而先归会葬。 +丁未,葬我君成公,书,顺也。 +译文 +十八年春季,周王朝历法的正月初五日,晋国的栾书、中行偃派程滑杀死晋厉公,葬在翼地的东门外边,仅仅用了一辆车子。派遣荀罃、士鲂到京师迎接周子而立他为国君,这时周子才十四岁。大夫在清原迎接,周子说:“我开始的愿望并没有到这地步,现在虽然到了这地步,难道不是上天的意志吗?然而人们要求有国君,这是为了让他发布命令。立了以后又不听他的,还哪里用得着国君?您几位用得着我,在今天;用不着,也在今天,恭敬而听从国君,这是神灵所保佑的。”大夫们回答说:“这是下臣们的愿望,岂敢不唯命是听。”十五日,结盟以后才进入国都,住在伯子同氏家里。二十六日,周子在武宫朝见。驱逐了不适合做臣的七个人。周子有一个哥哥是白痴,不能辨别豆子和麦子,所以不能立为国君。 +齐国由于庆氏祸难的缘故,正月二十九日,齐灵公派士华免用戈把国佐杀死在内宫的前堂,大家逃到夫人的宫里。《春秋》记载说“齐杀其大夫国佐”,这是由于国佐丢弃君命、专权杀人、据有穀地而叛变的缘故。让清地人杀了国胜。国弱逃亡到鲁国来。王湫逃亡到莱地。庆封做大夫,庆佐做司寇。不久以后,齐灵公让国弱回国,要他继承国氏宗嗣,这是合于礼的。 +二月初一日,晋悼公在朝廷上即位。开始任命百官,赐舍财物而免除百姓对国家的欠债,照顾施恩惠给鳏夫寡妇,起用被废黜和长居下位的好人,救济贫困,援救灾难,禁止邪恶,少征赋税,宽恕罪过,节约器用,在农闲时使用农民,个人的欲望不侵占农时。派魏相、士鲂、魏颉、赵武做卿;荀家、荀会、栾黡、韩无忌做公族大夫,让他们教育卿的子弟恭敬、节俭、孝顺、友爱。派士渥浊做太傅,让他学习范武子的法度;右行辛做司空,让他学习士?的法度。弁纠驾御战车,校正官属他管辖,让他教育御者们明白道理。荀宾作为车右,司士官属他管辖,让他教育勇士们待时选用。卿没有固定的御者,设立军尉兼管这些事。祁奚做中军尉,羊舌职辅佐他;魏绛做司马,张老做侦察长,铎遏寇做上军尉,籍偃为他做司马,让他教育步兵车兵,一致听从命令。程郑做乘马御,六驺属他管辖,让他教育他们明白礼仪。凡是各部门的长官,都是百姓赞扬的人。举拔的人不失职,做官的人不改变常规,爵位不超过德行,师不欺陵正,旅不逼迫师,百姓没有指责的话,这就是晋悼公再次称霸于诸侯的原因。 +鲁成公去到晋国,朝见新立的国君晋悼公。 +夏季,六月,郑成公入侵宋国,到达宋国曹门外。于是就会合楚共王一起进攻宋国,占领了朝郏。楚国子辛、郑国的皇辰入侵城郜,占取幽丘。一起进攻彭城,送回了宋国的鱼石、向为人、鳞朱、向带、鱼府,用三百辆战车留守,然后回国。《春秋》记载说“复入”。凡是离开自己的国家,本国迎接而且立他,叫做“入”;回复原来的位置,叫做“复归”;诸侯把他送回来,叫做“归”;用武力的叫做“复入”。宋国人担心这件事。西鉏吾说:“担心干什么?如果楚国人和我们同仇敌忾,施恩德给我们,我们本来是会事奉他们的,不敢有三心二意。现在大国的欲望没有个止境,即使把我国作为他们的边邑还会觉得遗憾。否则,收留我们讨厌的人,让他们辅助政事,等机会钻我们的空子,也是我们的祸害。现在却尊崇诸侯的乱臣而且分给他们以土地,阻塞各国之间的通道,使乱臣得以快意而使服从他们的国家离心,毒害诸侯而使吴国,晋国恐惧,这样,我们的利益多啦,并不是我们的忧患。而且事奉晋国为了什么?晋国必然会来救助我们。” +鲁成公从晋国回到鲁国。晋国的范宣子来鲁国聘问,同时答拜对晋君的朝见。君子认为晋国在这件事情上合于礼。 +秋季,杞桓公前来朝见,慰劳成公,同时询问晋国的消息。成公把晋君的政治措施告诉他。杞桓公因此很快地向晋国朝见并请求通婚。 +七月,宋国的老佐、华喜包围彭城,老佐死于这次战役中。 +八月,邾宣公前来朝见,这是由于他新即位而前来进见。 +鲁国建造鹿囿,《春秋》所以记载这件事,是由于不合于时令。 +初七日,鲁成公死在寝宫里,这是说合于正常的情况。 +冬季,十一月,楚国的子重救援彭城,进攻宋国。宋国的华元去到晋国告急。这时韩献子执政,说:“想要得到别人的拥护,一定要先为他付出勤劳。成就霸业,安定疆土,从宋国开始了。”晋悼公领兵驻扎在台谷以救宋国。在靡角之谷和楚军相遇,楚军退走回国。 +晋国的士鲂前来请求出兵。季文子向臧武仲问出兵的数字,他回答说:“攻打郑国那次战役,是知伯来请求出兵的,他是下军的辅佐。现在士鲂也辅佐下军,所出兵数,像攻打郑国时一样就可以了。事奉大国,不要违背使者的爵位次序而要更加恭敬,这是合于礼的。”季文子听从了。 +十二月,孟献子和晋悼公、宋平公、卫献公、邾宣公、齐国崔杼在虚朾会见,策划救援宋国。宋国人辞谢诸侯,而请求出兵以包围彭城。孟献子向诸侯请求先回国参加葬礼。 +十二月二十六日,“葬我君成公”,《春秋》这样说,是表示一切安排顺当。 + + +襄公 + + +襄公元年 +【经】元年春王正月,公即位。仲孙蔑会晋栾□、宋华元、卫宁殖、曹人、莒人、邾人、滕人、薛人围宋彭城。夏,晋韩厥帅师伐郑,仲孙蔑会齐崔杼、曹人、邾人、杞人次于鄫。秋,楚公子壬夫帅师侵宋。九月辛酉,天王崩。邾子来朝。冬,卫侯使公孙剽来聘。晋侯使荀罃来聘。 +【传】元年春己亥,围宋彭城。非宋地,追书也。于是为宋讨鱼石,故称宋,且不登叛人也,谓之宋志。彭城降晋,晋人以宋五大夫在彭城者归,置诸瓠丘。齐人不会彭城,晋人以为讨。二月,齐大子光为质于晋。 +夏五月,晋韩厥、荀偃帅诸侯之师伐郑,入其郛,败其徒兵于洧上。于是东诸侯之师次于鄫,以待晋师。晋师自郑以鄫之师侵楚焦夷及陈,晋侯、卫侯次于戚,以为之援。 +秋,楚子辛救郑,侵宋吕、留。郑子然侵宋,取犬丘。 +九月,邾子来朝,礼也。 +冬,卫子叔、晋知武子来聘,礼也。凡诸侯即位,小国朝之,大国聘焉,以继好结信,谋事补阙,礼之大者也。 +译文 +元年春季,正月己亥这一天,诸侯军队包围宋国彭城。彭城已经不属于宋国的地方了,《春秋》所以这样记载,这是追记以前的情况。当时为了宋国去讨伐鱼石,所以仍称宋国,而且反对叛变者,这是宋国人的意志。彭城投降晋国,晋国人带了在彭城的五个宋国大夫回去,安置在瓠丘。齐国人没有在彭城会合,晋国人因此讨伐齐国。二月,齐太子光到晋国作为人质。 +夏季,五月,晋国韩厥、荀偃率领诸侯的军队进攻郑国,进入它的外城,在洧水边上打败了它的步兵。在这时候东方各诸侯国的军队驻扎在鄫地,等待晋军。晋军从郑国带领驻在鄫地的军队入侵楚国的焦地、夷地和陈国。晋悼公、卫献公住在戚地,作为后援。 +秋季,楚国子辛救援郑国,入侵宋国的吕地和留地。郑国子然入侵宋国,占取了犬丘。 +九月,邾宣公来鲁国朝见,这是合于礼的。 +冬季,卫国子叔、晋国知武子来鲁国聘问,这是合于礼的。凡是诸侯即位,小国前来朝见,大国就来聘问,以继续友好、取得信任、商讨国事、补正过失,这是礼仪中的大事。 + + +襄公二年 +【经】二年春王正月,葬简王。郑师伐宋。夏五月庚寅,夫人姜氏薨。六月庚辰,郑伯仑卒。晋师、宋师、卫宁殖侵郑。秋七月,仲孙蔑会晋荀罃、宋华元、卫孙林父、曹人、邾人于戚。己丑,葬我小君齐姜。叔孙豹如宋。冬,仲孙蔑会晋荀罃、齐崔杼、宋华元、卫孙林父、曹人、邾人、滕人、薛人、小邾人于戚,遂城虎牢。楚杀其大夫公子申。 +【传】二年春,郑师侵宋,楚令也。 +齐侯伐莱,莱人使正舆子赂夙沙卫以索马牛,皆百匹,齐师乃还。君子是以知齐灵公之为“灵”也。 +夏,齐姜薨。初,穆姜使择美檟,以自为榇与颂琴。季文子取以葬。君子曰:“非礼也。礼无所逆,妇,养姑者也,亏姑以成妇,逆莫大焉。《诗》曰:‘其惟哲人,告之话言,顺德之行。’季孙于是为不哲矣。且姜氏,君之妣也。《诗》曰:‘为酒为醴,烝畀祖妣,以洽百礼,降福孔偕。’” +齐侯使诸姜宗妇来送葬。召莱子,莱子不会,故晏弱城东阳以逼之。 +郑成公疾,子驷请息肩于晋。公曰:“楚君以郑故,亲集矢于其目,非异人任,寡人也。若背之,是弃力与言,其谁昵我?免寡人,唯二三子!” +秋七月庚辰,郑伯仑卒。于是子罕当国,子驷为政,子国为司马。晋师侵郑,诸大夫欲从晋。子驷曰:“官命未改。”   会于戚,谋郑故也。孟献子曰:“请城虎牢以逼郑。”知武子曰:“善。鄫之会,吾子闻崔子之言,今不来矣。滕、薛、小邾之不至,皆齐故也。寡君之忧不唯郑。罃将复于寡君,而请于齐。得请而告,吾子之功也。若不得请,事将在齐。君子之请,诸侯之福也,岂唯寡君赖之。” +穆叔聘于宋,通嗣君也。 +冬,复会于戚,齐崔武子及滕、薛、小邾之大夫皆会,知武子之言故也。遂城虎牢,郑人乃成。 +楚公子申为右司马,多受小国之赂,以逼子重、子辛,楚人杀之。故书曰:“楚杀其大夫公子申。” +译文 +二年春季,郑国的军队侵袭宋国,这是受楚国的命令。 +齐灵公进攻莱国,莱国人派正舆子把精选的马和牛各一百匹赠送给夙沙卫,齐军就退兵回去。君子因此而知道了齐灵公所以谥为“灵”的缘故。 +夏季,齐姜去世。当初,穆姜派人选择上好的槚木,为自己作了内棺和颂琴,季文子把它拿来安葬齐姜。君子说:“这是不合于礼的,礼不能有所不顺。媳妇是奉养婆婆的人,亏损婆婆以成全了媳妇,没有比这再大的不顺了。《诗》说:‘只有明智的人,才可以把好话告诉他,要他顺着道德而行事。’季孙在这件事情上就很不明智了,而且穆姜还是国君的祖母。《诗》说:‘酿造甜酒,敬献祖妣,合于礼仪,遍降福气。’” +齐灵公派遣嫁给齐大夫的宗女和同姓大夫的妻子前来鲁国送葬,召见莱子。莱子不参加会见,所以晏弱在东阳筑城来逼迫莱国。 +郑成公生病,子驷请求服从晋国来解除对楚国的负担。郑成公说:“楚国的国君由于郑国的缘故,他的眼睛被箭射中。不是为了别人,是为了我啊!如果背弃他,这是丢弃了人家的功劳和自己的誓言,还有谁来亲近我?使我免于过错,就是看你们几位的了。” +秋季,七月庚辰,郑成公仑去世。于是由子罕掌政,由子驷处理政务,子国出任司马。当时晋军侵略郑国,郑大夫都主张服从晋国。子驷说:“国君的命令没有改变。” +仲孙蔑和晋国荀罃、宋国华元、卫国孙林父、曹国人、邾国人在戚地会见,这是为了商讨征服郑国的办法。仲孙蔑说:“请在虎牢筑城以逼迫郑国。”知武子说:“好。鄫地的盟会,您听到了齐国代表崔杼的话,现在他不来了。滕国、薛国、小邾国的都不来了,都是由于齐国的缘故。寡君的忧虑不仅在于郑国。罃准备向寡君报告并向齐国请求会见。得到允许后而告诉诸侯在虎牢筑城,这是大夫的功劳。如果得不到允许,战争就会在齐国发生。大夫的请求,是诸侯的福气,岂独寡君依靠这些?” +穆叔到宋国聘问,通告新君即位的事。 +冬季,再次在戚地会见,齐国的崔武子和滕国、薛国、小邾国的大夫都参加会见,这是由于知武子这一番话的缘故。于是就在虎牢筑城。郑国人这才要求讲和。 +楚国的公子申做右司马,接受了小国很多财礼,以逼迫子重、子辛。楚国人杀了他,所以《春秋》记载说“楚杀其大夫公子申。” + +襄公三年 +【经】三年春,楚公子婴齐帅师伐吴。公如晋。夏四月壬戌,公及晋侯盟于长樗。公至自晋。六月,公会单子、晋侯、宋公、卫侯、郑伯、莒子、邾子、齐世子光。己未,同盟于鸡泽。陈侯使袁侨如会。戊寅,叔孙豹及诸侯之大夫及陈袁侨盟。秋,公至自会。冬,晋荀罃帅师伐许。 +【传】三年春,楚子重伐吴,为简之师,克鸠兹,至于衡山。使邓廖帅组甲三百、被练三千以侵吴。吴人要而击之,获邓廖。其能免者,组甲八十、被练三百而已。子重归,既饮至,三日,吴人伐楚,取驾。驾,良邑也。邓廖,亦楚之良也。君子谓:“子重于是役也,所获不如所亡。”楚人以是咎子重。子重病之,遂遇心病而卒。 +公如晋,始朝也。夏,盟于长樗。孟献子相,公稽首。知武子曰:“天子在,而君辱稽首,寡君惧矣。”孟献子曰:“以敝邑介在东表,密迩仇雠,寡君将君是望,敢不稽首?” +晋为郑服故,且欲修吴好,将合诸侯。使士□告于齐曰:“寡君使□,以岁之不易,不虞之不戒,寡君愿与一二兄弟相见,以谋不协,请君临之,使□乞盟。”齐侯欲勿许,而难为不协,乃盟于耏外。 +祁奚请老,晋侯问嗣焉。称解狐,其仇也,将立之而卒。又问焉,对曰:“午也可。”于是羊舌职死矣,晋侯曰:“孰可以代之?”对曰:“赤也可。”于是使祁午为中军尉,羊舌赤佐之。君子谓:“祁奚于是能举善矣。称其仇,不为谄。立其子,不为比。举其偏,不为党。《商书》曰:‘无偏无党,王道荡荡。’其祁奚之谓矣!解狐得举,祁午得位,伯华得官,建一官而三物成,能举善也夫!唯善,故能举其类。《诗》云:‘惟其有之,是以似之。’祁奚有焉。” +六月,公会单顷公及诸侯。己未,同盟于鸡泽。 +晋侯使荀会逆吴子于淮上,吴子不至。 +楚子辛为令尹,侵欲于小国。陈成公使袁侨如会求成,晋侯使和组父告于诸侯。秋,叔孙豹及诸侯之大夫及陈袁侨盟,陈请服也。 +晋侯之弟扬干乱行于曲梁,魏绛戮其仆。晋侯怒,谓羊舌赤曰:“合诸侯以为荣也,扬干为戮,何辱如之?必杀魏绛,无失也!”对曰:“绛无贰志,事君不辟难,有罪不逃刑,其将来辞,何辱命焉?”言终,魏绛至,授仆人书,将伏剑。士鲂、张老止之。公读其书曰:“日君乏使,使臣斯司马。臣闻师众以顺为武,军事有死无犯为敬。君合诸侯,臣敢不敬?君师不武,执事不敬,罪莫大焉。臣惧其死,以及扬干,无所逃罪。不能致训,至于用金戊。臣之罪重,敢有不从,以怒君心,请归死于司寇。”公跣而出,曰:“寡人之言,亲爱也。吾子之讨,军礼也。寡人有弟,弗能教训,使干大命,寡人之过也。子无重寡人之过,敢以为请。” +晋侯以魏绛为能以刑佐民矣,反役,与之礼食,使佐新军。张老为中军司马,士富为候奄。 +楚司马公子何忌侵陈,陈叛故也。 +许灵公事楚,不会于鸡泽。冬,晋知武子帅师伐许。 +译文 +三年春季,楚国的子重率军进攻吴国,选择了一支经过演习的军队。攻克鸠兹,到达衡山。派遣邓廖率领穿组甲的车兵三百人、穿被练的步兵三千人以侵袭吴国。吴军拦阻攻击楚军,俘掳了邓廖。免于死及被俘的只有车兵八十人、被练的步兵三百人而已。子重回国,在太庙庆祝慰劳,三天后,吴国人攻打楚国,占领了驾地。驾地,是好的城邑;邓廖,也是楚国的良将。君子认为:“子重在这次战役中,所得到的不如所失去的。”楚国人因此责备子重。子重很不痛快,就碰上心脏病发作而死去。 +鲁襄公到晋国,这是初次去朝见。夏季,在长樗会盟,孟献子作为相礼者。襄公行叩头礼。知武子说:“有天子在那里,而承贵君行叩头的大礼,寡君感到害怕。”孟献子说:“由于敝邑地近东海,紧挨着仇敌,寡君将要仰望贵君协助,哪里敢不叩头呢?” +晋国由于郑国顺服的缘故,又想要和吴国修好,准备会合诸侯。派遣士匄向齐国报告说:“寡君派匄前来,是由于近年来各国之间纠纷不少,对意外的事情又没有戒备,寡君愿意和几位兄弟相见,来商讨解决彼此的不和睦。请君王光临,派匄来请求结盟。”齐灵公本想不答应,而又难于表示不和睦,就在耏水之外结盟。 +祁奚请求告老退休,晋悼公问谁来接替他。祁奚称道解狐。解狐,是祁奚的仇人,晋悼公打算任命解狐,他却死了。晋悼公又问祁奚,祁奚回答说:“祁午也可以胜任。”这时羊舌职死了,晋悼公说:“谁可以接代他?”祁奚回答说:“羊舌赤也可以胜任。”因此,晋悼公就派遣祁午做中军尉,羊舌赤为副职。君子认为:“祁奚在这种情况下能够推举有德行的人。举荐他的仇人而不是谄媚,推荐他的儿子而不是自私,推举他的副手而不是结党。《商书》说:‘不偏私不结党,君王之道浩浩荡荡。’这说的就是祁奚啊。解狐得到推荐,祁午得到安排,羊舌赤能有官位,建立一个官位而成全三件事,这是由于能够推举贤能的人的缘故啊。唯其有德行,才能推举类似他的好人。《诗》说,‘正因为具有美德,推举他的人才能和他相似’,祁奚就是这样的人。” +六月,鲁襄公会见单顷公和诸侯。二十三日,在鸡泽会盟。 +晋悼公派遣荀会在淮水边上迎接吴子,吴子没有来。 +楚国的子辛做令尹,侵害小国以满足欲望。陈成公派遣袁侨到会求和好。晋悼公派遣和组父向诸侯报告。秋季,叔孙豹和诸侯的大夫同陈国的袁侨结盟,这是由于陈国请求顺服的缘故。 +晋悼公的弟弟扬干在曲梁扰乱军队的行列,魏绛杀了他的驾车人。晋悼公发怒,对羊舌赤说:“会合诸侯,是以此为光荣。扬干受到侮辱,还有什么侮辱比这更大?一定要杀掉魏绛,不要耽误了。”羊舌赤回答说:“魏绛一心为公,事奉国君不避危难,有了罪过不逃避惩罚,他大概会来说明的,何必劳动君王发布命令呢?”话刚说完,魏绛来了,把信交给仆人,准备抽剑自杀。士鲂、张老劝阻了他。晋悼公读他的上书,说:“以前君王缺乏使唤的人,让下臣担任司马的职务。下臣听说‘军队里的人服从军纪叫做武,在军队里做事宁死也不触犯军纪叫做敬’。君王会合诸侯,下臣岂敢不执行军纪军法?君王的军队不武,办事的人不敬,没有比这再大的罪过了。下臣畏惧触犯死罪,所以连累到扬干,罪责无可逃避。下臣不能够事先教导全军,以至于动用了斧钺,下臣的罪过很重,岂敢不服从惩罚来激怒君王呢?请求回去死在司寇那里。”晋悼公光着脚赶紧走出来,说:“寡人的话,是出于对兄弟的亲爱;大夫杀杨干,是出于按军法从事。寡人有弟弟,没有能够教导他,而让他触犯了军令,这是寡人的过错。您不要加重寡人的过错,谨以此作为请求。” +晋悼公认为魏绛能够用刑罚来治理百姓了,从盟会回国,在太庙设宴招待魏绛,派他为新军副帅。张老做中军司马,士富做了侦察长。 +楚国的司马公子何忌率军入侵陈国,这是由于陈国背叛了楚国的缘故。 +许灵公事奉楚国,不参加鸡泽的会见。冬季,晋国的知武子领兵讨伐许国。 + +襄公四年 +【经】四年春王三月己酉,陈侯午卒。夏,叔孙豹如晋。秋七月戊子,夫人姒氏薨。葬陈成公。八月辛亥,葬我小君定姒。冬,公如晋。陈人围顿。 +【传】四年春,楚师为陈叛故,犹在繁阳。韩献子患之,言于朝曰:“文王帅殷之叛国以事纣,唯知时也。今我易之,难哉!” +三月,陈成公卒。楚人将伐陈,闻丧乃止。陈人不听命。臧武仲闻之,曰:“陈不服于楚,必亡。大国行礼焉而不服,在大犹有咎,而况小乎?”夏,楚彭名侵陈,陈无礼故也。 +穆叔如晋,报知武子之聘也,晋侯享之。金奏《肆夏》之三,不拜。工歌《文王》之三,又不拜。歌《鹿鸣》之三,三拜。韩献子使行人子员问之,曰:“子以君命,辱于敝邑。先君之礼,藉之以乐,以辱吾子。吾子舍其大,而重拜其细,敢问何礼也?”对曰:“三《夏》,天子所以享元侯也,使臣弗敢与闻。《文王》,两君相见之乐也,使臣不敢及。《鹿鸣》,君所以嘉寡君也,敢不拜嘉。?《四牡》,君所以劳使臣也,敢不重拜?《皇皇者华》,君教使臣曰:‘必咨于周。’臣闻之:‘访问于善为咨,咨亲为询,咨礼为度,咨事为诹,咨难为谋。’臣获五善,敢不重拜?” +秋,定姒薨。不殡于庙,无榇,不虞。匠庆谓季文子曰:“子为正卿,而小君之丧不成,不终君也。君长,谁受其咎?” +初,季孙为己树六檟于蒲圃东门之外。匠庆请木,季孙曰:“略。”匠庆用蒲圃之檟,季孙不御。君子曰:“《志》所谓‘多行无礼,必自及也’,其是之谓乎!” +冬,公如晋听政,晋侯享公。公请属鄫,晋侯不许。孟献子曰:“以寡君之密迩于仇雠,而愿固事君,无失官命。鄫无赋于司马,为执事朝夕之命敝邑,敝邑褊小,阙而为罪,寡君是以愿借助焉!”晋侯许之。 +楚人使顿间陈而侵伐之,故陈人围顿。 +无终子嘉父使孟乐如晋,因魏庄子纳虎豹之皮,以请和诸戎。晋侯曰:“戎狄无亲而贪,不如伐之。”魏绛曰:“诸侯新服,陈新来和,将观于我,我德则睦,否则携贰。劳师于戎,而楚伐陈,必弗能救,是弃陈也,诸华必叛。戎,禽兽也,获戎失华,无乃不可乎?《夏训》有之曰:‘有穷后羿。’”公曰:“后羿何如?”对曰:“昔有夏之方衰也,后羿自鉏迁于穷石,因夏民以代夏政。恃其射也,不修民事而淫于原兽。弃武罗、伯困、熊髡、龙圉而用寒浞。寒浞,伯明氏之谗子弟也。伯明后寒弃之,夷羿收之,信而使之,以为己相。浞行媚于内而施赂于外,愚弄其民而虞羿于田,树之诈慝以取其国家,外内咸服。羿犹不悛,将归自田,家众杀而亨之,以食其子。其子不忍食诸,死于穷门。靡奔有鬲氏。浞因羿室,生浇及豷,恃其谗慝诈伪而不德于民。使浇用师,灭斟灌及斟寻氏。处浇于过,处豷于戈。靡自有鬲氏,收二国之烬,以灭浞而立少康。少康灭浇于过,后杼灭豷于戈。有穷由是遂亡,失人故也。昔周辛甲之为大史也,命百官,官箴王阙。于《虞人之箴》曰:‘芒芒禹迹,尽为九州,经启九道。民有寝庙,兽有茂草,各有攸处,德用不扰。在帝夷羿,冒于原兽,忘其国恤,而思其麀牡。武不可重,用不恢于夏家。兽臣司原,敢告仆夫。’《虞箴》如是,可不惩乎?”于是晋侯好田,故魏绛及之。 +公曰:“然则莫如和戎乎?”对曰:“和戎有五利焉:戎狄荐居,贵货易土,土可贾焉,一也。边鄙不耸,民狎其野,穑人成功,二也。戎狄事晋,四邻振动,诸侯威怀,三也。以德绥戎,师徒不勤,甲兵不顿,四也。鉴于后羿,而用德度,远至迩安,五也。君其图之!”公说,使魏绛盟诸戎,修民事,田以时。 +冬十月,邾人、莒人伐鄫。臧纥救鄫,侵邾,败于狐骀。国人逆丧者皆髽。鲁于是乎始髽,国人诵之曰:“臧之狐裘,败我于狐骀。我君小子,朱儒是使。朱儒!朱儒!使我败于邾。” +译文 +四年春季,楚军由于陈国背叛的缘故,仍旧驻扎在繁阳。韩献子担心这件事,在朝廷上说:“周文王率领背叛商朝的国家去事奉纣,这是由于知道时机未到。现在我们反了过来,想要称霸,难哪!” +三月,陈成公死。楚国人正准备进攻陈国,听到陈国有丧事,就停止进攻。陈国不听从楚国的命令,臧武仲听说这种情况,说:“陈国不服从楚国,一定灭亡。大国实行礼仪而不去顺服,对大国来说尚且有灾难,何况是小国呢?” +夏季,楚国的彭名攻打陈国,这是由于陈国缺乏礼节的缘故。 +穆叔去到晋国,回报知武子的聘问。晋悼公设享礼招待他。乐器演奏《肆夏》的三章,穆叔没有答拜。乐工歌唱《文王》三曲,又没有答拜。歌唱《鹿鸣》三曲,三次答拜。韩献子派行人子员去问他,说:“您奉着君王的命令光临敝邑,敝邑按先君之礼并用音乐来招待大夫。大夫舍弃重大的而三拜细小的,请问这是什么礼仪?”穆叔回答说:“《三夏》,是天子用来招待诸侯领袖的,使臣不敢听到。《文王》,是两国国君相见的音乐,使臣不敢参预。《鹿鸣》,是君王用来嘉奖寡君的,岂敢不拜谢这种嘉奖?《四牡》,是君王用来慰劳使臣的,岂敢不再拜?《皇皇者华》,君王告诫使臣说:‘一定要向忠信的人咨询。’使臣听说:‘向善人访求询问就是咨,咨询亲戚就是询,咨询礼仪就是度,咨询事情就是诹,咨询困难就是谋。’臣得到这五善,岂敢不再三拜谢?” +秋季,定姒去世。没有在祖庙内停放棺木,没有用内棺,没有举行虞祭。匠庆对季文子说:“您做正卿,但是小君的丧礼没有完成,这是让国君不能为他生母送终。国君长大后,谁将会受到责备?” +起初,季孙为自己在蒲圃的东门外边种植六棵檟木,匠庆请求用它做定姒的棺椁木料,季孙说:“简单点吧。”匠庆还是使用了蒲圃的檟木,季孙也没有阻止。君子说:“《志》所说的‘多做不合礼仪的事,祸患一定会来到自己身上’,说的就是这个吧!” +冬季,鲁襄公去到晋国听取晋国的要求。晋悼公设享礼招待襄公,襄公请求把鄫国作为鲁国的附庸,晋悼公不答应。孟献子说:“由于寡君紧挨着仇敌,还是愿意坚决事奉君王,没有耽误君王的命令。鄫国并没有向晋国的司马交纳贡赋,而君王的左右却经常对我国有所命令,我国褊窄狭小,无法满足要求就是罪过,寡君因此希望得到鄫国作为帮助。”晋悼公允许了。 +楚国人让顿国乘陈国的空子而进攻陈国,所以陈国人包围了顿国。 +无终子嘉父派遣孟乐去到晋国,依靠魏庄子的关系,奉献了虎豹的皮革,以请求晋国和各部戎人讲和。晋悼公说:“戎狄没有什么亲近的人而且贪婪,不如进攻他们。”魏庄子说:“诸侯新近顺服,陈国最近前来讲和,都将观察我们的行动。我们有德,就亲近我们;不这样,就背离我们。在戎人那里去用兵,楚国进攻陈国,一定不能去救援,这就是丢弃陈国了。中原诸国一定背叛我们。戎人,不过是禽兽。得到戎人而失去中原,恐怕不可以吧!《夏训》有这样的话‘有穷的后羿——’”晋悼公说:“后羿怎么样?”魏庄子回答说:“从前夏朝刚刚衰落的时候,后羿从鉏地迁到穷石,依靠夏朝的百姓取代了夏朝政权。后羿仗着他的射箭技术,不致力于治理百姓而沉溺于打猎,抛弃了武罗、伯因、熊髡、尨圉等贤臣而任用寒浞。寒浞,是伯明氏的坏子弟,伯明后寒丢弃了他。后羿收养了他,信任并且使用他,作为自己的辅助。寒浞在里边对女人献媚,在外边广施财物,愚弄百姓而使后羿专以打猎为乐。扶植了奸诈邪恶,用这个取得了后羿的国和家,外部和内部都顺从归服。后羿还是不肯改悔,准备从打猎的地方回来,他的手下人把他杀了煮熟,让他的儿子吃,他的儿子不忍心吃,又被杀死在穷国的城门口。靡逃亡到有鬲氏。寒浞和后羿的妻妾生了浇和豷,仗着他的奸诈邪恶,对百姓不施恩德,派浇带兵,灭了斟灌和斟寻氏。让浇住在过地,让豷住在戈地。靡从有鬲氏那里收集两国的遗民,用以灭亡了寒促而立了少康。少康在过地灭掉了浇,后杼在戈地灭掉了豷,有穷从此就灭亡了,这是由于失去贤人的缘故。从前周朝的辛甲做太史的时候,命令百官,每人都劝诫天子的过失。在《虞人之箴》里说:‘辽远的夏禹遗迹,分为九州,开通了许多大道。百姓有屋有庙,野兽有丰茂的青草;各得其所,他们因此互不干扰。后羿身居帝位,贪恋着打猎,忘记了国家的忧患,想到的只是飞鸟走兽。武事不能太多,太多就不能扩大夏后氏的国家。主管禽兽的臣,谨以此报告君王左右的人。’《虞箴》是这样,难道能不警戒吗?”当时晋悼公喜欢打猎,所以魏庄子提到这件事。 +晋悼公说:“然而再好的办法也莫过于跟戎人讲和吗?”魏庄子回答说:“跟戎人讲和有五种利益:戎狄逐水草而居,重财货而轻土地,他们的土地可以收买,这是一。边境不再有所警惧,百姓安心在田野里耕作,农田管理的人可以完成任务,这是二。戎狄事奉晋国,四边的邻国震动,诸侯因为我们的威严而慑服,这是三。用德行安抚戎人,将士不辛劳,武器不损坏,这是四。有鉴于后羿的教训,而利用道德法度,远国前来而邻国安心,这是五。君王还是慎重谋划吧!”晋悼公听了很高兴,派遣魏庄子与各部戎人讲和。又致力于治理百姓,按照时令去打猎。 +冬季,十月,邾国人、莒国人进攻鄫国,臧纥救援鄫国,入侵邾国,在狐骀被击败。国内的人们去接丧的都用麻系发,鲁国从这时开始就有了用麻系发的习俗。国内的人们讽刺说:“姓臧的身穿狐皮袄,使我们在狐骀战败了。我们的国君小孩子,把个侏儒当差使。侏儒啊,侏儒!使我们被打败在邾。” + +襄公五年 +【经】五年春,公至自晋。夏,郑伯使公子发来聘。叔孙豹、鄫世子巫如晋。仲孙蔑、卫孙林父子会吴于善道。秋,大雩。楚杀其大夫公子壬夫。公会晋侯、宋公、陈侯、卫侯、郑伯、曹伯、莒子、邾子、滕子、薛伯、齐世子光、吴人、鄫人于戚。公至自会。冬,戍陈。楚公子贞帅师伐陈。公会晋侯、宋公、卫侯、郑伯、曹伯、齐世子光救陈。十有二月,公至自救陈。辛未,季孙行父卒。 +【传】五年春,公至自晋。 +王使王叔陈生愬戎于晋,晋人执之。士鲂如京师,言王叔之贰于戎也。 +夏,郑子国来聘,通嗣君也。 +穆叔觌鄫大子于晋,以成属鄫。书曰:“叔孙豹、鄫大子巫如晋。”言比诸鲁大夫也。 +吴子使寿越如晋,辞不会于鸡泽之故,且请听诸侯之好。晋人将为之合诸侯,使鲁、卫先会吴,且告会期。故孟献子、孙文子会吴于善道。 +秋,大雩,旱也。 +楚人讨陈叛故,曰:“由令尹子辛实侵欲焉。”乃杀之。书曰:“楚杀其大夫公子壬夫。”贪也。君子谓:“楚共王于是不刑。《诗》曰:‘周道挺挺,我心扃扃,讲事不令,集人来定。’己则无信,而杀人以逞,不亦难乎?《夏书》曰:‘成允成功。’” +九月丙午,盟于戚,会吴,且命戍陈也。穆叔以属鄫为不利,使鄫大夫听命于会。 +楚子囊为令尹。范宣子曰:“我丧陈矣!楚人讨贰而立子囊,必改行而疾讨陈。陈近于楚,民朝夕急,能无往乎?有陈,非吾事也,无之而后可。” +冬,诸侯戍陈。子囊伐陈。十一月甲午,会于城棣以救之。 +季文子卒。大夫入敛,公在位。宰庀家器为葬备,无衣帛之妾,无食粟之马,无藏金玉,无重器备。君子是以知季文子之忠于公室也。相三君矣,而无私积,可不谓忠乎? +译文 +五年春季,鲁襄公从晋国到达鲁国。 +周灵王派遣王叔陈生向晋国控告戎人,晋国人把他抓了起来。士鲂去到京师,报告说王叔倾向戎人。 +夏季,郑国的子国来鲁国聘问,这是由于为新立的国君来通好。 +穆叔带领鄫国的太子去到晋国和君臣作私人会晤,以完成鄫国归属鲁国的手续。《春秋》记载说:“叔孙豹、鄫太子巫如晋”,这就是把鄫国的太子巫比作鲁国的大夫。 +吴子派遣寿越去到晋国,解释没有参加鸡泽会见的缘故,同时请求听从命令和诸侯友好。晋人将为吴国会合诸侯,于是让鲁国、卫国先会见吴国,同时告诉吴国会见的日期。所以孟献子、孙文子在善道会见了吴人。 +秋季,举行盛大的雩祭,这是由于天旱的缘故。 +楚国人质问陈国背叛的原因,陈人说:“由于令尹子辛侵害小国以满足他个人欲望。”楚国就杀死了子辛。《春秋》记载说:“楚杀其大夫公子壬夫”,是由于他贪婪的缘故。君子认为:“楚共王在这件事情上用刑律不当。《诗》说:‘大道笔直,我的心里明白。计划不善灵,应招集贤人决定。’自己就没有信用,反而杀人以快意,不也是很难了吗?《夏书》说:‘完成信用然后才能成功。’” +九月二十三日,鲁襄公和晋悼公、宋平公、陈哀公、卫献公、郑僖公、曹成公、莒子、邾子、滕成公、薛伯、齐国世子光、吴国人、鄫国人在戚地结盟,这是为了会见吴人,同时由晋悼公命令诸侯出兵戍守陈国。穆叔认为鄫国的归属对鲁国不利,就让鄫国的大夫以独立国家的身份参加会见听取命令。 +楚国的子囊做令尹,范宣子说:“我们失去陈国了。楚国人讨伐三心二意的国家而又立了子囊,一定会改变子辛的所作所为而很快讨伐陈国。陈国接近楚国,百姓时时骇怕兵患,能够不归向楚国吗?保有陈国,不是我们的事情;放弃陈国,以后反倒好办。” +冬季,诸侯派兵戍守陈国。子囊进攻陈国。十一月十二日,鲁襄公和晋悼公、宋平公、卫献公、郑僖公、曹成公、齐国世子光在城棣会合以救援陈国。 +冬季,诸侯派兵戍守陈国。子囊进攻陈国。十一月十二日,鲁襄公和晋悼公、宋平公、卫献公、郑僖公、曹成公、齐国世子光在城棣会合以救援陈国。季文子死。根据大夫人敛的礼仪,鲁襄公亲自看视。家臣收集家里的器物作为葬具。家里没有穿丝绸的妾,没有吃粮食的马,没有收藏铜器玉器,一切用具没有重复。君子从这里知道季文子对公室的忠心:辅助过三位国君而没有私人积蓄,可以说不是忠心吗? + + +襄公六年 +【经】六年春王三月,壬午,杞伯姑容卒。夏,宋华弱来奔。秋,杞葬桓公。滕子来朝。莒人灭鄫。冬,叔孙豹如邾,季孙宿如晋。十有二月,齐侯灭莱。 +【传】六年春,杞桓公卒,始赴以名,同盟故也。 +宋华弱与乐辔少相狎,长相优,又相谤也。子荡怒,以弓梏华弱于朝。平公见之,曰:“司武而梏于朝,难以胜矣!”遂逐之。夏,宋华弱来奔。司城子罕曰:“同罪异罚,非刑也。专戮于朝,罪孰大焉!”亦逐子荡。子荡射子罕之门,曰:“几日而不我从!”子罕善之如初。 +秋,滕成公来朝,始朝公也。 +莒人灭鄫,鄫恃赂也。 +冬,穆叔如邾,聘,且修平。 +晋人以鄫故来讨,曰:“何故亡鄫?”季武子如晋见,且听命。 +十一月,齐侯灭莱,莱恃谋也。于郑子国之来聘也,四月,晏弱城东阳,而遂围莱。甲寅,堙之环城,傅于堞。及杞桓公卒之月,乙未,王湫帅师及正舆子、棠人军齐师,齐师大败之。丁未,入莱。莱共公浮柔奔棠。正舆子、王湫奔莒,莒人杀之。四月,陈无宇献莱宗器于襄宫。晏弱围棠,十一月丙辰,而灭之。迁莱于郳。高厚、崔杼定其田。 +译文 +六年春季,杞桓公死了。讣告首次记载他的名字,这是由于两国同盟的缘故。 +宋国的华弱和乐辔小时候彼此很亲昵,长大了就彼此戏谑,又互相诽谤。乐辔有一次发怒,在朝廷上用弓套住华弱的脖子如同带枷一样。宋平公见到了,说:“司武而在朝廷上带弓枷,打仗就难于取胜了。”于是就把他赶走。夏季,华弱逃亡到鲁国。司城子罕说:“罪过相同而惩罚不同,这是不合于刑法的。在朝廷上专横和侮辱别人,还有比这大的罪过吗?”于是也赶走乐辔,乐辔把箭射在子罕的大门上,说:“看你还有几天会不跟着我一样被赶走?”子罕害怕,优待乐辔像过去一样。 +秋季,滕成公前来朝见,这是第一次朝见鲁襄公。 +莒国人灭亡了鄫国,这是由于鄫国仗着送过财礼而疏于防备的缘故。 +冬季,穆叔去到邾国聘问,同时重修友好关系。 +晋国人由于鄫国的缘故前来讨伐,说:“为什么把鄫国灭亡?”季武子去到晋国,听候晋国处置。 +十一月,齐灵公灭亡莱国,这是由于莱国只是仗着谋略而不务实际的缘故。当郑国子国来鲁国聘问的时候,即去年四月,晏弱在东阳筑城,因而就包围莱国,四月的一天,环城堆起土山,紧挨着女墙。到杞桓公死去的那一个月的十五日,王湫领兵和正舆子、棠邑人迎战齐军,齐军把他们打得大败。二十七日,进入莱国。莱共公浮柔逃亡到棠地,正舆子、王湫逃亡到莒国,莒国人杀了他们。四月,陈无宇把莱国宗庙里的宝器献于襄宫。晏弱包围棠邑,十二月初十灭了它,把莱国的百姓迁到郳地。高厚、崔杼主持划定分配莱国的土地疆界。 + +襄公七年 +【经】七年春,郯子来朝。夏四月,三卜郊,不从,乃免牲。小邾子来朝。城费。秋,季孙宿如卫。八月,螽。冬十月,卫侯使孙林父来聘。壬戌,及孙林父盟。楚公子贞帅师围陈。十有二月,公会晋侯、宋公、陈侯、卫侯、曹伯、莒子、邾子于鄬。郑伯髡顽如会,未见诸侯,丙戌,卒于鄵。陈侯逃归。 +【传】七年春,郯子来朝,始朝公也。 +夏四月,三卜郊,不从,乃免牲。孟献子曰:“吾乃今而后知有卜筮。夫郊,祀后稷以祈农事也。是故启蛰而郊,郊而后耕。今既耕而卜郊,宜其不从也。” +南遗为费宰。叔仲昭伯为隧正,欲善季氏而求媚于南遗,谓遗:“请城费,吾多与而役。”故季氏城费。 +小邾穆公来朝,亦始朝公也。 +秋,季武子如卫,报子叔之聘,且辞缓报,非贰也。 +冬十月,晋韩献子告老。公族穆子有废疾,将立之。辞曰:“《诗》曰:‘岂不夙夜,谓行多露。’又曰:‘弗躬弗亲,庶民弗信。’无忌不才,让,其可乎?请立起也!与田苏游,而曰好仁。《诗》曰:‘靖共尔位,好是正直。神之听之,介尔景福。’恤民为德,正直为正,正曲为直,参和为仁。如是,则神听之,介福降之。立之,不亦可乎?”庚戌,使宣子朝,遂老。晋侯谓韩无忌仁,使掌公族大夫。 +卫孙文子来聘,且拜武子之言,而寻孙桓子之盟。公登亦登。叔孙穆子相,趋进曰:“诸侯之会,寡君未尝后卫君。今吾子不后寡君,寡君未知所过。吾子其少安!”孙子无辞,亦无悛容。 +穆叔曰:“孙子必亡。为臣而君,过而不悛,亡之本也。《诗》曰:‘退食自公,委蛇委蛇。’谓从者也。衡而委蛇必折。” +楚子囊围陈,会于鄬以救之。 +郑僖公之为大子也,于成之十六年,与子罕适晋,不礼焉。又与子丰适楚,亦不礼焉。及其元年,朝于晋。子丰欲愬诸晋而废之,子罕止之。及将会于鄬,子驷相,又不礼焉。侍者谏,不听,又谏,杀之。及鄵,子驷使贼夜弑僖公,而以疟疾赴于诸侯。简公生五年,奉而立之。 +陈人患楚。庆虎、庆寅谓楚人曰:“吾使公子黄往而执之。”楚人从之。二庆使告陈侯于会,曰:“楚人执公子黄矣!君若不来,群臣不忍社稷宗庙,惧有二图。”陈侯逃归。 +译文 +七年春季,郯子前来朝见,这是他第一次朝见鲁襄公。 +夏季,四月,鲁国三次为郊祭而占卜,都不吉利,于是就免除使用牺牲。孟献子说:“我从今以后才知道有占卜和占筮了。郊祭是祭祀后稷,而祈求农事顺利。所以一到启蛰节就举行郊祭,郊祭以后开始耕种。现在已经开始耕种再来为郊祭占卜,占卜不吉利是应该的。” +南遗出任费邑县宰。叔仲昭伯做了管理修隧道的头目,想要讨好季氏,因而谄媚南遗。他对南遗说:“你去请求在费地筑城,我多给你劳力。”所以季氏在费地筑城。 +小邾穆公来鲁国朝见,也是第一次朝见襄公。 +秋季,季武子去到卫国,这是为了回报子叔的聘问,同时解释所以延迟回报不是出于三心二意。 +冬季,十月,晋国韩献子告老退休,公族穆子患有残疾,准备立他为卿。穆子辞谢说:“《诗》说:‘难道不是早晚都想着前来?无奈路上的露水太多。’又说:‘不能亲自办事,百姓不会信任。’无忌没有才能,让给别人,也许可以吧?请立起吧。起和田苏有交往,田苏称赞他‘好仁’。《诗》说:‘忠诚谨慎地对待你的职位,喜爱这正直的人。神灵将会听到,赐给你以大福。’体恤百姓是德,纠正直是正,纠正曲是直,把这三者合而为一是仁。像这样,那么神灵就会听到,降给他大福。立他为卿,不也是可以的吗?” 初九日,让韩宣子朝见,于是他就告老退休。晋悼公认为韩无忌具有仁德,让他做首席公族大夫。 +卫国的孙文子来鲁国聘问,同时答谢季武子的解释,重温和孙桓子结盟的友好关系。鲁襄公登上台阶,孙林父同时登上。叔孙穆子相礼,快步进入,说:“诸侯会见,寡君从来没有走在卫君后面。现在您没有走在寡君后面,寡君不知道自己错在哪里。大夫您稍停一下吧!”孙林父没有话说,也没有改悔的样子。穆叔说:“孙子必然逃亡。作为臣下而和国君并行,有了过错又不改悔,这是逃亡的根本原因。《诗》说,‘退朝回家吃饭,从容自得’,说的是小心顺从的人。专横而又自得,必然遭受挫折。” +楚国的子襄包围陈国,鲁襄公和晋悼公、宋平公、陈哀公、卫献公、曹成公、莒子、邾子在鄬地会见以救援陈国。 +郑值公做太子的时候,在鲁成公十六年和子罕同去晋国,对子罕不加礼遇。又和子丰同去楚国,对子丰也不加礼遇。等到僖公即位的元年去晋国朝见,子丰想要向晋国控告而废立僖公,子罕加以劝阻。等到将要在鄬地会见,子驷做相礼,僖公不以礼遇待子驷。侍者劝谏,不听;又劝谏,杀了说话的人。到达鄵地,子驷派人夜里害死僖公,而用急病致死讣告诸侯。简公当时五岁,就奉立他为国君。 +陈国人担心楚国。庆虎、庆寅对楚国人说:“我们派公子黄去,你们逮住他。”楚国人听从了。二庆派人到会报告陈哀公,说:“楚国人抓住公子黄了。君王如果不回来,群臣不忍心国家宗庙的被楚灭亡,恐怕会有其他想法。”陈哀公于是就逃了回来。 + +襄公八年 +【经】八年春王正月,公如晋。夏,葬郑僖公。郑人侵蔡,获蔡公子燮。季孙宿会晋侯、郑伯、齐人、宋人、卫人、邾人于邢丘。公至自晋。莒人伐我东鄙。秋九月,大雩。冬,楚公子贞帅师伐郑。晋侯使士□来聘。 +【传】八年春,公如晋,朝,且听朝聘之数。 +郑群公子以僖公之死也,谋子驷。子驷先之。夏四月庚辰,辟杀子狐、子熙、子侯、子丁。孙击、孙恶出奔卫。 +庚寅,郑子国、子耳侵蔡,获蔡司马公子燮。郑人皆喜,唯子产不顺,曰:“小国无文德,而有武功,祸莫大焉。楚人来讨,能勿从乎?从之,晋师必至。晋、楚伐郑,自今郑国不四五年,弗得宁矣。”子国怒之曰:“尔何知?国有大命,而有正卿。童子言焉,将为戮矣。” +五月甲辰,会于邢丘,以命朝聘之数,使诸侯之大夫听命。季孙宿、齐高厚、宋向戌、卫宁殖、邾大夫会之。郑伯献捷于会,故亲听命。大夫不书,尊晋侯也。 +莒人伐我东鄙,以疆鄫田。 +秋九月,大雩,旱也。 +冬,楚子囊伐郑,讨其侵蔡也。 +子驷、子国、子耳欲从楚,子孔、子蟜、子展欲待晋。子驷曰:“《周诗》有之曰:‘俟河之清,人寿几何?兆云询多,职竞作罗。’谋之多族,民之多违,事滋无成。民急矣,姑从楚以纾吾民。晋师至,吾又从之。敬共币帛,以待来者,小国之道也。牺牲玉帛,待于二竞,以待强者而庇民焉。寇不为害,民不罢病,不亦可乎?”子展曰:“小所以事大,信也。小国无信,兵乱日至,亡无日矣。五会之信,今将背之,虽楚救我,将安用之?亲我无成,鄙我是欲,不可从也。不如待晋。晋君方明,四军无阙,八卿和睦,必不弃郑。楚师辽远,粮食将尽,必将速归,何患焉?舍之闻之:‘杖莫如信。’完守以老楚,杖信以待晋,不亦可乎?”子驷曰:“《诗》云:‘谋夫孔多,是用不集。发言盈庭,谁敢执其咎?如匪行迈谋,是用不得于道。’请从楚,□非也受其咎。”乃及楚平。 +使王子伯骈告于晋,曰:“君命敝邑:‘修而车赋,儆而师徒,以讨乱略。’蔡人不从,敝邑之人,不敢宁处,悉索敝赋,以讨于蔡,获司马燮,献于邢丘。今楚来讨曰:‘女何故称兵于蔡?’焚我郊保,冯陵我城郭。敝邑之众,夫妇男女,不皇启处,以相救也。翦焉倾覆,无所控告。民死亡者,非其父兄,即其子弟,夫人愁痛,不知所庇。民知穷困,而受盟于楚,狐也与其二三臣不能禁止。不敢不告。”知武子使行人子员对之曰:“君有楚命,亦不使一介行李告于寡君,而即安于楚。君之所欲也,谁敢违君?寡君将帅诸侯以见于城下,唯君图之!” +晋范宣子来聘,且拜公之辱,告将用师于郑。公享之,宣子赋《摽有梅》。季武子曰:“谁敢哉!今譬于草木,寡君在君,君之臭味也。欢以承命,何时之有?”武子赋《角弓》。宾将出,武子赋《彤弓》。宣子曰:“城濮之役,我先君文公献功于衡雍,受彤弓于襄王,以为子孙藏。□也,先君守官之嗣也,敢不承命?”君子以为知礼。 +译文 +八年春季,鲁襄公去到晋国朝见,同时听取晋国要求所献财币的数字。 +郑国的公子们由于僖公的死去,谋划杀死子驷。子驷先下手。夏季,四月十二日,假造罪名,杀了子狐、子熙、子侯、子丁。孙击、孙恶逃亡到卫国。 +四月二十二日,郑国的子国、子耳入侵蔡国,俘虏了蔡国司马公子燮。郑国人都高兴,唯独子产不随声附和,说:“小国没有文治却有了武功,没有比这再大的祸患了。楚国人前来讨伐,能够不顺从他们吗?顺从楚国,晋国的军队必然来到。晋、楚两国进攻郑国,从今以后郑国至少四五年内不得安宁。”子国对他发怒说:“你知道什么!国家有出兵的重大命令,而且有执政的卿在那里,小孩子说这些话,将要被杀的!” +五月初七日,季孙宿和晋悼公、郑简公、齐国人、宋国人、卫国人、邾国人在邢丘会见,由晋国提出朝聘的财礼数字,让诸侯的大夫听取命令。鲁国季孙宿、齐国高厚、宋国向戌、卫国宁殖、邾国大夫参加会见。郑简公在这次会上奉献战利品,所以亲自听取命令。《春秋》没有记载大夫的名字,为的是尊重晋侯。 +莒国人攻打我国东部边境,以划定鄫国土田的疆界。 +秋季九月,举行盛大的雩祭,这是由于天旱。 +冬季,楚国的子囊进攻郑匡,讨伐郑国入侵蔡国。 +子驷、子国、子耳要顺从楚国,子孔、子?、子展要等待晋国救援。子驷说:“《周诗》有这样的话:‘等待黄河澄清,人的寿命能有几何?占卜太多,等于为自己结成网罗。’跟很多人商量,主意太多,百姓多数不能跟从,事情更难成功。百姓危急了,姑且顺从楚国,以缓和百姓的苦难。晋国军队来到,我们又再顺从他。恭恭敬敬地供给财货,以等待别人前来,这是小国所应当做的。用牺牲玉帛,在两国的边境上等待,以等待强有力的国家来保护百姓。敌人不为祸害,百姓不疲劳困乏,不也是可以的吗?”子展说:“小国用来事奉大国的,是信用。小国没有信用,战争和祸乱会每天都有,很快就要灭亡了。与晋国五次盟会的条约,如今却打算背弃,虽然楚国救援我国,还有什么用?楚国的亲近对我国不会有了结果,他们是想把我国作他们的边郡县邑,不能顺从他们。不如等待晋国。晋国的国君正当贤明的时候,四个军完备无缺,八个卿和睦无间,必然不会丢弃郑国。楚军距离我们遥远,粮食将要吃完了,一定会很快回去,怕什么?舍之听说:仗恃不如讲信用。完缮守备以使楚军疲惫,依靠信用以等待晋军,不也是可以的吗?”子驷说:“《诗》说:‘出主意的人很多,因此不能有所成就。发言的人挤满庭院,谁敢承担过错?好象一个人一边走路一边还和路人商量,因此一无所得。”请顺从楚国,騑来承担责任。” +于是郑国就和楚国讲和,派王子伯骈向晋国报告,说:“君王命令敝邑:‘整修你们的战车,使你们的车兵徒兵保持戒备,以讨伐动乱。’蔡国人不顺从,敝邑的人不敢贪图安逸,收尽我国的军队,以讨伐蔡国,俘虏了司马燮,奉献于邢丘的盟会上。现在楚国前来付伐,说:‘你们为什么对蔡国用兵?’焚烧我国郊外的小堡,侵略我国的城郭。敝邑的大众,夫妻男女,顾不得休息而互相救援。国家将要倾覆,没有地方可以控告。百姓死去和逃亡的,不是父兄,就是子弟。人人忧愁悲痛,不知道在哪里可以得到保护。百姓知道毫无办法,只好接受楚国的盟约。我和我的几个臣子不能禁止,不敢不报告。” 知武子派行人子员回答说:“君王受到楚国讨伐的命令,也不派一个使者来告诉我,反而立刻屈服于楚国。君王的愿望,谁敢反对?寡君准备率领诸侯和你们在城下相见。请君王考虑一下。” +晋国范宣子来鲁国聘问,同时拜谢鲁襄公的朝见,报告将出兵郑国。襄公设享礼招待他,范宣子赋《摽有梅》这首诗。季武子说:“谁敢不及时啊!现在用草木来比喻,寡君之于君王,不过是作为草木散发出来的气味而已。高高兴兴地接受命令,有什么时间早晚?”季武子赋《角弓》这首诗。客人将要退出,季武子赋《彤弓》这首诗。范宣子说:“城濮这一战,我们的先君文公在衡雍奉献战功,在襄王那里接受了红色的弓,作为子孙的宝藏。匄是先君官员的后代,岂敢不接受您的命令?”君子认为范宣子懂得礼仪。 + +襄公九年 +【经】九年春,宋灾。夏,季孙宿如晋。五月辛酉,夫人姜氏薨。秋八月癸未,葬我小君穆姜。冬,公会晋侯、宋公、卫侯、曹伯、莒子、邾子、滕子、薛伯、杞伯,小邾子、齐世子光伐郑。十有二月己亥,同盟于戏。楚子伐郑。 +【传】九年春,宋灾。乐喜为司城以为政。使伯氏司里,火所未至,彻小屋,涂大屋;陈畚挶具绠缶,备水器;量轻重,蓄水潦,积土涂;巡丈城,缮守备,表火道。使华臣具正徒,令隧正纳郊保,奔火所。使华阅讨右官,官庀其司。向戌讨左,亦如之。使乐遄庀刑器,亦如之。使皇郧命校正出马,工正出车,备甲兵,庀武守使西鉏吾庀府守,令司宫、巷伯儆宫。二师令四乡正敬享,祝宗用马于四墉,祀盘庚于西门之外。 +晋侯问于士弱曰:“吾闻之,宋灾,于是乎知有天道。何故?”对曰:“古之火正,或食于心,或食于咮,以出内火。是故咮为鹑火,心为大火。陶唐氏之火正阏伯居商丘,祀大火,而火纪时焉。相土因之,故商主大火。商人阅其祸败之衅,必始于火,是以日知其有天道也。”公曰:“可必乎?”对曰:“在道。国乱无象,不可知也。” +夏,季武子如晋,报宣子之聘也。 +穆姜薨于东宫。始往而筮之,遇《艮》之八三。史曰:“是谓《艮》之《随》三。《随》其出也。君必速也。”姜曰:“亡。是于《周易》曰:‘《随》,元亨利贞,无咎。’元,体之长也;享,嘉之会也;利,义之和也;贞,事之干也。体仁足以长人,嘉德足以合礼,利物足以和义,贞固足以干事,然,故不可诬也,是以虽《随》无咎。今我妇人而与于乱。固在下位而有不仁,不可谓元。不靖国家,不可谓亨。作而害身,不可谓利。弃位而姣,不可谓贞。有四德者,《随》而无咎。我皆无之,岂《随》也哉?我则取恶,能无咎乎?必死于此,弗得出矣。” +秦景公使士雅乞师于楚,将以伐晋,楚子许之。子囊曰:“不可。当今吾不能与晋争。晋君类能而使之,举不失选,官不易方。其卿让于善,其大夫不失守,其士竞于教,其庶人力于农穑。商工皂隶,不知迁业。韩厥老矣,知罃禀焉以为政。范□少于中行偃而上之,使佐中军。韩起少于栾□,而栾□、士鲂上之,使佐上军。魏绛多功,以赵武为贤而为之佐。君明臣忠,上让下竞。当是时也,晋不可敌,事之而后可。君其图之!”王曰:“吾既许之矣。虽不及晋,必将出师。”秋,楚子师于武城以为秦援。秦人侵晋,晋饥,弗能报也。 +冬十月,诸侯伐郑。庚午,季武子、齐崔杼、宋皇郧从荀罃、士□门于鄟门。卫北宫括、曹人、邾人从荀偃、韩起门于师之梁。滕人、薛人从栾□、士鲂门于北门。杞人、郳人从赵武、魏绛斩行栗。甲戌,师于汜,令于诸侯曰:“修器备,盛□粮,归老幼,居疾于虎牢,肆眚,围郑。”郑人恐,乃行成。中行献子曰:“遂围之,以待楚人之救也而与之战。不然,无成。”知武子曰:“许之盟而还师,以敝楚人。吾三分四军,与诸侯之锐以逆来者,于我未病,楚不能矣,犹愈于战。暴骨以逞,不可以争。大劳未艾。君子劳心,小人劳力,先王之制也”诸侯皆不欲战,乃许郑成。十一月己亥,同盟于戏,郑服也。 +将盟,郑六卿公子□非、公子发、公子嘉、公孙辄、公孙虿、公孙舍之及其大夫、门子皆从郑伯。晋士庄子为载书,曰:“自今日既盟之后,郑国而不唯晋命是听,而或有异志者,有如此盟。”公子□非趋进曰:“天祸郑国,使介居二大国之间。大国不加德音而乱以要之,使其鬼神不获歆其禋祀,其民人不获享其土利,夫妇辛苦垫隘,无所底告。自今日既盟之后,郑国而不唯有礼与强可以庇民者是从,而敢有异志者,亦如之。”荀偃曰:“改载书。”公孙舍之曰:“昭大神,要言焉。若可改也,大国亦可叛也。”知武子谓献子曰:“我实不德,而要人以盟,岂礼也哉!非礼,何以主盟?姑盟而退,修德息师而来,终必获郑,何必今日?我之不德,民将弃我,岂唯郑?若能休和,远人将至,何恃于郑?”乃盟而还。 +晋人不得志于郑,以诸侯复伐之。十二月癸亥,门其三门。闰月,戊寅,济于阴阪,侵郑。次于阴口而还。子孔曰:“晋师可击也,师老而劳,且有归志,必大克之。”子展曰:“不可。” +公送晋侯。晋侯以公晏于河上,问公年,季武子对曰:“会于沙随之岁,寡君以生。”晋侯曰:“十二年矣!是谓一终,一星终也。国君十五而生子。冠而生子,礼也,君可以冠矣!大夫盍为冠具?”武子对曰:“君冠,必以祼享之礼行之,以金石之乐节之,以先君之祧处之。今寡君在行,未可具也。请及兄弟之国而假备焉。”晋侯曰:“诺。”公还,及卫,冠于成公之庙,假钟磬焉,礼也。 +楚子伐郑,子驷将及楚平。子孔、子蟜曰:“与大国盟,口血未干而背之,可乎?”子驷、子展曰:“吾盟固云:‘唯强是从。’今楚师至,晋不我救,则楚强矣。盟誓之言,岂敢背之?且要盟无质,神弗临也,所临唯信。信者,言之瑞也,善之主也,是故临之。明神不蠲要盟,背之可也。”乃及楚平。公子罢戎入盟,同盟于中分。 +楚庄夫人卒,王未能定郑而归。 +晋侯归,谋所以息民。魏绛请施舍,输积聚以贷。自公以下,苟有积者,尽出之。国无滞积,亦无困人。公无禁利,亦无贪民。祈以币更,宾以特性,器用不作,车服从给。行之期年,国乃有节。三驾而楚不能与争。 +译文 +九年春季,宋国发生火灾。乐喜正做司城执掌政权,派伯氏管理街巷。火没有到达的地方,拆除小屋,用泥土涂在大屋上,摆列盛土和运土的器具;具备汲水的绳索和瓦罐,准备盛水的器具,估量人力的大小、任务的轻重,储满水塘,堆积泥土,巡查城郭,修缮守卫工具,标明火的趋向。乐喜派华臣调集常备兵,华臣又命令隧正调集远郊城堡的士兵,奔赴火灾发生的地点。派华阅主管右师,作为长官督促他的官属。向戌主管左师,也如同华阅一样。派乐遄准备刑具,也如同华阅一样。派皇郧命令管马的人牵出马匹,工正推出战车,装备武器,守卫武器库,派西鉏吾保护国库。西鉏吾命令司宫,巷伯在宫内警戒。左师、右师命令四个乡正祭祀四乡的神灵,祝宗杀马来祭祀四城的神灵,在宋都西门外边祭祀盘庚。 +晋悼公向士弱询问说:“我听说,宋国遭了火灾,从这里就知道了天道,为什么?”士弱回答说:“古代的火正,祭祀火星的时候或者用心宿陪祭,或者用柳宿陪祭,由于火星运行在这两个星宿中间。所以柳宿就是鹑火星,心宿就是大火星。陶唐氏的火正阏伯住在商丘,祭祀大火星,而用火星来确定时节。相土沿袭这个方法,所以商朝以大火星为祭祀的主星。商朝人观察他们祸乱失败的预兆,一定从火灾开始,因此在过去自以为掌握了天道。”晋悼公说:“靠得住吗?”士弱回答说:“在于有道或者无道。国家动乱而上天不给预兆,这就不能预知了。” +夏季,季武子去到晋国,这是由于回报范宣子的聘问。 +穆姜死在东宫里。开始住进去的时候,占筮,得到《艮》变为八■,太史说:“这叫做《艮》变为《随》■。《随》,是出走的意思。您一定要赶紧出去。”穆姜说:“不用出去!这卦象在《周易》里说‘《随》,元、亨、利、贞,没有灾祸。’元,是躯体最高的地方;亨,是嘉礼中的主宾相会;利,是道义的总和;贞,是事情的本体。体现了仁就足以领导别人,美好的德行足以协调礼仪,有利于万物足以总括道义,本体坚强足以办好事情。这样,所以是不能欺骗的。因此虽然得到《随》卦而没有灾祸。现在我作为女人而参与了动乱。本来地位低下而又没有仁德,不能说是元。使国家不安定,不能说是亨。做了事情而害自身,不能说是利。丢弃寡妇的地位而修饰爱美,不能说是贞。具有上面四种德行的,得到《随》卦才可以没有灾祸。而我都没有,难道合于《随》卦卦辞吗?我挑取邪恶,能够没有灾祸吗?一定死在这里,不能出去了。” +秦景公派遣士雃向楚国请求出兵,准备进攻晋国,楚共王答应了。子囊说:“不行。目前我们不能和晋国争夺。晋国国君按人的能力之大小而使用他们,举拔人才不失去能胜任的人,任命官员不改变原则。他的卿把职位让给善人,他的大夫不失职守,他的士努力于教育百姓,他的庶人致力于农事,商贾技工和贱役不想改变职业。韩厥告老退休,知罃继承他而执政。范匄比中行偃年轻而在中行偃之上,让他辅佐中军。韩起比栾黡年轻,而栾黡、士鲂使他在自己之上,让他辅佐上军。魏绛的功劳很多,却认为赵武贤能而甘愿做他的辅佐。国君明察,臣下忠诚,上面谦让,下面尽力。在这个时候,晋国不能抵挡,事奉他们才行。君王还是考虑一下!”楚共王说:“我已经答应他们了,虽然比不上晋国,一定要出兵。” +秋季,楚共王驻军在武城,以作为秦国的后援。秦国人侵袭晋国。晋国正遭受饥荒,不能反击。 +冬季,十月,诸侯进攻郑国。十月十一日,季武子、齐国的崔杼、宋国的皇郧跟荀罃、士匄进攻鄟门。卫国的北宫括、曹国人、邾国人跟随荀偃、韩起进攻师之梁门,滕国人、薛国人跟随栾黡、士鲂进攻北门,杞国人、郳国人跟随赵武、魏绛砍伐路边的栗树。十五日,军队驻扎在汜水边上,于是传令诸侯说:“修理作战工具,备好干粮,送回老的小的,让有病的人住在虎牢,赦免错误,包围郑国。” +郑国人害怕,就派人求和。荀偃说:“对郑国实际包围,以等待楚国人救援,和他们作战。不这样,就没有真正的讲和。”知罃说:“答应他们结盟然后退兵,用这样的办法引诱楚国人进攻郑国,使楚国人疲劳。我们把四军分为三部分,加上诸侯的精锐部队,以迎击前来的军队,对我们来说并不困乏,而楚军就不能持久了。这样,还是比打仗好。暴露白骨以图一时之快,不能用这样的办法和敌人争胜。很大的疲劳还没有停止,君子用智,小人用力,这是先王的训示。”诸侯都不想打仗,于是就允许郑国讲和。 +十一月初十日,一起在戏地结盟,这是由于郑国顺服了。 +准备结盟,郑国的六卿公子騑、公子发、公子嘉、公孙辄、公孙虿、公孙舍之以及他们的大夫、卿的嫡子,都跟随郑简公赴会。晋国的士庄子制作盟书,说:“从今天已经盟誓以后,郑国如果对晋国不唯命是听或者有别的想法,就像这份盟书所记载的一样。”公子騑快步走上前,说:“上天降祸郑国,让我国夹于两个大国之间。大国不赐给我们友好的话语,反而发动战乱以要挟我们结盟,让我们的鬼神不能得到祭祀,百姓不能享受土地上的出产,男人女人都辛苦瘦弱,没有地方可以诉说。从今天已经盟誓以后,郑国如果不服从既合于礼仪而且有强大力量来保护我们的国家,反而敢有其他想法,也像这份盟书所记载的一样。”荀偃说:“修改这篇盟辞!”公孙舍之说:“已经把盟约报告神灵了。如果可以修改,大国也可以背叛了。”知罃对荀偃说:“我们实在不合于道德,反而用盟约来要挟别人,这难道合于礼仪吗?不合礼仪,用什么主持盟会?姑且结盟而退兵,修养德行、休整军队然后再来,最终必然得到郑国,何必一定在今天?我们不合于道德,百姓将会丢弃我们,岂只是郑国?如果能够休养民力和睦民心,远方的人将会来顺服,有什么要依靠郑国呢?”于是就结盟然后回国。 +晋国人不能随心所欲号令郑国,便带领诸侯再次进攻郑国。十二月初五日,攻击郑国的三面城门,十二月二十日在阴阪渡河,侵袭郑国。驻扎在阴口然后回去。子孔说:“晋军可以攻击,军队长久在外边因而疲劳,只想回去。必然可以胜他们。”子展说:“不行。” +鲁襄公送晋悼公,晋悼公为襄公在黄河边上设宴,问起襄公的年龄。季武子回答说:“在沙随会见的那一年,寡君出生。”晋悼公说:“十二年了,这叫做一终,这是岁星运行一圈的终止。国君十五岁而生孩子,举行冠礼以后生孩子,这是合于礼仪的,您可以举行冠礼了。大夫何不准备举行冠礼的用具?”季武子回答说:“国君举行冠礼,一定要请补饮酒的仪节作为序幕,用钟磬的音乐表示节度,在先君的宗庙里才能举行。现在寡君正在路上,不能具备各种冠礼工具,请在到达兄弟国家以后借用这些设备。”晋悼公说:“好。”襄公回国,到达卫国,在卫成公庙里举行冠礼,借用了钟磬,这是合于礼的。 +楚共王进攻郑国,子驷打算和楚国讲和,子孔、子蟜说:“和大国结盟,嘴里的血没有干就违背了它,行吗?”子驷、子展说:“我们的盟誓本来就说‘唯有跟从强大的国家’,现在楚国军来到,晋国不救援我国,那么楚国就是强大的国家了。盟誓的话,难道敢违背?而且在要挟之下举行的盟誓没有诚信可言,神灵不会降临,神灵所降临的只是有诚信的盟会。信,是言语的凭证,善良的主体,所以神灵降临。明察一切的神灵认为在要挟下举行的盟会不洁净,违背它是可以的。”于是郑国就和楚国讲和。公子罢戎进入郑国结盟,一起在中分盟誓。 +楚庄王夫人死,楚共王没有能安定郑国就回国了。  晋悼公回国,计议让百姓休养生息的办法。魏绛请求赐予恩惠,把积聚的财物拿出来借给百姓。从晋侯以下,如果有积聚的财物,全都拿了出来。国内没有不流通的财物,也没有困乏的百姓;公家不禁止百姓牟利,也没有贪婪的百姓。祈祷用财币代替牺牲,招待宾客只用一种牲畜,新的器物不添制,车马服饰只要够用就行了。这些措施推行一年,国家才有了法度。三次出兵而楚国不能和晋国争夺。 + +襄公十年 +【经】十年春,公会晋侯、宋公、卫侯、曹伯、莒子、邾子、滕子、薛伯、杞伯、小邾子、齐世子光会吴于柤。夏,五月甲午,遂灭逼阳。公至自会。楚公子贞、郑公孙辄帅师伐宋。晋师伐秦。秋,莒人伐我东鄙。公会晋侯、宋公、卫侯、曹伯、莒子、邾子、齐世子光、滕子、薛伯、杞伯、小邾子伐郑。冬,盗杀郑公子□非、公子发、公孙辄。戍郑虎牢。楚公子贞帅师救郑。公至自伐郑。 +【传】十年春,会于柤,会吴子寿梦也。三月癸丑,齐高厚相大子光以先会诸侯于钟离,不敬。士庄子曰:“高子相大子以会诸侯,将社稷是卫,而皆不敬,弃社稷也,其将不免乎!” +夏四月戊午,会于柤。 +晋荀偃、士□请伐逼阳,而封宋向戌焉。荀罃曰:“城小而固,胜之不武,弗胜为笑。”固请。丙寅,围之,弗克。孟氏之臣秦堇父辇重如役。逼阳人启门,诸侯之士门焉。县门发,郰人纥抉之以出门者。狄虒弥建大车之轮而蒙之以甲以为橹,左执之,右拔戟,以成一队。孟献子曰:“《诗》所谓‘有力如虎’者也。”主人县布,堇父登之,及堞而绝之。队则又县之,苏而复上者三。主人辞焉乃退,带其断以徇于军三日。 +诸侯之师久于逼阳,荀偃、士□请于荀罃曰:“水潦将降,惧不能归,请班师。”知伯怒,投之以机,出于其间,曰:“女成二事而后告余。余恐乱命,以不女违。女既勤君而兴诸侯,牵帅老夫以至于此,既无武守,而又欲易余罪,曰:‘是实班师,不然克矣’。余赢老也,可重任乎?七日不克,必尔乎取之!”五月庚寅,荀偃、士□帅卒攻逼阳,亲受矢石。甲午,灭之。书曰“遂灭逼阳”,言自会也。以与向戌,向戌辞曰:“君若犹辱镇抚宋国,而以逼阳光启寡君,群臣安矣,其何贶如之?若专赐臣,是臣兴诸侯以自封也,其何罪大焉?敢以死请。”乃予宋公。 +宋公享晋侯于楚丘,请以《桑林》。荀罃辞。荀偃、士□曰:“诸侯宋、鲁,于是观礼。鲁有禘乐,宾祭用之。宋以《桑林》享君,不亦可乎?”舞,师题以旌夏,晋侯惧而退入于房。去旌,卒享而还。及着雍,疾。卜,桑林见。荀偃、士□欲奔请祷焉。荀罃不可,曰:“我辞礼矣,彼则以之。犹有鬼神,于彼加之。”晋侯有间,以逼阳子归,献于武宫,谓之夷俘。逼阳妘姓也。使周内史选其族嗣,纳诸霍人,礼也。 +师归,孟献子以秦堇父为右。生秦丕兹,事仲尼。 +六月,楚子囊、郑子耳伐宋,师于訾毋。庚午,围宋,门于桐门。 +晋荀罃伐秦,报其侵也。 +卫侯救宋,师于襄牛。郑子展曰:“必伐卫,不然,是不与楚也。得罪于晋,又得罪于楚,国将若之何?”子驷曰:“国病矣!”子展曰:“得罪于二大国,必亡。病不犹愈于亡乎?”诸大夫皆以为然。故郑皇耳帅师侵卫,楚令也。孙文子卜追之,献兆于定姜。姜氏问繇。曰:“兆如山陵,有夫出征,而丧其雄。”姜氏曰:“征者丧雄,御寇之利也。大夫图之!”卫人追之,孙蒯获郑皇耳于犬丘。 +秋七月,楚子囊、郑子耳伐我西鄙。还,围萧,八月丙寅,克之。九月,子耳侵宋北鄙。孟献子曰:“郑其有灾乎!师竞已甚。周犹不堪竞,况郑乎?有灾,其执政之三士乎!” +莒人间诸侯之有事也,故伐我东鄙。 +诸侯伐郑。齐崔杼使大子光先至于师,故长于滕。己酉,师于牛首。 +初,子驷与尉止有争,将御诸侯之师而黜其车。尉止获,又与之争。子驷抑尉止曰:“尔车,非礼也。”遂弗使献。初,子驷为田洫,司氏、堵氏、侯氏、子师氏皆丧田焉,故五族聚群不逞之人,因公子之徒以作乱。于是子驷当国,子国为司马,子耳为司空,子孔为司徒。冬十月戊辰,尉止、司臣、侯晋、堵女父、子师仆帅贼以入,晨攻执政于西宫之朝,杀子驷、子国、子耳,劫郑伯以如北宫。子孔知之,故不死。书曰“盗”,言无大夫焉。 +子西闻盗,不儆而出,尸而追盗,盗入于北宫,乃归授甲。臣妾多逃,器用多丧。子产闻盗,为门者,庀群司,闭府库,慎闭藏,完守备,成列而后出,兵车十七乘,尸而攻盗于北宫。子蟜帅国人助之,杀尉止,子师仆,盗众尽死。侯晋奔晋。堵女父、司臣、尉翩、司齐奔宋。 +子孔当国,为载书,以位序,听政辟。大夫、诸司、门子弗顺,将诛之。子产止之,请为之焚书。子孔不可,曰:“为书以定国,众怒而焚之,是众为政也,国不亦难乎?”子产曰:“众怒难犯,专欲难成,合二难以安国,危之道也。不如焚书以安众,子得所欲,众亦得安,不亦可乎?专欲无成,犯众兴祸,子必从之。”乃焚书于仓门之外,众而后定。 +诸侯之师城虎牢而戍之。晋师城梧及制,士鲂、魏绛戍之。书曰“戍郑虎牢”,非郑地也,言将归焉。郑及晋平。楚子囊救郑。十一月,诸侯之师还郑而南,至于阳陵,楚师不退。知武子欲退,曰:“今我逃楚,楚必骄,骄则可与战矣。”栾□曰:“逃楚,晋之耻也。合诸侯以益耻,不如死!我将独进。”师遂进。己亥,与楚师夹颖而军。子矫曰:“诸侯既有成行,必不战矣。从之将退,不从亦退。退,楚必围我。犹将退也。不如从楚,亦以退之。”宵涉颖,与楚人盟。栾□欲伐郑师,荀罃不可,曰:“我实不能御楚,又不能庇郑,郑何罪?不如致怨焉而还。今伐其师,楚必救之,战而不克,为诸侯笑。克不可命,不如还也!”丁未,诸侯之师还,侵郑北鄙而归。楚人亦还。 +王叔陈生与伯舆争政。王右伯舆,王叔陈生怒而出奔。及河,王复之,杀史狡以说焉。不入,遂处之。晋侯使士□平王室,王叔与伯舆讼焉。王叔之宰与伯舆之大夫瑕禽坐狱于王庭,士□听之。王叔之宰曰:“筚门闺窦之人而皆陵其上,其难为上矣!”瑕禽曰:“昔平王东迁,吾七姓从王,牲用备具。王赖之,而赐之騂旄之盟,曰:‘世世无失职。’若筚门闺窦,其能来东底乎?且王何赖焉?今自王叔之相也,政以贿成,而刑放于宠。官之师旅,不胜其富,吾能无筚门闺窦乎?唯大国图之!下而无直,则何谓正矣?”范宣子曰:“天子所右,寡君亦右之。所在,亦左之。”使王叔氏与伯舆合要,王叔氏不能举其契。王叔奔晋。不书,不告也。单靖公为卿士,以相王室。 +译文 +十年春季,鲁襄公和晋悼公、宋平公、卫献公、曹成公、莒子、邾子、滕子、薛伯、杞伯、小邾子、齐国太子光在柤地会见,这是为了会见吴王寿梦。三月二十六日,齐国的高厚作为太子光的相礼,和诸侯在钟离先行会见,表现出不恭敬。士庄子说:“高子作为太子的相礼会见了诸侯,应当捍卫他们的国家,但却表现出不严肃,这是丢弃国家,恐怕将会不免于祸吧!” +夏季,四月初一日,诸侯在柤地会见。 +晋国的荀偃、士匄请求进攻偪阳而把它作为向戌的封邑。荀罃说:“城小而坚固,攻下来不算勇敢,攻它不下被人讥笑。”荀偃等人坚决请求。初九日,包围偪阳,不能攻克。孟氏的家臣秦堇父用人力拉了装备车到达战地,偪阳人打开城门,诸侯的将士乘机进攻。内城的人把闸门放下,郰县长官纥双手举门,把进攻城里的将士放出来。狄虒弥把大车轮子立起来,蒙上皮甲作为大盾牌,左手拿着它,右手拔戟,领兵单成一队。孟献子说:“这就是《诗》所说的‘像老虎一样有力气’的人啊。”偪阳的守城人把布挂下来,秦堇父拉着布登城,刚到墙垛,守城人就把布割断。秦堇父跌落在地,守城人又把布挂下来。秦堇父醒起来重新上去,这样三次,守城人表示钦佩他的勇敢,不再挂布。这才退兵,把割的布做了带子在军内游行示众三天。 +诸侯的军队在偪阳很久了,荀偃、士匄请示荀罃说:“快下雨了,恐怕到时不能回去,请您退兵吧。”荀罃发怒,把弩机向他们扔过去,机从两个人中间飞过,说:“你们把这两件事情办成了再来跟我说话,原来我恐怕意见不一而扰乱了军令,所以不违背你们。你们既已使国君勤劳而发动了诸侯的军队,牵着我老头子到了这里,既没有坚持进攻,而又想归罪于我,回去说:‘就是他下令退兵。不这样,攻下来了。’我已经衰老了,还能再承担一次罪责吗?七天攻不下来,一定要取你们的脑袋!”五月初四日,荀偃、士匄率领步兵攻打偪阳,亲身受到箭和石块的攻击,初八日,灭亡了偪阳。《春秋》记载说“遂灭偪阳”,说的是从柤地盟会以后就进攻了偪阳。把偪阳封给向戌。向戌辞谢说:“如果还承蒙君王安抚宋国,而用偪阳来扩大寡君的疆土,下臣们就安心了,还有什么比得上这样的赐予呢?如果专门赐给下臣,那就是下臣发动诸侯的军队而为自己求得封地了,还有什么罪过比这再大呢?谨以一死来请求。”于是就把偪阳给了宋平公。 +宋平公在楚丘设宴招待晋悼公,请求使用《桑林》之乐舞。荀罃辞谢。荀偃、士匄说:“诸侯中的鲁国、宋国,在那里可以参观礼仪。鲁国有禘乐,在招待贵宾和举行大祭的时候用它。宋国使用《桑林》之舞招待国君,不也是可以的吗?”开始舞蹈,乐师手举旌夏之旗率领乐队进来,晋悼公害怕而退入房里。宋国人去掉旌夏,使这次宴会顺利结束,晋悼公方才回国。到达著雍,晋悼公生病。占卜,从卜兆里见到桑林之神。荀偃、士匄想要奔回宋国请求祈祷,荀罃不同意,说:“我们已经辞去这种礼仪了,他们还是要用它。如果有鬼神,会把灾祸加在他们身上的。”晋悼公病愈,带了偪阳子回国,奉献于武宫,把它称为夷人俘虏。偪阳,是姓妘的一族统治的。晋悼公派周朝的内史选择妘姓宗族的族嗣,让他们居住在霍人地方,这是合于礼的。 +鲁军回国,孟献子让秦堇父做车右。秦堇父生了秦丕兹,拜孔子为师。 +六月,楚国的子囊、郑国的子耳进攻宋国,军队驻扎在訾毋。十四日,包围宋国,攻打桐门。 +晋国的荀罃进攻秦国,这是为了报复秦国的入侵。 +卫献公救援宋国,军队驻在襄牛。郑国的子展说:“一定要进攻卫国。不这样,就是不亲附楚国了。得罪了晋国,又得罪了楚国,国家怎么办?”子驷说:“国家已经很困乏了。”子展说:“得罪了两个大国,一定灭亡。困乏,不还比灭亡强一些吗?”大夫们都认为子展的话说得对,所以郑国的皇耳入侵卫国,这是出于楚国的命令。 +孙文子为追逐郑国军队占卜,把卜兆献给定姜。定姜问繇辞怎么样。孙文子说:“繇辞是:‘卜兆如同山陵,有人出国征伐,丧失他们的英雄。’”定姜说:“征伐而丧失英雄,这是有利于抵御敌人的。大夫考虑一下!”卫国人追逐郑国军队,孙蒯在犬耳俘虏了郑将皇耳。 +秋季七月,楚国的子囊、郑国的子耳联军入侵我国西部边境。回国,包围萧地。八月十一日,攻克萧地。九月,子耳入侵宋国北部边境。孟献子说:“郑国恐怕有灾祸吧!军队争战太过分了。周天子还经不起经常用兵,何况郑国呢?有灾祸,恐怕会在执政的三位大夫身上吧!” +莒国人钻了诸侯有战事的空子,所以进攻我国东部边境。 +诸侯发兵攻打郑国,齐国的崔杼让太子光先到达军队里,所以排在滕国前面。二十五日,军队驻扎在牛首。 +当初,子驷和尉止有争执,在将要抵御诸侯军队的时候减少了尉止的兵车。尉止俘虏了敌人,子驷又和他争夺功劳。子驷压抑尉止说:“你的战车太多不合礼制。”于是就不让他献俘虏。当初,子驷疏通田里的水沟,司氏、堵氏、侯氏、子师氏都丧失了土田。所以五个宗族聚集了一伙不得志的人凭借了公子的族党以发动叛乱。这时候子驷掌握国政,子国做司马,子耳做司空,子孔做司徒。冬季,十月十四日,尉止、司臣、侯晋、堵女父、子师仆率领叛乱分子进入,早晨在西宫的朝廷上攻打执政,杀死了子驷、子国、子耳,劫持郑简公到了北宫。子孔事先知道这件事,所以没有死。《春秋》记载说“盗”,这是说没有大夫参预这次叛乱。 +子西听说有叛乱,不设警戒就出来了,收了他父亲子驷的尸骨就去追赶叛乱分子。叛乱分子进入北宫,子西就回去,召集甲兵,但是家臣和妾婢多数已经逃走,器物也已经大多丢失。子产听说有叛乱,设置守门的警卫,配齐所有的官员,关闭档案库,慎重收藏,完成防守设备,把士兵排成行列以后才出来,有战车十七辆。子产先收他父亲尸骨然后在北宫攻打叛乱分子,子?率领国内的人们帮助他,杀了尉止、子师仆,这伙叛乱分子全部被杀死。侯晋逃亡到晋国,堵女父、司臣、尉翩、司齐逃亡到宋国。 +子孔掌握国政,制作盟书,规定官员各守其位、听取执政的法令。大夫、官员们、卿的嫡子不肯顺从,子孔准备加以诛杀。子产劝阻他,请求烧掉盟书。子孔不同意,说:“制作盟书用来安定国家,大伙发怒就烧了它,这是大伙当政,国家不也很为难了吗?”子产说:“大伙怒气难于触犯,专权的愿望难于成功,把两件难办的事合在一起来安定国家,这是危险的办法。不如烧掉盟书来安定大家,您得到了所需要的东西,大伙也能够安定,不也是可以的吗?专权的愿望不能成功,触犯大伙会发生祸乱,您一定要听我的话。”于是就在仓门外边烧掉了盟书,大伙这才安定下来。 +诸侯的军队在虎牢筑城并且戍守,晋国军队在梧地和制地筑城,士鲂、魏绛戍守。《春秋》记载说“戍郑虎牢”,不是郑国的领土而这样记载,这是说将要归还给郑国了。郑国和楚国讲和。楚国的子囊救援郑国。十一月,诸侯联军环绕郑国然后往南,到达阳陵,楚军不退。知武子想要退兵,说:“现在我们避开楚军,楚军必然骄傲,骄傲了就可以和他们打仗了。”栾黡说:“避开楚军,这是晋国的耻辱。会和诸侯来增加耻辱,不如一死。我打算单独进军。”军队就往前推进。十六日,和楚军隔着颍水相对而驻扎下来。郑将子?说:“诸侯已经完成了退兵准备,一定不会作战了。顺从他们要退兵,不顺从他们也要退兵。他们退兵,楚国必然包围我们。同样是要退兵,不如顺从楚国,用这样的办法让他们退兵。”郑军夜里渡过颍水,和楚国人结盟。栾黡想要攻打郑国军队,荀罃不同意,说:“我们实在不能抵抗楚军,又不能保护郑国,郑国有什么罪?不如把怨恨奉送给楚国然后回去。现在攻打他们的军队,楚国必然救援他们。作战不能胜利,就被诸侯笑话,胜利不能肯定,不如回去吧。”二十四日,诸侯的军队撤退,攻打了郑国的北部边境然后回国。楚国人也退兵回国。 +王叔陈生和伯舆争夺政权,周灵王赞助伯舆。王叔陈生发怒而逃亡。到达黄河,周灵王让他官复原位,杀了史狡以让他高兴。王叔陈生不回成周,就住在黄河边上。晋悼公派士匄调和王室的争端,王叔陈生和伯舆提出争讼。王叔的家臣头子和伯舆的大夫瑕禽在周天子的朝廷上争论是非,士匄听取他们的诉讼。王叔的家臣头子说:“柴门小户的人都要陵驾于他上面的人,上面的人就很难处了。”瑕禽说:“从前平王东迁,我们七姓人家跟随周天子,牺牲全都具备,天子信赖他们,而赐给他们用赤牛祭神的盟约,说:‘世世代代不要失职’如果是柴门小户,他们能够来到东方而住下来吗?而且天子又怎么信赖他们呢?现在自从王叔把持周政权,政事用贿赂来完成,而把执行法律的责任放在宠臣身上。官员中的师和旅,阔气得没有办法,这样,我们能够不是柴门小户吗?请大国考虑一下!下面的人就不能有理,那么什么叫做公正呢?”士匄说:“天子所赞助的,寡君也赞助他;天子所不赞助的,寡君也不赞助他。”就让王叔和伯舆对证讼辞,王叔拿不出他的文件来。王叔逃亡到晋国,《春秋》所以没有记载,这是由于没有通告鲁国的缘故。单靖公做了卿士以辅助王室。 + +襄公十一年 +【经】十有一年春王正月,作三军。夏四月,四卜郊,不从,乃不郊。郑公孙舍之帅师侵宋。公会晋侯、宋公、卫侯、曹伯、齐世子光、莒子、邾子、滕子、薛伯、杞伯、小邾子伐郑。秋七月己未,同盟于亳城北。公至自伐郑。楚子、郑伯伐宋。公会晋侯、宋公、卫侯、曹伯、齐世子光、莒子、邾子、滕子、薛伯、杞伯、小邾子伐郑,会于萧鱼。公至自会。楚执郑行人良霄。冬,秦人伐晋。 +【传】十一年春,季武子将作三军,告叔孙穆子曰:“请为三军,各征其军。”穆子曰:“政将及子,子必不能。”武子固请之,穆子曰:“然则盟诸?”乃盟诸僖闳,诅诸五父之衢。 +正月,作三军,三分公室而各有其一。三子各毁其乘。季氏使其乘之人,以其役邑入者,无征;不入者,倍征。孟氏使半为臣,若子若弟。叔孙氏使尽为臣,不然,不舍。 +郑人患晋、楚之故,诸大夫曰:“不从晋,国几亡。楚弱于晋,晋不吾疾也。晋疾,楚将辟之。何为而使晋师致死于我,楚弗敢敌,而后可固与也。”子展曰:“与宋为恶,诸侯必至,吾从之盟。楚师至,吾又从之,则晋怒甚矣。晋能骤来,楚将不能,吾乃固与晋。”大夫说之,使疆埸之司恶于宋。宋向戌侵郑,大获。子展曰:“师而伐宋可矣。若我伐宋,诸侯之伐我必疾,吾乃听命焉,且告于楚。楚师至,吾又与之盟,而重赂晋师,乃免矣。”夏,郑子展侵宋。 +四月,诸侯伐郑。己亥,齐大子光、宋向戌先至于郑,门于东门。其莫,晋荀罃至于西郊,东侵旧许。卫孙林父侵其北鄙。六月,诸侯会于北林,师于向,右还,次于琐,围郑。观兵于南门,西济于济隧。郑人惧,乃行成。 +秋七月,同盟于亳。范宣子曰:“不慎,必失诸侯。诸侯道敝而无成,能无贰乎?”乃盟,载书曰:“凡我同盟,毋蕴年,毋壅利,毋保奸,毋留慝,救灾患,恤祸乱,同好恶,奖王室。或间兹命,司慎司盟,名山名川,群神群祀,先王先公,七姓十二国之祖,明神殛之,俾失其民,队命亡氏,踣其国家。” +楚子囊乞旅于秦,秦右大夫詹帅师从楚子,将以伐郑。郑伯逆之。丙子,伐宋。 +九月,诸侯悉师以复伐郑。郑人使良霄、大宰石□如楚,告将服于晋,曰:“孤以社稷之故,不能怀君。君若能以玉帛绥晋,不然则武震以摄威之,孤之愿也。”楚人执之,书曰“行人”,言使人也。诸侯之师观兵于郑东门,郑人使王子伯骈行成。甲戌,晋赵武入盟郑伯。冬十月丁亥,郑子展出盟晋侯。十二月戊寅,会于萧鱼。庚辰,赦郑囚,皆礼而归之。纳斥候,禁侵掠。晋侯使叔肸告于诸侯。公使臧孙纥对曰:“凡我同盟,小国有罪,大国致讨,苟有以藉手,鲜不赦宥。寡君闻命矣。”郑人赂晋侯以师悝、师触、师蠲,广车、軘车淳十五乘,甲兵备,凡兵车百乘,歌钟二肆,及其鏄磐,女乐二八。 +晋侯以乐之半赐魏绛,曰:“子教寡人和诸戎狄,以正诸华。八年之中,九合诸侯,如乐之和,无所不谐。请与子乐之。”辞曰:“夫和戎狄,国之福也;八年之中,九合诸侯,诸侯无慝,君之灵也,二三子之劳也,臣何力之有焉?抑臣愿君安其乐而思其终也!《诗》曰:‘乐只君子,殿天子之邦。乐只君子,福禄攸同。便蕃左右,亦是帅从。’夫乐以安德,义以处之,礼以行之,信以守之,仁以厉之,而后可以殿邦国,同福禄,来远人,所谓乐也。《书》曰:‘居安思危。’思则有备,有备无患,敢以此规。”公曰:“子之教,敢不承命。抑微子,寡人无以待戎,不能济河。夫赏,国之典也,藏在盟府,不可废也,子其受之!”魏绛于是乎始有金石之乐,礼也。 +秦庶长鲍、庶长武帅师伐晋以救郑。鲍先入晋地,士鲂御之,少秦师而弗设备。壬午,武济自辅氏,与鲍交伐晋师。己丑,秦、晋战于栎,晋师败绩,易秦故也。 +译文 +十一年春季,季武子准备编定三个军,告诉叔孙穆子说:“请编三个军,每家管一个军。”叔孙穆子说:“政权将要轮到您执掌,您一定办不好的。”季武子坚决请求,叔孙穆子说:“那么结个盟吧。”于是就在僖公宗庙门口订立盟约,在五父之衢发誓。 +正月,编定三个军,把公室的军队一分为三,而各家掌握一军。三家各自把原有私家车兵合并,季氏让他私人武装中的成员参加军队的免除征税,不参加的人加倍征税。孟氏让他的私邑士兵中的一半,或子或弟做奴隶兵。叔孙氏仍然把他私邑士兵全编为奴隶兵,不这样,就不并入所分的公室军队里。 +郑国人担心晋国和楚国,大夫们说:“不顺从晋国,国家几乎灭亡。楚国比晋国弱,而晋国并不急于争夺我国。如果晋国急于争夺我国,楚国会避开他们的。怎么才能让晋军出死力攻打我们,楚国就不敢抵挡,然后才能够坚决依附晋国。”子展说:“向宋国挑衅,诸侯必然来到,我们跟从他们结盟。楚军来到,我们又跟从楚国,这样晋国就更要生气了。晋国如果能不断地前来,楚国将会不能抵挡,我们就坚决依附晋国。”大夫们对这计划表示高兴,派边境的官吏向宋国挑衅。宋国的向戌入侵郑国,俘获甚多。子展说:“可以出兵攻打宋国了。如果我们进攻宋国,诸侯进攻我们必然努力攻击。我们就听从命令,同时报告楚国。楚军来到,我们就和他们结盟而又重重地贿赂晋军,就可以免于祸患了。”夏季,郑国的子展率军入侵宋国。 +四月,诸侯联军进攻郑国。十九日,齐国太子光、宋国向戌先到达郑国,驻军在东门外。当天晚上,晋国荀罃到达西郊,往东进攻许国的旧地。卫国孙林父进攻郑国的北部边境。六月,诸侯在北林会见,军队驻扎在向地。又转向西北,驻扎在琐地。包围郑国,在南门外显示军力。又有军队从西边渡过济隧。郑国人畏惧,就向诸侯求和。 +秋季,七月,各诸侯和郑国在毫地结盟。范宣子说:“如果盟辞不谨慎,必然失去诸侯。诸侯来往疲乏而没有得到成功,能够没有二心吗?”于是就盟誓。盟书说:“凡是我们同盟国家,不要囤积粮食,不要垄断利益,不要庇护罪人,不要收留坏人。救济灾荒,安定祸患,统一好恶,辅助王室。有人触犯这些命令,司慎、司盟的神,名山、名川的神,各种天神,先王、先公,七姓十二国的祖宗,明察的神灵诛戮他,使他失去百姓,丧君灭族,灭国亡家。” +楚国的子囊向秦国请求出兵,秦国的右大夫詹率领军队跟随楚共王,由楚王率领进攻郑国。郑简公前去迎接表示顺服。七月二十七日,进攻宋国。 +九月,诸侯用全部兵力再次进攻郑国,郑国人派良霄、太宰石chuò[“免”字之“儿”换为“比”。一种似兔而大的青色小兽]去到楚国,告诉说准备对晋国顺服,说:“孤由于国家的缘故,不能怀念君王了。君王如果能够用玉帛安抚晋国,不这样,那就用武力对他们加以威慑,这都是我的愿望。”楚国人囚禁了他们。《春秋》记载说“行人”,这是说他们是使者“不应该有罪”的意思。 +诸侯联军在东门外示威,郑国人派王子伯骈求和。九月二十六日,晋国的赵武进入郑国和郑简公结盟。冬季十月初九日,郑国的子展出城和晋悼公结盟。十二月初一日,在萧鱼会见。初三日,赦免郑国的俘虏,都给以礼遇放回去。收回巡逻兵,禁止掠夺。晋悼公派叔肸通告诸侯。鲁襄公派臧孙纥回答说:“凡是我们同盟国家,小国有了罪过,大国派兵讨伐,如果稍有所得,很少对小国不加赦免的,寡君听到命令了。” +郑国人赠给晋悼公师悝、师触、师蠲;配对的广车、軘车各十五辆,盔甲武器齐备,和其他战车一共一百辆;歌钟两架以及和它相配的鎛和磬;女乐两佾十六人。晋悼公把乐队的一半赐给魏绛,说:“您教寡人同各部落戎狄讲和以整顿中原诸国,八年中间九次会合诸侯,好像音乐的和谐,没有地方不协调,请和您一起享用快乐。”魏绛辞谢说:“同戎狄讲和,这是国家的福气。八年中间九次会合诸侯,诸侯顺从,这是由于君王的威灵,也是由于其他人员的功劳,下臣有什么力量?然而下臣希望君王既安于这种快乐,而又想到它的终了。《诗》说:‘快乐啊君子,镇抚天子的家邦。快乐啊君子,他的福禄和别人同享。治理好附近的小国,使他们相率服从。’音乐用来巩固德行,用道义对待它,用礼仪推行它,用信用保守它,用仁爱勉励它,然后能用来安定邦国、同亨福禄、召来远方的人,这就是所说的快乐。《书》说:‘处于安定要想到危险。’想到了就有防备,有了防备就没有祸患。谨以此向君王规劝。”晋悼公说:“您的教导,岂敢不承受命令!而且要是没有您,寡人无法对待戎人,又不能渡过黄河。赏赐,是国家的典章,藏在盟府,不能废除的。您还是接受吧!”魏绛从这时开始才有了金石的音乐,这是合于礼的。 +秦国庶长鲍、庶长武领兵进攻晋国来救援郑国。鲍先进入晋国国境,士鲂抵御他,认为秦军人少而不加防备。十二月初五日,武从辅氏渡河,和鲍夹攻晋军。十二日,秦军和晋军在栎地作战,晋军大败,这是由于轻视秦军的缘故。 + +襄公十二年 +【经】十有二年春王二月,莒人伐我东鄙,围台。季孙宿帅师救台,遂入郓。夏,晋侯使士鲂来聘。秋九月,吴子乘卒。冬,楚公子贞帅师侵宋。公如晋。 +【传】十二年春,莒人伐我东鄙,围台。季武子救台,遂入郓,取其钟以为公盘。 +夏,晋士鲂来聘,且拜师。 +秋,吴子寿梦卒。临于周庙,礼也。凡诸侯之丧,异姓临于外,同姓于宗庙,同宗于祖庙,同族于祢庙。是故鲁为诸姬,临于周庙。为邢、凡、蒋、茅、胙、祭临于周公之庙。 +冬,楚子囊、秦庶长无地伐宋,师于扬梁,以报晋之取郑也。 +灵王求后于齐。齐侯问对于晏桓子,桓子对曰:“先王之礼辞有之,天子求后于诸侯,诸侯对曰:‘夫妇所生若而人。妾妇之子若而人。’无女而有姊妹及姑姊妹,则曰:‘先守某公之遗女若而人。’”齐侯许昏,王使阴里逆之。 +公如晋,朝,且拜士鲂之辱,礼也。 +秦嬴归于楚。楚司马子庚聘于秦,为夫人宁,礼也。 +译文 +十二年春季,莒国人进攻我国东部边境,包围台地。季武子救援台地,就乘机进入郓国,掠取了他们的钟,改铸为鲁襄公的盘。 +夏季,晋国的士鲂来鲁国聘问,同时拜谢我国出兵。 +秋季,吴王寿梦死了,鲁襄公在周文王庙哭泣吊唁,这是合于礼的。诸侯的丧事,异姓的在城外哭泣吊唁,同姓的在宗庙里,同宗的在祖庙里,同族的在父庙里。因为这样,鲁国为了姬姓诸国,到周文王庙里哭泣吊唁。为了邢、凡、蒋、茅、胙、祭各国,在周公庙里哭泣吊唁。 +冬季,楚国子囊、秦国庶长无地进攻宋国,军队驻扎在杨梁,以报复晋国的得到郑国。 +周灵王在齐国求娶王后,齐灵公向晏桓子询问如何答复。桓子回答说:“先王的礼仪辞令有这样的话:天子在诸侯那里求取王后,诸侯回答说:‘夫人所生的若干人,妾妇所生的若干人。’没有女儿而有姐妹和姑母,就说:‘先君某公的遗女若干人。’齐灵公答应了婚事,周灵王派遣阴里作了口头约定。 +鲁襄公去到晋国朝见,同时拜谢士鲂的到来,这是合于礼的。 +秦赢嫁给楚国,楚国的司马子庚到秦国聘问,为了夫人回娘家,这是合于礼的。 + +襄公十三年 +【经】十有三年春,公至自晋。夏,取邿。秋九月庚辰,楚子审卒。冬,城防。 +【传】十三年春,公至自晋,孟献子书劳于庙,礼也。 +夏,邿乱,分为三。师救邿,遂取之。凡书“取”,言易也。用大师焉曰“灭”。弗地曰“入”。 +荀罃、士鲂卒。晋侯搜于上以治兵,使士□将中军,辞曰:“伯游长。昔臣习于知伯,是以佐之,非能贤也。请从伯游。”荀偃将中军,士□佐之。使韩起将上军,辞以赵武。又使栾□,辞曰:“臣不如韩起。韩起愿上赵武,君其听之!”使赵武将上军,韩起佐之。栾□将下军,魏绛佐之。新军无帅,晋侯难其人,使其什吏,率其卒乘官属,以从于下军,礼也。晋国之民,是以大和,诸侯遂睦。君子曰:“让,礼之主也。范宣子让,其下皆让。栾□为汰,弗敢违也。晋国以平,数世赖之。刑善也夫!一人刑善,百姓休和,可不务乎?《书》曰:‘一人有庆,兆民赖之,其宁惟永。’其是之谓乎?周之兴也,其《诗》曰:‘仪刑文王,万邦作孚。’言刑善也。及其衰也,其《诗》曰:‘大夫不均,我从事独贤。’言不让也。世之治也,君子尚能而让其下,小人农力以事其上,是以上下有礼,而谗慝黜远,由不争也,谓之懿德。及其乱也,君子称其功以加小人,小人伐其技以冯君子,是以上下无礼,乱虐并生,由争善也,谓之昏德。国家之敝,恒必由之。” +楚子疾,告大夫曰:“不谷不德,少主社稷,生十年而丧先君,未及习师保之教训,而应受多福。是以不德,而亡师于鄢,以辱社稷,为大夫忧,其弘多矣。若以大夫之灵,获保首领以殁于地,唯是春秋窀穸之事,所以从先君于祢庙者,请为‘灵’若‘厉’。大夫择焉!”莫对。及五命乃许。 +秋,楚共王卒。子囊谋谥。大夫曰:“君有命矣。”子囊曰:“君命以共,若之何毁之?赫赫楚国,而君临之,抚有蛮夷,奄征南海,以属诸夏,而知其过,可不谓共乎?请谥之‘共’。”大夫从之。 +吴侵楚,养由基奔命,子庚以师继之。养叔曰:“吴乘我丧,谓我不能师也,必易我而不戒。子为三覆以待我,我请诱之。”子庚从之。战于庸浦,大败吴师,获公子党。君子以吴为不吊。《诗》曰:“不吊昊天,乱靡有定。” +冬,城防,书事,时也。于是将早城,臧武仲请俟毕农事,礼也。 +郑良霄、大宰石□犹在楚。石□言于子囊曰:“先王卜征五年,而岁习其祥,祥习则行,不习则增修德而改卜。今楚实不竞,行人何罪?止郑一卿,以除其逼,使睦而疾楚,以固于晋,焉用之?使归而废其使,怨其君以疾其大夫,而相牵引也,不犹愈乎?”楚人归之。 +译文 +十三年春季,鲁襄公从晋国回来,孟献子在宗庙里记载功勋,这是合于礼的。 +夏季,邿国发生动乱,一分为三。出兵救援邿国,就乘机占取了它。凡是《春秋》记载说“取”,就是说事情很容易。使用了大军叫做“灭’。虽得了国家,并不占有它的土地叫做“入”。 +荀罃、士鲂死了。晋悼公在绵上打猎并训练军队。派遣士匄率领中军,他辞谢说:“荀偃比我强。过去下臣熟悉知伯,因此辅佐他,而不是由于我的贤能啊。请派遣荀偃。”荀偃率领中军,士匄作为辅佐。派遣韩起率领上军,他辞让给赵武。又派遣栾黡,他辞谢说:“下臣不如韩起。韩起愿意让赵武在上位,君王还是听从他的意见。”就派遣赵武率领上军,韩起作为辅佐。栾黡率领下军,魏绛作为辅佐。新军没有统帅,晋悼公对这个人选感到困难,让新军的十个官吏率领步兵、骑兵和所属官员,附在下军里,这是合于礼的。晋国的百姓因此大大和顺,诸侯也就和睦。 +君子说:“谦让,是礼的主体。士匄谦让,他的下属都谦让。栾黡即使专横,也不敢违背。晋国因此而团结,几世都受到利益,这是由于取法于善的缘故啊!一个人取法于善,各族各姓都美好协调,难道可以不尽力于这一点吗?《书》说,‘一个人好善,亿万人有利,国家的安宁可以久长’,说的就是这个吧!周朝兴起的时候,反映它的诗说,‘效法文王,万邦信任’,说的是取法于善。等到它衰弱的时候,反映它的诗说,‘大夫不公平,我所作的独最多’,说的是不谦让。当时世太平的时候,君子崇尚贤能而对下属谦让,小人努力以事奉他的上司,因此上下有礼而奸邪废黜远离,这是由于不争夺的缘故,这叫做美德。到了天下动乱的时候,君子夸耀他的功劳以凌驾于小人之上,小人夸耀他的技能以凌驾于君子之上,因此上下无礼,动乱和残暴一起发生,这是由于争相自以为是。这叫做昏德。国家的败坏,常常是由于这样而来的。” +楚共王生病,告诉大夫说:“寡人没有德行,年幼的时候就做了一国之主。生下来十年而先君去世,没有来得及学习师保的教训而承受了许多福禄,因此缺乏德行而在鄢陵丧失了军队,让国家蒙受耻辱,让大夫担心,这都够严重的了。如果由于大夫的福气,我得以保全首领而善终,在这些祭祀安葬的事情上,得以在祢庙中追随先君,只能请求谥做‘灵’或者‘厉’了,请大夫选择吧。”没有人回答。等到五次命令以后才答应了。 +秋季,楚共王去世。子囊和大家商量谥号。大夫说:“国君已经有过命令了。”子囊说:“国君是用‘恭’来命令的,怎么能不用这个字呢?声威赫赫的楚国,国君在上边统治,安抚着蛮夷,大征南海,让他们从属于中原诸国,而国君又知道自己的过错,可以不说是恭吗?请谥做‘共’。”大夫们都听从了他的意见。 +吴国侵袭楚国,养由基迅速奔向敌人,子庚领兵跟着去。养由基说:“吴国乘我国有丧事,认为我们是不能出兵的,必然轻视我们而不存戒备之心。您设置三处伏兵来等我,我去引诱他们。”子庚听从了。在庸浦作战,大败吴军,俘虏了公子党。君子认为吴国不善,《诗》说:“上天认为你不善,国家祸乱就不能安定。” +冬季,在防地筑城。《春秋》所以记载这件事,这是由于合于时令。当时准备早些时候筑城,臧武仲请求等待农活完了以后再动工,这是合于礼的。 +郑国的良霄、太宰石毚还在楚国。石毚对子囊说:“先王为了征伐,要连续占卜五年,每年重复吉兆,就出兵。如果有一年卜征不吉利,那就更加努力于修养道德而重新占卜。现在楚国实在不能自强,行人有什么罪过?留下郑国一个卿,这就去掉了对郑国君臣的威逼,让他们上下和睦而怨恨楚国,因而坚决顺从晋国,这对楚国有什么好处?让他回去,使他没有完成出使任务,他会埋怨国君和怀恨大夫,因而互相牵制,这不是好一些吗?”于是楚国人就把良霄放了回去。 + + +襄公十四年 +【经】十有四年春王正月,季孙宿、叔老会晋士□、齐人、宋人、卫人、郑公孙虿、曹人、莒人、邾人、滕人、薛人、杞人、小邾人会吴于向。二月乙朔,日有食之。夏四月,叔孙豹会晋荀偃、齐人、宋人、卫北宫括、郑公孙虿、曹人、莒人、邾人、滕人、薛人、杞人、小邾人伐秦。己未,卫侯出奔齐。莒人侵我东鄙。秋,楚公子贞帅师伐吴。冬,季孙宿会晋士□、宋华阅、卫孙林父、郑公孙虿、莒人、邾人于戚。 +【传】十四年春,吴告败于晋。会于向,为吴谋楚故也。范宣子数吴之不德也,以退吴人。 +执莒公子务娄,以其通楚使也。 +将执戎子驹支。范宣子亲数诸朝,曰:“来!姜戎氏!昔秦人迫逐乃祖吾离于瓜州,乃祖吾离被苫盖,蒙荆棘,以来归我先君。我先君惠公有不腆之田,与女剖分而食之。今诸侯之事我寡君不知昔者,盖言语漏泄,则职女之由。诘朝之事,尔无与焉!与将执女!”对曰:“昔秦人负恃其众,贪于土地,逐我诸戎。惠公蠲其大德,谓我诸戎,是四岳之裔胄也,毋是翦弃。赐我南鄙之田,狐狸所居,豺狼所嗥。我诸戎除翦其荆棘,驱其狐狸豺狼,以为先君不侵不叛之臣,至于今不贰。昔文公与秦伐郑,秦人窃与郑盟而舍戍焉,于是乎有殽之师。晋御其上,戎亢其下,秦师不复,我诸戎实然。譬如捕鹿,晋人角之,诸戎掎之,与晋踣之,戎何以不免?自是以来,晋之百役,与我诸戎相继于时,以从执政,犹殽志也。岂敢离逖?今官之师旅,无乃实有所阙,以携诸侯,而罪我诸戎!我诸戎饮食衣服,不与华同,贽币不通,言语不达,何恶之能为?不与于会,亦无瞢焉!”赋《青蝇》而退。宣子辞焉,使即事于会,成恺悌也。于是,子叔齐子为季武子介以会,自是晋人轻鲁币,而益敬其使。 +吴子诸樊既除丧,将立季札。季札辞曰:“曹宣公之卒也,诸侯与曹人不义曹君,将立子臧。子臧去之,遂弗为也,以成曹君。君子曰:‘能守节。’君,义嗣也。谁敢奸君?有国,非吾节也。札虽不才,愿附于子臧,以无失节。”固立之。弃其室而耕。乃舍之。 +夏,诸侯之大夫从晋侯伐秦,以报栎之役也。晋侯待于竟,使六卿帅诸侯之师以进。及泾,不济。叔向见叔孙穆子。穆子赋《匏有苦叶》。叔向退而具舟,鲁人、莒人先济。郑子蟜见卫北宫懿子曰:“与人而不固,取恶莫甚焉!若社稷何?”懿子说。二子见诸侯之师而劝之济,济泾而次。秦人毒泾上流,师人多死。郑司马子蟜帅郑师以进,师皆从之,至于棫林,不获成焉。荀偃令曰:“鸡鸣而驾,塞井夷灶,唯余马首是瞻!”栾□曰:“晋国之命,未是有也。余马首欲东。”乃归。下军从之。左史谓魏庄子曰:“不待中行伯乎?”庄子曰:“夫子命从帅。栾伯,吾帅也,吾将从之。从帅,所以待夫子也。”伯游曰:“吾令实过,悔之何及,多遗秦禽。”乃命大还。晋人谓之迁延之役。 +栾金咸曰:“此役也,报栎之败也。役又无功,晋之耻也。吾有二位于戎路,敢不耻乎?”与士鞅驰秦师,死焉。士鞅反,栾□谓士□曰:“余弟不欲住,而子召之。余弟死,而子来,是而子杀余之弟也。弗逐,余亦将杀之。”士鞅奔秦。 +于是,齐崔杼、宋华阅、仲江会伐秦,不书,惰也。向之会亦如之。卫北宫括不书于向,书于伐秦,摄也。 +秦伯问于士鞅曰:“晋大夫其谁先亡?”对曰:“其栾氏乎!”秦伯曰:“以其汰乎?”对曰:“然。栾□汰虐已甚,犹可以免。其在盈乎!”秦伯曰:“何故?”对曰:“武子之德在民,如周人之思召公焉,爱其甘棠,况其子乎?栾□死,盈之善未能及人,武子所施没矣,而□之怨实章,将于是乎在。”秦伯以为知言,为之请于晋而复之。 +卫献公戒孙文子、宁惠子食,皆服而朝。日旰不召,而射鸿于囿。二子从之,不释皮冠而与之言。二子怒。孙文子如戚,孙蒯入使。公饮之酒,使大师歌《巧言》之卒章。大师辞,师曹请为之。初,公有嬖妾,使师曹诲之琴,师曹鞭之。公怒,鞭师曹三百。故师曹欲歌之,以怒孙子以报公。公使歌之,遂诵之。 +蒯惧,告文子。文子曰:“君忌我矣,弗先。必死。”并帑于戚而入,见蘧伯玉曰:“君之暴虐,子所知也。大惧社稷之倾覆,将若之何?”对曰:“君制其国,臣敢奸之?虽奸之,庸如愈乎?”遂行,从近关出。公使子蟜、子伯、子皮与孙子盟于丘宫,孙子皆杀之。四月己未,子展奔齐。公如鄄,使子行于孙子,孙子又杀之。公出奔齐,孙氏追之,败公徒于河泽。鄄人执之。 +初,尹公佗学射于庚公差,庚公差学射于公孙丁。二子追公,公孙丁御公。子鱼曰:“射为背师,不射为戮,射为礼乎。”射两軥而还。尹公佗曰:“子为师,我则远矣。”乃反之。公孙丁授公辔而射之,贯臂。 +子鲜从公,及竟,公使祝宗告亡,且告无罪。定姜曰:“无神何告?若有,不可诬也。有罪,若何告无?舍大臣而与小臣谋,一罪也。先君有冢卿以为师保,而蔑之,二罪也。余以巾栉事先君,而暴妾使余,三罪也。告亡而已,无告无罪。” +公使厚成叔吊于卫,曰:“寡君使瘠,闻君不抚社稷,而越在他竟,若之何不吊?以同盟之故,使瘠敢私于执事曰:‘有君不吊,有臣不敏,君不赦宥,臣亦不帅职,增淫发泄,其若之何?’”卫人使大叔仪对曰:“群臣不佞,得罪于寡君。寡君不以即刑而悼弃之,以为君忧。君不忘先君之好,辱吊群臣,又重恤之。敢拜君命之辱,重拜大贶。”厚孙归,覆命,语臧武仲曰:“卫君其必归乎!有大叔仪以守,有母弟鱄以出,或抚其内,或营其外,能无归乎?” +齐人以郲寄卫侯。及其复也,以郲粮归。右宰谷从而逃归,卫人将杀之。辞曰:“余不说初矣,余狐裘而羔袖。”乃赦之。卫人立公孙剽,孙林父、宁殖相之,以听命于诸侯。 +卫侯在郲,臧纥如齐,唁卫侯。与之言,虐。退而告其人曰:“卫侯其不得入矣!其言粪土也,亡而不变,何以复国?”子展、子鲜闻之,见臧纥,与之言,道。臧孙说,谓其人曰:“卫君必入。夫二子者,或挽之,或推之,欲无入,得乎?” +师归自伐秦,晋侯舍新军,礼也。成国不过半天子之军,周为六军,诸侯之大者,三军可也。于是知朔生盈而死,盈生六年而武子卒,彘裘亦幼,皆未可立也。新军无帅,故舍之。 +师旷侍于晋侯。晋侯曰:“卫人出其君,不亦甚乎?”对曰:“或者其君实甚。良君将赏善而刑淫,养民如子,盖之如天,容之如地。民奉其君,爱之如父母,仰之如日月,敬之如神明,畏之如雷霆,其可出乎?夫君,神之主而民之望也。若困民之主,匮神乏祀,百姓绝望,社稷无主,将安用之?弗去何为?天生民而立之君,使司牧之,勿使失性。有君而为之贰,使师保之,勿使过度。是故天子有公,诸侯有卿,卿置侧室,大夫有贰宗,士有朋友,庶人、工、商、皂、隶、牧、圉皆有亲昵,以相辅佐也。善则赏之,过则匡之,患则救之,失则革之。自王以下,各有父兄子弟,以补察其政。史为书,瞽为诗,工诵箴谏,大夫规诲,士传言,庶人谤,商旅于市,百工献艺。故《夏书》曰:‘遒人以木铎徇于路。官师相规,工执艺事以谏。’正月孟春,于是乎有之,谏失常也。天之爱民甚矣。岂其使一人肆于民上,以从其淫,而弃天地之性?必不然矣。” +秋,楚子为庸浦之役故,子囊师于棠以伐吴,吴不出而还。子囊殿,以吴为不能而弗儆。吴人自皋舟之隘要而击之,楚人不能相救。吴人败之,获楚公子宜谷。 +王使刘定公赐齐侯命,曰:“昔伯舅大公,右我先王,股肱周室,师保万民,世胙大师,以表东海。王室之不坏,繄伯舅是赖。今余命女环!兹率舅氏之典,纂乃祖考,无忝乃旧。敬之哉,无废朕命!” +晋侯问卫故于中行献子,对曰:“不如因而定之。卫有君矣,伐之,未可以得志而勤诸侯。史佚有言曰:‘因重而抚之。’仲虺有言曰:‘亡者侮之,乱者取之,推亡固存,国之道也。’君其定卫以待时乎!” +冬,会于戚,谋定卫也。 +范宣子假羽毛于齐而弗归,齐人始贰。 +楚子囊还自伐吴,卒。将死,遗言谓子庚:“必城郢。”君子谓:“子囊忠。君薨不忘增其名,将死不忘卫社稷,可不谓忠乎?忠,民之望也。《诗》曰:‘行归于周,万民所望。’忠也。” +译文 +十四年春季,吴国到晋国报告战败情况,季孙宿,叔老和晋国的士匄、齐国人、宋国人、卫国人、郑国公孙趸、曹国人、莒国人、邾人、滕人、薛人、杞人、小邾人和吴国人在向地会见,这是为吴国策划进攻楚国的缘故。范宣子责备吴国不道德,以此拒绝了吴国人。 +晋国逮捕了莒国的公子务娄,这是因为莒国的使者和楚国有来往。将要逮捕戎子驹支,范宣子亲自在朝廷上责备他,说:“过来,姜戎氏!从前秦国人追逐你的祖父吾离到瓜州,你的祖父吾离身披蓑衣、头戴草帽前来归附我们先君。我们先君惠公只有并不太多的土田,还和你的祖父平分着吃。现在诸侯事奉我们寡君不如从前,这是因为说话泄漏机密,应当是由于你的缘故。明天早晨的事情,你不要参加了。如果参加,将要把你抓起来。”戎子回答说:“从前秦国人仗着他们人多,贪求土地,驱逐我们各部戎人。晋惠公显示了他的大德,说我们各部戎人,都是四岳的后代,不能加以丢弃。赐给我们南部边境的土田,那里是狐狸居住的地方,豺狼嚎叫的地方。我们各部戎人砍伐这里的荆棘,驱逐这里的狐狸豺狼,作为先君不侵犯不背叛的臣下,直到如今没有三心二意。从前晋文公和秦国进攻郑国时,秦国人偷偷地和郑国结盟而并派兵戍守,因此就有殽地的战役。晋国在上边抵御,戎人在下边对抗,秦国的军队回不去,实在是我们各部戎人出力才让他们这样的。譬如捕鹿,晋国人抓住它的角,各部戎人拖住了它的后腿,和晋国一起让它仆倒。戎人为什么不能免于罪责呢?从这个时候以来,晋国的多次战役,我各部戎人没有不按时与晋军共同参加,以追随执事,如同支援殽地战役一样,岂敢违背?现在各级官员恐怕实在有着过失,因而使诸侯有二心反倒要责怪我们各部戎人!我们各部戎人饮食衣服和中原不同,财礼不相往来,言语不通,能够做什么坏事呢?不参加明天的会见,我也没有什么不舒畅的。”赋了《青蝇》这首诗然后退下。范宣子表示歉意,让他参加会见的事务,显示了平易而不听谗言的美德。当时子叔齐子作为季武子的副手而参加会见,从此晋国人减轻了鲁国的财礼而更加敬重鲁国的使臣。 +吴子诸樊已经免除了丧服,打算立季札为国君,季札辞谢说:“曹宣公死的时候,诸侯和曹国人不赞成曹成公,打算立子臧为国君。子臧离开了曹国,曹国人就没有按原来的计划去做,以成全了曹成公。君子称赞子臧说‘能够保持节操’。君王是合法的继承人,谁敢冒犯君位?据有国家,不是我的节操。札虽然没有才能,愿意追随子臧,以不失节操。”诸樊坚决要立他为国君,季札丢掉了他的家产而去种田,于是就不再勉强他。 +夏季,诸侯的大夫跟随着晋悼公进攻秦国,以报复栎地一役。晋悼公在国境内等待,让六卿率领诸侯的军队前进。到达泾水,诸侯的军队不肯渡河。叔向进见叔孙穆子,穆子赋《匏有苦叶》这首诗。叔向退出以后就准备船只,鲁国人、莒国人先渡河。郑国的子蟜进见卫国的北宫懿子说:“亲附别人而不坚定,最使人讨厌了,把国家怎么办?”懿子很高兴。两个人去见诸侯的军队而劝他们渡河,军队渡过泾水驻扎下来。秦国人在泾水上游放置毒物,诸侯的军队死去很多。郑国司马子?率领郑国的军队前进,其他国家的军队也都跟上,到达棫林,不能让秦国屈服讲和。荀偃命令说:“鸡叫套车,填井平灶,你只看着我的马首而行动。”栾黡说:“晋国的命令,从来没有这样的。我的马头可要往东呢。”就回国了。下军跟随他回去。左史对魏庄子说:“不等中行伯了吗?”魏庄子说:“他老人家命令我们跟从主将,栾黡,是我的主将,我打算跟从他。跟从主将,也就是合理地对待他老人家。”荀偃说:“我的命令确实有错误,后悔哪里来得及,多留下人马只能被秦国俘虏。”于是就命令全军撤退。晋国人称这次战役为“迁延之役”。 +栾鍼说:“这次战役,是为了报复栎地的战败。作战又没有功劳,这是晋国的耻辱。我兄弟俩在兵车上,哪能不感到耻辱呢?”和士鞅冲入秦军中间,战死,士鞅回来。栾黡对士匄说:“我的兄弟不想前去,你的儿子叫他去。我的兄弟战死,你的儿子回来,这是你的儿子杀了我的兄弟。如果不赶走他,我也要杀死他。”士鞅逃亡到秦国。 +当时,齐国崔杼、宋国华阅、仲江一起进攻秦国。《春秋》没有记载他们的名字,是由于他们怠惰。向地会见的记载也和这一样。对卫国的北宫括在向地的会见不加记载,而记载在这次攻打秦国的战役中,这是由于他积极帮助的缘故。 +秦景公问士鞅说:“晋国的大夫谁先灭亡?”士鞅回答说:“恐怕是栾氏吧!”秦景公说:“由于他的骄横吗?”士鞅回答说:“对。栾黡太骄横了,还可以免于祸难,祸难恐怕要落在栾盈的身上吧!”秦景公说:“为什么?”士鞅回答说:“栾武子的恩德留在百姓中间,好像周朝人思念召公,就爱护他的甘棠树,何况他的儿子呢?栾黡死了,盈的好处没有能到达别人那里,栾武子所施舍的又逐渐完了,而对栾黡的怨恨实在太明显,所以灭亡将会落在栾盈身上了。”秦景公认为这是有见识的话,就为士鞅向晋国请求而恢复了他的职位。 +卫献公约请孙文子、宁惠子吃饭,这两个人都穿上朝服在朝廷上等待。太阳快下山了还不召见,反而在林子里射鸿雁。两个人跟到林子里,卫献公不取下皮帽跟他们说话。两个人都生气。孙文子去了戚地,孙蒯入朝请命。卫献公招待孙蒯喝酒,让乐官唱《巧言》的最后一章。乐宫辞谢。乐工师曹请求歌唱这一章。当初,卫献公有一个宠妾,让师曹教她弹琴,师曹鞭打过她。卫献公生气,鞭打师曹三百下。所以现在师曹想利用唱这章诗的机会,来激怒孙蒯,以作为对卫献公的报复。卫献公让师曹歌唱,师曹作了朗诵。 +孙蒯恐惧,告诉孙文子。孙文子说:“国君忌恨我了,如果不先下手,就必死于他的手中。”孙文子把家中大小集中在戚地,然后进入国都,遇见蘧伯玉,说:“国君的暴虐,这是您所知道的。我很害怕国家的颠覆,您准备怎么办?”蘧伯玉回答说:“国君控制他的国家,下臣哪里敢冒犯他?即使冒犯了他,立了新的国君,难道能确知比旧的国君会强一些吗?”于是就从最近的关口出国。 +卫献公派子蟜、子伯、子皮和孙文子在丘宫结盟,孙文子把他们全都杀了。四月二十六日,子展逃亡到齐国,卫献公到了鄄地,派子行向孙文子请求和解,孙文子又杀了他。卫献公逃亡到齐国,孙家的人追了上去,把卫献公的亲兵在阿泽击败,鄄地人逮捕了败兵。 +当初,尹公佗到庾公差那里学射箭,庾公差又到公孙丁那里学射箭,尹公佗和庾公差追逐卫献公,公孙丁驾御卫献公的车子。庾公差说:“如果射,是背弃老师;不射,将被诛戮,射了还是合于礼的吧!”射中了车子两边的曲木然后回去。尹公佗说:“您为了老师,我和他的关系就远了。”于是回过车去追赶。公孙丁把马缰递给卫献公然后向尹公佗射去,射穿了他的臂膀。 +子鲜跟随卫献公出亡。到达边境,卫献公派祝宗向祖先报告逃亡,同时说自己没有罪过。定姜说:“如果没有神灵,报告什么?如果有,就不能欺骗。有罪,为什么报告说没有罪?不与大臣商量而和小臣商量,这是第一条罪。先君有正卿作为师保,而你却轻视他们,这是第二条罪。我用手巾梳子事奉过先君,而你残暴地对待我像对婢妾一样,这是第三条罪。只报告逃亡算了,不要报告没有罪!” +鲁襄公派厚成叔到卫国慰问,说:“寡君派遣瘠,听说君王失去了国家而流亡在别国境内,怎么能不来慰问?由于同盟的缘故,谨派瘠私下对大夫们说:‘国君不善良,臣下不明达事理,国君不宽恕,臣下也不尽职责,积怨很久而发泄出来,怎么办?’”卫国人派太叔仪回答,说:“下臣们没有才能,得罪了寡君。寡君不把下臣们依法惩处,反而远远地抛弃了下臣们,以成为君王的忧虑。君王不忘记先君的友好,承您来慰问下臣们,又再加哀怜。谨拜谢君王的命令,再拜谢对下臣们的哀怜。”厚成叔回国复命,告诉臧武仲说:“卫君恐怕会回去的吧!有太叔仪留守,有同胞兄弟鱄和他一起出国。有人安抚国内,有人经营国外,能够不回去吗?” +齐国人把郲地让给卫献公寄住。等到卫献公复位的时候,还带着郲地的粮食回去。右宰穀先跟从卫献公后来又逃回国去,卫国人要杀掉他。他辩解说:“对过去的事情我不是乐于干的。我穿的是狐皮衣羊皮袖子。”于是就赦免了他。卫国人立公孙剽为国君,孙林父、宁殖辅助他,以听取诸侯的命令。 +卫献公在郲地,臧纥去到齐国慰问卫献公。卫献公和他说话,态度粗暴。臧纥退出以后告诉他的手下人说:“卫献公大概不能回国了。他的话好像粪土。逃亡在外而不悔改,怎么能够恢复国君的地位呢?”子展、子鲜听说这话,进见臧纥,和他们说话,通情达理。臧纥很高兴,对他的手下人说:“卫君一定能回国。这两个人,有的拉他,有的推他,想不回国,行吗?” +军队进攻秦国回来。晋悼公取消新军,这是合于礼的。大国不超过天子军队的一半。周朝编定六个军,诸侯中强大的,三个军就可以了。当时,知朔生了盈就死去,盈出生六年以后武子就死了,彘裘也还小,都不能做继承人。新军没有主将,所以就取消编制解散了。 +师旷随侍在晋悼公旁边,晋悼公说:“卫国人赶走他们的国君,不也太过分了吗?”师旷回答说:“也许是他们国君实在太过分了。好的国君将会奖赏善良而惩罚邪恶,抚养百姓好像儿女,覆盖他们好像上天一样,容纳他们好像大地一样。百姓尊奉国君,热爱他好像父母,尊仰他好像日月,恭敬他好像神灵,害怕他好像雷霆,哪里能够赶走呢?国君,是祭神的主持者同时是百姓的希望。如果让百姓的财货缺乏,神灵失去了祭祀者,百姓绝望,国家没有主人,哪里还用得着他?不赶走干什么?上天生了百姓而立他们的国君,让他统治他们,不让失去天性。有了国君而又为他设立辅佐,让他们去教育保护他,不让他做事过分。由于这样天子有公,诸侯有卿,卿设置侧室,大夫有贰宗,士有朋友,庶人、工、商、皂、隶、牧、圉各有他们亲近的人,用来互相帮助。善良就奖赏,过失就纠正,患难就救援,错失就改正。从天子以下各有父兄子弟来观察补救他们的过失。太史加以记载,乐师写作诗歌,乐工诵读箴谏,大夫规劝开导,士传话,庶人指责,商人在市场上议论,各种工匠献技艺。所以《夏书》说:“宣令的官员摇着木铎在大路上巡行,官师小吏规劝,工匠呈献技艺以作为劝谏。”正月初春,在这个时候有人在路上摇动木铎,这是由于劝谏失去常规的缘故。上天爱护百姓无微不至,难道会让一个人在百姓头上任意妄为,以放纵他的邪恶而失去天地的本性?一定不会这样的。” +秋季,楚康王由于庸浦这次战役的缘故,让子囊在棠地出兵,以攻打吴国。吴军不出战,楚军就回去了。子囊殿后,认为吴国无能因而不加警戒。吴国人从皋舟的险道上拦腰截击楚军,楚国人不能彼此救应,吴国人打败了他们,俘虏了楚国公子宜穀。 +周灵王派刘定公将荣宠赐给齐灵公,说:“从前伯舅太公辅助我先王,作为周室的左右手,百姓的师保。世世代代酬谢太师的功劳,为东海各国的表率。王室之所以没有败坏,所依靠的就是伯舅。现在我命令你环,孜孜不倦地遵循舅氏的常法,继承你的祖先,不要玷辱你的先人。要恭敬啊!不要废弃我的命令!” +晋悼公向中行献子询问卫国的事情。中行献子回答说:“不如根据现状而安定它。卫国有国君了,攻打它,不见得能够如愿,反而烦劳诸侯。史佚有话说:‘因为他已经安定而加以安抚。’仲虺有话说:‘灭亡着的可以欺侮,动乱着的可以打倒。推翻已灭亡的巩固已存在的,这是国家的常道。’君王还是安定卫国以等待时机吧!” +冬季,季孙宿和晋国的士匄,宋国华阅、卫国孙林父、郑国公孙虿、莒人、邾人在戚地会见,这是为了商讨安定卫国。 +范宣子在齐国借了装饰仪仗的羽毛而不归还,齐国人开始有了二心。 +楚国的子囊进攻吴国回来后,就死了。临死,遗言对子庚说:“一定要在郢地筑城。”君子认为:“子囊忠心。国君死,不忘记谥他为‘共’;临死,不忘记保卫国家,难道能不说他忠心吗?忠心,是百姓的希望。《诗》说,‘行动归结到忠信,这是广大百姓的希望’,这就是忠心的意思。” + + +襄公十五年 +【经】十有五年春,宋公使向戌来聘。二月己亥,及向戌盟于刘。刘夏逆王后于齐。夏,齐侯伐我北鄙,围成。公救成,至遇。季孙宿、叔孙豹帅师城成郛。秋八月丁巳,日有食之。邾人伐我南鄙。冬十有一月癸亥,晋侯周卒。 +【传】十五年春,宋向戌来聘,且寻盟。见孟献子,尤其室,曰:“子有令闻,而美其室,非所望也!”对曰:“我在晋,吾兄为之,毁之重劳,且不敢间。” +官师从单靖公逆王后于齐。卿不行,非礼也。 +楚公子午为令尹,公子罢戎为右尹,蒍子冯为大司马,公子櫜师为右司马,公子成为左司马,屈到为莫敖,公子追舒为箴尹,屈荡为连尹,养由基为宫厩尹,以靖国人。君子谓:“楚于是乎能官人。官人,国之急也。能官人,则民无觎心。《诗》云:‘嗟我怀人,置彼周行。’能官人也。王及公、侯、伯、子、男,甸、采、卫大夫,各居其列,所谓周行也。” +郑尉氏、司氏之乱,其馀盗在宋。郑人以子西、伯有、子产之故,纳贿于宋,以马四十乘与师伐、师慧。三月,公孙黑为质焉。司城子罕以堵女父、尉翩、司齐与之。良司臣而逸之,托诸季武子,武子置诸卞。郑人醢之,三人也。 +师慧过宋朝,将私焉。其相曰:“朝也。”慧曰:“无人焉。”相曰:“朝也,何故无人?”慧曰:“必无人焉。若犹有人,岂其以千乘之相易淫乐之?必无人焉故也。”子罕闻之,固请而归之。 +夏,齐侯围成,贰于晋故也。于是乎城成郛。 +秋,邾人伐我南鄙。使告于晋,晋将为会以讨邾、莒晋侯有疾,乃止。冬,晋悼公卒,遂不克会。 +郑公孙夏如晋奔丧,子蟜送葬。 +宋人或得玉,献诸子罕。子罕弗受。献玉者曰:“以示玉人,玉人以为宝也,故敢献之。”子罕曰:“我以不贪为宝,尔以玉为宝,若以与我,皆丧宝也。不若人有其宝。”稽首而告曰:“小人怀璧,不可以越乡。纳此以请死也。”子罕置堵其里,使玉人为之攻之,富而后使复其所。 +十二月,郑人夺堵狗之妻,而归诸范氏。 +译文 +十五年春季,宋国的向戌来鲁国聘问,同时重温过去的盟约。见了孟献子,责备他的房屋太华丽,说:“您有好名声而把房屋修饰得太华丽,这不是别人所希望的。”孟献子回答说:“我在晋国的时候,我哥哥修建的。要毁坏它,又觉得毁坏又得用劳力,而且不敢说哥哥所做的事不对。” +官师跟随单靖公在齐国迎接王后。卿没有去,这是不合于礼的。 +楚国公子午做令尹,公子罢戎做右尹,蒍子冯做大司马,公子橐师做右司马,公子成做左司马,屈到做莫敖,公子追舒做箴尹,屈荡做连尹,养由基做宫厩尹,来安定国内的人们。君子认为“楚国在这时候能够合理地安排官职的人选。安排官职的人选,这是国家的当务之急。能够合理地安排,那么百姓就没有非分的想法。《诗》说,‘嗟叹我所怀念的贤人,要把他们全都安排在恰当的职位上’,这就是能够安排官职的人选。天子和公、侯、伯、子、男以及甸、采、卫的各级大夫,各就各位。这就是所说的‘同行’了。” +郑国尉氏、司氏的叛乱,留下的叛乱分子待在宋国。郑国人由于子西、伯有、子产的缘故,用马一百六十匹和师茷、师慧作为财礼送给宋国。三月,公孙黑去宋国作为人质。司城子罕把堵女父、尉翩、司齐给了郑国,认为司臣有才能而放走了他,托付给季武子,武子把他安置在卞地。郑国人把这三个人剁成肉酱。 +师慧经过宋国朝廷,打算小便。扶他的人说:“这里是朝廷。”师慧说:“没有人啊。”扶他的人说:“朝廷,为什么没有人?”师慧说:“一定是没有人啊。如果还有人,难道会用拥有千乘战车国家的相国去交换一个演唱淫乐的瞎子?一定是由于没有人的缘故。”子罕听到了,坚决向宋平公请求而让师慧回国。 +夏季,齐灵公包围成地,这是因为齐国对晋国有了二心的缘故。在那时候就在成邑建造外城。 +秋季,邾国人攻打我国南部边境,我国派使者向晋国报告。晋国准备举行会见以讨伐邾国、莒国。晋悼公有病,就停止下来。冬季,晋悼公死,就没有能举行会见。 +郑国的公孙夏去到晋国奔丧吊唁,又派子蟜前去送葬。 +宋国有人得到美玉,献给子罕。子罕不受。献玉的人说:“拿给玉工看过,玉工认为是宝物,所以才敢进献。”子罕说:“我把不贪婪作为宝物,你把美玉作为宝物,如果把玉给了我,我们两人都丧失了宝物,不如各人保有自己的宝物。”献玉的人叩头告诉子罕说:“小人带着玉璧,不能够越过乡里,把它送给您是用来免于一死的。”子罕把美玉放在自己的乡里,让玉工为他雕琢,卖出去,使献玉的人富有以后,然后让他回到家里。 +十二月,郑国人夺取了堵狗的妻子,让她回到娘家范氏去。 + +襄公十六年 +【经】十有六年春王正月,葬晋悼公。三月,公会晋侯、宋公、卫侯、郑伯、曹伯、莒子、邾子、薛伯、杞伯、小邾子,于湨梁。戊寅,大夫盟。晋人执莒子、邾子以归。齐侯伐我北鄙。夏,公至自会。五月甲子,地震。叔老会郑伯、晋荀偃、卫宁殖、宋人伐许。秋,齐侯伐我北鄙,围郕。大雩。冬,叔孙豹如晋。 +【传】十六年春,葬晋悼公。平公即位,羊舌肸为傅,张君臣为中军司马,祁奚、韩襄、栾盈、士鞅为公族大夫,虞丘书为乘马御。改服修官,烝于曲沃。警守而下,会于湨梁。命归侵田。以我故,执邾宣公、莒犁比公,且曰:“通齐、楚之使。” +晋侯与诸侯宴于温,使诸大夫舞,曰:“歌诗必类!”齐高厚之诗不类。荀偃怒,且曰:“诸侯有异志矣!”使诸大夫盟高厚,高厚逃归。于是,叔孙豹、晋荀偃、宋向戌、卫宁殖、郑公孙虿、小邾之大夫盟曰:“同讨不庭。” +许男请迁于晋。诸侯遂迁许,许大夫不可。晋人归诸侯。 +郑子蟜闻将伐许,遂相郑伯以从诸侯之师。穆叔从公。齐子帅师会晋荀偃。书曰:“会郑伯。”为夷故也。 +夏六月,次于棫林。庚寅,伐许,次于函氏。 +晋荀偃、栾□帅师伐楚,以报宋扬梁之役。楚公子格帅师及晋师战于湛阪,楚师败绩。晋师遂侵方城之外,复伐许而还。 +秋,齐侯围郕,孟孺子速缴之。齐侯曰:“是好勇,去之以为之名。”速遂塞海陉而还。 +冬,穆叔如晋聘,且言齐故。晋人曰:“以寡君之未禘祀,与民之未息。不然,不敢忘。”穆叔曰:“以齐人之朝夕释憾于敝邑之地,是以大请!敝邑之急,朝不及夕,引领西望曰:‘庶几乎!’比执事之间,恐无及也!”见中行献子,赋《圻父》。献子曰:“偃知罪矣!敢不从执事以同恤社稷,而使鲁及此。”见范宣子,赋《鸿雁》之卒章。宣子曰:“□在此,敢使鲁无鸠乎?” +译文 +十六年春季,安葬晋悼公。晋平公即位,羊舌肸做太傅,张君臣做中军司马,祁奚、韩襄、栾盈、士鞅做公族大夫,虞丘书做乘马御。改穿吉服,选贤任能,在曲沃举行烝祭。晋平公在国都布置守备以后就沿黄河而下,和鲁襄公、宋平公、卫献公、郑简公、曹成公、莒子、邾子、薛伯、杞伯、小邾子在湨梁会见。命令诸侯退回互相侵占的土田。由于我国的缘故,拘捕了邾宣公、莒犁比公,而且说这两国“使者来往齐国、楚国之间”。 +晋平公和诸侯在温地举行宴会,让大夫们舞蹈,说:“唱诗一定要和舞蹈相配合。”齐国高厚的诗与舞蹈配不好。荀偃发怒,并且说:“诸侯有别的想法了。”让大夫们和高厚结盟,高厚逃走回国。当时叔孙豹、晋国荀偃、宋国向戌、卫国宁殖、郑国公孙虿、小邾国的大夫盟誓说:“共同讨伐不忠于盟主的人。” +许灵公向晋国请求迁都。诸侯就让许国迁移,许国的大夫不同意,晋国人让各国诸侯回国而单独出兵进攻许国。 +郑国的子蟜听到将要进攻许国,就辅佐郑简公跟从诸侯的军队。穆叔跟从鲁襄公回国。齐子率领军队会见晋国荀偃。《春秋》记载说“会郑伯”,是为了把序列摆平。 +夏季,六月,军队驻扎在棫林。初九日,攻进许国,驻扎在函氏。 +晋国的荀偃、栾黡带兵进攻楚国,报复在宋国扬梁的那一次战役。楚国的公子格带兵,和晋军在湛坂作战。楚军大败。晋军就侵袭方城山的外边,再次进攻许国然后回国。 +秋季,齐灵公包围成地,孟孺子速拦击齐军。齐灵公说:“这个人喜欢勇敢,我们离开这里以使他成名。”孟孺子速就堵塞了海陉险道然后回去。 +冬季,穆叔去到晋国聘问,同时说到齐国的事情。晋国人说:“由于寡君还没有举行禘祭和百姓没有安息,所以不能救援,如果不是这样,那是不敢忘记的。”穆叔说:“由于齐国人早晚都在敝邑的土地上发泄愤恨,因此才来郑重请求。敝邑的危急,早晨等不到晚上,伸长了脖子望着西边说:‘也许可以来救援了吧!’等到执事得空闲,恐怕来不及了。”见了中行献子,赋了《圻父》这首诗。献子说“偃知道罪过了,岂敢不跟从执事来一起为国家忧虑,而让鲁国到达这样的地步!”见了范宣子,赋《鸿雁》这首诗的最后一章。范宣子说:“匄在这里,岂敢让鲁国不得安宁?” + + +襄公十七年 +【经】十有七年春王二月庚午,邾子卒。宋人伐陈。夏,卫石买帅师伐曹。秋,齐侯伐我北鄙,围桃。高厚帅师伐我北鄙,围防。九月,大雩。宋华臣出奔陈。冬,邾人伐我南鄙。 +【传】十七年春,宋庄朝伐陈,获司徒卬,卑宋也。 +卫孙蒯田于曹隧,饮马于重丘,毁其瓶。重丘人闭门而呴之,曰:“亲逐而君,尔父为厉。是之不忧,而何以田为?” +夏,卫石买、孙蒯伐曹,取重丘。曹人愬于晋。 +齐人以其未得志于我故,秋,齐侯伐我北鄙,围桃。高厚围臧纥于防。师自阳关逆臧孙,至于旅松。郰叔纥、臧畴、臧贾帅甲三百,宵犯齐师,送之而复。齐师去之。 +齐人获臧坚。齐侯使夙沙卫唁之,且曰:“无死!”坚稽首曰:“拜命之辱!抑君赐不终,姑又使其刑臣礼于士。”以杙抉其伤而死。 +冬,邾人伐我南鄙,为齐故也。 +宋华阅卒。华臣弱皋比之室,使贼杀其宰华吴。贼六人以铍杀诸卢门合左师之后。左师惧曰:“老夫无罪。”贼曰:“皋比私有讨于吴。”遂幽其妻,曰:“畀余而大璧!”宋公闻之,曰:“臣也,不唯其宗室是暴,大乱宋国之政,必逐之!”左师曰:“臣也,亦卿也。大臣不顺,国之耻也。不如盖之。”乃舍之。左师为己短策,苟过华臣之门,必聘。 +十一月甲午,国人逐□狗,□狗入于华臣氏,国人从之。华臣惧,遂奔陈。 +宋皇国父为大宰,为平公筑台,妨于农功。子罕请俟农功之毕,公弗许。筑者讴曰:“泽门之皙,实兴我役。邑中之黔,实尉我心。”子罕闻之,亲执扑,以行筑者,而抶其不勉者,曰:“吾侪小人,皆有阖庐以辟燥湿寒暑。今君为一台而不速成,何以为役?”讴者乃止。或问其故,子罕曰:“宋国区区,而且诅有祝,祸之本也。” +齐晏桓子卒。晏婴粗縗斩,苴絰、带、杖,菅屦,食鬻,居倚庐,寝苫,枕草。其老曰:“非大夫之礼也。”曰:“唯卿为大夫。” +译文 +十七年春季,宋国的庄朝进攻陈国,俘虏了司徒卬,这是由于陈国轻视宋国的缘故。 +卫国的孙蒯在曹隧打猎,在重丘上让马喝水,打破了水瓶。重丘人关起门来骂他,说:“亲自赶走你的国君,你的父亲做了坏事。你不为这个担忧,为什么来打猎?” +夏季,卫国的石买、孙蒯率兵进攻曹国,占取了重丘。曹国人向晋国提出诉讼。 +齐国人由于他们没有能在我国满足愿望的缘故,秋季,齐灵公攻打我国北部边境,包围桃地。高厚把臧纥包围在防地。我军从阳关出动迎接臧纥,到达旅松。郰叔纥、臧畴、臧贾率领甲兵三百人,夜袭齐军,把臧纥送到旅松然后回来。齐军离开了鲁国。 +齐国人俘虏了臧坚,齐灵公派夙沙卫去慰问他,并且说“不要死”。臧坚叩头说:“谨拜谢君王的命令。然而君王赐我不死,却又故意派一个宦官来对一个士表示敬意。”臧坚用小木桩刺进伤口而死。 +冬季,邾国人进攻我国南部边境,这是为了齐国的缘故。 +宋国的华阅死,华臣认为皋比家族力量微弱,派坏人去杀他的家总管华吴。六个坏人用铍刀把华吴杀死在卢门合左师后边。左师害怕,说:“我老头子没有罪。”坏人说:“皋比私自讨伐吴国。”就幽禁了华吴的妻子,说:“把你的大玉璧给我。”宋平公听说这件事,说:“华臣不仅残暴地对待他的宗室,而且使宋国的政令大乱,一定要驱逐他。”左师说:“华臣,也是卿。大臣不和顺,这是国家的耻辱。不如掩盖起来算了。”宋平公就不再加罪。左师讨厌华臣,他给自己做了一根短马鞭子,如果经过华臣的门口,必定快马加鞭。 +十一月二十二日,国内的人们追赶疯狗。疯狗跑到华臣家里,人们就跟着追进去。华臣恐惧,就逃亡到陈国。 +宋国的皇国父做太宰,给宋平公建造一座台,妨碍了农业收割。子罕请求等待农事完毕以后再建造,平公不答应。筑城的人唱着歌谣说:“泽门里的白面孔,要我们服劳役。城里的黑皮肤,体贴我们的心意。”子罕听到了,亲自拿着竹鞭,巡行督察筑城的人,又鞭打那些不勤快的人,说:“我们这一辈小人都有房子躲避干湿冷热。现在国君造一座台而不很快完成,怎么能做事情呢?”唱歌的人就停止不唱了。有人问他什么缘故?子罕说:“宋国虽小,既有诅咒,又有歌颂,这是祸乱的根本。” +齐国的晏桓子死,晏婴穿着粗布丧服,头上和腰里系着麻带,手执竹杖,脚穿草鞋,喝粥,住在草棚里,睡草垫子,用草作为枕头。他的家臣头子说:“这不是大夫的礼仪。”晏婴说:“唯独具有卿身分的人才是大夫,才能行大夫的礼仪。” + +襄公十八年 +【经】十有八年春,白狄来。夏,晋人执卫行人石买。秋,齐师伐我北鄙。冬十月,公会晋侯、宋公、卫侯、郑伯、曹伯、莒子、邾子、滕子、薛伯、杞伯、小邾子同围齐。曹伯负刍卒于师。楚公子午帅师伐郑。 +【传】十八年春,白狄始来。 +夏,晋人执卫行人石买于长子,执孙蒯于纯留,为曹故也。 +秋,齐侯伐我北鄙。中行献子将伐齐,梦与厉公讼,弗胜,公以戈击之,首队于前,跪而戴之,奉之以走,见梗阳之巫皋。他日,见诸道,与之言,同。巫曰:“今兹主必死,若有事于东方,则可以逞。”献子许诺。 +晋侯伐齐,将济河。献子以朱丝系玉二□,而祷曰:“齐环怙恃其险,负其众庶,弃好背盟,陵虐神主。曾臣彪将率诸侯以讨焉,其官臣偃实先后之。苟捷有功,无作神羞,官臣偃无敢复济。唯尔有神裁之!”沉玉而济。 +冬十月,会于鲁济,寻湨梁之言,同伐齐。齐侯御诸平阴,堑防门而守之,广里。夙沙卫曰:“不能战,莫如守险。”弗听。诸侯之士门焉,齐人多死。范宣子告析文子曰:“吾知子,敢匿情乎?鲁人、莒人皆请以车千乘自其乡入,既许之矣。若入,君必失国。子盍图之?”子家以告公,公恐。晏婴闻之曰:“君固无勇,而又闻是,弗能久矣。”齐侯登巫山以望晋师。晋人使司马斥山泽之险,虽所不至,必旗而疏陈之。使乘车者左实右伪,以旗先,舆曳柴而从之。齐侯见之,畏其众也,乃脱归。丙寅晦,齐师夜遁。师旷告晋侯曰:“鸟乌之声乐,齐师其遁。”邢伯告中行伯曰:“有班马之声,齐师其遁。”叔向告晋侯曰:“城上有乌,齐师其遁。” +十一月丁卯朔,入平阴,遂从齐师。夙沙卫连大车以塞隧而殿。殖绰、郭最曰:“子殿国师,齐之辱也。子姑先乎!”乃代之殿。卫杀马于隘以塞道。晋州绰及之,射殖绰,中肩,两矢夹脰,曰:“止,将为三军获。不止,将取其衷。”顾曰:“为私誓。”州绰曰:“有如日!”乃弛弓而自后缚之。其右具丙亦舍兵而缚郭最,皆衿甲面缚,坐于中军之鼓下。 +晋人欲逐归者,鲁、卫请攻险。己卯,荀偃、士□以中军克京兹。乙酉,魏绛、栾盈以下军克邿。赵武、韩起以上军围卢,弗克。十二月戊戌,及秦周,伐雍门之萩。范鞅门于雍门,其御追喜以戈杀犬于门中。孟庄子斩其以为公琴。己亥,焚雍门及西郭、南郭。刘难、士弱率诸侯之师焚申池之竹木。壬寅,焚东郭、北郭。范鞅门于扬门。州绰门于东闾,左骖迫,还于门中,以枚数阖。 +齐侯驾,将走邮棠。大子与郭荣扣马,曰:“师速而疾,略也。将退矣,君何惧焉!且社稷之主,不可以轻,轻则失众。君必待之。”将犯之,大子抽剑断鞅,乃止。甲辰,东侵及潍,南及沂。 +郑子孔欲去诸大夫,将叛晋而起楚师以去之。使告子庚,子庚弗许。楚子闻之,使杨豚尹宜告子庚曰:“国人谓不谷主社稷,而不出师,死不从礼。不谷即位,于今五年,师徒不出,人其以不谷为自逸,而忘先君之业矣。大夫图之!其若之何?”子庚叹曰:“君王其谓午怀安乎!吾以利社稷也。”见使者,稽首而对曰:“诸侯方睦于晋,臣请尝之。若可,君而继之。不可,收师而退,可以无害,君亦无辱。”子庚帅师治兵于汾。于是子蟜、伯有、子张从郑伯伐齐,子孔、子展、子西守。二子知子孔之谋,完守入保。子孔不敢会楚师。 +楚师伐郑,次于鱼陵。右师城上棘,遂涉颖,次于旃然。蒍子冯、公子格率锐师侵费滑、胥靡、献于、雍梁,右回梅山,侵郑东北,至于虫牢而反。子庚门于纯门,信于城下而还。涉于鱼齿之下,甚雨及之,楚师多冻,役徒几尽。 +晋人闻有楚师,师旷曰:“不害。吾骤歌北风,又歌南风。南风不竞,多死声。楚必无功。”董叔曰:“天道多在西北,南师不时,必无功。”叔向曰:“在其君之德也。” +译文 +十八年春季,白狄第一次来鲁国。 +夏季,晋国人在长子拘捕了卫国的行人石买,在纯留拘捕了孙蒯,这是为了曹国的缘故。 +秋季,齐灵公进攻我国北部边境。中行献子准备进攻齐国,梦见和晋厉公争讼,没有胜诉。晋厉公用戈打他,脑袋在前面掉下来,跪下来安在脖子上,两手捧着他的头走路,见到梗阳的巫皋。过了几天,在路上遇见巫皋,中行献子和他谈起做梦的情况,居然和巫皋梦见的相同。巫皋说:“今年您一定要死,如果在东边有战事,那是可以如愿的。”中行献子答应了。 +晋平公发兵进攻齐国,将要渡过黄河,中行献子用朱丝系着两对玉而祷告说:“齐国的环靠着地形险要,仗着人多,丢弃好友违背盟誓,欺凌虐待百姓。陪臣彪将要率领诸侯去讨伐,他的官臣偃在前后辅助,如果得到成功,不要使神灵羞耻,官臣偃不敢再次渡河。惟你神灵加以制裁。”把玉沉入黄河然后渡河。 +冬季,十月,鲁襄公和晋平公、宋平公、卫殇公、郑简公、曹成公、莒子、邾子、滕子、薛伯、杞伯、小邾子在鲁国济水上会见,重温湨梁的盟誓,一起进攻齐国。齐灵公在平阴抵御,在防门外挖壕据守,壕沟的长度有一里。夙沙卫说:“如果不能作战,还不如扼守险要为好。”齐灵公不听。诸侯的士兵进攻防门,齐军战死很多人。范宣子告诉析文子说:“我了解您,难道敢隐瞒情况吗?鲁国人、莒国人都请求带一千辆战车从他们那里一往西北,一往东北打进去,我们已经答应了。如果攻进来,贵国君王必然丢掉国家。您何不考虑一下!”析文子把这些话告诉齐灵公,齐灵公听了十分恐惧。晏婴听到了,说:“国君本来没有勇气,而又听到了这些话,活不了多久了。”齐灵公登上巫山观望晋。晋国人派司马排除山林河泽的险阻,虽然是军队达不到的地方,也一定树起大旗而稀疏地布置军阵。让战车左边坐上真人而右边放上伪装的人,用大旗前导,战车后面拖上木柴跟着走。齐灵公看到,害怕晋军人多,就离开军队脱身回去。二十九日,齐军夜里逃走。师旷告诉晋平公说:“乌鸦的声音愉快,齐军恐怕逃走了。”邢伯告诉中行献子说:“有马匹盘旋不进的声音,齐军恐怕逃走了。”叔向告诉晋平公说:“城上有乌鸦,齐军恐怕逃走了。” +十一月初一日,晋军进入平阴,于是就追赶齐军。夙沙卫拉着大车,堵塞山里的小路然后自己作为殿后。殖绰、郭最说:“您来作为国家军队的殿后,这是齐国的耻辱。您姑且先走吧!”便代他殿后。夙沙卫杀了马匹放在狭路上来堵塞道路。晋国的州绰追上来,用箭射殖绰,射中肩膀,两枝箭夹着脖子。州绰说:“停下别跑,你还可以被我军俘虏;不停,我将会向你心口射一箭。”殖绰回过头来说:“你发誓。”州绰说:“有太阳为证!”于是就把弓弦解下来而从后边捆绑殖绰的手,他的车右具丙也放下武器而捆绑郭最,都不解除盔甲从后面捆绑,他们坐在中军的战鼓下边。 +晋国人要追赶逃兵,鲁国、卫国请求进攻险要的地方。十三日,荀偃、士匄带领中军攻下京兹。十九日,魏绛、栾盈带领下军攻下邿地;赵武、韩起带领上军包围卢地,没有攻下。十二月初二日,到达秦周地方,砍伐了雍门外边的萩木。范鞅进攻雍门,他的御者追喜用戈在门里杀死一条狗。孟庄子砍下橁木制作颂琴。初三日,放火烧毁了雍门和西边、南边的外城。刘难、士弱率领诸侯的军队放火烧了申池边上的竹子树木。初六日,放火烧了东边、北边的外城,范鞅攻打扬门。州绰攻打东闾,左边的骖马由于拥挤而不能前进,回到门里盘旋,停留很久,把城门门扇上的铜钉都数清楚了。 +齐灵公驾了车,准备逃到邮棠去。太子和郭荣牵住马,说:“诸侯的兵行动快速而且勇敢,这是在掠取物资,将要退走了,君王害怕什么?而且国家之主不能逃走,逃走就会失去大众。君王一定要等着!”齐灵公准备冲向前去,太子抽出剑来砍断马缰,这才停了下来。初八日,诸侯的军队向东边进攻到达潍水,南边到达沂水。 +郑国的子孔想要除掉大夫们,准备背叛晋国然后发动楚国军队来除掉他们。派人告诉子庚,子庚不答应。楚康王听说了这件事,派扬豚尹宜告诉子庚说:“国内的人们认为我主持国政而不出兵,死后就不能用规定的礼仪安葬祭祀。我即位后,到现在五年,军队不出动,人们恐怕认为我只顾自己安逸而忘了先君的霸业了。大夫考虑一下,怎么办?”子庚叹气说:“君王恐怕认为午是贪图安逸吧!我这样做是为了有利于国家啊。”接见使者,叩头然后回答:“诸侯正和晋国和睦,下臣请求试探一下。如果可行,君王就跟着来。如果不行,收兵而退回去,可以没有损害,君王也不会受到羞辱。” 子庚率领军队在汾地颁发武器。当时子蟜、伯有、子张跟从郑简公进攻齐国,子孔、子展、子西留守。子展、子西两个人知道子孔的策略,就加强守备入城坚守。子孔不敢和楚军会合。 +楚军进攻郑国,驻扎在鱼陵。右翼部队在上棘筑城,就徒步渡过颍水,驻扎在旃然水边。蒍子冯、公子格率领精锐部队攻打费滑、胥靡、献于、雍梁,向右绕过梅山,入侵郑国东北部,到达虫牢然后回去。子庚进攻纯门,在城下住了两晚然后回去。军队渡过鱼齿山下的滍水,遇到大雨,楚军大多被冻坏,服杂役的人几乎死光。 +晋国人听到楚国出兵,师旷说:“没有妨害。我屡次歌唱北方的曲调,又歌唱南方的曲调。南方的曲调不强,象征死亡的声音很多。楚国一定不能建功。”董叔说:“天象在于西北。南方的军队不合天时,一定不能建功。”叔向说:“决定胜负还在于他们国君的德行。” + +襄公十九年 +【经】十有九年春王正月,诸侯盟于祝柯。晋人执邾子,公至自伐齐。取邾田,自漷水。季孙宿如晋。葬曹成公。夏,卫孙林父帅师伐齐。秋七月辛卯,齐侯环卒。晋士□帅师侵齐,至谷,闻齐侯卒,乃还。八月丙辰,仲孙蔑卒。齐杀其大夫高厚。郑杀其大夫公子嘉。冬,葬齐灵公。城西郛。叔孙豹会晋士□于柯。城武城。 +【传】十九年春,诸侯还自沂上,盟于督扬,曰:“大毋侵小。” +执邾悼公,以其伐我故。遂次于泗上,疆我田。取邾田,自漷水归之于我。晋侯先归。公享晋六卿于蒲圃,赐之三命之服。军尉、司马、司空、舆尉、候奄,皆受一命之服。贿荀偃束锦,加璧,乘马,先吴寿梦之鼎。 +荀偃瘅疽,生疡于头。济河,及着雍,病,目出。大夫先归者皆反。士□请见,弗内。请后,曰:“郑甥可。”二月甲寅,卒,而视,不可含。宣子盥而抚之,曰:“事吴,敢不如事主!”犹视。栾怀子曰:“其为未卒事于齐故也乎?”乃复抚之曰:“主苟终,所不嗣事于齐者,有如河!”乃暝,受含。宣子出,曰:“吾浅之为丈夫也。” +晋栾鲂帅师从卫孙文子伐齐。季武子如晋拜师,晋侯享之。范宣子为政,赋《黍苗》。季武子兴,再拜稽首曰:“小国之仰大国也,如百谷之仰膏雨焉!若常膏之,其天下辑睦,岂唯敝邑?”赋《六月》。 +季武子以所得于齐之兵,作林钟而铭鲁功焉。臧武仲谓季孙曰:“非礼也。夫铭,天子令德,诸侯言时计功,大夫称伐。今称伐则下等也,计功则借人也,言时则妨民多矣,何以为铭?且夫大伐小,取其所得以作彝器,铭其功烈以示子孙,昭明德而惩无礼也。今将借人之力以救其死,若之何铭之?小国幸于大国,而昭所获焉以怒之,亡之道也。” +齐侯娶于鲁,曰颜懿姬,无子。其侄鬲声姬,生光,以为大子。诸子仲子、戎子,戎子嬖。仲子生牙,属诸戎子。戎子请以为大子,许之。仲子曰:“不可。废常,不祥;间诸侯,难。光之立也,列于诸侯矣。今无故而废之,是专黜诸侯,而以难犯不祥也。君必悔之。”公曰:“在我而已。”遂东大子光。使高厚傅牙,以为大子,夙沙卫为少傅。 +齐侯疾,崔杼微逆光。疾病,而立之。光杀戎子,尸诸朝,非礼也。妇人无刑。虽有刑,不在朝市。 +夏五月壬辰晦,齐灵公卒。庄公即位,执公子牙于句渎之丘。以夙沙卫易己,卫奔高唐以叛。 +晋士□侵齐,及谷,闻丧而还,礼也。 +于四月丁未,郑公孙虿卒,赴于晋大夫。范宣子言于晋侯,以其善于伐秦也。六月,晋侯请于王,王追赐之大路,使以行,礼也。 +秋八月,齐崔杼杀高厚于洒蓝而兼其室。书曰:“齐杀其大夫。”从君于昏也。 +郑子孔之为政也专。国人患之,乃讨西宫之难,与纯门之师。子孔当罪,以其甲及子革、子良氏之甲守。甲辰,子展、子西率国人伐之,杀子孔而分其室。书曰:“郑杀其大夫。”专也。子然、子孔,宋子之子也;士子孔,圭妫之子也。圭妫之班亚宋子,而相亲也;二子孔亦相亲也。僖之四年,子然卒,简之元年,士子孔卒。司徒孔实相子革、子良之室,三室如一,故及于难。子革、子良出奔楚,子革为右尹。郑人使子展当国,子西听政,立子产为卿。 +齐庆封围高唐,弗克。冬十一月,齐侯围之,见卫在城上,号之,乃下。问守备焉,以无备告。揖之,乃登。闻师将傅,食高唐人。殖绰、工偻会夜缒纳师,醢卫于军。 +城西郛,惧齐也。 +齐及晋平,盟于大隧。故穆叔会范宣子于柯。穆叔见叔向,赋《载驰》之四章。叔向曰:“肸敢不承命。”穆叔曰:“齐犹未也,不可以不惧。”乃城武城。 +卫石共子卒,悼子不哀。孔成子曰:“是谓蹶其本,必不有其宗。” +译文 +十九年春季,诸侯从沂水边上回来,在督扬结盟,说:“大国不要侵犯小国。” +逮捕了邾悼公,这是因为进攻我国的缘故。诸侯的军队就驻扎在泗水边上,划定我国的疆界。取得了邾国的土田,从漷水以西的地方都划归我国。 +晋平公先回国。鲁襄公在蒲圃设享招待晋国的六卿,赐给他们华丽的三命车服。军尉、司马、司空、舆尉、候奄都接受一命车服。送给荀偃五匹束锦,加上玉璧,四匹马,再送给他吴寿梦的铜鼎。 +荀偃长了恶疮,痈疽生在头部。渡过黄河,到达著雍,病危,眼珠子都鼓了出来。大夫先回去的都赶回来。士匄请求进见,荀偃不接见。派人问立谁为继承人,荀偃说:“郑国的外甥可以。”二月十九日,死,眼睛不闭,口闭紧不能放进珠玉。士匄盥洗然后抚摸尸体,说:“事奉吴岂敢不如事奉您!”荀偃的尸体还是没有闭眼。栾怀子说:“是为了齐国的事情没有完成的缘故吗?”就又抚摸着尸体说:“您如果死去以后,我不继续从事于齐国的事情,有河神为证!”荀偃这才闭了眼,接受了放进嘴里的含玉。士匄出去,说:“作为一个男人,我实在是浅薄啊。” +晋国的栾鲂领兵跟从卫国的孙文子进攻齐国。季武子去到晋国拜谢出兵,晋平公设享礼招待他。范宣子主政,赋《黍苗》这首诗。季武子站起来,再拜叩头,说:“小国的仰望大国,好像各种谷物仰望润泽的雨水。如果经常润泽,天下将会和睦,岂独是我国?”就赋了《六月》这首诗。 +季武子把在齐国得到的兵器制作了林钟并用铭文记载鲁国的武功,臧武仲对季武子说:“这是不合于礼的。铭文,只是用来记载天子的德行,诸侯用来记载举动合于时令和建立的功绩,大夫用来记载征伐。现在记载征伐,那是降了一等了,记载功劳,那是借助别人的力量;记载合于时令,那么对百姓的妨碍又很多,用什么来载人铭文?而且大国攻打小国,拿他们所得到的东西来制作宗庙器具,记载他们的功绩,以此让子孙看到,这是为了宣扬明德而惩罚无礼。现在是借助了别人的力量来拯救自己的死亡,怎么能记载这个呢?小国侥幸战胜大国,反而显示所得的战利品以激怒敌人,这是亡国之道啊。” +齐灵公从鲁国娶妻,名叫颜懿姬,没有生孩子,她的侄女鬷声姬生了光,齐灵公把子光立为太子。姬妾中有仲子,戎子,戎子受到宠爱。仲子生了牙,把他托付给戎子,戎子请求立牙为太子,齐灵答应了。仲子说:“不行。废弃常规,不吉祥;触犯诸侯,难于成功。光立为太子,已经参与诸侯盟会的行列了。现在没有大罪而废掉他,这是专横而看不起诸侯,而用难于成功的事去触犯不吉祥的事。君王一定会后悔。”齐灵公说:“一切由我。”就把太子光迁移到东部边境,派高厚做牙的太傅,立牙为太子,让夙沙卫做少傅。 +齐灵公生病了,崔杼偷偷地把光接来,趁在齐灵公病危的时候,立光为太子。光杀了戎子,把尸体摆在朝廷上,这是不合于礼的。对妇女没有专门的刑罚,即使用刑,也不能把尸体摆在朝廷上。 +夏季,五月二十九日,齐灵公死。齐庄公即位,在句渎之丘逮捕了公子牙。齐庄公认为夙沙卫出主意废掉自己,夙沙卫就逃亡到高唐并且叛变。 +晋国的士匄入侵齐国,到达穀地,听到齐国的丧事就回去了,这是合于礼的。 +四月十三日,郑国的公孙虿死,向晋国的大夫发出讣告。范宣子告诉了晋平公,因为他在进攻秦国的战役中表现很不错。六月,晋平公向周灵王请求,周灵王追赐给他大路的车,让他跟着葬车行走,这是合于礼的。 +秋季,八月,齐国崔杼在洒蓝杀了高厚,然后兼并了他的财货采邑。《春秋》记载说:“齐杀其大夫”,这是由于高厚听从了国君昏庸的命令。 +郑国的子孔执政独断专行,国内的人们很担心,就追究西宫那次祸难和纯门那次出兵的罪责。子孔应该抵罪,就带领了他的甲士和子革、子良的甲士来保卫自己。十一日,子展、子西率领国内的人们进攻,杀了子孔,瓜分了他的家财采邑。《春秋》记载说“郑杀其大夫”,这是因为子孔独断专行。子然、子孔,是宋子的儿子;士子孔,是圭妫的儿子。圭妫的位置在宋子之下,但是互相亲近,两个子孔也互相亲近。郑僖公四年,子然死;郑简公元年,士子孔死。子孔辅助子革、子良两家,三家像一家一样,所以都遭到祸难。子革、子良逃亡到楚国。子革做了右尹。郑国人让子展主持国事,子西主持政事,立子产为卿。 +齐国的庆封率军包围高唐,没有取胜。冬季,十一月,齐庄公亲自领兵包围高唐。见到夙沙卫在城墙上,大声喊他,他就下来了。齐庄公问夙沙卫防守的情况,夙沙卫告诉齐庄公说没有什么防备。齐庄公向夙沙卫作揖,夙沙卫还揖以后,登上城墙。他听说齐军将要依着城墙进攻,就让高唐城里的人好好吃一顿。殖绰、工偻会在夜里垂下城去,迎接齐军进城,把夙沙卫在军中剁成肉酱。 +鲁国在外城西边修筑城墙,这是由于畏惧齐国入侵。 +齐国和晋国讲和,在大隧结盟。所以穆叔和范宣子在柯地会见。穆叔进见叔向,赋《载驰》这首诗的第四章。叔向说:“肸岂敢不接受命令!”穆叔回国,说:“齐国还没有停止入侵,不能不害怕。”就在武城筑城。 +卫国的石共子死了,他的儿子悼子不表示悲哀。孔成子说:“这叫做拔掉了根本,必然不能保有他的宗族。” + +襄公二十年 +【经】二十年春王正月辛亥,仲孙速会莒人盟于向。夏六月庚申,公会晋侯、齐侯、宋公、卫侯、郑伯、曹伯、莒子、邾子、滕子、薛伯、杞伯,小邾子盟于澶渊。秋,公至自会。仲孙速帅师伐邾。蔡杀其大夫公子燮。蔡公子履出奔楚。陈侯之弟黄出奔楚。叔老如齐。冬十月丙辰朔,日有食之。季孙宿如宋。 +【传】二十年春,及莒平。孟庄子会莒人,盟于向,督扬之盟故也。 +夏,盟于澶渊,齐成故也。 +邾人骤至,以诸侯之事,弗能报也。秋,孟庄子伐邾以报之。 +蔡公子燮欲以蔡之晋,蔡人杀之。公子履,其母弟也,故出奔楚。 +陈庆虎、庆寅畏公子黄之逼,愬诸楚曰:“与蔡司马同谋。”楚人以为讨。公子黄出奔楚。 +初,蔡文侯欲事晋,曰:“先君与于践士之盟,晋不可弃,且兄弟也。”畏楚,不能行而卒。楚人使蔡无常,公子燮求从先君以利蔡,不能而死。书曰:“蔡杀其大夫公子燮”,言不与民同欲也;“陈侯之弟黄出奔楚”,言非其罪也。公子黄将出奔,呼于国曰:“庆氏无道,求专陈国,暴蔑其君,而去其亲,五年不灭,是无天也。” +齐子初聘于齐,礼也。 +冬,季武子如宋,报向戌之聘也。褚师段逆之以受享,赋《常棣》之七章以卒。宋人重贿之。归,覆命,公享之。赋《鱼丽》之卒章。公赋《南山有台》。武子去所,曰:“臣不堪也。” +卫宁惠子疾,召悼子曰:“吾得罪于君,悔而无及也。名藏在诸侯之策,曰:‘孙林父、宁殖出其君。’君入则掩之。若能掩之,则吾子也。若不能,犹有鬼神,吾有馁而已,不来食矣。”悼子许诺,惠子遂卒。 +译文 +二十年春季,鲁国和莒国讲和。孟庄子在向地会见莒人结盟,这是由于有督扬的盟会的缘故。 +夏季,鲁襄公和晋平公、齐庄公、宋平公、卫殇公、郑简公、曹武公、莒子、邾子、滕子、薛伯、杞伯、小邾子在澶渊结盟,这是为了和齐国讲和。 +邾国人屡次来犯,这是由于邾国认为鲁国参加了诸侯的征伐盟会无力报复的缘故。秋季,孟庄子率兵攻打邾国以作为报复。 +蔡国的公子燮想要让蔡国归服晋国,蔡国人杀了他。公子履,是公子燮的同母兄弟,所以逃亡到楚国。 +陈国的庆虎、庆寅害怕公子黄的逼迫,向楚国起诉说:“公子黄和蔡国司马一起策划顺服晋国。”楚国人因此而讨伐,公子黄逃亡到楚国去当面辩解。 +当初,蔡文侯想要事奉晋国,说:“先君参与了践土的盟会,晋国不能丢弃,而且还是兄弟国家呢。”可是又害怕楚国,没有能够办到就死了。楚国人役使蔡国没有一定的常规,公子燮要求继承先君的遗志以有利于蔡国,没有办到而死去。《春秋》记载说“蔡杀其大夫公子燮”,就是说愿望和百姓的不同;“陈哀公之弟黄出奔楚”,就是说不是公子黄的罪过。公子黄将要逃亡,在国都里喊叫说:“庆氏无道,谋求在陈国专政,轻慢和蔑视国君而去掉他的亲属,五年之内如果不灭亡,这就是没有天理了。” +齐子第一次到齐国聘问,这是合于礼的。 +冬季,季武子去到宋国,这是回报向戌的聘问。褚师段迎接他让他接受宋平公的享礼,季武子赋《常棣》这首诗的第七章和最后一章。宋国人重重地送给他财礼。回国复命,鲁襄公设享礼招待他,他赋了《鱼丽》这首诗的最后一章。鲁襄公赋《南山有台》这首诗。季武子离开坐席说:“下臣不敢当。” +卫国的甯殖生了病,告诉悼子说:“我得罪了国君,后悔也来不及了。我的名字记载在诸侯的简册上而加以收藏,说‘孙林父、甯殖赶走他们的国君’。国君回国,你要掩盖这件事。如果能够掩盖它,你就是我的儿子。如果不能,假如有鬼神的话,我宁可挨饿,也不来享受你的祭祀。”悼子答应,宁殖就死了。 + +襄公二十一年 +【经】二十有一年春王正月,公如晋。邾庶其以漆、闾丘来奔。夏,公至自晋。秋,晋栾出奔楚。九月庚戌朔,日有食之。冬十月庚辰朔,日有食之。曹伯来朝。公会晋侯、齐侯、宋公、卫侯、郑伯、曹伯、莒子、邾子于商任。 +【传】二十一年春,公如晋,拜师及取邾田也。 +邾庶其以漆、闾丘来奔。季武子以公姑姊妻之,皆有赐于其从者。 +于是鲁多盗。季孙谓臧武仲曰:“子盍诘盗?”武仲曰:“不可诘也,纥又不能。”季孙曰:“我有四封,而诘其盗,何故不可?子为司寇,将盗是务去,若之何不能?”武仲曰:“子召外盗而大礼焉,何以止吾盗?子为正卿,而来外盗;使纥去之,将何以能?庶其窃邑于邾以来,子以姬氏妻之,而与之邑,其从者皆有赐焉。若大盗礼焉以君之姑姊与其大邑,其次皋牧舆马,其小者衣裳剑带,是赏盗也。赏而去之,其或难焉。纥也闻之,在上位者,洒濯其心,壹以待人,轨度其信,可明征也,而后可以治人。夫上之所为,民之归也。上所不为而民或为之,是以加刑罚焉,而莫敢不惩。若上之所为而民亦为之,乃其所也,又可禁乎?《夏书》曰:‘念兹在兹,释兹在兹,名言兹在兹,允出兹在兹,惟帝念功。’将谓由己壹也。信由己壹,而后功可念也。” +庶其非卿也,以地来,虽贱必书,重地也。 +齐侯使庆佐为大夫,复讨公子牙之党,执公子买于句渎之丘。公子鉏来奔。叔孙还奔燕。 +夏,楚子庚卒,楚子使薳子冯为令尹。访于申叔豫,叔豫曰:“国多宠而王弱,国不可为也。”遂以疾辞。方署,阙地,下冰而床焉。重茧衣裘,鲜食而寝。楚子使医视之,复曰:“瘠则甚矣,而血气未动。”乃使子南为令尹。 +栾桓子娶于范宣子,生怀子。范鞅以其亡也,怨栾氏,故与栾盈为公族大夫而不相能。桓子卒,栾祁与其老州宾通,几亡室矣。怀子患之。祁惧其讨也,愬诸宣子曰:“盈将为乱,以范氏为死桓主而专政矣,曰:‘吾父逐鞅也,不怒而以宠报之,又与吾同官而专之,吾父死而益富。死吾父而专于国,有死而已,吾蔑从之矣!’其谋如是,惧害于主,吾不敢不言。”范鞅为之征。怀子好施,士多归之。宣子畏其多士也,信之。怀子为下卿,宣子使城着而遂逐之。 +秋,栾盈出奔楚。宣子杀箕遗、黄渊、嘉父、司空靖、邴豫、董叔、邴师、申书、羊舌虎、叔罴。囚伯华、叔向、籍偃。人谓叔向曰:“子离于罪,其为不知乎?”叔向曰:“与其死亡若何?《诗》曰:‘优哉游哉,聊以卒岁。’知也。”乐王鲋见叔向曰:“吾为子请!”叔向弗应。出,不拜。其人皆咎叔向。叔向曰:“必祁大夫。。”室老闻之,曰:“乐王鲋言于君无不行,求赦吾子,吾子不许。祁大夫所不能也,而曰‘必由之’,何也?”叔向曰:“乐王鲋,从君者也,何能行?祁大夫外举不弃仇,内举不失亲,其独遗我乎?《诗》曰:‘有觉德行,四国顺之。’夫子,觉者也。” +晋侯问叔向之罪于乐王鲋,对曰:“不弃其亲,其有焉。”于是祁奚老矣,闻之,乘馹而见宣子,曰:“《诗》曰:‘惠我无疆,子孙保之。’《书》曰:‘圣有谟勋,明征定保。’夫谋而鲜过,惠训不倦者,叔向有焉,社稷之固也。犹将十世宥之,以劝能者。今壹不免其身,以弃社稷,不亦惑乎?鲧殛而禹兴。伊尹放大甲而相之,卒无怨色。管、蔡为戮,周公右王。若之何其以虎也弃社稷?子为善,谁敢不勉?多杀何为?”宣子说,与之乘,以言诸公而免之。不见叔向而归。叔向亦不告免焉而朝。 +初,叔向之母□石叔虎之母美而不使,其子皆谏其母。其母曰:“深山大泽,实生龙蛇。彼美,余惧其生龙蛇以祸女。女,敝族也。国多大宠,不仁人间之,不亦难乎?余何爱焉!”使往视寝,生叔虎。美而有勇力,栾怀子嬖之,故羊舌氏之族及于难。 +栾盈过于周,周西鄙掠之。辞于行人,曰:“天子陪臣盈,得罪于王之守臣,将逃罪。罪重于郊甸,无所伏窜,敢布其死。昔陪臣书能输力于王室,王施惠焉。其子□,不能保任其父之劳。大君若不弃书之力,亡臣犹有所逃。若弃书之力,而思□之罪,臣,戮余也,将归死于尉氏,不敢还矣。敢布四体,唯大君命焉!”王曰:“尤而效之,其又甚焉!”使司徒禁掠栾氏者,归所取焉。使候出诸轘辕。 +冬,曹武公来朝,始见也。 +会于商任,锢栾氏也。齐侯、卫侯不敬。叔向曰:“二君者必不免。会朝,礼之经也;礼,政之舆也;政,身之守也;怠礼失政,失政不立,是以乱也。” +知起、中行喜、州绰、邢蒯出奔齐,皆栾氏之党也。乐王鲋谓范宣子曰:“盍反州绰、邢蒯,勇士也。”宣子曰:“彼栾氏之勇也,余何获焉?”王鲋曰:“子为彼栾氏,乃亦子之勇也。” +齐庄公朝,指殖绰、郭最曰:“是寡人之雄也。”州绰曰:“君以为雄,谁敢不雄?然臣不敏,平阴之役,先二子鸣。”庄公为勇爵。殖绰、郭最欲与焉。州绰曰:“东闾之役,臣左骖迫,还于门中,识其枚数。其可以与于此乎?”公曰:“子为晋君也。”对曰:“臣为隶新。然二子者,譬于禽兽,臣食其肉而寝处其皮矣。” +译文 +二十一年春季,鲁襄公到晋国,这是为了拜谢出兵和取得邾国的土田。 +邾国的庶其带着漆地和闾丘逃亡前来,季武子把鲁襄公的姑母嫁给他作妻子,对他的随从都有赏赐。 +当时鲁国的盗贼很多。季武子对臧武仲说:“您为什么不禁止盗贼?”臧武仲说:“盗贼不可以禁止,纥又没有能力。”季武子说:“我国有四面的边境,用来禁止盗贼,为什么不可以?您做司寇,应当从事于禁止盗贼,为什么不能?”武仲说:“您把外边的盗贼叫来而大大地给予礼遇,怎么能禁止国内的盗贼?您做正卿,反而使外边的盗贼进来,让纥禁止国内的盗贼,怎么能够办到?庶其在邾国偷盗了城邑而前来,您把姬氏作为他的妻子,还给了他城邑,他的随从人员都得到赏赐。如果用国君的姑母和他的大城邑对盗表示尊敬,其次的用皂牧车马,再小的给衣服佩剑带子,这是赏赐盗贼。赏赐了而要去掉他,恐怕困难吧。纥听说过,在上位的人要洗涤他的心,专一地以诚待人,使它合于法度而且使人们相信,可以明确地验证,然后才能治理人。上面的所作所为,是百姓的归依。上面所不做的,百姓有人做了,因此加以惩罚就没有人敢于不警戒。如果上面的所作所为百姓也照样做了,这是势所必然,又能够禁止吗?《夏书》说:‘想要干的就是这个,想舍去不干的就是这个,所要号令的就是这个,诚信所在的就是这个,只有天帝才能记下这功劳。’大约说的是要由自身来体现言行一致。诚信是由于自己的言行一致,然后才可以谈建立功劳。” +庶其不是卿,他带着土地来鲁国,虽然身份低贱,《春秋》必定要加以记载,这是为了重视土地。 +齐庄公派庆佐做大夫,再次讨伐公子牙的亲族,在句渎之丘抓了公子买。公子鉏逃亡前来。叔孙还逃亡到燕国。 +夏季,楚国的子庚死。楚康王派薳子冯做令尹,薳子冯与申叔豫商议。申叔豫说:“国家宠臣很多而君王又年轻,国家的事情不能办好。”于是薳子冯就用有病来推辞不干。当时正好是大热天,挖地,放上冰然后安置床。薳子冯身穿新棉衣,又穿上皮袍,少吃东西而睡在床上。楚康王派医生去诊视,回来报告说:“瘦弱到极点了,但血气还正常。”于是楚王就派子南做令尹。 +栾桓子娶范宣子的女儿做妻子,生了怀子。范鞅由于他一度逃亡,怨恨栾氏,所以和栾盈一起做公族大夫而不能很好相处。栾桓子死,栾祁和他的家臣头子州宾私通,州宾几乎侵占了全部家产。怀子担心这件事。栾祁害怕怀子讨伐,向范宣子毁谤说:“盈将要发动叛乱,认为范氏弄死了桓子而在晋国专权,说:‘我的父亲赶走范鞅,范鞅回国,不对他表示愤怒反而用宠信来报答他,又和我担任同样的官职,而使他得以独断专权。我的父亲死后范氏更加富有。弄死我父亲而在国内专政,我只有死路一条,也不能跟从他了。’他的计划就是这样,我怕会伤害您,不敢不说。”范鞅为她作证。怀子喜好施舍,很多的士都归附他。宣子害怕他人多,相信了栾祁的话。怀子当时做下卿,宣子派他在著地筑城并且由此赶走了他。 +秋季,栾盈逃亡到楚国。宣子杀了箕遗、黄渊、嘉父、司空靖、邴豫、董叔、邴师、申书、羊舌虎、叔罴,同时囚禁了伯华、叔向、籍偃。有人对叔向说:“您得到了罪过,恐怕是不聪明吧!”叔向说:“比起死去和逃亡来怎么样?《诗》说,‘悠闲啊多么逍遥自在,聊且这样来度过岁月’,这才是聪明啊。”乐王鲋去见叔向,说:“我为您去请求免罪。”叔向不回答。乐王鲋退出,叔向不拜送。叔向的手下人都责备叔向。叔向说:“一定要祁大夫才行。”家臣头子听到了,说:“乐王鲋对国君说的话,没有不被采纳的,他想请求赦免您,您又不答应。这是祁大夫所做不到的,但您说一定要由他去办,这是为什么?”叔向说:“乐王鲋,是一切都顺从国君的人,怎么能行?祁大夫举拔宗族外的人不放弃仇人,举拔宗族内的人不失掉亲人,难道只会留下我吗?《诗》说:‘有正直的德行,使四方的国家归顺。’他老人家是正直的人啊。” +晋平公向乐王鲋询问叔向的罪过,乐王鲋回答说:“叔向不丢弃他的亲人,他可能是同谋的。”当时祁奚已经告老回家,听说这情况,坐上快车而去拜见范宣子,说:“《诗》说‘赐给我们无边的恩惠,子子孙孙永远保持它。’《书》说:‘智慧的人有谋略训海,应当相信保护。’说到谋划而少有过错,教育别人而不知疲倦的,叔向是这样的,他是国家的柱石。即使他的十代子孙有过错还要赦免,用这样来勉励有能力的人。现在一旦自身不免于祸而死,放弃国家,这不也会使人困惑吗?鲧被诛戮而禹兴起;伊尹放逐太甲又做了他的宰相,太甲始终没有怨色;管叔、蔡叔被诛戮,周公仍然辅佐成王。为什么叔向要为了叔虎而被杀?您做了好事,谁敢不努力?多杀人作什么?”宣子高兴了,和祁奚共坐一辆车子,向晋平公劝说而赦免了叔向。祁奚不去见叔向就回去了,叔向也不向祁奚报告他已得赦,而就去朝见晋平公。 +当初,叔向的母亲嫉妒叔虎的母亲美丽,而不让她陪丈夫睡觉,儿了们都劝谏母亲。叔向的母亲说:“深山大泽之中,确实会生长龙蛇。她美丽,我害怕她生下龙蛇来祸害你们,你们,是衰败的家族,国内受到宠信的大官很多,坏人又从中挑拨,不也是很难处了吗?我自己有什么可爱惜的?”就让叔虎的母亲去陪侍丈夫睡觉,生了叔虎,美丽并有勇力,栾怀子宠爱他,所以羊舌氏这一家族遭到祸难。 +栾盈经过成周,周朝西部边境的人,劫掠他的财物。栾盈向周室使者申诉说:“天子的陪臣盈,得罪了天子的守土的臣,打算逃避惩罚。又重新在天子的郊外得罪,没有地方可以逃了,谨冒死上言:从前陪臣书能为王室效力,天子施给了恩惠。他的儿子黡不能保住他父亲的辛劳。天王如果不丢弃书的努力,逃亡在外的陪臣还有地方可以逃。如果丢弃书的努力,而想到黡的罪过,那么陪臣本来就是刑戮余生的人,就将要回国死在尉氏那里,不敢再回来了。谨敢直言不讳,后果怎么样,唯有听天子命令了。”周灵王说:“有了过错而去学它,过错更大了。”于是,周灵王让司徒禁止那些掠夺栾氏的人,所掠取的东西都归还,派迎送宾客的人把栾盈送出轘辕山。 +冬季,曹武公前来朝见,这是第一次朝见鲁襄公。 +鲁襄公和晋平公、齐庄公、宋平公、卫殇公、郑简公、曹武公、莒子、邾子在商任会见,这是为了禁锢栾盈。齐庄公、卫殇公表现得不恭敬。叔向说:“这两位国君必然不免于祸难。会见和朝见,这是礼仪的常规;礼仪,是政事的车子;政事,是身体的寄托。轻慢礼仪,政事会有失误;政事失误,就难于立身处世,因此就会发生动乱。” +知起、中行喜、州绰、邢蒯逃亡到齐国,他们都是栾氏的亲族。乐王鲋对范宣子说:“为什么不让州绰、邢蒯回来?他们是勇士啊。”宣子说:“他们是栾氏的勇士,我能得到什么?”乐王鲋说:“您如果做他们的栾氏,那就是您的勇士了。” +齐庄公上朝,指着殖绰、郭最说:“这是我的雄鸡。”州绰说:“君王认为他们是雄鸡,谁敢不认为是雄鸡?然而下臣不才,在平阴这次战役中,比他们二位可是先打鸣。”齐庄公设置勇士的爵位,殖绰、郭最想要参加。州绰说:“东闾这次战役,下臣的左骖马被逼迫,盘旋城门里不能前进,记下了门上铜钉的数字,是不是可以在这里有一份呢?”齐庄公说:“您是为的晋君啊。”州绰回答说:“臣下是初来的臣,然而这两位,如果用禽兽作比方,臣下已经吃了他们的肉而睡在他们的皮上了。” + +襄公二十二年 +【经】二十有二年春王正月,公至自会。夏四月。秋七月辛酉,叔老卒。冬,公会晋侯、齐侯、宋公、卫侯、郑伯、曹伯、莒子、邾子、薛伯、杞伯、小邾子于沙随。公至自会。楚杀其大夫公子追舒。 +【传】二十二年春,臧武仲如晋,雨,过御叔。御叔在其邑,将饮酒,曰:“焉用圣人!我将饮酒而己,雨行,何以圣为?”穆叔闻之曰:“不可使也,而傲使人,国之蠹也。”令倍其赋。 +夏,晋人征朝于郑。郑人使少正公孙侨对曰:“在晋先君悼公九年,我寡君于是即位。即位八月,而我先大夫子驷从寡君以朝于执事。执事不礼于寡君。寡君惧,因是行也,我二年六月朝于楚,晋是以有戏之役。楚人犹竞,而申礼于敝邑。敝邑欲从执事而惧为大尤,曰晋其谓我不共有礼,是以不敢携贰于楚。我四年三月,先大夫子蟜又从寡君以观衅于楚,晋于是乎有萧鱼之役。谓我敝邑,迩在晋国,譬诸草木,吾臭味也,而何敢差池?楚亦不竞,寡君尽其土实,重之以宗器,以受齐盟。遂帅群臣随于执事以会岁终。贰于楚者,子侯、石盂,归而讨之。湨梁之明年,子蟜老矣,公孙夏从寡君以朝于君,见于尝酎,与执燔焉。间二年,闻君将靖东夏,四月又朝,以听事期。不朝之间,无岁不聘,无役不从。以大国政令之无常,国家罢病,不虞荐至,无日不惕,岂敢忘职?大国若安定之,其朝夕在庭,何辱命焉?若不恤其患,而以为口实,其无乃不堪任命,而翦为仇雠,敝邑是惧。其敢忘君命?委诸执事,执事实重图之。” +秋,栾盈自楚适齐。晏平仲言于齐侯曰:“商任之会,受命于晋。今纳栾氏,将安用之?小所以事大,信也。失信不立,君其图之。”弗听。退告陈文子曰:“君人执信,臣人执共,忠信笃敬,上下同之,天之道也。君自弃也,弗能久矣!” +九月,郑公孙黑肱有疾,归邑于公。召室老、宗人立段,而使黜官、薄祭。祭以特羊,殷以少牢。足以共祀,尽归其馀邑。曰:“吾闻之,生于乱世,贵而能贫,民无求焉,可以后亡。敬共事君,与二三子。生在敬戒,不在富也。”己巳,伯张卒。君子曰:“善戒。《诗》曰:‘慎尔侯度,用戒不虞。’郑子张其有焉。” +冬,会于沙随,复锢栾氏也。 +栾盈犹在齐,晏子曰:“祸将作矣!齐将伐晋,不可以不惧。” +楚观起有宠于令尹子南,未益禄,而有马数十乘。楚人患之,王将讨焉。子南之子弃疾为王御士,王每见之,必泣。弃疾曰:“君三泣臣矣,敢问谁之罪也?”王曰:“令尹之不能,尔所知也。国将讨焉,尔其居乎?”对曰:“父戮子居,君焉用之?泄命重刑,臣亦不为。”王遂杀子南于朝,轘观起于四竟。子南之臣谓弃疾,请徙子尸于朝,曰:“君臣有礼,唯二三子。”三日,弃疾请尸,王许之。既葬,其徒曰:“行乎?”曰:“吾与杀吾父,行将焉入?”曰:“然则臣王乎?”曰:“弃父事仇,吾弗忍也。”遂缢而死。 +复使薳子冯为令尹,公子齮为司马。屈建为莫敖。有宠于薳子者八人,皆无禄而多马。他日朝,与申叔豫言。弗应而退。从之,入于人中。又从之,遂归。退朝,见之,曰:“子三困我于朝,吾惧,不敢不见。吾过,子姑告我。何疾我也?”对曰:“吾不免是惧,何敢告子?”曰:“何故?”对曰:“昔观起有宠于子南,子南得罪,观起车裂。何故不惧?”自御而归,不能当道。至,谓八人者曰:“吾见申叔,夫子所谓生死而肉骨也。知我者,如夫子则可。不然,请止。”辞八人者,而后王安之。 +十二月,郑游贩将归晋,未出竟,遭逆妻者,夺之,以馆于邑。丁巳,其夫攻子明,杀之,以其妻行。子展废良而立大叔,曰:“国卿,君之贰也,民之主也,不可以苟。请舍子明之类。”求亡妻者,使复其所。使游氏勿怨,曰:“无昭恶也。” +译文 +二十二年春季,臧武仲到晋国去,下雨,去看望御叔。御叔在自己的封邑里,准备喝酒,说:“哪里用得着圣人?我准备喝酒,而他自己冒着雨而来,聪明有什么用?”穆叔听到了,说:“他不配出使反而对使者骄傲,这是国家的蛀虫。”命令把他的赋税增加一倍。 +夏季,晋国人让郑国人前去朝见。郑国人派少正公孙侨回答,说:“在晋国先君悼公九年,我寡君在这个时候即了位。即位八个月,我国的先大夫子驷跟从寡君来向执事朝见,执事对寡君不加礼遇,寡君恐惧。由于这一趟,我国二年六月就向楚国朝见,晋国因此有了戏地这一役。楚国人还很强大,但对敝邑表明了礼仪。敝邑想要跟从执事,而又害怕犯下大罪,说,‘晋国恐怕认为我们不尊敬有礼仪的国家’,因此不敢对楚国有二心。我国四年三月,先大夫子?又跟从寡君到楚国观察他们有没有空子可钻,晋国因此有了萧鱼这一役。我们认为敝邑靠近晋国,譬如草木,我们不过是散发出来的气味,哪里敢有不一致?楚国逐渐衰弱,寡君拿出了土地上的全部出产,加上宗庙的礼器,来接受盟约。于是就率领下臣们随着执事到晋国,参加年终的会见。敝邑偏向楚国,是子侯和石盂,回去以后就讨伐了他们。湨梁会盟的第二年,子?已经告老退休了,公孙夏跟从寡君向君王朝见,在尝祭的时候拜见君王,参与了祭祀,饮酒吃肉。隔了两年,听说君王要安定东方,四月,又向君王朝见以听取结盟的日期。在没有朝见的时候,没有一年不聘问,没有一次事情不跟从。由于大国的政令没有定准,国家和家族都很困乏,意外的事情不断发生,没有一天不恐惧,岂敢忘掉自己的职责?大国如果安定敝邑,我们自己会来朝见,哪里用得着命令呢?如果不体恤敝邑的忧患,反而把它作为借口,那就恐怕不能忍受大国的命令,而被大国丢弃成为仇敌了。敝邑害怕这样的后果,岂敢忘记贵君的命令?一切托付给执事,执政深思一下。” +秋季,栾盈从楚国去到齐国。晏平仲对齐庄公说:“商任的会见,接受了晋国的命令。现在接纳栾氏,准备怎么任用他?小国所用来事奉大国的,是信用,失去信用,不能立身立国。君王还是考虑一下。”齐庄公不听。晏平仲退出以后告诉陈文子说:“做人君主的保持信用,做人臣下的保持恭敬。忠实、信用、诚笃、恭敬,上下共同保持它,这是上天的常道。国君自暴自弃,不能长久在位了。” +九月,郑国公孙黑肱有病,把封邑归还给郑简公,召来家臣之长、宗人立了段为后嗣,而且让他减省家臣、祭祀从简。通常的祭祀用羊一只,盛祭有羊和猪,留下足以供给祭祀的土地,其余的全部归还给郑简公,说:“我听说,生在乱世,地位尊贵但能够守贫,不向百姓求取什么,这就能够在别人之后灭亡。恭敬地事奉国君和几位大夫。生存,在于警戒,不在于富有。”二十五日,公孙黑肱死。君子说:“公孙黑肱善于警戒。《诗》说:‘谨慎地使用你公侯的法度,用以警戒意外’,郑国的公孙黑肱恐怕是做到了吧!” +冬季,鲁襄公和晋平公、齐庄公、宋平公、卫侯、郑简公、曹武公、莒子、邾子、薛伯、杞伯、小邾子在沙随会见,这是为了再次禁锢栾氏。 +栾盈还是在齐国住着。晏子说:“祸乱将要起来了。齐国将会进攻晋国,不能不使人害怕。” +楚国的观起受到令尹子南的宠信,没有增加俸禄,而有能驾几十辆车子的马匹。楚国人担心这种情况,楚康王打算诛戮他们。子南的儿了弃疾做楚康王的御士,楚康王每次见到他,一定哭泣。弃疾说:“君王三次向下臣哭泣了,谨敢请问是谁的罪过?”楚康王说:“令尹的不善,这是你所知道的。国家打算诛戮他,你还是住着不逃走吗?”弃疾回答说:“父亲被诛戮儿子住着不逃走,君王哪里还能加以任用?泄露命令而加重刑罚,下臣也不会这么做的。”楚康王就把子南杀死在朝廷上,把观起车裂,并把尸体在国内四方示众。子南的家臣对弃疾说:“请求让我们在朝廷上把子南的尸体搬出来。”弃疾说:“君臣之间有规定的礼仪,这只有看他们诸位大臣怎么办了。”过了三天,弃疾请求收尸。楚康王答应了。安葬完毕后,他的手下人说:“出走吗?”弃疾说:“我参与杀我父亲的预谋,出走,有什么地方可以去?”手下人说:“那么还是做君王的臣下吗?”弃疾说:“丢掉父亲事奉仇人,我不能忍受这么做。”弃疾就上吊死了。 +楚康王再次派薳子冯做令尹,公子齮做司马,屈建做莫敖。受到薳子冯宠信的有八个人,都没有俸禄而马匹很多。过了些日子,薳子冯上朝,和申叔豫说话,申叔豫不答应而退走。薳子冯跟着他走,申叔豫走进人群中。又跟着他走,申叔豫就回家了。薳子冯退朝,进见申叔豫,说:“您在朝廷上三次不理我,我害怕,不敢不来见您。我有过错,您不妨告诉我,为什么嫌弃我呢?”申叔豫回答说:“我害怕的是不能免于罪,哪里敢告诉您?”薳子冯说:“什么缘故?”申叔豫回答说:“从前观起受子南的宠信,子南有了罪过,观起被车裂,为什么不害怕?”薳子冯自己驾着车子回去,车子都不能走在正道上。到家,对那八个人说:“我进见申叔,这个人就是所谓能使死者复生,使白骨长肉的人啊。能够了解我像这个人一样的就可以留下,否则请就此罢休。”辞退了这八个人,楚康王才对他放心。 +十二月,郑国的游眅将要回到晋国去,没有出国境,遇到迎娶妻子的人,游眅夺走了他的妻子,就在那个城里住下。十二月某一天,那个女人的丈夫攻打游眅,并杀死了游眅,带着他的妻子走了。子展废掉了良而立了太叔,说:“国卿,是君主的副手,百姓的主人,不能随便的。请舍弃游眅之流的人。”派人寻求丢失妻子的人,让他回到他的乡里,让游氏不要怨恨他,说:“不要宣扬邪恶了。” + +襄公二十三年 +【经】二十有三年春王二月癸酉朔,日有食之。三月己巳,杞伯□卒。夏,邾畀我来奔。葬杞孝公。陈杀其大夫庆虎及庆寅。陈侯之弟黄自楚归于陈。晋栾盈复入于晋,入于曲沃。秋,齐侯伐卫,遂伐晋。八月,叔孙豹帅师救晋次于雍榆。己卯,仲孙速卒。冬十月乙亥,臧孙纥出奔邾。晋人杀栾盈。齐侯袭莒。 +【传】二十三年春,杞孝公卒,晋悼夫人丧之。平公不彻乐,非礼也。礼,为邻国阙。 +陈侯如楚。公子黄愬二庆于楚,楚人召之。使庆乐往,杀之。庆氏以陈叛。夏,屈建从陈侯围陈。陈人城,板队而杀人。役人相命,各杀其长。遂杀庆虎、庆寅。楚人纳公子黄。君子谓:“庆氏不义,不可肆也。故《书》曰:‘惟命不于常。’” +晋将嫁女于吴,齐侯使析归父媵之,以藩载栾盈及其士,纳诸曲沃。栾盈夜见胥午而告之。对曰:“不可。天之所废,谁能兴之?子必不免。吾非爱死也,知不集也。”盈曰:“虽然,因子而死,吾无悔矣。我实不天,子无咎焉。”许诺。伏之,而觞曲沃人。乐作。午言曰:“今也得栾孺子,何如?”对曰:“得主而为之死,犹不死也。”皆叹,有泣者。爵行,又言。皆曰:“得主,何贰之有?”盈出,遍拜之。 +四月,栾盈帅曲沃之甲,因魏献子,以昼入绛。初,栾盈佐魏庄子于下军,献子私焉,故因之。赵氏以原、屏之难怨栾氏,韩、赵方睦。中行氏以伐秦之役怨栾氏,而固与范氏和亲。知悼子少,而听于中行氏。程郑嬖于公。唯魏氏及七舆大夫与之。 +乐王鲋待坐于范宣子。或告曰:“栾氏至矣!”宣子惧。桓子曰:“奉君以走固宫,必无害也。且栾氏多怨,子为政,栾氏自外,子在位,其利多矣。既有利权,又执民柄,将何惧焉?栾氏所得,其唯魏氏乎!而可强取也。夫克乱在权,子无懈矣。”公有姻丧,王鲋使宣子墨縗冒絰,二妇人辇以如公,奉公以如固宫。 +范鞅逆魏舒,则成列既乘,将逆栾氏矣。趋进,曰:“栾氏帅贼以入,鞅之父与二三子在君所矣。使鞅逆吾子。鞅请骖乘。”持带,遂超乘,右抚剑,左援带,命驱之出。仆请,鞅曰:“之公。”宣子逆诸阶,执其手,赂之以曲沃。 +初,斐豹隶也,着于丹书。栾氏之力臣曰督戎,国人惧之。斐豹谓宣子曰:“苟焚丹书,我杀督戎。”宣子喜,曰:“而杀之,所不请于君焚丹书者,有如日!”乃出豹而闭之,督戎从之。逾隐而待之,督戎逾入,豹自后击而杀之。范氏之徒在台后,栾氏乘公门。宣子谓鞅曰:“矢及君屋,死之!”鞅用剑以帅卒,栾氏退。摄车从之,遇栾氏,曰:“乐免之,死将讼女于天。”乐射之,不中;又注,则乘槐本而覆。或以戟钩之,断肘而死。栾鲂伤。栾盈奔曲沃,晋人围之。 +秋,齐侯伐卫。先驱,谷荣御王孙挥,召扬为右。申驱,成秩御莒恒,申鲜虞之傅挚为右。曹开御戎,晏父戎为右。贰广,上之登御邢公,卢蒲癸为右。启,牢成御襄罢师,狼蘧疏为右。胠,商子车御侯朝,桓跳为右。大殿,商子游御夏之御寇,崔如为右,烛庸之越驷乘。 +自卫将遂伐晋。晏平仲曰:“君恃勇力以伐盟主,若不济,国之福也。不德而有功,忧必及君。”崔杼谏曰:“不可。臣闻之,小国间大国之败而毁焉,必受其咎。君其图之!”弗听。陈文子见崔武子,曰:“将如君何?”武子曰:“吾言于君,君弗听也。以为盟主,而利其难。群臣若急,君于何有?子姑止之。”文子退,告其人曰:“崔子将死乎!谓君甚,而又过之,不得其死。过君以义,犹自抑也,况以恶乎?” +齐侯遂伐晋,取朝歌,为二队,入孟门,登大行,张武军于荧庭,戍郫邵,封少水,以报平阴之役,乃还。赵胜帅东阳之师以追之,获晏□。八月,叔孙豹帅师救晋,次于雍榆,礼也。 +季武子无适子,公弥长,而爱悼子,欲立之。访于申丰,曰:“弥与纥,吾皆爱之,欲择才焉而立之。”申丰趋退,归,尽室将行。他日,又访焉,对曰:“其然,将具敝车而行。”乃止。访于臧纥,臧纥曰:“饮我酒,吾为子立之。”季氏饮大夫酒,臧纥为客。既献,臧孙命北面重席,新尊絜之。召悼之,降,逆之。大夫皆起。及旅,而召公鉏,使与之齿,季孙失色。 +季氏以公鉏为马正,愠而不出。闵子马见之,曰:“子无然!祸福无门,唯人所召。为人子者,患不孝,不患无所。敬共父命,何常之有?若能孝敬,富倍季氏可也。奸回不轨,祸倍下民可也。”公鉏然之。敬共朝夕,恪居官次。季孙喜,使饮己酒,而以具往,尽舍旃。故公鉏氏富,又出为公左宰。 +孟孙恶臧孙,季孙爱之。孟氏之御驺丰点好羯也,曰:“从余言,必为孟孙。”再三云,羯从之。孟庄子疾,丰点谓公鉏:“苟立羯,请仇臧氏。”公鉏谓季孙曰:“孺子秩,固其所也。若羯立,则季氏信有力于臧氏矣。”弗应。己卯,孟孙卒,公鉏奉羯立于户侧。季孙至,入,哭,而出,曰:“秩焉在?”公鉏曰:“羯在此矣!”季孙曰:“孺子长。”公鉏曰:“何长之有?唯其才也。且夫子之命也。”遂立羯。秩奔邾。 +臧孙入,哭甚哀,多涕。出,其御曰:“孟孙之恶子也,而哀如是。季孙若死,其若之何?”臧孙曰:“季孙之爱我,疾疢也。孟孙之恶我,药石也。美疢不如恶石。夫石犹生我,疢之美,其毒滋多。孟孙死,吾亡无日矣。” +孟氏闭门,告于季秋曰:“臧氏将为乱,不使我葬。”季孙不信。臧孙闻之,戒。冬十月,孟氏将辟,藉除于臧氏。臧孙使正夫助之,除于东门,甲从己而视之。孟氏又告季孙。季孙怒,命攻臧氏。乙亥,臧纥斩鹿门之关以出,奔邾。 +初,臧宣叔娶于铸,生贾及为而死。继室以其侄,穆姜之姨子也。生纥,长于公宫。姜氏爱之,故立之。臧贾、臧为出在铸。臧武仲自邾使告臧贾,且致大蔡焉,曰:“纥不佞,失守宗祧,敢告不吊。纥之罪,不及不祀。子以大蔡纳请,其可。”贾曰:“是家之祸也,非子之过也。贾闻命矣。”再拜受龟。使为以纳请,遂自为也。臧孙如防,使来告曰:“纥非能害也,知不足也。非敢私请!苟守先祀,无废二勋,敢不辟邑。”乃立臧为。臧纥致防而奔齐。其人曰:“其盟我乎?”臧孙曰:“无辞。”将盟臧氏,季孙召外史掌恶臣,而问盟首焉,对曰:“盟东门氏也,曰:‘毋或如东门遂,不听公命,杀适立庶。’盟叔孙氏也,曰:‘毋或如叔孙侨如,欲废国常,荡覆公室。’”季孙曰:“臧孙之罪,皆不及此。”孟椒曰:“盍以其犯门斩关?”季孙用之。乃盟臧氏曰:“无或如臧孙纥,干国之纪,犯门斩关。”臧孙闻之,曰:“国有人焉!谁居?其孟椒乎!” +晋人克栾盈于曲沃,尽杀栾氏之族党。栾鲂出奔宋。书曰:“晋人杀栾盈。”不言大夫,言自外也。 +齐侯还自晋,不入。遂袭莒,门于且于,伤股而退。明日,将复战,期于寿舒。杞殖、华还载甲,夜入且于之隧,宿于莒郊。明日,先遇莒子于蒲侯氏。莒子重赂之,使无死,曰:“请有盟。”华周对曰:“贪货弃命,亦君所恶也。昏而受命,日未中而弃之,何以事君?”莒子亲鼓之,从而伐之,获杞梁。莒人行成。 +齐侯归,遇杞梁之妻于郊,使吊之。辞曰:“殖之有罪,何辱命焉?若免于罪,犹有先人之敝庐在,下妾不得与郊吊。”齐侯吊诸其室。 +齐侯将为臧纥田。臧孙闻之,见齐侯,与之言伐晋,对曰:“多则多矣!抑君似鼠。夫鼠昼伏夜动,不穴于寝庙,畏人故也。今君闻晋之乱而后作焉。宁将事之,非鼠如何?”乃弗与田。 +仲尼曰:“知之难也。有臧武仲之知,而不容于鲁国,抑有由也。作不顺而施不恕也。《夏书》曰:‘念兹在兹。’顺事、恕施也。” +译文 +二十三年春季,杞孝公死去,晋悼夫人为他服丧。晋平公不撤除音乐,这是不合于礼的。按照礼,应该为邻国的丧事撤除音乐。 +陈哀公到达楚国,公子黄在楚国对二庆提出控诉,楚国人召见二庆,二庆让庆乐前往,楚国人杀了庆乐。庆氏带领陈国背叛楚国。夏季,屈建跟从陈哀公包围陈国。陈国人筑城,夹板掉下来,庆氏就杀死了筑城人。筑城的人互相传令,各自杀死他们的工头,于是乘机杀死了庆虎、庆寅。楚国人把公子黄送回陈国。君子认为:“庆氏行动不合于道义,就不能放肆。所以《书》说:‘天命不能常在。’” +晋国将要把女儿嫁给吴国,齐庄公让析归父致送妾媵,用篷车装着栾盈和他的士,把他安置在曲沃。栾盈夜里进见胥午并把情况告诉他。胥午回答说:“不能那么做。上天所废弃的,谁能够把他兴起?您必然不免于死。我不是爱惜一死,明知事情是不能成功的。”栾盈说:“尽管这样,依靠您而死去,我不后悔。我确实不为上天保佑,您没有过错。”胥午答应了。把栾盈藏起来以后就请曲沃人喝酒,音乐开始演奏,胥午发话说:“现在要是找到栾孺子,怎么办?”人们回答说:“找到了主人而为他死,虽死犹生。”大家都叹息,还有哭泣的。举杯,胥午又说栾盈回来的话。大家都说:“找到了主人,还有什么二心的!”栾盈走出来,对大家一一拜谢。 +四月,栾盈率领曲沃的甲兵,靠着魏献子,在白天进入绛地。当初,栾盈在下军中辅佐魏庄子,魏献子和他私下里很要好,所以依靠他。赵氏由于原、屏的祸难怨恨栾氏,韩氏、赵氏刚刚和睦。中行氏由于攻打秦国的那次战役怨恨栾氏,本来和范宣子亲近。知悼子年纪小,因此听从中行氏的话。程郑受到晋平公的宠信。只有魏氏和七舆大夫帮助栾氏。 +乐王鲋陪侍在范宣子旁边。有人报告说:“栾氏来了。”宣子恐惧。乐王鲋说:“奉事国君逃到固宫,一定没有危害。而栾氏怨敌很多,您主持国政,栾氏从外边来的,您处在掌权的地位,这有利的条件就多了。既然有利有权,又掌握着对百姓的赏罚,还害怕什么?栾氏所得到的,不就仅仅魏氏吗!而且魏氏是可以用强力争取过来的。平定叛乱在于有权力,您不要懈怠!” +晋平公有亲戚的丧事,乐王鲋让范宣子穿着黑色的丧服,和两个女人坐上手拉车去到晋平公那里,陪侍晋平公去到固宫。范鞅去迎接魏献子,魏献子的军队已经排成行列、登上战车,准备去迎接栾氏了。范鞅快步走进,说:“栾氏率领叛乱分子进入国都,鞅的父亲和几位大夫都在国君那里,派鞅来迎接您,鞅请求在车上作为骖乘。”拉着带子,就跳上魏献子的战车。范鞅右手摸着剑,左手拉着带子,下令驱车离开行列。驾车的人请问到哪里去,范鞅说:“到国君那里。”范宣子在阶前迎接魏献子,拉着他的手,答应把曲沃送给他。 +当初,斐豹是一个奴隶,用红字记载在竹简上,栾氏有一个大力士叫督戎,国内的人们都害怕他。斐豹对范宣子说:“如果烧掉这竹简,我去杀死督戎。”范宣子很高兴,说:“你杀了他,如果不请求国君烧掉这竹简,太阳可作明证!”于是就让斐豹出宫门,然后关上宫门,督戎跟上他。斐豹翻进矮墙等着督戎,督戎翻进墙来,斐豹从后面猛击而杀死了他。 +范氏的手下人在公台的后面,栾氏登上宫门。范宣子对范鞅说:“箭要射到国君的屋子,你就死去!”范鞅用剑带领步兵迎战,栾氏败退,范鞅跳上战车追击,遇到栾乐,范鞅说:“乐,别打了,我死了将会向上天控告你。”栾乐用箭射他,没有射中,又把箭搭上弓弦,车轮碰上槐树根而翻了车。有人用戟钩打他,把他的手臂打断,他就死了。栾鲂受伤。栾盈逃到曲沃,晋国人包围了他。 +秋季,齐庄公发兵攻打卫国。第一前锋,穀荣驾御王孙挥的战车,召扬作为车右。第二前锋,成秩驾御莒恒的战车,申鲜虞的儿子傅挚作为车右。曹开驾御齐庄公的战车,晏父戎作为车右。齐庄公的副车,上之登驾御邢公的战车,卢蒲癸作为车右,左翼部队,牢成驾御襄罢师的战车,狼蘧疏作为车右。右翼部队,商子车驾御侯朝的战车,桓跳作为车右。后军,商子游驾御夏之御寇的战车,崔如作为车右,烛庸之越等四人共乘一辆车殿后。 +从卫国出发并将由此进攻晋国。晏平仲说:“君王依靠勇力,来进攻盟主。如果不成功,这是国家的福气。没有德行而有功劳,忧患必然会降到君王身上。”崔杼劝谏说:“不行。下臣听说:‘小国钻了大国败坏的空子而加之以武力,一定要受到灾祸。’君王还是考虑一下。”齐庄公不听。陈文子进见崔杼,说:“打算把国君怎么办?”崔杼说:“我对国君说了,国君不听。把晋国奉为盟主,反而以它的祸难为利。下臣们如果急了,哪里还能顾及国君?您暂且不用管了。”陈文子退出,告诉他的手下人说:“崔子将要死了吧!指责国君太狠而所作所为又超过国君所为,会得不到善终的。用道义超过国君,还需要自己抑制,何况自己将作恶呢?” +齐庄公因此而进攻晋国,占取朝歌。兵分两路,一路进入孟门,一路上太行山口,在荧庭建筑纪念物,派人戍守郫邵,在少水收集晋军尸体合于一坑筑成大坟,以报复平阴那次战役,这才收兵回去,赵胜领着东阳的军队追赶上,俘虏了晏氂。八月,叔孙豹领兵救援晋国,驻扎在雍榆,这是合于礼的。 +季武子没有嫡子,公弥年长,但是季武子喜欢悼子,想立他为继承人。向申丰说:“弥和纥,我都喜欢,想要选择有才能的立为继承人。”申丰快步走出,回家,打算全家出走。过了几天,季武子又问申丰。申丰回答说:“如果这样,我准备套上我的车走了。”季武子就不说了。季武子又去问臧纥。臧纥说:“招待我喝酒,我为您立他。”季氏招待大夫们喝酒,臧纥是上宾。向宾客献酒完毕,臧纥命令朝北铺上两层席子,换上洗净的酒杯,召见悼子,走下台阶迎接他。大夫们都站起来,等到宾主互相敬酒酬答以后,才召见公鉏,让他和别人按年龄大小排列座位。季武子感到突然,脸上都变了颜色。 +季氏让公鉏担任马正,公鉏怨恨,不肯做。闵子马见到公鉏,说:“您不要这样,祸和福没有门,在于人们所召唤。做儿子的,只怕不孝,而不怕没有地位。恭敬地对待父亲的命令,难道会没有变化吗?如果能够孝顺恭敬,富有可以比季氏增加一倍。邪乱不合法度,祸患可以比老百姓增加一倍。”公鉏同意他的话,就恭敬地早晚问父亲安,谨慎地执行任务。季武子高兴了,让他招待自己喝酒,而带着饮宴的器具前往,季氏把器具全部留下给他,公鉏氏因此致富。又做了鲁襄公的左宰。 +孟庄子讨厌臧孙,但季武子喜欢他。孟氏的车马官丰点,喜欢羯,说:“听从我的话,你一定成为孟氏的继承人。”再三地说,羯就听从了他。孟庄子生病,丰点对公鉏说:“如果立了羯,就是报复了臧氏。”公鉏对季武子说:“孺子秩本来应当做孟氏的继承人。如果羯能够改立为继承人,那么季氏就确实比臧氏有力量了。”季武子不答应。八月初十日,孟孙死了。公鉏奉事羯立在门边接受宾客来吊唁。季武子来到,进门就哭,出门,说:“秩在哪里?”公鉏说:“羯在这里了。”季孙说:“孺子年长。”公鉏说:“有什么年长不年长?只要他有才能,而且是他老人家的命令。”就立了羯。秩逃亡到邾国。 +臧孙进门也哭,很哀痛的样子,眼泪很多。出门,他的御者说:“孟庄子讨厌您,而您却悲哀成这个样子。季武子如果死了,您怎么办?”臧孙说:“季武子喜欢我,这是没有痛苦的疾病。孟庄子讨厌我,这是治疾病的药石。没有痛苦的疾病不如使人痛苦的药石。药石还可以让我活下去,疾病没有痛苦,它的毒害太多。孟庄子死了,我的灭亡也没有多少日子了。” +孟氏关起大门,告诉季武子说:“臧氏准备发动变乱,不让我家安葬。”季武子不相信。臧孙听到了,实行戒备。冬季,十月,孟氏准备挖开墓道,在臧氏那里借用役夫。臧孙让正夫去帮忙,在东门挖掘墓道,让甲士跟随着自己前去视察。孟氏又告诉季武子。季武子生气,命令进攻臧氏。十月初七日,臧孙砍断鹿门的门栓逃亡到邾国。 +当初,臧宣叔在铸国娶妻,她生了臧贾和臧为就死了。臧宣叔以妻子的侄女作为继室,就是穆姜妹妹的女儿,生了纥,长在鲁公的宫中。穆姜喜欢他,所以立为臧宣叔的继承人。臧贾、臧为离开家住在铸国。臧孙从邾国派人告诉臧贾,同时送去大龟说:“纥没有才能,不能祭祀宗庙,谨向您报告不善。纥的罪过不至于断绝后代,您把大龟进献而请求立为我家的继承人,看是否可行。”臧贾说:“这是家里的灾祸,不是您的过错,贾听到命令了。”再拜,接受了大龟,让臧为去代他进献大龟并请求,臧为却请求立自己为继承人。臧纥去到防地,派人来报告说:“纥并不能伤害别人,而是由于智谋不足的缘故。纥并不敢为个人请求。如果保存先人的祭祀,不废掉两位先人的勋劳,岂敢不离开防地?”于是就立了臧为。臧纥献出了防地而逃亡到齐国。他的手下人说:“他们能为我们盟誓吗?”臧纥说:“不好写盟辞。”打算为臧氏盟誓。季武子召见掌管逃亡臣子的外史而询问盟辞的写法。外史回答说:“为东门氏盟誓,说:‘不要有人像东门遂那样,不听国君的命令,杀嫡子、立庶子。’为叔孙氏盟誓,说‘不要有人像叔孙侨如那样,想要废弃国家的常道,颠覆公室!”季武子说:“臧纥的罪过都不至于此。”孟椒说:“何不把他攻砍城门栓写进盟辞?”季武子采用,就和臧氏盟誓,说:“不要像臧孙纥那样触犯国家的法纪,进城门砍门栓!”臧纥听到了,说:“国内有人才啊!是谁呀?恐怕是孟椒吧!” +晋国人在曲沃战胜栾盈,把栾氏的亲族全部杀完。栾鲂逃亡到宋国。《春秋》记载说“晋人杀栾盈”,不说大夫,这是说他从国外进入国内发动叛乱。 +齐庄公从晋国回来,不进入国都,就袭击莒国,攻打且于,大腿受伤而退却。第二天,准备再战,约定军队在寿舒集中。杞梁、华还用战车装载甲士夜里进入且于的狭路,宿在莒国郊外。第二天,先和莒子在蒲侯氏相遇。莒子赠给他们以重礼,让他们不要死,说:“请和你们结盟。”华还回答说:“贪得财货丢弃命令,这也是君王所厌恶的。昨天晚上接受命令,今天太阳没有正午就丢掉,还用什么事奉君王?”莒子亲自击鼓,追击齐军,杀死了杞梁。莒国人就和齐国讲和。 +齐庄公回国以后,在郊外遇到杞梁的妻子,派人向他吊唁,她辞谢说:“杞梁有罪,岂敢劳动国君派人吊唁?如果能够免罪,还有先人的破屋在那里,下妾不能在郊外接受吊唁。”于是齐庄公又到杞梁家去吊唁。 +齐庄公准备封给臧纥土地。臧纥听说了,来见齐庄公。齐庄公对他说起进攻晋国的事,他回答说:“功劳太多了,可是君王却像老鼠,白天藏起来,夜里出动,不在宗庙里打洞,这是由于怕人的缘故。现在君王听说晋国有了动乱然后出兵,一旦晋国安宁又准备事奉晋国,这不是老鼠又是什么?”齐庄公听了就不赏赐臧纥田地了。 +孔子说:“聪明是很难做到的啊。有了臧武仲的聪明,而不能为鲁国容纳,这是有原因的,因为他的所作不顺于事理而所施不合于恕道。《夏书》说:‘想着这个,一心在于这个’,这就是顺于事理,合于恕道啊。” + + +襄公二十四年 +【经】二十有四年春,叔孙豹如晋。仲孙羯帅师侵齐。夏,楚子伐吴。秋七月甲子朔,日有食之,既。齐崔杼帅师伐莒。大水。八月癸巳朔,日有食之。公会晋侯、宋公、卫侯、郑伯、曹伯、莒子、邾子、滕子、薛伯、杞伯、小邾子于夷仪。冬,楚子、蔡侯、陈侯、许男伐郑。公至自会。陈金咸宜咎出奔楚。叔孙豹如京师。大饥。 +【传】二十四年春,穆叔如晋。范宣子逆之,问焉,曰:“古人有言曰,‘死而不朽’,何谓也?”穆叔未对。宣子曰:“昔□之祖,自虞以上,为陶唐氏,在夏为御龙氏,在商为豕韦氏,在周为唐杜氏,晋主夏盟为范氏,其是之谓乎?”穆叔曰:“以豹所闻,此之谓世禄,非不朽也。鲁有先大夫曰臧文仲,既没,其言立。其是之谓乎!豹闻之,大上有立德,其次有立功,其次有立言,虽久不废,此之谓不朽。若夫保姓受氏,以守宗祊,世不绝祀,无国无之,禄之大者,不可谓不朽。” +范宣子为政,诸侯之币重。郑人病之。二月,郑伯如晋。子产寓书于子西以告宣子,曰:“子为晋国,四邻诸侯,不闻令德,而闻重币,侨也惑之。侨闻君子长国家者,非无贿之患,而无令名之难。夫诸侯之贿聚于公室,则诸侯贰。若吾子赖之,则晋国贰。诸侯贰,则晋国坏。晋国贰,则子之家坏。何没没也!将焉用贿?夫令名,德之舆也。德,国家之基也。有基无坏,无亦是务乎!有德则乐,乐则能久。《诗》云:‘乐只君子,邦家之基。’有令德也夫!‘上帝临女,无贰尔心。’有令名也夫!恕思以明德,则令名载而行之,是以远至迩安。毋宁使人谓子‘子实生我’,而谓‘子濬我以生’乎?像有齿以焚其身,贿也。”宣子说,乃轻币。是行也,郑伯朝晋,为重币故,且请伐陈也。郑伯稽首,宣子辞。子西相,曰:“以陈国之介恃大国而陵虐于敝邑,寡君是以请罪焉。敢不稽首。” +孟孝伯侵齐,晋故也。 +夏,楚子为舟师以伐吴,不为军政,无功而还。 +齐侯既伐晋而惧,将欲见楚子。楚子使薳启强如齐聘,且请期。齐社,搜军实,使客观之。陈文子曰:“齐将有寇。吾闻之,兵不戢,必取其族。” +秋,齐侯闻将有晋师,使陈无宇从薳启强如楚,辞,且乞师。崔杼帅师送之,遂伐莒,侵介根。 +会于夷仪,将以伐齐,水,不克。 +冬,楚子伐郑以救齐,门于东门,次于棘泽。诸侯还救郑。晋侯使张骼、辅跞致楚师,求御于郑。郑人卜宛射犬,吉。子大叔戒之曰:“大国之人,不可与也。”对曰:“无有众寡,其上一也。”大叔曰:“不然,部娄无松柏。”二子在幄,坐射犬于外,既食而后食之。使御广车而行,己皆乘乘车。将及楚师,而后从之乘,皆踞转而鼓琴。近,不告而驰之。皆取胄于櫜而胄,入垒,皆下,搏人以投,收禽挟囚。弗待而出。皆超乘,抽弓而射。既免,复踞转而鼓琴,曰:“公孙!同乘,兄弟也。胡再不谋?”对曰:“曩者志入而已,今则怯也。”皆笑,曰:“公孙之亟也。” +楚子自棘泽还,使薳启强帅师送陈无宇。 +吴人为楚舟师之役故,召舒鸠人,舒鸠人叛楚。楚子师于荒浦,使沈尹寿与师祁犁让之。舒鸠子敬逆二子,而告无之,且请受盟。二子覆命,王欲伐之。薳子曰:“不可。彼告不叛,且请受盟,而又伐之,伐无罪也。姑归息民,以待其卒。卒而不贰,吾又何求?若犹叛我,无辞有庸。”乃还。 +陈人复讨庆氏之党,金咸宜咎出奔楚。 +齐人城郏。穆叔如周聘,且贺城。王嘉其有礼也,赐之大路。 +晋侯嬖程郑,使佐下军。郑行人公孙挥如晋聘。程郑问焉,曰:“敢问降阶何由?”子羽不能对。归以语然明,然明曰:“是将死矣。不然将亡。贵而知惧,惧而思降,乃得其阶,下人而已,又何问焉?且夫既登而求降阶者,知人也,不在程郑。其有亡衅乎?不然,其有惑疾,将死而忧也。” +译文 +二十四年春季,穆叔到了晋国,范宣子迎接他,询问他,说:“古人有话说,‘死而不朽’,这是说的什么?”穆叔没有回答。范宣子说:“从前匄的祖先,从虞舜以上是陶唐氏,在夏朝是御龙氏,在商朝是豕韦氏,在周朝是唐杜氏,晋国主持中原的盟会的时候是范氏,恐怕所说的不朽就是这个吧!”穆叔说:“据豹所听到的,这叫做世禄,不是不朽。鲁国有一位先大夫叫臧文仲,死了以后,他的话世代不废,所谓不朽,说的就是这个吧!豹听说:‘最高的是树立德行,其次是树立功业,再其次是树立言论。’能做到这样,虽然死了也久久不会废弃,这叫做不朽。像这样保存姓、接受氏,用业守住宗庙,世世代代不断绝祭祀。没有一个国家没有这种情况。这只是官禄中的大的,不能说是不朽。” +范宣子主持政事,诸侯朝见晋国的贡品很重,郑国人对这件事感到忧虑。二月,郑简公去到晋国,子产托子西带信给范宣子,说:“您治理晋国,四邻的诸侯不听说有美德,而听说要很重的贡品,侨对这种情况感到迷惑。侨听说君子治理国和家,不是担心没有财礼,而是害怕没有好名声。诸侯的财货,聚集在国君家里,内部就分裂。如果您把这个作为利己之物,晋国的内部就不和。诸侯的内部不和,晋国就受到损害。晋国的内部不和,您的家就受到损害。为什么那么糊涂呢!还哪里用得着财货?好名声,是装载德行的车子。德行,是国家和家族的基础。有基础才不至于毁坏,您不也应该这么做吗?有了德行就快乐,快乐了就能长久。《诗》说,‘快乐啊君子,是国家和家族的基础’,这就是有美德吧!‘天帝在你的上面,你不要有二心’,这就是有好名声吧!用宽恕来发扬德行,那么好的名声就会自然传布天下,因此远方的人会因仰慕而来,近处的人也会获得安宁。您是宁可使人对您说‘您确实养活了我’,还是说‘您剥削了我,来养活自己’呢?象有了象牙而毁了自己,这是由于象牙值钱的缘故。”范宣子听了子产的这番道理之后很高兴,就减轻了贡品。这一趟,郑简公朝见晋国,是为了贡品太重的缘故,同时请求进攻陈国。郑简公行叩首礼,范宣子辞谢不敢当。子西相礼,说:“由于陈国仗恃大国而欺凌侵害敝邑,寡君因此请求向陈国问罪,岂敢不叩头?” +孟孝伯入侵齐国,这是为了晋国的缘故。 +夏季,楚康王出动水兵以攻打吴国,由于不教育军队,没有得到成功就回来了。 +齐庄公对晋国发动进攻以后又害怕,打算会见楚康王。楚康王派薳启彊去到齐国聘问,同时请问会见的日期。齐国人在军队中祭祀土地神,并举行大检阅,让客人观看。陈文子说:“齐国将要受到侵犯。我听说,不收敛武力,还会自己害自己。” +秋季,齐庄公听说晋国打算出兵,就派遣陈无宇跟随薳启彊去到楚国。说明将有战事而不能会见,同时请求出兵。崔杼带兵送他,就乘机进攻莒国,侵袭介根。 +鲁襄公和晋平公、宋平公、卫殇公、郑简公、曹武公、莒子、邾子、滕子、薛伯、杞伯、小邾子在夷仪会见,准备进攻齐国。由于大水,没有能进攻。 +冬季,楚康王进攻郑国以救援齐国,进攻东门,驻扎在棘泽。诸侯回军救援郑国。晋平公派遣张骼,辅跞向楚军单车挑战,向郑国求取驾御战车的人。郑国人占卜派遣宛射犬,吉利。子太叔告诫宛射犬说:“对大国的人不能和他们平行抗礼。”宛射犬回答说:“不论兵多兵少,御者的地位在车左车右之上是一样的。”太叔说:“不是这样。小土山上没有松柏。”张骼、辅跞两个人在帐篷里,让射犬坐在帐篷外,吃完饭,才让射犬吃。让射犬驾御进攻的车前进,张、辅自己却坐着平时的战车,将要到达楚军营垒,然后才登上射犬的车子,二人均蹲在车后边的横木上弹琴。车子驶近楚营,射犬没有告诉这两个人就疾驰而进。这两个人都从袋子里拿出头盔戴上,进入营垒,都下车,把楚兵抓起来扔出去,把俘虏的楚兵捆绑好或者挟在腋下。射犬不等待这两个人而独自驱车出来,这两个人就都跳上车,抽出弓箭来射向追兵。脱险以后,张、辅二人又蹲在车后边横木上弹琴,说:“公孙!同坐一辆战车,就是兄弟,为什么两次都不招呼一下?”射犬回答说:“从前一心想着冲人敌营,这次是心里害怕敌军人多,顾不上商量。”两个人都笑了,说:“公孙是个急性的人啊!” +楚康王从棘泽回来,派薳启彊护送陈无宇。 +吴国人为楚国“舟师之役”的缘故,召集舒鸠人。舒鸠人背叛楚国。楚康王在荒浦驻兵,派沈尹寿和师祁犁责备他们。舒鸠子恭恭敬敬地迎接这两个人,告诉他们没有这回事。同时请求接受盟约。这两个人回见楚康王复命,楚康王想要进攻舒鸠。薳子说:“不行。他告诉我们说不背叛,同时又请求接受盟约,而我们又去进攻他,这是进攻无罪的国家。姑且回去使百姓休息,以等待结果。结果没有三心二意,我们还有什么可要求的?如果还是背叛我们,他就无话可说,我们打它就可以获得成功了。”楚康王于是就退兵回去。 +陈国人再次讨伐庆氏的亲族,鍼宜咎逃亡到楚国。 +齐国人在郏地为周王筑城。穆叔到成周聘问,同时祝贺筑城完工。周灵王嘉奖穆叔合于礼仪,赐给他大路之车。 +晋平公宠信程郑,任命他为下军副帅。郑国的行人公孙挥去到晋国聘问,程郑向他请教,说:“谨敢请问怎样才能降级?”公孙挥不能回答,回去告诉了然明。然明说:“这个人将要死了。否则,就将要逃亡。地位尊贵而知道害怕,害怕而想到了降级,就可以得到适合他的地位,不过是在别人下面罢了,又问什么?而且既己登上高位而要求降级的,这是聪明人,不是程郑这样的人。恐怕有了逃亡的迹象了吧!否则,恐怕就是有疑心病,自知将要死了而忧虑啊!” + +襄公二十五年 +【经】二十有五年春,齐崔杼帅师伐我北鄙。夏五月乙亥,齐崔杼弑其君光。公会晋侯、宋公、卫侯、郑伯、曹伯、莒子、邾子、滕子、薛伯、杞伯、小邾子于夷仪。六月壬子,郑公孙舍之帅师入陈。秋八月己巳,诸侯同盟于重丘。公至自会。卫侯入于夷仪。楚屈建帅师灭舒鸠。冬,郑公孙夏帅师伐陈。十有二月,吴子遏伐楚,门于巢,卒。 +【传】二十五年春,齐崔杼帅师伐我北鄙,以报孝伯之师也。公患之,使告于晋。孟公绰曰:“崔子将有大志,不在病我,必速归,何患焉!其来也不寇,使民不严,异于他日。”齐师徒归。 +齐棠公之妻,东郭偃之姊也。东郭偃臣崔武子。棠公死,偃御武子以吊焉。见棠姜而美之,使偃取之。偃曰:“男女辨姓,今君出自丁,臣出自桓,不可。”武子筮之,遇《困》三之《大过》三。史皆曰:“吉。”示陈文子,文子曰:“夫从风,风陨,妻不可娶也。且其《繇》曰:‘困于石,据于蒺藜,入于其宫,不见其妻,凶。’困于石,往不济也。据于蒺藜,所恃伤也。入于其宫,不见其妻,凶,无所归也。”崔子曰:“嫠也何害?先夫当之矣。”遂取之。庄公通焉,骤如崔氏。以崔子之冠赐人,侍者曰:“不可。”公曰:“不为崔子,其无冠乎?”崔子因是,又以其间伐晋也,曰:“晋必将报。”欲弑公以说于晋,而不获间。公鞭侍人贾举而又近之,乃为崔子间公。 +夏五月,莒为且于之役故,莒子朝于齐。甲戌,飨诸北郭。崔子称疾,不视事。乙亥,公问崔子,遂从姜氏。姜入于室,与崔子自侧户出。公拊楹而歌。侍人贾举止众从者,而入闭门。甲兴,公登台而请,弗许;请盟,弗许;请自刃于庙,勿许。皆曰:“君之臣杼疾病,不能听命。近于公宫,陪臣干掫有淫者,不知二命。”公逾墙。又射之,中股,反队,遂弑之。贾举,州绰、邴师、公孙敖、封具、铎父、襄伊、偻堙皆死。祝佗父祭于高唐,至,覆命。不说弁而死于崔氏。申蒯侍渔者,退,谓其宰曰:“尔以帑免,我将死。”其宰曰:“免,是反子之义也。”与之皆死。崔氏杀融蔑于平阴。 +晏子立于崔氏之门外,其人曰:“死乎?”曰:“独吾君也乎哉?吾死也。”曰:“行乎?”曰:“吾罪也乎哉?吾亡也。”“归乎?”曰:“君死,安归?君民者,岂以陵民?社稷是主。臣君者,岂为其口实,社稷是养。故君为社稷死,则死之;为社稷亡,则亡之。若为己死而为己亡,非其私昵,谁敢任之?且人有君而弑之,吾焉得死之,而焉得亡之?将庸何归?”门启而入,枕尸股而哭。兴,三踊而出。人谓崔子:“必杀之!”崔子曰:“民之望也!舍之,得民。”卢蒲癸奔晋,王何奔莒。 +叔孙宣伯之在齐也,叔孙还纳其女于灵公。嬖,生景公。丁丑,崔杼立而相之。庆封为左相。盟国人于大宫,曰:“所不与崔、庆者。”晏子仰天叹曰:“婴所不唯忠于君利社稷者是与,有如上帝。”乃歃。辛巳,公与大夫及莒子盟。 +大史书曰:“崔杼弑其君。”崔子杀之。其弟嗣书而死者,二人。其弟又书,乃舍之。南史氏闻大史尽死,执简以往。闻既书矣,乃还。 +闾丘婴以帷缚其妻而栽之,与申鲜虞乘而出,鲜虞推而下之,曰:“君昏不能匡,危不能救,死不能死,而知匿其昵,其谁纳之?”行及弇中,将舍。婴曰:“崔、庆其追我!”鲜虞曰:“一与一,谁能惧我?”遂舍,枕辔而寝,食马而食。驾而行,出弇中,谓婴曰:“速驱这!崔、庆之众,不可当也。”遂来奔。 +崔氏侧庄公于北郭。丁亥,葬诸士孙之里,四翣,不跸,下车七乘,不以兵甲。 +晋侯济自泮,会于夷仪,伐齐,以报朝歌之役。齐人以庄公说,使隰鉏请成。庆封如师,男女以班。赂晋侯以宗器、乐器。自六正、五吏、三十帅、三军之大夫、百官之正长、师旅及处守者,皆有赂。晋侯许之。使叔向告于诸侯。公使子服惠伯对曰:“君舍有罪,以靖小国,君之惠也。寡君闻命矣!” +晋侯使魏舒、宛没逆卫侯,将使卫与之夷仪。崔子止其帑,以求五鹿。 +初,陈侯会楚子伐郑,当陈隧者,井堙木刊。郑人怨之,六月,郑子展、子产帅车七百乘伐陈,宵突陈城,遂入之。陈侯扶其大子偃师奔墓,遇司马桓子,曰:“载余!”曰:“将巡城。”遇贾获,载其母妻,下之,而授公车。公曰:“舍而母!”辞曰:“不祥。”与其妻扶其母以奔墓,亦免。子展命师无入公宫,与子产亲御诸门。陈侯使司马桓子赂以宗器。陈侯免,拥社。使其众,男女别而累,以待于朝。子展执絷而见,再拜稽首,承饮而进献。子美入,数俘而出。祝祓社,司徒致民,司马致节,司空致地,乃还。 +秋七月己巳,同盟于重丘,齐成故也。 +赵文子为政,令薄诸侯之币而重其礼。穆叔见之,谓穆叔曰:“自今以往,兵其少弭矣!齐崔、庆新得政,将求善于诸侯。武也知楚令尹。若敬行其礼,道之以文辞,以靖诸侯,兵可以弭。” +楚薳子冯卒,屈建为令尹。屈荡为莫敖。舒鸠人卒叛楚。令尹子木伐之,及离城。吴人救之,子木遽以右师先,子强、息桓、子捷、子骈、子盂帅左师以退。吴人居其间七日。子强曰:“久将垫隘,隘乃禽也。不如速战!请以其私卒诱之,简师陈以待我。我克则进,奔则亦视之,乃可以免。不然,必为吴禽。”从之。五人以其私卒先击吴师。吴师奔,登山以望,见楚师不继,复逐之,傅诸其军。简师会之,吴师大败。遂围舒鸠,舒鸠溃。八月,楚灭舒鸠。 +卫献公入于夷仪。 +郑子产献捷于晋,戎服将事。晋人问陈之罪,对曰:“昔虞阏父为周陶正,以服事我先王。我先王赖其利器用也,与其神明之后也,庸以元女大姬配胡公,而封诸陈,以备三恪。则我周之自出,至于今是赖。桓公之乱,蔡人欲立其出。我先君庄公奉五父而立之,蔡人杀之。我又与蔡人奉戴厉公,至于庄、宣,皆我之自立。夏氏之乱,成公播荡,又我之自入,君所知也。今陈忘周之大德,蔑我大惠,弃我姻亲,介恃楚众,以凭陵我敝邑,不可亿逞。我是以有往年之告。未获成命,则有我东门之役。当陈隧者,井堙木刊。敝邑大惧不竟,而耻大姬。天诱其衷,启敝邑之心。陈知其罪,授手于我。用敢献功!”晋人曰:“何故侵小?”对曰:“先王之命,唯罪所在,各致其辟。且昔天子之地一圻,列国一同,自是以衰。今大国多数圻矣!若无侵小,何以至焉?”晋人曰:“何故戎服?”对曰:“我先君武、庄,为平、桓卿士。城濮之役,文公布命,曰:‘各复旧职!’命我文公戎服辅王,以授楚捷,不敢废王命故也。”士庄伯不能诘,复于赵文子。文子曰:“其辞顺,犯顺不祥。”乃受之。 +冬十月,子展相郑伯如晋,拜陈之功。子西复伐陈,陈及郑平。仲尼曰:“《志》有之:‘言以足志,文以足言。’不言,谁知其志?言之无文,行而不远。晋为伯,郑入陈,非文辞不为功。慎辞也!” +楚蒍掩为司马,子木使庀赋,数甲兵。甲午,蒍掩书土田,度山林,鸠薮泽,辨京陵,表淳卤,数疆潦,规偃猪,町原防,牧隰皋,井衍沃,量入修赋。赋车籍马,赋车兵、徒卒、甲楯之数。既成,以授子木,礼也。 +十二月,吴子诸樊伐楚,以报舟师之役。门于巢。巢牛臣曰:“吴王勇而轻,若启之,将亲门。我获射之,必殪。是君也死,强其少安!”从之。吴子门焉,牛臣隐于短墙以射之,卒。 +楚子以灭舒鸠赏子木。辞曰:“先大夫蒍子之功也。”以与蒍掩。 +晋程郑卒。子产始知然明,问为政焉。对曰:“视民如子。见不仁者诛之,如鹰鸇之逐鸟雀也。”子产喜,以语子大叔,且曰:“他日吾见蔑之面而已,今吾见其心矣。”子大叔问政于子产。子产曰:“政如农功,日夜思之,思其始而成其终。朝夕而行之,行无越思,如农之有畔。其过鲜矣。” +卫献公自夷仪使与宁喜言,宁喜许之。大叔文子闻之,曰:“乌乎!《诗》所谓‘我躬不说,皇恤我后’者,宁子可谓不恤其后矣。将可乎哉?殆必不可。君子之行,思其终也,思其复也。《书》曰:‘慎始而敬终,终以不困。’《诗》曰:‘夙夜匪解,以事一人。’今宁子视君不如弈棋,其何以免乎?弈者举棋不定,不胜其耦。而况置君而弗定乎?必不免矣。九世之卿族,一举而灭之。可哀也哉!” +会于夷仪之岁,齐人城郏。其五月,秦、晋为成。晋韩起如秦莅盟,秦伯车如晋莅盟,成而不结。 +译文 +二十五年春季,齐国的崔杼率领军队进攻鲁国北部边境,报复孝伯那次进攻齐国。鲁襄公担心,派人向晋国报告,孟公绰说:“崔子将要有大志,不在于困扰我国,一定很快回去,担心什么?他来的时候不劫掠,使用百姓不严厉,和平日不同。”齐军空来了一趟而退兵。 +齐国棠公的妻子,是东郭偃的姐姐。东郭偃是崔武子的家臣。棠公死,东郭偃为崔武子驾车去吊唁。崔武子看到棠姜很美,便很喜爱她,让东郭偃为他娶过来。东郭偃说:“男女婚配要辨别姓氏。现在您是丁公的后代,下臣是桓公的后代,这可不行。”崔武子占筮,得到《困》卦变成《大过》,太史都说“吉利”。拿给陈文子看,陈文子说:“丈夫跟从风,风坠落妻子,不能娶的。而且它的繇辞说:‘为石头所困,据守在蒺藜中,走进屋,不见妻,凶。’为石头所困,这意味前去不能成功。据守在蒺藜中,这意味所依靠的东西会使人受伤。走进屋,不见妻,凶,这意味无所归宿。”崔武子说:“她是寡妇,有什么妨碍?死去的丈夫已经承担过这凶兆了。”于是崔武子就娶了棠姜。 +齐庄公和棠姜私通,经常到崔家去,把崔武子的帽子赐给别人。侍者说:“不行。”齐庄公说:“不用崔子的帽子,难道就没有帽子了?”崔武子由此怀恨齐庄公,又因为齐庄公乘晋国的动乱而进攻晋国,说:“晋国必然要报复。”崔武子想要杀死齐庄公来讨好晋国,而又没有得到机会。齐庄公鞭打了侍人贾举,后来又亲近贾举,贾举就为崔武子找机会杀死齐庄公。 +夏季,五月,莒国由于且于这次战役的缘故,莒子到齐国朝见。十六日,齐庄公在北城设享礼招待他,崔武子推说有病,不办公事。十七日,齐庄公去问候崔武子,乘机又与棠姜幽会。姜氏进入室内和崔武子从侧门出去。齐庄公拍着柱子唱歌。侍人贾举禁止庄公的随从入内,自己走进去,关上大门。甲士们一哄而起,齐庄公登上高台请求免死,众人不答应;请求在太庙自杀,还不答应。都说:“君王的下臣崔杼病得厉害。不能听取您的命令。这里靠近君王的宫室,陪臣巡夜搜捕淫乱的人,此外不知道有其他命令。”齐庄公跳墙,有人用箭射他,射中大腿,掉在墙内,于是就杀死了他。贾举、州绰、邴师、公孙敖、封具、铎父、襄伊、偻堙都被杀死。祝佗父在高唐祭祀,到达国都,复命,还没有脱掉官帽,就在崔武子家里被杀死。申蒯,是管理渔业的人,退出来,对他的家臣头子说:“你带着我的妻子儿女逃走,我准备一死。”他的家臣头子说:“如果我逃走,这是违背了您的道义了。”就和申蒯一起自杀。崔氏在平阴杀死了鬷蔑。 +晏子立在崔氏的门外边,他的手下人说:“死吗?”晏子说:“是我一个人的国君吗?我去死?”手下人说:“逃吗?”晏子说:“是我的罪过吗?我逃走?”手上人说:“回去吗?”晏子说:“国君死了,回到哪儿去?作为百姓的君主,难道是用他的地位,来凌驾于百姓之上?应当主持国政。作为君主的臣下,难道是为了他的俸禄?应当保护国家。所以君主为国家而死,那么也就是为他而死,为国家而逃亡,那么也就是为他而逃亡。如果君主为自己而死,为自己而逃亡,不是他个人宠爱的人,谁敢承担这个责任?而且别人有了君主反而杀死了他,我哪能为他而死?哪里能为他而逃亡?但是又能回到哪里去呢?”开了大门,晏子进去,头枕在尸体的大腿上而号哭,起来,往上跳三次以后才出去。有人对崔武子说:“一定要杀了他!”崔武子说:“他是百姓所向往的人,放了他,可以得民心。”卢蒲癸逃亡到晋国,王何逃亡到莒国。 +叔孙宣伯在齐国的时候,叔孙还把叔孙宣伯的女儿嫁给齐灵公,受到宠爱,生了齐景公。十九日,崔武子拥立景公为国君而自己出任宰相,庆封做左相,和国内的人们在太公的宗庙结盟,说:“有不依附崔氏、庆氏的—”晏子向天叹气说:“婴如果不依附忠君利国的人,有上帝为证!”于是就歃血。二十三日,齐景公和大夫以及莒子结盟。 +太史记载说:“崔杼杀了他的国君。”崔武子杀死了太史。他的弟弟接着这样写,因而死了两人。太史还有一个弟弟又这样写,崔武子就没杀了。南史氏听说太史都死了,拿了照样写好了的竹简前去,听到已经如实记载了,这才回去。 +闾丘婴用车子的帷幕包了妻子,装上车,和申鲜虞坐一辆车逃走。鲜虞把闾丘婴的妻子推下车,说:“国君昏昧不能纠正,国君危险不能救驾,国君死亡不能以身殉,只知道把自己所亲爱的人藏匿起来,有谁会接纳我们?”走到弇中狭道,准备住下来,闾丘婴说:“崔氏、庆氏可能在追我们。”鲜虞说:“一对一,谁能让我们害怕?”就住下来,头枕着马缰而睡,先喂饱马然后自己吃饭,套上马车继续赶路。走出弇中,对闾丘婴说:“快点赶马,崔氏、庆氏人多,是不能抵挡的。”于是就逃亡到鲁国来。 +崔氏没有把齐庄公的棺材殡于庙就放在外城北边。二十九日,安葬在士孙之里,葬礼用四把长柄扇,不清道,不警戒,送葬的破车七辆,不用武器盔甲随葬。 +晋平公渡过泮水,和鲁襄公、宋平公、卫殇公、郑简公、曹武公、莒子、邾于、滕子、薛伯、杞伯、小邾子在夷仪会合,进攻齐国,以报复朝歌这一战役。齐国人想用杀齐庄公这件事情向晋国解释,派隰鉏请求讲和。庆封来到军中,男男女女分开排列、捆绑。齐国把宗庙里的祭器和乐器送给晋平公。从六卿、五吏、三个师的将领、各部门的首长、属官和留守的人都赠送财礼。晋平公答应了。派叔向告诉诸侯。襄公派子服惠伯回答说:“君王宽恕了有罪,以安定小国,这是君王的恩惠。寡君听到命令了。” +晋平公派魏舒、宛没迎接卫献公,准备让卫国把夷仪给卫献公居住。崔武子留下卫献公的妻子儿女,来谋求五鹿这块地方。 +当初,陈哀公会合楚王进攻郑国,陈军经过的路上,水井被填,树木被砍,郑国人很怨恨。六月,郑国的子展、子产领着七百辆战车攻打陈国,夜里发动突然袭击,就进了城。陈哀公扶着他的太子偃师逃奔到坟地里,碰到司马桓子,说:“用车装上我!”司马桓子说:“我正打算巡城呢。”碰到贾获,车上装着他的母亲和妻了,贾获让他母亲、妻子下车而把车子交给陈哀公。陈哀公说:“安置好你的母亲。”贾获辞谢说:“妇女和你同坐,不吉祥。”贾获说完就和他妻子扶着他母亲逃奔到坟地里,也免于祸难。 +子展命令军队不要进入陈哀公的宫室,和子产亲自守卫在宫门口,陈哀公让司马桓子把宗庙的祭器赠送给他们。陈哀公穿上丧服,抱着土地神的神主,让他手下的男男女女分开排列、捆绑,在朝廷上等待。子展拿着绳子进见陈哀公,再拜叩头,捧着酒杯向陈哀公献礼。子产进入,点了点俘虏的人数就出去了。郑国人向陈国的土地神祝告消灾去邪,司徒归还百姓,司马归还兵符,司空归还土地,于是就回国。 +秋季,七月二十日,诸侯在重丘一起结盟,这是由于跟齐国讲和的缘故。 +赵文子主持政事,命令减轻诸侯的贡品而着重礼仪。穆叔进见他。赵文子对穆叔说:“从今以后,战争恐怕可以稍稍停止了。齐国的崔氏、庆氏新近当政,将要向诸侯改善关系。武也了解楚国的令尹。如果恭敬地执行礼仪,用外交辞令和他说,用来安定诸侯,战争可以停止。” +楚国的薳子冯死了,屈建做令尹,屈荡做莫敖。舒鸠人终于肯叛楚国。屈建率兵进攻舒鸠,到达离城,吴国人救援舒鸠。屈建急忙让右翼部队先出动,子强、息桓、子捷、子骈、子盂率领左翼部队向后撤退。吴国人处在左右两军之间七天。子强说:“时间久了将会疲弱,疲弱就会被俘,不如赶快打仗。我请求带领家兵去引诱他们,你们选择精兵,摆开阵势等待我。我得胜就前进,我败逃就看情况办,这样就可以免于被俘。不这样,一定被吴国俘虏。”大家听从了他的话。五个人带领他们的家兵先攻吴军,吴军败逃,登山而远望,看到楚军没有后继,就再次追赶,迫近楚军。楚军精选部队就和家兵会合作战,吴军大败。楚军乘机就包围了舒鸠,舒鸠溃散。八月,楚国灭亡了舒鸠。 +卫献公进入夷仪。 +郑国的子产向晋国奉献战利品,穿着军服主持事务。晋国人质问陈国的罪过,子产回答说:“从前虞父做周朝的陶正,服事我们先王。我们先王嘉奖他能制作器物,于人有利,并且是虞舜的后代,就把大女儿太姬匹配给胡公,封他在陈地,以表示对黄帝、尧、舜的后代的诚敬。所以陈国是我周朝的后代,到今天还依靠着周朝。陈桓公死后发生动乱,蔡国人想要立他们的后代,我们先君庄公奉事五父而立了他,蔡国人杀死了五父。我们又和蔡国人奉事厉公,至于庄公、宣公,都是我们所立的。夏氏的祸乱杀死了灵公,成公流离失所,又是我们让他回国的,这是君王知道的。现在陈国忘记了周朝在的大德,丢弃我们的大恩,抛弃我们这个亲戚,倚仗楚国人多,以进逼我敝邑,但是并不能满足,我国因此而有去年请求攻打陈国的报告。没有得到贵国的命令,反却有了陈国进攻我国东门那次战役。在陈军经过的路上,水井被填塞,树木被砍伐。敝邑非常害怕敌兵压境,给太姬带来羞耻,上天诱导我们的心,启发了敝邑攻打陈国的念头。陈国知道自己的罪过,在我们这里得到惩罚。因此我们敢于奉献俘虏。”晋国人说:“为什么侵犯小国?”子产回答说:“先王的命令,只要是罪过所在,就要分别给刑罚。而且从前天子的土地方圆一千里,诸侯的土地方圆一百里,以此递减。现在大国的土地多到方圆几千里,如果没有侵占小国,怎么能到这地步呢?”晋国人说:“为什么穿上军服?”子产回答说:“我们先君武公、庄公做周平王、周桓王的卿士。城濮这一战役后,晋文公发布命令,说:‘各人恢复原来的职务。’命令我郑文公穿军服辅佐天子,以接受楚国俘虏献给天子,现在我穿着军服,这是由于不敢废弃天子命令的缘故。”士庄伯已经不能再质问,于是向赵文子回复。赵文子说:“他的言辞顺理成章,违背了情理不吉利。”于是就接受郑国奉献的战利品。 +冬季,十月,子展作为郑简公的相礼一起去到晋国,拜谢晋国接受他们奉献的陈国战利品。子西再次发兵进攻陈国,陈国和郑同讲和。 +孔子说:“古书上说:‘言语用来完成意愿,文采用来完成言语。’不说话,谁知道他的意愿是什么?说话没有文采,不能到达远方。晋国成为霸主,郑国进入陈国,不是善于辞令就不能成功。要谨慎地使用辞令。” +楚国的蒍掩做司马,子木让他治理军赋,检查盔甲武器。十月初八日,蒍掩记载土泽地田的情况:度量山林的木材,聚集水泽的出产,区别高地的情况,标出盐碱地,计算水淹地。规划蓄水池,划分小块耕地,在水草地上放牧,在肥沃的土地上划定井田。计量收入制定赋税制度,征收百姓交纳战车和马匹税、征收战车步卒所用的武器和盔甲盾牌税。完成以后,把它交付给子木,这是合于礼的。 +十二月,吴王诸樊进攻楚国,为报复“舟师之战”。进攻巢地的城门。巢牛臣说:“吴王勇敢而轻率,如果我们打开城门,他将会亲自带头进门。我乘机射他,一定能射死。这个国君死了,边境上或可以稍为安定一些。”听从了他的意见。吴王进入城门,牛臣躲在短墙后用箭射他,吴王死了。 +楚康王由于灭亡了舒鸠赏赐子木。子木推辞说:“这是先大夫蒍子的功劳。”楚康王就把赏赐给了蒍掩。 +晋国的程郑死,子产才开始了解然明。子产向然明询问有关施政的方针。然明回答说:“把百姓看成像儿子一样。见到不仁的人,就诛戮他,好像老鹰追赶鸟雀。”子产很高兴,把这些话告诉子太叔,而且说:“以前我见到的只是然明的面貌,现在我了解到他内心甚有见识。” 子太叔向子产询问政事。子产说:“政事好像农活,白天黑夜想着它,要想着他的开始又想着要取得好结果。早晨晚上都照想着的去做,所做的不超过所想的,好像农田里有田埂一样,过错就会少一些。” +卫献公从夷仪派人向宁喜谈复国的事情,宁喜同意了。太叔文子听说了,说:“啊!《诗》所谓‘我的一身还不能被人容纳,哪里来得及顾念我的后代?”宁子可以说是不顾他的后代了。难道可以吗?大概是一定不可以的。君子有所行动,要想到结果,想到下次能够再如此。《书》说:‘慎重于开始,而重视其结果,结果就不会困惑。’《诗》说:‘早晚不敢懈怠,以事奉一人。’现在宁子看待国君不如下棋,他怎么能免于祸难呢?下棋的人举棋不定,就不能击败他的对方,而何况安置国君而不能决定呢?必定不能免于祸难了。九代相传的卿族,一旦被灭亡,可悲啊!” +在夷仪会见的那一年,齐国人在郏地筑城。那年五月,秦国、晋国讲和,晋国的韩起去到秦国参加结盟,秦国的伯车去到晋国参加结盟。虽然讲和但是并不巩固。 + +襄公二十六年 +【经】二十有六年春王二月辛卯,卫宁喜弑其君剽。卫孙林父入于戚以叛。甲午,卫侯衎复归于卫。夏,晋侯使荀吴来聘。公会晋人、郑良霄、宋人、曹人于澶渊。秋,宋公弑其世子痤。晋人执卫宁喜。八月壬午,许男宁卒于楚。冬,楚子、蔡侯、陈侯伐郑。葬许灵公。 +【传】二十六年春,秦伯之弟金咸如晋修成,叔向命召行人子员。行人子朱曰:“朱也当御。”三云,叔向不应。子朱怒,曰:“班爵同,何以黜朱于朝?”抚剑从之。叔向曰:“秦、晋不和久矣!今日之事,幸而集,晋国赖之。不集,三军暴骨。子员道二国之言无私,子常易之。奸以事君者,吾所能御也。”拂衣从之。人救之。平公曰:“晋其庶乎!吾臣之所争者大。”师旷曰:“公室惧卑。臣不心竞而力争,不务德而争善,私欲已侈,能无卑乎?” +卫献公使子鲜为复,辞。敬姒强命之。对曰:“君无信,臣惧不免。”敬姒曰:“虽然,以吾故也。”许诺。初,献公使与宁喜言,宁喜曰:“必子鲜在,不然必败。”故公使子鲜。子鲜不获命于敬姒,以公命与宁喜言,曰:“苟反,政由宁氏,祭则寡人。”宁喜告蘧伯玉,伯玉曰:“瑗不得闻君之出,敢闻其入?”遂行,从近关出。告右宰谷,右宰谷曰:“不可。获罪于两君,天下谁畜之?”悼子曰:“吾受命于先人,不可以贰。”谷曰:“我请使焉而观之。”遂见公于夷仪。反曰:“君淹恤在外十二年矣,而无忧色,亦无宽言,犹夫人也。若不已,死无日矣。”悼子曰:“子鲜在。”右宰谷曰:“子鲜在,何益?多而能亡,于我何为?”悼子曰:“虽然,不可以已。”孙文子在戚,孙嘉聘于齐,孙襄居守。 +二月庚寅,宁喜、右宰谷伐孙氏,不克。伯国伤。宁子出舍于郊。伯国死,孙氏夜哭。国人召宁子,宁子复攻孙氏,克之。辛卯,杀子叔及大子角。书曰:“宁喜弑其君剽。”言罪之在宁氏也。孙林父以戚如晋。书曰:“入于戚以叛。”罪孙氏也。臣之禄,君实有之。义则进,否则奉身而退,专禄以周旋,戮也。 +甲午,卫侯入。书曰:“复归。”国纳之也。大夫逆于竟者,执其手而与之言。道逆者,自车揖之。逆于门者,颔之而已。公至,使让大叔文子曰:“寡人淹恤在外,二三子皆使寡人朝夕闻卫国之言,吾子独不在寡人。古人有言曰:‘非所怨勿怨。’寡人怨矣。”对曰:“臣知罪矣!臣不佞不能负羁泄,以从手干牧圉,臣之罪一也。有出者,有居者。臣不能贰,通外内之言以事君,臣之罪二也。有二罪,敢忘其死?”乃行,从近关出。公使止之。 +卫人侵戚东鄙,孙氏愬于晋,晋戍茅氏。殖绰伐茅氏,杀晋戍三百人。孙蒯追之,弗敢击。文子曰:“厉之不如!”遂从卫师,败之圉。雍鉏获殖绰。复愬于晋。 +郑伯赏入陈之功。三月甲寅朔,享子展,赐之先路,三命之服,先八邑。赐子产次路,再命之服,先六邑。子产辞邑,曰:“自上以下,隆杀以两,礼也。臣之位在四,且子展之功也。臣不敢及及赏礼,请辞邑。”公固予之,乃受三邑。公孙挥曰:“子产其将知政矣!让不失礼。” +晋人为孙氏故,召诸侯,将以讨卫也。夏,中行穆子来聘,召公也。 +楚子、秦人侵吴,及雩娄,闻吴有备而还。遂侵郑,五月,至于城麇。郑皇颉戍之,出,与楚师战,败。穿封戌囚皇颉,公子围与之争之。正于伯州犁,伯州犁曰:“请问于囚。”乃立囚。伯州犁曰:“所争,君子也,其何不知?”上其手,曰:“夫子为王子围,寡君之贵介弟也。”下其手,曰:“此子为穿封戌,方城外之县尹也。谁获子?”囚曰:“颉遇王子,弱焉。”戌怒,抽戈逐王子围,弗及。楚人以皇颉归。 +印堇父与皇颉戍城麇,楚人囚之,以献于秦。郑人取货于印氏以请之,子大叔为令正,以为请。子产曰:“不获。受楚之功而取货于郑,不可谓国,秦不其然。若曰:‘拜君之勤郑国,微君之惠,楚师其犹在敝邑之城下。’其可。”弗从,遂行。秦人不予。更币,从子产而后获之。 +六月,公会晋赵武、宋向戌、郑良霄、曹人于澶渊以讨卫,疆戚田。取卫西鄙懿氏六十以与孙氏。赵武不书,尊公也。向戌不书,后也。郑先宋,不失所也。于是卫侯会之。晋人执宁喜、北宫遗,使女齐以先归。卫侯如晋,晋人执而囚之于士弱氏。 +秋七月,齐侯、郑伯为卫侯故,如晋,晋侯兼享之。晋侯赋《嘉乐》。国景子相齐侯,赋《蓼萧》。子展相郑伯,赋《缁衣》。叔向命晋侯拜二君曰:“寡君敢拜齐君之安我先君之宗祧也,敢拜郑君之不贰也。”国子使晏平仲私于叔向,曰:“晋君宣其明德于诸侯,恤其患而补其阙,正其违而治其烦,所以为盟主也。今为臣执君,若之何?”叔向告赵文子,文子以告晋侯。晋侯言卫侯之罪,使叔向告二君。国子赋《辔之柔矣》,子展赋《将仲子兮》,晋侯乃许归卫侯。叔向曰:“郑七穆,罕氏其后亡者也。子展俭而壹。” +初,宋芮司徒生女子,赤而毛,弃诸堤下,共姬之妾取以入,名之曰弃。长而美。平公入夕,共姬与之食。公见弃也,而视之,尤。姬纳诸御,嬖,生佐。恶而婉。大子痤美而很,合左师畏而恶之。寺人惠墙伊戾为大子内师而无宠。 +秋,楚客聘于晋,过宋。大子知之,请野享之。公使往,伊戾请从之。公曰:“夫不恶女乎?”对曰:“小人之事君子也,恶之不敢远,好之不敢近。敬以待命,敢有贰心乎?纵有共其外,莫共其内,臣请往也。”遣之。至,则□欠,用牲,加书,征之,而聘告公曰:“大子将为乱,既与楚客盟矣。”公曰:“为我子,又何求?”对曰:“欲速。”公使视之,则信有焉。问诸夫人与左师,则皆曰:“固闻之。”公囚大子。大子曰:“唯佐也能免我。”召而使请,曰:“日中不来,吾知死矣。”左师闻之,聒而与之语。过期,乃缢而死。佐为大子。公徐闻其无罪也,乃亨伊戾。 +左师见夫人之步马者,问之,对曰:“君夫人氏也。”左师曰:“谁为君夫人?余胡弗知?”圉人归,以告夫人。夫人使馈之锦与马,先之以玉,曰:“君之妾弃使某献。”左师改命曰:“君夫人。”而后再拜稽首受之。 +郑伯归自晋,使子西如晋聘,辞曰:“寡君来烦执事,惧不免于戾,使夏谢不敏。”君子曰:“善事大国。” +初,楚伍参与蔡太师子朝友,其子伍举与声子相善也。伍举娶于王子牟,王子牟为申公而亡,楚人曰:“伍举实送之。”伍举奔郑,将遂奔晋。声子将如晋,遇之于郑郊,班荆相与食,而言复故。声子曰:“子行也!吾必复子。”及宋向戌将平晋、楚,声子通使于晋。还如楚,令尹子木与之语,问晋故焉,且曰:“晋大夫与楚孰贤?”对曰:“晋卿不如楚,其大夫则贤,皆卿材也。如杞、梓、皮革,自楚往也。虽楚有材,晋实用之。”子木曰:“夫独无族姻乎?”对曰:“虽有,而用楚材实多。归生闻之:‘善为国者,赏不僭而刑不滥。’赏僭,则惧及淫人;刑滥,则惧及善人。若不幸而过,宁僭无滥。与其失善,宁其利淫。无善人,则国从之。《诗》曰:‘人之云亡,邦国殄瘁。’无善人之谓也。故《夏书》曰:‘与其杀不幸,宁失不经。’惧失善也。《商颂》有之曰:‘不僭不滥,不敢怠皇,命于下国,封建厥福。’此汤所以获天福也。古之治民者,劝赏而畏刑,恤民不倦。赏以春夏,刑以秋冬。是以将赏,为之加膳,加膳则饫赐,此以知其劝赏也。将刑,为之不举,不举则彻乐,此以知其畏刑也。夙兴夜寐,朝夕临政,此以知其恤民也。三者,礼之大节也。有礼无败。今楚多淫刑,其大夫逃死于四方,而为之谋主,以害楚国,不可救疗,所谓不能也。子仪之乱,析公奔晋。晋人置诸戎车之殿,以为谋主。绕角之役,晋将遁矣,析公曰:‘楚师轻窕,易震荡也。若多鼓钧声,以夜军之,楚师必遁。’晋人从之,楚师宵溃。晋遂侵蔡,袭沈,获其君;败申、息之师于桑隧,获申丽而还。郑于是不敢南面。楚失华夏,则析公之为也。雍子之父兄谮雍子,君与大夫不善是也。雍子奔晋。晋人与之鄐,以为谋主。彭城之役,晋、楚遇于靡角之谷。晋将遁矣。雍子发命于军曰:‘归老幼,反孤疾,二人役,归一人,简兵搜乘,秣马蓐食,师陈焚次,明日将战。’行归者而逸楚囚,楚师宵溃。晋绛彭城而归诸宋,以鱼石归。楚失东夷,子辛死之,则雍子之为也。子反与子灵争夏姬,而雍害其事,子灵奔晋。晋人与之邢,以为谋主。扞御北狄,通吴于晋,教吴判楚,教之乘车、射御、驱侵,使其子孤庸为吴行人焉。吴于是伐巢、取驾、克棘、入州来,楚罢于奔命,至今为患,则子灵之为也。若敖之乱,伯贲之子贲皇奔晋。晋人与之苗,以为谋主。鄢陵之役,楚晨压晋军而陈,晋将遁矣。苗贲皇曰:‘楚师之良,在其中军王族而已。若塞井夷灶,成陈以当之,栾、范易行以诱之,中行、二郤必克二穆。吾乃四萃于其王族,必大败之。’晋人从之,楚师大败,王夷师熠,子反死之。郑叛吴兴,楚失诸侯,则苗贲皇之为也。”子木曰:“是皆然矣。”声子曰:“今又有甚于此。椒举娶于申公子牟,子牟得戾而亡,君大夫谓椒举:‘女实遣之!’惧而奔郑,引领南望曰:‘庶几赦余!’亦弗图也。今在晋矣。晋人将与之县,以比叔向。彼若谋害楚国,岂不为患?”子木惧,言诸王,益其禄爵而复之。声子使椒鸣逆之。 +许灵公如楚,请伐郑,曰:“师不兴,孤不归矣!”八月,卒于楚。楚子曰:“不伐郑,何以求诸侯?”冬十月,楚子伐郑。郑人将御之,子产曰:“晋、楚将平,诸侯将和,楚王是故昧于一来。不如使逞而归,乃易成也。夫小人之性,衅于勇,啬于祸,以足其性而求名焉者,非国家之利也。若何从之?”子展说,不御寇。十二月乙酉,入南里,堕其城。涉于乐氏,门于师之梁。县门发,获九人焉。涉入汜而归,而后葬许灵公。 +卫人归卫姬于晋,乃释卫侯。君子是以知平公之失政也。 +晋韩宣子聘于周。王使请事。对曰:“晋士起将归时事于宰旅,无他事矣。”王闻之曰:“韩氏其昌阜于晋乎!辞不失旧。” +齐人城郏之岁,其夏,齐乌余以廪丘奔晋,袭卫羊角,取之;遂袭我高鱼。有大雨,自其窦入,介于其库,以登其城,克而取之。又取邑于宋。于是范宣子卒,诸侯弗能治也,及赵文子为政,乃卒治之。文子言于晋侯曰:“晋为盟主。诸侯或相侵也,则讨而使归其地。今乌余之邑,皆讨类也,而贪之,是无以为盟主也。请归之!”公曰:“诺。孰可使也?”对曰:“胥梁带能无用师。”晋侯使往。 +译文 +二十六年春季,秦景公的弟弟鍼去到晋国重温盟约,叔向命令召唤行人子员。行人子朱说:“朱是值班的。”说了三次,叔向不答理。子朱生气,说:“职位级别相同,为什么在朝廷上不用朱?”拿着剑跟上去。叔向说:“秦国和晋国不和睦已经很久了。今天的事情,幸而成功,晋国依靠着它。不成功,就要打仗。子员沟通两国的话没有私心,您却常常违背原意。用邪恶来事奉国君的人,我是能够抵抗的。”提起衣服跟上去,被别人止住了。晋平公说:“晋国差不多要大治了吧!我的臣下所争执的是大问题。”师旷说:“公室的地位怕要下降。臣下不在心里竞争而用力量来争夺,不致力于德行而争执是非,个人的欲望太大,公室的地位能不下降吗?” +卫献公派子鲜为自己谋求再登君位,子鲜辞谢。他们的母亲敬姒一定要子鲜去,子鲜回答说:“国君没有信用,下臣害怕不能免于祸难。”敬姒说:“尽管这样,为了我的缘故,你还是去干吧!”子鲜答应了。当初,献公派人和宁喜谈这件事,宁喜说:“一定要子鲜在场。不这样,事情必然失败。”所以献公派遣,子鲜。子鲜没有得到敬姒的指示,就把献公的命令告诉宁氏,说:“如果回国,政权由宁氏主持,祭祀则由我主持。”宁喜告诉蘧伯玉。蘧伯玉说:“瑷没有能听到国君的出走,岂敢听到他的进入?”于是蘧伯玉就起程,从近处的城门出走。宁喜告诉右宰穀。右宰穀说:“不行。得罪了两个国君,天下谁能收容你?”宁喜说:“我在先人那里接受了命令,不能三心二意。”右宰穀说:“我请求出使去观望一下。”于是就在夷仪进见献公。回来,说:“国君逗留在外已十二年了,却没有忧愁的样子,也没有宽容的话,还是那样一个人。如果不停止原复君计划,我们离死就没有几天了。”宁喜说:“有子鲜在那里。”右宰穀说:“子鲜在那里,有什么用处?至多不过他自己逃亡,又能为我们做些什么呢?”宁喜说:“尽管这样,不能停止了。孙文子在戚地,孙嘉去齐国聘问,孙襄留守在都城家里。 +二月初六日,宁喜、右宰穀进攻孙氏,没有取胜。孙襄受伤。宁喜退出城住在郊外。孙襄死了,孙家的人在夜里号哭。城里的人们召唤宁喜,宁喜再次攻打孙氏,攻克了。初七日,杀死了卫侯剽和太子角。《春秋》记载说:“宁喜弑其君剽”,这是说罪过在宁氏。孙林父以戚邑去投靠晋国。《春秋》记载说“入于戚以叛”,这是归罪于孙氏。臣下的俸禄,实在是为国君所有的。合于道义就往前进,不合于道义就保全身子引退。把俸禄作为私有,并以此和人打交道,应该受到诛戮。 +初十日,卫献公进入都城,《春秋》记载说“复归”,这表示本国人让他回来。大夫在国境上迎接的,卫献公拉着他们的手跟他们说话;在大路上迎接的,卫献公从车上向他们作揖;在城门口迎接的,卫献公点点头而已。卫献公一到达,就派人责备太叔文子说:“寡人流亡在外边,几位大夫都使寡人早早晚晚听到卫国的消息,大夫独独不问候寡人。古人有话说:‘不是应该怨恨的,不要怨恨。’寡人可要怨恨了。”太叔文子回答说:“下臣知道罪过了。下臣没有才能,不能背着马笼头马缰绳跟随君王保护财物,这是下臣的第一条罪状。有人在国外,有人在国内,下臣不能三心二意,传递里外的消息来事奉君王,这是下臣的第二条罪状。有两条罪状,岂敢忘记一死?”于是就出走,从近处的城门出国。卫献公派人阻止了他。 +卫国侵袭戚地的东部边境,孙氏向晋国控告,晋国派兵戍守茅氏,殖绰进攻茅氏杀了晋国守兵三百个人。孙蒯追赶殖绰,不敢攻击。孙文子说:“你连恶鬼都不如。”孙蒯就跟上卫军,在圉地打败了他们。雍鉏俘虏了殖绰。孙氏再次向晋国控告。 +郑简公赏赐攻入陈国有功劳的人。三月初一日,设享礼招待子展,赐给他先路和三命车服,然后再赐给他八个城邑。赐给子产次路和再命车服,然后再赐给他六个城邑。子产辞去城邑,说:“从上而下,礼数以二的数目递降,这是规定。下臣的地位在第四,而且这是子展的功劳,下臣不敢受到赏赐的礼仪,请求辞去城邑。”郑简公坚决要给他,他就接受了三个城邑。公孙挥说:“子产恐怕将要主持政事了。谦让而不失去礼仪。” +晋国人为了孙氏的缘故,召集诸侯,准备讨伐卫国。夏季,中行穆子来鲁国聘问,这是为了召请鲁襄公。 +楚康王、秦国人联兵侵袭吴国,到达雩娄,听到吴国有了准备而退回,就乘机入侵郑国。五月,到达城虞。郑国的皇颉在城糜戍守,出城,和楚军作战,战败。穿封戌俘虏了皇颉,公子围和他争功,要伯州犁主持公正。伯州犁说:“请问一下俘虏。”于是就让俘虏站在前面。伯州犁悦:“所争夺的对象便是您,您是君子,有什么不明白的?”举起手,说:“那一位是王子围,是寡君的尊贵的弟弟。”放下手,说:“这个人是穿封戌,是方城山外边的县尹。谁俘虏您了?”俘虏说:“颉碰上王子,抵抗不住,”穿封戌发怒,抽出戈追赶王子围,没有追上。楚国人带着皇颉回去。 +印堇父和皇颉一起留守在城麇,楚国人囚禁印堇父,把他献给秦国。郑国人在印氏那里拿了财货向秦国请求赎回印堇父,子太叔正做令正,为他们提出请求赎回的话。子产说:“这样是不能得到印堇父的。秦国接受了楚国奉献的俘虏,却在郑国拿财物,不能说合于国家的体统,秦国不会这样做的。如果说‘拜谢君王帮助郑国。如果没有君王的恩惠,楚军恐怕还在敝邑城下’,这才可以。”子太叔不听,就动身了。秦国人不给,把财物改为其他礼品,按照子产的话去说,然后得到了印堇父。 +六月,鲁襄公和晋国赵武、宋国向戌、郑国良霄、曹国人在澶渊会见,以讨伐卫国,划正戚地的疆界。占领了卫国西部边境懿氏六十邑给了孙氏。《春秋》对赵武不加记载,这是由于尊重鲁襄公。对向戌不加记载,这是由于他到迟了。记载郑国在宋国之前,是由于郑国人如期到达。当时卫献公参加了会见。晋国人拘捕了宁喜、北宫遗,让女齐带了他们先回去。卫献公去到晋国,晋国人抓了他关闭在士弱家里。 +秋季,七月,齐景公、郑简公为了卫献公的缘故去到晋国,晋平公同时设享礼招待他们。晋平公赋《嘉乐》这首诗。国景子做齐景公的相礼者,赋《蓼萧》这首诗。子展做郑简公的相礼者,赋《缁衣》这首诗。叔向要晋平公向两位国君下拜,说:“寡君谨敢拜谢齐国国君安定我国先君的宗庙,谨敢拜谢郑国国君没有二心。”国景子派晏平仲私下对叔向说:“晋国国君在诸侯之中宣扬他的明德,担心他们的忧患而补正他们的过失,纠正他们的违礼,而治理他们的动乱,因此才能作为盟主。现在为了臣下而逮了国君,怎么办?”叔向告诉赵文子,赵文子把这些话告诉晋平公。晋平公举出卫献公的罪过,派叔向告诉齐、郑二国国君。国景子赋《辔之柔矣》这首诗,子展赋《将仲子兮》这首诗,晋平公于是就允许让卫献公回国。叔向说:“郑穆公的后代七个家族,罕氏大概是最后灭亡的,因为子展节俭而用心专一。” +当初,宋国的芮司徒生了女儿,皮肤红而且长着毛,就把她丢在堤下。共姬的侍妾把她拣进宫来,命名叫做弃。长大了很漂亮。宋平公向共姬问候晚安,共姬让他吃东西。平公见了弃,细看,觉得漂亮极了。共姬就把她送给平公做侍妾,受到宠爱,生了佐。佐长得难看,但性情和顺。太子痤长得漂亮,但心里狠毒,向戌对他又害怕又讨厌。寺人惠墙伊戾做太子的内师而不受宠信。 +秋季,楚国的客人到晋国聘问,经过宋国。太子和楚国的客人原来相识,请求在野外设宴招待他,平公让他去了。伊戾请求跟从太子。平公说:“他不讨厌你吗?”伊戾回答说:“小人事奉君子,被讨厌不敢远离,被喜欢不敢亲近,恭敬地等待命令,岂敢有三心二意呢?太子那里即使有人在外边服务,却没有人在里边服务,下臣请求前去。”平公就派他去了。到那里,就挖坑,用牺牲,把盟书放在牲口上,并且检查一遍,驰马回来报告平公,说“太子将要作乱,已经和楚国的客人结盟了。”宋平公说:“已经是我的继承人了,还谋求什么?”伊戾回答说:“想快点即位。”平公派人去视察,果然有这回事。向夫人和左师询问,他们都说:“的确听到过。”宋平公囚禁了太子。太子说:“只有佐能够使我免于祸难。”召请佐并让他向平公请求,说:“到中午还不来,我知道应该死了。”左师向戌听到了,就和佐说个不停。过了中午,太子就上吊死了。佐被立为太子。宋平公慢慢地听到痤没有罪,就把伊戾烹杀了。 +左师见到夫人的溜马人,就问他是什么人。溜马人说:“我是君夫人家的人。”左师说:“谁是君夫人?我为什么不知道?”溜马的人回去,把这话报告夫人。夫人派人送给左师锦和马,先送去玉,说“国君的侍妾弃让我送给您的。”左师改换口气说:“君夫人”,然后再拜叩头接受了。 +郑简公从晋国回来,派子西去到晋国聘问,致辞说:“寡君来麻烦执事,害怕不敬而不免于有罪,特派夏前来表示歉意。”君子说:“郑国善于事奉大国。” +当初,楚国的伍参和蔡国的太师子朝友好,他的儿子伍举和声子也互相友好。伍举娶了王子牟的女儿。王子牟为申公而逃亡,楚国人说:“伍举确实护送了他。”伍举逃亡到郑国,准备乘机再到晋国。声子打算去到晋国,在郑国郊外碰到了他,把草铺在地上一起吃东西,谈到回楚国去的事,声子说:“您走吧,我一定让您回去。”等到宋国的向戌准备调解晋国和楚国的关系,声子出使到晋国,回到楚国,令尹子木和他谈话,询问晋国的情况,而且说:“晋国的大夫和楚国的大夫谁更贤明?”声子回答说:“晋国的卿不如楚国,晋国的大夫是贤明的,都是当卿的人材。好像杞木、梓木、皮革,都是楚国运去的。虽然楚国有人才,晋国却实在使用了他们。”子木说:“他们没有同宗和亲戚吗?”声子回答说: +“虽然有,但使用楚国的人材确实多。归生听说:善于为国家做事的,赏赐不过分,而刑罚不滥用。赏赐过分,就怕及于坏人;刑罚滥用,就怕牵涉好人。如果不幸而过分了,宁可过分,不要滥用。与其失掉好人,宁可利于坏人。没有好人,国家就跟着受害。《诗》说,‘这个能人不在,国家就遭受灾害’,这就是说没有好人。所以《夏书》说:‘与其杀害无辜的人,宁可对罪人失于刑罚’,这就是怕失掉好人。《商颂》有这样的话说,‘不过分不滥用,不敢懈怠偷闲,向下国发布命令,大大地建立他的福禄’。这就是汤所以获得上天赐福的原因。古代治理百姓的人,乐于赏赐而怕用刑罚,为百姓担扰而不知疲倦。在春天、夏天行赏,在秋季、冬季行刑。因此,在将要行赏的时候就为它增加膳食,加膳以后可以把剩菜大批赐给下面,由于这样而知道他乐于赏赐。将要行刑的时候就为它减少膳食,减了膳食就撤去音乐,由于这样而知道他怕用刑罚。早起晚睡,早晚都亲临办理国事,由于这样而知道他为百姓操心。这三件事,是礼仪的大关键。讲求礼仪就不会失败。现在楚国滥用刑罚,楚国的大夫逃命到四方的国家,并且做别国的主要谋士,来危害楚国,至于不可救药了,这就是说的滥用刑罚不能容忍。子仪的叛乱,析公逃亡到晋国,晋国人把他安置在晋侯战车的后面,让他作为主要谋士。绕角那次战役,晋国人将要逃走,析公说:‘楚军不厚重,容易被震动。如果同时敲打许多鼓发出大声,在夜里全军进攻,楚军必然会逃走。’晋国人听从了,楚军夜里崩溃。晋国于是就侵入蔡国,袭击沈国,俘虏了沈国的国君,在桑隧打败申国和息国军队,俘虏了申丽而回国。郑国在那时候不敢向着南方的楚国。楚国丧失了中原,这就是析公干出来的。 +“雍子的父亲的哥哥诬陷雍子,国君和大夫不为他们去调解,雍子逃亡到晋国,晋国人将鄐地给了他,让他作为主要谋士。彭城那次战役,晋国、楚国在靡角之谷相遇。晋国人将要逃走了,雍子对军队发布命令说:‘年纪老的和年纪小的都回去,孤儿和有病的也都回去,兄弟两个服役的回去一个。精选徒兵,检阅车兵,喂饱马匹,让兵士吃饱,军队摆开阵势,焚烧帐篷,明天将要决战。’让该回去的走开,并且故意放走楚国俘虏,楚军夜里崩溃。晋国降服了彭城而归还给宋国,带了鱼石回国。楚国失去东夷,子辛为此战而阵亡,这都是雍子所谋划的。 +“子反和子灵争夺夏姬而阻碍子灵的婚事,子灵逃亡到晋国,晋国人将邢地给了他,让他作为谋士,抵御北狄,让吴国和晋国通好,教吴国背叛楚国,教他们坐车、射箭、驾车作战,让他的儿子狐庸做了吴国的行人。吴国在那时候时进攻巢地、占取驾地、攻下棘地、进入州来,楚国疲于奔命,到今天还是祸患,这就是子灵干出来的。若敖的叛乱,伯贲的儿子贲皇逃亡到晋国,晋国人封给他苗地,让他作为主要谋士。鄢陵那次战役,楚军早晨逼近晋军并摆开阵势,晋国人就要逃走了。苗贲皇说:‘楚军的精锐在于他们中军的王族而已,如果填井平灶,摆开阵势以抵挡他们,栾、范用家兵引诱楚军,中行和郤锜、郤至一定能够战胜子重、子辛。我们就用四军集中对付他们的王族,一定能够把他们打得大败。’晋国人听从了,楚军大败,君王受伤,军队士气不振,子反为此而死。郑国背叛,吴国兴起,楚国失去诸侯,这就是苗贲皇干出来的。” +子木说:“阁下所说的都是那样的。”声子说:“现在又有比这厉害的。椒举娶了申公子牟的女儿,子牟得罪而逃亡。国君和大夫对椒举说:‘实在是你让他走的。’椒举害怕而逃亡到郑国,伸长了脖子望着南方,说:‘也许可以赦免我。’但是我们也不存希望。现在他在晋国了。晋国人将要把县封给他,以和叔向并列。他如果要危害楚国,难道不是祸患?”子木听了这些很恐惧,对楚康王说了,楚康王提高了椒举的官禄爵位而让他官复原职。声子让椒鸣去迎接椒举。 +许灵公去到楚国,请求进攻郑国,说:“不发兵,我就不回去了。”八月,许灵公死在楚国。楚康王说:“不攻打郑国,怎么能求得诸侯?” +冬季,十月,楚康王攻打郑国,郑国人准备抵御。子产说:“晋国将要和楚国讲和,诸侯将要和睦,楚康王因此冒昧来这一趟。不如让他称心回去,就容易讲和了。小人的本性,一有空子就凭血气之勇,在祸乱中有所贪图,以满足他的本性而追求虚名,这不符合国家的利益,怎么可以听从?”子展高兴了,就不抵御敌人,十二月初五日,楚军进入南里,拆毁城墙。从乐氏渡过洧水,进攻师之梁的城门。放下内城的闸门,俘虏了九个不能进城的郑国人。楚国人渡过汜水回国,然后安葬许灵公。 +卫国人把卫姬送给晋国,晋国这才释放了卫献公。君子因此而知道晋平公失去了治国的常道。 +晋国的韩宣子在成周聘问,周灵王派人请问明来意。韩宣子回答说:“晋国的士起前来向宰旅奉献贡品,没有别的事情。”周天子听到了,说:“韩氏恐怕要在晋国昌盛了吧!他的辞令仍和过去一样。” +齐国人在郏地筑城的那一年,夏季,齐国的乌馀带着廪丘逃亡到晋国,袭击卫国的羊角,占取了这地方,就乘机侵袭我国的高鱼。正逢下大雨,齐军从城墙的排水孔进入城中,走到城里的武器库,取出了甲胄装备士兵,然后登上城墙,攻克并占领了高鱼。又占取了宋国的城邑。当时范宣子已经死了,诸侯不能惩治乌馀。等到赵文子执政以后,才终于把他惩治了。赵文子对晋平公说:“晋国作为盟主,诸侯有人互相侵犯,就要讨伐他。让他归还侵夺的土地。现在乌馀的城邑,都是侵夺来的,属于应该讨伐之列,而我们贪图它,这就没有资格作盟主了。请归还给诸侯。”晋平公说:“好。谁可以做使者?”赵文子回答说:“胥梁带能够不用兵而完成任务。”晋平公就派胥梁带前去。 + +襄公二十七年 +【经】二十有七春,齐侯使庆封聘。夏,叔孙豹会晋赵武、楚屈建、蔡公孙归生、卫石恶、陈孔奂、郑良霄、许人、曹人于宋。卫杀其大夫宁喜。卫侯之弟鱄出奔晋。秋七月辛巳,豹及诸侯之大夫盟于宋。冬十有二月乙卯朔,日有食之。 +【传】二十七年春,胥梁带使诸丧邑者具车徒以受地,必周。使乌余车徒以受封,乌余以众出。使诸侯伪效乌余之封者,而遂执之,尽获之。皆取其邑而归诸侯,诸侯是以睦于晋。 +齐庆封来聘,其车美。孟孙谓叔孙曰:“庆季之车,不亦美乎?”叔孙曰:“豹闻之:‘服美不称,必以恶终。’美车何为?”叔孙与庆封食,不敬。为赋《相鼠》,亦不知也。卫宁喜专,公患之。公孙免余请杀之。公曰:“微宁子不及此,吾与之言矣。事未可知,只成恶名,止也。”对曰:“臣杀之,君勿与知。”乃与公孙无地、公孙臣谋,使攻宁氏。弗克,皆死。公曰:“臣也无罪,父子死余矣!”夏,免余复攻宁氏,杀宁喜及右宰谷,尸诸朝。石恶将会宋之盟,受命而出。衣其尸,枕之股而哭之。欲敛以亡,惧不免,且曰:“受命矣。”乃行。 +子鲜曰:“逐我者出,纳我者死,赏罚无章,何以沮劝?君失其信,而国无刑。不亦难乎!且鱄实使之。”遂出奔晋。公使止之,不可。及河,又使止之。止使者而盟于河,托于木门,不乡卫国而坐。木门大夫劝之仕,不可,曰:“仕而废其事,罪也。从之,昭吾所以出也。将准愬乎?吾不可以立于人之朝矣。”终身不仕。公丧之,如税服,终身。 +公与免余邑六十,辞曰:“唯卿备百邑,臣六十矣。下有上禄,乱也,臣弗敢闻。且宁子唯多邑,故死。臣惧死之速及也。”公固与之,受其半。以为少师。公使为卿,辞曰:“大叔仪不贰,能赞大事。君其命之!”乃使文子为卿。 +宋向戌善于赵文子,又善于令尹子木,欲弭诸侯之兵以为名。如晋,告赵孟。赵孟谋于诸大夫,韩宣子曰:“兵,民之残也,财用之蠹,小国之大灾也。将或弭之,虽曰不可,必将许之。弗许,楚将许之,以召诸侯,则我失为盟主矣。”晋人许之。如楚,楚亦许之。如齐,齐人难之。陈文子曰:“晋、楚许之,我焉得已。且人曰弭兵,而我弗许,则固携吾民矣!将焉用之?”齐人许之。告于秦,秦亦许之。皆告于小国,为会于宋。 +五月甲辰,晋赵武至于宋。丙午,郑良霄至。六月丁未朔,宋人享赵文子,叔向为介。司马置折俎,礼也。仲尼使举是礼也,以为多文辞。戊申,叔孙豹、齐庆封、陈须无、卫石恶至。甲寅,晋荀盈从赵武至。丙辰,邾悼公至。壬戌,楚公子黑肱先至,成言于晋。丁卯,宋戌如陈,从子木成言于楚。戊辰,滕成公至。子木谓向戌:“请晋、楚之从交相见也。”庚午,向戌复于赵孟。赵孟曰:“晋、楚、齐、秦,匹也。晋之不能于齐,犹楚之不能于秦也。楚君若能使秦君辱于敝邑,寡君敢不固请于齐?”壬申,左师复言于子木。子木使馹谒诸王,王曰:“释齐、秦,他国请相见也。”秋七月戊寅,左师至。是夜也,赵孟及子皙盟,以齐言。庚辰,子木至自陈。陈孔奂、蔡公孙归生至。曹、许之大夫皆至。以藩为军,晋、楚各处其偏。伯夙谓赵孟曰:“楚氛甚恶,惧难。”赵孟曰:“吾左还,入于宋,若我何?” +辛巳,将盟于宋西门之外,楚人衷甲。伯州犁曰:“合诸侯之师,以为不信,无乃不可乎?夫诸侯望信于楚,是以来服。若不信,是弃其所以服诸侯也。”固请释甲。子木曰:“晋、楚无信久矣,事利而已。苟得志焉,焉用有信?”大宰退,告人曰:“令尹将死矣,不及三年。求逞志而弃信,志将逞乎?志以发言,言以出信,信以立志,参以定之。信亡,何以及三?”赵孟患楚衷甲,以告叔向。叔向曰:“何害也?匹夫一为不信,犹不可,单毙其死。若合诸侯之卿,以为不信,必不捷矣。食言者不病,非子之患也。夫以信召人,而以僭济之。必莫之与也,安能害我?且吾因宋以守病,则夫能致死,与宋致死,虽倍楚可也。子何惧焉?又不及是。曰弭兵以召诸侯,而称兵以害我,吾庸多矣,非所患也。” +季武子使谓叔孙以公命,曰:“视邾、滕。”既而齐人请邾,宋人请滕,皆不与盟。叔孙曰:“邾、滕,人之私也;我,列国也,何故视之?宋、卫,吾匹也。”乃盟。故不书其族,言违命也。 +晋、楚争先。晋人曰:“晋固为诸侯盟主,未有先晋者也。”楚人曰:“子言晋、楚匹也,若晋常先,是楚弱也。且晋、楚狎主诸侯之盟也久矣!岂专在晋?”叔向谓赵孟曰:“诸侯归晋之德只,非归其尸盟也。子务德,无争先!且诸侯盟,小国固必有尸盟者。楚为晋细,不亦可乎?”乃先楚人。书先晋,晋有信也。 +壬午,宋公兼享晋、楚之大夫,赵孟为客。子木与之言,弗能对。使叔向侍言焉,子木亦不能对也。 +乙酉,宋公及诸侯之大夫盟于蒙门之外。子木问于赵孟曰:“范武子之德何如?”对曰:“夫人之家事治,言于晋国无隐情。其祝史陈信于鬼神,无愧辞。”子木归,以语王。王曰:“尚矣哉!能歆神人,宜其光辅五君以为盟主也。”子木又语王曰:“宜晋之伯也!有叔向以佐其卿,楚无以当之,不可与争。”晋荀寅遂如楚莅盟。 +郑伯享赵孟于垂陇,子展、伯有、子西、子产、子大叔、二子石从。赵孟曰:“七子从君,以宠武也。请皆赋以卒君贶,武亦以观七子之志。”子展赋《草虫》,赵孟曰:“善哉!民之主也。抑武也不足以当之。”伯有赋《鹑之贲贲》,赵孟曰:“床第之言不逾阈,况在野乎?非使人之所得闻也。”子西赋《黍苗》之四章,赵孟曰:“寡君在,武何能焉?”子产赋《隰桑》,赵孟曰:“武请受其卒章。”子大叔赋《野有蔓草》,赵孟曰:“吾子之惠也。”印段赋《蟋蟀》,赵孟曰:“善哉!保家之主也,吾有望矣!”公孙段赋《桑扈》,赵孟曰:“‘匪交匪敖’,福将焉往?若保是言也,欲辞福禄,得乎?”卒享。文子告叔向曰:“伯有将为戮矣!诗以言志,志诬其上,而公怨之,以为宾荣,其能久乎?幸而后亡。”叔向曰:“然。已侈!所谓不及五稔者,夫子之谓矣。”文子曰:“其馀皆数世之主也。子展其后亡者也,在上不忘降。印氏其次也,乐而不荒。乐以安民,不淫以使之,后亡,不亦可乎?” +宋左师请赏,曰:“请免死之邑。”公与之邑六十。以示子罕,子罕曰:“凡诸侯小国,晋、楚所以兵威之。畏而后上下慈和,慈和而后能安靖其国家,以事大国,所以存也。无威则骄,骄则乱生,乱生必灭,所以亡也。天生五材,民并用之,废一不可,谁能去兵?兵之设久矣,所以威不轨而昭文德也。圣人以兴,乱人以废,废兴存亡昏明之术,皆兵之由也。而子求去之,不亦诬乎?以诬道蔽诸侯,罪莫大焉。纵无大讨,而又求赏,无厌之甚也!”削而投之。左师辞邑。向氏欲攻司城,左师曰:“我将亡,夫子存我,德莫大焉,又可攻乎?”君子曰:“‘彼己之子,邦之司直。’乐喜之谓乎?‘何以恤我,我其收之。’向戌之谓乎?” +齐崔杼生成及强而寡。娶东郭姜,生明。东郭姜以孤入,曰棠无咎,与东郭偃相崔氏。崔成有病,而废之,而立明。成请老于崔,崔子许之。偃与无咎弗予,曰:“崔,宗邑也,必在宗主。”成与强怒,将杀之。告庆封曰:“夫子之身亦子所知也,唯无咎与偃是从,父兄莫得进矣。大恐害夫子,敢以告。”庆封曰:“子姑退,吾图之。”告卢蒲弊。卢蒲弊曰:“彼,君之仇也。天或者将弃彼矣。彼实家乱,子何病焉!崔之薄,庆之厚也。”他日又告。庆封曰:“苟利夫子,必去之!难,吾助女。” +九月庚辰,崔成、崔强杀东郭偃、棠无咎于崔氏之朝。崔子怒而出,其众皆逃,求人使驾,不得。使圉人驾,寺人御而出。且曰:“崔氏有福,止余犹可。”遂见庆封。庆封曰:“崔、庆一也。是何敢然?请为子讨之。”使卢蒲弊帅甲以攻崔氏。崔氏堞其宫而守之,弗克。使国人助之,遂灭崔氏,杀成与强,而尽俘其家。其妻缢。弊覆命于崔子,且御而归之。至,则无归矣,乃缢。崔明夜辟诸大墓。辛巳,崔明来奔,庆封当国。 +楚薳罢如晋莅盟,晋将享之。将出,赋《既醉》。叔向曰:“薳氏之有后于楚国也,宜哉!承君命,不忘敏。子荡将知政矣。敏以事君,必能养民。政其焉往?” +崔氏之乱,申鲜虞来奔,仆赁于野,以丧庄公。冬,楚人召之,遂如楚为右尹。 +十一月乙亥朔,日有食之。辰在申,司历过也,再失闰矣。 +译文 +二十七年春季,胥梁带让失去城邑的那些国家准备好车兵徒兵来接受土地,行动必须周密。让乌馀准备车兵来接受封地。乌馀带领他的一批人出来,胥梁带让诸侯假装把土地送给乌馀,因而乘乌馀不备而加以逮捕,全部俘虏了他们。把乌馀的城邑都夺了回来,还给诸侯,诸侯因此归向晋国。 +齐国的庆封来鲁国聘问,他的车子很漂亮。盂孙对叔孙说:“庆封的车子,不也很漂亮么!”叔孙说:“豹听说:‘衣饰和人不相称,必然得到恶果。’漂亮的车子有什么用?”叔孙设便宴招待庆封,庆封表现得不恭敬。叔孙为他赋《相鼠》这首诗,他也不明白其中的意思。 +卫国的甯喜把持朝政,卫献公担心这件事,公孙免馀请求杀死甯喜。卫献公说:“如果没有甯子,我不能到这地步。我已经对他说过了‘政由甯氏’。事情的结果不能知道,只是得到坏名声,不能做。”公孙免馀回答说:“下臣去杀他,君王不要参与计划就行了。”就和公孙无地、公孙臣商量,让他们攻打甯氏,没有攻下,公孙无地和公孙臣都因此战死了。卫献公说:“臣是没有罪的,父子二人都为我而死了!”夏季,公孙免馀再次攻打甯氏,杀死了甯喜和右宰穀,陈尸在朝廷上。石恶将要参加宋国的结盟,接受了命令而出来,给尸首穿上衣服,头枕在尸体的大腿上而为他们号哭,想要入殓以后自己逃亡,又害怕不能免于祸难,姑且说:“接受使命了。”于是就动身走了。 +子鲜说:“驱逐我的逃亡了,接纳我的死去了,赏罚没有章程,如何禁止为恶和勉励为善?国君失掉他的信用而国家没有正常的刑罚,不也很难了吗?而且鱄实在是让甯喜这么做的。”子鲜说完这话就逃亡到晋国去。卫献公让人阻止他,不行。子鲜到达黄河,卫献公又派人阻止他。他不让使者前进,而向黄河发誓。子鲜寄住在木门,坐着都不肯面对着卫国。木门大夫劝他做官,他不同意,说:“做官而废弃自己的职责,这是罪过;要尽自己的职责,这就宣扬了我逃亡的原因。我将要向谁诉说呢?我不能够立在别人的朝廷上了。”一辈子也不出来做官。卫献公为他服丧一直到死。 +卫献公给公孙免馀六十个城邑,他辞谢说:“只有卿才具备一百个城邑,下臣已经有六十个邑了。下面的人而有了上面的人的禄位,这是祸乱。下臣不敢听到这种事。而且甯子就因为城邑多了,所以死了,下臣害怕死期快到。”卫献公一定要给他,他接受了一半。让他做了少师。卫献公让他做卿,他辞谢说:“太叔仪没有二心,能够赞助大事,君王还是任命他吧。”于是就让太叔仪做了卿。 +宋国的向戌和赵文子友好,又和令尹子木友好,想要停止诸侯之间的战争以取得名声。他去到晋国,告诉了赵文子。赵文子和大夫们商量。韩宣子说:“战争,是残害百姓的祸事,是财货的蛀虫,是小国的大灾难,有人要消除它,虽然说办不到,一定要答应。不答应,楚国将会答应,用来号召诸侯,那么我国就失去盟主的地位了。”晋国人答应了向戌。向戌又去楚国,楚国也答应了。去到齐国,齐国人感到为难。陈文子说:“晋国、楚国答应了,我们怎么能够不答应?而且别人说‘消灭战争’,而我们不答应,那么就使我们的百姓离心了,将要怎么使用他们?”齐国人答应了。告诉秦国,秦国也答应了。这四个国家都通告小国,在宋国举行会见。 +五月二十七日,晋国的赵文子到达宋国。二十九日,郑国的良霄也来了。六月初一日,宋国人设享礼招待赵文子,叔向作为赵文子的副手。司马把煮熟的牲畜切成碎块,放在盘子里,这是合于礼的。以后孔子看到了这次礼仪的记载,认为文辞太多。初二日,叔孙豹、齐国的庆封、陈须无、卫国的石恶到达。初八日,晋国的荀盈跟随赵文子之后到达。初十日,邾悼公到达。十六日,楚国的公子黑肱先到达,和晋国商定了有关的条件。二十一日,宋国的向戌去到陈国,和子木商定有关楚国的条件。二十二日,滕成公到达。子木告诉向戌,请求跟从晋国和楚国的国家互相见面。二十四日,向戌向赵文子复命。赵文子说:“晋、楚、齐、秦四国地位对等,晋国不能指挥齐国,如同楚国不能指挥秦国一样。楚国国君如果能让秦国国君驾临敝邑,寡君岂敢不坚决向齐国国君请求?”二十六日,向戌向子木复命,子木派传车请示楚康王。楚康王说:“放下齐国、秦国,请求和其他国家互相见面。”秋季,七月初二日,向戌到达。当夜,赵文子和公子黑肱统一了盟书的措辞。初四日,子木从陈国到达。陈国的孔奂、蔡国的公孙归生到达。曹国和许国的大夫也都来到。各国军队用篱笆做墙作为分界。晋国和楚国各自驻扎在两头。伯夙对赵文子说:“楚国的气氛很不好,恐怕会发生患难。”赵文子说:“我们转折向左,进入宋国,能把我们怎么办?” +初五日,各诸侯国代表准备在宋国西门外边结盟。楚国人在外衣里边穿上皮甲。伯州犁说:“会合诸侯的军队,而做别人不信任的事,恐怕不可以吧,诸侯盼望得到楚国的信任,因此前来顺服。如果不信任别人,这就是丢掉了所用来使诸侯顺服的东西了。”他坚决请求脱去皮甲。子木说:“晋国和楚国缺乏信用已经很久了,唯有去做对我有利的事就是了。如果能如愿,哪里用得着有信用?”伯州犁退下去。对人说:“令尹将要死了,不会到三年。但求满足意志而丢弃信用,意志会满足吗?有意志就形成为语言,有语言就要有信用,有信用就加强意志。这三件事互相关联统一,然后才能确定。信用丢掉了,怎么能活到三年呢?” 赵文子担心楚国人外衣里边穿皮甲,把这情形告诉了叔向。叔向说:“有什么危害?一个普通人一旦做出不守信用的事,尚且不可以,都不得好死。如果一个会合诸侯的卿做出不守信用的事情,就必然不能成功了。说话不算数的人不能给人造成困难,这不是您的祸患。用信用召集别人,而又利用了虚伪,必然没有人同意他,哪里能危害我们?而且我们依靠着宋国来防守他们制造的困难,那就能人人舍命。和宋军一起誓死对抗,即使楚军增加一倍也是可以抵抗的,您有什么可害怕的呢?但是事情又不至于到这一步。口称消除战争以召集诸侯,反而发动战争来危害我们,我们的用处就多了,不必担心。” +季武子派人以鲁襄公的名义对叔孙豹说:“把我国比作和邾国、滕国小国一样。”不久齐国人请求把邾国作为属国,宋国人请求把滕国作为属国,邾国、滕国都不参加结盟,叔孙说:“邾国、滕国,是别人的私属国;我们,是诸侯之国,为什么要看作和他们一样?宋国、卫国,才是和我们对等的。”于是就参加结盟。所以《春秋》不记载叔孙豹的族名,这是说他违背了鲁襄公命令的缘故。 +晋国和楚国争执歃血盟誓的先后。晋国人说:“晋国本来是诸侯的盟主,从来没有在晋国之前歃血的。”楚国人说:“您说晋国和楚国的地位相等,如果晋国总是在前面,这就是楚国比晋国弱。而且晋国和楚国交换着主持诸侯的结盟已经很久了。难道专门由晋国主持?”叔向对赵文子说:“诸侯归服晋国的德行,不是归服它主持结盟。您致力于德行,不要去争执先后。而且诸侯结盟会,小国本来一定有主持结盟的事务,让楚国做小国盟主,不也是可以的吗?”于是就让楚国先歃血。《春秋》记载把晋国放在前面,这是由于晋国有信用。 +初六日,宋平公同时招待晋国和楚国的大夫,赵文子作为主宾坐首席,子木跟他说话,赵文子不能回答,让叔向在旁边帮着对答,子木也不能回答。 +初九日,宋平公和诸侯的大夫在蒙门外结盟。子木向赵文子询问说:“范武子的德行怎么样?”赵文子回答说:“这个人的家事治理得井井有条,对晋国人来说没有可以隐瞒的情况,他的祝史向鬼神表示诚信没有言不由衷的话。”子木回去把话报告楚康王。楚康王说:“高尚啊!能够让神和人高兴,无怪乎他能辅佐五世国君作为盟主。”子木又对楚康王说:“晋国称霸诸侯是合适的,有叔向来辅佐它的卿,楚国没有和他相当的人,不能和他相争。”于是晋国的荀盈就去到楚国参加结盟。 +郑简公在垂陇设享礼招待赵文子,子展、伯有、子西、子产、子太叔、两个子石跟从郑简公。赵文子说:“这七位跟从着君王,这是赐给武以光荣。请求都赋诗以完成君王的恩赐,武也可以从这里看到这七位的志向。”子展赋《草虫》这首诗。赵文子说:“好啊,这是百姓的主人!但武是不足以承当的。”伯有赋《鹑之贲贲》这首诗。赵文子说:“床上的话不出门槛,何况在野外呢?这不是使人所应该听到的。”子西赋《黍苗》的第四章。赵文子说:“有寡君在那里,武有什么能力呢?”子产赋《隰桑》这首诗。赵文子说:“武请求接受它的最后一章。”子太叔赋《野有蔓草》这首诗。赵文子说:“这是大夫的恩惠。”印段赋《蟋蟀》这首诗。赵文子说:“好啊,这是保住家族的大夫!我有希望了。”公孙段赋《桑扈》这首诗。赵文子说:“‘不骄不傲’,福禄还会跑到哪儿去?如果保持这些话,即使想要辞掉福禄,能行吗?” 享礼结束,赵文子告诉叔向说:“伯有将要被杀了!诗用来说明心意,心意在于诬蔑他的国君并且公开怨恨国君,又以此作为宾客的光荣,他能够长久吗?即使侥幸,后来也一定逃亡。”叔向说:“对,他太骄奢。所谓不到五年,说的就是这个人了。”赵文子说:“其余的人都是可以传下几世的大夫。子展也许是最后灭亡的,因为处在上位而不忘记降抑自己。印氏是最后第二家灭亡的,因为欢乐而有节制。欢乐用来安定百姓。不要过分使用它们,灭亡在后,不也是可以的吗?” +宋国的左师请求赏赐,说:“下臣免于一死,请求赐给城邑。”宋平公给他六十个城邑,他把文件交给子罕看。子罕说:“凡是诸侯小国,晋国、楚国都用武力来威慑他们,使他们害怕然后就上下慈爱和睦,慈爱和睦然后能安定他们的国家,以事奉大国,这是所以生存的原因。没有威慑就要骄傲,骄傲了祸乱就要发生,祸乱发生必然被灭亡,这就是所以灭亡的原因。上天生长了金、木、水、火、土五种材料,百姓把它们样样使用上,缺一种都不可,谁能够废除武器?武器的设置已经很久了,这是用来威慑不轨而宣扬文德的。圣人由于武力而兴起,作乱的人由于武力而废弃。使兴起者废弃、灭亡者生存、明白者糊涂的策略,都是从武力来的,而您谋求去掉它,不也是欺骗吗?以欺骗蒙蔽诸侯,没有比这再大的罪过了。即使没有大的讨伐,反而又求取赏赐,这是不满足到了极点了。”因此,子罕就把封赏文件上的字削去并且扔了它。左师也就推辞了接受城邑。向氏想要攻打子罕,左师说:“我将要灭亡时,他老人家救了我,没有比这再大的恩德了。又可以攻打吗?”君子说:“‘那位人物,是国家主持正义的人’,这说的就是子罕吧!‘用什么赐给我,我将要接受它’,这说的就是向戌吧?” +齐国的崔杼生下成和强妻子就死了,又娶了东郭姜,生了明。东郭姜带了前夫的儿子,名叫棠无咎,和东郭偃辅佐崔氏。崔成有病被废,立了崔明做继承人。崔成请求在崔地退休,崔杼答应了,偃和无咎不给,说:“崔地,是宗庙所在的地方,一定要归于宗主。”成和强生气,要杀死他们。告诉庆封说:“他老人家的为人,也是您所知道的,惟独听从无咎和偃的话,父老兄长都说不上话。很怕有害于他老人家,谨敢向您报告。”庆封说:“您姑且退出去,我考虑一下。”就告诉卢蒲嫳。卢蒲嫳说:“他,是国君的仇人。上天或者将要抛弃他了。他家里确实出了乱子,您担的什么心?崔家的削弱,就是庆家的加强。”过几天成和强又对庆封说这件事。庆封说:“如果有利于他老人家,一定要去掉他们。如有危难,我来帮助你们。” +九月初五日,在崔氏的朝廷上,崔成、崔强把东郭偃和棠无咎杀了。崔杼生气走了出来,他的手下人都逃了,找人套车,找不着。让养马的圉人套上车,寺人驾着车子出门,崔杼还说:“崔氏如果有福气,祸患仅仅停留在我身上还可以。”就进见庆封。庆封说:“崔、庆是一家。这些人怎么敢这样?请为您讨伐他们。”让卢蒲嫳领着甲士以攻打崔氏。崔氏加筑宫墙据以防守,没有攻下。发动国内的人们帮着攻打,就灭亡了崔氏,杀了成和强,夺取了他家里全部的人口和财货。崔杼的妻子上吊死了。卢蒲嫳向崔杼复命,并且为他驾车送他回家。崔杼到家,已经无家可归了,于是就上吊而死。崔明在夜里躲在墓群里。初六日,崔明逃亡前来,庆封掌握了政权。 +楚国的薳罢去到晋国参加盟会,晋平公设享礼招待他。薳罢将要退出的时候,赋了《既醉》这首诗。叔向说:“薳氏在楚国的后代将会长享禄位,应当啊!承受国君的命令,不忘记敏捷从事。子荡将要掌握政权了。用敏捷来事奉国君,必然能保养百姓,政权还跑到哪儿去?” +崔氏那次叛乱,申鲜虞逃亡到鲁国来,在郊外雇用了仆人,为齐庄公服丧。冬季,楚国人召请申鲜虞,申鲜虞去到楚国,做了右尹。 +十一月初一日,日食。当时斗柄指申,应该是九月,由于主管历法官员的过错,两次应该置闰月而没有置闰月。 + +襄公二十八年 +【经】二十有八年春,无冰。夏,卫石恶出奔晋。邾子来朝。秋八月,大雩。仲孙羯如晋。冬,齐庆封来奔。十有一月,公如楚。十有二月甲寅,天王崩。乙未,楚子昭卒。 +【传】二十八年春,无冰。梓慎曰:“今兹宋、郑其饥乎?岁在星纪,而淫于玄枵,以有时灾,阴不堪阳。蛇乘龙。龙,宋、郑之星也,宋、郑必饥。玄枵,虚中也。枵,秏名也。土虚而民秏,不饥何为?” +夏。齐侯、陈侯、蔡侯、北燕伯、杞伯、胡子、沈子、白狄朝于晋,宋之盟故也。齐侯将行,庆封曰:“我不与盟,何为于晋?”陈文子曰:“先事后贿,礼也。小事大,未获事焉,从之如志,礼也。虽不与盟,敢叛晋乎?重丘之盟,未可忘也。子其劝行!” +卫人讨宁氏之党,故石恶出奔晋。卫人立其从子圃以守石氏之祀,礼也。 +邾悼公来朝,时事也。 +秋八月,大雩,旱也。 +蔡侯归自晋,入于郑。郑伯享之,不敬。子产曰:“蔡侯其不免乎?日其过此也,君使子展廷劳于东门之外,而傲。吾曰:‘犹将更之。’今还,受享而惰,乃其心也。君小国事大国,而惰傲以为己心,将得死乎?若不免,必由其子。其为君也,淫而不父。侨闻之,如是者,恒有子祸。” +孟孝伯如晋,告将为宋之盟故如楚也。 +蔡侯之如晋也,郑伯使游吉如楚。及汉,楚人还之,曰:“宋之盟,君实亲辱。今吾子来,寡君谓吾子姑还!吾将使馹奔问诸晋而以告。”子大叔曰:“宋之盟,君命将利小国,而亦使安定其社稷,镇抚其民人,以礼承天之休,此君之宪令,而小国之望也。寡君是故使吉奉其皮币,以岁之不易,聘于下执事。今执事有命曰:‘女何与政令之有?必使而君弃而封守,跋涉山川,蒙犯霜露,以逞君心。’小国将君是望,敢不唯命是听。无乃非盟载之言,以阙君德,而执事有不利焉,小国是惧。不然,其何劳之敢惮?”子大叔归,覆命,告子展曰:“楚子将死矣!不修其政德,而贪昧于诸侯,以逞其愿,欲久,得乎?《周易》有之,在《复》三之《颐》三,曰:‘迷复,凶。’其楚子之谓乎?欲复其愿,而弃其本,复归无所,是谓迷复。能无凶乎?君其往也!送葬而归,以快楚心。楚不几十年,未能恤诸侯也。吾乃休吾民矣。”裨灶曰:“今兹周王及楚子皆将死。岁弃其次,而旅于明年之次,以害鸟帑。周、楚恶之。” +九月,郑游吉如晋,告将朝于楚,以从宋之盟。子产相郑伯以如楚,舍不为坛。外仆言曰:“昔先大夫相先君,适四国,未尝不为坛。自是至今,亦皆循之。今子草舍,无乃不可乎?”子产曰:“大适小,则为坛。小适大,苟舍而已,焉用坛?侨闻之,大适小有五美:宥其罪戾,赦其过失,救其灾患,赏其德刑,教其不及。小国不困,怀服如归。是故作坛以昭其功,宣告后人,无怠于德。小适大有五恶:说其罪戾,请其不足,行其政事,共某职贡,从其时命。不然,则重其币帛,以贺其福而吊其凶,皆小国之祸也。焉用作坛以昭其祸?所以告子孙,无昭祸焉可也。” +齐庄封好田而耆酒,与庆舍政。则以其内实迁于卢蒲弊氏,易内而饮酒。数日,国迁朝焉。使诸亡人得贼者,以告而反之,故反卢蒲癸。癸臣子之,有宠,妻之。庆舍之士谓卢蒲癸曰:“男女辨姓。子不辟宗,何也?”曰:“宗不馀辟,余独焉辟之?赋诗断章,余取所求焉,恶识宗?”癸言王何而反之,二人皆嬖,使执寝戈,而先后之。 +公膳,日双鸡。饔人窃更之以鹜。御者知之,则去其肉而以其洎馈。子雅、子尾怒。庆封告卢蒲弊。卢蒲弊曰;“譬之如禽兽,吾寝处之矣。”使析归父告晏平仲。平仲曰:“婴之众不足用也,知无能谋也。言弗敢出,有盟可也。”子家曰:“子之言云,又焉用盟?”告北郭子车。子车曰:“人各有以事君,非佐之所能也。”陈文子谓桓子曰:“祸将作矣!吾其何得?”对曰:“得庆氏之木百车于庄。”文子曰:“可慎守也已!” +卢蒲癸、王何卜攻庆氏,示子之兆,曰:“或卜攻仇,敢献其兆。”子之曰:“克,见血。”冬十月,庆封田于莱,陈无宇从。丙辰,文子使召之。请曰:“无宇之母疾病,请归。”庆季卜之,示之兆,曰:“死。”奉龟而泣。乃使归。庆嗣闻之,曰:“祸将作矣!”谓子家:“速归!祸作必于尝,归犹可及也。”子家弗听,亦无悛志。子息曰:“亡矣!幸而获在吴、越。”陈无宇济水而戕舟发梁。卢蒲姜谓癸曰:“有事而不告我,必不捷矣。”癸告之。姜曰:“夫子愎,莫之止,将不出,我请止之。”癸曰:“诺。”十一月乙亥,尝于大公之庙,庆舍莅事。卢蒲姜告之,且止之。弗听,曰:“谁敢者!”遂如公。麻婴为尸,庆圭为上献。卢蒲癸、王何执寝戈。庆氏以其甲环公宫。陈氏、鲍氏之圉人为优。庆氏之马善惊,士皆释甲束马而饮酒,且观优,至于鱼里。栾、高、陈、鲍之徒介庆氏之甲。子尾抽桷击扉三,卢蒲癸自后刺子之,王何以戈击之,解其左肩。犹援庙桷,动于甍,以俎壶投,杀人而后死。遂杀庆绳、麻婴。公惧,鲍国曰:“群臣为君故也。”陈须无以公归,税服而如内宫。 +庆封归,遇告乱者,丁亥,伐西门,弗克。还伐北门,克之。入,伐内宫,弗克。反,陈于岳,请战,弗许。遂来奔。献车于季武子,美泽可以鉴。展庄叔见之,曰:“车甚泽,人必瘁,宜其亡也。”叔孙穆子食庆封,庆封汜祭。穆子不说,使工为之诵《茅鸱》,亦不知。既而齐人来让,奔吴。吴句余予之朱方,聚其族焉而居之,富于其旧。子服惠伯谓叔孙曰:“天殆富淫人,庆封又富矣。”穆子曰:“善人富谓之赏,淫人富谓之殃。天其殃之也,其将聚而歼旃?” +癸巳,天王崩。未来赴,亦未书,礼也。 +崔氏之乱,丧群公子。故鉏在鲁,叔孙还在燕,贾在句渎之丘。及庆氏亡,皆召之,具其器用而反其邑焉。与晏子邶殿,其鄙六十,弗受。子尾曰:“富,人之所欲也,何独弗欲?”对曰:“庆氏之邑足欲,故亡。吾邑不足欲也。益之以邶殿,乃足欲。足欲,亡无日矣。在外,不得宰吾一邑。不受邶殿,非恶富也,恐失富也。且夫富如布帛之有幅焉,为之制度,使无迁也。夫民生厚而用利,于是乎正德以幅之,使无黜嫚,谓之幅利。利过则为败。吾不敢贪多,所谓幅也。”与北郭佐邑六十,受之。与子雅邑,辞多受少。与子尾邑,受而稍致之。公以为忠,故有宠。 +释卢蒲弊于北竟。求崔杼之尸,将戮之,不得。叔孙穆子曰:“必得之。武王有乱臣十人,崔杼其有乎?不十人,不足以葬。”既,崔氏之臣曰:“与我其拱璧,吾献其柩。”于是得之。十二月乙亥朔,齐人迁庄公,殡于大寝。以其棺尸崔杼于市,国人犹知之,皆曰:“崔子也。” +为宋之盟故,公及宋公、陈侯、郑伯、许男如楚。公过郑,郑伯不在。伯有廷劳于黄崖,不敬。穆叔曰:“伯有无戾于郑,郑必有大咎。敬,民之主也,而弃之,何以承守?郑人不讨,必受其辜,济泽之阿,行潦之苹藻,置诸宗室,季兰尸之,敬也。敬可弃乎?” +及汉,楚康王卒。公欲反,叔仲昭伯曰:“我楚国之为,岂为一人?行也!”子服惠伯曰:“君子有远虑,小人从迩。饥寒之不恤,谁遑其后?不如姑归也。”叔孙穆子曰:“叔仲子专之矣,子服子始学者也。”荣成伯曰:“远图者,忠也。”公遂行。宋向戌曰:“我一人之为,非为楚也。饥寒之不恤,谁能恤楚?姑归而息民,待其立君而为之备。”宋公遂反。 +楚屈建卒。赵文子丧之如同盟,礼也。 +王人来告丧,问崩日,以甲寅告,故书之,以征过也。 +译文 +二十八年春季,没有冰。梓慎说:“今年宋国和郑国恐怕要发生饥荒了吧!岁星应当在星纪,但已经过头到了玄枵。这是因为要发生天时不正的灾荒,阴不能战胜阳。蛇乘坐在龙的上边,龙是宋国、郑国的星宿,所以宋国、郑国必然发生饥荒。玄枵,虚宿在它的中间。枵,是消耗的名称。土地虚而百姓耗,不发生饥荒才怪呢!” +夏季,齐景公、陈哀公、蔡景侯、北燕伯、杞文公、胡子、沈子、白狄到晋国朝见,这是由于在宋国那次结盟的缘故。齐景公准备出行,庆封说:“我们没有参加结盟,为什么要向晋国朝见?”陈文子说:“先考虑事奉大国而后考虑财货,这是合于礼的。小国事奉大国,如果没有得到事奉的机会,就要顺从大国的意图,这也是合于礼的。我们虽然没有参加结盟,岂敢背叛晋国呢?重丘的盟会,不可以忘记啊。您还是劝国君出行!” +卫国人讨伐甯氏的亲族,所以石恶逃亡到晋国。卫国人立了他的侄儿石圃,以保存石氏的祭祀,这是合于礼的。 +邾悼公前来朝见,这是按时令而来朝见。 +秋季,八月,举行大雩祭,这是由于发生了旱灾。 +蔡景侯从晋国回国,路过郑国。郑简公设享礼招待他,蔡景侯表现得不恭敬。子产说:“蔡侯恐怕不能免于祸难吧!以前经过这里的时候,国君派子展去到东门外边慰劳,但是他很骄傲。我认为他还是会改变的。现在他回来,接受享礼而显得怠惰,这就是他的本性了。作为小国的国君,事奉大国,反而把怠惰骄傲作为本性,将来能有好死吗?如果不免于祸难,一定由于他的儿子。他做国君,淫乱而不像做父亲的样子。侨听说,像这样的人,经常会遇到儿子来作乱。” +孟孝伯去到晋国,这是由于报告为“宋之盟”的缘故而将到楚国去。 +蔡景公去到晋国的时候,郑简公派游吉去到楚国。到达汉水,楚国人让他回去,说:“在宋国的那次结盟,贵国君王亲自参加。现在大夫前来,寡君说大夫暂且回去,我将要派传车奔赴晋国询问以后再告诉您。”游吉说:“在宋国的那次结盟,贵国君王的命令将要有利于小国,而也使小国安定他的国家,镇抚它的百姓,用礼仪承受上天的福禄,这是贵国君王的法令,同时也是小国的希望。寡君因此派吉奉上财礼,由于年来多难,特向下级执事聘问。现在执事命令说:你怎么能参与郑国的政令?一定要让你们国君丢掉你们的疆土和守备,跋山涉水,冒着霜露,以满足我国君王的心意。小国还想期望贵国君王赐给恩惠,哪里敢不唯命是听?但这不符合盟书的话,而使贵国君王的德行有缺失,也对执享有所不利,小国就害怕这个。否则,还敢怕什么劳苦呢?” +游吉回国,复命,告诉子展说:“楚王将要死了。不修明他的政事德行,反而在诸侯那里贪图进奉,以达到自己的愿望,想要活得长久,行吗?《周易》有这样的情况,得到《复》卦变成《颐》卦,说‘迷路往回走,不吉利。’这说的就是楚王吧?想实现他的愿望,而放弃了本来的道路,想回去没有了归路,这就叫‘迷复’,能够吉利吗?国君就去吧,送了葬回来,让楚国痛快一下。楚国没有近十年的时间,不能争霸,我们就可以让百姓休息了。”裨灶说:“今年周天子和楚王都将死去。岁星失去它应有的位置,而运行在明年的位置上,要危害鸟尾,周朝和楚国要受灾祸。” +九月,郑国的游吉去到晋国,报告说按照在宋国的盟誓将要去楚国朝见。子产辅助郑伯去到楚国,搭了帐篷而不筑坛。外仆说:“从前先大夫辅助先君到四方各国,从没有不筑坛的。从那个时候到今天也都没有改变。现在您不除草就搭起帐篷,恐怕不可以吧!”子产说:“大国君臣去到小国,就筑坛;小国去到大国,随便搭个帐篷就行了,哪里用得着筑坛?侨听说过:大国君臣去到小国有五种好处:赦免它的罪过,原谅它的失误,救助它的灾难,赞赏它的德行和刑法。教导它所想不到的地方,小国不困乏,想念和顺服大国,好像回家一样,因此筑坛来表扬它的功德,公开告诉后代的人,不要怠情于修德业。小国去到大国有五种坏处:向小国掩饰它的罪过,请求得到它所缺乏的东西,要求小国奉行它的命令,供给它贡品,服从它的随时发出的命令。不这样,就得加重小国的财礼,用来祝贺它的喜事和吊唁它的祸事,这都是小国的祸患,哪里用得着筑坛招来它的祸患?把这些告诉子孙,不要招来祸患就可以了。” +齐国的庆封喜欢打猎而嗜好喝酒,把政权交付给庆舍,就带着他的妻妾财物迁到卢蒲嫳家里,交换妻妾而喝酒。几天以后,官员们就改到这里来朝见。庆封让逃亡在外而知道崔氏馀党的人,如果前来报告就允许他回国,所以就让卢蒲癸回来。卢蒲癸做了庆舍的家臣,受到宠信,庆舍就把女儿嫁给了卢蒲癸。庆舍的家臣对卢蒲癸说:“男女结婚要区别是否同姓,您却不避同宗,为什么?”卢蒲癸说:“同宗不避我,我怎么能独独避开同宗?比如赋诗时的断章取义,我取我所需要的就是了,哪里知道什么同宗不同宗?”卢蒲癸又对庆舍说起王何而让他回来,两个人都受到了庆舍的宠信。庆舍让他们拿着武器寝戈作为随身警卫。 +卿大夫在朝廷办公务用餐,每天有两只鸡,管伙食的人偷偷地换成鸭子。送饭的人知道了,把肉都拿掉而只将肉汤送上来。子雅、子尾生气。庆封告诉卢蒲嫳。卢蒲嫳说:“把他们比成禽兽,我睡在他们的皮毛上了。”于是就派析归父告诉晏平仲。晏平仲说:“婴的一伙人不足以使用,聪明也出不了主意。但是决不敢泄露这些话,可以盟誓。”析归父说:“您已经这样说了,哪里还用盟誓?”又告诉北郭子车。子车说:“各人都有不同的方式事奉国君,这不是佐所能做到的。”陈文子对陈无宇说:“祸难将要发生了,我们能得到什么?”陈无宇回答说:“可以在庄街上得到庆氏的木头一百车。”陈文子说:“可以谨慎地保守住就行了。” +卢蒲癸、王何为进攻庆氏而占卜,把卦像给庆舍看,说:“有人为攻打仇人而占卜,谨敢奉献卦像。”庆舍说:“攻下了,见到血。”冬季,十月,庆封在莱地打猎,陈无宇跟从。十七日,陈文子派人召唤陈无宇回去,陈无宇请求说:“无宇的母亲病了,请求回去。”庆封占卜,把卦像给陈无宇看,陈无宇说:“这是死的卦像。”捧着龟甲而哭泣,于是就让他回去了。庆嗣听到这件事,说:“祸难将要发生了。”告诉庆封说:“赶快回去,祸难必然发生在秋祭的时候,回去还来得及。”庆封不听,也没有改悔的意思。庆嗣说:“他要逃亡了,能够逃到吴国、楚国就是侥幸。”陈无宇渡过河,就破坏了渡船撤毁了桥梁。 +卢蒲姜对卢蒲癸说:“有事情而不告诉我,必然不能成功。”卢蒲癸告诉了她。卢蒲姜说:“我父亲性情倔强,没有人劝阻他,反倒不出来了。请让我去劝阻他。”卢蒲癸说:“好。”十一月初七日,在太公的庙里举行秋祭,庆舍将亲临主持祭祀。卢蒲姜告诉他有人要发动祸乱,而且劝他不要去。他不听,说:“谁敢这么干?”就去到太庙参加祭祀。麻婴充当祭尸,庆奊充当上献。卢蒲癸、王何手拿寝戈,庆氏领着他的甲士围住公宫。陈氏、鲍氏的养马人表演,庆氏的马容易受惊,甲士都解甲系马而喝酒,同时看戏,到了鱼里。栾氏、高氏、陈氏、鲍氏的徒兵就穿上了庆氏的皮甲。子尾抽出槌子,在门上敲了三下,卢蒲癸从后边刺庆舍,王何用戈对他猛击,打下了庆舍的左肩。庆舍还能攀着庙宇的椽子,震动了栋梁,把俎和壶向人扔去,杀死了人才死去。卢蒲癸等人就杀死了庆绳、麻婴。齐景公恐惧,鲍国说:“臣下们是为了君王的缘故。”陈须无带着齐景公回去,脱去祭服进了内宫。 +庆封回来,碰到报告动乱的人。十九日,攻打西门,没有攻下。回过来攻打北门,攻下了。进城,攻打内宫,没有攻下。返回来,列阵于大街上,庆封请求决战,没有得到允许,就逃亡到鲁国来。庆封把车子献给季武子,美丽光亮可以作镜子。展庄叔进见季武子,说:“车很光亮,人必然憔悴,无怪乎他要逃亡了。”叔孙穆子设便宴招待庆封,庆封先遍祭诸神。穆子不高兴,让乐工为他诵《茅鸱》这首诗,他也不明白。不久以后齐国人前来责问,庆封又逃亡到吴国。吴子勾馀把朱方封给了庆封,他聚集了族人住在那里,比以前更富有。子服惠伯对叔孙穆子说:“上天大概要让坏人富有的,庆封又富有起来了。”叔孙穆子说:“好人富有叫做奖赏,坏人富有叫做灾殃。上天恐怕是降灾于他了,将要让他们聚集而一起被杀尽吧!” +十一月二十五日,周灵王逝世。没有发来讣告,《春秋》也没有记载,这是合于礼的。 +崔氏那次动乱,公子们各自逃亡,所以鉏在鲁国,叔孙还在燕国,贾在句渎之丘。等到庆氏逃亡,把他们都召了回来,为他们准备了器物用具并且发还给他们封邑。另外封给晏子邶殿边上六十个城邑,晏子不接受。子尾说:“富有,是人所需要的。为什么独独您不要?”晏子回答说:“庆氏的城邑满足了欲望,所以逃亡。我的城邑不能满足欲望,加上邶殿,就满足欲望了。满足了欲望,离逃亡就没有几天了。逃亡在外边连一个城邑都不能主宰。不接受邶殿,不是讨厌富有,而是恐怕失去富有。而且富有,就像布帛的有一定宽度。给它规定幅度,让它不能改变。百姓,总是想生活丰厚,器用富饶,因此就要端正道德,而加以限制,让它不要不够,也不要过分,这叫做限制私利。私利过了头就会败坏。我不敢贪多,就是所谓限制私利。”齐景公赐给北郭佐六十个城邑,他接受了。赐给子雅城邑,他婉辞了大多数而接受了少数。赐给子尾城邑,他接受之后又奉还了。齐景公认为子尾忠诚,所以子尾很得宠信。 +把卢蒲嫳放逐到齐国北部边境。齐国人接着求取崔杼的尸体,准备戮尸,但没找到。叔孙穆子说:“一定找得着的。武王有十个治世之臣,崔杼难道能有吗?不到十个人,不足以安葬。”过了不久,崔氏的家臣说:“把他的大玉璧给我,我献出他的棺材。”因此就找到了崔杼的尸体。十二月初一日,齐国人迁葬庄公,停棺在正寝。用崔杼的棺材装着崔杼的尸体放在街上示众。国内人们都知道,都说:“这是崔杼。” +由于“宋国之盟”的缘故,鲁襄公和宋平公、陈哀公、郑简公、许悼公到了楚国。鲁襄公经过郑国,郑简公不在国内,伯有到黄崖慰劳,表现得不恭敬,穆叔说:“伯有如果在郑国没有罪,郑国必然有大灾祸。恭敬,是百姓的主宰,现在丢弃了它,如何能继承祖宗保持的家业?郑国人不讨伐他,必然要遭到他的灾祸。水边的薄土,路边积水中的浮萍水草,用来作祭品,季兰作为祭尸,这是由于恭敬。恭敬难道能丢弃吗?” +到达汉水,楚康王死。鲁襄公想要回去。叔仲昭伯说:“我们是为了楚国,哪里是为了一个人?继续走吧!”子服惠伯说:“君子有长远考虑,小人只看到眼前。饥寒都顾不上,谁有工夫顾到后果?不如暂且回去吧。”叔孙穆子说:“叔仲子可以被专门任用了,子服子,是刚刚开始学习的人。“荣成伯说:“长远打算的人是忠诚的。”鲁襄公就继续前往楚国。宋国的向戌说:“我们是为了一个人,不是为了楚国。饥寒都顾不上,谁能顾得上楚国?姑且回去而使百姓休息,等他们立了国君再戒备他们。”宋平公就回去了。 +楚国的屈建死,赵文子去吊丧好像对待盟国一样,这是合于礼的。 +周朝的使者来鲁国通知丧事,问他周天子死去的日期,用十二月十六日作为回答,所以《春秋》也这样记载,用以惩戒过错。 + +襄公二十九年 +【经】二十有九年春王正月,公在楚。夏五月,公至自楚。庚午,卫侯衎卒,阍弑吴子余祭。仲孙羯会晋荀盈、齐高止、宋华定、卫世叔仪、郑公孙段、曹人、莒人、滕子、薛人、小邾人城杞。晋侯使士鞅来聘。杞子来盟。吴子使札来聘。秋九月,葬卫献公。齐高止出奔北燕。冬,仲孙羯如晋。 +【传】二十九年春,王正月,公在楚,释不朝正于庙也。楚人使公亲襚,公患之。穆叔曰:“祓殡而襚,则布币也。”乃使巫以桃列先祓殡。楚人弗禁,既而悔之。 +二月癸卯,齐人葬庄公于北郭。 +夏四月,葬楚康王。公及陈侯、郑伯、许男送葬,至于西门之外。诸侯之大夫皆至于墓。楚郏敖即位。王子围为令尹。郑行人子羽曰:“是谓不宜,必代之昌。松柏之下,其草不殖。” +公还,及方城。季武子取卞,使公冶问,玺书追而与之,曰:“闻守卞者将叛,臣帅徒以讨之,既得之矣,敢告。”公冶致使而退,及舍而后闻取卞。公曰:“欲之而言叛,只见疏也。”公谓公冶曰:“吾可以入乎?”对曰:“君实有国,谁敢违君!”公与公冶冕服。固辞,强之而后受。公欲无入,荣成伯赋《式微》,乃归。五月,公至自楚。公冶致其邑于季氏,而终不入焉。曰:“欺其君,何必使余?”季孙见之,则言季氏如他日。不见,则终不言季氏。及疾,聚其臣,曰:“我死,必以在冕服敛,非德赏也。且无使季氏葬我。” +葬灵王,郑上卿有事,子展使印段往。伯有曰:“弱,不可。”子展曰:“与其莫往,弱不犹愈乎?《诗》云:‘王事靡盬,不遑启处,东西南北,谁敢宁处?坚事晋、楚,以蕃王室也。王事无旷,何常之有?”遂使印段如周。 +吴人伐越,获俘焉,以为阍,使守舟。吴子余祭观舟,阍以刀弑之。 +郑子展卒,子皮即位。于是郑饥而未及麦,民病。子皮以子展之命,饩国人粟,户一钟,是以得郑国之民。故罕氏常掌国政,以为上卿。宋司城子罕闻之,曰:“邻于善,民之望也。”宋亦饥,请于平公,出公粟以贷。使大夫皆贷。司城氏贷而不书,为大夫之无者贷。宋无饥人。叔向闻之,曰:“郑之罕,宋之乐,其后亡者也!二者其皆得国乎!民之归也。施而不德,乐氏加焉,其以宋升降乎!” +晋平公,杞出也,故治杞。六月,知悼子合诸侯之大夫以城杞,孟孝伯会之。郑子大叔与伯石往。子大叔见大叔文子,与之语。文子曰:“甚乎!其城杞也。”子大叔曰:“若之何哉?晋国不恤周宗之阙,而夏肄是屏。其弃诸姬,亦可知也已。诸姬是弃,其谁归之?吉也闻之,弃同即异,是谓离德。《诗》曰:‘协比其邻,昏姻孔云。’晋不邻矣,其谁云之?” +齐高子容与宋司徒见知伯,女齐相礼。宾出,司马侯言于知伯曰:“二子皆将不免。子容专,司徒移,皆亡家之主也。”知伯曰:“何如?”对曰:“专则速及,侈将以其力毙,专则人实毙之,将及矣。” +范献子来聘,拜城杞也。公享之,展庄叔执币。射者三耦,公臣不足,取于家臣,家臣:展瑕、展玉父为一耦。公臣,公巫召伯、仲颜庄叔为一耦,鄫鼓父、党叔为一耦。 +晋侯使司马女叔侯来治杞田,弗尽归也。晋悼夫人愠曰:“齐也取货。先君若有知也,不尚取之!”公告叔侯,叔侯曰:“虞、虢、焦、滑、霍、扬、韩、魏,皆姬姓也,晋是以大。若非侵小,将何所取?武、献以下,兼国多矣,谁得治之?杞,夏余也,而即东夷。鲁,周公之后也,而睦于晋。以杞封鲁犹可,而何有焉?鲁之于晋也,职贡不乏,玩好时至,公卿大夫相继于朝,史不绝书,府无虚月。如是可矣,何必瘠鲁以肥杞?且先君而有知也,毋宁夫人,而焉用老臣?” +杞文公来盟。书曰“子”,贱之也。 +吴公子札来聘,见叔孙穆子,说之。谓穆子曰:“子其不得死乎?好善而不能择人。吾闻‘君子务在择人’。吾子为鲁宗卿,而任其大政,不慎举,何以堪之?祸必及子!” +请观于周乐。使工为之歌《周南》、《召南》,曰:“美哉!始基之矣,犹未也。然勤而不怨矣。”为之歌《邶》、《鄘》、《卫》,曰:“美哉,渊乎!忧而不困者也。吾闻卫康叔、武公之德如是,是其《卫风》乎?”为之歌《王》,曰:“美哉!思而不惧,其周之东乎?”为之歌《郑》,曰:“美哉!其细已甚,民弗堪也,是其先亡乎!”为之歌《齐》,曰:“美哉!泱泱乎!大风也哉!表东海者,其大公乎!国未可量也。”为之歌《豳》,曰:“美哉!荡乎!乐而不淫,其周公之东乎?”为之歌《秦》,曰:“此之谓夏声。夫能夏则大,大之至也,其周之旧乎?”为之歌《魏》,曰:“美哉!渢渢乎!大而婉,险而易行,以德辅此,则明主也。”为之歌《唐》,曰:“思深哉!其有陶唐氏之遗民乎?不然,何忧之远也?非令德之后,谁能若是?”为之歌《陈》,曰:“国无主,其能久乎?”自《郐》以下无讥焉。为之歌《小雅》,曰:“美哉!思而不贰,怨而不言,其周德之衰乎?犹有先王之遗民焉。”为之歌《大雅》,曰:“广哉!熙熙乎!曲而有直体,其文王之德乎?”为之歌《颂》,曰:“至矣哉!直而不倨,曲而不屈,迩而不逼,远而不携,迁而不淫,复而不厌,哀而不愁,乐而不荒,用而不匮,广而不宣,施而不费,取而不贪,处而不底,行而不流,五声和,八风平,节有度,守有序,盛德之所同也。” +见舞《象箾》《南籥》者,曰:“美哉!犹有憾。”见舞《大武》者,曰:“美哉!周之盛也,其若此乎!”见舞《韶濩》者,曰:“圣人之弘也,而犹有惭德,圣人之难也。”见舞《大夏》者,曰:“美哉!勤而不德,非禹其谁能修之?”见舞《韶箾》者,曰:“德至矣哉!大矣!如天之无不帱也,如地之无不载也,虽甚盛德,其蔑以加于此矣。观止矣!若有他乐,吾不敢请已!” +其出聘也,通嗣君也。故遂聘于齐,说晏平仲,谓之曰:“子速纳邑与政!无邑无政,乃免于难。齐国之政,将有所归,未获所归,难未歇也。”故晏子因陈桓子以纳政与邑,是以免于栾、高之难。 +聘于郑,见子产,如旧相识,与之缟带,子产献丝宁衣焉。谓子产曰:“郑之执政侈,难将至矣!政必及子。子为政,慎之以礼。不然,郑国将败。” +适卫,说蘧瑗、史狗、史鳅,公子荆、公叔发、公子朝,曰:“卫多君子,未有患也。” +自卫如晋,将宿于戚。闻钟声焉,曰:“异哉!吾闻之也:‘辩而不德,必加于戮。’夫子获罪于君以在此,惧犹不足,而又何乐?夫子之在此也,犹燕之巢于幕上。君又在殡,而可以乐乎?”遂去之。文子闻之,终身不听琴瑟。 +适晋,说赵文子、韩宣子、魏献子,曰:“晋国其萃于三族乎!”说叔向,将行,谓叔向曰:“吾子勉之!君侈而多良,大夫皆富,政将在家。吾子好直,必思自免于难。” +秋九月,齐公孙虿、公孙灶放其大夫高止于北燕。乙未,出。书曰:“出奔。”罪高止也。高止好以事自为功,且专,故难及之。 +冬,孟孝伯如晋,报范叔也。 +为高氏之难故,高竖以卢叛。十月庚寅,闾丘婴帅师围卢。高竖曰:“苟请高氏有后,请致邑。”齐人立敬仲之曾孙宴,良敬仲也。十一月乙卯,高竖致卢而出奔晋,晋人城绵而置旃。 +郑伯有使公孙黑如楚,辞曰:“楚、郑方恶,而使余往,是杀余也。”伯有曰:“世行也。”子皙曰:“可则往,难则已,何世之有?”伯有将强使之。子皙怒,将伐伯有氏,大夫和之。十二月己巳,郑大夫盟于伯有氏。裨谌曰:“是盟也,其与几何?《诗》曰:‘君子屡盟,乱是用长。’今是长乱之道也。祸未歇也,必三年而后能纾。”然明曰:“政将焉往?”裨谌曰:“善之代不善,天命也,其焉辟子产?举不逾等,则位班也。择善而举,则世隆也。天又除之,夺伯有魄,子西即世,将焉辟之?天祸郑久矣,其必使子产息之,乃犹可以戾。不然,将亡矣。” +译文 +二十九年春季,周王朝历法的正月,“公在楚”,这是为了解释不在祖庙中举行听政的原因。楚国人让鲁襄公亲自为楚康王的尸体赠送寿衣,襄公对这感到忧虑。穆叔说:“先扫除棺材的凶邪然后给死者赠送衣服,这就等于朝见时陈列皮币。”于是就让巫人用桃棒、笤帚先在棺材上扫除不祥。楚国人没有禁止,不久以后又感到后悔。 +二月初六日,齐国人在外城北部安葬齐庄公。 +夏季,四月,安葬楚康王,鲁襄公和陈哀公、郑简公、许悼公都参加送葬,到达西门外边,各诸侯的大夫都到了墓地。楚国的郏敖即位,王子围做令尹。郑国的使者子羽说:“这叫做不恰当,令尹必然要代替楚君而昌盛。松柏的下面,草是不能繁殖的。” +鲁襄公回来,到达方城山。季武子占领了卞地,派公冶来问候襄公,用封泥加印把信封好了追上去给了公冶,信上说:“听到戍守卞地的人打算叛变,下臣率领部下讨伐了他,已经得到卞地了,谨此报告。”公冶表达了使命就退出去,到达帐篷以后才听到占领了卞地。鲁襄公说:“想要这块地方而又说叛变,只能是对我表示疏远。” 鲁襄公对公冶说:“我可以进入国境吗?”公冶回答说:“君王据有国家,谁敢违背君王?”鲁襄公赐给公冶冕服,公冶坚决辞谢,勉强他,然后才接受了。鲁襄公想不进入国境,荣成伯赋《式微》这首诗,鲁襄公这才回国。 +五月,鲁襄公从楚国回来。公冶把他的封邑送还给季氏,而且始终不再进入季孙的家门,说:“欺骗他的国君,何必派我?”季孙和他见面,就和季孙像以前一样说话。不相见,公冶始终不谈季氏。等到公冶病危,聚集他的家臣,说:“我死了以后,一定不要用冕服入敛,因为这不是由于德行而所得的赏赐。并且还不要让季氏来安葬我。” +安葬周灵王。郑国的上卿子展有事不能离开,他派印段前去。伯有说:“年纪轻,不行。”子展说:“与其没有人去,尽管年轻,比没人去还要好一点吧?《诗》说:‘王事应当细致,没有空闲安居。’东西南北,谁敢安安稳稳地居住?坚定地事奉晋国、楚国,用以捍卫王室。王事没有缺失,有什么常例不常例?”于是就派印段前去成周。 +吴国人进攻越国,抓到了俘虏,让他做看门人,派他看守船只。吴王馀祭观看船只,看门人用刀杀死了吴王。 +郑国的子展死,子皮即位为上卿。当时郑国有饥荒而还没有到麦收,百姓很困乏。子皮用子展的遗命把粮食赠给国内的人们,每户一钟,因此得到郑国百姓的拥护。所以罕氏经常掌握国政,作为上卿。宋国的司城子罕听到了,说:“接近于善,这是百姓的期望。”宋国也发生了饥荒,司城子罕向宋平公请求,拿出公家的粮食借给百姓,让大夫也都出借粮食。司城氏借出粮食不写契约,又替缺少粮食的大夫借给百姓。宋国没有挨饿的人。叔向听说了这件事,说:“郑国的罕氏,宋国的乐氏,大约是最后灭亡的啊,两家恐怕都要掌握政权吧!这是因为百姓归向他们的缘故。施舍而不自以为给人恩惠,乐氏就更高出一筹了,这一家大概是会随着宋国的盛衰而升降吧!” +晋平公,是杞女所生的,所以修整杞国的城墙。六月,知悼子会合诸侯的大夫为杞国筑城墙,孟孝伯参加了。郑国的子太叔和伯石前去。子太叔见到太叔文子,和他说话。文子说:“为杞国筑城这件事过分了!”子太叔说:“拿他怎么办好啊!晋国不担心周室的衰微,反而保护夏朝的残馀,它会丢弃姬姓诸国,也就可以想象到了。丢弃姬姓诸国,有谁去归向他?吉听说:丢弃同姓而亲近异姓,这叫做离德。《诗》说:‘和谐他的近亲,姻亲就会和他友好来往。’晋国把近亲不看作近亲,还有谁来和他友好往来?” +齐国的高子容和宋国的司徒进见知伯,女齐作为相礼者,客人出去了,女齐对知伯说:“这两位将不免于祸。子容专权,司徒奢侈,都是使家族灭亡的大夫。”知伯说:“怎么呢?”女齐回答说:“专横就会很快及于祸患,奢侈将会由于力量强大而死,专横别人就会要他的命,他将要及于祸患了。” +范献子来鲁国聘问,拜谢在杞国筑城。鲁襄公设享礼招待他,展庄叔拿着束帛。参加射礼的要三对人。公臣的人选不够,在家臣中选取。家臣,展暇、展王父作为一对,公臣,公巫召伯、仲颜庄叔作为一对,鄫鼓父、党叔作为一对。 +晋平公派司马女叔侯来鲁国办理使鲁国归还杞国土田的事情,但没有全部归还给杞国。晋悼公夫人很生气他说:“女齐办事不得力,先君如果有知,不会赞助他这样办事的。”晋平公把这件事告诉了叔侯。叔侯说:“虞国、虢国、焦国、滑国、霍国、杨国、韩国、魏国,都是姬姓,晋国因此而扩大。如果不是入侵小国,将要从哪里取得?武公、献公以来,兼并的国家就多了,谁能够治理它?杞国,是夏朝的后代,而接近东夷。鲁国,是周公的后代,而和晋国和睦。把杞国封给鲁国还是可以的,有什么杞国不杞国?鲁国对于晋国,贡品不缺乏,玩物按时送到,公卿大夫不断前来朝见,史官没有中断过记载,国库没有一个月不接受鲁国的贡品。像这样就可以了,何必要损害鲁国而增强杞国?如果先君有知,就宁可让夫人自己去办,又哪里用得着我老臣?” +杞文公来鲁国结盟,《春秋》称他为“子”,这是表示对他不尊重。 +吴国的公子札来鲁国聘问,见到叔孙穆子,很喜欢他。对穆子说:“您恐怕不得善终吧!喜欢善良而不能够选择贤人,我听说君子应当致力选择贤人。您做鲁国的宗卿而主持国政,不慎重举拔善人,怎么能受得了呢?祸患必然到您身上。” +公子札请求聆听观看周朝的音乐和舞蹈。于是让乐工为他歌唱《周南》、《召南》。季札说:“美啊!王业开始奠定基础了,还没有完善,然而百姓勤劳而不怨恨了。”为他歌唱《邶风》、《邶风》、《卫风》之歌,他说:“美好又深沉啊!忧愁而不困惑。我听说卫康叔、武公的德行就像这样,这大概就是《卫风》吧!”为他歌唱《王风》之歌,他说:“美啊!思虑而不恐惧,大概是周室东迁以后的音乐吧!”为他歌唱《郑风》之歌,他说:“美啊!但是它琐碎得太过分了,百姓不堪忍受了。这大概是郑国要先灭亡的原因吧!”为他歌唱《齐风》之歌,他说:“美啊,多么宏大的声音呵!这是大国的音乐啊!作为东海的表率的,大概是太公的国家吧!国家前途是不可限量的。”为他歌唱《豳风》之歌,他说:“美啊,浩荡博大呵!欢乐而不过度,大概是周公东征的音乐吧!”为他歌唱《秦风》之歌,他说:“这就叫做西方的夏声。夏就是大,大到极点了,恐怕是周朝的旧乐吧!”为他歌唱《魏风》,他说:“美啊!抑扬顿挫呵!宏亮而又婉转,艰难而流畅,再用德行加以辅助,就是贤明的君主了。”为他歌唱《唐风》,他说:“思虑很深啊!大概有陶唐氏的遗民吧?否则,为什么那么忧深思远呢?不是美德者的后代,谁能像这样?”为他歌唱《陈风》,他说:“国家没有主人,难道能够长久吗?”从《郐风》以下的诗歌,季札听了就没有评论了。乐师为他歌唱《小雅》,他说:“美啊!忧愁而没有背叛的心,怨恨却不表现在语言中,恐怕是周朝德行衰微的乐章吧!还有先王的遗民啊。”为他歌唱《大雅》,他说:“广博啊,和美呵!抑扬顿挫而本体刚健劲直,大概是文王的德行吧!”为他歌唱《颂》,他说:“到达顶点了!正直而不倨傲,婉柔而不屈挠,亲近而不相逼,疏远而不离心,活泼而不邪乱,反复而不厌倦,哀伤而不忧愁,欢乐而不过度,常用而不匮乏,宽广而不显露,施舍而不浪费,收取而不贪婪,静止而不停滞,行进而不流荡。五声和谐,八风协调。节奏有一定的规律,乐器都按次序,这都是盛德之人所共同具有的。” +公子札看到跳《象箾》、《南籥》舞,说:“美啊,但还有所遗憾。”看到跳《大武》舞,说:“美啊!周朝兴盛的时候,大概就像这种情况吧!”看到跳《韶濩》舞,说:“像圣人那样的弘大,尚且还有所惭愧,可见当圣人不容易啊!”看到跳《大夏》舞,说:“美啊!勤劳而不自以为有德,如果不是禹,还有谁能做到呢?”看到跳《韶箾》舞,说:“功德到达顶点了,伟大啊!像上天的没有不覆盖,像大地的没有不承载。盛德到达顶点,就不能再比这更有所增加了,聆听观看就到这里了。如果还有别的音乐,我不敢再请求欣赏了。” +公子札的出国聘问,是为了新立的国君通好的缘故,因此就到齐国聘问,喜欢晏平仲,对他说:“您赶快交还封邑和政权。没有封邑没有政权,这才能免于祸难。齐国的政权将会有所归属,没有得到归属,祸难不会停止。”所以晏子通过陈桓子交还了政权和封邑,因为这样,而免于栾氏、高氏发动的祸难。 +季札到郑国聘问,见了子产,好像老朋友一般。季札给子产赠送白绢大带,子产给季札献上麻布衣服,公子札对子产说:“郑国的执政者奢侈,祸难将要来临了!政权必然落到您手中。您执政,要用礼来谨慎地处事。否则,郑国将会败亡。” +季札到达卫国,与蘧瑗、史狗、史?、公子荆、公叔发、公子朝谈得很投机,他说:“卫国有很多贤能的君子,不会有什么祸患。” +公子札从卫国去晋国,准备在戚地住宿。听到钟声,说:“奇怪啊!我听说了,发动变乱而没有德行,必然遭到诛戮。这一位就在这地方得罪国君,害怕还来不及,又有什么可以寻欢作乐的?这一位在这地方,就像燕子在帐幕上做窝。国君又正停棺还没有安葬,难道可以寻欢作乐吗?”于是就不住在戚地。孙文子听到了这番话,一辈子不再听音乐。 +公子札到了晋国,喜爱赵文子、韩宣子、魏献子,说:“晋国的政权大约要聚集在这三家了!”他喜爱叔向,离别时,对叔向说:“您努力吧!国君奢侈而优秀的臣子很多,大夫都富有,政权将要归于大夫家。您好直话直说,一定要考虑使自己免于祸难。” +秋季,九月,齐国的公孙虿、公孙灶放逐他们的大夫高止到北燕。初二日,出国。《春秋》记载说“出奔”,这是由于高止有罪。高止喜欢生事,而且自己居功,同时又专横,所以祸难到了他身上。 +冬季,孟孝伯去到晋国,这是回报范叔的聘问。 +由于高氏受到放逐的缘故,高竖在卢地发动叛乱。十月二十七日,闾丘婴带兵包围卢地。高竖说:“如果让高氏有后代,我请求把封邑交还给国君。”齐国人立了敬仲的曾孙酀,这是认为敬仲贤良。十一月二十三日,高竖归还卢地而逃亡到晋国,晋国人在绵地筑城,把他安置在那里。 +郑国的伯有派公孙黑去楚国,公孙黑不肯去,说:“楚国和郑国正在关系不好,互相憎恨,而派我去,这是等于杀死我。”伯有说:“你家世世代代都是办外交的。”公孙黑说:“可以去就去,有困难就不去,有什么世世代代是办外交的。”伯有要强迫他去。公孙黑发怒,准备攻打伯有氏,大夫们为他们调和。十二月初七日,郑国的大夫们在伯有家里结盟。裨谌说:“这次结盟,它能管多久呢?《诗》说:‘君子多次结盟,动乱因此滋长。’现在这样是滋长动乱的做法,祸乱不能停止,一定要三年然后才能解除。”然明说:“政权将会到哪家去?”裨谌说:“好人代替坏人,这是天命,政权哪能避开子产?如果不是越级提拔别人,那么按班次也应该子产执政了。选择贤人而提拔,这是为大家所尊重的。上天又为子产清除障碍,使伯有丧失了精神,子西又去世了,执政的人只有子产不能辞其责。上天降祸于郑国很久了,一定要让子产平息它,国家才可以安定。不这样,就将会灭亡了。” + +襄公三十年 +【经】三十年春王正月,楚子使薳罢来聘。夏四月,蔡世子般弑其君固。五月甲午。宋灾。宋伯姬卒。天王杀其弟佞夫。王子瑕奔晋。秋七月,叔弓如宋,葬宋共姬。郑良霄出奔许,自许入于郑,郑人杀良霄。冬十月,葬蔡景公。晋人、齐人、宋人、卫人、郑人、曹人、莒人、邾人、滕子、薛人、杞人、小邾人会于澶渊,宋灾故。 +【传】三十年春,王正月,楚子使薳罢来聘,通嗣君也。穆叔问:“王子之为政何如?”对曰:“吾侪小人,食而听事,犹惧不给命而不免于戾,焉与知政?”固问焉,不告。穆叔告大夫曰:“楚令尹将有大事,子荡将与焉,助之匿其情矣。” +子产相郑伯以如晋,叔向问郑国之政焉。对曰:“吾得见与否,在此岁也。驷、良方争,未知所成。若有所成,吾得见,乃可知也。”叔向曰:“不既和矣乎?”对曰:“伯有侈而愎,子皙好在人上,莫能相下也。虽其和也,犹相积恶也,恶至无日矣。” +三月癸未,晋悼夫人食舆人之城杞者。绛县人或年长矣,无子,而往与于食。有与疑年,使之年。曰:“臣小人也,不知纪年。臣生之岁,正月甲子朔,四百有四十五甲子矣,其季于今三之一也。”吏走问诸朝,师旷曰:“鲁叔仲惠伯会郤成子于承匡之岁也。是岁也,狄伐鲁。叔孙庄叔于是乎败狄于咸,获长狄侨如及虺也豹也,而皆以名其子。七十三年矣。”史赵曰:“亥有二首六身,下二如身,是其日数也。”士文伯曰:“然则二万六千六百有六旬也。” +赵孟问其县大夫,则其属也。召之,而谢过焉,曰:“武不才,任君之大事,以晋国之多虞,不能由吾子,使吾子辱在泥涂久矣,武之罪也。敢谢不才。”遂仕之,使助为政。辞以老。与之田,使为君复陶,以为绛县师,而废其舆尉。于是,鲁使者在晋,归以语诸大夫。季武子曰:“晋未可媮也。有赵孟以为大夫,有伯瑕以为佐,有史赵、师旷而咨度焉,有叔向、女齐以师保其君。其朝多君子,其庸可媮乎?勉事之而后可。” +夏四月己亥,郑伯及其大夫盟。君子是以知郑难之不已也。 +蔡景侯为大子般娶于楚,通焉。大子弑景侯。 +初,王儋季卒,其子括将见王,而叹。单公子愆期为灵王御士,过诸廷,闻其叹而言曰:“乌乎!必有此夫!”入以告王,且曰:“必杀之!不戚而愿大,视躁而足高,心在他矣。不杀,必害。”王曰:“童子何知?”及灵王崩,儋括欲立王子佞夫,佞夫弗知。戊子,儋括围蒍,逐成愆。成愆奔平畦。五月癸巳,尹言多、刘毅、单蔑、甘过、巩成杀佞夫。括、瑕、廖奔晋。书曰“天王杀其弟佞夫。”罪在王也。 +或叫于宋大庙,曰:“譆,譆!出出!”鸟鸣于亳社,如曰:“譆譆。”甲午,宋大灾。宋伯姬卒,待姆也。君子谓:“宋共姬,女而不妇。女待人,妇义事也。” +六月,郑子产如陈莅盟。归,覆命。告大夫曰:“陈,亡国也,不可与也。聚禾粟,缮城郭,恃此二者,而不抚其民。其君弱植,公子侈,大子卑,大夫敖,政多门,以介于大国,能无亡乎?不过十年矣。” +秋七月,叔弓如宋,葬共姬也。 +郑伯有耆酒,为窟室,而夜饮酒击钟焉,朝至未已。朝者曰:“公焉在?”其人曰:“吾公在壑谷。”皆自朝布路而罢。既而朝,则又将使子皙如楚,归而饮酒。庚子,子皙以驷氏之甲伐而焚之。伯有奔雍梁,醒而后知之,遂奔许。大夫聚谋,子皮曰:“《仲虺之志》云:‘乱者取之,亡者侮之。推亡固存,国之利也。’罕、驷、丰同生。伯有汰侈,故不免。” +人谓子产:“就直助强!”子产曰:“岂为我徒?国之祸难,谁知所儆?或主强直,难乃不生。姑成吾所。”辛丑,子产敛伯有氏之死者而殡之,不乃谋而遂行。印段从之。子皮止之,众曰:“人不我顺,何止焉?”子皮曰:“夫人礼于死者,况生者乎?”遂自止之。壬寅,子产入。癸卯,子石入。皆受盟于子皙氏。乙巳,郑伯及其大夫盟于大宫。盟国人于师之梁之外。 +伯有闻郑人之盟己也,怒。闻子皮之甲不与攻己也,喜。曰:“子皮与我矣。”癸丑,晨,自墓门之渎入,因马师颉介于襄库,以伐旧北门。驷带率国人以伐之。皆召子产。子产曰:“兄弟而及此,吾从天所与。”伯有死于羊肆,子产襚之,枕之股而哭之,敛而殡诸伯有之臣在市侧者。既而葬诸斗城。子驷氏欲攻子产,子皮怒之曰:“礼,国之干也,杀有礼,祸莫大焉。”乃止。 +于是游吉如晋还,闻难不入,覆命于介。八月甲子,奔晋。驷带追之,及酸枣。与子上盟,用两珪质于河。使公孙肸入盟大夫。己巳,复归。书曰“郑人杀良霄。”不称大夫,言自外入也。 +于子蟜之卒也,将葬,公孙挥与裨灶晨会事焉。过伯有氏,其门上生莠。子羽曰:“其莠犹在乎?”于是岁在降娄,降娄中而旦。裨灶指之曰:“犹可以终岁,岁不及此次也已。”及其亡也,岁在娵訾之口。其明年,乃及降娄。 +仆展从伯有,与之皆死。羽颉出奔晋,为任大夫。鸡泽之会,郑乐成奔楚,遂适晋。羽颉因之,与之比,而事赵文子,言伐郑之说焉。以宋之盟故,不可。子皮以公孙鉏为马师。 +楚公子围杀大司马蒍掩而取其室。申无宇曰:“王子必不免。善人,国之主也。王子相楚国,将善是封殖,而虐之,是祸国也。且司马,令尹之偏,而王之四体也。绝民之主,去身之偏,艾王之体,以祸其国,无不祥大焉!何以得免?” +为宋灾故,诸侯之大夫会,以谋归宋财。冬十月,叔孙豹会晋赵武、齐公孙虿、宋向戌、卫北宫佗、郑罕虎及小邾之大夫,会于澶渊。既而无归于宋,故不书其人。 +君子曰:“信其不可不慎乎!澶渊之会,卿不书,不信也夫!诸侯之上卿,会而不信,宠名皆弃,不信之不可也如是!《诗》曰:‘文王陟降,在帝左右。’信之谓也。又曰:‘淑慎尔止,无载尔伪。’不信之谓也。”书曰“某人某人会于澶渊,宋灾故。”尤之也。不书鲁大夫,讳之也。 +郑子皮授子产政,辞曰:“国小而逼,族大宠多,不可为也。”子皮曰:“虎帅以听,谁敢犯子?子善相之,国无小,小能事大,国乃宽。” +子产为政,有事伯石,赂与之邑。子大叔曰:“国,皆其国也。奚独赂焉?”子产曰:“无欲实难。皆得其欲,以从其事,而要其成,非我有成,其在人乎?何爱于邑?邑将焉往?”子大叔曰:“若四国何?”子产曰:“非相违也,而相从也,四国何尤焉?《郑书》有之曰:‘安定国家,必大焉先。’姑先安大,以待其所归。”既,伯石惧而归邑,卒与之。伯有既死,使大史命伯石为卿,辞。大史退,则请命焉。覆命之,又辞。如是三,乃受策入拜。子产是以恶其为人也,使次己位。 +子产使都鄙有章,上下有服,田有封洫,庐井有伍。大人之忠俭者,从而与之。泰侈者,因而毙之。 +丰卷将祭,请田焉。弗许,曰:“唯君用鲜,众给而已。”子张怒,退而征役。子产奔晋,子皮止之而逐丰卷。丰卷奔晋。子产请其田里,三年而复之,反其田里及其入焉。 +从政一年,舆人诵之,曰:“取我衣冠而褚之,取我田畴而伍之。孰杀子产,吾其与之!”及三年,又诵之,曰;“我有子弟,子产诲之。我有田畴,子产殖之。子产而死,谁其嗣之?” +译文 +三十年春季,周王朝历法的正月,楚王郏敖派遣薳罢来鲁国聘问,这是为新立的国君通好。穆叔问:“王子围执政的情况怎么样?”薳罢回答说:“我辈小人吃饭听使唤,还害怕不足以完成使命而不能免于罪过,哪里能参与政事?”再三地询问,他还是不回答。穆叔告诉大夫说:“楚国的令尹将要发动大乱,薳罢将参与协助,他在隐瞒情况。” +子产辅助郑简公而去到晋国,叔向问起郑国的政事。子产回答说:“我能不能见到,就在这一年了。驷氏、良氏正在争夺,不知道怎么调和。如果能调和,我能够见到,这就可以知道了。”叔向说:“不是已经和好了吗?”子产回答说:“伯有奢侈倔强而又固执,子皙喜欢居于别人之上,两人互不相让,虽然他们已经和好,还是积聚了憎恶,不久就会爆发。” +二月二十二日,晋悼公夫人请为杞国筑城的役卒吃饭。绛县人中间有一个人年纪很大了,没有儿子而自己服役,也去接受夫人的饭食。有人怀疑他的年龄,让他说出自己的年龄。他说:“下臣,是小人,不知道记录年龄。下臣生的那一年,是正月初一甲子日,已经过了四百四十五个甲子日了,最末一个甲子日到今天正好是二十天。”官吏走到朝廷里询问,师旷说:“这是鲁国的叔仲惠伯在承筐会见郤成子的那一年。这一年,狄人进攻鲁国,叔孙庄叔当时在碱地打败狄人,俘虏了长狄侨如和虺、豹,而都用来命名他儿子。满七十三岁了。”史赵说:“亥字是‘二’字头‘六’字身,把‘二’拿下来当作身子,这就是他的日子数。”士文伯说:“那么是二万六千六百六十天了。” +赵孟问起老人的县大夫是谁,原来就是他的下属。赵孟把老人召来向他道歉,说:“武没有才能,担负了国君的重要职务,由于晋国多有忧患,没有能任用您,让您屈居卑下已经很久了,这是武的罪过。谨由于没有才能而向您道歉。”于是就任命老人做官,派他辅助自己执政。老人因年纪大了而辞谢,赵孟就给了他土地,让他为国君办理免除徭役的事务,做绛地县师,而撤除了他的舆尉的职务。 +当时鲁国的使臣正在晋国,回去把这件事告诉了大夫们。季武子说:“晋国不能轻视啊。有赵孟做正卿,有伯瑕做辅佐,有史赵、师旷可以咨询,有叔向、女齐做国君的师保。他们朝廷上君子很多,哪里能够轻视呢?尽力事奉他们然后才可以。” +夏季四月某一天,郑简公和他的大夫结盟。君子因此而知道郑国的祸难还没有结束。 +蔡景侯为太子般在楚国娶妻,又和儿媳妇私通。太子杀死了蔡景侯。 +当初,周灵王的弟弟儋季死了,他的儿子括将要进见灵王,叹气。单国的公子愆期做灵王侍卫,经过朝廷,听到叹气声,就说:“啊,一定是想夺取朝廷的权!”进去把情况报告灵王,而且说:“一定要杀了他!他不悲哀而愿望大,目光到处张望而抬高脚,心在其他地方了。不杀,必然造成危害。”灵王说:“小孩子知道什么?等到灵王死去,儋括想要立王子佞夫。佞夫不知道。二十八日,儋括包围苏地,赶走成愆。成愆逃亡到平畤。五月初四日,尹言多、刘毅、单蔑、甘过、巩成杀了佞夫。括、瑕、廖逃亡到晋国。《春秋》记载说“天王杀死他的兄弟佞夫”,这是由于罪过在于周王。 +有人在宋国太庙里大喊大叫,说:“嘻嘻,出出。”鸟在亳社上鸣叫,声音好像在说:“嘻嘻。”五月初五日,宋国发生大火灾。宋伯姬被烧死,这是为了等待保姆来。君子认为:“宋伯姬奉行的是大闺女而不是媳妇的守则。大闺女应当等待保姆,媳妇就可以看具体情况行事。” +六月,郑国的子产去到陈国参加结盟,回来,复命。告诉大夫们说:“陈国,是要灭亡的国家,不能结好。他们积聚粮食,修理城郭,靠了这两条而不安抚百姓,他们的国君根基不巩固,公子奢侈,太子卑微,大夫骄傲,政事各行其是,谁也作不了主,在这种情况下处于大国之间,能够不灭亡吗?不超过十年了。” +秋季,七月,叔弓去到宋国,这是由于安葬共姬。 +郑国的伯有喜欢喝酒,造了地下室,并在夜里喝酒,奏乐。朝见的人来到,他还没有喝完酒。朝见的人说:“主人在哪里?”他的手下人说:“我们的主人在地下室。”朝见的人都分路回去。不久伯有去朝见郑伯,又要派子皙去楚国,回家以后又喝酒。七月十一日,子皙带者驷氏的甲士攻打并且放火烧了他的家。伯有逃亡到雍梁,酒醒以后才明白是怎么回事,于是又逃亡到许国。大夫们聚在一起商量。子皮说:“《仲虺之志》说:‘动乱的就攻取它,灭亡的就欺侮它。’摧毁灭亡的而巩固存在的,这是国家的利益。罕氏、驷氏、丰氏本来是同胞兄弟,伯有骄傲奢侈,所以不免于祸难。” +有人对子产说:“要靠拢正直的帮助强大的。”子产说:“他们难道是我的同伙?国家的祸难,谁知道如何平定?如果有主持国政的人强大而且正直,祸难就不会发生。姑且保住我的地位吧。”十二日,子产收了伯有氏死者的尸体而加以殡葬,来不及和大夫们商量就出走了。印段跟从他。子皮不让他走。大家说:“别人不顺从我们,为什么不让他走?”子皮说:“这个人对死去的人有礼,何况对活着的人呢?”于是就亲自劝阻子产。十三日,子产进入国都。十四日,印段进入国都。两个人都在子皙家里接受了盟约。十六日,郑简公和他的大夫们在太庙结盟,又与国内的人们在郑国城门外结盟。 +伯有听到郑国人为他结盟,很生气;听到子皮的甲士没有参加攻打他,很高兴,说:“子皮帮助我了。”二十四日,从墓门的排水洞进入,靠着马师颉用襄库的兵甲装备士兵,带着他们攻打旧北门。驷带率领国内的人们攻打伯有。两家都召请子产。子产说:“兄弟之间到达这地步,我服从上天所要帮助的一家。”伯有死在买卖羊的街市上,子产给伯有的尸体穿上衣服,头枕在尸体的大腿上而为他号哭,收尸并把棺材停放在街市旁边伯有家臣的家里,不久又葬在斗城。驷氏想要攻打子产。子皮为这发怒,说:“礼仪,是国家的支柱。杀死有礼的人,没有比这再大的祸患了。”于是就停止了。 +当时,游吉去晋国以后回来,听说发生祸难,不进入。让副手回来复命。八月初六日,逃亡到晋国。驷带追赶他,到达酸枣。游吉和驷带结盟,把两件玉圭沉在黄河里表示诚意。让公孙肸进入国都和大夫结盟。十一日,游吉再次回到国内。《春秋》记载说:“郑人杀良霄。”不称他为大夫,这是说伯有从国外进来已经丧失官位了。 +当子蟜死了以后,将要安葬时,公孙挥和裨灶早晨商量丧事。他们路过伯有氏家时,看见门上长了狗尾草,公孙挥说:“他门上的狗尾巴草还在吗?”当时岁星在降娄,降娄星在天空中部,天就亮了。裨灶指着降娄星,说:“还可以等岁星绕一周,不过活不到岁星再到这个位置就是了。”等到伯有被杀,岁星正在娵訾的口上,明年才能到达降娄。 +仆展跟从伯有,和他一起死了。羽颉逃亡到晋国,做了任邑的长官。鸡泽的会见,郑国的乐成逃亡到楚国,就乘机去到晋国。羽颉靠着他,和他勾结着一起奉事赵文子,提出了进攻郑国的建议。由于有宋国盟誓的缘故,赵文子不同意这项建议。子皮让公孙鉏代替羽颉做了马师。 +楚国的公子围杀了大司马?掩而占取了他的家财。申无宇说:“王子必然不能免于祸难。善人,是国家的栋梁。王子辅助楚国的政事,应该培养好人,现在反倒对他们暴虐,这是危害国家。而且司马,是令尹的辅佐,也是国君的手足。断绝百姓的栋梁,去掉自己的辅佐,斩除国君的手足,以危害国家,没有比这再大的不吉利了。怎么能免于祸难呢?” +为了宋国火灾的缘故,诸侯的大夫会见,商量给宋国赠送财货。冬季十月,叔孙豹和晋国赵武、齐国的公孙虿、宋国的向戌、卫国的北宫佗、郑国的罕虎以及小邾国的大夫在澶渊会见,并没有给宋国赠送什么东西,所以《春秋》没有记载与会者的姓名。 +君子说:“信用恐怕不能不谨慎吧!澶渊的会见,不记载卿的名字,这是由于不守信用的缘故。诸侯的上卿,会见了又不守信用,他们尊贵的姓名全都丢掉了,不守信用是这样的不可以啊。《诗》说,‘文王或升或降,都是在天帝的左右’,这是说要守信义。又说,‘好好地谨慎你的行动,不要表现你的虚伪’,这是说不守信义。”《春秋》记载说“某人某人会于澶渊,宋灾故”,这是为了责备他们。不记载鲁国的大夫,这是由于为他隐瞒。 +郑国的子皮把政权交给子产,子产辞谢说:“国家小而逼近大国,家族庞大而受宠的人又多,我不能治理好。”子皮说:“虎率领他们听从,谁敢触犯您?您好好地辅助国政吧。国家不在于小,小国能够事奉大国,国家就可以不受逼迫了。” +子产治理政事,有事情要伯石去办,赠送给他城邑,子太叔说:“国家是大家的国家,为什么独给他送东西?”子产说:“要没有欲望确实是难的。使他们都满足欲望,去办他们的事情而取得成功。这不是我的成功,难道是别人的成功吗?对城邑有什么爱惜的,它会跑到哪里去?”子太叔说:“四方邻国将怎么看待?”子产说:“这样做不是为了互相违背,而是为了互相顺从,四方的邻国对我们有什么可责备的?《郑书》有这样的话:‘安定国家,一定要优先照顾大族。’姑且先照顾大族,再看它归向何处。”不久,伯石恐惧而把封邑归还,最终子产还是把城邑给了他。伯有死了以后,郑简公让太史去命令伯石做卿,伯石辞谢。太史退出,伯石又请求太史重新发布命令,命令下来了再次辞谢。像这样一连三次,这才接受策书入朝拜谢。子产因此讨厌伯石的为人,但担心他作乱,就让他居于比自己低一级的地位。 +子产让城市和乡村有所区别,上下尊卑各有职责,田土四界有水沟,庐舍和耕地能互相适应。对卿大夫中忠诚俭朴的,听从他,亲近他;骄傲奢侈的,推翻他。 +丰卷准备祭祀,请求猎取祭品。子产不答应,说:“只有国君祭祀才用新猎取的野兽,一般人只要大致足够就可以了。”丰卷生气,退出以后就召集士兵。子产准备逃亡到晋国,子皮阻止他而驱逐了丰卷。丰卷逃亡到晋国,子产请求不要没收他的田地住宅,三年以后让丰卷回国复位,把他的田地住宅和一切收入都退还给他。 +子产参与政事一年,人们歌唱道:“计算我的家产而收财物税,丈量我的耕地而征收田税。谁杀死子产,我就帮助他。”到了三年,又歌唱道:“我有子弟,子产教诲;我有土田,子产使之增产。万一子产逝世谁来接替他呢?” + +襄公三十一年 +【经】三十有一年春王正月。夏六月辛巳,公薨于楚宫。秋九月癸巳,子野卒。己亥,仲孙羯卒。冬十月,滕子来会葬。癸酉,葬我君襄公。十有一月,莒人杀其君密州。 +【传】三十一年春,王正月,穆叔至自会,见孟孝伯,语之曰:“赵孟将死矣。其语偷,不似民主。且年未盈五十,而谆谆焉如八九十者,弗能久矣。若赵孟死,为政者其韩子乎!吾子盍与季孙言之,可以树善,君子也。晋君将失政矣,若不树焉,使早备鲁,既而政在大夫,韩子懦弱,大夫多贪,求欲无厌,齐、楚未足与也,鲁其惧哉!”孝伯曰:“人生几何?谁能无偷?朝不及夕,将安用树?”穆叔出而告人曰:“孟孙将死矣。吾语诸赵孟之偷也,而又甚焉。”又与季孙语晋故,季孙不从。 +及赵文子卒,晋公室卑,政在侈家。韩宣子为政,为能图诸侯。鲁不堪晋求,谗慝弘多,是以有平丘之会。 +齐子尾害闾丘婴,欲杀之,使帅师以伐阳州。我问师故。夏五月,子尾杀闾丘婴以说于我师。工偻洒、渻灶、孔虺、贾寅出奔莒。出群公子。 +公作楚宫。穆叔曰:“《大誓》云:‘民之所欲,天必从之。’君欲楚也夫!故作其宫。若不复适楚,必死是宫也。”六月辛巳,公薨于楚宫。叔仲带窃其拱璧,以与御人,纳诸其怀而从取之,由是得罪。 +立胡女敬归之子子野,次于季氏。秋九月癸巳,卒,毁也。 +己亥,孟孝伯卒。 +立敬归之娣齐归之子公子裯,穆叔不欲,曰:“大子死,有母弟则立之,无则长立。年钧择贤,义钧则卜,古之道也。非适嗣,何必娣之子?且是人也,居丧而不哀,在戚而有嘉容,是谓不度。不度之人,鲜不为患。若果立之,必为季氏忧。”武子不听,卒立之。比及葬,三易衰,衰衽如故衰。于是昭公十九年矣,犹有童心,君子是以知其不能终也。 +冬十月,滕成公来会葬,惰而多涕。子服惠伯曰:“滕君将死矣!怠于其位,而哀已甚,兆于死所矣。能无从乎?”癸酉,葬襄公。 +公薨之月,子产相郑伯以如晋,晋侯以我丧故,未之见也。子产使尽坏其馆之垣而纳车马焉。士文伯让之,曰:“敝邑以政刑之不修,寇盗充斥,无若诸侯之属辱在寡君者何?是以令吏人完客所馆,高其□闳,厚其墙垣,以无忧客使。今吾子坏之,虽从者能戒,其若异客何?以敝邑之为盟主,缮完葺墙,以待宾客,若皆毁之,其何以共命?寡君使□请命。”对曰:“以敝邑褊小,介于大国,诛求无时,是以不敢宁居,悉索敝赋,以来会时事。逢执之不间,而未得见,又不获闻命,未知见时,不敢输币,亦不敢暴露。其输之,则君之府实也,非荐陈之,不敢输也。其暴露之,则恐燥湿之不时而朽蠹,以重敝邑之罪。侨闻文公之为盟主也,宫室卑庳,无观台榭,以崇大诸侯之馆。馆如公寝,库厩缮修,司空以时平易道路,圬人以时塓馆宫室。诸侯宾至,甸设庭燎,仆人巡宫,车马有所,宾从有代,巾车脂辖,隶人牧圉,各瞻其事,百官之属,各展其物。公不留宾,而亦无废事,忧乐同之,事则巡之,教其不知,而恤其不足。宾至如归,无宁灾患?不畏寇盗,而亦不患燥湿。今铜鞮之宫数里,而诸侯舍于隶人。门不容车,而不可逾越。盗贼公行,而天厉不戒。宾见无时,命不可知。若又勿坏,是无所藏币,以重罪也。敢请执事,将何以命之?虽君之有鲁丧,亦敝邑之忧也。若获荐币,修垣而行,君之惠也,敢惮勤劳?”文伯覆命,赵文子曰:“信!我实不德,而以隶人之垣以赢诸侯,是吾罪也。”使士文伯谢不敏焉。晋侯见郑伯,有加礼,厚其宴好而归之。乃筑诸侯之馆。 +叔向曰:“辞之不可以已也如是夫!子产有辞,诸侯赖之,若之何其释辞也?《诗》曰:‘辞之辑矣,民之协矣。辞之绎矣,民之莫矣。’其知之矣。” +郑子皮使印段如楚,以适晋告,礼也。 +莒犁比公生去疾及展舆,既立展舆,又废之。犁比公虐,国人患之。十一月,展舆因国人以攻莒子,弑之,乃立。去疾奔齐,齐出也。展舆,吴出也。书曰“莒人弑其君买朱鉏。”言罪之在也。 +吴子使屈狐庸聘于晋,通路也。赵文子问焉,曰:“延州来季子其果立乎?巢陨诸樊,阍戕戴吴,天似启之,何如?”对曰:“不立。是二王之命也,非启季子也。若天所启,其在今嗣君乎!甚德而度,德不失民,度不失事,民亲而事有序,其天所启也。有吴国者,必此君之子孙实终之。季子,守节者也。虽有国,不立。” +十二月,北宫文子相卫襄公以如楚,宋之盟故也。过郑,印段廷劳于棐林,如聘礼而以劳辞。文子入聘。子羽为行人,冯简子与子大叔逆客。事毕而出,言于卫侯曰:“郑有礼,其数世之福也,其无大国之讨乎!《诗》曰:‘谁能执热,逝不以濯。’礼之于政,如热之有濯也。濯以救热,何患之有?” +子产之从政也,择能而使之。冯简子能断大事,子大叔美秀而文,公孙挥能知四国之为,而辨于其大夫之族姓、班位、贵贱、能否,而又善为辞令,裨谌能谋,谋于野则获,谋于邑则否。郑国将有诸侯之事,子产乃问四国之为于子羽,且使多为辞令。与裨谌乘以适野,使谋可否。而告冯简子,使断之。事成,乃授子大叔使行之,以应对宾客。是以鲜有败事。北宫文子所谓有礼也。 +郑人游于乡校,以论执政。然明谓子产曰:“毁乡校,何如?”子产曰:“何为?夫人朝夕退而游焉,以议执政之善否。其所善者,吾则行之。其所恶者,吾则改之。是吾师也,若之何毁之?我闻忠善以损怨,不闻作威以防怨。岂不遽止,然犹防川,大决所犯,伤人必多,吾不克救也。不如小决使道。不如吾闻而药之也。”然明曰:“蔑也今而后知吾子之信可事也。小人实不才,若果行此,其郑国实赖之,岂唯二三臣?” +仲尼闻是语也,曰:“以是观之,人谓子产不仁,吾不信也。” +子皮欲使尹何为邑。子产曰:“少,未知可否?”子皮曰:“愿,吾爱之,不吾叛也。使夫往而学焉,夫亦愈知治矣。”子产曰:“不可。人之爱人,求利之也。今吾子爱人则以政,犹未能操刀而使割也,其伤实多。子之爱人,伤之而已,其谁敢求爱于子?子于郑国,栋也,栋折榱崩,侨将厌焉,敢不尽言?子有美锦,不使人学制焉。大官、大邑,身之所庇也,而使学者制焉,其为美锦,不亦多乎?侨闻学而后入政,未闻以政学者也。若果行此,必有所害。譬如田猎,射御贯则能获禽,若未尝登车射御,则败绩厌覆是惧,何暇思获?”子皮曰:“善哉!虎不敏。吾闻君子务知大者、远者,小人务知小者、近者。我,小人也。衣服附在吾身,我知而慎之。大官、大邑所以庇身也,我远而慢之。微子之言,吾不知也。他日我曰:‘子为郑国,我为吾家,以庇焉,其可也。’今而后知不足。自今,请虽吾家,听子而行。”子产曰:“人心之不同,如其面焉。吾岂敢谓子面如吾面乎?抑心所谓危,亦以告也。”子皮以为忠,故委政焉。子产是以能为郑国。 +卫侯在楚,北宫文子见令尹围之威仪,言于卫侯曰:“令尹似君矣!将有他志,虽获其志,不能终也。《诗》云:‘靡不有初,鲜克有终。’终之实难,令尹其将不免?”公曰:“子何以知之?”对曰:“《诗》云:‘敬慎威仪,惟民之则。’令尹无威仪,民无则焉。民所不则,以在民上,不可以终。”公曰:“善哉!何谓威仪?”对曰:“有威而可畏谓之威,有仪而可像谓之仪。君有君之威仪,其臣畏而爱之,则而象之,故能有其国家,令闻长世。臣有臣之威仪,其下畏而爱之,故能守其官职,保族宜家。顺是以下皆如是,是以上下能相固也。《卫诗》曰:‘威仪棣棣,不可选也。’言君臣、上下、父子、兄弟、内外、大小皆有威仪也。《周诗》曰:‘朋友攸摄,摄以威仪。’言朋友之道,必相教训以威仪也。《周书》数文王之德,曰:‘大国畏其力,小国怀其德。’言畏而爱之也。《诗》云:‘不识不知,顺帝之则。’言则而象之也。纣囚文王七年,诸侯皆从之囚。纣于是乎惧而归之,可谓爱之。文王伐崇,再驾而降为臣,蛮夷帅服,可谓畏之。文王之功,天下诵而歌舞之,可谓则之,文王之行,至今为法,可谓象之。有威仪也。故君子在位可畏,施舍可爱,进退可度,周旋可则,容止可观,作事可法,德行可像,声气可乐,动作有文,言语有章,以临其下,谓之有威仪也。” +译文 +三十一年春季,周王朝历法的正月,穆叔从澶渊会见回来,见了孟孝伯,对他说:“赵孟将要死了。他的话毫无远虑,不像百姓的主人。而且年纪不到五十,就絮絮叨叨好像八九十岁的人,他不能活得很长久了。如果赵孟死了,掌握政权的恐怕是韩起吧!您为何不对季孙去说这件事,可以及早建立友好关系,他是个君子。晋国的国君将要失去政权了,如果不去建立友好,让韩子早点为鲁国做些准备工作,不久以后政权落在大夫手里,韩子又懦弱,大夫大多贪婪,要求和欲望没有个止境,齐国、楚国却不足以依靠,鲁国将陷入可怕的困境!”孟孝伯说:“人的一辈子能活多久,谁能说没有点得过且过的思想?早晨活着还怕到不了晚上,哪里用得着去建立友好?”穆叔出去,告诉别人说:“孟孝伯将要死了。我告诉他赵孟的得过且过,但他比赵孟还不如。”又和季孙说到晋国的事情,季孙不听。等到赵文子死了,晋国公室的地位下降,政权落在豪奢的大夫手里。韩宣子掌握国政,不能为诸侯所拥护。鲁国难以担负晋国的要求,奸邪小人很多,因此有了平丘的会见。 +齐国的子尾惧怕闾丘婴,想杀死他,派他带兵进攻阳州。我国询问他们为什么要出兵。夏季,五月,子尾杀了闾丘婴,来向我军解释。工偻洒、渻灶、孔虺、贾寅逃亡到莒国。子尾驱逐了公子们。 +鲁襄公建造楚国式的宫殿。穆叔说:“《大誓》说:‘百姓所要求的,上天必然听从。’国君想要楚国了,所以建造楚国式的宫殿。如果不再去楚国,必然死在这座宫殿里。” +六月二十八日,鲁襄公死在楚宫里。 +叔仲带偷了襄公的大玉璧,给了驾车的人,放在他的怀里,又从他那里拿了过来,因此而得罪。 +鲁国拥立胡国女人敬归的儿子子野,住在季氏那里。秋季,九月十一日,子野死,这是由于哀痛过度。 +十七日,孟孝伯死了。 +鲁国拥立敬归的妹妹齐归生的儿子公子裯为国君。穆叔不愿意,说:“太子死了,有同母兄弟就立他,没有就立年长的。年纪差不多就选择贤能的,贤能又差不多就占卜,这是古代的常规。死去的子野并不是嫡子,何必非要立他母亲的妹妹的儿子?而且这个人,居丧却不哀痛,父母死了反而有喜悦的脸色,这叫做不孝。不孝的人,很少不捣乱的。假如立了他,必然造成季氏的忧患。”季武子不听,结果立了他。等到安葬襄公,三次更换丧服,丧服的衣襟脏得好像旧丧服一样。当时昭公已十九岁了,还有孩子脾气,君子因此知道他不能善终。 +冬季,十月,滕成公来鲁国参加葬礼,表现得不恭敬而眼泪很多。子服惠伯说:“滕国的国君将要死了。在他吊临的位置上表现懈怠,而哀痛太过分,在葬礼中已经显出将死的预兆了,能够不相继死吗?” +十月二十一日,安葬鲁襄公。 +襄公死去的那一个月,子产陪同郑简公到晋国去,晋平公由于我国有丧事,没有接见。子产派人将晋国宾馆的围墙全部拆毁而安放自己的车马。士文伯责备他,说:“敝邑由于政事和刑罚不够完善,到处都是盗贼,无奈诸侯的属官来向寡君朝聘,因此派官吏修缮宾客所住的馆舍,加高大门,围墙增厚,以不让宾客使者担忧。现在您拆毁了它,虽然您的随从能够自己戒备,让别国的宾客又怎么办呢?由于敝邑是盟主,修缮围墙,为接待宾客。如果都拆毁了,那么将怎么供应宾客的需要呢?寡君派匄前来请问拆墙的意图。” +子产回答说:“由于敝邑地方狭小,夹在大国之间,而大国需索贡品又没有一定的时候,因此不敢安居,尽量搜索敝邑的财富,以便随时来朝会。碰上执事没有空闲,而没有能够见到;又得不到命令,不知道什么时候才能接见。我们不敢献上财币,也不敢让它日晒夜露。如果奉献,那么它就是君王府库中的财物,不经过在庭院里陈列的仪式,就不敢奉献。如果让它日晒夜露,就又害怕时而干燥时而潮湿因而腐朽坏,以加重敝邑的罪过。侨听说晋文公做盟主的时候,宫室矮小,没有可供观望的台榭,而把接待诸侯的宾馆修得又高又大,宾馆好像现在君王的寝宫一样。对宾馆内的库房、马厩都加以修缮,司空及时整修道路,泥瓦工按时粉刷墙壁,诸侯的宾客来了,甸人点起火把,仆人巡逻宫馆。车马有一定的处所,宾客的随从有人替代服役,管理车子的管理员为车轴加油,打扫的人、牧羊人、养马的人各人做自己分内的事情。各部官吏各自陈列他的礼品。文公不让宾客耽搁,也没有因为这样而荒废宾主的公事。和宾客忧乐相同,有事就加以安抚,对宾客所不知道的加以教导,不周到的加以体谅。宾客来到晋国就像在自己家里一样,还有什么灾患?不怕抢劫偷盗,也不担心干燥潮湿。现在铜鞮山的宫室绵延几里,而诸侯住在像奴隶住的屋子里,门口进不去车子,而又不能翻墙而入。盗贼公开行动,而传染病又不能防止。宾客进见诸侯没有一定的时候,君王接见的命令也不知道什么时候才能发布。如果还不拆毁围墙,这就没有地方收藏财礼,反而要加重罪过了。”谨敢问执事,对我们将有什么指示?虽然君王有鲁国的丧事,但这同样也是敝国的忧虑。如果能够奉上财礼,我们愿把围墙修好了再走。这是君王的恩惠,岂敢害怕修墙的辛勤劳动!” +文伯回到朝廷汇报。赵文子说:“说得对。我们实在是不好,用容纳奴隶的房屋去接待诸侯,这是我们的罪过啊。”就派士文伯去表示歉意并说自己无能。晋平公接见郑简公,礼仪有加,举行极隆重的宴会,赠送更加丰厚,然后让他回去。于是就建造接待诸侯的宾馆。叔向说:“辞令的不能废弃就像这样吧!子产善于辞令,诸侯因他而得利,为什么要放弃辞令呢?《诗》说:‘辞令和谐,百姓团结,辞令动听,百姓安定。’他已经懂得这个道理了。” +郑国的子皮派印段去楚国,先到晋国报告这件事,这是合于礼的。 +莒犁比公生了去疾和展舆,已经立了展舆,又废了他。犁比公暴虐,国内的人们为此担心。十一月,展舆倚靠国内的人们攻打莒犁比公,杀死了他,就自立为国君。去疾逃亡到齐国,因为他是齐女所生的。展舆是吴女所生,《春秋》记载说“莒人弑其君买朱鉏”,这是说罪过在于莒犁比公。 +吴王派屈狐庸到晋国聘问,这是为了沟通吴、晋两国交往的道路。赵文子询问他,说:“延州来季子最终能立为国君吗?从前进攻巢地死了诸樊,看门人杀了戴吴,上天似乎为季子打开了做国君的大门,怎么样?”屈狐庸回答说:“不立。这是两位国王的命运不好,不是为季子打开做国君的大门。如果上天打开了大门,恐怕是为了现在的国君吧!他很有德行而又合于法度。有德行就不会失去百姓,合于法度就不会办错事情。百姓亲附而事情有秩序,大概是上天为他打开大门的。保有吴国的,最后一定是这位国君的子孙。季子,是保持节操的人,虽然他应享有国家,也是不愿做国君的。” +十二月,北宫文子陪同卫襄公到楚国去,这是由于在宋国结盟的缘故。经过郑国,印段到棐林去慰劳他们,依照聘问的礼仪,而使用慰劳的辞令。文子进入国都聘问。子羽做行人,冯简子和太叔迎接客人。事情完毕以后文子出来,对卫襄公说:“郑国讲究礼仪,这是几代的福气,恐怕不会有大国去讨伐他吧!《诗》说:‘谁能耐热,不去洗澡。’礼仪对于政事,好像天热得要洗澡一样。洗澡用来消除炎热,有什么可担心的?” +子产参与政事,选择贤能而使用他们。冯简子能决断大事。子太叔外貌秀美而内有文采。子羽能了解四方诸侯的政令而且了解他们大夫的家族姓氏、官职爵位、地位贵贱、才能高低,又善于辞令。裨谌能出谋划策,在野外策划就正确,在城里策划就不得当。郑国将要有外交上的事情,子产就向子羽询问四方诸侯的政令,并且让他写一些有关的外交辞令稿;和裨谌一起坐车到野外去,让他策划是否可行;把结果告诉冯简子,让他决定。计划完成,就交给子太叔执行,交往诸侯应对宾客,所以很少有把事情办坏的时候。这就是北宫文子所说的讲究礼节。 +郑国人在乡校里游玩聚会,议论国家政事。然明对子产说:“毁了乡校怎么样?”子产说:“为什么?人们早晚事情完了到那里游玩,来议论政事的好坏。他们认为好的,我就推行它;他们所讨厌的,我就改掉它。这是我的老师。为什么要毁掉它?我听说用忠于为善,能减少怨恨,没有听说用摆出权威能防止怨恨。靠权威难道不能很快制止议论?但是就像防止河水一样:大水来了,伤人必然很多,我不能挽救。不如把水稍稍放掉一点加以疏通,不如让我听到这些话而作为药石。”然明说:“蔑从今以后知道您确实是可以成就大事的。小人实在没有才能。如果终于这样做下去,这确实有利于郑国,岂独有利于二三位大臣?” +孔子听到这些话,说:“从这里来看,别人说子产不仁,我不相信。” +子皮想要让尹何来治理自己的封邑。子产说:“尹何年纪轻,不知道能不能胜任。”子皮说:“这个人谨慎善良,我喜欢他,他不会背叛我的。让他去学习一下,他也就更加知道该怎么办事情了。”子产说:“不行。人家喜欢一个人,总是希望对这个人有利。现在您喜欢一个人却把政事交给他,这好像一个人不会用刀而让他去割东西,多半是要损伤他自己的。您喜欢他,不过是伤害他罢了,有谁还敢在您这里求得喜欢?您对于郑国来说是国家的栋梁。栋梁折断,椽子就会崩塌,侨将会被压在底下,我哪敢不把话全部说出来?您有了漂亮的丝绸,是不会让别人用它来学习裁制的。大官和大的封邑,是庇护自身的,反而让学习的人去裁制,这比起漂亮的丝绸来价值不就多得多吗?侨听说学习以后才能从政,没有听说用从政来学习的。如果真是这么办,一定有所伤害。譬如打猎,熟悉射箭驾车的,就能获得猎物,如果从没有登车射过箭驾过车,那么只担心翻车被压,哪里有闲心想获得猎物?”子皮说:“好啊!虎真是不聪明。我听说君子懂得大的远的,小人只懂得小的近的。我,是小人啊。衣服穿在我身上,我知道而且慎重对待它,大官和大的封邑是用来庇护自身的,我却疏远而且轻视它。要没有您的话,我是不知道的。从前我曾说过,您治理郑国,我治理我的家族以庇护我自己,这就可以了。从今以后才知道这样不行。从现在起我请求,虽然是我家族的事情,也听从您的意见去办理。”子产说:“每个人的想法不一样,好像他的面孔,我难道敢说您的面孔像我的面孔吗?不过心里觉得这样做是危险的,就把它告诉您了。”子皮认为他忠诚,所以把政事全交付给他。子产因此能够执掌郑国大权。 +卫襄公在楚国,北宫文子见到楚令尹围的仪表,对卫襄公说:“令尹的言行像国君了,将要有别的想法。虽然能实现这种想法,但是不能善终。《诗》说:‘什么都有个开头,可是很少能有好的结束。’善终实在很难,令尹恐怕要不能免于祸难。”卫襄公说:“你怎么知道?”北宫文子回答说:“《诗》说:‘恭敬而慎重地使用威仪,因为它是百姓的准则。’令尹没有威仪,百姓就没有准则。百姓所不会效法的人,而在百姓之上,就不能善终。”卫襄公说:“好啊!什么叫威仪?”北宫文子回答说:“有威严而使人能害怕叫做威,有仪表而使人能仿效叫做仪。国君有国君的威仪,他的臣子敬畏而爱戴他,把他作为准则而仿效他,所以能保有他的国家,有好名声,传于子孙后代。臣子有臣子的威仪,他的下面害怕而爱护他,所以能保住他的官职,保护家族,使家庭和睦。按照这个次序以下都像这样,因此上下能够互相巩固。《卫诗》说‘威仪安详,好处不能计量’,这是说君臣、上下、父子、兄弟、内外、大小都有威仪。《周诗》说,‘朋友之间互相辅助,所用的就是威仪’,这是说朋友之道一定要用威仪来互相教导。《周书》列举文王的德行,说,‘大国害怕他的力量,小国怀念他的恩德’,这是说对他既害怕而又爱护。《诗》说,‘无知无识,顺着天帝的准则’,这是说把他作为准则而加以仿效。殷纣王囚禁周文王七年,诸侯跟着他去坐牢,纣王于是就害怕而把文王放了回去。可以说是敬爱文王了,文王攻打崇国,两次发兵,崇国就降服为臣,蛮夷相继归服,可以说是害怕文王了。文王的功业,天下赞诵而歌舞,可以说以文王为准则了。文王的措施,到今天还作为法则,可以说是仿效文王了。这是因为有威仪的缘故。所以君子在官位上可使人怕他,施舍可使人爱他,进退可以作为法度,应付得体,容貌举止可以值得观赏,做事情可以让人学习,德行可以作为仿效,声音气度可以使人高兴,举动有修养,说话有条理,用这些来对待下面的人,这就叫做有威仪。” + + +昭公 + +昭公元年 +【经】元年春王正月,公即位。叔孙豹会晋赵武、楚公子围、齐国弱、宋向戌、卫齐恶、陈公子招、蔡公孙归生、郑罕虎、许人、曹人于虢。三月,取郓。夏,秦伯之弟金咸出奔晋。六月丁巳,邾子华卒。晋荀吴帅师败狄于大卤。秋,莒去疾自齐入于莒。莒展舆出奔吴。叔弓帅师疆郓田。葬邾悼公。冬十有一月己酉,楚子麇卒。公子比出奔晋。 +【传】元年春,楚公子围聘于郑,且娶于公孙段氏,伍举为介。将入馆,郑人恶之,使行人子羽与之言,乃馆于外。既聘,将以众逆。子产患之,使子羽辞,曰:“以敝邑褊小,不足以容从者,请墠听命!”令尹命大宰伯州犁对曰:“君辱贶寡大夫围,谓围:‘将使丰氏抚有而室。围布几筵,告于庄、共之庙而来。若野赐之,是委君贶于草莽也!是寡大夫不得列于诸卿也!不宁唯是,又使围蒙其先君,将不得为寡君老,其蔑以复矣。唯大夫图之!”子羽曰:“小国无罪,恃实其罪。将恃大国之安靖己,而无乃包藏祸心以图之。小国失恃而惩诸侯,使莫不憾者,距违君命,而有所壅塞不行是惧!不然,敝邑,馆人之属也,其敢爱丰氏之祧?”伍举知其有备也,请垂橐而入。许之。 +正月乙未,入,逆而出。遂会于虢,寻宋之盟也。祁午谓赵文子曰:“宋之盟,楚人得志于晋。今令尹之不信,诸侯之所闻也。子弗戒,惧又如宋。子木之信称于诸侯,犹诈晋而驾焉,况不信之尤者乎?楚重得志于晋,晋之耻也。子相晋国以为盟主,于今七年矣!再合诸侯,三合大夫,服齐、狄,宁东夏,平秦乱,城淳于,师徒不顿,国家不罢,民无谤讟,诸侯无怨,天无大灾,子之力也。有令名矣,而终之以耻,午也是惧。吾子其不可以不戒!”文子曰:“武受赐矣!然宋之盟,子木有祸人之心,武有仁人之心,是楚所以驾于晋也。今武犹是心也,楚又行僭,非所害也。武将信以为本,循而行之。譬如农夫,是□麃是衮,虽有饥馑,必有丰年。且吾闻之:‘能信不为人下。’吾未能也。《诗》曰:‘不僭不贼,鲜不为则。’信也。能为人则者,不为人下矣。吾不能是难,楚不为患。” +楚令尹围请用牲,读旧书,加于牲上而已。晋人许之。 +三月甲辰,盟。楚公子围设服离卫。叔孙穆子曰:“楚公子美矣,君哉!”郑子皮曰:“二执戈者前矣!”蔡子家曰:“蒲宫有前,不亦可乎?”楚伯州犁曰:“此行也,辞而假之寡君。”郑行人挥曰:“假不反矣!”伯州犁曰:“子姑忧子皙之欲背诞也。”子羽曰:“当璧犹在,假而不反,子其无忧乎?”齐国子曰:“吾代二子愍矣!”陈公子招曰:“不忧何成,二子乐矣。”卫齐子曰:“苟或知之,虽忧何害?”宋合左师曰:“大国令,小国共。吾知共而已。”晋乐王鲋曰:“《小旻》之卒章善矣,吾从之。” +退会,子羽谓子皮曰:“叔孙绞而婉,宋左师简而礼,乐王鲋字而敬,子与子家持之,皆保世之主也。齐、卫、陈大夫其不免乎?国子代人忧,子招乐忧,齐子虽忧弗害。夫弗及而忧,与可优而乐,与忧而弗害,皆取忧之道也,忧必及之。《大誓》曰:‘民之所欲,天必从之。’三大夫兆忧,能无至乎?言以知物,其是之谓矣。” +季武子伐莒,取郓,莒人告于会。楚告于晋曰:“寻盟未退,而鲁伐莒,渎齐盟,请戮其使。”乐桓子相赵文子,欲求货于叔孙而为之请,使请带焉,弗与。梁其跁曰:“货以藩身,子何爱焉?”叔孙曰:“诸侯之会,卫社稷也。我以货免,鲁必受师。是祸之也,何卫之为?人之有墙,以蔽恶也。墙之隙坏,谁之咎也?卫而恶之,吾又甚焉。虽怨季孙,鲁国何罪?叔出季处,有自来矣,吾又谁怨?然鲋也贿,弗与,不已。”召使者,裂裳帛而与之,曰:“带其褊矣。”赵孟闻之,曰:“临患不忘国,忠也。思难不越官,信也;图国忘死,贞也;谋主三者,义也。有是四者,又可戮乎?”乃请诸楚曰:“鲁虽有罪,其执事不辟难,畏威而敬命矣。子若免之,以劝左右可也。若子之群吏处不辟污,出不逃难,其何患之有?患之所生,污而不治,难而不守,所由来也。能是二者,又何患焉?不靖其能,其谁从之?鲁叔孙豹可谓能矣,请免之以靖能者。子会而赦有罪,又赏其贤,诸侯其谁不欣焉望楚而归之,视远如迩?疆埸之邑,一彼一此,何常之有?王伯之令也,引其封疆,而树之官。举之表旗,而着之制令。过则有刑,犹不可壹。于是乎虞有三苗,夏有观、扈,商有姺、邳,周有徐、奄。自无令王,诸侯逐进,狎主齐盟,其又可壹乎?恤大舍小,足以为盟主,又焉用之?封疆之削,何国蔑有?主齐盟者,谁能辩焉?吴、濮有衅,楚之执事岂其顾盟?莒之疆事,楚勿与知,诸侯无烦,不亦可乎?莒、鲁争郓,为日久矣,苟无大害于其社稷,可无亢也。去烦宥善,莫不竞劝。子其图之!”固请诸楚,楚人许之,乃免叔孙。 +令尹享赵孟,赋《大明》之首章。赵孟赋《小宛》之二章。事毕,赵孟谓叔向曰:“令尹自以为王矣,何如?”对曰:“王弱,令尹强,其可哉!虽可,不终。”赵孟曰:“何故?”对曰:“强以克弱而安之,强不义也。不义而强,其毙必速。《诗》曰:‘赫赫宗周,褒姒灭之。’强不义也。令尹为王,必求诸侯。晋少懦矣,诸侯将往。若获诸侯,其虐滋甚。民弗堪也,将何以终?夫以强取,不义而克,必以为道。道以淫虐,弗可久已矣!” +夏四月,赵孟、叔孙豹、曹大夫入于郑,郑伯兼享之。子皮戒赵孟,礼终,赵孟赋《瓠叶》。子皮遂戒穆叔,且告之。穆叔曰:“赵孟欲一献,子其从之!”子皮曰:“敢乎?”穆叔曰:“夫人之所欲也,又何不敢?”及享,具五献之笾豆于幕下。赵孟辞,私于子产曰:“武请于冢宰矣。”乃用一献。赵孟为客,礼终乃宴。穆叔赋《鹊巢》。赵孟曰:“武不堪也。”又赋《采蘩》,曰:“小国为蘩,大国省穑而用之,其何实非命?”子皮赋《野有死麇》之卒章。赵孟赋《常棣》,且曰:“吾兄弟比以安,龙也可使无吠。”穆叔、子皮及曹大夫兴,拜,举兕爵,曰:“小国赖子,知免于戾矣。”饮酒乐。赵孟出,曰:“吾不复此矣。” +天王使刘定公劳赵孟于颖,馆于洛汭。刘子曰:“美哉禹功,明德远矣!微禹,吾其鱼乎!吾与子弁冕端委,以治民临诸侯,禹之力也。子盍亦远绩禹功,而大庇民乎?”对曰:“老夫罪戾是惧,焉能恤远?吾侪偷食,朝不谋夕,何其长也?”刘子归,以语王曰:“谚所为老将知而耄及之者,其赵孟之谓乎!为晋正卿,以主诸侯,而侪于隶人,朝不谋夕,弃神人矣。神怒民叛,何以能久?赵孟不复年矣。神怒,不歆其祀;民叛,不即其事。祀事不从,又何以年?” +叔孙归,曾夭御季孙以劳之。旦及日中不出。曾夭谓曾阜曰:“旦及日中,吾知罪矣。鲁以相忍为国也,忍其外不忍其内,焉用之?”阜曰:“数月于外,一旦于是,庸何伤?贾而欲赢,而恶嚣乎?”阜谓叔孙曰:“可以出矣!”叔孙指楹曰:“虽恶是,其可去乎?”乃出见之。 +郑徐吾犯之妹美,公孙楚聘之矣,公孙黑又使强委禽焉。犯惧,告子产。子产曰:“是国无政,非子之患也。唯所欲与。”犯请于二子,请使女择焉。皆许之,子皙盛饰入,布币而出。子南戎服入。左右射,超乘而出。女自房观之,曰:“子皙信美矣,抑子南夫也。夫夫妇妇,所谓顺也。”适子南氏。子皙怒,既而櫜甲以见子南,欲杀之而取其妻。子南知之,执戈逐之。及冲,击之以戈。子皙伤而归,告大夫曰:“我好见之,不知其有异志也,故伤。” +大夫皆谋之。子产曰:“直钧,幼贱有罪。罪在楚也。”乃执子南而数之,曰:“国之大节有五,女皆奸之:畏君之威,听其政,尊其贵,事其长,养其亲。五者所以为国也。今君在国,女用兵焉,不畏威也。奸国之纪,不听政也。子皙,上大夫,女,嬖大夫,而弗下之,不尊贵也。幼而不忌,不事长也。兵其从兄,不养亲也。君曰:‘余不女忍杀,宥女以远。’勉,速行乎,无重而罪!” +五月庚辰,郑放游楚于吴,将行子南,子产咨于大叔。大叔曰:“吉不能亢身,焉能亢宗?彼,国政也,非私难也。子图郑国,利则行之,又何疑焉?周公杀管叔而蔡蔡叔,夫岂不爱?王室故也。吉若获戾,子将行之,何有于诸游?” +秦后子有宠于桓,如二君于景。其母曰:“弗去,惧选。”癸卯,金咸适晋,其车千乘。书曰:“秦伯之弟金咸出奔晋。”罪秦伯也。后子享晋侯,造舟于河,十里舍车,自雍及绛。归取酬币,终事八反。司马侯问焉,曰:“子之车,尽于此而已乎?”对曰:“此之谓多矣!若能少此,吾何以得见?”女叔齐以告公,且曰:“秦公子必归。臣闻君子能知其过,必有令图。令图,天所赞也。” +后子见赵孟。赵孟曰:“吾子其曷归?”对曰:“金咸惧选于寡君,是以在此,将待嗣君。”赵孟曰:“秦君何如?”对曰:“无道。”赵孟曰:“亡乎?”对曰:“何为?一世无道,国未艾也。国于天地,有与立焉。不数世淫,弗能毙也。”赵孟曰:“天乎?”对曰:“有焉。”赵孟曰:“其几何?”对曰:“金咸闻之,国无道而年谷和熟,天赞之也。鲜不五稔。”赵孟视荫,曰:“朝夕不相及,谁能待五?”后子出,而告人曰:“赵孟将死矣。主民,玩岁而愒日,其与几何?” +郑为游楚乱故,六月丁巳,郑伯及其大夫盟于公孙段氏,罕虎、公孙侨、公孙段、印段、游吉、驷带私盟于闺门之外,实薰隧。公孙黑强与于盟,使大史书其名,且曰七子。子产弗讨。 +晋中行穆子败无终及群狄于大原,崇卒也。将战,魏舒曰:“彼徒我车,所遇又厄,以什共车必克。困诸厄,又克。请皆卒,自我始。”乃毁车以为行,五乘为三伍。荀吴之嬖人不肯即卒,斩以徇。为五陈以相离,两于前,伍于后,专为左角,参为左角,偏为前拒,以诱之。翟人笑之。未陈而薄之,大败之。 +莒展舆立,而夺群公子秩。公子召去疾于齐。秋,齐公子鉏纳去疾,展舆奔吴。 +叔弓帅师疆郓田,因莒乱也。于是莒务娄、瞀胡及公子灭明以大厖与常仪靡奔齐。君子曰:“莒展之不立,弃人也夫!人可弃乎?《诗》曰:‘无竞维人。’善矣。” +晋侯有疾,郑伯使公孙侨如晋聘,且问疾。叔向问焉,曰:“寡君之疾病,卜人曰:‘实沈、台骀为祟。’史莫之知,敢问此何神也?”子产曰:“昔高辛氏有二子,伯曰阏伯,季曰实沈,居于旷林,不相能也。日寻干戈,以相征讨。后帝不臧,迁阏伯于商丘,主辰。商人是因,故辰为商星。迁实沈于大夏,主参。唐人是因,以服事夏、商。其季世曰唐叔虞。当武王邑姜方震大叔,梦帝谓己:‘余命而子曰虞,将与之唐,属诸参,其蕃育其子孙。’及生,有文在其手曰:‘虞’,遂以命之。及成王灭唐而封大叔焉,故参为晋星。由是观之,则实沈,参神也。昔金天氏有裔子曰昧,为玄冥师,生允格、台骀。台骀能业其官,宣汾、洮,障大泽,以处大原。帝用嘉之,封诸汾川。沈、姒、蓐、黄,实守其祀。今晋主汾而灭之矣。由是观之,则台骀,汾神也。抑此二者,不及君身。山川之神,则水旱疠疫之灾,于是乎禜之。日月星辰之神,则雪霜风雨之不时,于是乎禜之。若君身,则亦出入饮食哀乐之事也,山川星辰之神,又何为焉”?侨闻之,君子有四时:朝以听政,昼以访问,夕以修令,夜以安身。于是乎节宣其气,勿使有所壅闭湫底,以露其体。兹心不爽,而昏乱百度。今无乃壹之,则生疾矣。侨又闻之,内官不及同姓,其生不殖,美先尽矣,则相生疾,君子是以恶之。故《志》曰:‘买妾不知其姓,则卜之。’违此二者,古之所慎也。男女辨姓,礼之大司也。今君内实有四姬焉,其无乃是也乎?若由是二者,弗可为也已。四姬有省犹可,无则必生疾矣。”叔向曰:“善哉!肸未之闻也。此皆然矣。” +叔向出,行人挥送之。叔向问郑故焉,且问子皙。对曰:“其与几何?无礼而好陵人,怙富而卑其上,弗能久矣。” +晋侯闻子产之言,曰:“博物君子也。”重贿之。 +晋侯求医于秦。秦伯使医和视之,曰:“疾不可为也。是谓:‘近女室,疾如蛊。非鬼非食,惑以丧志。良巨将死,天命不佑’”公曰:“女不可近乎?”对曰:“节之。先王之乐,所以节百事也。故有五节,迟速本末以相及,中声以降,五降之后,不容弹矣。于是有烦手淫声,慆堙心耳,乃忘平和,君子弗德也。物亦如之,至于烦,乃舍也已,无以生疾。君子之近琴瑟,以仪节也,非以慆心也。天有六气,降生五味,发为五色,征为五声,淫生六疾。六气曰阴、阳、风、雨、晦、明也。分为四时,序为五节,过则为灾。阴淫寒疾,阳淫热疾,风淫末疾,雨淫腹疾,晦淫惑疾,明淫心疾。女,阳物而晦时,淫则生内热惑蛊之疾。今君不节不时,能无及此乎?”出,告赵孟。赵孟曰:“谁当良臣?”对曰:“主是谓矣!主相晋国,于今八年,晋国无乱,诸侯无阙,可谓良矣。和闻之,国之大臣,荣其宠禄,任其宠节,有灾祸兴而无改焉,必受其咎。今君至于淫以生疾,将不能图恤社稷,祸孰大焉!主不能御,吾是以云也。”赵孟曰:“何谓蛊”对曰:“淫溺惑乱之所生也。于文,皿虫为蛊。谷之飞亦为蛊。在《周易》,女惑男,风落山,谓之《蛊》三。皆同物也。”赵孟曰:“良医也。”厚其礼归之。 +楚公子围使公子黑肱、伯州犁城雠、栎、郏,郑人惧。子产曰:“不害。令尹将行大事,而先除二子也。祸不及郑,何患焉?” +冬,楚公子围将聘于郑,伍举为介。未出竟,闻王有疾而还。伍举遂聘。十一月己酉,公子围至,入问王疾,缢而弑之。遂杀其二子幕及平夏。右尹子干出奔晋。宫厩尹子皙出奔郑。杀大宰伯州犁于郏。葬王于郏,谓之郏敖。使赴于郑,伍举问应为后之辞焉。对曰:“寡大夫围。”伍举更之曰:“共王之子围为长。” +子干奔晋,从车五乘。叔向使与秦公子同食,皆百人之饩。赵文子曰:“秦公子富。”叔向曰:“底禄以德,德钧以年,年同以尊。公子以国,不闻以富。且夫以千乘去其国,强御已甚。《诗》曰:‘不侮鳏寡,不畏强御。’秦、楚,匹也。”使后子与子干齿。辞曰:“金咸惧选,楚公子不获,是以皆来,亦唯命。且臣与羁齿,无乃不可乎?史佚有言曰:‘非羁何忌?’” +楚灵王即位,薳罢为令尹,薳启强为大宰。郑游吉如楚,葬郏敖,且聘立君。归,谓子产曰:“具行器矣!楚王汰侈而自说其事,必合诸侯。吾往无日矣。”子产曰:“不数年,未能也。” +十二月,晋既烝,赵孟适南阳,将会孟子余。甲辰朔,烝于温。庚戌,卒。郑伯如晋吊,及雍乃复。 +译文 +元年春季,楚国的公子围到郑国去聘问,同时娶了公孙段的女儿为妻。伍举作为副使,将要进入宾馆,郑国人讨厌他,派行人子羽婉辞拒绝,于是就住在城外。聘礼举行以后,将要带领很多兵去迎娶。子产担心这件事,派子羽辞谢,说:“由于敝邑狭小,不足以容纳您的随从,请求让我们清除地面作可以祭祀的地方,再听取您的命令。”令尹命令太宰伯州犁回答说:“贵君给寡大夫围恩惠,对围说将要让丰氏的女儿嫁给你做妻子。围陈列几筵,在庄王、共王的神庙中祭告然后前来娶妇。如果在野外赐给我,这是把贵君的恩赐丢在草丛中去了,这也是让寡大夫不能处在卿的行列里了。不仅如此,又让围欺骗了我的先君,将要不再能做寡君的大臣,恐怕也不能回去复命了。请大夫考虑罢!”子羽说:“小国没有罪过,依靠大国而不设防备就是他的罪过。小国打算依靠大国安定自己,而大国却恐怕是包藏祸心来打小国的主意吧!怕的是小国失去了依靠,就让诸侯得到戒惧,而全部怨恨大国,对国君命令抗拒违背,使它行不通。否则,敝邑就等于贵国的宾馆,岂敢爱惜丰氏的神庙?”伍举知道郑国有了防备,请求倒转弓袋子进入国都。郑国才同意了。 +正月十五日,公子围进入国都,迎娶后出来。于是就和叔孙豹、晋国赵武、齐国国弱、宋国向戌、陈国公子招、蔡国公子归生、郑国罕虎、许国人、曹国人在虢地会见,这是为了重温宋国盟会的友好。祁午对赵文子说:“在宋国的盟会,楚国人占了晋国的先。现在令尹不守信用,这是诸侯都听说的。您如果还不戒备,怕的是又像在宋国一样。子木的信用为诸侯所称道,尚且欺骗晋国而要驾凌在上面,何况是不守信用的突出人物呢?楚国再次占了晋国的上风,是晋国的耻辱。您辅佐晋国作为盟主,到现在已经七年了。两次会合诸侯,三次会合大夫,使齐国、狄人归服,使华夏的东方国家安宁,平定秦国造成的动乱,在淳于修筑城墙,军队不疲弊,国家不疲乏,百姓没有诽谤,诸侯没有怨言。天不降大灾,这是您的力量。有了好名声了,反而用耻辱来结束,午就是害怕这个,您不能不警惕。”赵文子说:“武接受您的恩赐了。然而在宋国的结盟,子木有害人之心,武有爱人之心,这就是楚国所以驾凌在晋国上面的缘故。现在武还是这样的心,楚国又不守信用,这可不是他所能伤害的了。武将要用信用作为根本,按照这去做。譬如农夫,只要勤于除草培土,虽然有一时灾荒,最终必然获得丰收。而且我听说,能守信用就不会在别人下面,我还是不能做到守信用啊。《诗》说,‘待人以信,很少不能做榜样’,这是由于守信用的缘故。能够做别人典范的,不会在别人的下面了。我的难处在不能做到这一点。楚国不能造成祸患。” +楚国的令尹围请求使用牺牲,宣读一遍过去的盟约然后放在牺牲上面。晋国人答应了。 +三月二十五日,结盟。楚国的公子围陈列了国君的服饰,两个卫士拿着戈站在旁边。叔孙穆子说:“楚国的公子很神气,像个国君啊!”郑国的子皮说:“两个拿着戈的人站在前面来了。”蔡国的子家说:“蒲宫有一对执戈卫士站在前面,不也可以吗?”楚国的伯州犁说:“这些东西是这次出来的时侯,向国君请求而借来的。”郑国的行人子羽说:“借了就不还了。”伯州犁说:“您还是去担心一下你们子皙想要违命作乱吧。”子羽说:“公子弃疾还在那里,借了不还您难道没有忧虑吗?”齐国的国子说:“我替这两位担心哪。”陈国的公子招说:“不忧愁怎么能办成事情?这两位可高兴啦。”卫国的齐子说:“如果有人事先知道,虽然有忧虑又有什么危害?”宋国的合左师说:“大国发令,小国供职,我知道供职就是了。”恶国的乐王鲋说:《小旻》的最后一章很好,我照着那样做。” +退出会场,子羽对子皮说:“叔孙言辞恰切而委婉,宋国左师语言简明而合于礼仪,乐王鲋自爱而恭敬,您和子家说话得当,都是可以保持几代爵禄的大夫。齐国、卫国、陈国的大夫大概不能免于祸难吧!国子替人忧虑,子招以高兴代替忧虑,齐子虽然有忧虑却不当作危害,凡是忧虑没有到自己身上而替人忧虑,和可以忧虑反而高兴,和把忧虑不当作危害,这都是招来忧虑的原由,忧虑必然到他的身上来。《大誓》说:‘百姓所要求的,上天必然听从。’三位大夫有了忧虑的兆头,忧虑能不来吗?从言语来说明情况,说的就是这个了。” +季武子进攻莒国,占据了郓地,莒国人向盟会报告。楚国对晋国说:“重温过去的盟会还没有结束,鲁国就进攻莒国,轻视盟约,请求诛杀鲁国的使者。” 乐桓子辅佐赵文子,想要向叔孙豹索取财货,而为他向赵文子说情。派人向叔孙豹要他的带子,叔孙豹不给。梁其跁说:“财货用来保护身体,您有什么可吝惜呢?”叔孙豹说:“诸侯的会见,是为了保卫国家。我用财货来免于祸患,鲁国就必然受到进攻了,这是为它带来祸患啊,还有什么保卫可言?人所以有墙壁,是用来遮挡坏人的。墙壁裂缝,这是谁的过错?为了保卫反而让鲁国受攻击,我的罪过又超过了墙壁。虽然应当埋怨季孙,鲁国有什么罪过呢?叔孙出使季孙守国,一向就是这样的,我又去怨谁呢?然而鲋喜欢财货,不给他,没有完。”召见使者,撕下一片做裙子的帛给他,说:“身上的带子恐怕太窄了。”赵孟听到了,说:“面临祸患而不忘记国家,这是忠心。想到危难而不放弃职守,这是诚意。为国家打算而不惜一死,这是坚定。计谋以上述三点作为主体,这是道义。有了这四点,难道可以诛戮吗?”就向楚国请求说:“鲁国虽然有罪,它的执事不避祸难,畏惧贵国的威严而恭敬地从命了。您如果赦免他,用来勉励您的左右,这还是可以的。如果您的官吏们在国内不避困难,在国外不逃避祸难,还有什么可忧虑的?忧虑之所以产生,就是有困难而不能治理、祸难来了而不顶住,就是这样来的。能做到这两点,又忧虑什么?不安定贤能的人了,有谁去跟从他?鲁国的叔孙豹可以说是贤能的人,请求赦免他,用来安定贤能的人。您参加了盟会而赦免了有罪的国家,又奖励它的贤能的人,还有谁不高高兴兴的望着楚国而归服你们,把疏远看成亲近呢?国境上的城邑,一时属那边,一时属这边,有什么一定?三王五伯的政令,划定疆界,在那里设置官员,树立界碑,而写明在章程法令上。越境就要惩罚,尽管这样,尚且不能一成不变。在这种情况下虞舜时代有三苗,夏朝有观氏、扈氏,商朝有姺氏、邳氏,周朝有徐国、奄国。自从没有英明的天子以后,诸侯争相扩张,交替主持结盟,难道又能够一成不变吗?担心大祸不计较小错,足以做盟主,又哪里用得着管这些小事?边境被侵削,哪个国家没有?主持结盟的,谁能治理得了?吴国、百濮有隙可乘,楚国的执事难道只顾到盟约不去进攻?莒国边境上的事情,楚国不要过问,不要烦劳诸侯,不也可以吗?莒国、鲁国争执郓地,日子很久了。只要对他们国家没有大妨害,可以不必去保护。免除烦劳、赦免善人,就没有不争相努力的。您还是考虑一下。”晋国人坚决向楚国请求,楚国人答应了,就赦免了叔孙。 +令尹设宴招待赵孟,赋《大明》的第一章。赵孟赋《小宛》的第二章。事情完了,赵孟对叔向说:“令尹自以为是国王了,怎么样?”叔向回答说:“国王弱,令尹强,大概是可以成功的吧!虽然可以成功,不能有好结果。”赵孟说:“为什么?”叔向回答说:“用强大制服弱小而心安理得,强大而不合于道义。不合于道义而强大,他的灭亡必然很快。《诗》说‘声威赫赫的宗周,褒姒灭亡了它’,这是由于强大又不合道义的缘故。令尹做了国王,必然请求诸侯的拥护。晋国有些衰弱了,诸侯就会投靠他。如果得到了诸侯,他的暴虐就更厉害,百姓不能忍受他的残暴,他如何能善终?用强力来取得君位,不合于道义而能获成功,必然把它作为常道。把荒淫暴虐作为常道,是不能持久的啊!” +夏季,四月,赵孟、叔孙豹、曹国的大夫进入郑国,郑简公同时设享礼招待他们。子皮通知赵孟,通知的礼仪结束,赵孟赋《瓠叶》这首诗。子皮通知叔孙豹,同时告诉他赵孟赋诗的情况。叔孙豹说:“赵孟想要一献之宴,您还是听从他。”子皮说:“敢吗?”叔孙豹说:“那个人想要这样,又有什么不敢?”等到举行享礼,在东房准备了五献的用具。赵孟辞谢,私下对子产说:“武已经向上卿请求过了。”于是就使用了一献。赵孟作为主宾,享礼完毕就饮宴。叔孙豹赋《鹊巢》这首诗,赵孟说:“武不敢当啊。”叔孙豹又赋《采蘩》这首诗,说:“小国献上薄礼蘩,大国爱惜而加以使用,岂敢不服从大国的命令?”子皮赋《野有死麇》的最后一章,赵孟赋《常棣》这首诗,同时说:“我们兄弟亲密而安好,可以别让狗叫了。”叔孙豹、子皮和曹国的大夫起立,下拜,举起牛角杯,说:“小国靠着您,知道免于罪过了。”大家喝酒喝得很高兴。赵孟出来,说:“我不会再见到这样的欢乐了。” +周景王派刘定公在颍地慰劳赵孟,让他住在洛水边上。刘定公说:“美好啊,禹的功绩!他美的德行多么深远。如果没有禹,我们大约要变成鱼了吧!我和您戴着礼帽穿着礼服,来治 理百姓、面对诸侯,都是禹的力量。您何不远继禹的功绩,而大大地庇护百姓呢?”赵孟回答说:“我老头子惟恐犯下罪过,哪里能考虑得长远的事情?我们这些人苟且度日,早晨不想到晚上,哪里能够作长远考虑呢?”刘子回去,把情况告诉周景王,说:“俗话所说老了会聪明些,可是糊涂也跟着来了,这说的就是赵孟吧!做晋国的正卿以主持诸侯,反而把自己等同于那些下贱的人,早晨不想到晚上,这是丢弃了神灵和百姓了。神灵发怒,百姓背叛,何以能长久?赵孟不再能过年了。神灵发怒,不享用他的祭祀。百姓背叛,不替他做事情。祭祀和国事不能办理,又怎么能过得了年?” +叔孙回国,曾夭为季孙驾车去慰劳他。从早晨到中午,叔孙没有出来。曾夭对曾阜说:“从早晨一直等到中午,我们已经知道罪过了。鲁国是用互相忍让来治理国家的。在国外忍让,在国内不忍让,那又何必呢?”曾阜说:“他几个月在外边,我们在这里只一早晨,有什么妨碍?商人要赢利,还能讨厌喧闹吗?”曾阜对叔孙说:“可以出去了。”叔孙指着柱子说:“虽然讨厌这个柱子,难道能够去掉吗?”于是就出去接见季孙。 +郑国徐吾犯的妹妹很漂亮,公孙楚已经和她订了婚,公孙黑又硬派人送去聘礼。徐吾犯害怕,告诉子产。子产说:“这是国家政事混乱,不是您的忧患。她愿意嫁给谁就嫁给谁。”徐吾犯请求这二位,让女子自己选择。他们都答应了。公孙黑打扮得非常华丽,进来,陈设财礼然后出去了。公孙楚穿着军服进来,左右开弓,一跃登车而去。女子在房间内观看他们,说:“子皙确实是很美,不过子南是个真正的男子汉。丈夫要像丈夫,妻子要像妻子,这就是所谓顺。”徐女嫁给了公孙楚家。公孙黑发怒,不久以后就把皮甲穿在外衣里而去见公孙楚,想要杀死他而占取他的妻子。公孙楚知道他的企图,拿了戈追赶他,到达交叉路口,用戈敲击他。公孙黑受伤回去,告诉大夫说:“我很友好地去见他,不知道他有别的想法,所以受了伤。” +大夫们都议论这件事。子产说:“各有理由,年幼地位低的有罪,罪在于公孙楚。”于是就抓住公孙楚而列举他的罪状,说:“国家的大节有五条,你都触犯了。惧怕国君的威严,听从他的政令,尊重贵人,事奉长者,奉养亲属,这五条是用来治理国家的。现在国君在国都里,你动用武器,这是不惧怕威严。触犯国家的法纪,这是不听从政令。子皙是上大夫,你是下大夫,而又不肯在他下面,这是不尊重贵人。年纪小而不恭敬,这是不事奉长者。用武器对付堂兄,这是不奉养亲属。国君说:‘我不忍杀你,赦免你让你到远地。’尽你的力量,快走吧,不要加重你的罪行!” +五月初二日,郑国放逐公孙楚到吴国。准备让公孙楚起程,子产征求太叔的意见。太叔说:“吉不能保护自身,哪里能保护一族?他的事情属于国家政治,不是私家的危难。您为郑国打算,有利国家就去办,又有什么疑惑呢?周公杀死管叔,放逐了蔡叔,难道不爱他们?这是为巩固王室。吉如果得罪,您也将要执行惩罚,何必顾虑游氏诸人?” +秦国的后子受到秦桓公的宠信,在秦景公即位的时候和景公如同两君并列一样。他的母亲说:“如果不离开,恐怕会要被放逐的。”五月二十日,后子到晋国去,他的车子有一千辆。《春秋》记载说“秦伯之弟鍼出奔晋”,这是把罪责归于秦景公。 +后子设享礼招待晋平公,在黄河搭了浮桥,每隔十里就停放一批车辆,从雍城绵延到绛城。回去取奉献的礼物,到享礼结束往返取币八次。司马侯询问说:“您的车辆都在这里了吗?”后子回答说:“这已经算够多了。如果能比这些少,我怎么能见到你呢?”司马侯把这些话报告晋平公,而且说:“秦公子必然回国。下臣听说君子能够知道自己的过错,一定有好的计谋。好的计谋,这是上天所赞助的。” +后子进见赵孟。赵孟说:“您大约什么时候回去呢?”后子回答说:“鍼害怕被国君放逐,因此留在这里,准备等到新君即位再回国。”赵孟说:“秦国的国君怎么样?”后子回答说:“无道。”赵孟说:“国家会灭亡吗?”后子回答说:“为什么?一代的君主无道,国家还不致到达绝境。立国在天地之间,必然有辅助的人。不是几代的荒淫,不能灭亡的。”赵孟说:“国君会短命吗?”后子回答说:“会的。”赵孟说:“大约多久呢?”后子回答说:“鍼听说,国家无道而粮食丰收,这是上天在辅助他。少则不过五年。”赵孟看着太阳的影子,说:“早晨等不到晚上,谁能等待五年?”后子出来,告诉别人说:“赵孟将要死了。主持百姓的事情,既想混日子又急于怕自己活不久,他还能活多久呢?” +郑国由于游楚作乱的缘故,六月初九日,郑简公和他的大夫们在公孙段家里结盟。罕虎、公孙侨、公孙段、印段、游吉、驷带在闺门外边私下结盟,盟地就在薰隧。公孙黑硬要参加结盟,让太史写下他的名字,而且称为“七子”。子产并不加讨伐。 +晋国的中行穆子在大原打败了无终和各部狄人,这是由于重用步兵的缘故。即将作战时,魏舒说:“他们是步兵我们是车兵,两军相遇的地方形势险要,用十个步兵对付一辆战车,必然得胜。把他们围困在险地,我们又能胜他们。请全部改为步兵,从我开始。”于是就不用战车改为步兵的行列,五乘战车改成三个伍。荀吴的宠臣不肯编入步兵,就杀了巡行示众。晋军摆成五种阵势以互相呼应,两在前面,伍在后面,专作为右翼,参作为左翼,偏作为前锋方阵,用这个来诱敌。狄人讥笑他们。没有等狄人摆开阵势,晋兵就迫近进攻,大胜狄人。 +莒国的展舆即位,夺去了公子们的俸禄。公子们把去疾从齐国召回来。秋季,齐国的公子鉏把去疾送回莒国,展舆逃亡到吴国。 +叔弓率领军队划定郓地的疆界,这是乘莒国发生内乱的缘故。在这时候莒国的务娄、瞀胡和公子灭明带着大厖和常仪靡逃亡到齐国。君子说:“莒展不能被立,这是由于失去了人才的缘故吧!人才可以不要吗?《诗》说,‘要强大只有得到贤人’,很正确啊。” +晋平公有病,郑伯派子产去到晋国聘问,同时探视病情。叔向询问子产说:“寡君的疾病,卜人说‘是实沈、台骀在作怪’,太史不知道他们,谨敢请问这是什么神灵?”子产说:“从前高辛氏有两个儿子,大的叫阏伯,小的叫实沈,住在大树林里,不能相容,每天使用武器互相攻打。帝尧认为他们不好,把阏伯迁移到商丘,用大火星来定时节。商朝人沿袭下来,所以大火星成了商星。把实沈迁移到大夏,用参星来定时节,唐国人沿袭下来,以归服事奉夏朝、商朝。它的末世叫做唐叔虞。正当武王的邑姜怀着太叔的时候,梦见天帝对自己说:‘我为你的儿子起名为虞,准备将唐国给他,属于参星,而繁衍养育他的子孙。’等到生下来,有纹路在他掌心像虞字,就名为虞。等到成王灭了唐国,就封给了太叔,所以参星是晋国的星宿。从这里看来,那么实沈就是参星之神了。从前金天氏有后代叫做昧,做水官,生了允格、台骀。台骀能世代为官,疏通汾水、洮水,堵住大泽,带领人们就住在广阔的高平的地区。颛顼因此嘉奖他,把他封在汾川,沈、姒、蓐、黄四国世代守着他的祭祀。现在晋国主宰了汾水一带而灭掉了这四个国家。从这里看来,那么台骀就是汾水之神了。然而这两位神灵与晋君之病无关。山川的神灵,遇到水旱瘟疫这些灾祸就向他们祭祀禳灾。日月星辰的神灵,遇到雪霜风雨不合时令,就向他们祭祀禳灾。至于疾病在您身上,也就是由于劳逸、饮食、哀乐不适度的缘故。山川、星辰的神灵又哪能降病给您呢?侨听说,君子有四段时间,早晨用来听取政事,白天用来调查询问,晚上用来确定政令,夜里用来安歇身体。在这时就可以有节制地散发体气,别让它有所壅塞以使身体衰弱。心里不明白这些,就会使百事昏乱。现在恐怕是体气用在一处,就生病了。侨又听说,国君的妻妾不能有同姓,因为子孙不能昌盛。美人都占尽了,那么就会得病,君子因此讨厌这个。所以《志》说:‘买姬妾侍女不知道她的姓,就占卜一下。’违反这两条,古代是很慎重的。男女要辨别姓氏,这是礼仪的大事。现在君王的宫里有四个姬姓侍妾,那恐怕就是为了这个缘故吧!如果是由于这两条,病就不能治了。去掉这四个姬姓女子还可以,否则就必然得病了。”叔向说:“好啊,肸没有听说过呢,所说都是对的啊。” +叔向出来,行人子羽送他。叔向询问郑国的情况,同时询问子皙的情况。子羽回答说:“他还能活多久?没有礼仪而喜欢凌驾于人,仗着富有而轻视他的上级,不能长久了。” +晋平公听说了子产的话,说:“他是知识渊博的君子啊。”送给子产以很厚的财物。 +晋平公在秦国求医,秦景公让医和为他看病。医和说:“病不能治了,这叫做亲近女人,得病好像蛊惑。不是由于鬼神,也不是由于饮食,而是被女色迷惑而丧失了意志。良臣将要死去,上天不能保佑。”晋平公问:“女人不能亲近吗?”医和回答说:“节制它。先王的音乐,是用来节制百事的,所以有五声的节奏,快慢、本末以互相调节,声音和谐然后降下来。五声下降后,就不允许再弹了。这时候再弹就有了繁复的手法和靡靡之音,使人心烦耳乱,就会忘记了平正和谐,因此君子是不听的。事情也像音乐一样,一到过度,就应该停止,不要因此得病。君子接近妻室,是用礼来节制的,不是用来烦心的。天有六种气候,派生为五种口味,表现为五种颜色,应验为五种声音。凡是过了头就会发生六种疾病。六种气候就叫做阴、晴、风、雨、夜、昼,分为四段时间,顺序为五声的节奏,过了头就是灾祸:阴没有节制是寒病,阳没有节制是热病,风没有节制是四肢病,雨没有节制是腹病,夜里没有节制是迷惑病,白天没有节制是心病。女人,属于阳事而时间在夜里,对女人没有节制就会发生内热蛊惑的疾病。现在您没有节制不分昼夜,能不到这个地步吗?” +医和出来,告诉赵孟。赵孟说:“谁相当于良臣?”医和说:“就是您了。您辅佐晋国,到现在八年,晋国没有动乱,诸侯没有缺失,可以说是良了。和听说,国家的大臣,光荣地受到信任和爵禄,承担国家的大事。有灾祸发生却不能改变作法,必然受到灾殃。现在国君到了没有节制的程度因而得病,将要不能为国家图谋考虑,还有比这更大的灾祸吗?您不能禁止,我因此才这样说。”赵孟说:“什么叫做蛊?”医和回答说:“这是沉迷惑乱所引起的。在文字里,器皿中毒虫是蛊。稻谷中的飞虫也是蛊。在《周易》里,女人迷惑男人,大风吹落山木叫做《蛊》。这都是同类事物。”赵孟说:“真是好医生啊。”赠给他很重的礼物而让他回去。 +楚国的公子围派公子黑肱、伯州犁在犫、栎、郏地筑城,郑国人害怕。子产说:“没有妨害。令尹准备干大事而先除掉这两位。祸患不会到达郑国,担心什么?” +冬季,楚国的公子围准备到晋国聘问,伍举作为副手。没有走出国境,听说楚王有病而回来,伍举就到郑国聘问。十一月初四日,公子围到达,进宫问候楚王的病情,把楚王勒死了,并乘机杀了他的两个儿子幕和平夏。右尹子干逃亡到晋国,宫厩尹子皙逃亡到郑国。把太宰伯州犁绞死在郏地。把楚王葬在郏地,称他为郏敖。派使者发讣告到郑国,伍举问使者关于继承人的措辞,使者说:“寡大夫围。”伍举改正说:“共王的儿子围是长子。” +子干逃亡到晋国,跟从的车子有五辆,叔向让他和秦公子后子食禄相同,都是一百人的口粮。赵文子说:“秦公子富有。”叔向说:“根据德行得到俸禄,德行相等根据年龄,年龄相等根据地位。公子的食禄根据他国家的大小,没有听说根据什么富有情况来给。而且带着一千辆车子离开他的国家,强暴太过分了。《诗》说:‘不欺侮鳏寡,不害怕强暴。’秦国、楚国是地位相同的大国。”于是就让后子和子干并列。后子辞谢说:“鍼害怕被放逐,楚公子怕被怀疑,所以都来晋国,也就唯命是听。而且下臣和旅客并列,恐怕不可以吧!史佚有话说:‘不是旅客,为什么要对他恭敬?’” +楚灵王即位,薳罢作令尹,薳启彊作太宰。郑国的游吉到楚国参加郏敖的葬礼,同时为新国君的即位聘问。回国后对子产说:“准备行装吧。楚王骄傲奢侈而自我欣赏他的所作所为,必然要会合诸侯,我没有几天就要前去开会了。”子产说:“没有几年是办不到的。 +十二月,晋国已经举行了冬祭。赵孟去到南阳,准备祭祀孟子馀。初一日,在温地家庙举行冬祭。初七日,死去。郑简公到晋国吊唁,到达雍地就回去了。 + +昭公二年 +【经】二年春,晋侯使韩起来聘。夏,叔弓如晋。秋,郑杀其大夫公孙黑。冬,公如晋,至河乃复。季孙宿如晋。 +【传】二年春,晋侯使韩宣子来聘,且告为政而来见,礼也。观书于大史氏,见《易》《象》与《鲁春秋》,曰:“周礼尽在鲁矣。吾乃今知周公之德,与周之所以王也。”公享之。季武子赋《绵》之卒章。韩子赋《角弓》。季武子拜,曰:“敢拜子之弥缝敝邑,寡君有望矣。”武子赋《节》之卒章。既享,宴于季氏,有嘉树焉,宣子誉之。武子曰:“宿敢不封殖此树,以无忘《角弓》。”遂赋《甘棠》。宣子曰:“起不堪也,无以及召公。” +宣子遂如齐纳币。见子雅。子雅召子旗,使见宣子。宣子曰:“非保家之主也,不臣。”见子尾。子尾见强,宣子谓之如子旗。大夫多笑之,唯晏子信之,曰:“夫子,君子也。君子有信,其有以知之矣。”自齐聘于卫。卫侯享之,北宫文子赋《淇澳》。宣子赋《木瓜》。 +夏四月,韩须如齐逆女。齐陈无宇送女,致少姜。少姜有宠于晋侯,晋侯谓之少齐。谓陈无宇非卿,执诸中都。少姜为之请曰:“送从逆班,畏大国也,犹有所易,是以乱作。” +叔弓聘于晋,报宣子也。晋侯使郊劳。辞曰:“寡君使弓来继旧好,固曰:‘女无敢为宾!’彻命于执事,敝邑弘矣。敢辱郊使?请辞。”致馆。辞曰:“寡君命下臣来继旧好,好合使成,臣之禄也。敢辱大馆?”叔向曰:“子叔子知礼哉!吾闻之曰:‘忠信,礼之器也。卑让,礼之宗也。’辞不忘国,忠信也。先国后己,卑让也。《诗》曰:‘敬慎威仪,以近有德。’夫子近德矣。” +秋,郑公孙黑将作乱,欲去游氏而代其位,伤疾作而不果。驷氏与诸大夫欲杀之。子产在鄙,闻之,惧弗及,乘遽而至。使吏数之,曰:“伯有之乱,以大国之事,而未尔讨也。尔有乱心,无厌,国不女堪。专伐伯有,而罪一也。昆弟争室,而罪二也。薰隧之盟,女矫君位,而罪三也。有死罪三,何以堪之?不速死,大刑将至。”再拜稽首,辞曰:“死在朝夕,无助天为虐。”子产曰:“人谁不死?凶人不终,命也。作凶事,为凶人。不助天,其助凶人乎?”请以印为褚师。子产曰:“印也若才,君将任之。不才,将朝夕从女。女罪之不恤,而又何请焉?不速死,司寇将至。”七月壬寅,缢。尸诸周氏之衢,加木焉。 +晋少姜卒。公如晋,及河。晋侯使士文伯来辞,曰:“非伉俪也。请君无辱!”公还,季孙宿遂致服焉。叔向言陈无宇于晋侯曰:“彼何罪?君使公族逆之,齐使上大夫送之。犹曰不共,君求以贪。国则不共,而执其使。君刑已颇,何以为盟主?且少姜有辞。”冬十月,陈无宇归。 +十一月,郑印段如晋吊。 +译文 +二年春季,晋平公派韩宣子来鲁国聘问,同时报告他掌握国政,因此来进见,这是合于礼的。韩宣子在太史那里观看书籍,看到《易》、《像》和《鲁春秋》,说:“《周礼》都在鲁国了,我现在才知道周公的德行和周朝的所以能成就王业的缘故了。”昭公设享礼招待他,季武子赋《绵》的最后一章。韩宣子赋《角弓》这首诗。季武子参拜说:“谨敢拜谢您弥补敝邑,寡君有了希望了。”季武子赋了《节》的最后一章。享礼完毕,在季武子家里饮宴。有一棵好树,韩宣子赞美它。季武子说:“宿岂敢不培植这棵树,以不忘记《角弓》。”就赋了《甘棠》这首诗。韩宣子说:“起不敢当,赶不上召公。” +韩宣子于是就到齐国奉献财礼。进见子雅。子雅召见子旗,让他拜见韩宣子。韩宣子说:“这不是保住家族的大夫,不像个臣子。”进见子尾。子尾让彊拜见韩宣子。韩宣子对他的评价像对子旗的一样,大夫大多讥笑他,只有晏子相信他,说:“韩先生是个君子。君子有诚心,他是很了解的。”韩宣子从齐国到卫国聘问。卫襄公设享礼招待他。北宫文子赋《淇澳》这首诗,韩宣子赋《木瓜》这首诗。 +夏季,四月,韩须到齐国迎接齐女少姜。齐国的陈无宇送少姜,把她送到晋国。晋平公宠爱少姜,晋平公称她为少齐。认为陈无宇不是卿,把他在中都抓了起来。少姜为他请求,说:“送亲的人地位同于迎亲的人。由于害怕大国,还有一些改变,因此才发生了混乱。” +叔弓到晋国聘问,这是为了回报韩宣子前来聘问的缘故。晋平公派人在郊外慰劳,叔弓辞谢说:“寡君派弓前来重修过去的友好,坚持说‘你不能作为宾客’,只要把命令上达给执事,敝邑就大有光彩了,岂敢烦劳郊使?请允许辞谢。”请他住宾馆,叔弓辞谢说:“寡君命令下臣前来重修过去的友好,友好结合,使命完成,这就是下臣的福禄了。岂敢住进宏大的宾馆!”叔向说:“子叔子懂得礼啊!我听说:‘忠信是礼的容器,卑让是礼的根本。’言辞不忘记国家,这是忠信。先国家后自己,这是卑让。《诗》说:‘不要滥用威仪,以亲近有德的人。’先生已经接近贤德了。” +秋季,郑国的公孙黑准备发动叛乱,想要去掉游氏而代替他的地位,由于旧伤发作,而没有实现。驷氏和大夫们想要杀死公孙黑。子产正在边境,听说了这件事,害怕赶不到,乘坐了传车到达。让官吏历数他的罪状,说:“伯有那次动乱,由于当时正致力于事奉大国,因而没有讨伐你。你有祸乱之心不能满足,国家对你不能容忍。专权而攻打伯有,这是你罪状的第一条。兄弟争夺妻子,这是你罪状的第二条。薰隧的盟会,你假托君位,这是你罪状的第三条。有了死罪三条,怎么能够容忍?你不快点去死,死刑就会到你的头上。”公孙黑再拜叩头,推托说:“我早晚就死,不要帮着上天来虐待我。”子产说:“人谁不死!凶恶的人不得善终,这是天命。做了凶恶的事情,就是凶恶的人。不帮着上天,难道帮着凶恶的人?”公孙黑请求让其子印担任褚师的官职。子产说:印如果有才能,国君将会任命他。如果没有才能,将会早晚跟你去。你对自己的罪过不担心,而又请求什么?不快点去死,司寇将要来到了。”七月初一日,公孙黑上吊死了。暴尸在周氏地方的要道上,把写着罪状的木头放在尸体上。 +晋国的少姜死了。鲁昭公要到晋国去吊唁,到达黄河,晋平公派士文伯来辞谢,说:“不是正式的配偶,请您不必光临。”昭公回国,季孙宿就送去了少姜下葬的衣服。叔向对晋平公谈论陈无宇说:“他有什么罪?君王派公族大夫迎亲,齐国派上大夫送亲,还说不恭敬,君王的要求也太过分了。我国自己就不恭敬,反而把齐国的使者抓起来,君王的刑罚太偏了,怎么做盟主?而且少姜曾经为他说过话的。”冬季十月,陈无宇回国。 +十一月,郑国的印段到晋国去吊唁。 + + +昭公三年 +【经】三年春王正月丁未,滕子原卒。夏,叔弓如滕。五月,葬滕成公。秋,小邾子来朝。八月,大雩。冬,大雨雹。北燕伯款出奔齐。 +【传】三年春,王正月,郑游吉如晋,送少姜之葬。梁丙与张趯见之。梁丙曰:“甚矣哉!子之为此来也。”子大叔曰:“将得已乎?昔文、襄之霸也,其务不烦诸侯。令诸侯三岁而聘,五岁而朝,有事而会,不协而盟。君薨,大夫吊,卿共葬事。夫人,士吊,大夫送葬。足以昭礼命事谋阙而已,无加命矣。今嬖宠之丧,不敢择位,而数于守适,唯惧获戾,岂敢惮烦?少姜有宠而死,齐必继室。今兹吾又将来贺,不唯此行也。”张趯曰:“善哉!吾得闻此数也。然自今,子其无事矣。譬如火焉,火中,寒暑乃退。此其极也,能无退乎?晋将失诸侯,诸侯求烦不获。”二大夫退。子大叔告人曰:“张趯有知,其犹在君子之后乎!” +丁未,滕子原卒。同盟,故书名。 +齐侯使晏婴请继室于晋,曰:“寡君使婴曰:‘寡人愿事君,朝夕不倦,将奉质币,以无失时,则国家多难,是以不获。不腆先君之适,以备内官,焜耀寡人之望,则又无禄,早世殒命,寡人失望。君若不忘先君之好,惠顾齐国,辱收寡人,徼福于大公、丁公,照临敝邑,镇抚其社稷,则犹有先君之适及遗姑姊妹若而人。君若不弃敝邑,而辱使董振择之,以备嫔嫱,寡人之望也。’”韩宣子使叔向对曰:“寡君之愿也。寡君不能独任其社稷之事,未有伉俪。在縗絰之中,是以未敢请。君有辱命,惠莫大焉。若惠顾敝邑,抚有晋国,赐之内主,岂唯寡君,举群臣实受其贶。其自唐叔以下,实宠嘉之。” +既成昏,晏子受礼。叔向从之宴,相与语。叔向曰:“齐其何如?”晏子曰:“此季世也,吾弗知。齐其为陈氏矣!公弃其民,而归于陈氏。齐旧四量,豆、区、釜、钟。四升为豆,各自其四,以登于釜。釜十则钟。陈氏三量,皆登一焉,钟乃大矣。以家量贷,而以公量收之。山木如市,弗加于山。鱼盐蜃蛤,弗加于海。民参其力,二入于公,而衣食其一。公聚朽蠹,而三老冻馁。国之诸市,屦贱踊贵。民人痛疾,而或燠休之,其爱之如父母,而归之如流水,欲无获民,将焉辟之?箕伯、直柄、虞遂、伯戏,其相胡公、大姬,已在齐矣。” +叔向曰:“然。虽吾公室,今亦季世也。戎马不驾,卿无军行,公乘无人,卒列无长。庶民罢敝,而宫室滋侈。道堇相望,而女富溢尤。民闻公命,如逃寇仇。栾、郤、胥、原、狐、续、庆、伯,降在皂隶。政在家门,民无所依,君日不悛,以乐慆忧。公室之卑,其何日之有?《谗鼎之铭》曰:‘昧旦丕显,后世犹怠。’况日不悛,其能久乎?” +宴子曰:“子将若何?”叔向曰:“晋之公族尽矣。肸闻之,公室将卑,其宗族枝叶先落,则公从之。肸之宗十一族,唯羊舌氏在而已。肸又无子。公室无度,幸而得死,岂其获祀?” +初,景公欲更晏子之宅,曰:“子之宅近市,湫隘嚣尘,不可以居,请更诸爽垲者。”辞曰:“君之先臣容焉,臣不足以嗣之,于臣侈矣。且小人近市,朝夕得所求,小人之利也。敢烦里旅?”公笑曰:“子近市,识贵贱乎?”对曰:“既利之,敢不识乎?”公曰:“何贵何贱?”于是景公繁于刑,有鬻踊者。故对曰:“踊贵屦贱。”既已告于君,故与叔向语而称之。景公为是省于刑。君子曰:“仁人之言,其利博哉。晏子一言而齐侯省刑。《诗》曰:‘君子如祉,乱庶遄已。’其是之谓乎!” +及宴子如晋,公更其宅,反,则成矣。既拜,乃毁之,而为里室,皆如其旧。则使宅人反之,曰:“谚曰:‘非宅是卜,唯邻是卜。’二三子先卜邻矣,违卜不祥。君子不犯非礼,小人不犯不祥,古之制也。吾敢违诸乎?”卒复其旧宅。公弗许,因陈桓子以请,乃许之。 +夏四月,郑伯如晋,公孙段相,甚敬而卑,礼无违者。晋侯嘉焉,授之以策,曰:“子丰有劳于晋国,余闻而弗忘。赐女州田,以胙乃旧勋。”伯石再拜稽首,受策以出。君子曰:“礼,其人之急也乎!伯石之汰也,一为礼于晋,犹荷其禄,况以礼终始乎?《诗》曰:‘人而无礼,胡不遄死?’其是之谓乎!” +初,州县,栾豹之邑也。及栾氏亡,范宣子、赵文子、韩宣子皆欲之。文子曰:“温,吾县也。”二宣子曰:“自郤称以别,三传矣。晋之别县不唯州,谁获治之?”文子病之,乃舍之。二子曰:“吾不可以正议而自与也。”皆舍之。及文子为政,赵获曰:“可以取州矣。”文子曰:“退!二子之言,义也。违义,祸也。余不能治余县,又焉用州?其以徼祸也?君子曰:‘弗知实难。’知而弗从,祸莫大焉。有言州必死。” +丰氏故主韩氏,伯石之获州也,韩宣子为请之,为其复取之之故。 +五月,叔弓如滕,葬滕成公,子服椒为介。及郊,遇懿伯之忌,敬子不入。惠伯曰:“公事有公利,无私忌,椒请先入。”乃先受馆。敬子从之。 +晋韩起如齐逆女。公孙虿为少姜之有宠也,以其子更公女而嫁公子。人谓宣子:“子尾欺晋,晋胡受之?”宣子曰:“我欲得齐而远其宠,宠将来乎?” +秋七月,郑罕虎如晋,贺夫人,且告曰:“楚人日征敝邑,以不朝立王之故。敝邑之往,则畏执事其谓寡君‘而固有外心。’其不往,则宋之盟云。进退罪也。寡君使虎布之。”宣子使叔向对曰:“君若辱有寡君,在楚何害?修宋盟也。君苟思盟,寡君乃知免于戾矣。君若不有寡君,虽朝夕辱于敝邑,寡君猜焉。君实有心,何辱命焉?君其往也!苟有寡君,在楚犹在晋也。” +张趯使谓大叔曰:“自子之归也,小人粪除先人之敝庐,曰子其将来。今子皮实来,小人失望。”大叔曰:“吉贱,不获来,畏大国,尊夫人也。且孟曰:‘而将无事。’吉庶几焉。” +小邾穆公来朝。季武子欲卑之,穆叔曰:“不可。曹、滕、二邾,实不忘我好,敬以逆之,犹惧其贰。又卑一睦,焉逆群好也?其如旧而加敬焉!《志》曰:‘能敬无灾。’又曰:‘敬逆来者,天所福也。’”季孙从之。 +八月,大雩,旱也。 +齐侯田于莒,卢蒲弊见,泣且请曰:“余发如此种种,余奚能为?”公曰:“诺,吾告二子。”归而告之。子尾欲复之,子雅不可,曰:“彼其发短而心甚长,其或寝处我矣。”九月,子雅放卢蒲弊于北燕。 +燕简公多嬖宠,欲去诸大夫而立其宠人。冬,燕大夫比以杀公之外嬖。公惧,奔齐。书曰:“北燕伯款出奔齐。”罪之也。 +十月,郑伯如楚,子产相。楚子享之,赋《吉日》。既享,子产乃具田备,王以田江南之梦。 +齐公孙灶卒。司马灶见晏子,曰:“又丧子雅矣。”晏子曰:“惜也!子旗不免,殆哉!姜族弱矣,而妫将始昌。二惠竞爽,犹可,又弱一个焉,姜其危哉!” +译文 +三年春季,周王朝历法的正月,郑国的游吉到晋国去,为少姜送葬,梁丙和张趯拜见他。梁丙说:“太过分了,您为这件事情而来!”游吉说:“不得已呀!从前文公、襄公称霸的时候,他们的事情不烦劳诸侯。命令诸侯三年一聘问,五年一朝觐,有事就会见,不和睦就结盟。国君死,大夫吊唁,卿参加安葬。夫人死,士去吊唁,大夫送葬。只要发扬礼仪、发布命令,商量补救缺失就足够了,不再用额外的命令加于诸侯。现在宠姬的丧事,别国不敢选择适当职位的人参加丧礼,而且礼数超过正夫人,惟恐得到罪过,岂敢怕麻烦?少姜得到宠爱而死,齐国必然继续送女子前来。现在我又一次将要来祝贺,不仅是这一趟啊。”张趯说:“好啊,我能够听到这样的礼数!然而从今以后您大约没有这样的事情了。譬如大火星,它在天空正中,寒气或者暑气就要消退。这一次就是极点,能够不衰退吗?晋国将会失去诸侯的拥护,诸侯想要麻烦还得不到呢。”两位大夫退出。游吉告诉别人说:“张趯明白事理,也许还是跟在君子的行列里吧!” +正月二十四日,滕成公原死了。由于是同盟国家,所以《春秋》记载他的名字。 +齐景公派晏婴请求继续送女子到晋国,说:“寡君派遣婴的时候说:‘寡人愿意奉事君王,早晚都不倦怠,要奉献财礼而不失去定时,然而由于国家多难,因此不能前来。先君的嫡女有幸在君王的内宫充数,照亮了寡人的希望,但又没有福气,过早地死去了,寡人失去了希望。君王如果不忘记先君的友好,加恩顾念齐国,对寡人和睦,求福于太公、丁公,光辉照耀敝邑,镇定安抚我们的国家,那么还有先君的嫡女和其余姑姐妹若干人。君王如果不抛弃敝邑,而派遣使者慎重选择,作为姬妾,这就是寡人的希望。’”韩宣子派叔向回答说:“这正是寡君的愿望。寡君不能单独承担国家大事,没有正式的配偶,由于在服丧期间,因此没有敢提出请求。君王有命令,没有比这再大的恩惠了。如果加恩顾念敝邑,安抚晋国,赐给晋国内主,岂独是寡君,所有的臣下都受到他的恩赐,从唐叔以下都会尊崇赞许他。” +订婚以后,晏子接受享礼,叔向陪他饮宴,互相谈话。叔向说:“齐国怎么样?”晏子说:“到了末世了,我不能不说齐国可能属于陈氏了。国君不爱护他的百姓,让他们归附陈氏。齐国过去有四种量器,豆、区、釜、钟。四升为一豆,各自再翻四倍,以成为一釜。十釜就是一钟。陈氏的豆、区、釜三种量器都加大四分之一,钟的容量就大了。他用私家的大量器借出,而用公家的小量器收回。山上的木料运到市场,价格不高于山上。鱼盐蜃蛤,价格不高于海边。百姓力量如果分为三份,两分归于国君,只有一份维持衣食。国君的积蓄腐朽生虫,而老人们却挨冻受饥。国都的市场上,鞋子便宜而假足昂贵。百姓有痛苦疾病,陈氏就厚加赏赐。他爱护百姓如同父母,而百姓归附如同流水。想要不得到百姓的拥护,哪里能避开?箕伯、直柄、虞遂、伯戏,他们跟随着胡公、太姬,已经在齐国了。” +叔向说:“是呀。即使是我们公室,现在也是末世了。战马不驾战车,卿不率领军队,公室的战车没有御者和戎右,步兵的行列没有长官。百姓困疲,而宫室更加奢侈。道路上饿死的人坟堆一个接着一个可以互相看见,而宠姬的家里财富特别多,百姓听到国君的命令,好像躲避仇敌一样。栾、郤、胥、原、狐、续、庆、伯这八家已经降为低贱吏役,政事在于私家,百姓无依无靠。国君毫不改悔,用欢乐来排遣忧患。公室的卑微,还能有几天?谗鼎上的铭文说,‘黎明即起,声名可以显赫,子孙后代还会懈怠’,何况毫不改悔,他能够长久吗?” +晏子说:“您打算怎么办?”叔向说:“晋国的公族完结了。肸听说,公室将要卑微,它的宗族像树叶一样先落,公室就跟着凋零了。肸的一宗十一族,只有羊舌氏还在。肸又没有好儿子,公室又没有法度,得到善终就是侥幸,难道还会受到祭祀?” +当初,齐景公要为晏子更换住宅,说:“您的住房靠近市区,低湿狭小,喧闹多尘,不能居住,请您换到高爽明亮的房子里去。”晏子辞谢说:“君王的先臣住在这里,下臣不足以继承祖业,住在里边已经过分了。而且小人靠近市场,早晚能得到所需要的东西,这是小人的利益,岂敢麻烦邻里大众为我造新房子?”齐景公笑着说:“您靠近市场,知道物价的贵贱吗?”晏子回答说:“既然以它为利,哪能不知道呢?”景公说:“什么贵?什么贱?”当时,齐景公滥用刑罚,有出卖假腿的,所以晏子回答说:“假腿贵,鞋子贱。”晏子已经告诉国君,所以跟叔向说话的时候也谈到这个。齐景公为此就减省了刑罚。君子说:“仁人的话,它的利益多么广大啊!晏子一句话,齐侯就减省刑罚。《诗》说,‘君子如果喜悦,祸乱庶几乎很快停歇’,说的就是这个吧!” +等到晏子去晋国,齐景公更换他的住宅,回来,新屋就已经完工。晏子拜谢以后,就拆毁了新房而建造邻居的房屋,恢复如原来的一样,让原来的住户回来,说:“俗话说:‘不是住宅需要占卜,惟有邻居需要占卜。’这几位已经先占卜邻居了,违背占卜不祥。君子不去做不合礼的事情,小人不去做不祥的事情,这是古代的制度,我敢违背它吗?”终于恢复了旧居。齐景公开始不允许,晏子托除桓子代为请求,齐景公才允许了。 +夏季,四月,郑简公到晋国,公孙段作为相礼者,很恭敬而卑躬屈节,礼仪没有违背的。晋平公赞许,把策书授给公孙段,说:“子丰在晋国有过功劳,我听说了以后不会忘记。赐给你州县的土田,以报答你们过去的勋劳。”公孙段再拜叩头,接受了策书而去,君子说:“礼仪,大约是人所急迫需要的吧!公孙段这样骄傲,一旦在晋国有了礼仪,尚且承受了它的福禄,何况始终都有礼仪呢?《诗》说,‘人没有礼仪,为什么不快点死’,说的就是这个吧!” +当初,州县是栾豹的采邑。等到栾氏灭亡,范宣子、赵文子、韩宣子都想要这块地方。赵文子说:“温县,是我的县。”两个宣子说:“从郤称划分州县以来,已经传了三家了。晋国把一县划分为二的不仅只州县,谁能够按划分前的情况去治理它?”赵文子感到惭愧,就放弃了州县。两个宣子说:“我们不能口头上公正,而把好处给自己。”就都放弃了。等到赵文子执政,赵获说:“可以把州县拿过来了。”赵文子说:“出去!这两位的话,是合于道义的。违背道义,就是祸患。我不能治理我的封邑,又哪里用得着州县,而去自找祸患?君子说:‘不知道祸患是很难的。’知道了不照着做,没有比这再大的祸患了。再有人提到州县的一定处死!” +丰氏原来住在韩氏家里,公孙段得到州县,是韩宣子为公孙段请求的,这是为了他可以再次取得州县的缘故。 +五月,叔弓到滕国去,参加滕成公的葬礼,子服椒作为副手。到达郊外,碰上懿伯的忌日,叔弓便不进入滕国。子服椒说:“公家的事情只能考虑公家的利益,没有私家的忌避。椒请求先进入。”于是就先住进宾馆。叔弓听从了他的意见。 +晋国的韩起到齐国迎接齐女。公孙虿因为少姜受到宠爱,把他的女儿更换了齐景公的女儿,而把齐景公的女儿嫁给别人。别人对韩宣子说:“子尾欺骗晋国,晋国为什么接受?”韩宣子说:“我们想要得到齐国,却反而疏远他的宠臣,宠臣能够来吗?” +秋季,七月,郑国的罕虎到晋国去,祝贺夫人,并且报告说:“楚国人每天来问敝邑不去朝贺他们新立国君的原因。如果敝邑派人前去,就害怕执事会说寡君本来就有心向外。如果不去,那么在宋国的盟约又规定了是要去朝见的。进退都是罪过。寡君派虎前来陈述。”宣子派叔向回答说:“君王如果心向着寡君,在楚国有什么害处?这是为了重修在宋国盟会的友好。君王如果想到盟约,寡君就知道可以免于罪过了。君王如果心中没有寡君,虽然早晚光临敝邑,寡君也会猜疑的。君王果真实心向寡君,何必来告诉寡君。君王还是前去吧!如果心向寡君,在楚国在晋国都是一样的。” +张趯派人对太叔说:“自从您回去以后,小人扫除先人的破旧房子,说,‘您可能会来的。’现在子皮来了,小人失去了希望。”太叔说:“吉的地位低下,不能前来,这是由于害怕大国、尊敬夫人的缘故。而且孟说‘你将要没事了’,吉大概没事了。” +小邾穆公前来朝见,季武子不想用诸侯的礼仪接待他。穆叔说:“不行。曹国、滕国和两个邾国确实没有忘记和我国的友好,恭恭敬敬的迎接他,还害怕他有二心,反而又降低一个友好国家的地位,怎么能迎接许多友好国家呢?还是像过去一样更加恭敬些。《志》说:‘能够恭敬没有灾祸。’又说:‘恭敬地迎接前来的人,这就是上天降福的原因。’”季孙听从了他的话。 +八月,举行大雩祭,这是由于旱灾的缘故。 +齐景公在莒地打猎,卢蒲嫳进见,哭泣,而且请求说:“我的头发这么短,我还能做什么?”齐景公说:“好。我告诉那两位。”回去以后就告诉了子尾和子雅。子尾想要让他官复原位,子雅不同意,说:“他的头发短,心计长,他也许要睡在我的皮上了。”九月,子雅把卢蒲嫳放逐到北燕。 +燕简公有很多宠爱的人,想要去掉大夫们而立宠臣为大夫。冬季,燕国的大夫们勾结起来杀死了简公的宠臣。简公害怕,逃亡到齐国。《春秋》记载说“北燕伯款出奔齐”,这是说他有罪。 +十月,郑简公去到楚国,子产作为相礼者。楚灵王设享礼招待郑简公,赋《吉日》这首诗。享礼结束,子产就准备了打猎用具,楚灵王和郑简公在江南的云梦打猎。 +齐国的公孙灶死了。司马灶进见晏子,说:“又失去了子雅了。”晏子说:“可惜啊!子旗不能免于祸患,危险啊!姜族削弱了,而妫氏将要开始昌盛。惠公的两个子孙刚强明白,还可以维持姜氏,又丧失了一个,姜氏恐怕危险呀!” + +昭公四年 +【经】四年春王正月,大雨雹。夏,楚子、蔡侯、陈侯、郑伯、许男、徐子、滕子、顿子、胡子、沈子、小邾子、宋世子佐、淮夷会于申。楚子执徐子。秋七月,楚子、蔡侯、陈侯、许男、顿子、胡子、沈子、淮夷伐吴,执齐庆封,杀之。遂灭赖。九月,取鄫。冬十有二月乙卯,叔孙豹卒。 +【传】四年春,王正月,许男如楚,楚子止之,遂止郑伯,复田江南,许男与焉。使椒举如晋求诸侯,二君待之。椒举致命曰:“寡君使举曰:‘日君有惠,赐盟于宋,曰:晋、楚之从,交相见也。以岁之不易,寡人愿结欢于二三君。’使举请间。君若苟无四方之虞,则愿假宠以请于诸侯。” +晋侯欲勿许。司马侯曰:“不可。楚王方侈,天或者欲逞其心,以厚其毒而降之罚,未可知也。其使能终,亦未可知也。晋、楚唯天所相,不可与争。君其许之,而修德以待其归。若归于德,吾犹将事之,况诸侯乎?若适淫虐,楚将弃之,吾又谁与争?”曰:“晋有三不殆,其何敌之有?国险而多马,齐、楚多难。有是三者,何乡而不济?”对曰:“恃险与马,而虞邻国之难,是三殆也。四岳、三涂、阳城、大室、荆山、中南,九州之险也,是不一姓。冀之北土,马之所生,无兴国焉。恃险与马,不可以为固也,从古以然。是以先王务修德音以亨神人,不闻其务险与马也。邻国之难,不可虞也。或多难以固其国,启其疆土;或无难以丧其国,失其守宇。若何虞难?齐有仲孙之难而获桓公,至今赖之。晋有里、丕之难而获文公,是以为盟主。卫、邢无难,敌亦丧之。故人之难,不可虞也。恃此三者,而不修政德,亡于不暇,又何能济?君其许之!纣作淫虐,文王惠和,殷是以陨,周是以兴,夫岂争诸侯?”乃许楚使。使叔向对曰:“寡君有社稷之事,是以不获春秋时见。诸侯,君实有之,何辱命焉?”椒举遂请昏,晋侯许之。 +楚子问于子产曰:“晋其许我诸侯乎?”对曰:“许君。晋君少安,不在诸侯。其大夫多求,莫匡其君。在宋之盟,又曰如一,若不许君,将焉用之?”王曰:“诸侯其来乎?”对曰:“必来。从宋之盟,承君之欢,不畏大国,何故不来?不来者,其鲁、卫、曹、邾乎?曹畏宋,邾畏鲁,鲁、卫逼于齐而亲于晋,唯是不来。其馀,君之所及也,谁敢不至?”王曰:“然则吾所求者,无不可乎?”对曰:“求逞于人,不可;与人同欲,尽济。” +大雨雹。季武子问于申丰曰:“雹可御乎?”对曰:“圣人在上,无雹,虽有,不为灾。古者,日在北陆而藏冰;西陆,朝觌而出之。其藏冰也,深山穷谷,固阴冱寒,于是乎取之。其出之也,朝之禄位,宾食丧祭,于是乎用之。其藏之也,黑牲、秬黍,以享司寒。其出之也,桃弧、棘矢,以除其灾。其出入也时。食肉之禄,冰皆与焉。大夫命妇,丧浴用冰。祭寒而藏之,献羔而启之,公始用之。火出而毕赋。自命夫、命妇,至于老疾,无不受冰。山人取之,县人传之,舆人纳之,隶人藏之。夫冰以风壮,而以风出。其藏之也周,其用之也遍,则冬无愆阳,夏无伏阴,春无凄风,秋无苦雨,雷不出震,无灾霜雹,疠疾不降,民不夭札。今藏川池之冰,弃而不用。风不越而杀,雷不发而震。雹之为灾,谁能御之?《七月》之卒章,藏冰之道也。” +夏,诸侯如楚,鲁、卫、曹、邾不会。曹、邾辞以难,公辞以时祭,卫侯辞以疾。郑伯先待于申。六月丙午,楚子合诸侯于申。椒举言于楚子曰:“臣闻诸侯无归,礼以为归。今君始得诸侯,其慎礼矣。霸之济否,在此会也。夏启有钧台之享,商汤有景亳之命,周武有孟津之誓,成有岐阳之搜,康有酆宫之朝,穆有涂山之会,齐桓有召陵之师,晋文有践土之盟。君其何用?宋向戌、郑公孙侨在,诸侯之良也,君其选焉。”王曰:“吾用齐桓。”王使问礼于左师与子产。左师曰:“小国习之,大国用之,敢不荐闻?”献公合诸侯之礼六。子产曰:“小国共职,敢不荐守?”献伯、子、男会公之礼六。君子谓合左师善守先代,子产善相小国。王使椒举侍于后,以规过。卒事,不规。王问其故,对曰:“礼,吾所未见者有六焉,又何以规?”宋大子佐后至,王田于武城,久而弗见。椒举请辞焉。王使往,曰:“属有宗祧之事于武城,寡君将堕币焉,敢谢后见。” +徐子,吴出也,以为贰焉,故执诸申。 +楚子示诸侯侈,椒举曰:“夫六王二公之事,皆所以示诸侯礼也,诸侯所由用命也。夏桀为仍之会,有婚叛之。商纣为黎之搜,东夷叛之。周幽为大室之盟,戎狄叛之。皆所以示诸侯汰也,诸侯所由弃命也。今君以汰,无乃不济乎?”王弗听。 +子产见左师曰:“吾不患楚矣,汰而愎谏,不过十年。”左师曰:“然。不十年侈,其恶不远,远恶而后弃。善亦如之,德远而后兴。” +秋七月,楚子以诸侯伐吴。宋大子、郑伯先归。宋华费遂、郑大夫从。使屈申围朱方,八月甲申,克之。执齐庆封而尽灭其族。将戮庆封。椒举曰:“臣闻无瑕者可以戮人。庆封唯逆命,是以在此,其肯从于戮乎?播于诸侯,焉用之?”王弗听,负之斧钺,以徇于诸侯,使言曰:“无或如齐庆封,弑其君,弱其孤,以盟其大夫。”庆封曰:“无或如楚共王之庶子围,弑其君、兄之子麇而代之,以盟诸侯。”王使速杀之。 +遂以诸侯灭赖。赖子面缚衔璧,士袒,舆榇从之,造于中军。王问诸椒举,对曰:“成王克许,许僖公如是,王亲释其缚,受其璧,焚其榇。”王从之。迁赖于鄢。楚子欲迁许于赖,使斗韦龟与公子弃疾城之而还。申无宇曰:“楚祸之首,将在此矣。召诸侯而来,伐国而克,城竟莫校。王心不违,民其居乎?民之不处,其谁堪之?不堪王命,乃祸乱也。” +九月,取鄫,言易也。莒乱,着丘公立而不抚鄫,鄫叛而来,故曰取。凡克邑不用师徒曰取。 +郑子产作丘赋。国人谤之,曰:“其父死于路,己为虿尾。以令于国,国将若之何?”子宽以告。子产曰:“何害?苟利社稷,死生以之。且吾闻为善者不改其度,故能有济也。民不可逞,度不可改。《诗》曰:‘礼义不愆,何恤于人言。’吾不迁矣。”浑罕曰:“国氏其先亡乎!君子作法于凉,其敝犹贪。作法于贪,敝将若之何?姬在列者,蔡及曹、滕其先亡乎!逼而无礼。郑先卫亡,逼而无法。政不率法,而制于心。民各有心,何上之有?” +冬,吴伐楚,入棘、栎、麻,以报朱方之役。楚沈尹射奔命于夏汭,咸尹宜咎城钟离,薳启强城巢,然丹城州来。东国水,不可以城。彭生罢赖之师。 +初,穆子去叔孙氏,及庚宗,遇妇人,使私为食而宿焉。问其行,告之故,哭而送之。适齐,娶于国氏,生孟丙、仲壬。梦天压己,弗胜。顾而见人,黑而上偻,深目而豭喙。号之曰:“牛!助余!”乃胜之。旦而皆召其徒,无之。且曰:“志之。”及宣伯奔齐,馈之。宣伯曰:“鲁以先子之故,将存吾宗,必召女。召女,何如?”对曰:“愿之久矣。”鲁人召之,不告而归。既立,所宿庚宗之妇人,献以雉。问其姓,对曰:“余子长矣,能奉雉而从我矣。”召而见之,则所梦也。未问其名,号之曰:“牛!”曰:“唯”。皆召其徒,使视之,遂使为竖。有宠,长使为政。公孙明知叔孙于齐,归,未逆国姜,子明取之。故怒,其子长而后使逆之。田于丘莸,遂遇疾焉。竖牛欲乱其室而有之,强与孟盟,不可。叔孙为孟钟,曰:“尔未际,飨大夫以落之。”既具,使竖牛请日。入,弗谒。出,命之日。及宾至,闻钟声。牛曰:“孟有北妇人之客。”怒,将往,牛止之。宾出,使拘而杀诸外,牛又强与仲盟,不可。仲与公御莱书观于公,公与之环。使牛入示之。入,不示。出,命佩之。牛谓叔孙:“见仲而何?”叔孙曰:“何为?”曰:“不见,既自见矣。公与之环而佩之矣。”遂逐之,奔齐。疾急,命召仲,牛许而不召。 +杜泄见,告之饥渴,授之戈。对曰:“求之而至,又何去焉?”竖牛曰:“夫子疾病,不欲见人。”使置馈于个而退。牛弗进,则置虚,命彻。十二月癸丑,叔孙不食。乙卯,卒。牛立昭子而相之。 +公使杜泄葬叔孙。竖牛赂叔仲昭子与南遗,使恶杜泄于季孙而去之。杜泄将以路葬,且尽卿礼。南遗谓季孙曰:“叔孙未乘路,葬焉用之?且冢卿无路,介卿以葬,不亦左乎?”季孙曰:“然。”使杜泄舍路。不可,曰:“夫子受命于朝,而聘于王。王思旧勋而赐之路。覆命而致之君,君不敢逆王命而复赐之,使三官书之。吾子为司徒,实书名。夫子为司马,与工正书服。孟孙为司空,以书勋。今死而弗以,同弃君命也。书在公府而弗以,是废三官也。若命服,生弗敢服,死又不以,将焉用之?”乃使以葬。 +季孙谋去中军。竖牛曰:“夫子固欲去之。” +译文 +四年春季,周王朝历法的正月,许悼公到楚国,楚灵王留下了他,也就留下郑简公,再次到江南打猎,许悼公参加了。 +楚灵王派椒举去到晋国去求得诸侯的拥护,郑简公、许悼公在这里等待,椒举传达楚灵王的命令说:“寡君派遣举前来的时候说:从前蒙贵君的恩惠,赐给敝邑在宋国结盟,说:‘从前跟从晋国和楚国的国家互相朝见。’由于近年来多难,寡人愿意讨取几位国君的欢心,派举前来请您在闲空时听取寡人的请求。您如果对四方边境没有忧患,那么就希望借您的影响向诸侯请求。” +晋平公不想允许。司马侯说:“不行。楚灵王做事正在胡作妄为的时侯,上天也许是想让他满足愿望,以增加他的劣迹,然后给他降下惩罚,这是说不定的。或者让他得以善终,这也是说不定的。晋国和楚国的霸业只有靠上天的帮助,而不是彼此可以争夺的。君王还是允许他,而修明德行以等待他的结局。如果归结到德行,我们还要去事奉他,何况诸侯?如果走到荒淫暴虐,楚国自己会抛弃他,我们又与谁去争夺?”晋平公说:“晋国有三条可以免于危险,还有谁能和我们相比?国家的地势险要而多产马匹,齐国、楚国祸难又多。有这三条,到哪儿不成功?”司马侯回答说:“仗着地势险要和马匹,而对邻国幸灾乐祸,这是三条危险。四岳、三涂、阳城、太室、荆山、中南,都是九州中的险要地方,它们并不属于一姓所有。冀州的北部,是出产马的地方,并没有新兴的国家。仗着地势险要和马匹,不能巩固,从古以来就是这样。因此国君致力于修明德行来沟通神和人,没有听说他致力于地形险要和马匹的。邻国的祸难,是不能以此来高兴的。或者是由于多有祸难而巩固了国家,开辟了疆土。或者是由于没有祸难而丧失了国家,失掉了疆土,怎么能幸灾乐祸?齐国发生了仲孙的祸难,因而桓公得为霸主,到今天齐国还靠着他的余荫。晋国发生了里克、丕郑的祸难因而文公回国,因此当了盟主。卫国、邢国没有祸难,敌人也就灭了它们。所以别人的祸难是不能去高兴的。依仗这三条,而不去修明政事和德行,挽救危亡还来不及,又怎么能够成功?您还是允许他们。殷纣王淫乱暴虐,文王仁慈和蔼。殷朝因此灭亡,周朝因此兴起,难道只是在于争夺诸侯?”晋平公就允许了楚国使者的请求,派叔向回答说:“寡君因为有国家大事,所以不能在春秋两季按时进见。至于诸侯,他们本来就跟着君王,何必再惠赐命令呢?”椒举就为楚灵王求婚,晋平公答应了婚事。 +楚灵王向子产询问说:“晋国会允许诸侯归服我国吗?”子产说:“会允许君王的。晋平公贪图小的安逸,志向不在于诸侯。他的大夫们多所需求,不能帮助国君。在宋国的盟约又说两国友好如同一国。如果不允许君王,哪里用得着在宋国的盟约?”楚灵王说:“诸侯会来吗?”子产说:“一定来。服从在宋国的盟约,取得君王的欢心,不害怕晋国,为什么不来?不来的国家,大约是鲁、卫、曹、邾几个国家吧!曹国害怕宋国,邾国害怕鲁国,鲁国、卫国为齐国所逼迫而亲近晋国,因此不来。其余的国家,是君王的威力所能达到的,谁敢不来?”楚灵王说:“那么我所要求的没有不行的了?”子产回答说:“在别人那里求取快意,不行。和别人愿望相同,都能成功。” +天下大雨和冰雹。季武子向申丰询问说:“冰雹可以防止吗?”申丰说:“圣人在上面,没有冰雹。即使有也不成灾。在古代,太阳在虚宿和危宿的位置上就藏冰,昴宿和毕宿在早晨出现就把冰取出来。当藏冰的时候,深山穷谷,凝聚着阴寒之气,就在这里凿取。当把冰取出来的时候,朝廷上有禄位的人,迎宾、用膳、丧事、祭祀,就在这里取用。当收藏冰的时候,用黑色的公羊和黑色的黍子来祭祀司寒之神。当把冰取出的时候,门上挂上桃木弓、荆棘箭,来消除灾难。冰的收藏取出都按一定的时令。凡是禄位足以吃肉的官吏,都是有资格用冰的。大夫和妻子死后洗擦身体要用冰。祭祀司寒之神而加以收藏,奉献羔羊祭祖打开冰室,国君最早使用。大火星出现而分配完毕,从大夫和他们的妻子以至于老弱的生病的,没有人不分到冰。小官在深山中凿取冰,县正运输,舆人交付,隶人收藏。冰由于寒风而坚固,而由于春风而取出使用。它的收藏周密,它的使用普遍,那就冬天没有温暖,夏天没有阴寒,春天没有凄风。秋天没有苦雨,雷鸣不伤人,霜雹不成灾,瘟疫不流行,百姓不死于传染病。现在收藏着河川池塘的冰放在那里不用,风不散而草木凋零,雷不鸣而畜伤亡,冰雹成灾,谁能够防止它?《七月》这首诗的最后一章,就是藏冰的道理。” +夏季,诸侯到楚国去,鲁国、卫国、曹国、邾国不参加会见。曹国、邾国用国内不安定来推辞,鲁昭公用祭祖来推辞,卫襄公用生病来推辞。郑简公先在申地等待。六月十六日,楚灵王在申地会合诸侯。椒举对楚灵王说:“下臣听说,诸侯不归服于别的,只归服于有礼。现在君王开始得到诸侯,对礼仪要谨慎啊。霸业的成功与否,都在这次会见了。夏启有钧台的宴享,商汤有景亳的命令,周武王有孟津的盟誓,成王有岐阳的田猎,康王有鄷宫的朝觐,穆王有涂山的会见,齐桓公有召陵的会师,晋文公有践土的会盟。君王打算采用哪一种?宋国的左师、郑国的子产在这里,他们是诸侯大夫中的能干人物,君王可以加以挑选。”楚灵王说:“我采用齐桓公的方式。”楚灵王派人向左师和子产询问礼仪。左师说:“小国学习礼仪,大国使用礼仪,岂敢不进献所听到的?”献上公侯会合诸侯的礼仪六项。子产说:“小国以事奉大国作为职责,岂敢不进献所该做的?”献上伯爵、子爵、男爵会见公爵的礼仪六项。君子认为左师善于保持前代的札仪,子产善于辅佐小国。楚灵王让椒举侍从在身后,以便纠正错误,到事情结束,没有任何纠正。楚灵王问他什么缘故,椒举回答说:“礼仪,我没有见到的有六项,又怎么纠正?”宋国的太子佐晚到,楚灵王在武城打猎,很久没有接见他。椒举请楚灵王辞谢他。楚灵王派使者前去,说:“在武城正有祭祀宗庙的事情,寡君将要把财礼敬献给宗庙,谨为不能及时接见您而致意。” +徐国的国君,是吴国女子生的,楚灵王认为他有二心,所以在申地把他逮捕了。 +楚灵王向诸侯显示出骄纵。椒举说:“六王、二公的事情,都是以此向诸侯显示礼仪,诸侯也因此而听命。夏桀举行仍地的会见,有缗背叛了他。商纣举行黎地打猎,东夷背叛了他。周幽王举行太室的盟会,戎狄背叛了他。都是以此向诸侯显示骄纵所造成的,诸侯也因此而违命。现在君王过于骄纵,恐怕不会成功吧!”楚灵王不听。 +子产见到左师说:“我不担心楚国了。骄纵又不听劝谏,不超过十年。”左师说:“对。不是十年的骄纵,他的邪恶不会远播。邪恶远播然后被抛弃。善也像恶一样,德行远播然后兴盛。” +秋季,七月,楚灵王带领诸侯进攻吴国,宋国太子佐、郑简公先行回国。宋国的华费遂、郑国的大夫跟从军队。派屈申包围朱方,八月某日,攻下了朱方,逮住了齐国的庆封而把他的族人全部消灭。将要诛戮庆封,椒举说:“臣听说没有缺点的人才可以诛杀别人。庆封就因为违逆君命,才在这里,他肯不吭一声地被杀戮吗?如果丑事在诸侯中宣扬,为什么要那么做呢?”楚灵王不听,让庆封背上大斧头,在诸侯军队中巡行示众,让他说:“不要有人像齐国的庆封那样杀死他的国君,削弱国君的孤儿,来和他的大夫会盟!”庆封说:“不要有人像楚共王的庶子围,杀死他的国君——哥哥的儿子麇而取代他,来和诸侯盟会!”楚灵王赶快让人把他杀了。 +楚灵王于是就带领诸侯灭亡赖国。赖国的国君两手反绑,嘴里叼着玉璧,士袒背,抬着棺材跟从,到了中军之中。楚灵王向椒举询问,椒举回答说:“成王攻克许国,许僖公就像这样。成王亲手解除他的捆绑,接受了他的玉璧,烧掉了他的棺材。”楚灵王听从了他的意见。把赖国迁移到鄢地。楚灵王想要把许国迁移到赖国内,派鬬韦龟和公子弃疾为许国筑了城后才回国。申无宇说:“楚国祸难的开始将会在这里了。召集诸侯就前来,攻打别国就得胜,在边境筑城诸侯没有人争论,国君的愿望都能如意,百姓能够安居吗?百姓不能安居,谁能够受得了?不能忍受国君的命令,就是祸乱。” +九月,取得鄫国,这是说事情很容易。莒国发生动乱,莒丘公即位而不安抚鄫国,鄫国背叛而来,所以说“取”。凡是攻下城邑,不使用兵力叫做“取”。 +郑国的子产制订丘赋的制度,国内的人们指责他,说:“他的父亲死在路上,他自己做蝎子的尾巴,还在国内发布命令,国家将要怎么办?”子宽把话告诉子产。子产说:“有什么妨害?如果有利于国家,生死都不计较。而且我听说做好事的不改变他的法制,所以能够有所成功。百姓不能放纵,法制不能更改。《诗》说:‘在礼义上没有过错,为什么怕别人说的话。’我不改变了。”子宽说:“国氏恐怕要先灭亡吧!君子在不厚道的基础上制订法令,它的后果尚且是贪婪。在贪婪的基础上制定法令,后果将会怎么样?姬姓的国家,蔡国和曹国、滕国大约是要先灭亡的吧!因为它们逼近大国而没有礼仪。郑国在卫国之前灭亡,因为它逼近大国而没有法度。政策不遵循法度,而由自己的意志来决定。百姓各人有各人的意志,哪里能够尊敬上面的人?” +冬季,吴国进攻楚国,进入棘地、栎地、麻地,以报复朱方这次战役。楚国的沈尹射到夏汭奔赴应命,箴尹宜咎在钟离筑城,薳启彊在巢地筑城,然丹在州来筑城。东部地区发生水灾,不能筑城。彭生停止了赖地的筑城任务。 +当初,穆子离开宗族叔孙氏,到达庚宗,碰到一个女人,让她私下弄点东西吃了以后就和她私通。女人问他的行动,穆子把原因告诉她,她哭着送走了穆子。去到齐国,在国氏那里娶了妻子,生了孟丙、仲壬。穆子梦见天塌下来压着自己,要顶不住了,回头一看,见到一个人,黑皮肤,驼背,抠眼睛,猪嘴巴,就喊叫说:“牛,来帮我!”这才顶住了。早晨召见手下人,没有像梦中见到的人,就说:“记住这个人!”等到宣伯逃亡到齐国,穆子送给他食物。宣伯说:“鲁国由于我们先人的缘故,将会保存我们的宗族,一定会召你回去。要是召你回去,怎么样?”穆子回答说:“早就愿意了。”鲁国人召他回去,他不告诉宣伯就走了。穆子立为卿以后,在庚宗和他睡觉的女人献上野鸡。穆子问他儿子的情况,回答说:“我儿子长大了,能够捧着野鸡跟着我了。”把孩子召来一看,就像穆子所梦见的人。穆子没有问他的名字,就喊他叫“牛”,孩子回答说:“唯。”穆子把手下人都召来让他们看这个孩子,就让他做了小臣。牛受到宠信,大了以后就让他主管家政。穆子在齐国的时候公孙明和他很友好,穆子回国,没有去接国姜,公孙明娶了她。穆子生气妻子已改嫁,等两个儿了长大以后才派人去接回鲁国。 +穆子在丘莸打猎,便得了病。竖牛想要搅乱他的家室而自己占有,一定要和孟丙盟誓,孟丙不同意。穆子为孟丙铸造了一口钟,说:“你还没有入正式交际场合,在为大夫们举行享礼的时候,举行钟的落成典礼。”孟丙将享礼准备好了,让竖牛请穆子定了日期。竖牛进去了,不报告这件事。出来,假说穆子的命令定了日期。等到宾客来到,穆子听到钟声。竖牛说:“孟丙那里有北边女人的客人。”穆子发怒,准备前去,竖牛阻止了他。客人出去以后,穆子派人拘禁了孟丙而在外边把他杀了。竖牛硬要和仲壬盟誓,仲壬不同意。仲壬和昭公的御者莱书在公宫游玩,昭公赐给他玉环。仲壬让竖牛送去给穆子看。竖牛进去了不给他看。出来,假说穆子的命令让仲壬佩戴。竖牛对穆子说:“让仲壬进见国君怎么样?”穆子说:“为什么?”竖牛说:“不让他进见,他自己已经去见过了,国君给了他玉环佩在身上了。”穆子就把仲壬赶走了,仲壬逃亡到齐国。穆子病危,命令召仲壬回来,竖牛虽答应了,却不去召他回来。 +杜泄进见,穆子告诉他自己又饥又渴,把戈交给杜泄让他去杀死竖牛。杜泄回答说:“找他他来了,为什么又要去掉他?”竖牛说:“他老人家病得很重,不想见人。”让别人把送来的食物放在厢房里,就退出去。竖牛不把食物送进去,就倒掉了,让人撤走食具。十二月二十六日,穆子不吃东西,二十八日死。竖牛立了昭子并辅佐他。 +鲁昭公派杜泄安葬穆子,竖牛把财货送给叔仲昭子和南遗,让他们在季孙那里说杜泄的坏话,而去掉他。杜泄准备用路车随葬,并且全部按照卿的礼仪安葬。南遗对季孙说:“叔孙没有乘坐过路车,怎么能用它安葬?而且正卿没有路车,副卿用来随葬,不也是不正当吗?”季孙说:“对。”让杜泄不要使用路车。杜泄不同意,说:“他老人家在朝廷上接受命令,而到天子那里聘问,天子念他过去的功勋而赐给他路车,回来复命时把它上交国君。国君不敢违逆天子的命令而再次赐给他,让他三个官员记载这件事。您做司徒,记载姓名。他老人家做司马,让工正记载车服。孟孙做司空,以记载功勋。现在他死了而不用路车,这是丢掉国君的命令。记载藏在公府而不实行,这是废弃三个官员。如果国君命令使用的车服,活着时不敢用,死了又不用来随葬,哪里还用得着它?”季孙这才让他用路车随葬。 +季孙策划去掉中军。竖牛说:“他老人家本来就要去掉它了。” + +昭公五年 +【经】五年春王正月,舍中军。楚杀其大夫屈申。公如晋。夏,莒牟夷以牟娄及防、兹来奔。秋七月,公至自晋。戊辰,叔弓帅师败莒师于蚡泉。秦伯卒。冬,楚子、蔡侯、陈侯、许男、顿子、沈子、徐人、越人伐吴。 +【传】五年春,王正月,舍中军,卑公室也。毁中军于施氏,成诸臧氏。初作中军,三分公室而各有其一。季氏尽征之,叔孙氏臣其子弟,孟氏取其半焉。及其舍之也,四分公室,季氏择二,二子各一。皆尽征之,而贡于公。以书。使杜泄告于殡,曰:“子固欲毁中军,既毁之矣,故告。”杜泄曰:“夫子唯不欲毁也,故盟诸僖闳,诅诸五父之衢。”受其书而投之,帅士而哭之。叔仲子谓季孙曰:“带受命于子叔孙曰:‘葬鲜者自西门。’”季孙命杜泄。杜泄曰:“卿丧自朝,鲁礼也。吾子为国政,未改礼,而又迁之。群臣惧死,不敢自也。”既葬而行。 +仲至自齐,季孙欲立之。南遗曰:“叔孙氏厚则季氏薄。彼实家乱,子勿与知,不亦可乎?”南遗使国人助竖牛以攻诸大库之庭。司宫射之,中目而死。竖牛取东鄙三十邑,以与南遗。 +昭子即位,朝其家众,曰:“竖牛祸叔孙氏,使乱大从,杀适立庶,又披其邑,将以赦罪,罪莫大焉。必速杀之。”竖牛惧,奔齐。孟、仲之子杀诸塞关之外,投其首于宁风之棘上。 +仲尼曰:“叔孙昭子之不劳,不可能也。周任有言曰:‘为政者不赏私劳,不罚私怨。’《诗》云:‘有觉德行,四国顺之。’” +初,穆子之生也,庄叔以《周易》筮之,遇《明夷》三之《谦》三,以示卜楚丘。曰:“是将行,而归为子祀。以谗人入,其名曰牛,卒以馁死。《明夷》,日也。日之数十,故有十时,亦当十位。自王已下,其二为公,其三为卿。日上其中,食日为二,旦日为三。《明夷》之《谦》,明而未融,其当旦乎,故曰:‘为子祀’。日之《谦》,当鸟,故曰‘明夷于飞’。明之未融,故曰‘垂其翼’。象日之动,故曰‘君子于行’。当三在旦,故曰‘三日不食’。《离》,火也。《艮》,山也。《离》为火,火焚山,山败。于人为言,败言为谗,故曰‘有攸往,主人有言’,言必谗也。纯《离》为牛,世乱谗胜,胜将适《离》,故曰‘其名曰牛’。谦不足,飞不翔,垂不峻,翼不广,故曰‘其为子后乎’。吾子,亚卿也,抑少不终。” +楚子以屈申为贰于吴,乃杀之。以屈生为莫敖,使与令尹子荡如晋逆女。过郑,郑伯劳子荡于汜,劳屈生于菟氏。晋侯送女于邢丘。子产相郑伯,会晋侯于邢丘。 +公如晋,自郊劳至于赠贿,无失礼。晋侯谓女叔齐曰:“鲁侯不亦善于礼乎?”对曰:“鲁侯焉知礼?”公曰:“何为?自郊劳至于赠贿,礼无违者,何故不知?”对曰:“是仪也,不可谓礼。礼所以守其国,行其政令,无失其民者也。今政令在家,不能取也。有子家羁,弗能用也。奸大国之盟,陵虐小国。利人之难,不知其私。公室四分,民食于他。思莫在公,不图其终。为国君,难将及身,不恤其所。礼这本末,将于此乎在,而屑屑焉习仪以亟。言善于礼,不亦远乎?”君子谓:“叔侯于是乎知礼。” +晋韩宣子如楚送女,叔向为介。郑子皮、子大叔劳诸索氏。大叔谓叔向曰:“楚王汰侈已甚,子其戒之。”叔向曰:“汰侈已甚,身之灾也,焉能及人?若奉吾币帛,慎吾威仪,守之以信,行之以礼,敬始而思终,终无不复,从而不失仪,敬而不失威,道之以训辞,奉之以旧法,考之以先王,度之以二国,虽汰侈,若我何?” +及楚,楚子朝其大夫,曰:“晋,吾仇敌也。苟得志焉,无恤其他。今其来者,上卿、上大夫也。若吾以韩起为阍,以羊舌肸为司宫,足以辱晋,吾亦得志矣。可乎?”大夫莫对。薳启强曰:“可。苟有其备,何故不可?耻匹夫不可以无备,况耻国乎?是以圣王务行礼,不求耻人,朝聘有珪,享《兆见》有璋。小有述职,大有巡功。设机而不倚,爵盈而不饮;宴有好货,飧有陪鼎,入有郊劳,出有赠贿,礼之至也。国家之败,失之道也,则祸乱兴。城濮之役,晋无楚备,以败于邲。邲之役,楚无晋备,以败于鄢。自鄢以来,晋不失备,而加之以礼,重之以睦,是以楚弗能报而求亲焉。既获姻亲,又欲耻之,以召寇仇,备之若何?谁其重此?若有其人,耻之可也。若其未有,君亦图之。晋之事君,臣曰可矣:求诸侯而麇至;求昏而荐女,君亲送之,上卿及上大夫致之。犹欲耻之,君其亦有备矣。不然,奈何?韩起之下,赵成、中行吴、魏舒、范鞅、知盈;羊舌肸之下,祁午、张趯、籍谈、女齐、梁丙、张骼、辅跞、苗贲皇,皆诸侯之选也。韩襄为公族大夫,韩须受命而使矣。箕襄、邢带、叔禽、叔椒、子羽,皆大家也。韩赋七邑,皆成县也。羊舌四族,皆强家也。晋人若丧韩起、杨肸,五卿八大夫辅韩须、杨石,因其十家九县,长毂九百,其馀四十县,遗守四千,奋其武怒,以报其大耻,伯华谋之,中行伯、魏舒帅之,其蔑不济矣。君将以亲易怨,实无礼以速寇,而未有其备,使群臣往遗之禽,以逞君心,何不可之有?”王曰:“不谷之过也,大夫无辱。”厚为韩子礼。王欲敖叔向以其所不知,而不能,亦厚其礼。 +韩起反,郑伯劳诸圉。辞不敢见,礼也。 +郑罕虎如齐,娶于子尾氏。晏子骤见之,陈桓子问其故,对曰:“能用善人,民之主也。” +夏,莒牟夷以牟娄及防兹来奔。牟夷非卿而书,尊地也。莒人愬于晋。晋侯欲止公,范献子曰:“不可。人朝而执之,诱也。讨不以师,而诱以成之,惰也。为盟主而犯此二者,无乃不可乎?请归之,间而以师讨焉。”乃归公。秋七月,公至自晋。 +莒人来讨,不设备。戊辰,叔弓败诸□分泉,莒未陈也。 +冬十月,楚子以诸侯及东夷伐吴,以报棘、栎、麻之役。薳射以繁扬之师,会于夏汭。越大夫常寿过帅师会楚子于琐。闻吴师出,薳启强帅师从之,遽不设备,吴人败诸鹊岸。 +楚子以馹至于罗汭。吴子使其弟蹶由犒师,楚人执之,将以衅鼓。王使问焉,曰:“女卜来吉乎?”对曰:“吉。寡君闻君将治兵于敝邑,卜之以守龟,曰:‘余亟使人犒师,请行以观王怒之疾徐,而为之备,尚克知之。’龟兆告吉,曰:‘克可知也。’君若欢焉,好逆使臣,滋邑休殆,而忘其死,亡无日矣。今君奋焉,震电冯怒,虐执使臣,将以衅鼓,则吴知所备矣。敝邑虽羸,若早修完,其可以息师。难易有备,可谓吉矣。且吴社稷是卜,岂为一人?使臣获衅军鼓,而敝邑知备,以御不虞,其为吉孰大焉?国之守龟,其何事不卜?一臧一否,其谁能常之?城濮之兆,其报在邲。今此行也,其庸有报志?”乃弗杀。 +楚师济于罗汭,沈尹赤会楚子,次于莱山。薳射帅繁扬之师,先入南怀,楚师从之。及汝清,吴不可入。楚子遂观兵于坻箕之山。是行也,吴早设备,楚无功而还,以蹶由归。楚子惧吴,使沈尹射待命于巢。薳启强待命于雩娄。礼也。 +秦后子复归于秦,景公卒故也。 +译文 +五年春季,周王朝历法的正月,废除中军,这是为了降低公室的地位。在施氏家里讨论废除,在臧氏家里达成协议。开始编定中军的时候,把公室的军队一分为三而各家掌握一军。季氏掌握的公室军队采用征兵或者征税的方式,叔孙氏让壮丁作为奴隶,老弱的作为自由民,孟氏则把一半作为奴隶,一半作为自由民。等到这次废除中军,就把公室的军队一分为四,季氏择取了四分之二,叔孙氏、孟氏各有四分之一。全都改为征兵或者征税,而向昭公交纳贡赋。季氏用策书让杜泄向叔孙的棺材报告说:“您本来要废除中军,现在已经废除了,所以向您报告。”杜泄说:“他老人家正因为不想废掉中军,所以在僖公宗庙前门口盟誓,在五父之衢诅咒。”接了策书扔在地上,率领他手下人哭泣起来。叔仲子对季孙说:“带从子叔孙那里接受命令,说,安葬不是寿终的人从西门出去。”季孙命令杜泄执行。杜泄说:“卿的丧礼从朝门出去,这是鲁国的礼仪。您主持国政,没有正式修改礼仪而现在又自己加以改变。下臣们害怕被杀戮,不敢服从。”安葬完毕就出走了。 +仲壬从齐国来到,季孙想要立他为叔孙的继承人。南遗说:“叔孙氏势力强大,季氏势力削弱。他发生家乱,您不要参予,不也是可以的吗?”南遗让国内人们帮助竖牛在府库的庭院里攻打仲壬。司宫用箭射仲壬,射中眼睛死了。竖牛取得了东部边境的三十个城邑,把它送给了南遗。 +昭子即位,召集他家族上下人等来朝见,说:“竖牛给叔孙氏造成祸乱,搅乱了重大的正常秩序,杀死嫡子立庶子,又分裂封邑,将要以此逃避罪责,罪过没有比这再大的了。一定要赶紧杀死他!”竖牛害怕,出奔齐国。孟丙、仲壬的儿子把他杀死在塞关之外,把脑袋扔在宁风的荆棘上。 +孔子说:“叔孙昭子不酬劳竖牛,这是一般人做不到的。周任有话说:‘掌握政权的人不赏赐对于私人的功劳,不惩罚个人的怨恨。’《诗》说:‘具有正直的德行,四方的国家都来归顺。’” +当初,穆子出生的时候,庄叔用《周易》来卜筮,得到《明夷》变成《谦》,把卦像给卜楚丘看。楚丘说:“这个孩子将会出奔,而又能回来为您祭祀。领着坏人回来,他名叫牛,这个孩子最终以饥饿而死。《明夷》,是日。日的数目是十,所以有十时,也和十日的位次相配。从王以下,第二位是公,第三位是卿。日从地下上升,这个时候最为尊贵,露一点头是第二,刚刚升起是第三。《明夷》变为《谦》,已经明亮然而不高,大概是正相当于刚刚升起的时候吧,所以说可以继承卿位为您祭祀。日变为《谦》,和鸟相配,所以说《明夷》飞翔。已经明亮然而不高,所以说垂下它的翅膀。像征日的运动,所以说君子在路上。位在刚刚升起的时候相当于第三,所以说三天不吃饭。《离》,是火。《艮》,是山。《离》是火,火烧山,山就毁坏。《艮》对人来说就是语言。毁坏语言就是诬罔,所以说有人离开。主人有话,这话一定是诬罔,配合《离》的是牛,世道动乱而诬罔得到胜利,胜利将会归向于《离》,所以说他名叫牛。《谦》就是不满足,所以虽然能飞而不能回旋,下垂就是不高,所以虽有翅膀而不能飞行高远。所以说大约是您的继承人吧。您,是副卿,但是继承人虽老却有点不得善终。” +楚灵王认为屈申倾向吴国,就杀了他。让屈生做莫敖,派他和令尹子荡到晋国迎接晋女。经过郑国,郑简公在汜地慰劳子荡,在菟氏慰劳屈生。晋平公送女儿到邢丘,子产辅佐郑简公在邢丘会见晋平公。 +鲁昭公去到晋国,从郊外慰劳一直到赠送财货,从没有失礼。晋平公对女叔齐说:“鲁侯不也是很懂礼吗?”女叔齐回答说:“鲁侯哪里懂得礼!”晋平公说:“为什么?从郊外慰劳一直到赠送财货,没有违背礼节,为什么不懂得?”女叔齐回答说:“这是仪式,不能说是礼。礼,是用来保有国家、推行政令,不失去百姓的。现在政令在于私家,不能拿回来。有子家羁,不能任用。触犯大国的盟约,欺侮虐待小国。利用别人的危难,却不知道自己也有危难。公室的军队一分为四,百姓靠三家大夫生活。民心不在国君,国君不考虑后果。做为一个国君,危难将要到他身上,却不去忧虑他的地位。礼的根本和枝节在于此,他却琐琐屑屑地急于学习仪式。说他懂得礼,不也是距离太远了吗?”君子认为:“女叔齐在这里是懂得礼的。” +晋国的韩宣子去到楚国护送晋女,叔向做副手。郑国的子皮、子太叔在索氏慰劳他们。太叔对叔向说:“楚王骄纵太过分,您还是警惕一点。”叔向说:“骄纵太过分是自身的灾殃,哪能波及到别人?只要奉献我们的财礼,谨慎地保持我们的威仪,守信用,行礼仪,开始恭敬而考虑结果,以后就可以照样办。顺从而不过度,恭敬而有节制,以古圣先贤的言语作为引导,对传统的法度加以奉行,考核先王的事情,把两国的利害得失加以衡量,楚王虽然骄纵,能把我怎么样?” +到了楚国,楚灵王让大夫们上朝,说:“晋国,是我们的仇敌。如果我们能够满足愿望,就不用顾虑其他。现在他们来的人,是上卿、上大夫。假使我们让韩起做守门人,让叔向做内宫司宫,这足以羞辱晋国,我们也满足了愿望。行吗?”大夫没有一个人回答。薳启彊说:“行。如果有防备,为什么不行?羞辱一个普通人还不能不作防备,何况羞辱一个国家呢?因此圣王致力于推行礼仪,不想羞辱别人。朝觐聘问有圭,宴享进见有璋,小国有述职的规定,大国有巡狩的制度。设置了几而不依靠,爵中酒满而不饮用,宴会时有友好的礼品,吃饭时有很多的菜肴。入境有郊外的慰劳,离开有赠送的财货,这都是礼仪的最高形式。国家的败亡,由于失去了这种常道,祸乱就会发生。城濮那次战役,晋国得胜而没有防备楚国,因此在邲地打了败仗。邲地那次战役,楚国得胜而没有防备晋国,因此在鄢地打了败仗。自从鄢地战役以来,晋国没有丧失防备,而且对楚国礼仪有加,以和睦为重,因此楚国不能报复,而只能请求亲善了。既然得到了婚姻的亲戚关系,又想要羞辱他们,以自寻敌人,又怎么防备它?谁来承担责任?如果有能承担责任的人,羞辱他们是可以的。如果没有,君王还是考虑一下。晋国的事奉君王,下臣认为很可以了。要求得到诸侯就大家都来了,求婚就进奉女子。国君亲自送她,上卿和上大夫送到我国。如果还要羞辱他们,君王恐怕也要有所防备。不这样,怎么办?韩起的下面,有赵成、中行吴、魏舒、范鞅、知盈;叔向的下面,有祁午、张趯、籍谈、女齐、梁丙、张骼、辅跞、苗贲皇,都是诸侯所选拔的能人。韩襄做公族大夫,韩须接受命令而出使了。箕襄、邢带、叔禽、叔椒、子羽,都是大家族。韩氏征收赋税的七个城邑,都是大县。羊舌氏四族,都是强盛的家族。晋国人如果丧失韩起、叔向,五卿、八大夫辅助韩须、杨石,靠了他们的十家九县,战车九百辆,其余四十具,留守的战车有四千辆,发扬他们的勇武,发泄他们的愤怒,以报复他们的奇耻大辱。伯华为他们出谋划策,中行伯、魏舒率领他们,就没有不成功的了。君王将要把亲善换成怨恨,确实违背礼仪以招致敌人,而又没有应有的防备,让下臣们去当俘虏以满足君王的心意,有什么不可以呢?”楚灵王说:“这是我的过错,大夫不用再说了。”对韩起厚加礼遇,楚灵王想要用叔向不知道的事物来为难他,没有做到,于是也对他厚加优礼。 +韩起回国,郑简公在圉地慰劳他。他辞谢不敢进见,这是合于礼的。 +郑国的罕虎到齐国去,在子尾氏那里娶亲。晏子屡次进见。陈桓子问什么缘故,晏子回答说:“他能够任用好人,是百姓的主人。” +夏季,莒国的牟夷带了牟娄和防地、兹地逃亡前来。牟夷不是卿,但《春秋》加以记载,这是由于重视这些地方。莒人向晋国起诉,晋平公想要扣留昭公。范献子说:“不行。别人来朝见而囚禁人家,这就如同引诱。讨伐他不想用武力,而用引诱来取得成功,这是怠惰。做盟主而犯了这两条,恐怕不行吧!请让他回去,等有机会时再用武力去讨伐他们。”于是就让昭公回国了。秋季,七月,昭公从晋国回到鲁国。 +莒国人前来攻打鲁国,但他们自己却不设防。十四日,叔弓在蚡泉击败了他们,这是由于莒国人没有摆开阵势的缘故。 +冬季,十月,楚灵王带领诸侯和东夷的军队进攻吴国,以报复棘地、栎地、麻地的那次战役。薳射带领繁扬的军队在夏汭会师,越国的大夫常寿过领兵和楚王在琐地会合。听说吴军出动,薳启彊领兵迎战,匆忙中没有设防,吴国人在鹊岸击败了他。楚灵王乘坐驿车到达罗汭。 +吴王派他的兄弟蹶由到楚营犒劳军队,楚国人把他抓起来,准备杀了他用血祭鼓。楚灵王派人询问,说:“你占卜过,来这里吉利吗?”蹶由回答说:“吉利。寡君听说君王将要向敝邑出兵,就用守龟占卜,致告龟甲说:‘我赶快派人去犒劳军队,请前去以观察楚王生气的大小而加以戒备,也许神能使我预先知道吉凶。’占卜的卦像告诉我们说吉利,说:‘得胜是可以预知的。’君王如果高高兴兴地迎接使臣,增加敝邑的懈怠而忘记危险,我们被灭亡就没有几天了。现在君王勃然大怒,虐待和逮捕使臣,将要用使臣的血来祭鼓,那么吴国就知道该怎么戒备了。敝邑虽然疲弱,如果早日修城郭备器用,也许可以阻止贵军的进攻。无论对患难还是平安都有准备,这可以说是吉利了。而且吴国为国家而占卜,难道是为了使臣一个人?使臣得以用血祭祀军鼓,而敝邑就知道防备,以抵御意外,难道说还有比这更大的吉利吗?国家的守护神龟,有什么事情不能占卜?一吉一凶,谁能够肯定落在哪件事情上?城濮的卦像,在邲城应验。现在这一趟出使,占卜的卦像也许会有应验的。”楚灵王于是就没有杀蹶由。 +楚国的军队在罗汭渡河,沈尹赤和楚灵王会合,驻扎在莱山,薳射率领繁扬的军队先进入南怀,楚军跟上去。到达汝清,不能进入吴国。楚灵王就在坻箕之山检阅军队。这一次行动,吴国早已设防,楚国没有建功就回去了,带着蹶由回国。楚灵王惧怕吴国,派沈尹射在巢地待命,薳启彊在雩娄待命,这是合于礼的。 +秦国的后子再次回到秦国,这是由于秦景公去世的缘故。 + + +昭公六年 +【经】六年春王正月,杞伯益姑卒。葬秦景公。夏,季孙宿如晋。葬杞文公。宋华合比出奔卫。秋九月,大雩。楚薳罢帅师伐吴。冬,叔弓如楚。齐侯伐北燕。 +【传】六年春,王正月,杞文公卒,吊如同盟,礼也。大夫如秦,葬景公,礼也。 +三月,郑人铸刑书。叔向使诒子产书,曰:“始吾有虞于子,今则已矣。昔先王议事以制,不为刑辟,惧民之有争心也。犹不可禁御,是故闲之以义,纠之以政,行之以礼,守之以信,奉之以仁,制为禄位以劝其从,严断刑罚以威其淫。惧其未也,故诲之以忠,耸之以行,教之以务,使之以和,临之以敬,莅之以强,断之以刚。犹求圣哲之上,明察之官,忠信之长,慈惠之师,民于是乎可任使也,而不生祸乱。民知有辟,则不忌于上,并有争心,以征于书,而徼幸以成之,弗可为矣。夏有乱政而作《禹刑》,商有乱政而作《汤刑》,周有乱政而作《九刑》,三辟之兴,皆叔世也。今吾子相郑国,作封洫,立谤政,制参辟,铸刑书,将以靖民,不亦难乎?《诗》曰:‘仪式刑文王之德,日靖四方。’又曰:‘仪刑文王,万邦作孚。’如是,何辟之有?民知争端矣,将弃礼而征于书。锥刀之末,将尽争之。乱狱滋丰,贿赂并行,终子之世,郑其败乎!肸闻之,国将亡,必多制,其此之谓乎!”复书曰:“若吾子之言,侨不才,不能及子孙,吾以救世也。既不承命,敢忘大惠?” +士文伯曰:“火见,郑其火乎?火未出而作火以铸刑器,藏争辟焉。火如象之,不火何为?” +夏,季孙宿如晋,拜莒田也。晋侯享之,有加笾。武子退,使行人告曰:“小国之事大国也,苟免于讨,不敢求贶。得贶不过三献。今豆有加,下臣弗堪,无乃戾也。”韩宣子曰:“寡君以为欢也。”对曰:“寡君犹未敢,况下臣,君之隶也,敢闻加贶?”固请彻加而后卒事。晋人以为知礼,重其好货。 +宋寺人柳有宠,大子佐恶之。华合比曰:“我杀之。”柳闻之,乃坎、用牲、埋书,而告公曰:“合比将纳亡人之族,既盟于北郭矣。”公使视之,有焉,遂逐华合比,合比奔卫。于是华亥欲代右师,乃与寺人柳比,从为之征,曰“闻之久矣。”公使代之,见于左师,左师曰:“女夫也。必亡!女丧而宗室,于人何有?人亦于女何有?《诗》曰:‘宗子维城,毋俾城坏,毋独斯畏。’女其畏哉!” +六月丙戌,郑灾。 +楚公子弃疾如晋,报韩子也。过郑,郑罕虎、公孙侨、游吉从郑伯以劳诸柤。辞不敢见,固请见之,见,如见王,以其乘马八匹私面。见子皮如上卿,以马六匹。见子产,以马四匹。见子大叔,以马二匹。禁刍牧采樵,不入田,不樵树,不采刈,不抽屋,不强丐。誓曰:“有犯命者,君子废,小人降。”舍不为暴,主不慁宾。往来如是。郑三卿皆知其将为王也。 +韩宣子之适楚也,楚人弗逆。公子弃疾及晋竟,晋侯将亦弗逆。叔向曰:“楚辟我衷,若何效辟?《诗》曰:‘尔之教矣,民胥效矣。’从我而已,焉用效人之辟?《书》曰:‘圣作则。’无宁以善人为则,而则人之辟乎?匹夫为善,民犹则之,况国君乎?”晋侯说,乃逆之。 +秋九月,大雩,旱也。 +徐仪楚聘于楚。楚子执之,逃归。惧其叛也,使薳泄伐徐。吴人救之。令尹子荡帅师伐吴,师于豫章,而次于乾溪。吴人败其师于房钟,获宫厩尹弃疾。子荡归罪于薳泄而杀之。 +冬,叔弓如楚聘,且吊败也。 +十一月,齐侯如晋,请伐北燕也。士□相士鞅,逆诸河,礼也。晋侯许之。十二月,齐侯遂伐北燕,将纳简公。晏子曰:“不入。燕有君矣,民不贰。吾君贿,左右谄谀,作大事不以信,未尝可也。” +译文 +六年春季,周王朝历法的正月,杞文公去世。鲁国前去吊唁好像对同盟的国家一样,这是合于礼的。鲁国大夫去到秦国,参加秦景公的葬礼,这是合于礼的。 +三月,郑国把刑法铸在鼎上。叔向派人送给子产一封信,说:“开始我对您寄予希望,现在完了。从前先王衡量事情的轻重来断定罪行,不制定刑法,这是害怕百姓有争夺之心。还是不能防止犯罪,因此用道义来防范,用政令来约束,用礼仪来奉行,用信用来保持,用仁爱来奉养。制定禄位,以勉励服从的人,严厉地判罪,以威胁放纵的人。还恐怕不能收效,所以用忠诚来教诲他们,根据行为来奖励他们,用专业知识技艺教导他们,用和悦的态度使用他们,用严肃认真对待他们,用威严监临他们,用坚决的态度判断他们的罪行。还要访求聪明贤能的卿相、明白事理的官员、忠诚守信的乡长、慈祥和蔼的老师,百姓在这种情况下才可以使用,而不致于发生祸乱。百姓知道有法律,就对上面不恭敬。大家都有争夺之心,用刑法作为根据,而且侥幸得到成功,就不能治理了。夏朝有违犯政令的人,就制定禹刑。商朝有触犯政令的人,就制定汤刑。周朝有触犯政令的人,就制定九刑。三种法律的产生,都处于末世了。现在您辅佐郑国,划定田界水沟,设置毁谤政事的条例,制定三种法规,把刑法铸在鼎上,准备用这样的办法安定百姓,不也是很难的吗?《诗》说:‘效法文王的德行,每天抚定四方。’又说:‘效法文王,万邦信赖。’像这样,何必要有法律?百姓知道了争夺的依据,将会丢弃礼仪而征用刑书。刑书的一字一句,都要争个明白。触犯法律的案件更加繁多,贿赂到处使用。在您活着的时候,郑国恐怕要衰败吧!肸听说,‘国家将要灭亡,必然多订法律’,恐怕说的就是这个吧!”子产复信说:“像您所说的这样。侨没有才能,不能考虑到子孙,我是用来挽救当前的世界。既然不能接受您的命令,又岂敢忘了您的恩惠?” +士文伯说:“大火星出现,郑国恐怕会发生大火灾吧!大火星还没有出现,而使用火来铸造刑器,包藏着引起争论的法律。大火星如果象征这个,不引起火灾还能表示什么?” +夏季,季孙宿到晋国去,这是为了拜谢不讨伐占取莒国土田的缘故。晋平公设享礼招待他,有外加的菜肴。季孙宿退出,派行人报告说:“小国事奉大国,如果免于被讨伐。不敢再求赏赐。得到赏赐也不超过三献。现在菜肴有所增加,下臣不敢当,恐怕这是罪过。”韩宣子说:“寡君用它来讨取您的欢心。”季孙宿回答说:“寡君尚且不敢当,何况下臣是君王的奴隶,岂敢听到有外加多赏赐?”坚决请求撤去加菜,然后结束享宴。晋国人认为他懂得礼仪,在宴礼中重重地送给他财物。 +宋国的寺人柳受到宋平公宠信,太子佐讨厌他。华合比说:“我去杀了他。”寺人柳听到了,就挖坑、杀牲口、把盟书放在牲口上埋起来。然后报告宋平公说:“合比准备将逃亡在外的人召回来,已经在北边外城结盟了。”宋平公派人去看,果然有这回事,就驱逐了华合比。华合比逃亡到卫国。当时华亥想要取代华合比的右师这一官职,就和寺人柳勾结,为他作证明说:“这件事我也早已听到。”宋平公让他代替了华合比。华亥进见左师,左师说:“你这个人一定要逃亡。你毁坏你的宗族,对别人会怎么样?别人也会对你怎么样?《诗》说:‘嫡长子就是城垣,不要使城垣毁坏,不要使自己孤立而有所害怕。’你大概会害怕的吧!” +六月初七日,郑国发生火灾。 +楚国的公子弃疾到晋国去,这是为了回报韩宣子的致送晋女。经过郑国,郑国的子皮、子产、子太叔跟从郑简公在柤地慰劳他。公子弃疾辞谢不敢见面。郑简公坚决请求,这才肯见面。进见郑简公好像进见楚王,用驾车的马八匹作为私人进见的礼物。进见子皮好像进见楚国的上卿,用马六匹。进见子产,用马四匹。进见子太叔,用马两匹。禁止割草放牧采摘砍柴,不进入农田,不砍树木,不摘菜果,不拆房屋,不强行讨取。发誓说:“有触犯命令的,君子撤职,小人降等。”寄住的时期不作暴行,主人不用担心客人。一往一来都像这样,郑国的三个卿都知道他将要做楚王了。 +韩宣子到楚国去的时候,楚国人不出来迎接。公子弃疾到达晋国国境,晋平公也不想派人迎接。叔向说:“楚国不正派,我们正派。为什么去学不正派?《诗》说,‘你的教导,百姓都要仿效。’根据我们自己的办就是了,哪里用得着学别人的不正派?《书》说,‘圣人做出准则。’宁可以善人做准则,难道还去学别人的不正派吗?一个普通人做好事,百姓还以他为准则,何况国君?”晋平公高兴了,就派人迎接公子弃疾。 +秋季,九月,举行大的雩祭,这是由于发生了旱灾。 +徐仪楚到楚国聘问,楚灵王囚禁了他,他逃回徐国。楚灵王害怕他背叛,派薳泄进攻徐国。吴国人救援徐国。令尹子荡率领军队进攻吴国,在豫章出兵而住在乾谿。吴国人在房钟击败了令尹子荡的军队,俘虏了宫厩尹弃疾。子荡把罪过推在薳泄身上而杀了他。 +冬季,叔弓到楚国聘问,并且慰问战争失败。 +十一月,齐景公到晋国,请求同意进攻北燕。士匄辅佐士鞅在黄河边上迎接,这是合于礼的。晋平公同意了。十二月,齐景公就发兵进攻北燕,打算把燕简公送回去。晏子说:“简公不要送回去。燕国有了国君,百姓对他没有二心。我们的国君贪财,左右的人阿谀奉承,办大事不讲信用,所以还是不可以呢!” + +昭公七年 +【经】七年春王正月,暨齐平。三月,公如楚。叔孙婼如齐莅盟。夏四月甲辰朔,日有食之。秋八月戊辰,卫侯恶卒。九月,公至自楚。冬十有一月癸未,季孙宿卒。十有二月癸亥,葬卫襄公。 +【传】七年春,王正月,暨齐平,齐求之也。癸巳,齐侯次于虢。燕人行成,曰:“敝邑知罪,敢不听命?先君之敝器,请以谢罪。”公孙皙曰:“受服而退,俟衅而动,可也。”二月戊午,盟于濡上。燕人归燕姬,赂以瑶瓮、玉椟、斗耳,不克而还。 +楚子之为令尹也,为王旌以田。芋尹无宇断之,曰:“一国两君,其谁堪之?”及即位,为章华之宫,纳亡人以实之。无宇之阍入焉。无宇执之,有司弗与,曰:“执人于王宫,其罪大矣。”执而谒诸王。王将饮酒,无宇辞曰:“天子经略,诸侯正封,古之制也。封略之内,何非君土?食土之毛,谁非君臣?故《诗》曰:‘普天之下,莫非王土。率土之滨,莫非王臣。’天有十日,人有十等,下所以事上,上所以共神也。故王臣公,公臣大夫,大夫臣士,士臣皂,皂臣舆,舆臣隶,隶臣僚,僚臣仆,仆臣台。马有圉,牛有牧,以待百事。今有司曰:‘女胡执人于王宫?’将焉执之?周文王之法曰:‘有亡,荒阅’,所以得天下也。吾先君文王,作仆区之法,曰:‘盗所隐器,与盗同罪’,所以封汝也。若从有司,是无所执逃臣也。逃而舍之,是无陪台也。王事无乃阙乎?昔武王数纣之罪,以告诸侯曰:‘纣为天下逋逃主,萃渊薮’,故夫致死焉。君王始求诸侯而则纣,无乃不可乎?若以二文之法取之,盗有所在矣。”王曰:“取而臣以往,盗有宠,未可得也。”遂赦之。 +楚子成章华之台,愿与诸侯落之。大宰薳启强曰:“臣能得鲁侯。”薳启强来召公,辞曰:“昔先君成公,命我先大夫婴齐曰:‘吾不忘先君之好,将使衡父照临楚国,镇抚其社稷,以辑宁尔民’。婴齐受命于蜀,奉承以来,弗敢失陨,而致诸宗祧。日我先君共王,引领北望,日月以冀。传序相授,于今四王矣。嘉惠未至,唯襄公之辱临我丧。孤与其二三臣,悼心失图,社稷之不皇,况能怀思君德!今君若步玉趾,辱见寡君,宠灵楚国,以信蜀之役,致君之嘉惠,是寡君既受贶矣,何蜀之敢望?其先君鬼神,实嘉赖之,岂唯寡君?君若不来,使臣请问行期,寡君将承质币而见于蜀,以请先君之贶。” +公将往,梦襄公祖。梓慎曰:“君不果行。襄公之适楚也,梦周公祖而行。今襄公实祖,君其不行。”子服惠伯曰:“行。先君未尝适楚,故周公祖以道之。襄公适楚矣,而祖以道君,不行,何之?” +三月,公如楚,郑伯劳于师之梁。孟僖子为介,不能相仪。及楚,不能答郊劳。 +夏四月甲辰朔,日有食之。晋侯问于士文伯曰:“谁将当日食?”对曰:“鲁、卫恶之,卫大鲁小。”公曰:“何故?”对曰:“去卫地,如鲁地。于是有灾,鲁实受之。其大咎,其卫君乎?鲁将上卿。”公曰:“《诗》所谓‘彼日而食,于何不臧’者,何也?”对曰:“不善政之谓也。国无政,不用善,则自取谪于日月之灾,故政不可不慎也。务三而已,一曰择人,二曰因民,三曰从时。” +晋人来治杞田,季孙将以成与之。谢息为孟孙守,不可。曰:“人有言曰:‘虽有挈瓶之知,守不假器,礼也’。夫子从君,而守臣丧邑,虽吾子亦有猜焉。”季孙曰:“君之在楚,于晋罪也。又不听晋,鲁罪重矣。晋师必至,吾无以待之,不如与之,间晋而取诸杞。吾与子桃,成反,谁敢有之?是得二成也。鲁无忧而孟孙益邑,子何病焉?”辞以无山,与之莱、柞,乃迁于桃。晋人为杞取成。 +楚子享公于新台,使长鬣者相,好以大屈。既而悔之。薳启强闻之,见公。公语之,拜贺。公曰:“何贺?”对曰:“齐与晋、越欲此久矣。寡君无适与也,而传诸君,君其备御三邻。慎守宝矣,敢不贺乎?”公惧,乃反之。 +郑子产聘于晋。晋侯疾,韩宣子逆客,私焉,曰:“寡君寝疾,于今三月矣,并走群望,有加而无瘳。今梦黄熊入于寝门,其何厉鬼也?”对曰:“以君之明,子为大政,其何厉之有?昔尧殛鲧于羽山,其神化为黄熊,以入于羽渊,实为夏郊,三代祀之。晋为盟主,其或者未之祀也乎?”韩子祀夏郊,晋侯有间,赐子产莒之二方鼎。 +子产为丰施归州田于韩宣子,曰:“日君以夫公孙段为能任其事,而赐之州田,今无禄早世,不获久享君德。其子弗敢有,不敢以闻于君,私致诸子。”宣子辞。子产曰:“古人有言曰:‘其父析薪,其子弗克负荷’。施将惧不能任其先人之禄,其况能任大国之赐?纵吾子为政而可,后之人若属有疆场之言,敝邑获戾,而丰氏受其大讨。吾子取州,是免敝邑于戾,而建置丰氏也。敢以为请。”宣子受之,以告晋侯。晋侯以与宣子。宣子为初言,病有之,以易原县于乐大心。 +郑人相惊以伯有,曰“伯有至矣”,则皆走,不知所往。铸刑书之岁二月,或梦伯有介而行,曰:“壬子,余将杀带也。明年壬寅,余又将杀段也。”及壬子,驷带卒,国人益惧。齐、燕平之月壬寅,公孙段卒。国人愈惧。其明月,子产立公孙泄及良止以抚之,乃止。子大叔问其故,子产曰:“鬼有所归,乃不为厉,吾为之归也。”大叔曰:“公孙泄何为?”子产曰:“说也。为身无义而图说,从政有所反之,以取媚也。不媚,不信。不信,民不从也。” +及子产适晋,赵景子问焉,曰:“伯有犹能为鬼乎?”子产曰:“能。人生始化曰魄,既生魄,阳曰魂。用物精多,则魂魄强。是以有精爽,至于神明。匹夫匹妇强死,其魂魄犹能冯依于人,以为淫厉,况良霄,我先君穆公之胄,子良之孙,子耳之子,敝邑之卿,从政三世矣。郑虽无腆,抑谚曰‘蕞尔国’,而三世执其政柄,其用物也弘矣,其取精也多矣。其族又大,所冯厚矣。而强死,能为鬼,不亦宜乎?” +子皮之族饮酒无度,故马师氏与子皮氏有恶。齐师还自燕之月,罕朔杀罕魋。罕朔奔晋。韩宣子问其位于子产。子产曰:“君之羁臣,苟得容以逃死,何位之敢择?卿违,从大夫之位,罪人以其罪降,古之制也。朔于敝邑,亚大夫也,其官,马师也。获戾而逃,唯执政所置之。得免其死,为惠大矣,又敢求位?”宣子为子产之敏也,使从嬖大夫。 +秋八月,卫襄公卒。晋大夫言于范献子曰:“卫事晋为睦,晋不礼焉,庇其贼人而取其地,故诸侯贰。《诗》曰:‘即□鴒在原,兄弟急难。’又曰:‘死丧之威,兄弟孔怀。’兄弟之不睦,于是乎不吊,况远人,谁敢归之?今又不礼于卫之嗣,卫必叛我,是绝诸侯也。”献子以告韩宣子。宣子说,使献子如卫吊,且反戚田。 +卫齐恶告丧于周,且请命。王使臣简公如卫吊,且追命襄公曰:“叔父陟恪,在我先王之左右,以佐事上帝。余敢高圉、亚圉?” +九月,公至自楚。孟僖子病不能相礼,乃讲学之,苟能礼者从之。及其将死也,召其大夫曰:“礼,人之干也。无礼,无以立。吾闻将有达者曰孔丘,圣人之后也,而灭于宋。其祖弗父何,以有宋而授厉公。及正考父,佐戴、武、宣,三命兹益共。故其鼎铭云:‘一命而偻,再命而伛,三命而俯。循墙而走,亦莫余敢侮。饘是,鬻于是,以糊余口。’其共也如是。臧孙纥有言曰:‘圣人有明德者,若不当世,其后必有达人。’今其将在孔丘乎?我若获没,必属说与何忌于夫子,使事之,而学礼焉,以定其位。”故孟懿子与南宫敬叔师事仲尼。仲尼曰:“能补过者,君子也。《诗》曰:‘君子是则是效。’孟僖子可则效已矣。” +单献公弃亲用羁。冬十月辛酉,襄、顷之族杀献公而立成公。 +十一月,季武子卒。晋侯谓伯瑕曰:“吾所问日食,从矣,可常乎?”对曰:“不可。六物不同,民心不一,事序不类,官职不则,同始异终,胡可常也?《诗》曰:‘或燕燕居息,或憔悴事国。’其异终也如是。”公曰:“何谓六物?”对曰:“岁、时、日、月、星、辰,是谓也。”公曰:“多语寡人辰,而莫同。何谓辰?”对曰:“日月之会,是谓辰,故以配日。” +卫襄公夫人姜氏无子,嬖人婤姶生孟絷。孔成子梦康叔谓己:“立元,余使羁之孙圉与史苟相之。”史朝亦梦康叔谓己:“余将命而子苟与孔烝锄之曾孙圉相元。”史朝见成子,告之梦,梦协。晋韩宣子为政聘于诸侯之岁,婤姶生子,名之曰元。孟絷之足不良,能行。孔成子以《周易》筮之,曰:“元尚享卫国主其社稷。”遇《屯》三。又曰:“余尚立絷,尚克嘉之。”遇《屯》三之《比三。以示史朝。史朝曰:“元亨,又何疑焉?”成子曰:“非长之谓乎?”对曰:“康叔名之,可谓长矣。孟非人也,将不列于宗,不可谓长。且其繇曰‘利建侯’。嗣吉,何建?建非嗣也。二卦皆云,子其建之。康叔命之,二筮袭于梦,武王所用也,弗从何为?弱足者居,侯主社稷,临祭祀,奉民人,事民人,鬼神,从会朝,又焉得居?各以所利,不亦可乎?”故孔成子立灵公。十二月癸亥,葬卫襄公。 +译文 +七年春季,周王朝历法的正月,北燕和齐国讲和,这是由于齐国的要求。十八日,齐景公住在虢地。燕国人求和,说:“敝邑知道罪过,岂敢不听从命令?请求把先君的破旧器物用来谢罪。”公孙皙说:“接受他们的归服而退兵,等待有空子再采取行动,可以这样做。”二月十四日,在濡水边上结盟。燕国人把燕姬嫁给齐景公,送给他玉瓮、玉柜、玉杯。齐国没有取得胜利而回国。 +楚灵王做令尹的时候,打了国王用的旌旗去打猎,芋尹无宇砍断旌旗的飘带,说:“一个国家两个君主,有谁能忍受得了?”等到楚灵王即位,又建造章华宫,接纳逃亡的人安置在里面。无宇的守门人逃到章华宫里。无宇要抓他,管理宫室的官员不肯,说:“在国王的宫里抓人,这罪过就大了。”抓住无宇而进见楚灵王。楚灵王准备喝酒,无宇申诉说:“天子经营天下,诸侯治理封疆,这是古代的制度。边境之内,哪里不是国君的土地?吃着土地上的出产,谁不是国君的下臣?所以《诗》说:‘普天之下,无不是天子的土地。沿着土地的边涯,无不是天子的臣仆。’天有十个日子,人有十个等级。下边以此事奉上边,上边以此祭祀神明。所以王统治公,公统治大夫,大夫统治士,士统治皂,皂统治舆,舆统治隶,隶统治僚,僚统治仆,仆统治台。养马有圉,放牛有牧,各有专司以应付各种事情。现在官员说:‘你为什么在王宫里抓人?’不在王宫,又在哪里抓他呢?周文王的法令说,‘有逃亡的,要大肆搜捕’,因此就得了天下。我们的先君文王制订惩罚窝藏的法令,说,‘隐藏盗贼的赃物,和盗贼同罪’,因此就得到直到汝水的疆土。如果按照那些官员的做法,这就是没有地方去逮捕逃亡的奴隶了。逃亡的就让他逃亡,这就没有奴仆了。这样,国家的工作恐怕就会有所缺失了!从前武王列举纣的罪状通告诸侯说:‘纣是天下逃亡者的窝藏主,是逃亡者聚集的渊薮。’所以人们致死也要攻打他。君王开始求取诸侯而效法纣,只怕不可以吧!如果用两位文王的法令来逮捕盗贼,盗贼是有地方可抓的。”楚灵王说:“抓了你的奴隶走吧。有一个盗贼正受到恩宠,还抓不到呢。”于是就赦免了无宇。 +楚灵王建成章华之台,希望和诸侯一起举行落成典礼。太宰薳启彊说:“下臣能够得到鲁侯。”薳启彊前来召请鲁昭公,致辞说:“从前贵国的先君成公命令我们的先大夫婴齐说:‘我不忘记先君的友好,将要派衡父光临楚国,镇抚安定国家,使得你们百姓安宁。’婴齐在蜀地接受了命令。接受命令回来,不敢废弃,而祭告于宗庙。过去我们先君共王伸着脖子向北望,每天每月都在盼望着贵国使者的到来,世代相传,到今天经历四位国王了。恩赐没有来到,只有襄公为了我国的丧事而光临。孤和手下的几个臣子心中动摇失掉了主意,治理国家尚且不得闲空,哪里还能够怀念您的恩德!现在君王如果移步屈尊,和寡君见面,使楚国得到福泽,以重申蜀地那次会盟,送来君王的恩惠,这样,寡君就已经受到恩赐了,哪里敢希望再像蜀地那次结盟一样!敝邑的先君鬼神也会嘉许和依靠它,岂独寡君?如果君王不来,使臣请问君王带兵出动的日期,寡君将要捧着进见的财币,而到蜀地去见君王,以请问鲁先君成公的恩赐。” +鲁昭公准备前去,梦见鲁襄公为他出行,祭祀路神。梓慎说:“君王最终是去不了的。襄公去楚国的时候,梦见周公祭祀路神,然后出行。现在襄公在祭祀路神,君王还是不去为好。”子服惠伯说:“去!先君从没有去过楚国,所以周公祭祀路神来引导他。襄公去过楚国了,然后祭祀路神,来引导君王。不去,到哪里去?” +三月,昭公到楚国去,郑简公在师之梁慰劳昭公。孟僖子做副手,不能相礼。到达楚国,不能对答郊外的慰劳礼。 +夏季,四月初一,日食。晋平公向士文伯询问说:“谁将要承当日食的灾祸?”士文伯说:“鲁国和卫国会遭到凶险。卫国受祸大,鲁国受祸小。”晋平公说:“什么缘故?”士文伯回答说:“日食的时候日头离开卫国的分野到了鲁国的分野。在这种情况下发生灾祸,鲁国就应该承受。这次大灾恐怕要落在卫君的头上吧!鲁国将要由上卿来承当。”晋平公说:“《诗》所说的‘那个日头发生日食。是什么地方不好’,是什么意思?”士文伯回答说:“这说的是不善于处理政事。国家没有好政事,不用好人,那就在日月的灾祸里会自找倒霉,所以政事是不能不谨慎的。致力于三条就行了:第一叫做选择贤人,第二叫做依靠百姓,第三叫做顺从时令。” +晋国派人前来划定鲁国与杞国的边界,季孙打算把成地给他们。谢息为孟孙镇守成地,不同意,说:“人们有这样的话说,‘虽然只有小智小慧,守着器物就不能出借,这是礼。”他老人家跟随国君,而守臣却丢掉他的城邑,即使是您也会怀疑我不忠的。”季孙说:“国君在楚国,对于晋国来说就是罪过。又不听从晋国,鲁国的罪过就加重了,晋军必然到来,我没法抵御他们,不如给他们算了。等晋国有机可乘,而再取之于杞国。我给您桃地,如果成地重归于我国,谁敢占有它?这就是得到两份成地了。鲁国没有忧患而孟孙增加封邑,您又担心什么呢?”谢息推辞说桃地没有山,季孙又给他莱山和柞山,谢息这才迁到桃地。晋国人为杞国取得了成地。 +楚灵王在新台设享礼招待鲁昭公,让一个长须的人相礼。把大屈之弓送给昭公表示友好。随即又后悔。薳启彊听说这件事,进见昭公。昭公跟他说起这件事,薳启彊下拜祝贺。昭公说:“为什么祝贺?”薳启彊回答说:“齐国和晋国、越国想要它很久了,寡君并没有肯定给他们,而送给了君王。君王防备抵御三个邻国,谨慎地保有宝物,难道敢不祝贺吗?”昭公恐惧,就把弓送还给楚灵王。 +郑国的子产到晋国聘问。晋平公有病。韩宣子迎接客人,私下说:“寡君卧病,到现在三个月了,所应该祭祀的山川都祈祷过了,但是病情只有增加而没有见好。现在梦见黄熊进入寝门,这是什么恶鬼?”子产回答说:“以君王的英明,您做正卿,哪里会有恶鬼?从前尧在羽山杀死了鲧,他的精灵变成黄熊,钻进羽渊里,成为夏朝郊祭的神灵,三代都祭祀他。晋国做盟主,或者没有祭祀他吧!”韩宣子祭祀鲧。晋平公的病逐渐痊愈,把莒国的两个方鼎赏赐给子产。 +子产为丰施把州地的土田归还给韩宣子,说:“过去君王认为那个公孙段能够承担大事,因而赐给他州地的土田。现在他不幸早死,不能长久地享有君王的赐予。他的儿子不敢占有,也不敢告诉君王,所以私下送给您”宣子辞谢。子产说:“古人有话说:‘他父亲劈的柴,他的儿子不能承受。’施将会惧怕不能承受他先人的俸禄,更何况担当大国的恩赐?即使您执政而可以使他免于罪戾,后来的人如果碰巧有关于边界的闲话,敝邑得罪,丰氏就会受到大的讨伐。您取得州地,这是使敝邑免于罪过,又等于建立扶持丰氏。谨敢以此作为请求。”宣子接受了,把情况报告晋平公。晋平公把州地给了宣子。宣子由于当初的话,占有州地感到惭愧,用州地跟乐大心交换了原县。 +郑国有人因为伯有而互相惊扰,说:“伯有来了!”大家都跑,不知跑到哪里去才好。把刑法铸在鼎上的那年二月,有人梦见伯有披甲而行,说:“三月初二日,我将要杀死带。明年正月二十七日,我又将要杀死段。”到去年三月初二日那一天,驷带死了,国内的人们更加害怕。齐国和燕国讲和的那一月,二十七日,公孙段死了。国内的人们就越来越恐惧了。下一月,子产立了公孙泄和良止来安抚伯有的鬼魂,这才停了下来。子太叔问这样做的原因。子产说:“鬼有所归宿,这才不做恶鬼,我是为他寻找归宿啊。”太叔说:“立公孙泄干什么?”子产说:“为了使他们高兴,立身没有道义而希图高兴,执政的人违反礼仪,这是用来取得百姓欢心。不取得百姓欢心,不能使人信服。不能使人信服,百姓是不会服从的。” +等到子产去晋国,赵景子问他,说:“伯有还能做鬼吗?”子产说:“能。人刚刚死去叫做魄,已经变成魄,阳气叫做魂。生时衣食精美丰富魂魄就强有力,因此有现形的能力,一直达到神化。普通的男人和女人不能善终,他们的魂魄还能附在别人身上,以大肆惑乱暴虐,何况伯有是我们先君穆公的后代,子良的孙子,子耳的儿子,敝邑的卿,执政已经三代了。郑国虽然不强大,或者就像俗话所说的是‘小小的国家’,可是三代执掌政权,他使用东西很多,他在其中汲取精华也很多,他的家族又大,所凭借的势力雄厚,可又不得善终,能够做鬼,不也是应该的吗?” +子皮的族人饮酒没有节制,所以马师氏和子皮氏的关系很坏。齐军从燕国回去的那个月,罕朔杀了罕魋。罕朔逃亡到晋国,韩宣子向子产询问安排他什么官职。子产说:“君王的寄居之臣,如果能容他逃避死罪,还敢选择什么官职?卿离开本国,随大夫的班位。有罪的人根据他的罪行降等,这是古代的制度。朔在敝邑的班位,是亚大夫。他的官职,是马师。得罪逃亡,就随您安排了。能够免他一死,所施的恩惠就很大了,又岂敢要求官职?”宣子由于子产答复恰当,让他随下大夫的班位。 +秋季,八月,卫襄公死了。晋国的大夫对范献子说:“卫国事奉晋国恭敬亲近,晋国不加礼遇,包庇它的叛乱者而占取它的土地,所以诸侯有了二心。《诗》说:‘鹡鸰在平原上,遇到急难兄弟互相救援。’又说:‘死丧是那么可怕,兄弟要互相怀念。’兄弟不和睦,因此不相亲善,何况远方的人们,谁敢前来归服?现在又对卫国的继位之君不加礼遇,卫国必然背叛我们,这种做法是和诸侯绝交。”献子把这些话告诉韩宣子。韩宣子很高兴,派献子去卫国吊唁,同时归还戚地的土田给卫国。 +卫国的齐恶向周朝报告丧事,同时请求赐予恩命。周景王派郕简公去卫国吊唁,同时追命卫襄公说:“叔父升天,在我先王的左右,以辅佐事奉上帝。我岂敢忘了高圉、亚圉?” +九月,昭公从楚国到达。孟僖子不满意自己对礼仪不熟悉,就学习礼仪,如果有精通礼仪的人就跟他学习。等到临死的时候,召集他手下的大夫,说:“礼仪,是做人的根本。没有礼仪,不能自立。我听说有一个将要得志的人名叫孔丘,是聪明人的后代,而他的家族却在宋国灭亡了。他的祖先弗父何本来应当据有宋国而让给了宋厉公。到了正考父,辅佐戴公、武公、宣公,三命而做了上卿就更加恭敬,所以他的鼎铭说:‘一命低头,二命弯身,三命把腰深深弯下。沿着墙赶快走,也没有敢把我欺侮。稠粥在这里,稀粥也在这里,用来糊住我的口。’他的恭敬就像这样。臧孙纥有话说:‘聪明人里具有明德的人,如果不能做国君,他的后代必然有显贵的。’现在恐怕会在孔丘身上吧!我如得以善终,一定把说和何忌托给他老人家,让他们事奉他而学习礼仪,以稳定他们的地位。”所以孟懿子和南宫敬叔把孔子作为老师来事奉。孔子说:“能够弥补过错的,就是君子啊。《诗》说,‘要取法仿效君子’。孟僖子可以学习仿效了。” +单献公抛开亲族而任用寄居的客臣。冬季,十月二十日,襄公、顷公的族人杀死了单献公而立了单成公。 +十一月,季武子死了。晋平公对伯瑕说:“我所询问的关于日食的事情,应验了。可以经常这样占验吗?”伯瑕说:“不行。六种事物不相同,百姓心志不一致,事情轻重不是一类,官员好坏不一样,开始相同而结果相异,怎么可以经常这样呢?《诗》说‘有人舒舒服服地安居休息,有人精疲力尽地为国操劳’,它的结果不同就像这样。”晋平公说:“六种事物说的是什么?”伯瑕回答说:“这说的就是岁、时、日、月、星、辰。”晋平公说:“很多人告诉我辰的意义而没有相同的,什么叫做辰?”伯瑕回答说:“日和月相会叫做辰,所以用来和日相配。” +卫襄公夫人姜氏没有儿子,宠姬婤姶生了孟絷。孔成子梦见康叔对自己说:“立元为国君,我让羁的孙子圉和史苟辅佐他。”史朝也梦见康叔对自己说:“我将要命令你的儿子苟和孔烝鉏的曾孙圉辅佐元。”史朝进见孔成子,告诉他梦见的情况,两梦情况相合。晋国韩宣子执政,向诸侯聘问的那一年,婤姶生了儿子,为他取名叫元。孟絷的脚不好不善走路,孔成子用《周易》来占筮,祝告说:“元希望享有卫国,主持国家。”得到《屯》卦。又祝告说:“我还想立絷,希望神灵能够允许。”得到《屯》卦变成《比》卦。把卦像给史朝看。史朝说:“‘元亨’,就是元将会享有国家,又有什么怀疑呢?”孔成子说:“‘元’不是说为首的吗?”史朝回答说:“康叔为他取名,可以说是为首的了。孟不是这样的人,他将不能列为宗主,不能叫做为首的。而且它的繇辞说:‘利建侯’。嫡子嗣位而吉利,还建立什么侯?建立不就是嗣位。两次卦像都那么说,您还是建立他为好。康叔命令了我们,两次卦像告诉了我们。占筮和梦境相合,这是武王所经过的,为什么不听从?脚有毛病只能待在家里闲居。国君主持国家,亲临祭祀,奉养百姓,事奉鬼神,参加会见朝觐,又哪里能够闲居?各人按照他所有利的去做,不也可以吗?”所以孔成子立了灵公。十二月二十三日,安葬卫襄公。 + +昭公八年 +【经】八年春,陈侯之弟招杀陈世子偃师,夏四月辛丑,陈侯溺卒。叔弓如晋。楚人执陈行人干征师杀之。陈公子留出奔郑。秋,蒐于红。陈人杀其大夫公子过。大雩,冬十月壬午,楚师灭陈。执陈公子招,放之于越。杀陈孔奂。葬陈哀公。 +【传】八年春,石言于晋魏榆。晋侯问于师旷曰:“石何故言?”对曰:“石不能言,或冯焉。不然,民听滥也。抑臣又闻之曰:‘作事不时,怨讟动于民,则有非言之物而言。’今宫室崇侈,民力凋尽,怨讟并作,莫保其性。石言,不亦宜乎?”于是晋侯方筑虒祁之宫。叔向曰:“子野之言,君子哉!君子之言,信而有徵,故怨远于其身。小人之言,僭而无征,故怨咎及之。《诗》曰:‘哀哉不能言,匪舌是出,唯躬是瘁。哿矣能言,巧言如流,俾躬处休。’其是之谓乎?是宫也成,诸侯必叛,君必有咎,夫子知之矣。” +陈哀公元妃郑姬,生悼大子偃师,二妃生公子留,下妃生公子胜。二妃嬖,留有宠,属诸徒招与公子过。哀公有废疾。三月甲申,公子招、公子过杀悼大子偃师,而立公子留。 +夏四月辛亥,哀公缢。干征师赴于楚,且告有立君。公子胜愬之于楚,楚人执而杀之。公子留奔郑。书曰“陈侯之弟招杀陈世子偃师”,罪在招也;“楚人执陈行人干征师杀之”,罪不在行人也。 +叔弓如晋,贺虒祁也。游吉相郑伯以如晋,亦贺虒祁也。史赵见子大叔,曰:“甚哉,其相蒙也!可吊也,而又贺之?”子大叔曰:“若何吊也?其非唯我贺,将天下实贺。” +秋,大蒐于红,自根牟至于商、卫,革车千乘。 +七月甲戌,齐子尾卒,子旗欲治其室。丁丑,杀梁婴。八月庚戌,逐子成、子工、子车,皆来奔,而立子良氏之宰。其臣曰:“孺子长矣,而相吾室,欲兼我也。”授甲,将攻之。陈桓子善于子尾,亦授甲,将助之。或告子旗,子旗不信。则数人告。将往,又数人告于道,遂如陈氏。桓子将出矣,闻之而还,游服而逆之。请命,对曰:“闻强氏授甲将攻子,子闻诸?”曰:“弗闻。”“子盍亦授甲?无宇请从。”子旗曰:“子胡然?彼孺子也,吾诲之犹惧其不济,吾又宠秩之。其若先人何?子盍谓之?《周书》曰:‘惠不惠,茂不茂。’康叔所以服弘大也。”桓子稽颡曰:“顷、灵福子,吾犹有望。”遂和之如初。 +陈公子招归罪于公子过而杀之。九月,楚公子弃疾帅师奉孙吴围陈,宋戴恶会之。冬十一月壬午,灭陈。舆嬖袁克,杀马毁玉以葬。楚人将杀之,请置之。既又请私,私于幄,加絰于颡而逃。使穿封戌为陈公,曰:“城麇之役,不谄。”侍饮酒于王,王曰:“城麇之役,女知寡人之及此,女其辟寡人乎?”对曰:“若知君之及此,臣必致死礼,以息楚。”晋侯问于史赵,曰:“陈其遂亡乎?”对曰:“未也。”公曰:“何故?”对曰:“陈,颛顼之族也。岁在鹑火,是以卒灭,陈将如之。今在析木之津,犹将复由。且陈氏得政于齐而后陈卒亡。自幕至于瞽瞍,无违命。舜重之以明德,置德于遂,遂世守之。及胡公不淫,胡周赐之姓,使祀虞帝。臣闻盛德必百世祀,虞之世数未也。继守将在齐,其兆既存矣。” +译文 +八年春季,在晋国的魏榆有块石头说话。晋平公向师旷询问说:“石头为什么说话?”师旷回答说:“石头不能说话,有的东西凭借着它。否则,就是百姓听错了。下臣又听说:‘做事情违背了农时,怨恨诽谤在百姓中发生,就有不能说话的东西说话。’现在宫室高大奢侈,百姓的财力用尽,怨恨诽谤一齐起来,没有人能确保自己的性命。石头说话,不也是相宜的吗?”当时晋平公正在建造虒祁之宫,叔向说:“子野的话真是君子啊!君子的话,诚实而有证明,所以怨恨远离他的身体。小人的话,虚伪而没有证明,所以怨恨和灾祸来到他身上。《诗》说,‘不会说话多么伤心,话不能从他舌头上出来,只有劳累他自己。会说话的多么美好,漂亮话好像流水,使他自己安居休息’,说的就是这个吧!这座宫殿落成,诸侯必然背叛,国君必然有灾殃,师旷先生已经知道这一点了。” +陈哀公的第一夫人郑姬生了悼太子偃师,第二夫人生了公子留,第三夫人生了公子胜。第二夫人受到宠爱,公子留得宠,哀公把他托付给司徒招和公子过。陈哀公患有长期不愈的疾病,三月十六日,公子招、公子过杀了悼太子偃师而立公子留做太子。 +夏季,四月十三日,陈哀公上吊而死。干徵师到楚国报丧,同时报告又立了国君。公子胜向楚国控诉,楚国人抓住干徵师并杀死了他。公子留逃亡到郑国。《春秋》记载说“陈侯之弟招杀陈世子偃师”,这是由于罪过在于公子招,“楚人执陈行人干徵师杀之”,这是由于罪过不在于行人。 +叔弓到晋国去,祝贺虒祁之宫的落成。游吉辅佐郑伯而去到晋国,也是祝贺虒祁之宫的落成。史赵见到游吉,说:“大家互相欺骗也太过分了!可以吊唁的事,反而又来祝贺它!”游吉说:“怎么吊唁啊?大概不仅我国祝贺,天下都将会来祝贺。” +秋季,在红地举行大检阅,从根牟直到宋国、卫国边境线上,兵车有一千辆。 +七月初八日,齐国的子尾死了,子旗想要管理子尾的家政。十一日,杀梁婴。八月十四日,驱逐了子成、子工、子车,这三个人都逃亡前来我国,子旗为子良立了家臣头子。子良的家臣说:“孩子已经长大了,子旗却要帮忙管我们的家事,这是想要兼并我们。”把武器发下去,准备攻打子旗。陈桓子和子尾亲近,也把武器发下去,准备帮助子良的家臣。有人报告给子旗,子旗不相信,又有几个人来报告。子旗准备去子良家里,又有几个人在路上向他报告,因此就去到陈氏那里。桓子将要出动了,听说子旗来,就转回去,穿上便服迎接子旗。子旗请问桓子的意见。桓子回答说:“听说子良家里把武器发下去准备攻打您,您听说了吗?”子旗说:“没有听说。”桓子说:“您何不也把武器发下去?无宇请求跟从您。”子旗说:“您为什么要这样做?他是个孩子,我教导他,还恐怕他不能成功,我又宠信他为他立了家臣头子,如果和他互相攻打,怎么对待先人?您何不对他去说一说?《周书》说,‘施惠于不感激施惠的人,劝勉不受劝勉的人’,这就是康叔所以能够作事宽大的缘故。”陈桓子叩着头说:“顷公、灵公保佑您,我还希望您赐惠于我呢。”于是两家和好如同以前一样。 +陈国的公子招把罪过推给公子过而杀死了他。九月,楚国的公子弃疾带兵奉事太孙吴包围陈国,宋国的戴恶领兵会合。冬季,十月十八日,灭亡了陈国。管车人袁克杀了马毁了玉为陈哀公殉葬。楚国人要杀死他。他请求赦免,不久又请求去小便。他在帐幕里小便,把麻带缠在头上逃走了。 +楚灵王派穿封戌做陈公,说:“在城麇那次事件中他不谄媚。”穿封戌事奉楚灵王饮酒,楚灵王说:“城麇那次事件,你要知道寡人能到这一步,你大约会让我的吧!”穿封戌回答说:“如果知道您能到这一步,臣下一定冒死来安定楚国。” +晋平公向史赵询问说:“陈国大约就此灭亡了吧!”史赵说:“没有。”晋平公说:“什么缘故?”史赵回答说:“陈国,是颛顼的后代。岁星在于鹑火,颛顼氏由此而终于灭亡。陈国也将会和过去一样。现在岁星在箕宿、斗宿间的银河中,陈国还将会复兴。而且陈氏要在齐国取得政权,以后才最终灭亡。这一族从幕直到瞽瞍都没有违背天命,舜又增加了盛德,德行一直落到遂的身上。遂的后代保持了它。到了胡公不淫,所以周朝给他赐姓,让他祭祀虞帝。下臣听说,盛德一定享有一百代的祭祀。现在虞的世代数字不满一百,将会继续在齐国保持下去,它的征兆已经有了。” + +昭公九年 +【经】九年春,叔弓会楚子于陈。许迁于夷。夏四月,陈灾。秋,仲孙玃如齐。冬,筑郎囿。 +【传】九年春,叔弓、宋华亥、郑游吉、卫赵□会楚子于陈。 +二月庚申,楚公子弃疾迁许于夷,实城父,取州来淮北之田以益之。伍举授许男田。然丹迁城父人于陈,以夷濮西田益之。迁方城外人于许。 +周甘人与晋阎嘉争阎田。晋梁丙、张趯率阴戎伐颖。王使詹桓伯辞于晋曰:“我自夏以后稷,魏、骀、芮、岐、毕,吾西土也。及武王克商,蒲姑、商奄,吾东土也;巴、濮、楚、邓,吾南土也;肃慎、燕、亳,吾北土也。吾何迩封之有?文、武、成、康之建母弟,以蕃屏周,亦其废队是为,岂如弁髦而因以敝之?先王居檮杌于四裔,以御螭魅,故允姓之奸,居于瓜州,伯父惠公归自秦,而诱以来,使逼我诸姬,入我郊甸,则戎焉取之。戎有中国,谁之咎也?后稷封殖天下,今戎制之,不亦难乎?伯父图之。我在伯父,犹衣服之有冠冕,木水之有本原,民人之有谋主也。伯父若裂冠毁冕,拔本塞原,专弃谋主,虽戎狄其何有馀一人?”叔向谓宣子曰:“文之伯也,岂能改物?翼戴天子而加之以共。自文以来,世有衰德而暴灭宗周,以宣示其侈,诸侯之贰,不亦宜乎?且王辞直,子其图之。”宣子说。 +王有姻丧,使赵成如周吊,且致阎田与襚,反颖俘。王亦使宾滑执甘大夫襄以说于晋,晋人礼而归之。 +夏四月,陈灾。郑裨灶曰:“五年,陈将复封。封五十二年而遂亡。”子产问其故,对曰:“陈,水属也,火,水妃也,而楚所相也。今火出而火陈,逐楚而建陈也。妃以五成,故曰五年。岁五及鹑火,而后陈卒亡,楚克有之,天之道也,故曰五十二年。” +晋荀盈如齐逆女,还,六月,卒于戏阳。殡于绛,未葬。晋侯饮酒,乐。膳宰屠蒯趋入,请佐公使尊,许之。而遂酌以饮工,曰:“女为君耳,将司聪也。辰在子卯,谓之疾日。君彻宴乐,学人舍业,为疾故也。君之卿佐,是谓股肱。股肱或亏,何痛如之?女弗闻而乐,是不聪也。”又饮外嬖嬖叔曰:“女为君目,将司明也。服以旌礼,礼以行事,事有其物,物有其容。今君之容,非其物也,而女不见。是不明也。”亦自饮也,曰:“味以行气,气以实志,志以定言,言以出令。臣实司味,二御失官,而君弗命,臣之罪也。”公说,彻酒。 +初,公欲废知氏而立其外嬖,为是悛而止。秋八月,使荀跞佐下军以说焉。 +孟僖子如齐殷聘,礼也。 +冬,筑郎囿,书,时也。季平子欲其速成也,叔孙昭子曰:“《诗》曰:‘经始勿亟,庶民子来。’焉用速成?其以剿民也?无囿犹可,无民其可乎?” +译文 +九年春季,叔弓、宋国华亥、郑国游吉、卫国赵黡在陈国会见楚灵王。 +二月某日,楚国的公子弃疾把许国迁到夷地,其实就是城父。再增加州来、淮北的土田给许国,由伍举把土田授给许男。然丹把城父的人迁到陈地,用濮地、夷地西部的土田补给陈地。把方城山外边的人迁到许地。 +周朝的甘地人和晋国的阎嘉争夺阎地的土田。晋国的梁丙、张趯率领阴戎进攻颍地。周天子派詹桓伯去谴责晋国说:“我们在夏代由于后稷的功劳,魏国、骀国、芮国、岐国、毕国,是我们的西部领土。到武王战胜商朝,蒲姑、商奄,是我们的东部领土。巴国、濮国、楚国、邓国,是我们的南部领土。肃慎、燕国、亳国,是我们的北部领土。我们有什么近处的封疆领土?文王、武王、成王、康王建立同母兄弟的国家,用来护卫周室,也是为了防止周室的毁坏衰落,难道只是像不用的东西因而就抛弃了它?先王让梼杌住在四方边远的地方,来抵御山中的精怪,所以允姓中的坏人住在瓜州。伯父惠公从秦国回去,就引诱他们前来,让他们逼迫我们姬姓的国家,进入我们的郊区,戎人于是就占取了这些地方。戎人占有中原,这是谁的罪责?后稷缔造了天下,现在为戎人割据,不也很难吗?伯父考虑一下,我们对于伯父来说,犹如衣服之有帽子,树木流水之有本源,百姓之有谋主。伯父如果撕毁了帽子,拔掉树木塞断水源,专断并抛弃谋主,即使是戎狄,他们心里哪里会有我这天子?”叔向对宣子说:“文公称霸诸侯,难道能改变旧制?他辅佐拥戴天子,而又加上恭敬。从文公以来,每一代都是德行衰减,而且损害、轻视王室,用来宣扬它的骄横,诸侯有三心二意,不也是应该的吗?而且天子的辞令理直气壮,您还是考虑一下。”宣子心服。 +周景王有姻亲的丧事,宣子就派赵成到成周吊唁,而且送去阎地的土田和入殓的衣服,遣返在颍地抓到的俘虏。周景王也派宾滑抓了甘地的大夫襄来讨晋国的欢心,晋国人对他加以礼遇而放他回去了。 +夏季,四月,陈地发生火灾。郑国的裨灶说:“过五年陈国将会重新受封,受封以后五十二年被灭亡。”子产问这样说的缘故。裨灶回答说:“陈国,是水的隶属;火,是水的配偶,而是楚国所主治。现在大火星出现而陈国发生火灾,这是驱逐楚国而建立陈国。阴阳五行用五来相配,所以说五年。岁星过五年到达鹑火,然后陈国终于灭亡,楚国战胜而占有它,这是上天之道,所以说是五十二年。” +晋国的荀盈到齐国去接齐女,回来,六月,死在戏阳。停棺在绛地,没有安葬。晋平公喝酒,奏乐。主持饮食的官员屠蒯快步走进,请求帮着斟酒,晋平公答应了,屠蒯就斟酒给乐工喝,说:“你作为国君的耳朵,职责是让它聪敏。日子在甲子乙卯,叫做忌日,国君撤除音乐,学乐的人停止演习,这是为了忌避的缘故。国君的卿佐,这叫做股肱之臣。股肱之臣有了亏损,多么痛心呀!你没有听到而奏乐,这是耳朵不灵敏。”又给宠臣嬖叔喝酒,说:“你作为国君的眼睛,职责是让它明亮。服饰用来表示礼仪,礼仪用来推行事情,事情有它的类别,类别有它的外貌。现在国君的外貌,不是他应有的类别,而你看不见,这是眼睛不明亮。”屠蒯自己也喝了一杯,说:“口味用来让气血流通,气血用来充实意志,意志用来确定语言,语言用来发布命令。臣下的职责是管调和口味,两个侍候国君的人失职,而国君没有下令治罪,这是下臣的罪过。”晋平公很高兴,撤除了酒宴。 +当初,晋平公想要废掉荀盈而立他的宠臣,因为上述这件事就改变想法,而停止了。秋季,八月,派荀跞辅佐下军以表明自己的意思。 +孟僖子到齐国举行盛大的聘问,这是合于礼的。 +冬季,修造郎囿。《春秋》加以记载,这是由于合于时令。季平子想要迅速完成,叔孙昭子说:“《诗》说:‘营造开始不要着急,百姓却像儿子一样自动跑来。’哪里用得着急于求成来劳累百姓呢?没有园林还是可以的,没有百姓可以吗?” + +昭公十年 +【经】十年春王正月。夏,齐栾施来奔。秋七月,季孙意如、叔弓、仲孙玃帅师伐莒。戊子,晋侯彪卒。九月,叔孙婼如晋,葬晋平公。十有二月甲子,宋公成卒。 +【传】十年春,王正月,有星出于婺女。郑裨灶言于子产曰:“七月戊子,晋君将死。今兹岁在颛顼之虚,姜氏、任氏实守其地。居其维首,而有妖星焉,告邑姜也。邑姜,晋之妣也。天以七纪。戊子,逢公以登,星斯于是乎出。吾是以讥之。” +齐惠栾、高氏皆耆酒,信内多怨,强于陈、鲍氏而恶之。 +夏,有告陈桓子曰:“子旗、子良将攻陈、鲍。”亦告鲍氏。桓子授甲而如鲍氏,遭子良醉而骋,遂见文子,则亦授甲矣。使视二子,则皆从饮酒。桓子曰:“彼虽不信,闻我授甲,则必逐我。及其饮酒也,先伐诸?”陈、鲍方睦,遂伐栾、高氏。子良曰:“先得公,陈、鲍焉往?”遂伐虎门。 +晏平仲端委立于虎门之外,四族召之,无所往。其徒曰:“助陈、鲍乎?”曰:“何善焉?”“助栾、高乎?”曰:“庸愈乎?”“然则归乎?”曰:“君伐,焉归?”公召之而后入。公卜使王黑以灵姑金ぶ率,吉,请断三尺焉而用之。五月庚辰,战于稷,栾、高败,又败诸庄。国人追之,又败诸鹿门。栾施、高强来奔。陈、鲍分其室。 +晏子谓桓子:“必致诸公。让,德之主也,谓懿德。凡有血气,皆有争心,故利不可强,思义为愈。义,利之本也,蕴利生孽。姑使无蕴乎!可以滋长。”桓子尽致诸公,而请老于莒。 +桓子召子山,私具幄幕、器用、从者之衣屦,而反棘焉。子商亦如之,而反其邑。子周亦如之,而与之夫于。反子城、子公、公孙捷,而皆益其禄。凡公子、公孙之无禄者,私分之邑。国之贫约孤寡者,私与之粟。曰:“《诗》云:‘陈锡载周’,能施也,桓公是以霸。” +公与桓子莒之旁邑,辞。穆孟姬为之请高唐,陈氏始大。秋七月,平子伐莒,取郠,献俘,始用人于亳社。臧武仲在齐,闻之,曰:“周公其不飨鲁祭乎!周公飨义,鲁无义。《诗》曰:‘德音孔昭,视民不佻。’佻之谓甚矣,而壹用之,将谁福哉?” +戊子,晋平公卒。郑伯如晋,及河,晋人辞之。游吉遂如晋。九月,叔孙婼、齐国弱、宋华定、卫北宫喜、郑罕虎、许人、曹人、莒人、邾人、薛人、杞人、小邾人如晋,葬平公也。郑子皮将以币行。子产曰:“丧焉用币?用币必百两,百两必千人,千人至,将不行。不行,必尽用之。几千人而国不亡?”子皮固请以行。既葬,诸侯之大夫欲因见新君。叔孙昭子曰:“非礼也。”弗听。叔向辞之,曰:“大夫之事毕矣。而又命孤,孤斩焉在衰絰之中。其以嘉服见,则丧礼未毕。其以丧服见,是重受吊也。大夫将若之何?”皆无辞以见。子皮尽用其币,归,谓子羽曰:“非知之实难,将在行之。夫子知之矣,我则不足。《书》曰:‘欲败度,纵败礼。’我之谓矣。夫子知度与礼矣,我实纵欲而不能自克也。” +昭子至自晋,大夫皆见。高强见而退。昭子语诸大夫曰:“为人子,不可不慎也哉!昔庆封亡,子尾多受邑而稍致诸君,君以为忠而甚宠之。将死,疾于公宫,辇而归,君亲推之。其子不能任,是以在此。忠为令德,其子弗能任,罪犹及之,难不慎也?丧夫人之力,弃德旷宗,以及其身,不亦害乎?《诗》曰:‘不自我先,不自我后。’其是之谓乎!” +冬十二月,宋平公卒。初,元公恶寺人柳。欲杀之。及丧,柳炽炭于位,将至,则去之。比葬,又有宠。 +译文 +十年春季,周王朝历法的正月,有一颗星出现在婺女宿。郑国的裨灶对子产说:“七月初三日,晋国国君将要死去。现在岁星在玄枵,姜氏、任氏保守着这里的土地,婺女宿正当玄枵的首位,而有了妖星在这里出现,这是预告灾祸将要归于邑姜。邑姜,是晋侯的先妣。上天用七来记数,七月初三日,是逢公的死日,妖星就在这时候出现了,我是用它占卜而知道的。” +齐惠公的后代栾氏、高氏都喜欢喝酒,听信女人的话,所以别人的怨恨很多,势力比陈氏、鲍氏还要大而又讨厌陈氏、鲍氏。 +夏季,有人告诉陈桓子说:“子良、子旗将要进攻陈氏、鲍氏。”同时也告诉了鲍氏。陈桓子把兵器发给部下并且亲自到鲍氏那里,路上遇到子良喝醉了酒而骑马奔驰,就进见鲍文子,鲍文子也已经把兵器发下去了。派人去看子良、子旗两个人,他们都准备喝酒。陈桓子说:“他们将攻打我们的传闻即使不真实,但是他们听说我发下兵器,就一定会追赶我们。趁着他们在喝酒,抢先攻打他们怎么样?”陈氏、鲍氏正在和睦的时候,就攻打栾氏、高氏。子良说:“先得到国君的支持,陈氏、鲍氏往哪里去?”于是就攻打虎门。 +晏平仲穿着朝服站在虎门外边,四个家族召见他,他都不去。他的手下人说:“帮助陈氏、鲍氏吗?”晏平仲说:“他们有什么好处值得帮助?”“帮助栾氏、高氏吗?”晏平仲说:“难道能胜过陈氏、鲍氏?”“那么回去吗?”晏平仲说:“国君被攻打,回哪里去?”齐景公召见他,然后进去。齐景公为了派王黑用龙旗领兵而占卜,吉利,请求砍去三尺以后再使用。五月某日,在稷地作战,栾氏、高氏战败,在庄地又击败他们。国内的人们追赶他们,又在鹿门再次击败他们。栾施、高彊逃亡到鲁国来,陈氏、鲍氏分了他们的家产。 +晏子对陈桓子说:“一定要把获得的栾氏、高氏家产交给国君。谦让,是德行的根本,让给别人叫做美德。凡是有血气的人,都有争夺之心,所以利益不能勉强,想着道义就能胜过别人。道义,是利益的根本。积聚利益就会产生妖孽。姑且使它不要积聚吧!可以让它慢慢地生长。”陈桓子把陈氏、鲍氏的家产全都交给齐景公,并请求在莒地告老退休。 +陈桓子召见子山,私下准备了帷幕、器物、从者的衣服鞋子,并把棘地还给了子山。对子商也像这样做,而把封邑也还给了子商,对子周也是这样,而把夫于给了他。让子城、子公、公孙捷回国,并且都增加了他们的俸禄。凡是公子、公孙中没有俸禄的,私下把封邑分给他们。对国内贫困孤寡的人,私下给他们粮食。他说“《诗》说,‘把受到的赏赐摆出来赐给别人就创建了周朝’,这就是能够施舍的缘故。齐桓公因此而成为霸主。” +齐景公把莒地旁边的城邑赐给陈桓子,他辞谢了。穆孟姬为他请求高唐,陈氏开始昌大。秋季,七月,季平子进攻莒国,占领郠地。奉献俘虏,在亳社开始用人祭祀。臧武子在齐国,听到了这件事,说:“周公大约不去享用鲁国的祭祀了吧!周公享用合于道义的祭祀,鲁国不符合道义。《诗》说:‘那德行声誉特别显明,让百姓不要轻佻随便。’现在的做法可以说轻佻随便得过分了,而把人同牲畜一样使用,上天将会降福给谁呀!” +七月初三日,晋平公死了。郑简公去晋国,到达黄河,晋国人辞谢了,游吉就去到晋国。九月,叔孙婼、齐国国弱、宋国华定、卫国北宫喜、郑国罕虎、许人、曹人、莒人、邾人、滕人、薛人、杞人、小邾人到晋国去,这是为了安葬晋平公。 +郑国的子皮准备带着财礼前去,子产说:“吊丧哪里要用财礼,用财礼一定要一百辆车拉,一定要一千人。一千人到那里,一时不会回来。不回来,财物一定会用光。几千人的礼物出去几次,国家还有不灭亡的?”子皮坚决请求带着财礼出去。安葬完毕,诸侯的大夫想要乘机拜见新国君。叔孙昭子说:“这是不合于礼的。”大家不听。叔向辞谢他们,说:“大夫们的送葬事情已经完了,又命令我与诸卿相见,我哀痛地处在服丧期间,如果用吉服相见,那么丧礼还没有完毕;如果以丧服相见,这就是再受一次吊唁。大夫们准备怎么办?”大家都没有理由再请求拜见。子皮用光了他带去的财礼。回国后,对子羽说:“并不是难于懂得道理,难在实行。他老人家懂得道理,我对道理还懂得不够。《书》说‘欲望败坏法度,放纵败坏礼仪’,这就是说我啊。他老人家懂得法度和礼仪了,我确实是放纵欲望,又不能自我克制。” +昭子从晋国归来,大夫们都来进见。高彊进见以后就退了出去。昭子对大夫们说:“做一个人的儿子不能不谨慎啊!过去庆封逃亡,子尾接受城邑之后,又稍稍奉还给国君一部分,国君认为他忠诚,因而很宠信他。临死以前,在公宫得病,坐上车子回家,国君亲自推着他走。他的儿子不能继承父业,因此在这里。忠诚是美德,他的儿子不能继承,罪过就会延及到他身上,怎么能不谨慎呢?丧失了那个人的功劳,丢掉德行,让宗庙闲空而无人祭祀,而罪过就延及到他身上,不也是祸害吗?《诗》说,‘忧患的到来不在我前头,也不在我后头’,说的就是这个吧!” +冬季,十二月,宋平公死去。当初,宋元公讨厌寺人柳,想要杀死他。等到有了丧事,寺人柳在元公坐的地方烧上炭火,元公将要到达,就把炭撤去。等到安葬以后,寺人柳又得到了宠信。 + +昭公十一年 +【经】十有一年春王二月,叔弓如宋。葬宋平公。夏四月丁巳,楚子虔诱蔡侯般杀之于申。楚公子弃疾帅师围蔡。五月甲申,夫人归氏薨。大蒐于比蒲。仲孙玃会邾子,盟于祲祥。秋,季孙意如会晋韩起、齐国弱、宋华亥、卫北宫佗、郑罕虎、曹人、杞人于厥憖。九月己亥,葬我小君齐归。冬十有一月丁酉,楚师灭蔡,执蔡世子有以归,用之。 +【传】十一年春,王二月,叔弓如宋,葬平公也。 +景王问于苌弘曰:“今兹诸侯,何实吉?何实凶?”对曰:“蔡凶。此蔡侯般弑其君之岁也,岁在豕韦,弗过此矣。楚将有之,然壅也。岁及大梁,蔡复,楚凶,天之道也。” +楚子在申,召蔡灵侯。灵侯将往,蔡大夫曰:“王贪而无信,唯蔡于感,今币重而言甘,诱我也,不如无往。”蔡侯不可。五月丙申,楚子伏甲而飨蔡侯于申,醉而执之。夏四月丁巳,杀之,刑其士七十人。公子弃疾帅师围蔡。 +韩宣子问于叔向曰:“楚其克乎?”对曰:“克哉!蔡侯获罪于其君,而不能其民,天将假手于楚以毙之,何故不克?然肸闻之,不信以幸,不可再也。楚王奉孙吴以讨于陈,曰:‘将定而国。’陈人听命,而遂县之。今又诱蔡而杀其君,以围其国,虽幸而克,必受其咎,弗能久矣。桀克有婚以丧其国,纣克东夷而陨其身。楚小位下,而亟暴于二王,能无咎乎?天之假助不善,非祚之也,厚其凶恶而降之罚也。且譬之如天,其有五材而将用之,力尽而敝之,是以无拯,大可没振。” +五月,齐归薨,大蒐于比蒲,非礼也。 +孟僖子会邾庄公,盟于祲祥,修好,礼也。泉丘人有女梦以其帷幕孟氏之庙,遂奔僖子,其僚从之。盟于清丘之社,曰:“有子,无相弃也。”僖子使助薳氏之簉。反自祲祥,宿于薳氏,生懿子及南宫敬叔于泉丘人。其僚无子,使字敬叔。 +楚师在蔡,晋荀吴谓韩宣子曰:“不能救陈,又不能救蔡,物以无亲,晋之不能,亦可知也已!为盟主而不恤亡国,将焉用之?” +秋,会于厥憖,谋救蔡也。郑子皮将行,子产曰:“行不远。不能救蔡也。蔡小而不顺,楚大而不德,天将弃蔡以壅楚,盈而罚之。蔡必亡矣,且丧君而能守者,鲜矣。三年,王其有咎乎!美恶周必复,王恶周矣。”晋人使狐父请蔡于楚,弗许。 +单子会韩宣子于戚,视下言徐。叔向曰:“单子其将死乎!朝有着定,会有表,衣有禬带有结。会朝之言,必闻于表着之位,所以昭事序也。视不过结、禬之中,所以道容貌也。言以命之,容貌以明之,失则有阙。今单子为王官伯,而命事于会,视不登带,言不过步,貌不道容,而言不昭矣。不道,不共;不昭,不从。无守气矣。” +九月,葬齐归,公不戚。晋士之送葬者,归以语史赵。史赵曰:“必为鲁郊。”侍者曰:“何故?”曰:“归姓也,不思亲,祖不归也。”叔向曰:“鲁公室其卑乎?君有大丧,国不废蒐。有三年之丧,而无一日之戚。国不恤丧,不忌君也。君无戚容,不顾亲也。国不忌君,君不顾亲,能无卑乎?殆其失国。” +冬十一月,楚子灭蔡,用隐大子于冈山。申无宇曰:“不祥。五牲不相为用,况用诸侯乎?王必悔之。” +十二月,单成公卒。 +楚子城陈、蔡、不羹。使弃疾为蔡公。王问于申无宇曰:“弃疾在蔡,何如?”对曰:“择子莫如父,择臣莫如君。郑庄公城栎而置子元焉,使昭公不立。齐桓公城谷而置管仲焉,至于今赖之。臣闻五大不在边,五细不在庭。亲不在外,羁不在内,今弃疾在外,郑丹在内。君其少戒。”王曰:“国有大城,何如?”对曰:“郑京、栎实杀曼伯,宋萧、亳实杀子游,齐渠丘实杀无知,卫蒲、戚实出献公,若由是观之,则害于国。末大必折,尾大不掉,君所知也。” +译文 +十一年春季,周王朝历法的二月,叔弓到宋国去,这是为了安葬宋平公。 +周景王向苌弘询问说:“现在诸侯之中,哪里吉祥,哪里凶险?”苌弘回答说:“蔡国凶险。这是蔡侯般杀死他国君的年份。岁星在豕韦,不会过这一年了。楚国将会据有蔡国,然而这是积累邪恶。岁星到达大梁,蔡国复国,楚国不吉利,这是上天的常道。” +楚灵王在申地,召见蔡灵侯。蔡灵侯打算前去,蔡国的大夫说:“楚王贪婪而没有信用,唯独怨恨蔡国。现在财礼重而说话甜,这是引诱我们,不如不去。”蔡灵侯不同意。三月十五日,楚灵王在申地埋伏甲士而设享礼招待蔡灵侯,让他喝醉了酒就囚禁了他。夏季,四月初七日,杀死了蔡灵侯,杀死了蔡国的士七十人。公子弃疾领兵包围蔡国。 +韩宣子向叔向询问说:“楚国会战胜吗?”叔向回答说:“可以战胜的!蔡灵侯得罪了他的国君,而得不到百姓的拥护,上天将要借楚国的手来把他杀死,为什么不能战胜?然而肸听说,由于没有信用而得利,不可能有第二次。楚灵王事奉太孙吴讨伐陈国,说:‘将要安定你们的国家。’陈国人听从了他的命令,就灭了陈国建置为县。现在又诱骗蔡国而杀了他们的国君,来包围他们的国家,虽然侥幸而得胜,必然受到它的灾殃,不能长久了。夏桀战胜了有缗而丢掉了国家,商纣战胜东夷而丢掉了生命。楚国疆域小地位低,而屡次表现得比上面两个国王还要暴虐,能够没有灾祸吗?上天借助于坏人,不是降福给他,而是增多他的凶恶然后给他惩罚。而且比如像天有金、木、水、火、土五种材料而由人加以使用,材力用尽就丢弃了,因此楚国不可拯救,最后也不能兴盛了。” +五月,齐归去世。在比蒲举行盛大的阅兵,这是不符合礼的。 +孟僖子会见邾庄公,在祲祥结盟,重修从前的友好,这是符合礼的。泉丘人有一个女儿,梦见用她的帷幕覆盖了孟氏的祖庙,就私奔到孟僖子那里,她的同伴也跟着去了。在清丘的土地神庙里盟誓说:“有了儿子,不要丢掉我!”孟僖子让她们住在薳氏那个地方做妾。孟僖子从祲祥回来,住在薳氏那里,在泉丘的那个女人生了懿子和南宫敬叔。她的同伴没有儿子,就让同伴抚养敬叔。 +楚国的军队在蔡国,晋国的荀吴对韩宣子说:“不能救援陈国,又不能救援蔡国,别人因此就不来亲附了。晋国的不行也就可以知道。自己做盟主而不去为灭亡的国家担忧,又哪里用得着盟主?” +秋季,季孙意如和晋国韩起、齐国国弱、宋国华亥、卫国北宫佗、郑国罕虎、曹国人、杞国人在厥慭会见,为了商量救援蔡国。郑国的子皮将要出行。子产说:“走不远的,已经不能救援蔡国了。蔡国小而不顺服,楚国大而不施仁德,上天将要抛弃蔡国来使楚国积累邪恶,恶贯满盈然后惩罚它,蔡国一定灭亡了。而且丧失了国君而能够守住国家的也是很少的。到了三年,楚王大概有灾难吧!美和恶的岁星绕行一周的时候必然会有报应,楚灵王的邪恶已经要到岁星绕行一周的时候了。”晋国人派狐父到楚国请求楚国宽免蔡国,楚国人不答应。 +单成公在戚地会见韩宣子,目光向下,说话迟缓。叔向说:“单子大概将要死了吧!朝见有规定的席位,会见有标志,衣服有交叉,衣带有交结子。会见和朝见的言语,一定要使在座的人都能听到,用它来表明事情有条有理。目光不低于衣服交叉和衣带交结之处,用它来端正仪容形貌。言语用来发布命令,仪容相貌用来表明态度,做不到就有错误。现在单子做天子的百官之长,在盟会上宣布天子的命令,目光不高于衣带,声音超过一步就听不到,相貌不能端正仪容,言事就不能明白了。不端正,就不恭敬;不明白,别人就不顺从。他已经没有保养身体的精气了。” +九月,安葬齐归,鲁昭公不悲痛。晋国来送葬的士人,回去把情况告诉史赵。史赵说:“昭公一定会寄居到别国的郊外。”侍从的人说:“为什么?”史赵说:“他是归氏的儿子,不想念母亲,祖先不会保佑他的。” 叔向说:“鲁国公室的地位要下降了吧!国君发生大丧事,国家却不停止阅兵。有三年的丧期,却没有一天的悲痛。国家不为丧事去悲哀,这是不畏惧国君。国君没有悲痛的样子,这是不顾念亲人。国人不畏惧国君,国君不顾念亲人,地位能够不下降吗?恐怕将会丢掉他的国家。” +冬季,十一月,楚灵王灭亡了蔡国,杀死了隐太子用来祭祀冈山。申无宇说:“不吉祥。五种牲口不能互相用来祭祀,何况用诸侯呢?国君一定要后悔的。” +十二月,单成公去世。 +楚灵王在陈地、蔡地、不羹筑城。派弃疾做蔡公。楚灵王向申无宇询问说:“弃疾在蔡地怎么样?”申无宇回答说:“选择儿子没有像父亲那样合适的,选择臣子没有像国君那样合适的。郑庄公在栎地筑城而安置子元,让昭公不能立为国君。齐桓公在穀地筑城而安置管仲,到现在齐国还得到利益。臣听说五种大人物不在边境,五种小人物不在朝廷。亲近的人不在外边,寄居的人不在里边。现在弃疾在外边,郑丹在朝廷,君王恐怕要稍加戒备!”楚灵王说:“国都有高大的城墙,怎么样?”申无宇回答说:“在郑国的京地、栎地杀死了曼伯,在宋国的萧地、亳地杀死了子游,在齐国的渠丘杀死了公孙无知,在卫国的蒲地、戚地驱逐了献公。如果从这些看来,就有害于国都。树枝大了一定折断,尾巴大了就不能摇摆,这是君王所知道的。” + + +昭公十二年 +【经】十有二年春,齐高偃帅师纳北燕伯于阳。三月壬申,郑伯嘉卒。夏,宋公使华定来聘。公如晋,至河乃复。五月,葬郑简公。楚杀其大夫成熊。秋七月。冬十月,公子憖出奔齐。楚子伐徐。晋伐鲜虞。 +【传】十二年春,齐高偃纳北燕伯款于唐,因其众也。 +三月,郑简公卒,将为葬除。及游氏之庙,将毁焉。子大叔使其除徒执用以立,而无庸毁,曰:“子产过女,而问何故不毁,乃曰:‘不忍庙也!诺,将毁矣!’”既如是,子产乃使辟之。司墓之室有当道者,毁之,则朝而塴;弗毁,则日中而塴。子大叔请毁之,曰:“无若诸侯之宾何!”子产曰:“诸侯之宾,能来会吾丧,岂惮日中?无损于宾,而民不害,何故不为?”遂弗毁,日中而葬。君子谓:“子产于是乎知礼。礼,无毁人以自成也。” +夏,宋华定来聘,通嗣君也。享之,为赋《蓼萧》,弗知,又不答赋。昭子曰:“必亡。宴语之不怀,宠光之不宣,令德之不知,同福之不受,将何以在?” +齐侯、卫侯、郑伯如晋,朝嗣君也。公如晋,至河乃复。取郠之役,莒人诉于晋,晋有平公之丧,未之治也,故辞公。公子憖遂如晋。晋侯享诸侯,子产相郑伯,辞于享,请免丧而后听命。晋人许之,礼也。晋侯以齐侯宴,中行穆子相。投壶,晋侯先。穆子曰:“有酒如淮,有肉如坻。寡君中此,为诸侯师。”中之。齐侯举矢,曰:“有酒如渑,有肉如陵。寡人中此,与君代兴。”亦中之。伯瑕谓穆子曰:“子失辞。吾固师诸侯矣,壶何为焉,其以中俊也?齐君弱吾君,归弗来矣!”穆子曰:“吾军帅强御,卒乘竞劝,今犹古也,齐将何事?”公孙叟趋进曰:“日旰君勤,可以出矣!”以齐侯出。 +楚子谓成虎若敖之馀也,遂杀之。或谮成虎于楚子,成虎知之而不能行。书曰:“楚杀其大夫成虎。”怀宠也。 +六月,葬郑简公。 +晋荀吴伪会齐师者,假道于鲜虞,遂入昔阳。秋八月壬午,灭肥,以肥子绵皋归。 +周原伯绞虐其舆臣,使曹逃。冬十月壬申朔,原舆人逐绞而立公子跪寻,绞奔郊。 +甘简公无子,立其弟过。过将去成、景之族,成、景之族赂刘献公。丙申,杀甘悼公,而立成公之孙鳅。丁酉,杀献太子之傅庾皮之子过,杀瑕辛于市,及宫嬖绰、王孙没、刘州鸠、阴忌、老阳子。 +季平子立,而不礼于南蒯。南蒯谓子仲:“吾出季氏,而归其室于公。子更其位。我以费为公臣。”子仲许之。南蒯语叔仲穆子,且告之故。 +季悼子之卒也,叔孙昭子以再命为卿。及平子伐莒,克之,更受三命。叔仲子欲构二家,谓平子曰:“三命逾父兄,非礼也。”平子曰:“然。”故使昭子。昭子曰:“叔孙氏有家祸,杀适立庶,故婼也及此。若因祸以毙之,则闻命矣。若不废君命,则固有着矣。”昭子朝,而命吏曰:“婼将与季氏讼,书辞无颇。”季孙惧,而归罪于叔仲子。故叔仲小、南蒯、公子憖谋季氏。憖告公,而遂从公如晋。南蒯惧不克,以费叛如齐。子仲还,及卫,闻乱,逃介而先。及郊,闻费叛,遂奔齐。 +南蒯之将叛也,其乡人或知之,过之而叹,且言曰:“恤恤乎,湫乎,攸乎!深思而浅谋,迩身而远志,家臣而君图,有人矣哉”南蒯枚筮之,遇《坤》三之《比》三,曰:“黄裳元吉。”以为大吉也,示子服惠伯,曰:“即欲有事,何如?”惠伯曰:“吾尝学此矣,忠信之事则可,不然必败。外强内温,忠也。和以率贞,信也。故曰‘黄裳元吉’。黄,中之色也。裳,下之饰也。元,善之长也。中不忠,不得其色。下不共,不得其饰。事不善,不得其极。外内倡和为忠,率事以信为共,供养三德为善,非此三者弗当。且夫《易》,不可以占险,将何事也?且可饰乎?中美能黄,上美为元,下美则裳,参成可筮。犹有阙也,筮虽吉,未也。” +将适费,饮乡人酒。乡人或歌之曰:“我有圃,生之杞乎!从我者子乎,去我者鄙乎,倍其邻者耻乎!已乎已乎,非吾党之士乎!” +平子欲使昭子逐叔仲小。小闻之,不敢朝。昭子命吏谓小待政于朝,曰:“吾不为怨府。”楚子狩于州来,次于颖尾,使荡侯、潘子、司马督、嚣尹午、陵尹喜帅师围徐以惧吴。楚子次于乾溪,以为之援。雨雪,王皮冠,秦复陶,翠被,豹舄,执鞭以出,仆析父从。右尹子革夕,王见之,去冠、被,舍鞭,与之语曰:“昔我先王熊绎,与吕级、王孙牟、燮父、禽父,并事康王,四国皆有分,我独无有。今吾使人于周,求鼎以为分,王其与我乎?”对曰:“与君王哉!昔我先王熊绎,辟在荆山,筚路蓝缕,以处草莽。跋涉山林,以事天子。唯是桃弧、棘矢,以共御王事。齐,王舅也。晋及鲁、卫,王母弟也。楚是以无分,而彼皆有。今周与四国服事君王,将唯命是从,岂其爱鼎?”王曰:“昔我皇祖伯父昆吾,旧许是宅。今郑人贪赖其田,而不我与。我若求之,其与我乎?”对曰:“与君王哉!周不爱鼎,郑敢爱田?”王曰:“昔诸侯远我而畏晋,今我大城陈、蔡、不羹,赋皆千乘,子与有劳焉。诸侯其畏我乎?”对曰:“畏君王哉!是四国者,专足畏也,又加之以楚,敢不畏君王哉!” +工尹路请曰:“君王命剥圭以为金戚铋,敢请命。”王入视之。析父谓子革:“吾子,楚国之望也!今与王言如响,国其若之何?”子革曰:“摩厉以须,王出,吾刃将斩矣。”王出,复语。左史倚相趋过。王曰:“是良史也,子善视之。是能读《三坟》、《五典》、《八索》、《九丘》。”对曰:“臣尝问焉。昔穆王欲肆其心,周行天下,将皆必有车辙马迹焉。祭公谋父作《祈招》之诗,以止王心,王是以获没于祗宫。臣问其诗而不知也。若问远焉,其焉能知之?”王曰:“子能乎?”对曰:“能。其诗曰:‘祈招之愔愔,式昭德音。思我王度,式如玉,式如金。形民之力,而无醉饱之心。’”王揖而入,馈不食,寝不寐,数日,不能自克,以及于难。 +仲尼曰:“古也有志:‘克己复礼,仁也’。信善哉!楚灵王若能如是,岂其辱于乾溪?” +晋伐鲜虞,因肥之役也。 +译文 +十二年春季,齐国的高偃把北燕伯款送到唐地,这是因为唐地的群众愿意接纳他。 +三月,郑简公去世了。将要为安葬而清除道路上的障碍。到达游氏的祖庙,准备拆毁它。子太叔让他手下清道的人拿着工具站着,暂时不要去拆,说:“子产经过你们这里,如果问你们为什么不拆,就说:‘不忍毁掉祖庙啊。对,准备拆了。’”这样一番以后,子产就让清道的人避开游氏的祖庙。管理坟墓的人的房屋,有位于当路的。拆了它,就可以在早晨下葬,不拆,就要到中午才能下葬。子太叔请求拆了它,说:“不拆,把各国的宾客怎么办?”子产说:“各国的宾客能够前来参加我国的丧礼,难道会担心迟到中午?对宾客没有损害,只要百姓不遭危害,为什么不做?”于是就不拆,到中午下葬。君子认为:“子产在这件事情上懂得礼。礼,没有毁坏别人而成全了自己的事。” +夏季,宋国的华定来鲁国聘问,为新即位的宋君通好。设享礼招待他,为他赋《蓼萧》这首诗,他不知道,又不赋诗回答。昭子说:“他必定会逃亡。诗中所说宴会的笑语不怀念,宠信和光耀不宣扬,美好的德行不知道,共同的福禄不接受,他将凭什么在卿位?” +齐景公、卫灵公、郑定公到晋国去,朝见新立的国君。昭公到晋国去,到达黄河边就返回去了。占取郠地的那一次战役,莒国人向晋国控诉,晋国正好有平公的丧事,没有能够办理,所以辞谢昭公。于是公子慭就到了晋国。 +晋昭公设享礼招待诸侯,子产辅佐郑定公,请求不参加享礼,请求丧服期满然后听取命令。晋国人答应了,这是合于礼的。 +晋昭公和齐景公举行宴会,中行穆子相礼。以箭投入壶中为乐,晋昭公先投,穆子说:“有酒像淮流,有肉像高丘。寡君投中壶,统帅诸侯。”投中了。齐景公举起矢,说:“有酒如渑水,有肉像山陵。寡人投中壶,代君兴盛。”也投中了。伯瑕对穆子说:“您的话不恰当。我们本来就称霸诸侯了,壶有什么用?还是不要把投中看成希奇事。齐君认为我们国君软弱,回去以后不会来了。”穆子说:“我们军队统帅强而有力,士兵争相勉励,今天就像从前一样,齐国能做些什么?”公孙傁快步走进,说:“天晚了,国君也累了,可以出去了!”就和齐景公一起出去了。 +楚灵王认为成虎是若敖的余党,就杀死了他。有人在楚灵王那里诬陷成虎,成虎知道了,但是不能出走。《春秋》记载说“楚杀其大夫成虎”,这是由于他留恋宠幸。 +六月,安葬郑简公。 +晋国的荀吴假装会合齐军的样子,向鲜虞借路,就乘机进入昔阳。秋季,八月初十日,灭亡肥国,带了肥子绵皋回国。 +周朝的原伯绞残暴,他的许多手下人集体逃走。冬季,十月初一,原地大众赶走绞,立了公子跪寻。绞逃亡到郊地。 +甘简公没有儿子,立了他兄弟甘过做国君。过准备去掉成公、景公的族人。成公、景公的族人贿赂刘献公,二十五日,杀死了甘悼公,立了成公的孙子。二十六日,杀了献太子保傅、庾皮的儿子过,在市上杀了瑕辛,又杀了宫嬖绰、王孙没、刘州鸠、阴忌、老阳子。 +季平子即位后,对南蒯不加礼遇。南蒯对子仲说:“我赶走季氏,把他的家产归公,您取代他的地位,我带着费地作为公臣。”子仲答应了。南蒯告诉叔仲穆子,同时把原因告诉了他。 +季悼子死的时候,叔孙昭子由于再命而做了卿士。等到季平子进攻莒国得胜,昭子改受三命。叔仲穆子想要离间季氏和叔孙氏两家,对平子说:“三命超过了父兄,这是不合于礼的。”平子说:“是这样。”所以就让昭子自己辞谢。昭子说:“叔孙氏发生家祸,杀死嫡子立了庶子,所以婼才到了这一步。如果是因为祸乱而来讨伐,那么我听从命令了。如果不废弃国君的命令,那么本来就有我的位次。”昭子朝见,命令官吏说:“婼打算和季氏打官司,写诉讼辞的时候不要偏袒。”季平子畏惧,就归罪于叔仲子,因此叔仲穆子、南蒯、子仲就打季氏的主意。子仲告诉昭公,就跟随昭公去了晋国。南蒯害怕打不赢,带了费地叛变到了齐国。子仲回国,到达卫国,听到动乱的情况,丢下副使先行逃回国内,到达郊外,听到费地叛乱就逃亡到齐国。 +南蒯将要叛变的时候,他的家乡有人知道情况,走过他门口,叹了口气说:“忧愁啊,愁啊,忧啊!想法高而智谋浅,关系近而志向远,作为家臣而想为国君图谋,要有人材才行啊!”南蒯不提出所问的事情而占筮,得到《坤》卦变为《比》卦,卦辞说,“黄裳元吉”,就认为是大吉大利。把它给子服惠伯看,说:“如果有事情,怎么样?”惠伯说:“我曾经学习过《易》,如果是忠信的事情就可以符合卦辞的预测,不然就必定失败。外表强盛内部温顺,这是忠诚,用和顺来实行占卜,这是信用,所以说‘黄裳元吉’。黄,是内衣的颜色。裳,是下身的服装。元,是善的第一位。内心不忠诚,就和颜色不相符合。在下面不恭敬,就和服装不相符合。事情办理不好,就和标准不相符合。内外和谐就是忠,根据诚信办事就是恭,崇尚上述三种德行,就是善,不是这三种德行就无法承当卦辞的预测。而且《易》不能用来预测冒险的事情,您打算做什么呢?而且能不能在下位而恭敬呢?中美就是黄,上美就是元,下美就是裳,这三者都具备了才可以合于卦辞的预测。如果有所缺少,卦辞虽然吉利,未必能行。” +南蒯将要到费地去,请乡里的人喝酒。乡里有人唱歌说:“我有块菜地,却生长了枸杞啊!跟我走的是大男子呵,不跟我走的是鄙陋的人呵,背弃他亲人的可耻呵!得了得了,不是我们一伙的人士呵!” +季平子想要让昭子赶走叔仲子。叔仲子听到了,不敢朝见。昭子命令官吏告诉叔仲子在朝廷上等待办公,说:“我不充当怨恨聚集的角色。” +楚灵王在州来打猎阅兵,驻扎在颍尾,派荡侯、潘子、司马督、嚣尹午、陵尹喜带兵包围徐国以威胁吴国。楚灵王驻在乾谿,作为他们的后援。下雪,楚灵王头戴皮帽子,身穿秦国的羽衣,披着翠羽披肩,脚穿豹皮鞋,手拿着鞭子走了出来。仆析父作为随从。右尹子革晚上去朝见,楚王接见他,脱去帽子、披肩,放下鞭子,和他说话,说:“从前我们先王熊绎,和吕级、王孙牟、燮父、禽父一起事奉康王,齐、晋、鲁、卫四国都分赐了宝器,唯独我国没有。现在我派人到成周,请求把鼎作为赏赐,周天子会给我吗?”子革回答说:“会给君王啊!从前我们先王熊绎住在荆山僻处,乘柴车、穿破衣以开辟丛生的杂草,跋山涉水以事奉天子,只能用桃木弓、枣木箭作为进贡。齐国,是天子的舅父。晋国和鲁国、卫国,是天子的同胞兄弟。楚国因此没有得到赏赐,而他们却有,现在是周朝和四国顺服事奉君王了。将会都听从您的命令,难道还爱惜鼎?”楚灵王说:“以前我们的皇祖伯父昆吾,居住在旧许,现在郑国人贪利这里的土田而不给我们。我们如果求取,他会给我们吗?”子革回答说:“会给君王啊!周朝不爱惜鼎,郑国还敢爱惜土田?”楚灵王说:“从前诸侯认为我国偏僻而害怕晋国,现在我们大大地修筑陈国、蔡国两个不羹城的城墙,每地都有战车一千辆,您是有功劳的,诸侯会害怕我们了吧!”子革回答说:“害怕君王啊!光是这四个城邑,也就足够使人害怕了,又加上楚国全国的力量,岂敢不怕君王呢?” +工尹路请求说:“君王命令破开圭玉以装饰斧柄,谨请发布命令。”楚灵王走进去察看。析父对子革说:“您,是楚国有名望的人。现在和君王说话,答对好像回声一样,国家将怎么办?”子革说:“我磨快了刀刃等着,君王出来,我的刀刃就将砍下去了。”楚灵王出来,又和子革说话。左史倚相快步走过,楚灵王说:“这个人是好史官,您要好好看待他,这个人能够读《三坟》、《五典》、《八索》、《九丘》。”子革回答说:“下臣曾经问过他。从前周穆王想要放纵他自己的私心,周游天下,想要让天下到处都有他的车辙马迹。祭公谋父作了《祈招》这首诗来阻止穆王的私心,穆王因此得以善终于祗宫。下臣问他这首诗,他都不知道。如果问更远的事情,他哪里能知道?”楚灵王说:“您能知道吗?”子革回答说:“能。这首诗说:‘祈招安祥和悦,表现有德者的声音。想起我们君王的风度,样子好像玉好像金。保存百姓的力量,而自己没有醉饱之心。’”楚灵王向子革作揖,便走了进去,送上饭来不吃,睡觉睡不着,有好几天,不能克制自己,所以终于遇上了祸难。 +孔子说:“古时候有话说:‘克制自己回到礼仪上,这就是仁。’真是说得好啊!楚灵王如果能够这样,难道还会在乾谿受到羞辱?” +晋国进攻鲜虞,这是乘灭亡肥国以后而顺路进攻的。 + +昭公十三年 +【经】十有三年春,叔弓帅师围费。夏四月,楚公子比自晋归于楚,杀其君虔于乾溪。楚公子弃疾杀公子比。秋,公会刘子、晋侯、宋公、卫侯、郑伯、曹伯、莒子、邾子、滕子、薛伯、杞伯、小邾子于平丘。八月甲戌,同盟于平丘。公不与盟。晋人执季孙意如以归。公至自会。蔡侯庐归于蔡。陈侯吴归于陈。冬十月,葬蔡灵公。公如晋,至河乃复。吴灭州来。 +【传】十三年春,叔弓围费,弗克,败焉。平子怒,令见费人执之以为囚俘。冶区夫曰:“非也。若见费人,寒者衣之,饥者食之,为之令主,而共其乏困。费来如归,南氏亡矣,民将叛之,谁与居邑?若惮之以威,惧之以怒,民疾而叛,为之聚也。若诸侯皆然,费人无归,不亲南氏,将焉入矣?”平子从之,费人叛南氏。 +楚子之为令尹也,杀大司马薳掩而取其室。及即位,夺薳居田;迁许而质许围。蔡洧有宠于王,王之灭蔡也,其父死焉,王使与于守而行。申之会,越大夫戮焉。王夺斗韦龟中犨,又夺成然邑而使为郊尹。蔓成然故事蔡公,故薳氏之族及薳居、许围、蔡洧、蔓成然,皆王所不礼也。因群丧职之族,启越大夫常寿过作乱,围固城,克息舟,城而居之。 +观起之死也,其子从在蔡,事朝吴,曰:“今不封蔡,蔡不封矣。我请试之。”以蔡公之命召子干、子皙,及郊,而告之情,强与之盟,入袭蔡。蔡公将食,见之而逃。观从使子干食,坎,用牲,加书,而速行。己徇于蔡曰:“蔡公召二子,将纳之,与之盟而遣之矣,将师而从之。”蔡人聚,将执之。辞曰:“失贼成军,而杀余,何益?”乃释之。朝吴曰:“二三子若能死亡,则如违之,以待所济。若求安定,则如与之,以济所欲。且违上,何适而可?”众曰:“与之。”乃奉蔡公,召二子而盟于邓,依陈、蔡人以国。楚公子比、公子黑肱、公子弃疾、蔓成然、蔡朝吴帅陈、蔡、不羹、许、叶之师,因四族之徒,以入楚。及郊,陈、蔡欲为名,故请为武军。蔡公知之曰:“欲速。且役病矣,请藩而已。”乃藩为军。蔡公使须务牟与史卑先入,因正仆人杀大子禄及公子罢敌。公子比为王,公子黑肱为令尹,次于鱼陂。公子弃疾为司马,先除王宫。使观从从师于乾溪,而遂告之,且曰:“先归复所,后者劓。”师及訾梁而溃。 +王闻群公子之死也,自投于车下,曰:“人之爱其子也,亦如余乎?”侍者曰:“甚焉。小人老而无子,知挤于沟壑矣。”王曰:“余杀人子多矣,能无及此乎?”右尹子革曰:“请待于郊,以听国人。”王曰:“众怒不可犯也。”曰:“若入于大都而乞师于诸侯。”王曰:“皆叛矣。”曰:“若亡于诸侯,以听大国之图君也。”王曰:“大福不再,只取辱焉。”然丹乃归于楚。王沿夏,将欲入鄢。芋尹无宇之子申亥曰:“吾父再奸王命,王弗诛,惠孰大焉?君不可忍,惠不可弃,吾其从王。”乃求王,遇诸棘围以归。夏五月癸亥,王缢于芋尹申亥氏。申亥以其二女殉而葬之。 +观从谓子干曰:“不杀弃疾,虽得国,犹受祸也。”子干曰:“余不忍也。”子玉曰:“人将忍子,吾不忍俟也。”乃行。国每夜骇曰:“王入矣!”乙卯夜,弃疾使周走而呼曰:“王至矣!”国人大惊。使蔓成然走告子干、子皙曰:“王至矣!国人杀君司马,将来矣!君若早自图也,可以无辱。众怒如水火焉,不可为谋。”又有呼而走至者曰:“众至矣!”二子皆自杀。丙辰,弃疾即位,名曰熊居。葬子干于訾,实訾敖。杀囚,衣之王服而流诸汉,乃取而葬之,以靖国人。使子旗为令尹。 +楚师还自徐,吴人败诸豫章,获其五帅。 +平王封陈、蔡,复迁邑,致群赂,施舍宽民,宥罪举职。召观从,王曰:“唯尔所欲。”对曰:“臣之先,佐开卜。”乃使为卜尹。使枝如子躬聘于郑,且致犨、栎之田。事毕,弗致。郑人请曰:“闻诸道路,将命寡君以犨、栎,敢请命。”对曰:“臣未闻命。”既复,王问犨、栎。降服而对,曰:“臣过失命,未之致也。”王执其手,曰:“子毋勤。姑归,不谷有事,其告子也。”他年芋尹申亥以王柩告,乃改葬之。 +初,灵王卜,曰:“余尚得天下。”不吉,投龟,诟天而呼曰:“是区区者而不馀畀,余必自取之。”民患王之无厌也,故从乱如归。 +初,共王无冢适,有宠子五人,无适立焉。乃大有事于群望,而祈曰:“请神择于五人者,使主社稷。”乃遍以璧见于群望,曰:“当璧而拜者,神所立也,谁敢违之?”既,乃与巴姬密埋璧于大室之庭,使五人齐,而长入拜。康王跨之,灵王肘加焉,子干、子皙皆远之。平王弱,抱而入,再拜,皆厌纽。斗韦龟属成然焉,且曰:“弃礼违命,楚其危哉!” +子干归,韩宣子问于叔向曰:“子干其济乎?”对曰:“难。”宣子曰:“同恶相求,如市贾焉,何难?”对曰:“无与同好,谁与同恶?取国有五难:有宠而无人,一也;有人而无主,二也;有主而无谋,三也;有谋而无民,四也;有民而无德,五也。子干在晋十三年矣,晋、楚之从,不闻达者,可谓无人。族尽亲叛,可谓无主。无衅而动,可谓无谋。为羁终世,可谓无民。亡无爱征,可谓无德。王虐而不忌,楚君子干,涉五难以弑旧君,谁能济之?有楚国者,其弃疾乎!君陈、蔡,城外属焉。苛慝不作,盗贼伏隐,私欲不违,民无怨心。先神命之。国民信之,芈姓有乱,必季实立,楚之常也。获神,一也;有民,二也;令德,三也;宠贵,四也;居常,五也。有五利以去五难,谁能害之?子干之官,则右尹也。数其贵宠,则庶子也。以神所命,则又远之。其贵亡矣,其宠弃矣,民无怀焉,国无与焉,将何以立?”宣子曰:“齐桓、晋文,不亦是乎?”对曰:“齐桓,卫姬之子也,有宠于僖。有鲍叔牙、宾须无、隰朋以为辅佐,有莒、卫以为外主,有国、高以为内主。从善如流,下善齐肃,不藏贿,不从欲,施舍不倦,求善不厌,是以有国,不亦宜乎?我先君文公,狐季姬之子也,有宠于献。好学而不贰,生十七年,有士五人。有先大夫子余、子犯以为腹心,有魏犨、贾佗以为股肱,有齐、宋、秦、楚以为外主,有栾、郤、狐、先以为内主。亡十九年,守志弥笃。惠、怀弃民,民从而与之。献无异亲,民无异望,天方相晋,将何以代文?此二君者,异于子干。共有宠子,国有奥主。无施于民,无援于外,去晋而不送,归楚而不逆,何以冀国?” +晋成虒祁,诸侯朝而归者皆有贰心。为取郠故,晋将以诸侯来讨。叔向曰:“诸侯不可以不示威。”乃并征会,告于吴。秋,晋侯会吴子于良。水道不可,吴子辞,乃还。 +七月丙寅,治兵于邾南,甲车四千乘,羊舌鲋摄司马,遂合诸侯于平丘。子产、子大叔相郑伯以会。子产以幄幕九张行。子大叔以四十,既而悔之,每舍,损焉。及会,亦如之。 +次于卫地,叔鲋求货于卫,淫刍荛者。卫人使屠伯馈叔向羹,与一箧锦,曰:“诸侯事晋,未敢携贰,况卫在君之宇下,而敢有异志?刍荛者异于他日,敢请之。”叔向受羹反锦,曰:“晋有羊舌鲋者,渎货无厌,亦将及矣。为此役也,子若以君命赐之,其已。”客从之,未退,而禁之。 +晋人将寻盟,齐人不可。晋侯使叔向告刘献公曰:“抑齐人不盟,若之何?”对曰:“盟以厎信。君苟有信,诸侯不贰,何患焉?告之以文辞,董之以武师,虽齐不许,君庸多矣。天子之老,请帅王赋,‘元戎十乘,以先启行’,迟速唯君。”叔向告于齐,曰:“诸侯求盟,已在此矣。今君弗利,寡君以为请。”对曰:“诸侯讨贰,则有寻盟。若皆用命,何盟之寻?”叔向曰:“国家之败,有事而无业,事则不经。有业而无礼,经则不序。有礼而无威,序则不共。有威而不昭,共则不明。不明弃共,百事不终,所由倾覆也。是故明王之制,使诸侯岁聘以志业,间朝以讲礼,再朝而会以示威,再会而盟以显昭明。志业于好,讲礼于等。示威于众,昭明于神。自古以来,未之或失也。存亡之道,恒由是兴。晋礼主盟,惧有不治。奉承齐牺,而布诸君,求终事也。君曰:‘余必废之,何齐之有?’唯君图之,寡君闻命矣!”齐人惧,对曰:“小国言之,大国制之,敢不听从?既闻命矣,敬共以往,迟速唯君。”叔向曰:“诸侯有间矣,不可以不示众。”八月辛未,治兵,建而不旆。壬申,复旆之。诸侯畏之。 +邾人、莒人言斥于晋曰:“鲁朝夕伐我,几亡矣。我之不共,鲁故之以。”晋侯不见公,使叔向来辞曰:“诸侯将以甲戌盟,寡君知不得事君矣,请君无勤。”子服惠伯对曰:“君信蛮夷之诉,以绝兄弟之国,弃周公之后,亦唯君。寡君闻命矣。”叔向曰:“寡君有甲车四千乘在,虽以无道行之,必可畏也,况其率道,其何敌之有?牛虽瘠,偾于豚上,其畏不死?南蒯、子仲之忧,其庸可弃乎?若奉晋之众,用诸侯之师,因邾、莒、杞、鄫之怒,以讨鲁罪,间其二忧,何求而弗克?”鲁人惧,听命。 +甲戌,同盟于平丘,齐服也。令诸侯日中造于除。癸酉,退朝。子产命外仆速张于除,子大叔止之,使待明日。及夕,子产闻其未张也,使速往,乃无所张矣。 +及盟,子产争承,曰:“昔天子班贡,轻重以列,列尊贡重,周之制也。卑而贡重者,甸服也。郑伯,男也,而使从公侯之贡,惧弗给也,敢以为请。诸侯靖兵,好以为事。行理之命,无月不至,贡之无艺,小国有阙,所以得罪也。诸侯修盟,存小国也。贡献无及,亡可待也。存亡之制,将在今矣。”自日中以争,至于昏,晋人许之。既盟,子大叔咎之曰:“诸侯若讨,其可渎乎?”子产曰:“晋政多门,贰偷之不暇,何暇讨?国不竞亦陵,何国之为?” +公不与盟。晋人执季孙意如,以幕蒙之,使狄人守之。司铎射怀锦,奉壶饮冰,以蒲伏焉。守者御之,乃与之锦而入。晋人以平子归,子服湫从。 +子产归,未至,闻子皮卒,哭,且曰:“吾已,无为为善矣,唯夫子知我。”仲尼谓:“子产于是行也,足以为国基矣。《诗》曰:‘乐只君子,邦家之基。’子产,君子之求乐者也。”且曰:“合诸侯,艺贡事,礼也。” +鲜虞人闻晋师之悉起也,而不警边,且不修备。晋荀吴自着雍以上军侵鲜虞,及中人,驱冲竞,大获而归。 +楚之灭蔡也,灵王迁许、胡、沈、道、房、申于荆焉。平王即位,既封陈、蔡,而皆复之,礼也。隐大子之子庐归于蔡,礼也。悼大子之子吴归于陈,礼也。 +冬十月,葬蔡灵公,礼也。 +公如晋。荀吴谓韩宣子曰:“诸侯相朝,讲旧好也,执其卿而朝其君,有不好焉,不如辞之。”乃使士景伯辞公于河。 +吴灭州来。令尹子期请伐吴,王弗许,曰:“吾未抚民人,未事鬼神,未修守备,未定国家,而用民力,败不可悔。州来在吴,犹在楚也。子姑待之。” +季孙犹在晋,子服惠伯私于中行穆子曰:“鲁事晋,何以不如夷之小国?鲁,兄弟也,土地犹大,所命能具。若为夷弃之,使事齐、楚,其何瘳于晋?亲亲,与大,赏共、罚否,所以为盟主也。子其图之。谚曰:‘臣一主二。’吾岂无大国?”穆子告韩宣子,且曰:“楚灭陈、蔡,不能救,而为夷执亲,将焉用之?”乃归季孙。惠伯曰:“寡君未知其罪,合诸侯而执其老。若犹有罪,死命可也。若曰无罪而惠免之,诸侯不闻,是逃命也,何免之?为请从君惠于会。”宣子患之,谓叔向曰:“子能归季孙乎?”对曰:“不能。鲋也能。”乃使叔鱼。叔鱼见季孙曰:“昔鲋也得罪于晋君,自归于鲁君。微武子之赐,不至于今。虽获归骨于晋,犹子则肉之,敢不尽情?归子而不归,鲋也闻诸吏,将为子除馆于西河,其若之何?”且泣。平子惧,先归。惠伯待礼。 +译文 +十三年春季,叔弓包围费地,没有攻下,被击败。季平子发怒,命令接见城外的费地人,就抓住他们作为囚犯。冶区夫说“不对。如果接见费地人,受冻的给他们衣服,受饿的给他们饭吃,做他们的好主子,供应他们所缺乏的东西,费地人前来就会像回家一样,南氏就要灭亡了。百姓将要背叛他,谁跟他住在围城里?如果用威严使他们害怕,用愤怒使他们畏惧,百姓讨厌而背叛您,这是为他招聚了百姓。如果诸侯都这样,费地人没有地方可去,他们不亲近南氏,还会到哪里去呢?”平子听从了他的意见,费地人背叛了南氏。 +当楚灵王做令尹的时候,杀了大司马薳掩并占取了他的家财。等到即位以后,夺取了薳居的土田。把许地的人迁走而以许围作为人质。蔡洧受到楚灵王的宠信,楚灵王灭亡蔡国的时候,他的父亲死在这次战争中,楚灵王派他参与守卫国都的任务然后灵王出发到乾谿。申地的盟会,越大夫受到侮辱。楚灵王夺取了鬬韦龟的封邑中犫,又夺取了成然的封邑,而让他做郊区大夫。蔓成然以前事奉蔡公。所以薳氏的亲族和薳居、许围、蔡洧、蔓成然,都是楚王不加礼遇的人。凭借着那些丧失职位的人的亲族,诱导越大夫常寿过发动叛乱,包围固城,攻下息舟,筑城而住在里面。 +观起死的时候,他儿子从在蔡地,事奉朝吴,说:“现在还不恢复蔡国,蔡国将永远被灭亡了。我请求试一下。”用蔡公的名义召回子干、子皙,到达郊区,就把真像告诉了他们,强迫与他们结盟,进而入侵蔡地。蔡公正要吃饭,见到这种情况就逃走了。观从让子干吃饭,挖坑,杀牲口,把盟书放在牲口上,然后让他赶快走。观从自己对蔡地人公开宣布说:“蔡公召见这两个人,准备送到楚国,和他们结盟以后已经把他们派出去了,而且准备带领军队跟上去。”蔡地人聚集起来,准备抓住观从。观从解释说:“失去了贼人,组成了军队,杀我,有什么好处?”蔡地人就放了他。朝吴说:“您几位如果想为楚王而死去或者逃亡,那就应当不听蔡公的,以等待事情的成败。如果要求安定,那就应当赞成他,以成就他的愿望。而且要是违背上官,你们将到哪里去呢?”大家说:“赞成他!”就奉事蔡公,召见子干、子皙两个人而在邓地会盟,依赖陈地人和蔡地人复国的心愿达到自己的目的。楚国的公子比、公子黑肱、公子弃疾、蔓成然、蔡国的朝吴率领陈、蔡、不羹、许、叶等地的军队,依靠四族的族人,进入楚国。到达郊区,陈地人、蔡地人想要宣扬名声,所以请求筑起壁垒。蔡公知道了,说:“我们的行动必须迅速,而且役人已经很疲劳了,编成篱笆就行了。”于是就用篱笆围起军营。蔡公派须务牟和史猈先进入国都,靠着太子亲近的官杀了太子禄和公子罢敌。公子比做了楚王,公子黑肱做了令尹,驻扎在鱼陂。公子弃疾做了司马,先清除王宫,派观从到乾谿和那里的军队联系,乘机告诉他们所发生的情况,同时说:“先回去的可以恢复禄位资财,后回去的受割鼻子的重刑。”楚灵王的军队到达訾梁就溃散了。 +楚灵王听到公子们的死讯,自己摔到车下,说:“别人爱他的儿子,也像我一样吗?”侍者说:“还有超过的。小人年老而没有儿子,自己知道会被挤到沟壑里去的。”楚灵王说:“我杀死别人的儿子很多了,能够不到这一步吗?”右尹子革说:“请在国都郊外等待,听从国内人们的选择。”楚灵王说:“大众的愤怒不可触犯。”子革说:“也许可以去到大的都邑,然后向诸侯请求出兵。”楚灵王说:“都背叛了。”子革说:“也许可以逃亡到诸侯那里,听从大国为君王的安排。”楚灵王说:“好运气不会再来,只是自取侮辱而已。”子革于是离开了楚灵王而回到楚国去。楚王沿汉水而下,打算到鄢地去。芋尹无宇的儿子申亥说:“我父亲再次触犯王命,君王没有诛戮,还有比这更大的恩惠吗?对国君不能忍心,恩惠不能丢弃,我还是跟着君王。”就去寻找楚灵王,在棘门前遇到楚灵王便一起回来。夏季,五月二十五日,楚灵王在芋尹申亥家上吊死了。申亥把两个女儿作为人殉而安葬了楚灵王。 +观从对子干说:“如果不杀死弃疾,虽然得到国家,还会受到灾祸。”子干说:“我不忍心啊。”观从说:“别人会对您忍心的,我不忍心等待了。”于是就走了。都城里常常有人夜里惊叫说:“君王进来了!”十七日夜里,弃疾派人走遍各处喊叫说:“君王到了!”都城里的人们大为惊恐。让蔓成然跑去报告子干、子皙说:“君王到了,都城里的人杀了您的司马弃疾,就要杀来了。您如果早一点自己打主意,可以不受侮辱。众怒好像水火,没有法子可以想了。”又有喊叫着跑来的人,说:“大伙都来到了!” 子干他们两个人都自杀了。十八日,弃疾即位,改名为熊居。 把子干安葬在訾地,称之为訾敖。杀死一个囚犯,穿上国王的衣服,却让尸体在汉水中漂流,只得收尸安葬,来安定国内的人心。让子旗担任令尹。 +楚军从徐国回来,吴军在豫章打败楚军,俘虏了他们的五个将领。 +楚平王重建陈、蔡两国,让迁移出去的人回来,给有功之臣赏赐财物,取消苛政,赦免罪人,举拔被废弃的官员。召见观从,楚平王说:“你所要求的都可以答应。”观从说:“下臣的祖先是卜尹的助手。”于是就让他做了卜尹。楚平王派枝如子躬到郑国聘问,同时交还犫地、栎地的土田。聘问结束,并没有交还。郑国人请求说:“听道路传闻,打算把犫地、栎地赐给寡君,谨敢请命。”枝如子躬说:“下臣没有听到这样的命令。”回国复命以后,楚平王问起归还犫地、栎地的事,枝如子躬脱去上衣谢罪说:“臣有错,违背了王命,没有交还。”楚平王拉着他的手,说:“您不要归罪自己!先回去罢,我以后有事,还是会告诉您的。” 过了几年,芋尹申亥把楚灵王的棺材所在报告平王,于是就改葬灵王。 +当初,楚灵王占卜说:“我希望能得到天下!”结果不吉利。灵王把龟甲扔在地上,责骂上天说:“这一点点好处都不给我,我一定要自己争取。”百姓担心灵王的欲望不能满足,所以参加动乱好像回家一样。 +当初,楚共王没有嫡长子,有五个宠爱的儿子,不知道应该立谁。于是就遍祭名山大川的神明,祈祷说:“请求神灵在五个人中选择,让他主持国家。”于是就把玉璧展示给名山大川的神明,说:“正对着玉璧下拜的,是神明所立的,谁敢违背?”祭祀完毕,就和巴姬秘密地把玉璧埋在祖庙的院子里,让这五个人斋戒,然后按长幼次序下拜。康王两脚跨在玉璧上,灵王的胳臂放在玉璧上,子干、子皙都离璧很远。平王还小,由别人抱了进来,两次下拜都压在璧纽上。鬬韦龟把成然嘱托给平王,而且说:“抛弃礼义而违背天命,楚国大概危险了。” +子干回国,韩宣子向叔向询问说:“子干可能会成功吧?”叔向回答说:“很难。”韩宣子说:“人们有共同的憎恶而互相需求,好像商人一样,有什么难的?”叔向回答说:“没有人和他有共同的爱好,谁会和他有共同的憎恶?得到国家有五条难处:有了显贵的身分而没有贤人,这是第一条;有了贤人而没有内应,这是第二条;有了内应而没有谋略,这是第三条;有了谋略而没有百姓,这是第四条;有了百姓而没有德行,这是第五条。子干在晋国十三年了,晋国、楚国跟从他的人,没有听说有知名之士,可以说没有贤人。族人被消灭,亲人背叛,可以说没有内应,没有空子而轻举妄动,可以说没有谋略。在外边作客一辈子,可以说没有百姓。流亡在外没有怀念他的像征,可以说没有德行。楚王虽暴虐却不忌刻,楚国如果以子干为国君,关系到这五条难处而杀死原来的国君,谁能帮助他成功?享有楚国的,恐怕是弃疾吧!统治着陈、蔡两地,方城山以外也归属于他。烦杂和邪恶的事情没有发生,盗贼潜伏隐藏,虽然有私欲而不违背礼仪,百姓没有怨恨之心。先代神明任命他,国民相信他。羋姓发生动乱,必然就是小儿子立为国君,这是楚国的常例。得到神灵的保佑,这是一;拥有百姓,这是二;具有美德,这是三;受宠又显贵,这是四;所居地位符合常例,这是五。有五条利益来除掉五条难处,谁能够伤害他?子干的官职,不过是右尹;数他的地位,不过是庶子;论起神明所命令的,那又远离了玉璧。他的显贵丧失了,他的宠信丢掉了。百姓没有怀念他的。国内没有亲附他的,将凭什么立为国君?”韩宣子说:“齐桓公、晋文公不也是这样吗?”叔向回答说:“齐桓公,是卫姬的儿子,僖公宠爱他。有鲍叔牙、宾须无、隰朋作为辅助,有莒国、卫国作为外援,有国氏、高氏作为内应。从善好像流水一样行动迅速,不贪财货,不放纵私欲,施舍不知疲倦,求善不厌其烦。由于这样而享有国家,不也是合适的吗?至于我们的先君文公,是狐季姬的儿子,献公宠爱他。喜欢学习而专心一志,生下来十七年,得到了五个人才。有先大夫子馀,予犯作为心腹,有魏犫、贾佗作为左右手,有齐国、宋国、秦国、楚国作为外援,有栾氏、郤氏、狐氏、先氏作为内应,逃亡在外十九年,意志坚定。惠公、怀公丢弃百姓,百姓都跟着文公。献公没有别的亲人,百姓没有别的希望。上天正在保佑晋国,将会用谁来代替晋文公?这两位国君,和子干不同。共王还有受宠的儿子,国内还有高深莫测的君主。对百姓没有施予,在外边没有援助。离开晋国没有人送行,回到楚国没有人迎接,凭什么希望享有楚国?” +晋国落成了虒祁宫,诸侯前去朝见而回去的都对晋国有了二心。为了占取郠地的缘故,晋国打算带领诸侯前来讨伐。叔向说:“不能不向诸侯显示一下威力。”于是就召集全体诸侯会见,而且告诉吴国。秋季,晋昭公到良地打算会见吴王,水路不通,吴王辞谢不来,晋昭公就回去了。 +七月二十九日,在邾国南部检阅军队。装载有甲士的战车四千辆。羊舌鲋代理司马,就在平丘会合诸侯。子产、子太叔辅助郑定公参加会见,子产带了帷布、幕布各九张出发,子太叔带了各四十张,不久又后悔,每住宿一次,就减少一些帷幕。等到达会见的地方,也和子产的一样了。 +停驻在卫国境内,羊舌鲋向卫国索取财货,放纵手下砍柴草的人捣乱。卫国人派屠伯送给叔向羹汤和一箧锦缎,说:“诸侯事奉晋国,不敢怀有二心,何况在君王的房檐下,哪里敢有别的念头?砍柴的人和过去不大一样,谨敢请您阻止他们。”叔向接受了羹汤退回了锦缎,说:“晋国有一个羊舌鲋,贪求财货没有满足,也将要及于祸难了。为了这次的事情,您如果以君王的命令赐给他锦缎,事情就了结了。”客人照办,还没有退出去,羊舌鲋就下令禁止砍柴草人的捣乱。 +晋国人要重温过去的盟约,齐国人不同意。晋昭公派叔向告诉刘献公说:“齐国人不肯结盟,怎么办?”刘献公回答说:“结盟是用来表示信用的,君王如果有信用,诸侯又没有二心,担什么心?用文辞向它报告,用武力对他监督,虽然齐国不同意,君王的功绩就很多了。天子的卿士请求带领天子的军队,‘大车十辆,在前面开路’,早晚只听凭君王决定。”叔向告诉齐国,说:“诸侯请求结盟,已经在这里了。现在君王以不结盟为有利,寡君以此作为请求。”齐国人回答说:“诸侯讨伐三心二意的国家,这才需要重温过去的盟约。如果都能听从命令,哪里需要重温旧盟?”叔向说:“国家的衰败,有了事情而没有贡赋,事情就不能正常。有了贡赋而没有礼节,正常会失去上下的次序。有了礼仪而没有威严,虽有次序也不能恭敬。有了威严而不能显著,虽有恭敬也不能昭告神明。不能昭告神明而失去了恭敬,各种事务没有结果,这就是国家败亡的原因。因此明王的制度,让诸侯每年聘问以记住自己的职责。每隔三年朝觐一次以演习礼仪,再次朝觐而诸侯会见以表现威严,再次会见而结盟以显示信义。在友好中记住自己的职责,用等级次序来演习礼仪,向百姓表现威严,向神明显示信义。从古以来,也许并没有缺失。存亡之道,常常由这里开始。晋国按照礼仪而主持结盟,惟恐不能办好,谨奉结盟的牺牲而展布于君王之前,以求得事情的良好结果。君王说‘我一定要废除它’,何必结盟呢?请君王考虑一下。寡君听到命令了。”齐国人恐惧,回答说:“小国说了话,大国加以决断,岂敢不听从?已经知道了你们的意思,我们会恭恭敬敬地前去,时间迟早听任君王的决定。”叔向说:“诸侯对晋国有嫌隙了,不能不向他们显示一下威力。”八月初四日,检阅军队,建立旌旗而不加飘带。初五日,又加上飘带。诸侯都感到畏惧。 +邾人、莒人向晋国控诉说:“鲁国经常进攻我国,我国快要灭亡了。我国不能进贡财礼,是由于鲁国的缘故。”晋昭公不接见鲁昭公,派叔向前来辞谢说:“诸侯将要在初七日结盟,寡君知道不能事奉君王了,请君王不必劳驾。”子服惠伯回答说:“君王听信蛮夷的控诉,断绝兄弟国家的关系,丢弃周公的后代,也只能由得君王。你们的意见,我们已经知道了。”叔向说:“寡君有装载甲士的战车四千辆在那里,即使不按常道办事,也必然是可怕的了。何况按照常道,还有谁能抵挡?牛虽然瘦,压在小猪身上,难道怕小猪不死?对南蒯、子仲的忧虑,难道可以忘记吗?如果凭着晋国的大众,使用诸侯的军队,依靠邾国、莒国、杞国、鄫国的愤怒,来讨伐鲁国的罪过,利用你们对两个人的忧虑,什么要求得不到?”鲁国人害怕了,就听从了命令。 +初七日,诸侯在平丘一起会盟,这是由于齐国顺服了。命令诸侯在中午到达盟会地点。初六日,朝见晋国完毕。子产命令外仆赶紧在盟会的地方搭起帐篷,子太叔阻拦仆人,让他们等第二天再搭。到晚上,子产听说他们还没有搭起帐篷,就派他们赶紧去,到那里已经没有地方可以搭帐篷了。 +等到结盟的时候,子产争论进贡物品的轻重次序,说:“从前天子确定进贡物品的次序,轻重是根据地位排列的。地位尊贵,贡赋就重,这是周朝的制度,地位低下而贡赋重的,这是距天子附近的小国。郑伯,是男服。让我们按照公侯的贡赋标准,恐怕不能足数供应的,谨敢以此作为请求。诸侯之间应当休息甲兵,从事于友好。使者催问贡税的命令,没有一个月不来到。贡赋没有个限度,小国不能满足要求而有所缺少,这就是得罪的原因。诸侯重温旧盟,这是为了使小国得以生存。贡赋没有个限制,灭亡的日子将会马上到来。决定存亡的规定,就在今天了。”从中午开始争论,直到晚上,晋国人同意了。结盟以后,子太叔责备子产说:“诸侯如果来讨伐,难道可以轻易地对待吗?”子产说:“晋国的政事出于很多家族,他们不能一心一意,苟且偷安还来不及,哪里来得及讨伐别人?国家不和别国竞争,也就会遭到欺凌,还成个什么国家?” +鲁昭公不参加结盟。晋国人逮捕了季孙意如,用幕布遮住他,让狄人看守。司铎射怀里藏了锦,捧着用壶盛着的冰水,悄悄地爬过去。看守人阻止他,就把锦送给看守人,然后进去。晋国人带了季孙回到晋国,子服湫跟随前去。 +子产回国,没有到达,听说子皮死了,号哭,说:“我完了!没有人帮我做好事了。只有他老人家了解我。”孔子认为:“子产在这次盟会中,足以成为国家的柱石了。《诗》说:‘是君子欢乐,他是国家和家族的柱石。’子产是君子中追求欢乐的人。”又说:“会合诸侯,制定贡赋的限度,这就是礼。” +鲜虞人听说晋国军队全部出动,可是并不在边境警戒,而且不修治武备。晋国的荀吴从著雍带领上军侵袭鲜虞,到达中人,驱使冲车和鲜虞人争逐,大获全胜然后回国。 +楚国灭亡蔡国的时候,楚灵王把许国、胡国、沈国、道地、房地、申地的人迁到楚国国内。楚平王即位,在封了陈国、蔡国以后,就都让他们迁回去,这是合于礼的。使隐太子的儿子庐回到蔡国,这是合于礼的。使悼太子的儿子吴回到陈国,这是合于礼的。 +冬季,十月,安葬蔡灵公,这是合于礼的。 +鲁昭公到晋国去。荀吴对韩宣子说:“诸侯互相朝见,这是由于重温过去的友好。抓了他们的大夫而朝见他们的国君,这是不友好的,不如辞谢他。”于是就派士景伯在黄河边上辞谢昭公。 +吴国灭亡州来,令尹子期请求进攻吴国。楚王不答应,说:“我没有安抚百姓,没有事奉鬼神,没有修缮防御设备,没有安定国家和家族,在这种情况下去使用百姓的力量,失败了来不及后悔。州来在吴国,就像在楚国一样。您姑且等着吧。” +季孙还在晋国,子服惠伯私下对中行穆子说:“鲁国事奉晋国,凭什么不如夷人的小国?鲁国,是兄弟,国土面积还很大,你们所规定的进贡物品都能具备。如果为了夷人而抛弃鲁国,让鲁国事奉齐国、楚国,对晋国有什么好处?亲近兄弟国家,赞助版图大的国家,奖赏能供给的国家,惩罚不供给的国家,这才是作为盟主的态度。您还是考虑一下!俗话说:‘一个臣子要有两个主人。’我们难道没有大国可以去奉事了?”穆子告诉韩宣子,而且说:“楚国灭亡陈、蔡,我们不能救援,反而为了夷人抓了亲人,这有什么用?”于是就把季孙放回去。惠伯说:“寡君不知道自己的罪过,会合诸侯而抓了他的元老。如果有罪,可以奉命而死。如果说没有罪而加恩赦免他,诸侯没有听到,这是逃避命令,这怎么算是赦免呢?请求赐给恩惠在盟会上赦免。”韩宣子担心这件事,对叔向说:“您能让季孙回去吗?”叔向回答说:“我办不到。鲋是能办得到的。”于是就让叔鱼去。叔鱼进见季孙,说:“从前鲋得罪了晋国国君,自己到了鲁国,如果不是武子的恩赐,不能到今天。即使老骨头已经回到晋国,等于您再次给了我生命,岂敢不为您尽心尽力?让您回去而您不回去,鲋听官吏说,将要在西河修造一所房子把您安置在那里,那怎么办?”说着,流下泪来。季孙害怕,就先回去了。惠伯不走,等晋国人以礼相送。 + +昭公十四年 +【经】十有四年春,意如至自晋。三月,曹伯滕卒。夏四月。秋,葬曹武公。八月,莒子去疾卒。冬,莒杀其公子意恢。 +【传】十四年春,意如至自晋,尊晋罪己也。尊晋、罪己,礼也。 +南蒯之将叛也,盟费人。司徒老祁、虑癸伪废疾,使请于南蒯曰:“臣愿受盟而疾兴,若以君灵不死,请待间而盟。”许之。二子因民之欲叛也,请朝众而盟。遂劫南蒯曰:“群臣不忘其君,畏子以及今,三年听命矣。子若弗图,费人不忍其君,将不能畏子矣。子何所不逞欲?请送子。”请期五日。遂奔齐。侍饮酒于景公。公曰:“叛夫?”对曰:“臣欲张公室也。”子韩皙曰:“家臣而欲张公室,罪莫大焉。”司徒老祁、虑癸来归费,齐侯使鲍文子致之。 +夏,楚子使然丹简上国之兵于宗丘,且抚其民。分贫,振穷;长孤幼,养老疾,收介特,救灾患,宥孤寡,赦罪戾;诘奸慝,举淹滞;礼新,叙旧;禄勋,合亲;任良,物官。使屈罢简东国之兵于召陵,亦如之。好于边疆,息民五年,而后用师,礼也。 +秋八月,莒着丘公卒,郊公不戚。国人弗顺,欲立着丘公之弟庚舆。蒲余侯恶公子意恢而善于庚舆,郊公恶公子铎而善于意恢。公子铎因蒲余侯而与之谋曰:“尔杀意恢,我出君而纳庚舆。”许之。 +楚令尹子旗有德于王,不知度。与养氏比,而求无厌。王患之。九月甲午,楚子杀斗成然,而灭养氏之族。使斗辛居郧,以无忘旧勋。 +冬十二月,蒲余侯兹夫杀莒公子意恢,郊公奔齐。公子铎逆庚舆于齐。齐隰党、公子锄送之,有赂田。 +晋邢侯与雍子争赂田,久而无成。士景伯如楚,叔鱼摄理,韩宣子命断旧狱,罪在雍子。雍子纳其女于叔鱼,叔鱼蔽罪邢侯。邢侯怒,杀叔鱼与雍子于朝。宣子问其罪于叔向。叔向曰:“三人同罪,施生戮死可也。雍子自知其罪而赂以买直,鲋也鬻狱,刑侯专杀,其罪一也。己恶而掠美为昏,贪以败官为墨,杀人不忌为贼。《夏书》曰:‘昏、墨、贼,杀。’皋陶之刑也。请从之。”乃施邢侯而尸雍子与叔鱼于市。 +仲尼曰:“叔向,古之遗直也。治国制刑,不隐于亲,三数叔鱼之恶,不为末减。曰义也夫,可谓直矣。平丘之会,数其贿也,以宽卫国,晋不为暴。归鲁季孙,称其诈也,以宽鲁国,晋不为虐。邢侯之狱,言其贪也,以正刑书,晋不为颇。三言而除三恶,加三利,杀亲益荣,犹义也夫!” +译文 +十四年春季,季孙意如从晋国回来,《春秋》这样记载,是尊重晋国而归罪于我国。尊重晋国而归罪于我国,这是合于礼的。 +南蒯将要叛变的时候,和费地人结盟。司徒老祁、虑癸假装发病,派人请求南蒯说:“下臣愿意接受盟约,然而疾病发作。如果托您的福而不死,请等病稍稍好一点再和您结盟。”南蒯答应了。这两个人依靠百姓想要背叛南蒯,就要求集合百姓一起结盟。于是就劫持南蒯说:“下臣没有忘记他们的君主,但是害怕您直到现在,服从您的命令三年了。您如果不考虑,费地的人由于不能对君主狠心,将要不再害怕您了。您在哪里不能满足愿望?请让我们把您送走吧!”南蒯请求等待五天。到时就逃亡到齐国。侍奉齐景公喝酒,齐景公说“叛徒!”南蒯回答说:“下臣是为了想要公室强大。”子韩皙说:“家臣想要使公室强大,没有比这再大的罪过了。”司徒老祁、虑癸前来收回费地,齐景公也派鲍文子来送还费地。 +夏季,楚平王派然丹在宗丘选拔检阅西部的军队,并且安抚当地的百姓。施舍贫贱,救济穷困,抚育年幼的孤儿,奉养有病的老人,收容单身汉,救济灾难,宽免孤儿寡妇的赋税,赦免有罪的人。禁治奸邪,提拔被埋没的贤才。以礼接待新人,交往旧人,奖赏功勋,和睦亲族,任用贤良,物色官吏。派屈罢在召陵选拔检阅东部地区的武装,也和西部一样。和四边的邻国友好,让百姓休养生息五年,然后用兵,这是合于礼的。 +秋季,八月,莒国国君著丘公死了,郊公不悲哀。国内的人们不服从他,想要立著丘公的兄弟庚舆。蒲馀侯讨厌公子意恢而和庚舆要好。郊公讨厌公子铎而和意恢要好。公子铎依靠蒲馀侯并且和他商量,说:“你去杀死意恢,我赶走国君而接纳庚舆。”蒲馀侯答应了。 +楚国的令尹子旗对楚平王有过功劳,但自己却不知道节制,和养氏勾结,贪得无厌。楚平王很担心。九月初三日,楚平王杀了鬬成然,灭掉养氏这一家族。让鬬辛住在郧地,以此表示不忘过去的功勋。 +冬季,十二月,蒲馀侯兹夫杀死了莒国的公子意恢。郊公逃亡到齐国。公子铎在齐国迎接庚舆,齐国的隰党、公子鉏送行,莒国向齐国贿赂土田。 +晋国的邢侯和雍子争夺鄐地的土田,很长时间也没有调解成功。士景伯去楚国,叔鱼代理他的职务。韩宣子命令他判处旧案,罪过在于雍子。雍子把女儿嫁给叔鱼,叔鱼宣判邢侯有罪。邢侯发怒,在朝廷上杀了叔鱼和雍子。韩宣子向叔向询问怎样治他们的罪。叔向说:“三个人罪状相同,杀了活着的人示众、暴露死者的尸体就可以了。雍子知道自己的罪过,而用他女儿作为贿赂来取得胜诉;鲋出卖法律,邢侯擅自杀人,他们的罪状相同。自己有罪恶而掠取别人的美名就是昏,贪婪而败坏职责就是不干净,杀人而没有顾忌就是贼。《夏书》说,‘昏、墨、贼,处死’,这是皋陶的刑法,请照办。”于是就杀了邢侯陈尸示众,并且把雍子和叔鱼的尸体摆在市上示众。 +孔子说:“叔向,他有着古代流传下来的正直作风。治理国家大事使用刑法,不包庇亲人。三次指出叔鱼的罪恶,不给他减轻。做事合于道义啊,可以说得上正直了!平丘的盟会,责备他贪财,以宽免卫国,晋国就做到了不凶暴。让鲁国季孙回去,称道他的欺诈,以宽免鲁国,晋国就做到了不凌虐。邢侯这次案件,说明他的贪婪,以执行法律,晋国就做到了不偏颇。三次说话而除掉三次罪恶,加上三种利益。杀死了亲人而名声更加显著,这也是合乎道义的吧!” + +昭公十五年 +【经】十有五年春王正月,吴子夷末卒。二月癸酉,有事于武宫。籥入,叔弓卒。去乐,卒事。夏,蔡朝吴出奔郑。六月丁巳朔,日有食之。秋,晋荀吴帅师伐鲜虞。冬,公如晋。 +【传】十五年春,将禘于武公,戒百官。梓慎曰:“禘之日,其有咎乎!吾见赤黑之祲,非祭祥也,丧氛也。其在莅事乎?”二月癸酉,禘,叔弓莅事,籥入而卒。去乐,卒事,礼也。 +楚费无极害朝吴之在蔡也,欲去之。乃谓之曰:“王唯信子,故处子于蔡。子亦长矣,而在下位,辱。必求之,吾助子请。”又谓其上之人曰:“王唯信吴,故处诸蔡,二三子莫之如也。而在其上,不亦难乎?弗图,必及于难。”夏,蔡人遂朝吴。朝吴出奔郑。王怒,曰:“余唯信吴,故置诸蔡。且微吴,吾不及此。女何故去之?”无极对曰:“臣岂不欲吴?然而前知其为人之异也。吴在蔡,蔡必速飞。去吴,所以翦其翼也。” +六月乙丑,王大子寿卒。 +秋八月戊寅,王穆后崩。 +晋荀吴帅师伐鲜虞,围鼓。鼓人或请以城叛,穆子弗许。左右曰:“师徒不勤,而可以获城,何故不为?”穆子曰:“吾闻诸叔向曰:‘好恶不愆,民知所适,事无不济。’或以吾城叛,吾所甚恶也。人以城来,吾独何好焉?赏所甚恶,若所好何?若其弗赏,是失信也,何以庇民?力能则进,否则退,量力而行。吾不可以欲城而迩奸,所丧滋多。”使鼓人杀叛人而缮守备。围鼓三月,鼓人或请降,使其民见,曰:“犹有食色,姑修而城。”军吏曰:“获城而弗取,勤民而顿兵,何以事君?”穆子曰:“吾以事君也。获一邑而教民怠,将焉用邑?邑以贾怠,不如完旧,贾怠无卒,弃旧不祥。鼓人能事其君,我亦能事吾君。率义不爽,好恶不愆,城可获而民知义所,有死命而无二心,不亦可乎!”鼓人告食竭力尽,而后取之。克鼓而反,不戮一人,以鼓子鸢鞮归。 +冬,公如晋,平丘之会故也。 +十二月,晋荀跞如周,葬穆后,籍谈为介。既葬,除丧,以文伯宴,樽以鲁壶。王曰:“伯氏,诸侯皆有以镇抚室,晋独无有,何也?”文伯揖籍谈,对曰:“诸侯之封也,皆受明器于王室,以镇抚其社稷,故能荐彝器于王。晋居深山,戎狄之与邻,而远于王室。王灵不及,拜戎不暇,其何以献器?”王曰:“叔氏,而忘诸乎?叔父唐叔,成王之母弟也,其反无分乎?密须之鼓,与其大路,文所以大蒐也。阙巩之甲,武所以克商也。唐叔受之以处参虚,匡有戎狄。其后襄之二路,金戚钺,秬鬯,彤弓,虎贲,文公受之,以有南阳之田,抚征东夏,非分而何?夫有勋而不废,有绩而载,奉之以土田,抚之以彝器,旌之以车服,明之以文章,子孙不忘,所谓福也。福祚之不登,叔父焉在?且昔而高祖孙伯□,司晋之典籍,以为大政,故曰籍氏。及辛有之二子董之晋,于是乎有董史。女,司典之后也,何故忘之?”籍谈不能对。宾出,王曰:“籍父其无后乎!数典而忘其祖。” +籍谈归,以告叔向。叔向曰:“王其不终乎!吾闻之:‘所乐必卒焉。’今王乐忧,若卒以忧,不可谓终。王一岁而有三年之丧二焉,于是乎以丧宾宴,又求彝器,乐忧甚矣,且非礼也。彝器之来,嘉功之由,非由丧也。三年之丧,虽贵遂服,礼也。王虽弗遂,宴乐以早,亦非礼也。礼,王之大经也。一动而失二礼,无大经矣。言以考典,典以志经,忘经而多言举典,将焉用之?” +译文 +十五年春季,将要对武公举行大的祭祀,告诫百官斋戒,梓慎说:“大的祭祀那一天恐怕会有灾祸吧!我看到了红黑色的妖气,这不是祭祀的祥瑞,是丧事的气氛。恐怕会应在主持祭祀者的身上吧!”二月十五日,举行大的祭祀。叔弓主持祭祀,在奏籥的人进入时,突然死亡。撤去音乐,把祭祀进行完毕,这是合于礼的。 +楚国的费无极嫉妒朝吴在蔡国,想要除去他,于是,就对朝吴说:“君王唯独相信您,所以把您安置在蔡国。您的年纪也不小了,可是地位低下,这是耻辱。一定要求得上位,我帮助您申请。”又对位在朝吴之上的人说:“君王唯独相信朝吴,所以把他安置在蔡国,您几位比不上他,而在他上面,不也很难吗?不加考虑,必然遭到祸难。”夏季,蔡国人赶走了朝吴,朝吴逃亡到郑国。楚平王发怒,说:“我唯独相信朝吴,所以把他安置在蔡国。而且如果没有朝吴,我到不了今天的地步。你为什么去掉他?”费无极回答说:“下臣难道不想要朝吴?然而早知道他有别的念头,朝吴在蔡国,蔡国必然很快飞走。去掉朝吴,这就是剪除蔡国的翅膀。” +六月初九日,王太子寿死了。 +秋季,八月二十二日,王穆后去世。 +晋国荀吴领兵进攻鲜虞,包围鼓国。鼓国有人请求带着城邑里面的人叛变,荀吴不答应,左右的随从说:“军人不辛劳而可以得到城邑,为什么不干?”荀吴说:“我听到叔向说:‘喜好、厌恶都不过分,百姓知道行动的方向,事情就没有不成功的。’有人带着我们的城邑叛变,这是我们所最厌恶的。别人带着城邑前来,我们为什么独独喜欢这样呢?奖赏我们所最厌恶的,对所喜欢的又怎么办?如果不加奖赏,这就是失信,又用什么保护百姓?力量达得到就进攻,否则就撤退,量力而行。我们不可以想要得到城邑而接近奸邪,这样所丧失的会更多。”于是让鼓国人杀了叛徒而修缮防御设备。包围鼓国三个月,鼓国有人请求投降。穆子让鼓国人进见,说:“看你们的脸色还好,姑且去修缮你们的城墙。”军吏说:“得到城邑而不占取,辛劳百姓而损毁武器,用什么事奉国君?”穆子说:“我用这样的做法来事奉国君。得到一个城邑而教百姓懈怠,这个城邑又哪里用得着?得到城邑而买来懈怠,不如保持一贯的勤快。买来懈怠,没有好结果。丢掉一贯的勤快,不吉祥。鼓国人能够事奉他们的国君,我也能够事奉我们的国君。合理就不出差错,喜好、厌恶都不过分,城邑可以得到而百姓懂得道义之所在,肯拼命而没有二心,不也是可以的吗?”鼓国人报告粮食吃完、力量用尽,然后占取了它。穆子攻下鼓国回国,不杀一个人,将鼓子鸢鞮带回国。 +冬季,鲁昭公到晋国去,这是由于平丘那次盟会的缘故。 +十二月,晋国的荀跞到成周去。安葬穆后,籍谈作为副使。安葬完毕,除去丧服。周景王和荀跞饮宴,把鲁国进贡的壶作为酒杯。周景王说:“伯父,诸侯都有礼器进贡王室,唯独晋国没有,为什么?”荀跞向籍谈作揖请他回答。籍谈回答说:“诸侯受封的时候,都从王室接受了明德之器,来镇抚国家,所以能把彝器进献给天子。晋国处在深山,戎狄和我们相邻,而远离王室,天子的威信不能达到,顺服戎人还来不及,怎么能进献彝器?”周景王说:“叔父,你忘了吧!叔父唐叔,是成王的同胞兄弟,难道反而没有分得赏赐吗?密须的名鼓和它的大辂车,是文王所用来检阅军队的。阙巩的铠甲,是武王用来攻克商朝的。唐叔接受了,用来居住在晋国的地域上,境内有着戎人和狄人。这以后襄王所赐的大辂、戎辂之车,斧钺、黑黍酿造的香酒,红色的弓、勇士,文公接受了,保有南阳的土田,安抚和征伐东边各国,这不是分得的赏赐还是什么?有了功勋而不废弃,有了功劳而记载在策书上,用土田来奉养他,用彝器来安抚他,用车服来表彰他,用旌旗来显耀他,子子孙孙不要忘记,这就是所谓福。这种福佑不记住,叔父的心哪里去了呢?而且从前你的高祖孙伯黡掌管晋国典籍,以主持国家大事,所以称为籍氏。等到辛有的第二个儿子董到了晋国,在这时就有了董氏的史官。你是司典的后氏,为什么忘了呢?”籍谈回答不出。客人退出去以后,周景王说:“籍谈的后代恐怕不能享有禄位了吧!举出了典故却忘记了祖宗。” +籍谈回国后,把这些情况告诉叔向。叔向说:“天子恐怕不得善终吧!我听说:‘喜欢什么,必然死在这上面。’现在天子把忧虑当成欢乐,如果因为忧虑致死,就不能说是善终。天子一年中有了两次三年之丧,在这个时候和吊丧的宾客饮宴,又要求彝器,把忧虑当成欢乐也太过分了,而且不合于礼。彝器的到来,由于嘉奖功勋,不是由于丧事。三年的丧礼,虽然贵为天子,服丧仍得满期,这是礼。现在天子即使不能服丧满期,饮宴奏乐也太早了,也是不合于礼的。礼,是天子奉行的重要规则。一次举动而失去了两种礼,这就没有重要规则了。言语用来考核典籍,典籍用来记载纲常。忘记了纲常而言语很多,举出了典故,又有什么用?” + +昭公十六年 +【经】十有六年春,齐侯伐徐。楚子诱戎蛮子杀之。夏,公至自晋。秋八月己亥,晋侯夷卒。九月,大雩。季孙意如如晋。冬十月,葬晋昭公。 +【传】十六年春,王正月,公在晋,晋人止公。不书,讳之也。 +齐侯伐徐。 +楚子闻蛮氏之乱也,与蛮子之无质也,使然丹诱戎蛮子嘉杀之,遂取蛮氏。既而复立其子焉,礼也。 +二月丙申,齐师至于蒲隧。徐人行成。徐子及郯人、莒人会齐侯,盟于蒲隧,赂以甲父之鼎。叔孙昭子曰:“诸侯之无伯,害哉!齐君之无道也,兴师而伐远方,会之,有成而还,莫之亢也,无伯也夫!《诗》曰:‘宗周既灭,靡所止戾。正大夫离居,莫知我肄。’其是之谓乎!” +二月,晋韩起聘于郑,郑伯享之。子产戒曰:“苟有位于朝,无有不共恪。”孔张后至,立于客间。执政御之,适客后。又御之,适县间。客从而笑之。事毕,富子谏曰:“夫大国之人,不可不慎也,几为之笑而不陵我?我皆有礼,夫犹鄙我。国而无礼,何以求荣?孔张失位,吾子之耻也。”子产怒曰:“发命之不衷,出令之不信,刑之颇类,狱之放纷,会朝之不敬,使命之不听,取陵于大国,罢民而无功,罪及而弗知,侨之耻也。孔张,君之昆孙子孔之后也,执政之嗣也,为嗣大夫,承命以使,周于诸侯,国人所尊,诸侯所知。立于朝而祀于家,有禄于国,有赋于军,丧祭有职,受脤、归脤,其祭在庙,已有着位,在位数世,世守其业,而忘其所,侨焉得耻之?辟邪之人而皆及执政,是先王无刑罚也。子宁以他规我。” +宣子有环,有一在郑商。宣子谒诸郑伯,子产弗与,曰:“非官府之守器也,寡君不知。”子大叔、子羽谓子产曰:“韩子亦无几求,晋国亦未可以贰。晋国、韩子,不可偷也。若属有谗人交斗其间,鬼神而助之,以兴其凶怒,悔之何及?吾子何爱于一环,其以取憎于大国也,盍求而与之?”子产曰:“吾非偷晋而有二心,将终事之,是以弗与,忠信故也。侨闻君子非无贿之难,立而无令名之患。侨闻为国非不能事大字小之难,无礼以定其位之患。夫大国之人,令于小国,而皆获其求,将何以给之?一共一否,为罪滋大。大国之求,无礼以斥之,何餍之有?吾且为鄙邑,则失位矣。若韩子奉命以使,而求玉焉,贪淫甚矣,独非罪乎?出一玉以起二罪,吾又失位,韩子成贪,将焉用之?且吾以玉贾罪,不亦锐乎?” +韩子买诸贾人,既成贾矣,商人曰:“必告君大夫。”韩子请诸子产曰:“日起请夫环,执政弗义,弗敢复也。今买诸商人,商人曰,必以闻,敢以为请。”子产对曰:“昔我先君桓公,与商人皆出自周,庸次比耦,以艾杀此地,斩之蓬蒿藜藿,而共处之。世有盟誓,以相信也,曰:‘尔无我叛,我无强贾,毋或丐夺。尔有利市宝贿,我勿与知。’恃此质誓,故能相保,以至于今。今吾子以好来辱,而谓敝邑强夺商人,是教弊邑背盟誓也,毋乃不可乎!吾子得玉而失诸侯,必不为也。若大国令,而共无艺,郑,鄙邑也,亦弗为也。侨若献玉,不知所成,敢私布之。”韩子辞玉,曰:“起不敏,敢求玉以徼二罪?敢辞之。” +夏四月,郑六卿饯宣子于郊。宣子曰:“二三君子请皆赋,起亦以知郑志。”子赋《野有蔓草》。宣子曰:“孺子善哉!吾有望矣。”子产赋《郑之羔裘》。宣子曰:“起不堪也。”子大叔赋《褰裳》。宣子曰:“起在此,敢勤子至于他人乎?”子大叔拜。宣子曰:“善哉,子之言是!不有是事,其能终乎?”子游赋《风雨》,子旗赋《有女同车》,子柳赋《蘀兮》。宣子喜曰:“郑其庶乎!二三君子以君命贶起,赋不出郑志,皆昵燕好也。二三君子数世之主也,可以无惧矣。”宣子皆献马焉,而赋《我将》。子产拜,使五卿皆拜,曰:“吾子靖乱,敢不拜德?”宣子私觐于子产以玉与马,曰:“子命起舍夫玉,是赐我玉而免吾死也,敢不藉手以拜?” +公至自晋。子服昭伯语季平子曰:“晋之公室,其将遂卑矣。君幼弱,六卿强而奢傲,将因是以习,习实为常,能无卑乎?” +平子曰:“尔幼,恶识国?” +秋八月,晋昭公卒。 +九月,大雩,旱也。郑大旱,使屠击、祝款、竖柎有事于桑山。斩其木,不雨。子产曰:“有事于山,蓺山林也,而斩其木,其罪大矣。”夺之官邑。 +冬十月,季平子如晋葬昭公。平子曰:“子服回之言犹信,子服氏有子哉!” +译文 +十六年春季,周王朝历法的正月,鲁昭公在晋国,晋国人扣留了昭公。《春秋》不记载这件事,这是由于隐讳。 +齐景公发兵进攻徐国。 +楚平王听说戎蛮部落发生动乱和蛮子没有信用,派然丹诱骗戎蛮子嘉而杀了他,就占领了戎蛮部落。不久以后又立了他的儿子,这是合于礼的。 +二月十四日,齐军到达蒲隧。徐国人求和,徐子和郯人、莒人会见齐景公,在蒲隧结盟,送给齐景公甲父之鼎。叔孙昭子说:“诸侯没有领袖,对小国是个危险啊!齐国的国君无道,起兵攻打远方的国家,会见了他们,缔结了和约而回来,没有人能够抵御,这是由于没有霸主啊!《诗》说,‘宗周已经衰亡,无所安定。执政的大夫四处分居,没有人知道我的辛劳’,说的就是这个吧!” +三月,晋国的韩起到郑国聘问,郑定公设享礼招待他。子产告诫大家说:“如果在朝廷的享礼上有一个席位,不要发生不恭敬的事!”孔张后到,站在客人中间,主管典礼的人挡住他,去到客人后边,主管典礼的人又挡住他,他只好到悬挂乐器的间隙中待着。客人因此而笑他。事情结束,富子劝谏说:“对待大国的客人,是不可以不慎重的。难道说被他们笑话了,而他们会不欺负我们?我们样样都能做到有礼,那些人还会看不起我们。国家没有礼仪,凭什么求得光荣?孔张没有站到应该站的位置上,这是您的耻辱。”子产发怒说:“发布命令不恰当,命令发出后没有信用,刑罚偏颇不平,诉讼放任混乱,朝会有时失去礼仪,命令没有人听从,招致大国的欺负,使百姓疲惫而没有功劳,罪过来到还不知道,这是我的耻辱。孔张,是国君哥哥的孙子,子孔的后代,执政大夫的继承人,做了嗣大夫,他接受命令而出使,遍及诸侯各国,为国内的人们所尊敬,为诸侯所熟悉。他在朝中有官职,在家里有祖庙,接受国家的爵禄,分担战争所需的军赋,丧事、祭祀有一定的职责,接受和归还祭肉,辅助国君在宗庙里祭祀,已经有了固定的地位。他家在位已经几代,世世代代保守自己的家业,现在忘记了他应该处的地位,侨哪里能为他感到耻辱?不正派的人把一切都归罪于我这个执政的人,等于说先王没有刑罚。你最好用别的事来纠正我。” +韩宣子有一付玉环,其中一个在郑国的商人手里。韩宣子向郑定公请求得到那只玉环,子产不给,说:“这不是公家府库中保管的器物,寡君不知道。”子太叔、子羽对子产说:“韩子也没有太多的要求,对晋国也不能怀有二心。晋国和韩子都是不能轻视的。如果正好有坏人在两国中间挑拨,如果鬼神再帮着坏人,以兴起他们的凶心怒气,后悔哪里来得及?您为什么爱惜一个玉环而以此使大国来讨厌呢?为什么不去找来给他?”子产说:“我不是轻慢晋国而有二心,而是要始终事奉他们,所以才不给他,这是为了忠实和守信用的缘故。侨听说君子不是怕没有财物,而是担心没有美好的名声。侨又听说治理国家不是怕不能事奉大国、抚养小国,而是怕没有礼仪来安定他的地位。大国命令小国,如果一切要求都得到满足,将要用什么来不断地供给他们?一次给了,一次不给,所得的罪过更大。大国的要求,如果不合乎礼就驳斥,他们哪里会有满足的时候?我们如果将成为他们的边境城市,那就失去了作为一个国家的地位了。如果韩子奉命出使而求取玉环,他的贪婪邪恶就太过分了,难道不是罪过吗?拿出一只玉环而引起两种罪过,我们又失去了国家的地位,韩子成为贪婪的人,哪里用得着这样?而且我们因为玉环招来罪过,不也是太不值得了吧?” +韩宣子向商人购买玉环,已经成交了。商人说:“一定要告诉君大夫!”韩宣子向子产请求说:“前些时候我请求得到这只玉环,执政认为不合于道义,所以不敢再次请求。现在在商人那里买到了,商人说一定要把这件事情报告,谨敢以此作为请求。”子产回答说:“从前我们先君桓公和商人们都是从周朝迁居出来的,共同合作清除这块土地,砍去野草杂木,一起居住在这里。世世代代都有盟誓,互相信赖。誓辞说:‘你不要背叛我,我不要强买你的东西,不要乞求、不要掠夺。你有赚钱的买卖和宝贵的货物,我也不加过问。’仗着这个有信用的盟誓,所以能互相支持直到今天。现在你带着友好的情谊光临敝邑,而告诉我们去强夺商人的东西,这是教导敝邑背叛盟誓,未免不可以吧!如果得到玉环而失去诸侯,那您一定是不干的。如果大国有命令,要我们没原则地供应,那就是把郑国当成了边境里的城市,我们也是不干的。侨如果献上玉环,真不知道有什么道理和好处。谨敢私下向您布达。”韩宣子就把玉环退了回去,说:“我韩起虽然不聪明,岂敢求取玉环以求得两项罪过?谨请把玉环退还。” +夏季,四月,郑国的六卿为韩宣子在郊外饯行。韩宣子说:“请几位大臣都赋诗一首,起也可以了解郑国的意图。”子齹赋《野有蔓草》。韩宣子说:“孺子好啊!我有希望了。”子产赋郑国的《羔裘》。韩宣子说:“起是不敢当的。”子太叔赋《褰裳》。韩宣子说:“有起在这里,难道敢劳动您去事奉别人吗?”子太叔拜谢。韩宣子说:“好啊,您说起了这个!要不是有这回事,能从始至终地友好下去吗?”子游赋《风雨》,子旗赋《有女同车》。子柳赋《萚兮》。韩宣子很高兴,说:“郑国差不多要强盛了吧!几位大臣用国君的名义赏赐起,所赋的《诗》不出郑国之外,都是表示友好的。几位大臣都是传了几世的大夫,可以不再有所畏惧了。”韩宣子对他们都奉献马匹,而且赋了《我将》。子产拜谢,又让其他五个卿也都拜谢,说:“您安定动乱,岂敢不拜谢恩德!”韩宣子用玉和马作为礼物私下拜见子产,说:“您命令起舍弃那个玉环,这是赐给了我金玉良言而免我一死,岂敢不借此薄礼表示拜谢!” +鲁昭公从晋国回到国内,子服昭伯对季平子说:“晋国的公室的地位恐怕将要降低了。国君年幼而力量微弱,六卿强大而奢侈骄傲,将要由此而成习惯。习惯而成自然,能够不降低吗?”季平子说:“你年轻,哪里懂得国家大事?” +秋季,八月,晋昭公逝世。 +九月,举行盛大的雩祭,这是由于发生了旱灾。郑国大旱,派屠击、祝款、竖柎祭祀桑山。砍去了山上的树木,不下雨。子产说:“祭祀山神,应当培育和保护山林,现在反而砍去山上的树木,他们的罪过就很大了。”于是就剥夺了他们的官爵和封邑。   +冬季,十月,季平子到晋国去参加昭公的丧礼。季平子说:“子服回的话还是可以相信的,子服氏有了好儿子了!” + +昭公十七年 +【经】十有七年春,小邾子来朝。夏六月甲戌朔,日有食之。秋,郯子来朝。八月,晋荀吴帅师灭陆浑之戎。冬,有星孛于大辰。楚人及吴战于长岸。 +【传】十七年春,小邾穆公来朝,公与之燕。季平子赋《采叔》,穆公赋《菁菁者莪》。昭子曰:“不有以国,其能久乎?” +夏六月甲戌朔,日有食之。祝史请所用币。昭子曰:“日有食之,天子不举,伐鼓于社;诸侯用币于社,伐鼓于朝。礼也。”平子御之,曰:“止也。唯正月朔,慝未作,日有食之,于是乎有伐鼓用币,礼也。其馀则否。”大史曰:“在此月也。日过分而未至,三辰有灾。于是乎百官降物,君不举,辟移时,乐奏鼓,祝用币,史用辞。故《夏书》曰:‘辰不集于房,瞽奏鼓,啬夫驰,庶人走。’此月朔之谓也。当夏四月,是谓孟夏。”平子弗从。昭子退曰:“夫子将有异志,不君君矣。” +秋,郯子来朝,公与之宴。昭子问焉,曰:“少皞氏鸟名官,何故也?”郯子曰:“吾祖也,我知之。昔者黄帝氏以云纪,故为云师而云名;炎帝氏以火纪,故为火师而火名;共工氏以水纪,故为水师而水名;大皞氏以龙纪,故为龙师而龙名。我高祖少皞挚之立也,凤鸟适至,故纪于鸟,为鸟师而鸟名。凤鸟氏,历正也。玄鸟氏,司分者也;伯赵氏,司至者也;青鸟氏,司启者也;丹鸟氏,司闭者也。祝鸠氏,司徒也;□鸠氏,司马也;鳲鸠氏,司空也;爽鸠氏,司寇也;鹘鸠氏,司事也。五鸠,鸠民者也。五雉,为五工正,利器用、正度量,夷民者也。九扈为九农正,扈民无淫者也。自颛顼以来,不能纪远,乃纪于近,为民师而命以民事,则不能故也。”仲尼闻之,见于郯子而学之。既而告人曰:“吾闻之:‘天子失官,学在四夷’,犹信。” +晋侯使屠蒯如周,请有事于雒与三涂。苌弘谓刘子曰:“客容猛,非祭也,其伐戎乎?陆浑氏甚睦于楚,必是故也。君其备之!”乃警戎备。九月丁卯,晋荀吴帅师涉自棘津,使祭史先用牲于洛。陆浑人弗知,师从之。庚午,遂灭陆浑,数之以其贰于楚也。陆浑子奔楚,其众奔甘鹿。周大获。宣子梦文公携荀吴而授之陆浑,故使穆子帅师,献俘于文宫。 +冬,有星孛于大辰,西及汉。申须曰:“彗所以除旧布新也。天事恒象,今除于火,火出必布焉。诸侯其有火灾乎?”梓慎曰:“往年吾见之,是其征也,火出而见。今兹火出而章,必火入而伏。其居火也久矣,其与不然乎?火出,于夏为三月,于商为四月,于周为五月。夏数得天。若火作,其四国当之,在宋、卫、陈、郑乎?宋,大辰之虚也;陈,大皞之虚也;郑,祝融之虚也,皆火房也。星孛天汉,汉,水祥也。卫,颛顼之虚也,故为帝丘,其星为大水,水,火之牡也。其以丙子若壬午作乎?水火所以合也。若火入而伏,必以壬午,不过其见之月。”郑裨灶言于子产曰:“宋、卫、陈、郑将同日火,若我用瓘斝玉瓒,郑必不火。”子产弗与。 +吴伐楚。阳丐为令尹,卜战,不吉。司马子鱼曰:“我得上流,何故不吉。且楚故,司马令龟,我请改卜。”令曰:“鲂也,以其属死之,楚师继之,尚大克之”。吉。战于长岸,子鱼先死,楚师继之,大败吴师,获其乘舟余皇。使随人与后至者守之,环而堑之,及泉,盈其隧炭,陈以待命。吴公子光请于其众,曰:“丧先王之乘舟,岂唯光之罪,众亦有焉。请藉取之,以救死。”众许之。使长鬣者三人,潜伏于舟侧,曰:“我呼皇,则对,师夜从之。”三呼,皆迭对。楚人从而杀之,楚师乱,吴人大败之,取余皇以归。 +译文 +十七年春季,小邾穆公来鲁国朝见,昭公和他一起饮宴。季平子赋了《采叔》,穆公赋了《菁菁者莪》。昭子说:“假若没有治理国家的人才,国家能长久吗?” +夏季,六月初一日,发生日食。掌管祭祀的官员请示所应该使用的祭品,昭子说:“发生日食,天子不进丰盛的菜肴,在土地神庙里击鼓。诸侯用祭品在土地神庙里祭祀,在朝廷上击鼓。这是礼制。”平子禁止这样做,说:“不能那样做。只有周正六月初一,阴气没有发作,发生日食,才击鼓用祭品,这是礼制。其他的时候就不这样。”太史说:“就是在这个月。太阳过了春分而没有到夏至,日、月、星有了灾殃,在这时候百官穿上素服,国君不进丰盛的菜肴,离开正寝躲过日食的时辰,乐工击鼓,祝使用祭品,史官使用辞令来祈祷消灾去祸。所以《夏书》说:‘日月交会不在正常的地位上,瞽师击鼓,啬夫驾车,百姓奔跑’,说的就是这个月初一的情况。正当夏正的四月,所以叫做孟夏。”平子不听从。昭子退出,说:“这个人将要有别的念头,他不把国君当成国君了。” +秋季,郯子来鲁国朝见,昭公和他一起饮宴。昭子询问他,说:“少皞氏用鸟名作为官名,这是什么缘故?”郯子说:“他是我的祖先,我知道。从前黄帝氏用云记事,所以设置各部门长官都用云字命名。炎帝氏用火记事,所以设置各部门长官都用火字命名。共工氏用水记事,所以设置各部门长官都用水字命名。太皞氏用龙记事,所以设置各部门长官都用龙来命名。我的高祖少皞挚即位的时候,凤鸟正好来到,所以就从鸟开始记事,设置各部门长官都用鸟来命名。凤鸟氏,就是掌管天文历法的官。玄鸟氏,就是掌管春分、秋分的官。伯赵氏,是掌管夏至、冬至的官。青鸟氏,是掌管立春、立夏的官。丹鸟氏,是掌管立秋、立冬的官。祝鸠氏,就是司徒;鴡鸠氏,就是司马;鸤鸠氏,就是司空;爽鸠氏,就是司寇;鹘鸠氏,就是司事。这五鸠,是鸠聚百姓的。五雉是五种管理手工业的官,是改善器物用具、统一尺度容量、让百姓得到平均的。九扈是九种管理农业的官,是制止百姓不让他们放纵的。自从颛顼以来,不能记述远古的事情,就从近古开始记述,做百姓的长官而用百姓的事情来命名,那已经是不能照过去办理了。” +孔子听到了这件事,进见郯子并向他学习古代官制。不久以后告诉别人说:“我听说,‘在天子那里失去了古代官制,官制的学问还保存在远方的小国’,这话还是可以相信的。” +晋顷公派屠蒯去到周朝,请求祭祀洛水和三涂山。苌弘对刘子说:“客人的脸色凶猛,不是为了祭祀,恐怕是为了进攻戎人吗!陆浑氏和楚国很友好,一定是这个缘故。您还是防备一下。”于是就对戎人加强警备。九月二十四日,晋国的荀吴领兵从棘津徒步涉水,让祭史先用牲口祭祀洛水。陆浑人不知道,部队就跟着打过去。二十七日,就灭亡了陆浑,责备他们和楚国勾结。陆浑子逃亡到楚国,他的部下逃亡到甘鹿。周朝俘虏了大批陆浑人。韩宣子梦见晋文公拉着荀吴而把陆浑交付给他,所以让他领兵,在晋文公庙里奉献俘虏。 +冬季,彗星在大火星旁边出现,光芒西达银河。申须说:“彗星是用来除旧布新的,天上发生的事常常像征凶吉,现在对大火星清扫,大火星再度出现必然散布灾殃,诸侯各国恐怕会有火灾吧!”梓慎说:“去年我见到它,这就是它的征兆了。大火星出现而见到它。现在它在大火星出现时更加明亮,必然在大火星消失时潜伏。它和大火星在一起已经很久了,难道不是这样吗?大火星出现,在夏正是三月,在商正是四月,在周正是五月。夏代的历数和天像适应,如果发生火灾,恐怕有四个国家承当,在宋国、卫国、陈国、郑国吧!宋国,是大火星的分野;陈国,是太皞的分野;郑国,是祝融的分野,都是大火星所居住的地方。彗星到达银河,银河,就是水。卫国,是颛顼的分野,所以是帝丘,和它相配的星是大水。水,是火的阳姓配偶。恐怕会在丙子日或者壬午日发生火灾吧!水火会在那个时候配合的。如果大火星消失而彗星随着潜伏,一定在壬午日发生火灾,不会超过它发现的那个月。”郑国的神灶对子产说:“宋、卫、陈、郑四国将要在同一天发生火灾。如果我们用瓘斝玉瓒祭神,郑国一定不发生火灾。”子产不肯给。 +吴国攻打楚国,楚国的阳匄做令尹,占卜战争的结果,不吉利。司马子鱼说:“我们地处上游,为什么不吉利?而且楚国的惯例,由司马在占卜前报告占卜的事情,我请求重新占卜。”报告说:“鲂带领部属战死,楚军跟上去,希望大获全胜。吉利。”两国军队在长岸作战,子鱼先战死,楚军跟着上去,把吴军打得大败,得到一条名叫馀皇的船,派随国人和后来到达的人看守,环绕这条船挖深沟,一直见到泉水,用炭填满,摆开阵势听候命令。吴国的公子光向大家请求说:“丢掉先王坐的船,难道只是光一人的罪过,大家也是有罪的。请求借大家的力量夺取回来以救一死。”大家答应了。派遣身高力壮的三个人偷偷地埋伏在船旁边,说:“我喊馀皇,你们就回答。”军队在夜里跟上去。喊了三次,埋伏的人都交替回答。楚国人上去把他们杀了。楚军混乱,吴军大败楚军,把馀皇号船夺回去了。 + +昭公十八年 +【经】十有八年春王三月,曹伯须卒。夏五月壬午,宋、卫、陈、郑灾。六月,邾人入鄅。秋,葬曹平公。冬,许迁于白羽。 +【传】十八年春,王二月乙卯,周毛得杀毛伯过而代之。苌弘曰:“毛得必亡,是昆吾稔之日也,侈故之以。而毛得以济侈于王都,不亡何待!” +三月,曹平公卒。 +夏五月,火始昏见。丙子,风。梓慎曰:“是谓融风,火之始也。七日,其火作乎!”戊寅,风甚。壬午,大甚。宋、卫、陈、郑皆火。梓慎登大庭氏之库以望之,曰:“宋、卫、陈、郑也。”数日,皆来告火。裨灶曰:“不用吾言,郑又将火。”郑人请用之,子产不可。子大叔曰:“宝,以保民也。若有火,国几亡。可以救亡,子何爱焉?”子产曰:“天道远,人道迩,非所及也,何以知之?灶焉知天道?是亦多言矣,岂不或信?”遂不与,亦不复火。 +郑之未灾也,里析告子产曰:“将有大祥,民震动,国几亡。吾身泯焉,弗良及也。国迁其可乎?”子产曰:“虽可,吾不足以定迁矣。”及火,里析死矣,未葬,子产使舆三十人,迁其柩。火作,子产辞晋公子、公孙于东门。使司寇出新客,禁旧客勿出于宫。使子宽、子上巡群屏摄,至于大宫。使公孙登徙大龟。使祝史徙主祏于周庙,告于先君。使府人、库人各儆其事。商成公儆司宫,出旧宫人,置诸火所不及。司马、司寇列居火道,行火所□欣。城下之人,伍列登城。明日,使野司寇各保其征。郊人助祝史除于国北,禳火于玄冥、回禄,祈于四鄘。书焚室而宽其征,与之材。三日哭,国不市。使行人告于诸侯。宋、卫皆如是。陈不救火,许不吊灾,君子是以知陈、许之先亡也。 +六月,鄅人藉稻。邾人袭鄅,鄅人将闭门。邾人羊罗摄其首焉,遂入之,尽俘以归。鄅子曰:“余无归矣。”从帑于邾,邾庄公反鄅夫人,而舍其女。秋,葬曹平公。往者见周原伯鲁焉,与之语,不说学。归以语闵子马。闵子马曰:“周其乱乎?夫必多有是说,而后及其大人。大人患失而惑,又曰:‘可以无学,无学不害。’不害而不学,则苟而可。于是乎下陵上替,能无乱乎?夫学,殖也,不学将落,原氏其亡乎?” +七月,郑子产为火故,大为社祓禳于四方,振除火灾,礼也。乃简兵大蒐,将为蒐除。子大叔之庙在道南,其寝在道北,其庭小。过期三日,使除徒陈于道南庙北,曰:“子产过女而命速除,乃毁于而乡。”子产朝,过而怒之,除者南毁。子产及冲,使从者止之曰:“毁于北方。” +火之作也,子产授兵登陴。子大叔曰:“晋无乃讨乎?”子产曰:“吾闻之,小国忘守则危,况有灾乎?国之不可小,有备故也。”既,晋之边吏让郑曰:“郑国有灾,晋君、大夫不敢宁居,卜筮走望,不爱牲玉。郑之有灾,寡君之忧也。今执事手间然授兵登陴,将以谁罪?边人恐惧不敢不告。”子产对曰:“若吾子之言,敝邑之灾,君之忧也。敝邑失政,天降之灾,又惧谗慝之间谋之,以启贪人,荐为弊邑不利,以重君之忧。幸而不亡,犹可说也。不幸而亡,君虽忧之,亦无及也。郑有他竟,望走在晋。既事晋矣,其敢有二心?” +楚左尹王子胜言于楚子曰:“许于郑,仇敌也,而居楚地,以不礼于郑。晋、郑方睦,郑若伐许,而晋助之,楚丧地矣。君盍迁许?许不专于楚。郑方有令政。许曰:‘余旧国也。’郑曰:‘余俘邑也。’叶在楚国,方城外之蔽也。土不可易,国不可小,许不可俘,仇不可启,君其图之。”楚子说。冬,楚子使王子胜迁许于析,实白羽。 +译文 +十八年春季,周王朝历法的二月十五日,周朝的毛得杀死毛伯过,取代了他。苌弘说:“毛得必然逃亡。这一天正好是昆吾恶贯满盈的日子,这是由于骄横的缘故。而毛得在天子的都城以骄横成事,不逃亡,还等待什么?” +三月,曹平公去世。 +夏季,五月,大火星开始在黄昏出现。初七日,刮风。梓慎说:“这就叫做融风,是火灾的开始,七天以后,恐怕要发生火灾吧!”初九日,风刮得很大。十四日,风刮得更大。宋国、卫国、陈国、郑国都发生火灾。梓慎登上大庭氏的库房远望,说:“这是在宋国、卫国、陈国、郑国。”几天以后,四国都来报告火灾。裨灶说:“不采纳我的意见,郑国还要发生火灾。”郑国人请求采纳他的意见,子产不同意。子太叔说:“宝物是用来保护百姓的。如果有了火灾,国家差不多会灭亡。可以挽救灭亡,您爱惜它干什么?”子产说:“天道悠远,人道切近,两不相关。如何由天道而知人道?灶哪里懂得天道?这个人的话多了,难道不会偶尔也说中的?”于是就不给。后来也没有再发生火灾。 +郑国还没有发生火灾以前,里析告诉子产说:“将要发生大的变异,百姓震动、国家差不多会灭亡。那时我自己已经死了,赶不上了。迁都,可以吗?”子产说:“即使可以,我一个人不能决定迁都的事。”等到发生火灾,里析已经死了,没有下葬,子产派三十个人搬走了他的棺材。火灾发生以后,子产在东门辞退了晋国的公子、公孙,派司寇把新来的客人送出去,禁止早已来的客人走出宾馆的大门。派子宽、子上巡察许多祭祀处所以至大宫。派公孙登迁走大龟,派祝史迁走宗庙里安放神主的石匣到周庙,向先君报告。派府人、库人各自戒备自己的管理范围以防火。派商成公命令司宫戒备,迁出先公的宫女,安置在火烧不到的地方。司马、司寇排列在火道上,到处救火。城下的人列队登城。第二天,派野司寇各自约束他们所征发的徒役不散开,郊区的人帮助祝史在国都北面清除地面修筑祭坛,向水神、火神祈祷,又在四城祈祷。登记被烧的房屋,减免他们的赋税,发给他们建筑材料。号哭三天,停止开放国都中的市场。派行人向诸侯报告。宋国和卫国也都这样。陈国不救火,许国不慰问火灾,君子因此而知道陈国、许国将先被灭亡。 +六月,鄅国国君巡视农奴耕种,邾国军队入侵鄅国。鄅国人将要关闭城门。邾国人羊罗把关闭城门人的脑袋砍下,用手提着,就因此进入鄅国,把百姓全都俘虏回去。鄅子说:“我没有地方回去了。”跟随他的妻子儿女到了邾国。邾庄公归还了鄅君的夫人而留下了他的女儿。 +秋季,安葬曹平公。去参加葬礼的人见到周朝的原伯鲁,跟他说话,发现他不爱学习。回去把情况告诉闵子马。闵子马说:“周朝恐怕要发生动乱了吧!一定是这种说法很多,然后才影响到当权的人。大夫们担心丢掉官位而不明事理,又说:‘可以不学习,不学习没有坏处。’认为没有坏处就不学习,得过且过,因此就下面驾凌上面,上面废弛,能不发生动乱吗?学习,如同种植一样,不学习就如草木一样枝叶要堕落,原氏大概要灭亡了吧!” +七月,郑国的子产因为火灾的缘故,大筑土地神庙,祭祀四方之神解除灾患,救治火灾的损失,这是合于礼的。于是精选士兵举行盛大检阅,将要进行清除场地。子太叔的家庙在路的南边,住房在路的北边,庙寝庭院不大。超过期限三天,他让清除场地的小工排列在路南庙北,说:“子产经过你们这里,下命令赶快清除,就向你们面对的方向动手拆除。”子产上朝,经过这里而发怒,清除的人就往南毁庙。子产走到十字路口,让跟随的人制止他们,说:“向北方拆除居室,不要拆庙。” +火灾发生的时候,子产登上城墙的矮墙颁发武器。子太叔说:“晋国恐怕要来讨伐吧?”子产说:“我听说,小国忘记守御就危险,何况有火灾呢?国家不能被轻视,就因为有防备。”不久,晋国的边防官吏责备郑国说:“郑国有了火灾,晋国的国君、大夫不敢安居,占卜占筮、奔走四处,遍祭名山大川,不敢爱惜牺牲玉帛。郑国有火灾,是寡君的忧虑。现在执事狠狠地颁发武器登上城墙,将要拿谁来治罪?边境上的人害怕,不敢不报告。”子产回答说:“像您所说的那样,敝邑的火灾,是君王的忧虑。敝邑的政事不顺,上天降下火灾,又害怕邪恶的人乘机打敝邑的主意,以引诱贪婪的人,再次增加敝邑的不利,以加重君王的忧虑。幸亏没有灭亡,还可以解释。如果不幸而被灭亡,君王虽然为敝邑忧虑,恐怕也是来不及了。郑国如果遭到别国的攻击,只有希望和投奔晋国,已经事奉晋国了,哪里敢有二心?” +楚国的左尹王子胜对楚平王说:“许国对于郑国,是仇敌,而住在楚国的土地上,由此对郑国无礼。晋国和郑国正在友好,郑国如果进攻许国,而晋国帮助他们,楚国就丧失土地了。君王何不把许国迁走?许国不为楚国专有,郑国正在推行好的政令。许国说:‘那里是我们原来的都城。’郑国说:‘那里是我们战胜而获得的城邑。’叶地在楚国,是方城山外边的屏障土地不能轻视,国家不能小看,许国不能俘虏,仇恨不能挑起,君王还是考虑一下!”楚王很高兴。冬季,楚平王派王子胜把许国迁移到析地,就是原来的白羽。 + + +昭公十九年 +【经】十有九年春,宋公伐邾。夏五月戊辰,许世子止弑其君买。己卯,地震。秋,齐高发帅师伐莒。冬,葬许悼公。 +【传】十九年春,楚工尹赤迁阴于下阴,令尹子瑕城郏。叔孙昭子曰:“楚不在诸侯矣!其仅自完也,以持其世而已。” +楚子之在蔡也,狊阜阳封人之女奔之,生大子建。及即位,使伍奢为之师。费无极为少师,无宠焉,欲谮诸王,曰:“建可室矣。”王为之聘于秦,无极与逆,劝王取之,正月,楚夫人嬴氏至自秦。 +鄅夫人,宋向戌之女也,故向宁请师。二月,宋公伐邾,围虫。三月,取之。乃尽归鄅俘。 +夏,许悼公疟。五月戊辰,饮大子止之药卒。大子奔晋。书曰:“弑其君。”君子曰:“尽心力以事君,舍药物可也。” +邾人、郳人、徐人会宋公。乙亥,同盟于虫。 +楚子为舟师以伐濮。费无极言于楚子曰:“晋之伯也,迩于诸夏,而楚辟陋,故弗能与争。若大城城父而置大子焉,以通北方,王收南方,是得天下也。”王说,从之。故太子建居于城父。 +令尹子瑕聘于秦,拜夫人也。 +秋,齐高发帅师伐莒。莒子奔纪鄣。使孙书伐之。初,莒有妇人,莒子杀其夫,已为嫠妇。及老,托于纪鄣,纺焉以度而去之。及师至,则投诸外。或献诸子占,子占使师夜缒而登。登者六十人。缒绝。师鼓噪,城上之人亦噪。莒共公惧,启西门而出。七月丙子,齐师入纪。 +是岁也,郑驷偃卒。子游娶于晋大夫,生丝,弱。其父兄立子瑕。子产憎其为人也,且以为不顺,弗许,亦弗止。驷氏耸。他日,丝以告其舅。冬,晋人使以币如郑,问驷乞之立故。驷氏惧,驷乞欲逃。子产弗遣。请龟以卜,亦弗予。大夫谋对,子产不待而对客曰:“郑国不天,寡君之二三臣,札瘥夭昏,今又丧我先大夫偃。其子幼弱,其一二父兄惧队宗主,私族于谋而立长亲。寡君与其二三老曰:‘抑天实剥乱是,吾何知焉?’谚曰:‘无过乱门。’民有兵乱,犹惮过之,而况敢知天之所乱?今大夫将问其故,抑寡君实不敢知,其谁实知之?平丘之会,君寻旧盟曰:‘无或失职。’若寡君之二三臣,其即世者,晋大夫而专制其位,是晋之县鄙也,何国之为?”辞客币而报其使。晋人舍之。 +楚人城州来。沈尹戌曰:“楚人必败。昔吴灭州来,子旗请伐之。王曰:‘吾未抚吾民。’今亦如之,而城州来以挑吴,能无败乎?”侍者曰:“王施舍不倦,息民五年,可谓抚之矣。”戌曰:“吾闻抚民者,节用于内,而树德于外,民乐其性,而无寇仇。今宫室无量,民人日骇,劳罢死转,忘寝与食,非抚之也。” +郑大水,龙斗于时门之外洧渊。国人请为焉,子产弗许,曰:“我斗,龙不我觌也。龙斗,我独何觌焉?禳之,则彼其室也。吾无求于龙,龙亦无求于我。”乃止也。 +令尹子瑕言蹶由于楚子曰:“彼何罪?谚所谓‘室于怒,市于色’者,楚之谓矣。舍前之忿可也。”乃归蹶由。 +译文 +十九年春季,楚国的工尹赤把阴戎迁移到下阴,令尹子瑕在郏地筑城。叔孙昭子说:“楚国的意图不在于诸侯了!楚国仅仅是为了保持自己的完整,以维持它的世代而已。” +楚平王在蔡国的时候,郹阳封人的女儿私奔到他那里,生了太子建。等楚平王即位,派伍奢做太子的师傅,费无极做少师。费无极不受宠信,想要向楚平王诬谄太子以求得宠信,说:“建可以娶妻了。”楚平王为太子在秦国行聘,费无极参加迎娶,劝楚平王自己娶这个女子。正月,楚夫人嬴氏从秦国来到。 +鄅国国君的夫人,是宋国向戌的女儿,所以向宁请求出兵。二月,宋公进攻邾国,包围虫地。三月,占取虫地,就把鄅国的俘虏全部放了回去。 +夏季,许悼公得了疟疾,五月初五日,喝了太子止送的药就死了。太子逃亡到晋国。《春秋》记载说:“弑其君。”君子说:“尽心竭力以事奉国君,不进药物是可以的。” +邾人、郳人、徐人会见宋元公。五月十二日,在虫地一起结盟。 +楚平王发动水军以进攻濮地。费无极对楚平王说:“晋国称霸诸侯的时候,接近中原诸国,而楚国偏僻简陋,所以不能和它争夺,如果扩大城父的城墙,而把太子安置在那里,用来和北方交通,君王收取南方,这是得到天下的好办法。”楚平王很高兴,听从了他的话,所以太子建住在城父。 +令尹子瑕到秦国聘问,这是为了拜谢把夫人嫁给楚国。 +秋季,齐国的高发领兵进攻莒国,莒共公逃亡到纪鄣。派孙书进攻纪鄣。当初,莒国有个女人,莒子杀了她丈夫,她就成了寡妇。等到年老,寄居在纪鄣,纺线搓绳量了城墙的高度然后收藏起来。等到齐军来到,就把绳扔出城外。有人把绳子献给孙书,孙书派部队在夜里攀绳登城,登上城的有六十个人,绳子断了。军队击鼓呐喊,城上的人也呐喊。莒共公害怕,打开西门逃跑。七月十四日,齐军进入纪鄣。 +这一年,郑国的驷偃死了。驷偃在晋国的大夫那里娶妻,生了丝,年幼。他的父辈兄辈立了驷乞做继承人。子产讨厌驷乞的为人,而且认为不合继承法规,不答应,也不制止。驷氏害怕。过了几天,丝把情况告诉了他舅父。冬季,晋国的大夫派人带了财礼来到郑国,询问立驷乞的缘故。驷氏害怕,驷乞想要逃走,子产不让走;请求用龟甲占卜,也不给。大夫们商量如何回答晋国,子产不等他们商量好就回答客人说:“郑国不能得到上天保佑,寡君的几个臣下不幸夭折病死。现在又丧失了我们的先大夫偃。他的儿子年幼,他的几位父兄害怕断绝宗主,和族人商量立了年长的亲子。寡君和他的几位大夫说:‘或者上天确实搅乱了这种继承法,我能知道什么呢?’俗话说,‘不要走过动乱人家的门口’,百姓动武作乱,尚且害怕经过那里,而何况敢知道上天所降的动乱?现在大夫将要询问它的原因,寡君确实不敢知道,还有谁知道?平丘的会盟,君王重温过去的盟约说:‘不要有人失职。’如果寡君的几个臣下,其中有去世的,晋国的大夫却要专断地干涉他们的继承人,这是晋国把我们当作边境的县城了,还成什么国家?”辞谢客人的财礼而回报他的使者,晋国人对这件事不再过问了。 +楚国人在州来筑城,沈尹戌说:“楚国人一定失败。过去吴国灭亡州来,子旗请求攻打吴国。君王说:‘我没有安抚好我的百姓。’现在也像当时一样,而又在州来筑城去挑动吴国,能够不失败吗?”侍者说:“君王施舍从不厌倦,让百姓休息五年,可以说安抚他们了。”沈尹戌说:“我听说安抚百姓,在国内节约开支,在国外树立德行,百姓生活安乐,而没有仇敌。现在宫室的规模没有限度,百姓时刻惊恐不安,辛劳疲乏至死还没有人收葬,忘掉了睡觉和吃饭,这不是安抚他们。” +郑国发生大水灾,有龙在时门外边的洧渊争斗,国内的人们请求举行禳灾求福的祭祀。子产不答应,说:“我们争斗,龙不看,龙争斗,我们为什么偏要去看呢?向它们祭祀祈祷,那洧渊本来是龙居住的地方,岂能使它们离开呢?我们对龙没有要求,龙对我们也没有要求。”于是就停止了祭祀。 +令尹子瑕为蹶由对楚平王说:“他有什么罪?俗话所说‘在家里发怒,而在大街上给人脸色看’,说的就是楚国了。舍弃以前的怨愤可以了。”楚平王就把蹶由放回了吴国。 + +昭公二十年 +【经】二十年春王正月。夏,曹公孙会自鄸出奔宋。秋,盗杀卫侯之兄絷。冬十月,宋华亥、向宁、华定出奔陈。十有一月辛卯,蔡侯卢卒。 +【传】二十年春,王二月己丑,日南至。梓慎望氛曰:“今兹宋有乱,国几亡,三年而后弭。蔡有大丧。”叔孙昭子曰:“然则戴、桓也!汏侈无礼已甚,乱所在也。” +费无极言于楚子曰:“建与伍奢将以方城之外叛。自以为犹宋、郑也,齐、晋又交辅之,将以害楚。其事集矣。”王信之,问伍奢。伍奢对曰:“君一过多矣,何言于谗?”王执伍奢。使城父司马奋扬杀大子,未至,而使遣之。三月,大子建奔宋。王召奋扬,奋扬使城父人执己以至。王曰:“言出于余口,入于尔耳,谁告建也?”对曰:“臣告之。君王命臣曰:‘事建如事余。’臣不佞,不能苟贰。奉初以还,不忍后命,故遣之。既而悔之,亦无及已。”王曰:“而敢来,何也?”对曰:“使而失命,召而不来,是再奸也。逃无所入。”王曰:“归。”从政如他日。 +无极曰:“奢之子材,若在吴,必忧楚国,盍以免其父召之。彼仁,必来。不然,将为患。”王使召之,曰:“来,吾免而父。”棠君尚谓其弟员曰:“尔适吴,我将归死。吾知不逮,我能死,尔能报。闻免父之命,不可以莫之奔也;亲戚为戮,不可以莫之报也。奔死免父,孝也;度功而行,仁也;择任而往,知也;知死不辟,勇也。父不可弃,名不可废,尔其勉之,相从为愈。”伍尚归。奢闻员不来,曰:“楚君、大夫其旰食乎!”楚人皆杀之。 +员如吴,言伐楚之利于州于。公子光曰:“是宗为戮而欲反其仇,不可从也。”员曰:“彼将有他志。余姑为之求士,而鄙以待之。”乃见鱄设诸焉,而耕于鄙。 +宋元公无信多私,而恶华、向。华定、华亥与向宁谋曰:“亡愈于死,先诸?”华亥伪有疾,以诱群公子。公子问之,则执之。夏六月丙申,杀公子寅、公子御戎、公子朱、公子固、公孙援、公孙丁、拘向胜、向行于其廪。公如华氏请焉,弗许,遂劫之。癸卯,取大子栾与母弟辰、公子地以为质。公亦取华亥之子无戚、向宁之子罗、华定之子启,与华氏盟,以为质。 +卫公孟絷狎齐豹,夺之司寇与鄄,有役则反之,无则取之。公孟恶北宫喜、褚师圃,欲去之。公子朝通于襄夫人宣姜,惧,而欲以作乱。故齐豹、北宫喜、褚师圃、公子朝作乱。 +初,齐豹见宗鲁于公孟,为骖乘焉。将作乱,而谓之曰:“公孟之不善,子所知也。勿与乘,吾将杀之。”对曰:“吾由子事公孟,子假吾名焉,故不吾远也。虽其不善,吾亦知之。抑以利故,不能去,是吾过也。今闻难而逃,是僭子也。子行事乎,吾将死之,以周事子,而归死于公孟,其可也。” +丙辰,卫侯在平寿,公孟有事于盖获之门外,齐子氏帷于门外而伏甲焉。使祝蛙置戈于车薪以当门,使一乘从公孟以出。使华齐御公孟,宗鲁骖乘。及闳中,齐氏用戈击公孟,宗鲁以背蔽之,断肱,以中公孟之肩,皆杀之。 +公闻乱,乘,驱自阅门入,庆比御公,公南楚骖乘,使华寅乘贰车。及公宫,鸿魋驷乘于公,公载宝以出。褚师子申遇公于马路之衢,遂从。过齐氏,使华寅肉袒,执盖以当其阙。齐氏射公,中南楚之背,公遂出。寅闭郭门,逾而从公。公如死鸟,析朱锄宵从窦出,徒行从公。 +齐侯使公孙青聘于卫。既出,闻卫乱,使请所聘。公曰:“犹在竟内,则卫君也。”乃将事焉。遂从诸死鸟,请将事。辞曰:“亡人不佞,失守社稷,越在草莽,吾子无所辱君命。”宾曰:“寡君命下臣于朝,曰:‘阿下执事。’臣不敢贰。”主人曰:“君若惠顾先君之好,昭临敝邑,镇抚其社稷,则有宗祧在。”乃止。卫侯固请见之,不获命,以其良马见,为未致使故也。卫侯以为乘马。宾将掫,主人辞曰:“亡人之忧,不可以及吾子。草莽之中,不足以辱从者。敢辞。”宾曰:“寡君之下臣,君之牧圉也。若不获扞外役,是不有寡君也。臣惧不免于戾,请以除死。”亲执铎,终夕与于燎。 +齐氏之宰渠子召北宫子。北宫氏之宰不与闻谋,杀渠子,遂伐齐氏,灭之。丁巳晦,公入,与北宫喜盟于彭水之上。秋七月戊午朔,遂盟国人。八月辛亥,公子朝、褚师圃、子玉霄、子高鲂出奔晋。闰月戊辰,杀宣姜。卫侯赐北宫喜谥曰贞子,赐析朱锄谥曰成子,而以齐氏之墓予之。 +卫侯告宁于齐,且言子石。齐侯将饮酒,遍赐大夫曰:“二三子之教也。”苑何忌辞,曰:“与于青之赏,必及于其罚。在《康诰》曰:‘父子兄弟,罪不相及。’况在群臣?臣敢贪君赐以干先王?” +琴张闻宗鲁死,将往吊之。仲尼曰:“齐豹之盗,而孟絷之贼,女何吊焉?君子不食奸,不受乱,不为利疚于回,不以回待人,不盖不义,不犯非礼。” +宋华、向之乱,公子城、公孙忌、乐舍、司马强、向宜、向郑、楚建、郳甲出奔郑。其徒与华氏战于鬼阎,败子城。子城适晋。华亥与其妻必盥而食所质公子者而后食。公与夫人每日必适华氏,食公子而后归。华亥患之,欲归公子。向宁曰:“唯不信,故质其子。若又归之,死无日矣。”公请于华费遂,将攻华氏。对曰:“臣不敢爱死,无乃求去忧而滋长乎!臣是以惧,敢不听命?”公曰:“子死亡有命,余不忍其呴。”冬十月,公杀华、向之质而攻之。戊辰,华、向奔陈,华登奔吴。向宁欲杀大子,华亥曰:“干君而出,又杀其子,其谁纳我?且归之有庸。”使少司寇牼以归,曰:“子之齿长矣,不能事人,以三公子为质,必免。”公子既入,华牼将自门行。公遽见之,执其手曰:“余知而无罪也,入,复而所。” +齐侯疥,遂痁,期而不瘳,诸侯之宾问疾者多在。梁丘据与裔款言于公曰:“吾事鬼神丰,于先君有加矣。今君疾病,为诸侯忧,是祝史之罪也。诸侯不知,其谓我不敬。君盍诛于祝固、史嚣以辞宾?”公说,告晏子。晏子曰:“日宋之盟,屈建问范会之德于赵武。赵武曰:‘夫子之家事治,言于晋国,竭情无私。其祝史祭祀,陈信不愧。其家事无猜,其祝史不祈。’建以语康王,康王曰:‘神人无怨,宜夫子之光辅五君,以为诸侯主也。’”公曰:“据与款谓寡人能事鬼神,故欲诛于祝史。子称是语,何故?”对曰:“若有德之君,外内不废,上下无怨,动无违事,其祝史荐信,无愧心矣。是以鬼神用飨,国受其福,祝史与焉。其所以蕃祉老寿者,为信君使也,其言忠信于鬼神。其适遇淫君,外内颇邪,上下怨疾,动作辟违,从欲厌私。高台深池,撞钟舞女,斩刈民力,输掠其聚,以成其违,不恤后人。暴虐淫从,肆行非度,无所还忌,不思谤讟不惮鬼神,神怒民痛,无悛于心。其祝史荐信,是言罪也。其盖失数美,是矫诬也。进退无辞,则虚以求媚。是以鬼神不飨其国以祸之,祝史与焉。所以夭昏孤疾者,为暴君使也。溲再辕稼鬼神。”公曰:“然则若之何?”对曰:“不可为也:山林之木,衡鹿守之;泽之萑蒲,舟鲛守之;薮之薪蒸,虞候守之。海之盐蜃,祈望守之。县鄙之人,入从其政。逼介之关,暴征其私。承嗣大夫,强易其贿。布常无艺,征敛无度;宫室日更,淫乐不违。内宠之妾,肆夺于市;外宠之臣,僭令于鄙。私欲养求,不给则应。民人苦病,夫妇皆诅。祝有益也,诅亦有损。聊、摄以东,姑、尤以西,其为人也多矣。虽其善祝,岂能胜亿兆人之诅?君若欲诛于祝史,修德而后可。”公说,使有司宽政,毁关,去禁,薄敛,已责。 +十二月,齐侯田于沛,招虞人以弓,不进。公使执之,辞曰:“昔我先君之田也,旃以招大夫,弓以招士,皮冠以招虞人。臣不见皮冠,故不敢进。”乃舍之。仲尼曰:“守道不如守官,君子韪之。” +齐侯至自田,晏子侍于遄台,子犹驰而造焉。公曰:“唯据与我和夫!”晏子对曰:“据亦同也,焉得为和?”公曰:“和与同异乎?”对曰:“异。和如羹焉,水火醯醢盐梅以烹鱼肉,燀之以薪。宰夫和之,齐之以味,济其不及,以泄其过。君子食之,以平其心。君臣亦然。君所谓可而有否焉,臣献其否以成其可。君所谓否而有可焉,臣献其可以去其否。是以政平而不干,民无争心。故《诗》曰:‘亦有和羹,既戒既平。鬷嘏无言,时靡有争。’先王之济五味,和五声也,以平其心,成其政也。声亦如味,一气,二体,三类,四物,五声,六律,七音,八风,九歌,以相成也。清浊,小大,短长,疾徐,哀乐,刚柔,迟速,高下,出入,周疏,以相济也。君子听之,以平其心。心平,德和。故《诗》曰:‘德音不瑕。’今据不然。君所谓可,据亦曰可;君所谓否,据亦曰否。若以水济水,谁能食之?若琴瑟之专一,谁能听之?同之不可也如是。” +饮酒乐。公曰:“古而无死,其乐若何?”晏子对曰:“古而无死,则古之乐也,君何得焉?昔爽鸠氏始居此地,季萴因之,有逢伯陵因之,蒲姑氏因之,而后大公因之。古者无死,爽鸠氏之乐,非君所愿也。” +郑子产有疾,谓子大叔曰:“我死,子必为政。唯有德者能以宽服民,其次莫如猛。夫火烈,民望而畏之,故鲜死焉。水懦弱,民狎而玩之,则多死焉。故宽难。”疾数月而卒。大叔为政,不忍猛而宽。郑国多盗,取人于萑苻之泽。大叔悔之,曰:“吾早从夫子,不及此。”兴徒兵以攻萑苻之盗,尽杀之,盗少止。 +仲尼曰:“善哉!政宽则民慢,慢则纠之以猛。猛则民残,残则施之以宽。宽以济猛,猛以济宽,政是以和。《诗》曰:‘民亦劳止,汔可小康。惠此中国,以绥四方。’施之以宽也。‘毋从诡随,以谨无良。式遏寇虐,惨不畏明。’纠之以猛也。‘柔远能迩,以定我王。’平之以和也。又曰:‘不竞不絿,不刚不柔。布政优优,百禄是遒。’和之至也。” +及子产卒,仲尼闻之,出涕曰:“古之遗爱也。” +译文 +二十年春季,周王朝历法的二月初一日,冬至。梓慎观察云气,说:“今年宋国有动乱,国家几乎灭亡,三年以后才平定。蔡国有大的丧事。”叔孙昭子说:“这就是戴、桓两族了,他们奢侈、无礼到了极点,动乱会发生在他们那里。” +费无极对楚平王说:“太子建和伍奢将要领着方城山外的人背叛,自以为如同宋国、郑国一样,齐国、晋国又一起辅助他们,将会危害楚国,这事情快成功了。”楚平王相信了这些话,质问伍奢。伍奢回答说:“君王有一次过错已经很严重了,为什么还听信谗言?”楚平王逮捕了伍奢,派城父司马奋扬去杀太子。奋扬没有到达,派人通知太子逃走。三月,太子建逃亡到宋国。楚平王召回奋扬,奋扬让城父大夫逮捕自己回到郢都。楚平王说:“话从我的嘴里说出去,进到你的耳朵里,是谁告诉建的?”奋扬回答说:“是下臣告诉他的。君王命令我说:‘事奉建要像事奉我一样。’下臣不才,不能或有二心。奉了起初的命令去对待太子,就不忍心执行您后来的命令。所以要他逃走了。不久我后悔,也来不及了。”楚平王说:“你敢回来,为什么?”奋扬回答说:“被派遣而没有完成使命,召见我又不回来,这是再次违背命令,逃走也没有地方可去。”楚平王说:“回城父去吧!”奋扬还像过去一样做官。 +费无极说:“伍奢的儿子有才能,如果在吴国,一定要使楚国担忧,何不用赦免他们父亲的办法召回他们。他们仁爱,一定回来。不这样,将要成为祸患。”楚平王派人召回他们,说:“回来,我赦免你们的父亲。”棠邑大夫伍尚对他的兄弟员说:“你去到吴国,我准备回去死。我的才智不如你,我能够死,你能够报仇。听到赦免父亲的命令,不能不奔走回去。亲人被杀戮,不能不报仇。奔走回去使父亲赦免,这是孝。估计功效而后行动,这是选择任务而前去,这是智。明知要死而不躲避,这是勇。父亲不能丢掉,名誉不能废弃,你还是努力吧!各人不必勉强为好。”伍尚回去。伍奢听说伍员不来,说:“楚国的国君、大夫恐怕不能准时吃饭了。”楚国人把他们都杀了。 +伍员去到吴国,向州于说明进攻楚国的利益。公子光说:“是这个家族被杀戮而想要报私仇,不能听他的。”伍员说:“他将要有别的志向,我姑且为他寻求勇士,而在郊外等着他。”于是就推荐了鱄设诸,自己在边境上种地。 +宋元公不讲信用、私心很多,而讨厌华氏、向氏。华定、华亥和向宁策划说:“逃亡比死强,先下手吗?”华亥假装有病,以引诱公子们。凡是公子去探病,就扣押起来。夏季,六月初九,杀死公子寅、公子御戎、公子朱、公子固、公孙援、公孙丁,把向胜、向行囚禁在谷仓里。宋元公到华亥氏那里去请求,华氏不答应,反而要乘机劫持元公。十六日,将太子栾和他的同母兄弟辰、公子地作为人质。元公也取得了华亥的儿子无慼,向宁的儿子罗、华定的儿子启,和华氏结盟,把他们作为人质。 +卫国的公孟絷轻慢齐豹,剥夺了他的司寇官职和鄄地。有战事就让他回去,没事就占取过来。公孟絷讨厌北宫喜、褚师圃,想要去掉他们。公子朝和襄夫人宣姜私通,害怕,想乘机发动祸乱。所以齐豹、北宫喜、褚师圃、公子朝发动了叛乱。 +当初,齐豹把宗鲁推荐给公孟絷,做了骖乘。齐豹将要发动叛乱,对宗鲁说:“公孟这个人不好,这是您所知道的,不要和他一起乘车,我将要杀死他。”宗鲁回答说:“我由于您而事奉公孟絷,您说我有好名声,所以公孟絷才亲近我。虽然他不好,我也知道,但是由于对自己有利,不能离去,这是我的过错。现在听到祸难而逃走,这是使您的话不可相信了。您办您的事吧!我将为此而死,用保密事奉您,回去死在公孟絷那里,也许是可以的。” +六月二十九日,卫灵公正在平寿,公孟絷在盖获之门外祭祀,齐子氏在门外设置帷帐,在里边埋伏甲士。派祝蛙把戈藏在车上的柴禾里挡着城门,派一辆车跟着公孟絷出来。派华齐驾御公孟的坐车,宗鲁做骖乘。到达曲门中,齐氏用戈敲击公孟,宗鲁用背部遮护他,折断了胳臂,戈击中公孟的肩膀。齐氏把他们一起杀死了。 +卫灵公听到动乱的消息,坐上车子,驱车从阅门进入国都。庆比驾车,公南楚做骖乘。派华寅乘坐副车。到达灵公的宫室,鸿駵魋又坐上卫灵公的车子。灵公装载了宝物而出来,褚师子申在马路的十字路口遇到灵公,就跟上去。经过齐氏那里,让华寅光着上身,拿着车盖遮蔽空处。齐氏用箭射卫灵公,射中公南楚的脊背,卫灵公就逃出国都。华寅关闭城门,跳出城墙跟随卫侯。卫灵公去到死鸟。析朱鉏夜里从城墙的排水沟里逃出,徒步跟随卫灵公。 +齐景公派公孙青到卫国聘问。已经走出国境,听说卫国发生了动乱,派人请示关于聘问的事情。齐景公说:“卫侯还在国境之内,就还是卫国的国君。”于是就奉命行事,跟着到了死鸟。公孙青请求按照命令行聘礼。卫灵公辞谢说:“逃亡的人没有才能,失守了国家,流亡在杂草丛中,没有地方可以让您执行君王的命令。”客人说:“寡君在朝廷上命令下臣说:‘卑微地亲附执事。’下臣不敢违命。”主人说:“君王如果照顾到先君的友好,光照敝邑,镇定安抚我们的国家,那么有宗庙在那里。”公孙青就停止了聘问。卫灵公坚决请求见他。公孙青不得已,只好用他的好马作为进见的礼物,这是由于没有行聘礼的缘故。卫灵公把公孙青馈送的马作为驾车的马。客人准备在夜里设置警戒,主人辞谢说:“逃亡人的忧虑,不能落到您身上,杂草丛中的人,不足以劳动您。谨敢辞谢。”客人说:“寡君的下臣,就是君王牧牛放马的人。如果得不到在外面警戒的差役,就是心目中没有寡君了。下臣害怕不能免于罪过,请求以此免死。”就亲自拿着大铃,整晚和卫国的夜巡人在一起。 +齐氏的家臣头子渠子召则北宫喜。北宫喜的家臣头子不让他知道密谋的事,策划杀死了渠子,并乘机攻打齐氏,消灭了他们。六月三十日,卫灵公进入国都,和北宫喜在彭水盟誓。秋季,七月初一,就和国内的人们盟誓。八月二十五日,公子朝、褚师圃、子玉霄、子高鲂逃亡到晋国。闰八月十二日,杀死宣姜。卫灵公赐给北宫喜的谥号叫贞子,赐给析朱鉏的谥号叫成子,而且把齐氏的墓地给了他们。 +卫灵公向齐国报告国内安定,同时述说公孙青的有礼。齐景公将要喝酒,把酒普遍赏赐给大夫们,说:“这是诸位的教导。”苑何忌辞谢不喝,说:“参与了对公孙青的赏赐,必然涉及对他的责罚。在《康诰》上说,‘父子兄弟,罪过互不相干,何况在群臣之间?下臣岂敢贪受君王的赏赐来干犯先王?” +琴张听说宗鲁死了,准备去吊唁。孔子说:“齐豹所以成为坏人,孟絷所以被害,都是由于他的缘故,你为什么要去吊唁呢?君子不吃坏人的俸禄,不接受动乱,不为了利而受到邪恶的侵扰,不用邪恶对待别人,不袒护不义的事情,不做出非礼的事情。” +宋国华氏、向氏的作乱,公子城、公孙忌、乐舍、司马彊、向宜、向郑、楚建郳申逃亡到郑国。他们的党羽和华氏在鬼阎作战,子城被打败。子城去到晋国。 +华亥和他的妻子,一定要盥洗干净、伺候作为人质的公子吃完饭以后才吃饭。宋元公和夫人每天一定到华氏那里,让公子吃完以后才回去,华亥担心这种情况,想要让公子回去。向宁说:“正因为元公没有信用,所以把他的儿子作为人质。如果又让他回去,死就很快来到了。”宋元公向华费遂请求,准备攻打华氏。华费遂回答说:“下臣不敢爱惜一死,恐怕是想要去掉忧虑反而滋长忧虑吧!下臣因此害怕,怎敢不听命令?”宋元公说:“孩子们死了是命中注定,我不能忍受他们受耻辱。”冬季,十月,宋元公杀了华氏、向氏的人质而攻打这两家。十三日,华氏、向氏逃亡到陈国,华登逃亡到吴国。向宁想要杀死太子。华亥说:“触犯了国君而出逃,又杀死他的儿子,还有谁接纳我们?而且放他们回去有功劳。”派少司寇牼带着公子们回去,说:“您的年岁大了,不能再事奉别人。用三个公子作为证明,一定可以免罪。”公子们进入国都,华牼将要从公门出去。宋元公急忙接见他,拉着他的手,说:“我知道你没有罪,进来,恢复你的官职。” +齐景公患了两日一发的疟疾,后来又恶化成每天发一次,一年没有痊愈。诸侯派来问候的客人,大多在齐国。梁丘据和裔款对齐景公说:“我们事奉鬼神很丰厚,比先君已经有所增加了。现在君王病得很厉害,成为诸侯的忧虑,这是祝、史的罪过。诸侯不了解,恐怕要认为我们不敬鬼神,君王何不诛戮祝固、史嚚以辞谢客人?”齐景公很高兴,告诉晏子。晏子说:“从前在宋国的盟会,屈建向赵武询问范会的德行。赵武说:‘他老人家家族中的事务井然有序,在晋国说话,竭尽自己的心意而没有个人打算。他的祝、史祭祀,向鬼神陈说实际情况不内愧。他的家族中没有可猜疑的事情,所以他的祝、史也不向鬼神祈求。’屈建把这些话告诉康王。康王说:‘神和人都没有怨恨,他老人家所以能够辅助五位国君而作为诸侯的主人就是很相宜的了。’”齐景公说:“据和款认为寡人能够事奉鬼神,所以要诛戮祝、史,您提出这些话,是什么缘故?”晏子回答说:“如果是有德行的君主,国家和宫里的事情都没有荒废,上下没有怨恨,举动没有违背礼仪的事,他的祝、史向鬼神陈述实际情况,就没有惭愧的心了。所以鬼神享用祭品,国家受到鬼神所降的福禄,祝、史也有一份。他们所以繁衍有福、健康长寿,由于是诚实的国君的使者,他们的话忠诚信实。他们如果恰好碰上放纵的国君,里外偏颇邪恶,上下怨恨嫉妒,举动邪僻背理,放纵欲望满足私心,高台深池,奏乐歌舞,砍伐民力,掠夺百姓的积蓄,以这些行为铸成过错,而不体恤后代,暴虐放纵,随意行动没有法度,无所顾忌,不考虑怨谤,不害怕鬼神。天怒人怨,在心里还不肯改悔。他的祝、史陈说实际情况,这是报告国君的罪过。他们掩盖过错、专谈好事,这是虚诈欺骗,真假都不能陈述,只好陈述不相干的空话来向鬼神讨好,所以鬼神不享用他们国家的祭品,还让它发生祸难,祝、史也有一份。他们所以夭折患病,由于是暴虐的国君的使者,他们的话对鬼神欺诈轻侮。”齐景公说:“那末怎么办?”晏子回答说:“没法办了。山林中的树木,由守山林的人看守它。洼地里的芦苇,舟鲛看守它。草野中的柴禾,虞侯看守它。大海中的盐蛤,祈望看守它。偏僻地方的人,进来管理政事。邻近国都的关卡,横征暴敛,世袭的大夫,强买货物。发布政令没有准则,征收赋税没有节制,宫室每天轮换着住,荒淫作乐不肯离开。宫内的宠妾,在市场上肆意掠夺,外边的宠臣,在边境上假传圣旨。奉养自己、追求玩好这些私欲,下边不能满足就立即治罪。百姓痛苦困乏,丈夫妻子都在诅咒。祝祷有好处,诅咒也有害处。聊地、摄地以东,姑水、尤水以西,人口多得很呢。虽然祝史善于祝祷,难道能胜过亿兆人的诅咒?君王如果要诛戮祝,史,只有修养德行然后才可以。”齐景公很高兴,让官吏放宽政令,毁掉关卡,废除禁令,减轻赋税,免除对官府所欠的债务。 +十二月,齐景公在沛地打猎,用弓招唤虞人,虞人没有来。齐景公派人扣押了他,虞人辩解说:“从前我们先君打猎的时候,用红旗招唤大夫,用弓招唤士,用皮冠招唤虞人。下臣没有见到皮冠,所以不敢进见。”齐景公于是就释放了虞人。孔子说:“遵守道义,不如遵守官制。”君子认为说得对。 +齐景公从打猎的地方回来,晏子在遄台侍候,梁丘据驱车来到。齐景公说:“惟有据与我和谐啊!”晏子回答说:“据也只不过相同而已,哪里说得上和谐?”齐景公说:“和谐跟相同不一样吗?”晏子回答说:“不一样。和协好像做羹汤,用水、火、醋、酱、盐、梅来烹调鱼和肉,用柴禾烧煮,厨工加以调和,使味道适中,味道太淡就增加调料,味道太浓就加水冲淡。君子喝汤,内心平静。君臣之间也是这样。国君所认为行而其中有不行的,臣下指出它的不行的而使行的部分更加完备。国君所认为不行而其中有行的,臣下指出它的行的部分而去掉它的不行,因此政事平和而不肯违背礼仪,百姓没有争夺之心。所以《诗》说:‘有着调和的羹汤,已经告诫厨工把味道调得匀净。神灵来享而无所指责,上下也都没有争竞。’先王调匀五味、谐和五声,是用来平静他的内心,完成政事的。声音也像味道一样,是由一气、二体、三类、四物、五声、六律、七音、八风、九歌互相组成的。是由清浊、大小、短长、缓急、哀乐、刚柔、快慢、高低、出入、疏密互相调节的。君子听了,内心平静。内心平静,德行就和协。所以《诗》说‘德音没有缺失’。现在据不是这样。国君认为行的,据也认为行。国君认为不行的,据也认为不行。如同用清水去调剂清水,谁能吃它呢?如同琴瑟老弹一个音调,谁去听它呢?不应该相同的道理就像这样。” +喝酒喝得很高兴。齐景公说:“从古以来如果没有死,它的欢乐会怎么样啊!”晏子回答说:“从古以来如果没有死,现在的欢乐就是古代人的欢乐了,君王能得到什么呢?从前爽鸠氏开始居住在这里,季萴沿袭下来,有逢伯陵沿袭下来,蒲姑氏因袭下来,然后太公沿袭下来。从古以来如果没有死,那是爽鸠氏的欢乐,并不是君王所希望的啊。” +郑国的子产有病,对子太叔说:“我死以后,您必定执政。只有有德行的人能够用宽大来使百姓服从,其次就莫如严厉。火势猛烈,百姓看着就害怕,所以很少有人死于火。水性懦弱,百姓轻视并玩弄它,很多人就死在水中。所以宽大不容易。”子产病了几个月就死去了。子太叔执政,不忍心严厉却奉行宽大政策。郑国盗贼很多,聚集在芦苇塘里。太叔后悔,说:“我早点听从他老人家的话,就不至于到这一步。”发动徒兵攻打藏在芦苇丛生的湖泽里的盗贼,全部杀死他们,盗贼稍稍收敛了一些。 +孔子说:“好啊!政事宽大百姓就怠慢,怠慢就用严厉来纠正。严厉百姓就受到伤害,伤害就实施宽大。用宽大调节严厉,用严厉调节宽大,因此政事调和。《诗》说,‘百姓已经很辛劳,差不多可以稍稍安康。赐恩给中原各国,用以安定四方’,这是实施宽大。‘不要放纵随声附和的人,以约束不良之人。应当制止侵夺残暴的人,他们从来不怕法度’,这是用严厉来纠正。‘安抚边远,柔服近邦,用来安定我国王’,这是用和平来安定国家。又说,‘不争强不急躁,不刚猛不柔弱。施政平和宽裕,各种福禄都聚集’,这是和谐的顶点。” +等到子产死去,孔子听到这消息,流着眼泪,说:“他的仁爱,是古人流传下来的遗风啊。” + +昭公二十一年 +【经】二十有一年春王三月,葬蔡平公。夏,晋侯使士鞅来聘。宋华亥、向宁、华定自陈入于宋南里以叛。秋七月壬午朔,日有食之。八月乙亥,叔辄卒。冬,蔡侯朱出奔楚。公如晋,至河乃复。 +【传】二十一年春,天王将铸无射。泠州鸠曰:“王其以心疾死乎?夫乐,天子之职也。夫音,乐之舆也。而钟,音之器也。天子省风以作乐,器以钟之,舆以行之。小者不窕,大者不□瓠,则和于物,物和则嘉成。故和声入于耳而藏于心,心亿则乐。窕则不咸,总则不容,心是以感,感实生疾。今钟□瓠矣,王心弗堪,其能久乎?” +三月,葬蔡平公。蔡大子朱失位,位在卑。大夫送葬者归,见昭子。昭子问蔡故,以告。昭子叹曰:“蔡其亡乎!若不亡,是君也必不终。《诗》曰:‘不解于位,民之攸塈。’今蔡侯始即位,而适卑,身将从之。” +夏,晋士鞅来聘,叔孙为政。季孙欲恶诸晋,使有司以齐鲍国归费之礼为士鞅。士鞅怒,曰:“鲍国之位下,其国小,而使鞅从其牢礼,是卑敝邑也。将复诸寡君。”鲁人恐,加四牢焉,为十一牢。 +宋华费遂生华貙、华多僚、华登。貙为少司马,多僚为御士,与貙相恶,乃谮诸公曰:“貙将纳亡人。”亟言之。公曰:“司马以吾故,亡其良子。死亡有命,吾不可以再亡之。”对曰:“君若爱司马,则如亡。死如可逃,何远之有?”公惧,使侍人召司马之侍人宜僚,饮之酒而使告司马。司马叹曰:“必多僚也。吾有谗子而弗能杀,吾又不死,抑君有命,可若何?”乃与公谋逐华貙,将使田孟诸而遣之。公饮之酒,厚酬之,赐及从者。司马亦如之。张丐尤之,曰:“必有故。”使子皮承宜僚以剑而讯之。宜僚尽以告。张丐欲杀多僚,子皮曰:“司马老矣,登之谓甚,吾又重之,不如亡也。”五月丙申,子皮将见司马而行,则遇多僚御司马而朝。张丐不胜其怒,遂与子皮、臼任、郑翩杀多僚,劫司马以叛,而召亡人。壬寅,华、向入。乐大心、丰愆、华牼御诸横。华氏居卢门,以南里叛。六月庚午,宋城旧鄘及桑林之门而守之。 +秋七月壬午朔,日有食之。公问于梓慎曰:“是何物也,祸福何为?”对曰:“二至、二分,日有食之,不为灾。日月之行也,分,同道也;至,相过也。其他月则为灾,阳不克也,故常为水。” +于是叔辄哭日食。昭子曰:“子叔将死,非所哭也。”八月,叔辄卒。 +冬十月,华登以吴师救华氏。齐乌枝鸣戍宋。厨人濮曰:“《军志》有之:‘先人有夺人之心,后人有待其衰。’盍及其劳且未定也伐诸?若入而固,则华氏众矣,悔无及也。”从之。丙寅,齐师、宋师败吴师于鸿口,获其二帅公子苦雂、偃州员。华登帅其馀以败宋师。公欲出,厨人濮曰:“吾小人,可藉死而不能送亡,君请待之。”乃徇曰:“杨徽者,公徒也。”众从之。公自杨门见之,下而巡之,曰:“国亡君死,二三子之耻也,岂专孤之罪也?”齐乌枝鸣曰:“用少莫如齐致死,齐致死莫如去备。彼多兵矣,请皆用剑。”从之。华氏北,复即之。厨人濮以裳裹首而荷以走,曰:“得华登矣!”遂败华氏于新里。翟偻新居于新里,既战,说甲于公而归。华妵居于公里,亦如之。 +十一月癸未,公子城以晋师至。曹翰胡会晋荀吴、齐苑何忌、卫公子朝救宋。丙戌,与华氏战于赭丘。郑翩愿为鹳,其御愿为鹅。子禄御公子城,庄堇为右。干犨御吕封人华豹,张丐为右。相遇,城还。华豹曰:“城也!”城怒而反之,将注,豹则关矣。曰:“平公之灵,尚辅相余。”豹射,出其间。将注,则又关矣。曰:“不狎,鄙!”押矢。城射之,殪。张丐抽殳而下,射之,折股。扶伏而击之,折轸。又射之,死。干丐请一矢,城曰:“余言汝于君。”对曰:“不死伍乘,军之大刑也。干刑而从子,君焉用之?子速诸。”乃射之,殪。大败华氏,围诸南里。华亥搏膺而呼,见华貙,曰:“吾为栾氏矣。”貙曰:“子无我迋。不幸而后亡。”使华登如楚乞师。华貙以车十五乘,徒七十人,犯师而出,食于睢上,哭而送之,乃复入。楚薳越帅师将逆华氏。大宰犯谏曰:“诸侯唯宋事其君,今又争国,释君而臣是助,无乃不可乎?”王曰:“而告我也后,既许之矣。” +蔡侯朱出奔楚。费无极取货于东国,而谓蔡人曰:“朱不用命于楚,君王将立东国。若不先从王欲,楚必围蔡。”蔡人惧,出朱而立东国。朱诉于楚,楚子将讨蔡。无极曰:“平侯与楚有盟,故封。其子有二心,故废之。灵王杀隐大子,其子与君同恶,德君必甚。又使立之,不亦可乎?且废置在君,蔡无他矣。”公如晋,及河,鼓叛晋。晋将伐鲜虞,故辞公。 +译文 +二十一年春季,周景王准备铸造无射大钟。泠州鸠说:“天子大概会由于心病而死去吧!音乐,是天子所主持的。声音,是音乐的车床,而钟,是发音的器物。天子考察风俗因而制作乐曲,用乐器来汇聚它,用声音来表达它,小的乐器发音不纤细,大的乐器发音不洪亮,那样就使一切事物和谐。一切事物和谐,美好的音乐才能完成。所以和谐的声音进入耳朵而藏在心里,心安就快乐。纤细就不能让四处都听到,洪亮就不能忍受,内心因此感到不安,不安就会生病。现在钟声粗大,天子的内心受不住,难道能够长久吗?” +三月,安葬蔡平公。蔡国的太子朱没有站在葬礼中应站的位置上,站在下面。大夫中送葬的回来,进见昭子。昭子问蔡国葬礼的事情,送葬的大夫就把当时的情况告诉昭子,昭子叹气说:“蔡国大约要灭亡了吧!如果不灭亡,这个国君一定不得好死。《诗》说:‘在他的地位上不懈怠,百姓就能够休息。’现在蔡侯刚刚即位就站到下面去,他自己也将会跟着跨下去的。” +夏季,晋国的士鞅前来聘问,叔孙主持接待。季孙存心得罪晋国,让官吏用齐国的鲍国回费地的礼节招待士鞅。士鞅发怒,说:“鲍国的地位低,他的国家小,现在让我接受招待他所用七牢的礼节,这是轻视敝邑,我将要向寡君报告。”鲁国人恐惧,增加四牢,使用了十一牢。 +宋国的华费遂生了华貙、华多僚、华登。华貙做少司马,华多僚做御士,与华貙不和,就在宋公面前诬陷说:“华貙打算接纳逃亡的人。”屡次说这些话,宋元公说:“司马由于我的缘故,使他的儿子逃亡。死和逃亡都是命中注定,我不能让他的儿子再逃亡。”华多僚回答说:“君王如果爱惜司马,就应当逃亡。死如果可以逃避,哪有什么远不远?”宋元公害怕,让侍者召来司马的侍者宜僚,给他酒喝,让他告诉司马驱逐华貙。司马叹气说:“一定是多僚干的。我有一个造谣的儿子而不能杀死他,我又不死,国君有了命令,怎么办?”就和宋元公商量驱逐华貙,准备让他在孟诸打猎时打发他走。宋元公给他酒喝,厚厚地送给他礼物,还赏赐随行的人。司马也像宋元公一样,张匄感到奇怪,说:“一定有原因。”让华貙用剑架在宜僚脖子上追问他,宜僚把话全说出来,张匄想要杀死多僚,华貙说:“司马年老了,华登的逃亡已经很伤他的心,我又加重了他的伤心,不如逃亡。”五月十四日,华貙准备进见司马以后再走。在朝廷上遇见多僚为司马驾车上朝,张牼不能控制自己的愤怒,就和华貙、臼任、郑翩杀了多僚,劫持了司马叛变,召集逃亡的人。二十日,华氏、向氏回来,乐大心。丰愆、华貙在横地抵御他们。华氏住在卢门,领着南里的人叛变。六月十九日,宋国修缮旧城和桑林之门用以据守。 +秋季,七月初一,发生日食。鲁昭公问梓慎说:“这是什么事?是什么样的祸福?”梓慎回答说:“冬至夏至、春分秋分,发生日食,不是灾祸。日月的运行,在春分秋分的时候,黄道和赤道交点相同;在夏至冬至的时候,相交点远。其他的月分就要发生灾祸,因为阳气不胜,所以常常发生水灾。”在那个时候叔辄因为发生日食号哭,昭子说:“叔辄快死了,因为这不是他所应该哭的事情。”八月,叔辄死了。   +冬季,十月,华登率领吴军救援华氏,齐国的乌枝鸣在宋国戍守,厨邑大夫濮说:“《军志》有这样的话:‘先发制人可以摧毁敌人士气,后发制人要等到敌人士气衰竭。’何不乘他们疲劳和没有安定而进攻?如果敌人已经进来而军心安定,华氏的人就多了,我们就后悔不及了。”乌枝鸣听从了。十七日,齐军、宋军在鸿口击败吴军,俘虏了他们两个将领公子苦雂、偃州员。华登率领余部击败宋军。宋元公想要逃亡,厨邑大夫濮说:“我是小人,可以为君王死难,而不能护送君王逃亡,请君王等待一下。”于是就巡行全军说:“挥舞旗帜的,是国君的战士。”众人按他的话挥舞旗帜,宋元公在扬门上见到这种情况,下城巡视,说:“国家亡,国君死,这是各位的耻辱,岂独是我一人的罪过呢?”齐国的乌枝鸣说:“使用少量的兵力,最好是一起拼命,一起拼命,最好是撤去守备。他们的武器多得很,建议我军都用剑和他们作战。”宋公听从了。华氏败走,宋军、齐军又追上去,厨邑大夫濮用裙子包着砍下的脑袋,扛在肩上快跑,说:“杀死华登了!”于是就在新里打败了华氏,翟偻新住在新里,战斗开始以后,到宋元公那里脱下盔甲而归附。华妵住在公里,也像翟偻新一样。 +十一月初四日,公子城带着晋军来到,曹国翰胡会合晋国荀吴、齐国苑何忌、卫国公子朝救援宋国,初七日,和华氏在赭丘作战,郑翩希望摆成鹳阵,他的御者希望摆成鹅阵,子禄为公子城驾御战车,庄堇作为车右,干犫为吕地封人华豹驾御战车,张匄作为车右。两车相遇,公子城退了回去,华豹大喊说:“城啊!”公子城发怒,转回来,将要装上箭,而华豹已经拉开了弓。公子城说:“平公的威灵,还在保佑我!”华豹射箭,穿过公子城和子禄之间,公子城又要装上箭,华豹又已经拉开了弓,公子城说:“不让我还手,卑鄙啊!”华豹从弓上抽下箭,公子城一箭射去,把华豹射死,张匄抽出殳下车,公子城一箭射去,射断张匄的腿,张匄爬过来用殳敲断了公子城的车轸,公子城又发了一箭,张匄死去,干犫请求给他一箭,公子城说:“我替你向国君说情。”干犫回答说:“不和战友一起战死,这是犯了军队中的大法,犯了法而跟从您,君王哪里用得着我?您快点吧!”于是公子城就射了他一箭,射死了,宋军、齐军把华氏打得大败,包围南里,华亥拍着胸脯大喊,进见华貙,说:“我们成了晋国的栾氏了。”华貙说:“您不要吓唬我,碰上倒霉才会死呢。”派华登到楚国请求出兵,华貙带领战车十五辆,步兵七十人突围而出,在睢水岸边吃饭,哭着送走华登,就再次冲进包围圈。楚国的薳越率领军队打算迎接华氏,太宰犯劝谏说:“诸侯之中惟有宋国的臣下还事奉着国君,现在又争夺国政,丢开国君而帮助臣下,恐怕不可以吧!”楚平王说:“我对你说晚了,已经答应他们了。” +蔡侯朱逃亡到楚国。费无极得到东国的财礼,对蔡国人说:“朱不听楚国的命令,君王将要立东国做国君,如果不先顺从君王的愿望,楚国一定包围蔡国。”蔡国人害怕,赶走朱而立了东国,朱向楚国控诉,楚平王准备讨伐蔡国。费无极说:“蔡平侯和楚国有盟约,所以封他,他的儿子有二心,所以废掉他。灵王杀了隐太子,隐太子的儿子和君王有共同的仇人,一定会感谢君王。现在又让他立为国君,不也是可以的吗?而且废、立的权操在君王手里,蔡国就不会有别的念头了。” +昭公去到晋国,到达黄河。鼓地背叛晋国,晋国准备进攻鲜虞,所以辞谢了昭公。 + + +昭公二十二年 +【经】二十有二年春,齐侯伐莒。宋华亥、向宁、华定自宋南里出奔楚。大蒐于昌间。夏四月乙丑,天王崩。六月,叔鞅如京师,葬景王,王室乱。刘子、单子以王猛居于皇。秋,刘子、单子以王猛入于王城。冬十月,王子猛卒。十有二月癸酉朔,日有食之。 +【传】二十二年春,王二月甲子,齐北郭启帅师伐莒。莒子将战,苑羊牧之谏曰:“齐帅贱,其求不多,不如下之。大国不可怒也。”弗听,败齐师于寿余。齐侯伐莒,莒子行成。司马灶如莒莅盟,莒子如齐莅盟,盟子稷门之外。莒于是乎大恶其君。 +楚薳越使告于宋曰:“寡君闻君有不令之臣为君忧,无宁以为宗羞?寡君请受而戮之。”对曰:“孤不佞,不能媚于父兄,以为君忧,拜命之辱。抑君臣日战,君曰‘余必臣是助’,亦唯命。人有言曰:‘唯乱门之无过’。君若惠保敝邑,无亢不衷,以奖乱人,孤之望也。唯君图之!”楚人患之。诸侯之戍谋曰:“若华氏知困而致死,楚耻无功而疾战,非吾利也。不如出之,以为楚功,其亦能无为也已。救宋而除其害,又何求?”乃固请出之。宋人从之。己巳,宋华亥、向宁、华定、华貙、华登、皇奄伤、省臧,士平出奔楚。宋公使公孙忌为大司马,边卬为大司徒,乐祁为司马,仲几为左师,乐大心为右师,乐挽为大司寇,以靖国人。 +王子朝、宾起有宠于景王,王与宾孟说之,欲立之。刘献公之庶子伯蚡事单穆公,恶宾孟之为人也,愿杀之。又恶王子朝之言,以为乱,愿去之。宾孟适郊,见雄鸡自断其尾。问之,侍者曰:“自惮其牺也。”遽归告王,且曰:“鸡其惮为人用乎?人异于是。牺者,实用人,人牺实难,己牺何害?”王弗应。 +夏四月,王田北山,使公卿皆从,将杀单子、刘子。王有心疾,乙丑,崩于荣錡氏。戊辰,刘子挚卒,无子,单子立刘。五月庚辰,见王,遂攻宾起,杀之,盟群王子于单氏。 +晋之取鼓也,既献,而反鼓子焉,又叛于鲜虞。 +六月,荀吴略东阳,使师伪籴负甲以息于昔阳之门外,遂袭鼓,灭之。以鼓子鸢鞮归,使涉佗守之。 +丁巳,葬景王。王子朝因旧官、百工之丧职秩者,与灵、景之族以作乱。帅郊、要、饯之甲,以逐刘子。壬戌、刘子奔扬。单子逆悼王于庄宫以归。王子还夜取王以如庄宫。癸亥,单子出。王子还与召庄公谋,曰:“不杀单旗,不捷。与之重盟,必来。背盟而克者多矣。”从之。樊顷子曰:“非言也,必不克。”遂奉王以追单子。及领,大盟而复,杀挚荒以说。刘子如刘,单子亡。乙丑,奔于平畤,群王子追之。单子杀还、姑、发、弱、鬷延、定、稠,子朝奔京。丙寅,伐之,京人奔山。刘子入于王城。辛未,巩简公败绩于京。乙亥,甘平公亦败焉。叔鞅至自京师,言王室之乱也。闵马父曰:“子朝必不克,其所与者,天所废也。”单子欲告急于晋,秋七月戊寅,以王如平畤,遂如圃车,次于皇。刘子如刘。单子使王子处守于王城,盟百工于平宫。辛卯,鄩肸伐皇,大败,获鄩肸。壬辰,焚诸王城之市。八月辛酉,司徒丑以王师败绩于前城,百工叛。己巳,伐单氏之宫,败焉。庚午,反伐之。辛未,伐东圉。冬十月丁巳,晋籍谈、荀跞帅九州之戎及焦、瑕、温、原之师,以纳王于王城。庚申,单子、刘蚡以王师败绩于郊,前城人败陆浑于社。十一月乙酉,王子猛卒,不成丧也。已丑,敬王即位,馆于子族氏。 +十二月庚戌,晋籍谈、荀跞、贾辛、司马督帅师军于阴,于侯氏,于溪泉,次于社。王师军于泛,于解,次于任人。闰月,晋箕遗、乐征,右行诡济师,取前城,军其东南。王师军于京楚。辛丑,伐京,毁其西南。 +译文 +二十二年春季,周王朝历法的二月十六日,齐国的北郭启领兵进攻莒国。莒子将要迎战,苑羊牧之劝谏说:“齐国的元帅地位低下,他的要求不多,不如向他低头,大国是不能激怒的。”莒子不听,在寿馀打败了齐军。齐景公又亲自领兵进攻莒国,莒子求和。司马灶到莒国参加结盟,莒子到齐国参加结盟,在稷门外边盟誓。莒国人因此而大大地讨厌他们的国君。 +楚国的薳越派人告诉宋国说:“寡君听说君王有不好的臣下使君王忧虑,恐怕成为宗庙的羞耻,寡君请求接受下来加以诛戮。”宋元公回答说:“孤没有才能,不能取得父兄的欢心,因此成为君王的忧虑,承蒙君王下达命令。君臣之间每天作战,如果君王说:‘我一定帮助臣下’,也只能唯命是听,人们有话说:‘不要经过动乱人家的门口。”君王如果赐恩保护敝邑,不去保护不忠,以奖励作乱的人,这是孤的愿望,请君王考虑一下。”楚国人担心这件事,诸侯派往宋国戌守的将领商量说:“如果华氏感到没有前途而拼命战斗,楚国由于不见功效而很快出兵作战,这于我们不利,不如让他们出去,以成就楚国的功绩,华氏也不能有所作为了,救援了宋国而除掉了他们的祸害,还有什么要求呢?”于是坚决请求放出华氏,宋国人听从了。二月二十一日,宋国的华亥、向宁、华定、华貙、华登、皇奄伤、省臧、士平逃亡楚国。宋元公派公孙忌做大司马,边卬做大司徒,乐祁做司城,仲几做左师,乐大心做右师,乐輓做大司寇,以便用来安定国内的人们。 +王子朝、宾起受到周景王的宠信,景王和宾起喜爱王子朝,要立王子朝为太子。刘献公的庶子伯蚠事奉单穆公,讨厌宾起的为人,愿意杀掉他。又讨厌王子朝的话,认为违背了礼制,愿意除掉他。有一次宾起走到郊外,看到雄鸡自己弄断自己的尾巴。他问为什么,侍者说:“这是它自己害怕作牺牲。”宾起赶快回来报告景王,而且说:“鸡大概是害怕被人利用吧!人就和这不一样,牺牲,是被人使用的,被人利用确实困难,被自己利用还有什么妨碍?”景王不回答。 +夏季,四月,景王在北山打猎,让公卿们都跟着,准备杀掉单子、刘子。景王有心脏病,十八日,死在荣锜氏那里。二十二日,刘子挚死了,没有嫡子,单子立了刘蚠。五月初四日,刘蚠进见周悼王,就乘势攻打宾起。杀死了他,和王子们在单氏那里结盟。 +晋国占取鼓地的时候,在宗庙里进献战利品以后就让鼓子回国。鼓子回去又背叛晋国归属鲜虞。 +六月,荀吴巡视东阳,派军队伪装籴米的人,背着皮甲在昔阳城门外休息,就乘机侵袭鼓国,灭亡了它,带着鼓子鸢鞮回去,派涉佗镇守鼓地。 +六月十一日,安葬周景王。王子朝依仗旧官和百工中失去官职的人和灵王、景王的族人而发动叛乱。王子朝率领郊地、要地、饯地的甲士以驱逐刘子。十六日,刘子逃亡到扬地,单子在庄宫迎接悼王回到自己家里,王子还在夜里又把悼王带到庄宫。十七日,单子出奔,王子还和召庄公谋划,说:“不杀死单旗,不能算胜利。和他再次结盟,他必定会来。违背盟约而战胜敌人的事情是很多的。”召庄公听从了他的话。樊顷子说:“这不成话,必然不能战胜敌人。”于是王子还就事奉悼王追赶单子,到达崿岭,大张旗鼓地结盟后一起回去,杀死了挚荒以向单子解释,刘子到刘地去。单子逃亡,十九日,逃亡到平畤。王子们追赶他,单子杀了还、姑、发、弱、鬷、延、定、稠,王子朝逃亡到京地。二十日,单子攻打京地。京地人逃亡到山里,刘子进入王城。二十五日,巩简公在京地大败。二十九日,甘平公也在那里战败。 +叔鞅从京师回来,说起王室的动乱,闵马父说:“王子朝必定不能得胜,他所亲附的人,都是上无所废弃的。”单子想要向晋国报告紧急情况。秋季,七月初三日,带着周悼王去到平畤,于是又到了圃车,住在皇地。刘子到刘地去,单子派王子处在王城守卫,和百工在平宫结盟。十六日,鄩肸攻打皇地,大败,被俘。十七日,把鄩肸在王城的市上烧死。八月十六日,司徒丑带领周天子的军队在前城大败,百工叛变。二十四日,攻打单氏的住宅,被打败。二十五日,单氏进攻。二十六日,进攻东圉。冬季,十月十三日,晋国的籍谈、荀跞率领九州的戎人和焦地、瑕地、温地、原地的军队,把周悼王送回王城。十六日,单子、刘蚠率领周天子的军队在郊地作战大败,前城人在社地打败陆浑。十一月十二日,王子猛死。《春秋》不记载“崩”,是由于没有举行天子丧葬礼的缘故。十六日,周敬王即位,住在子旅氏家里。 +十二月初七日,晋国的籍谈、荀跞、贾辛、司马督领兵分别驻扎在阴地、侯氏、溪泉和住在社地。周天子的军队驻扎在汜地、解地、任人。闰十二月,晋国的箕遗、乐征、右行诡带领部队渡河占取前城,驻扎在前城的东南,周天子的军队驻扎在京楚。二十九日,攻打京地,破坏了京地的西南部。 + +昭公二十三年 +【经】二十有三年春王正月,叔孙□若如晋。癸丑,叔鞅卒。晋人执我行人叔孙□若。晋人围郊。夏六月,蔡侯东国卒于楚。秋七月,莒子庚舆来奔。戊辰,吴败顿、胡沈、蔡、陈、许之师于鸡父,胡子髡、沈子逞灭,获陈夏啮。天王居于狄泉。尹氏立王子朝。八月乙未,地震。冬,公如晋,至河,有疾,乃复。 +【传】二十三年春,王正月壬寅朔,二师围郊。癸卯,郊、鄩溃。丁未,晋师在平阴,王师在泽邑。王使告间,庚戌,还。 +邾人城翼,还,将自离姑。公孙锄曰:“鲁将御我。”欲自武城还,循山而南。徐锄、丘弱、茅地曰:“道下,遇雨,将不出,是不归也。”遂自离姑。武城人塞其前,断其后之木而弗殊。邾师过之,乃推而蹶之。遂取邾师,获锄、弱、地。 +邾人诉于晋,晋人来讨。叔孙蹶如晋,晋人执之。书曰:“晋人执我行人叔孙□若。”言使人也。晋人使与邾大夫坐。叔孙曰:“列国之卿,当小国之君,固周制也。邾又夷也。寡君之命介子服回在,请使当之,不敢废周制故也。”乃不果坐。 +韩宣子使邾人取其众,将以叔孙与之。叔孙闻之,去众与兵而朝。士弥牟谓韩宣子曰:“子弗良图,而以叔孙与其仇,叔孙必死之。鲁亡叔孙,必亡邾。邾君亡国,将焉归?子虽悔之,何及?所谓盟主,讨违命也。若皆相执,焉用盟主?”乃弗与,使各居一馆。士伯听其辞而诉诸宣子,乃皆执之。士伯御叔孙,从者四人,过邾馆以如吏。先归邾子。士伯曰:“以刍荛之难,从者之病,将馆子于都。”叔孙旦而立,期焉。乃馆诸箕。舍子服昭伯于他邑。 +范献子求货于叔孙,使请冠焉。取其冠法,而与之两冠,曰:“尽矣。”为叔孙故,申丰以货如晋。叔孙曰:“见我,吾告女所行货。”见,而不出。吏人之与叔孙居于箕者,请其吠狗,弗与。及将归,杀而与之食之。叔孙所馆者,虽一日必葺其墙屋,去之如始至。 +夏四月乙酉,单子取訾,刘子取墙人、直人。六月壬午,王子朝入于尹。癸未,尹圉诱刘佗杀之。丙戌,单子从阪道,刘子从尹道伐尹。单子先至而败,刘子还。己丑,召伯奂、南宫极以成周人戍尹。庚寅,单子、刘子、樊齐以王如刘。甲午,王子朝入于王城,次于左巷。秋七月戊申,鄩罗纳诸庄宫。尹辛败刘师于唐。丙辰,又败诸鄩。甲子,尹辛取西闱。丙寅,攻蒯,蒯溃。 +莒子庚舆虐而好剑,苟铸剑,必试诸人。国人患之。又将叛齐。乌存帅国人以逐之。庚舆将出,闻乌存执殳而立于道左,惧将止死。苑羊牧之曰:“君过之!乌存以力闻可矣,何必以弑君成名?”遂来奔。齐人纳郊公。 +吴人伐州来,楚薳越帅师及诸侯之师奔命救州来。吴人御诸钟离。子瑕卒,楚师熸薳。吴公子光曰:“诸侯从于楚者众,而皆小国也。畏楚而不获己,是以来。吾闻之曰:‘作事威克其爱,虽小必济’。胡、沈之君幼而狂,陈大夫啮壮而顽,顿与许、蔡疾楚政。楚令尹死,其师熸。帅贱、多宠,政令不壹。而七国同役不同心,帅贱而不能整,无大威命,楚可败也,若分师先以犯胡、沈与陈,必先奔。三国败,诸侯之师乃摇心矣。诸侯乖乱,楚必大奔。请先者去备薄威,后者敦陈整旅。”吴子从之。戊辰晦,战于鸡父。吴子以罪人三千,先犯胡、沈与陈,三国争之。吴为三军以击于后,中军从王,光帅右,掩余帅左。吴之罪人或奔或止,三国乱。吴师击之,三国败,获胡、沈之君及陈大夫。舍胡、沈之囚,使奔许与蔡、顿,曰:“吾君死矣!”师噪而从之,三国奔,楚师大奔。书曰:“胡子髡、沈子逞灭,获陈夏啮。”君臣之辞也。不言战,楚未陈也。 +八月丁酉,南宫极震。苌弘谓刘文公曰:“君其勉之!先君之力可济也。周之亡也,其三川震。今西王之大臣亦震,天弃之矣!东王必大克。” +楚大子建之母在狊阜,召吴人而启之。冬十月甲申,吴大子诸樊入狊阜,取楚夫人与其宝器以归。楚司马薳越追之,不及。将死,众曰:“请遂伐吴以徼之。”薳越曰:“再败君师,死且有罪。亡君夫人,不可以莫之死也。”乃缢于薳澨。 +公为叔孙故如晋,及河,有疾而复。 +楚囊瓦为令尹,城郢。沈尹戌曰:“子常必亡郢!苟不能卫,城无益也。古者,天子守在四夷;天子卑,守在诸侯。诸侯守在四邻;诸侯卑,守在四竟。慎其四竟,结其四援,民狎其野,三务成功,民无内忧,而又无外惧,国焉用城?今吴是惧而城于郢,守己小矣。卑之不获,能无亡乎?昔梁伯沟其公宫而民溃。民弃其上,不亡何待?夫正其疆场,修其土田,险其走集,亲其民人,明其伍候,信其邻国,慎其官守,守其交礼,不僭不贪,不懦不耆,完其守备,以待不虞,又何畏矣?《诗》曰:‘无念尔祖,聿修厥德。’无亦监乎若敖、蚡冒至于武、文?土不过同,慎其四竟,犹不城郢。今土数圻,而郢是城,不亦难乎?” +译文 +二十三年春季,周王朝历法的正月初一,周、晋两国的两支军队包围郊地。初二日,郊地、?地人溃散。初六日,晋国的军队在平阴,周天子的军队在泽邑。周敬王派人向晋军报告情势好转。初九日,晋军回国。 +邾人在翼地筑城,回去,准备从离姑那条路上走,公孙鉏说:“鲁国将会抵御我们。”就考虑从武城折回去,沿着山路往南走。徐鉏、丘弱、茅地说:“山道一直往下,碰上雨,将会出不去,这就不能回去了。”于是就取道离姑,武城人出兵挡在前面,又把退路两旁的树木,加以砍伐又不砍断。邾军经过这里以后,武城人推到树木,于是消灭邾军,俘虏了徐鉏、丘弱、茅地。 +邾人向晋国控诉,晋国人前来问罪,叔孙婼到晋国去,晋国人就把他扣押了。《春秋》记载说“晋国执我行人叔孙婼”,是说明晋人扣押了使臣。晋人让叔孙婼和邾国的大夫辩论,叔孙婼说:“各国的卿,相当于小国的国君,本来是周朝的制度,小小的邾国还是夷人呢。有寡君所任命的副使子服回在,请让他担任这件事,这是由于不敢废除周朝的制度。”于是就不去辩论。 +韩宣子让邾人聚集他们的人,准备把叔孙婼交给他们,叔孙婼听说这件事,撤去随从和武器前去朝见晋君,士弥牟对韩宣子说:“您的主意不好,而把叔孙婼交给他们的仇人,叔孙婼必然为此而死,鲁国丧失了叔孙婼,必然灭亡邾国,邾君亡国,将要回到哪里去?到时您虽然后悔,哪里还来得及呢?所谓盟主,任务是讨伐违背命令的国家,如果互相抓人,哪里还用得着盟主?”于是韩宣子就没有把叔孙婼交给邾国人,让他和子服回各自住在一个宾馆里。士弥牟听了他们的辩解,告诉韩宣子,就把他们都扣押了。士弥牟为叔孙婼驾车,跟从的有四个人,经过邾人的宾馆而到官吏那里去,先让邾子回国,士弥牟说:“由于柴草供应困难,随从人员辛苦,准备让您住在别的城邑里。”叔孙婼一早晨就站着,等候命令。晋国人就让他住在箕地。让子服回住在另外的城邑里。 +范献子向叔孙婼求取财货,派人去请求送给他帽子,叔孙婼拿来他帽子的样子,照样送给他两顶,说:“都在这里了。”为了叔孙婼的缘故,申丰带着财货去到晋国,叔孙婼说:“来见我,我告诉你把财货送到哪里去。”申丰进见叔孙婼,就没有出来,和叔孙婼一起住在箕地的看守人请求得到他的吠狗,叔孙婼不给,等到将要回去的时候,杀了这条狗和官吏一起吃了。叔孙婼所住过的地方,尽管只住一天,也一定修缮墙屋,离开的时候好像刚来的时候一样。 +夏季,四月十四日,单子攻取了訾地,刘子攻取了墙人、直人。六月十二日,王子朝进入尹地。十三日,尹圉诱骗刘佗把他杀死了。十六日,单子从山道、刘子从大道出兵进攻尹地。单子先抵达而战败,刘子就回去了。十九日,召伯奂、南宫极带着成周的军队在尹地戍守。二十日,单子、刘子、樊齐带了周敬王去到刘地。二十四日,王子朝进入王城,住在左巷。秋季,七月初九日,鄩罗把王子朝送到庄宫,尹辛在唐地击败刘子的军队。十七日,又在鄩地击败刘军。二十五日,尹辛占取西闱。二十七日,进攻蒯地,蒯地人溃散。 +莒子庚舆残暴而喜欢剑,如果铸造了剑,必定要用人来试一试,国内的人们都讨厌他。他又准备背叛齐国。乌存率领国内的人们驱逐他。庚舆将要出国,听说乌存拿着殳在路边站着,恐惧会把他留下杀死,苑羊牧之说:“君王过去吧!乌存由于勇力过人而出名就行了,何必用杀死国君来成名?”庚舆就逃亡前来,齐国人把郊公送回莒国即位。 +吴人进攻州来,楚国的薳越率领楚国和诸侯的军队奉命奔赴救援州来,吴人在钟高抵御他们,令尹子瑕死,楚军丧失战斗力。吴国的公子光说:“诸侯跟从楚国的很多,而都是小国,害怕楚国而不得已,因此前来。我听说:‘做事情如果威严胜过感情,虽然弱小,必然成功。’胡国、沈国的国君年轻而浮躁,陈国的大夫齧虽然年富力强但是顽固,顿国和许国、蔡国憎恨楚国的政事,楚国的令尹死了,他们的军队失去战斗力,元帅地位低,而很受宠信,政令又不一致,七国同伙而不同心,元帅地位低而不能整齐号令,没有重大的威信,楚国是可以打败的。如果分兵先攻胡国、沈国和陈国的军队,他们必然首先奔逃,三国败退,诸侯的军队的军心就动摇了,诸侯混乱,楚军必然拼命奔逃。请让先头部队放松戒备减少军威,后继部队巩固军阵整顿师旅,以引诱敌人。”吴王听从了他的意见。七月二十九日,在鸡父作战,吴王用三千名罪犯先攻胡国、沈国和陈国,三国军队争着俘虏吴军。吴国整编了三个军紧跟在后,中军跟随吴王,公子光率领右军,公子掩馀率领左军,吴国的罪犯有的奔逃,有的停止,三国的军阵乱了阵脚,吴军进攻,三国的军队败退,俘虏了胡、沈两国的国君和陈国的大夫。吴军释放胡国、沈国的浮虏,让他们奔逃到许国和蔡国、顿国的军队里,说:“我们的国君死了!”吴军擂鼓呐喊跟上去,三国的军队败逃,楚军拼命逃跑。《春秋》记载说“胡子髡、沈子逞灭,获陈夏齧”,这是对国君和臣下所使用的不同文辞,不说交战,这是因为楚国没有摆开阵势。 +八月二十七日,南宫极因为地震被压死,苌弘对刘文公说:“君王还是努力吧!先君所致力的事可以成功了,周室灭亡的时候,泾水、渭水、洛水一带发生地震,现在西王的大臣那里也发生地震,这是上天丢弃他了,东王必然大胜。” +楚国太子建的母亲住在郹地,召来吴国人,为他们打开城门。冬季,十月十六日,吴国的太子诸樊进入郹地,带了楚夫人和她的宝器回国了。楚国的司马薳越追赶他,没有追上。准备自杀,众人说:“乘机攻打吴国可能侥幸取胜。”薳越说:“再次让国君的军队打败,死了也还是有罪。丢了君王的夫人,没有谁不能为此而死。”于是薳越就在薳澨上吊死了。 +昭公为叔孙的缘故到晋国去,到达黄河,有病而返回来。 +楚国的囊瓦做令尹,在郢都增修城墙。沈尹戌说:“子常一定丢掉郢都,如果不能保卫,增修城墙是没有好处的。古代,天子的守卫在于四夷。天子的地位降低,守卫在于诸侯,诸侯的守卫在于四方邻国。诸侯的地位降低,守卫在于四方边境。警惕四方边境,结交四方邻国,百姓在自己土地上安居乐业,春夏秋三时的农事有所收获,百姓没有内忧,又没有外患,国都哪里用得着增修城墙?现在害怕吴国,而在郢都增修城墙,守卫的范围只在四境。地位降低以后的其他守卫都办不到,能够不亡吗?从前梁国国君在公宫旁边挖沟而百姓溃散,百姓抛弃他们上边的人,不亡,还等什么?划定疆界,修治土地,巩固边垒,亲近百姓,加强瞭望,不欺邻国,谨慎官吏的职责,保持交接的礼仪,没有过失,不贪婪,不懦弱,不强霸,修整自己的防御,以防备发生意外,又有什么可害怕呢?《诗》说:‘思念你的祖先,发扬他们的美德。’试看若敖、蚡冒到文王、武王,土地不超过百里见方,警惕四方边境,尚且不在郢都增修城墙。现在土地超过几千里见方,反而在郢都增修城墙,不也是很难了吗?” + +昭公二十四年 +【经】二十四年春王三月丙戌,仲孙玃卒。□若至自晋。夏五月乙未朔,日有食之。秋八月,大雩。丁酉,杞伯郁厘卒。冬,吴灭巢。葬杞平公。 +【传】二十四年春,王正月辛丑,召简公、南宫嚚以甘桓公见王子朝。刘子谓苌弘曰:“甘氏又往矣。”对曰:“何害?同德度义。《大誓》曰:‘纣有亿兆夷人,亦有离德。余有乱臣十人,同心同德。’此周所以兴也。君其务德,无患无人。”戊午,王子朝入于邬。 +晋士弥牟逆叔孙于箕。叔孙使梁其迳待于门内,曰:“余左顾而欬,乃杀之。右顾而笑,乃止。”叔孙见士伯,士伯曰:“寡君以为盟主之故,是以久子。不腆敝邑之礼,将致诸从者。使弥牟逆吾子。”叔孙受礼而归。二月,□若至自晋,尊晋也。 +三月庚戌,晋侯使士景伯莅问周故,士伯立于乾祭而问于介众。晋人乃辞王子朝,不纳其使。 +夏五月乙未朔,日有食之。梓慎曰:“将水。”昭子曰:“旱也。日过分而阳犹不克,克必甚,能无旱乎?阳不克莫,将积聚也。” +六月壬申,王子朝之师攻瑕及杏,皆溃。 +郑伯如晋,子大叔相,见范献子。献子曰:“若王室何?”对曰:“老夫其国家不能恤,敢及王室。抑人亦有言曰:‘嫠不恤其纬,而忧宗周之陨,为将及焉。’今王室实蠢蠢焉,吾小国惧矣。然大国之忧也,吾侪何知焉?吾子其早图之!《诗》曰:瓶之罄矣,惟罍之耻。’王室之不宁,晋之耻也。”献子惧,而与宣子图之。乃征会于诸侯,期以明年。 +秋八月,大雩,旱也。 +冬十月癸酉,王子朝用成周之宝珪于河。甲戌,津人得诸河上。阴不佞以温人南侵,拘得玉者,取其玉,将卖之,则为石。王定而献之,与之东訾。 +楚子为舟师以略吴疆。沈尹戌曰:“此行也,楚必亡邑。不抚民而劳之,吴不动而速之,吴踵楚,而疆埸无备,邑能无亡乎?” +越大夫胥犴劳王于豫章之汭。越公子仓归王乘舟,仓及寿梦帅师从王,王及圉阳而还。吴人踵楚,而边人不备,遂灭巢及钟离而还。沈尹戌曰:“亡郢之始,于此在矣。王一动而亡二姓之帅,几如是而不及郢?《诗》曰:‘谁生厉阶,至今为梗?’其王之谓乎?” +译文 +二十四年春季,周王朝历法的正月初五日,召简公、南宫嚚带着甘桓公进见王子朝。刘子对苌弘说:“甘氏又去了。”苌弘回答说:“有什么妨碍?同心同德在于合乎正义。《太誓》说:‘纣有亿兆人,离心离德,我有治世之臣十个人,同心同德。’这就是周朝所以兴起的原因,君王还是致力于德行,不要担心没有人。”二十二日,王子朝进入邬地。 +晋国的士弥牟在箕地迎接叔孙,叔孙派梁其踁埋伏在门里边,说:“我向左边看并且咳嗽,就把他杀了。向右边看并且笑笑,就不要动手。”叔孙接见士弥牟,士弥牟说:“寡君由于作为盟主的缘故,因此把您久留在敝邑,不丰厚的敝邑的礼物,将要致送给您的左右随从,派弥牟来迎接您。”叔孙接受礼物回国了。二月,《春秋》记载说“婼至自晋”,这是表示尊重晋国。 +三月十五日,晋顷公派士景伯到王城调查周朝发生的事故。士景伯站在乾祭门上,向大众询问,晋国人就辞谢王子朝,不接纳他的使者。 +夏季,五月初一日,发生日食。梓慎说:“将要发生水灾。”昭子说:“这是旱灾,太阳过了春分而阳气尚且不胜阴气,一旦胜过阴气,能不发生旱灾吗?阳气迟迟不能战胜阴气,这是正在积聚阳气。” +六月初八日,王子朝的军队进攻瑕地和杏地,两地军队都溃散了。 +郑定公到晋国去,子太叔相礼,进见范献子。范献子说:“对王室该怎么办?”子太叔回答说:“我老头子对自己的国家和家族都不能操心了,哪里敢涉及王室的事情?人们有话说:‘寡妇不操心纬线,而忧虑宗周的陨落,因为恐怕祸患也会落到她头上。’现在王室确实动荡不安,我们小国害怕了,然而大国的忧虑,我们哪里知道呢?您还是早作打算。《诗》说:‘酒瓶空空,是酒坛子的耻辱。’王室的不安宁,这是晋国的耻辱。”范献子害怕,和韩宣子谋划。于是就召集诸侯会见,时间定在明年。 +秋季,八月,举行盛大的雩祭,这是由于发生了旱灾。 +冬季,十月十一日,王子朝使用成周的宝圭沉到黄河里向河神祈祷。十二日,渡船的船工在黄河上得到了这块宝圭。阴不佞带着温地人往南袭击王子朝,拘捕了得到玉的人,把玉拿过来,准备卖掉它,却是一块石头。阴不佞在王室安定以后把它奉献给周敬王,周敬王把东訾赐给他。 +楚平王组织水军去侵略吴国的疆土。沈尹戌说:“这一趟,楚国必然丢掉城邑。不安抚百姓而让他们疲惫,吴国没有动静而让他们加速出动,吴军紧紧追逐楚军,然而边境却没有戒备,城邑能够不丢掉吗?” +越国的大夫胥犴在豫章的江边上慰劳楚平王,越国的公子仓把一只船赠送给楚平王。公子仓和寿梦领兵跟随楚平王。楚平王到达圉阳而返回。吴军紧紧追逐楚军,但是边境的守军没有戒备,吴国人就灭掉了巢和钟离而回去。沈尹戌说:“丢掉郢都的开端就在这里,君王一个举动就失去了两个将领,照这样来几次,难道就不会兵临郢都城下?《诗》说:‘是谁制造了祸端,到今天还是灾害’,恐怕说的就是君王吧!” + + +昭公二十五年 +【经】二十五年春,叔孙□若如宋。夏,叔诣会晋赵鞅、宋乐大心,卫北宫喜、郑游吉、曹人、邾人、滕人、薛人、小邾人于黄父。有鸲鹆来巢。秋七月上辛,大雩;季辛,又雩。九月己亥,公孙于齐,次于阳州。齐侯唁公于野井。冬十月戊辰,叔孙□若卒。十有一月己亥,宋公佐卒于曲棘。十有二月,齐侯取郓。 +【传】二十五年春,叔孙□若聘于宋,桐门右师见之。语,卑宋大夫,而贱司城氏。昭子告其人曰:“右师其亡乎!君子贵其身而后能及人,是以有礼。今夫子卑其大夫而贱其宗,是贱其身也,能有礼乎?无礼必亡。” +宋公享昭子,赋《新宫》。昭子赋《车辖》。明日宴,饮酒,乐,宋公使昭子右坐,语相泣也。乐祁佐,退而告人曰:“今兹君与叔孙,其皆死乎?吾闻之:‘哀乐而乐哀,皆丧心也。’心之精爽,是谓魂魄。魂魄去之,何以能久?” +季公若之姊为小邾夫人,生宋元夫人,生子以妻季平子。昭子如宋聘,且逆之。公若从,谓曹氏勿与,鲁将逐之。曹氏告公,公告乐祁。乐祁曰:“与之。如是,鲁君必出。政在季氏三世矣,鲁君丧政四公矣。无民而能逞其志者,未之有也。国君是以镇抚其民。《诗》曰:‘人之云亡,心之忧矣。’鲁君失民矣,焉得逞其志?靖以待命犹可,动必忧。” +夏,会于黄父,谋王室也。赵简子令诸侯之大夫输王粟,具戍人,曰:“明年将纳王。”子大叔见赵简子,简子问揖让周旋之礼焉。对曰:“是仪也,非礼也。”简子曰:“敢问何谓礼?”对曰:“吉也闻诸先大夫子产曰:‘夫礼,天之经也。地之义也,民之行也。’天地之经,而民实则之。则天之明,因地之性,生其六气,用其五行。气为五味,发为五色,章为五声,淫则昏乱,民失其性。是故为礼以奉之:为六畜、五牲、三牺,以奉五味;为九文、六采、五章,以奉五色;为九歌、八风、七音、六律,以奉五声;为君臣、上下,以则地义;为夫妇、外内,以经二物;为父子、兄弟、姑姊、甥舅、昏媾、姻亚,以象天明,为政事、庸力、行务,以从四时;为刑罚、威狱,使民畏忌,以类其震曜杀戮;为温慈、惠和,以效天之生殖长育。民有好、恶、喜、怒、哀、乐,生于六气。是故审则宜类,以制六志。哀有哭泣,乐有歌舞,喜有施舍,怒有战斗;喜生于好,怒生于恶。是故审行信令,祸福赏罚,以制死生。生,好物也;死,恶物也;好物,乐也;恶物,哀也。哀乐不失,乃能协于天地之性,是以长久。”简子曰:“甚哉,礼之大也!”对曰:“礼,上下之纪,天地之经纬也,民之所以生也,是以先王尚之。故人之能自曲直以赴礼者,谓之成人。大,不亦宜乎?”简子曰:“鞅也请终身守此言也。”宋乐大心曰:“我不输粟。我于周为客?若之何使客?”晋士伯曰:“自践土以来,宋何役之不会,而何盟之不同?曰‘同恤王室’,子焉得辟之?子奉君命,以会大事,而宋背盟,无乃不可乎?”右师不敢对,受牒而退。士伯告简子曰:“宋右师必亡。奉君命以使,而欲背盟以干盟主,无不祥大焉。” +‘有鸲鹆来巢’,书所无也。师己曰:“异哉!吾闻文、武之世,童谣有之,曰:‘鸲之鹆之,公出辱之。鸲鹆之羽,公在外野,往馈之马。鸲鹆跦跦,公在乾侯,征褰与襦。鸲鹆之巢,远哉遥遥。稠父丧劳,宋父以骄。鸲鹆鸲鹆,往歌来哭。’童谣有是,今鸲鹆来巢,其将及乎?” +秋,书再雩,旱甚也。 +初,季公鸟娶妻于齐鲍文子,生甲。公鸟死,季公亥与公思展与公鸟之臣申夜姑相其室。及季姒与饔人檀通,而惧,乃使其妾抶己,以示秦遄之妻,曰:“公若欲使余,余不可而抶余。”又诉于公甫,曰:“展与夜姑将要余。”秦姬以告公之,公之与公甫告平子。平子拘展于卞而执夜姑,将杀之。公若泣而哀之,曰:“杀是,是杀余也。”将为之请。平子使竖勿内,日中不得请。有司逆命,公之使速杀之。故公若怨平子。 +季、郤之鸡斗。季氏介其鸡,郤氏为之金距。平子怒,益宫于郤氏,且让之。故郤昭伯亦怨平子。臧昭伯之从弟会,为谗于臧氏,而逃于季氏,臧氏执旃。平子怒,拘臧氏老。将褅于襄公,万者二人,其众万于季氏。臧孙曰:“此之谓不能庸先君之庙。”大夫遂怨平子。公若献弓于公为,且与之出射于外,而谋去季氏。公为告公果、公贲。公果、公贲使侍人僚柤告公。公寝,将以戈击之,乃走。公曰:“执之。”亦无命也。惧而不出,数月不见,公不怒。又使言,公执戈惧之,乃走。又使言,公曰:“非小人之所及也。”公果自言,公以告臧孙,臧孙以难。告郤孙,郤孙以可,劝。告子家懿伯,懿伯曰:“谗人以君侥幸,事若不克,君受其名,不可为也。舍民数世,以求克事,不可必也。且政在焉,其难图也。”公退之。辞曰:“臣与闻命矣,言若泄,臣不获死。”乃馆于公。 +叔孙昭子如阚,公居于长府。九月戊戌,伐季氏,杀公之于门,遂入之。平子登台而请曰:“君不察臣之罪,使有司讨臣以干戈,臣请待于沂上以察罪。”弗许。请囚于费,弗许。请以五乘亡,弗许。子家子曰:“君其许之!政自之出久矣,隐民多取食焉。为之徒者众矣,日入慝作,弗可知也。众怒不可蓄也,蓄而弗治,将温。温畜,民将生心。生心,同求将合。君必悔之。”弗听。郤孙曰:“必杀之。”公使郤孙逆孟懿子。叔孙氏之司马鬷戾言于其众曰:“若之何?”莫对。又曰:“我,家臣也,不敢知国。凡有季氏与无,于我孰利?”皆曰:“无季氏,是无叔孙氏也。”鬷戾曰:“然则救诸!”帅徒以往,陷西北隅以入。公徒释甲,执冰而踞。遂逐之。孟氏使登西北隅,以望季氏。见叔孙氏之旌,以告。孟氏执郈昭伯,杀之于南门之西,遂伐公徒。子家子曰:“诸臣伪劫君者,而负罪以出,君止。意如之事君也,不敢不改。”公曰:“余不忍也。”与臧孙如墓谋,遂行。 +己亥,公孙于齐,次于阳州。齐侯将唁公于平阴,公先于野井。齐侯曰:“寡人之罪也。使有司待于平阴,为近故也。”书曰:“公孙于齐,次于阳州,齐侯唁公于野井。”礼也。将求于人,则先下之,礼之善物也。齐侯曰:“自莒疆以西,请致千社,以待君命。寡人将帅敝赋以从执事,唯命是听,君之忧,寡人之忧也。”公喜。子家子曰:“天禄不再,天若胙君,不过周公,以鲁足矣。失鲁,而以千社为臣,谁与之立,且齐君无信,不如早之晋。”弗从。臧昭伯率从者将盟,载书曰:“戮力壹心,好恶同之。信罪之有无,缱绻从公,无通外内。”以公命示子家子。子家子曰:“如此,吾不可以盟,羁也不佞,不能与二三子同心,而以为皆有罪。或欲通外内,且欲去君。二三子好亡而恶定,焉可同也?陷君于难,罪孰大焉?通外内而去君,君将速入,弗通何为?而何守焉?”乃不与盟。 +昭子自阚归,见平子。平子稽颡,曰:“子若我何?”昭子曰:“人谁不死?子以逐君成名,子孙不忘,不亦伤乎!将若子何?”平子曰:“苟使意如得改事君,所谓生死而肉骨也。”昭子从公于齐,与公言。子家子命适公馆者执之。公与昭子言于幄内,曰将安众而纳公。公徒将杀昭子,伏诸道。左师展告公,公使昭子自铸归。平子有异志。冬十月辛酉,昭子齐于其寝,使祝宗祈死。戊辰,卒。左师展将以公乘马而归,公徒执之。 +壬申,尹文公涉于巩,焚东訾,弗克。 +十一月,宋元公将为公故如晋。梦大子栾即位于庙,己与平公服而相之。旦,召六卿。公曰:“寡人不佞,不能事父兄,以为二三子忧,寡人之罪也。若以群子之灵,获保首领以没,唯是匾柎所以藉干者,请无及先君。”仲几对曰:“君若以社稷之故,私降昵宴,群臣弗敢知。若夫宋国之法,死生之度,先君有命矣。群臣以死守之,弗敢失队。臣之失职,常刑不赦。臣不忍其死,君命只辱。”宋公遂行。己亥,卒于曲棘。 +十二月庚辰,齐侯围郓。 +初,臧昭伯如晋,臧会窃其宝龟偻句,以卜为信与僭,僭吉。臧氏老将如晋问,会请往。昭伯问家故,尽对。及内子与母弟叔孙,则不对。再三问,不对。归,及郊,会逆,问,又如初。至,次于外而察之,皆无之。执而戮之,逸,奔郤。郤鲂假使为贾正焉。计于季氏。臧氏使五人以戈盾伏诸桐汝之闾。会出,逐之,反奔,执诸季氏中门之外。平子怒,曰:“何故以兵入吾门?”拘臧氏老。季、臧有恶。及昭伯从公,平子立臧会。会曰:“偻句不馀欺也。” +楚子使薳射城州屈,复茄人焉。城丘皇,迁訾人焉。使熊相衣某郭巢,季然郭卷。子大叔闻之,曰:“楚王将死矣。使民不安其土,民必忧,忧将及王,弗能久矣。” +译文 +二十五年春季,叔孙婼到宋国聘问。桐门右师接见他,谈话,右师看不起宋国的大夫,并且轻视司城氏。叔孙婼告诉他的手下人说:“右师恐怕要逃亡吧!君子尊重他自己,然后能及于别人,因此有礼。现在这个人对他们的大夫和宗族都不加尊重,这是轻视他自己,能够有礼吗?无礼必定逃亡。” +宋元公设享礼招待叔孙婼,赋《新宫》这首诗,叔孙婼赋《车辖》这首诗。第二天设宴,喝酒,很高兴,宋元公让昭子坐在右边,说着话就相对掉下了眼泪。乐祁帮着主持宴会,退下去告诉别人说:“今年国君和叔孙恐怕都要死了吧!我听说:‘该高兴的时候悲哀,而该悲哀的时候高兴,这都是心意丧失。’心的精华神明,这就叫魂魄,魂魄离去了,怎么能活得久长?” +季公若的姐姐是小邾君夫人,生了宋元公夫人,宋元公夫人生了个女儿,嫁给季平子,叔孙婼到宋国行聘,并且迎亲。季公若跟随前去,告诉宋元公夫人让她不要答应亲事,因为鲁国正在准备赶走季平子。宋元公夫人告诉宋元公,宋元公告诉乐祁,乐祁说:“给他。如果像所说的那样,鲁国国君一定要逃往国外。政权掌握在季氏手中已经三代了,鲁国国君丧失政权已经四代了。失掉民心而能满足他愿望的,还没有过。国君因此才镇抚他的百姓。《诗》说:‘人才的丧失,就是心头的忧虑。’鲁国国君已经失去了民心,哪里能实现他的愿望?安静地等待天命还可以,有所举动必定造成忧患。” +夏季,鲁国子太叔和晋国赵鞅、宋国乐大心、卫国北宫喜、郑国游吉、曹人、邾人、滕人、薛人、小邾人在黄父会见,这是为了商量安定王室。赵鞅命令诸侯的大夫向周敬王输送粮食、准备戍守的将士,说:“明年将要送天子回去。” +子太叔进见赵简子,赵简子向他询问揖让、周旋的礼节。子太叔回答说:“这是仪,不是礼。”赵简子说:“谨敢请问什么叫礼?”子太叔回答说:“吉曾经听到先大夫子产说:‘礼,是上天的规范,大地的准则,百姓行动的依据。’天地的规范,百姓就加以效法,效法上天的英明,依据大地的本性,产生了上天的六气,使用大地的五行。气是五种味道,表现为五种颜色,显示为五种声音,过了头就昏乱,百姓就失掉本性,因此制作了礼用来使它有所遵循:制定了六畜、五牲、三牺,以使五味有所遵循。制定九文、六采、五章,以使五色有所遵循。制定九歌、八风、七音、六律,以使五声有所遵循。制定君臣上下的关系,以效法大地的准则。制定夫妇内外的关系,以规范两种事物。制定父子、兄弟、姑姊、甥舅、翁婿、连襟的关系,以象征上天的英明。制定政策政令、农工管理、行动措施,以随顺四时。制定刑罚、牢狱让百姓害怕,以模仿雷电的杀伤。制定温和慈祥的措施,以效法上天的生长万物。百姓有好恶、喜怒、哀乐,它们以六气派生,所以要审慎地效法,适当地模仿,以制约六志。哀痛有哭泣,欢乐有歌舞,高兴有施舍,愤怒有战斗。高兴从爱好而来,愤怒从讨厌而来。所以要使行动审慎、使命令有信用,用祸福赏罚,来制约死生。生,是人们喜好的事情。死,是人们讨厌的事物。喜好的事物,是欢乐。讨厌的事物,是哀伤。欢乐不失于礼,就能协调天地的本性,因此能够长久。’”赵简子说:“礼的伟大达到极点!”子太叔回答说:“礼,是上下的纲纪,天地的准则,百姓所生存的依据,因此先王尊崇它,所以人们能够从不同的天性经过自我修养改造或者直接达到礼的,就叫做完美无缺的人。它的伟大,不也是适宜的吗?”赵简子说:“我赵鞅啊,请求一辈子遵循这些话。” +宋国的乐大心说:“我们不给天子送粮食,我们对周朝来说是客人,为什么要指使客人送粮食?”晋国的士伯说:“从践土结盟以来,宋国有哪一次战役不参加,又有哪一次结盟不在一起?盟辞说‘一起为王室操心’,您哪里能躲开?您奉了君王的命令,来参加这重大的事件,而宋国倒违背盟约,恐怕不可以吧!”乐大心不敢回答,接受了简札退出去。士伯告诉赵简子说:“宋国的右师必然逃亡。奉了国君的命令出使,而想要背弃盟约以触犯盟主,没有比这再大的不吉祥了。” +“有鸜鹆来巢”,这是过去所没有记载的事情。师己说:“怪呀!我听说文王、成王的时代,童谣有这样的话说:‘鸜啊鹆啊,国君出国受到羞辱。鸜鹆的羽毛,国君住在远郊,臣下去把马匹送到。鸜鹆蹦蹦跳跳,国君住在乾侯,向人要裤子短袄。鸜鹆的老巢,路远遥遥,稠父死于辛劳,宋父代立而骄,鸜鹆鸜鹆,去的时候唱歌,回来的时候号哭。’童谣有这个。现在鸜鹆前来筑巢,恐怕将要发生祸难了吧!” +秋季,《春秋》记载两次大的雩祭,这是由于旱灾严重。 +当初,季公鸟在齐国鲍文子家娶了妻子,生了某甲。季公鸟死,季公亥、公思展和季公鸟的家臣申夜姑管理他的家务。等到季姒和管伙食的檀私通,季姒感到害怕,就让她的侍女打了自己一顿,跑去给秦遄的妻子看,说:“公若要让我陪他睡觉,我不答应,就打了我。”又向公甫诉苦,说:“展和夜姑准备要挟我。”秦遄的妻子把话告诉公之。公之和公甫告诉了平子,平子把公思展拘留在卞地,抓了夜姑准备杀他。季公亥哭泣着哀求说:“杀了这个人,就是杀了我。”准备为他请求。平子让小仆役不让他进来,太阳到中午没有能得到请求。官吏去接受处理夜姑的命令,公之要他快点杀了夜姑,所以季公亥怨恨平子。 +季氏、郈氏斗鸡。季氏给鸡套上皮甲,郈氏给鸡安上金属爪子。季氏的鸡斗败,季平子发怒,在郈氏那里扩建自己的住宅,并且责备他们。所以郈昭伯也怨恨季平子。 +臧昭伯的叔伯兄弟臧会在臧氏那里诬陷别人,逃到季氏那里,臧氏扣押了他。季平子发怒,拘留了臧氏的家臣。将要在襄公庙里举行祭祀,跳万舞的只有两个人,多数人到季氏那里跳万舞去了。臧昭伯说:“这叫做不能在先君的宗庙里酬谢先君的功劳。”大夫们于是也就怨恨季平子。 +季公亥向公为献弓,并且和他外出射箭,谋划去掉季氏。公为告诉了公果、公贲。公果、公贲派随从僚柤报告昭公。昭公已经睡了,要拿起戈来打僚柤,僚柤就跑了,昭公说:“逮住他!”但也没有正式下命令。僚柤恐惧不敢出门,几个月不去朝见昭公。昭公并不发怒。后来又派僚柤去报告昭公,昭公拿起戈来吓唬他,他就跑了。又派僚柤去说,昭公说:“这不是小人管得着的。”公果自己去说了,昭公把话告诉臧孙。臧孙认为难办。告诉了郈昭伯,郈昭伯认为可行,劝昭公干。昭公告诉子家懿伯。懿伯说:“坏人们让君王侥幸行事,事情如果不成功,君王蒙受坏名声,这是不能做的。丢掉百姓已经几代了,以此要求事情成功,这是没有把握的事。而且政权在人家手里,恐怕是很难算计他的。”昭公让懿伯下去,懿伯回答说:“下臣已经听到您的命令了,话如果泄漏,下臣会不得好死的。”于是就住在公宫里。 +叔孙昭子到阚地去,昭公住在长府里。九月十一日,攻打季氏,在大门口杀死公之,就攻了进去。季平子登台请求说:“君上没有调查下臣的罪过,派官吏使用武力讨伐下臣,下臣请求待在沂水边上让君王审查。”昭公不答应。请求囚禁在费地,昭公也不答应。请求带着五辆车子逃亡,昭公也不答应。子家子说:“君王还是答应他吧!政令从他那里发出已经很久了,贫困的百姓大都靠他吃饭,做他一党的人也很多了,太阳下山以后,坏人是否冒出来,还不知道呢。众人的怒气不能让它积聚,积聚起来而不妥善处理,怒气会越来越大。越来越大的怒气积聚起来,百姓将会产生叛变之心,生背叛之心,和有同样要求的人会纠合一起,君王必然要后悔的!”昭公不听从他的意见,郈昭伯说:“一定要杀了他。” +昭公派郈昭伯迎接孟懿子,叔孙氏的司马鬷戾问他的手下人说:“怎么办?”没有人回答。又说:“我是家臣,不敢考虑国家大事,有季氏和没有季氏,哪一种情况对于我有利?”大家都说:“没有季氏,就是没有叔孙氏。”鬷戾说:“那么就去救援他吧!”率领手下人前去,攻破西北角进去。昭公的亲兵正脱去皮甲拿着箭筒蹲着,鬷戾就把他们赶走了,孟氏派人登上西北角,瞭望季氏。瞭望的人看到叔孙氏的旗子,把情况报告孟氏。孟氏逮捕了郈昭伯,把他在南门的西边杀死了他,就乘势攻打昭公的亲兵,子家子说:“臣下们假装是劫持君王的人,背着罪名出国,君王留下来,意如事奉君王,就不敢不改变态度。”昭公说:“我不能忍受。”就和臧昭伯去祖坟上辞别祖宗,并且谋划逃亡的事,动身走了。 +十一月十三日,昭公逃亡到齐国,住在阳州。齐景公准备在平阴慰问昭公,昭公先到达野井。齐景公说:“这是寡人的罪过。”让官吏在平阴等待,是为了就近的缘故。《春秋》记载说“公孙于齐,次于阳州,齐侯唁公于野井”,这是合于礼的。将要有求于人,就要先居于人下,这是合于礼的好事。齐景公说:“从莒国的国境以西,请奉送君王二万五千户,以等待君王的命令,寡人将要率领敝邑的军队以跟从执事,唯命是听。君王的忧虑,就是我的忧虑。”昭公很高兴,子家子说:“上天所赐的爵禄不再降给君王了,上天如果保佑君王,也不能超过周公。给君王鲁国就足够了。失去鲁国而带着二万五千户做臣下,谁还为君王复位?况且齐国的国君不讲信用,不如早点到晋国去。”昭公不听从他的意见。 +臧昭伯率领跟随昭公的人将要结盟,盟书说:“合力同心,好恶一致,明确有罪无罪,坚决跟从国君,不要内外沟通。”用昭公的名义给子家子看,子家子说:“像这样,我不能盟誓,羁没有才能,不能和您几位合力同心,而是认为都有罪,我也可能与国外交谈,并且想要离开国君为国君奔走四方。您几位喜欢逃亡而不想安定君位,我哪里能和您几位好恶一致?陷国君于危难之中,还有比这再大的罪过吗?为了里外通气而离开国君,国君就能快一点回国,不通消息做什么?又能死守在哪里?”于是就不参加结盟。 +昭子从阚地回国,进见季平子,平子叩头,说:“您要我怎么办?”昭子说:“人有谁不死?您由于驱逐国君成了名,子子孙孙不忘记,不也可悲吗?我能把您怎么办?”季平子说:“如果让我能改变态度事奉国君,就是所谓让死人再生、白骨长肉的事情了。”昭子到齐国去跟随昭公,向昭公报告,子家子命令把凡是到昭公宾馆去的人都抓起来,昭公和昭子在帐幕里说话,昭子说:“将要安定大众而接纳您。”昭公的亲兵准备杀死昭子,埋伏在路边。左师展报告昭公,昭公让昭子取道从铸地回国。这时季平子有了别的想法。冬季,十月初四日,昭子在正寝中斋戒,让祝宗为他求死。十一日,死去。左师展准备带着昭公坐一辆车回国,昭公的亲兵逮捕了他。 +十月十五日,尹文公领兵徒步渡过洛水,放火烧了东訾,没有战胜。 +十一月,宋元公准备为鲁昭公的缘故到晋国去,梦见太子栾在宗庙中即位,自己和宋平公穿着朝服辅助他。早晨,召见六卿,宋元公说:“寡人没有才能,不能事奉父辈兄辈,成为您几位的忧虑,这是寡人的罪过。如果托诸位的福气,能够保全脑袋而善终,那些用来装载我的骸骨的棺木,请不要超过先君的体制。”仲几回答说:“君王如果由于国家的缘故,自己减损饮宴声色的供奉,下臣们不敢与闻。至于宋国的法度,出生和下葬的礼制,先君早已经有了成文规定了,下臣们用生命来维护它,不敢违背。下臣失职,法律是不能赦免的。下臣不愿这样地死去,只能不听君王的命令。”宋元公就动身了。十三日,死在曲棘。 +十二月十四日,齐景公包围了郓地。 +当初,臧昭伯去到晋国,臧会偷了他的宝龟偻句,臧会用来占卜应该诚实还是不诚实,结果是不诚实吉利。臧氏的家臣将要到晋国问候臧昭伯,臧会请求派他前去。昭伯问起家里的事,臧会全都回答了。昭伯问到妻子和同母弟叔孙,就不回答。再三问他,还是不回答。等到昭伯回国到达郊外,臧会前去迎接。问起那件事,还像从前那样不回答。昭伯抵达国都,先住在城外而查问妻子兄弟,都没有问出什么事。昭伯就抓了臧会要杀他,臧会逃走,逃亡到郈地,郈鲂假让他做了贾正。一次臧会到季氏那里去送帐本,臧氏派五个人带着戈和楯埋伏在桐汝的里门里。臧会出来,就赶上去,臧会转身逃走,在季氏的中门之外被抓住,季氏发怒,说:“为什么带武器进我的家门?”拘留了臧氏的家臣。季氏、臧氏因此互相有了恶感,等到昭伯随从昭公,季氏立了臧会做臧氏的继承人。臧会说:“偻句没有欺骗我呀。” +楚平王派薳射在州屈筑城,让茄地人回去居住。在丘皇筑城,让訾地人迁去居住,派熊相禖在巢地筑外城,派季然在卷地筑外城。子太叔听到了这件事,说:“楚平王快要死了。让百姓不能安居在原来的土地上,百姓必然忧愁,忧愁将要延及到君王的身上,君王不能活长久了。” + +昭公二十六年 +【经】二十有六年春王正月,葬宋元公。三月,公至自齐,居于郓。夏,公围成。秋,公会齐侯、莒子、邾子、杞伯,盟于鄟陵。公至自会,居于郓。九月庚申,楚子居卒。冬十月,天王入于成周。尹氏、召伯、毛伯以王子朝奔楚。 +【传】二十六年春,王正月庚申,齐侯取郓。 +葬宋元公,如先君,礼也。 +三月,公至自齐,处于郓,言鲁地也。 +夏,齐侯将纳公,命无受鲁货。申丰从女贾,以币锦二两,缚一如瑱,适齐师。谓子犹之人高齮:“能货子犹,为高氏后,粟五千庾。”高齮以锦示子犹,子犹欲之。能货子犹,为高氏后,粟五千庚。高齮以锦示子犹,子犹欲之。齮曰:“鲁人买之,百两一布,以道之不通,先入币财。”子犹受之,言于齐侯曰:“群臣不尽力于鲁君者,非不能事君也。然据有异焉。宋元公为鲁君如晋,卒于曲棘。叔孙昭子求纳其君,无疾而死。不知天之弃鲁耶,抑鲁君有罪于鬼神,故及此也?君若待于曲棘,使群臣从鲁君以卜焉。若可,师有济也。君而继之,兹无敌矣。若其无成,君无辱焉。”齐侯从之,使公子锄帅师从公。成大夫公孙朝谓平子曰:“有都以卫国也,请我受师。”许之。请纳质,弗许,曰:“信女,足矣。”告于齐师曰:“孟氏,鲁之敝室也。用成已甚,弗能忍也,请息肩于齐。”齐师围成。成人伐齐师之饮马于淄者,曰:“将以厌众。”鲁成备而后告曰:“不胜众。”师及齐师战于炊鼻。齐子渊捷从泄声子,射之,中楯瓦。繇朐汰輈,匕入者三寸。声子射其马,斩鞅,殪。改驾,人以为鬷戾也而助之。子车曰:“齐人也。”将击子车,子车射之,殪。其御曰:“又之。”子车曰:“众可惧也,而不可怒也。”子囊带从野泄,叱之。泄曰:“军无私怒,报乃私也,将亢子。”又叱之,亦叱之。冉竖射陈武子,中手,失弓而骂。以告平子,曰:“有君子白皙,鬒须眉,甚口。”平子曰:“必子强也,无乃亢诸?”对曰:“谓之君子,何敢亢之?”林雍羞为颜鸣右,下。苑何忌取其耳,颜鸣去之。苑子之御曰:“视下顾。”苑子刜林雍,断其足。{轻金}而乘于他车以归,颜鸣三入齐师,呼曰:“林雍乘!” +四月,单子如晋告急。五月戊午,刘人败王城之师于尸氏。戊辰,王城人、刘人战于施谷,刘师败绩。 +秋,盟于鄟陵,谋纳公也。 +七月己巳,刘子以王出。庚午,次于渠。王城人焚刘。丙子,王宿于褚氏。丁丑,王次于萑谷。庚辰,王入于胥靡。辛巳,王次于滑。晋知跞、赵鞅帅师纳王,使汝宽守关塞。 +九月,楚平王卒。令尹子常欲立子西,曰:“大子壬弱,其母非适也,王子建实聘之。子西长而好善。立长则顺,建善则治。王顺国治,可不务乎?”子西怒曰:“是乱国而恶君王也。国有外援,不可渎也。王有适嗣,不可乱也。败亲、速仇、乱嗣,不祥,我受其名。赂吾以天下,吾滋不从也。楚国何为?必杀令尹!”令尹惧,乃立昭王。 +冬十月丙申,王起师于滑。辛丑,在郊,遂次于尸。十一月辛酉,晋师克巩。召伯盈逐王子朝,王子朝及召氏之族、毛伯得、尹氏固、南宫嚚奉周之典籍以奔楚。阴忌奔莒以叛。召伯逆王于尸,及刘子、单子盟。遂军圉泽,次于堤上。癸酉,王入于成周。甲戌,盟于襄宫。晋师使成公般戍周而还。十二月癸未,王入于庄宫。 +王子朝使告于诸侯曰:“昔武王克殷,成王靖四方,康王息民,并建母弟,以蕃屏周。亦曰:‘吾无专享文、武之功,且为后人之迷败倾覆,而溺入于难,则振救之。’至于夷王,王愆于厥身,诸侯莫不并走其望,以祈王身。至于厉王,王心戾虐,万民弗忍,居王于彘。诸侯释位,以间王政。宣王有志,而后效官。至于幽王,天不吊周,王昏不若,用愆厥位。携王奸命,诸侯替之,而建王嗣,用迁郏鄏。则是兄弟之能用力于王室也。至于惠王,天不靖周,生颓祸心,施于叔带,惠、襄辟难,越去王都。则有晋、郑,咸黜不端,以绥定王家。则是兄弟之能率先王之命也。在定王六年,秦人降妖,曰:‘周其有王,亦克能修其职。诸侯服享,二世共职。王室其有间王位,诸侯不图,而受其乱灾。’至于灵王,生而有。王甚神圣,无恶于诸侯。灵王、景王,克终其世。今王室乱,单旗、刘狄,剥乱天下,壹行不若。谓:‘先王何常之有?唯余心所命,其谁敢请之?’帅群不吊之人,以行乱于王室。侵欲无厌,规求无度,贯渎鬼神,慢弃刑法,倍奸齐盟,傲很威仪,矫诬先王。晋为不道,是摄是赞,思肆其罔极。兹不谷震荡播越,窜在荆蛮,未有攸厎。若我一二兄弟甥舅,奖顺天法,无助狡猾,以从先王之命,毋速天罚,赦图不谷,则所愿也。敢尽布其腹心,及先王之经,实深图之。昔先王之命曰:‘王后无适,则择立长。年钧以德,德钧以卜。’王不立爱,公卿无私,古之制也。穆后及大子寿早夭即世,单、刘赞私立少,以间先王,亦唯伯仲叔季图之!” +闵马父闻子朝之辞,曰:“文辞以行礼也。子朝干景之命,远晋之大,以专其志,无礼甚矣,文辞何为?” +齐有彗星,齐侯使禳之。晏子曰:“无益也,只取诬焉。天道不谄,不贰其命,若之何禳之?且天之有彗也,以除秽也。君无秽德,又何禳焉?若德之秽,禳之何损?《诗》曰:‘惟此文王,小心翼翼,昭事上帝,聿怀多福。厥德不回,以受方国。’君无违德,方国将至,何患于彗?《诗》曰:‘我无所监,夏后及商。用乱之故,民卒流亡。’若德回乱,民将流亡,祝史之为,无能补也。”公说,乃止。 +齐侯与晏子坐于路寝,公叹曰:“美哉室!其谁有此乎?”晏子曰:“敢问何谓也?”公曰:“吾以为在德。”对曰:“如君之言,其陈氏乎!陈氏虽无大德,而有施于民。豆区釜钟之数,其取之公也簿,其施之民也厚。公厚敛焉,陈氏厚施焉,民归之矣。《诗》曰:‘虽无德与女,式歌且舞。’陈氏之施,民歌舞之矣。后世若少惰,陈氏而不亡,则国其国也已。”公曰:“善哉!是可若何?”对曰:“唯礼可以已之。在礼,家施不及国,民不迁,农不移,工贾不变,士不滥,官不滔,大夫不收公利。”公曰:“善哉!我不能矣。吾今而后知礼之可以为国也。”对曰:“礼之可以为国也久矣。与天地并。君令臣共,父慈子孝,兄爱弟敬,夫和妻柔,姑慈妇听,礼也。君令而不违,臣共而不贰,父慈而教,子孝而箴;兄爱而友,弟敬而顺;夫和而义,妻柔而正;姑慈而从,妇听而婉:礼之善物也。”公曰:“善哉!寡人今而后闻此礼之上也。”对曰:“先王所禀于天地,以为其民也,是以先王上之。” +译文 +二十六年春季,周王朝历法的正月初五日,齐景公攻取郓地。 +安葬宋元公,像安葬先君一样,这是符合礼的。 +三月,昭公从齐国到达,住在郓地,这是说已经到了鲁国境内。 +夏季,齐景公准备送昭公回国,命令不要接受鲁国的财礼。申丰跟着女贾,用两匹锦缎作为财礼,捆紧在一起像一块瑱圭,到齐军中去,对子犹的家臣高齮说:“如果你能收买子犹,我们让你当高氏的继承人,给你五千庾粮食。”高齮把锦给子犹看,子犹想要。高齮说:“鲁国人买得很多,一百匹一堆,由于道路不畅通,先把这点礼品送来。”子犹收下了礼物,对齐景公说:“臣下们对鲁国国君不肯尽力,不是不能奉行君命,然而据却感到奇怪。宋元公为了鲁国国君去到晋国,死在曲棘。叔孙昭子请求让他的国君复位,无病而死。不知道是上天抛弃鲁国呢,还是鲁国国君得罪了鬼神所以才到这地步呢?君王如果在曲棘等待,派臣下们跟从鲁国国君试探向鲁作战可胜与否。如果行,军事有了成功,君王就继续前去,这就不会有抵抗的人了。如果没有成功,就不必麻烦君王了。”齐景公听从了他的话,派公子鉏带兵跟从昭公。 +成大夫公孙朝对平子说:“城市,是用来保卫国家的,请让我们来抵御齐军。”平子答应了。公孙朝请求送上人质,平子不答应,说:“相信你,这就够了。”公孙朝告诉齐军说:“孟氏,是鲁国的破落户。他们使用成地太过分了,我们不能忍受,请求降服于齐国以便休息。”齐军就包围成地。成地的军队进攻在淄水饮马的齐军,说:“这是做给大家看的。”鲁国准备充分以后告诉齐国人说:“我们拗不过大家。” +鲁军和齐军在炊鼻作战,齐国的子渊捷追赶泄声子,用箭射泄声子,射中盾脊,箭从横木穿过车辕,箭头射进盾脊三寸。泄声子用箭射子渊捷的马,射断马颈上的皮带,马倒地死去。子渊捷改乘别的战车,鲁国人误认为他是鬷戾,就上去帮他,子渊捷说:“我是齐国人。”鲁国人将要攻击子渊捷,子渊捷一箭射去,射死了鲁国人。子囊带的赶车人说:“再射。”子渊捷说:“大队人马可以让他们害怕,而不能激怒他们。”子囊带追赶声子,叱骂他。声子说:“作战的时候没有个人的愤怒,我回骂就是为私人了,我将要抵挡您一阵。”子渊捷还是叱骂声子,声子也就回骂他。冉竖用箭射陈武子,谢中手,弓落到地上而大骂。冉竖报告平子,说:“有一个君子皮肤白胡子眉毛黑而密,很会骂人。”平子说:“一定是子彊,不是抵挡了他吧?”冉竖回答说:“既称他为君子,怎么敢抵挡他?”林雍不愿意做颜鸣的车右,下车,苑何忌割了他的耳朵,颜鸣要把他带走。苑何忌的赶车人说:“朝下看!”就看着林雍的脚。苑何忌砍斫林雍,砍断了他的一只脚,林雍用一只脚跳上别的战车逃回来,颜鸣三次冲进齐军,大喊说:“林雍来坐车!” +四月,单子到晋国去报告紧急情况。五月初五日,刘国人在尸氏打败了王城的军队。十五日,王城人、刘国人在施谷作战,刘军大败。 +秋季,鲁昭公和齐景公、莒子、邾子、杞伯在鄟陵结盟,这是为了谋划送昭公回国。 +七月十七日,刘子带了周敬王出去。十八日,住在渠地,王城的军队放火烧了刘子的城邑。二十四日,周敬王住在褚氏。二十五日,周敬王住在萑谷。二十八日,周敬王进入胥靡。二十九日,周敬王住在滑地。晋国的知跞、赵鞅领兵接纳周敬王,派汝宽镇守阙塞。 +九月,楚平王死去,令尹子常想要立子西,说:“太子壬年纪小,他的母亲不是正妻,而是王子建所聘的,子西年纪大而喜好善良,立年长就顺于情理,建立善良的国家就得治。君王顺理国家太平,能不努力去做吗?”子西发怒说:“这是扰乱国家,宣扬君王的坏事,国家有外援,不能轻慢。君王有嫡出的继承人,不能混乱。败坏亲人、召来仇敌、混乱继承人,不吉利,我会蒙受恶名。即使用天下来贿赂我,我也是不能听从的,楚国有什么用?一定要杀死令尹。”令尹恐惧,就立了楚昭王。 +冬季,十月十六日,周敬王在滑地起兵。二十一日,在郊地,就住在尸地。十一月十一日,晋军攻下巩地,召伯盈赶走了王子朝。王子朝和召氏的族人、毛伯得、尹氏固、南宫嚚保护着周朝的典籍逃亡楚国,阴忌逃亡莒地叛变。召伯盈在尸地迎接周敬王,和刘子、单子结盟。于是就驻扎在圉泽,住在堤上。二十三日,周敬王进入成周。二十四日,在襄王的庙里盟誓。晋军派成公般在成周戍守,就回去了。十二月初四日,周敬王进入庄宫。 +王子朝派人报告诸侯说:“从前武王战胜殷朝,成王安定四方,康王与民休息,一起分封同母兄弟,以此作为周朝的屏障,还说:“我不能独自承受文王、武王的功业,而且还是为了后代,一旦荒淫败坏而陷入危难,就可以拯救他。”到了夷王,恶疾缠身,诸侯没有不遍祭境内的名山大川,为夷王的健康作祈祷。到了厉王,他的内心乖张暴虐,老百姓不能忍受,就让他住到彘地去。诸侯各自离开他们的职位,来参与王朝的政事。宣王有知识,然后把王位奉还给了他。到了幽王,上天不保佑周朝,天子昏乱不顺,因此失去王位。携王触犯天命,诸侯废弃了他,立了继承人,因此迁都到郏鄏。这就是由于兄弟们为王室出力。到了惠王,上天不使周朝安定,使颓生出祸心,波及于叔带。惠王、襄王避难,离开了国都。这时候就有晋国、郑国都来驱走不正派的人,以安定王室。这就是由于兄弟们遵先王的命令。在定王六年的时候,秦国人中降下妖孽,说:“周朝会有一个长胡子的天子,也能够完成自己的职分。使诸侯顺服而享有国家,两代谨守自己的职分,王室中有人觊觎王位,诸侯不为王室图谋,受到了动乱灾祸。”到了灵王,生下来就有胡子,他十分神奇聪明,对诸侯没有做什么恶事。灵王、景王都能善始善终。 +“现在王室动乱,单旗、刘狄搅乱天下,专门倒行逆施,说:‘先王登位根据什么常规?只要我心里想立谁,有谁敢来讨伐?’带了一些不好的人,以此在王室中制造混乱。他们侵吞没有满足,贪求没有限度,惯于亵渎鬼神,轻慢抛弃刑法,违背触犯盟约,蔑视礼制,诬蔑先王。晋国无道,对他们加以赞助,无限度放纵他们。现在我动荡流离,逃窜到荆蛮,还没有归宿。如果我们一两位兄弟甥舅顺从上天的法度,不要帮助狡猾之徒,以服从先王的命令,不要招来上天的惩罚,除去我的忧虑并为我谋划,就是我的愿望了。谨敢完全披露腹心和先王的命令,希望诸侯认真地考虑一下。 +“从前先王的命令说:‘王后没有嫡子,就选立年长的,年纪相当根据德行,德行相当根据占卜。’天子不立偏爱,公卿没有私心,这是古代的制度。穆后和太子寿早年去世,单氏、刘氏偏立了年幼的,来违犯先王的命令。请所有长于我或小于我的诸侯考虑一下。” +闵马父听到王子朝的辞令,说:“文辞是用来实行礼的。子朝违背了周景王的命令,疏远晋国这个大国,一心一意想做天子,太不讲礼了,文辞有什么用处?” +齐国出现彗星,齐景公派人祭祀消灾。晏子说:“没有益处的,只能招来欺骗。天道不可怀疑,不能使它有所差错,怎么能去祭祷?而且上天的有彗星,是用来清除污秽的。君王没有污秽的德行,又祭祷什么?如果德行污秽,祭祷又能减轻什么?《诗》说:‘这个文王,小心恭敬。隆重地事奉天帝,求取各种福禄,他的德行不违背天命,接受着四方之国。’君王没有违德的事,四方的国家将会来到,为什么怕有彗星?《诗》说:“我没有什么借鉴,要有就是夏后和商,由于政事混乱,百姓终于流亡。’如果德行违背天命而混乱,百姓将要流亡,祝史的所作所为,于事无补。”齐景公很高兴,就停止了祭祷。 +齐景公和晏子在路寝里坐着,齐景公叹气说:“多么漂亮的房子啊!是谁会据有这里呢?”晏子说:“请问,这是什么意思?”齐景公说:“我认为在于有德行的人。”晏子说:“像君王所说,恐怕在于陈氏吧!陈氏虽然没有大的德行,然而对百姓有施舍。豆、区、釜、钟这几种量器的容积,从公田征税时就用小的,向百姓施舍时就用大的。您征税多,陈氏施舍多,百姓倾向于他了。《诗》说:‘虽然没有德行给予你,也应当且歌且舞。’陈氏的施舍,百姓已经为之歌舞了。您的后代如果稍稍怠惰,陈氏又如果不灭亡,他的封地就变成国家了。”齐景公说:“对啊!这可怎么办?”晏子回答说:“只有礼可以制止这个,如果符合礼,家族的施舍不能扩大到国内,百姓不迁移,农夫不变动,工人、商人不改行,士不失职,官吏不怠慢,大夫不占取公家的利益。”齐景公说:“对呀!我不能做到了。我从今以后开始知道礼能够用来治理国家了。”晏子回答说:“礼可以治理国家,由来很久了,和天地相等。国君发令,臣下恭敬,父亲慈爱,儿子孝顺,哥哥仁爱,弟弟恭敬,丈夫和蔼,妻子温柔,婆婆慈爱,媳妇顺从,这是合于礼的。国君发令而不违背礼,臣下恭敬而没有二心,父亲慈爱而教育儿子,儿子孝顺而规劝父亲,哥哥仁爱而友善,弟弟恭敬而顺服,丈夫和蔼而知义,妻子温柔而正直,婆婆慈爱而肯听从规劝,媳妇顺从而能委婉陈辞,这又是礼中的好事情。”齐景公说:“对呀!我从今以后开始听到了礼应当加以崇尚了。”晏子回答说:“先王从天地那里接受了礼以治理百姓,所以先王尊崇礼。” + + +昭公二十七年 +【经】二十有七年春,公如齐。公至自齐,居于郓。夏四月,吴弑其君僚。楚杀其大夫郤宛。秋,晋士鞅、宋乐祁犁、卫北宫喜、曹人、邾人、滕人会于扈。冬十月,曹伯午卒。邾快来奔。公如齐。公至自齐,居于郓。 +【传】二十七年春,公如齐。公至自齐,处于郓,言在外也。 +吴子欲因楚丧而伐之,使公子掩余、公子烛庸帅师围潜。使延州来季子聘于上国,遂聘于晋,以观诸侯。楚莠尹然,工尹麇帅师救潜。左司马沈尹戌帅都君子与王马之属以济师,与吴师遇于穷。令尹子常以舟师及沙汭而还。左尹郤宛、工尹寿帅师至于潜,吴师不能退。 +吴公子光曰:“此时也,弗可失也。”告鱄设诸曰:“上国有言曰:‘不索何获?’我,王嗣也,吾欲求之。事若克,季子虽至,不吾废也。”鱄设诸曰:“王可弑也。母老子弱,是无若我何。”光曰:“我,尔身也。” +夏四月,光伏甲于堀室而享王。王使甲坐于道,及其门。门阶户席,皆王亲也,夹之以铍。羞者献体改服于门外,执羞者坐行而入,执铍者夹承之,及体以相授也。光伪足疾,入于堀室。鱄设诸置剑于鱼中以进,抽剑剌王,铍交于胸,遂弑王。阖庐以其子为卿。 +季子至,曰:“苟先君废无祀,民人无废主,社稷有奉,国家无倾,乃吾君也。吾谁敢怨?哀死事生,以待天命。非我生乱,立者从之,先人之道也。”覆命哭墓,复位而待。吴公子掩余奔徐,公子烛庸奔钟吾。楚师闻吴乱而还。 +郤宛直而和,国人说之。鄢将师为右领,与费无极比而恶之。令尹子常贿而信谗,无极谮郤宛焉,谓子常曰:“子恶欲饮子酒。”又谓子恶:“令尹欲饮酒于子氏。”子恶曰:“我,贱人也,不足以辱令尹。令尹将必来辱,为惠已甚。吾无以酬之,若何?”无极曰:“令尹好甲兵,子出之,吾择焉。”取五甲五兵,曰:“置诸门,令尹至,必观之,而从以酬之。”及飨日,帷诸门左。无极谓令尹曰:“吾几祸子。子恶将为子不利,甲在门矣,子必无往。且此役也,吴可以得志,子恶取赂焉而还,又误群帅,使退其师,曰:‘乘乱不祥。’吴乘我丧,我乘其乱,不亦可乎?”令尹使视郤氏,则有甲焉。不往,召鄢将师而告之。将师退,遂令攻郤氏,且爇之。子恶闻之,遂自杀也。国人弗爇,令曰:“爇郤氏,与之同罪。”或取一编菅焉,或取一秉秆焉,国人投之,遂弗也。令尹炮之,尽灭郤氏之族党,杀阳令终与其弟完及佗与晋陈及其子弟。晋陈之族呼于国曰:“鄢氏、费氏自以为王,专祸楚国,弱寡王室,蒙王与令尹以自利也。令尹尽信之矣,国将如何?”令尹病之。 +秋,会于扈,令戍周,且谋纳公也。宋、卫皆利纳公,固请之。范献子取货于季孙,谓司城子梁与北宫贞子曰:“季孙未知其罪,而君伐之,请囚,请亡,于是乎不获。君又弗克,而自出也。夫{山乙}无备而能出君乎?季氏之复,天救之也。休公徒之怒,而启叔孙氏之心。不然,岂其伐人而说甲执冰以游?叔孙氏惧祸之滥,而自同于季氏,天之道也。鲁君守齐,三年而无成。季氏甚得其民,淮夷与之,有十年之备,有齐、楚之援,有天之赞,有民之助,有坚守之心,有列国之权,而弗敢宣也,事君如在国。故鞅以为难。二子皆图国者也,而欲纳鲁君,鞅之愿也,请从二子以围鲁。无成,死之。”二子惧,皆辞。乃辞小国,而以难复。 +孟懿子、阳虎伐郓。郓人将战,子家子曰:“天命不慆久矣。使君亡者,必此众也。天既祸之,而自福也,不亦难乎?犹有鬼神,此必败也。乌呼!为无望也夫,其死于此乎!”公使子家子如晋,公徒败于且知。 +楚郤宛之难,国言未已,进胙者莫不谤令尹。沈尹戌言于子常曰:“夫左尹与中厩尹莫知其罪,而子杀之,以兴谤讟,至于今不已。戌也惑之。仁者杀人以掩谤,犹弗为也。今吾子杀人以兴谤,而弗图,不亦异乎?夫无极,楚之谗人也,民莫不知。去朝吴,出蔡侯朱,丧太子建,杀连尹奢,屏王之耳目,使不聪明。不然,平王之温惠共俭,有过成、庄,无不及焉。所以不获诸侯,迩无极也。今又杀三不辜,以兴大谤,几及子矣。子而不图,将焉用之?夫鄢将师矫子之命,以灭三族,国之良也,而不愆位。吴新有君,疆埸日骇,楚国若有大事,子其危哉!知者除谗以自安也,今子爱谗以自危也,甚矣其惑也!”子常曰:“是瓦之罪,敢不良图。”九月己未,子常杀费无极与鄢将师,尽灭其族,以说于国。谤言乃止。 +冬,公如齐,齐侯请飨之。子常子曰:“朝夕立于其朝,又何飨焉?其饮酒也。”乃饮酒,使宰献,而请安。子仲之子曰重,为齐侯夫人,曰:“请使重见。”子家子乃以君出。 +十二月,晋籍秦致诸侯之戍于周,鲁人辞以难。 +译文 +二十七年春季,昭公到齐国去。昭公从齐国回来,住在郓地,这是说住在国都以外。 +吴王想要借楚国有丧事的机会进攻楚国,派公子掩馀、公子烛庸领兵包围潜地,派延州来季子到中原各国聘问。季子到晋国聘问,以观察诸侯的态度。楚国的莠尹然、工尹麇领兵救援潜地,左司马沈尹戌率领都邑亲兵和王马的部属增援部队,和吴军在穷地相遇。令尹子常带着水军到了沙汭而回来,左尹郤宛、工尹寿领兵到达潜地,吴军不能撤退。 +吴国的公子光说:“这是机会,不能失去了。”告诉鱄设诸说:“中原的国家有话说:‘不去寻求,哪里能够得到王位。’我是王位的继承人,我就要寻求。事情如果成功,季子虽然来到,也不能废掉我。” 鱄设诸说:“君王是可以杀掉的。但是我母亲老了,儿子还小,我拿他们没有办法。”公子光说:“我,就是你。” +夏季,四月,公子光在地下室埋伏甲士而设享礼招待吴王。吴王让甲士坐在道路两旁,一直到大门口。大门、台阶、里门、坐席上,都是吴王的亲兵,手持短剑护卫在吴王两旁,端菜的人在门外先脱光衣服再换穿别的衣服,端菜的人膝行而入,持剑的人用剑夹着他,剑尖几乎碰到身上,然后才递给上菜的人。公子光假装有病,躲进地下室,鱄设诸把剑放在鱼肚子里然后进入,抽出剑猛刺吴王,两旁亲兵的短剑也交叉刺进了鱄设诸的胸膛,结果还是杀死了吴王。阖庐让鱄设诸的儿子做了卿。 +季子到达,说:“如果先君没有废弃祭祀,百姓没有废弃主子,土地和五谷之神有人奉献,国家和家族没有颠覆,他就是我的国君。我敢怨恨谁?哀痛死去的,事奉活着的,以等待天命。不是我发起了动乱,谁立为国君,我就服从谁,这是先代的常法。”到坟墓前哭泣复命,回到自己原来的官位上等待命令。吴国的公子掩馀逃奔徐国,公子烛庸逃亡钟吾,楚军听说吴国发生动乱就收兵返回。 +郤宛正直而和善,国内的人们都喜欢他。鄢将师做右领,和费无极勾结,憎恨郤宛。令尹子常贪求财物而相信诬蔑人的话,费无极就诬陷郤宛,对子常说:“郤宛要请您喝酒。”又对郤宛说:“令尹要到您家里去喝酒。”郤宛说:“我是下贱的人,不足以让令尹到这里来。令尹如果真想要前来,赐给我的恩惠就太大了。我没有东西奉献,怎么办?”费无极说:“令尹喜欢皮甲武器,您拿出来,我来挑选。”选取了五领皮甲,五种武器,说:“放在门口,令尹到来,一定要观看,就乘机献给他。”等到举行享礼的那一天,郤宛把皮甲武器放在门边的帐幔里,费无极对令尹说:“我几乎让您遭祸,郤宛打算对您不利,皮甲和武器都放在门口了。您一定不要去!况且这次潜地的战役,本来楚国可以得志于吴国,郤宛受了贿赂而回来,又贻误了将领们,让他们退兵,说‘乘人动乱而进攻,不吉祥’。吴国乘我们有丧事,我们乘他们的动乱,不也是可以的吗?”令尹让人到郤氏那里看动静,就看到有皮甲和武器在门口。令尹不去郤家了,便召见鄢将师并把情况告诉他,鄢将师退下,就下令攻打郤氏,并且放火烧了他的家。郤宛听到消息,就自杀了。国内的人们不肯放火,鄢将师下令说:“不烧郤家,和他同罪。”有人拿着一张席子,有人拿着一把稻草,国内的人们都拿去扔掉,因此没有烧着,令尹派人烧了郤家,把郤氏的族人、亲属全都消灭,杀了阳令终和他的弟弟完及佗,还杀了晋陈和他的子弟。晋陈的族人在国都里喊叫说:“鄢氏、费氏以君王自居,专权而祸乱楚国,削弱孤立王室,蒙蔽君王和令尹来为自己牟利。令尹全都相信他们了,国家将要怎么办?”令尹很担心。 +秋季,晋国士鞅、宋国乐祁犁、卫国北宫喜、曹人、邾人、滕人在扈地会见,这是为了命令去成周戍守,同时商量送回昭公。宋国、卫国都认为送回昭公对自己国家有利,坚决地请求。范献子在季孙那里取得了财礼,对司城子梁和北宫贞子说:“季孙还不知道他自己的罪过,而国君攻打他,他请求囚禁、请求逃亡,在当时都得不到同意。国君又没有战胜他,就自己出国了,难道没有防备而能赶走国君吗?季氏恢复原来的职位,是上天挽救了他,止息了昭公亲兵的愤怒,启发了叔孙氏的心意。不是这样,难道那些人攻打别人反而脱下皮甲手拿箭筒在那里玩?叔孙氏害怕祸难的泛滥,因而自愿和季氏站在一边,这是上天的意志。鲁国的国君请求齐国帮助,三年没有成功。季氏很受百姓的拥护,淮夷亲附他,有打十年的准备,有齐国、楚国的支援,有上天的赞助,有百姓的帮助,有坚守的决心,有诸侯一样的权势,但没有敢把事情公开,事奉国君像在国内一样。所以鞅认为难办。您二位都是为国家考虑的人,想要送回鲁国国君,这也是鞅的愿望。请跟随您二位去包围鲁国,如果不成功,我就为此而死。”这二位害怕,都辞谢了。于是就辞退小国,而答复晋国说事情不好办。 +孟懿子、阳虎进攻郓地,郓地人准备迎战。子家子说:“天命无可怀疑已经很久了,让国君逃亡的,一定就是这批人。上天已经降祸于国君,而要自己求福,不也是很困难吗?如果有鬼神,这一战必然失败。啊!没有希望了吧!恐怕要死在这里了吧!”昭公派子家子到晋国去。昭公的亲兵在且知被打败。 +楚国郤宛的祸难,国内的怨言没有停止,进胙肉的人无不指责令尹,沈尹戌对令尹子常说:“左尹和中厩尹,没有人知道他们的罪过,而您杀了他们,招致指责,到现在没有停止。戌很怀疑:仁爱的人杀了人来掩盖指责,他还不干呢,现在您杀了人来招致指责,而不考虑补救办法,不也很奇怪吗?那个费无极,是楚国的坏人,百姓没有不知道的。去掉朝吴、赶走蔡侯朱、丧失太子建、杀害连尹伍奢,遮蔽君王的耳目,让他听不清看不明。如果不是这样,平王的温和仁慈,恭敬节俭,有超过成王、庄王而没有不及他们的地方。所以还得不到诸侯的拥戴,是由于接近了费无极。现在又杀了三个无罪的人,招致了极大的指责,几乎要牵涉到您身上了。而您不去想办法,哪里还用得着您?鄢将师假传您的命令,消灭了三个家族。这三个家族,都是国家杰出的良材,在位没有过错。吴国新近立了国君,边境一天天紧张。楚国如果发生战事,您恐怕危险了!聪明人消除诬陷来使自己安定,现在您喜欢谗人来使自己危险,您的昏庸也太过份了!”令尹子常说:“这是我的罪过,岂敢不好好想一下!”九月十六日,令尹子常杀了费无极和鄢将师,把他们的族人全部消灭了,来让国内的人们高兴,于是怨谤的言论就停止了。 +冬季,昭公到齐国去,齐景公请求设享礼招待他。子家子说:“每天早晚都在他的朝廷上,又设享礼干什么?还是喝酒吧。”于是就喝酒,让宰臣向昭公敬酒,自己却请求退席。子仲的女儿名叫重,是齐景公的夫人,齐景公说:“请让重出来见您。”子家子就带着昭公出去了。 +十二月,晋国的籍秦把诸侯的戍卒送到成周,鲁国人用发生祸难为理由,辞谢不去。 + +昭公二十八年 +【经】二十有八年春王三月,葬曹悼公。公如晋,次于乾侯。夏四月丙戌,郑伯宁卒。六月,葬郑定公。秋七月癸巳,滕子宁卒。冬,葬滕悼公。 +【传】二十八年春,公如晋,将如乾侯。子家子曰:“有求于人,而即其安,人孰矜之?其造于竟。”弗听。使请逆于晋。晋人曰:“天祸鲁国,君淹恤在外。君亦不使一个辱在寡人,而即安于甥舅,其亦使逆君?”使公复于竟而后逆之。 +晋祁胜与邬臧通室,祁盈将执之,访于司马叔游。叔游曰:“《郑书》有之:‘恶直丑正,实蕃有徒。’无道立矣,子惧不免。《诗》曰:‘民之多辟,无自立辟。’姑已,若何?”盈曰:“祁氏私有讨,国何有焉?”遂执之。祁胜赂荀跞,荀跞为之言于晋侯,晋侯执祁盈。祁盈之臣曰:“钧将皆死,憖使吾君闻胜与臧之死以为快。”乃杀之。夏六月,晋杀祁盈及杨食我。食我,祁盈之党也,而助乱,故杀之。遂灭祁氏、羊舌氏。 +初,叔向欲娶于申公巫臣氏,其母欲娶其党。叔向曰:“吾母多而庶鲜,吾惩舅氏矣。”其母曰:“子灵之妻杀三夫,一君,一子,而亡一国、两卿矣。可无惩乎?吾闻之:‘甚美必有甚恶,’是郑穆少妃姚子之子,子貉之妹也。子貉早死,无后,而天钟美于是,将必以是大有败也。昔有仍氏生女,鬒黑而甚美,光可以鉴,名曰玄妻。乐正后夔取之,生伯封,实有豕心,贪婪无餍,忿类无期,谓之封豕。有穷后羿灭之,夔是以不祀。且三代之亡,共子之废,皆是物也。女何以为哉?夫有尤物,足以移人,苟非德义,则必有祸。”叔向惧,不敢取。平公强使取之,生伯石。伯石始生,子容之母走谒诸姑,曰:“长叔姒生男。”姑视之,及堂,闻其声而还,曰:“是豺狼之声也。狼子野心,非是,莫丧羊舌氏矣。”遂弗视。 +秋,晋韩宣子卒,魏献子为政。分祁氏之田以为七县,分羊舌氏之田以为三县。司马弥牟为邬大夫,贾辛为祁大夫,司马乌为平陵大夫,魏戊为梗阳大夫,知徐吾为涂水大夫,韩固为马首大夫,孟丙为盂大夫,乐霄为铜鞮大夫,赵朝为平阳大夫,僚安为杨氏大夫。谓贾辛、司马乌为有力于王室,故举之。谓知徐吾、赵朝、韩固、魏戊,余子之不失职,能守业者也。其四人者,皆受县而后见于魏子,以贤举也。 +魏子谓成鱄:“吾与戊也县,人其以我为党乎?”对曰:“何也?戊之为人也,远不忘君,近不逼同,居利思义,在约思纯,有守心而无淫行。虽与之县,不亦可乎?昔武王克商,光有天下。其兄弟之国者十有五人,姬姓之国者四十人,皆举亲也。夫举无他,唯善所在,亲疏一也。《诗》曰:‘唯此文王,帝度其心。莫其德音,其德克明。克明克类,克长克君。王此大国,克顺克比。比于文王,其德靡悔。既受帝祉,施于孙子。’心能制义曰度,德正应和曰莫,照临四方曰明,勤施无私曰类,教诲不倦曰长,赏庆刑威曰君,慈和遍服曰顺,择善而从之曰比,经纬天地曰文。九德不愆,作事无悔,故袭天禄,子孙赖之。主之举也,近文德矣,所及其远哉!” +贾辛将适其县,见于魏子。魏子曰:“辛来!昔叔向适郑,鬲□蔑恶,欲观叔向,从使之收器者而往,立于堂下。一言而善。叔向将饮酒,闻之,曰:‘必鬷明也。’下,执其手以上,曰‘昔贾大夫恶,娶妻而美,三年不言不笑,御以如皋,射雉,获之。其妻始笑而言。贾大夫曰:“才之不可以已,我不能射,女遂不言不笑夫!”今子少不扬,子若无言,吾几失子矣。言不可以已也如是。’遂知故在。今女有力于王室,吾是以举女。行乎!敬之哉!毋堕乃力!” +仲尼闻魏子之举也,以为义,曰:“近不失亲,远不失举,可谓义矣。”又闻其命贾辛也,以为忠:“《诗》曰:‘永言配命,自求多福’,忠也。魏子之举也义,其命也忠,其长有后于晋国乎!” +冬,梗阳人有狱,魏戊不能断,以狱上。其大宗赂以女乐,魏子将受之。魏戊谓阎没、女宽曰:“主以不贿闻于诸侯,若受梗阳人,贿莫甚焉。吾子必谏。”皆许诺。退朝,待于庭。馈入,召之。比置,三叹。既食,使坐。魏子曰:“吾闻诸伯叔,谚曰:‘唯食忘忧。’吾子置食之间三叹,何也?”同辞而对曰:“或赐二小人酒,不夕食。馈之始至,恐其不足,是以叹。中置,自咎曰:‘岂将军食之,而有不足?’是以再叹。及馈之毕,愿以小人之腹为君子之心,属厌而已。”献子辞梗阳人。 +译文 +二十八年春季,鲁昭公到晋国去,将要到乾侯去。子家子说:“有求于别人,而又跑去安安稳稳地住着,有谁还来同情您,还是到我国和晋国的边境上等着好。”昭公不听,派人请求晋国来人迎接。晋国人说:“上天降祸鲁国,君王淹留在外,也不派一个人来问候寡人,而是跑去安安稳稳地住在甥舅的国家里,难道还要派人到齐国迎接君王?”让昭公回到鲁国的边境上,然后派人迎接。 +晋国的祁胜和邬臧互相交换妻子。祁盈准备逮捕他们,去问司马叔游。叔游说:“《郑书》有这样的话:‘嫉害正直,这样的人多的是。’无道的人在位,您恐怕不能免于祸患。《诗》说:‘百姓的邪恶很多,自己不要再陷入邪恶。’暂时不执行,怎么样?”祁盈说:“对祁氏私家的讨伐,和国家有什么关系?”于是就逮捕了他们。祁胜贿赂荀跞,荀跞为他在晋顷公面前说话。晋顷公逮捕了祁盈,祁盈的家臣说:“同样是一起被杀,宁可让我们主子听到祁胜和邬臧的死讯,我们也可以痛快一下。”就杀了这两个人。夏季,六月,晋顷公杀了祁盈和杨食我,杨食我,是祁盈的党羽,并且帮着祁盈作乱,所以杀了他,于是就灭亡了祁氏、羊舌氏。 +起初,叔向想要娶申公巫臣的女儿做妻子,他的母亲要他娶她的亲族。叔向说:“我的母亲多而庶兄弟少,舅家女儿不易生子,我把这作为鉴戒了。”他的母亲说:“巫臣的妻子杀死三个丈夫,一个国君,一个儿子,灭亡一个国家,使两个卿逃亡了,能够不作为鉴戒吗?我听说:‘很美丽必然有很丑恶的一面。’那个人是郑穆公少妃姚子的女儿,子貉的妹妹,子貉早死,没有后代,而上天把美丽集中在她身上,必然是要用她来大大地败坏事情。从前有仍氏生了一个女儿,头发稠密乌黑而非常美丽,头发的光泽可以照见人影,名叫‘玄妻’。乐官之长后夔娶了她,生下伯封,心地和猪一样,贪婪没有个满足,暴躁乖戾没有限度,人们叫他大猪。有穷后羿灭了他,夔因此而不能得到祭祀。而且夏、商、周三代的被灭亡,公子申生的被废,都是由于美色为害。你娶她做什么呢?有了特别美丽的女人,就完全可以使人改变。如果不是极有道德正义的人娶她,就必然有祸。”叔向害怕,不敢娶了。晋平公强迫叔向娶了她,生了杨食我。杨食我刚生下来,子容的母亲跑去告诉婆婆,说:“大弟媳妇生了个男孩。”叔向的母亲走去看看,走到堂前,听到孩子的哭声就往回走,说:“这是豺狼的声音。豺狼似的男子,必然有野心。不是这个人,没有人会毁掉羊舌氏。”于是就不去看他。 +秋季,晋国的韩宣子死了,魏献子执政。把祁氏的土田分割为七个县,把羊舌氏的土田分割为三个县。司马弥牟做邬大夫,贾辛做祁大夫,司马乌做平陵大夫,魏戊做梗阳大夫,知徐吾做涂水大夫,韩固做马首大夫,孟丙做盂大夫,乐霄做铜鞮大夫,赵朝做平阳大夫,僚安做杨氏大夫。认为贾辛、司马乌曾经给王室出过力,所以举拔他们。认为知徐吾、赵朝、韩固、魏戊,是卿的庶子中不失职、能够保守家业的人。另外四个人,都先接受县的职务然后进见魏献子,是由于贤能而加以提拔的。 +魏献子对成鱄说:“我把一个县给了戊,别人会以为我是偏袒吗?”成鱄回答说:“哪里会呢?戊的为人,远不忘国君,近不逼同事,处在有利的地位上想到道义,处在困难之中想到保持纯正,有保持礼义之心而没有过度的行动,即使给了他一个县,不也是可以的吗!从前武王战胜商朝,广有天下,他的兄弟领有封国的十五人,姬姓领有封国的四十人,都是举拔自己的亲属。举拔没有别的条件,只要是善的所在,亲密、疏远都是一样的。《诗》说:‘只有这位文王,上帝审度了他的内心,认定了他的美德名声,他的德行在于是非明辨,是非明辨就能为善,就能为人师长做人君王,成为这个大国的君主,能使四方顺服。与文王一样,他的德行,从没有悔恨。既承受了上帝的福佑,还要延及到他的子子孙孙。’内心能制约于道义叫做‘度’,德行端正反应和谐叫做‘莫’,光照四方叫做‘明’,勤于施舍没有私心叫做‘类’,教导别人不知疲倦叫做‘长’,严明赏罚显示威严叫做‘君’,慈祥和顺使别人归服叫做‘顺’,选择好的而跟从叫做‘比’,用天地作经纬叫做‘文’。这九种德行不出过错,做事情就没有悔恨,所以承袭上天的福禄,以利于子子孙孙。现在您的举拔,已经接近文王的德行了,影响会很深远的啊!” +贾辛将要到他的县里去,进见魏献子。魏献子说:“辛,过来!从前叔向到郑国去,鬷蔑氏得丑,想要观察叔向,就跟着收拾器皿的人前去,而站在堂下,说了一句话,说得很好。叔向正要喝酒,听到了鬷蔑的话,说:‘一定是鬷蔑。’走下堂来,拉着他的手上堂,说:‘从前贾大夫长得丑,娶了个妻子却很美,三年不说不笑。贾大夫为她驾着车子去到沼泽地,射野鸡,射中,她才笑着说话。贾大夫说:“才能是不能没有的,我要是不能射箭,你就不说不笑了啊!”现在您的外貌不扬,您如果再不说话,我几乎错过和您见面的机会了。话不能不说,就像这一样。’两个人就像老朋友一样。现在你为王室出了力,我因此举拔你。动身吧!保持着恭敬,不要损毁了你的功劳。” +孔子听到魏献子举拔的事,认为合于道义,说:“举拔近的而不失去亲族,举拔远的而不失去应当举拔的人,可以说是合于道义了。”又听说他命令贾辛的话,认为体现了忠诚,说:“《诗》说,‘永远符合于天命,自己求取各种福禄’,这是忠诚。魏子举拔合于道义,他的命令又体现了忠城,恐怕他的后代会在晋国长享禄位吧!” +冬季,梗阳人有诉讼,魏戊不能判断,把案件上报给魏献子。诉讼一方的大宗把女乐送给魏献子,魏献子准备接受。魏戊对阎没、女宽说:“主人以不接受贿赂名闻于诸侯,如果收下梗阳人的女乐,就没有比这再大的贿赂了。您二位一定要劝谏。”两个人都答应了。退朝以后,在庭院里等待。送饭菜进来,魏献子叫他们二人吃饭。等到摆上饭菜,两个人三次叹气。吃完了,让他们坐下。魏献子说:“我从我伯父、叔父那里听说过:‘只有吃饭的时候忘记忧愁。’您二位在摆上饭菜的时候三次叹气,为什么?”两个人异口同声说:“有人把酒赐给我们两个小人,昨天没有吃晚饭。饭菜刚送到,恐怕不够吃,所以叹气。上菜上了一半,就责备自己说:‘难道将军让我们吃饭会不够吃?’所以再次叹气。等到饭菜上完,愿意把小人的肚子作为君子的内心,刚刚满足就行了。”魏献子辞谢了梗阳人的贿赂。 + +昭公二十九年 +【经】二十有九年春,公至自乾侯,居于郓,齐侯使高张来唁公。公如晋,次于乾侯。夏四月庚子,叔诣卒。秋七月。冬十月,郓溃。 +【传】二十九年春,公至自乾侯,处于郓。齐侯使高张来唁公,称主君。子家子曰:“齐卑君矣,君只辱焉。”公如乾侯。 +三月己卯,京师杀召伯盈、尹氏固及原伯鲁之子。尹固之复也,有妇人遇之周郊,尤之,曰:“处则劝人为祸,行则数日而反,是夫也,其过三岁乎?” +夏五月庚寅,王子赵车入于鄻以叛,阴不佞败之。 +平子每岁贾马,具从者之衣屦,而归之于乾侯。公执归马者,卖之,乃不归马。卫侯来献其乘马曰启服,堑而死,公将为之椟。子家子曰:“从者病矣,请以食之。”乃以帏裹之。 +公赐公衍羔裘,使献龙辅于齐侯,遂入羔裘。齐侯喜,与之阳谷。公衍、公为之生也,其母偕出。公衍先生,公为之母曰:“相与偕出,请相与偕告。”三日,公为生,其母先以告,公为为兄。公私喜于阳谷而思于鲁,曰:“务人为此祸也。且后生而为兄,其诬也久矣。”乃黜之,而以公衍为大子。 +秋,龙见于绛郊。魏献子问于蔡墨曰:“吾闻之,虫莫知于龙,以其不生得也。谓之知,信乎?”对曰:“人实不知,非龙实知。古者畜龙,故国有豢龙氏,有御龙氏。”献子曰:“是二氏者,吾亦闻之,而知其故,是何谓也?”对曰:“昔有飂叔安,有裔子曰董父,实甚好龙,能求其耆欲以饮食之,龙多归之。乃扰畜龙,以服事帝舜。帝赐之姓曰董,氏曰豢龙。封诸鬷川,鬷夷氏其后也。故帝舜氏世有畜龙。及有夏孔甲,扰于有帝,帝赐之乘龙,河、汉各二,各有雌雄,孔甲不能食,而未获豢龙氏。有陶唐氏既衰,其后有刘累,学扰龙于豢龙氏,以事孔甲,能饮食之。夏后嘉之,赐氏曰御龙,以更豕韦之后。龙一雌死,潜醢以食夏后。夏后飨之,既而使求之。惧而迁于鲁县,范氏其后也。”献子曰:“今何故无之?”对曰:“夫物,物有其官,官修其方,朝夕思之。一日失职,则死及之。失官不食。官宿其业,其物乃至。若泯弃之,物乃坻伏,郁湮不育。故有五行之官,是谓五官。实列受氏姓,封为上公,祀为贵神。社稷五祀,是尊是奉。木正曰句芒,火正曰祝融,金正曰蓐收,水正曰玄冥,土正曰后土。龙,水物也。水官弃矣,故龙不生得。不然,《周易》有之,在《乾》ⅰⅰ之《姤》ⅰⅳ,曰:‘潜龙勿用。’其《同人》ⅰⅵ曰:‘见龙在田。’其《大有》ⅵⅰ曰:‘飞龙在天。’其《夬》ⅷⅰ曰:‘亢龙有悔。’其《坤》ⅱⅱ曰:‘见群龙无首,吉。’《坤》之《剥》ⅶⅱ曰:‘龙战于野。’若不朝夕见,谁能物之?”献子曰:“社稷五祀,谁氏之五官也?”对曰:“少皞氏有四叔,曰重、曰该、曰修、曰熙,实能金、木及水。使重为句芒,该为蓐收,修及熙为玄冥,世不失职,遂济穷桑,此其三祀也。颛顼氏有子曰犁,为祝融;共工氏有子曰句龙,为后土,此其二祀也。后土为社;稷,田正也。有烈山氏之子曰柱为稷,自夏以上祀之。周弃亦为稷,自商以来祀之。” +冬,晋赵鞅、荀寅帅师城汝滨,遂赋晋国一鼓铁,以铸刑鼎,着范宣子所为刑书焉。仲尼曰:“晋其亡乎!失其度矣。夫晋国将守唐叔之所受法度,以经纬其民,卿大夫以序守之。民是以能尊其贵,贵是以能守其业。贵贱不愆,所谓度也。文公是以作执秩之官,为被庐之法,以为盟主。今弃是度也,而为刑鼎,民在鼎矣,何以尊贵?贵何业之守?贵贱无序,何以为国?且夫宣子之刑,夷之蒐也,晋国之乱制也,若之何以为法?”蔡史墨曰:“范氏、中行氏其亡乎!中行寅为下卿,而干上令,擅作刑器,以为国法,是法奸也。又加范氏焉,易之,亡也。其及赵氏,赵孟与焉。然不得已,若德,可以免。” +译文 +二十九年春季,鲁昭公从乾侯来到,住在郓地。齐景公派高张来慰问昭公,称他为主君。子家子说:“齐国轻视君王了,君王只得自取耻辱。”昭公就到乾侯去了。 +二月十三日,京城里杀了召伯盈、尹氏固和原伯鲁的儿子。尹氏固回去复位的时候,有个女人在成周郊外碰上他,责备他,说:“在国内就怂恿别人惹祸,逃亡出去了又几天就回来,这个人啊,难道能活过三年吗?” +夏季,五月二十五日,王子赵车跑到鄻地而叛变,阴不佞打败了他。 +季平子每年买马,准备好随从人员的衣服鞋子,送到乾侯去,昭公逮捕了送马的人,卖掉了马。于是平子就不再送马去了。 +卫灵公前来奉献他自己驾车的马,名叫启服,掉进坑里死了。昭公准备把马装进棺材埋起来,子家子说:“随从的人在生病了,请让他们把马吃了吧。”于是就用破帷幕包着马埋了。 +昭公把羔羊皮赐给公衍,派他把龙纹的美玉献给齐景公,他就把羔羊皮也一起奉献,齐景公很高兴,给了他阳谷。公衍、公为出生的时候,他们的母亲一起出去住在产房里,公衍先出生。公为的母亲说:“我们一起出来,就一起去报喜。”过了三天,公为出生。公为的母亲先去报告,公为就做了哥哥。昭公心里对得到阳谷很高兴,而又想起鲁国的这段往事,说:“公为惹起了这场祸事。而且出生在后而做哥哥,这欺骗也很久了。”就废了公为,而把公衍作为太子。 +秋季,龙出现在绛地郊外,魏献子问蔡墨说:“我听说,虫类没有比龙再聪明的了,因为它不能被人活捉。认为它聪明,是这样吗?”蔡墨说:“实在是人不聪明,不是龙聪明,古代养龙,所以国内有豢龙氏、御龙氏。”献子说:“这两家,我也听说过,但不知道他们的来历,这是说的什么呢?”蔡墨回答说:“过去有飂国的国君叔安,有一个后代叫董父,实在很喜欢龙,能够了解龙的嗜好要求来喂养它们,龙去他那里的很多,于是就驯服饲养龙,用来伺候帝舜。帝舜赐他姓叫董,氏叫豢龙,封他在鬷川,鬷夷氏就是他的后代。所以帝舜氏世世代代有养龙的。到了夏代国君孔甲,顺服天帝,天帝赐给他驾车的龙,黄河、汉水的各两条,各有一雌一雄。孔甲不能饲养,而又没有找到豢龙氏。有陶唐氏已经衰落,后来又有刘累,向豢龙氏学习驯龙,以此事奉孔甲,能够饲养这几条龙。孔甲嘉奖他,赐氏叫御龙,用他代替豕韦的后代。龙中一条雌的死了,刘累偷偷地剁成肉酱给孔甲吃,孔甲吃了,后来又让刘累再找来吃。刘累害怕而迁移到鲁县,范氏就是他的后代。”献子说:“现在为什么没有了?”蔡墨回答说:“事物都有管理它的官吏,官吏修治他的管理方法,早晚都考虑这些事。一旦失职,就要丢掉性命。丢了官就不能吃公家的俸禄。官员世代从事这方面的工作,生物才会来到。如果消灭丢弃它们,生物就自己潜伏,抑郁不能成长。因此有职掌五行的官员,这叫做五官,一代一代继承姓氏,封爵是上公,祭祀是贵神。在土地神、五谷神和五行之神的祭祀中,对他们尊敬崇奉。木官之长叫做句芒,火官之长叫祝融,金官之长叫蓐收,水官之长叫玄冥,土官之长叫后土。龙,是属于水生的生物,水官废弃了,所以龙不能被人活捉。如果不这样,《周易》就有《乾》卦初九《爻辞》说:‘潜伏的龙不被使用’;九二《爻辞》说,‘活着的龙在土田里’;九五《爻辞》说,‘飞舞的龙在天上’;上九《爻辞》说,‘伸直身子的龙有所悔恨’;用九《爻辞》说:‘见到群龙没有首领,吉利’;《坤》卦变成《剥》卦说,‘龙在野外交战’,如果不是早晚都见到,谁能够说出它们的状态?”献子说:“土地神、五谷神庙里的五种祭祀,是哪一代帝王的五官?”蔡墨回答说:“少皞氏有四个叔父,叫重、叫该、叫修、叫熙,能够管理金、木和水。派重做句芒,该做蓐收,修和熙做玄冥。世世代代不失职守,就帮助穷桑氏成功,这是其中的三种祭祀。颛顼氏有个儿子叫犁,做了祝融,共工氏有个儿子叫句龙,做了后土,这是其中的两种祭祀。后土做了土地神。五谷神,是管理土田的官员之长,有烈山氏的儿子叫柱,做了谷神,从夏朝以上祭祀他,周朝的弃也做了五谷神,从商朝以来祭祀他。” +冬季,晋国的赵鞅、荀寅带兵在汝水岸边筑城,于是向晋国的百姓征收了四百八十斤铁,用来铸造刑鼎,在鼎上铸着范宣子所制定的刑书。 +孔子说:“晋国恐怕要灭亡了吧!失掉了法度了。晋国应该遵守唐叔传下来的法度,作为百姓的准则,卿大夫按照他们的位次来维护它,百姓才能尊敬贵人,贵人因此能保守他们的家业。贵贱的差别没有错乱,这就是所谓法度。文公因此设立执掌官职位次的官员,在被庐制定法律,以作为盟主。现在废弃这个法令,而铸造了刑鼎,百姓都能看到鼎上的条文,还用什么来尊敬贵人?贵人还有什么家业可保守?贵贱没有次序,还怎么治理国家?而且范宣子的刑书,是在夷地检阅时制定的,是违犯晋国旧礼的乱法,怎么能把它当成法律呢?”蔡史墨说:“范氏、中行氏恐怕要灭亡了吧!中行寅是下卿,但违反上面的命令,擅自铸造刑鼎,以此作为国家的法律,这是违犯法令的罪人,又加上范氏改变被庐制定的法律,这就要灭亡了。恐怕还要牵涉到赵氏,因为赵孟参与了。但赵孟出于不得已,如果修养德行,是可以避免祸患的。” + +昭公三十年 +【经】三十年春王正月,公在乾侯。夏六月庚辰,晋侯去疾卒。秋八月,葬晋顷公。冬十有二月,吴灭徐,徐子章羽奔楚。 +【传】三十年春,王正月,公在乾侯。不先书郓与乾侯,非公,且征过也。 +夏六月,晋顷公卒。秋八月,葬。郑游吉吊,且送葬,魏献子使士景伯诘之,曰:“悼公之丧,子西吊,子蟜送葬。今吾子无贰,何故?”对曰:“诸侯所以归晋君,礼也。礼也者,小事大,大字小之谓。事大在共其时命,字小在恤其所无。以敝邑居大国之间,共其职贡,与其备御不虞之患,岂忘共命?先王之制:诸侯之丧,士吊,大夫送葬;唯嘉好、聘享、三军之事,于是乎使卿。晋之丧事,敝邑之间,先君有所助执绋矣。若其不间,虽士大夫有所不获数矣。大国之惠,亦庆其加,而不讨其乏,明厎其情,取备而已,以为礼也。灵王之丧,我先君简公在楚,我先大夫印段实往,敝邑之少卿也。王吏不讨,恤所无也。今大夫曰:‘女盍从旧?’旧有丰有省,不知所从。从其丰,则寡君幼弱,是以不共。从其省,则吉在此矣。唯大夫图之。”晋人不能诘。 +吴子使徐人执掩余,使钟吾人执烛庸二公子奔楚,楚子大封,而定其徙。使监马尹大心逆吴公子,使居养莠尹然、左司马沈尹戌城之,取于城父与胡田以与之。将以害吴也。子西谏曰:“吴光新得国,而亲其民,视民如子,辛苦同之,将用之也。若好吴边疆,使柔服焉,犹惧其至。吾又疆其仇以重怒之,无乃不可乎!吴,周之胄裔也,而弃在海滨,不与姬通。今而始大,比于诸华。光又甚文,将自同于先王。不知天将以为虐乎,使翦丧吴国而封大异姓乎?其抑亦将卒以祚吴乎?其终不远矣。我盍姑亿吾鬼神,而宁吾族姓,以待其归。将焉用自播扬焉?”王弗听。吴子怒。冬十二月,吴子执钟吴子,遂伐徐,防山以水之。己卯,灭徐。徐子章禹断其发,携其夫人,以逆吴子。吴子唁而送之,使其迩臣从之,遂奔楚。楚沈尹戌帅师救徐,弗及,遂城夷,使徐子处之。 +吴子问于伍员曰:“初而言伐楚,余知其可也,而恐其使余往也,又恶人之有馀之功也。今余将自有之矣,伐楚何如?”对曰:“楚执政众而乖,莫适任患。若为三师以肄焉,一师至,彼必皆出。彼出则归,彼归则出,楚必道敝。亟肄以罢之,多方以误之。既罢而后以三军继之,必大克之。”阖庐从之,楚于是乎始病。 +译文 +三十年春季,周王朝历法的正月,鲁昭公在乾侯。《春秋》以前不记载“公在郓”或“在乾侯”,这是认为昭公不对,而且说明过错所在。 +夏季,六月,晋顷公死了。秋季,八月,下葬。郑国的游吉前去吊唁并送葬。魏献子让士景伯质问游吉,说:“悼公的丧事,子西吊唁,子?送葬。现在您只有一个人,是什么缘故?”游吉回答说:“诸侯所以归服晋国国君,这是认为晋国有礼。礼这件事,就是说小国事奉大国,大国爱抚小国。事奉大国在于恭敬地按时执行命令,爱抚小国在于体恤小国的缺乏。由于敝邑处在大国之间,供应它所需的贡品,还要参与战备以防意外,难道能忘了恭敬地执行吊丧送葬的礼节?先王的制度:诸侯的丧事,士吊唁,大夫送葬,只有朝会、聘问、宴享、军事行动才派遣卿。晋国的丧事,当敝邑闲暇无事,先君曾经亲自来送葬。如果不得闲暇,即使是士、大夫有时也难于派遣。大国的恩惠,也会是嘉许敝邑对大国的常礼有所增加,而不责备它的缺乏,明白敝邑的忠诚,只是要求礼仪具备,就可以认为合于礼了。周灵王的丧事,我们先君简公在楚国,我们先大夫印段前去送葬,他还是敝邑的下卿。天子的官吏并没有责备我们,这是由于体恤敝邑的缺乏。现在大夫说:‘你们为什么不按照过去的礼节办?’过去的礼节有隆重有减省,不知道应该按照什么。根据隆重,那么寡君年纪小,因此不能前来。根据减省,那么吉在这里了。请大夫考虑一下!”晋国人不能再质问了。 +吴王让徐国人逮捕掩馀,让钟吾人逮捕烛庸,两个公子逃亡到楚国。楚昭王大封土地给他们,并确定他们迁居的地方,派监马尹大心迎接吴国公子,让他们住在养地,派莠尹然、左司马沈尹戌在那里筑城,把城父和胡地的土田给他们,准备用他们危害吴国。子西劝谏楚昭王说:“吴光新近得到国家,亲爱他的百姓,把百姓看成像儿子一样,和百姓同甘共苦,这是准备使用他们了。如果和吴国边境上的人结好,让他们温柔亲服,还恐怕吴军的到来。现在我们又让他们的仇人强大,以加重他们的愤怒,恐怕不可以吧!吴国是周朝的后代,而被抛弃在海边,不能和姬姓各国相往来,现在才开始壮大,可以和中原各国相比,吴光又很有知识,准备使自己和先王一样。不知道上天将要使他暴虐,让他灭亡吴国而使异姓之国扩大土地呢?还是将最终要保佑吴国呢?恐怕它的结果不久可以知道。我们何不姑且安定我们的鬼神,宁静我们的百姓,以等待他的结果,哪里用得着自己辛劳呢?”楚昭王不听子西的谏言。 +吴王阖庐发怒。冬季,十二月,吴王逮捕了钟吾子。于是就进攻徐国,堵住山上的水再灌入徐国。二十三日,灭亡徐国。徐国国君章禹剪断头发,带着他夫人迎接吴王。吴王加以慰问后送走了他,让他的近臣跟着,于是就逃亡到楚国。楚国的沈尹戌领兵救徐国,没有赶上。于是就在夷地筑城,让徐国国君住在那里。 +吴王问伍员说:“当初你说进攻楚国,我知道能够成功,但恐怕他们派我前去,又不愿意别人占了我的功劳。现在我将要自己占有这份功劳了。进攻楚国怎么样?”伍员回答说:“楚国执政的人多而不和,没有人敢承担责任。如果组织三支部队对楚国来个突然袭击而又迅速撤退,一支部队到那里,他们必然会全军应战。他们出来,我们就退回来;他们回去,我们就出动,楚军必定在路上疲于奔命。屡次突袭快撤使他们疲劳,用各种方法使他们失误。他们疲乏以后再派三军继续进攻,必定大胜他们。”阖庐听从了他的意见,楚国从此就开始困顿疲乏了。 + +昭公三十一年 +【经】三十有一年春王正月,公在乾侯。季孙意如晋荀跞于适历。夏四月丁巳,薛伯谷卒。晋侯使荀跞唁公于乾侯。秋,葬薛献公。冬,黑肱以滥来奔。十有二月辛亥朔,日有食之。 +【传】三十一年春,王正月,公在乾侯,言不能外内也。 +晋侯将以师纳公。范献子曰:“若召季孙而不来,则信不臣矣。然后伐之,若何?”晋人召季孙,献子使私焉,曰:“子必来,我受其无咎。”季孙意如会晋荀跞于适历。荀跞曰:“寡君使跞谓吾子:‘何故出君?有君不事,周有常刑,子其图之!’”季孙练冠麻衣跣行,伏而对曰:“事君,臣之所不得也,敢逃刑命?君若以臣为有罪,请囚于费,以待君之察也,亦唯君。若以先臣之故,不绝季氏,而赐之死。若弗杀弗亡,君之惠也,死且不朽。若得从君而归,则固臣之愿也。敢有异心?” +夏四月,季孙从知伯如乾侯。子家子曰:“君与之归。一惭之不忍,而终身惭乎?”公曰:“诺。”众曰:“在一言矣,君必逐之。”荀跞以晋侯之命唁公,且曰:“寡君使跞以君命讨于意如,意如不敢逃死,君其入也!”公曰:“君惠顾先君之好,施及亡人将使归粪除宗祧以事君,则不能夫人。己所能见夫人者,有如河!”荀跞掩耳而走,曰:“寡君其罪之恐,敢与知鲁国之难?臣请复于寡君。”退而谓季孙:“君怒未怠,子姑归祭。”子家子曰:“君以一乘入于鲁师,季孙必与君归。”公欲从之,众从者胁公,不得归。 +薛伯谷卒,同盟,故书。 +秋,吴人侵楚,伐夷,侵潜、六。楚沈尹戌帅师救潜,吴师还。楚师迁潜于南冈而还。吴师围弦。左司马戌、右司马稽帅师救弦,及豫章。吴师还。始用子胥之谋也。 +冬,邾黑肱以滥来奔,贱而书名,重地故也。君子曰:“名之不可不慎也如是。夫有所名,而不如其已。以地叛,虽贱,必书地,以名其人。终为不义,弗可灭已。是故君子动则思礼,行则思义,不为利回,不为义疚。或求名而不得,或欲盖而名章,惩不义也。齐豹为卫司寇,守嗣大夫,作而不义,其书为‘盗’。邾庶其、莒牟夷、邾黑肱以土地出,求食而已,不求其名,贱而必书。此二物者,所以惩肆而去贪也。若艰难其身,以险危大人,而有名章彻,攻难之士将奔走之。若窃邑叛君,以徼大利而无名,贪冒之民将置力焉。是以《春秋》书齐豹曰‘盗’,三叛人名,以惩不义,数恶无礼,其善志也。故曰:《春秋》之称微而显,婉而辨。上之人能使昭明,善人劝焉,淫人惧焉,是以君子贵之。” +十二月辛亥朔,日有食之。是夜也,赵简子梦童子羸而转以歌。旦占诸史墨,曰:“吾梦如是,今而日食,何也?”对曰:“六年及此月也,吴其入郢乎!终亦弗克。入郢,必以庚辰,日月在辰尾。庚午之日,日始有谪。火胜金,故弗克。” +译文 +三十一年春季,周王朝历法的正月,鲁昭公在乾侯,这是说他既不能去国外,又不能回国内。 +晋定公准备用兵力送昭公回国。范献子说:“如果召见季孙而他不来,那么确实是有失臣道了,然后再攻打他,怎么样?”晋国人召见季孙,范献子派人私下告诉他说:“您一定要来,我保证您不会有罪。”季孙意如和晋国的荀砾在適历会见。荀跞说:“寡君让跞对您说:为什么赶走国君?有国君而不事奉,周朝有一定的刑罚。您还是考虑一下!”季孙头戴练冠、身穿麻衣,光着脚走路,俯伏而回答说:“事奉国君,这是下臣求之不得的,岂敢逃避判刑的命令?君王如果认为下臣有罪,就请把下臣囚禁在费地,以等待君王的查问,也唯君王之命是听。如果由于先君的缘故,不断绝季氏的后代,而赐下臣一死。如果不杀,也不让逃亡,这是君王的恩惠,死而不敢忘记恩德。如果能跟随君王一同回去,那么本来就是下臣的愿望,岂敢有别的念头?” +夏季,四月,季孙跟随荀跞到了乾侯。子家子说:“君王和他一起回去,一次羞耻不能忍受,终身的羞耻反而能忍受吗?”昭公说:“对。”大家说:“这就在一句话了,君王一定要赶走他!”荀跞以晋定公的名义慰问昭公,而且说:“寡君派跞以国君的名义责备意如,意如不敢逃避死亡,君王还是回国吧!”昭公说:“君王赐惠照顾到先君的友好,延续到逃亡的人身上,准备让我回去扫除宗庙以事奉君王,那就不能见那个人,我要是能见那个人,有河神为证!”荀跞捂上耳朵跑开,说:“寡君诚惶诚恐,岂敢预闻鲁国的祸难!下臣请求去回复寡君。”退出去告诉季孙,说:“国君的怒气没有平息,您姑且回去主持祭祀。”子家子说:“君王驾一辆车进入鲁军,季孙一定和君王一起回去。”昭公想要听从。跟随的人们胁迫昭公,就没有能回去。 +薛伯穀死了,由于是同盟国,所以《春秋》加以记载。 +秋季,吴军侵袭楚国,进攻夷地,又侵袭潜地、六地。楚国沈尹戌带兵救援潜地,吴军退走。楚军把潜地人迁移到南岗然后回去。吴军包围弦地,左司马戌、右司马稽带兵救援弦地,到达豫章,吴军撤走。这是吴王开始使用伍子胥的计谋了。 +冬季,邾国的黑肱带着滥地逃亡前来。这个人低贱而《春秋》记载他的名字,这是由于重视土地的缘故。 +君子说:“名声的不能不慎重就像这样:有时有了名声,反而不如没有名声。带了土地背叛,即使这个人地位低贱,也一定要记载地名,以此来记载这个人,结果成为不义,不能磨灭。因此君子行动就想到礼,办事就想到义,不做图利而失去礼的事,不做不符合义而感到内疚的事,有人求名而得不到,有人想要掩盖反而明白地记下了名字,这是惩罚不义的人。齐豹做卫国的司寇,是世袭大夫,做事情不义,就被记载为‘盗’。邾国的庶其、莒国的牟夷,邾国的黑肱带着领地逃亡,只是为了谋求生活而已,不求什么名义,即使地位低贱也必定加以记载。这两件事情,是用来惩罚放肆而除去贪婪的。如果经历艰苦,使上面的人陷入危险,反而名声显扬,发动祸难的人就要为此而奔走。如果盗窃城邑背叛国君去追求大利而不记下他的名字,贪婪的人就会卖力去干。因此《春秋》记载齐豹叫做‘盗’,也记载三个叛逆的名字,用来惩戒不义,斥责无礼,这真是善于记述啊。所以说,《春秋》的记载文字隐微文雅而意义显著,言辞委婉而各有分寸。上面的人能够发扬《春秋》大义,就使善人得到劝勉,恶人有所畏惧,因此君子重视《春秋》。” +十二月初一日,发生日食。这天夜里,赵简子梦见一个孩子光着身子按着节拍唱歌跳舞,早晨让史墨占卜,说:“我梦见这样,现在发生日食,是什么意思?”史墨回答说:“六年以后到这个月,吴国恐怕要进入郢都吧!但结果还是不能胜利。进入郢都,一定在庚辰那一天。日月在苍龙之尾,庚午那天,太阳开始有灾。火能战胜金,所以不能胜利。” + +昭公三十二年 +【经】三十有二年春王正月,公在乾侯。取阚。夏,吴伐越。秋七月。冬,仲孙何忌会晋韩不信、齐高张、宋仲几、卫世叔申、郑国参、曹人、莒人、薛人、杞人、小邾人城成周。十有二月己未,公薨于乾侯。 +【传】三十二年春,王正月,公在乾侯。言不能外内,又不能用其人也。 +夏,吴伐越,始用师于越也。史墨曰:“不及四十年,越其有吴乎!越得岁而吴伐之,必受其凶。” +秋八月,王使富辛与石张如晋,请城成周。天子曰:“天降祸于周,俾我兄弟并有乱心,以为伯父忧。我一二亲昵甥舅,不遑启处,于今十年,勤戍五年。余一人无日忘之,闵闵焉如农夫之望岁,惧以待时。伯父若肆大惠,复二文之业,驰周室之忧,徼文、武之福,以固盟主,宣昭令名,则余一人有大愿矣。昔成王合诸侯,城成周,以为东都,崇文德焉。今我欲徼福假灵于成王,修成周之城,俾戍人无勤,诸侯用宁,蝥贼远屏,晋之力也。其委诸伯父,使伯父实重图之。俾我一人无征怨于百姓,而伯父有荣施,先王庸之。”范献子谓魏献子曰:“与其戍周,不如城之。天子实云,虽有后事,晋勿与知可也。从王命以纾诸侯,晋国无忧。是之不务,而又焉从事?”魏献子曰:“善!”使伯音对曰:“天子有命,敢不奉承,以奔告于诸侯。迟速衰序,于是焉在。” +冬十一月,晋魏舒、韩不信如京师,合诸侯之大夫于狄泉,寻盟,且令城成周。魏子南面。卫彪徯曰:“魏子必有大咎。干位以令大事,非其任也。《诗》曰:‘敬天之怒,不敢戏豫。敬天之渝,不敢驰驱。’况敢干位以作大事乎?” +己丑,士弥牟营成周,计丈数,揣高卑,度厚薄,仞沟恤,物土方,议远迩,量事期,计徒庸,虑材用,书餱粮,以令役于诸侯,属役赋丈,书以授帅,而效诸刘子。韩简子临之,以为成命。 +十二月,公疾,遍赐大夫,大夫不受。赐子家子双琥,一环,一璧,轻服,受之。大夫皆受其赐。己未,公薨。子家子反赐于府人,曰:“吾不敢逆君命也。”大夫皆反其赐。书曰:“公薨于乾侯。”言失其所也。 +赵简子问于史墨曰:“季氏出其君,而民服焉,诸侯与之,君死于外,而莫之或罪也。”对曰:“物生有两,有三,有五,有陪贰。故天有三辰,地有五行,体有左右,各有妃耦。王有公,诸侯有卿,皆有贰也。天生季氏,以贰鲁侯,为日久矣。民之服焉,不亦宜乎?鲁君世从其失,季氏世修其勤,民忘君矣。虽死于外,其谁矜之?社稷无常奉,君臣无常位,自古以然。故《诗》曰:‘高岸为谷,深谷为陵。’三后之姓,于今为庶,王所知也。在《易》卦,雷乘《乾》曰《大壮》,天之道也。昔成季友,桓之季也,文姜之爱子也,始震而卜。卜人谒之,曰:‘生有嘉闻,其名曰友,为公室辅。’及生,如卜人之言,有文在其手曰‘友’,遂以名之。既而有大功于鲁,受费以为上卿。至于文子、武子,世增其业,不废旧绩。鲁文公薨,而东门遂杀适立庶,鲁君于是乎失国,政在季氏,于此君也,四公矣。民不知君,何以得国?是以为君,慎器与名,不可以假人。” +译文 +三十二年春季,周王朝历法的正月,鲁昭公在乾侯,这是说他既不能去国外,也不能去国内,又不能使用他手下的人才。 +夏季,吴国进攻越国,这是开始对越国用兵。史墨说:“不到四十年,越国大概要占有吴国吧!越国得到岁星的照临而吴国进攻它,必然受到岁星降下的灾祸。” +秋季,八月,周敬王派富辛和石张到晋国去,请求增筑成周的城墙。天子说:“上天给周朝降下灾祸,使我的兄弟都发生乱心,以此成为伯父的忧虑。我几个亲近的甥舅之国也不得休息,到现在已经十年。诸侯派兵来戍守也已经五年。我本人没有一天忘记这个,忧心忡忡地好像农夫的盼望丰收一样,提心吊胆等待收割时候到来。伯父如果施放大恩,重建文侯、文公的功业,缓解周室的忧患,向文王、武王求取福佑,以巩固盟主的地位,宣扬美名,这就是我本人很大的愿望了。从前成王会合诸侯在成周筑城,以作为东都,尊崇文治。现在我想要向成王求取福佑,增修成周的城墙,使戍守的兵士不再辛劳,诸侯得以安宁,把坏人放逐到远方,这都是晋国的力量。谨将这件事委托给伯父,让伯父重新考虑,以使我本人不致于在百姓中召致怨恨,而伯父有了光荣的功绩,先王会酬谢伯父的。” +范献子对魏献子说:“与其在成周戍守,不如增筑那里的城墙。天子已经说了话,即使以后有事,晋国可以不参加。服从天子的命令,使诸侯缓一口气,晋国就没有忧患了。不致力去做这件事,又去从事什么?”魏献子说:“好。”派伯音回答说:“天子有命令,岂敢不承奉而奔走报告诸侯,工作的进度和工程量的分配,听周天子的命令。” +冬季,十一月,晋国的魏舒、韩不信到京师,在狄泉会合诸侯的大夫,重温过去的盟约,而且命令增筑成周的城墙。魏舒面朝南,卫国的彪傒说:“魏子一定要有大灾难。逾越本分而颁布重大的命令,这不是他能承担得了的。《诗》说,‘恭敬地对待上天的怒气,不敢轻慢。恭敬地对待上天的变异,不敢任意放纵’,何况敢逾越本分而去做大事呢?” +十四日,士弥牟为成周城墙的工程设计方案,计算长度,估计高低,度量厚薄,计算沟渠的深度,考察用土的数量,商计运输的远近,预算完工的日期,计算人工,考虑器材,记载所需要的粮食,以命令诸侯服役。按照情况分配劳役和工程地段,记下来交给诸侯大夫,而归总交到刘子那里。韩简子监工,以此作为既定方案。 +十二月,鲁昭公生病了,把东西普遍赏赐给大夫们,大夫们不接受。赏赐给子家子一对玉虎、一只玉环、一块玉璧、又轻又好的衣服,子家子接受了。大夫们也都接受了赏赐。十四日,昭公死了,子家子把赏赐给他的东西还给管理府库的人,说:“我之所以接受是不敢违背国君的命令。”大夫们也都归还了赏赐的东西。《春秋》记载说“公薨于乾侯”,这是说他死的不是地方。 +赵简子问史墨说:“季氏赶走他的国君而百姓顺服他,诸侯亲附他,国君死在外边而没有人去惩罚他,这是为什么?”史墨回答说:“事物的存在有的成双、有的成三、有的成五、有的有辅佐。所以天有三辰,地有五行,身体有左右,各有配偶,王有公,诸侯有卿,都是有辅助的。上天生了季氏,让他辅佐鲁侯,时间已经很久了。百姓顺服他,不也是很合适吗?鲁国的国君世世代代放纵安逸,季氏世世代代勤勤恳恳,百姓已经忘记他们的国君了。即使死在国外,有谁去怜惜他?社稷没有固定的祭祀人,君臣没有固定不变的地位,自古以来就是这样。所以《诗》说:‘高高的堤岸变成深谷,深深的谷地变成山陵。’三王的子孙在今天成了平民,这是主人所知道的。在《易》的卦像上,代表雷的《震》卦在《乾》卦之上,叫做《大壮》,这是上天的常道。以前的成季友,是桓公的小儿子,文姜所宠爱的儿子。刚刚怀孕就占卜,卜人报告说:‘生下来就有好名声,他的名字叫友,成为公室的辅佐。’等到生出来,和卜人所说的一样,在左手掌上有个‘友’字,就以此命名。后来在鲁国立下大功,受封在费地而做了上卿。一直到文子、武子,世世代代增加家业,不废弃过去的功业。鲁文公去世,东门遂杀死嫡子,立了庶子,鲁国国君在这时就失掉了国政,政权落到了季氏手中,到这一位国君已经是第四代了。百姓不知道有国君,凭什么得到国政?因此做国君的要谨慎地对待器物和名位,不可能随便拿来借给别人。 + + +定公 + + +定公元年 +【经】元年春王三月。晋人执宋仲几于京师。夏六月癸亥,公之丧至自乾侯。戊辰,公即位。秋七月癸巳,葬我君昭公。九月,大雩。立炀宫。冬十月,陨霜杀菽。 +【传】元年春,王正月辛巳,晋魏舒合诸侯之大夫于狄泉,将以城成周。魏子莅政。卫彪傒曰:“将建天子,而易位以令,非义也。大事奸义,必有大咎。晋不失诸侯,魏子其不免乎!”是行也,魏献子属役于韩简子及原寿过,而田于大陆,焚焉,还,卒于宁。范献子去其柏椁,以其未覆命而田也。 +孟懿子会城成周,庚寅,栽。宋仲几不受功,曰:“滕、薛、郳,吾役也。”薛宰曰:“宋为无道,绝我小国于周,以我适楚,故我常从宋。晋文公为践土之盟,曰:‘凡我同盟,各复旧职。’若从践土,若从宋,亦唯命。”仲几曰:“践土固然。”薛宰曰:“薛之皇祖奚仲,居薛以为夏车正。奚仲迁于邳,仲虺居薛,以为汤左相。若复旧职,将承王官,何故以役诸侯?”仲几曰:“三代各异物,薛焉得有旧?为宋役,亦其职也。”士弥牟曰:“晋之从政者新,子姑受功。归,吾视诸故府。”仲几曰:“纵子忘之,山川鬼神其忘诸乎?”士伯怒,谓韩简子曰:“薛征于人,宋征于鬼,宋罪大矣。且己无辞而抑我以神,诬我也。启宠纳侮,其此之谓矣。必以仲几为戮。”乃执仲几以归。三月,归诸京师。 +城三旬而毕,乃归诸侯之戌。 +齐高张后,不从诸侯。晋女叔宽曰:“周苌弘、齐高张皆将不免。苌叔违天,高子违人。天之所坏,不可支也。众之所为,不可奸也。” +夏,叔孙成子逆公之丧于乾侯。季孙曰:“子家子亟言于我,未尝不中吾志也。吾欲与之从政,子必止之,且听命焉。”子家子不见叔孙,易几而哭。叔孙请见子家子,子家子辞,曰:“羁未得见,而从君以出。君不命而薨,羁不敢见。”叔孙使告之曰:“公衍、公为实使群臣不得事君。若公子宋主社稷,则群臣之愿也。凡从君出而可以入者,将唯子是听。子家氏未有后,季孙愿与子从政,此皆季孙之愿也,使不敢以告。”对曰:“若立君,则有卿士、大夫与守龟在,羁弗敢知。若从君者,则貌而出者,入可也;寇而出者,行可也。若羁也,则君知其出也,而未知其入也,羁将逃也。” +丧及坏隤,公子宋先入,从公者皆自坏隤反。 +六月癸亥,公之丧至自乾侯。戊辰,公即位。季孙使役如阚公氏,将沟焉。荣驾鹅曰:“生不能事,死又离之,以自旌也。纵子忍之,后必或耻之。”乃止。季孙问于荣驾鹅曰:“吾欲为君谥,使子孙知之。”对曰:“生弗能事,死又恶之,以自信也。将焉用之?”乃止。 +秋七月癸巳,葬昭公于墓道南。孔子之为司寇也,沟而合诸墓。 +昭公出,故季平子祷于炀公。九月,立炀宫。 +周巩简公弃其子弟,而好用远人。 +译文 +元年春季,周王朝历法的正月初七日,晋国的魏舒与诸侯的大夫在狄泉会合,准备增筑成周城墙。魏舒主持这件事,卫国的彪傒说:“准备为天子筑城,而超越自己的地位来命令诸侯,这是不合于道义的。重大的事情违背道义,必然有大灾祸,晋国要不失去诸侯,魏子恐怕不能免于灾祸吧!”这一趟,魏舒把事情交给韩简子和原寿过,自己跑到大陆泽去打猎,放火烧荒,回来,死在宁地,范献子撤除了安装魏舒尸体的柏木外棺,这是由于魏舒还没有复命就去打猎的缘故。 +孟懿子参加增筑成周城墙的工程,十六日,开始夯土,宋国的仲几不接受工程任务,说:“滕国、薛国、郳国,是为我们服役的。”薛国的宰臣说:“宋国无道,让我们小国和周朝断绝关系,带领我国事奉楚国,所以我国常常服从宋国。晋文公主持了践土结盟,说:‘凡是我国的同盟,各自恢复原来的职位。’或者服从践土的盟约,或者服从宋国,都唯命是听。”仲几说:“践土的盟约本来就是让你们为宋国服役的。”薛国的宰臣说:“薛国的始祖奚仲住在薛地,做了夏朝的车正,奚仲迁居到邳地,仲虺住在薛地,做了汤的左相。如果恢复原来的职位,将会接受天子的官位,为什么要为诸侯服役?”仲几说:“三代的情事各不相同,薛国哪里能按旧章程办事?为宋国服役,也是你们的职责。”士弥牟说:“晋国的执政者是新人,您姑且接受工程任务,我去查看一下旧档案。”仲几说:“即使您忘了,山川的鬼神难道会忘记吗?”士弥牟发怒,对韩简子说:“薛国用人作证明,宋国用鬼神作证明,宋国的罪过大了,而且他自己无话可说,而用鬼神来向我们施加压力,这是欺骗我们。‘给予宠信反而招来侮辱’,这就是说的这种情况了,一定要惩罚仲几。”于是就抓了仲几回国。三月,把他送到京师。 +增筑城墙的工程三十天完工,就让诸侯的戍卒回国了。齐国的高张迟到,没有赶上诸侯,晋国的女叔宽说:“周朝苌弘、齐国的高张都将要不免于祸患。苌弘违背上天,高子违背人意,上天要毁坏谁,谁也不能保护他。大众所要做的事,谁也不能违背。” +夏季,叔孙成子到乾侯迎接昭公的灵柩。季孙说:“子家子屡次与我谈话,未尝不合我的心意。我想让他参与政事,您一定要留下他,并且听取他的意见。”子家子不肯会见叔孙,改变了原定的哭丧时间,叔孙请求进见子家子,子家子辞谢说:“羁没有见到您,就跟着国君出国了。国君没有命令就死了,羁不敢见到您。”叔孙派人告诉他说:“公衍、公为实在让臣不能事奉国君,如果公子宋主持国家,那是臣下们的愿望,凡是跟随国君出国的谁可以回国,都将由您的命令决定。子家氏没有继承人,季孙愿意让您参与政事,这都是季孙的愿望,派不敢前来奉告。”子家子说:“如果立国君,那么有卿士、大夫和守龟在那里,羁不敢参与。如果跟随国君的人,那么表面上跟着出国的,可以回去;和季氏结了仇而出国的,可以走开。至于羁,那么是国君知道我出国却不知道我回去的,羁准备逃走。”昭公灵柩到达坏隤,公子宋先进入国内,跟随昭公的人都从坏隤回来了。 +六月二十一日,昭公的灵柩从乾侯到达。二十六日,定公即位。季孙派遣劳役到阚公那里,准备在那里挖沟,荣驾鹅说:“国君活着不能事奉,死了又把他的坟墓和祖茔隔离,用这个来表明自己的过失吗?即使您狠心这样干,后来必然有人以此为羞耻。”于是就停止了。季孙问荣驾鹅说:“我要为国君制定谥号,让子子孙孙都知道。”荣驾鹅说:“活着不能事奉,死了又给予恶谥,用这个来自我表白吗?哪里用得着这个?”于是就停止了。 +秋季,七月二十二日,在墓道南面安葬昭公。孔子做司寇的时候,在昭公坟墓外挖沟扩大墓地,使它和先公的坟墓同在一个范围内。 +由于昭公出国的缘故,季平子向炀公祈祷。九月,建立炀公庙。 +周朝的巩简公丢弃他的子弟,而喜欢任用疏远的异族客卿。 + +定公二年 +【经】二年春王正月。夏五月壬辰,雉门及两观灭。秋,楚人伐吴。冬十月,新作雉门及两观。 +【传】二年夏四月辛酉,巩氏之群子弟贼简公。 +桐叛楚。吴子使舒鸠氏诱楚人,曰:“以师临我,我伐桐,为我使之无忌。” +秋,楚囊瓦伐吴,师于豫章。吴人见舟于豫章,而潜师于巢。冬十月,吴军楚师于豫章,败之。遂围巢,克之,获楚公子繁。 +邾庄公与夷射姑饮酒,私出。阍乞肉焉。夺之杖以敲之。 +译文 +二年夏季,四月二十四日,巩氏的子弟们刺杀了巩简公。 +桐地背叛楚国,吴王派舒鸠氏诱骗楚国人,说:“请楚国用军队逼近我国,我国就进攻桐地,为了让他们对我国没有猜疑。” +秋季,楚国的囊瓦从豫章进攻吴国的军队,吴国人让战船出现在豫章,而暗中在巢地集结部队。冬季,十月,吴军在豫章攻击楚军,击败了他们。于是就包围巢地,攻占了它,俘虏了楚国的公子繁。 +邾庄公和夷射姑喝酒,夷射姑出去小便。守门人向他讨肉,他夺过守门人的棍子就敲打他们。 + +定公三年 +【经】三年春王正月,公如晋,至河,乃复。二月辛卯,邾子穿卒。夏四月。秋,葬邾庄公。冬,仲孙何忌及邾子盟于拔。 +【传】三年春二月辛卯,邾子在门台,临廷。阍以瓶水沃廷。邾子望见之,怒。阍曰:“夷射姑旋焉。”命执之,弗得,滋怒。自投于床,废于炉炭,烂,遂卒。先葬以车五乘,殉五人。庄公卞急而好洁,故及是。 +秋九月,鲜虞人败晋师于平中,获晋观虎,恃其勇也。 +冬,盟于郯,修邾好也。 +蔡昭侯为两佩与两裘,以如楚,献一佩一裘于昭王。昭王服之,以享蔡侯。蔡侯亦服其一。子常欲之,弗与,三年止之。唐成公如楚,有两肃爽马,子常欲之,弗与,亦三年止之。唐人或相与谋,请代先从者,许之。饮先从者酒,醉之,窃马而献之子常。子常归唐侯。自拘于司败,曰:“君以弄马之故,隐君身,弃国家,群臣请相夫人以偿马,必如之。”唐侯曰:“寡人之过也,二三子无辱。”皆赏之。蔡人闻之,固请而献佩于子常。子常朝,见蔡侯之徒,命有司曰:“蔡君之久也,官不共也。明日,礼不毕,将死。”蔡侯归,及汉,执玉而沈,曰“余所有济汉而南者,有若大川。”蔡侯如晋,以其子元与其大夫之子为质焉,而请伐楚。 +译文 +三年春季,二月二十九日,邾庄公在门楼上,下临庭院。守门人用瓶装水洒在庭院里。邾庄公远远看见了,发怒。守门人说:“夷射姑曾在这里小便。”邾庄公命令把夷射姑逮捕起来。没有抓到,更加生气,自己从床上跳下来,摔在炉子里的炭火上,皮肉溃烂,就死了,用五辆车陪葬,用五个人殉葬。邾庄公急躁而爱干净,所以才弄到这地步。 +秋季,九月,鲜虞人在平中打败晋军,俘虏了晋国的观虎,这是因为他自恃勇敢。 +冬季,仲孙何忌和邾子在郯地结盟,这是为重修和邾国的友好。 +蔡昭侯制作了两块玉佩和两件皮衣到楚国去,把一块玉佩和一件皮衣献给楚昭王。昭王穿上皮衣带好玉佩,设享礼招待蔡侯。蔡侯也穿带了另外一件皮衣和玉佩。子常想要蔡侯的皮衣和玉佩,蔡侯不给,子常就把蔡侯扣留了三年。唐成公到楚国去,有两匹肃爽马,子常也想要,唐成公不给,子常也把唐成公扣留了三年。唐国有人互相商量,请求代替先跟成公去的人,答应了。让先跟去的人喝酒,灌醉了他们,偷了马献给子常。子常送回了唐侯。偷马的人自己囚禁到了唐国司法官那里,说:“国君由于玩马的缘故,使自身失去自由,抛弃了国家和群臣,臣下们请求帮助养马人赔偿马,一定要像以往两匹马一样的好。”唐侯说:“这是寡人的过错。您几位不要羞辱自己!”对他们全都给予赏赐。蔡国人听说了这件事,坚决请求,而把玉佩献给了子常。子常上朝,见到蔡侯的手下人,就命令官员们说:“蔡侯所以长久留在我国,都是由于你们不供给饯别的礼物。到明天礼物再不完备,就要处死你们。”蔡侯回国,到达汉水,拿起玉丢入汉水中,说:“我要是再渡汉水往南,有大河为证!”蔡侯到晋国去,以他的儿子元和大夫的儿子作为人质,请求进攻楚国。 + + +定公四年 +【经】四年春王二月癸巳,陈侯吴卒。三月,公会刘子、晋侯、宋公、蔡侯、卫侯、陈子、郑伯、许男、曹伯、莒子、邾子、顿子、胡子、滕子、薛伯、杞伯、小邾子、齐国夏于召陵,侵楚。夏四月庚辰,蔡公孙姓帅师灭沈,以沈子嘉归,杀之。五月,公及诸侯盟于皋鼬。杞伯成卒于会。六月,葬陈惠公。许迁于容城。秋七月,至自会。刘卷卒。葬杞悼公。楚人围蔡。晋士鞅、卫孔围帅师伐鲜虞。葬刘文公。冬十有一月庚午,蔡侯以吴子及楚人战于柏举,楚师败绩。楚囊瓦出奔郑。庚辰,吴入郢。 +【传】四年春三月,刘文公合诸侯于召陵,谋伐楚也。 +晋荀寅求货于蔡侯,弗得。言于范献子曰:“国家方危,诸侯方贰,将以袭敌,不亦难乎!水潦方降,疾疟方起,中山不服,弃盟取怨,无损于楚,而失中山,不如辞蔡侯。吾自方城以来,楚未可以得志,只取勤焉。”乃辞蔡侯。 +晋人假羽旄于郑,郑人与之。明日,或旆以会。晋于是乎失诸侯。将会,卫子行敬子言于灵公曰:“会同难,啧有烦言,莫之治也。其使祝佗从!”公曰:“善。”乃使子鱼。子鱼辞,曰:“臣展四体,以率旧职,犹惧不给而烦刑书,若又共二,徼大罪也。且夫祝,社稷之常隶也。社稷不动,祝不出竟,官之制也。君以军行,祓社衅鼓,祝奉以从,于是乎出竟。若嘉好之事,君行师从,卿行旅从,臣无事焉。”公曰:“行也。”及皋鼬,将长蔡于卫。卫侯使祝佗私于苌弘曰:“闻诸道路,不知信否。若闻蔡将先卫,信乎?”苌弘曰:“信。蔡叔,康叔之兄也,先卫,不亦可乎?”子鱼曰:“以先王观之,则尚德也。昔武王克商,成王定之,选建明德,以蕃屏周。故周公相王室,以尹天下,于周为睦。分鲁公以大路,大旂,夏后氏之璜,封父之繁弱,殷民六族,条氏、徐氏、萧氏、索氏、长勺氏、尾勺氏。使帅其宗氏,辑其分族,将其类丑,以法则周公,用即命于周。是使之职事于鲁,以昭周公之明德。分之土田倍敦,祝、宗、卜、史,备物、典策,官司、彝器。因商奄之民,命以《伯禽》,而封于少皞之虚。分康叔以大路、少帛、綪茷、旃旌、大吕,殷民七族,陶氏、施氏、繁氏、錡氏、樊氏、饥氏、终葵氏;封畛土略,自武父以南,及圃田之北竟,取于有阎之土,以共王职。取于相土之东都,以会王之东蒐。聃季授土,陶叔授民,命以《康诰》,而封于殷虚。皆启以商政,疆以周索。分唐叔以大路,密须之鼓,阙巩,沽洗,怀姓九宗,职官五正。命以《唐诰》,而封于夏虚,启以夏政,疆以戎索。三者皆叔也,而有令德,故昭之以分物。不然,文、武、成康、之伯犹多,而不获是分也,唯不尚年也。管蔡启商,惎间王室。王于是乎杀管叔而蔡蔡叔,以车七乘,徒七十人。其子蔡仲,改行帅德,周公举之,以为己卿士。见诸王而命之以蔡,其命书云:‘王曰:胡!无若尔考之违王命也。’若之何其使蔡先卫也?武王之母弟八人,周公为大宰,康叔为司寇,聃季为司空,五叔无官,岂尚年哉!曹,文之昭也;晋,武之穆也。曹为伯甸,非尚年也。今将尚之,是反先王也。晋文公为践土之盟,卫成公不在,夷叔,其母弟也,犹先蔡。其载书云:‘王若曰,晋重、鲁申、卫武、蔡甲午、郑捷、齐潘、宋王臣、莒期。’藏在周府,可覆视也。吾子欲覆文、武之略,而不正其德,将如之何?”苌弘说,告刘子,与范献子谋之,乃长卫侯于盟。 +反自召陵,郑子大叔未至而卒。晋赵简子为之临,甚哀,曰:“黄父之会,夫子语我九言,曰:‘无始乱,无怙富,无恃宠,无违同,无敖礼,无骄能,无复怒,无谋非德,无犯非义。’” +沈人不会于召陵,晋人使蔡伐之。夏,蔡灭沈。 +秋,楚为沈故,围蔡。伍员为吴行人以谋楚。楚之杀郤宛也,伯氏之族出。伯州犁之孙嚭为吴大宰以谋楚。楚自昭王即位,无岁不有吴师。蔡侯因之,以其子乾与其大夫之子为质于吴。 +冬,蔡侯、吴子、唐侯伐楚。舍舟于淮汭,自豫章与楚夹汉。左司马戌谓子常曰:“子水公汉而与之上下,我悉方城外以毁其舟,还塞大隧、直辕、冥厄,子济汉而伐之,我自后击之,必大败之。”既谋而行。武城黑谓子常曰:“吴用木也,我用革也,不可久也。不如速战。”史皇谓子常:“楚人恶而好司马,若司马毁吴舟于淮,塞城口而入,是独克吴也。子必速战,不然不免。”乃济汉而陈,自小别至于大别。三战,子常知不可,欲奔。史皇曰:“安求其事,难而逃之,将何所入?子必死之,初罪必尽说。” +十一月庚午,二师陈于柏举。阖庐之弟夫概王,晨请于阖庐曰:“楚瓦不仁,其臣莫有死志,先伐之,其卒必奔。而后大师继之,必克。”弗许。夫概王曰:“所谓‘臣义而行,不待命’者,其此之谓也。今日我死,楚可入也。”以其属五千,先击子常之卒。子常之卒奔,楚师乱,吴师大败之。子常奔郑。史皇以其乘广死。吴从楚师,及清发,将击之。夫□王曰:“困兽犹斗,况人乎?若知不免而致死,必败我。若使先济者知免,后者慕之,蔑有斗心矣。半济而后可击也。”从之。又败之。楚人为食,吴人及之,奔。食而从之,败诸雍澨五战及郢。 +己卯,楚子取其妹季芈畀我以出,涉睢。针尹固与王同舟,王使执燧象以奔吴师。 +庚辰,吴入郢,以班处宫。子山处令尹之宫,夫概王欲攻之,惧而去之,夫□王入之。 +左司马戌及息而还,败吴师于雍澨,伤。初,司马臣阖庐,故耻为禽焉。谓其臣曰:“谁能免吾首?”吴句卑曰:“臣贱可乎?”司马曰:“我实失子,可哉!”三战皆伤,曰:“吾不用也已。”句卑布裳,刭而裹之,藏其身而以其首免。楚子涉雎,济江,入于云中。王寝,盗攻之,以戈击王。王孙由于以背受之。中肩。王奔郧,钟建负季芈以从,由于徐苏而从。郧公辛之弟怀将弑王,曰:“平王杀吾父,我杀其子,不亦可乎?”辛曰:“君讨臣,谁敢仇之?君命,天也,若死天命,将谁仇?《诗》曰:‘柔亦不茹,刚亦不吐,不侮矜寡,不畏强御。’唯仁者能之。违强陵弱,非勇也。乘人之约,非仁也。灭宗废祀,非孝也。动无令名,非知也。必犯是,余将杀女。”斗辛与其弟巢以王奔随。吴人从之,谓随人曰:“周之子孙在汉川者,楚实尽之。天诱其衷,致罚于楚,而君又窜之。周室何罪?君若顾报周室,施及寡人,以奖天衷,君之惠也。汉阳之田,君实有之。”楚子在公宫之北,吴人在其南。子期似王,逃王,而己为王,曰:“以我与之,王必免。”随人卜与之,不吉。乃辞吴曰:“以随之辟小而密迩于楚,楚实存之,世有盟誓,至于今未改。若难而弃之,何以事君?执事之患,不唯一人。若鸠楚竟,敢不听命。”吴人乃退。鑢金初官于子期氏,实与随人要言。王使见,辞,曰:“不敢以约为利。”王割子期之心,以与随人盟。 +初,伍员与申包胥友。其亡也,谓申包胥曰:“我必复楚国。”申包胥曰:“勉之!子能复之,我必能兴之。”及昭王在随,申包胥如秦乞师,曰:“吴为封豕、长蛇,以荐食上国,虐始于楚。寡君失守社稷,越在草莽。使下臣告急,曰:‘夷德无厌,若邻于君,疆埸之患也。逮吴之未定,君其取分焉。若楚之遂亡,君之土也。若以君灵抚之,世以事君。’”秦伯使辞焉,曰:“寡人闻命矣。子姑就馆,将图而告。”对曰:“寡君越在草莽,未获所伏。下臣何敢即安?”立,依于庭墙而哭,日夜不绝声,勺饮不入口七日。秦哀公为之赋《无衣》,九顿首而坐,秦师乃出。 +译文 +四年春季,三月,刘文公在召陵会合诸侯,这是为了策划进攻楚国。晋国的荀寅向蔡侯求取财货,没有得到,就对范献子说:“国家正在危急之时,诸侯正怀有二心,准备在这种情况下袭击敌人,不也是很困难吗!大雨正在下着,疟疾正在流行,中山不臣服,抛弃盟约而招来怨恨,对楚国没有什么损害,反而失去了中山,不如辞谢蔡侯。我们自从方城那次战役以来,到现在还不见得能在楚国得志,只不过是劳兵伤财。”于是就辞谢了蔡侯。 +晋国人向郑国借用装饰旌旗的羽毛,郑国人给了他们。第二天,把羽毛装饰在旗杆顶上去参加会,晋国就因此失掉了诸侯的拥护。 +将要举行会见,卫国的子行敬子对卫灵公说:“朝会难得达到预期的目的,有分歧又争论不休,就不好办了。是不是让祝佗跟随与会?”卫灵公说:“好。”就派祝佗跟着去。祝佗辞谢,说:“下臣竭力从事工作,以继承先人的职位,尚且恐怕完不成任务而得到罪过,如果又从事第二种职务,就会获得大罪了。况且太祝这职务,是土地神和五谷神经常使唤的小臣。土地神和五谷神不出动,太祝不出国境,这是官制规定的。君王率领军队出征,祭祀神庙杀牲衅鼓,太祝奉社主跟随出国境。如果是朝会一类的好事,国君出去有一师人马跟随,卿出去有一旅人马跟随,下臣是没有事情的。”卫灵公说:“去吧!” +到达皋鼬,准备把蔡国安排在卫国前面歃血。卫灵公派祝佗私下对苌弘说:“在道路上听到,不知是否确实,听说把蔡国安排在卫国之前歃血,确实吗?”苌弘说:“确实。蔡叔,是康叔的兄长,把位次排在卫国之前,不也是可以的吗?”祝佗说:“用先王的标准来看,是尊重德行的。从前武王战胜商朝,成王平定天下,选择有明德的人分封,把他们作为保卫周朝的藩篱屏障。所以周公辅佐王室,以治理天下,诸侯也和周朝和睦相处。分赐给鲁公大路、大旂,夏后氏的璜玉,封父的良弓,还有殷朝的六个家族条氏、徐氏、萧氏、索氏、长勺氏、尾勺氏,让他们率领本宗各氏族,集合其余的小宗族,统治六族的奴隶,来服从周公的法制,由此归附周朝听取命令。这是让他为鲁国执行职务,以宣扬周公的明德。分赐给鲁国附庸小国,太祝、宗人、太卜、太史,服用器物、典籍简册、百官彝器,安抚商奄的百姓,用《伯禽》来告诫他们,而封在少皞的故城,分赐给康叔大路、少白、綪茷、旃旌、大吕,还有殷朝的七个家族,陶氏、施氏、繁氏、锜氏、樊氏、饥氏、终葵氏,封疆边界,从武父以南到达圃田北界,从有阎氏那里取得了土地,以执行王室任命的职务。取得了相土的东都,以协助天子在东方巡视。聃季授予土地,陶叔授予百姓,用《康诰》来告诫他,而封在殷朝的故城。鲁公和康叔都沿用商朝的政事,而按照周朝的制度来划定疆土。分赐给唐叔大路、密须的鼓、阙巩的甲、沽洗,还有怀姓的九个宗族,五正的职官,用《唐诰》来告诫他,而封在夏朝的故城。唐叔沿用夏朝的政事,用戎人的制度来划定疆土。这三个人都是天子的兄弟而有美好的德行,所以用分赐东西来为他们宣扬德行。不这样,文王、武王、成王、康王的兄长还很多,而没有得到这些赐予,就因为不是崇尚年龄。管叔、蔡叔引诱商人,策划侵犯王室。天子因此杀了管叔而放逐蔡叔,给了蔡叔七辆车子,七十个奴隶。蔡叔的儿子蔡仲改恶从善,周公提拔他,让他作为自己的卿士。让他拜见天子,天子命令他做了蔡侯。任命书说:‘天子说:胡,不要像你父亲那样违背天子的命令!’怎么能让蔡国在卫国之前歃血呢?武王的同母兄弟八个人,周公做太宰,康叔做司寇,聃季做司空,其余五个叔父没有官职,难道是以年龄为主吗?曹国,是文王的后代。晋国,是武王的后代。曹国以伯爵作为甸服,并不是由于尊崇年龄。现在要尊崇它,这就是违反先王的遗制。晋文公召集践土的盟会,卫成公不在场,夷叔,是他的同母兄弟,尚且列在蔡国之前。盟书说:‘天子说:晋国的重、鲁国的申、卫国的武、蔡国的甲午、郑国的捷、齐国的潘、宋国的王臣、莒国的期。’藏在成周的府库里,这是可以查看的。您想要恢复文王、武王的法度,而不端正自己的德行,您准备怎么办?”苌弘很高兴,告诉了刘子,和范献子商量这件事,在结盟时就让卫侯在蔡侯之前歃血。 +从召陵回国,郑国的子太叔没有回到国内就死了。晋国的赵简子吊丧号哭,很悲哀,说:“黄父那次会见,他老人家对我说了九句话,说:‘不要发动祸乱,不要凭借富有,不要仗恃宠信,不要违背共同的意愿,不要傲视有礼的人,不要自负有才能,不要为同一事情再次发怒,不要谋划不合道德的事,不要触犯不合正义的事。’” +沈国人不参加在召陵的会见,晋国人让蔡国人进攻沈国。夏季,蔡国灭亡了沈国。 +秋季,楚国由于沈国被灭亡的缘故,包围了蔡国。伍员作为吴国的外交 +官,在策划对付楚国。当楚国杀死郤宛的时候,伯氏的族人逃往国外。伯州犁的孙子伯嚭担任了吴国的宰相,也在策划对付楚国。楚国自从昭王即位以后,没有一年不和吴国交战,蔡昭侯仗着这个,把他的儿了乾和一个大夫的儿子放在吴国作为人质。 +冬季,蔡昭侯、吴王阖庐、唐成公联合发兵进攻楚国。他们把船停在淮河边上,从豫章进发,和楚军隔着汉水对峙。楚国司马沈尹戌对子常说:“您沿着汉水和他们上下周旋,我带领方城山之外的全部人马来毁掉他们的船只,回来时再堵塞大隧、直辕、冥阨。这时,您渡过汉水而进攻,我从后面夹击,必定把他们打得大败。”商量完了就出发。楚国武城黑对子常说:“吴国人用木头制的战车,我们用皮革蒙的战车,天雨不能持久,不如速战速决。”史皇对子常说:“楚国人讨厌您而喜欢司马。如果沈司马在淮河边上毁掉了吴国的船,堵塞了城口而回来,这是他一个人独享战胜吴军的功劳。您一定要速战速决。不这样,就不能免于祸难。”于是就渡过汉水摆开阵势。从小别山直到大别山。同吴军打了三仗,子常知道不行,想逃走。史皇说:“平平安安,您争着当权;国家有了祸难就逃避,你打算到哪里去?您一定要拼命打这一仗,以前的罪过必然可以全部免除。” +十一月十八日,吴、楚两军在柏举摆开阵势。吴王阖庐的弟弟夫槩王早晨请示阖庐说:“楚国的令尹囊瓦不仁,他的部下没有死战的决心。我们抢先进攻,他们的士兵必定奔逃,然后大部队跟上去,必然得胜。”阖庐不答应。夫概王说:“所谓‘臣下合于道义就去做,不必等待命令’,说的就是这个吧!今天我拼命作战,就可以攻进郢都了。”于是,夫槩王带着他的部下五千人,抢先攻打子常的队伍,子常的士兵奔逃,楚军乱了阵脚,吴军大败楚军。子常逃亡到郑国。史皇带着子常的兵车战死。吴军追赶楚军,到达清发,准备发动攻击。夫槩王说:“被围困的野兽还要争斗一番,何况人呢?如果明知不免一死而同我们拼命决战,必定会打败我们。如果让先渡过河的楚军知道一过河就可以逃脱,后边的人羡慕先渡河的,楚军就没有斗志了。渡过一半才可以攻击。”照这样做,又一次打败楚军。楚军做饭,吴军又赶到了,楚军奔逃。吴军吃完楚军做的饭,又继续追击,在雍澨打败了楚军。经过五次战斗,吴军到达楚国的郢都。 +十一月二十八日,楚王带了他妹妹季羋畀我逃出郢都,徒步渡过睢水。鍼尹固和楚王同船,楚昭王让鍼尹固迫使尾巴上点火的大象冲入吴军中。 +二十九日,吴军进入郢都,按照上下次序分别住在楚国宫室里。吴王阖庐的儿子子山住进了令尹府,夫槩王想要攻打他,子山害怕,离开了,夫槩王就住进了令尹府。 +左司马沈尹戌到达息地就往回退兵,在雍澨打败吴军,负了伤。当初,左司马曾经做过阖庐的臣下,所以把被吴军俘虏看成羞耻,对他的部下说:“谁能够不让吴国人得到我的脑袋?”吴国人句卑说:“下臣卑贱,可以担当这任务吗?”司马说:“我过去竟然没重视您,您行啊!”司马三次战斗都负了伤,说:“我不中用了。”句卑展开裙子,割下沈司马的脑袋包裹起来,藏好尸体,便带着沈尹戌的头逃走了。 +楚昭王渡过睢水,渡过长江,进入云梦泽。楚昭王在睡觉,强盗加以袭击,用戈刺击楚昭王,王孙由于用背去挡,击中了肩膀。楚昭王逃到郧地,钟建背着季羋跟随着。王孙由于慢慢苏醒过来以后,也跟上去。郧公辛的弟弟怀准备杀死楚昭王,说:“平王杀了我父亲,我杀死他的儿子,不也是应该的吗?”辛说:“国君讨伐臣下,谁敢仇恨他?国君的命令,代表上天的意志。如果死于天意,您还要仇恨谁?《诗》说,‘软的不吞下,硬的不吐掉。不欺鳏寡,不畏强暴’,这只有仁爱的人才能这样。逃避强暴,欺凌弱小,这不是勇;乘人之危,这不是仁;灭亡宗族,废弃祭祀,这不是孝;举动没有正当的名义,这不是明智。你要是一定这样做,我就先杀死你。”鬬辛就和他的弟弟巢护卫着楚昭王逃亡到随国。吴国人追赶楚昭王,吴王派人对随国国君说:“周朝的子孙封在汉水一带的,楚国全都灭了他们。上天的意志,降罚于楚国,而您又把楚君藏匿起来。周室有什么罪?您如果报答周室的恩惠,波及于寡人,来完成天意,这是您的恩惠,汉水北边的土地,您就可以享有。”楚王住在随国宫殿的北面,吴军在随国宫殿的南面。子期长得像楚昭王,他逃到楚昭王那里,穿上楚昭王的服饰,说:“把我交给吴军,君王一定可以脱险。”随国人为交出子期占卜吉凶,不吉利,就辞谢吴国说:“以随国的偏僻狭小而紧挨着楚国,楚国确实保全了我们。随、楚世世代代都有盟誓,到今天没有改变。如果有了危难而抛弃他们,又怎么能事奉君王?执事所担心的并不在于昭王这一个人,如果对楚国境内加以安抚,我国怎敢不听您的命令?”吴军就撤退了。鑢金当初在子期氏那里做家臣,曾经和随国人有过约定不要把楚昭王交给吴国人。楚昭王让他进见随君订盟,他辞谢,说:“不敢因为君王处于困难而谋求私利。”楚昭王割破子期的胸口和随国人盟誓。 +当初,伍员和申包胥是朋友。伍员逃亡的时候,对申包胥说:“我一定要颠覆楚国。”申包胥说:“尽力干吧!您能颠覆楚国,我一定能复兴楚国。”等到楚昭王在随国避难,申包胥就到秦国去请求出兵,说:“吴国就是大猪、长蛇,一再吞食中原国家,为害从楚国开始。寡君失守国家,远在杂草丛林之中,使下臣报告急难,说:‘夷人的本性是贪得无厌,如果吴国成为君王的邻国,这是边境的祸患。乘着吴国没有安定下来,君王可以平分楚国。如果楚国就此灭亡,那就是君王的土地了。如果仰仗君王的威福派兵镇抚楚国,楚国将世世代代事奉君王。’”秦哀公辞谢申包胥,说:“我知道您的意见了,您姑且到宾馆休息,我们要商量一下再答复您。”申包胥回答说:“寡君逃亡到杂草丛林之中,还没有得到安身的地方,下臣哪敢去休息呢?”申包胥靠着院墙站着嚎陶大哭,日夜哭声不断,七天不喝一口水。秦哀公大为感动,赋了《无衣》这首诗。申包胥叩头九次,然后坐下。秦军于是出动。 + +定公五年 +【经】五年春王三月辛亥朔,日有食之。夏,归粟于蔡。于越入吴。六月丙申,季孙意如卒。秋七月壬子,叔孙不敢卒。冬,晋士鞅帅师围鲜虞。 +【传】五年春,王人杀子朝于楚。 +夏,归粟于蔡,以周亟,矜无资。 +越入吴,吴在楚也。 +六月,季平子行东野,还,未至,丙申,卒于房。阳虎将以与璠敛,仲梁怀弗与,曰:“改步改玉。”阳虎欲逐之,告公山不狃。不狃曰:“彼为君也,子何怨焉?”既葬,桓子行东野,及费。子泄为费宰,逆劳于郊,桓子敬之。劳仲梁怀,仲梁怀弗敬。子泄怒,谓阳虎:“子行之乎?” +申包胥以秦师至,秦子蒲、子虎帅车五百乘以救楚。子蒲曰:“吾未知吴道。”使楚人先与吴人战,而自稷会之,大败夫□王于沂。吴人获薳射于柏举,其子帅奔徒以从子西,败吴师于军祥。秋七月,子期、子蒲灭唐。 +九月,夫□王归,自立也。以与王战而败,奔楚,为堂溪氏。吴师败楚师于雍澨,秦师又败吴师。吴师居麇,子期将焚之,子西曰:“父兄亲暴骨焉,不能收,又焚之,不可。”子期曰:“国亡矣!死者若有知也,可以歆旧祀,岂惮焚之?”焚之,而又战,吴师败。又战于公婿之溪,吴师大败,吴子乃归。囚闉舆罢,闉舆罢请先,遂逃归。叶公诸梁之弟后臧从其母于吴,不待而归。叶公终不正视。 +乙亥,阳虎囚季桓子及公父文伯,而逐仲梁怀。冬十月丁亥,杀公何藐。己丑,盟桓子于稷门之内。庚寅,大诅,逐公父歜及秦遄,皆奔齐。 +楚子入于郢。初,斗辛闻吴人之争宫也,曰:“吾闻之:‘不让则不和,不和不可以远征。’吴争于楚,必有乱。有乱则必归,焉能定楚?”王之奔随也,将涉于成臼,蓝尹亹涉其帑,不与王舟。及宁,王欲杀之。子西曰:“子常唯思旧怨以败,君何效焉?”王曰:“善。使复其所,吾以志前恶。”王赏斗辛、王孙由于、王孙圉、钟建、斗巢、申包胥、王孙贾、宋木、斗怀。子西曰:“请舍怀也。”王曰:“大德灭小怨,道也。”申包胥曰:“吾为君也,非为身也。君既定矣,又何求?且吾尤子旗,其又为诸?”遂逃赏。王将嫁季芈,季芈辞曰:“所以为女子,远丈夫也。钟建负我矣。”以妻钟建,以为乐尹。 +王之在随也,子西为王舆服以保路,国于脾泄。闻王所在,而后从王。王使由于城麇,覆命,子西问高厚焉,弗知。子西曰:“不能,如辞。城不知高厚,小大何知?”对曰:“固辞不能,子使余也。人各有能有不能。王遇盗于云中,余受其戈,其所犹在。”袒而示之背,曰:“此余所能也。脾泄之事,余亦弗能也。” +晋士鞅围鲜虞,报观虎之役也。 +译文 +五年春季,成周人在楚国杀死了王子朝。 +夏季,鲁国把粮食送到蔡国,用来救济急难,怜悯他们没有粮食。 +越国人进入吴国,这是由于吴国人正侵入楚国。 +六月,季平子巡视东野,回来,没有到达,十七日,死在房地。阳虎准备用美玉随葬,仲梁怀不给,说:“步子改变了,美玉也要跟着改变。”阳虎想要赶走他,告诉公山不狃。不狃说:“他是为着国君,您有什么怨恨的呢?”安葬以后,桓子巡视东野,到达费地。子泄做费地宰,在郊外迎接慰劳,桓子对他表示尊敬。慰劳仲梁怀,仲梁怀对他却不表示恭敬。子泄发怒,对阳虎说:“您要把他赶走吗?” +申包胥带着秦军到达,秦国的子蒲、子虎率领战车五百辆以救援楚国。子蒲说:“我不知道吴军的战术。”让楚军先和吴军作战,秦军在稷地和吴军会合,在沂地大败夫概王。吴国人在柏举俘虏了薳射,薳射的儿子率领溃逃的士兵跟随子西,在军祥地方打败了吴军。 +秋季,七月,子期、子蒲灭亡唐国。九月,夫槩王回国,自立为王,因为和吴王阖庐作战,被打败,逃亡到楚国,就是后来的棠溪氏。 +吴军在雍澨打败楚军,秦军又打败了吴军。吴军驻扎在麇地,子期准备用火攻打吴军,子西说:“父兄亲戚的尸骨暴露在那里,不能收敛又要烧掉,不行。”子期说:“国家将要灭亡了!死去的人如果有知觉,国家复兴他们就可以享有以往的祭祀了,哪里还怕烧掉尸骨?”楚军放火焚烧吴军,又接着进攻,吴军败退,又在公婿之溪作战,吴军大败,吴王就回国去了。吴军俘虏了闉舆罢。闉舆罢请求先行到吴国,就乘机逃回了楚国。叶公诸梁的弟弟后臧与他母亲在吴国,后来后臧抛弃了他的母亲回到楚国。叶公见后臧不仁不孝,就一直不用正眼看他。 +九月二十八日,阳虎囚禁了季桓子和公父文伯,并驱逐了仲梁怀。冬季,十月初十日,杀了公何藐。十二日,与桓子在稷门里边盟誓。十三日,举行大的诅咒,驱逐了公父文伯和秦遄,两个人都逃亡到齐国。 +楚昭王进入郢都。当初,鬬辛听说吴军将帅争住楚国宫室,说:“我听说:‘不谦让就会不和睦,不和睦就不能远征。’吴国人在楚国争夺,必定会发生动乱,发生动乱,就必定会撤军回国,哪里能平定楚国呢?” +楚昭王逃亡到随国的时候,要在成臼渡河,蓝尹亹用船把他妻子儿子先渡过河,不把船给楚昭王用,等到楚国安定以后,楚昭王要杀他。子西说:“当初子常就因为记挂着过去的怨恨而失败,君王为什么学他呢?”楚昭王说:“好,让蓝尹亹官复原职,我用这件事来记住以往的过失。”楚昭王赏赐鬬辛、王孙由于、王孙圉、钟建、鬬巢、申包胥、王孙贾、宋木、鬬怀。子西说:“请您不要赏赐鬬怀!”楚昭王说:“大德消除了小怨,这是合于正道的。”申包胥说:“我是为了国君,不是为了自己。国君已经安定了,我还追求什么?而且我也恨子旗,难道又要去学子旗贪得无厌吗?”于是申包胥就逃避了楚王的赏赐。楚昭王准备把季羋出嫁,季羋辞谢说:“作为女人,就是要远离男人。可是钟建已经背过我了。”楚昭王把她嫁给钟建,封钟建担任乐尹。 +楚昭王在随国的时候,子西仿制了楚昭王的车子和服饰来收集和保护溃散的人,在脾泄建立了国都以此安定人心。听到了楚昭王的下落,然后赶去。楚昭王派王孙由于在麇地筑城,王孙由于回来复命。子西问起城墙的高度厚度,王孙由于不知道。子西说:“你如果干不了,就应当推辞,不知道城墙的高度、厚度和城的大小,那还知道什么?”王孙由于回答说:“我坚决推辞,说干不了,是您让我去做了。人人都有干得了的事,也有干不了的事。君王在云梦泽碰上强盗,我挡住强盗的戈,伤处还在这里!”王孙由于脱去衣服把背部给子西看,说:“这是我干得了的。像在脾泄建立楚王行都的事情,我是干不了的。” +晋国的士鞅包围鲜虞,是为了报复观虎被俘的那次战役。 + +定公六年 +【经】六年春王正月癸亥,郑游速帅师灭许,以许男斯归。二月,公侵郑。公至自侵郑。夏,季孙斯、仲孙何忌如晋。秋,晋人执宋行人乐祁犁。冬,城中城。季孙斯、仲孙忌帅师围郓。 +【传】六年春,郑灭许,因楚败也。 +二月,公侵郑,取匡,为晋讨郑之伐胥靡也。往不假道于卫;及还,阳虎使季、孟自南门入,出自东门,舍于豚泽。卫侯怒,使弥子瑕追之。公叔文子老矣,辇而如公,曰:“尤人而效之,非礼也。昭公之难,君将以文之舒鼎,成之昭兆,定之鞶鉴,苟可以纳之,择用一焉。公子与二三臣之子,诸侯苟忧之,将以为之质。此群臣之所闻也。今将以小忿蒙旧德,无乃不可乎!大姒之子,唯周公、康叔为相睦也。而效小人以弃之,不亦诬乎!天将多阳虎之罪以毙之,君姑待之,若何?”乃止。 +夏,季桓子如晋,献郑俘也。阳虎强使孟懿子往报夫人之币。晋人兼享之。孟孙立于房外,谓范献子曰:“阳虎若不能居鲁,而息肩于晋,所不以为中军司马者,有如先君!”献子曰:“寡君有官,将使其人。鞅何知焉?”献子谓简子曰:“鲁人患阳虎矣,孟孙知其衅,以为必适晋,故强为之请,以取入焉。” +四月己丑,吴大子终累败楚舟师,获潘子臣、小惟子及大夫七人。楚国大惕,惧亡。子期又以陵师败于繁扬。令尹子西喜曰:“乃今可为矣。”于是乎迁郢于郤,而改纪其政,以定楚国。 +周儋翩率王子朝之徒,因郑人将以作乱于周。郑于是乎伐冯、滑、胥靡、负黍、狐人、阙外。六月,晋阎没戍周,且城胥靡。 +秋八月,宋乐祁言于景公曰:“诸侯唯我事晋,今使不往,晋其憾矣。”乐祁告其宰陈寅。陈寅曰:“必使子往。”他日,公谓乐祁曰:“唯寡人说子之言,子必往。”陈寅曰:“子立后而行,吾室亦不亡,唯君亦以我为知难而行也。”见溷而行。赵简子逆,而饮之酒于绵上,献杨楯六十于简子。陈寅曰:“昔吾主范氏,今子主赵氏,又有纳焉。以杨楯贾祸,弗可为也已。然子死晋国,子孙必得志于宋。”范献子言于晋侯曰:“以君命越疆而使,未致使而私饮酒,不敬二君,不可不讨也。”乃执乐祁。 +阳虎又盟公及三桓于周社,盟国人于亳社,诅于五父之衢。 +冬,十二月,天王处于姑莸,辟儋翩之乱也。 +译文 +六年春季,郑国灭亡了许国,这是由于楚国战败,不能救援。 +二月,定公发兵侵袭郑国,夺取匡地,这是为晋国去讨伐郑国的攻打胥靡。去的时候不向卫国借路;等到回来,阳虎让季桓子、孟献子从卫国国都的南门进入,从东门出去,住在豚泽。卫灵公发怒,派弥子瑕追赶他们。公叔文子已经告老退休了,坐了人拉的车子去进见卫灵公,说:“怨恨别人而效法他,这是不符合礼的。鲁昭公遭遇危险的时候,君王准备用文公的舒鼎、成公的宝龟、定公的鞶鉴作为赏赐,如果有人能送回鲁昭公,对这些宝物就可以任意选用一件。君王的儿子和几位臣下的儿子,诸侯如果为鲁昭公操心,就可以把他们送去作为人质。这是下臣们所听到的。现在将要用小小的愤恨掩盖过去的恩德,恐怕不可以吧!太姒的儿子,惟有周公、康叔是互相和睦的,而现在要效法小人而丢掉和睦,不是受骗吗?上天将要让阳虎的罪过增多而使他灭亡,君王姑且等着,怎么样?”卫灵公就停止出兵。 +夏季,季桓子去到晋国,这是为了奉献郑国的俘虏。阳虎强派孟懿子前去向晋夫人回送财礼。晋国人同时设享礼招待他们。孟孙站在房外,对范献子说:“阳虎如果在鲁国住不下去,卸除职任而来晋国,晋国不让他做中军司马,有先君在上!”范献子说:“寡君设置官职,将要选择适当的人选,鞅知道什么?”范献子对赵简子说:“鲁国人讨厌阳虎了。孟孙看到了这预兆,认为阳虎一定会来晋国,所以竭力为他请求,以期求得禄位而进入晋国。” +四月十五日,吴国的太子终累打败楚国的水军,俘虏了潘子臣、小惟子和七个大夫。楚国大为恐惧,害怕灭亡。子期又带着陆军在繁扬被战败。令尹子西高兴地说:“现在可以治理了。”从这时开始把郢都迁到鄀地,改革政治,来安定楚国。 +成周的儋翩率领王子朝的部下依仗郑国人,准备在成周发动叛乱,郑国在这时攻打冯地、滑地、胥靡、负黍、狐人、阙外。六月,晋国的阎没到成周戌守,并且在胥靡筑城。 +秋季,八月,宋国的乐祁对宋景公说:“诸侯中间惟有我们事奉晋国,现在使者不去,晋国恐怕要怨恨我们了。”乐祁把话告诉了他的宰臣陈寅。陈寅说:“一定会让您去。”过了些时候,宋景公对乐祁说:“唯有寡人对您的话感到高兴,您一定得去!”陈寅说:“您立了继承人再动身,我们家也不会灭亡,希望国君也认为我们是明知困难才去的。”乐祁就让溷拜见了宋景公才动身。赵简子迎接乐祁,和他在绵上喝酒,乐祁奉献六十面杨木盾牌给赵简子。陈寅说:“从前我们事奉范氏,现在您事奉赵氏,又有进奉的东西,用杨木盾牌招来祸患,设法办了。然而由于您出使晋国而死,子孙必然在宋国得志。”范献子对晋定公说:“由于国君的命令越过别国而出使,没有正式报告使命而私自饮酒,不尊敬两国国君,不能不加以讨伐。”于是晋国就逮捕了乐祁。 +阳虎又和鲁定公与三桓在周社盟誓,和国内的人们在亳社盟誓,在五父之衢诅咒。 +冬季,十二月,周敬王住在姑莸,这是为了逃避儋翩的祸乱。 + +定公七年 +【经】七年春王正月。夏四月。秋,齐侯、郑伯盟于咸。齐人执卫行人北宫结以侵卫。齐侯、卫侯盟于沙。大雩。齐国夏帅师伐我西鄙。九月,大雩。冬十月。 +【传】七年春二月,周儋翩入于仪栗以叛。 +齐人归郓、阳关,阳虎居之以为政。 +夏四月,单武公、刘桓公败尹氏于穷谷。 +秋,齐侯、郑伯盟于咸,征会于卫。卫侯欲叛晋,诸大夫不可。使北宫结如齐,而私于齐侯曰:“执结以侵我。”齐侯从之,乃盟于琐。 +齐国夏伐我。阳虎御季桓子,公敛处父御孟懿子,将宵军齐师。齐师闻之,堕,伏而待之。处父曰:“虎不图祸,而必死。”苫夷曰:“虎陷二子于难,不待有司,余必杀女。”虎惧,乃还,不败。 +冬十一月戊午,单子、刘子逆王于庆氏。晋籍秦送王。己巳,王入于王城,馆于公族党氏,而后朝于庄宫。 +译文 +七年春季,二月,周朝的儋翩进入仪栗而叛变。 +齐国人归还郓地、阳关,阳虎住在那里主持政事。 +夏季,四月,单武公、刘桓公在穷谷打败了尹氏。 +秋季,齐景公、郑献公在咸地结盟,在卫国召集诸侯会见。卫灵公想要背叛晋国,大夫们认为不行。卫灵公派北宫结去到齐国,私下告诉齐景公说:“把结抓起来,侵袭我国。”齐景公听从了他的话,就在琐地结盟。 +齐国国夏进攻我国。阳虎为季桓子驾御战车,公敛处父为孟懿子驾御战车,准备夜里袭击齐军。齐军听到这个消息,假装没有防备,设下埋伏等待鲁军。公敛处父说:“阳虎你不考虑到这样做会引起祸患,你一定会死。”苫夷说:“阳虎你如果使他们两位陷入祸难,不等军法官的判决,我一定杀了你。”阳虎害怕,就撤兵,才没有招致失败。 +冬季,十一月二十三日,单子、刘子在庆氏那里迎接周敬王。晋国的籍秦护送周敬王。十二月初五日,周敬王进入王城,住在公族党氏家里,然后到庄王庙朝拜。 + +定公八年 +【经】八年春王正月,公侵齐。公至自侵齐。二月,公侵齐。三月,公至自侵齐。曹伯露卒。夏,齐国夏帅师伐我西鄙。公会晋师于瓦。公至自瓦。秋七月戊辰,陈侯柳卒。晋士鞅帅师侵郑,遂侵卫。葬曹靖公。九月,葬陈怀公。季孙斯、仲孙何忌帅师侵卫。冬,卫侯、郑伯盟于曲濮。从祀先公。盗窃宝玉、大弓。 +【传】八年春,王正月,公侵齐,门于阳州。士皆坐列,曰:“颜高之弓六钧。”皆取而传观之。阳州人出,颜高夺人弱弓,籍丘子锄击之,与一人俱毙。偃,且射子锄,中颊,殪。颜息射人中眉,退曰:“我无勇,吾志其目也。”师退,冉猛伪伤足而先。其兄会乃呼曰:“猛也殿!” +二月己丑,单子伐谷城,刘子伐仪栗。辛卯,单子伐简城,刘子伐盂,以定王室。 +赵鞅言于晋侯曰:“诸侯唯宋事晋,好逆其使,犹惧不至。今又执之,是绝诸侯也。”将归乐祁。士鞅曰:“三年止之,无故而归之,宋必,叛晋。”献子私谓子梁曰:“寡君惧不得事宋君,是以止子。子姑使溷代子。”子梁以告陈寅,陈寅曰:“宋将叛晋是弃溷也,不如侍之。”乐祁归,卒于大行。士鞅曰:“宋必叛,不如止其尸以求成焉。”乃止诸州。 +公侵齐,攻廪丘之郛。主人焚冲,或濡马褐以救之,遂毁之。主人出,师奔。阳虎伪不见冉猛者,曰:“猛在此,必败。”猛逐之,顾而无继,伪颠。虎曰:“尽客气也。”苫越生子,将待事而名之。阳州之役获焉,名之曰阳州。 +夏,齐国夏、高张伐我西鄙。晋士鞅、赵鞅、荀寅救我。公会晋师于瓦。范献子执羔,赵简子、中行文子皆执雁。鲁于是始尚羔。 +晋师将盟卫侯于鄟泽。赵简子曰:“群臣谁敢盟卫君者?”涉佗、成何曰:“我能盟之。”卫人请执牛耳。成何曰:“卫,吾温、原也,焉得视诸侯?”将歃,涉佗捘卫侯之手,及捥。卫侯怒,王孙贾趋进,曰:“盟以信礼也。有如卫君,其敢不唯礼是事,而受此盟也。” +卫侯欲叛晋,而患诸大夫。王孙贾使次于郊,大夫问故。公以晋诟语之,且曰:“寡人辱社稷,其改卜嗣,寡人从焉。”大夫曰:“是卫之祸,岂君之过也?”公曰:“又有患焉。谓寡人‘必以而子与大夫之子为质。’”大夫曰:“苟有益也,公子则往。群臣之子,敢不皆负羁绁以从?”将行。王孙贾曰:“苟卫国有难,工商未尝不为患,使皆行而后可。”公以告大夫,乃皆将行之。行有日,公朝国人,使贾问焉,曰:“若卫叛晋,晋五伐我,病何如矣?”皆曰:“五伐我,犹可以能战。”贾曰:“然则如叛之,病而后质焉,何迟之有?”乃叛晋。晋人请改盟,弗许。 +秋,晋士鞅会成桓公,侵郑,围虫牢,报伊阙也。遂侵卫。 +九月,师侵卫,晋故也。 +季寤、公锄极、公山不狃皆不得志于季氏,叔孙辄无宠于叔孙氏,叔仲志不得志于鲁。故五人因阳虎。阳虎欲去三桓,以季寤更季氏,以叔孙辄更叔孙氏,己更孟氏。冬十月,顺祀先公而祈焉。辛卯,禘于僖公。壬辰,将享季氏于蒲圃而杀之,戒都车曰:“癸巳至。”成宰公敛处父告孟孙,曰:“季氏戒都车,何故?”孟孙曰:“吾弗闻。”处父曰:“然则乱也,必及于子,先备诸?”与孟孙以壬辰为期。 +阳虎前驱,林楚御桓子,虞人以铍盾夹之,阳越殿,将如蒲圃。桓子咋谓林楚曰:“而先皆季氏之良也,尔以是继之。”对曰:“臣闻命后。阳虎为政,鲁国服焉。违之,征死。死无益于主。”桓子曰:“何后之有?而能以我适孟氏乎?”对曰:“不敢爱死,惧不免主。”桓子曰:“往也。”孟氏选圉人之壮者三百人,以为公期筑室于门外。林楚怒马及衢而骋,阳越射之,不中,筑者阖门。有自门间射阳越,杀之。阳虎劫公与武叔,以伐孟氏。公敛处父帅成人,自上东门入,与阳氏战于南门之内,弗胜。又战于棘下,阳氏败。阳虎说甲如公宫,取宝玉、大弓以出,舍于五父之衢,寝而为食。其徒曰:“追其将至。”虎曰:“鲁人闻余出,喜于征死,何暇追余?”从者曰:“嘻!速驾!公敛阳在。”公敛阳请追之,孟孙弗许。阳欲杀桓子,孟孙惧而归之。子言辨舍爵于季氏之庙而出。阳虎入于欢、阳关以叛。 +郑驷歂嗣子大叔为政。 +译文 +八年春季,周王朝历法的正月,鲁定公发兵入侵齐国,攻打阳州的城门。士兵们都排成行列坐着,说:“颜高的硬弓有一百八十斤呢!”大家都拿来传看。阳州人出战,颜高把别人的软弓抢过来准备射箭,籍丘子鉏击打颜高,颜高和另外一个人都被击倒在地上。颜高倒在地上,向子鉏射了一箭,射中他的脸颊,把他射死了。颜息射人射中眉毛,退下来说:“我没有本事,我本来是想射他的眼睛。”军队撤退,冉猛假装脚上受伤而走在前面,他的哥哥冉会就大喊说:“猛啊,到后面去吧!” +三月二十六日,单武公发兵进攻谷城,刘桓公发兵进攻仪栗,三月二十八日,单武公发兵进攻简城,刘桓公发兵进攻盂地,以安定王室。 +赵鞅对晋定公说:“诸侯之中惟有宋国事奉晋国,好好迎接他们的使者,还恐怕不来,现在又逮捕了他们的使者,这样将会使自己继绝与诸侯的关系。”准备放回乐祁,士鞅说:“扣留了他三年,无缘无故又把他放回去,宋国必然背叛晋国。”士鞅私下对乐祁说:“寡君害怕不能事奉宋君,因此没有让您回去,您姑且让溷来代替您。”乐祁把话告诉陈寅。陈寅说:“宋国将要背叛晋国,这是丢弃溷,乐祁不如等一下。”乐祁动身回去,死在太行。士鞅说:“宋国必定背叛,不如留下他的尸体来求和。”于是就把尸体留在州地。 +鲁定公入侵齐国,攻打廪丘外城。廪丘守将放火焚烧冲城的战车,有人把麻布短衣沾湿了灭火,就攻破了外城。守将出战,鲁军奔逃。阳虎假装没有看见冉猛的样子,说:“冉猛要在这里,一定能打败他们。”冉猛追逐廪丘人,看到后面没有人跟上来,就假装从车上掉下来。阳虎说:“都是言不由衷。”苫越生了儿子,准备等到有了大事再来命名。阳州这一役俘虏了敌人,就把儿子命名为阳州。 +夏季,齐国的国夏、高张进攻我国西部边境。晋国的士鞅、赵鞅、荀寅救援我国。鲁国在瓦地会见晋军,士鞅手拿小羔,赵鞅、荀寅都手拿大雁作为礼物。鲁国从这时开始就以羔羊为贵重礼物。 +晋军将要和卫灵公在鄟泽结盟,赵简子说:“臣下们有谁敢和卫国国君结盟?”涉佗、成何说:“我们能和他结盟。”卫国人请他们两人执牛耳。成何说:“卫国,不过和我国温地、原地差不多,哪里能和诸侯相比?”将要歃血,涉佗推开卫灵公的手,血顺着淌到手腕上。卫灵公发怒,王孙贾快步走进,说:“结盟是用来伸张礼仪的,就像卫国国君所做的那样,难道敢不奉行礼仪而接受这个盟约?” +卫灵公想要背叛晋国而又担心大夫们反对。王孙贾让卫灵公住在郊外,大夫问什么缘故,卫灵公把所受晋国人的侮辱告诉他们,而且说:“寡人对不起国家,还是改卜其他人作为继承人,寡人愿意服从。”大夫说:“这是卫国的祸患,哪里是君王的过错吗?”卫灵公说:“还有使人担心的事呢,他们对寡人说:‘一定要你的儿子和大夫的儿子作为人质。’”大夫说:“如果有好处,公子就去,臣下们的儿子岂敢不背负着马笼头和马缰绳跟随前去?”将要动身,王孙贾说:“如果卫国有了灾难,工匠商人未尝不是祸患,要让他们全都走了才行。”卫灵公把话告诉大夫,于是就要他们都走。已经定了起程日期,卫灵公让国内的人们朝见,派王孙贾向大家说:“如果卫国背叛晋国,晋国攻打我们五次,会危险到什么程度?”大家都说:“攻打我们五次,还可以有能力作战。”王孙贾说:“那么应当先背叛晋国,发生危险再送人质,还不晚吧?”于是就背叛晋国,晋国人请求重新结盟,卫国人不同意。 +秋季,晋国的士鞅会合成桓公侵袭郑国,包围虫牢,以报复伊阙那次战役。于是就乘机侵袭卫国。 +九月,鲁军侵袭卫国,这是为了协同于晋国作战的缘故。 +季寤,公鉏极、公山不狃在季氏那里不得志,叔孙辄在叔孙氏那里不受宠信,叔孙志在鲁国不得志,所以这五个人依靠阳虎。阳虎想要去掉三桓,用季寤取代季氏,用叔孙辄取代叔孙氏,自己取代孟氏。冬季十月,依即位的先后次序祭祀先公并且祈祷。初二日,在僖公庙里举行大规模祭祀。初三日,准备在蒲圃设享礼招待季氏时而杀死他,命令都邑里的战车部队说:“初四那天都要来。”成地的宰臣公敛处父告诉孟孙说:“季氏命令战车部队,是什么缘故?”孟孙说:“我没有听说过。”处父说:“那么这就是叛乱了,必定会涉及您,是不是先准备一下?”和孟孙约定以初三作为预定日期。 +阳虎驱车走在前边,林楚为桓子驾车,警卫军官手持铍、盾在两边夹护,阳越走在最后。将到蒲圃,桓子突然对林楚说:“你的先人都是季氏家里的忠良之臣,你也要以此来继承他们。”林楚说:“下臣听到这话已经迟了。阳虎执政,鲁国人都服从他,违背他就是找死,死了也对主人没有好处。”桓子说:“有什么迟?你能带我去到孟氏那里吗?”林楚回答说:“我不敢爱惜一死,怕的是不能使主人免于祸难。”桓子说:“去吧!”孟氏挑选了三百个健壮奴隶为公期在门外造房子。林楚鞭打乘马,到了大街上就飞跑而去,阳越用箭射他,没有射中,造房子的人关上大门。有人从门缝里用箭射阳越,杀死了他。阳虎劫持鲁定公和武叔以攻打孟氏。公敛处父率领成地人从上东门进入,和阳氏在南门里边作战,没有战胜。又在棘下作战,阳氏战败。阳虎脱去皮甲去到公宫,拿了宝玉、大弓出来,住在五父之衢,自己睡下而让人做饭。他的同伙说:“追赶的人恐怕快来了。”阳虎说:“鲁国人听说我出去了,正高兴可以晚点死了,哪里有空来追我?”跟随的人说:“呀,快点套上马车吧,公敛处父在那里。”公敛处父请求追赶阳虎,孟孙不答应。公敛处父想要杀死季桓子,孟孙害怕,就把季桓子送回家去。季寤在季氏的祖庙里向祖宗一一斟酒祭告然后逃走。阳虎进入讙地、阳关而叛变。 +郑国的驷歂继承子太叔执政。 + +定公九年 +【经】九年春王正月。夏四月戊申,郑伯虿卒。得宝玉、大弓。六月,葬郑献公。秋,齐侯、卫侯次于五氏。秦伯卒。冬,葬秦哀公。 +【传】九年春,宋公使乐大心盟于晋,且逆乐祁之尸。辞,伪有疾。乃使向巢如晋盟,且逆子梁之尸。子明谓桐门右师出,曰:“吾犹衰絰,而子击钟,何也?”右师曰:“丧不在此故也。”既而告人曰:“己衰絰而生子,余何故舍钟?”子明闻之,怒,言于公曰:“右师将不利戴氏,不肯适晋,将作乱也。不然无疾。”乃逐桐门右师。 +郑驷歂杀邓析,而用其《竹刑》。君子谓子然:“于是不忠。苟有可以加于国家者,弃其邪可也。《静女》之三章,取彤管焉。《竿旄》‘何以告之’,取其忠也。故用其道,不弃其人。《诗》云:‘蔽芾甘棠,勿翦勿伐、召伯所茇。’思其人犹爱其树,况用其道而不恤其人乎?子然无以劝能矣。” +夏,阳虎归宝玉、大弓。书曰“得”,器用也。凡获器用曰得,得用焉曰获。 +六月,伐阳关。阳虎使焚莱门。师惊,犯之而出,奔齐,请师以伐鲁,曰:“三加必取之。”齐侯将许之。鲍文子谏曰:“臣尝为隶于施氏矣,鲁未可取也。上下犹和,众庶犹睦,能事大国,而无天灾,若之何取之?阳虎欲勤齐师也,齐师罢,大臣必多死亡,己于是乎奋其诈谋。夫阳虎有宠于季氏,而将杀季孙,以不利鲁国,而求容焉。亲富不亲仁,君焉用之?君富于季氏,而大于鲁国,兹阳虎所欲倾覆也。鲁免其疾,而君又收之,无乃害乎!”齐侯执阳虎,将东之。阳虎愿东,乃囚诸西鄙。尽借邑人之车,锲其轴,麻约而归之。载葱灵,寝于其中而逃。追而得之,囚于齐。又以葱灵逃,奔晋,适赵氏。仲尼曰:“赵氏其世有乱乎!” +秋,齐侯伐晋夷仪。敝无存之父将室之,辞,以与其弟,曰:“此役也不死,反,必娶于高、国。”先登,求自门出,死于溜下。东郭书让登,犁弥从之,曰:“子让而左,我让而右,使登者绝而后下。”书左,弥先下。书与王猛息。猛曰:“我先登。”书敛甲,曰:“曩者之难,今又难焉!”猛笑曰:“吾从子如骖之靳。” +晋车千乘在中牟。卫侯将如五氏,卜过之,龟焦。卫侯曰:“可也。卫车当其半,寡人当其半,敌矣。”乃过中牟。中牟人欲伐之,卫褚师圃亡在中牟,曰:“卫虽小,其君在焉,未可胜也。齐师克城而骄,其帅又贱,遇,必败之。不如从齐。”乃伐齐师,败之。齐侯致禚、媚、杏于卫。齐侯赏犁弥,犁弥辞,曰:“有先登者,臣从之,皙帻而衣狸制。”公使视东郭书,曰:“乃夫子也,吾贶子。”公赏东郭书,辞,曰:“彼,宾旅也。”乃赏犁弥。 +齐师之在夷仪也,齐侯谓夷仪人曰:“得敝无存者,以五家免。”乃得其尸。公三襚之。与之犀轩与直盖,而先归之。坐引者,以师哭之,亲推之三。 +译文 +九年春季,宋景公派乐大心到晋国结盟,并且迎接乐祁的灵柩。乐大心推辞,假装有病,于是就派向巢去到晋国结盟,并且迎接乐祁的灵柩。子明要乐大心出国迎接,说:“我还穿着丧服,而您却敲钟作乐,这是为什么?”乐大心说:“这是因为丧事不在这里。”不久以后告诉别人说:“自己穿着丧服却生了孩子,我为什么不敲钟?”子明听到了,发怒,对宋景公说:“乐大心将要不利于宋国。他不肯去晋国,是要准备发动叛乱。不是这样,为什么没病装病?”于是就驱逐了乐大心。 +郑国的驷歂杀了邓析,而又用邓析制订的《竹刑》。君子认为驷歂在这件事情上不忠。如果有人对国家有利,就可以不指责他的邪恶。《静女》这三章诗,是采取它的彤管。《竿旄》的‘用什么来劝告他’,是采取它的忠诚。所以采用了一个人的主张,就不责罚这个人。《诗》说:“甘棠树高大而枝叶茂密,不要剪除,不要砍伐,召伯曾在这里听讼执法。’想念这个人,尚且爱护这棵树,何况用了他的主张,而不顾念这个人呢?驷歂没有办法勉励贤能的人。” +夏季,阳虎送回宝玉、大弓,《春秋》记载说“得”,因为它们是器物用具。凡是获得器物用具叫做“得”,用器物来获得生物,叫做“获”。 +六月,进攻阳关,阳虎派人焚烧了莱门。鲁军惊恐,阳虎突围而逃亡到齐国,请求出兵去进攻鲁国,说:“进攻三次,一定能占取鲁国。”齐景公准备答应他。鲍文子劝谏说:“下臣曾经在施氏那里做过家臣,鲁国是不能占取的。上下协调,百姓和睦,能够事奉大国而没有天灾,怎么能占取它?阳虎想要劳动齐军,齐军困疲,大臣一定死亡很多,他自己就在这里施展阴谋。阳虎受到季氏的宠信,而准备杀死季氏,以不利于鲁国而讨好别人。喜欢富有而不喜欢仁爱,君主哪里用得着他?君王比季氏富有,而比鲁国强大,这就是阳虎所要颠覆的。鲁国免除了他的祸害,而君王又收容他,恐怕也是祸害吧!”齐景公逮捕了阳虎,准备把他囚禁在东部边境。阳虎假装愿意到东部去,齐侯就把他囚禁在西部边境。阳虎把当地的车子全都借来,用刀子在车轴上刻得很深,缠上麻然后归还。阳虎在车上装上衣物,躺在里边逃走。齐国人追上去抓住了他,囚禁在齐国都城。他又一次躺在装衣物的车子里逃走,逃亡到宋国,又逃到晋国,归顺赵氏。孔子说:“赵氏恐怕世世代代会有祸乱了吧!” +秋季,齐景公发兵攻打晋国的夷仪。敝无存的父亲准备为他娶妻,他推辞,给了他兄弟,说:“这一回,如果不死,回来,一定要娶高氏、国氏的女子。”抢先登上夷仪的城墙,又想从城门冲出去,死在城门的门檐下。东郭书抢先登上城墙,犁弥跟着他,说:“您抢着上去向左边,我抢着上去向右边,让登上城墙的人都来了再下去。”东郭书上城往左,犁弥先下了城。战斗结束,东郭书和犁弥一起休息,犁弥说:“我先登上城墙。”东郭书收拾一下皮甲,说:“上一次使我为难,现在还要使我为难!”犁弥笑着说:“我跟着您,好像骖马跟着服马走一样,哪能抢先?” +晋国的战车一千辆在中牟,卫灵公准备去五氏,占卜经过中牟如何,龟甲烤焦了,卫灵公说:“行了,卫国的战车相当于他们的一半,寡人也相当于他们一半,这就相等了。”于是就经过中牟。中牟人想要攻打他们,卫国的褚师圃逃亡到中牟,说:“卫国虽然小,他们的国君在那里,是不能战胜的。齐军攻下城邑就骄傲,他们的元帅又地位低贱,两军相遇,一定可以打败他们,不如向齐军挑战。”于是就进攻齐军,打败了他们。齐景公把禚地、媚地、杏地送给卫灵公。 +齐景公赏赐犁弥,犁弥辞谢,说:“有先登城墙的人,下臣跟着他,他戴着白色头巾,而披着猪皮斗篷”齐景公让他看看是不是东郭书,他说:“正是那一位先生,我把赏赐让给您。”齐景公赏赐东郭书,东郭书辞谢,说:“他是客卿。”于是就赏赐犁弥。 +齐国军队在夷仪的时候,齐景公对夷仪人说:“得到敝无存的人,赏赐五户,免除劳役。”于是就找到了他的尸体。齐景公三次为尸体穿衣服,给他犀牛皮装饰的高贵车子和长柄伞作为殉葬品,而且先把尸体送回去。齐景公让拉车的人跪着行走,全军吊哭他,景公亲自推车三次。 + + +定公十年 +【经】十年春王三月,乃齐平。夏,公会齐侯于夹谷。公至自夹谷。晋赵鞅帅师围卫。齐人来归郓、欢、龟阴田。叔孙州仇、仲孙何忌帅师围郈。秋,叔孙州仇、仲孙何忌帅师围郈。宋乐大心出奔曹。宋公子地出奔陈。冬,齐侯、卫侯、郑游速会于安甫。叔孙州仇如齐。宋公之弟辰暨仲佗、石彄出奔陈。 +【传】十年春,及齐平。 +夏,公会齐侯于祝其,实夹谷。孔丘相。犁弥言于齐侯曰:“孔丘知礼而无勇,若使莱人以兵劫鲁侯,必得志焉。”齐侯从之。孔丘以公退,曰:“士,兵之!两君合好,而裔夷之俘以兵乱之,非齐君所以命诸侯也。裔不谋夏,夷不乱华,俘不干盟,兵不逼好。于神为不祥,于德为愆义,于人为失礼,君必不然。”齐侯闻之,遽辟之。 +将盟,齐人加于载书曰:“齐师出竟,而不以甲车三百乘从我者,有如此盟。”孔丘使兹无还揖对曰:“而不反我汶阳之田,吾以共命者,亦如之。”齐侯将享公,孔丘谓梁丘据曰:“齐、鲁之故,吾子何不闻焉?事既成矣,而又享之,是勤执事也。且牺象不出门,嘉乐不野合。飨而既具,是弃礼也。若其不具,用秕稗也。用秕稗,君辱,弃礼,名恶,子盍图之?夫享,所以昭德也。不昭,不如其已也。”乃不果享。 +齐人来归郓、欢、龟阴之田。 +晋赵鞅围卫,报夷仪也。 +初,卫侯伐邯郸午于寒氏,城其西北而守之,宵熸。及晋围卫,午以徒七十人门于卫西门,杀人于门中,曰:“请报寒氏之役。”涉佗曰:“夫子则勇矣,然我往,必不敢启门。”亦以徒七十人,旦门焉,步左右,皆至而立,如植。日中不启门,乃退。反役,晋人讨卫之叛故,曰:“由涉佗、成何。”于是执涉佗以求成于卫。卫人不许,晋人遂杀涉佗。成何奔燕。君子曰:“此之谓弃礼,必不钧。《诗》曰:‘人而无礼,胡不遄死。’涉佗亦遄矣哉!” +初,叔孙成子欲立武叔,公若藐固谏曰:“不可。”成子立之而卒。公南使贼射之,不能杀。公南为马正,使公若为郈宰。武叔既定,使郈马正侯犯杀公若,不能。其圉人曰:“吾以剑过朝,公若必曰:‘谁也剑也?’吾称子以告,必观之。吾伪固,而授之末,则可杀也。”使如之,公若曰:“尔欲吴王我乎?”遂杀公若。侯犯以郈叛,武叔懿子围郈,弗克。 +秋,二子及齐师复围郈,弗克。叔孙谓郈工师驷赤曰:“郈非唯叔孙氏之忧,社稷之患也。将若之何?”对曰:“臣之业,在《扬水》卒章之四言矣。”叔孙稽首。驷赤谓侯犯曰:“居齐、鲁之际,而无事,必不可矣。子盍求事于齐以临民?不然,将叛。”侯犯从之。齐使至,驷赤与郈人为之宣言于郈中曰:“侯犯将以郈易于齐,齐人将迁郈民。”众凶惧。驷赤谓侯犯曰:“众言异矣。子不如易于齐,与其死也。犹是郈也,而得纾焉,何必此?齐人欲以此逼鲁,必倍与子地。且盍多舍甲于子之门,以备不虞?”侯犯曰:“诺。”乃多舍甲焉。侯犯请易于齐,齐有司观郈,将至。驷赤使周走呼曰:“齐师至矣!”郈人大骇,介侯犯之门甲,以围侯犯。驷赤将射之。侯犯止之,曰:“谋免我。”侯犯请行,许之。驷赤先如宿,侯犯殿。每出一门,郈人闭之。及郭门,止之,曰:“子以叔孙氏之甲出,有司若诛之,群臣惧死。”驷赤曰:“叔孙氏之甲有物,吾未敢以出。”犯谓驷赤曰:“子止而与之数。”驷赤止,而纳鲁人。侯犯奔齐,齐人乃致郈。 +宋公子地嬖蘧富猎,十一分其室,而以其五与之。公子地有白马四。公嬖向魋,魋欲之,公取而朱其尾鬣以与之。地怒,使其徒扶魋而夺之。魋惧,将走。公闭门而泣之,目尽肿。母弟辰曰:“子分室以与猎也,而独卑魋,亦有颇焉。子为君礼,不过出竟,君必止子。”公子地奔陈,公弗止。辰为之请,弗听。辰曰:“是我迋吾兄也。吾以国人出,君谁与处?”冬,母弟辰暨仲佗、石彄出奔陈。 +武叔聘于齐,齐侯享之,曰:“子叔孙!若使郈在君之他竟,寡人何知焉?属与敝邑际,故敢助君忧之。”对曰:“非寡君之望也。所以事君,封疆社稷是以。敢以家隶勤君之执事?夫不令之臣,天下之所恶也。君岂以为寡君赐?” +译文 +十年春季,鲁国和齐国讲和。 +夏季,鲁定公在祝其会见齐景公,祝其也就是夹谷。孔丘相礼。犁弥对齐景公说:“孔丘懂得礼而缺乏勇,如果派莱地人用武力劫持鲁侯,一定可以如愿以偿。”齐景公听从了。孔丘领着定公退出,说:“士兵拿起武器攻上去!两国的国君会见友好,而边远的东夷俘虏用武力来捣乱,这不是齐君所以对待诸侯的态度,边远不能图谋中原,东夷不能搅乱华人,俘虏不能侵犯盟会,武力不能逼迫友好,这些对于神明来说是大不吉祥的,对于德行来说是丧失道义的,对于人们来说是丢弃礼仪,君王必定不会这样做。”齐景公听了以后,很快就让莱地人避开。 +将要盟誓,齐国人在盟书上加上一句话说:“如果齐军出境,而鲁国不派三百辆甲车跟随我们的话,有盟誓为证!”孔丘让兹无还作揖回答说:“你们不归还我们汶阳的土田,让我们用来供应齐国的需要,也有盟誓为证!” +齐景公准备设享礼招待定公。孔丘对梁丘据说:“齐国、鲁国旧有的典礼,您为什么没有听说过呢?事情已经完成了,而又设享礼,这是麻烦了执事。而且牺尊、象尊不出国门,钟磐不在野外合奏。设享礼而全部具备这些东西,这是不合礼仪的。如果不具备,那就像秕子稗子一样轻微而不郑重。像秕子稗子一样的礼节,这是君王的耻辱。不合礼仪,就名声不好,您何不考虑一下呢!享礼,是用来宣扬德行的。不能宣扬,不如不用。”于是终于没有设享礼。 +齐国人前来归还郓地、讙地、龟阳的土地。 +晋国的赵鞅包围卫国,这是为了报复夷仪那次战役。 +当初,卫侯在寒氏进攻邯郸午,攻破城的西北角而派兵据守。到晚上邯郸午的军队溃散,等到晋国包围卫国,邯郸午带了七十个徒兵进攻卫国西门,在城门里杀了人,说:“用这来报复寒氏那次战役。”涉佗说:“这个人算得是勇敢了,然而我前去,他们一定不敢开门。”也带领士兵七十人,早晨攻打城门,走向城门左右两边,全部站定,像树木一样不动。到中午不开城门,这才退回去。 +回兵以后,晋国人责问卫国背叛的原因,卫国人说:“由于涉佗、成何。”晋国人因此逮捕了涉佗,以此向卫国要求讲和。卫国人不答应,晋国人就杀了涉佗。成何逃亡到燕国。君子说:“这叫做不讲礼仪,两个人的罪过必然轻重不同,《诗》说:‘做人而不讲礼仪,为什么不快点死?’涉佗死得也算很快了。” +当初,叔孙成子想要立武叔做继承人,公若藐坚决劝谏说:“不行。”成子还是立了武叔然后死去。公南派坏人用箭暗射公若,没有成功。公南做马正,就让公若做郈地宰臣。武叔在大局已定之后,派郈地的马正侯犯谋杀公若,没有能办到。侯犯的管马人说:“我拿着剑经过朝廷,公若一定会问这剑是谁的。我告诉他是您的,公若一定要细看这剑,我假装不懂礼节而把剑尖递给他,就可以杀死他了。”侯犯就派他照办。公若说:“你要把我当吴王吗?”管马人就杀死了公若。侯犯带领郈地人叛变,武叔包围郈地,没有攻下。 +秋季,武叔、公南两个人和齐军再次包围郈地,也没有攻下。武叔对郈地的工匠官驷赤说:“郈地不仅是叔孙氏的忧虑,而且是国家的祸患,将要怎么办?”驷赤说:“下臣的事情在《扬之水》这首诗最后一章的四个字上了。”叔孙向他叩头。驷赤就对侯犯说:“处在齐国、鲁国之间而不事奉哪一国,必定是不行的。您何不请求事奉齐国以统治百姓?不这样,他们将会叛变的。”侯犯听从了他的话。齐国的使者来到,驷赤和郈地人在郈地宣布说:“侯犯准备把郈地和齐国交换,齐国人准备迁走郈地的百姓。”大家都很害怕。驷赤对侯犯说:“大家的意见和您不同,您不如把郈地和齐国人交换。所得到的等于这块郈地,而且可以缓和后患,为什么非死抱着这里不放?齐国人想借此逼迫鲁国,必然加倍给您土地。而且何不多准备一些皮甲,放在门里以防意外?”侯犯说:“对。”于是就多准备些皮甲放在门里。侯犯请求在齐国换一块土地,齐国的官员要求视察郈地。将要到达,驷赤派人遍绕全城喊着说:“齐国的军队到了!”郈地人十分害怕,穿上侯犯准备好的皮甲来包围侯犯。驷赤要射这些人,侯犯阻止他,说:“想办法让我免除祸难。”侯犯请求出走,大家答应了。驷赤先去宿地,侯犯走在最后。每出一道门,郈地人就关上这道门。到了外城门,大家拦住侯犯说:“您带着叔孙氏的皮甲出去,官员们如果因此而要治罪,臣下们害怕被杀。”驷赤说:“叔孙氏的皮甲有标记,我没有敢带出去。”侯犯对驷赤说:“您留下来同他们数数。”驷赤留下,而接纳了鲁国人。侯犯逃亡到齐国。齐国人就把郈地送还给鲁国。 +宋国的公子地宠信蘧富猎,把家产分成十一份,给了蘧富猎五份。公子地有四匹白马,宋公宠信向魋,向魋想要这四匹马。宋景公把马牵来,在马尾、马鬣上涂上红颜色给向魋。公子地生气,派手下人打了向魋一顿并且夺回马匹。向魋害怕,准备逃走,宋景公关上门对向魋哭泣,眼睛都哭肿了。宋景公的同母兄弟辰对公子地说:“您把家产分给猎,而惟独看不起魋,这也是不公平的。您平日对国君有礼,至多不过出国,国君必挽留您。”公子地逃亡陈国,宋景公没有挽留他。公子辰为他请求,宋景公不听。公子辰说:“这是我欺骗了我哥哥。我领着国内的人们出国,国君和谁处在一起?”冬季,宋景公同母兄弟辰和仲佗、石彄逃亡到陈国。 +武叔到齐国聘问,齐景公设享礼招待他,说:“子叔孙!如果郈地在君王其他的边境上,寡人知道什么呢?这里刚好和敝邑交界,所以敢帮助您分担忧愁。”武叔回答说:“这不是寡君的愿望。我们所以事奉君王,是为了国家疆土的安全,岂敢为了家臣而劳驾君王的执事?不好的臣下,是天下所共同讨厌的,君王难道用这来作为对寡君的赏赐?” + +定公十一年 +【经】十有一年春,宋公之弟辰及仲佗、石彄、公子地自陈入于萧以叛。夏四月。秋,宋乐大心自曹入于萧。冬,及郑平。叔还如郑莅盟。 +【传】十一年春,宋公母弟辰暨仲佗、石彄、公子地入于萧以叛。秋,乐大心从之,大为宋患,宠向魋故也。 +冬,及郑平,始叛晋也。 +译文 +十一年春季,宋景公的同母兄弟辰和仲佗、石彄、公子地进入萧地而叛变。秋季,乐大心跟着叛变,大大地成为宋国的祸患,这是由于宠信向魋的缘故。 +冬季,鲁国和郑国讲和,鲁国开始背叛晋国。 + + +定公十二年 +【经】十有二年春,薛伯定卒。夏,葬薛襄公。叔孙州仇帅师堕郈。卫公孟彄帅师伐曹。季孙斯、仲孙何忌帅师堕费。秋,大雩。冬十月癸亥,公会齐侯盟于黄。十有一月丙寅朔,日有食之。公至自黄。十有二月,公围成。公至自侯成。 +【传】十二年夏,卫公孟彄伐曹,克郊。还,滑罗殿。未出,不退于列。其御曰:“殿而在列,其为无勇乎?”罗曰:“与其素厉,宁为无勇。” +仲由为季氏宰,将堕三都,于是叔孙氏堕郈。季氏将堕费,公山不狃、叔孙辄帅费人以袭鲁。公与三子入于季氏之宫,登武子之台。费人攻之,弗克。入及公侧。仲尼命申句须、乐颀下,伐之,费人北。国人追之,败诸姑蔑。二子奔齐,遂堕费。将堕成,公敛处父谓孟孙:“堕成,齐人必至于北门。且成,孟氏之保障也,无成,是无孟氏也。子伪不知,我将不堕。” +冬十二月,公围成,弗克。 +译文 +十二年夏季,卫国的公孟彄领兵攻打曹国,攻下郊地。军队回国,滑罗走在最后。没有离开曹国,滑罗并不从队伍里退到最后。他的御者说:“殿后而待在队列里,恐怕是缺乏勇气吧!”滑罗说:“与其空有勇猛之名,宁可让人说我没有勇气。” +仲由做季氏的家臣之长,准备毁掉三都,因此叔孙氏毁掉了郈邑。季氏准备毁掉费邑,公山不狃、叔孙辄率领费邑人袭击鲁国国都。鲁定公和季孙等三个人躲进季氏的宫室,登上武子之台。费邑人进攻,没有攻下。费邑人已经攻到了定公的附近。孔子命令申句须、乐颀下台反击,费邑人战败。国内的人们追上去,在姑蔑打败了他们。公山不狃、叔孙辄逃亡齐国,于是就毁掉了费邑。 +将要毁掉成邑,公敛处父对孟孙说:“毁掉成邑,齐国人必定可以直抵国境北门。而且成邑是孟氏的保障,没有成邑,这就是没有孟氏。您假装不知道,我不准备毁掉。” +冬季,十二月,定公领兵包围成邑,没有攻下。 + +定公十三年 +【经】十有三年春,齐侯、卫侯次于垂葭。夏,筑蛇渊囿。大蒐于比蒲。卫公孟彄帅师伐曹。晋赵鞅入于晋阳以叛。冬,晋荀寅、士吉射入于朝歌以叛。晋赵鞅归于晋。薛弑其君比。 +【传】十三年春,齐侯、卫侯次于垂葭,实狊阜氏。使师伐晋,将济河。诸大夫皆曰:“不可。”邴意兹曰:“可。锐师伐河内,传必数日而后及绛。绛不三月,不能出河,则我既济水矣。”乃伐河内。齐侯皆敛诸大夫之轩,唯邴意兹乘轩。齐侯欲与卫侯乘,与之宴,而驾乘广,载甲焉。使告曰:“晋师至矣!”齐侯曰:“比君之驾也,寡人请摄。”乃介而与之乘,驱之。或告曰:“无晋师。”乃止。 +晋赵鞅谓邯郸午曰:“归我卫贡五百家,吾舍诸晋阳。”午许诺。归,告其父兄,父兄皆曰:“不可。卫是以为邯郸,而置诸晋阳,绝卫之道也。不如侵齐而谋之。”乃如之,而归之于晋阳。赵孟怒,召午,而囚诸晋阳。使其从者说剑而入,涉宾不可。乃使告邯郸人曰:“吾私有讨于午也,二三子唯所欲立。”遂杀午。赵稷、涉宾以邯郸叛。夏六月,上军司马籍秦围邯郸。邯郸午,荀寅之甥也;荀寅,范吉射之姻也,而相与睦。故不与围邯郸,将作乱。董安于闻之,告赵孟,曰:“先备诸?”赵孟曰:“晋国有命,始祸者死,为后可也。”安于曰:“与其害于民,宁我独死,请以我说。”赵孟不可。秋七月,范氏、中行氏伐赵氏之宫,赵鞅奔晋阳。晋人围之。范皋夷无宠于范吉射,而欲为乱于范氏。梁婴父嬖于知文子,文子欲以为卿。韩简子与中行文子相恶,魏襄子亦与范昭子相恶。故五子谋,将逐荀寅而以梁婴父代之,逐范吉射而以范皋夷代之。荀跞言于晋侯曰:“君命大臣,始祸者死,载书在河。今三臣始祸,而独逐鞅,刑已不钧矣。请皆逐之。” +冬十一月,荀跞、韩不信、魏曼多奉公以伐范氏、中行氏,弗克。二子将伐公,齐高强曰:“三折肱知为良医。唯伐君为不可,民弗与也。我以伐君在此矣。三家未睦,可尽克也。克之,君将谁与?若先伐君,是使睦也。”弗听,遂伐公。国人助公,二子败,从而伐之。丁未,荀寅、士吉射奔朝歌。 +韩、魏以赵氏为请。十二月辛未,赵鞅入于绛,盟于公宫。 +初,卫公叔文子朝而请享灵公。退,见史鳅而告之。史鳅曰:“子必祸矣。子富而君贪,其及子乎!”文子曰:“然。吾不先告子,是吾罪也。君既许我矣,其若之何?”史鳅曰:“无害。子臣,可以免。富而能臣,必免于难,上下同之。戍也骄,其亡乎。富而不骄者鲜,吾唯子之见。骄而不亡者,未之有也。戍必与焉。”及文子卒,卫侯始恶于公叔戍,以其富也。公叔戍又将去夫人之党,夫人诉之曰:“戍将为乱。” +译文 +十三年春季,齐景公、卫灵公住在垂葭,垂葭就是郹氏。派军队进攻晋国,将要渡过黄河,大夫们都说不行,邴意兹说:“可以,用精兵攻打河内,传车一定需要几天才能到达绛邑。绛邑兵马不到三个月不能到达黄河,到那时我军已经回兵渡河了。”于是就进攻河内。 +齐景公把大夫们的车子都收起来,只有邴意兹可以坐车。齐景公想和卫灵公同坐一辆车,跟他一起饮宴而命令乘广套车,载上甲兵。派人报告说:“晋军到了!”齐景公说:“等到君王的车子套好,寡人就代您的御者驾车。”于是就披甲和卫灵公一起登年,驱车向前。有人报告说:“没有晋军。”这才把车停下。 +晋国的赵鞅对邯郸午说:“把卫国进贡的五百家还给我,我要把他们安置到晋阳去。”邯郸午答应了。回去告诉他的父老兄长。父老兄长都说:“不行。卫国是用这五百家来帮助邯郸午的,要安置在晋阳,这就是断绝和卫国的友好之路。不如用侵袭齐国的办法来解决。”于是就照着父兄的说法办,然后把五百家迁到晋阳。赵鞅发怒,把邯郸午找来,囚禁在晋阳。赵鞅让邯郸午的随从解除佩剑再进来,涉宾不同意。赵鞅就派人告诉邯郸人说:“我私人对午进行惩罚,您几位可以按自己的愿望立继承人。”就杀了邯郸午。赵稷、涉宾领着邯郸人叛变。夏季,六月,上军司马籍秦包围邯郸。邯郸午,是荀寅的外甥;荀寅,是范吉射女婿的父亲,彼此和睦,所以不参与包围邯郸,准备发动叛乱。董安于听到了消息,报告赵鞅说:“先作好准备吗?”赵鞅说:“晋国有一条法令,开始发动祸乱的人处死。我们后发制人就行了。”董安于说:“与其危害百姓,宁可我一个人去死。请用我作为解释。”赵鞅不答应。秋季七月,范氏、中行氏进攻赵氏的宫室,赵鞅逃亡到晋阳,晋国人包围晋阳。 +范皋夷不受范吉射的宠信,想要在范氏族中发动叛乱。梁婴父受到知文子的宠信,知文子想让他做卿。韩简子和荀寅互相不和,魏襄子也和范吉射互相不和,所以五个人策划,准备驱逐荀寅而用梁婴父代替他,驱逐范吉射而用范皋夷代替他。荀跞对晋定公说:“君王命令大臣,开始发动祸乱的人处死,盟书沉在黄河里。现在三个大臣开始发动祸乱,而唯独驱逐赵鞅,处罚已经不公正了。请把他们都驱逐。” +冬季,十一月,荀跞、韩不信、魏曼多事奉晋定公而攻打范氏、中行氏,没有攻下。这两个人准备进攻晋定公。齐国的高强说:“久病成良医。唯有攻打国君是不行的。百姓是不赞成的。我正是因为攻打国君才待在这里了啊。三家不和睦,可以全部战胜他们。战胜他们,国君还去倚靠谁?如果先攻打国君,这是促使他们和睦。”两个人不听,于是就攻打晋定公。国内的人们帮助晋定公,两个人战败,三家跟着就去攻打他们。 +十八日,荀寅、范吉射逃亡朝歌,韩氏、魏氏替赵氏请求。十二月十二日,赵鞅进入绛邑,在公宫盟誓。 +当初,卫国的公孙文子上朝请求设享礼招待卫灵公。退朝,见到史?告诉了他。史?说:“您必然招来祸患了!您富有而国君贪婪,祸患恐怕要到您身上吧!”文子说:“是这样。我没有先告诉您,这是我的罪过。国君已经答应我了,怎么办?”史?说:“没有关系。您谨守臣道,可以免祸。富有而能谨守臣道,一定能免于祸难。无论尊卑都适用这一原则的。戌骄傲,恐怕要逃亡吧!富有而不骄傲的人很少,我只见到您一个。骄傲而不逃亡的人,我还没有见过。戌必定要成为其中一个的。”等到公叔文子死了,卫灵公才开始讨厌公叔戌,因为他富有。公叔戌又准备去掉夫人的党羽,夫人向卫灵公控告说:“戌将要发动叛乱。” + + +定公十四年 +【经】十有四年春,卫公叔戍来奔。卫赵阳出奔宋。二月辛巳,楚公子结、陈公孙佗人帅师灭顿,以顿子牂归。夏,卫北宫结来奔。五月,于越败吴于檇李。吴子光卒。公会齐侯、卫侯于牵。公至自会。秋,齐侯、宋公会于洮。天王使石尚来归脤。卫世子蒯瞶出奔宋。卫公孟彄出奔郑。宋公之弟辰自萧来奔。大蒐于比蒲。邾子来会公。城莒父及霄。 +【传】十四年春,卫侯逐公叔戍与其党,故赵阳奔宋,戍来奔。 +梁婴父恶董安于,谓知文子曰:“不杀安于,使终为政于赵氏,赵氏必得晋国。盍以其先发难也,讨于赵氏?”文子使告于赵孟曰:“范、中行氏虽信为乱,安于则发之,是安于与谋乱也。晋国有命,始祸者死。二子既伏其罪矣,敢以告。”赵孟患之。安于曰:“我死而晋国宁,赵氏定,将焉用生?人谁不死,吾死莫矣。”乃缢而死。赵孟尸诸市,而告于知氏曰:“主命戮罪人,安于既伏其罪矣,敢以告。”知伯从赵孟盟,而后赵氏定,祀安于于庙。 +顿子牂欲事晋,背楚而绝陈好。二月,楚灭顿。 +夏,卫北宫结来奔,公叔戍之故也。 +吴伐越。越子句践御之,陈于檇李。句践患吴之整也,使死士再禽焉,不动。使罪人三行,属剑于颈,而辞曰:“二君有治,臣奸旗鼓,不敏于君之行前,不敢逃刑,敢归死。”遂自刭也。师属之目,越子因而伐之,大败之。灵姑浮以戈击阖庐,阖庐伤将指,取其一屦。还,卒于陉,去檇李七里。夫差使人立于庭,苟出入,必谓己曰:“夫差!而忘越王之杀而父乎?”则对曰:“唯,不敢忘!”三年,乃报越。 +晋人围朝歌,公会齐侯、卫侯于脾、上梁之间,谋救范、中行氏。析成鲋、小王桃甲率狄师以袭晋,战于绛中,不克而还。士鲋奔周,小王桃甲入于朝歌。秋,齐侯、宋公会于洮,范氏故也。 +卫侯为夫人南子召宋朝,会于洮。大子蒯聩献盂于齐,过宋野。野人歌之曰:“既定尔娄猪,盍归吾艾豭。”大子羞之,谓戏阳速曰:“从我而朝少君,少君见我,我顾,乃杀之。”速曰:“诺。”乃朝夫人。夫人见大子,大子三顾,速不进。夫人见其色,啼而走,曰:“蒯聩将杀余。”公执其手以登台。大子奔宋,尽逐其党。故公孟彄出奔郑,自郑奔齐。 +大子告人曰:“戏阳速祸余。”戏阳速告人曰:“大子则祸余。大子无道,使余杀其母。余不许,将戕于余;若杀夫人,将以余说。余是故许而弗为,以纾余死。谚曰:‘民保于信。’吾以信义也。” +冬十二月,晋人败范、中行氏之师于潞,获籍秦、高强。又败郑师及范氏之师于百泉。 +译文 +十四年春季,卫灵公驱逐公叔戌和他的党羽,所以赵阳逃亡宋国,戌逃亡来到鲁国。 +梁婴父讨厌董安于,对知文子说:“不杀死安于,让他始终在赵氏那里主持一切,赵氏一定能得到晋国,何不因为他先发动祸难而去责备赵氏?”知文子派人告诉赵鞅说:“范氏、中行氏虽然确实发动了叛乱,但这是安于挑起的,是安于共同作乱。晋国有命令,开始发动祸乱的人处死。范氏、中行氏已经伏罪了,谨此奉告。”赵孟担心这件事。董安于说:“我死了而晋国安宁,赵氏安定,哪里用得着活下去?人谁不死?我死得晚了。”于是就上吊死了。赵鞅把他暴尸在市上而告诉知氏说:“您命令杀罪人安于,他已经伏罪了。谨此奉告。”知伯和赵鞅结盟,然后赵氏得以安定。赵氏把安于陪祀在宗庙里。 +顿子牂想要事奉晋国,背叛楚国而断绝和陈国的友好关系。二月,楚国灭亡了顿国。 +夏季,卫国的北宫结逃亡到鲁国来,这是由于公叔戌的缘故。 +吴国进攻越国,越王勾践发兵抵御吴军,在檇李摆开阵势。勾践担心吴军军阵严整,派敢死队再冲锋擒捉吴军,吴军阵势不动。勾践派罪犯排成三行,把剑架在脖子上而致辞说:“两国国君出兵交战,下臣触犯军令,在君王的队列之前显示出无能,不敢逃避刑罚,谨自首而死。”于是都自刎而死。吴军都注意地看着,越王乘机下令进攻,大败吴军。灵姑浮用戈击刺吴王阖庐,阖庐的脚趾受伤,灵姑浮得到吴王的一只鞋。阖庐退兵,死在陉地,距离檇李七里地。夫差派人站在院子里,只要自己出去进来,都一定要对自己说:“夫差!你忘记越王杀了你父亲吗?”夫差自己就回答说:“是。不敢忘记!”到第三年就向越国报了仇。 +晋国人包围朝歌,鲁定公在脾地和上梁之间会见齐景公、卫灵公,谋划救援范氏、中行氏。析成鲋、小王桃甲率领狄军袭击晋国,在绛地作战,没有攻下而回来。析成鲋逃亡到成周,小王桃甲进入朝歌。秋季,齐景公、宋景公在洮地会见,这是为了营救范氏的缘故。 +卫灵公为了夫人南子召见宋朝。在洮地会见。太子蒯聩把盂地献给齐国,路过宋国野外。野外的人唱歌说:“已经满足了你们的母猪,何不归还我们那漂亮的公猪?”太子感到羞耻,对戏阳速说:“跟着我去朝见夫人,夫人接见我,我一回头看你,你就杀死她。”戏阳速说:“是。”于是就去朝见夫人。夫人接见太子,太子回头看了三次,戏阳速不肯向前。夫人看到了太子的脸色,号哭着逃走,说:“蒯聩将要杀死我。”卫灵公拉着她的手登上高台。太子逃亡到宋国,卫灵公把太子的党羽都赶走,所以公孟彄逃亡到郑国,从郑国逃亡到齐国。 +太子告诉别人说:“戏阳速嫁祸于我。”戏阳速告诉别人说:“太子才是嫁祸于我哩,太子无道,派我杀死他的母亲。我不答应。他就会杀死我。如果我杀死了夫人,他就会把罪过推到我身上以解脱自己。我所以答应而不去做,以此暂免一死。俗话说:‘百姓用信用保全自己。’我是用道义来作为信用的。” +冬季,十二月,晋国人在潞地打败范氏、中行氏的军队,俘虏了籍秦、高强。又在百泉打败了郑国和范氏的军队。 + +定公十五年 +【经】十有五年春王正月,邾子来朝。鼷鼠食郊牛,牛死,改卜牛。二月辛丑,楚子灭胡,以胡子豹归。夏五辛亥,郊。壬申,公薨于高寝。郑罕达帅师伐宋。齐侯、卫侯次于渠蒢。邾子来奔丧。秋七月壬申,姒氏卒。八月庚辰朔,日有食之。九月,滕子来会葬。丁巳,葬我君定公,雨,不克葬。戊午,日下昊,乃克葬。辛巳,葬定姒。冬,城漆。 +【传】十五年春,邾隐公来朝。子贡观焉。邾子执玉高,其容仰。公受玉卑,其容俯。子贡曰:“以礼观之,二君者,皆有死亡焉。夫礼,死生存亡之体也。将左右周旋,进退俯仰,于是乎取之;朝祀丧戎,于是乎观之。今正月相朝,而皆不度,心已亡矣。嘉事不体,何以能久?高仰,骄也,卑俯,替也。骄近乱,替近疾。君为主,其先亡乎!” +吴之入楚也,胡子尽俘楚邑之近胡者。楚既定,胡子豹又不事楚,曰:“存亡有命,事楚何为?多取费焉。”二月,楚灭胡。 +夏五月壬申,公薨。仲尼曰:“赐不幸言而中,是使赐多言者也。” +郑罕达败宋师于老丘。 +齐侯、卫侯次于蘧挐,谋救宋也。 +秋七月壬申,姒氏卒。不称夫人,不赴,且不祔也。 +葬定公。雨,不克襄事,礼也。 +葬定姒。不称小君,不成丧也。 +冬,城漆。书,不时告也。 +译文 +十五年春季,邾隐公前来鲁国朝见。子贡观礼。邾子把玉高高地举起,他的脸仰着。鲁定公谦卑地接受了玉,他的脸向下。子贡说:“用礼来看待这件事,两位国君都快要死亡了。礼,是死生存亡的主体,一举一动或左或右,以及揖让、进退、俯仰,就从这里来选取它。朝会、祭礼、丧事、征战,也从这里来观察它。现在在正月互相朝见,而都不合法度,两位国君的心里已经不存在礼了。朝会不符合礼仪,哪里能够长久?高和仰,这是骄傲。低和俯,这是衰颓。骄傲接近动乱,衰颓接近疾病。君王是国家的主人,恐怕会先死去吧!” +吴国进攻楚国的时候,胡子把楚国城邑靠近胡国的百姓全部俘虏。楚国安定以后,胡子豹又不事奉楚国,说:“国家的存亡由于天命,事奉楚国干什么?只不过多花费一点而已。”二月,楚国灭亡胡国。 +夏季,五月二十二日,鲁定公死。孔丘说:“赐不幸而说中了,这件事使他成为多嘴的人了。” +郑国的罕达在老丘打败宋军。 +齐景公、卫灵公住在蘧挐。这是为了谋划救援宋国。 +秋季,七月二十三日,鲁定公夫人姒氏死了。《春秋》不称她为夫人,这是因为没有发讣告,而且也没有陪祀祖姑之庙。 +安葬鲁定公。下雨,没有能办完事情,这是符合礼的。 +安葬定姒。《春秋》不称她为小君,这是因为没有按夫人的葬礼来安葬。 +冬季,在漆地筑城,《春秋》所以记载这件事,是由于没有按时祭告祖庙。 + +哀公 + +哀公元年 +【经】元年春王正月,公即位。楚子、陈侯、随侯、许男围蔡。鼷鼠食郊牛,改卜牛。夏四月辛巳,郊。秋,齐侯,卫侯伐晋。冬,仲孙何忌帅师伐邾。 +【传】元年春,楚子围蔡,报柏举也。里而栽,广丈,高倍。夫屯昼夜九日,如子西之素。蔡人男女以辨,使疆于江、汝之间而还。蔡于是乎请迁于吴。 +吴王夫差败越于夫椒,报檇李也。遂入越。越子以甲楯五千,保于会稽。使大夫种因吴大宰嚭以行成,吴子将许之。伍员曰:“不可。臣闻之树德莫如滋,去疾莫如尽。昔有过浇杀斟灌以伐斟鄩,灭夏后相。后婚方娠,逃出自窦,归于有仍,生少康焉,为仍牧正。惎浇,能戒之。浇使椒求之,逃奔有虞,为之庖正,以除其害。虞思于是妻之以二姚,而邑诸纶。有田一成,有众一旅,能布其德,而兆其谋,以收夏众,抚其官职。使女艾谍浇,使季杼诱豷,遂灭过、戈,复禹之绩。祀夏配天,不失旧物。今吴不如过,而越大于少康,或将丰之,不亦难乎?句践能亲而务施,施不失人,亲不弃劳。与我同壤而世为仇雠,于是乎克而弗取,将又存之,违天而长寇仇,后虽悔之,不可食已。姬之衰也,日可俟也。介在蛮夷,而长寇仇,以是求伯,必不行矣。”弗听。退而告人曰:“越十年生聚,而十年教训,二十年之外,吴其为沼乎!”三月,越及吴平。吴入越,不书,吴不告庆,越不告败也。 +夏四月,齐侯、卫侯救邯郸,围五鹿。 +吴之入楚也,使召陈怀公。怀公朝国人而问焉,曰:“欲与楚者右,欲与吴者左。陈人从田,无田从党。”逢滑当公而进,曰:“臣闻国之兴也以福,其亡也以祸。今吴未有福,楚未有祸。楚未可弃,吴未可从。而晋,盟主也,若以晋辞吴,若何?”公曰:“国胜君亡,非祸而何?”对曰:“国之有是多矣,何必不复。小国犹复,况大国乎?臣闻国之兴也,视民如伤,是其福也。其亡也,以民为土芥,是其祸也。楚虽无德,亦不艾杀其民。吴日敝于兵,暴骨如莽,而未见德焉。天其或者正训楚也!祸之适吴,其何日之有?”陈侯从之。及夫差克越,乃修先君之怨。秋八月,吴侵陈,修旧怨也。 +齐侯、卫侯会于乾侯,救范氏也,师及齐师、卫孔圉、鲜虞人伐晋,取棘蒲。 +吴师在陈,楚大夫皆惧,曰:“阖庐惟能用其民,以败我于柏举。今闻其嗣又甚焉,将若之何?”子西曰:“二三子恤不相睦,无患吴矣。昔阖庐食不二味,居不重席,室不崇坛,器不彤镂,宫室不观,舟车不饰,衣服财用,择不取费。在国,天有灾疠,亲巡孤寡,而共其乏困。在军,熟食者分,而后敢食。其所尝者,卒乘与焉。勤恤其民而与之劳逸,是以民不罢劳,死知不旷。吾先大夫子常易之,所以败我也。今闻夫差次有台榭陂池焉,宿有妃嫱嫔御焉。一日之行,所欲必成,玩好必从。珍异是聚,观乐是务,视民如仇,而用之日新。夫先自败也已。安能败我?” +冬十一月,晋赵鞅伐朝歌。 +译文 +元年春季,楚昭王发兵包围蔡国国都,这是为了报复柏举那次战役。离城一里建筑堡垒,宽一丈,高二丈。役夫屯驻九昼夜,和子西的预定计划一样。蔡国人把男女奴隶分别排列捆绑作为礼物出降。楚昭王让蔡国迁移到长江、汝水之间就回去了。蔡国因此向吴国请求迁移到吴国去。 +吴王夫差在夫椒打败越军,报复在檇李被越国打败的仇恨。接着,吴军就乘势攻打越国。越王带着披甲持盾的士兵五千人踞守在会稽山,派大夫种通过吴国太宰嚭而向吴国求和。吴王打算答应越国的请求。伍员说:“不行。下臣听说:‘建树德行最好不断增加,除去邪恶最好彻底干净。’从前有过国的国君浇杀了斟灌而攻打斟?,灭亡了夏后相,后缗正怀着孕,从城墙的小洞里逃出去,回到娘家有仍国,生了少康。少康后来在有仍做了管理畜牧的官,对浇满怀仇恨而能警惕戒备。浇派椒寻找少康,少康逃奔到有虞国,做了那里掌管庖厨的长官,才逃避了浇的杀害,虞思因此把两个女儿嫁给了他,封他在纶邑,拥有方圆十里的土田,有五百人的兵力,能广施恩德,并开始实施复国计划。他收集夏朝的余部,安抚他的官员,派遣女艾到浇那里去做间谍,派季杼去引诱浇的弟弟豷。这样就灭亡了过国、戈国,复兴了禹的事业。少康奉祀夏朝的祖先同时祭祀天帝,维护了原有的天下。现在吴国不如过国,而越国大于少康,上天也许将会使越国壮大,如果允许讲和,不也很难了吗?勾践能够亲近别人而注意施行恩惠,施舍皆各得其人。对有功劳的人从不抛弃而加以亲近。越国和我国土地相连,而又世世代代是仇敌。在这种情况下如果我们战胜越国而不灭亡它,又准备保存下去,这是违背了无意而又助长了仇敌,以后即使懊悔,也来不及消除祸患了。姬姓的衰微,为时不远了。我国介于蛮夷之间,而还去助长仇敌的发展,用这样的办法来求取霸业,必定是办不到的。”吴王夫差不听。伍员退下去告诉别人说:“越国用十年时间繁衍积聚,用十年时间教育训练,二十年以后,吴国的宫殿恐怕要成为池沼了。”三月,越国和吴国讲和。 +吴国进入越国,《春秋》不加记载,这是由于吴国没有报告胜利,越国没有报告失败。 +夏季,四月,齐景公、卫灵公救援邯郸,包围五鹿。 +吴国进入楚国的时候,派人召见陈怀公。怀公向国内的人们征求意见,说:“想要亲附楚国的站到右边。想要亲附吴国的站到左边。陈国人有土田的,根据土田的所在而分立左右,没有土田的和亲族站在一起。”逢滑正对着怀公走上前去,说:“下臣听说,国家的兴起由于福德,它的灭亡由于祸殃,现在吴国还没有福德,楚国还没有祸殃,楚国还不能抛弃,吴国还不能跟从。晋国是盟主,如果用晋国作为借口而辞谢吴国,怎么样?”怀公说:“国家被吴国战胜,国君逃亡,这不是祸殃是什么?”逢滑回答说:“国家有这种情况的太多了,为什么一定不能恢复?小国尚且能恢复,何况大国呢?下臣听说,国家的兴起,看待百姓如同受伤者而不加惊动,这就是它的福德。国家的灭亡,把百姓作为粪土草芥,这就是它的祸殃。楚国虽然没有德行,也没有斩杀它的百姓。吴国每天在战争中凋敝,暴露尸骨多得像杂草一样,而又没有见到什么德行。上天恐怕正是在给楚国一次教训吧!吴国遭致祸殃,不会太久了。”陈怀公听从了。等到夫差攻下越国,吴国就重新清算先君时代结下的怨恨。秋季,八月,吴国侵袭陈国,这就是为了重新清算过去的怨恨。 +齐景公、卫灵公在乾侯会见,这是为了救援范氏。鲁军和齐军、卫国的孔圉、鲜虞人进攻晋国,占取了棘蒲。 +吴军驻在陈国,楚国的大夫们都恐惧,说:“吴王阖庐善于使用他的百姓作战,在柏举把我们打败了。现在听说他的继承人比他还要厉害,我们将对他怎么办?”子西说:“您几位只应当忧虑自己不相和睦,不用害怕吴国的侵袭。从前阖庐吃饭不吃两道菜,坐着不用两层席子,房子不造在高坛上,器用不加红漆和雕刻,宫室之中不造亭台楼阁,车船不加装饰,衣服和用具,取其实用而不尚虚华。在国内,上天降下天灾瘟疫,就亲自巡视,安抚孤寡和资助贫困的人。在军队中,煮熟的食物必须等士兵都得到了,自己才食用,他吃的山珍海味,士兵们都有一份。吴王阖庐经常抚恤百姓而和他们同甘共苦,因此百姓不疲劳,死了也知道不是白白死去。我们的先大夫子常的作法正相反,所以吴国就打败了我国。现在听说夫差住宿有楼台池沼,睡觉有嫔妃宫女,即使是一天在外头,想要的东西一定要到手,玩赏爱好的东西,一定要随身带走;积聚珍奇,享乐为务;把百姓看得如同仇人,没完没了驱使他们。这样做只不过是先自取失败而已,哪里能打败我国呢?” +冬季,十一月,晋国的赵鞅进攻朝歌。 + + +哀公二年 +【经】二年春王二月,季孙斯、叔孙州仇、仲孙何忌帅师伐邾,取漷东田及沂西田。癸巳,叔孙州仇、仲孙何忌及邾子盟于句绎。夏四月丙子,卫侯元卒。滕子来朝。晋赵鞅帅师纳卫世子蒯聩于戚。秋八月甲戌,晋赵鞅帅师及郑罕达帅师战于铁,郑师败绩。冬十月,葬卫灵公。十有一月,蔡迁于州来。蔡杀其大夫公子驷。 +【传】二年春,伐邾,将伐绞。邾人爱其土,故赂以淳阜、沂之田而受盟。 +初,卫侯游于郊,子南仆。公曰:“余无子,将立女。”不对。他日,又谓之。对曰:“郢不足以辱社稷,君其改图。君夫人在堂,三揖在下。君命只辱。” +夏,卫灵公卒。夫人曰:“命公子郢为大子,君命也。”对曰:“郢异于他子。且君没于吾手,若有之,郢必闻之。且亡人之子辄在。”乃立辄。 +六月乙酉,晋赵鞅纳卫大子于戚。宵迷,阳虎曰:“右河而南,必至焉。”使大子絻,八人衰絰,伪自卫逆者。告于门,哭而入,遂居之。 +秋八月,齐人输范氏粟,郑子姚、子般送之。士吉射逆之,赵鞅御之,遇于戚。阳虎曰:“吾车少,以兵车之旆,与罕、驷兵车先陈。罕、驷自后随而从之,彼见吾貌,必有惧心。于是乎会之,必大败之。”从之。卜战,龟焦。乐丁曰:“《诗》曰:‘爰始爰谋,爰契我龟。’谋协,以故兆询可也。”简子誓曰:“范氏、中行氏,反易天明,斩艾百姓,欲擅晋国而灭其君。寡君恃郑而保焉。今郑为不道,弃君助臣,二三子顺天明,从君命,经德义,除诟耻,在此行也。克敌者,上大夫受县,下大夫受郡,士田十万,庶人工商遂,人臣隶圉免。志父无罪,君实图之。若其有罪,绞缢以戮,桐棺三寸,不设属辟,素车朴马,无入于兆,下卿之罚也。”甲戌,将战,邮无恤御简子,卫太子为右。登铁上,望见郑师众,大子惧,自投于车下。子良授大子绥而乘之,曰:“妇人也。”简子巡列,曰:“毕万,匹夫也。七战皆获,有马百乘,死于牖下。群子勉之,死不在寇。”繁羽御赵罗,宋勇为右。罗无勇,麇之。吏诘之,御对曰:“痁作而伏。”卫大子祷曰:“会孙蒯聩敢昭告皇祖文王、烈祖康叔、文祖襄公:郑胜乱从,晋午在难,不能治乱,使鞅讨之。蒯聩不敢自佚,备持矛焉。敢告无绝筋,无折骨,无面伤,以集大事,无作三祖羞。大命不敢请,佩玉不敢爱。” +郑人击简子中肩,毙于车中,获其峰旗。大子救之以戈,郑师北,获温大夫赵罗。大子复伐之,郑师大败,获齐粟千车。赵孟喜曰:“可矣。”傅叟曰:“虽克郑,犹有知在,忧未艾也。” +初,周人与范氏田,公孙尨税焉。赵氏得而献之,吏请杀之。赵孟曰:“为其主也,何罪?”止而与之田。及铁之战,以徒五百人宵攻郑师,取峰旗于子姚之幕下,献曰:“请报主德。” +追郑师。姚、般、公孙林殿而射,前列多死。赵孟曰:“国无小。”既战,简子曰:“吾伏弢呕血,鼓音不衰,今日我上也。”大子曰:“吾救主于车,退敌于下,我,右之上也。”邮良曰:“我两靷将绝,吾能止之,我,御之上也。”驾而乘材,两靷皆绝。 +吴泄庸如蔡纳聘,而稍纳师。师毕入,众知之。蔡侯告大夫,杀公子驷以说,哭而迁墓。冬,蔡迁于州来。 +译文 +二年春季,鲁军攻打邾国,准备先进攻绞地。邾国人爱惜绞地的土地,所以用漷、沂两地的土田作为贿赂,接受盟约。 +当初,卫灵公在郊外游玩,公子子南为他驾车。卫灵公说:“我没有嫡子,打算立你做继承人。”子南不回答。过了些时候,卫灵公又对子南那么说,子南回答说:“郢不足以有国家,您还是改变一下主意。君夫人在堂上,卿、大夫、士在下边。您没有和他们商量,我听从了只能是有辱您的命令。” +夏季,卫灵公死了。夫人说:“命令公子郢做太子,这是国君的命令。”公子郢回答说:“郢和别的儿子不一样,而且我伺候国君到死,如果有这话,郢一定会听到。并且还有逃亡者的儿子辄在那里。”于是就立了辄。 +六月十七日,晋国的赵鞅把卫国的太子送回戚地。夜里迷了路,阳虎说:“右边到黄河再渡河往南,一定就到了。”让太子脱帽,八个人穿着丧服,假装是从卫国前来迎接的样子。他们通报守门人,号哭入城,于是就住在那里。 +秋季,八月,齐国人运送粮食给范氏,郑国的子姚、子般押送。士吉射迎接他们,赵鞅抵御他们,在戚地相遇。阳虎说:“我们的车子少,把大将的旗子插在车上,先与子姚、子般的战车对阵,子姚、子般从后面跟上来,他们看到我军的阵容,必定有恐惧之心。在那时候会合战斗,一定可以把他们打得大败。”赵鞅听从了。占卜战争的吉凶,龟甲烤焦了。乐丁说:“《诗》说:‘先行谋划,于是占卜。’谋划一致,相信过去的卜兆就行了。”赵鞅起誓说:“范氏、中行氏违背天命,斩杀百姓,想要在晋国专权而灭亡国君,我们国君依仗着郑国保护自己,现在郑国无道,抛弃国君帮助臣下,我们几个人顺从天命,服从君令,推行德义,消除耻辱就在这次行动了。战胜敌人的,上大夫可得到县,下大夫可得到郡,士可得到十万亩土田,庶人工商可做官,奴隶可获得自由。志父如果没有罪过,就请国君加以考虑。如果战败有罪,就用绞刑把我诛戮,死后用三寸厚的桐木棺,不要再有衬版和外椁,用没有装饰的马装运棺材,不要葬入本族的墓地中,这是按照下卿的地位所作的处罚。” +八月初七日,将要作战,邮无恤为赵鞅驾御战车,卫国的太子做车右。登上铁丘,远望郑军人数众多,卫太子害怕,自己跳到车下。邮无恤把车上的拉手带子递给太子而让他上车,说:“你像个女人。”赵鞅巡视队伍,说:“毕万是个普通人,七次战斗都俘获了敌人,后来有了四百匹马,在家里善终。诸位努力吧!未必就死在敌人手里。”繁羽为赵罗驾御战车,宋勇做车右。赵罗胆小,别人用绳子把他捆在车上。军吏询问原因,车御回答说:“疟疾发作躺下了。”卫国的太子祷告说:“远孙蒯聩谨敢报告皇祖文王,烈祖康叔,文祖襄公:郑胜搅乱常道,晋午处在危难之中,不能平定祸乱,派赵鞅前来讨伐。蒯聩不敢放纵安逸,居于持矛作战的行列里,谨敢祈祷保佑不要断筋,不要折骨,脸上不要受伤,以成就大事,不给三位祖先带来羞辱。死生的命运不敢请求,佩玉不敢爱惜。” +郑国人击中赵鞅的肩膀,赵鞅倒在车里,郑国人缴获了他的蜂旗。太子用戈救援赵鞅,郑军败逃。俘虏了温大夫赵罗。太子再次进攻,郑军大败,获得了齐国的一千车粮食。赵鞅高兴地说:“行了。”傅傁说:“虽然打败了郑国,还有知氏在那里,忧患还不能消除呢” +当初,周朝人给范氏土田,公孙尨为范氏收税,赵氏抓住了他献给赵鞅。军吏请求把他杀了。赵鞅说:“他是为了主人,有什么罪?”阻止了军吏并且给了公孙尨土田。等到铁丘这一战,公孙尨带领部下五百人夜里进攻郑军,在子姚的帐幕下取得了蜂旗,献上,说:“请允许我以此报答主人的恩德。” +追逐郑军,子姚、子般、公孙林殿后掩护退军并射击追军,前锋部队大多战死,赵鞅说:“对小国也不能轻视。”战斗结束,赵鞅说:“我伏在弓袋上吐了血,但鼓声不衰,今天我的功劳最大。”太子说:“我在车上救了您,在下边追击敌人,我是车右中功劳最大的。”邮无恤说:“我骖马的两根带子快要断了,我还能控制它,我是车御中功劳最大的。”他又驾车装上点木材,两根带子就全断了。 +吴国的泄庸到蔡国去致送聘礼,逐渐把军队混进蔡国。等到吴军全部进入,大家才知道这回事。蔡侯告诉大夫,杀了公子驷来取悦吴国,号哭着把先君的坟墓迁走。冬季,蔡国迁到州来。 + +哀公三年 +【经】三年春,齐国夏、卫石曼姑帅师围戚。夏四月甲午,地震。五月辛卯,桓宫、僖宫灾。季孙斯、叔孙州仇帅师城启阳。宋乐髡帅师伐曹。秋七月丙子,季孙斯卒。蔡人放其大夫公孙猎于吴。冬十月癸卯,秦伯卒。叔孙州仇、仲孙何忌帅师围邾。 +【传】三年春,齐、卫围戚,救援于中山。 +夏五月辛卯,司铎火。火逾公宫,桓、僖灾。救火者皆曰:“顾府。”南宫敬叔至,命周人出御书,俟于宫,曰:“庀女而不在,死。”子服景伯至,命宰人出礼书,以待命:“命不共,有常刑。”校人乘马,巾车脂辖。百官官备,府库慎守,官人肃给。济濡帷幕,郁攸从之,蒙葺公屋。自大庙始,外内以悛,助所不给。有不用命,则有常刑,无赦。公父文伯至,命校人驾乘车。季桓子至,御公立于象魏之外,命救火者伤人则止,财可为也。命藏《象魏》,曰:“旧章不可亡也。”富父槐至,曰:“无备而官办者,犹拾也。”于是乎去表之蒿,道还公宫。孔子在陈,闻火,曰:“其桓、僖乎!” +刘氏、范氏世为婚姻,苌弘事刘文公,故周与范氏。赵鞅以为讨。六月癸卯,周人杀苌弘。 +秋,季孙有疾,命正常曰:“无死。南孺子之子,男也,则以告而立之。女也,则肥也可。”季孙卒,康子即位。既葬,康子在朝。南氏生男,正常载以如朝,告曰:“夫子有遗言,命其圉臣曰:‘南氏生男,则以告于君与大夫而立之。’今生矣,男也,敢告。”遂奔卫。康子请退。公使共刘视之,则或杀之矣,乃讨之。召正常,正常不反。 +冬十月,晋赵鞅围朝歌,师于其南。荀寅伐其郛,使其徒自北门入,己犯师而出。癸丑,奔邯郸。十一月,赵鞅杀士皋夷,恶范氏也。 +译文 +三年春季,齐国、卫国包围戚地,戚地人向中山请求救援。 +夏季,五月二十八日,鲁国司铎官署发生火灾。火势越过公宫,桓公庙、僖公庙都被烧毁。救火的人都说:“照顾府库财物。”南宫敬叔来到,命令周人拿出国君所看的书,让他在宫里等着,说:“交给你了,如有损失,就处死你。”子服景伯来到,命令宰人拿出礼书,让他等候命令。如果不能尽职,就要按规定处罚。校人驾上马,巾车在车轴上涂上油脂,百官坚守自己的岗位,府库加强戒备,官人认真执行供应,用透湿的帷幕覆盖火场附近的建筑物,救火的器材就放在旁边。然后又用浸湿的东西把公屋覆盖起来,从太庙开始,由外到内依次覆盖。帮助力量不足的。有不听从命令的,就按规定处罚,不加赦免。公父文伯来到,命令校人为公车套上马。季桓子来到,为哀公驾车站在象魏外边,命令救火的人受伤就停下来,因为财物是可以生产出来的。又命令把文献收藏起来,说:“旧的章典不能丢失。”富父槐来到,说:“没有准备而叫百官仓促办事,就好像拾起地上的汤水。”因此就拆去火道上的干枯易燃物品,围绕公宫四周开辟火巷隔火。 +孔子正在陈国,听到发生火灾,说:“恐怕是桓公庙、僖公庙吧!” +刘氏、范氏世世代代互通婚姻,苌弘事奉刘文公,所以周朝亲近范氏。赵鞅因此而讨伐。六月十一日,周人杀死了苌弘。 +秋季,季孙有病,命令正常说:“不要跟随我死!如果南孺子生下的孩子是男孩,就把我的话报告国君、大夫而立这个孩子为继承人;如果是个女孩,那么立肥就可以了。”季孙死,康子即位。安葬刚刚完毕,康子正在朝廷上。南氏生了个男孩,正常用车把男孩载着送到朝廷上,报告说:“他老人家有遗言,命令他的贱臣说:‘南氏生了男孩,就报告国君和大夫而立他为继承人。’现在继承人生下来了,是个男孩,谨此报告。”于是就逃亡到卫国去。康子请求退位,哀公派共刘去巡察,有人却已经把婴儿杀死了。于是就讨伐杀人凶手。召见正常,正常不回来。 +冬季,十月,晋国的赵鞅包围朝歌,军队驻扎在朝歌南边。荀寅攻打朝歌外城,让他的部下从北门进来,自己突围出来。二十三日,荀寅逃亡到邯郸。 +十一月,赵鞅杀死了士皋夷,这是由于讨厌范氏。 + +哀公四年 +【经】四年春王二月庚戌,盗杀蔡侯申。蔡公孙辰出奔吴。葬秦惠公。宋人执小邾子。夏,蔡杀其大夫公孙姓、公孙霍。晋人执戎蛮子赤归于楚。城西郛。六月辛丑,亳社灾。秋八月甲寅,滕子结卒。冬十有二月,葬蔡昭公。葬滕顷公。 +【传】四年春,蔡昭侯将如吴,诸大夫恐其又迁也,承,公孙翩逐而射之,入于家人而卒。以两矢门之。众莫敢进。文之锴后至,曰:“如墙而进,多而杀二人。”锴执弓而先,翩射之,中肘。锴遂杀之。故逐公孙辰,而杀公孙姓、公孙盱。 +夏,楚人既克夷虎,乃谋北方。左司马眅、申公寿余、叶公诸梁致蔡于负函,致方城之外于缯关,曰:“吴将水斥江入郢,将奔命焉。”为一昔之期,袭梁及霍。单浮余围蛮氏,蛮氏溃。蛮子赤奔晋阴地。司马起丰、析与狄戎,以临上雒。左师军于菟和,右师军于仓野,使谓阴地之命大夫士蔑曰:“晋、楚有盟,好恶同之。若将不废,寡君之愿也。不然,将通于少习以听命。”士蔑请诸赵孟。赵孟曰:“晋国未宁,安能恶于楚,必速与之。”士蔑乃致九州之戎。将裂田以与蛮子而城之,且将为之卜。蛮子听卜,遂执之,与其五大夫,以畀楚师于三户。司马致邑,立宗焉,以诱其遗民,而尽俘以归。 +秋七月,齐陈乞、弦施、卫宁跪救范氏。庚午,围五鹿。九月,赵鞅围邯郸。冬十一月,邯郸降。荀寅奔鲜虞,赵稷奔临。十二月,弦施逆之,遂堕临。国夏伐晋,取邢、任、栾、鄗、逆畤、阴人、盂、壶口。会鲜虞,纳荀寅于柏人。 +译文 +四年春季,蔡昭公准备到吴国去。大夫们恐怕他又要迁移,跟着公孙翩追赶蔡昭公并用箭射他,蔡昭公逃进百姓家里就死了。公孙翩拿着两支箭守在门口,大家不敢进去。文之锴后到,说:“并排像一垛墙一样往前走,至多只能杀死我们两个人。”文之锴拿着弓走在前面,公孙翩射他,射中肘部。文之锴就杀死了公孙翩,并因此驱逐了公孙辰而杀死了公孙姓、公孙盱。 +夏季,楚国人攻下夷虎以后,就策划向北方扩张。左司马眅、申公寿馀、叶公诸梁在负函集合蔡国人,方城山外的人在缯关集合,说:“吴国将要溯江而上进入郢都,大家都要奔走听命。”规定一晚上的期限,袭击梁地和霍地。单浮馀领兵包围蛮氏,蛮氏溃散。蛮子赤逃亡到晋国的阴地。司马征召丰地兵卒、析地人和狄戎入伍当兵,逼近上洛。左翼部队驻扎在菟和,右翼部队驻扎在仓野,派人对阴地的命大夫士蔑说:“晋国和楚国有过盟约,喜爱和厌恶彼此相共。如果这个盟约不废除,这是寡君的愿望。不这样,我们准备打通少习山再来听取你们的命令。”士蔑请示赵孟,赵孟说:“晋国没有安定,哪里能和楚国搞坏关系?一定要快点把人交给他们!”士蔑就召集九州之戎,说将要分给蛮子土田而在那里筑城,而且准备为这件事情占卜。蛮子前来听取占卜,就逮捕了他和他的五个大夫,在三户交给楚军。司马假装给蛮子城邑和建立宗主,来引诱分散的戎人,然后全部俘虏回去。 +秋季,七月,齐国的陈乞、弦施、卫国的宁跪救援范氏。十四日,包围五鹿。九月,赵鞅包围邯郸。冬季,十一月,邯郸投降。荀寅逃亡到鲜虞,赵稷逃奔到临地。十二月,弦施迎接赵稷,就拆毁了临地的城墙。国夏攻打晋国,占取了邢地、任地、栾地、鄗地、逆畤、阴人、盂地、壶口,会合鲜虞,把荀寅送到柏人邑。 + + +哀公五年 +【经】五年春,城毗。夏,齐侯伐宋。晋赵鞅帅师伐卫。秋九月癸酉,齐侯杵臼卒。冬,叔还如齐。闰月,葬齐景公。 +【传】五年春,晋围柏人,荀寅、士吉射奔齐。初,范氏之臣王生恶张柳朔,言诸昭子,使为柏人。昭子曰:“夫非而仇乎?”对曰:“私仇不及公,好不废过,恶不去善,义之经也。臣敢违之?”及范氏出,张柳朔谓其子:“尔从主,勉之!我将止死,王生授我矣。吾不可以僭之。”遂死于柏人。 +夏,赵鞅伐卫,范氏之故也,遂围中牟。 +齐燕姬生子,不成而死,诸子鬻姒之子荼嬖。诸大夫恐其为大子也,言于公曰:“君之齿长矣,未有大子,若之何?”公曰:“二三子间于忧虞,则有疾疢。亦姑谋乐,何忧于无君?”公疾,使国惠子、高昭子立荼,置群公子于莱。秋,齐景公卒。冬十月,公子嘉、公子驹、公子黔奔卫,公子锄、公子阳生来奔。莱人歌之曰:“景公死乎不与埋,三军之事乎不与谋。师乎师乎,何党之乎?” +郑驷秦富而侈,嬖大夫也,而常陈卿之车服于其庭。郑人恶而杀之。子思曰:“《诗》曰:‘不解于位,民之攸塈。’不守其位,而能久者鲜矣。《商颂》曰:‘不僭不滥,不敢怠皇,命以多福。’” +译文 +五年春季,晋国包围柏人,荀寅、士吉射逃奔到齐国。 +当初,范氏的家臣王生讨厌张柳朔,向范昭子建议,让张柳朔去做柏人地方长官。昭子说:“这个人不是你的仇人吗?”王生回答说:“私仇不能危害公事,喜爱不能废弃过错,厌恶不能排除善良,这是道义的常规,我岂敢违背它?”等到范氏离开柏人,张柳朔对他儿子说:“你跟随主人,努力吧!我准备留下来死守,王生把死难的大节交给了我,我不能对他不讲信用。”于是就战死在柏人。 +夏季,赵鞅进攻卫国,这是为了帮助范氏的缘故,并乘机包围中牟。 +齐国的燕姬生了个儿子,未成年就死了。但是诸子鬻姒所生的儿子荼受到宠爱。大夫们恐怕荼被立为太子,就对齐景公说:“您的年纪大了,还没有太子,怎么办?”齐景公说:“您这几位如有忧虑,就会生出疾病,姑且去寻欢作乐,何必担心没有国君?”齐景公生病,让国惠子、高昭子立荼为太子,把公子们安置在莱地。秋季,齐景公死去。冬季十月,公子嘉、公子驹、公子黔逃亡到卫国,公子鉏,公子阳生逃亡到鲁国来。莱地人歌唱说:“景公死了啊不参加埋葬,三军的大事啊不参加商量,众人啊众人,又要前往何方?” +郑国的驷秦富有而奢侈,是一个下大夫,但常常把卿的车马服饰陈列在他的院子里。郑国人讨厌他而把他杀了。子思说:“《诗》说:‘努力不懈在职位上,百姓所以才得以安宁。’不安于他的职位而能够保持长久的是很少的。《商颂》说:‘不出差错不自满,不敢懈怠不偷闲,上天赐予各种福禄。’” + +哀公六年 +【经】六年春,城邾瑕。晋赵鞅帅师伐鲜虞。吴伐陈。夏,齐国夏及高张来奔。叔还公吴于柤。秋七月庚寅,楚子轸卒。齐阳生入齐。齐陈乞弑其君荼。冬,仲孙何忌帅师伐邾。宋向巢帅师伐曹。 +【传】六年春,晋伐鲜虞,治范氏之乱也。 +吴伐陈,复修旧怨也。楚子曰:“吾先君与陈有盟,不可以不救。”乃救陈,师于城父。 +齐陈乞伪事高、国者,每朝必骖乘焉。所从必言诸大夫,曰:“彼皆偃蹇,将弃子之命。皆曰:‘高、国得君,必逼我,盍去诸?’固将谋子,子早图之。图之,莫如尽灭之。需,事之下也。”及朝,则曰:“彼虎狼也,见我在子之侧,杀我无日矣。请就之位。”又谓诸大夫曰:“二子者祸矣!恃得君而欲谋二三子,曰:‘国之多难,贵宠之由,尽去之而后君定。’既成谋矣,盍及其未作也,先诸?作而后悔,亦无及也。”大夫从之。 +夏六月戊辰,陈乞、鲍牧及诸大夫,以甲入于公宫。昭子闻之,与惠子乘如公,战于庄,败。国人追之,国夏奔莒,遂及高张、晏圉、弦施来奔。 +秋七月,楚子在城父,将救陈。卜战,不吉;卜退,不吉。王曰:“然则死也!再败楚师,不如死。弃盟逃仇,亦不如死。死一也,其死仇乎!”命公子申为王,不可;则命公子结,亦不可;则命公子启,五辞而后许。将战,王有疾。庚寅,昭王攻大冥,卒于城父。子闾退,曰:“君王舍其子而让,群臣敢忘君乎?从君之命,顺也。立君之子,亦顺也。二顺不可失也。”与子西、子期谋,潜师闭涂,逆越女之子章,立之而后还。 +是岁也,有云如众赤鸟,夹日以飞,三日。楚子使问诸周大史。周大史曰:“其当王身乎!若禜之,可移于令尹、司马。”王曰:“除腹心之疾,而置诸股肱,何益?不谷不有大过,天其夭诸?有罪受罚,又焉移之?”遂弗禜。 +初,昭王有疾。卜曰:“河为祟。”王弗祭。大夫请祭诸郊,王曰:“三代命祀,祭不越望。江、汉、雎、章,楚之望也。祸福之至,不是过也。不谷虽不德,河非所获罪也。”遂弗祭。孔子曰:“楚昭王知大道矣!其不失国也,宜哉!《夏书》曰:‘惟彼陶唐,帅彼天常,有此冀方。今失其行,乱其纪纲,乃灭而亡。’又曰:‘允出兹在兹。’由己率常可矣。” +八月,齐邴意兹来奔。 +陈僖子使召公子阳生。阳生驾而见南郭且于,曰:“尝献马于季孙,不入于上乘,故又献此,请与子乘之。”出莱门而告之故。阚止知之,先待诸外。公子曰:“事未可知,反,与壬也处。”戒之,遂行。逮夜,至于齐,国人知之。僖子使子士之母养之,与馈者皆入。 +冬十月丁卯,立之。将盟,鲍子醉而往。其臣差车鲍点曰:“此谁之命也?”陈子曰:“受命于鲍子。”遂诬鲍子曰:“子之命也。”鲍子曰:“女忘君之为孺子牛而折其齿乎?而背之也!”悼公稽首,曰:“吾子奉义而行者也。若我可,不必亡一大夫。若我不可,不必亡一公子。义则进,否则退,敢不唯子是从?废兴无以乱,则所愿也。”鲍子曰:“谁非君之子?”乃受盟。使胡姬以安孺子如赖。去鬻姒,杀王甲,拘江说,囚王豹于句窦之丘。 +公使朱毛告于陈子,曰:“微子则不及此。然君异于器,不可以二。器二不匮,君二多难,敢布诸大夫。”僖子不对而泣,曰:“君举不信群臣乎?以齐国之困,困又有忧。少君不可以访,是以求长君,庶亦能容群臣乎!不然,夫孺子何罪?”毛覆命,公悔之。毛曰:“君大访于陈子,而图其小可也。”使毛迁孺子于骀,不至,杀诸野幕之下,葬诸殳冒淳。 +译文 +六年春季,晋国进攻鲜虞,这是为惩治鲜虞帮助范氏作乱。 +吴国攻打陈国,这是重提旧怨。楚昭王说:“我们先君和陈国有过盟约,不能不去救援。”于是就救援陈国,楚军驻扎在城父。 +齐国的陈乞伪装出事奉高氏、国氏的样子,每逢上朝,一定和他们同坐一辆车。随从时一定要说到大夫们,说:“他们都很骄傲,将要抛弃您的命令。他们都说:‘高氏、国氏受到国君的宠信,必然要逼迫我们,何不除去他们?’本来想要打您的主意,您要早点考虑对策!考虑了,最好是全部灭亡他们。等待是下策。”到了朝廷上,就说:“他们都是虎狼,见到我在您的旁边,早就要杀死我了,请让我靠到大夫们那边去。”到了大夫们那里,又对大夫们说:“这两位要发动祸乱了!仗着得到国君的宠信而要打您几位的主意,说:‘国家的患难多,这是由贵宠造成的,全部去掉他们然后国君才能安定。’现在已经定下计划了,何不乘他们没有下手而抢在他们前头?等他们发动了再后悔,也来不及了。”大夫们听从了。 +夏季,六月二十三日,陈乞、鲍牧和大夫们率领甲士进入公宫。高张听到了,和国夏坐车到齐侯那里去。在庄街作战,被打败。国内的人们追赶他们,国夏逃亡到莒国,就和高张、晏圉、弦施一起逃亡前来。 +秋季,七月,楚昭王驻在城父,准备救援陈国。占卜战争,不吉利。占卜退兵,不吉利。楚昭王说:“那么只有死了。如果再次让楚军失败,不如死。抛弃盟约、逃避仇敌,也不如死。同是一死,还是死在仇敌手里吧!”命令公子申继承王位,公子申不同意;就命令公子结,公子结也不同意,又命令公子启,公子启辞谢五次然后同意。将要作战,楚昭王得了病。十六日,楚昭王进攻大冥,死在城父。子闾退兵说:“君王舍弃他的儿子而让位,臣下们岂敢忘记君王呢?服从君王的命令,这是顺乎情理的;立君王的儿子,也是顺乎情理的。两种顺乎情理都不能丢掉。”和子西、子期商量,秘密转移军队,封闭有关的通路,迎接越国女子的儿子章而立他做国君,然后退兵回国。 +这一年,有云彩好像一群红色的鸟一样,夹在太阳两边飞翔了三天。楚昭王派人询问成周的太史。成周的太史说:“恐怕要应在君王的身上吧!如果禳祭,可以移到令尹、司马身上。”楚昭王说:“把腹心的疾病去掉,而放在大腿胳臂上,有什么益处?我没有重大的过错,上天能让我夭折吗?有罪受到处罚,又能移到哪里去呢?”于是就不去禳祭。 +当初,楚昭王有病,占卜的人说:“黄河之神在作怪。”楚昭王不去祭祀。大夫们请求在郊外祭祀。楚昭王说:“三代时规定的祭祀制度,祭祀不超越本国的山川。长江、汉水、睢水、漳水,是楚国的大川。祸福的来到,不会超过这些地方。我即使没有德行,也不会得罪黄河之神。”于是就不去祭祀。 +孔子说:“楚昭王理解大道理了。他的不失去国家,就是当然的了!《夏书》说:‘那位古代的君王陶唐,遵循天道纲常,据有这中国地方。现在走到邪道上,搅乱了治国的大纲,于是就被灭亡。’又说:‘付出了什么,就会收获什么。’由自己来服从天道,这就可以了。” +八月,齐国的邴意兹逃亡到鲁国来。 +陈僖子派人召见公子阳生。阳生套上车去见南郭且于,说:“我曾经把马奉献给季孙,但没有能列入他的上等乘马之中,所以又奉献这几匹,请和您一起坐上车试试。”出了莱门然后把原因告诉南郭且于。阚止知道了,先在城外等着。公子阳生说:“事情是好是坏还不能知道,回去,和壬在一起。”告诫了阚止,就动身了。等到夜里,到达齐国,国内的人们就知道他到了。陈僖子让子士的母亲照顾阳生,又让阳生跟着送食物的人一起进入公宫。 +冬季,十月二十四日,立阳生为国君。将要盟誓,鲍子喝醉了前去。他管车的家臣鲍点说:“这是谁的命令?”陈僖子说:“接受鲍子的命令。”于是就诬赖鲍子说:“这是您的命令!”鲍子说:“您忘记先君为荼做牛而折掉牙齿吗?现在又要违背先君吗?”齐悼公叩头,说:“您是按照道义办事情的。如果我行,不必杀死一个大夫。如果我不行,也不必杀死一个公子。合于道义就前进,不合就后退,岂敢不唯您是从?废一个,立一个,不要因此发生动乱,这就是我的愿望。”鲍子说:“你们有谁不是先君的儿子呢?”于是就接受了盟约。悼公让胡姬带着安孺到赖地去,把鬻姒送到别处,杀死王申,拘捕江说,把王豹囚禁在句窦之丘。 +齐悼公派朱毛告诉陈僖子,说:“没有您,我不能到这一步。然而国君和器物不一样,不能有两个。有两件器物就不愁缺乏,有两个国君祸难就多了,谨敢向您陈述。”陈僖子不回答而哭泣,说:“国君对臣下们都不相信吗?齐国有困难,贫困而又有忧患,年幼的国君不能去请示,因此我才找来年长的,大约还能够对臣下们加以容忍吧!不这样,孺子荼有什么罪过?”朱毛向悼公复命,悼公后悔失言。朱毛说:“您大事征求陈子的意见,小事情自己拿主意就行了。”悼公派朱毛把孺子迁移到骀地。没有到达,把他杀死在野外的帐篷里,葬在殳冒淳。 + +哀公七年 +【经】七年春,宋皇瑗帅师侵郑。晋魏曼多帅师侵卫。夏,公会吴于鄫。秋,公伐邾。八月己酉,入邾,以邾子益来。宋人围曹。冬,郑驷弘帅师救曹。 +【传】七年春,宋师侵郑,郑叛晋故也。 +晋师侵卫,卫不服也。 +夏,公会吴于鄫。吴来征百牢,子服景伯对曰:“先王未之有也。”吴人曰:“宋百牢我,鲁不可以后宋。且鲁牢晋大夫过十,吴王百牢,不亦可乎?”景伯曰:“晋范鞅贪而弃礼,以大国惧敝邑,故敝邑十一牢之。君若以礼命于诸侯,则有数矣。若亦弃礼,则有淫者矣。周之王也,制礼,上物不过十二,以为天之大数也。今弃周礼,而曰必百牢,亦唯执事。”吴人弗听。景伯曰:“吴将亡矣!弃天而背本不与,必弃疾于我。”乃与之。 +大宰嚭召季康子,康子使子贡辞。大宰嚭曰:“国君道长,而大夫不出门,此何礼也?”对曰:“岂以为礼?畏大国也。大国不以礼命于诸侯,苟不以礼,岂可量也?寡君既共命焉,其老岂敢弃其国?大伯端委以治周礼,仲雍嗣之,断发文身,赢以为饰,岂礼也哉?有由然也。”反自鄫,以吴为无能为也。 +季康子欲伐邾,乃飨大夫以谋之。子服景伯曰:“小所以事大,信也。大所以保小,仁也。背大国,不信。伐小国,不仁。民保于城,城保于德,失二德者,危,将焉保?”孟孙曰:“二三子以为何如?恶贤而逆之?”对曰:“禹合诸侯于涂山,执玉帛者万国。今其存者,无数十焉。唯大不字小,小不事大也。知必危,何故不言?鲁德如邾,而以众加之,可乎?”不乐而出。 +秋,伐邾,及范门,犹闻钟声。大夫谏,不听,茅成子请告于吴,不许,曰:“鲁击柝闻于邾,吴二千里,不三月不至,何及于我?且国内岂不足?”成子以茅叛,师遂入邾,处其公宫,众师昼掠,邾众保于绎。师宵掠,以邾子益来,献于亳社,囚诸负瑕。负瑕故有绎。邾茅夷鸿以束帛乘韦,自请救于吴,曰:“鲁弱晋而远吴,冯恃其众,而背君之盟,辟君之执事,以陵我小国。邾非敢自爱也,惧君威之不立。君威之不立,小国之忧也。若夏盟于鄫衍,秋而背之,成求而不违,四方诸侯,其何以事君?且鲁赋八百乘,君之贰也。邾赋六百乘,君之私也。以私奉贰,唯君图之。”吴子从之。 +宋人围曹。郑桓子思曰:“宋人有曹,郑之患也。不可以不救。”冬,郑师救曹,侵宋。 +初,曹人或梦众君子立于社宫,而谋亡曹,曹叔振铎请待公孙强,许之。旦而求之曹,无之。戒其子曰:“我死,尔闻公孙强为政,必去之。”及曹伯阳即位,好田弋。曹鄙人公孙强好弋,获白雁,献之,且言田弋之说,说之。因访政事,大说之。有宠,使为司城以听政。梦者之子乃行。强言霸说于曹伯,曹伯从之,乃背晋而奸宋。宋人伐之,晋人不救。筑五邑于其郊,曰黍丘、揖丘、大城、钟、邗。 +译文 +七年春季,宋军入侵郑国,这是因为郑国背叛晋国的缘故。 +晋军入侵卫国,这是因为卫国不顺服。 +夏季,鲁哀公和吴国人在鄫地会见。吴国前来要求取牛、羊、猪一百头为享宴品。子服景伯回答说:“先王没有过这样的事。”吴国人说:“宋国享我们以牛羊猪各一百头,鲁国不能落在宋国之后。而且鲁国享宴晋国大夫超过各十头,给吴王各一百头,不也是可以的吗?”子服景伯说:“晋国的范鞅贪婪而抛弃礼仪,用大国的势力来迫使敝邑恐惧,所以敝邑享他以牛羊猪各十一头。君王如果用礼仪来命令诸侯,那么就有一定的数字。如果也抛弃礼仪,那么就太过分了。周朝统一天下,制定礼仪,上等的物品数字不过十二,因为这是上天的大数。现在抛弃周礼,而说一定要太牢一百,也只好听从执事的命令。”吴国人不听,子服景伯说:“吴国快要灭亡了,抛弃上天而违背根本。如果不给,一定要加害于我们。”于是就照数给了他们。 +太宰嚭召见季康子,康子让子贡去辞谢。太宰嚭说:“国君走了那么远的路程,而大夫不出门,这是什么礼仪?”子贡回答说:“岂敢把这作为礼仪,只是由于害怕大国。大国不用礼仪来命令诸侯,如果不用礼仪,其后果小国就不能估计了。寡君即已奉命前来,他的老臣岂敢丢下国家?太伯穿着玄端的衣服戴着委貌的帽子来推行周礼,仲雍继承他,把头发剪断,身上刺上花纹,作为裸体的装饰,难道合于礼吗?因为有原因所以才这样做的。”从鄫地回来,季康子认为吴国没有能力做出什么事来的。 +季康子想要攻打邾国,就设享礼招待大夫们来一起商量。子服景伯说:“小国用来事奉大国的,是信;大国用来保护小国的,是仁。违背大国,这是不信,攻打小国,这是不仁。百姓由城邑来保护,城邑由德行来保护。丢掉了信和仁两种德行,就危险了,还能保护什么?”孟孙说:“各位以为怎么样?哪一种意见好我就采纳。”大夫们回答说:“大禹在涂山会合诸侯,拿着玉帛的有一万个国家。现在还存在的,没有几十个了,就是因为大国不养育小国,小国不事奉大国。明知必有危险,为什么不说?鲁国的德行和邾国一样,而要用大兵来施加压力,行吗?”不欢而散。 +秋季,鲁国攻打邾国,到达范门,还能听到乐钟的声音。大夫劝谏,邾子不听。茅成子请求向吴国报告,邾子不答应,说:“鲁国敲打梆子的声音,在邾国可以听到,吴国相距二千里,没有三个月到不了,哪里能管得了我们?而且国内的力量难道就不足够?”茅成子领着茅地人叛变了,鲁国的军队就攻进了邾国国都,住在邾子的宫内,各军白天抢劫。邾国的军队在绎山守卫。鲁军在夜里抢劫,带了邾子益回来,把他奉献于亳社,囚禁在负瑕,负瑕因此而有了绎山人。 +邾国的茅夷鸿带了五匹帛四张熟牛皮自己去请求吴国救援,说:“鲁国以为晋国衰弱而吴国遥远,倚仗着他们人多,而背弃了和君王订立的盟约,看不起君王的执事,来欺凌我们小国。邾国不敢自己爱惜,惧怕的是君王的威信不能建立。君王的威信不能建立,这是小国所担心的。如果夏天在鄫衍结盟,秋天就背弃它,鲁国得到了所求而没有阻力,四方的诸侯还用什么来事奉君王?而且鲁国拥有战车八百辆是君王的对手,邾国战车六百辆却是君王的部属。把部属去送给对手,请君考虑一下!”吴王听从了茅夷鸿的话。 +宋国人包围曹国,郑国的桓子思说:“宋国人如果据有曹国,这是郑国的忧患,不能不救。”郑军救援曹国,入侵宋国。 +当初,曹国有人梦见一伙君子站在国社墙外,商量灭亡曹国。曹叔振铎请求等待公孙彊,众君子答应了。早晨起来去寻找,曹国没有这个人。做梦的人告诫他儿子说:“我死以后,你听说公孙彊执政,一定要离开曹国。” +等到曹伯阳即位,喜欢打猎射鸟,曹国边境上的人公孙彊喜欢射鸟,得到一只白雁,献给曹伯阳,还讲述了打猎射鸟的技巧,曹伯很喜欢他。由此而向公孙彊询问国家大事,他应对得体,曹伯阳更加喜欢他,加以宠信,让他担任司城执掌国政。做梦的人的儿子这时就离开曹国。 +公孙彊向曹伯讲述称霸的策略,曹伯阳听从了,就背弃晋国而侵犯宋国。宋国人攻打曹国,晋国人不去救援,公孙彊在国都郊外建造了五个城邑,名叫黍丘、揖丘、大城、钟、邘。 + +哀公八年 +【经】八年春王正月,宋公入曹,以曹伯阳归。吴伐我。夏,齐人取讙及阐。归邾子益子邾。秋七月。冬十有二月癸亥,杞伯过卒。齐人归讙及阐。 +【传】八年春,宋公伐曹,将还,褚师子肥殿。曹人诟之,不行,师待之。公闻之,怒,命反之,遂灭曹。执曹伯及司城强以归,杀之。 +吴为邾故,将伐鲁,问于叔孙辄。叔孙辄对曰:“鲁有名而无情,伐之,必得志焉。”退而告公山不狃。公山不狃曰:“非礼也。君子违,不适仇国。未臣而有伐之,奔命焉,死之可也。所托也则隐。且夫人之行也,不以所恶废乡。今子以小恶而欲覆宗国,不亦难乎?若使子率,子必辞,王将使我。”子张疾之。王问于子泄,对曰:“鲁虽无与立,必有与毙;诸侯将救之,未可以得志焉。晋与齐、楚辅之,是四仇也。夫鲁、齐、晋之唇,唇亡齿寒,君所知也。不救何为?” +三月,吴伐我,子泄率,故道险,从武城。初,武城人或有因于吴竟田焉,拘鄫谒之沤菅者,曰:“何故使吾水滋?”及吴师至,拘者道之,以伐武城,克之。王犯尝为之宰,澹枱子羽之父好焉。国人惧,懿子谓景伯:“若之何?”对曰:“吴师来,斯与之战,何患焉?且召之而至,又何求焉?”吴师克东阳而进,舍于五梧,明日,舍于蚕室。公宾庚、公甲叔子与战于夷,获叔子与析朱锄。献于王,王曰:“此同车,必使能,国未可望也。”明日,舍于庚宗,遂次于泗上。微虎欲宵攻王舍,私属徒七百人,三踊于幕庭,卒三百人,有若与焉,及稷门之内。或谓季孙曰:“不足以害吴,而多杀国士,不如已也。”乃止之。吴子闻之,一夕三迁。吴人行成,将盟。景伯曰:“楚人围宋,易子而食,析骸而爨,犹无城下之盟。我未及亏,而有城下之盟,是弃国也。吴轻而远,不能久,将归V请少待之。”弗从。景伯负载,造于莱门,乃请释子服何于吴,吴人许之。以王子姑曹当之,而后止。吴人盟而还。 +齐悼公之来也,季康子以其妹妻之,即位而逆之。季鲂侯通焉,女言其情,弗敢与也。齐侯怒,夏五月,齐鲍牧帅师伐我,取讙及阐。 +或谮胡姬于齐侯,曰:“安孺子之党也。”六月,齐侯杀胡姬。 +齐侯使如吴请师,将以伐我,乃归邾子。邾子又无道,吴子使大宰子余讨之,囚诸楼台,栫之以棘。使诸大夫奉大子革以为政。 +秋,及齐平。九月,臧宾如如齐莅盟,齐闾丘明来莅盟,且逆季姬以归,嬖。 +鲍牧又谓群公子曰:“使女有马千乘乎?”公子愬之。公谓鲍子:“或谮子,子姑居于潞以察之。若有之,则分室以行。若无之,则反子之所。”出门,使以三分之一行。半道,使以二乘。及潞,麇之以入,遂杀之。 +冬十二月,齐人归讙及阐,季姬嬖故也。 +译文 +八年春季,宋景公进攻了曹国,准备撤兵回国,褚师子肥走在最后。曹国人辱骂他,他就不走了,全军等待褚师子肥。宋景公听说了这件事,发怒,命令回兵,于是就灭了曹国,逮捕了曹伯阳和司城公孙彊回去,杀死了他们。 +吴国为了邾国的缘故,准备攻打鲁国。吴王询问叔孙辄,叔孙辄回答说:“鲁国有名而无实,攻打他们,一定能如愿以偿。”退出来告诉公山不狃。公山不狃说:“这是不合于礼的。君子离开自己的国家,不到敌国去。在鲁国没有尽到臣下责任而又去攻打它,为吴国效力,这就可以死去。这样的委任就要避开。而且一个人离开祖国,不应该因为有所怨恨而祸害乡土。现在您由于小怨而要颠覆祖国,不也很难吗?如果派您领兵先行,您一定要推辞。君王将会派我去。”叔孙辄悔恨自己说错了话。吴王又问公山不狃。公山不狃回答说:“鲁国平时虽然没有可靠的盟国,危急的时候却一定会有愿共同抵抗的援国。诸侯将会救援它,是不能实现愿望的。晋国和齐国、楚国会帮助它,这就是吴国的四个敌国了。鲁国是齐国和晋国的嘴唇,唇亡齿寒,这是您所知道的,他们不去救援还干什么?” +三月,吴国攻打我鲁国,公山不狃领兵先行,故意从险路进军,经过武城。当初,武城人有人在边境上种田,拘捕了浸泡菅草的鄫国人,说:“为什么把我的水弄脏?”等到吴军来到,被拘捕的那个人领着吴军攻打武城,攻下了这个城邑。王犯曾经做过武城的地方官,澹台子羽的父亲和王犯友好,国内的人们害怕。孟孙对景伯说:“怎么办?”景伯回答说:“吴军来就和他们作战,怕什么?而且是去找他们来的,还要求什么?”吴军攻下东阳而后前进,驻扎在五梧。第二天,驻扎在蚕室。公宾庚、公甲叔子和吴军在夷地作战,吴军俘虏了叔子和析朱鉏,把死俘献给吴王。吴王说:“这是同一辆战车上的人,鲁国一定任用了能人。鲁国还不能觊觎呢。”第二天,住在庚宗,就在泗水边上驻扎。微虎想要夜袭吴王的住处,让他的私人部队七百人在帐幕外的庭院里,每人向上跳三次,最后挑选了三百人,有若也在里边。出发到达稷门之内,有人对季孙说:“这样做不足以危害吴国,反而让国内许多突出的人物送了命,不如停止。”季孙就下令停止这样做。吴王听说这情况,一晚上迁移了三次住处。 +吴国人求和,鲁、吴两国将要订立盟约。子服景伯说:“楚国人包围宋国,宋国人交换儿子来吃,劈开尸骨烧饭,尚且没有订立城下之盟。我们还不到那样的地步,订有城下之盟,这是丢掉国家。吴国轻率而离本土很远,不能持久,快要回去了,请稍等一下。”不听,景伯背着盟书,去到莱门。鲁国就请求把子服景伯留在吴国,吴国人答应了,鲁国又要求用王子姑曹相抵押,结果是双方停止交换人质。吴国人订立了盟约然后回国。 +齐悼公来鲁国的时候,季康子把他的妹妹嫁给悼公,悼公即位以后来迎接她。季鲂侯和她私通,这个女人向季康子讲出了私通的情况。季康子不敢把她送到齐国去。齐悼公发怒。夏季五月,齐国的鲍牧带兵进攻鲁国,占领了讙地和阐地。 +有人在齐悼公那里诬陷胡姬说:“她是安孺子的同党。”六月,齐悼公杀了胡姬。 +齐悼公派人到吴国请求发兵,将要用来攻打鲁国,鲁国送回了邾子。邾子还是无道,吴王派太宰子馀付伐他,把他囚禁在楼台里,用荆棘做成篱笆围起来,让大夫们事奉太子革执政。 +秋季,和齐国讲和。九月,臧宾如去到齐国参加结盟。齐国的闾丘明前来参加结盟,而且迎接季姬回去,齐悼公对她很宠爱。 +鲍牧又对公子们说:“要使你拥有四千匹马吗?”公子们告诉了齐悼公。齐悼公对鲍牧说:“有人说您的坏话,您姑且住在潞地观察一下。如果有这件事,您就把家产的一半带走出国,如果没有,就回到原来的地方去。”鲍牧出门,让他带着家产的三分之一出走。走到半路,只让他带着两辆车子走。到达潞地,就把他捆绑了回来,杀死了他。 +冬季,十二月,齐国人把讙地和阐地归还给鲁国,这是由于季姬受到宠爱的缘故。 + +哀公九年 +【经】九年春王二月,葬杞僖公。宋皇瑗帅师取郑师于雍丘。夏,楚人伐陈。秋,宋公伐郑。冬十月。 +【传】九年春,齐侯使公孟绰辞师于吴。吴子曰:“昔岁寡人闻命。今又革之,不知所从,将进受命于君。” +郑武子剩之嬖许瑕求邑,无以与之。请外取,许之。故围宋雍丘。宋皇瑗围郑师,每日迁舍,垒合,郑师哭。子姚救之,大败。二月甲戌,宋取郑师于雍丘,使有能者无死,以郏张与郑罗归。 +夏,楚人伐陈,陈即吴故也。 +宋公伐郑。 +秋,吴城邗,沟通江、淮。 +晋赵鞅卜救郑,遇水适火,占诸史赵、史墨、史龟。史龟曰:“是谓渖阳,可以兴兵。利以伐姜,不利子商。伐齐则可,敌宋不吉。”史墨曰:“盈,水名也。子,水位也。名位敌,不可干也。炎帝为火师,姜姓其后也。水胜火,伐姜则可。”史赵曰:“是谓如川之满,不可游也。郑方有罪,不可救也。救郑则不吉,不知其他。”阳虎以《周易》筮之,遇《泰》ⅱⅰ之《需》ⅴⅰ,曰:“宋方吉,不可与也。微子启,帝乙之元子也。宋、郑,甥舅也。祉,禄也。若帝乙之元子归妹,而有吉禄,我安得吉焉?”乃止。 +冬,吴子使来人敬师伐齐。 +译文 +九年春季,齐悼公派公孟绰到吴国辞谢出兵。吴王说:“去年我听到君王的命令,现在又改变了,不知道该听从什么,我准备到贵国去接受君王的命令。” +郑国武子賸的宠臣许瑕求取封邑,没有地方可以封给他了。许瑕请求取之于外国,武子賸答应,所以包围了宋国的雍丘。宋国的皇瑗又包围郑军,每天挖沟修筑堡垒,连成一线。郑国军士都号啕大哭,武子賸前去救援,大败。二月十四日,宋军在雍丘全歼郑军,让有才能的人留下性命,带了郏张和郑罗回去。 +夏季,楚国人进攻陈国,这是因为陈国投向吴国的缘故。 +宋景公发兵攻打郑国。 +秋季,吴国在邗地筑城,穿沟贯通长江、淮水。 +晋国的赵鞅为救援郑国而占卜,得到水流向火的卦象,向史赵、史墨、史龟询问卦象的吉凶。史龟说:“这叫做阳气下沉,可以发兵,利于攻打姜氏,不利于攻打子商。攻打齐国就可以,攻打宋国就不吉利。”史墨说:“盈,是水泊名称。子,是水的方位。名称方位相当,不能触犯,炎帝是火师,姜姓是他的后代。水胜火,攻打姜姓就可以。”史赵说:“这卦叫做像河水涨满,不能游泳;郑国正有罪,不能救,救援郑国就不吉利,其他的不知道。”阳虎用《周易》占筮,得到《泰》卦变成《需》卦,说:“宋国正在吉利的时候,不能以他为敌。微子启,是帝乙的大儿子。宋国和郑国,是舅舅和外甥。福祉,是爵禄。如果帝乙的大儿子嫁女儿而又有吉利的爵禄,我们哪里能够吉利?”于是晋国就不去救援郑国。 +冬季,吴王派人来鲁国通知出兵攻打齐国。 + +哀公十年 +【经】十年春王二月,邾子益来奔。公会吴伐齐。三月戊戌,齐侯阳生卒。夏,宋人伐郑。晋赵鞅帅师侵齐。五月,公至自伐齐。葬齐悼公。卫公孟彄自齐归于卫。薛伯夷卒。秋,葬薛惠公。冬,楚公子结帅师伐陈。吴救陈。 +【传】十年春,邾隐公来奔。齐甥也,故遂奔齐。 +公会吴子、邾子、郯子伐齐南鄙,师于鄎。齐人弑悼公,赴于师。吴子三日哭于军门之外。徐承帅舟师,将自海入齐,齐人败之,吴师乃还。 +夏,赵鞅帅师伐齐,大夫请卜之。赵孟曰:“吾卜于此起兵,事不再令,卜不袭吉,行也。”于是乎取犁及辕,毁高唐之郭,侵及赖而还。 +秋,吴子使来复人】敬师。 +冬,楚子期伐陈。吴延州来季子救陈,谓子期曰:“二君不务德,而力争诸侯,民何罪焉?我请退,以为子名,务德而安民。”乃还。 +译文 +十年春季,邾隐公逃亡到鲁国来,他是齐国的外甥,因此就再逃亡到齐国。 +哀公会合吴王、邾子、郯子攻打齐同南部边境,军队驻扎在鄎地。齐国人杀死齐悼公,向联军发了讣告。吴王在军门外边号哭三天。徐承率领水军打算从海上进入齐国。齐国人把他打败了,吴军就退兵回国。 +夏季,赵鞅领兵攻打齐国,大夫请求占卜,赵鞅说:“我为对齐国出兵占卜过,事情不能再卜,占卜也不一定再次吉利,起行!”因此占取了犁地和辕地,拆毁了高唐的外城,侵袭到赖地然后回去。 +秋季,吴王派人到鲁国来,再次通知出兵。 +冬季,楚国的子期进攻陈国,吴国的延州来季子救援陈国,对子期说:“两国的国君不致力于德行,而用武力争夺诸侯,百姓有什么罪过呢?我请求撤退,以此使您得到好名声,请您致力于德行而安定百姓。”于是就撤兵回国。 + + +哀公十一年 +【经】十有一年春,齐国书帅师伐我。夏,陈辕颇出奔郑。五月,公会吴伐齐。甲戌,齐国书帅师及吴战于艾陵,齐师败绩,获齐国书。秋七月辛酉,滕子虞母卒。冬十有一月,葬滕隐公。卫世叔齐出奔宋。 +【传】十一年春,齐为鄎故,国书、高无丕帅师伐我,及清。季孙谓其宰冉求曰:“齐师在清,必鲁故也。若之何?”求曰:“一子守,二子从公御诸竟。”季孙曰:“不能。”求曰:“居封疆之间。”季孙告二子,二子不可。求曰:“若不可,则君无出。一子帅师,背城而战。不属者,非鲁人也。鲁之群室,众于齐之兵车。一室敌车,优矣。子何患焉?二子之不欲战也宜,政在季氏。当子之身,齐人伐鲁而不能战,子之耻也。大不列于诸侯矣。”季孙使从于朝,俟于党氏之沟。武叔呼而问战焉,对曰:“君子有远虑,小人何知?”懿子强问之,对曰:“小人虑材而言,量力而共者也。”武叔曰:“是谓我不成丈夫也。”退而蒐乘,孟孺子泄帅右师,颜羽御,邴泄为右。冉求帅左师,管周父御,樊迟为右。季孙曰:“须也弱。”有子曰:“就用命焉。”季氏之甲七千,冉有以武城人三百为己徒卒。老幼守宫,次于雩门之外。五日,右师从之。公叔务人见保者而泣,曰:“事充政重,上不能谋,士不能死,何以治民?吾既言之矣,敢不勉乎!” +师及齐师战于郊,齐师自稷曲,师不逾沟。樊迟曰:“非不能也,不信子也。请三刻而逾之。”如之,众从之。师入齐军,右师奔,齐人从之,陈瓘、陈庄涉泗。孟之侧后入以为殿,抽矢策其马,曰:“马不进也。”林不狃之伍曰:“走乎?”不狃曰:“谁不如?”曰:“然则止乎?”不狃曰:“恶贤?”徐步而死。师获甲首八十,齐人不能师。宵,谍曰:“齐人遁。”冉有请从之三,季孙弗许。孟孺子语人曰:“我不如颜羽,而贤于邴泄。子羽锐敏,我不欲战而能默。泄曰:‘驱之。’”公为与其嬖僮汪錡乘,皆死,皆殡。孔子曰:“能执干戈以卫社稷,可无殇也。”冉有用矛于齐师,故能入其军。孔子曰:“义也。” +夏,陈辕颇出奔郑。初,辕颇为司徒,赋封田以嫁公女。有馀,以为己大器。国人逐之,故出。道渴,其族辕咺进稻醴、梁糗、糗脯焉。喜曰:“何其给也?”对曰:“器成而具。”曰:“何不吾谏?”对曰:“惧先行。” +为郊战故,公会吴子伐齐。五月,克博,壬申,至于羸。中军从王,胥门巢将上军,王子姑曹将下军,展如将右军。齐国书将中军,高无丕将上军,宗楼将下军。陈僖子谓其弟书:“尔死,我必得志。”宗子阳与闾丘明相厉也。桑掩胥御国子,公孙夏曰:“二子必死。”将战,公孙夏命其徒歌《虞殡》。陈子行命其徒具含玉。公孙挥命其徒曰:“人寻约,吴发短。”东郭书曰:“三战必死,于此三矣。”使问弦多以琴,曰:“吾不复见子矣。”陈书曰:“此行也,吾闻鼓而已,不闻金矣。” +甲戌,战于艾陵,展如败高子,国子败胥门巢。王卒助之,大败齐师。获国书、公孙夏、闾丘明、陈书、东郭书,革车八百乘,甲首三千,以献于公。将战,吴子呼叔孙,曰:“而事何也?”对曰:“从司马。”王赐之甲、剑、铍,曰:“奉尔君事,敬无废命。”叔孙未能对,卫赐进,曰:“州仇奉甲从君。”而拜。公使大史固归国子之元,置之新箧,褽之以玄纁,加组带焉。置书于其上,曰:“天若不识不衷,何以使下国?” +吴将伐齐,越子率其众以朝焉,王及列士,皆有馈赂。吴人皆喜,惟子胥惧,曰:“是豢吴也夫!”谏曰:“越在我,心腹之疾也。壤地同,而有欲于我。夫其柔服,求济其欲也,不如早从事焉。得志于齐,犹获石田也,无所用之。越不为沼,吴其泯矣,使医除疾,而曰:‘必遗类焉’者,未之有也。《盘庚之诰》曰:‘其有颠越不共,则劓殄无遗育,无俾易种于兹邑。’是商所以兴也。今君易之,将以求大,不亦难乎?”弗听,使于齐,属其子于鲍氏,为王孙氏。反役,王闻之,使赐之属镂以死,将死,曰:“树吾墓梵檟檟可材也。吴其亡乎!三年,其始弱矣。盈必毁,天之道也。” +秋,季孙命修守备,曰:“小胜大,祸也。齐至无日矣。” +冬,卫大叔疾出奔宋。初,疾娶于宋子朝,其娣嬖。子朝出。孔文子使疾出其妻而妻之。疾使侍人诱其初妻之娣,置于犁,而为之一宫,如二妻。文子怒,欲攻之。仲尼止之。遂夺其妻。或淫于外州,外州人夺之轩以献。耻是二者,故出。卫人立遗,使室孔姞。疾臣向魋纳美珠焉,与之城锄。宋公求珠,魋不与,由是得罪。及桓氏出,城锄人攻大叔疾,卫庄公复之。使处巢,死焉。殡于郧,葬于少禘。 +初,晋悼公子憖亡在卫,使其女仆而田。大叔懿子止而饮之酒,遂聘之,生悼子。悼子即位,故夏戊为大夫。悼子亡,卫人翦夏戊。孔文子之将攻大叔也,访于仲尼。仲尼曰:“胡簋之事,则尝学之矣。甲兵之事,未之闻也。”退,命驾而行,曰:“鸟则择木,木岂能择鸟?”文子遽止之,曰:“圉岂敢度其私,访卫国之难也。”将止。鲁人以币召之,乃归。 +季孙欲以田赋,使冉有访诸仲尼。仲尼曰:“丘不识也。”三发,卒曰:“子为国老,待子而行,若之何子之不言也?”仲尼不对。而私于冉有曰:“君子之行也,度于礼,施取其厚,事举其中,敛从其薄。如是则以丘亦足矣。若不度于礼,而贪冒无厌,则虽以田赋,将又不足。且子季孙若欲行而法,则周公之典在。若欲苟而行,又何访焉?”弗听。 +译文 +十一年春季,齐国因为鄎地这一战的缘故,国书、高无邳带兵进攻我国,到达清地。季孙对他的家臣之长冉求说:“齐国驻扎在清地,必然是为了鲁国的缘故,怎么办?”冉求说:“您三位中间一位留守,两位跟着国君在边境抵御。”季孙说:“不行。”冉求说:“那就在境内近郊抵御。”季孙告诉了叔孙、孟孙,这两人不同意。冉求说:“如果不同意,那么国君就不要出去。您一人带领军队,背城作战,不参加战斗的就不能算是鲁国人。鲁国的卿大夫各家的总数比齐国的战车要多,即使您一家的战车也多于齐军,您担心什么?他们两位不想作战是很自然的,因为政权掌握在季氏手里。国政承担在您的肩上,齐国人攻打鲁国而不能作战,这是您的耻辱。这就完全不配和诸侯并列了。”季孙氏让冉求跟着他上朝,在党氏之沟等着,叔孙喊过冉求问他关于作战的意见。冉求回答说:“君子有着深远的考虑,小人知道什么?”孟孙硬是问他,他回答说:“小人是考虑了才干而说话,估计了力量才出力的。”叔孙说:“这是说我成不了大丈夫啊。”退回去以后就检阅部队。孟孺子泄率领右军,颜羽为他驾御战车,邴泄作为车右。冉求率领左军,管周父为他驾御战车,樊迟作为车右。季孙说:“樊迟年纪太轻了。”冉求说:“因为他能够听从命令。”季氏的甲士七千人,冉求带着三百个武城人作为自己的亲兵,老的小的守在宫里,驻扎在雩门外边。过了五天,右军才跟上来。公叔务人见到守城的人就掉眼泪说:“徭役烦、赋税多,上面不能谋划,战士不能拼命,用什么来治理百姓?我已经这么说了,怎么敢不努力呢!” +鲁军和齐军在郊外作战。齐军从稷曲攻击鲁军,鲁军不敢过沟迎战。樊迟说:“不是不能,是不相信您,请您把号令申明三次,然后带头过沟。”冉求照他的话办,众人就跟着他过沟。 +鲁军攻入齐军。鲁国右军奔逃,齐国追赶。陈瓘、陈庄徒步渡过泗水。孟之侧在全军之后最后回来,他抽出箭来打他的马,说:“我走在最后是马不肯往前走。”林不狃的伙伴说:“逃跑吗?”不狃说:“我不如谁?”伙伴说:“那么停下来抵抗吗?”不狃说:“停下来抵抗就好么?”从容缓步,被杀死。 +鲁军砍下甲士的脑袋八十个,齐国人不能整顿军队。晚上,侦探报告说:“齐国人逃跑了。”冉有三次请求追击,季孙没有允许。孟孺子对别人说:“我不如颜羽,但比邴泄高明。颜羽敏锐善战,我心虽不想作战,但口中不说逃走的话,邴泄却说‘赶着马逃走’。”公为和他宠爱的小僮汪锜同坐一辆战车,一起战死,都加以殡敛。孔子说:“能够拿起干戈保卫国家,可以不作为夭折来对待。”冉有使用矛攻杀齐军,所以能攻破齐军。孔子说:“这是合于道义的。” +夏季,陈国的辕颇逃亡到郑国。当初,辕颇做司徒,对封邑内的土田征收赋税为哀公的女儿出嫁之用;还有剩余的,就用来为自己铸造钟鼎。国内的人们驱逐他,所以出国。在路上口渴,他的部下辕咺奉上甜酒、小米干饭、腌肉干。辕颇高兴地说:“为什么这样丰盛?”辕咺回答说:“器物铸成就准备食物了。”辕颇说:“为什么不劝阻我?”辕咺回答说:“怕被你先赶走。” +为了在郊外作战的缘故,鲁哀公会合吴王进攻齐国。五月,攻下博地。二十五日到达嬴地,中军跟随吴王,胥门率领上军,王子姑曹率领下军,展如率领右军,齐国的国书率领中军,高无邳率领上军,宗楼率领下军。陈僖子对他的弟弟陈书说:“你要是战死,我一定能够得志。”宗子阳和闾丘明也互相勉励。桑掩胥为国书驾御战车。公孙夏说:“这两个人必然战死。”将要开始战斗,公孙夏命令他的部下唱《虞殡》,陈子行命令他的部下准备好含玉。公孙挥命令他的部下说:“每人拿一根八尺的绳子,吴国人头发短。”东郭书说:“打了三次仗,一定得战死,在这里是第三次了。”东郭书派人拿琴做礼品去问候弦多,说:“我不会再见到您了。”陈书说:“这次去,我只能听进军的鼓声,听不到退军的金声了。” +五月二十七日,两军在艾陵作战。展如打败高无邳,国书打败胥门巢。吴王率领的部队救助胥门巢,大败齐军,俘虏了国书、公孙夏、闾丘明、陈书、东郭书,革车八百辆,甲士的脑袋三千个,用来献给哀公。快要进入战斗,吴王喊叔孙说:“你担任什么职务?”叔孙说:“司马。”吴王把甲、剑、铍赐给他,说:“认真地承担你国君交给的任务,不要废弃命令。”叔孙不知该如何回答,子贡走在前面,说:“州仇敬受皮甲跟随着您。”叔孙叩头接受了赏赐。哀公派太史送回国书的头,放在新的筐里,下面垫上黑色和红色的丝绸,加上绸带,在上面放上一封信,说:“上天如果不了解你们的行为不正,怎么能让下国得胜?” +吴国将要攻打齐国,越王率领他的部下前去朝见,吴王和臣下都赠送食物财礼。吴国人都很高兴,惟独伍子胥感到忧惧,说:“这是在豢养吴国的骄气啊!”就劝谏说:“越国在我们这里,是心腹中的一个病,同处在一块土地上而对我们有所要求。他们的驯服,是为了要求达到他们的欲望,我们不如早点下手。在齐国如愿以偿,就好像得到了石头田一样,没法使用。我们不把越国变成池沼,吴国就会被灭掉了,好比让医生治病,而说‘一定要留下病根’,是从来没有的。《尚书》的《盘庚》篇告诫说,‘如果有猖狂捣乱不顺从命令的,就统统铲除不留后患,不要让他们的种族延长下去’,这就是商朝所以兴起的原因。现在您的做法相反,想要用这种办法来求得称霸的大业,不是太困难了吗?”吴王夫差不听,派伍子胥到齐国去。伍子胥把儿子托付给齐国的鲍氏,改姓王孙氏。伍子胥从齐国回来,吴王听说这件事,便派人把属镂宝剑赐给伍子胥让他自杀。伍子胥临死的时候说:“在我的坟墓上种植檟树,檟树可以成材。吴国大概就要灭亡了吧!三年以后,吴国就要开始衰弱了。骄傲自满必然失败,这是自然的道理啊。” +秋季,季孙命令整顿防务,说:“小国战胜大国,这是祸患,齐国没有几天就会来到的。” +冬季,卫国的太叔疾逃亡到宋国。当初,太叔疾娶了宋国子朝的女儿,她的妹妹受到宠爱。子朝逃亡出国,孔文子让太叔疾休弃了他的妻子,而把女儿嫁给他。太叔疾派随从引诱他前妻的妹妹,把她安置在犁地而为她造了一所房子,好像有两个妻子一样。孔文子发怒,想要攻打太叔疾,孔子加以劝阻,孔文子就夺回了女儿,太叔疾又在外州和另外一个女人通奸,外州人夺走了他的车子献给国君。太叔疾为这两件事情感到羞耻,所以逃亡出国。卫国人立了遗做继承人,让他娶了孔姞。太叔疾做了向魋的家臣,把珍珠献给向魋,向魋赠给他城鉏。宋景公索取这珍珠,向魋不给,因此得罪了宋景公。等到桓氏逃亡出国,城鉏人攻打太叔疾,卫庄公又让他回卫国去,让他待在巢地,死在那里。棺材停放在郧地,安葬在少禘。 +当初,晋悼公的儿子慭逃亡在卫国,让他的女儿为他驾车打猎。太叔懿子留他喝酒,就聘他的女儿做妻子,生了悼子。悼子即位,所以夏戊做了大夫。悼子逃亡,卫国削去夏戊的官爵和封邑。 +孔文子将要攻打太叔的时候,去征求孔子的意见,孔子说:“祭祀的事情,那是我曾经学过的;打仗的事情,我没有听说过。”退下去,叫人套上车子就走,说:“鸟可以选择树木,树木哪里能选择鸟?”孔文子立刻阻止他,说:“圉哪里敢自己打算,为的是防止卫国的祸患。”孔子打算留下来,鲁国人用财礼来召请他,于是就回到鲁国。 +季孙想要按田亩征税,派冉有征求孔子的意见。孔子说:“丘不懂得这个。”问了三次,最后说:“您是国家的元老,等着您的意见办事,为什么您不说话呢?”孔子不作正式答复,私下对冉有说:“君子推行政事,要根据礼来衡量:施舍要力求丰厚,事情要做得适当,赋敛要尽量微薄。如果这样,那么照我看来也就够了。如果不根据礼来衡量,而贪婪没有满足,那么虽然按田亩征税,还会不够的。而且季孙如果要办事合于法度,那么周公的典章就在那里。如果要随便办事,又何必征求意见呢?”季孙不听。 + +哀公十二年 +【经】十有二年春,用田赋。夏五月甲辰,孟子卒。公会吴于皋阜。秋,公会卫侯、宋皇瑗于郧。宋向巢帅师伐郑。冬十有二月,螽。 +【传】十二年春,王正月,用田赋。 +夏五月,昭夫人孟子卒。昭公娶于吴,故不书姓。死不赴,故不称夫人。不反哭,故言不葬小君。孔子与吊,适季氏。季氏不絻,放絰而拜。 +公会吴于橐皋。吴子使大宰嚭请寻盟。公不欲,使子贡对曰:“盟所以周信也,故心以制之,玉帛以奉之,言以结之,明神以要之。寡君以为苟有盟焉,弗可改也已。若犹可改,日盟何益?今吾子曰:‘必寻盟。’若可寻也,亦可寒也。”乃不寻盟。 +吴征会于卫。初,卫人杀吴行人且姚而惧,谋于行人子羽。子羽曰:“吴方无道,无乃辱吾君,不如止也。”子木曰:“吴方无道,国无道,必弃疾于人。吴虽无道,犹足以患卫。往也。长木之毙,无不噬也。国狗之□,无不噬也。而况大国乎?” +秋,卫侯会吴于郧。公及卫侯、宋皇瑗盟,而卒辞吴盟。吴人藩卫侯之舍。子服景伯谓子贡曰:“夫诸侯之会,事既毕矣,侯伯致礼,地主归饩,以相辞也。今吴不行礼于卫,而藩其君舍以难之,子盍见大宰?”乃请束锦以行。语及卫故,大宰嚭曰:“寡君愿事卫君,卫君之来也缓,寡君惧,故将止之。”子贡曰:“卫君之来,必谋于其众。其众或欲或否,是以缓来。其欲来者,子之党也。其不欲来者,子之仇也。若执卫君,是堕党而崇仇也。夫堕子者得其志矣!且合诸侯而执卫君,谁敢不惧?堕党崇仇,而惧诸侯,或者难以霸乎!”大宰嚭说,乃舍卫侯。卫侯归,效夷言。子之尚幼,曰:“君必不免,其死于夷乎!执焉,而又说其言,从之固矣。” +冬十二月,螽。季孙问诸仲尼,仲尼曰:“丘闻之,火伏而后蜇者毕。今火犹西流,司历过也。” +宋郑之间有隙地焉,曰弥作、顷丘、玉畅、岩、戈、锡。子产与宋人为成,曰:“勿有是。”及宋平、元之族自萧奔郑,郑人为之城岩、戈、锡。九月,宋向巢伐郑,取锡,杀元公之孙,遂围岩。十二月,郑罕达救岩。丙申,围宋师。 +译文 +十二年春季,周王朝历法的正月,采用按田亩征税的制度。 +夏季,五月,鲁昭公夫人孟子死了。昭公在吴国娶妻,所以《春秋》不记载孟子的姓。死了没有发讣告,所以不称夫人。安葬以后没有回到祖庙号哭,所以不说葬小君。孔子参加吊唁,到了季氏那里。季氏不脱帽,孔子除掉丧服下拜。 +哀公在橐皋会见吴国人,吴王派太宰嚭请求重温过去的盟约。哀公不愿意,派子贡回答说:“盟誓,是用来巩固信用的,所以用诚心来约束它,用玉帛来奉献它,用言语来完成它,用神明来保证它。寡君认为如果有了盟约,就不能更改了。如果还是可以更改,每天盟誓又有什么好处?现在您说‘一定要重温过去的盟约’,如果可以重温,它同样可以寒凉下去的。”于是就没有重温盟约。 +吴国召集卫国参加诸侯会见。当初,卫国人杀了吴国的行人且姚因而害怕,就和行人子羽商量。子羽说:“吴国正在无道的时候,恐怕会羞辱我们国君。不如不做。”子木说:“吴国正在无道的时候,国家无道,必然加害于人。吴国即使无道,还足以祸害卫国。去吧!高大的树倒下,遇到的东西没有不受打击的;最好的狗发疯,没有不咬人的,而何况是大国呢?” +秋季,卫出公在郧地会见吴人。哀公和卫出公、宋国皇瑷结盟,而终于辞谢了和吴国结盟。吴国人围住了卫出公的馆舍。子服景伯对子贡说:“诸侯的会见,事情完了,盟主礼宾,所在地的主人馈送食物,以此互相辞别。现在吴国对卫国不执行礼节,反而围住他们国君的馆舍使他为难,您何不去见太宰?”子贡请求给了他五匹锦,就去了。谈到卫国的事情,太宰嚭说:“寡君愿意事奉卫国国君,但是他来晚了,寡君害怕,所以要把他留下。”子贡说:“卫君前来,一定和他的臣下们商量,那些人有的同意他来,有的不同意他来,因此才来晚了。那些同意的人,是您的朋友。那些不同意的人,是您的仇人。如果拘禁了卫国国君,这是毁了朋友而抬高了仇人,那些想毁坏您的人就得意了,而且会合诸侯却拘留了卫国国君,谁敢不怕?毁坏了朋友,抬高了仇人,而又让诸侯害怕,也许难于称霸吧!”太宰嚭高兴了,就释放了卫出公。卫出公回国,学着说夷人的话,子之当时还年幼,说:“国君必定不能免于祸难,恐怕会死在夷人那里吧!被他们拘禁还喜欢学他们的话,跟他们走是必然的了。” +冬季,十二月,蝗虫成灾。季孙向孔子询问这件事。孔子说:“丘听说,大火星下沉以后昆虫都蛰伏完毕。现在大火星还经过西方,这是司历官的过错。” +宋国和郑国之间有些空地,名叫弥作、顷丘、玉畅、嵒、戈、钖。子产和宋国人讲和,说“不要这些地方了。”等到宋国平公、元公的族人从萧地逃亡到郑国,郑国人为他们在嵒地、戈地、钖地筑了城。九月,宋国的向巢进攻郑国,占领了钖地,杀死了元公的孙子,并进而包围了嵒地十二月,郑国的罕达救援嵒地。二十八日,包围了宋军。 + +哀公十三年 +【经】十有三年春,郑罕达帅师取宋师于岩。夏,许男成卒。公会晋侯及吴子于黄池。楚公子申帅师伐陈。于越入吴。秋,公至自会。晋魏曼多帅师侵卫。葬许元公。九月,螽。冬十有一月,有星孛于东方。盗杀陈夏区夫。十有二月,螽。 +【传】十三年春,宋向魋救其师。郑子剩使徇曰:“得桓魋者有赏。”魋也逃归,遂取宋师于岩,获成讙、郜延。以六邑为虚。 +夏,公会单平公、晋定公、吴夫差于黄池。 +六月丙子,越子伐吴,为二隧。畴无馀、讴阳自南方,先及郊。吴大子友、王子地、王孙弥庸、寿于姚自泓上观之。弥庸见姑蔑之旗,曰:“吾父之旗也。不可以见仇而弗杀也。”大子曰:“战而不克,将亡国。请待之。”弥庸不可,属徒五千,王子地助之。乙酉,战,弥庸获畴无馀,地获讴阳。越子至,王子地守。丙戌,复战,大败吴师。获大子友、王孙弥庸、寿于姚。丁亥,入吴。吴人告败于王,王恶其闻也,自刭七人于幕下。 +秋七月辛丑,盟,吴、晋争先。吴人曰:“于周室,我为长。”晋人曰:“于姬姓,我为伯。”赵鞅呼司马寅曰:“日旰矣,大事未成,二臣之罪也。建鼓整列,二臣死之,长幼必可知也。”对曰:“请姑视之。”反,曰:“肉食者无墨。今吴王有墨,国胜乎?大子死乎?且夷德轻,不忍久,请少待之。”乃先晋人。吴人将以公见晋侯,子服景伯对使者曰:“王合诸侯,则伯帅侯牧以见于王。伯合诸侯,则侯帅子男以见于伯。自王以下,朝聘玉帛不同。故敝邑之职贡于吴,有丰于晋,无不及焉,以为伯也。今诸侯会,而君将以寡君见晋君,则晋成为伯矣,敝邑将改职贡。鲁赋于吴八百乘,若为子男,则将半邾以属于吴,而如邾以事晋。且执事以伯召诸侯,而以侯终之,何利之有焉?”吴人乃止。既而悔之,将囚景伯,景伯曰:“何也立后于鲁矣。将以二乘与六人从,迟速唯命。”遂囚以还。及户牖,谓大宰曰:“鲁将以十月上辛,有事于上帝先王,季辛而毕。何世有职焉,自襄以来,未之改也。若不会,祝宗将曰:‘吴实然。’且谓鲁不共,而执其贱者七人,何损焉?”大宰嚭言于王曰:“无损于鲁,而只为名,不如归之。”乃归景伯。 +吴申叔仪乞粮于公孙有山氏,曰:“佩玉、忌兮,余无所系之。旨酒一盛兮,余与褐之父睨之。”对曰:“梁则无矣,粗则有之。若登首山以呼曰:‘庚癸乎!’则诺。” +王欲伐宋,杀其丈夫而囚其妇人。大宰嚭曰:“可胜也,而弗能居也。”乃归。 +冬,吴及越平。 +译文 +十三年春季,宋国的向魋救援他们的军队。郑国的武子魋派人通告全军说:“抓到向魋的有赏。”向魋就逃走回国。郑军就在嵒地全部歼灭宋军,俘虏了成讙郜延,把六个城邑掳掠一空,然后两国都不加管辖。 +夏季,哀公在黄池会见单平公、晋定公、吴王夫差。 +六月十一日,越王攻打吴国,兵分两路,越国的畴无馀、讴阳从南边走,先到达吴国国都的郊区。吴国的太子友、王子地、王孙弥庸、寿於姚在泓水上观察越军。弥庸见到姑蔑的旗帜,说:“那是我父亲的旗帜。我不能见到仇人而不杀死他们。”太子友说:“如果作战不能取胜,将会亡国,请等一等。”王孙弥庸不同意,集合部下五千人出战,王子地帮助他。二十日,两军交战,弥庸俘虏了畴无馀,王子地俘虏了讴阳。越王勾践率军到达,王子地防守。二十一日,再次交战,越军大败吴军,俘虏了太子友、王孙弥庸、寿於姚。二十二日,越军进入吴国。吴国人向吴王报告战败。吴王深恐诸侯听到这个消息,亲自把七个报信的吴人杀死在帐幕里边。 +秋季,七月初六日,吴国和晋国争执歃血的先后。吴国人说:“在周王室中,我们是老大。”晋国人说:“在姬姓之中,我们为首。”赵鞅对司马寅说:“天已晚了,大事没有成功,是我们两个臣下的罪过。竖起旗帜整顿队列,我们两人战斗到死,次序先后就可以定了。”司马寅说:“请姑且到吴营那里观察一下。”回来,说:“高贵的人的脸色没有灰暗无神的。现在吴王面色灰暗,是他的国家被敌人战胜了吗?或许是太子死了吧?而且夷人轻佻不沉着,不能长久忍耐,请稍等一等。”吴国人就让晋国人先歃血。 +吴国人要带领哀公进见晋定公,子服景伯对使者说:“天子会合诸侯,那么诸侯之长就率领诸侯进见天子;诸侯之长会合诸侯,那么侯就率领子、男进见诸侯领袖。从天子以下,朝聘时所用的玉帛也不相同。所以敝邑进贡给吴国的,要比晋国丰厚,而没有不如的,因为把吴国作为诸侯的领袖。现在诸侯会见,而君王准备带领寡君进见晋君,那么晋国就成为诸侯的领袖了,敝邑将会改变进贡的数量:鲁国进贡按八百辆战车给贵国,如果变成子、男,那么将会按邾国战车的一半作为贡品,而按邾国战车的数来事奉晋国。而且执事以诸侯之长的身分召集诸侯,而以一般诸侯的身分结束,这有什么好处呢?”吴国人就没有那么做。不久又后悔了,准备囚禁景伯。景伯说:“何已经在鲁国立了继承人了,打算带两辆车子和六个人跟随去,早走晚走听你们的命令。”吴国人就囚禁了景伯,带回去。到达户牖,景伯对太宰说:“鲁国将要在十月的第一个辛日祭祀天帝和先王,最后一个辛日完毕。何世世代代都在祭祀中担任一定的职务,从鲁襄公以来没有改变过。如果我不参加,祝宗将会说‘是吴国让他这样的’,而且贵国认为鲁国不恭敬,而只逮捕了他们七个卑微的人,对鲁国有什么损害呢?”太宰嚭对吴王说:“对鲁国没有损害,而只能造成坏名声,不如放他回去。”于是就放回了景伯。 +吴国的申叔仪到公孙有山氏那里讨粮食,说:“佩玉垂下来啊,我没有地方系住;甜酒一杯啊,我和贫苦的老头斜视着。”公孙有山氏回答说:“细粮已经没了,粗粮还有一些。如果你登上首山喊‘下等货啊’,就答应你。” +吴王夫差想要攻打宋国,准备杀死那里的男人而囚禁妇女,太宰嚭说:“我们虽然可以战胜,但不能在那里久留。”吴王这才回国。 +冬季,吴国和越国讲和。 + +哀公十四年 +【经】十有四年春,西狩获麟。小邾射以句绎来奔。夏四月,齐陈心互执其君,置于舒州。庚戌,叔还卒。五月庚申朔,日有食之。陈宗竖出奔楚。宋向魋入于曹以叛。莒子狂卒。六月,宋向魋自曹出奔卫。宋向巢来奔。齐人弑其君壬于舒州。秋,晋赵鞅帅师伐卫。八月辛丑,仲孙何忌卒。冬,陈宗竖自楚复入于陈,陈人杀之。陈辕买出奔楚。有星孛。饥。 +【传】十四年春,西狩于大野,叔孙氏之车子锄商获麟,以为不祥,以赐虞人。仲尼观之,曰:“麟也。”然后取之。 +小邾射以句绎来奔,曰:“使季路要我,吾无盟矣。”使子路,子路辞。季康子使冉有谓之曰:“千乘之国,不信其盟,而信子之言,子何辱焉?”对曰:“鲁有事于小邾,不敢问故,死其城下可也。彼不臣而济其言,是义之也。由弗能。” +齐简公之在鲁也,阚止有宠焉。及即位,使为政。陈成子惮之,骤顾诸朝。诸御鞅言于公曰:“陈、阚不可并也,君其择焉。”弗听。子我夕,陈逆杀人,逢之,遂执以入。陈氏方睦,使疾,而遗之潘沐,备酒肉焉,飨守囚者,醉而杀之,而逃。子我盟诸陈于陈宗。 +初,陈豹欲为子我臣,使公孙言己,已有丧而止。既,而言之,曰:“有陈豹者,长而上偻,望视,事君子必得志,欲为子臣。吾惮其为人也,故缓以告。”子我曰:“何害?是其在我也。”使为臣。他日,与之言政,说,遂有宠,谓之曰:“我尽逐陈氏,而立女,若何?”对曰:“我远于陈氏矣。且其违者,不过数人,何尽逐焉?”遂告陈氏。子行曰:“彼得君,弗先,必祸子。”子行舍于公宫。 +夏五月壬申,成子兄弟四乘如公。子我在幄,出,逆之。遂入,闭门。侍人御之,子行杀侍人。公与妇人饮酒于檀台,成子迁诸寝。公执戈,将击之。大史子余曰:“非不利也,将除害也。”成子出舍于库,闻公犹怒,将出,曰:“何所无君?”子行抽剑,曰:“需,事之贼也。谁非陈宗?所不杀子者,有如陈宗!”乃止。子我归,属徒,攻闱与大门,皆不胜,乃出。陈氏追之,失道于弇中,适丰丘。丰丘人执之,以告,杀诸郭关。成子将杀大陆子方,陈逆请而免之。以公命取车于道,及耏,众知而东之。出雍门,陈豹与之车,弗受,曰:“逆为余请,豹与余车,余有私焉。事子我而有私于其仇,何以见鲁、卫之士?”东郭贾奔卫。 +庚辰,陈恒执公于舒州。公曰:“吾早从鞅之言,不及此。” +宋桓魋之宠害于公,公使夫人骤请享焉,而将讨之。未及,魋先谋公,请以鞍易薄,公曰:“不可。薄,宗邑也。”乃益鞍七邑,而请享公焉。以日中为期,家备尽往。公知之,告皇野曰:“余长魋也,今将祸余,请即救。”司马子仲曰:“有臣不顺,神之所恶也,而况人乎?敢不承命。不得左师不可,请以君命召之。”左师每食击钟。闻钟声,公曰:“夫子将食。”既食,又奏。公曰:“可矣。”以乘车往,曰:“迹人来告曰:‘逢泽有介麇焉。’公曰:‘虽魋未来,得左师,吾与之田,若何?’君惮告子。野曰:‘尝私焉。’君欲速,故以乘车逆子。”与之乘,至,公告之故,拜,不能起。司马曰:“君与之言。”公曰:“所难子者,上有天,下有先君。”对曰:“魋之不共,宋之祸也,敢不唯命是听。”司马请瑞焉,以命其徒攻桓氏。其父兄故臣曰:“不可。”其新臣曰:“从吾君之命。”遂攻之。子颀骋而告桓司马。司马欲入,子车止之,曰:“不能事君,而又伐国,民不与也,只取死焉。”向魋遂入于曹以叛。六月,使左师巢伐之。欲质大夫以入焉,不能。亦入于曹,取质。魋曰:“不可。既不能事君,又得罪于民,将若之何?”乃舍之。民遂叛之。向魋奔卫。向巢来奔,宋公使止之,曰:“寡人与子有言矣,不可以绝向氏之祀。”辞曰:“臣之罪大,尽灭桓氏可也。若以先臣之故,而使有后,君之惠也。若臣,则不可以入矣。” +司马牛致其邑与珪焉,而适齐。向魋出于卫地,公文氏攻之,求夏后氏之璜焉。与之他玉,而奔齐,陈成子使为次卿。司马牛又致其邑焉,而适吴。吴人恶之,而反。赵简子召之,陈成子亦召之。卒于鲁郭门之外,阬氏葬诸丘舆。 +甲午,齐陈恒弑其君壬于舒州。孔丘三日齐,而请伐齐三。公曰:“鲁为齐弱久矣,子之伐之,将若之何?”对曰:“陈恒弑其君,民之不与者半。以鲁之众,加齐之半,可克也。”公曰:“子告季孙。”孔子辞。退而告人曰:“吾以从大夫之后也,故不敢不言。” +初,孟孺子泄将圉马于成。成宰公孙宿不受,曰:“孟孙为成之病,不圉马焉。”孺子怒,袭成。从者不得入,乃反。成有司使,孺子鞭之。秋八月辛丑,孟懿子卒。成人奔丧,弗内。袒免哭于衢,听共,弗许。惧,不归。 +译文 +十四年春季,在西部的大野打猎,叔孙氏的驾车人子鉏商猎获一只麒麟,认为不吉利,赏赐给管山林的人。孔子细看后,说“这是麒麟”,然后收下它。 +小邾国的射献上句绎逃亡到鲁国来,说:“派季路和我约定,可以不用盟誓了。”派子路去,子路推辞。季康子派冉有对子路说:“一千辆战车的国家,不相信盟誓,反而相信您的话,您有什么屈辱呢?”子路回答说:“鲁国如果和小邾国发生战事,我不敢询问原因曲直,战死在城下就行了。他不尽臣道,而使他的话得以实现,这是把他的不尽臣道当成正义了,我不能那么办。” +齐简公在鲁国的时候,阚止受到宠信。等到简公即位,就让阚止执政。陈成子惧怕他,在朝廷上屡次回头看他。御者鞅对齐简公说:“陈氏、阚氏不能并列,你还是选择一个。”齐简公不听。 +阚止晚上朝见齐简公,陈逆杀人,阚止碰见,就把他逮捕,带进公宫。陈氏一族正好和睦团结,族人就让陈逆假装生病,并送去洗头的淘米水,备有酒肉。陈逆请看守的人吃喝,看守喝醉以后陈逆就杀了他,然后逃走,阚止和陈氏族人在陈氏宗主家里结盟。 +当初,陈豹想要当阚止的家臣,让公孙推荐自己。不久陈豹有丧事,就停下来,丧事完了,公孙又对阚止谈起这件事说:“有一个叫陈豹的人,身高背驼,眼睛仰视,事奉君子一定能让人满意,想要当您的家臣。我怕他人品不好,所以没有立即告诉您。”阚止说“这有什么害处?这都在于我。”就要陈豹做了家臣。过了些日子,阚止和他谈政事,很高兴,于是就宠信他。阚止对陈豹说:“我把陈氏全部驱逐而立你做继承人,怎么样?”陈豹回答说:“我在陈氏族中是远支,而且他们不服从的不过几个人,为什么要把他们全部驱逐呢?”就把话告诉了陈氏,子行对陈成子说:“他得到国君信任,不先下手,必然要加祸于您。”子行就在公宫里住下。 +夏季,五月十三日,成子兄弟四人坐车到齐简公那里去。阚止正在帐幕里,出来迎接他们,成子兄弟就走进去,把阚止关在门外。侍者抵御他们,子行杀了侍者。齐简公和女人在檀台上喝酒,成子要让他迁到寝室里去。简公拿起戈,就要击打他们。太史子馀说:“不是要对国君不利,而是要除掉有害的人。”成子搬出去住在府库里,听说简公还在生气,就准备逃亡,说:“哪个地方没有国君?”子行抽出剑,说:“迟疑软弱,反害大事。您要走了,谁不能做陈氏的宗主?您走,我要是不杀您,有历代宗主为证!”陈成子就不出走了。 +阚止回去,集合部下,攻打宫墙的小门和大门,都没有得胜就逃走了。陈氏追赶他,阚止在弇中迷了路,到了丰丘。丰丘人拘捕他,报告陈成子,把他杀死在外城城关。陈成子准备杀大陆子方,陈逆请求而赦免了。子方用简公的名义在路上得到一辆车,到达耏地,大家发现了就逼他向东去。出了雍门,陈豹给他车子,他不接受,说:“逆为我请求,豹给我车子,我和他们有私交。事奉子我而和他的仇人有私交,怎么能和鲁国、卫国人士相见?”子方就逃亡到卫国。二十一日,陈成子在舒州拘捕了齐简公。简公说:“我要早听了御鞅的话,不会到这一地步。” +宋国桓魋受宠而扩充势力,发展到损害宋景公。宋景公让夫人突然邀请桓魋参加享礼,准备乘机讨伐他,还没有来得及,桓魋先打宋景公的主意,请求用鞌地交换薄地。宋景公说:“不行,薄地,是宋国殷商祖庙的所在地。”于是就把七个城邑并入鞌地,而请求设享礼答谢宋景公,以太阳正中作为期限,私家的武装全都开去了。宋景公知道了,告诉皇野说:“我把桓魋养育大了,现在他要加祸于我,请马上救我。”皇野说:“臣下不服从,这是神明都厌恶的,何况人呢?岂敢不接受命令。但不得到左师的同意是不行的,请用您的名义召见他。”左师每次吃饭,要敲打乐钟。听到钟声,宋景公说:“那一位快要吃饭了。”吃完饭以后,又奏乐。宋景公说:“行了。”皇野坐一辆车子去了,说:“猎场的人来报告说:‘逢泽有一只麋鹿。’国君说:‘即使桓魋没有来,有了左师,我和他一起打猎,怎么样?’国君难于直接告诉您,野说:‘我试着私下和他谈谈。’国君想要快一点,所以用一辆车子来接您。”左师和皇野同乘一辆车,到达,宋景公把原因告诉他,左师下拜,不能起立。皇野说:“君王和他盟誓。”宋景公说:“如果要使您遭到祸难,上有天,下有先君。”左师回答说:“魋不恭敬,这是宋国的祸患。岂敢不唯命是听。”皇野请求兵符,以命令他的部下攻打桓魋。他的父老兄长和旧臣说:“不行。”他的新臣说:“服从我们国君的命令。”皇野就进攻。子颀纵马奔告桓魋。桓魋想要往宫里攻打宋景公,子车劝阻他,说:“不能事奉国君,而又要攻打公室,百姓是不会亲附你的,只能找死。”桓魋就进入曹地叛变。六月,宋景公派左师巢攻打桓魋,左师想要得到大夫做人质而回来,没有办到,也进入曹地,取得人质。桓魋说:“不行,既不能事奉国君,又得罪了百姓,打算怎么办?”于是就释放了人质,百姓就背叛了他们。桓魋逃亡到卫国。向巢逃亡到鲁国来,宋景公派人留下他,说:“我跟您有盟誓了,不能断绝向氏的祭祀。”向巢辞谢说:“我的罪过大,君王把桓氏全部灭亡也是可以的。如果由于先臣的缘故,而让桓氏有继承人,这是君王的恩惠。像我,那就不能再回来了。” +司马牛把他的封邑和玉圭交还给宋景公,就到了齐国。桓魋逃亡到卫国,公文氏攻打他,向他索取夏后氏的玉璜。桓魋给了公文氏别的玉,就逃亡到齐国,陈成子让桓魋做次卿,司马牛又把封邑交还齐国而去到吴国,吴国人讨厌他,他就回到宋国。晋国的赵简子召唤他去,齐国的陈成子也召唤他去,在途中死在鲁国国都的外城门外,阬氏把他葬在丘舆。 +六月初五,齐国的陈桓在舒州杀了他们的国君壬。孔子斋戒三天,三次请求攻打齐国。哀公说:“鲁国被齐国削弱已经很久了,您攻打他们,打算怎么办?”孔子回答说:“陈桓杀了他们的国君,百姓不亲附他的有一半。以鲁国的群众加上齐国不服从陈桓的一半,是可以战胜的。”哀公说:“您告诉季孙。”孔子辞谢,退下去告诉别人说:“我由于曾经列于大夫之末,所以不敢不说话。” +当初,孟孺子泄准备在成地养马,成地的宰臣公孙宿不接受,说:“孟孙由于成地百姓贫困,不在这里养马。”孺子发怒,侵袭成地,跟从的人们没能攻入,就回去了。成地的官员派人去,孺子鞭打了来人。秋季,八月十三日,孟懿子死了。成地的人去奔丧,孺子不接纳。成地的人脱去上衣、帽子而在大路上号哭,表示愿供驱使,孺子不答应。成地的人害怕,不敢回成地。 + +哀公十五年 +【经】十有五年春王正月,成叛。夏五月,齐高无ぶ出奔北燕。郑伯伐宋。秋八月,大雩。晋赵鞅帅师伐卫。冬,晋侯伐郑。及齐平。卫公孟彄出奔齐。 +【传】十五年春,成叛于齐。武伯伐成,不克,遂城输。 +夏,楚子西、子期伐吴,乃桐汭。陈侯使公孙贞子吊焉,及良而卒,将以尸入。吴子使大宰嚭劳,且辞曰:“以水潦之不时,无乃廪然陨大夫之尸,以重寡君之忧。寡君敢辞。”上介芋尹盖对曰:“寡君闻楚为不道,荐伐吴国,灭厥民人。寡君使盖备使,吊君之下吏。无禄,使人逢天之戚,大命陨队,绝世于良,废日共积,一日迁次。今君命逆使人曰:‘无以尸造于门。’是我寡君之命委于草莽也。且臣闻之曰:‘事死如事生,礼也。’于是乎有朝聘而终,以尸将事之礼。又有朝聘而遭丧之礼。若不以尸将命,是遭丧而还也,无乃不可乎!以礼防民,犹或逾之。今大夫曰:‘死而弃之’,是弃礼也。其何以为诸侯主?先民有言曰:‘无秽虐士。’备使奉尸将命,苟我寡君之命达于君所,虽陨于深渊,则天命也,非君与涉人之过也。”吴人内之。 +秋,齐陈瓘如楚。过卫,仲田见之,曰:“天或者以陈氏为斧斤,既斫丧公室,而他人有之,不可知也。其使终飨之,亦不可知也。若善鲁以待时,不亦可乎?何必恶焉?”子玉曰:“然,吾受命矣,子使告我弟。” +冬,及齐平。子服景伯如齐,子赣为介,见公孙成,曰:“人皆臣人,而有背人之心。况齐人虽为子役,其有不贰乎?子,周公之孙也,多飨大利,犹思不义。利不可得,而丧宗国,将焉用之?”成曰:“善哉!吾不早闻命。” +陈成子馆客,曰:“寡君使恒告曰:‘寡君愿事君如事卫君。’”景伯揖子赣而进之。对曰:“寡君之愿也。昔晋人伐卫,齐为卫故,伐晋冠氏,丧车五百,因与卫地,自济以西,禚、媚、杏以南,书社五百。吴人加敝邑以乱,齐因其病,取讙与阐。寡君是以寒心。若得视卫君之事君也,则固所愿也。”成子病之,乃归成。公孙宿以其兵甲入于嬴。 +卫孔圉取大子蒯聩之姊,生悝。孔氏之竖浑良夫长而美,孔文子卒,通于内。大子在戚,孔姬使之焉。大子与之言曰:“苟使我入获国,服冕乘轩,三死无与。”与之盟,为请于伯姬。 +闰月,良夫与大子入,舍于孔氏之外圃。昏,二人蒙衣而乘,寺人罗御,如孔氏。孔氏之老栾宁问之,称姻妾以告。遂入,适伯姬氏。既食,孔伯姬杖戈而先,大子与五人介,舆豭从之。迫孔悝于厕,强盟之,遂劫以登台。栾宁将饮酒,炙未熟,闻乱,使告季子。召获驾乘车,行爵食炙,奉卫侯辄来奔。季子将入,遇子羔将出,曰:“门已闭矣。”季子曰:“吾姑至焉。”子羔曰:“弗及,不践其难。”季子曰:“食焉,不辟其难。”子羔遂出。子路入,及门,公孙敢门焉,曰:“无入为也。”季子曰:“是公孙,求利焉而逃其难。由不然,利其禄,必救其患。”有使者出,乃入。曰:“大子焉用孔悝?虽杀之,必或继之。”且曰:“大子无勇,若燔台,半,必舍孔叔。”大子闻之,惧,下石乞、盂□敌子路。以戈击之,断缨。子路曰:“君子死,冠不免。”结缨而死。孔子闻卫乱,曰:“柴也其来,由也死矣。”孔悝立庄公。庄公害故政,欲尽去之,先谓司徒瞒成曰:“寡人离病于外久矣,子请亦尝之。”归告褚师比,欲与之伐公,不果。 +译文 +十五年春季,成地背叛孟氏而投靠齐国。孟武伯攻打成地,没有攻下,于是就在输地筑城。 +夏季,楚国的子西、子期攻打吴国,到达桐汭,陈闵公派公孙贞子去吴国慰问,到达良地就死了,副使准备把灵柩运进城里。吴王派太宰嚭慰劳,而且辞谢说:“由于雨水不调和,恐怕大水泛滥而毁坏大夫的灵柩,增加寡君的忧虑,寡君谨此辞谢。”第一副使芋尹盖回答说:“寡君听说楚国无道,屡次攻打吴国,消灭你们百姓,寡君派盖备充使臣的行列,向贵君的下级官吏慰问。不幸,使臣正逢上天的忧戚,丧了性命,在良地去世。我们耗费时间积聚殡敛的财物,又怕耽误使命,每天变换住地,加紧赶路。现在您命令迎接使臣说‘不要让灵柩到城门上来’,这就把寡君的命令,丢弃在杂草丛中了。而且下臣听说,‘事奉死人像事奉活人一样,这是礼’,因此而有了在朝聘过程中使臣死去、奉着灵柩完成使命的礼仪,同时又有在进聘过程中,遇到受聘国家发生丧事的礼仪。如果不奉灵柩完成使命,这就像是遇到受聘国家发生丧事而回国一样了,恐怕不可以吧!用礼仪来防止百姓,还恐怕有所逾越,现在您说‘死了就丢弃他’,这是丢掉礼仪,还怎么能当诸侯的盟主?从前的人有话说:‘不要把死者看成污秽。’我奉着灵柩完成使命,如果我们寡君的命令能上达于贵君那里,即使坠入深渊,那么也是上天的意志,不是贵君和划船人的过错。”吴国人接纳了他们和灵柩。 +秋季,齐国的陈瓘到楚国去,经过卫国,仲由拜见他,说:“上天或许是用陈氏作为斧子,把公室砍削以后又为别人所有,现在不能知道,可能让陈氏最后享有,现在也不能知道。如果和鲁国友好以等待时机,不也是可以的吗?何必搞坏关系呢?”陈瓘说:“对。我接受您的命令了。您派人去告诉我的弟弟。” +冬季,鲁国和齐国讲和。子服景伯到齐国去,子赣做副使,会见公孙成,说:“人们都是别人的臣下,有人还有背叛别人的念头,何况齐国人,虽然为您服役,能没有二心吗?您,是周公的后代,享受到巨大的利益,还想做不义的事情。利益不能得到,反而失掉了祖国,何必这样?”公孙成说:“对啊!我没有早听到您的命令。” +陈成子在宾馆会见客人,说:“寡君派恒报告您说:‘我愿意事奉贵君就像事奉卫君一样。’”景伯向子赣作揖请他走上一步。让子赣回答说:“这正是寡君的愿望。从前晋国人进攻卫国,齐国为了卫国的缘故,进攻晋国的冠氏,丧失了五百辆战车。由于这样就给了卫国土地,从济水以西和禚地、媚地、杏地以南,一共五百个村子。吴国人把动乱加于敝邑,齐国乘敝邑的困难,占取了瓘地和阐地,寡君因此而寒心,如果能像卫君那样事奉贵君,那本来就是我们所希望的。”陈成子感到愧恨,就把成地归还给鲁国。公孙宿带了他的武器装备进入嬴地。 +卫国的孔圉娶了太子蒯聩的姐姐,生了悝。孔氏的童仆浑良夫个子高,并且长得漂亮,孔圉死后,就和孔姬私通。太子在戚地,孔姬派浑良夫前去,太子对他说:“如果让我回国即位,给你大夫的冠服、车子,赦免死罪三次。”浑良夫和太子盟誓,为他向孔姬请求。 +闰十二月,浑良夫和太子回到国都,住在孔氏家外面菜园子里。天黑以后,两个人用头巾盖住脸,寺人罗为他们驾车,到了孔氏家里。孔氏的家臣之长栾宁问他们,他们说是姻戚家的侍妾,就进了门。到了孔姬那里,吃完饭,孔姬手拿着戈走在前面,太子和五个人身披皮甲,用车装上公猪跟着,把孔悝逼到墙边,强迫他盟誓,于是就劫持他登上台去。栾宁正要喝酒,肉没有烤熟,听说有动乱,派人告诉子路,召唤获驾上坐车,在车上喝酒吃肉,事奉卫出公辄逃亡到鲁国来。 +子路正要进入国都,碰上子羔正要出来,说:“城门已经关上了。”子路说:“我还是去一下。”子羔说:“来不及了,不要去遭受祸难!”子路说:“吃了他的俸禄,不应躲避祸难。”子羔就出去,子路进入。到达孔氏大门口;公孙敢在那里守门,说:“不要进去干什么了。”子路说:“这是公孙,在这里谋求利益而躲避祸难。我不是这样,以他的俸禄为利益,就一定要救援他的患难。”有使者从门里出来,子路就乘机进去,说:“太子哪里用得着孔悝作帮手?即使杀了他,一定有人接替他。”而且说:“太子没有勇气,如果放火烧台,烧到一半,必然会释放孔叔。”太子听到了,很害怕,让石乞、盂黡下台和子路搏斗,用戈击中子路,把帽带也斩断了。子路说:“君子死,帽子也不能除掉。”于是子路结好帽带子就死了。孔子听到卫国发生动乱,说“柴能回来,可是由死去了。” +孔悝立了卫庄公。庄公认为原来的大臣都靠不住,想要全部去掉他们,就先对司徒瞒成说:“我在外边遭遇忧患很久了,请您也尝一尝。”瞒成回去告诉褚师比,想要和他攻打庄公,没能实现。 + +哀公十六年 +【经】十有六年春王正月己卯,卫世子蒯聩自戚入于卫,卫侯辄来奔。二月,卫子还成出奔宋。夏四月己丑,孔丘卒。 +【传】十六年春,瞒成、褚师比出奔宋。 +卫侯使鄢武子告于周曰:“蒯聩得罪于君父君母,逋窜于晋。晋以王室之故,不弃兄弟,置诸河上。天诱其衷,获嗣守封焉。使下臣肸敢告执事。”王使单平公对曰:“肸以嘉命来告余一人。往谓叔父,余嘉乃成世,复尔禄次。敬之哉!方天之休,弗敬弗休,悔其可追?” +夏四月己丑,孔丘卒。公诔之曰:“旻天不吊,不憖遗一老。俾屏余一人以在位,茕茕余在疚。呜呼哀哉!尼父。无自律。”子赣曰:“君其不没于鲁乎!夫子之言曰:‘礼失则昏,名失则愆。’失志为昏,失所为愆。生不能用,死而诔之,非礼也。称一人,非名也。君两失之。” +六月,卫侯饮孔悝酒于平阳,重酬之,大夫皆有纳焉。醉而送之,夜半而遣之。载伯姬于平阳而行,及西门,使贰车反祏于西圃。子伯季子初为孔氏臣,新登于公,请追之,遇载祏者,杀而乘其车。许公为反祏,遇之,曰:“与不仁人争明,无不胜。”必使先射,射三发,皆远许为。许为射之,殪。或以其车从,得祏于囊中。孔悝出奔宋。 +楚大子建之遇谗也,自城父奔宋。又辟华氏之乱于郑,郑人甚善之。又适晋,与晋人谋袭郑,乃求复焉。郑人复之如初。晋人使谍于子木,请行而期焉。子木暴虐于其私邑,邑人诉之。郑人省之,得晋谍焉。遂杀子木。其子曰胜,在吴。子西欲召之,叶公曰:“吾闻胜也诈而乱,无乃害乎?”子西曰:“吾闻胜也信而勇,不为不利,舍诸边竟,使卫藩焉。”叶公曰:“周仁之谓信,率义之谓勇。吾闻胜也好复言,而求死士,殆有私乎?复言,非信也。期死,非勇也。子必悔之。”弗从。召之使处吴竟,为白公。请伐郑,子西曰:“楚未节也。不然,吾不忘也。”他日,又请,许之。未起师,晋人伐郑,楚救之,与之盟。胜怒,曰:“郑人在此,仇不远矣。” +胜自厉剑,子期之子平见之,曰:“王孙何自厉也?”曰:“胜以直闻,不告女,庸为直乎?将以杀尔父。”平以告子西。子西曰:“胜如卵,余翼而长之。楚国第,我死,令尹、司马,非胜而谁?”胜闻之,曰:“令尹之狂也!得死,乃非我。”子西不悛。胜谓石乞曰:“王与二卿士,皆五百人当之,则可矣。”乞曰:“不可得也。”曰:“市南有熊宜僚者,若得之,可以当五百人矣。”乃从白公而见之,与之言,说。告之故,辞。承之以剑,不动。胜曰:“不为利谄,不为威惕,不泄人言以求媚者,去之。” +吴人伐慎,白公败之。请以战备献,许之。遂作乱。秋七月,杀子西、子期于朝,而劫惠王。子西以袂掩面而死。子期曰:“昔者吾以力事君,不可以弗终。”抉豫章以杀人而后死。石乞曰:“焚库弑王,不然不济。”白公曰:“不可。弑王,不祥,焚库,无聚,将何以守矣?”乞曰:“有楚国而治其民,以敬事神,可以得祥,且有聚矣,何患?”弗从。叶公在蔡,方城之外皆曰:“可以入矣。”子高曰:“吾闻之,以险侥幸者,其求无餍,偏重必离。”闻其杀齐管修也而后入。 +白公欲以子闾为王,子闾不可,遂劫以兵。子闾曰:“王孙若安靖楚国,匡正王室,而后庇焉,启之愿也,敢不听从。若将专利以倾王室,不顾楚国,有死不能。”遂杀之,而以王如高府,石乞尹门,圉公阳穴宫,负王以如昭夫人之宫。叶公亦至,及北门,或遇之,曰:“君胡不胄?国人望君如望慈父母焉。盗贼之矢若伤君,是绝民望也。若之何不胄?”乃胄而进。又遇一人曰:“君胡胄?国人望君如望岁焉,日日以几。若见君面,是得艾也。民知不死,其亦夫有奋心,犹将旌君以徇于国,而反掩面以绝民望,不亦甚乎?”乃免胄而进。遇箴尹固,帅其属将与白公。子高曰:“微二子者,楚不国矣。弃德从贼,其可保乎?”乃从叶公。使与国人以攻白公。白公奔山而缢,其徒微之。生拘石乞而问白公之死焉,对曰:“余知其死所,而长者使余勿言。”曰:“不言将烹。”乞曰:“此事克则为卿,不克则烹,固其所也,何害?”乃烹石乞。王孙燕奔黄氏。诸梁兼二事,国宁,乃使宁为令尹,使宽为司马,而老于叶。 +卫侯占梦,嬖人求酒于大叔僖子,不得,与卜人比而告公曰:“君有大臣在西南隅,弗去,惧害。”乃逐大叔遗。遗奔晋。卫侯谓浑良夫曰:“吾继先君而不得其器,若之何?”良夫代执火者而言,曰:“疾与亡君,皆君之子也。召之而择材焉可也,若不材,器可得也。”竖告大子。大子使五人舆豭从己,劫公而强盟之,且请杀良夫。公曰:“其盟免三死。”曰:“请三之后,有罪杀之。”公曰:“诺哉!” +译文 +十六年春季,瞒成、褚师比逃亡到宋国。 +卫庄公派鄢武子向周室报告,说:“蒯聩得罪了君父、君母,逃窜到晋国。晋国由于王室的缘故,不抛弃兄弟,把蒯聩安置在黄河边上。上天开恩,得继承保有封地,派下臣肸谨向执事报告。”周敬王派单平公回答说:“肸把消息带来告诉我,回去对叔父说:我赞许你继承先世,恢复你的禄位。要恭敬啊!这样才能得到上天赐福。不恭敬上天就不能赐福,后悔哪里来得及?” +夏季,四月十一日,孔丘死了,哀公致悼辞说:“上天不善,不肯留下这一位国老,让他捍卫我一人居于君位,使我孤零零地忧愁成病。呜呼哀哉!尼父,我失去了律己的榜样。”子赣说:“国君恐怕不能在鲁国善终吧!他老人家的话说:“礼仪丧失就要昏暗,名分丧失就有过错。’失去意志就是昏暗,失去身份是过错。活着不能任用,死了又致悼辞,这不合于礼仪,自称‘一人’,这不合于名分。国君把礼与名两样都丧失了。” +六月,卫庄公在平阳招待孔悝喝酒,重重酬谢他,对大夫都有所赠送。喝醉了送走他,半夜把他打发走。孔悝用车子装上伯姬动身离平阳,到达西门,派副车回到西圃宗庙中去取神主盒子。子伯季子当初是孔氏的家臣,近来晋升为卫庄公的大夫,请求追赶孔悝,路上碰到载神主盒子的人,就杀了他而坐上他的车子。许公为回去迎接神主盒子,遇到子伯季子,许公为说:“和不仁的人争强,没有不胜的。”就一定要让子伯季子先射,射了三箭,箭都落到离许公为很远的地方。许公为射他,只一箭就把他射死了。有人坐着子伯季子的车子跟上去,在袋子里得到了神主盒子。孔悝逃亡到宋国。 +楚国太子建遭到诬陷的时候,从城父逃亡到宋国,又去郑国躲避宋国华氏之乱。郑国人待他很好。又到晋国,和晋国人策划袭击郑国,为此就要求再回到郑国去。郑国人待他像以前一样。晋国人派间谍和太子建联系,事情完了准备回晋国,同时约定入袭郑国的日期。太子建在他的封邑里大肆暴虐,封邑的人告发他。郑国人来查问,发现了晋国间谍,于是就杀死了太子建。太子建的儿子名胜,在吴国,子西想找他来。叶公说:“我听说胜这个人狡诈而好作乱,不是一个祸害吧!”子西说:“我听说胜这个人诚实而勇敢,不做没有利的事情。把他安置在边境上,让他保卫边疆。”叶公说:“符合仁爱叫做诚信,遵循道义叫做勇敢。我听说胜这个人务求实践诺言,而又遍求不怕死的人,大概是有私心吧?不管什么话都要实践,这不是诚信,不管什么事情都不怕死,这不是勇敢。您一定会后悔的。”子西不听,把胜召回来,让他住在和吴国边境的地方,号为白公。胜请求进攻郑国,子西说:“楚国一切政事还没纳入正常轨道。不是这样,我是不会忘记的。”过了些时候,胜又请求,子西同意了。还没有出兵,晋国攻打郑国,楚国却救援郑国,并和郑国结盟。白公胜发怒,说:“郑国人在这里,仇人不在远处了。” +白公胜亲自磨剑,子期的儿子平见到,说:“您为什么亲自磨剑呢?”他说:“胜是以爽直著称的,不告诉您,哪里能算得上直爽呢?我要杀死你父亲。”平把这些话报告子西。子西说:“胜就像鸟蛋,我覆翼而使他长大。在楚国,只要我死了,令尹、司马,不归于胜还归于谁?”胜听了子西的话,说:“令尹真狂妄啊!他要得到好死,我就不是我。”子西还是没有觉察。胜对石乞说:“君王和两位卿士,一共用五百个人对付,就行了。”石乞说“这五百个人是找不到的。”又说:“市场的南边有个叫熊宜僚的,如果找到他,可以抵五百个人。”石乞就跟着白公胜去见宜僚,和他谈话,很高兴。石乞就把要办的事告诉宜僚,宜僚拒绝。把剑架在宜僚脖子上,他一动不动。白公胜说:“这是不为利诱、不怕威胁、不泄漏别人的话去讨好的人,离开这里吧。” +吴国人进攻慎地,白公胜打败了他们。白公胜请求不解除军队武装奉献战利品,楚惠王同意了,白公胜就乘机发动叛乱。秋季,七月,在朝廷上杀了子西、子期,并且劫持楚惠王。子西用袖子遮着脸而死去。子期说:“过去我用勇力事奉君王,不能有始无终。”拔起一株樟树打死了敌人然后死去。石乞说:“焚烧府库,杀死君王。不这样,事情不能成功。”白公胜说:“不行,杀死君王不吉祥,烧掉府库没有积蓄,将要用什么来保有楚国?”石乞说:“有了楚国而治理百姓,用恭敬来事奉神灵,就能得到吉祥,而且还有物资,怕什么?”白公胜不肯听从。 +叶公住在蔡地,方城山外边的人都说:“可以进兵国都了。”叶公说:“我听说,用冒险而侥幸成功的,他的欲望不会满足,办事不公平,百姓必然不依附。”听到白公胜杀了齐国的管修,然后才进入郢都。 +白公胜想要让子闾做楚王,子闾不答应,就用武力劫持他。子闾说:“您如果安定楚国,整顿王室,然后对启加以庇护,这是启的愿望,岂敢不听从?如果要专谋私利来颠覆王室,置国家于不顾,那么启宁死不从。”白公胜就杀了子闾,带着惠王到高府。石乞守门,圉公阳在宫墙上打开一个洞,背上惠王到了昭夫人的宫中。 +叶公也在这时候来到,到达北门,有人遇到他,说:“您为什么不戴上头盔?国内的人们盼望您好像盼望慈爱的父母,盗贼的箭如果射伤您,这就断绝了百姓的盼望。为什么不戴上头盔?”叶公就戴上头盔前进,又遇到一个人说:“您为什么戴上头盔?国内的人们盼望您好像盼望丰收一样,天天盼望,如果见到您的面,就能安心了。百姓知道不至于再有生命危险,人人有奋战之心,还要把您的名字写在旗帜上在都城里巡行,但是您又把脸遮起来以断绝百姓的盼望,不也太过分了吗?”叶公就脱下头盔前进。遇到箴尹固率领他的部下,准备去帮助白公胜。叶公说:“如果没有子西他们两位,楚国就不成为国家了,抛弃德行跟从盗贼,难道能够安全吗?”箴尹固就跟随叶公。叶公派他和国内的人们攻打白公胜。白公胜逃到山上自己吊死了,他的部下把尸体藏起来。叶公活捉石乞而追问白公胜的尸体。石乞回答说:“我知道他尸体所藏的地方,但是白公让我别说。”叶公说:“不说就烹了你。”石乞说:“这件事成功就是卿,不成功就被烹,这本来是应有的结果,有什么妨碍?”于是就烹了石乞。王孙燕逃亡到頯黄氏。叶公身兼令尹、司马二职,国家安定以后,就让宁做令尹,宽做司马,自己在叶地退休养老。 +卫庄公占卜他做的梦,他的宠臣向太叔僖子要酒,没有得到,就和卜人勾结,而告诉卫庄公说:“您有大臣在西南角上,不去掉他,恐怕有危害。”于是就驱逐太叔遗。太叔遗逃亡到晋国。 +卫庄公对浑良夫说:“我继承了先君而没有得到他的宝器,怎么办?”浑良夫让执烛的人出去,自己代他执烛然后说:“疾和逃亡在外的国君,都是您的儿子,召他来可以量才选择。如果没有才能就废掉他,宝器就可以得到了。”童仆密告太子。太子派五个人用车子装上公猪跟着自己,劫持卫庄公强迫和他盟誓,而且请求杀死浑良夫。卫庄公说:“和他的盟誓说过要赦免死罪三次。”太子说:“请在三次以后,再有罪就杀死他。”卫庄公说:“好啊!” + +哀公十七年 +【传】十七年春,卫侯为虎幄于藉圃,成,求令名者,而与之始食焉。大子请使良夫。良夫乘衷甸两牡,紫衣狐裘,至,袒袭,不释剑而食。大子使牵以退,数之以三罪而杀之。 +三月,越子伐吴。吴子御之笠泽,夹水而陈。越子为左右句卒,使夜或左或右,鼓噪而进。吴师分以御之。越子以三军潜涉,当吴中军而鼓之,吴师大乱,遂败之。 +晋赵鞅使告于卫曰:“君之在晋也,志父为主。请君若大子来,以免志父。不然,寡君其曰,志父之为也。”卫侯辞以难。大子又使椓之。 +夏六月,赵鞅围卫。齐国观、陈瓘救卫,得晋人之致师者。子玉使服而见之,曰:“国子实执齐柄,而命瓘曰:‘无辟晋师。’岂敢废命?子又何辱?”简子曰:“我卜伐卫,未卜与齐战。”乃还。 +楚白公之乱,陈人恃其聚而侵楚。楚既宁,将取陈麦。楚子问帅于大师子谷与叶公诸梁,子谷曰:“右领差车与左史老,皆相令尹、司马以伐陈,其可使也。”子高曰:“率贱,民慢之,惧不用命焉。”子谷曰:“观丁父,鄀俘也,武王以为军率,是以克州、蓼,服随、唐,大启群蛮。彭仲爽,申俘也,文王以为令尹,实县申、息,朝陈、蔡,封畛于汝。唯其任也,何贱之有?”子高曰:“天命不谄。令尹有憾于陈,天若亡之,其必令尹之子是与,君盍舍焉?臣惧右领与左史有二俘之贱,而无其令德也。”王卜之,武城尹吉。使帅师取陈麦。陈人御之,败,遂围陈。秋七月己卯,楚公孙朝帅师灭陈。 +王与叶公枚卜子良以为令尹。沈尹朱曰:“吉,过于其志。”叶公曰:“王子而相国,过将何为?”他日,改卜子国而使为令尹。 +卫侯梦于北宫,见人登昆吾之观,被发北面而噪曰:“登此昆吾之虚,绵绵生之瓜。余为浑良夫,叫天无辜。”公亲筮之,胥弥赦占之,曰:“不害。”与之邑,置之,而逃奔宋。卫侯贞卜,其繇曰:“如鱼赬尾,衡流而方羊。裔焉大国,灭之将亡。阖门塞窦,乃自后逾。” +冬十月,晋复伐卫,入其郛。将入城,简子曰:“止。叔向有言曰:‘怙乱灭国者无后。’”卫人出庄公而晋平,晋立襄公之孙般师而还。十一月,卫侯自鄄入,般师出。 +初,公登城以望,见戎州。问之,以告。公曰:“我姬姓也,何戎之有焉?”翦之。公使匠久。公欲逐石圃,未及而难作。辛已,石圃因匠氏攻公,公阖门而请,弗许。逾于北方而队,折股。戎州人攻之,大子疾、公子青逾从公,戎州人杀之。公入于戎州己氏。初,公自城上见己氏之妻发美,使髡之,以为吕姜□。既入焉,而示之璧,曰:“活我,吾与女璧。”己氏曰:“杀女,璧其焉往?”遂杀之而取其璧。卫人复公孙般师而立之。十二月,齐人伐卫,卫人请平。立公子起,执般师以归,舍诸潞。 +公会齐侯,盟于蒙,孟武伯相。齐侯稽首,公拜。齐人怒,武伯曰:“非天子,寡君无所稽首。”武伯问于高柴曰:“诸侯盟,谁执牛耳?”季羔曰:“鄫衍之役,吴公子姑曹。发阳之役,卫石魋。”武伯曰:“然则彘也。” +宋皇瑗之子麇,有友曰田丙,而夺其兄劖般邑以与之。劖般愠而行,告桓司马之臣子仪克。子仪克适宋,告夫人曰:“麇将纳桓氏。”公问诸子仲。初,仲将以杞姒之子非我为子。曰:“必立伯也,是良材。”子仲怒,弗从,故对曰:“右师则老矣,不识麇也。”公执之。皇瑗奔晋,召之。 +译文 +十七年春季,卫庄公在藉圃建造了一座刻有虎兽纹的小木屋,造成了,要寻找一位有好名誉的人和他在里边吃第一顿饭。太子请求找浑良夫。浑良夫坐在两匹公马驾着的车子上,穿上紫色衣服和狐皮袍。来到以后,敞开皮袍,没有解下佩剑就吃饭。太子派人牵着他退下,举出三条罪状就杀死了他。 +三月,越王发兵进攻吴国,吴王发兵在笠泽抵御,隔着一条河摆开阵势。越王将越军编成左右两支部队,让他们在夜里忽左忽右,击鼓呐喊前进。吴军分兵抵御。越王带领三军偷渡,对准吴国的中军击鼓进攻。吴军大乱,于是越军就打败了吴军。 +晋国的赵鞅派人告诉卫国,说:“君王在晋国的时候,我是主人。现在请君王或者太子来一趟,以免除我的罪过。不这样,寡君恐怕会说这是我授意这样做的。”卫庄公以国内有祸难加以推辞,太子又派人在使者面前诽谤卫庄公。 +夏季,六月,赵鞅包围卫国。齐国的国观、陈瓘救援卫国,俘虏了晋国单车挑战的人。陈瓘让被俘者穿上本来的服装然后接见他,说:“国子掌握齐国政权,命令我说‘不要逃避晋军’,我哪里敢废弃这个命令?哪里又用得着劳驾您呢?”赵鞅说:“我为攻打卫国占卜过,没有为和齐国作战占卜。”于是就撤兵回国。 +楚国白公的那次动乱,陈国人仗着自己有积蓄而侵袭楚国。楚国安定以后,准备夺取陈国的麦子。楚国向太师子穀和叶公诸梁询问统帅的人选,子穀说:“右领差车和左史老都辅佐过令尹、司马攻打陈国,大概是可以派遣的。”子高说:“这两个人都是被俘虏过的,百姓轻慢他们,怕不会听从命令。”子穀说:“观丁父,做过鄀国俘虏,武王让他做军帅,因此战胜州国、蓼国,使随国、唐国顺服,大大地开导了各部蛮人。彭仲爽,做过申国俘虏,文王让他做令尹,使申国、息国成为我国的两县,使陈国、蔡国前来朝见,开拓封疆到达汝水。只要他们能够胜任,做过俘虏有什么关系?”子高说:“上天的意志不容怀疑。令尹对陈国有遗恨,上天如果要灭亡陈国,一定会保佑令尹儿子去完成,您何不任命他呢?我害怕右领和左史有俘虏的卑贱而没有他们的美德。”楚惠王占卜,公孙朝吉利,就派他带兵夺取陈国的麦子。陈国人抵抗,战败,公孙朝就包围了陈国。秋季,七月初八日,公孙朝领兵灭亡陈国。 +楚惠王和叶公为让子良做令尹而占卜。沈尹朱说:“吉利。超过了他的期望。”叶公说:“以王子的地位而辅助国王,超过这地位将会做什么?”过了几天,改为子国占卜而让他做了令尹。 +卫庄公在北宫做梦,梦见一个人登上昆吾之观,披头散发脸朝着北面叫嚷说:“登上这昆吾之墟,有绵延不断生长的大瓜小瓜。我是浑良夫,向上天呼诉无辜。”卫庄公亲自占筮,胥弥赦预测说:“没有妨碍。”封给胥弥赦城邑,他不接受而逃亡到宋国。卫庄公又占卜,繇辞说:“像一条浅色的红尾鱼,穿过急流而犹豫不安。靠近大国,消灭它,将要灭亡。关门塞洞,就越过后墙。” +冬季,十月,晋国再次攻打卫国,进入外城。将要进入内城,赵简子说:“停止!叔向说过:‘依仗着动乱而灭亡别国的没有后嗣。’”卫国人赶走了庄公而和晋国讲和。晋国人立了卫襄公的孙子般师为君然后回国。 +十一月,卫庄公从鄄地回国,般师出走。当初,卫庄公登城远望,见到戎州。他问是怎么回事,有人告诉他是戎人的居邑。卫庄公说:“我是姬姓,哪里有什么戎人?”就派人毁平了戎州。卫庄公使用匠人,长久不让休息。他又想要驱逐国卿石圃,没有来得及而祸难发生了。十二日,石圃联合匠人攻打卫庄公。卫庄公关上门请求饶命,石圃不答应。卫庄公超过北墙掉下去,折断了大腿骨。戎州人攻打卫庄公,太子疾、公子青越墙跟从卫庄公,戎州人杀死了他们。卫庄公逃到戎州己氏那里。当初,卫庄公从城上看到己氏的妻子头发很漂亮,派人让她剪下来,作为自己夫人吕姜的假发。这时庄公到了己氏家里,把玉璧给己氏看,说:“救我的命,给你玉璧。”己氏说:“杀了你,玉璧会那里去?”就杀死了卫庄公并获得了他的玉璧。卫国人让公孙般师回国并立他为君。十二月,齐国人进攻卫国,卫国人请求讲和。齐国人立了公子起为卫君,拘捕了般师回去,让他住在潞地。 +哀公在蒙地会见齐平公并且结盟,孟武伯相礼。齐平公叩头,哀公弯腰作揖,齐国人发怒。孟武伯说:“不是天子,寡君没法叩头。”孟武伯问高柴说:“诸侯结盟,谁执牛耳?”高柴说:“鄫衍那一次盟誓,执牛耳的是吴国公子姑曹,发阳那一次,是卫国石魋。”孟武伯说:“那么这次就是我了。” +宋国皇瑗的儿子麇有个朋友叫田丙,麇夺取了他哥哥酁般的封邑给了田丙。酁般含怒出走,告诉桓司马的家臣子仪克。子仪克去到宋国,告诉夫人说:“麇打算接纳桓氏。”宋景公询问子仲。当初,子仲打算把杞姒的儿子非我作为嫡子。麇说:“一定要立老大,这是好材料。”子仲发怒,不听从,所以回答说:“右师已经老了,不会作乱,对麇就不了解了。”宋景公抓了麇。皇瑗逃亡到晋国,宋景公又派人把他召唤回来。 + + +哀公十八年 +【传】十八年春,宋杀皇瑗。公闻其情,复皇氏之族,使皇缓为右师。 +巴人伐楚,围。初,右司马子国之卜也,观瞻曰:“如志。”故命之。及巴师至,将卜帅。王曰:“宁如志,何卜焉?”使帅师而行。请承,王曰:“寝尹、工尹,勤先君者也。”三月,楚公孙宁、吴由于、薳固败巴师于,故封子国于析。君子曰:“惠王知志。《夏书》曰‘官占,唯能蔽志,昆命于元龟。’其是之谓乎!《志》曰:‘圣人不烦卜筮。’惠王其有焉!” +夏,卫石圃逐其君起,起奔齐。卫侯辄自齐复归,逐石圃,而复石魋与大叔遗。 +译文 +十八年春季,宋国杀了皇瑗。宋景公听说了他们的情况,恢复了皇氏的家族,派皇缓做了右师。 +巴人进攻楚国,包围鄾地。当初,右司马子国占卜,观瞻说:“符合你的意愿。”所以就命令他做了右司马。等到巴军来到,将要占卜统帅的人选。楚惠王说:“宁已经符合意愿,还占卜什么?”派他领兵出行。请求任命副手,楚惠王说:“寝尹、工尹,都是为先君出过力的人。”三月,楚国的公孙宁、吴由于、薳固在鄾地击败巴军,所以把析地作为子国的封邑。 +君子说:“惠王了解人的意愿。《夏书》说:‘占卜的官员只有能够审察判断人的意愿,然后才使用龟甲。’说的就是这个吧!《志》说,‘圣人用不着占卜占筮’,楚惠王大概就能这样。” +夏季,卫国的石圃赶走了他的国君起,起逃亡到齐国。卫出公辄从齐国重新回国,赶走了石圃,恢复了石魋和太叔遗原来的官职。 + +哀公十九年 +【传】十九年春,越人侵楚,以误吴也。夏,楚公子庆、公孙宽追越师,至冥,不及,乃还。 +秋,楚沈诸梁伐东夷,三夷男女及楚师盟于敖。 +冬,叔青如京师,敬王崩故也。 +译文 +十九年春季,越国人侵袭楚国,是为了迷惑吴国。夏季,楚国的公子庆、公孙宽追赶越军,到达冥地,没有追上,就撤兵回去了。 +秋季,楚国的沈诸梁进攻东夷,三夷的男女和楚军在敖地结盟。 +冬季,叔青到京师去,这是由于周敬王死了的缘故。 + + +哀公二十年 +【传】二十年春,齐人来征会。夏,会于廪丘。为郑故,谋伐晋。郑人辞诸子侯,秋,师还。 +吴公子庆忌骤谏吴子,曰:“不改,必亡。”弗听。出居于艾,遂适楚。闻越将伐吴,冬,请归平越,遂归。欲除不忠者以说于越,吴人杀之。 +十一月,越围吴。赵孟降于丧食。楚隆曰:“三年之丧,亲昵之极也。主又降之,无乃有故乎!”赵孟曰:“黄池之役,先主与吴王有质,曰:‘好恶同之。’今越围吴,嗣子不废旧业而敌之,非晋之所能及也,吾是以为降。”楚隆曰:“若使吴王知之,若何?”赵孟曰:“可乎?”隆曰:“请尝之。”乃往。先造于越军,曰:“吴犯间上国多矣,闻君亲讨焉,诸夏之人莫不欣喜,唯恐君志之不从。请入视之。”许之。告于吴王曰:“寡君之老无恤,使陪臣隆敢展谢其不共。黄池之役,君之先臣志父得承齐盟,曰:‘好恶同之。’今君在难,无恤不敢惮劳。非晋国之所能及也,使陪臣敢展布之。”王拜稽首曰:“寡人不佞,不能事越,以为大夫忧,拜命之辱。”与之一箪珠,使问赵孟,曰:“句践将生忧寡人,寡人死之不得矣。”王曰:“溺人必笑,吾将有问也,史黯何以得为君子?”对曰:“黯也进不见恶,退无谤言。”王曰:“宜哉。” +译文 +二十年春季,齐国人来鲁国征召会见。夏季,在廪丘会见,为了郑国的缘故,策划攻打晋国。郑国人向诸侯辞谢。秋季,军队回国。 +吴国的公子庆忌屡次劝谏吴王说:“如果不改变政令,一定亡国。”吴王不听,庆忌离开国都住在艾地,又乘机到楚国去。庆忌听说越国准备进攻吴国,冬季,请求回国和越国讲和,于是就回国了。想要除掉不忠的人来讨越国的喜欢。吴国人杀死了庆忌。 +十一月,越国军队包围了吴国,赵孟的饮食比居丧时的饮食还要降等。楚隆说:“三年的丧礼,是表示亲情关系的极点,现在您又降等,恐怕另有缘故吧!”赵孟说:“黄池那一次盟会,先主和吴王有过盟誓,说:‘同好共恶。’现在越国包围吴国,继承人想不废弃过去的誓言而帮助吴国,但又不是晋国的力量所能达到的,我因此只能用饮食降等来表示心意。”楚隆说:“如果让吴王知道,怎么样?”赵孟说:“行吗?”楚隆说:“请试一试。”于是就前去,先到越军那里,说:“吴国冒犯上国已经多次了,听说君王亲自讨伐,中原的人们莫不欢欣鼓舞,惟恐君王的意愿不能实现,请让我进去看看吴军的情况。”越王答应了。楚隆告诉吴王说:“寡君的老臣无恤派陪臣隆前来,谨敢为他前来道歉;黄池那一次结盟,君王的先臣志父得以参加盟会,盟誓说‘同好共恶’。现在君王处在危难之中,无恤不敢害怕辛劳,但又不是晋国的力量所能达到的,谨派我向君王报告。”吴王下拜叩头说:“寡人没有才能,不能事奉越国,因而让大夫忧虑,谨拜谢您的命令。”给了楚隆一小盒珍珠,让他送给赵孟,说:“勾践要让我活着不好过,我是不得好死了。”又说:“快淹死的人必然强作欢笑,我还要问你,史黯为什么能成为君子?”楚隆回答说:“史黯这个人做官没有人讨厌他,不做官没有人诽谤他。”吴王说:“真是说得恰当啊!” + +哀公二十一年 +【传】二十一年夏五月,越人始来。 +秋八月,公及齐侯、邾子盟于顾。齐有责稽首,因歌之曰:“鲁人之皋,数年不觉,使我高蹈。唯其儒书。以为二国忧。” +是行也,公先至于阳谷。齐闾丘息曰:“君辱举玉趾,以在寡君之军。群臣将传遽以告寡君,比其复也,君无乃勤。为仆人之未次,请除馆于舟道。”辞曰:“敢勤仆人?” +译文 +二十一年夏季,五月,越国人第一次来鲁国。 +秋季,八月,鲁哀公和齐平公、邾隐公在顾地结盟。齐国人责备从前叩头而哀公不相应回礼那件事,因而唱歌说:“鲁人的罪过,几年还没有自己察觉,使我们发怒暴跳。正由于他们只拘泥儒家之书,造成了两国苦恼又忧愁。” +这一趟,哀公先到阳穀。齐国的闾丘息说:“劳驾君王亲自光临,来慰劳寡君的军队,臣下们将要用驿车向寡君报告。等到他们报告回来,君王未免太劳累了。由于仆人没有准备好宾馆,请在舟道暂设行馆。”哀公辞谢说:“岂敢烦劳贵国的仆人?” + +哀公二十二年 +【传】二十二年夏四月,邾隐公自齐奔越,曰:“吴为无道,执父立子。”越人归之,大子革奔越。 +冬十一月丁卯,越灭吴。请使吴王居甬东,辞曰:“孤老矣,焉能事君?”乃缢。越人以归。 +译文 +二十二年夏季,四月,邾隐公从齐国逃亡到越国,说:“吴国无道,拘捕了父亲立了儿子。”越国人把他送回去,太子革逃亡到越国。 +冬季,十一月二十七日,越国灭亡吴国,请求让吴王住在甬东。吴王辞谢说:“我老了,哪里还能事奉君王?”于是就上吊死了。越国人把他的尸体送了回去。 + +哀公二十三年 +【传】二十三年春,宋景曹卒。季康子使冉有吊,且送葬,曰:“敝邑有社稷之事,使肥与有职竞焉,是以不得助执绋,使求从舆人。曰:‘以肥人得备弥甥也,有不腆先人之产马,使求荐诸夫人之宰,其可以称旌繁乎?’” +夏六月,晋荀瑶伐齐。高无丕帅师御之。知伯视齐师,马骇,遂驱之,曰:“齐人知余旗,其谓余畏而反也。”乃垒而还。将战,长武子请卜。知伯曰:“君告于天子,而卜之以守龟于宗祧,吉矣,吾又何卜焉?且齐人取我英丘,君命瑶,非敢耀武也,治英丘也。以辞伐罪足矣,何必卜?” +壬辰,战于犁丘。齐师败绩,知伯亲禽颜庚。 +秋八月,叔青如越,始使越也。越诸鞅来聘,报叔青也。 +译文 +二十三年春季,宋国的景曹死了。季康子派冉有去吊唁,并且送葬,说:“敝邑有国家大事,使肥事务繁忙,因此不能帮着送葬,特派求前来跟随在舆人之后,说:‘由于肥忝居远房外甥,有不丰厚的先人的马匹,派求奉献给夫人的家宰,也许能和夫人的马匹相称吧!’” +夏季,六月,晋国的荀瑶攻打齐国,高无邳率军抵御。荀瑶观察齐军的虚实,马受惊,就索性驱马前进,说:“齐国人已经看到我的旗帜,如果不向前进,恐怕要说我害怕而回去了。”到达齐军的营垒以后才回去。将要作战,长武子请求占卜。荀瑶说:“国君报告了天子,在宗庙里已经用龟占卜过,卦像很吉利,我又占卜什么呢?况且齐国人占领了我们的英丘。国君命令瑶,不是敢于炫耀武力,而是为了治理英丘。用正当的理由讨伐有罪者就足够了,何必占卜?” +二十六日,在犁丘作战,齐军大败,荀瑶亲自捉住了颜庚。 +秋季,八月,叔青到越国去,这是第一次出使越国。越国的诸鞅前来鲁国聘问,这是回报叔青的访问。 + + +哀公二十四年 +【传】二十四年夏四月,晋侯将伐齐,使来乞师,曰:“昔臧文仲以楚师伐齐,取谷。宣叔以晋师伐齐,取汶阳。寡君欲徼福于周公,愿乞灵于臧氏。”臧石帅师会之,取廪丘。军吏令缮,将进。莱章曰:“君卑政暴,往岁克敌,今又胜都。天奉多矣,又焉能进?是躗言也。役将班矣!”晋师乃还。饩臧石牛,大史谢之,曰:“以寡君之在行,牢礼不度,敢展谢之。” +邾子又无道,越人执之以归,而立公子何。何亦无道。 +公子荆之母嬖,将以为夫人,使宗人衅夏献其礼。对曰:“无之。”公怒曰:“女为宗司,立夫人,国之大礼也,何故无之?”对曰:“周公及武公娶于薛,孝、惠娶于商,自桓以下娶于齐,此礼也则有。若以妾为夫人,则固无其礼也。”公卒立之,而以荆为大子。国人始恶之。 +闰月,公如越,得大子适郢,将妻公,而多与之地。公孙有山使告于季孙,季孙惧,使因大宰嚭而纳赂焉,乃止。 +译文 +二十四年夏季,四月,晋出公准备发兵进攻齐国,派人来鲁国请求出兵,说:“从前臧文仲带领楚军进攻齐国,占领了穀地;宣叔带领晋军进攻齐国,占领了汶阳。寡君想要向周公求福,也愿意向臧氏求得威灵。”臧石领兵和晋军会合,占领了廪丘。军吏下令作好战前准备,将要进军。莱章说:“晋国国君地位低下而政治暴虐,去年战胜敌人,现在又攻占都邑,上天赐给他们的已经很多了,又哪里能够前进?这是在说大话。军队将要撤回去了。”晋军果真撤退回国。晋国人把活牛送给臧石,太史表示歉意说:“由于寡君出行在外,使用的牲口不合礼仪规定的标准,谨敢表示歉意。” +邾隐公还是无道,越国人把他拘捕带回去,而立了公子何为君。公子何也同样无道。 +公子荆的母亲受到宠爱,哀公打算立她为夫人,派宗人釁夏献上立夫人的礼品。釁夏回答说:“没有这样的礼节。”哀公发怒说:“你做宗司,立夫人,这是国家的大礼,为什么没有?釁夏回答说:“周公和武公在薛国娶妻,孝公、惠公在宋国娶妻,从桓公以下在齐国娶妻,这样的礼节是有的。如果把妾作为夫人,那就本来没有这样的礼节。”哀公最终还是立了她为夫人,而把荆立为太子,国内的人们开始讨厌哀公。 +闰月,哀公到越国去,和太子適郢关系很友好,太子適郢要把女儿嫁给哀公而且多给他们土地。公孙有山派人告诉季孙。季孙恐惧,派人走太宰嚭的关系并且送上财礼,事情才得中止。 + +哀公二十五年 +【传】二十五年夏五月庚辰,卫侯出奔宋。卫侯为灵台于藉圃,与诸大夫饮酒焉。褚师声子袜而登席,公怒,辞曰:“臣有疾,异于人。若见之,君将之,是以不敢。”公愈怒,大夫辞之,不可。褚师出,公戟其手,曰:“必断而足。”闻之,褚师与司寇亥乘,曰:“今日幸而后亡。”公之入也,夺南氏邑,而夺司寇亥政。公使侍人纳公文懿子之车于池。 +初,卫人翦夏丁氏,以其帑赐彭封弥子。弥子饮公酒,纳夏戊之女,嬖,以为夫人。其弟期,大叔疾之从孙甥也,少畜于公,以为司徒。夫人宠衰,期得罪。公使三匠久。公使优狡盟拳弥,而甚近信之。故褚师比、公孙弥牟、公文要、司寇亥、司徒期因三匠与拳弥以作乱,皆执利兵,无者执斤。使拳弥入于公宫,而自大子疾之宫噪以攻公。鄄子士请御之。弥援其手,曰:“子则勇矣,将若君何?不见先君乎?君何所不逞欲?且君尝在外矣,岂必不反?当今不可,众怒难犯,休而易间也。”乃出。将适蒲,弥曰:“晋无信,不可。”将适鄄,弥曰:“齐、晋争我,不可。”将适泠,弥曰:“鲁不足与,请适城锄以钩越,越有君。”乃适城锄。弥曰:“卫盗不可知也,请速,自我始。”乃载宝以归。 +公为支离之卒,因祝史挥以侵卫。卫人病之。懿子知之,见子之,请逐挥。文子曰:“无罪。”懿子曰:“彼好专利而妄。夫见君之入也,将先道焉。若逐之,必出于南门而适君所。夫越新得诸侯,将必请师焉。”挥在朝,使吏遣诸其室。挥出,信,弗内。五日,乃馆诸外里,遂有宠,使如越请师。 +六月,公至自越。季康子、孟武伯逆于五梧。郭重仆,见二子,曰:“恶言多矣,君请尽之。”公宴于五梧,武伯为祝,恶郭重,曰:“何肥也!”季孙曰:“请饮彘也。以鲁国之密迩仇雠,臣是以不获从君,克免于大行,又谓重也肥。”公曰:“是食言多矣,能无肥乎?”饮酒不乐,公与大夫始有恶。 +译文 +二十五年夏季,五月二十五日,卫出公逃亡到宋国。卫出公在藉圃修造了灵台,和大夫们在那里喝酒,褚师声子穿着袜子登上席子,卫出公发怒。褚师辩解说:“我脚上生疮,和别人不一样。如果见到了,君王会作呕的,因此不敢脱去袜子。”卫出公更加生气。大夫们都为褚师辩解,卫出公不同意。褚师退出。卫出公把手叉在腰上,说:“一定要砍断你的脚!”褚师听了这话,就和司寇亥一起坐上车子说:“今天的事情能够落个逃亡就是幸运了。” +卫出公回国的时候,夺取了公孙弥牟的封邑,夺取了司寇亥的政权。卫出公又派侍者把公文懿子的车子推到池塘里。当初,卫国人灭了夏丁氏,把他的家财赐给彭封弥子。弥子请卫出公喝酒,进献夏戊的女儿,卫出公宠爱她,让她做了夫人。她的弟弟期,是太叔疾的从外孙,小时候养在卫出公的宫中,卫出公让他做司徒。夫人的宠爱衰减,期也就有了罪过。卫出公使用三种匠人久久不让休息。卫出公派优狡和拳弥盟誓,而又很亲近信任他,所以褚师比、公孙弥牟、公文要、司寇亥、司徒期利用三种匠人和拳弥来发动叛乱,都拿着锐利的武器,没有武器的人拿着斧子,派拳弥进入公宫,而从太子疾的宫里呐喊攻打卫出公。鄄子士请求抵御。拳弥拉着他的手,说:“您固然勇敢,可是打算把国君怎么办?您没有见到过先君的结局吗?君王到哪里不能满足愿望呢?而且君王曾经在外面待过,难道就一定不能回来吗?现在不能那么做,众怒难犯。叛乱平定才容易离间作乱的人。”于是卫出公就动身出走。准备到蒲地去,拳弥说:“晋国没有信用,不行。”准备到鄄地去,拳弥说:“齐国和晋国在争夺我们,不行。”准备到泠地去,拳弥说:“鲁国不足以亲附,请到城鉏去,可以联系越国。越国有能干的国君。”于是就去了城鉏。拳弥说:“卫国的盗贼是不是会来袭击您,还不能知道,请快点离开,从我开始。”于是就装上宝物回到了卫国。 +卫出公把士兵加以分散部署,利用祝史挥作为内应侵袭卫国。卫国人以此为患。公文懿子知道了,进见公孙弥牟,请求驱逐祝史挥。公孙弥牟说:“挥没有罪过。”懿子说:“他专权好利而又行为不轨,要是见到国君进入,会在前面引路的。如果驱逐他,一定出南门而去国君那里,越国最近得到诸侯,一定会请求他们出兵的。”祝史挥正在朝廷上,下朝后,懿子就派官吏把他从家里遣送走了。祝史挥出了城,住了两晚,想要回城,没有被接纳。过了五天,就住在外里,于是就受到卫出公的宠信,派他到越国去请求出兵。 +六月,哀公从越国回来,季康子、孟武伯到五梧迎接。郭重为哀公驾车,见到他们两位,回来对哀公说:“这两位的坏话多着呢,请君王当面一一追究。”哀公在五梧设宴,武伯祝酒,讨厌郭重,说:“你为什么那么肥胖?”季康子说:“请罚彘喝酒!由于鲁国紧挨着仇敌,臣下因此不能跟随君王,才得免于远行,可是他又认为奔波辛苦的重长得肥胖。”哀公说:“这个人吃自己的话吃多了,能不肥胖吗?”大家虽然喝酒但都不高兴,哀公和大夫从此就互相有了厌恶感。 + + +哀公二十六年 +【传】二十六年夏五月,叔孙舒帅师会越皋如、后庸、宋乐茷,纳卫侯。文子欲纳之,懿子曰:“君愎而虐,少待之,必毒于民,乃睦于子矣。”师侵外州,大获。出御之,大败。掘褚师定子之墓,焚之于平庄之上。文子使王孙齐私于皋如,曰:“子将大灭卫乎,抑纳君而已乎?”皋如曰:“寡君之命无他,纳卫君而已。”文子致众而问焉,曰:“君以蛮夷伐国,国几亡矣。请纳之。”众曰:“勿纳。”曰:“弥牟亡而有益,请自北门出。”众曰:“勿出。”重赂越人,申开守陴而纳公,公不敢入。师还,立悼公,南氏相之,以城锄与越人。公曰:“期则为此。”令苟有怨于夫人者,报之。司徒期聘于越。公攻而夺之币。期告王,王命取之。期以众取之。公怒,杀期之甥之为大子者。遂卒于越。 +宋景公无子,取公孙周之子得与启,畜诸公宫,未有立焉。于是皇缓为右师,皇非我为大司马,皇怀为司徒,灵不缓为左师,乐茷为司城,乐朱锄为大司寇。六卿三族降听政,因大尹以达。大尹常不告,而以其欲称君命以令。国人恶之。司城欲去大尹,左师曰:“纵之,使盈其罪。重而无基,能无敝乎?” +冬十月,公游于空泽。辛巳,卒于连中。大尹兴空泽之士千甲,奉公自空桐入,如沃宫。使召六子,曰:“闻下有师,君请六子画。”六子至,以甲劫之,曰:“君有疾病,请二三子盟。”乃盟于少寝之庭,曰:“无为公室不利。”大尹立启,奉丧殡于大宫。三日,而后国人知之。司城茷使宣言于国曰:“大尹惑蛊其君而专其利,令君无疾而死,死又匿之,是无他矣,大尹之罪也。”得梦启北首而寝于卢门之外,己为鸟而集于其上,咮加于南门,尾加于桐门。曰:“余梦美,必立。”大尹谋曰:“我不在盟,无乃逐我,复盟之乎?”使祝为载书,六子在唐盂。将盟之。祝襄以载书告皇非我,皇非我因子潞、门尹得、左师谋曰:“民与我,逐之乎?”皆归授甲,使徇于国曰:“大尹惑蛊其君,以陵虐公室。与我者,救君者也。”众曰:“与之。”大尹徇曰:“戴氏、皇氏将不利公室,与我者,无忧不富。”众曰:“无别。”戴氏、皇氏欲伐公,乐得曰:“不可。彼以陵公有罪,我伐公,则甚焉。”使国人施于大尹,大尹奉启以奔楚,乃立得。司城为上卿,盟曰:“三族共政,无相害也。” +卫出公自城锄使以弓问子赣,且曰:“吾其入乎?”子赣稽首受弓,对曰:“臣不识也。”私于使者曰:“昔成公孙于陈,宁武子、孙庄子为宛濮之盟而君入。献公孙于卫齐,子鲜、子展为夷仪之盟而君入。今君再在孙矣,内不闻献之亲,外不闻成之卿,则赐不识所由入也。《诗》曰:‘无竞惟人,四方其顺之。’若得其人,四方以为主,而国于何有?” +译文 +二十六年夏季,五月,叔孙舒带兵会合越国的皋如、后庸、宋国的乐茷送卫出公回国,公孙弥牟想要接纳。懿子说:“国君执拗又暴虐,稍等一些时候,必定残害百姓,百姓就会跟您和睦了。”联军侵袭外州,大肆劫掠。卫军出去抵御,大败。卫出公发掘褚师定子的坟墓,把棺材放在平庄之上放火烧了。 +公孙弥牟派王孙齐私下去见皋如,说:“您是打算大举灭亡卫国呢,还是把国君送回来就算了呢?”皋如说:“寡君的命令没有别的,只把卫君送回来就算了。”公孙弥牟召集大家征求意见,说:“国君带着蛮夷来攻打我国家,国家差一点灭亡了,请接纳他。”大家说:“不要接纳。”公孙弥牟说:“如果我逃亡对大家有好处,请让我从北门出去。”大家说:“不要出走。”公孙弥牟重重地贿赂越国人,大开城门接纳卫出公,城上守卫甚严,卫出公不敢进城。护送卫出公的联军退兵回去,卫国立了悼公,南氏辅助他,卫国把城鉏给越国人。卫出公说:“这是期干的。”命令如果对夫人有怨的可以报复。司徒期到越国聘问,卫出公攻打他并且夺走了财礼。司徒期报告越王,越王命令取回来,司徒期带了一批人又把财礼取了回来。卫出公发怒,杀死了太子,太子是司徒期的外甥。卫出公也就死在越国。 +宋景公没有儿子,要了公孙周的儿子得和启养在公宫里,还没有立继承人。当时皇缓做右师,皇非我做大司马,皇怀做司徒,灵不缓做左师,乐茷做司城,乐朱鉏做大司寇,六卿三族共同听取政事,通过大尹上达国君。大尹经常不向宋景公报告,而按照自己的意图假称君命以发号施令。国内的人们厌恶他。司城想要除掉大尹,左师说:“随他去,让他恶贯满盈。权势重而没有基础,能够不失败吗?” +冬季,十月,宋景公在空泽游玩。初四日,死在连中。大尹出动空泽的甲士一千人,奉着宋景公的尸体从空桐进入国都,到了沃宫。派人召来六卿,说:“听说下邑有战事,国君请六卿一起谋划。”六卿到达,用甲士劫持他们说:“国君有重病,请诸位盟誓。”就在小寝院子里盟誓,说:“不做对公室不利的事!”大尹立启为国君,奉着棺材停放在祖庙里。三天以后国内的人们才知道这件事。司城乐茷派人在国内宣布说:“大尹蛊惑他的国君,专权好利,现在国君没有生病就死了。死了以后又藏匿遗体,没有别的好说,就是大尹的罪过。” +得梦见启头向北睡在卢门的外边,自己变作大乌鸦栖止在他的上面,嘴巴搁在南门上,尾巴搁在北门上。醒来以后说:“我的梦很好,一定立为国君。” +大尹和别人策划说:“我没有参加盟誓,恐怕会驱逐我吧!再跟他们盟誓吧!”让太祝制作盟书。六卿正在唐盂,准备和他盟誓。太祝襄把盟书的内容告诉皇非我。皇非我依靠乐茷、门尹得、左师谋划说:“百姓亲附我们,把他赶走吧!”于是都回去把武装发给部下,让他们在国都内巡行,宣布说:“大尹蛊惑他的国君,欺压虐待公室。亲附我们的人,就是救援国君的人。”大家说:“亲附你们!”大尹也巡行,宣布说:“戴氏、皇氏准备对公室不利,亲附我的,不要担心不发财。”大家说:“你和国君没有什么两样!”戴氏、皇氏想要攻打启,乐得说:“不行,他因为欺凌国君有罪,我们要是出兵攻打,罪就更大了。”让国内的人们把罪过加在大尹身上。大尹奉事启逃亡到楚国,于是就立得为国君。司城做了上卿,盟誓说:“三族共同掌握国政,不要互相残害!” +卫出公从城鉏派人用弓问候子赣,并且说:“我能回国吗?”子赣叩头受弓,回答说:“我不知道。”私下对使者说:“从前成公流亡到陈国,宁武子、孙庄子在宛濮结盟然后国君回国。献公流亡到齐国,子鲜、子展在夷仪结盟然后国君回国。现在国君再次流亡在外,内部没有听说有像献公时代的亲信,外部没有听说有像成公时代的大臣,那么赐就不懂得根据什么能回国。《诗》说:‘最强莫过于得到人才,四方将会顺服。’如果得到这样的人,四方把他作为主人,取得国家又有什么困难呢?” + + +哀公二十七年 +【传】二十七年春,越子使后庸来聘,且言邾田,封于骀上。 +二月,盟于平阳,三子皆从。康子病之,言及子赣,曰:“若在此,吾不及此夫!”武伯曰:“然。何不召?”曰:“固将召之。”文子曰:“他日请念。” +夏四月己亥,季康子卒。公吊焉,降礼。 +晋荀瑶帅师伐郑,次于桐丘。郑驷弘请救于齐。齐师将兴,陈成子属孤子三日朝。设乘车两马,系五色焉。召颜涿聚之子晋,曰:“隰之役,而父死焉。以国之多难,未女恤也。今君命女以是邑也,服车而朝,毋废前劳。”乃救郑。及留舒,违谷七里,谷人不知。乃濮,雨,不涉。子思曰:“大国在敝邑之宇下,是以告急。今师不行,恐无及也。”成子衣制,杖戈,立于阪上,马不出者,助之鞭之。知伯闻之,乃还,曰:“我卜伐郑,不卜敌齐。”使谓成子曰:“大夫陈子,陈之自出。陈之不祀,郑之罪也。故寡君使瑶察陈衷焉。谓大夫其恤陈乎?若利本之颠,瑶何有焉?”成子怒曰:“多陵人者皆不在,知伯其能久乎?”中行文子告成子曰:“有自晋师告寅者,将为轻车千乘,以厌齐师之门,则可尽也。”成子曰:“寡君命恒曰:‘无及寡,无畏众。’虽过千乘,敢辟之乎?将以子之命告寡君。”文子曰:“吾乃今知所以亡。君子之谋也,始衷终皆举之,而后入焉。今我三不知而入之,不亦难乎?” +公患三桓之侈也,欲以诸侯去之。三桓亦患公之妄也,故君臣多间。公游于陵阪,遇孟武伯于孟氏之衢,曰:“请有问于子,余及死乎?”对曰:“臣无由知之。”三问,卒辞不对。公欲以越伐鲁,而去三桓。秋八月甲戌,公如公孙有陉氏,因孙于邾,乃遂如越。国人施公孙有山氏。 +悼之四年,晋荀瑶帅师围郑。未至,郑驷弘曰:“知伯愎而好胜,早下之,则可行也。”乃先保南里以待之。知伯入南里,门于桔柣之门。郑人俘酅魁垒,赂之以知政,闭其口而死。将门,知伯谓赵孟:“入之。”对曰:“主在此。”知伯曰:“恶而无勇,何以为子?”对曰:“以能忍耻,庶无害赵宗乎!”知怕不悛,赵襄子由是惎知伯,遂丧之。知伯贪而愎,故韩、魏反而丧之。 +译文 +二十七年春季,越王派后庸来鲁国聘问,并且商谈邾国土田的事,协议以骀上作为鲁、邾两国的边界。 +二月,在平阳结盟,季康子等三位都跟随前去。季康子对结盟感到忧虑,谈到子赣,说:“如果他在这里,我不会到这地步的!”孟武伯说:“对。为什么不召他来?”季康子说:“本来是要召他的。”叔孙文子说:“过些时候请仍然记着他。” +夏季,四月二十五日,季康子死。哀公去吊丧,礼节降等。 +晋国的知伯领兵进攻郑国,驻扎在桐丘。郑国的驷弘到齐国请求救援,齐军准备出发。陈成子集合为国战死者的儿子,通知他们三天内朝见国君。设置了一辆车两匹马,把册书放在五个口袋里。召见颜涿聚的儿子晋,说:“隰地那一役,你的父亲死在那里。由于国家多难,没有能抚恤你。现在国君命令把这个城邑给你,穿着朝服驾着车子去朝见,不要废弃你父亲的功劳。”于是就出兵救援郑国。到达留舒,离开穀地七里,縠地人竟没有发觉。到达濮地,天下雨军队不肯渡河。子思说:“大国的军队就在敝邑的屋檐底下,因此告急。现在军队不走,恐怕要来不及了。”陈成子披着雨衣拄着戈,站在山坡上,马不肯走出来的,就拉着它或者用鞭子抽打它。知伯听说,就收兵回去,说:“我占卜过进攻郑国,没有占卜和齐国作战。”派人对陈成子说:“大夫陈子,您这一族是从陈国分支出来的。陈国的断绝祭祀,是郑国的罪过,所以寡君派我来调查陈国被灭亡的实情,还要询问您是否为陈国忧虑。如果您对树干的倒置认为有利,那和我有什么关系?”陈成子发怒说:“经常欺压别人的人,都没有好结果,知伯难道能够长久吗?” +中行文子告诉陈成子说:“有一个从晋军中来告诉我的人说,晋军准备出动轻车一千辆,迫击齐军的营门,就可以全部歼灭齐军。”陈成子说:“寡君命令我说:‘不要追赶少数的士卒,不要害怕大批的敌人。’敌军即使超过一千辆战车,岂敢避开他们呢?我将要把您的话报告寡君。”中行文了说:“我到今天才知道自己为什么逃亡在外了。君子谋划一件事,对开始、发展、结果都要考虑到,然后向上报告。现在我对这三方面都不知道,就向上报告,不也是很难了吗?” +哀公担忧三桓的威胁,想要利用诸侯除掉他们;三桓也担忧哀公的狂妄,所以君臣之间嫌隙很多。哀公在陵坂游玩,在孟氏之衢碰上孟武伯,说:“请问您:我能得到善终吗?”孟武伯回答说:“我没法知道。”问了三次,始终辞谢不回答。哀公想要利用越国攻打鲁国而除掉三桓。秋季,八月初一日,哀公到了公孙有陉氏那里,由此又避居于邾国,后来就乘机去了越国。国内的人们拘捕了公孙有山氏。 +悼公四年,晋国的知伯领兵包围郑国,还没有到达,郑国的驷弘说:“知伯刚愎而好胜,我们及早向他表示软弱无能,他就可以退走了。”于是就先守在南里以等候晋军。知伯攻进南里,又攻打桔秩之门。郑国人俘虏了酅魁垒,用卿的地位来引诱他投降,不答应,就把他的嘴塞住而杀死了他。晋军将要攻打城门,知伯对赵孟说:“攻进去!”赵孟说:“主人在这里。”知伯说:“你貌丑而缺乏勇气,为什么成了太子?”赵孟回答说:“因为我能够忍受耻辱,也许对赵氏宗族没有害处吧!”知伯不肯改悔,赵孟因此而憎恨知伯,知伯就想要灭亡赵襄子。知伯贪婪而刚愎自用,所以韩、魏反过来与赵氏合谋灭亡了他。 diff --git a/Packages/SwiftyOpenCC/OpenCC/test/config_test/config_test.json b/Packages/SwiftyOpenCC/OpenCC/test/config_test/config_test.json new file mode 100644 index 0000000000000000000000000000000000000000..eef6c2cf88ee895fa6f9581a23a49af528257183 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/config_test/config_test.json @@ -0,0 +1,22 @@ +{ + "name": "Configuration Test", + "segmentation": { + "type": "mmseg", + "dict": { + "type": "text", + "file": "config_test_phrases.txt" + } + }, + "conversion_chain": [{ + "dict": { + "type": "group", + "dicts": [{ + "type": "text", + "file": "config_test_phrases.txt" + }, { + "type": "text", + "file": "config_test_characters.txt" + }] + } + }] +} diff --git a/Packages/SwiftyOpenCC/OpenCC/test/config_test/config_test_characters.txt b/Packages/SwiftyOpenCC/OpenCC/test/config_test/config_test_characters.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d573dcad592f62796d8a8e34bac9d825c2c2bde --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/config_test/config_test_characters.txt @@ -0,0 +1,2 @@ +于 於 +远 遠 diff --git a/Packages/SwiftyOpenCC/OpenCC/test/config_test/config_test_phrases.txt b/Packages/SwiftyOpenCC/OpenCC/test/config_test/config_test_phrases.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a7315608d0e4c273fb5dd37b5898d91d461cf69 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/config_test/config_test_phrases.txt @@ -0,0 +1,2 @@ +燕燕于飞 燕燕于飛 +之子于归 之子于歸 diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2s.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2s.ans new file mode 100644 index 0000000000000000000000000000000000000000..8644ddc48aafeea4dc2cb70883bd11864b65644a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2s.ans @@ -0,0 +1,3 @@ +虚伪叹息 +潮湿灶台 +赞叹沙河涌汹涌的波浪 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2s.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2s.in new file mode 100644 index 0000000000000000000000000000000000000000..3c454975413c14d5d24cf6a9a1a7a4866d355f94 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2s.in @@ -0,0 +1,3 @@ +虛偽歎息 +潮濕灶台 +讚歎沙河涌洶湧的波浪 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2t.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2t.ans new file mode 100644 index 0000000000000000000000000000000000000000..ae75d251c8c2d3f6485d2cfce7f4998bca6e5804 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2t.ans @@ -0,0 +1,2 @@ +爲賦新詞強說愁 +想到自己一緊張就口吃,我就沒胃口喫飯 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2t.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2t.in new file mode 100644 index 0000000000000000000000000000000000000000..1bbc409c5759d17eb0178df9c3a60a9547c8c210 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/hk2t.in @@ -0,0 +1,2 @@ +為賦新詞強説愁 +想到自己一緊張就口吃,我就沒胃口吃飯 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/jp2t.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/jp2t.ans new file mode 100644 index 0000000000000000000000000000000000000000..9cbcdcfc13e4a954aea1bb49f9a24797f60ad535 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/jp2t.ans @@ -0,0 +1,4 @@ +舊字體歷史假名遣 新字體現代假名遣 +橫濱 絲魚川 伊豫國 +驛辨當 辨別 辯護士 瓣膜 +藝術 缺航 欠缺 飲料罐 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/jp2t.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/jp2t.in new file mode 100644 index 0000000000000000000000000000000000000000..9178c8a992eea9f180e476ae8d0a24ea9ed3f53c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/jp2t.in @@ -0,0 +1,4 @@ +旧字体歴史仮名遣 新字体現代仮名遣 +横浜 糸魚川 伊予国 +駅弁当 弁別 弁護士 弁膜 +芸術 欠航 欠缺 飲料缶 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2hk.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2hk.ans new file mode 100644 index 0000000000000000000000000000000000000000..9a38de5aabf7ca7d0e9890ba173047933dd73a89 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2hk.ans @@ -0,0 +1,4 @@ +虛偽嘆息 +潮濕灶台 +讚歎沙河涌洶湧的波浪 +為了核實這説法 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2hk.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2hk.in new file mode 100644 index 0000000000000000000000000000000000000000..be99830a0afd2d96aec24e4bb01e36f4a3c8ffc6 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2hk.in @@ -0,0 +1,4 @@ +虚伪叹息 +潮湿灶台 +赞叹沙河涌汹涌的波浪 +为了核实这说法 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2t.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2t.ans new file mode 100644 index 0000000000000000000000000000000000000000..757df619e02c6039d9582d6143c15054276fa6ca --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2t.ans @@ -0,0 +1,9 @@ +誇誇其談 夸父逐日 +我幹什麼不干你事。 +太后的頭髮很乾燥。 +燕燕于飛,差池其羽。之子于歸,遠送於野。 +請成相,世之殃,愚闇愚闇墮賢良。人主無賢,如瞽無相何倀倀!請布基,慎聖人,愚而自專事不治。主忌苟勝,羣臣莫諫必逢災。 +曾經有一份真誠的愛情放在我面前,我沒有珍惜,等我失去的時候我才後悔莫及。人事間最痛苦的事莫過於此。如果上天能夠給我一個再來一次得機會,我會對那個女孩子說三個字,我愛你。如果非要在這份愛上加個期限,我希望是,一萬年。 +新的理論被發現了。 +金胄不是金色的甲冑。 +經理發現後勸諭兩人 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2t.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2t.in new file mode 100644 index 0000000000000000000000000000000000000000..ce309ae27f1dce35e4bd6e934162d6ee9c78e49c --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2t.in @@ -0,0 +1,9 @@ +夸夸其谈 夸父逐日 +我干什么不干你事。 +太后的头发很干燥。 +燕燕于飞,差池其羽。之子于归,远送于野。 +请成相,世之殃,愚暗愚暗堕贤良。人主无贤,如瞽无相何伥伥!请布基,慎圣人,愚而自专事不治。主忌苟胜,群臣莫谏必逢灾。 +曾经有一份真诚的爱情放在我面前,我没有珍惜,等我失去的时候我才后悔莫及。人事间最痛苦的事莫过于此。如果上天能够给我一个再来一次得机会,我会对那个女孩子说三个字,我爱你。如果非要在这份爱上加个期限,我希望是,一万年。 +新的理论被发现了。 +金胄不是金色的甲胄。 +经理发现后劝谕两人 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2tw.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2tw.ans new file mode 100644 index 0000000000000000000000000000000000000000..3ce62d5468e2103cae8c3829492eb1824c443982 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2tw.ans @@ -0,0 +1,2 @@ +著裝汙染虛偽發洩稜柱群眾裡面 +鯰魚和鯰魚是一種生物。 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2tw.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2tw.in new file mode 100644 index 0000000000000000000000000000000000000000..5f9967ba9d94f80a4d10f525713937c65790eb05 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2tw.in @@ -0,0 +1,2 @@ +着装污染虚伪发泄棱柱群众里面 +鲶鱼和鲇鱼是一种生物。 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2twp.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2twp.ans new file mode 100644 index 0000000000000000000000000000000000000000..b0764251a0bc301214852f3c7ede7a61ef14dc90 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2twp.ans @@ -0,0 +1,4 @@ +滑鼠裡面的矽二極體壞了,導致游標解析度降低。 +我們在寮國的伺服器的硬碟需要使用網際網路演算法軟體解決非同步的問題。 +為什麼你在床裡面睡著? +海內存知己 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2twp.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2twp.in new file mode 100644 index 0000000000000000000000000000000000000000..cfedb295316bda0b8eec6cf4b94b82f66d6c6436 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/s2twp.in @@ -0,0 +1,4 @@ +鼠标里面的硅二极管坏了,导致光标分辨率降低。 +我们在老挝的服务器的硬盘需要使用互联网算法软件解决异步的问题。 +为什么你在床里面睡着? +海内存知己 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2hk.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2hk.ans new file mode 100644 index 0000000000000000000000000000000000000000..704b68785e99127afa22a39379046e2c1537a20b --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2hk.ans @@ -0,0 +1,3 @@ +潮濕的露台 +為了核實這説法 +包粽子活動告一段落 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2hk.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2hk.in new file mode 100644 index 0000000000000000000000000000000000000000..26ac2e71f33262607fc4f7b52e4069a3bf5e9b99 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2hk.in @@ -0,0 +1,3 @@ +潮溼的露臺 +爲了覈實這說法 +包糉子活動告一段落 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2jp.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2jp.ans new file mode 100644 index 0000000000000000000000000000000000000000..c5e8a381d29e7c9569553bd78bcc8d21da6665e5 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2jp.ans @@ -0,0 +1,4 @@ +旧字体歴史仮名遣 新字体現代仮名遣 +横浜 糸魚川 伊予国 +駅弁当 弁別 弁護士 弁膜 +芸術 欠航 飲料缶 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2jp.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2jp.in new file mode 100644 index 0000000000000000000000000000000000000000..c2626d233fd9f1468f515e2767e2a19b69c38e03 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2jp.in @@ -0,0 +1,4 @@ +舊字體歷史假名遣 新字體現代假名遣 +橫濱 絲魚川 伊豫國 +驛辨當 辨別 辯護士 瓣膜 +藝術 缺航 飲料罐 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2s.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2s.ans new file mode 100644 index 0000000000000000000000000000000000000000..51850494358b192597d6f00621ab7857b7dfb907 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2s.ans @@ -0,0 +1 @@ +曾经有一份真诚的爱情放在我面前,我没有珍惜,等我失去的时候我才后悔莫及。人事间最痛苦的事莫过于此。如果上天能够给我一个再来一次得机会,我会对那个女孩子说三个字,我爱你。如果非要在这份爱上加个期限,我希望是,一万年。 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2s.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2s.in new file mode 100644 index 0000000000000000000000000000000000000000..86de44a22031eaa56dd8e1464b7c211ac86c1bad --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/t2s.in @@ -0,0 +1 @@ +曾經有一份真誠的愛情放在我面前,我沒有珍惜,等我失去的時候我才後悔莫及。人事間最痛苦的事莫過於此。如果上天能夠給我一個再來一次得機會,我會對那個女孩子說三個字,我愛你。如果非要在這份愛上加個期限,我希望是,一萬年。 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2s.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2s.ans new file mode 100644 index 0000000000000000000000000000000000000000..b010f7b8bc79b3c4bc6fbfd2b1cecb47f7b53578 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2s.ans @@ -0,0 +1 @@ +着装著作污染虚伪发泄棱柱群众里面 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2s.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2s.in new file mode 100644 index 0000000000000000000000000000000000000000..5595eb5f45650c2e83547c4c209bdbf3a565bd3a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2s.in @@ -0,0 +1 @@ +著裝著作汙染虛偽發洩稜柱群眾裡面 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2sp.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2sp.ans new file mode 100644 index 0000000000000000000000000000000000000000..863e0ab8a38296bdc94803bf396c49a2583bac13 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2sp.ans @@ -0,0 +1,5 @@ +鼠标里面的硅二极管坏了,导致光标分辨率降低。 +我们在老挝的服务器的硬盘需要使用互联网算法软件解决异步的问题。 +为什么你在床里面睡着? +用鼠标点击正则表达式 +KB大桥也被视为帕劳人的后花园 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2sp.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2sp.in new file mode 100644 index 0000000000000000000000000000000000000000..9187a36cb8f603d55edf7c863438940ce2b2ed6a --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2sp.in @@ -0,0 +1,5 @@ +滑鼠裡面的矽二極體壞了,導致游標解析度降低。 +我們在寮國的伺服器的硬碟需要使用網際網路演算法軟體解決非同步的問題。 +為什麼你在床裡面睡著? +用滑鼠點選正規表示式 +KB大橋也被視為帛琉人的後花園 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2t.ans b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2t.ans new file mode 100644 index 0000000000000000000000000000000000000000..aa48668bd99bbd611503c728d991a3c5ee8169bb --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2t.ans @@ -0,0 +1,3 @@ +爲了衆人化妝牀頭裏面衛生,醞釀羣峯鐵鉤嘆氣事件 +在廚房裏做手擀麪 +想到自己一緊張就口吃,我就沒胃口喫飯 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2t.in b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2t.in new file mode 100644 index 0000000000000000000000000000000000000000..be88d1bf2c7d11ffcd732fe6e4620d4e62d606f0 --- /dev/null +++ b/Packages/SwiftyOpenCC/OpenCC/test/testcases/tw2t.in @@ -0,0 +1,3 @@ +為了眾人化妝床頭裡面衛生,醞釀群峰鐵鉤嘆氣事件 +在廚房裡做手擀麵 +想到自己一緊張就口吃,我就沒胃口吃飯 \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/Package.swift b/Packages/SwiftyOpenCC/Package.swift new file mode 100644 index 0000000000000000000000000000000000000000..af2c4e23818b1bedc6641dc34a1ee6691f07f99d --- /dev/null +++ b/Packages/SwiftyOpenCC/Package.swift @@ -0,0 +1,85 @@ +// swift-tools-version:5.3 + +import PackageDescription + +let package = Package( + name: "SwiftyOpenCC", + products: [ + .library( + name: "OpenCC", + targets: ["OpenCC"]), + ], + targets: [ + .target( + name: "OpenCC", + dependencies: ["copencc"], + resources: [ + .copy("Dictionary") + ]), + .testTarget( + name: "OpenCCTests", + dependencies: ["OpenCC"], + resources: [ + .copy("benchmark"), + .copy("testcases"), + ]), + .target( + name: "copencc", + exclude: [ + "src/benchmark", + "src/tools", + "src/BinaryDictTest.cpp", + "src/Config.cpp", + "src/ConfigTest.cpp", + "src/ConversionChainTest.cpp", + "src/ConversionTest.cpp", + "src/DartsDictTest.cpp", + "src/DictGroupTest.cpp", + "src/MarisaDictTest.cpp", + "src/MaxMatchSegmentationTest.cpp", + "src/PhraseExtractTest.cpp", + "src/SerializedValuesTest.cpp", + "src/SimpleConverter.cpp", + "src/SimpleConverterTest.cpp", + "src/TextDictTest.cpp", + "src/UTF8StringSliceTest.cpp", + "src/UTF8UtilTest.cpp", + "deps/google-benchmark", + "deps/gtest-1.11.0", + "deps/pybind11-2.5.0", + "deps/rapidjson-1.1.0", + "deps/tclap-1.2.2", + + "src/CmdLineOutput.hpp", + "src/Config.hpp", + "src/ConfigTestBase.hpp", + "src/DictGroupTestBase.hpp", + "src/SimpleConverter.hpp", + "src/TestUtils.hpp", + "src/TestUtilsUTF8.hpp", + "src/TextDictTestBase.hpp", + "src/py_opencc.cpp", + + // ??? + "src/README.md", + "src/CMakeLists.txt", + "deps/marisa-0.2.6/AUTHORS", + "deps/marisa-0.2.6/CMakeLists.txt", + "deps/marisa-0.2.6/COPYING.md", + "deps/marisa-0.2.6/README.md", + ], + sources: [ + "source.cpp", + "src", + "deps/marisa-0.2.6", + ], + cxxSettings: [ + .headerSearchPath("src"), + .headerSearchPath("deps/darts-clone"), + .headerSearchPath("deps/marisa-0.2.6/include"), + .headerSearchPath("deps/marisa-0.2.6/lib"), + .define("ENABLE_DARTS"), + ]), + ], + cxxLanguageStandard: .cxx14 +) diff --git a/Packages/SwiftyOpenCC/README.md b/Packages/SwiftyOpenCC/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c728a1ca865f85ac2af9a82a6bc3bb1b1e542479 --- /dev/null +++ b/Packages/SwiftyOpenCC/README.md @@ -0,0 +1,33 @@ +# Swifty Open Chinese Convert + +[![Github CI Status](https://github.com/ddddxxx/SwiftyOpenCC/workflows/CI/badge.svg)](https://github.com/ddddxxx/SwiftyOpenCC/actions) +![platforms](https://img.shields.io/badge/platforms-Linux%20%7C%20macOS%20%7C%20iOS%20%7C%20tvOS%20%7C%20watchOS-lightgrey.svg) +[![codebeat badge](https://codebeat.co/badges/39f17620-4f1c-4a46-b3f9-8f5b248ac28f)](https://codebeat.co/projects/github-com-ddddxxx-swiftyopencc-master) + +Swift port of [Open Chinese Convert](https://github.com/BYVoid/OpenCC) + +## Requirements + +- macOS 10.10+ / iOS 8.0+ / tvOS 9.0+ / watchOS 2.0+ +- Swift 5.0 + +## Usage + +### Quick Start + +```swift +import OpenCC + +let str = "鼠标里面的硅二极管坏了,导致光标分辨率降低。" +let converter = try! ChineseConverter(option: [.traditionalize, .twStandard, .twIdiom]) +converter.convert(str) +// 滑鼠裡面的矽二極體壞了,導致游標解析度降低。 +``` + +## Documentation + +[Github Pages](http://ddddxxx.github.io/SwiftyOpenCC) (100% Documented) + +## License + +SwiftyOpenCC is available under the MIT license. See the [LICENSE file](LICENSE). diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/ChineseConverter.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/ChineseConverter.swift new file mode 100644 index 0000000000000000000000000000000000000000..18574bc9c2c3e9a6ac14c5766347c9ac6ea7bb47 --- /dev/null +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/ChineseConverter.swift @@ -0,0 +1,83 @@ +// +// ChineseConverter.swift +// OpenCC +// +// Created by ddddxxx on 2017/3/9. +// + +import Foundation +import copencc + +/// The `ChineseConverter` class is used to represent and apply conversion +/// between Traditional Chinese and Simplified Chinese to Unicode strings. +/// An instance of this class is an immutable representation of a compiled +/// conversion pattern. +/// +/// The `ChineseConverter` supporting character-level conversion, phrase-level +/// conversion, variant conversion and regional idioms among Mainland China, +/// Taiwan and HongKong +/// +/// `ChineseConverter` is designed to be immutable and threadsafe, so that +/// a single instance can be used in conversion on multiple threads at once. +/// However, the string on which it is operating should not be mutated +/// during the course of a conversion. +public class ChineseConverter { + + /// These constants define the ChineseConverter options. + public struct Options: OptionSet { + + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + + /// Convert to Traditional Chinese. (default) + public static let traditionalize = Options(rawValue: 1 << 0) + + /// Convert to Simplified Chinese. + public static let simplify = Options(rawValue: 1 << 1) + + /// Use Taiwan standard. + public static let twStandard = Options(rawValue: 1 << 5) + + /// Use HongKong standard. + public static let hkStandard = Options(rawValue: 1 << 6) + + /// Taiwanese idiom conversion. + public static let twIdiom = Options(rawValue: 1 << 10) + } + + private let seg: ConversionDictionary + private let chain: [ConversionDictionary] + + private let converter: CCConverterRef + + private init(loader: DictionaryLoader, options: Options) throws { + seg = try loader.segmentation(options: options) + chain = try loader.conversionChain(options: options) + var rawChain = chain.map { $0.dict } + converter = CCConverterCreate("SwiftyOpenCC", seg.dict, &rawChain, rawChain.count) + } + + /// Returns an initialized `ChineseConverter` instance with the specified + /// conversion options. + /// + /// - Parameter options: The convert’s options. + /// - Throws: Throws `ConversionError` if failed. + public convenience init(options: Options) throws { + let loader = DictionaryLoader(bundle: .module) + try self.init(loader: loader, options: options) + } + + /// Return a converted string using the convert’s current option. + /// + /// - Parameter text: The string to convert. + /// - Returns: A converted string using the convert’s current option. + public func convert(_ text: String) -> String { + let stlStr = CCConverterCreateConvertedStringFromString(converter, text)! + defer { STLStringDestroy(stlStr) } + return String(utf8String: STLStringGetUTF8String(stlStr))! + } + +} diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionDictionary.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionDictionary.swift new file mode 100644 index 0000000000000000000000000000000000000000..c91d515f7c6c60b0073dc07af5504360ad71617e --- /dev/null +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionDictionary.swift @@ -0,0 +1,30 @@ +// +// ConversionDictionary.swift +// OpenCC +// +// Created by ddddxxx on 2020/1/3. +// + +import Foundation +import copencc + +class ConversionDictionary { + + let group: [ConversionDictionary] + + let dict: CCDictRef + + init(path: String) throws { + guard let dict = CCDictCreateMarisaWithPath(path) else { + throw ConversionError(ccErrorno) + } + self.group = [] + self.dict = dict + } + + init(group: [ConversionDictionary]) { + var rawGroup = group.map { $0.dict } + self.group = group + self.dict = CCDictCreateWithGroup(&rawGroup, rawGroup.count) + } +} diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionError.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionError.swift new file mode 100644 index 0000000000000000000000000000000000000000..d0114359a4cc254311f9807d98c5ee7b533219d3 --- /dev/null +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionError.swift @@ -0,0 +1,37 @@ +// +// ConversionError.swift +// OpenCC +// +// Created by ddddxxx on 2020/1/3. +// + +import Foundation +import copencc + +public enum ConversionError: Error { + + case fileNotFound + + case invalidFormat + + case invalidTextDictionary + + case invalidUTF8 + + case unknown + + init(_ code: CCErrorCode) { + switch code { + case .fileNotFound: + self = .fileNotFound + case .invalidFormat: + self = .invalidFormat + case .invalidTextDictionary: + self = .invalidTextDictionary + case .invalidUTF8: + self = .invalidUTF8 + case .unknown, _: + self = .unknown + } + } +} diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/HKVariants.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/HKVariants.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..fa2edde1c2980919b1099f75b80a6bbdfa3a82c0 Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/HKVariants.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/HKVariantsRev.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/HKVariantsRev.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..abc97a940bb2dc080102337f835151d89d88a25f Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/HKVariantsRev.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/HKVariantsRevPhrases.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/HKVariantsRevPhrases.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..84822772424b640a4fd06aa54c006ae538258e37 Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/HKVariantsRevPhrases.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPShinjitaiCharacters.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPShinjitaiCharacters.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..23e59125bb05f6211406de555beb1f2bef829290 Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPShinjitaiCharacters.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPShinjitaiPhrases.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPShinjitaiPhrases.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..e4c823f11432f9720b4dab7706b3c493fa0fb0b5 Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPShinjitaiPhrases.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPVariants.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPVariants.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..68b9e5b1ea6a5cc10b08ffcfd068a1134dd23aac Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPVariants.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPVariantsRev.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPVariantsRev.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..bcca7d364b5f050c61b79563c379bda6b3888dfd Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/JPVariantsRev.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/STCharacters.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/STCharacters.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..554b4310e09b398f34c1901e7102fe179ebbac74 Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/STCharacters.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/STPhrases.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/STPhrases.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..a5ac4ec8d5c36a6a7a28013740d67ef7a2b7470e Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/STPhrases.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TSCharacters.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TSCharacters.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..042cf4232b5caff30932375e502cae9800e1037a Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TSCharacters.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TSPhrases.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TSPhrases.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..d93d3599722ffec0bf0d74039f3c3e08722474d3 Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TSPhrases.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWPhrases.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWPhrases.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..0b0028f95b86ded8141f690c420b50ccc996f258 Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWPhrases.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWPhrasesRev.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWPhrasesRev.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..b0fffa808631cc751df09cc8d7f63ca5ec7b3b16 Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWPhrasesRev.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWVariants.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWVariants.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..8d74395586e0ba932d2e371e0a704eb6bdbe8553 Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWVariants.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWVariantsRev.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWVariantsRev.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..2546811c433ecf42d365a1e32bf6e3b8dfa50e1e Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWVariantsRev.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWVariantsRevPhrases.ocd2 b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWVariantsRevPhrases.ocd2 new file mode 100644 index 0000000000000000000000000000000000000000..95f26afcc34b844e4b91ba23df91776b5f1783e5 Binary files /dev/null and b/Packages/SwiftyOpenCC/Sources/OpenCC/Dictionary/TWVariantsRevPhrases.ocd2 differ diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryLoader.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryLoader.swift new file mode 100644 index 0000000000000000000000000000000000000000..d97b11ef3d6ca3f894584b806929865a00a8fb78 --- /dev/null +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryLoader.swift @@ -0,0 +1,55 @@ +// +// DictionaryLoader.swift +// OpenCC +// +// Created by ddddxxx on 2018/5/5. +// + +import Foundation +import copencc + +extension ChineseConverter { + + struct DictionaryLoader { + + private static let subdirectory = "Dictionary" + private static let dictCache = WeakValueCache() + + private let bundle: Bundle + + init(bundle: Bundle) { + self.bundle = bundle + } + + func dict(_ name: ChineseConverter.DictionaryName) throws -> ConversionDictionary { + guard let path = bundle.path(forResource: name.description, ofType: "ocd2", inDirectory: DictionaryLoader.subdirectory) else { + throw ConversionError.fileNotFound + } + return try DictionaryLoader.dictCache.value(for: path) { + return try ConversionDictionary(path: path) + } + } + } +} + +extension ChineseConverter.DictionaryLoader { + + func segmentation(options: ChineseConverter.Options) throws -> ConversionDictionary { + let dictName = options.segmentationDictName + return try dict(dictName) + } + + func conversionChain(options: ChineseConverter.Options) throws -> [ConversionDictionary] { + return try options.conversionChain.compactMap { names in + switch names.count { + case 0: + return nil + case 1: + return try dict(names.first!) + case _: + let dicts = try names.map(dict) + return ConversionDictionary(group: dicts) + } + } + } +} diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryName.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryName.swift new file mode 100644 index 0000000000000000000000000000000000000000..c64b95c19fd0a2d905700c74a5c02cf601a73514 --- /dev/null +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryName.swift @@ -0,0 +1,98 @@ +// +// DictionaryName.swift +// OpenCC +// +// Created by ddddxxx on 2019/9/16. +// + +import Foundation + +extension ChineseConverter { + + enum DictionaryName: CustomStringConvertible { + + case hkVariants + case hkVariantsRev + case hkVariantsRevPhrases + case jpVariants + case stCharacters + case stPhrases + case tsCharacters + case tsPhrases + case twPhrases + case twPhrasesRev + case twVariants + case twVariantsRev + case twVariantsRevPhrases + + var description: String { + switch self { + case .hkVariants: return "HKVariants" + case .hkVariantsRev: return "HKVariantsRev" + case .hkVariantsRevPhrases: return "HKVariantsRevPhrases" + case .jpVariants: return "JPVariants" + case .stCharacters: return "STCharacters" + case .stPhrases: return "STPhrases" + case .tsCharacters: return "TSCharacters" + case .tsPhrases: return "TSPhrases" + case .twPhrases: return "TWPhrases" + case .twPhrasesRev: return "TWPhrasesRev" + case .twVariants: return "TWVariants" + case .twVariantsRev: return "TWVariantsRev" + case .twVariantsRevPhrases: return "TWVariantsRevPhrases" + } + } + } +} + +extension ChineseConverter.Options { + + var segmentationDictName: ChineseConverter.DictionaryName { + if contains(.traditionalize) { + return .stPhrases + } else if contains(.simplify) { + return .tsPhrases + } else if contains(.hkStandard) { + return .hkVariants + } else if contains(.twStandard) { + return .twVariants + } else { + return .stPhrases + } + } + + var conversionChain: [[ChineseConverter.DictionaryName]] { + var result: [[ChineseConverter.DictionaryName]] = [] + if contains(.traditionalize) { + result.append([.stPhrases, .stCharacters]) + if contains(.twIdiom) { + result.append([.twPhrases]) + } + if contains(.hkStandard) { + result.append([.hkVariants]) + } else if contains(.twStandard) { + result.append([.twVariants]) + } + } else if contains(.simplify) { + if contains(.hkStandard) { + result.append([.hkVariantsRevPhrases, .hkVariantsRev]) + } else if contains(.twStandard) { + result.append([.twVariantsRevPhrases, .twVariantsRev]) + } + if contains(.twIdiom) { + result.append([.twPhrasesRev]) + } + result.append([.tsPhrases, .tsCharacters]) + } else { + if contains(.hkStandard) { + result.append([.hkVariants]) + } else if contains(.twStandard) { + result.append([.twVariants]) + } + } + if result.isEmpty { + return [[.stPhrases, .stCharacters]] + } + return result + } +} diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/WeakValueCache.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/WeakValueCache.swift new file mode 100644 index 0000000000000000000000000000000000000000..648361fce2f0c71cfc37b27d4c5a1919eaf48131 --- /dev/null +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/WeakValueCache.swift @@ -0,0 +1,42 @@ +// +// WeakValueCache.swift +// OpenCC +// +// Created by ddddxxx on 2020/1/3. +// + +import Foundation + +class WeakBox { + + private(set) weak var value: Value? + + init(_ value: Value) { + self.value = value + } +} + +class WeakValueCache { + + private var storage: [Key: WeakBox] = [:] + + private var lock = NSLock() + + func value(for key: Key) -> Value? { + return storage[key]?.value + } + + func value(for key: Key, make: () throws -> Value) rethrows -> Value { + if let value = storage[key]?.value { + return value + } + lock.lock() + defer { lock.unlock() } + if let value = storage[key]?.value { + return value + } + let value = try make() + storage[key] = WeakBox(value) + return value + } +} diff --git a/Packages/SwiftyOpenCC/Sources/copencc/deps b/Packages/SwiftyOpenCC/Sources/copencc/deps new file mode 120000 index 0000000000000000000000000000000000000000..61916ef542d41d1691b750d8ae4d72b692b41962 --- /dev/null +++ b/Packages/SwiftyOpenCC/Sources/copencc/deps @@ -0,0 +1 @@ +../../OpenCC/deps \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/Sources/copencc/include/header.h b/Packages/SwiftyOpenCC/Sources/copencc/include/header.h new file mode 100644 index 0000000000000000000000000000000000000000..d40f6f763a0b630a791ce3190f587e4f92bc918f --- /dev/null +++ b/Packages/SwiftyOpenCC/Sources/copencc/include/header.h @@ -0,0 +1,52 @@ +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +// MARK: Error + +enum CCErrorCode { + CCErrorCodeFileNotFound = 1, + CCErrorCodeInvalidFormat, + CCErrorCodeInvalidTextDictionary, + CCErrorCodeInvalidUTF8, + CCErrorCodeUnknown, +} __attribute__((enum_extensibility(open))); + +typedef enum CCErrorCode CCErrorCode; + +CCErrorCode ccErrorno; + +// MARK: CCDict + +typedef void* CCDictRef; + +CCDictRef _Nullable CCDictCreateDartsWithPath(const char * _Nonnull path); + +CCDictRef _Nullable CCDictCreateMarisaWithPath(const char * _Nonnull path); + +CCDictRef _Nonnull CCDictCreateWithGroup(CCDictRef _Nonnull * const _Nonnull dictGroup, intptr_t count); + +void CCDictDestroy(CCDictRef _Nonnull dict); + +// MARK: CCConverter + +typedef void* CCConverterRef; + +CCConverterRef _Nonnull CCConverterCreate(const char * _Nonnull name, CCDictRef _Nonnull segmentation, CCDictRef _Nonnull * const _Nonnull conversionChain, intptr_t chainCount); + +void CCConverterDestroy(CCConverterRef _Nonnull dict); + +typedef void* STLString; + +STLString _Nullable CCConverterCreateConvertedStringFromString(CCConverterRef _Nonnull converter, const char * _Nonnull str); + +const char* _Nonnull STLStringGetUTF8String(STLString _Nonnull str); + +void STLStringDestroy(STLString _Nonnull str); + +#ifdef __cplusplus +} +#endif diff --git a/Packages/SwiftyOpenCC/Sources/copencc/include/module.modulemap b/Packages/SwiftyOpenCC/Sources/copencc/include/module.modulemap new file mode 100644 index 0000000000000000000000000000000000000000..331a67b3316795b361a9eae9597f6088a9d9e333 --- /dev/null +++ b/Packages/SwiftyOpenCC/Sources/copencc/include/module.modulemap @@ -0,0 +1,4 @@ +module copencc { + header "header.h" + export * +} diff --git a/Packages/SwiftyOpenCC/Sources/copencc/source.cpp b/Packages/SwiftyOpenCC/Sources/copencc/source.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06eb15dc5106797654cbc22378db1fb1451a8093 --- /dev/null +++ b/Packages/SwiftyOpenCC/Sources/copencc/source.cpp @@ -0,0 +1,105 @@ +#include "DartsDict.hpp" +#include "DictGroup.hpp" +#include "Converter.hpp" +#include "MarisaDict.hpp" +#include "MaxMatchSegmentation.hpp" +#include "Conversion.hpp" +#include "ConversionChain.hpp" + +#include "header.h" + +// MARK: Error + +void* catchOpenCCException(void* (^block)()) { + try { + return block(); + } catch (opencc::FileNotFound& ex) { + ccErrorno = CCErrorCodeFileNotFound; + return NULL; + } catch (opencc::InvalidFormat& ex) { + ccErrorno = CCErrorCodeInvalidFormat; + return NULL; + } catch (opencc::InvalidTextDictionary& ex) { + ccErrorno = CCErrorCodeInvalidTextDictionary; + return NULL; + } catch (opencc::InvalidUTF8& ex) { + ccErrorno = CCErrorCodeInvalidUTF8; + return NULL; + } catch (opencc::Exception& ex) { + ccErrorno = CCErrorCodeUnknown; + return NULL; + } +} + +// MARK: CCDict + +CCDictRef _Nullable CCDictCreateDartsWithPath(const char * _Nonnull path) { + return catchOpenCCException(^{ + auto dict = opencc::SerializableDict::NewFromFile(std::string(path)); + auto dictPtr = new opencc::DictPtr(dict); + return static_cast(dictPtr); + }); +} + +CCDictRef _Nullable CCDictCreateMarisaWithPath(const char * _Nonnull path) { + return catchOpenCCException(^{ + auto dict = opencc::SerializableDict::NewFromFile(std::string(path)); + auto dictPtr = new opencc::DictPtr(dict); + return static_cast(dictPtr); + }); +} + +CCDictRef _Nonnull CCDictCreateWithGroup(CCDictRef _Nonnull * const _Nonnull dictGroup, intptr_t count) { + std::list list; + for (int i=0; i(dictGroup[i]); + list.push_back(*dictPtr); + } + auto dict = new opencc::DictGroupPtr(new opencc::DictGroup(list)); + return static_cast(dict); +} + +void CCDictDestroy(CCDictRef _Nonnull dict) { + auto *dictPtr = static_cast(dict); + dictPtr->reset(); +} + +// MARK: CCConverter + +CCConverterRef _Nonnull CCConverterCreate(const char * _Nonnull name, CCDictRef _Nonnull segmentation, CCDictRef _Nonnull * const _Nonnull conversionChain, intptr_t chainCount) { + auto *segmentationPtr = static_cast(segmentation); + std::list conversions; + for (int i=0; i(conversionChain[i]); + auto conversion = opencc::ConversionPtr(new opencc::Conversion(*dictPtr)); + conversions.push_back(conversion); + } + auto covName = std::string(name); + auto covSeg = opencc::SegmentationPtr(new opencc::MaxMatchSegmentation(*segmentationPtr)); + auto covChain = opencc::ConversionChainPtr(new opencc::ConversionChain(conversions)); + auto converter = new opencc::Converter(covName, covSeg, covChain); + return static_cast(converter); +} + +void CCConverterDestroy(CCConverterRef _Nonnull dict) { + auto converter = static_cast(dict); + delete converter; +} + +STLString _Nullable CCConverterCreateConvertedStringFromString(CCConverterRef _Nonnull converter, const char * _Nonnull str) { + return catchOpenCCException(^{ + auto converterPtr = static_cast(converter); + auto string = new std::string(converterPtr->Convert(str)); + return static_cast(string); + }); +} + +const char* _Nonnull STLStringGetUTF8String(STLString _Nonnull str) { + auto string = static_cast(str); + return string->c_str(); +} + +void STLStringDestroy(STLString _Nonnull str) { + auto string = static_cast(str); + delete string; +} diff --git a/Packages/SwiftyOpenCC/Sources/copencc/src b/Packages/SwiftyOpenCC/Sources/copencc/src new file mode 120000 index 0000000000000000000000000000000000000000..0490c40d28b8595a730ceba7bd30527d60686cd8 --- /dev/null +++ b/Packages/SwiftyOpenCC/Sources/copencc/src @@ -0,0 +1 @@ +../../OpenCC/src \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/Tests/LinuxMain.swift b/Packages/SwiftyOpenCC/Tests/LinuxMain.swift new file mode 100644 index 0000000000000000000000000000000000000000..08eef2625fb16e4ff11da6ac031d4e365f6688cc --- /dev/null +++ b/Packages/SwiftyOpenCC/Tests/LinuxMain.swift @@ -0,0 +1 @@ +fatalError("Run the tests with `swift test --enable-test-discovery`.") diff --git a/Packages/SwiftyOpenCC/Tests/OpenCCTests/OpenCCTests.swift b/Packages/SwiftyOpenCC/Tests/OpenCCTests/OpenCCTests.swift new file mode 100644 index 0000000000000000000000000000000000000000..03c7d0937cf5b619375aa734f279d321b31f77bb --- /dev/null +++ b/Packages/SwiftyOpenCC/Tests/OpenCCTests/OpenCCTests.swift @@ -0,0 +1,64 @@ +import XCTest +@testable import OpenCC + +let testCases: [(String, ChineseConverter.Options)] = [ + ("s2t", [.traditionalize]), + ("t2s", [.simplify]), + ("s2hk", [.traditionalize, .hkStandard]), + ("hk2s", [.simplify, .hkStandard]), + ("s2tw", [.traditionalize, .twStandard]), + ("tw2s", [.simplify, .twStandard]), + ("s2twp", [.traditionalize, .twStandard, .twIdiom]), + ("tw2sp", [.simplify, .twStandard, .twIdiom]), +] + +class OpenCCTests: XCTestCase { + + func converter(option: ChineseConverter.Options) throws -> ChineseConverter { + return try ChineseConverter(options: option) + } + + func testConversion() throws { + func testCase(name: String, ext: String) -> String { + let url = Bundle.module.url(forResource: name, withExtension: ext, subdirectory: "testcases")! + return try! String(contentsOf: url) + } + for (name, opt) in testCases { + let coverter = try ChineseConverter(options: opt) + let input = testCase(name: name, ext: "in") + let converted = coverter.convert(input) + let output = testCase(name: name, ext: "ans") + XCTAssertEqual(converted, output, "Conversion \(name) fails") + } + } + + func testConverterCreationPerformance() { + let options: ChineseConverter.Options = [.traditionalize, .twStandard, .twIdiom] + measure { + for _ in 0..<10 { + _ = try! ChineseConverter(options: options) + } + } + } + + func testDictionaryCache() { + let options: ChineseConverter.Options = [.traditionalize, .twStandard, .twIdiom] + let holder = try! ChineseConverter(options: options) + measure { + for _ in 0..<1_000 { + _ = try! ChineseConverter(options: options) + } + } + _ = holder.convert("foo") + } + + func testConversionPerformance() throws { + let cov = try converter(option: [.traditionalize, .twStandard, .twIdiom]) + let url = Bundle.module.url(forResource: "zuozhuan", withExtension: "txt", subdirectory: "benchmark")! + // 1.9 MB, 624k word + let str = try String(contentsOf: url) + measure { + _ = cov.convert(str) + } + } +} diff --git a/Packages/SwiftyOpenCC/Tests/OpenCCTests/benchmark b/Packages/SwiftyOpenCC/Tests/OpenCCTests/benchmark new file mode 120000 index 0000000000000000000000000000000000000000..9caed6676edae00d59dfa904ff6eb7eaf1273464 --- /dev/null +++ b/Packages/SwiftyOpenCC/Tests/OpenCCTests/benchmark @@ -0,0 +1 @@ +../../OpenCC/test/benchmark \ No newline at end of file diff --git a/Packages/SwiftyOpenCC/Tests/OpenCCTests/testcases b/Packages/SwiftyOpenCC/Tests/OpenCCTests/testcases new file mode 120000 index 0000000000000000000000000000000000000000..d62c66ccf662b9eae1e2acd89d851687adbf74f0 --- /dev/null +++ b/Packages/SwiftyOpenCC/Tests/OpenCCTests/testcases @@ -0,0 +1 @@ +../../OpenCC/test/testcases \ No newline at end of file diff --git a/Packages/VXHanConvert/.gitignore b/Packages/VXHanConvert/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..bb460e7be912c891c334b80bcba6f61383c00f96 --- /dev/null +++ b/Packages/VXHanConvert/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata diff --git a/Packages/VXHanConvert/Package.swift b/Packages/VXHanConvert/Package.swift new file mode 100644 index 0000000000000000000000000000000000000000..47fdc5dc14e9fb9cc21548e288808c18c949f997 --- /dev/null +++ b/Packages/VXHanConvert/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version:5.3 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "VXHanConvert", + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "VXHanConvert", + targets: ["VXHanConvert"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "VXHanConvert", + dependencies: []), + .testTarget( + name: "VXHanConvertTests", + dependencies: ["VXHanConvert"]), + ] +) diff --git a/Packages/VXHanConvert/README.md b/Packages/VXHanConvert/README.md new file mode 100644 index 0000000000000000000000000000000000000000..87d74cc7007fe7e8cbdcab7bdb6ef9c9fdcc488c --- /dev/null +++ b/Packages/VXHanConvert/README.md @@ -0,0 +1,3 @@ +# VXHanConvert + +A description of this package. diff --git a/Packages/VXHanConvert/Sources/VXHanConvert/VXHCSC2TCTable.c b/Packages/VXHanConvert/Sources/VXHanConvert/VXHCSC2TCTable.c new file mode 100644 index 0000000000000000000000000000000000000000..c5102d69bfd80af1c0a60d5c8297531eec72b943 --- /dev/null +++ b/Packages/VXHanConvert/Sources/VXHanConvert/VXHCSC2TCTable.c @@ -0,0 +1,1676 @@ +/* VXHCSC2TCTable.c: Simplified Chinese -> Traditional Chinese conv. table + * (VX is abbr. for Vanilla OS X, a legacy from OpenVanilla 0.6.x) + * + * Copyright (c) 2004-2007 The OpenVanilla Project (http://openvanilla.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OpenVanilla nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The data is derived from Perl's Encode::HanConvert (0.31), + * Copyright (c) 2002-2004 by Autrijus Tang + * + */ + +unsigned short vxSC2TCTable[8189*2]={ +0x0000,0x0000, 0x0001,0x0001, 0x00a4,0x25ce, 0x00a8,0x2025, 0x00b7,0x2027, +0x00e0,0xff41, 0x00e1,0xff41, 0x00e8,0xff45, 0x00e9,0xff45, 0x00ea,0xff45, +0x00ec,0xff49, 0x00ed,0xff49, 0x00f2,0xff4f, 0x00f3,0xff4f, 0x00f9,0xff55, +0x00fc,0xff55, 0x0101,0xff41, 0x0113,0xff45, 0x011b,0xff45, 0x012b,0xff49, +0x0144,0xff4e, 0x0148,0xff4e, 0x014d,0xff4f, 0x016b,0xff55, 0x01ce,0xff41, +0x01d0,0xff49, 0x01d2,0xff4f, 0x01d4,0xff55, 0x01d6,0xff55, 0x01d8,0xff55, +0x01da,0xff55, 0x01dc,0xff55, 0x0251,0xff41, 0x0261,0xff47, 0x02c9,0x00af, +0x042f,0x30cb, 0x0430,0x30cc, 0x2010,0xff0d, 0x2014,0x2500, 0x2015,0x2500, +0x2016,0x2225, 0x2030,0x2105, 0x2033,0x301e, 0x2121,0x25a1, 0x216a,0xff38, +0x216b,0xff38, 0x2170,0x25a1, 0x2171,0x25a1, 0x2172,0x25a1, 0x2173,0x25a1, +0x2174,0x25a1, 0x2175,0x25a1, 0x2176,0x25a1, 0x2177,0x25a1, 0x2178,0x25a1, +0x2179,0x25a1, 0x2208,0x0395, 0x220f,0x03a0, 0x2211,0x03a3, 0x221d,0x03b1, +0x2227,0x039b, 0x2228,0xff36, 0x2236,0xfe30, 0x2237,0x203b, 0x223d,0xff5e, +0x2248,0x2252, 0x224c,0x2252, 0x2264,0x2266, 0x2265,0x2267, 0x226e,0x2190, +0x226f,0x2192, 0x2312,0xfe35, 0x247e,0xff11, 0x247f,0xff12, 0x2480,0xff13, +0x2481,0xff14, 0x2482,0xff15, 0x2483,0xff16, 0x2484,0xff17, 0x2485,0xff18, +0x2486,0xff19, 0x2487,0xff10, 0x2488,0xff11, 0x2489,0xff12, 0x248a,0xff13, +0x248b,0xff14, 0x248c,0xff15, 0x248d,0xff16, 0x248e,0xff17, 0x248f,0xff18, +0x2490,0xff19, 0x2491,0xff10, 0x2492,0xff11, 0x2493,0xff12, 0x2494,0xff13, +0x2495,0xff14, 0x2496,0xff15, 0x2497,0xff16, 0x2498,0xff17, 0x2499,0xff18, +0x249a,0xff19, 0x249b,0xff10, 0x2501,0x2550, 0x2503,0xff5c, 0x2504,0x2026, +0x2505,0x2026, 0x2506,0xff5c, 0x2507,0xff5c, 0x2508,0x2014, 0x2509,0x2013, +0x250a,0xff5c, 0x250b,0xff5c, 0x250d,0x250c, 0x250e,0x250c, 0x250f,0x250c, +0x2511,0x2510, 0x2512,0x2510, 0x2513,0x2510, 0x2515,0x2514, 0x2516,0x2514, +0x2517,0x2514, 0x2519,0x2518, 0x251a,0x2518, 0x251b,0x2518, 0x251d,0x255e, +0x251e,0x251c, 0x251f,0x251c, 0x2520,0x251c, 0x2521,0x251c, 0x2522,0x251c, +0x2523,0x251c, 0x2525,0x2561, 0x2526,0x2524, 0x2527,0x2524, 0x2528,0x2524, +0x2529,0x2524, 0x252a,0x2524, 0x252b,0x2524, 0x252d,0x252c, 0x252e,0x252c, +0x252f,0x252c, 0x2530,0x252c, 0x2531,0x252c, 0x2532,0x252c, 0x2533,0x252c, +0x2535,0x2534, 0x2536,0x2534, 0x2537,0x2534, 0x2538,0x2534, 0x2539,0x2534, +0x253a,0x2534, 0x253b,0x2534, 0x253d,0x253c, 0x253e,0x253c, 0x253f,0x256a, +0x2540,0x253c, 0x2541,0x253c, 0x2542,0x253c, 0x2543,0x253c, 0x2544,0x253c, +0x2545,0x253c, 0x2546,0x253c, 0x2547,0x253c, 0x2548,0x253c, 0x2549,0x253c, +0x254a,0x253c, 0x254b,0x253c, 0x2554,0xffe5, 0x2557,0x201d, 0x255a,0x300a, +0x255d,0x32a3, 0x2588,0x2593, 0x2609,0x2299, 0x3006,0x25a1, 0x3007,0x25a1, +0x3013,0x2550, 0x3016,0x3010, 0x3017,0x3011, 0x309b,0x201c, 0x309c,0x3002, +0x309d,0x2461, 0x309e,0x2462, 0x30fc,0x2500, 0x30fd,0x3001, 0x30fe,0x2460, +0x3220,0x4e00, 0x3221,0x4e8c, 0x3222,0x4e09, 0x3223,0x56db, 0x3224,0x4e94, +0x3225,0x516d, 0x3226,0x4e03, 0x3227,0x516b, 0x3228,0x4e5d, 0x3229,0x5341, +0x3231,0x25a1, 0x4e02,0x25a1, 0x4e04,0x25a1, 0x4e05,0x25a1, 0x4e06,0x25a1, +0x4e07,0x842c, 0x4e0e,0x8207, 0x4e11,0x919c, 0x4e12,0x56df, 0x4e13,0x5c08, +0x4e17,0x5345, 0x4e1a,0x696d, 0x4e1b,0x53e2, 0x4e1c,0x6771, 0x4e1d,0x7d72, +0x4e20,0x25a1, 0x4e21,0x5169, 0x4e22,0x4e1f, 0x4e23,0x25a1, 0x4e24,0x5169, +0x4e25,0x56b4, 0x4e27,0x55aa, 0x4e28,0xff5c, 0x4e29,0x25a1, 0x4e2a,0x500b, +0x4e2c,0x723f, 0x4e2f,0x4e30, 0x4e30,0x8c50, 0x4e34,0x81e8, 0x4e35,0x25a1, +0x4e36,0x2f02, 0x4e37,0x25a1, 0x4e3a,0x70ba, 0x4e3d,0x9e97, 0x4e3e,0x8209, +0x4e3f,0x2f03, 0x4e40,0x25a1, 0x4e41,0x25a1, 0x4e44,0x25a1, 0x4e46,0x25a1, +0x4e48,0x9ebc, 0x4e49,0x7fa9, 0x4e4a,0x25a1, 0x4e4c,0x70cf, 0x4e50,0x6a02, +0x4e51,0x25a1, 0x4e54,0x55ac, 0x4e55,0x25a1, 0x4e57,0x25a1, 0x4e5a,0x25a1, +0x4e5b,0x25a1, 0x4e60,0x7fd2, 0x4e61,0x9109, 0x4e62,0x25a1, 0x4e63,0x25a1, +0x4e64,0x25a1, 0x4e65,0x25a1, 0x4e66,0x66f8, 0x4e67,0x25a1, 0x4e68,0x25a1, +0x4e6a,0x25a1, 0x4e6b,0x25a1, 0x4e6c,0x25a1, 0x4e6d,0x25a1, 0x4e6e,0x25a1, +0x4e6f,0x25a1, 0x4e70,0x8cb7, 0x4e71,0x4e82, 0x4e72,0x25a1, 0x4e74,0x25a1, +0x4e75,0x25a1, 0x4e76,0x25a1, 0x4e77,0x25a1, 0x4e78,0x25a1, 0x4e79,0x25a1, +0x4e7a,0x25a1, 0x4e7b,0x25a1, 0x4e7c,0x25a1, 0x4e7d,0x25a1, 0x4e80,0x9f9c, +0x4e81,0x4e7e, 0x4e85,0x25a1, 0x4e87,0x25a1, 0x4e89,0x722d, 0x4e8a,0x25a1, +0x4e8f,0x8667, 0x4e90,0x25a1, 0x4e91,0x96f2, 0x4e96,0x25a1, 0x4e97,0x25a1, +0x4e98,0x4e99, 0x4e9a,0x4e9e, 0x4e9c,0x25a1, 0x4e9d,0x25a1, 0x4ea0,0x2f07, +0x4ea3,0x25a1, 0x4ea7,0x7522, 0x4ea9,0x755d, 0x4eaa,0x25a1, 0x4eaf,0x25a1, +0x4eb0,0x25a1, 0x4eb1,0x25a1, 0x4eb2,0x89aa, 0x4eb4,0x25a1, 0x4eb5,0x893b, +0x4eb7,0x25a1, 0x4eb8,0x56b2, 0x4ebb,0x4eba, 0x4ebc,0x25a1, 0x4ebd,0x25a1, +0x4ebe,0x25a1, 0x4ebf,0x5104, 0x4ec5,0x50c5, 0x4ec6,0x50d5, 0x4ecc,0x25a1, +0x4ece,0x5f9e, 0x4ecf,0x25a1, 0x4ed0,0x25a1, 0x4ed1,0x5d19, 0x4ed2,0x25a1, +0x4ed3,0x5009, 0x4edb,0x25a1, 0x4ee0,0x25a1, 0x4ee2,0x25a1, 0x4ee6,0x25a1, +0x4ee7,0x25a1, 0x4eea,0x5100, 0x4eeb,0x9ebc, 0x4eec,0x5011, 0x4eed,0x25a1, +0x4eee,0x5047, 0x4eef,0x25a1, 0x4ef7,0x50f9, 0x4ef8,0x25a1, 0x4ef9,0x25a1, +0x4efa,0x25a1, 0x4efc,0x25a1, 0x4efe,0x25a1, 0x4f03,0x25a1, 0x4f06,0x25a1, +0x4f07,0x25a1, 0x4f0c,0x25a1, 0x4f16,0x25a1, 0x4f17,0x773e, 0x4f18,0x512a, +0x4f1a,0x6703, 0x4f1b,0x50b4, 0x4f1c,0x25a1, 0x4f1e,0x5098, 0x4f1f,0x5049, +0x4f20,0x50b3, 0x4f21,0x25a1, 0x4f23,0x25a1, 0x4f24,0x50b7, 0x4f25,0x5000, +0x4f26,0x502b, 0x4f27,0x5096, 0x4f28,0x25a1, 0x4f29,0x25a1, 0x4f2a,0x507d, +0x4f2b,0x4f47, 0x4f2e,0x25a1, 0x4f31,0x25a1, 0x4f32,0x62b3, 0x4f35,0x25a1, +0x4f37,0x25a1, 0x4f39,0x25a1, 0x4f40,0x25a1, 0x4f42,0x25a1, 0x4f44,0x25a1, +0x4f45,0x25a1, 0x4f4a,0x25a1, 0x4f4b,0x25a1, 0x4f53,0x9ad4, 0x4f65,0x50c9, +0x4f66,0x25a1, 0x4f68,0x25a1, 0x4f6d,0x25a1, 0x4f71,0x25a1, 0x4f72,0x25a1, +0x4f8a,0x25a1, 0x4f8c,0x25a1, 0x4f8e,0x25a1, 0x4f93,0x25a1, 0x4f99,0x25a1, +0x4f9f,0x25a1, 0x4fa0,0x4fe0, 0x4fa1,0x25a1, 0x4fa2,0x25a1, 0x4fa3,0x4fb6, +0x4fa4,0x25a1, 0x4fa5,0x50e5, 0x4fa6,0x5075, 0x4fa7,0x5074, 0x4fa8,0x50d1, +0x4fa9,0x5108, 0x4faa,0x5115, 0x4fab,0x25a1, 0x4fac,0x5102, 0x4fad,0x25a1, +0x4fb0,0x25a1, 0x4fb1,0x25a1, 0x4fb4,0x25a1, 0x4fb8,0x25a1, 0x4fbc,0x25a1, +0x4fbd,0x25a1, 0x4fbe,0x25a1, 0x4fc6,0x25a1, 0x4fc8,0x25a1, 0x4fcc,0x25a1, +0x4fd2,0x25a1, 0x4fd5,0x25a1, 0x4fe2,0x25a1, 0x4fe3,0x4fc1, 0x4fe4,0x25a1, +0x4fe5,0x25a1, 0x4fe6,0x5114, 0x4fe7,0x25a1, 0x4fe8,0x513c, 0x4fe9,0x5006, +0x4fea,0x5137, 0x4feb,0x25a1, 0x4fed,0x5109, 0x4ff0,0x25a1, 0x4ff2,0x25a1, +0x4ff9,0x25a1, 0x4ffb,0x25a1, 0x4ffc,0x25a1, 0x4ffd,0x25a1, 0x4fff,0x25a1, +0x5001,0x25a1, 0x5002,0x25a1, 0x5003,0x25a1, 0x5004,0x25a1, 0x5008,0x25a1, +0x500a,0x25a1, 0x5010,0x25a1, 0x501d,0x25a1, 0x5024,0x25a1, 0x502e,0x60c8, +0x5032,0x25a1, 0x5034,0x25a1, 0x5036,0x25a1, 0x5038,0x25a1, 0x5039,0x25a1, +0x503a,0x50b5, 0x503b,0x25a1, 0x503d,0x25a1, 0x503e,0x50be, 0x503f,0x25a1, +0x5042,0x25a1, 0x5044,0x25a1, 0x5050,0x25a1, 0x5052,0x25a1, 0x5054,0x25a1, +0x5056,0x25a1, 0x5058,0x25a1, 0x5059,0x25a1, 0x5066,0x25a1, 0x5067,0x25a1, +0x506c,0x50af, 0x5071,0x25a1, 0x5078,0x25a1, 0x5079,0x25a1, 0x507b,0x50c2, +0x507c,0x25a1, 0x507e,0x50e8, 0x507f,0x511f, 0x5081,0x25a1, 0x5084,0x25a1, +0x5086,0x25a1, 0x5088,0x6144, 0x5089,0x25a1, 0x508a,0x25a1, 0x508f,0x25a1, +0x5090,0x25a1, 0x5093,0x25a1, 0x5097,0x25a1, 0x509f,0x25a1, 0x50a0,0x25a1, +0x50a1,0x25a1, 0x50a4,0x25a1, 0x50a5,0x513b, 0x50a6,0x25a1, 0x50a7,0x5110, +0x50a8,0x5132, 0x50a9,0x513a, 0x50aa,0x25a1, 0x50ab,0x25a1, 0x50b9,0x25a1, +0x50bc,0x25a1, 0x50c0,0x25a1, 0x50c3,0x25a1, 0x50cc,0x25a1, 0x50cd,0x25a1, +0x50d0,0x25a1, 0x50d2,0x25a1, 0x50d8,0x25a1, 0x50d9,0x25a1, 0x50dc,0x25a1, +0x50de,0x25a1, 0x50df,0x25a1, 0x50e1,0x25a1, 0x50e2,0x25a1, 0x50eb,0x25a1, +0x50f2,0x25a1, 0x50f4,0x25a1, 0x50f5,0x6bad, 0x50f7,0x25a1, 0x50fa,0x25a1, +0x50fc,0x25a1, 0x5101,0x25a1, 0x510d,0x25a1, 0x510e,0x25a1, 0x510f,0x25a1, +0x5116,0x25a1, 0x5119,0x25a1, 0x511b,0x25a1, 0x511d,0x25a1, 0x511e,0x25a1, +0x5123,0x25a1, 0x5127,0x25a1, 0x5128,0x25a1, 0x512b,0x25a1, 0x512c,0x25a1, +0x512f,0x25a1, 0x5136,0x25a1, 0x513e,0x25a1, 0x513f,0x5152, 0x5142,0x25a1, +0x514a,0x25a1, 0x514e,0x5154, 0x514f,0x25a1, 0x5150,0x25a1, 0x5151,0x514c, +0x5153,0x25a1, 0x5156,0x5157, 0x5158,0x25a1, 0x515a,0x9ee8, 0x5160,0x25a1, +0x5164,0x25a1, 0x5166,0x25a1, 0x516a,0x4fde, 0x516f,0x25a1, 0x5170,0x862d, +0x5172,0x25a1, 0x5173,0x95dc, 0x5174,0x8208, 0x5179,0x8332, 0x517a,0x25a1, +0x517b,0x990a, 0x517d,0x7378, 0x517e,0x7cde, 0x517f,0x85dd, 0x5181,0x56c5, +0x5182,0x2f0c, 0x5183,0x25a1, 0x5184,0x25a1, 0x5185,0x5167, 0x5186,0x4e39, +0x5188,0x5ca1, 0x518b,0x25a1, 0x518c,0x518a, 0x518e,0x25a1, 0x5190,0x25a1, +0x5196,0x2f0d, 0x5199,0x5beb, 0x519a,0x25a1, 0x519b,0x8ecd, 0x519c,0x8fb2, +0x519d,0x5b9c, 0x519f,0x25a1, 0x51a1,0x25a1, 0x51a2,0x585a, 0x51a3,0x25a1, +0x51a6,0x5bc7, 0x51a7,0x9716, 0x51a8,0x5bcc, 0x51a9,0x5beb, 0x51ab,0x2f0e, +0x51ad,0x25a1, 0x51ae,0x6c5f, 0x51af,0x99ae, 0x51b2,0x885d, 0x51b3,0x6c7a, +0x51b4,0x25a1, 0x51b5,0x6cc1, 0x51b8,0x6cee, 0x51ba,0x6cef, 0x51bb,0x51cd, +0x51bf,0x6d25, 0x51c0,0x6de8, 0x51c1,0x6d91, 0x51c2,0x6d7c, 0x51c3,0x6d82, +0x51c4,0x6dd2, 0x51c7,0x6dde, 0x51c9,0x6dbc, 0x51cf,0x6e1b, 0x51d1,0x6e4a, +0x51d2,0x6eb0, 0x51d3,0x6ea7, 0x51d5,0x6e9f, 0x51d6,0x6e96, 0x51d9,0x6fa4, +0x51da,0x6fbf, 0x51db,0x51dc, 0x51df,0x7006, 0x51e0,0x5e7e, 0x51e2,0x25a1, +0x51e3,0x25a1, 0x51e4,0x9cf3, 0x51e5,0x5c3b, 0x51e6,0x8655, 0x51e7,0x98a8, +0x51e8,0x4e91, 0x51e9,0x9591, 0x51ea,0x25a1, 0x51eb,0x9ce7, 0x51ec,0x51f0, +0x51ed,0x6191, 0x51ee,0x9cf3, 0x51ef,0x51f1, 0x51f2,0x25a1, 0x51f4,0x6191, +0x51f7,0x25a1, 0x51fb,0x64ca, 0x51fc,0x7a9e, 0x51fe,0x4e9f, 0x51ff,0x947f, +0x5204,0x5203, 0x5205,0x5203, 0x520b,0x520a, 0x520d,0x82bb, 0x520f,0x25a1, +0x5212,0x5283, 0x5214,0x25a1, 0x5215,0x25a1, 0x5218,0x5289, 0x5219,0x5247, +0x521a,0x525b, 0x521b,0x5275, 0x521f,0x25a1, 0x5220,0x522a, 0x5222,0x25a1, +0x5223,0x25a1, 0x5226,0x52ab, 0x5227,0x52ab, 0x522b,0x5225, 0x522c,0x25a1, +0x522d,0x5244, 0x522f,0x25a1, 0x5234,0x5241, 0x5239,0x524e, 0x523c,0x52ab, +0x523d,0x528a, 0x523e,0x25a1, 0x523f,0x528c, 0x5240,0x5274, 0x5242,0x5291, +0x5245,0x25a1, 0x5248,0x25a1, 0x524f,0x25a1, 0x5250,0x526e, 0x5251,0x528d, +0x5253,0x25a1, 0x5257,0x25a1, 0x5258,0x25a1, 0x5259,0x25a1, 0x5260,0x25a1, +0x5263,0x25a1, 0x5264,0x25a1, 0x5265,0x525d, 0x5266,0x25a1, 0x5267,0x5287, +0x5268,0x25a1, 0x5270,0x5269, 0x5271,0x25a1, 0x5273,0x25a1, 0x5276,0x25a1, +0x5279,0x25a1, 0x527e,0x25a1, 0x5285,0x25a1, 0x5286,0x25a1, 0x528e,0x528d, +0x528f,0x25a1, 0x5290,0x944a, 0x5292,0x528d, 0x5294,0x528d, 0x5295,0x25a1, +0x529a,0x25a1, 0x529c,0x25a1, 0x529d,0x52f8, 0x529e,0x8fa6, 0x52a1,0x52d9, +0x52a2,0x52f1, 0x52a4,0x25a1, 0x52a5,0x25a1, 0x52a7,0x25a1, 0x52a8,0x52d5, +0x52af,0x25a1, 0x52b0,0x6548, 0x52b1,0x52f5, 0x52b2,0x52c1, 0x52b3,0x52de, +0x52b4,0x52de, 0x52b5,0x5377, 0x52b6,0x25a1, 0x52b7,0x25a1, 0x52b8,0x25a1, +0x52b9,0x6548, 0x52ba,0x25a1, 0x52bd,0x88c2, 0x52bf,0x52e2, 0x52c4,0x25a1, +0x52c5,0x6555, 0x52c6,0x25a1, 0x52c8,0x25a1, 0x52ca,0x25a1, 0x52cb,0x52db, +0x52cc,0x25a1, 0x52ce,0x25a1, 0x52cf,0x25a1, 0x52d0,0x731b, 0x52d1,0x25a1, +0x52d4,0x25a1, 0x52da,0x52e9, 0x52dc,0x25a1, 0x52e0,0x622e, 0x52e1,0x25a1, +0x52e5,0x5f37, 0x52e7,0x52f8, 0x52e8,0x25a1, 0x52ea,0x25a1, 0x52ec,0x25a1, +0x52ed,0x25a1, 0x52ee,0x25a1, 0x52f2,0x52f3, 0x52f6,0x25a1, 0x52f9,0x2f13, +0x52fd,0x25a1, 0x5300,0x52fb, 0x5301,0x25a1, 0x5302,0x25a1, 0x5303,0x25a1, +0x5304,0x25a1, 0x5307,0x25a1, 0x530c,0x25a1, 0x5313,0x25a1, 0x5314,0x25a1, +0x5318,0x25a1, 0x531b,0x25a1, 0x531e,0x25a1, 0x5324,0x25a1, 0x5325,0x25a1, +0x5326,0x532d, 0x5327,0x25a1, 0x5328,0x25a1, 0x5329,0x25a1, 0x532b,0x25a1, +0x532c,0x25a1, 0x532e,0x5331, 0x5332,0x25a1, 0x5333,0x25a1, 0x5335,0x25a1, +0x5336,0x25a1, 0x5338,0x25a1, 0x533a,0x5340, 0x533b,0x91ab, 0x5342,0x25a1, +0x5344,0x3039, 0x5346,0x25a1, 0x534b,0x25a1, 0x534e,0x83ef, 0x534f,0x5354, +0x5350,0x534d, 0x5355,0x55ae, 0x5356,0x8ce3, 0x5358,0x55ae, 0x5359,0x659f, +0x535b,0x6523, 0x535d,0x25a1, 0x535f,0x5687, 0x5362,0x76e7, 0x5364,0x9e75, +0x5365,0x56df, 0x5367,0x81e5, 0x5368,0x25a1, 0x5369,0x2f19, 0x536a,0x25a1, +0x536b,0x885b, 0x536d,0x25a1, 0x5374,0x537b, 0x5376,0x25a1, 0x537a,0x5df9, +0x537d,0x25a1, 0x537e,0x25a1, 0x5380,0x25a1, 0x5381,0x25a1, 0x5382,0x5ee0, +0x5383,0x25a1, 0x5385,0x5ef3, 0x5386,0x6b77, 0x5387,0x25a1, 0x5388,0x25a1, +0x5389,0x53b2, 0x538b,0x58d3, 0x538c,0x53ad, 0x538d,0x5399, 0x5390,0x25a1, +0x5391,0x25a1, 0x5393,0x25a1, 0x5395,0x5ec1, 0x539b,0x5ef3, 0x53a0,0x5ec1, +0x53a1,0x25a1, 0x53a2,0x5ec2, 0x53a3,0x53b4, 0x53a6,0x5ec8, 0x53a8,0x5eda, +0x53a9,0x5ec4, 0x53aa,0x25a1, 0x53ab,0x25a1, 0x53ae,0x5edd, 0x53af,0x25a1, +0x53b0,0x5ee0, 0x53b1,0x25a1, 0x53b3,0x56b4, 0x53b5,0x25a1, 0x53b6,0x2f1b, +0x53b7,0x25a1, 0x53b8,0x25a1, 0x53ba,0x25a1, 0x53bc,0x25a1, 0x53bd,0x25a1, +0x53be,0x25a1, 0x53bf,0x7e23, 0x53c0,0x25a1, 0x53c1,0x53c3, 0x53c2,0x53c3, +0x53c4,0x53c3, 0x53c5,0x25a1, 0x53c6,0x9749, 0x53c7,0x9746, 0x53cc,0x96d9, +0x53ce,0x6536, 0x53cf,0x767c, 0x53d0,0x767c, 0x53d1,0x767c, 0x53d2,0x25a1, +0x53d3,0x25a1, 0x53d5,0x25a1, 0x53d8,0x8b8a, 0x53d9,0x6558, 0x53da,0x25a1, +0x53dc,0x25a1, 0x53dd,0x25a1, 0x53de,0x25a1, 0x53e0,0x758a, 0x53e7,0x53e6, +0x53f4,0x25a1, 0x53f6,0x8449, 0x53f7,0x865f, 0x53f9,0x5606, 0x53fa,0x25a1, +0x53fd,0x5630, 0x53fe,0x25a1, 0x53ff,0x25a1, 0x5400,0x25a1, 0x5401,0x7c72, +0x5402,0x25a1, 0x5405,0x25a1, 0x540e,0x5f8c, 0x5413,0x5687, 0x5414,0x8036, +0x5415,0x5442, 0x5416,0x55c4, 0x5417,0x55ce, 0x541a,0x25a1, 0x5421,0x55f6, +0x5422,0x25a1, 0x5423,0x551a, 0x5428,0x5678, 0x542c,0x807d, 0x542f,0x555f, +0x5432,0x5f15, 0x5434,0x5433, 0x543a,0x25a1, 0x543f,0x544a, 0x5444,0x25a1, +0x5449,0x25a1, 0x544b,0x5490, 0x544c,0x25a1, 0x544d,0x25a1, 0x5450,0x5436, +0x5451,0x541e, 0x5452,0x5638, 0x5453,0x56c8, 0x5455,0x5614, 0x5456,0x56a6, +0x5457,0x5504, 0x5458,0x54e1, 0x5459,0x54bc, 0x545a,0x25a1, 0x545b,0x55c6, +0x545c,0x55da, 0x545d,0x25a1, 0x545e,0x25a1, 0x545f,0x25a1, 0x5469,0x25a1, +0x546a,0x5492, 0x546d,0x25a1, 0x546e,0x25a1, 0x5479,0x25a1, 0x5483,0x25a1, +0x5485,0x25a1, 0x5489,0x25a1, 0x548a,0x25a1, 0x548f,0x8a60, 0x5493,0x25a1, +0x5494,0x54e2, 0x5497,0x25a1, 0x5499,0x56a8, 0x549b,0x5680, 0x549c,0x25a1, +0x549d,0x5431, 0x549e,0x25a1, 0x549f,0x25a1, 0x54a3,0x5149, 0x54a4,0x5412, +0x54b2,0x25a1, 0x54b4,0x5645, 0x54b5,0x25a1, 0x54b9,0x25a1, 0x54ca,0x25a1, +0x54cb,0x25a1, 0x54cc,0x5471, 0x54cd,0x97ff, 0x54d0,0x5321, 0x54d1,0x555e, +0x54d2,0x5660, 0x54d3,0x5635, 0x54d4,0x55f6, 0x54d5,0x5666, 0x54d7,0x5629, +0x54d8,0x25a1, 0x54d9,0x5672, 0x54da,0x54c6, 0x54db,0x25a1, 0x54dc,0x568c, +0x54dd,0x5665, 0x54df,0x55b2, 0x54e3,0x25a1, 0x54ec,0x25a1, 0x54ef,0x25a1, +0x54f0,0x25a1, 0x54f4,0x25a1, 0x54f5,0x25a1, 0x54f6,0x25a1, 0x54f9,0x25a1, +0x54fe,0x25a1, 0x5500,0x25a1, 0x5502,0x25a1, 0x550d,0x25a1, 0x5513,0x25a1, +0x5515,0x25a1, 0x5516,0x25a1, 0x5518,0x25a1, 0x5519,0x25a1, 0x551b,0x561c, +0x551c,0x25a1, 0x551d,0x55ca, 0x551e,0x25a1, 0x551f,0x25a1, 0x5520,0x562e, +0x5521,0x5562, 0x5522,0x55e9, 0x5523,0x55e6, 0x5524,0x559a, 0x5525,0x25a1, +0x5528,0x25a1, 0x5529,0x25a1, 0x552b,0x25a1, 0x553a,0x25a1, 0x553d,0x25a1, +0x553f,0x547c, 0x5542,0x25a1, 0x5547,0x25a1, 0x5549,0x54bb, 0x554c,0x25a1, +0x5553,0x25a1, 0x5554,0x25a1, 0x5558,0x25a1, 0x5559,0x25a1, 0x555a,0x25a1, +0x555b,0x25a1, 0x555d,0x25a1, 0x5560,0x25a1, 0x5567,0x5616, 0x5568,0x25a1, +0x5569,0x25a1, 0x556b,0x25a1, 0x556c,0x55c7, 0x556d,0x56c0, 0x556e,0x5699, +0x556f,0x25a1, 0x5570,0x56c9, 0x5571,0x25a1, 0x5572,0x25a1, 0x5573,0x25a1, +0x5574,0x563d, 0x5578,0x562f, 0x5579,0x25a1, 0x557a,0x25a1, 0x5585,0x25a1, +0x5586,0x25a1, 0x5590,0x25a1, 0x5596,0x25a1, 0x5597,0x25a1, 0x559b,0x25a1, +0x559e,0x25a1, 0x55a0,0x25a1, 0x55a9,0x25a1, 0x55af,0x25a1, 0x55b0,0x25a1, +0x55b4,0x25a1, 0x55b6,0x25a1, 0x55b7,0x5674, 0x55b8,0x25a1, 0x55b9,0x594e, +0x55ba,0x25a1, 0x55bc,0x25a1, 0x55bd,0x560d, 0x55be,0x56b3, 0x55c0,0xfa0d, +0x55c1,0x25a1, 0x55c9,0x8186, 0x55d7,0x25a1, 0x55d8,0x25a1, 0x55de,0x25a1, +0x55e0,0x25a1, 0x55ea,0x551a, 0x55eb,0x56c1, 0x55ec,0x5475, 0x55ed,0x25a1, +0x55ee,0x25a1, 0x55f0,0x25a1, 0x55f1,0x25a1, 0x55f3,0x566f, 0x55f4,0x25a1, +0x55f5,0x901a, 0x55f8,0x25a1, 0x55fb,0x25a1, 0x5603,0x25a1, 0x5605,0x25a1, +0x5607,0x25a1, 0x560a,0x25a1, 0x560b,0x25a1, 0x5611,0x25a1, 0x5618,0x5653, +0x5619,0x25a1, 0x561a,0x25a1, 0x561e,0x54a7, 0x5620,0x560e, 0x5621,0x25a1, +0x5622,0x25a1, 0x5623,0x8ff8, 0x5624,0x56b6, 0x5625,0x25a1, 0x5626,0x25a1, +0x5628,0x562f, 0x562b,0x25a1, 0x562d,0x81a8, 0x5631,0x56d1, 0x5637,0x568e, +0x563c,0x25a1, 0x5643,0x25a1, 0x5644,0x25a1, 0x5647,0x25a1, 0x564b,0x25a1, +0x564d,0x7126, 0x564f,0x25a1, 0x5650,0x25a1, 0x5651,0x25a1, 0x5652,0x25a1, +0x5654,0x767b, 0x5655,0x25a1, 0x5656,0x25a1, 0x565b,0x25a1, 0x565c,0x5695, +0x565d,0x25a1, 0x565f,0x25a1, 0x5661,0x25a1, 0x5667,0x25a1, 0x5675,0x25a1, +0x567a,0x25a1, 0x567b,0x585e, 0x567c,0x5288, 0x567d,0x25a1, 0x5688,0x25a1, +0x5689,0x25a1, 0x568a,0x25a1, 0x568b,0x25a1, 0x5691,0x25a1, 0x5692,0x25a1, +0x5694,0x6d95, 0x5696,0x25a1, 0x569b,0x25a1, 0x569e,0x25a1, 0x569f,0x25a1, +0x56a0,0x25a1, 0x56a1,0x25a1, 0x56a2,0x56ca, 0x56a3,0x56c2, 0x56a4,0x25a1, +0x56a9,0x25a1, 0x56af,0x8b14, 0x56b0,0x25a1, 0x56b1,0x25a1, 0x56b8,0x25a1, +0x56b9,0x25a1, 0x56ba,0x25a1, 0x56bb,0x25a1, 0x56bf,0x25a1, 0x56c4,0x25a1, +0x56c7,0x25a1, 0x56ce,0x25a1, 0x56cf,0x25a1, 0x56d0,0x25a1, 0x56d2,0x25a1, +0x56d5,0x25a1, 0x56d6,0x25a1, 0x56d8,0x25a1, 0x56d9,0x25a1, 0x56dc,0x25a1, +0x56e2,0x5718, 0x56e3,0x25a1, 0x56e6,0x25a1, 0x56e8,0x25a1, 0x56e9,0x25a1, +0x56ec,0x25a1, 0x56ed,0x5712, 0x56ef,0x25a1, 0x56f1,0x56ea, 0x56f2,0x25a1, +0x56f3,0x25a1, 0x56f4,0x570d, 0x56f5,0x5707, 0x56f6,0x25a1, 0x56f8,0x25a1, +0x56fb,0x25a1, 0x56fc,0x25a1, 0x56fd,0x570b, 0x56fe,0x5716, 0x5700,0x25a1, +0x5705,0x25a1, 0x5706,0x5713, 0x570e,0x25a1, 0x570f,0x25a1, 0x5710,0x25a1, +0x5711,0x25a1, 0x5715,0x25a1, 0x5717,0x25a1, 0x5719,0x25a1, 0x571d,0x25a1, +0x5721,0x25a1, 0x5723,0x8056, 0x5724,0x25a1, 0x5725,0x25a1, 0x5726,0x25a1, +0x5727,0x25a1, 0x572b,0x25a1, 0x5731,0x25a1, 0x5732,0x25a1, 0x5735,0x25a1, +0x5736,0x25a1, 0x5737,0x25a1, 0x5738,0x25a1, 0x5739,0x58d9, 0x573a,0x5834, +0x573c,0x25a1, 0x573d,0x25a1, 0x573f,0x25a1, 0x5742,0x962a, 0x5743,0x25a1, +0x5744,0x25a1, 0x5746,0x25a1, 0x5748,0x25a1, 0x574f,0x58de, 0x5753,0x25a1, +0x5754,0x25a1, 0x5755,0x25a1, 0x5756,0x25a1, 0x5757,0x584a, 0x5758,0x25a1, +0x5759,0x25a1, 0x575a,0x5805, 0x575b,0x58c7, 0x575c,0x58e2, 0x575d,0x58e9, +0x575e,0x5862, 0x575f,0x58b3, 0x5760,0x589c, 0x5763,0x25a1, 0x5765,0x25a1, +0x5767,0x25a1, 0x576c,0x25a1, 0x576e,0x25a1, 0x5778,0x25a1, 0x5779,0x25a1, +0x577a,0x25a1, 0x577e,0x25a1, 0x577f,0x25a1, 0x5781,0x25a1, 0x5784,0x58df, +0x5785,0x58df, 0x5786,0x58da, 0x5787,0x25a1, 0x5788,0x25a1, 0x5789,0x25a1, +0x578a,0x25a1, 0x578d,0x25a1, 0x578e,0x25a1, 0x5790,0x25a1, 0x5791,0x25a1, +0x5792,0x58d8, 0x5796,0x25a1, 0x579c,0x25a1, 0x57a1,0x5750, 0x57a6,0x58be, +0x57a7,0x5770, 0x57a8,0x25a1, 0x57a9,0x580a, 0x57aa,0x25a1, 0x57ab,0x588a, +0x57ac,0x25a1, 0x57ad,0x57e1, 0x57af,0x25a1, 0x57b0,0x25a1, 0x57b1,0x25a1, +0x57b2,0x584f, 0x57b3,0x25a1, 0x57b4,0x7459, 0x57b7,0x25a1, 0x57bb,0x25a1, +0x57be,0x25a1, 0x57c0,0x25a1, 0x57c4,0x25a1, 0x57c5,0x25a1, 0x57c8,0x25a1, +0x57c9,0x25a1, 0x57ca,0x25a1, 0x57cd,0x25a1, 0x57d1,0x25a1, 0x57d3,0x25a1, +0x57d6,0x25a1, 0x57d7,0x25a1, 0x57d8,0x5852, 0x57d9,0x5864, 0x57da,0x581d, +0x57db,0x25a1, 0x57dd,0x588a, 0x57de,0x25a1, 0x57e6,0x25a1, 0x57e8,0x25a1, +0x57ea,0x25a1, 0x57eb,0x25a1, 0x57ef,0x57b5, 0x57fe,0x25a1, 0x57ff,0x25a1, +0x5803,0x25a1, 0x580f,0x25a1, 0x5811,0x5879, 0x5812,0x25a1, 0x5813,0x25a1, +0x5815,0x58ae, 0x5816,0x25a1, 0x5817,0x25a1, 0x5818,0x25a1, 0x581a,0x25a1, +0x581f,0x25a1, 0x5822,0x25a1, 0x5826,0x25a1, 0x582b,0x25a1, 0x583a,0x25a1, +0x583c,0x25a1, 0x583e,0x25a1, 0x5840,0x25a1, 0x5841,0x25a1, 0x5842,0x25a1, +0x5843,0x25a1, 0x5844,0x043f, 0x5845,0x25a1, 0x5846,0x25a1, 0x5847,0x25a1, +0x5850,0x25a1, 0x5856,0x25a1, 0x585c,0x25a1, 0x585f,0x25a1, 0x5860,0x25a1, +0x5861,0x586b, 0x5866,0x25a1, 0x5867,0x25a1, 0x5869,0x25a1, 0x586a,0x25a1, +0x586c,0x539f, 0x586e,0x25a1, 0x5870,0x25a1, 0x5872,0x25a1, 0x5873,0x25a1, +0x5877,0x25a1, 0x5878,0x25a1, 0x5884,0x25a1, 0x588c,0x25a1, 0x588d,0x25a1, +0x5892,0x5891, 0x5895,0x25a1, 0x5896,0x25a1, 0x5897,0x25a1, 0x5899,0x7246, +0x589a,0x6a11, 0x589b,0x25a1, 0x58a2,0x25a1, 0x58a4,0x25a1, 0x58a7,0x25a1, +0x58aa,0x25a1, 0x58ad,0x25a1, 0x58b0,0x25a1, 0x58b2,0x25a1, 0x58b4,0x25a1, +0x58b5,0x25a1, 0x58b6,0x25a1, 0x58b7,0x25a1, 0x58b8,0x25a1, 0x58b9,0x25a1, +0x58bb,0x25a1, 0x58c0,0x25a1, 0x58c3,0x25a1, 0x58c4,0x25a1, 0x58ca,0x25a1, +0x58cb,0x25a1, 0x58cc,0x25a1, 0x58cd,0x25a1, 0x58d0,0x25a1, 0x58d7,0x25a1, +0x58dc,0x25a1, 0x58e0,0x25a1, 0x58e1,0x25a1, 0x58e5,0x25a1, 0x58e6,0x25a1, +0x58ea,0x25a1, 0x58ed,0x25a1, 0x58ee,0x58ef, 0x58f0,0x8072, 0x58f1,0x25a1, +0x58f2,0x25a1, 0x58f3,0x6bbc, 0x58f5,0x25a1, 0x58f6,0x58fa, 0x58f7,0x25a1, +0x58f8,0x58fc, 0x58fb,0x25a1, 0x5900,0x25a1, 0x5901,0x25a1, 0x5902,0x2f22, +0x5904,0x8655, 0x5905,0x25a1, 0x5907,0x5099, 0x5908,0x25a1, 0x5909,0x25a1, +0x590a,0x2f22, 0x590b,0x25a1, 0x590d,0x8907, 0x5910,0x25a1, 0x5911,0x25a1, +0x5913,0x25a1, 0x5918,0x25a1, 0x591b,0x25a1, 0x591d,0x25a1, 0x591e,0x25a1, +0x591f,0x5920, 0x5921,0x25a1, 0x5923,0x25a1, 0x5926,0x25a1, 0x5928,0x25a1, +0x5930,0x25a1, 0x5932,0x25a1, 0x5933,0x25a1, 0x5934,0x982d, 0x5935,0x25a1, +0x5936,0x25a1, 0x5938,0x8a87, 0x5939,0x593e, 0x593a,0x596a, 0x593b,0x25a1, +0x593d,0x25a1, 0x593f,0x25a1, 0x5941,0x5969, 0x5942,0x5950, 0x5943,0x25a1, +0x5946,0x25a1, 0x594b,0x596e, 0x594c,0x25a1, 0x594d,0x25a1, 0x5952,0x25a1, +0x5956,0x734e, 0x5959,0x25a1, 0x595b,0x25a1, 0x595d,0x25a1, 0x595e,0x25a1, +0x595f,0x25a1, 0x5963,0x25a1, 0x5964,0x25a1, 0x5965,0x5967, 0x5966,0x25a1, +0x5968,0x25a1, 0x596c,0x25a1, 0x596f,0x25a1, 0x5975,0x25a1, 0x597a,0x25a1, +0x5986,0x599d, 0x5987,0x5a66, 0x5988,0x5abd, 0x5989,0x25a1, 0x598b,0x25a1, +0x598c,0x25a1, 0x5991,0x25a1, 0x5994,0x25a1, 0x5995,0x25a1, 0x599a,0x25a1, +0x599b,0x25a1, 0x599c,0x25a1, 0x599f,0x25a1, 0x59a9,0x5af5, 0x59aa,0x5ad7, +0x59ab,0x5aaf, 0x59ac,0x25a1, 0x59ad,0x25a1, 0x59b0,0x25a1, 0x59b7,0x25a1, +0x59b8,0x25a1, 0x59bf,0x25a1, 0x59c2,0x25a1, 0x59c4,0x25a1, 0x59c9,0x25a1, +0x59d5,0x25a1, 0x59d7,0x59cd, 0x59d9,0x25a1, 0x59df,0x25a1, 0x59e2,0x25a1, +0x59e7,0x25a1, 0x59eb,0x25a1, 0x59ef,0x25a1, 0x59f0,0x25a1, 0x59f8,0x25a1, +0x59f9,0x597c, 0x5a02,0x25a1, 0x5a04,0x5a41, 0x5a05,0x5a6d, 0x5a06,0x5b08, +0x5a07,0x5b0c, 0x5a08,0x5b4c, 0x5a0b,0x25a1, 0x5a0d,0x25a1, 0x5a0e,0x25a1, +0x5a10,0x25a1, 0x5a12,0x25a1, 0x5a14,0x25a1, 0x5a1a,0x25a1, 0x5a1d,0x25a1, +0x5a21,0x25a1, 0x5a22,0x25a1, 0x5a24,0x25a1, 0x5a26,0x25a1, 0x5a27,0x25a1, +0x5a28,0x25a1, 0x5a2a,0x25a1, 0x5a2b,0x25a1, 0x5a2c,0x25a1, 0x5a2f,0x25a1, +0x5a30,0x59d2, 0x5a31,0x5a1b, 0x5a32,0x5aa7, 0x5a34,0x5afb, 0x5a3a,0x25a1, +0x5a3b,0x25a1, 0x5a3d,0x25a1, 0x5a3f,0x25a1, 0x5a45,0x25a1, 0x5a4b,0x25a1, +0x5a4e,0x25a1, 0x5a4f,0x25a1, 0x5a54,0x25a1, 0x5a59,0x25a1, 0x5a61,0x25a1, +0x5a63,0x25a1, 0x5a68,0x25a1, 0x5a6b,0x25a1, 0x5a6e,0x25a1, 0x5a6f,0x25a1, +0x5a71,0x25a1, 0x5a72,0x25a1, 0x5a73,0x5aff, 0x5a74,0x5b30, 0x5a75,0x5b0b, +0x5a76,0x5b38, 0x5a79,0x25a1, 0x5a7e,0x25a1, 0x5a80,0x25a1, 0x5a81,0x25a1, +0x5a82,0x25a1, 0x5a85,0x25a1, 0x5a86,0x25a1, 0x5a87,0x25a1, 0x5a88,0x25a1, +0x5a89,0x25a1, 0x5a8d,0x25a1, 0x5a91,0x25a1, 0x5a96,0x25a1, 0x5a98,0x25a1, +0x5a99,0x25a1, 0x5aa0,0x25a1, 0x5aa1,0x25a1, 0x5aa3,0x25a1, 0x5aa4,0x25a1, +0x5aa8,0x25a1, 0x5aaa,0x5abc, 0x5aab,0x25a1, 0x5aad,0x25a1, 0x5ac3,0x25a1, +0x5ac5,0x25a1, 0x5ace,0x25a1, 0x5acf,0x25a1, 0x5ad0,0x25a1, 0x5ad1,0x25a1, +0x5ad2,0x5b21, 0x5ad3,0x25a1, 0x5ad4,0x5b2a, 0x5ae4,0x25a1, 0x5ae7,0x25a1, +0x5aef,0x25a1, 0x5af0,0x25a1, 0x5af1,0x5b19, 0x5af2,0x25a1, 0x5afc,0x25a1, +0x5afe,0x25a1, 0x5b00,0x25a1, 0x5b04,0x25a1, 0x5b06,0x25a1, 0x5b0a,0x25a1, +0x5b0d,0x25a1, 0x5b0e,0x25a1, 0x5b11,0x25a1, 0x5b12,0x25a1, 0x5b15,0x25a1, +0x5b18,0x25a1, 0x5b1c,0x25a1, 0x5b1f,0x25a1, 0x5b22,0x25a1, 0x5b29,0x25a1, +0x5b2b,0x25a1, 0x5b31,0x25a1, 0x5b33,0x25a1, 0x5b35,0x25a1, 0x5b36,0x25a1, +0x5b37,0x5b24, 0x5b39,0x25a1, 0x5b3a,0x25a1, 0x5b3b,0x25a1, 0x5b41,0x25a1, +0x5b42,0x25a1, 0x5b44,0x25a1, 0x5b46,0x25a1, 0x5b49,0x25a1, 0x5b4a,0x25a1, +0x5b4f,0x25a1, 0x5b52,0x25a1, 0x5b59,0x5b6b, 0x5b5e,0x25a1, 0x5b60,0x25a1, +0x5b61,0x25a1, 0x5b66,0x5b78, 0x5b67,0x25a1, 0x5b68,0x25a1, 0x5b6a,0x5b7f, +0x5b6d,0x25a1, 0x5b6f,0x25a1, 0x5b74,0x25a1, 0x5b76,0x5b73, 0x5b79,0x25a1, +0x5b7c,0x25a1, 0x5b7e,0x25a1, 0x5b80,0x2f27, 0x5b81,0x5be7, 0x5b82,0x25a1, +0x5b86,0x25a1, 0x5b8a,0x25a1, 0x5b8d,0x25a1, 0x5b90,0x25a1, 0x5b91,0x25a1, +0x5b94,0x25a1, 0x5b96,0x25a1, 0x5b9d,0x5bf6, 0x5b9e,0x5be6, 0x5b9f,0x25a1, +0x5ba0,0x5bf5, 0x5ba1,0x5be9, 0x5ba9,0x25a1, 0x5baa,0x61b2, 0x5bab,0x5bae, +0x5baf,0x25a1, 0x5bb1,0x25a1, 0x5bb2,0x25a1, 0x5bb7,0x25a1, 0x5bba,0x25a1, +0x5bbb,0x25a1, 0x5bbc,0x25a1, 0x5bbd,0x5bec, 0x5bbe,0x8cd3, 0x5bc3,0x25a1, +0x5bc8,0x25a1, 0x5bc9,0x25a1, 0x5bcf,0x25a1, 0x5bd5,0x25a1, 0x5bd7,0x25a1, +0x5bda,0x25a1, 0x5bdb,0x25a1, 0x5bdc,0x25a1, 0x5bdd,0x5be2, 0x5bed,0x25a1, +0x5bf3,0x25a1, 0x5bf4,0x25a1, 0x5bf7,0x25a1, 0x5bf9,0x5c0d, 0x5bfb,0x5c0b, +0x5bfc,0x5c0e, 0x5bfd,0x25a1, 0x5bfe,0x5c0d, 0x5bff,0x58fd, 0x5c00,0x25a1, +0x5c02,0x5c08, 0x5c05,0x524b, 0x5c06,0x5c07, 0x5c13,0x723e, 0x5c14,0x723e, +0x5c17,0x25a1, 0x5c18,0x5875, 0x5c19,0x25a1, 0x5c1b,0x25a1, 0x5c1c,0x5c16, +0x5c1d,0x5617, 0x5c1e,0x25a1, 0x5c20,0x25a1, 0x5c21,0x25a1, 0x5c23,0x25a1, +0x5c26,0x25a1, 0x5c27,0x582f, 0x5c29,0x25a1, 0x5c2b,0x25a1, 0x5c2d,0x25a1, +0x5c2e,0x25a1, 0x5c2f,0x25a1, 0x5c32,0x25a1, 0x5c34,0x5c37, 0x5c35,0x25a1, +0x5c36,0x25a1, 0x5c3d,0x76e1, 0x5c42,0x5c64, 0x5c43,0x5c6d, 0x5c49,0x5c5c, +0x5c4a,0x5c46, 0x5c52,0x25a1, 0x5c53,0x25a1, 0x5c57,0x25a1, 0x5c5a,0x25a1, +0x5c5b,0x5c4f, 0x5c5e,0x5c6c, 0x5c5f,0x25a1, 0x5c61,0x5c62, 0x5c66,0x5c68, +0x5c6b,0x25a1, 0x5c70,0x25a1, 0x5c72,0x25a1, 0x5c75,0x25a1, 0x5c76,0x25a1, +0x5c77,0x25a1, 0x5c78,0x25a1, 0x5c7d,0x25a1, 0x5c7f,0x5dbc, 0x5c80,0x25a1, +0x5c81,0x6b72, 0x5c82,0x8c48, 0x5c83,0x25a1, 0x5c84,0x25a1, 0x5c85,0x25a1, +0x5c87,0x25a1, 0x5c8e,0x25a1, 0x5c96,0x5d87, 0x5c97,0x5d17, 0x5c98,0x5cf4, +0x5c99,0x5db4, 0x5c9a,0x5d50, 0x5c9b,0x5cf6, 0x5c9c,0x5c8a, 0x5c9e,0x25a1, +0x5cad,0x5dba, 0x5cb2,0x25a1, 0x5cb4,0x25a1, 0x5cb9,0x25a1, 0x5cba,0x5cad, +0x5cbb,0x25a1, 0x5cbc,0x25a1, 0x5cbd,0x5d20, 0x5cbe,0x25a1, 0x5cbf,0x5dcb, +0x5cc0,0x25a1, 0x5cc1,0x536c, 0x5cc2,0x25a1, 0x5cc3,0x5da8, 0x5cc4,0x5da7, +0x5cc5,0x25a1, 0x5ccd,0x25a1, 0x5cd1,0x25a1, 0x5cd5,0x25a1, 0x5cdc,0x25a1, +0x5cdd,0x25a1, 0x5ce0,0x25a1, 0x5ce1,0x5cfd, 0x5ce2,0x25a1, 0x5ce3,0x5da2, +0x5ce4,0x5da0, 0x5ce5,0x5d22, 0x5ce6,0x5dd2, 0x5ce7,0x25a1, 0x5ce9,0x25a1, +0x5ceb,0x25a1, 0x5cef,0x5cf0, 0x5cf2,0x25a1, 0x5cf3,0x25a1, 0x5cf5,0x25a1, +0x5cfa,0x25a1, 0x5cfc,0x25a1, 0x5cfe,0x25a1, 0x5d02,0x5d97, 0x5d03,0x5d0d, +0x5d04,0x5dae, 0x5d05,0x25a1, 0x5d08,0x25a1, 0x5d09,0x25a1, 0x5d0a,0x25a1, +0x5d10,0x25a1, 0x5d13,0x25a1, 0x5d15,0x25a1, 0x5d18,0x25a1, 0x5d1c,0x25a1, +0x5d21,0x25a1, 0x5d2a,0x25a1, 0x5d2b,0x25a1, 0x5d2c,0x25a1, 0x5d2d,0x5d84, +0x5d2f,0x25a1, 0x5d3b,0x25a1, 0x5d3e,0x8981, 0x5d44,0x25a1, 0x5d46,0x25a1, +0x5d48,0x25a1, 0x5d4d,0x25a1, 0x5d4f,0x25a1, 0x5d53,0x25a1, 0x5d54,0x25a1, +0x5d56,0x25a1, 0x5d57,0x25a1, 0x5d58,0x5db8, 0x5d5a,0x5d94, 0x5d5b,0x5d33, +0x5d5c,0x25a1, 0x5d5d,0x5d81, 0x5d5f,0x25a1, 0x5d60,0x25a1, 0x5d61,0x25a1, +0x5d64,0x25a1, 0x5d66,0x25a1, 0x5d6a,0x25a1, 0x5d6d,0x25a1, 0x5d6e,0x25a1, +0x5d70,0x25a1, 0x5d73,0x25a1, 0x5d74,0xf80a, 0x5d75,0x25a1, 0x5d76,0x25a1, +0x5d78,0x25a1, 0x5d7b,0x25a1, 0x5d83,0x25a1, 0x5d85,0x25a1, 0x5d8b,0x25a1, +0x5d8c,0x25a1, 0x5d8e,0x25a1, 0x5d8f,0x25a1, 0x5d90,0x25a1, 0x5d91,0x25a1, +0x5d96,0x25a1, 0x5d98,0x25a1, 0x5d9b,0x25a1, 0x5da3,0x25a1, 0x5da4,0x25a1, +0x5da5,0x25a1, 0x5da6,0x25a1, 0x5dab,0x25a1, 0x5db3,0x25a1, 0x5db6,0x25a1, +0x5db9,0x25a1, 0x5dbb,0x25a1, 0x5dbe,0x25a1, 0x5dbf,0x25a1, 0x5dc1,0x25a1, +0x5dc4,0x5dc3, 0x5dc5,0x5dd4, 0x5dc8,0x25a1, 0x5dca,0x25a1, 0x5dcc,0x5dd6, +0x5dce,0x25a1, 0x5dd0,0x25a1, 0x5dd3,0x5dd4, 0x5dd7,0x25a1, 0x5dd9,0x25a1, +0x5dda,0x25a1, 0x5ddb,0x2f2e, 0x5ddc,0x25a1, 0x5de3,0x25a1, 0x5de4,0x25a1, +0x5de9,0x978f, 0x5dea,0x25a1, 0x5dec,0x25a1, 0x5ded,0x25a1, 0x5def,0x5df0, +0x5df5,0x25a1, 0x5df6,0x25a1, 0x5df8,0x25a1, 0x5dfa,0x25a1, 0x5dfb,0x25a1, +0x5dfc,0x25a1, 0x5e00,0x25a1, 0x5e01,0x5e63, 0x5e05,0x5e25, 0x5e07,0x25a1, +0x5e08,0x5e2b, 0x5e09,0x25a1, 0x5e0b,0x25a1, 0x5e0d,0x25a1, 0x5e0f,0x5e43, +0x5e10,0x5e33, 0x5e12,0x25a1, 0x5e13,0x25a1, 0x5e18,0x7c3e, 0x5e1c,0x5e5f, +0x5e1e,0x25a1, 0x5e26,0x5e36, 0x5e27,0x5e40, 0x5e2a,0x25a1, 0x5e2c,0x25a1, +0x5e2e,0x5e6b, 0x5e2f,0x5e36, 0x5e30,0x25a1, 0x5e31,0x5e6c, 0x5e32,0x25a1, +0x5e35,0x25a1, 0x5e39,0x25a1, 0x5e3a,0x25a1, 0x5e3b,0x5e58, 0x5e3c,0x5e57, +0x5e3f,0x25a1, 0x5e42,0x51aa, 0x5e46,0x25a1, 0x5e47,0x5e6b, 0x5e48,0x25a1, +0x5e49,0x25a1, 0x5e50,0x25a1, 0x5e51,0x25a1, 0x5e52,0x25a1, 0x5e56,0x25a1, +0x5e5a,0x5e6b, 0x5e5e,0x8946, 0x5e64,0x25a1, 0x5e65,0x25a1, 0x5e71,0x25a1, +0x5e72,0x5e79, 0x5e76,0x4e26, 0x5e77,0x5e76, 0x5e7a,0x4e48, 0x5e7f,0x5ee3, +0x5e81,0x5ef3, 0x5e83,0x9ebc, 0x5e84,0x838a, 0x5e85,0x9ebc, 0x5e86,0x6176, +0x5e8e,0x5e84, 0x5e90,0x5eec, 0x5e91,0x5ee1, 0x5e92,0x25a1, 0x5e93,0x5eab, +0x5e94,0x61c9, 0x5e98,0x25a1, 0x5e99,0x5edf, 0x5e9d,0x25a1, 0x5e9e,0x9f90, +0x5e9f,0x5ee2, 0x5ea1,0x25a1, 0x5ea9,0x25a1, 0x5eaf,0x25a1, 0x5eba,0x25a1, +0x5ebb,0x25a1, 0x5ebc,0x5ece, 0x5ebd,0x25a1, 0x5ebf,0x25a1, 0x5ec0,0x25a1, +0x5ec3,0x25a1, 0x5ecd,0x25a1, 0x5ecf,0x5ec4, 0x5ed0,0x5ec4, 0x5ee4,0x25a1, +0x5eea,0x5ee9, 0x5eeb,0x25a1, 0x5eed,0x25a1, 0x5ef0,0x25a1, 0x5ef4,0x2f35, +0x5ef5,0x5de1, 0x5ef8,0x25a1, 0x5ef9,0x25a1, 0x5efb,0x25a1, 0x5efc,0x25a1, +0x5efd,0x25a1, 0x5f00,0x958b, 0x5f02,0x7570, 0x5f03,0x68c4, 0x5f06,0x25a1, +0x5f09,0x25a1, 0x5f0c,0x25a1, 0x5f0d,0x25a1, 0x5f0e,0x25a1, 0x5f10,0x25a1, +0x5f11,0x5f12, 0x5f16,0x25a1, 0x5f19,0x25a1, 0x5f1c,0x25a1, 0x5f1e,0x25a1, +0x5f20,0x5f35, 0x5f21,0x25a1, 0x5f25,0x5f4c, 0x5f2a,0x5f33, 0x5f2b,0x25a1, +0x5f2c,0x25a1, 0x5f2f,0x5f4e, 0x5f32,0x25a1, 0x5f34,0x25a1, 0x5f39,0x5f48, +0x5f3a,0x5f37, 0x5f3b,0x25a1, 0x5f3d,0x25a1, 0x5f3e,0x25a1, 0x5f3f,0x25a1, +0x5f41,0x25a1, 0x5f42,0x25a1, 0x5f45,0x25a1, 0x5f47,0x25a1, 0x5f4d,0x25a1, +0x5f50,0x2f39, 0x5f51,0x25a1, 0x5f52,0x6b78, 0x5f53,0x7576, 0x5f55,0x9304, +0x5f5a,0x5f59, 0x5f5b,0x7fbf, 0x5f5c,0x7fbf, 0x5f5d,0x5f5e, 0x5f5f,0x7372, +0x5f60,0x7372, 0x5f61,0x2f3a, 0x5f63,0x25a1, 0x5f66,0x5f65, 0x5f68,0x25a1, +0x5f6e,0x25a1, 0x5f72,0x25a1, 0x5f75,0x25a1, 0x5f77,0x5fac, 0x5f7a,0x25a1, +0x5f7b,0x5fb9, 0x5f83,0x25a1, 0x5f84,0x5f91, 0x5f8d,0x25a1, 0x5f8e,0x25a1, +0x5f8f,0x25a1, 0x5f93,0x25a1, 0x5f94,0x25a1, 0x5f95,0x5fa0, 0x5f9a,0x25a1, +0x5f9d,0x25a1, 0x5fa2,0x25a1, 0x5fa3,0x25a1, 0x5fa4,0x25a1, 0x5fa7,0x25a1, +0x5fb0,0x25a1, 0x5fb1,0x25a1, 0x5fb3,0x25a1, 0x5fb4,0x25a1, 0x5fb8,0x5fb7, +0x5fba,0x25a1, 0x5fc2,0x25a1, 0x5fc4,0x5fc3, 0x5fc6,0x61b6, 0x5fc7,0x25a1, +0x5fc8,0x25a1, 0x5fca,0x25a1, 0x5fcb,0x61b6, 0x5fce,0x25a1, 0x5fcf,0x61fa, +0x5fd3,0x25a1, 0x5fda,0x25a1, 0x5fdb,0x25a1, 0x5fdc,0x25a1, 0x5fdf,0x25a1, +0x5fe2,0x25a1, 0x5fe6,0x25a1, 0x5fe7,0x6182, 0x5fe9,0x25a1, 0x5fec,0x25a1, +0x5ff0,0x25a1, 0x5ff2,0x25a1, 0x5ff6,0x25a1, 0x5ff9,0x25a1, 0x5ffc,0x25a1, +0x5ffe,0x613e, 0x6000,0x61f7, 0x6001,0x614b, 0x6002,0x616b, 0x6003,0x61ae, +0x6004,0x616a, 0x6005,0x60b5, 0x6006,0x6134, 0x6007,0x25a1, 0x6008,0x25a1, +0x6018,0x25a1, 0x601c,0x6190, 0x601f,0x25a1, 0x6023,0x25a1, 0x6030,0x25a1, +0x6031,0x25a1, 0x6036,0x25a1, 0x6038,0x25a1, 0x603a,0x25a1, 0x603b,0x7e3d, +0x603c,0x61df, 0x603d,0x25a1, 0x603e,0x25a1, 0x603f,0x61cc, 0x6048,0x25a1, +0x604a,0x25a1, 0x604b,0x6200, 0x604e,0x25a1, 0x604f,0x25a1, 0x6051,0x25a1, +0x6052,0x6046, 0x6056,0x25a1, 0x6057,0x25a1, 0x605c,0x25a1, 0x6060,0x25a1, +0x6061,0x25a1, 0x6071,0x25a1, 0x6073,0x61c7, 0x6074,0x25a1, 0x6075,0x25a1, +0x6076,0x60e1, 0x6077,0x25a1, 0x6078,0x615f, 0x6079,0x61e8, 0x607a,0x6137, +0x607b,0x60fb, 0x607c,0x60f1, 0x607d,0x60f2, 0x607e,0x25a1, 0x6082,0x25a1, +0x608b,0x25a1, 0x608f,0x25a1, 0x6091,0x25a1, 0x6093,0x25a1, 0x6098,0x25a1, +0x6099,0x25a1, 0x609e,0x25a1, 0x60a1,0x25a1, 0x60a4,0x25a1, 0x60a5,0x25a1, +0x60a6,0x6085, 0x60a7,0x25a1, 0x60a9,0x25a1, 0x60aa,0x25a1, 0x60ab,0x6128, +0x60ac,0x61f8, 0x60ad,0x6173, 0x60ae,0x25a1, 0x60af,0x61ab, 0x60b3,0x25a1, +0x60c2,0x25a1, 0x60ca,0x9a5a, 0x60d0,0x25a1, 0x60d2,0x25a1, 0x60d6,0x25a1, +0x60d7,0x25a1, 0x60de,0x25a1, 0x60e3,0x25a1, 0x60e5,0x25a1, 0x60e7,0x61fc, +0x60e8,0x6158, 0x60e9,0x61f2, 0x60ea,0x25a1, 0x60eb,0x618a, 0x60ec,0x611c, +0x60ed,0x615a, 0x60ee,0x619a, 0x60ef,0x6163, 0x60fd,0x60db, 0x6102,0x25a1, +0x6107,0x25a1, 0x610c,0x25a1, 0x6111,0x25a1, 0x6117,0x25a1, 0x6119,0x25a1, +0x611e,0x25a1, 0x6120,0x614d, 0x6121,0x25a1, 0x6122,0x25a1, 0x6124,0x61a4, +0x6125,0x25a1, 0x6126,0x6192, 0x612a,0x25a1, 0x612d,0x25a1, 0x6130,0x25a1, +0x6131,0x25a1, 0x6133,0x25a1, 0x6135,0x25a1, 0x6138,0x25a1, 0x6139,0x25a1, +0x613a,0x25a1, 0x613c,0x25a1, 0x613d,0x25a1, 0x613f,0x9858, 0x6142,0x25a1, +0x6143,0x25a1, 0x6150,0x25a1, 0x6151,0x61fe, 0x6157,0x25a1, 0x6159,0x25a1, +0x615c,0x25a1, 0x6160,0x25a1, 0x6164,0x25a1, 0x6169,0x25a1, 0x616d,0x6196, +0x616f,0x25a1, 0x6178,0x25a1, 0x617b,0x25a1, 0x617d,0x25a1, 0x617f,0x25a1, +0x6181,0x25a1, 0x6184,0x25a1, 0x6185,0x25a1, 0x6186,0x25a1, 0x6187,0x25a1, +0x6188,0x25a1, 0x618f,0x25a1, 0x6195,0x25a1, 0x6197,0x25a1, 0x6198,0x25a1, +0x6199,0x25a1, 0x619c,0x25a1, 0x619e,0x25a1, 0x61a0,0x25a1, 0x61a3,0x25a1, +0x61a5,0x25a1, 0x61a6,0x25a1, 0x61b7,0x695a, 0x61b9,0x25a1, 0x61bb,0x25a1, +0x61bd,0x25a1, 0x61c0,0x25a1, 0x61c4,0x25a1, 0x61ce,0x25a1, 0x61cf,0x25a1, +0x61d0,0x25a1, 0x61d1,0x61e3, 0x61d2,0x61f6, 0x61d3,0x25a1, 0x61d4,0x61cd, +0x61d5,0x25a1, 0x61d7,0x25a1, 0x61d9,0x25a1, 0x61da,0x25a1, 0x61db,0x25a1, +0x61dc,0x25a1, 0x61dd,0x25a1, 0x61e1,0x25a1, 0x61e2,0x25a1, 0x61ec,0x25a1, +0x61ef,0x25a1, 0x61f3,0x25a1, 0x61f4,0x61fa, 0x6202,0x25a1, 0x6205,0x6207, +0x6206,0x6207, 0x620b,0x6214, 0x620f,0x6232, 0x6213,0x25a1, 0x6217,0x6227, +0x6218,0x6230, 0x621c,0x25a1, 0x621d,0x6557, 0x621e,0x25a1, 0x6226,0x6230, +0x6228,0x25a1, 0x622c,0x6229, 0x622f,0x6232, 0x6231,0x6232, 0x6235,0x25a1, +0x6237,0x6236, 0x6238,0x6236, 0x6239,0x25a1, 0x623b,0x25a1, 0x623c,0x25a1, +0x6244,0x25a1, 0x6245,0x25a1, 0x624c,0x624b, 0x624f,0x25a1, 0x6251,0x64b2, +0x6255,0x25a1, 0x6256,0x25a1, 0x6257,0x25a1, 0x625d,0x25a1, 0x625f,0x25a1, +0x6267,0x57f7, 0x6268,0x25a1, 0x6269,0x64f4, 0x626a,0x636b, 0x626b,0x6383, +0x626c,0x63da, 0x6270,0x64fe, 0x6275,0x25a1, 0x6278,0x25a1, 0x6282,0x25a1, +0x6285,0x62d8, 0x628b,0x25a1, 0x628d,0x25a1, 0x6290,0x25a1, 0x6299,0x25a1, +0x629a,0x64ab, 0x629b,0x62cb, 0x629c,0x25a1, 0x629d,0x25a1, 0x629e,0x25a1, +0x629f,0x6476, 0x62a0,0x6473, 0x62a1,0x6384, 0x62a2,0x6436, 0x62a3,0x25a1, +0x62a4,0x8b77, 0x62a5,0x5831, 0x62a6,0x25a1, 0x62a7,0x25a1, 0x62b2,0x25a1, +0x62b7,0x25a1, 0x62ba,0x25a1, 0x62c0,0x25a1, 0x62c1,0x25a1, 0x62c3,0x25a1, +0x62c5,0x64d4, 0x62d5,0x25a1, 0x62dd,0x25a1, 0x62de,0x25a1, 0x62df,0x64ec, +0x62e0,0x25a1, 0x62e1,0x25a1, 0x62e2,0x650f, 0x62e3,0x63c0, 0x62e4,0x25a1, +0x62e5,0x64c1, 0x62e6,0x6514, 0x62e7,0x64f0, 0x62e8,0x64a5, 0x62e9,0x64c7, +0x62ea,0x25a1, 0x6304,0x25a1, 0x6305,0x25a1, 0x6306,0x25a1, 0x630a,0x25a1, +0x6312,0x25a1, 0x6317,0x25a1, 0x6318,0x25a1, 0x6319,0x25a1, 0x631a,0x646f, +0x631b,0x6523, 0x631c,0x6397, 0x631d,0x64be, 0x631e,0x64bb, 0x631f,0x633e, +0x6320,0x6493, 0x6321,0x64cb, 0x6322,0x649f, 0x6323,0x6399, 0x6324,0x64e0, +0x6325,0x63ee, 0x6326,0x648f, 0x6327,0x25a1, 0x632e,0x25a1, 0x6330,0x25a1, +0x6331,0x25a1, 0x6335,0x25a1, 0x6337,0x25a1, 0x633f,0x25a1, 0x6352,0x25a1, +0x6353,0x25a1, 0x635b,0x25a1, 0x635c,0x25a1, 0x635d,0x25a1, 0x635e,0x6488, +0x635f,0x640d, 0x6360,0x25a1, 0x6361,0x64bf, 0x6362,0x63db, 0x6363,0x6417, +0x6364,0x25a1, 0x6366,0x25a1, 0x636a,0x25a1, 0x636c,0x25a1, 0x636e,0x64da, +0x6373,0x25a1, 0x6374,0x25a1, 0x6379,0x25a1, 0x637e,0x25a1, 0x637f,0x25a1, +0x6386,0x25a1, 0x638b,0x25a1, 0x6393,0x25a1, 0x6395,0x25a1, 0x639a,0x25a1, +0x63a6,0x25a1, 0x63b2,0x25a1, 0x63b3,0x64c4, 0x63b4,0x6451, 0x63b5,0x25a1, +0x63b6,0x25a1, 0x63b7,0x64f2, 0x63b8,0x64a3, 0x63b9,0x25a1, 0x63ba,0x647b, +0x63bb,0x25a1, 0x63bc,0x645c, 0x63bf,0x25a1, 0x63c1,0x25a1, 0x63d1,0x25a1, +0x63d4,0x25a1, 0x63de,0x6309, 0x63e2,0x25a1, 0x63e6,0x25a1, 0x63ec,0x25a1, +0x63f7,0x25a1, 0x63f8,0x55b3, 0x63fa,0x25a1, 0x63fb,0x25a1, 0x63fc,0x25a1, +0x63fd,0x652c, 0x63fe,0x25a1, 0x63ff,0x64b3, 0x6400,0x6519, 0x6401,0x64f1, +0x6402,0x645f, 0x6403,0x6460, 0x6404,0x25a1, 0x6405,0x652a, 0x6407,0x25a1, +0x6408,0x25a1, 0x640c,0x6990, 0x6411,0x25a1, 0x6419,0x25a1, 0x641d,0x25a1, +0x6429,0x25a1, 0x6431,0x25a1, 0x6432,0x25a1, 0x6438,0x25a1, 0x643a,0x651c, +0x643b,0x25a1, 0x643c,0x25a1, 0x6442,0x25a1, 0x6444,0x651d, 0x6445,0x6504, +0x6446,0x64fa, 0x6447,0x6416, 0x6448,0x64ef, 0x6449,0x25a1, 0x644a,0x6524, +0x644c,0x25a1, 0x644f,0x25a1, 0x6455,0x25a1, 0x6456,0x25a1, 0x6457,0x25a1, +0x645a,0x25a1, 0x6462,0x25a1, 0x6463,0x25a1, 0x6464,0x25a1, 0x646a,0x25a1, +0x6471,0x25a1, 0x647c,0x25a1, 0x647e,0x25a1, 0x6480,0x64ca, 0x6481,0x25a1, +0x6483,0x64ca, 0x6484,0x6516, 0x6486,0x25a1, 0x648d,0x25a1, 0x648e,0x25a1, +0x6491,0x6490, 0x6494,0x25a1, 0x649b,0x25a1, 0x64a1,0x25a1, 0x64a7,0x25a1, +0x64a8,0x25a1, 0x64aa,0x6506, 0x64af,0x25a1, 0x64b4,0x25a1, 0x64b5,0x6506, +0x64b6,0x25a1, 0x64b7,0x64f7, 0x64b8,0x64fc, 0x64b9,0x652a, 0x64ba,0x651b, +0x64c0,0x5e79, 0x64c6,0x25a1, 0x64c8,0x25a1, 0x64cc,0x25a1, 0x64d1,0x25a1, +0x64d3,0x25a1, 0x64d5,0x651c, 0x64dc,0x25a1, 0x64dd,0x25a1, 0x64de,0x64fb, +0x64df,0x25a1, 0x64e1,0x62ac, 0x64e5,0x6394, 0x64e7,0x8209, 0x64ea,0x58d3, +0x64ee,0x25a1, 0x64f5,0x25a1, 0x64f6,0x25a1, 0x64f9,0x25a1, 0x6502,0x25a1, +0x6505,0x25a1, 0x6508,0x25a1, 0x650a,0x25a1, 0x650b,0x25a1, 0x6511,0x25a1, +0x6512,0x6522, 0x651a,0x25a1, 0x651e,0x25a1, 0x651f,0x25a1, 0x6527,0x25a1, +0x6528,0x25a1, 0x6530,0x25a1, 0x6531,0x25a1, 0x6534,0x2f41, 0x6535,0x53c8, +0x653a,0x25a1, 0x653c,0x25a1, 0x6540,0x25a1, 0x6542,0x25a1, 0x6544,0x25a1, +0x6547,0x6555, 0x654b,0x25a1, 0x654c,0x6575, 0x654d,0x25a1, 0x654e,0x25a1, +0x6550,0x25a1, 0x6552,0x25a1, 0x655a,0x25a1, 0x655b,0x6582, 0x655f,0x25a1, +0x6560,0x25a1, 0x6561,0x25a1, 0x6569,0x25a1, 0x656b,0x6a84, 0x656d,0x25a1, +0x656e,0x6b43, 0x6570,0x6578, 0x6571,0x25a1, 0x657d,0x25a1, 0x657e,0x25a1, +0x6585,0x25a1, 0x6586,0x25a1, 0x6588,0x25a1, 0x6589,0x9f4a, 0x658a,0x25a1, +0x658b,0x9f4b, 0x658d,0x25a1, 0x658e,0x9f4b, 0x658f,0x25a1, 0x6593,0x6595, +0x6598,0x25a1, 0x659a,0x25a1, 0x65a3,0x25a1, 0x65a6,0x25a1, 0x65a9,0x65ac, +0x65ad,0x65b7, 0x65b1,0x25a1, 0x65b4,0x25a1, 0x65b5,0x25a1, 0x65ba,0x25a1, +0x65be,0x25a1, 0x65c0,0x25a1, 0x65c7,0x25a1, 0x65c8,0x25a1, 0x65c9,0x25a1, +0x65ca,0x25a1, 0x65d1,0x25a1, 0x65d4,0x25a1, 0x65d5,0x25a1, 0x65d8,0x25a1, +0x65d9,0x25a1, 0x65dc,0x25a1, 0x65e0,0x7121, 0x65e3,0x25a1, 0x65e4,0x25a1, +0x65e7,0x820a, 0x65ea,0x25a1, 0x65eb,0x25a1, 0x65f6,0x6642, 0x65f7,0x66e0, +0x65f8,0x6698, 0x65f9,0x25a1, 0x65fe,0x25a1, 0x65ff,0x25a1, 0x6601,0x25a1, +0x6616,0x25a1, 0x6617,0x25a1, 0x6618,0x25a1, 0x6619,0x66c7, 0x661a,0x25a1, +0x661b,0x25a1, 0x661e,0x25a1, 0x6623,0x25a1, 0x6629,0x25a1, 0x662a,0x25a1, +0x662c,0x25a1, 0x6630,0x25a1, 0x6635,0x66b1, 0x6637,0x25a1, 0x6638,0x25a1, +0x663b,0x25a1, 0x663c,0x665d, 0x663d,0x66e8, 0x663e,0x986f, 0x663f,0x25a1, +0x6640,0x25a1, 0x6644,0x25a1, 0x6646,0x25a1, 0x6648,0x25a1, 0x664b,0x6649, +0x664d,0x25a1, 0x664e,0x25a1, 0x6650,0x25a1, 0x6652,0x66ec, 0x6653,0x66c9, +0x6654,0x66c4, 0x6655,0x6688, 0x6656,0x6689, 0x6657,0x542b, 0x6658,0x25a1, +0x6660,0x25a1, 0x6663,0x25a1, 0x6667,0x25a1, 0x6669,0x25a1, 0x666b,0x25a1, +0x666d,0x25a1, 0x6673,0x25a1, 0x6675,0x25a1, 0x667d,0x25a1, 0x667f,0x25a1, +0x6681,0x25a1, 0x6682,0x66ab, 0x6683,0x25a1, 0x6685,0x25a1, 0x668e,0x25a1, +0x668f,0x25a1, 0x6692,0x25a1, 0x6693,0x25a1, 0x669a,0x25a1, 0x669b,0x25a1, +0x669c,0x25a1, 0x669e,0x25a1, 0x66a3,0x25a1, 0x66a4,0x25a1, 0x66a5,0x25a1, +0x66a6,0x25a1, 0x66a7,0x66d6, 0x66ac,0x25a1, 0x66ad,0x25a1, 0x66b3,0x25a1, +0x66b6,0x25a1, 0x66bc,0x25a1, 0x66bf,0x25a1, 0x66c1,0x25a1, 0x66c2,0x25a1, +0x66c3,0x25a1, 0x66c5,0x25a1, 0x66cd,0x25a1, 0x66ce,0x25a1, 0x66d0,0x25a1, +0x66d1,0x25a1, 0x66d3,0x25a1, 0x66d4,0x25a1, 0x66d5,0x25a1, 0x66d7,0x25a1, +0x66df,0x25a1, 0x66e1,0x25a1, 0x66e2,0x25a1, 0x66e5,0x25a1, 0x66e7,0x25a1, +0x66ea,0x25a1, 0x66ef,0x25a1, 0x66f1,0x25a1, 0x66f5,0x25a1, 0x66fa,0x25a1, +0x66fb,0x25a1, 0x66fd,0x25a1, 0x6702,0x25a1, 0x6706,0x25a1, 0x6707,0x25a1, +0x670c,0x25a1, 0x670e,0x25a1, 0x6711,0x25a1, 0x6716,0x25a1, 0x6719,0x25a1, +0x671a,0x25a1, 0x671c,0x25a1, 0x671e,0x25a1, 0x6724,0x25a1, 0x6725,0x25a1, +0x6729,0x25a1, 0x672f,0x8853, 0x6730,0x25a1, 0x6732,0x25a1, 0x6734,0x6a38, +0x6736,0x25a1, 0x6737,0x25a1, 0x673a,0x6a5f, 0x6740,0x6bba, 0x6741,0x25a1, +0x6742,0x96dc, 0x6743,0x6b0a, 0x6744,0x25a1, 0x6746,0x687f, 0x674a,0x25a1, +0x6752,0x25a1, 0x6754,0x25a1, 0x6758,0x25a1, 0x675b,0x25a1, 0x6761,0x689d, +0x6762,0x25a1, 0x6763,0x25a1, 0x6764,0x25a1, 0x6765,0x4f86, 0x6766,0x25a1, +0x6767,0x25a1, 0x6768,0x694a, 0x6769,0x69aa, 0x676b,0x25a1, 0x676e,0x25a1, +0x6770,0x5091, 0x6780,0x25a1, 0x6781,0x6975, 0x6782,0x25a1, 0x6784,0x69cb, +0x6788,0x25a1, 0x678a,0x25a1, 0x678f,0x25a1, 0x6796,0x25a1, 0x679b,0x25a1, +0x679e,0x6a05, 0x67a0,0x25a1, 0x67a1,0x25a1, 0x67a2,0x6a1e, 0x67a3,0x68d7, +0x67a4,0x25a1, 0x67a5,0x6aea, 0x67a6,0x25a1, 0x67a7,0x898b, 0x67a8,0x68d6, +0x67a9,0x25a1, 0x67aa,0x69cd, 0x67ab,0x6953, 0x67ac,0x25a1, 0x67ad,0x689f, +0x67b1,0x25a1, 0x67bc,0x25a1, 0x67bd,0x25a1, 0x67be,0x25a1, 0x67bf,0x25a1, +0x67c7,0x25a1, 0x67d5,0x25a1, 0x67d6,0x25a1, 0x67d7,0x25a1, 0x67dc,0x6ac3, +0x67e0,0x6ab8, 0x67e1,0x25a1, 0x67e8,0x25a1, 0x67f9,0x25a1, 0x67fb,0x25a1, +0x67fd,0x6a89, 0x67fe,0x25a1, 0x6800,0x6894, 0x6801,0x25a1, 0x6802,0x25a1, +0x6803,0x25a1, 0x6804,0x25a1, 0x6805,0x67f5, 0x6806,0x25a1, 0x6807,0x6a19, +0x6808,0x68e7, 0x6809,0x6adb, 0x680a,0x6af3, 0x680b,0x68df, 0x680c,0x6ae8, +0x680d,0x25a1, 0x680e,0x6adf, 0x680f,0x6b04, 0x6810,0x25a1, 0x6811,0x6a39, +0x6815,0x25a1, 0x6816,0x68f2, 0x6817,0x6144, 0x6819,0x25a1, 0x681b,0x25a1, +0x681e,0x25a1, 0x6822,0x25a1, 0x6823,0x25a1, 0x6824,0x25a1, 0x6827,0x25a1, +0x682c,0x25a1, 0x6830,0x25a1, 0x6836,0x25a1, 0x6837,0x6a23, 0x683e,0x6b12, +0x683f,0x25a1, 0x6847,0x25a1, 0x684a,0x68ec, 0x6852,0x25a1, 0x6855,0x6a01, +0x6856,0x25a1, 0x6857,0x25a1, 0x6858,0x25a1, 0x6859,0x25a1, 0x685a,0x25a1, +0x685b,0x25a1, 0x685c,0x25a1, 0x685d,0x25a1, 0x685e,0x25a1, 0x685f,0x25a1, +0x6860,0x690f, 0x6861,0x6a48, 0x6862,0x6968, 0x6863,0x6a94, 0x6864,0x69bf, +0x6865,0x6a4b, 0x6866,0x6a3a, 0x6867,0x6a9c, 0x6868,0x69f3, 0x6869,0x6a01, +0x686a,0x25a1, 0x686c,0x25a1, 0x6870,0x25a1, 0x6873,0x25a1, 0x687a,0x25a1, +0x6884,0x25a1, 0x6888,0x25a1, 0x688d,0x25a1, 0x688e,0x25a1, 0x6895,0x25a1, +0x6898,0x25a1, 0x6899,0x25a1, 0x689a,0x25a1, 0x689e,0x25a1, 0x68a5,0x25a1, +0x68a6,0x5922, 0x68b6,0x25a1, 0x68b7,0x25a1, 0x68b8,0x25a1, 0x68b9,0x25a1, +0x68ba,0x25a1, 0x68bb,0x25a1, 0x68bc,0x6aae, 0x68bd,0x25a1, 0x68be,0x68f6, +0x68bf,0x25a1, 0x68c0,0x6aa2, 0x68c1,0x25a1, 0x68c2,0x6b1e, 0x68c3,0x25a1, +0x68c5,0x25a1, 0x68ca,0x25a1, 0x68cf,0x25a1, 0x68d9,0x25a1, 0x68db,0x25a1, +0x68e2,0x25a1, 0x68e5,0x25a1, 0x68ed,0x25a1, 0x68fe,0x25a1, 0x68ff,0x25a1, +0x6900,0x25a1, 0x6901,0x69e8, 0x6902,0x25a1, 0x6903,0x25a1, 0x6909,0x25a1, +0x6916,0x25a1, 0x6918,0x25a1, 0x6919,0x25a1, 0x691a,0x25a1, 0x691b,0x25a1, +0x691c,0x25a1, 0x691d,0x25a1, 0x691e,0x25a1, 0x691f,0x6add, 0x6920,0x69e7, +0x6921,0x25a1, 0x6922,0x25a1, 0x6923,0x25a1, 0x6924,0x6b0f, 0x6926,0x25a1, +0x6927,0x25a1, 0x6928,0x25a1, 0x6929,0x25a1, 0x692b,0x25a1, 0x692c,0x25a1, +0x692d,0x6a62, 0x692e,0x25a1, 0x6931,0x25a1, 0x6936,0x25a1, 0x693a,0x25a1, +0x693e,0x25a1, 0x6943,0x25a1, 0x6946,0x25a1, 0x6947,0x25a1, 0x694d,0x25a1, +0x6950,0x25a1, 0x6955,0x25a1, 0x6961,0x25a1, 0x6964,0x25a1, 0x6967,0x25a1, +0x6972,0x25a1, 0x6973,0x25a1, 0x697c,0x6a13, 0x697d,0x6a02, 0x697e,0x25a1, +0x697f,0x25a1, 0x6980,0x54c1, 0x6981,0x25a1, 0x6984,0x6b16, 0x6985,0x25a1, +0x6987,0x6aec, 0x6988,0x6ada, 0x6989,0x6af8, 0x698a,0x25a1, 0x698b,0x25a1, +0x698c,0x25a1, 0x698f,0x25a1, 0x6992,0x25a1, 0x6998,0x77e9, 0x699d,0x25a1, +0x699f,0x25a1, 0x69a2,0x25a1, 0x69b2,0x25a1, 0x69b8,0x25a1, 0x69ba,0x25a1, +0x69c0,0x25a1, 0x69c5,0x25a1, 0x69c7,0x25a1, 0x69c8,0x25a1, 0x69d1,0x25a1, +0x69d2,0x25a1, 0x69d5,0x25a1, 0x69d6,0x25a1, 0x69d7,0x25a1, 0x69d8,0x25a1, +0x69da,0x6a9f, 0x69db,0x6abb, 0x69dc,0x25a1, 0x69dd,0x25a1, 0x69de,0x25a1, +0x69df,0x6ab3, 0x69e0,0x6ae7, 0x69e1,0x25a1, 0x69e3,0x25a1, 0x69e9,0x25a1, +0x69ea,0x25a1, 0x69ef,0x25a1, 0x69f0,0x25a1, 0x69f5,0x25a1, 0x69f9,0x25a1, +0x69fa,0x25a1, 0x6a03,0x25a1, 0x6a0b,0x25a1, 0x6a0c,0x25a1, 0x6a0e,0x25a1, +0x6a10,0x25a1, 0x6a12,0x25a1, 0x6a1a,0x25a1, 0x6a1c,0x25a1, 0x6a22,0x25a1, +0x6a24,0x25a1, 0x6a29,0x25a1, 0x6a2a,0x6a6b, 0x6a2b,0x25a1, 0x6a2c,0x25a1, +0x6a2d,0x25a1, 0x6a2e,0x25a1, 0x6a2f,0x6aa3, 0x6a30,0x25a1, 0x6a31,0x6afb, +0x6a33,0x25a1, 0x6a36,0x25a1, 0x6a37,0x25a1, 0x6a42,0x25a1, 0x6a43,0x25a1, +0x6a45,0x25a1, 0x6a4a,0x25a1, 0x6a4c,0x25a1, 0x6a52,0x25a1, 0x6a53,0x25a1, +0x6a57,0x25a1, 0x6a5c,0x25a1, 0x6a63,0x25a1, 0x6a65,0x6aeb, 0x6a6c,0x25a1, +0x6a6e,0x25a1, 0x6a70,0x25a1, 0x6a71,0x6ae5, 0x6a72,0x25a1, 0x6a73,0x25a1, +0x6a74,0x25a1, 0x6a75,0x25a1, 0x6a77,0x25a1, 0x6a78,0x25a1, 0x6a79,0x6ad3, +0x6a7a,0x25a1, 0x6a7b,0x25a1, 0x6a7c,0x6ade, 0x6a7d,0x25a1, 0x6a82,0x25a1, +0x6a86,0x25a1, 0x6a88,0x25a1, 0x6a8a,0x25a1, 0x6a8b,0x25a1, 0x6a8f,0x25a1, +0x6a90,0x7c37, 0x6a98,0x25a1, 0x6a99,0x25a1, 0x6a9d,0x25a1, 0x6aa7,0x25a1, +0x6aa9,0x6a81, 0x6aaa,0x6adf, 0x6aab,0x5bdf, 0x6ab0,0x25a1, 0x6ab1,0x25a1, +0x6ab2,0x25a1, 0x6ab5,0x25a1, 0x6abc,0x25a1, 0x6abe,0x25a1, 0x6abf,0x25a1, +0x6ac0,0x25a1, 0x6ac1,0x25a1, 0x6ac4,0x25a1, 0x6ac8,0x25a1, 0x6ac9,0x25a1, +0x6aca,0x25a1, 0x6ace,0x25a1, 0x6ad2,0x25a1, 0x6ad4,0x25a1, 0x6ad5,0x25a1, +0x6ad6,0x25a1, 0x6ad7,0x25a1, 0x6ad8,0x25a1, 0x6ae2,0x25a1, 0x6ae3,0x25a1, +0x6ae4,0x25a1, 0x6ae6,0x25a1, 0x6ae9,0x25a1, 0x6aed,0x25a1, 0x6af2,0x25a1, +0x6af4,0x25a1, 0x6af5,0x25a1, 0x6af6,0x25a1, 0x6af7,0x25a1, 0x6afd,0x25a1, +0x6afe,0x25a1, 0x6aff,0x25a1, 0x6b01,0x25a1, 0x6b05,0x25a1, 0x6b06,0x25a1, +0x6b07,0x25a1, 0x6b0c,0x25a1, 0x6b0d,0x25a1, 0x6b0e,0x25a1, 0x6b14,0x25a1, +0x6b15,0x25a1, 0x6b1b,0x25a1, 0x6b1c,0x25a1, 0x6b1d,0x25a1, 0x6b1f,0x25a1, +0x6b22,0x6b61, 0x6b24,0x6b5f, 0x6b26,0x25a1, 0x6b27,0x6b50, 0x6b29,0x25a1, +0x6b2a,0x25a1, 0x6b2b,0x6b43, 0x6b2e,0x25a1, 0x6b30,0x6b43, 0x6b35,0x25a1, +0x6b40,0x25a1, 0x6b44,0x25a1, 0x6b4f,0x25a1, 0x6b52,0x25a1, 0x6b53,0x25a1, +0x6b57,0x25a1, 0x6b58,0x25a1, 0x6b5a,0x25a1, 0x6b5d,0x25a1, 0x6b68,0x25a1, +0x6b69,0x25a1, 0x6b6b,0x25a1, 0x6b6c,0x25a1, 0x6b6e,0x25a1, 0x6b6f,0x25a1, +0x6b70,0x25a1, 0x6b71,0x25a1, 0x6b73,0x6b72, 0x6b74,0x66c6, 0x6b75,0x25a1, +0x6b7a,0x6b72, 0x6b7c,0x6bb2, 0x6b7d,0x25a1, 0x6b81,0x6b7f, 0x6b85,0x25a1, +0x6b87,0x6ba4, 0x6b8b,0x6b98, 0x6b90,0x25a1, 0x6b92,0x6b9e, 0x6b93,0x6bae, +0x6b9a,0x6bab, 0x6b9c,0x25a1, 0x6b9d,0x25a1, 0x6ba1,0x6baf, 0x6ba8,0x25a1, +0x6ba9,0x25a1, 0x6bac,0x25a1, 0x6bb1,0x6bb2, 0x6bb4,0x6bc6, 0x6bb8,0x25a1, +0x6bb9,0x25a1, 0x6bbb,0x25a1, 0x6bbe,0x25a1, 0x6bc1,0x6bc0, 0x6bc2,0x8f42, +0x6bce,0x25a1, 0x6bd1,0x25a1, 0x6bd5,0x7562, 0x6bd9,0x6583, 0x6bdc,0x25a1, +0x6bdd,0x25a1, 0x6bdf,0x25a1, 0x6be1,0x6c08, 0x6be5,0x25a1, 0x6be9,0x25a1, +0x6bea,0x725f, 0x6bed,0x25a1, 0x6bee,0x25a1, 0x6bf1,0x25a1, 0x6bf4,0x25a1, +0x6bf5,0x6bff, 0x6bf6,0x97a0, 0x6bfa,0x25a1, 0x6c07,0x6c0c, 0x6c0a,0x25a1, +0x6c0e,0x25a1, 0x6c12,0x25a1, 0x6c14,0x6c23, 0x6c17,0x6c23, 0x6c1c,0x25a1, +0x6c1e,0x25a1, 0x6c22,0x6c2b, 0x6c29,0x6c2c, 0x6c2d,0x25a1, 0x6c31,0x25a1, +0x6c32,0x6c33, 0x6c35,0x6c34, 0x6c37,0x25a1, 0x6c39,0x25a1, 0x6c3a,0x25a1, +0x6c3c,0x25a1, 0x6c3d,0x6c46, 0x6c44,0x25a1, 0x6c45,0x25a1, 0x6c47,0x532f, +0x6c48,0x25a1, 0x6c49,0x6f22, 0x6c51,0x25a1, 0x6c53,0x25a1, 0x6c56,0x25a1, +0x6c58,0x25a1, 0x6c5a,0x25a1, 0x6c62,0x25a1, 0x6c63,0x25a1, 0x6c64,0x6e6f, +0x6c6c,0x25a1, 0x6c6e,0x25a1, 0x6c75,0x25a1, 0x6c77,0x25a1, 0x6c79,0x6d36, +0x6c7c,0x25a1, 0x6c7f,0x25a1, 0x6c91,0x25a1, 0x6c97,0x25a1, 0x6c9e,0x25a1, +0x6c9f,0x6e9d, 0x6ca0,0x25a1, 0x6ca1,0x6c92, 0x6ca2,0x25a1, 0x6ca3,0x7043, +0x6ca4,0x6f1a, 0x6ca5,0x701d, 0x6ca6,0x6dea, 0x6ca7,0x6ec4, 0x6ca8,0x6e22, +0x6ca9,0x6e88, 0x6caa,0x6eec, 0x6caf,0x25a1, 0x6cb2,0x6c60, 0x6cb5,0x6fd4, +0x6cc4,0x6d29, 0x6cc8,0x25a1, 0x6ccb,0x25a1, 0x6cce,0x25a1, 0x6cd8,0x25a1, +0x6cde,0x6fd8, 0x6cdf,0x25a1, 0x6ce4,0x25a1, 0x6ce6,0x25a1, 0x6cea,0x6dda, +0x6cf4,0x25a1, 0x6cf6,0x6fa9, 0x6cf7,0x7027, 0x6cf8,0x7018, 0x6cfa,0x6ffc, +0x6cfb,0x7009, 0x6cfc,0x6f51, 0x6cfd,0x6fa4, 0x6cfe,0x6d87, 0x6cff,0x25a1, +0x6d01,0x6f54, 0x6d02,0x25a1, 0x6d05,0x25a1, 0x6d06,0x25a1, 0x6d12,0x7051, +0x6d13,0x25a1, 0x6d14,0x25a1, 0x6d15,0x25a1, 0x6d1c,0x25a1, 0x6d21,0x25a1, +0x6d23,0x25a1, 0x6d24,0x25a1, 0x6d26,0x25a1, 0x6d3c,0x7aaa, 0x6d43,0x6d79, +0x6d44,0x25a1, 0x6d45,0x6dfa, 0x6d46,0x6f3f, 0x6d47,0x6f86, 0x6d48,0x6e5e, +0x6d49,0x6eae, 0x6d4a,0x6fc1, 0x6d4b,0x6e2c, 0x6d4c,0x25a1, 0x6d4d,0x6fae, +0x6d4e,0x6fdf, 0x6d4f,0x700f, 0x6d50,0x6efb, 0x6d51,0x6e3e, 0x6d52,0x6ef8, +0x6d53,0x6fc3, 0x6d54,0x6f6f, 0x6d55,0x6fdc, 0x6d56,0x25a1, 0x6d57,0x25a1, +0x6d5b,0x25a1, 0x6d5c,0x6ff1, 0x6d5d,0x25a1, 0x6d6b,0x25a1, 0x6d71,0x25a1, +0x6d72,0x25a1, 0x6d73,0x25a1, 0x6d81,0x25a1, 0x6d82,0x5857, 0x6d8c,0x6e67, +0x6d8f,0x25a1, 0x6d96,0x25a1, 0x6d99,0x6dda, 0x6d9a,0x25a1, 0x6d9b,0x6fe4, +0x6d9c,0x25a1, 0x6d9d,0x6f87, 0x6d9e,0x6df6, 0x6d9f,0x6f23, 0x6da0,0x6f7f, +0x6da1,0x6e26, 0x6da2,0x6eb3, 0x6da3,0x6e19, 0x6da4,0x6ecc, 0x6da5,0x25a1, +0x6da6,0x6f64, 0x6da7,0x6f97, 0x6da8,0x6f32, 0x6da9,0x6f80, 0x6dad,0x25a1, +0x6db0,0x25a1, 0x6db1,0x25a1, 0x6db6,0x25a1, 0x6db9,0x25a1, 0x6dc0,0x6fb1, +0x6dc1,0x25a1, 0x6dc3,0x25a1, 0x6dce,0x25a1, 0x6de7,0x25a1, 0x6df8,0x25a1, +0x6dfe,0x25a1, 0x6dff,0x25a1, 0x6e01,0x25a1, 0x6e02,0x25a1, 0x6e04,0x25a1, +0x6e06,0x25a1, 0x6e07,0x25a1, 0x6e08,0x25a1, 0x6e09,0x25a1, 0x6e0a,0x6df5, +0x6e0b,0x25a1, 0x6e0c,0x6de5, 0x6e0d,0x6f2c, 0x6e0e,0x7006, 0x6e0f,0x25a1, +0x6e10,0x6f38, 0x6e11,0x6fa0, 0x6e12,0x25a1, 0x6e13,0x25a1, 0x6e14,0x6f01, +0x6e15,0x25a1, 0x6e16,0x700b, 0x6e17,0x6ef2, 0x6e18,0x25a1, 0x6e1e,0x25a1, +0x6e29,0x6eab, 0x6e2a,0x25a1, 0x6e37,0x25a1, 0x6e42,0x25a1, 0x6e48,0x25a1, +0x6e4c,0x25a1, 0x6e4f,0x25a1, 0x6e50,0x25a1, 0x6e57,0x25a1, 0x6e59,0x25a1, +0x6e6a,0x25a1, 0x6e6c,0x25a1, 0x6e6d,0x25a1, 0x6e70,0x25a1, 0x6e75,0x25a1, +0x6e76,0x25a1, 0x6e7a,0x25a1, 0x6e7b,0x25a1, 0x6e7c,0x6d85, 0x6e7d,0x25a1, +0x6e7e,0x7063, 0x6e7f,0x6fd5, 0x6e80,0x25a1, 0x6e81,0x25a1, 0x6e82,0x25a1, +0x6e83,0x6f70, 0x6e84,0x25a1, 0x6e85,0x6ffa, 0x6e86,0x6f35, 0x6e87,0x6f0a, +0x6e8a,0x25a1, 0x6e8b,0x25a1, 0x6e8c,0x25a1, 0x6e91,0x25a1, 0x6e95,0x25a1, +0x6e9a,0x25a1, 0x6ea8,0x25a1, 0x6ea9,0x25a1, 0x6eac,0x25a1, 0x6ead,0x25a1, +0x6eb5,0x25a1, 0x6eb8,0x25a1, 0x6ebb,0x79a2, 0x6ed7,0x6f77, 0x6ed9,0x532f, +0x6eda,0x6efe, 0x6edb,0x25a1, 0x6edd,0x7027, 0x6ede,0x6eef, 0x6edf,0x7069, +0x6ee0,0x7044, 0x6ee1,0x6eff, 0x6ee2,0x7005, 0x6ee3,0x25a1, 0x6ee4,0x6ffe, +0x6ee5,0x6feb, 0x6ee6,0x7064, 0x6ee7,0x25a1, 0x6ee8,0x6ff1, 0x6ee9,0x7058, +0x6eea,0x6fa6, 0x6ef0,0x25a1, 0x6ef3,0x25a1, 0x6efa,0x25a1, 0x6f04,0x25a1, +0x6f0b,0x25a1, 0x6f0c,0x25a1, 0x6f10,0x25a1, 0x6f11,0x6e89, 0x6f16,0x25a1, +0x6f17,0x25a1, 0x6f1b,0x25a1, 0x6f1d,0x25a1, 0x6f24,0x7060, 0x6f28,0x25a1, +0x6f34,0x25a1, 0x6f3d,0x25a1, 0x6f42,0x25a1, 0x6f44,0x25a1, 0x6f45,0x25a1, +0x6f46,0x7020, 0x6f47,0x701f, 0x6f48,0x25a1, 0x6f49,0x25a1, 0x6f4a,0x25a1, +0x6f4b,0x7032, 0x6f4c,0x25a1, 0x6f4d,0x6ff0, 0x6f56,0x25a1, 0x6f59,0x25a1, +0x6f5c,0x6f5b, 0x6f65,0x25a1, 0x6f68,0x25a1, 0x6f71,0x25a1, 0x6f74,0x7026, +0x6f75,0x25a1, 0x6f79,0x25a1, 0x6f81,0x25a1, 0x6f83,0x25a1, 0x6f8a,0x25a1, +0x6f8f,0x25a1, 0x6f91,0x25a1, 0x6f98,0x25a1, 0x6f99,0x25a1, 0x6f9a,0x25a1, +0x6f9b,0x25a1, 0x6f9c,0x703e, 0x6f9d,0x25a1, 0x6f9f,0x25a1, 0x6fb5,0x25a1, +0x6fb7,0x25a1, 0x6fbb,0x25a1, 0x6fbe,0x25a1, 0x6fc5,0x25a1, 0x6fd0,0x25a1, +0x6fd1,0x7028, 0x6fd2,0x7015, 0x6fd3,0x25a1, 0x6fd6,0x25a1, 0x6fd7,0x25a1, +0x6fd9,0x25a1, 0x6fda,0x25a1, 0x6fe5,0x25a1, 0x6fea,0x25a1, 0x6ff3,0x25a1, +0x6ff5,0x25a1, 0x6ff6,0x25a1, 0x6ff8,0x25a1, 0x6ff9,0x25a1, 0x6ffd,0x25a1, +0x7002,0x25a1, 0x7003,0x25a1, 0x7008,0x25a1, 0x7010,0x25a1, 0x7012,0x25a1, +0x7013,0x25a1, 0x701e,0x25a1, 0x7025,0x25a1, 0x702c,0x25a1, 0x702d,0x25a1, +0x702e,0x25a1, 0x7036,0x25a1, 0x703d,0x25a1, 0x7047,0x25a1, 0x704b,0x25a1, +0x704d,0x25a1, 0x704e,0x7069, 0x704f,0x705d, 0x7050,0x25a1, 0x7053,0x25a1, +0x7054,0x7069, 0x7059,0x25a1, 0x705c,0x701b, 0x7067,0x7069, 0x706c,0x706b, +0x706d,0x6ec5, 0x706e,0x25a1, 0x706f,0x71c8, 0x7072,0x25a1, 0x7073,0x25a1, +0x7075,0x9748, 0x7077,0x25a1, 0x7079,0x25a1, 0x707b,0x25a1, 0x707e,0x707d, +0x707f,0x71e6, 0x7080,0x716c, 0x7081,0x25a1, 0x7087,0x25a1, 0x7088,0x25a1, +0x7089,0x7210, 0x708b,0x25a1, 0x708c,0x25a1, 0x708d,0x25a1, 0x708f,0x25a1, +0x7090,0x25a1, 0x7096,0x71c9, 0x7097,0x25a1, 0x709b,0x25a1, 0x709c,0x7152, +0x709d,0x7197, 0x709e,0x25a1, 0x70a0,0x25a1, 0x70a2,0x25a1, 0x70a3,0x25a1, +0x70a5,0x25a1, 0x70a6,0x25a1, 0x70a7,0x25a1, 0x70a8,0x25a1, 0x70aa,0x25a1, +0x70b2,0x25a1, 0x70b6,0x25a1, 0x70b9,0x9ede, 0x70bb,0x77f3, 0x70bc,0x7149, +0x70bd,0x71be, 0x70bf,0x25a1, 0x70c0,0x4e4e, 0x70c1,0x720d, 0x70c2,0x721b, +0x70c3,0x70f4, 0x70c4,0x25a1, 0x70c9,0x25a1, 0x70cc,0x25a1, 0x70d0,0x25a1, +0x70d5,0x25a1, 0x70d6,0x25a1, 0x70db,0x71ed, 0x70df,0x7159, 0x70e3,0x25a1, +0x70e5,0x25a1, 0x70e6,0x7169, 0x70e7,0x71d2, 0x70e8,0x71c1, 0x70e9,0x71f4, +0x70ea,0x25a1, 0x70eb,0x71d9, 0x70ec,0x71fc, 0x70ed,0x71b1, 0x70ee,0x25a1, +0x70f1,0x25a1, 0x70f2,0x25a1, 0x70f5,0x25a1, 0x70fe,0x25a1, 0x7101,0x25a1, +0x7103,0x25a1, 0x7105,0x25a1, 0x7107,0x25a1, 0x7108,0x25a1, 0x710f,0x25a1, +0x7111,0x25a1, 0x7112,0x25a1, 0x7114,0x25a1, 0x7115,0x7165, 0x7116,0x71dc, +0x7118,0x71fe, 0x711d,0x25a1, 0x7124,0x25a1, 0x7127,0x25a1, 0x7129,0x25a1, +0x712a,0x25a1, 0x712b,0x25a1, 0x712c,0x25a1, 0x712d,0x25a1, 0x7133,0x25a1, +0x7134,0x25a1, 0x7135,0x25a1, 0x7137,0x25a1, 0x7138,0x25a1, 0x7139,0x25a1, +0x713b,0x25a1, 0x713c,0x25a1, 0x713d,0x25a1, 0x713e,0x25a1, 0x713f,0x25a1, +0x7140,0x25a1, 0x7145,0x7146, 0x7148,0x25a1, 0x714a,0x5ba3, 0x714f,0x25a1, +0x7151,0x25a1, 0x7155,0x25a1, 0x7157,0x25a1, 0x715b,0x25a1, 0x716b,0x25a1, +0x716d,0x25a1, 0x716f,0x25a1, 0x7171,0x25a1, 0x7173,0x7cca, 0x7174,0x25a1, +0x7175,0x25a1, 0x7176,0x25a1, 0x7177,0x25a1, 0x7179,0x25a1, 0x717a,0x9000, +0x717c,0x25a1, 0x717e,0x25a1, 0x717f,0x25a1, 0x7183,0x25a1, 0x7188,0x25a1, +0x718b,0x25a1, 0x718c,0x25a1, 0x718d,0x25a1, 0x718e,0x25a1, 0x7191,0x25a1, +0x7193,0x25a1, 0x7195,0x25a1, 0x7196,0x25a1, 0x7198,0x6e9c, 0x71a2,0x25a1, +0x71a3,0x25a1, 0x71a6,0x25a1, 0x71ab,0x25a1, 0x71ad,0x5f57, 0x71ae,0x25a1, +0x71b4,0x25a1, 0x71b6,0x25a1, 0x71b7,0x25a1, 0x71ba,0x25a1, 0x71bb,0x25a1, +0x71cc,0x25a1, 0x71cd,0x25a1, 0x71d1,0x25a1, 0x71d3,0x25a1, 0x71d7,0x25a1, +0x71dd,0x25a1, 0x71de,0x25a1, 0x71e3,0x25a1, 0x71e9,0x25a1, 0x71ea,0x25a1, +0x71eb,0x25a1, 0x71ef,0x25a1, 0x71f3,0x25a1, 0x71f5,0x25a1, 0x71f6,0x25a1, +0x71f7,0x25a1, 0x71fa,0x25a1, 0x7200,0x25a1, 0x7204,0x25a1, 0x7208,0x25a1, +0x7209,0x25a1, 0x720b,0x25a1, 0x720e,0x25a1, 0x720f,0x25a1, 0x7211,0x25a1, +0x7212,0x25a1, 0x7215,0x25a1, 0x7216,0x25a1, 0x7217,0x25a1, 0x7218,0x25a1, +0x721c,0x25a1, 0x7220,0x25a1, 0x7221,0x25a1, 0x7224,0x25a1, 0x7225,0x25a1, +0x722b,0x25a1, 0x722e,0x25a1, 0x722f,0x25a1, 0x7231,0x611b, 0x7232,0x70ba, +0x7233,0x25a1, 0x7234,0x25a1, 0x7237,0x723a, 0x723c,0x25a1, 0x7240,0x25a1, +0x7243,0x25a1, 0x7245,0x25a1, 0x724d,0x7258, 0x724e,0x25a1, 0x7250,0x25a1, +0x7251,0x25a1, 0x7254,0x25a1, 0x7255,0x25a1, 0x7257,0x25a1, 0x725c,0x725b, +0x7264,0x25a1, 0x7265,0x25a1, 0x7266,0x729b, 0x7268,0x25a1, 0x726b,0x25a1, +0x726d,0x25a1, 0x7271,0x25a1, 0x7275,0x727d, 0x727a,0x72a7, 0x7282,0x25a1, +0x7283,0x25a1, 0x7287,0x25a1, 0x728a,0x72a2, 0x728f,0x309b, 0x7294,0x25a1, +0x7299,0x25a1, 0x729c,0x25a1, 0x729f,0x5f37, 0x72a0,0x25a1, 0x72ab,0x25a1, +0x72ad,0x72ac, 0x72b1,0x25a1, 0x72b2,0x25a1, 0x72b3,0x25a1, 0x72b6,0x72c0, +0x72b7,0x7377, 0x72b8,0x99ac, 0x72b9,0x7336, 0x72bb,0x25a1, 0x72bc,0x25a1, +0x72be,0x25a1, 0x72c7,0x25a1, 0x72c8,0x72fd, 0x72cd,0x5305, 0x72cf,0x25a1, +0x72d3,0x25a1, 0x72d5,0x25a1, 0x72db,0x25a1, 0x72dd,0x736e, 0x72de,0x7370, +0x72e2,0x25a1, 0x72e5,0x25a1, 0x72e7,0x25a1, 0x72ec,0x7368, 0x72ed,0x72f9, +0x72ee,0x7345, 0x72ef,0x736a, 0x72f0,0x7319, 0x72f1,0x7344, 0x72f2,0x733b, +0x72f5,0x25a1, 0x7302,0x25a1, 0x7303,0x736b, 0x7304,0x25a1, 0x7305,0x25a1, +0x7306,0x25a1, 0x7309,0x25a1, 0x730d,0x25a1, 0x730e,0x7375, 0x7310,0x25a1, +0x7314,0x25a1, 0x7315,0x737c, 0x731a,0x25a1, 0x731f,0x25a1, 0x7320,0x25a1, +0x7321,0x7380, 0x7324,0x25a1, 0x7328,0x25a1, 0x732a,0x8c6c, 0x732b,0x8c93, +0x732c,0x875f, 0x732e,0x737b, 0x732f,0x25a1, 0x7338,0x875e, 0x7339,0x67e5, +0x733d,0x25a1, 0x7341,0x25a1, 0x7346,0x25a1, 0x7347,0x25a1, 0x7348,0x25a1, +0x734b,0x25a1, 0x734f,0x25a1, 0x7353,0x25a1, 0x7354,0x25a1, 0x7355,0x25a1, +0x7356,0x25a1, 0x735c,0x25a1, 0x7363,0x25a1, 0x7364,0x25a1, 0x736d,0x737a, +0x7371,0x25a1, 0x7374,0x25a1, 0x7379,0x25a1, 0x738c,0x25a1, 0x738d,0x25a1, +0x738f,0x25a1, 0x7390,0x25a1, 0x7391,0x74a3, 0x7398,0x25a1, 0x7399,0x74b5, +0x739a,0x7452, 0x739b,0x746a, 0x739c,0x25a1, 0x739e,0x25a1, 0x73a3,0x25a1, +0x73a7,0x25a1, 0x73aa,0x25a1, 0x73ae,0x744b, 0x73af,0x74b0, 0x73b0,0x73fe, +0x73b1,0x7472, 0x73ba,0x74bd, 0x73bd,0x25a1, 0x73c1,0x25a1, 0x73c4,0x25a1, +0x73c9,0x6c0f, 0x73ce,0x25a1, 0x73cf,0x73a8, 0x73d0,0x743a, 0x73d1,0x74cf, +0x73d5,0x25a1, 0x73df,0x25a1, 0x73e1,0x25a1, 0x73e2,0x25a1, 0x73e4,0x25a1, +0x73e6,0x25a1, 0x73ec,0x25a1, 0x73ef,0x25a1, 0x73f0,0x74ab, 0x73f1,0x74d4, +0x73f2,0x743f, 0x73f3,0x25a1, 0x73f7,0x25a1, 0x73f9,0x25a1, 0x73fb,0x25a1, +0x7402,0x25a1, 0x740e,0x74a1, 0x740f,0x7489, 0x7410,0x7463, 0x7411,0x25a1, +0x7412,0x25a1, 0x7413,0x25a1, 0x7414,0x25a1, 0x7415,0x25a1, 0x7417,0x25a1, +0x7418,0x25a1, 0x7419,0x25a1, 0x741c,0x25a1, 0x741e,0x25a1, 0x741f,0x25a1, +0x7427,0x25a1, 0x7437,0x25a1, 0x7438,0x25a1, 0x7439,0x25a1, 0x743b,0x25a1, +0x743c,0x74ca, 0x743d,0x25a1, 0x743e,0x25a1, 0x7443,0x25a1, 0x7445,0x25a1, +0x7447,0x25a1, 0x7448,0x25a1, 0x7449,0x25a1, 0x744c,0x25a1, 0x7453,0x25a1, +0x7456,0x25a1, 0x7458,0x25a1, 0x745d,0x25a1, 0x7460,0x25a1, 0x7461,0x25a1, +0x7465,0x25a1, 0x7466,0x25a1, 0x7468,0x25a1, 0x746b,0x25a1, 0x746c,0x25a1, +0x7474,0x25a1, 0x7476,0x7464, 0x7477,0x74a6, 0x7478,0x25a1, 0x747a,0x25a1, +0x747b,0x25a1, 0x7482,0x25a1, 0x7484,0x25a1, 0x748c,0x25a1, 0x748d,0x25a1, +0x748e,0x74d4, 0x748f,0x25a1, 0x7491,0x25a1, 0x7493,0x25a1, 0x7496,0x25a1, +0x7499,0x25a1, 0x749b,0x25a1, 0x749d,0x25a1, 0x74a2,0x25a1, 0x74a4,0x25a1, +0x74ac,0x25a1, 0x74ae,0x25a1, 0x74b3,0x25a1, 0x74b4,0x25a1, 0x74b9,0x25a1, +0x74bc,0x25a1, 0x74c4,0x25a1, 0x74c6,0x25a1, 0x74c7,0x25a1, 0x74c8,0x25a1, +0x74c9,0x25a1, 0x74cc,0x25a1, 0x74cd,0x25a1, 0x74ce,0x25a1, 0x74d0,0x25a1, +0x74d1,0x25a1, 0x74d2,0x74da, 0x74d3,0x25a1, 0x74e7,0x25a1, 0x74ea,0x25a1, +0x74eb,0x25a1, 0x74ed,0x25a1, 0x74ee,0x7515, 0x74ef,0x750c, 0x74f0,0x25a1, +0x74f1,0x25a1, 0x74f2,0x25a1, 0x74f3,0x25a1, 0x74f8,0x25a1, 0x74f9,0x25a1, +0x74fa,0x25a1, 0x74fc,0x25a1, 0x7501,0x25a1, 0x7505,0x25a1, 0x7506,0x25a1, +0x7509,0x25a1, 0x750a,0x25a1, 0x750e,0x25a1, 0x7519,0x8cb3, 0x751b,0x25a1, +0x751e,0x25a1, 0x7520,0x25a1, 0x7523,0x7522, 0x7524,0x25a1, 0x7527,0x8564, +0x7534,0x25a1, 0x7535,0x96fb, 0x7536,0x25a1, 0x753b,0x756b, 0x753c,0x25a1, +0x7541,0x25a1, 0x7542,0x25a1, 0x7543,0x25a1, 0x7544,0x25a1, 0x7545,0x66a2, +0x7546,0x25a1, 0x7549,0x25a1, 0x754a,0x25a1, 0x754d,0x25a1, 0x7550,0x25a1, +0x7551,0x25a1, 0x7552,0x25a1, 0x7553,0x25a1, 0x7555,0x25a1, 0x7556,0x25a1, +0x7557,0x25a1, 0x7558,0x25a1, 0x755e,0x25a1, 0x7560,0x25a1, 0x7561,0x25a1, +0x7567,0x25a1, 0x7568,0x25a1, 0x7569,0x25a1, 0x756d,0x25a1, 0x756e,0x25a1, +0x7571,0x25a1, 0x7572,0x756c, 0x7573,0x758a, 0x7574,0x7587, 0x7575,0x756b, +0x757a,0x25a1, 0x757b,0x25a1, 0x757c,0x25a1, 0x7581,0x25a1, 0x7582,0x25a1, +0x7583,0x757d, 0x7585,0x25a1, 0x7588,0x25a1, 0x7589,0x25a1, 0x758d,0x25a1, +0x758e,0x758f, 0x7592,0x2f67, 0x7593,0x25a1, 0x7596,0x7664, 0x7597,0x7642, +0x759b,0x25a1, 0x759c,0x25a1, 0x759e,0x25a1, 0x759f,0x7627, 0x75a0,0x7658, +0x75a1,0x760d, 0x75a6,0x25a1, 0x75a8,0x25a1, 0x75a9,0x25a1, 0x75ac,0x7646, +0x75ad,0x25a1, 0x75ae,0x7621, 0x75af,0x760b, 0x75b1,0x76b0, 0x75b4,0x75fe, +0x75b7,0x25a1, 0x75c3,0x7d43, 0x75c6,0x25a1, 0x75c8,0x7670, 0x75c9,0x75d9, +0x75d2,0x7662, 0x75d3,0x25a1, 0x75d6,0x555e, 0x75dc,0x25a1, 0x75e5,0x25a1, +0x75e8,0x7646, 0x75e9,0x7626, 0x75ea,0x7613, 0x75eb,0x7647, 0x75ec,0x760d, +0x75ee,0x25a1, 0x75f4,0x7661, 0x75f9,0x75fa, 0x7602,0x25a1, 0x7604,0x25a1, +0x7605,0x7649, 0x7606,0x75b9, 0x7607,0x25a1, 0x760e,0x25a1, 0x7612,0x25a1, +0x7617,0x761e, 0x7618,0x763a, 0x762a,0x765f, 0x762b,0x7671, 0x762c,0x25a1, +0x762e,0x25a1, 0x7636,0x25a1, 0x7637,0x25a1, 0x7639,0x25a1, 0x763b,0x25a1, +0x763e,0x766e, 0x763f,0x766d, 0x7640,0x5ee3, 0x7641,0x25a1, 0x7644,0x25a1, +0x7645,0x25a1, 0x764a,0x25a1, 0x764b,0x25a1, 0x764d,0x6591, 0x764e,0x7647, +0x764f,0x25a1, 0x7651,0x25a1, 0x7654,0x610f, 0x7655,0x25a1, 0x765b,0x25a1, +0x765d,0x25a1, 0x765e,0x7669, 0x7663,0x766c, 0x7666,0x25a1, 0x7667,0x75e2, +0x7668,0x25a1, 0x766b,0x7672, 0x766f,0x81d2, 0x7673,0x25a1, 0x7674,0x25a1, +0x7676,0x25a1, 0x7677,0x25a1, 0x767a,0x767c, 0x7680,0x7682, 0x7683,0x25a1, +0x7685,0x25a1, 0x768c,0x25a1, 0x768d,0x25a1, 0x7690,0x25a1, 0x7691,0x769a, +0x7694,0x25a1, 0x7697,0x25a1, 0x7698,0x25a1, 0x769f,0x25a1, 0x76a0,0x25a1, +0x76a1,0x25a1, 0x76a2,0x25a1, 0x76a3,0x25a1, 0x76a5,0x25a1, 0x76a7,0x25a1, +0x76a8,0x25a1, 0x76a9,0x25a1, 0x76ac,0x25a1, 0x76b1,0x76ba, 0x76b2,0x76b8, +0x76b3,0x25a1, 0x76b6,0x25a1, 0x76b7,0x25a1, 0x76b9,0x25a1, 0x76bc,0x25a1, +0x76c0,0x25a1, 0x76c1,0x25a1, 0x76c3,0x554a, 0x76c7,0x25a1, 0x76cb,0x25a1, +0x76cc,0x25a1, 0x76cf,0x76de, 0x76d0,0x9e7d, 0x76d1,0x76e3, 0x76d5,0x25a1, +0x76d6,0x84cb, 0x76d7,0x76dc, 0x76d8,0x76e4, 0x76d9,0x25a1, 0x76e0,0x25a1, +0x76e2,0x25a1, 0x76e8,0x25a1, 0x76eb,0x25a1, 0x76f6,0x25a1, 0x76fd,0x25a1, +0x76ff,0x25a1, 0x7700,0x25a1, 0x7702,0x25a1, 0x7706,0x25a1, 0x770c,0x7e23, +0x770d,0x5340, 0x770e,0x25a1, 0x770f,0x25a1, 0x7714,0x25a1, 0x7716,0x25a1, +0x7717,0x25a1, 0x7718,0x25a1, 0x771c,0x25a1, 0x771e,0x771f, 0x7721,0x25a1, +0x7724,0x25a1, 0x7726,0x7725, 0x772a,0x25a1, 0x772b,0x25a1, 0x772c,0x77d3, +0x772e,0x25a1, 0x772f,0x7787, 0x7730,0x25a1, 0x773f,0x25a1, 0x7740,0x8457, +0x7741,0x775c, 0x7742,0x25a1, 0x7743,0x68ad, 0x7748,0x25a1, 0x7749,0x25a1, +0x7750,0x775e, 0x7751,0x77bc, 0x7753,0x25a1, 0x7757,0x25a1, 0x7758,0x25a1, +0x775d,0x25a1, 0x7764,0x25a1, 0x7770,0x25a1, 0x7771,0x25a1, 0x7772,0x25a1, +0x7773,0x25a1, 0x7774,0x25a1, 0x7775,0x25a1, 0x7776,0x25a1, 0x7777,0x25a1, +0x7778,0x25a1, 0x777a,0x25a1, 0x777b,0x25a1, 0x7786,0x25a1, 0x778a,0x25a1, +0x7790,0x25a1, 0x7792,0x779e, 0x7793,0x25a1, 0x7794,0x25a1, 0x7796,0x25a1, +0x7798,0x25a1, 0x77a4,0x25a1, 0x77a6,0x25a1, 0x77a9,0x77da, 0x77ae,0x25a1, +0x77af,0x25a1, 0x77b8,0x25a1, 0x77b9,0x25a1, 0x77be,0x25a1, 0x77c0,0x25a1, +0x77c1,0x25a1, 0x77c3,0x25a1, 0x77c5,0x25a1, 0x77c6,0x25a1, 0x77c8,0x25a1, +0x77cb,0x25a1, 0x77d1,0x25a1, 0x77d2,0x25a1, 0x77d6,0x25a1, 0x77dd,0x25a1, +0x77df,0x25a1, 0x77e1,0x25a1, 0x77e4,0x75c5, 0x77e6,0x25a1, 0x77ea,0x25a1, +0x77eb,0x77ef, 0x77f4,0x25a1, 0x77f5,0x25a1, 0x77f6,0x78ef, 0x77fe,0x792c, +0x77ff,0x7926, 0x7800,0x78ad, 0x7801,0x78bc, 0x7804,0x25a1, 0x7807,0x25a1, +0x7808,0x25a1, 0x780a,0x25a1, 0x780b,0x25a1, 0x7815,0x25a1, 0x7816,0x78da, +0x7817,0x7868, 0x7818,0x5c6f, 0x7819,0x25a1, 0x781a,0x786f, 0x781b,0x25a1, +0x781c,0x98a8, 0x781e,0x25a1, 0x7824,0x25a1, 0x7836,0x25a1, 0x7839,0x827e, +0x783a,0x792a, 0x783b,0x7931, 0x783c,0x4edd, 0x783d,0x25a1, 0x783e,0x792b, +0x783f,0x25a1, 0x7840,0x790e, 0x7841,0x785c, 0x7842,0x25a1, 0x7844,0x25a1, +0x7846,0x25a1, 0x7847,0x6efe, 0x784b,0x25a1, 0x784f,0x25a1, 0x7851,0x25a1, +0x7853,0x25a1, 0x7854,0x25a1, 0x7855,0x78a9, 0x7856,0x7864, 0x7857,0x78fd, +0x7858,0x25a1, 0x7859,0x78d1, 0x785a,0x7904, 0x785b,0x25a1, 0x785f,0x25a1, +0x7861,0x25a1, 0x7863,0x25a1, 0x7866,0x25a1, 0x7867,0x25a1, 0x786e,0x78ba, +0x7872,0x25a1, 0x7873,0x25a1, 0x7874,0x25a1, 0x7875,0x25a1, 0x7876,0x25a1, +0x7877,0x9e7c, 0x7878,0x25a1, 0x787a,0x25a1, 0x787d,0x25a1, 0x7882,0x25a1, +0x7883,0x5834, 0x7888,0x25a1, 0x788a,0x25a1, 0x788b,0x25a1, 0x788d,0x7919, +0x7890,0x25a1, 0x7892,0x25a1, 0x789b,0x78e7, 0x789c,0x78e3, 0x789d,0x25a1, +0x78a6,0x25a1, 0x78ae,0x25a1, 0x78af,0x25a1, 0x78b1,0x9e7c, 0x78b5,0x25a1, +0x78b6,0x25a1, 0x78b7,0x25a1, 0x78b8,0x25a1, 0x78b9,0x5ba3, 0x78bd,0x25a1, +0x78bf,0x25a1, 0x78c0,0x25a1, 0x78c2,0x25a1, 0x78c6,0x25a1, 0x78c7,0x25a1, +0x78d2,0x25a1, 0x78d3,0x25a1, 0x78d6,0x25a1, 0x78d7,0x25a1, 0x78d8,0x25a1, +0x78d9,0x889e, 0x78dc,0x25a1, 0x78e4,0x25a1, 0x78e6,0x25a1, 0x78eb,0x25a1, +0x78ee,0x25a1, 0x78f0,0x25a1, 0x78f1,0x25a1, 0x78f5,0x25a1, 0x78f6,0x25a1, +0x78f8,0x25a1, 0x7900,0x25a1, 0x7903,0x25a1, 0x7906,0x25a1, 0x7907,0x25a1, +0x7908,0x25a1, 0x790a,0x25a1, 0x790b,0x25a1, 0x790c,0x790e, 0x790d,0x25a1, +0x790f,0x25a1, 0x7915,0x25a1, 0x7916,0x25a1, 0x7918,0x25a1, 0x791a,0x25a1, +0x791f,0x25a1, 0x7920,0x25a1, 0x7922,0x25a1, 0x792e,0x25a1, 0x7930,0x25a1, +0x7932,0x25a1, 0x7933,0x25a1, 0x7934,0x7921, 0x7936,0x25a1, 0x7937,0x25a1, +0x793b,0x793a, 0x793c,0x79ae, 0x7943,0x25a1, 0x794d,0x25a1, 0x794e,0x7995, +0x7958,0x25a1, 0x7959,0x25a1, 0x7962,0x79b0, 0x7966,0x25a1, 0x796c,0x25a1, +0x796e,0x25a1, 0x796f,0x798e, 0x7971,0x25a1, 0x7975,0x25a1, 0x7976,0x25a1, +0x7977,0x79b1, 0x7978,0x798d, 0x797b,0x25a1, 0x797e,0x25a1, 0x7980,0x7a1f, +0x7983,0x25a1, 0x7984,0x797f, 0x7985,0x79aa, 0x7986,0x25a1, 0x7987,0x25a1, +0x7989,0x25a1, 0x798c,0x25a1, 0x7991,0x25a1, 0x7992,0x6020, 0x7999,0x25a1, +0x799d,0x25a1, 0x799e,0x25a1, 0x799f,0x25a1, 0x79a3,0x25a1, 0x79a5,0x25a1, +0x79a9,0x25a1, 0x79af,0x25a1, 0x79b5,0x25a1, 0x79bb,0x96e2, 0x79bc,0x25a1, +0x79c2,0x25a1, 0x79c3,0x79bf, 0x79c4,0x25a1, 0x79c6,0x7a08, 0x79c7,0x25a1, +0x79ca,0x25a1, 0x79cc,0x25a1, 0x79cd,0x7a2e, 0x79d0,0x25a1, 0x79d3,0x25a1, +0x79d4,0x25a1, 0x79d7,0x25a1, 0x79d9,0x25a1, 0x79da,0x25a1, 0x79db,0x25a1, +0x79e1,0x25a1, 0x79e2,0x25a1, 0x79e5,0x25a1, 0x79e8,0x25a1, 0x79ef,0x7a4d, +0x79f0,0x7a31, 0x79f1,0x25a1, 0x79f2,0x25a1, 0x79f3,0x25a1, 0x79f4,0x25a1, +0x79f5,0x25a1, 0x79f9,0x25a1, 0x79fc,0x25a1, 0x79fd,0x7a62, 0x79fe,0x7a60, +0x79ff,0x25a1, 0x7a01,0x25a1, 0x7a06,0x7a6d, 0x7a07,0x25a1, 0x7a09,0x25a1, +0x7a0e,0x7a05, 0x7a0f,0x25a1, 0x7a16,0x25a1, 0x7a1d,0x25a1, 0x7a21,0x25a1, +0x7a23,0x7a4c, 0x7a24,0x25a1, 0x7a25,0x25a1, 0x7a27,0x25a1, 0x7a29,0x25a1, +0x7a2a,0x25a1, 0x7a2c,0x25a1, 0x7a2d,0x25a1, 0x7a32,0x25a1, 0x7a33,0x7a69, +0x7a34,0x25a1, 0x7a35,0x25a1, 0x7a36,0x25a1, 0x7a38,0x25a1, 0x7a3a,0x25a1, +0x7a3e,0x25a1, 0x7a41,0x25a1, 0x7a42,0x25a1, 0x7a43,0x25a1, 0x7a45,0x25a1, +0x7a49,0x25a1, 0x7a4f,0x25a1, 0x7a50,0x25a1, 0x7a51,0x7a61, 0x7a52,0x25a1, +0x7a53,0x25a1, 0x7a55,0x25a1, 0x7a59,0x25a1, 0x7a5d,0x25a1, 0x7a5e,0x25a1, +0x7a63,0x25a1, 0x7a64,0x25a1, 0x7a65,0x25a1, 0x7a66,0x25a1, 0x7a6a,0x25a1, +0x7a6f,0x25a1, 0x7a72,0x25a1, 0x7a73,0x25a1, 0x7a77,0x7aae, 0x7a7c,0x25a1, +0x7a7d,0x25a1, 0x7a82,0x25a1, 0x7a83,0x7aca, 0x7a8d,0x7ac5, 0x7a8e,0x25a1, +0x7a91,0x7aaf, 0x7a93,0x25a1, 0x7a9a,0x25a1, 0x7a9b,0x5202, 0x7a9c,0x7ac4, +0x7a9d,0x7aa9, 0x7aa1,0x25a1, 0x7aa2,0x8cb3, 0x7aa4,0x25a1, 0x7aa5,0x7aba, +0x7aa6,0x7ac7, 0x7aa7,0x25a1, 0x7aad,0x7ab6, 0x7ab0,0x25a1, 0x7ab9,0x25a1, +0x7abb,0x25a1, 0x7abc,0x25a1, 0x7abd,0x25a1, 0x7ac2,0x25a1, 0x7ac3,0x25a1, +0x7ac6,0x25a1, 0x7ac8,0x25a1, 0x7ac9,0x25a1, 0x7acc,0x25a1, 0x7acd,0x25a1, +0x7ace,0x25a1, 0x7acf,0x25a1, 0x7ad0,0x25a1, 0x7ad2,0x25a1, 0x7ad3,0x25a1, +0x7ad4,0x25a1, 0x7ad5,0x25a1, 0x7ad6,0x8c4e, 0x7ad7,0x25a1, 0x7ada,0x25a1, +0x7adb,0x25a1, 0x7adc,0x9f8d, 0x7add,0x25a1, 0x7ade,0x7af6, 0x7ae1,0x25a1, +0x7ae2,0x25a1, 0x7ae7,0x25a1, 0x7ae8,0x25a1, 0x7ae9,0x25a1, 0x7aea,0x25a1, +0x7aec,0x25a1, 0x7af0,0x25a1, 0x7af1,0x25a1, 0x7af2,0x25a1, 0x7af3,0x25a1, +0x7af4,0x25a1, 0x7af5,0x25a1, 0x7af8,0x25a1, 0x7afc,0x25a1, 0x7afe,0x25a1, +0x7b02,0x25a1, 0x7b03,0x7be4, 0x7b07,0x25a1, 0x7b0b,0x7b4d, 0x7b0c,0x25a1, +0x7b0d,0x25a1, 0x7b14,0x7b46, 0x7b15,0x7b67, 0x7b16,0x25a1, 0x7b17,0x25a1, +0x7b1c,0x25a1, 0x7b1f,0x25a1, 0x7b21,0x25a1, 0x7b27,0x25a1, 0x7b29,0x25a1, +0x7b2d,0x6d6e, 0x7b36,0x25a1, 0x7b37,0x25a1, 0x7b39,0x25a1, 0x7b3a,0x7b8b, +0x7b3c,0x7c60, 0x7b3d,0x25a1, 0x7b3e,0x7c69, 0x7b3f,0x25a1, 0x7b41,0x25a1, +0x7b42,0x25a1, 0x7b43,0x25a1, 0x7b51,0x7bc9, 0x7b53,0x25a1, 0x7b55,0x25a1, +0x7b57,0x25a1, 0x7b59,0x25a1, 0x7b5a,0x7bf3, 0x7b5b,0x7be9, 0x7b5c,0x7c39, +0x7b5d,0x7b8f, 0x7b5e,0x25a1, 0x7b5f,0x25a1, 0x7b62,0x628a, 0x7b68,0x25a1, +0x7b6a,0x25a1, 0x7b6b,0x25a1, 0x7b6c,0x25a1, 0x7b6f,0x25a1, 0x7b79,0x7c4c, +0x7b7a,0x25a1, 0x7b7b,0x66f4, 0x7b7c,0x25a1, 0x7b7d,0x25a1, 0x7b7e,0x7c3d, +0x7b7f,0x25a1, 0x7b80,0x7c21, 0x7b81,0x25a1, 0x7b83,0x25a1, 0x7b86,0x25a1, +0x7b89,0x25a1, 0x7b92,0x25a1, 0x7b93,0x7c59, 0x7b9a,0x25a1, 0x7b9e,0x25a1, +0x7b9f,0x25a1, 0x7ba2,0x5b9b, 0x7ba3,0x25a1, 0x7ba5,0x25a1, 0x7ba6,0x7c00, +0x7ba7,0x7bcb, 0x7ba8,0x7c5c, 0x7ba9,0x7c6e, 0x7baa,0x7c1e, 0x7bab,0x7c2b, +0x7bae,0x25a1, 0x7bb0,0x25a1, 0x7bb2,0x25a1, 0x7bb3,0x25a1, 0x7bb6,0x25a1, +0x7bba,0x25a1, 0x7bbb,0x25a1, 0x7bbc,0x25a1, 0x7bbd,0x25a1, 0x7bbf,0x25a1, +0x7bc2,0x25a1, 0x7bc3,0x25a1, 0x7bc5,0x25a1, 0x7bc8,0x25a1, 0x7bcd,0x25a1, +0x7bcf,0x25a1, 0x7bd0,0x25a1, 0x7bd1,0x7c23, 0x7bd2,0x25a1, 0x7bd3,0x7c0d, +0x7bd6,0x25a1, 0x7bd7,0x25a1, 0x7bec,0x25a1, 0x7bed,0x25a1, 0x7bee,0x7c43, +0x7bef,0x25a1, 0x7bf1,0x7c6c, 0x7bf5,0x25a1, 0x7bf6,0x25a1, 0x7bfa,0x25a1, +0x7bfc,0x515c, 0x7c04,0x25a1, 0x7c08,0x25a1, 0x7c12,0x25a1, 0x7c13,0x25a1, +0x7c14,0x25a1, 0x7c15,0x25a1, 0x7c16,0x7c6a, 0x7c17,0x25a1, 0x7c18,0x25a1, +0x7c1a,0x25a1, 0x7c1b,0x25a1, 0x7c24,0x25a1, 0x7c2e,0x25a1, 0x7c2f,0x25a1, +0x7c31,0x25a1, 0x7c32,0x25a1, 0x7c34,0x25a1, 0x7c35,0x25a1, 0x7c36,0x25a1, +0x7c3a,0x25a1, 0x7c41,0x7c5f, 0x7c42,0x9ab8, 0x7c44,0x25a1, 0x7c46,0x25a1, +0x7c4b,0x25a1, 0x7c4e,0x25a1, 0x7c4f,0x25a1, 0x7c51,0x25a1, 0x7c52,0x25a1, +0x7c55,0x25a1, 0x7c56,0x25a1, 0x7c58,0x25a1, 0x7c5d,0x25a1, 0x7c5e,0x25a1, +0x7c61,0x25a1, 0x7c62,0x25a1, 0x7c68,0x25a1, 0x7c6d,0x25a1, 0x7c70,0x25a1, +0x7c71,0x25a1, 0x7c74,0x7cf4, 0x7c76,0x25a1, 0x7c77,0x25a1, 0x7c7b,0x985e, +0x7c7c,0x79c8, 0x7c7e,0x25a1, 0x7c82,0x25a1, 0x7c83,0x25a1, 0x7c86,0x25a1, +0x7c87,0x25a1, 0x7c8b,0x25a1, 0x7c8e,0x25a1, 0x7c8f,0x25a1, 0x7c90,0x25a1, +0x7c93,0x25a1, 0x7c99,0x91c9, 0x7c9a,0x25a1, 0x7c9b,0x25a1, 0x7c9c,0x7cf6, +0x7c9d,0x7cf2, 0x7ca0,0x25a1, 0x7ca4,0x7cb5, 0x7ca6,0x25a1, 0x7ca9,0x25a1, +0x7caa,0x7cde, 0x7cab,0x25a1, 0x7cac,0x25a1, 0x7cad,0x25a1, 0x7cae,0x7ce7, +0x7cb0,0x25a1, 0x7cb6,0x25a1, 0x7cb7,0x25a1, 0x7cb8,0x25a1, 0x7cbb,0x5f27, +0x7cc0,0x25a1, 0x7cc1,0x7cdd, 0x7cc2,0x25a1, 0x7cc3,0x25a1, 0x7cc4,0x25a1, +0x7cc6,0x25a1, 0x7cc7,0x9931, 0x7cc9,0x25a1, 0x7ccd,0x9908, 0x7ccf,0x25a1, +0x7cd3,0x25a1, 0x7cd8,0x25a1, 0x7cda,0x25a1, 0x7cdb,0x25a1, 0x7ce1,0x25a1, +0x7ce3,0x25a1, 0x7ce4,0x25a1, 0x7ce5,0x25a1, 0x7ce6,0x25a1, 0x7ce9,0x25a1, +0x7ceb,0x25a1, 0x7ced,0x25a1, 0x7cf3,0x25a1, 0x7cf5,0x25a1, 0x7cf9,0x7cf8, +0x7cfa,0x25a1, 0x7cfc,0x25a1, 0x7cff,0x25a1, 0x7d23,0x25a1, 0x7d24,0x25a1, +0x7d25,0x25a1, 0x7d26,0x25a1, 0x7d27,0x7dca, 0x7d2a,0x25a1, 0x7d2d,0x25a1, +0x7d34,0x25a1, 0x7d36,0x808c, 0x7d37,0x25a1, 0x7d48,0x25a1, 0x7d49,0x25a1, +0x7d4b,0x25a1, 0x7d4c,0x25a1, 0x7d4d,0x25a1, 0x7d57,0x25a1, 0x7d59,0x25a1, +0x7d5a,0x25a1, 0x7d5d,0x25a1, 0x7d60,0x25a1, 0x7d64,0x25a1, 0x7d65,0x25a1, +0x7d6c,0x25a1, 0x7d74,0x25a1, 0x7d75,0x7e6a, 0x7d76,0x7d55, 0x7d77,0x7e36, +0x7d78,0x25a1, 0x7d7e,0x25a1, 0x7d82,0x25a1, 0x7d87,0x25a1, 0x7d89,0x25a1, +0x7d8a,0x25a1, 0x7d8b,0x25a1, 0x7d90,0x25a1, 0x7d95,0x25a1, 0x7d97,0x25a1, +0x7d98,0x5065, 0x7d99,0x7e7c, 0x7d9a,0x7e8c, 0x7d9b,0x25a1, 0x7da4,0x25a1, +0x7da5,0x25a1, 0x7da8,0x25a1, 0x7dab,0x25a1, 0x7db3,0x25a1, 0x7db6,0x25a1, +0x7dc3,0x25a1, 0x7dc8,0x25a1, 0x7dcd,0x25a1, 0x7dcf,0x25a1, 0x7dd0,0x25a1, +0x7dd1,0x25a1, 0x7dd3,0x25a1, 0x7dd4,0x25a1, 0x7dd5,0x25a1, 0x7dd6,0x25a1, +0x7ddc,0x7dbf, 0x7de2,0x25a1, 0x7de4,0x25a1, 0x7de5,0x25a1, 0x7deb,0x25a1, +0x7ded,0x25a1, 0x7df5,0x25a1, 0x7df8,0x25a1, 0x7dfa,0x76e1, 0x7dfc,0x25a1, +0x7dfd,0x25a1, 0x7dfe,0x25a1, 0x7dff,0x25a1, 0x7e00,0x25a1, 0x7e01,0x25a1, +0x7e02,0x7e3d, 0x7e04,0x7e69, 0x7e05,0x25a1, 0x7e06,0x25a1, 0x7e07,0x25a1, +0x7e18,0x25a1, 0x7e19,0x25a1, 0x7e26,0x25a1, 0x7e27,0x25a1, 0x7e28,0x25a1, +0x7e2c,0x25a1, 0x7e4a,0x25a1, 0x7e4b,0x7e6b, 0x7e4d,0x7e61, 0x7e4e,0x25a1, +0x7e4f,0x25a1, 0x7e5b,0x25a1, 0x7e5d,0x4fca, 0x7e64,0x25a1, 0x7e65,0x25a1, +0x7e66,0x25a1, 0x7e67,0x25a1, 0x7e6c,0x25a1, 0x7e6e,0x25a1, 0x7e71,0x25a1, +0x7e7f,0x25a1, 0x7e83,0x25a1, 0x7e84,0x25a1, 0x7e85,0x25a1, 0x7e89,0x25a1, +0x7e8e,0x25a1, 0x7e90,0x25a1, 0x7e92,0x25a1, 0x7e9d,0x25a1, 0x7e9e,0x25a1, +0x7e9f,0x7cf8, 0x7ea0,0x7cfe, 0x7ea1,0x7d06, 0x7ea2,0x7d05, 0x7ea3,0x7d02, +0x7ea4,0x7e96, 0x7ea5,0x7d07, 0x7ea6,0x7d04, 0x7ea7,0x7d1a, 0x7ea8,0x7d08, +0x7ea9,0x7e8a, 0x7eaa,0x7d00, 0x7eab,0x7d09, 0x7eac,0x7def, 0x7ead,0x7d1c, +0x7eae,0x7d18, 0x7eaf,0x7d14, 0x7eb0,0x7d15, 0x7eb1,0x7d17, 0x7eb2,0x7db1, +0x7eb3,0x7d0d, 0x7eb4,0x7d1d, 0x7eb5,0x7e31, 0x7eb6,0x7db8, 0x7eb7,0x7d1b, +0x7eb8,0x7d19, 0x7eb9,0x7d0b, 0x7eba,0x7d21, 0x7ebb,0x7d35, 0x7ebc,0x7d16, +0x7ebd,0x7d10, 0x7ebe,0x7d13, 0x7ebf,0x7dda, 0x7ec0,0x7d3a, 0x7ec1,0x7d32, +0x7ec2,0x7d31, 0x7ec3,0x7df4, 0x7ec4,0x7d44, 0x7ec5,0x7d33, 0x7ec6,0x7d30, +0x7ec7,0x7e54, 0x7ec8,0x7d42, 0x7ec9,0x7e10, 0x7eca,0x7d46, 0x7ecb,0x7d3c, +0x7ecc,0x7d40, 0x7ecd,0x7d39, 0x7ece,0x7e79, 0x7ecf,0x7d93, 0x7ed0,0x7d3f, +0x7ed1,0x7d81, 0x7ed2,0x7d68, 0x7ed3,0x7d50, 0x7ed4,0x8932, 0x7ed5,0x7e5e, +0x7ed6,0x7d70, 0x7ed7,0x7d4e, 0x7ed8,0x7e6a, 0x7ed9,0x7d66, 0x7eda,0x7d62, +0x7edb,0x7d73, 0x7edc,0x7d61, 0x7edd,0x7d55, 0x7ede,0x7d5e, 0x7edf,0x7d71, +0x7ee0,0x7d86, 0x7ee1,0x7d83, 0x7ee2,0x7d79, 0x7ee3,0x7e61, 0x7ee4,0x7d8c, +0x7ee5,0x7d8f, 0x7ee6,0x7d5b, 0x7ee7,0x7e7c, 0x7ee8,0x7d88, 0x7ee9,0x7e3e, +0x7eea,0x7dd2, 0x7eeb,0x7dbe, 0x7eec,0x25a1, 0x7eed,0x7e8c, 0x7eee,0x7dba, +0x7eef,0x7dcb, 0x7ef0,0x7dbd, 0x7ef1,0x979c, 0x7ef2,0x7dc4, 0x7ef3,0x7e69, +0x7ef4,0x7dad, 0x7ef5,0x7dbf, 0x7ef6,0x7dac, 0x7ef7,0x7e43, 0x7ef8,0x7da2, +0x7ef9,0x7daf, 0x7efa,0x7db9, 0x7efb,0x7da3, 0x7efc,0x7d9c, 0x7efd,0x7dbb, +0x7efe,0x7db0, 0x7eff,0x7da0, 0x7f00,0x7db4, 0x7f01,0x7dc7, 0x7f02,0x7dd9, +0x7f03,0x7dd7, 0x7f04,0x7dd8, 0x7f05,0x7dec, 0x7f06,0x7e9c, 0x7f07,0x7df9, +0x7f08,0x7df2, 0x7f09,0x7ddd, 0x7f0a,0x7e15, 0x7f0b,0x7e62, 0x7f0c,0x7de6, +0x7f0d,0x7d9e, 0x7f0e,0x7dde, 0x7f0f,0x7df6, 0x7f10,0x7dda, 0x7f11,0x7df1, +0x7f12,0x7e0b, 0x7f13,0x7de9, 0x7f14,0x7de0, 0x7f15,0x7e37, 0x7f16,0x7de8, +0x7f17,0x7de1, 0x7f18,0x7de3, 0x7f19,0x7e09, 0x7f1a,0x7e1b, 0x7f1b,0x7e1f, +0x7f1c,0x7e1d, 0x7f1d,0x7e2b, 0x7f1e,0x7e17, 0x7f1f,0x7e1e, 0x7f20,0x7e8f, +0x7f21,0x7e2d, 0x7f22,0x7e0a, 0x7f23,0x7e11, 0x7f24,0x7e7d, 0x7f25,0x7e39, +0x7f26,0x7e35, 0x7f27,0x7e32, 0x7f28,0x7e93, 0x7f29,0x7e2e, 0x7f2a,0x7e46, +0x7f2b,0x7e45, 0x7f2c,0x7e88, 0x7f2d,0x7e5a, 0x7f2e,0x7e55, 0x7f2f,0x7e52, +0x7f30,0x97c1, 0x7f31,0x7e7e, 0x7f32,0x7e70, 0x7f33,0x7e6f, 0x7f34,0x7e73, +0x7f35,0x7e98, 0x7f37,0x25a1, 0x7f3b,0x25a1, 0x7f3c,0x25a1, 0x7f40,0x25a1, +0x7f41,0x25a1, 0x7f42,0x7f4c, 0x7f46,0x25a1, 0x7f47,0x25a1, 0x7f49,0x25a1, +0x7f4e,0x25a1, 0x7f51,0x7db2, 0x7f52,0x25a1, 0x7f53,0x994b, 0x7f56,0x25a1, +0x7f57,0x7f85, 0x7f59,0x25a1, 0x7f5a,0x7f70, 0x7f62,0x7f77, 0x7f64,0x25a1, +0x7f6f,0x25a1, 0x7f71,0x5357, 0x7f74,0x7f86, 0x7f78,0x25a1, 0x7f80,0x25a1, +0x7f81,0x7f88, 0x7f82,0x25a1, 0x7f84,0x25a1, 0x7f8f,0x25a1, 0x7f90,0x25a1, +0x7f93,0x25a1, 0x7f97,0x7f8c, 0x7f98,0x25a1, 0x7f99,0x7f94, 0x7f9f,0x7fa5, +0x7fa1,0x7fa8, 0x7fa3,0x7fa4, 0x7faa,0x25a1, 0x7fab,0x25a1, 0x7fae,0x7fb9, +0x7fb4,0x25a1, 0x7fc4,0x25a1, 0x7fc6,0x25a1, 0x7fc8,0x25a1, 0x7fd3,0x25a1, +0x7fd6,0x25a1, 0x7fd8,0x7ff9, 0x7fd9,0x7ffd, 0x7fda,0x7fec, 0x7fdd,0x25a1, +0x7fe3,0x75e2, 0x7fe4,0x25a1, 0x7fe7,0x25a1, 0x7ff6,0x25a1, 0x7ffa,0x25a1, +0x8002,0x25a1, 0x8008,0x25a1, 0x8009,0x25a1, 0x800a,0x25a1, 0x8013,0x25a1, +0x801a,0x25a1, 0x801d,0x25a1, 0x8020,0xf7ed, 0x8022,0x52de, 0x8023,0x25a1, +0x8025,0x5c1a, 0x8027,0x802c, 0x802b,0x25a1, 0x802d,0x25a1, 0x802e,0x25a1, +0x802f,0x25a1, 0x8031,0x78e8, 0x8032,0x25a1, 0x8038,0x8073, 0x803a,0x25a1, +0x803b,0x6065, 0x803c,0x25a1, 0x8040,0x25a1, 0x8041,0x25a1, 0x8042,0x8076, +0x8044,0x25a1, 0x8045,0x25a1, 0x8049,0x25a1, 0x804b,0x807e, 0x804c,0x8077, +0x804d,0x8079, 0x804e,0x25a1, 0x8053,0x25a1, 0x8054,0x806f, 0x8055,0x25a1, +0x8057,0x25a1, 0x8059,0x25a1, 0x805b,0x25a1, 0x805f,0x25a1, 0x8060,0x25a1, +0x8061,0x25a1, 0x8062,0x25a1, 0x8063,0x25a1, 0x8065,0x25a1, 0x8066,0x25a1, +0x8068,0x25a1, 0x8069,0x8075, 0x806a,0x8070, 0x806b,0x25a1, 0x806d,0x25a1, +0x806e,0x25a1, 0x8074,0x25a1, 0x807a,0x25a1, 0x807b,0x25a1, 0x807c,0x25a1, +0x807d,0x807d, 0x8080,0x807f, 0x8081,0x25a1, 0x8083,0x8085, 0x8088,0x25a1, +0x808d,0x25a1, 0x808e,0x25a1, 0x8091,0x25a1, 0x8094,0x25a1, 0x8097,0x25a1, +0x809e,0x25a1, 0x809f,0x9ad2, 0x80a0,0x8178, 0x80a4,0x819a, 0x80a6,0x25a1, +0x80a7,0x25a1, 0x80a8,0x25a1, 0x80ac,0x25a1, 0x80ae,0x9aaf, 0x80b0,0x25a1, +0x80b3,0x25a1, 0x80b6,0x25a1, 0x80b7,0x6b20, 0x80b9,0x25a1, 0x80bb,0x25a1, +0x80bc,0x4e95, 0x80bd,0x592a, 0x80be,0x814e, 0x80bf,0x816b, 0x80c0,0x8139, +0x80c1,0x8105, 0x80c6,0x81bd, 0x80cb,0x25a1, 0x80d2,0x25a1, 0x80d3,0x25a1, +0x80dc,0x52dd, 0x80df,0x25a1, 0x80e2,0x25a1, 0x80e7,0x6727, 0x80e8,0x6771, +0x80e9,0x5361, 0x80ea,0x81da, 0x80eb,0x811b, 0x80ec,0x8089, 0x80ee,0x25a1, +0x80f6,0x81a0, 0x80f7,0x25a1, 0x80ff,0x25a1, 0x8103,0x25a1, 0x8104,0x25a1, +0x8107,0x25a1, 0x8109,0x8108, 0x810b,0x25a1, 0x810c,0x25a1, 0x810d,0x81be, +0x810e,0x6bba, 0x810f,0x9ad2, 0x8110,0x81cd, 0x8111,0x8166, 0x8112,0x7c73, +0x8113,0x81bf, 0x8114,0x81e0, 0x8117,0x25a1, 0x811a,0x8173, 0x811c,0x25a1, +0x8120,0x25a1, 0x8126,0x25a1, 0x8128,0x25a1, 0x812a,0x25a1, 0x812e,0x25a1, +0x8131,0x812b, 0x8132,0x53cd, 0x8133,0x25a1, 0x8134,0x25a1, 0x8135,0x25a1, +0x8136,0x8161, 0x8137,0x25a1, 0x8138,0x81c9, 0x813b,0x25a1, 0x813c,0x25a1, +0x813f,0x8b3e, 0x8140,0x25a1, 0x8141,0x25a1, 0x8142,0x25a1, 0x8145,0x25a1, +0x8148,0x9752, 0x8149,0x25a1, 0x814a,0x81d8, 0x814c,0x9183, 0x8156,0x25a1, +0x8157,0x25a1, 0x8158,0x8195, 0x8159,0x5b97, 0x815a,0x5b9a, 0x815d,0x25a1, +0x815f,0x25a1, 0x8163,0x25a1, 0x8168,0x25a1, 0x816a,0x25a1, 0x816c,0x25a1, +0x816d,0x9f76, 0x8175,0x25a1, 0x817b,0x81a9, 0x817c,0x9766, 0x817d,0x8183, +0x817e,0x9a30, 0x8181,0x25a1, 0x8184,0x25a1, 0x8185,0x25a1, 0x818e,0x25a1, +0x8190,0x25a1, 0x8191,0x81cf, 0x8192,0x25a1, 0x8193,0x25a1, 0x8194,0x25a1, +0x8196,0x25a1, 0x81a1,0x25a1, 0x81a4,0x25a1, 0x81a5,0x25a1, 0x81aa,0x557b, +0x81ad,0x25a1, 0x81af,0x25a1, 0x81b6,0x25a1, 0x81b8,0x25a1, 0x81c1,0x5ec9, +0x81c8,0x25a1, 0x81cb,0x25a1, 0x81ce,0x25a1, 0x81d3,0x6479, 0x81d4,0x25a1, +0x81d6,0x25a1, 0x81dc,0x81e2, 0x81e4,0x25a1, 0x81eb,0x25a1, 0x81ef,0x25a1, +0x81f0,0x25a1, 0x81f1,0x25a1, 0x81f5,0x25a1, 0x81f6,0x25a1, 0x81fd,0x25a1, +0x8203,0x25a1, 0x8206,0x8f3f, 0x820e,0x25a1, 0x820f,0x25a1, 0x8213,0x25a1, +0x8217,0x25a1, 0x8218,0x25a1, 0x8219,0x25a1, 0x821a,0x25a1, 0x8223,0x8264, +0x8224,0x5e06, 0x8226,0x25a1, 0x8227,0x25a1, 0x8229,0x25a1, 0x822d,0x6bd4, +0x822e,0x25a1, 0x8230,0x8266, 0x8231,0x8259, 0x823b,0x826b, 0x823e,0x897f, +0x8241,0x25a1, 0x8243,0x25a1, 0x8246,0x25a1, 0x8248,0x25a1, 0x824a,0x25a1, +0x824c,0x25a1, 0x824d,0x25a1, 0x8254,0x25a1, 0x825d,0x25a1, 0x8260,0x25a1, +0x8262,0x25a1, 0x8265,0x25a1, 0x8267,0x25a1, 0x8269,0x64f0, 0x826a,0x25a1, +0x8270,0x8271, 0x8273,0x8277, 0x8276,0x25a1, 0x8279,0x8278, 0x827a,0x85dd, +0x827b,0x25a1, 0x8281,0x25a1, 0x8282,0x7bc0, 0x8286,0x25a1, 0x8287,0x25a1, +0x8288,0x7f8b, 0x8289,0x25a1, 0x828c,0x25a1, 0x8295,0x25a1, 0x8296,0x25a1, +0x8297,0x858c, 0x829c,0x856a, 0x82a6,0x8606, 0x82aa,0x6c0f, 0x82b2,0x25a1, +0x82b8,0x8553, 0x82bf,0x25a1, 0x82c1,0x84ef, 0x82c4,0x8290, 0x82c5,0x25a1, +0x82c6,0x25a1, 0x82c7,0x8466, 0x82c8,0x85f6, 0x82c9,0x25a1, 0x82ca,0x5384, +0x82cb,0x83a7, 0x82cc,0x8407, 0x82cd,0x84bc, 0x82ce,0x82e7, 0x82cf,0x8607, +0x82d0,0x25a1, 0x82d8,0x8435, 0x82da,0x25a1, 0x82dd,0x25a1, 0x82e2,0x25a1, +0x82e9,0x25a1, 0x82ee,0x25a1, 0x82f7,0x7518, 0x82f8,0x25a1, 0x82f9,0x860b, +0x82fc,0x25a1, 0x82fd,0x25a1, 0x82ff,0x25a1, 0x8303,0x7bc4, 0x830a,0x25a1, +0x830b,0x25a1, 0x830e,0x8396, 0x830f,0x8622, 0x8310,0x25a1, 0x8311,0x8526, +0x8312,0x25a1, 0x8313,0x25a1, 0x8314,0x584b, 0x8315,0x7162, 0x8318,0x25a1, +0x831a,0x8306, 0x831d,0x25a1, 0x831f,0x25a1, 0x8321,0x25a1, 0x8323,0x25a1, +0x8327,0x7e6d, 0x832e,0x25a1, 0x8330,0x25a1, 0x833d,0x5564, 0x833e,0x25a1, +0x8346,0x834a, 0x8350,0x85a6, 0x8355,0x25a1, 0x8357,0x25a1, 0x8358,0x25a1, +0x8359,0x8598, 0x835a,0x83a2, 0x835b,0x8558, 0x835c,0x84fd, 0x835d,0x25a1, +0x835e,0x854e, 0x835f,0x8588, 0x8360,0x85ba, 0x8361,0x8569, 0x8362,0x25a1, +0x8363,0x69ae, 0x8364,0x8477, 0x8365,0x6ece, 0x8366,0x7296, 0x8367,0x7192, +0x8368,0x8541, 0x8369,0x85ce, 0x836a,0x84c0, 0x836b,0x852d, 0x836c,0x8ce3, +0x836d,0x8452, 0x836e,0x7d02, 0x836f,0x85e5, 0x8370,0x25a1, 0x8371,0x25a1, +0x8372,0x25a1, 0x8379,0x25a1, 0x8380,0x25a1, 0x8382,0x25a1, 0x8384,0x25a1, +0x8385,0x849e, 0x8391,0x25a1, 0x839c,0x84e8, 0x839f,0x25a1, 0x83a1,0x25a1, +0x83ac,0x25a1, 0x83ad,0x25a1, 0x83b1,0x840a, 0x83b2,0x84ee, 0x83b3,0x8494, +0x83b4,0x8435, 0x83b5,0x25a1, 0x83b6,0x859f, 0x83b7,0x7372, 0x83b8,0x8555, +0x83b9,0x7469, 0x83ba,0x9daf, 0x83bb,0x25a1, 0x83bc,0x84f4, 0x83be,0x25a1, +0x83cd,0x25a1, 0x83d0,0x25a1, 0x83d2,0x25a1, 0x83d3,0x25a1, 0x83da,0x25a1, +0x83e6,0x25a1, 0x83ed,0x6070, 0x83f7,0x25a1, 0x8400,0x25a1, 0x8402,0x25a1, +0x8405,0x25a1, 0x8408,0x25a1, 0x8414,0x25a1, 0x8415,0x25a1, 0x8416,0x25a1, +0x8417,0x25a1, 0x8418,0x5948, 0x8419,0x25a1, 0x841a,0x8600, 0x841c,0x5e16, +0x841d,0x863f, 0x841e,0x25a1, 0x841f,0x25a1, 0x8420,0x25a1, 0x8421,0x25a1, +0x8422,0x25a1, 0x8424,0x87a2, 0x8425,0x71df, 0x8426,0x7e08, 0x8427,0x856d, +0x8428,0x85a9, 0x842a,0x25a1, 0x842e,0x25a1, 0x843e,0x25a1, 0x8441,0x25a1, +0x8448,0x25a1, 0x844a,0x25a1, 0x844f,0x25a1, 0x8453,0x25a1, 0x8455,0x25a1, +0x8458,0x25a1, 0x845c,0x5951, 0x8462,0x25a1, 0x8464,0x25a1, 0x846a,0x25a1, +0x8471,0x8525, 0x8472,0x25a1, 0x847b,0x25a1, 0x847c,0x53d6, 0x847f,0x25a1, +0x8480,0x25a1, 0x8481,0x25a1, 0x8483,0x25a1, 0x8484,0x25a1, 0x8485,0x25a1, +0x8487,0x8546, 0x8488,0x7686, 0x8489,0x8562, 0x848a,0x25a1, 0x848b,0x8523, +0x848c,0x851e, 0x8492,0x25a1, 0x8493,0x25a1, 0x8495,0x25a1, 0x8496,0x25a1, +0x84a3,0x25a1, 0x84a5,0x25a1, 0x84a6,0x25a1, 0x84ad,0x25a1, 0x84b3,0x25a1, +0x84b5,0x25a1, 0x84b7,0x25a1, 0x84bd,0x6069, 0x84be,0x25a1, 0x84c3,0x25a1, +0x84c8,0x25a1, 0x84d5,0x25a1, 0x84d8,0x25a1, 0x84d9,0x25a1, 0x84da,0x25a1, +0x84dc,0x25a1, 0x84dd,0x85cd, 0x84de,0x25a1, 0x84df,0x858a, 0x84e0,0x863a, +0x84e1,0x25a1, 0x84e2,0x25a1, 0x84e3,0x8577, 0x84e4,0x25a1, 0x84e5,0x93a3, +0x84e6,0x9a40, 0x84ed,0x25a1, 0x84f5,0x25a1, 0x84f8,0x25a1, 0x8501,0x25a1, +0x8502,0x5098, 0x8503,0x25a1, 0x8504,0x25a1, 0x8505,0x25a1, 0x8510,0x25a1, +0x851b,0x25a1, 0x8522,0x25a1, 0x8532,0x25a1, 0x8533,0x25a1, 0x8534,0x25a1, +0x8535,0x25a1, 0x8536,0x25a1, 0x8537,0x8594, 0x8538,0x515c, 0x8539,0x861e, +0x853a,0x85fa, 0x853c,0x85f9, 0x853f,0x25a1, 0x8542,0x25a1, 0x854b,0x25a1, +0x854c,0x25a1, 0x854f,0x25a1, 0x8550,0x25a1, 0x8552,0x25a1, 0x855a,0x25a1, +0x855c,0x25a1, 0x855f,0x25a1, 0x856f,0x25a1, 0x8570,0x25a1, 0x8572,0x8604, +0x8573,0x25a1, 0x8574,0x860a, 0x857d,0x25a1, 0x857f,0x25a1, 0x8581,0x7701, +0x8592,0x25a1, 0x8593,0x25a1, 0x8597,0x25a1, 0x85a5,0x25a1, 0x85ab,0x25a1, +0x85ac,0x25a1, 0x85ad,0x25a1, 0x85ae,0x85ea, 0x85b2,0x25a1, 0x85bb,0x25a1, +0x85bc,0x25a1, 0x85c1,0x69c1, 0x85ca,0x25a1, 0x85cc,0x25a1, 0x85d3,0x861a, +0x85d4,0x25a1, 0x85d6,0x25a1, 0x85db,0x25a1, 0x85e0,0x25a1, 0x85e7,0x25a1, +0x85ee,0x25a1, 0x85f3,0x25a1, 0x85f4,0x25a1, 0x85f5,0x25a1, 0x85f8,0x6055, +0x85fc,0x25a1, 0x8602,0x25a1, 0x8603,0x25a1, 0x8608,0x25a1, 0x860d,0x25a1, +0x860e,0x25a1, 0x860f,0x25a1, 0x8610,0x25a1, 0x8612,0x25a1, 0x8613,0x25a1, +0x8614,0x25a1, 0x8615,0x25a1, 0x8616,0x8617, 0x861d,0x25a1, 0x8628,0x25a1, +0x862b,0x25a1, 0x862f,0x25a1, 0x8630,0x25a1, 0x8637,0x25a1, 0x863d,0x25a1, +0x8641,0x25a1, 0x8642,0x25a1, 0x8644,0x25a1, 0x8645,0x25a1, 0x8649,0x25a1, +0x864a,0x25a1, 0x864f,0x865c, 0x8651,0x616e, 0x8657,0x25a1, 0x8658,0x25a1, +0x865a,0x865b, 0x865d,0x25a1, 0x8660,0x25a1, 0x8666,0x25a1, 0x866a,0x737a, +0x866b,0x87f2, 0x866c,0x866f, 0x866e,0x87e3, 0x8672,0x25a1, 0x8675,0x25a1, +0x8676,0x25a1, 0x8678,0x25a1, 0x867d,0x96d6, 0x867e,0x8766, 0x867f,0x8806, +0x8680,0x8755, 0x8681,0x87fb, 0x8682,0x879e, 0x8683,0x25a1, 0x8684,0x25a1, +0x8688,0x25a1, 0x8689,0x25a1, 0x868f,0x25a1, 0x8692,0x25a1, 0x8695,0x8836, +0x869b,0x25a1, 0x869f,0x25a1, 0x86a0,0x25a1, 0x86a6,0x25a1, 0x86ab,0x25a1, +0x86ac,0x8706, 0x86ad,0x25a1, 0x86ae,0x25a1, 0x86b2,0x25a1, 0x86ca,0x8831, +0x86cd,0x25a1, 0x86ce,0x8823, 0x86cf,0x87f6, 0x86d2,0x25a1, 0x86d5,0x25a1, +0x86e0,0x25a1, 0x86e1,0x25a1, 0x86e5,0x25a1, 0x86e7,0x25a1, 0x86ee,0x883b, +0x86ef,0x25a1, 0x86f0,0x87c4, 0x86f1,0x86fa, 0x86f2,0x87ef, 0x86f3,0x8784, +0x86f4,0x8810, 0x86fc,0x25a1, 0x86fd,0x25a1, 0x86ff,0x25a1, 0x870f,0x25a1, +0x8710,0x25a1, 0x8714,0x25a1, 0x8715,0x86fb, 0x8716,0x6c40, 0x8717,0x8778, +0x871d,0x25a1, 0x871f,0x25a1, 0x8721,0x881f, 0x872b,0x25a1, 0x872f,0x25a1, +0x8736,0x25a1, 0x8739,0x25a1, 0x873d,0x25a1, 0x8744,0x25a1, 0x8745,0x25a1, +0x8747,0x8805, 0x8748,0x87c8, 0x8749,0x87ec, 0x874a,0x25a1, 0x874b,0x25a1, +0x874e,0x880d, 0x8770,0x594e, 0x8771,0x25a1, 0x8772,0x25a1, 0x877c,0x87bb, +0x877d,0x6625, 0x877e,0x8811, 0x877f,0x8805, 0x8780,0x87bf, 0x8786,0x25a1, +0x878a,0x25a1, 0x878b,0x53df, 0x878c,0x25a1, 0x878e,0x25a1, 0x8795,0x25a1, +0x8799,0x25a1, 0x87a0,0x25a1, 0x87a1,0x25a1, 0x87a4,0x5dcd, 0x87a5,0x25a1, +0x87a6,0x25a1, 0x87a7,0x25a1, 0x87a8,0x9862, 0x87a9,0x25a1, 0x87b1,0x25a1, +0x87c1,0x25a1, 0x87c7,0x25a1, 0x87cd,0x25a1, 0x87ce,0x25a1, 0x87cf,0x8828, +0x87d0,0x25a1, 0x87d5,0x25a1, 0x87d6,0x25a1, 0x87da,0x25a1, 0x87e9,0x25a1, +0x87ee,0x87fa, 0x87f0,0x25a1, 0x87f1,0x25a1, 0x87f5,0x25a1, 0x87f8,0x25a1, +0x87fd,0x25a1, 0x8804,0x25a1, 0x8807,0x25a1, 0x880e,0x87d2, 0x880f,0x25a1, +0x8812,0x25a1, 0x8818,0x25a1, 0x881a,0x25a1, 0x881e,0x25a1, 0x8827,0x25a1, +0x882d,0x25a1, 0x8834,0x25a1, 0x883a,0x25a1, 0x8842,0x25a1, 0x8845,0x91c1, +0x8846,0x25a1, 0x8847,0x25a1, 0x8849,0x25a1, 0x884f,0x25a1, 0x8850,0x25a1, +0x8851,0x25a1, 0x8854,0x929c, 0x8858,0x25a1, 0x885c,0x25a1, 0x885e,0x25a1, +0x885f,0x25a1, 0x8860,0x25a1, 0x8864,0x8863, 0x8865,0x88dc, 0x8866,0x25a1, +0x886c,0x896f, 0x886e,0x889e, 0x8873,0x25a1, 0x8878,0x25a1, 0x887a,0x25a1, +0x887b,0x25a1, 0x8884,0x8956, 0x8885,0x88ca, 0x8886,0x8918, 0x8887,0x25a1, +0x888a,0x25a1, 0x888f,0x25a1, 0x8890,0x25a1, 0x8894,0x25a1, 0x889c,0x896a, +0x889d,0x25a1, 0x88a0,0x25a1, 0x88a3,0x25a1, 0x88a5,0x25a1, 0x88a6,0x25a1, +0x88a9,0x25a1, 0x88aa,0x5c0f, 0x88ad,0x8972, 0x88ae,0x25a1, 0x88af,0x894f, +0x88b0,0x25a1, 0x88b3,0x25a1, 0x88b4,0x8932, 0x88b5,0x25a1, 0x88bb,0x25a1, +0x88bf,0x25a1, 0x88c3,0x25a1, 0x88c4,0x25a1, 0x88c5,0x88dd, 0x88c6,0x8960, +0x88c7,0x25a1, 0x88c8,0x890c, 0x88d1,0x25a1, 0x88d3,0x25a1, 0x88e0,0x25a1, +0x88e2,0x8933, 0x88e3,0x895d, 0x88e4,0x8932, 0x88e5,0x8949, 0x88e6,0x25a1, +0x88e9,0x25a1, 0x88ea,0x25a1, 0x88ed,0x25a1, 0x88f5,0x25a1, 0x88ff,0x25a1, +0x8900,0x25a1, 0x8903,0x25a1, 0x8904,0x25a1, 0x8908,0x25a1, 0x890d,0x25a1, +0x890f,0x25a1, 0x891b,0x8938, 0x891c,0x25a1, 0x891d,0x25a1, 0x8920,0x25a1, +0x8924,0x25a1, 0x8928,0x25a1, 0x8934,0x8964, 0x8937,0x9078, 0x8939,0x25a1, +0x893a,0x25a1, 0x893f,0x25a1, 0x8940,0x25a1, 0x8943,0x25a1, 0x8945,0x25a1, +0x8947,0x25a1, 0x8948,0x25a1, 0x894a,0x25a1, 0x894d,0x25a1, 0x894e,0x25a1, +0x8954,0x25a1, 0x8955,0x8974, 0x8965,0x25a1, 0x8967,0x25a1, 0x8968,0x25a1, +0x8970,0x25a1, 0x8975,0x25a1, 0x8977,0x25a1, 0x8978,0x25a1, 0x897d,0x25a1, +0x8980,0x25a1, 0x8984,0x25a1, 0x8987,0x9738, 0x8989,0x25a1, 0x898a,0x25a1, +0x898c,0x25a1, 0x898d,0x25a1, 0x898e,0x25a1, 0x8990,0x25a1, 0x8991,0x25a1, +0x8992,0x25a1, 0x8994,0x25a1, 0x8999,0x25a1, 0x899a,0x89ba, 0x89a0,0x25a1, +0x89a5,0x25a1, 0x89a7,0x89bd, 0x89a8,0x25a1, 0x89a9,0x7779, 0x89ab,0x25a1, +0x89b0,0x25a1, 0x89b1,0x25a1, 0x89b3,0x25a1, 0x89b4,0x25a1, 0x89b5,0x25a1, +0x89b8,0x25a1, 0x89bb,0x25a1, 0x89bc,0x25a1, 0x89c1,0x898b, 0x89c2,0x89c0, +0x89c3,0x25a1, 0x89c4,0x898f, 0x89c5,0x8993, 0x89c6,0x8996, 0x89c7,0x8998, +0x89c8,0x89bd, 0x89c9,0x89ba, 0x89ca,0x89ac, 0x89cb,0x89a1, 0x89cc,0x89bf, +0x89cd,0x25a1, 0x89ce,0x89a6, 0x89cf,0x89af, 0x89d0,0x89b2, 0x89d1,0x89b7, +0x89d7,0x89dd, 0x89d8,0x25a1, 0x89de,0x89f4, 0x89e6,0x89f8, 0x89e7,0x25a1, +0x89ea,0x25a1, 0x89ee,0x25a1, 0x89ef,0x89f6, 0x89f5,0x25a1, 0x89f9,0x25a1, +0x89fd,0x25a1, 0x8a01,0x25a1, 0x8a05,0x25a1, 0x8a06,0x25a1, 0x8a09,0x25a1, +0x8a0b,0x25a1, 0x8a0d,0x25a1, 0x8a14,0x25a1, 0x8a19,0x25a1, 0x8a1a,0x25a1, +0x8a1c,0x25a1, 0x8a20,0x25a1, 0x8a21,0x541f, 0x8a24,0x25a1, 0x8a26,0x25a1, +0x8a28,0x25a1, 0x8a29,0x25a1, 0x8a2b,0x25a1, 0x8a2e,0x25a1, 0x8a2f,0x25a1, +0x8a32,0x25a1, 0x8a33,0x25a1, 0x8a35,0x25a1, 0x8a37,0x25a1, 0x8a38,0x25a1, +0x8a3d,0x25a1, 0x8a42,0x25a1, 0x8a43,0x25a1, 0x8a47,0x25a1, 0x8a49,0x25a1, +0x8a4b,0x25a1, 0x8a53,0x25a1, 0x8a5a,0x25a1, 0x8a5c,0x25a1, 0x8a5d,0x25a1, +0x8a5f,0x8b8b, 0x8a64,0x8b0a, 0x8a65,0x25a1, 0x8a67,0x25a1, 0x8a6a,0x25a1, +0x8a6f,0x25a1, 0x8a78,0x25a1, 0x8a7d,0x25a1, 0x8a7e,0x25a1, 0x8a80,0x6d74, +0x8a88,0x25a1, 0x8a89,0x8b7d, 0x8a8a,0x8b04, 0x8a8e,0x25a1, 0x8a90,0x25a1, +0x8a94,0x25a1, 0x8a97,0x25a1, 0x8a9b,0x25a1, 0x8a9c,0x25a1, 0x8a9d,0x25a1, +0x8a9f,0x25a1, 0x8aa2,0x25a1, 0x8aa9,0x25a1, 0x8aac,0x8aaa, 0x8aad,0x8b80, +0x8aae,0x25a1, 0x8aaf,0x25a1, 0x8ab1,0x25a1, 0x8ab3,0x25a1, 0x8ab4,0x25a1, +0x8ab5,0x25a1, 0x8ab7,0x25a1, 0x8ac1,0x25a1, 0x8aca,0x25a1, 0x8acc,0x25a1, +0x8ace,0x25a1, 0x8ad0,0x25a1, 0x8ada,0x25a1, 0x8ae3,0x9358, 0x8ae5,0x25a1, +0x8ae9,0x25a1, 0x8aea,0x25a1, 0x8aec,0x25a1, 0x8af9,0x25a1, 0x8afd,0x25a1, +0x8b03,0x25a1, 0x8b09,0x25a1, 0x8b0c,0x25a1, 0x8b1f,0x25a1, 0x8b21,0x25a1, +0x8b29,0x25a1, 0x8b2d,0x25a1, 0x8b32,0x25a1, 0x8b34,0x25a1, 0x8b38,0x25a1, +0x8b3f,0x25a1, 0x8b43,0x25a1, 0x8b44,0x25a1, 0x8b45,0x5e40, 0x8b4c,0x25a1, +0x8b4d,0x25a1, 0x8b5b,0x25a1, 0x8b5e,0x25a1, 0x8b61,0x25a1, 0x8b62,0x25a1, +0x8b64,0x25a1, 0x8b69,0x25a1, 0x8b6e,0x25a1, 0x8b71,0x25a1, 0x8b72,0x25a1, +0x8b73,0x25a1, 0x8b75,0x25a1, 0x8b76,0x25a1, 0x8b7c,0x25a1, 0x8b81,0x8b2b, +0x8b83,0x25a1, 0x8b87,0x25a1, 0x8b89,0x25a1, 0x8b8d,0x25a1, 0x8b8f,0x25a1, +0x8b90,0x25a1, 0x8b91,0x25a1, 0x8b97,0x25a1, 0x8b9b,0x25a1, 0x8b9d,0x25a1, +0x8ba0,0x8a00, 0x8ba1,0x8a08, 0x8ba2,0x8a02, 0x8ba3,0x8a03, 0x8ba4,0x8a8d, +0x8ba5,0x8b4f, 0x8ba6,0x8a10, 0x8ba7,0x8a0c, 0x8ba8,0x8a0e, 0x8ba9,0x8b93, +0x8baa,0x8a15, 0x8bab,0x8a16, 0x8bac,0x25a1, 0x8bad,0x8a13, 0x8bae,0x8b70, +0x8baf,0x8a0a, 0x8bb0,0x8a18, 0x8bb1,0x8a12, 0x8bb2,0x8b1b, 0x8bb3,0x8af1, +0x8bb4,0x8b33, 0x8bb5,0x8a4e, 0x8bb6,0x8a1d, 0x8bb7,0x8a25, 0x8bb8,0x8a31, +0x8bb9,0x8a1b, 0x8bba,0x8ad6, 0x8bbb,0x25a1, 0x8bbc,0x8a1f, 0x8bbd,0x8af7, +0x8bbe,0x8a2d, 0x8bbf,0x8a2a, 0x8bc0,0x8a23, 0x8bc1,0x8a3c, 0x8bc2,0x8a41, +0x8bc3,0x8a36, 0x8bc4,0x8a55, 0x8bc5,0x8a5b, 0x8bc6,0x8b58, 0x8bc7,0x8a57, +0x8bc8,0x8a50, 0x8bc9,0x8a34, 0x8bca,0x8a3a, 0x8bcb,0x8a46, 0x8bcc,0x8b05, +0x8bcd,0x8a5e, 0x8bce,0x8a58, 0x8bcf,0x8a54, 0x8bd0,0x8a56, 0x8bd1,0x8b6f, +0x8bd2,0x8a52, 0x8bd3,0x8a86, 0x8bd4,0x8a84, 0x8bd5,0x8a66, 0x8bd6,0x8a7f, +0x8bd7,0x8a69, 0x8bd8,0x8a70, 0x8bd9,0x8a7c, 0x8bda,0x8aa0, 0x8bdb,0x8a85, +0x8bdc,0x8a75, 0x8bdd,0x8a71, 0x8bde,0x8a95, 0x8bdf,0x8a6c, 0x8be0,0x8a6e, +0x8be1,0x8a6d, 0x8be2,0x8a62, 0x8be3,0x8a63, 0x8be4,0x8acd, 0x8be5,0x8a72, +0x8be6,0x8a73, 0x8be7,0x8a6b, 0x8be8,0x8ae2, 0x8be9,0x8a61, 0x8bea,0x8b78, +0x8beb,0x8aa1, 0x8bec,0x8aa3, 0x8bed,0x8a9e, 0x8bee,0x8a9a, 0x8bef,0x8aa4, +0x8bf0,0x8aa5, 0x8bf1,0x8a98, 0x8bf2,0x8aa8, 0x8bf3,0x8a91, 0x8bf4,0x8aaa, +0x8bf5,0x8aa6, 0x8bf6,0x8a92, 0x8bf7,0x8acb, 0x8bf8,0x8af8, 0x8bf9,0x8acf, +0x8bfa,0x8afe, 0x8bfb,0x8b80, 0x8bfc,0x8ad1, 0x8bfd,0x8ab9, 0x8bfe,0x8ab2, +0x8bff,0x8ac9, 0x8c00,0x8adb, 0x8c01,0x8ab0, 0x8c02,0x8ad7, 0x8c03,0x8abf, +0x8c04,0x8ac2, 0x8c05,0x8ad2, 0x8c06,0x8ac4, 0x8c07,0x8ab6, 0x8c08,0x8ac7, +0x8c09,0x25a1, 0x8c0a,0x8abc, 0x8c0b,0x8b00, 0x8c0c,0x8af6, 0x8c0d,0x8adc, +0x8c0e,0x8b0a, 0x8c0f,0x8aeb, 0x8c10,0x8ae7, 0x8c11,0x8b14, 0x8c12,0x8b01, +0x8c13,0x8b02, 0x8c14,0x8ae4, 0x8c15,0x8aed, 0x8c16,0x8afc, 0x8c17,0x8b92, +0x8c18,0x8aee, 0x8c19,0x8af3, 0x8c1a,0x8afa, 0x8c1b,0x8ae6, 0x8c1c,0x8b0e, +0x8c1d,0x8ade, 0x8c1e,0x4f4f, 0x8c1f,0x8b28, 0x8c20,0x8b9c, 0x8c21,0x8b16, +0x8c22,0x8b1d, 0x8c23,0x8b20, 0x8c24,0x8b17, 0x8c25,0x8b1a, 0x8c26,0x8b19, +0x8c27,0x8b10, 0x8c28,0x8b39, 0x8c29,0x8b3e, 0x8c2a,0x8b2b, 0x8c2b,0x8b7e, +0x8c2c,0x8b2c, 0x8c2d,0x8b5a, 0x8c2e,0x8b56, 0x8c2f,0x8b59, 0x8c30,0x8b95, +0x8c31,0x8b5c, 0x8c32,0x8b4e, 0x8c33,0x8b9e, 0x8c34,0x8b74, 0x8c35,0x8b6b, +0x8c36,0x8b96, 0x8c38,0x25a1, 0x8c3a,0x25a1, 0x8c40,0x25a1, 0x8c44,0x25a1, +0x8c51,0x25a1, 0x8c52,0x25a1, 0x8c53,0x25a1, 0x8c58,0x25a1, 0x8c59,0x25a1, +0x8c5b,0x25a1, 0x8c5e,0x25a1, 0x8c60,0x25a1, 0x8c63,0x25a1, 0x8c67,0x25a1, +0x8c6e,0x8c76, 0x8c74,0x25a1, 0x8c7c,0x25a1, 0x8c7e,0x25a1, 0x8c7f,0x25a1, +0x8c83,0x25a1, 0x8c87,0x25a1, 0x8c88,0x25a1, 0x8c8b,0x25a1, 0x8c8e,0x25a1, +0x8c96,0x25a1, 0x8c9b,0x25a1, 0x8c9f,0x25a1, 0x8ca6,0x25a1, 0x8cad,0x4e8d, +0x8cae,0x8cb3, 0x8cb1,0x25a1, 0x8cc6,0x25a1, 0x8cc9,0x25a1, 0x8ccb,0x25a1, +0x8ccd,0x8d13, 0x8cce,0x8ce4, 0x8cd0,0x25a1, 0x8cd4,0x25a1, 0x8cd6,0x8cd2, +0x8cd8,0x9ad2, 0x8cdb,0x25a1, 0x8ce9,0x25a1, 0x8ceb,0x25a1, 0x8cef,0x25a1, +0x8cf2,0x25a1, 0x8cf6,0x25a1, 0x8cf7,0x25a1, 0x8cff,0x25a1, 0x8d01,0x25a1, +0x8d03,0x25a1, 0x8d0b,0x8d17, 0x8d0c,0x25a1, 0x8d0e,0x25a1, 0x8d11,0x25a1, +0x8d12,0x25a1, 0x8d18,0x511f, 0x8d1a,0x25a1, 0x8d1c,0x25a1, 0x8d1d,0x8c9d, +0x8d1e,0x8c9e, 0x8d1f,0x8ca0, 0x8d20,0x25a1, 0x8d21,0x8ca2, 0x8d22,0x8ca1, +0x8d23,0x8cac, 0x8d24,0x8ce2, 0x8d25,0x6557, 0x8d26,0x8cec, 0x8d27,0x8ca8, +0x8d28,0x8cea, 0x8d29,0x8ca9, 0x8d2a,0x8caa, 0x8d2b,0x8ca7, 0x8d2c,0x8cb6, +0x8d2d,0x8cfc, 0x8d2e,0x8caf, 0x8d2f,0x8cab, 0x8d30,0x8cb3, 0x8d31,0x8ce4, +0x8d32,0x8cc1, 0x8d33,0x8cb0, 0x8d34,0x8cbc, 0x8d35,0x8cb4, 0x8d36,0x8cba, +0x8d37,0x8cb8, 0x8d38,0x8cbf, 0x8d39,0x8cbb, 0x8d3a,0x8cc0, 0x8d3b,0x8cbd, +0x8d3c,0x8cca, 0x8d3d,0x8d04, 0x8d3e,0x8cc8, 0x8d3f,0x8cc4, 0x8d40,0x8cb2, +0x8d41,0x8cc3, 0x8d42,0x8cc2, 0x8d43,0x8d13, 0x8d44,0x8cc7, 0x8d45,0x8cc5, +0x8d46,0x8d10, 0x8d47,0x8cd5, 0x8d48,0x8cd1, 0x8d49,0x8cda, 0x8d4a,0x8cd2, +0x8d4b,0x8ce6, 0x8d4c,0x8ced, 0x8d4d,0x9f4e, 0x8d4e,0x8d16, 0x8d4f,0x8cde, +0x8d50,0x8cdc, 0x8d51,0x8d14, 0x8d52,0x8cd9, 0x8d53,0x8ce1, 0x8d54,0x8ce0, +0x8d55,0x8ce7, 0x8d56,0x8cf4, 0x8d57,0x8cf5, 0x8d58,0x8d05, 0x8d59,0x8cfb, +0x8d5a,0x8cfa, 0x8d5b,0x8cfd, 0x8d5c,0x8cfe, 0x8d5d,0x8d17, 0x8d5e,0x8d0a, +0x8d5f,0x8d07, 0x8d60,0x8d08, 0x8d61,0x8d0d, 0x8d62,0x8d0f, 0x8d63,0x8d1b, +0x8d65,0x25a1, 0x8d6a,0x8d6c, 0x8d71,0x25a1, 0x8d75,0x8d99, 0x8d76,0x8d95, +0x8d7a,0x25a1, 0x8d7c,0x25a1, 0x8d7e,0x25a1, 0x8d7f,0x25a1, 0x8d82,0x25a1, +0x8d83,0x25a1, 0x8d86,0x25a1, 0x8d87,0x25a1, 0x8d88,0x25a1, 0x8d8b,0x8da8, +0x8d97,0x25a1, 0x8d98,0x25a1, 0x8d9a,0x25a1, 0x8d9d,0x25a1, 0x8d9e,0x25a1, +0x8da2,0x25a1, 0x8da4,0x25a1, 0x8da6,0x25a1, 0x8da9,0x25a1, 0x8db0,0x25a1, +0x8db1,0x8db2, 0x8db8,0x8e89, 0x8dbb,0x25a1, 0x8dbd,0x25a1, 0x8dc0,0x25a1, +0x8dc3,0x8e8d, 0x8dc4,0x8e4c, 0x8dc9,0x25a1, 0x8dca,0x25a1, 0x8dd2,0x25a1, +0x8dd4,0x25a1, 0x8dde,0x8e92, 0x8de5,0x25a1, 0x8ded,0x25a1, 0x8df5,0x8e10, +0x8df6,0x8e82, 0x8df7,0x8e7a, 0x8df8,0x8e55, 0x8df9,0x8e9a, 0x8dfb,0x8e8b, +0x8e01,0x25a1, 0x8e08,0x25a1, 0x8e0b,0x25a1, 0x8e0c,0x8e8a, 0x8e0e,0x25a1, +0x8e28,0x25a1, 0x8e2a,0x8e64, 0x8e2c,0x8e93, 0x8e2d,0x25a1, 0x8e2f,0x8e91, +0x8e32,0x25a1, 0x8e37,0x25a1, 0x8e3a,0x8171, 0x8e3b,0x25a1, 0x8e43,0x25a1, +0x8e46,0x25a1, 0x8e4f,0x25a1, 0x8e51,0x8ea1, 0x8e52,0x8e63, 0x8e58,0x25a1, +0x8e68,0x25a1, 0x8e6b,0x25a1, 0x8e6e,0x25a1, 0x8e70,0x8e95, 0x8e71,0x90b8, +0x8e75,0x25a1, 0x8e77,0x25a1, 0x8e79,0x25a1, 0x8e7d,0x25a1, 0x8e7e,0x25a1, +0x8e7f,0x8ea5, 0x8e80,0x25a1, 0x8e83,0x25a1, 0x8e8f,0x8eaa, 0x8e99,0x25a1, +0x8e9b,0x25a1, 0x8e9c,0x8ea6, 0x8ea2,0x25a1, 0x8ea7,0x25a1, 0x8ead,0x25a1, +0x8eae,0x25a1, 0x8eaf,0x8ec0, 0x8eb0,0x25a1, 0x8eb1,0x25a1, 0x8eb3,0x25a1, +0x8eb4,0x25a1, 0x8eb5,0x25a1, 0x8eb6,0x25a1, 0x8eb7,0x25a1, 0x8eb8,0x25a1, +0x8eb9,0x25a1, 0x8ebb,0x25a1, 0x8ebc,0x25a1, 0x8ebe,0x25a1, 0x8ebf,0x25a1, +0x8ec1,0x25a1, 0x8ec3,0x25a1, 0x8ec4,0x25a1, 0x8ec5,0x25a1, 0x8ec6,0x25a1, +0x8ec7,0x25a1, 0x8ec8,0x25a1, 0x8ece,0x8eca, 0x8ed0,0x25a1, 0x8ed5,0x25a1, +0x8ed6,0x25a1, 0x8ed9,0x25a1, 0x8eda,0x25a1, 0x8ee2,0x25a1, 0x8ee3,0x25a1, +0x8ee4,0x5874, 0x8eea,0x25a1, 0x8eed,0x25a1, 0x8ef0,0x25a1, 0x8ef2,0x25a1, +0x8ef3,0x25a1, 0x8efd,0x25a1, 0x8f04,0x25a1, 0x8f0c,0x25a1, 0x8f0f,0x25a1, +0x8f19,0x25a1, 0x8f21,0x25a1, 0x8f22,0x25a1, 0x8f27,0x25a1, 0x8f28,0x25a1, +0x8f2b,0x25a1, 0x8f2d,0x25a1, 0x8f30,0x25a1, 0x8f31,0x25a1, 0x8f3a,0x25a1, +0x8f3c,0x25a1, 0x8f3d,0x25a1, 0x8f41,0x25a1, 0x8f4a,0x25a1, 0x8f4c,0x25a1, +0x8f5c,0x25a1, 0x8f65,0x25a1, 0x8f66,0x8eca, 0x8f67,0x8ecb, 0x8f68,0x8ecc, +0x8f69,0x8ed2, 0x8f6a,0x8ed1, 0x8f6b,0x8ed4, 0x8f6c,0x8f49, 0x8f6d,0x8edb, +0x8f6e,0x8f2a, 0x8f6f,0x8edf, 0x8f70,0x8f5f, 0x8f71,0x53e4, 0x8f72,0x8efb, +0x8f73,0x8f64, 0x8f74,0x8ef8, 0x8f75,0x8ef9, 0x8f76,0x8efc, 0x8f77,0x4e4e, +0x8f78,0x8eeb, 0x8f79,0x8f62, 0x8f7a,0x8efa, 0x8f7b,0x8f15, 0x8f7c,0x8efe, +0x8f7d,0x8f09, 0x8f7e,0x8f0a, 0x8f7f,0x8f4e, 0x8f80,0x8f08, 0x8f81,0x8f07, +0x8f82,0x8f05, 0x8f83,0x8f03, 0x8f84,0x8f12, 0x8f85,0x8f14, 0x8f86,0x8f1b, +0x8f87,0x8f26, 0x8f88,0x8f29, 0x8f89,0x8f1d, 0x8f8a,0x8f25, 0x8f8b,0x8f1e, +0x8f8c,0x8f2c, 0x8f8d,0x8f1f, 0x8f8e,0x8f1c, 0x8f8f,0x8f33, 0x8f90,0x8f3b, +0x8f91,0x8f2f, 0x8f92,0x8f40, 0x8f93,0x8f38, 0x8f94,0x8f61, 0x8f95,0x8f45, +0x8f96,0x8f44, 0x8f97,0x8f3e, 0x8f98,0x8f46, 0x8f99,0x8f4d, 0x8f9a,0x8f54, +0x8f9d,0x25a1, 0x8f9e,0x8fad, 0x8f9f,0x95e2, 0x8fa0,0x25a1, 0x8fa1,0x25a1, +0x8fa2,0x25a1, 0x8fa4,0x25a1, 0x8fa5,0x25a1, 0x8fa7,0x25a1, 0x8fa9,0x8faf, +0x8faa,0x25a1, 0x8fab,0x8fae, 0x8fac,0x8fa8, 0x8fb3,0x25a1, 0x8fb5,0x25a1, +0x8fb6,0x8d70, 0x8fb7,0x25a1, 0x8fb8,0x25a1, 0x8fb9,0x908a, 0x8fba,0x25a1, +0x8fbb,0x25a1, 0x8fbc,0x25a1, 0x8fbd,0x907c, 0x8fbe,0x9054, 0x8fc0,0x25a1, +0x8fc1,0x9077, 0x8fc3,0x25a1, 0x8fc7,0x904e, 0x8fc8,0x9081, 0x8fca,0x25a1, +0x8fcc,0x25a1, 0x8fcf,0x25a1, 0x8fd0,0x904b, 0x8fd8,0x9084, 0x8fd9,0x9019, +0x8fda,0x25a1, 0x8fdb,0x9032, 0x8fdc,0x9060, 0x8fdd,0x9055, 0x8fde,0x9023, +0x8fdf,0x9072, 0x8fe7,0x25a1, 0x8fe9,0x9087, 0x8fec,0x25a1, 0x8fef,0x25a1, +0x8ff1,0x25a1, 0x8ff2,0x25a1, 0x8ff3,0x9015, 0x8ff9,0x8de1, 0x9002,0x9069, +0x9007,0x25a1, 0x9008,0x25a1, 0x9009,0x9078, 0x900a,0x905c, 0x900e,0x25a1, +0x9012,0x905e, 0x9013,0x25a1, 0x9018,0x8556, 0x9025,0x25a1, 0x9026,0x9090, +0x9027,0x25a1, 0x9028,0x25a1, 0x9029,0x25a1, 0x902a,0x25a1, 0x902b,0x25a1, +0x902c,0x25a1, 0x9030,0x25a1, 0x9033,0x25a1, 0x9037,0x25a1, 0x9039,0x25a1, +0x903a,0x25a1, 0x903b,0x908f, 0x9040,0x25a1, 0x9043,0x25a1, 0x9045,0x25a1, +0x9046,0x25a1, 0x9048,0x25a1, 0x904c,0x25a1, 0x9056,0x25a1, 0x9057,0x907a, +0x905a,0x25a1, 0x905f,0x25a1, 0x9061,0x25a1, 0x9064,0x25a1, 0x9065,0x9059, +0x9066,0x25a1, 0x906a,0x25a1, 0x906c,0x25a1, 0x9071,0x25a1, 0x9089,0x25a1, +0x908c,0x25a1, 0x908e,0x25a1, 0x9092,0x25a1, 0x9093,0x9127, 0x9096,0x25a1, +0x909a,0x25a1, 0x909c,0x25a1, 0x909d,0x913a, 0x90a4,0x25a1, 0x90a8,0x25a1, +0x90a9,0x25a1, 0x90ab,0x25a1, 0x90ac,0x9114, 0x90ad,0x25a1, 0x90ae,0x90f5, +0x90b7,0x25a1, 0x90b9,0x9112, 0x90ba,0x9134, 0x90bb,0x9130, 0x90bc,0x25a1, +0x90c0,0x647a, 0x90c1,0x9b31, 0x90c2,0x25a1, 0x90c4,0x537b, 0x90c6,0x25a1, +0x90c9,0x25a1, 0x90cc,0x25a1, 0x90cd,0x25a1, 0x90cf,0x90df, 0x90d0,0x9136, +0x90d1,0x912d, 0x90d2,0x25a1, 0x90d3,0x9106, 0x90de,0x25a1, 0x90e6,0x9148, +0x90e7,0x9116, 0x90ee,0x25a1, 0x90f6,0x25a1, 0x90f7,0x9109, 0x90f8,0x9132, +0x910a,0x9109, 0x910c,0x25a1, 0x9113,0x25a1, 0x9115,0x9109, 0x9125,0x25a1, +0x9137,0x9146, 0x913c,0x25a1, 0x913d,0x25a1, 0x9142,0x25a1, 0x9144,0x5537, +0x9151,0x25a1, 0x9154,0x25a1, 0x9159,0x25a1, 0x915b,0x25a1, 0x915c,0x25a1, +0x915d,0x919e, 0x915e,0x6c70, 0x9166,0x91b1, 0x9167,0x25a1, 0x916b,0x25a1, +0x916d,0x25a1, 0x9170,0x2eb6, 0x9171,0x91ac, 0x9176,0x9ef4, 0x917b,0x25a1, +0x917c,0x25a1, 0x917d,0x91c5, 0x917e,0x91c3, 0x917f,0x91c0, 0x9188,0x25a1, +0x918c,0x6606, 0x918e,0x25a1, 0x9194,0x25a1, 0x9195,0x25a1, 0x9196,0x25a1, +0x9197,0x25a1, 0x9198,0x25a1, 0x91a4,0x25a1, 0x91a6,0x25a1, 0x91a9,0x25a1, +0x91b6,0x25a1, 0x91b8,0x25a1, 0x91bb,0x25a1, 0x91bf,0x25a1, 0x91c4,0x25a1, +0x91c7,0x63a1, 0x91c8,0x25a1, 0x91ca,0x91cb, 0x91d2,0x25a1, 0x91d6,0x25a1, +0x91db,0x25a1, 0x91de,0x25a1, 0x91df,0x25a1, 0x91e0,0x25a1, 0x91e1,0x65a7, +0x91e5,0x5e37, 0x91ef,0x25a1, 0x91f0,0x25a1, 0x91f2,0x25a1, 0x91f6,0x25a1, +0x91fa,0x25a1, 0x91fb,0x25a1, 0x91fc,0x25a1, 0x91fe,0x25a1, 0x9208,0x25a1, +0x920b,0x25a1, 0x920e,0x25a1, 0x9213,0x25a1, 0x9218,0x25a1, 0x921b,0x25a1, +0x921d,0x25a1, 0x921f,0x25a1, 0x9220,0x25a1, 0x9221,0x25a1, 0x9222,0x25a1, +0x9228,0x25a1, 0x9229,0x25a1, 0x922a,0x25a1, 0x922b,0x25a1, 0x922c,0x25a1, +0x922f,0x25a1, 0x9235,0x25a1, 0x923b,0x25a1, 0x923c,0x25a1, 0x9241,0x25a1, +0x9242,0x25a1, 0x9243,0x25a1, 0x9244,0x25a1, 0x9247,0x25a1, 0x9255,0x25a1, +0x9258,0x25a1, 0x9259,0x25a1, 0x925c,0x25a1, 0x925d,0x25a1, 0x925f,0x25a1, +0x9262,0x25a1, 0x9268,0x25a1, 0x9269,0x25a1, 0x926a,0x25a1, 0x926b,0x25a1, +0x926e,0x25a1, 0x9271,0x25a1, 0x9273,0x25a1, 0x9274,0x9452, 0x9275,0x25a1, +0x9277,0x25a1, 0x9281,0x25a1, 0x9284,0x25a1, 0x9289,0x25a1, 0x928f,0x25a1, +0x9290,0x25a1, 0x9292,0x25a1, 0x929e,0x25a1, 0x929f,0x25a1, 0x92a7,0x606a, +0x92ad,0x25a1, 0x92ae,0x947e, 0x92af,0x25a1, 0x92b0,0x25a1, 0x92b1,0x25a1, +0x92b8,0x25a1, 0x92ba,0x25a1, 0x92bd,0x25a1, 0x92be,0x25a1, 0x92bf,0x25a1, +0x92d4,0x25a1, 0x92d6,0x25a1, 0x92da,0x25a1, 0x92db,0x25a1, 0x92dc,0x25a1, +0x92e2,0x25a1, 0x92e3,0x25a1, 0x92e5,0x25a1, 0x92eb,0x25a1, 0x92ec,0x25a1, +0x92ed,0x25a1, 0x92f2,0x25a1, 0x92f3,0x25a1, 0x92f4,0x25a1, 0x92f5,0x25a1, +0x92f6,0x25a1, 0x92fd,0x25a1, 0x9303,0x25a1, 0x9305,0x25a1, 0x9307,0x25a1, +0x9309,0x6d39, 0x930a,0x25a1, 0x9311,0x25a1, 0x9317,0x25a1, 0x931c,0x25a1, +0x932c,0x25a1, 0x9330,0x25a1, 0x9331,0x25a1, 0x9332,0x25a1, 0x9337,0x25a1, +0x933a,0x25a1, 0x933b,0x25a1, 0x933d,0x25a1, 0x933e,0x93e8, 0x933f,0x25a1, +0x9340,0x25a1, 0x9341,0x25a1, 0x9342,0x25a1, 0x9343,0x25a1, 0x9344,0x25a1, +0x9345,0x25a1, 0x9348,0x25a1, 0x9353,0x25a1, 0x935d,0x25a1, 0x935f,0x25a1, +0x9362,0x25a1, 0x9366,0x25a1, 0x9368,0x25a1, 0x9369,0x25a1, 0x936b,0x6fc9, +0x936e,0x25a1, 0x936f,0x25a1, 0x9372,0x25a1, 0x9373,0x25a1, 0x9374,0x25a1, +0x9378,0x25a1, 0x937d,0x25a1, 0x937f,0x25a1, 0x9381,0x25a1, 0x9384,0x25a1, +0x9385,0x25a1, 0x9386,0x25a1, 0x9387,0x25a1, 0x938b,0x25a1, 0x9390,0x25a1, +0x9393,0x25a1, 0x939c,0x25a1, 0x93a0,0x25a1, 0x93ab,0x25a1, 0x93ad,0x25a1, +0x93b6,0x25a1, 0x93b8,0x25a1, 0x93b9,0x25a1, 0x93ba,0x25a1, 0x93bb,0x9396, +0x93bc,0x25a1, 0x93bd,0x25a1, 0x93be,0x25a1, 0x93bf,0x25a1, 0x93c1,0x25a1, +0x93c5,0x25a1, 0x93c6,0x25a1, 0x93c9,0x25a1, 0x93cb,0x25a1, 0x93d3,0x25a1, +0x93db,0x25a1, 0x93e0,0x25a1, 0x93e5,0x25a1, 0x93e9,0x25a1, 0x93ea,0x25a1, +0x93eb,0x25a1, 0x93ed,0x25a1, 0x93ef,0x25a1, 0x93f0,0x25a1, 0x93f1,0x25a1, +0x93f2,0x25a1, 0x93f3,0x25a1, 0x93f4,0x25a1, 0x9401,0x25a1, 0x9402,0x25a1, +0x9404,0x25a1, 0x9405,0x25a1, 0x9408,0x25a1, 0x9417,0x25a1, 0x941a,0x25a1, +0x941b,0x25a1, 0x941c,0x25a1, 0x941d,0x25a1, 0x941e,0x25a1, 0x941f,0x25a1, +0x9421,0x25a1, 0x9422,0x25a1, 0x9423,0x25a1, 0x9424,0x25a1, 0x9425,0x25a1, +0x9426,0x25a1, 0x9427,0x25a1, 0x942d,0x25a1, 0x942f,0x25a1, 0x9434,0x25a1, +0x943e,0x58c1, 0x9441,0x25a1, 0x9442,0x25a1, 0x9443,0x25a1, 0x944d,0x25a1, +0x944e,0x25a1, 0x9453,0x25a1, 0x9454,0x25a1, 0x9456,0x25a1, 0x9458,0x25a1, +0x9459,0x25a1, 0x945a,0x25a1, 0x945b,0x25a1, 0x945c,0x25a1, 0x945f,0x25a1, +0x9461,0x25a1, 0x9465,0x25a1, 0x9466,0x25a1, 0x9467,0x25a1, 0x946c,0x25a1, +0x9479,0x25a1, 0x947a,0x25a1, 0x947b,0x25a1, 0x9484,0x25a1, 0x9485,0x91d1, +0x9486,0x91d3, 0x9487,0x91d4, 0x9488,0x91dd, 0x9489,0x91d8, 0x948a,0x91d7, +0x948b,0x91d9, 0x948c,0x91d5, 0x948d,0x91f7, 0x948e,0x9431, 0x948f,0x91e7, +0x9490,0x91e4, 0x9491,0x9212, 0x9492,0x91e9, 0x9493,0x91e3, 0x9494,0x9346, +0x9495,0x91f9, 0x9496,0x935a, 0x9497,0x91f5, 0x9498,0x9203, 0x9499,0x9223, +0x949a,0x923d, 0x949b,0x9226, 0x949c,0x9245, 0x949d,0x920d, 0x949e,0x9214, +0x949f,0x9418, 0x94a0,0x9209, 0x94a1,0x92c7, 0x94a2,0x92fc, 0x94a3,0x9211, +0x94a4,0x9210, 0x94a5,0x9470, 0x94a6,0x6b3d, 0x94a7,0x921e, 0x94a8,0x93a2, +0x94a9,0x9264, 0x94aa,0x9227, 0x94ab,0x9201, 0x94ac,0x9225, 0x94ad,0x9204, +0x94ae,0x9215, 0x94af,0x9200, 0x94b0,0x923a, 0x94b1,0x9322, 0x94b2,0x9266, +0x94b3,0x9257, 0x94b4,0x9237, 0x94b5,0x7f3d, 0x94b6,0x9233, 0x94b7,0x93c2, +0x94b8,0x923d, 0x94b9,0x9238, 0x94ba,0x925e, 0x94bb,0x947d, 0x94bc,0x926c, +0x94bd,0x926d, 0x94be,0x9240, 0x94bf,0x923f, 0x94c0,0x923e, 0x94c1,0x9435, +0x94c2,0x9251, 0x94c3,0x9234, 0x94c4,0x9460, 0x94c5,0x925b, 0x94c6,0x925a, +0x94c7,0x25a1, 0x94c8,0x9230, 0x94c9,0x9249, 0x94ca,0x9248, 0x94cb,0x924d, +0x94cc,0x922e, 0x94cd,0x9239, 0x94ce,0x9438, 0x94cf,0x9276, 0x94d0,0x92ac, +0x94d1,0x92a0, 0x94d2,0x927a, 0x94d3,0x92e9, 0x94d4,0x930f, 0x94d5,0x92aa, +0x94d6,0x92ee, 0x94d7,0x92cf, 0x94d8,0x90aa, 0x94d9,0x9403, 0x94da,0x928d, +0x94db,0x943a, 0x94dc,0x9285, 0x94dd,0x92c1, 0x94de,0x540a, 0x94df,0x92a6, +0x94e0,0x93a7, 0x94e1,0x9358, 0x94e2,0x9296, 0x94e3,0x9291, 0x94e4,0x92cc, +0x94e5,0x92a9, 0x94e6,0x929b, 0x94e7,0x93f5, 0x94e8,0x9293, 0x94e9,0x93a9, +0x94ea,0x927f, 0x94eb,0x929a, 0x94ec,0x927b, 0x94ed,0x9298, 0x94ee,0x931a, +0x94ef,0x92ab, 0x94f0,0x9278, 0x94f1,0x92a5, 0x94f2,0x93df, 0x94f3,0x9283, +0x94f4,0x940b, 0x94f5,0x92a8, 0x94f6,0x9280, 0x94f7,0x92a3, 0x94f8,0x9444, +0x94f9,0x9412, 0x94fa,0x92ea, 0x94fb,0x92d9, 0x94fc,0x9338, 0x94fd,0x92f1, +0x94fe,0x93c8, 0x94ff,0x93d7, 0x9500,0x92b7, 0x9501,0x9396, 0x9502,0x92f0, +0x9503,0x5448, 0x9504,0x92e4, 0x9505,0x934b, 0x9506,0x92ef, 0x9507,0x92e8, +0x9508,0x93fd, 0x9509,0x92bc, 0x950a,0x92dd, 0x950b,0x92d2, 0x950c,0x92c5, +0x950d,0x7409, 0x950e,0x9272, 0x950f,0x9592, 0x9510,0x92b3, 0x9511,0x92bb, +0x9512,0x92c3, 0x9513,0x92df, 0x9514,0x92e6, 0x9515,0x9312, 0x9516,0x9306, +0x9517,0x937a, 0x9518,0x82e5, 0x9519,0x932f, 0x951a,0x9328, 0x951b,0x931b, +0x951c,0x9321, 0x951d,0x939d, 0x951e,0x9301, 0x951f,0x9315, 0x9520,0x741b, +0x9521,0x932b, 0x9522,0x932e, 0x9523,0x947c, 0x9524,0x9318, 0x9525,0x9310, +0x9526,0x9326, 0x9527,0x9455, 0x9528,0x6774, 0x9529,0x9308, 0x952a,0x5ffd, +0x952b,0x57f9, 0x952c,0x931f, 0x952d,0x9320, 0x952e,0x9375, 0x952f,0x92f8, +0x9530,0x9333, 0x9531,0x9319, 0x9532,0x9365, 0x9533,0x25a1, 0x9534,0x9347, +0x9535,0x93d8, 0x9536,0x9376, 0x9537,0x9354, 0x9538,0x9364, 0x9539,0x936c, +0x953a,0x937e, 0x953b,0x935b, 0x953c,0x93aa, 0x953d,0x9360, 0x953e,0x9370, +0x953f,0x9440, 0x9540,0x934d, 0x9541,0x9382, 0x9542,0x93e4, 0x9543,0x93a1, +0x9544,0x9428, 0x9545,0x92c2, 0x9546,0x93cc, 0x9547,0x93ae, 0x9548,0x939b, +0x9549,0x9398, 0x954a,0x9477, 0x954b,0x9482, 0x954c,0x942b, 0x954d,0x93b3, +0x954e,0x62ff, 0x954f,0x93a6, 0x9550,0x93ac, 0x9551,0x938a, 0x9552,0x93b0, +0x9553,0x93b5, 0x9554,0x944c, 0x9555,0x9394, 0x9556,0x93e2, 0x9557,0x93dc, +0x9558,0x93dd, 0x9559,0x93cd, 0x955a,0x25a1, 0x955b,0x93de, 0x955c,0x93e1, +0x955d,0x93d1, 0x955e,0x93c3, 0x955f,0x93c7, 0x9560,0x93d0, 0x9561,0x9414, +0x9562,0x9481, 0x9563,0x9410, 0x9564,0x93f7, 0x9565,0x9b6f, 0x9566,0x9413, +0x9567,0x946d, 0x9568,0x9420, 0x9569,0x4e32, 0x956a,0x93f9, 0x956b,0x9419, +0x956c,0x944a, 0x956d,0x9433, 0x956e,0x9436, 0x956f,0x9432, 0x9570,0x942e, +0x9571,0x943f, 0x9572,0x5bdf, 0x9573,0x9463, 0x9574,0x945e, 0x9575,0x9471, +0x9576,0x9472, 0x9578,0x25a1, 0x9579,0x25a1, 0x957e,0x25a1, 0x957f,0x9577, +0x9581,0x25a1, 0x9584,0x25a1, 0x9585,0x25a1, 0x9587,0x25a1, 0x958a,0x25a1, +0x9595,0x25a1, 0x9596,0x25a1, 0x9597,0x25a1, 0x9599,0x25a1, 0x959a,0x25a1, +0x959d,0x25a1, 0x95a0,0x25a1, 0x95a2,0x25a1, 0x95a6,0x25a1, 0x95a7,0x25a1, +0x95aa,0x25a1, 0x95af,0x25a1, 0x95b2,0x95b1, 0x95b3,0x25a1, 0x95b4,0x25a1, +0x95b8,0x25a1, 0x95c1,0x25a1, 0x95c2,0x25a1, 0x95c4,0x25a1, 0x95ce,0x25a1, +0x95cf,0x25a1, 0x95d7,0x25a1, 0x95d8,0x25a1, 0x95d9,0x25a1, 0x95dd,0x25a1, +0x95e6,0x25a1, 0x95e7,0x25a1, 0x95e8,0x9580, 0x95e9,0x9582, 0x95ea,0x9583, +0x95eb,0x9586, 0x95ec,0x9588, 0x95ed,0x9589, 0x95ee,0x554f, 0x95ef,0x95d6, +0x95f0,0x958f, 0x95f1,0x95c8, 0x95f2,0x9592, 0x95f3,0x958e, 0x95f4,0x9593, +0x95f5,0x9594, 0x95f6,0x958c, 0x95f7,0x60b6, 0x95f8,0x9598, 0x95f9,0x9b27, +0x95fa,0x95a8, 0x95fb,0x805e, 0x95fc,0x95e5, 0x95fd,0x95a9, 0x95fe,0x95ad, +0x95ff,0x95d3, 0x9600,0x95a5, 0x9601,0x95a3, 0x9602,0x95a1, 0x9603,0x95ab, +0x9604,0x9b2e, 0x9605,0x95b1, 0x9606,0x95ac, 0x9607,0x95cd, 0x9608,0x95be, +0x9609,0x95b9, 0x960a,0x95b6, 0x960b,0x9b29, 0x960c,0x95bf, 0x960d,0x95bd, +0x960e,0x95bb, 0x960f,0x95bc, 0x9610,0x95e1, 0x9611,0x95cc, 0x9612,0x95c3, +0x9613,0x95e0, 0x9614,0x95ca, 0x9615,0x95cb, 0x9616,0x95d4, 0x9617,0x95d0, +0x9618,0x95d2, 0x9619,0x95d5, 0x961a,0x95de, 0x961b,0x95e4, 0x961d,0x961c, +0x961f,0x968a, 0x9625,0x25a1, 0x9626,0x25a1, 0x9627,0x25a1, 0x9629,0x25a1, +0x962b,0x25a1, 0x9633,0x967d, 0x9634,0x9670, 0x9635,0x9663, 0x9636,0x968e, +0x9637,0x25a1, 0x9638,0x25a1, 0x963e,0x25a1, 0x9641,0x25a1, 0x9645,0x969b, +0x9646,0x9678, 0x9647,0x96b4, 0x9648,0x9673, 0x9649,0x9658, 0x9652,0x25a1, +0x9655,0x965d, 0x9656,0x25a1, 0x9657,0x25a1, 0x9659,0x25a1, 0x965a,0x25a1, +0x9660,0x25a1, 0x9665,0x25a1, 0x9666,0x25a1, 0x9667,0x9689, 0x9668,0x9695, +0x9669,0x96aa, 0x966e,0x25a1, 0x9679,0x25a1, 0x967a,0x25a1, 0x967b,0x25a1, +0x967f,0x25a1, 0x9681,0x25a1, 0x9682,0x9670, 0x968c,0x6697, 0x968f,0x96a8, +0x9690,0x96b1, 0x9696,0x25a1, 0x969a,0x25a1, 0x969d,0x25a1, 0x969f,0x25a1, +0x96a0,0x96b1, 0x96a3,0x25a1, 0x96a5,0x25a1, 0x96a6,0x25a1, 0x96ab,0x25a1, +0x96ad,0x25a1, 0x96af,0x25a1, 0x96b2,0x25a1, 0x96b5,0x25a1, 0x96b6,0x96b8, +0x96b7,0x96b8, 0x96ba,0x25a1, 0x96bd,0x96cb, 0x96be,0x96e3, 0x96cf,0x96db, +0x96d0,0x25a1, 0x96d1,0x25a1, 0x96e0,0x8b8e, 0x96e4,0x25a1, 0x96e6,0x25a1, +0x96e7,0x25a1, 0x96eb,0x25a1, 0x96ec,0x25a1, 0x96ed,0x25a1, 0x96ee,0x25a1, +0x96f3,0x9742, 0x96f4,0x25a1, 0x96fc,0x25a1, 0x96fe,0x9727, 0x9701,0x973d, +0x9703,0x25a1, 0x970a,0x9748, 0x970c,0x25a1, 0x9714,0x25a1, 0x9715,0x25a1, +0x9717,0x25a1, 0x971a,0x25a1, 0x971b,0x25a1, 0x9720,0x643f, 0x9721,0x25a1, +0x972d,0x9744, 0x9731,0x25a1, 0x9733,0x25a1, 0x9734,0x25a1, 0x9736,0x25a1, +0x9737,0x25a1, 0x973b,0x25a1, 0x973c,0x25a1, 0x9740,0x25a1, 0x9741,0x25a1, +0x9745,0x25a1, 0x974a,0x25a1, 0x974c,0x25a1, 0x974d,0x25a1, 0x974e,0x25a1, +0x974f,0x25a1, 0x9750,0x25a1, 0x9751,0x25a1, 0x9753,0x975a, 0x9754,0x25a1, +0x9755,0x25a1, 0x9757,0x25a1, 0x9759,0x975c, 0x975d,0x25a1, 0x975f,0x25a1, +0x9763,0x25a1, 0x9764,0x25a1, 0x9765,0x9768, 0x9767,0x25a1, 0x976b,0x25a1, +0x976d,0x25a1, 0x976f,0x25a1, 0x9771,0x25a1, 0x9775,0x25a1, 0x9779,0x25a1, +0x9786,0x25a1, 0x9787,0x25a1, 0x9789,0x25a1, 0x978c,0x25a1, 0x9790,0x25a1, +0x9791,0x97c3, 0x9792,0x8f4e, 0x9793,0x25a1, 0x9795,0x25a1, 0x9796,0x25a1, +0x979b,0x25a1, 0x979f,0x25a1, 0x97a7,0x25a1, 0x97a9,0x25a1, 0x97af,0x97c9, +0x97b0,0x25a1, 0x97b1,0x25a1, 0x97b2,0x97dd, 0x97b4,0x9781, 0x97b5,0x25a1, +0x97b8,0x25a1, 0x97ba,0x25a1, 0x97bc,0x25a1, 0x97bd,0x8f4e, 0x97be,0x25a1, +0x97c0,0x25a1, 0x97c2,0x25a1, 0x97c8,0x25a1, 0x97ca,0x25a1, 0x97d1,0x25a1, +0x97d2,0x25a1, 0x97da,0x25a1, 0x97db,0x25a1, 0x97e0,0x25a1, 0x97e2,0x25a1, +0x97e4,0x25a1, 0x97e6,0x97cb, 0x97e7,0x97cc, 0x97e8,0x97cd, 0x97e9,0x97d3, +0x97ea,0x97d9, 0x97eb,0x97de, 0x97ec,0x97dc, 0x97ee,0x25a1, 0x97ef,0x7c64, +0x97f2,0x9f4b, 0x97f4,0x25a1, 0x97f5,0x97fb, 0x97f7,0x25a1, 0x97fc,0x25a1, +0x9809,0x25a1, 0x980b,0x25a1, 0x9814,0x25a1, 0x9815,0x25a1, 0x9819,0x25a1, +0x981a,0x25a1, 0x981f,0x25a1, 0x9822,0x25a1, 0x9823,0x25a1, 0x9825,0x25a1, +0x982a,0x25a1, 0x982c,0x25a1, 0x982e,0x25a1, 0x9831,0x25a1, 0x9833,0x25a1, +0x9834,0x25a1, 0x9836,0x25a1, 0x983a,0x25a1, 0x983c,0x25a1, 0x983d,0x25a1, +0x983e,0x25a1, 0x983f,0x25a1, 0x9840,0x25a1, 0x9842,0x25a1, 0x9847,0x25a1, +0x984b,0x816e, 0x9854,0x984f, 0x9855,0x986f, 0x9856,0x25a1, 0x985a,0x25a1, +0x9861,0x25a1, 0x9866,0x25a1, 0x9868,0x25a1, 0x986c,0x25a1, 0x986d,0x25a1, +0x986e,0x7762, 0x9875,0x9801, 0x9876,0x9802, 0x9877,0x9803, 0x9878,0x9807, +0x9879,0x9805, 0x987a,0x9806, 0x987b,0x9808, 0x987c,0x980a, 0x987d,0x9811, +0x987e,0x9867, 0x987f,0x9813, 0x9880,0x980e, 0x9881,0x9812, 0x9882,0x980c, +0x9883,0x980f, 0x9884,0x9810, 0x9885,0x9871, 0x9886,0x9818, 0x9887,0x9817, +0x9888,0x9838, 0x9889,0x9821, 0x988a,0x9830, 0x988b,0x9832, 0x988c,0x981c, +0x988d,0x6f41, 0x988e,0x71b2, 0x988f,0x9826, 0x9890,0x9824, 0x9891,0x983b, +0x9892,0x25a1, 0x9893,0x9839, 0x9894,0x9837, 0x9895,0x7a4e, 0x9896,0x7a4e, +0x9897,0x9846, 0x9898,0x984c, 0x9899,0x9852, 0x989a,0x984e, 0x989b,0x9853, +0x989c,0x984f, 0x989d,0x984d, 0x989e,0x9873, 0x989f,0x9862, 0x98a0,0x985b, +0x98a1,0x9859, 0x98a2,0x9865, 0x98a3,0x7e87, 0x98a4,0x986b, 0x98a5,0x9808, +0x98a6,0x9870, 0x98a7,0x9874, 0x98aa,0x25a1, 0x98ab,0x25a1, 0x98b0,0x65cb, +0x98b4,0x25a1, 0x98b5,0x25a1, 0x98b7,0x98c6, 0x98b9,0x25a1, 0x98c3,0x25a1, +0x98c5,0x25a1, 0x98c7,0x25a1, 0x98c8,0x25a1, 0x98ca,0x25a1, 0x98cd,0x25a1, +0x98ce,0x98a8, 0x98cf,0x98ba, 0x98d0,0x98ad, 0x98d1,0x98ae, 0x98d2,0x98af, +0x98d3,0x98b6, 0x98d4,0x98b8, 0x98d5,0x98bc, 0x98d6,0x98bb, 0x98d7,0x98c0, +0x98d8,0x98c4, 0x98d9,0x98c6, 0x98da,0x98c6, 0x98dc,0x25a1, 0x98dd,0x25a1, +0x98de,0x98db, 0x98e0,0x25a1, 0x98e1,0x25a1, 0x98e4,0x25a1, 0x98e6,0x25a1, +0x98e8,0x9957, 0x98ec,0x990a, 0x98ee,0x98f2, 0x98f0,0x25a1, 0x98f1,0x9910, +0x98f3,0x25a1, 0x98f5,0x25a1, 0x98f7,0x25a1, 0x98f8,0x25a1, 0x98fb,0x25a1, +0x98ff,0x25a1, 0x9901,0x25a1, 0x9904,0x25a1, 0x9906,0x25a1, 0x9907,0x93a9, +0x990b,0x25a1, 0x990d,0x995c, 0x990e,0x25a1, 0x990f,0x25a1, 0x9919,0x25a1, +0x991c,0x25a1, 0x991d,0x25a1, 0x9920,0x25a1, 0x9922,0x25a1, 0x9923,0x25a1, +0x9926,0x25a1, 0x9934,0x25a1, 0x9936,0x25a1, 0x9937,0x25a1, 0x9938,0x25a1, +0x9939,0x25a1, 0x993b,0x25a1, 0x9940,0x25a1, 0x9942,0x25a1, 0x9944,0x25a1, +0x9946,0x25a1, 0x994a,0x00f8, 0x994d,0x25a1, 0x994f,0x25a1, 0x995a,0x25a1, +0x995d,0x25a1, 0x9960,0x25a1, 0x9962,0x25a1, 0x9963,0x98df, 0x9964,0x98e3, +0x9965,0x98e2, 0x9966,0x98e5, 0x9967,0x9933, 0x9968,0x98e9, 0x9969,0x993c, +0x996a,0x98ea, 0x996b,0x98eb, 0x996c,0x98ed, 0x996d,0x98ef, 0x996e,0x98f2, +0x996f,0x991e, 0x9970,0x98fe, 0x9971,0x98fd, 0x9972,0x98fc, 0x9973,0x25a1, +0x9974,0x98f4, 0x9975,0x990c, 0x9976,0x9952, 0x9977,0x9909, 0x9978,0x25a1, +0x9979,0x25a1, 0x997a,0x9903, 0x997b,0x25a1, 0x997c,0x9905, 0x997d,0x9911, +0x997e,0x9916, 0x997f,0x9913, 0x9980,0x9918, 0x9981,0x9912, 0x9982,0x9915, +0x9983,0x25a1, 0x9984,0x991b, 0x9985,0x9921, 0x9986,0x9928, 0x9987,0x67e5, +0x9988,0x994b, 0x9989,0x7a39, 0x998a,0x993f, 0x998b,0x995e, 0x998c,0x9941, +0x998d,0x9943, 0x998e,0x993a, 0x998f,0x993e, 0x9990,0x9948, 0x9991,0x9949, +0x9992,0x9945, 0x9993,0x00f8, 0x9994,0x994c, 0x9995,0x56ca, 0x999a,0x25a1, +0x999b,0x25a1, 0x999f,0x25a1, 0x99a0,0x25a1, 0x99a2,0x25a1, 0x99a4,0x25a1, +0x99a9,0x25a1, 0x99aa,0x25a1, 0x99b6,0x25a1, 0x99b7,0x25a1, 0x99b8,0x25a1, +0x99bc,0x25a1, 0x99be,0x25a1, 0x99bf,0x25a1, 0x99c0,0x25a1, 0x99c4,0x25a1, +0x99c5,0x25a1, 0x99c6,0x25a1, 0x99c8,0x25a1, 0x99ca,0x25a1, 0x99da,0x25a1, +0x99de,0x25a1, 0x99e0,0x25a1, 0x99e1,0x25a1, 0x99e6,0x25a1, 0x99e8,0x25a1, +0x99eb,0x25a1, 0x99ef,0x25a1, 0x99f2,0x25a1, 0x99f3,0x25a1, 0x99f5,0x25a1, +0x99f9,0x761b, 0x9a00,0x25a1, 0x9a08,0x25a1, 0x9a0c,0x25a1, 0x9a10,0x25a1, +0x9a12,0x25a1, 0x9a13,0x25a1, 0x9a17,0x25a1, 0x9a18,0x25a1, 0x9a1f,0x25a1, +0x9a21,0x25a1, 0x9a26,0x25a1, 0x9a28,0x25a1, 0x9a2f,0x25a1, 0x9a33,0x25a1, +0x9a3b,0x25a1, 0x9a3c,0x25a1, 0x9a47,0x25a1, 0x9a4b,0x25a1, 0x9a51,0x25a1, +0x9a58,0x25a1, 0x9a59,0x9821, 0x9a5c,0x25a1, 0x9a5d,0x25a1, 0x9a61,0x25a1, +0x9a63,0x25a1, 0x9a6c,0x99ac, 0x9a6d,0x99ad, 0x9a6e,0x99b1, 0x9a6f,0x99b4, +0x9a70,0x99b3, 0x9a71,0x9a45, 0x9a72,0x99b9, 0x9a73,0x99c1, 0x9a74,0x9a62, +0x9a75,0x99d4, 0x9a76,0x99db, 0x9a77,0x99df, 0x9a78,0x99d9, 0x9a79,0x99d2, +0x9a7a,0x9a36, 0x9a7b,0x99d0, 0x9a7c,0x99dd, 0x9a7d,0x99d1, 0x9a7e,0x99d5, +0x9a7f,0x9a5b, 0x9a80,0x99d8, 0x9a81,0x9a4d, 0x9a82,0x7f75, 0x9a83,0x99f0, +0x9a84,0x9a55, 0x9a85,0x9a4a, 0x9a86,0x99f1, 0x9a87,0x99ed, 0x9a88,0x99e2, +0x9a89,0x9a6b, 0x9a8a,0x9a6a, 0x9a8b,0x9a01, 0x9a8c,0x9a57, 0x9a8d,0x9a02, +0x9a8e,0x99f8, 0x9a8f,0x99ff, 0x9a90,0x9a0f, 0x9a91,0x9a0e, 0x9a92,0x9a0d, +0x9a93,0x9a05, 0x9a94,0x25a1, 0x9a95,0x9a4c, 0x9a96,0x9a42, 0x9a97,0x9a19, +0x9a98,0x9a2d, 0x9a99,0x9a24, 0x9a9a,0x9a37, 0x9a9b,0x9a16, 0x9a9c,0x9a41, +0x9a9d,0x9a2e, 0x9a9e,0x9a2b, 0x9a9f,0x9a38, 0x9aa0,0x9a43, 0x9aa1,0x9a3e, +0x9aa2,0x9a44, 0x9aa3,0x9a4f, 0x9aa4,0x9a5f, 0x9aa5,0x9a65, 0x9aa6,0x9a66, +0x9aa7,0x9a64, 0x9aa9,0x25a1, 0x9aaa,0x25a1, 0x9aac,0x25a1, 0x9aae,0x25a1, +0x9ab2,0x25a1, 0x9ab5,0x25a1, 0x9ab6,0x80dd, 0x9aba,0x2ed7, 0x9abd,0x25a1, +0x9ac3,0x25a1, 0x9ac4,0x25a1, 0x9ac5,0x9acf, 0x9ac8,0x25a1, 0x9ac9,0x25a1, +0x9acb,0x9ad6, 0x9acc,0x9ad5, 0x9ace,0x25a1, 0x9ad7,0x25a1, 0x9ad9,0x25a1, +0x9ada,0x25a1, 0x9adb,0x25a1, 0x9add,0x25a1, 0x9ade,0x25a1, 0x9ae0,0x25a1, +0x9ae2,0x25a1, 0x9ae4,0x25a1, 0x9ae5,0x25a1, 0x9ae8,0x25a1, 0x9ae9,0x25a1, +0x9aea,0x25a1, 0x9af0,0x25a1, 0x9af4,0x25a1, 0x9af5,0x25a1, 0x9af8,0x25a1, +0x9aff,0x25a1, 0x9b00,0x25a1, 0x9b02,0x25a1, 0x9b06,0x87c6, 0x9b07,0x25a1, +0x9b09,0x25a1, 0x9b0f,0x79cb, 0x9b13,0x9b22, 0x9b14,0x25a1, 0x9b1b,0x25a1, +0x9b1c,0x25a1, 0x9b1d,0x25a1, 0x9b21,0x25a1, 0x9b26,0x25a1, 0x9b2a,0x25a1, +0x9b2c,0x25a1, 0x9b2d,0x25a1, 0x9b30,0x25a1, 0x9b34,0x25a1, 0x9b36,0x25a1, +0x9b38,0x25a1, 0x9b39,0x25a1, 0x9b3d,0x25a1, 0x9b40,0x25a1, 0x9b47,0x9b58, +0x9b49,0x9b4e, 0x9b50,0x25a1, 0x9b53,0x25a1, 0x9b57,0x25a1, 0x9b5c,0x25a1, +0x9b5d,0x25a1, 0x9b5e,0x25a1, 0x9b62,0x25a1, 0x9b63,0x25a1, 0x9b65,0x25a1, +0x9b69,0x25a1, 0x9b6a,0x25a1, 0x9b6b,0x25a1, 0x9b6d,0x25a1, 0x9b6e,0x25a1, +0x9b72,0x25a1, 0x9b73,0x25a1, 0x9b78,0x25a1, 0x9b79,0x25a1, 0x9b7b,0x7c1f, +0x9b7f,0x25a1, 0x9b81,0x25a1, 0x9b83,0x25a1, 0x9b84,0x25a1, 0x9b89,0x25a1, +0x9b8a,0x25a1, 0x9b8b,0x25a1, 0x9b8c,0x25a1, 0x9b8d,0x25a1, 0x9b8e,0x25a1, +0x9b8f,0x25a1, 0x9b94,0x25a1, 0x9b96,0x25a1, 0x9b97,0x25a1, 0x9b98,0x25a1, +0x9b99,0x25a1, 0x9b9c,0x25a1, 0x9b9d,0x25a1, 0x9b9f,0x25a1, 0x9ba3,0x25a1, +0x9ba7,0x25a1, 0x9ba9,0x25a1, 0x9bac,0x25a1, 0x9bb0,0x25a1, 0x9bb1,0x25a1, +0x9bb2,0x25a1, 0x9bb3,0x25a1, 0x9bb4,0x25a1, 0x9bb7,0x25a1, 0x9bba,0x25a1, +0x9bbb,0x25a1, 0x9bbc,0x25a1, 0x9bbe,0x25a1, 0x9bc2,0x25a1, 0x9bc5,0x25a1, +0x9bcb,0x25a1, 0x9bcc,0x25a1, 0x9bcd,0x25a1, 0x9bce,0x25a1, 0x9bcf,0x25a1, +0x9bd0,0x25a1, 0x9bd1,0x25a1, 0x9bd2,0x25a1, 0x9bd8,0x25a1, 0x9bdd,0x25a1, +0x9bdf,0x25a1, 0x9be3,0x25a1, 0x9be9,0x25a1, 0x9bed,0x25a1, 0x9bee,0x25a1, +0x9bef,0x25a1, 0x9bf1,0x25a1, 0x9bf2,0x25a1, 0x9bf3,0x25a1, 0x9bf4,0x25a1, +0x9bf5,0x25a1, 0x9bf6,0x25a1, 0x9bf9,0x25a1, 0x9bfa,0x25a1, 0x9bfb,0x25a1, +0x9bfc,0x25a1, 0x9bfe,0x25a1, 0x9bff,0x25a1, 0x9c00,0x25a1, 0x9c01,0x25a1, +0x9c02,0x25a1, 0x9c03,0x25a1, 0x9c04,0x25a1, 0x9c0a,0x25a1, 0x9c0c,0x25a1, +0x9c0f,0x25a1, 0x9c10,0x25a1, 0x9c11,0x25a1, 0x9c15,0x25a1, 0x9c16,0x25a1, +0x9c18,0x25a1, 0x9c19,0x25a1, 0x9c1a,0x25a1, 0x9c1b,0x25a1, 0x9c1e,0x25a1, +0x9c1f,0x25a1, 0x9c20,0x25a1, 0x9c22,0x25a1, 0x9c26,0x25a1, 0x9c27,0x25a1, +0x9c2a,0x25a1, 0x9c2e,0x25a1, 0x9c2f,0x25a1, 0x9c30,0x25a1, 0x9c35,0x25a1, +0x9c38,0x25a1, 0x9c3a,0x25a1, 0x9c42,0x25a1, 0x9c43,0x25a1, 0x9c45,0x25a1, +0x9c47,0x25a1, 0x9c4f,0x25a1, 0x9c51,0x25a1, 0x9c53,0x25a1, 0x9c5a,0x25a1, +0x9c5b,0x25a1, 0x9c5c,0x25a1, 0x9c5d,0x25a1, 0x9c61,0x25a1, 0x9c64,0x25a1, +0x9c65,0x25a1, 0x9c69,0x25a1, 0x9c6a,0x25a1, 0x9c6b,0x25a1, 0x9c6c,0x25a1, +0x9c6f,0x25a1, 0x9c70,0x25a1, 0x9c72,0x25a1, 0x9c76,0x25a1, 0x9c7b,0x25a1, +0x9c7c,0x9b5a, 0x9c7d,0x9b5b, 0x9c7e,0x25a1, 0x9c7f,0x9b77, 0x9c80,0x9b68, +0x9c81,0x9b6f, 0x9c82,0x9b74, 0x9c83,0x25a1, 0x9c84,0x9b7a, 0x9c85,0x9c4d, +0x9c86,0x5e73, 0x9c87,0x5360, 0x9c88,0x9c78, 0x9c89,0x25a1, 0x9c8a,0x9b93, +0x9c8b,0x9b92, 0x9c8c,0x25a1, 0x9c8d,0x9b91, 0x9c8e,0x9c5f, 0x9c8f,0x25a1, +0x9c90,0x9b90, 0x9c91,0x9bad, 0x9c92,0x9b9a, 0x9c93,0x25a1, 0x9c94,0x9baa, +0x9c95,0x9b9e, 0x9c96,0x9ba6, 0x9c97,0x25a1, 0x9c98,0x25a1, 0x9c99,0x9c60, +0x9c9a,0x9c6d, 0x9c9b,0x9bab, 0x9c9c,0x9bae, 0x9c9d,0x25a1, 0x9c9e,0x9bd7, +0x9c9f,0x9c58, 0x9ca0,0x9bc1, 0x9ca1,0x9c7a, 0x9ca2,0x9c31, 0x9ca3,0x9c39, +0x9ca4,0x9bc9, 0x9ca5,0x9c23, 0x9ca6,0x9c37, 0x9ca7,0x9bc0, 0x9ca8,0x9bca, +0x9ca9,0x9bc7, 0x9caa,0x9bb6, 0x9cab,0x9bfd, 0x9cac,0x25a1, 0x9cad,0x9bd6, +0x9cae,0x9bea, 0x9caf,0x9bd5, 0x9cb0,0x9beb, 0x9cb1,0x9be1, 0x9cb2,0x9be4, +0x9cb3,0x9be7, 0x9cb4,0x56fa, 0x9cb5,0x9be2, 0x9cb6,0x9bf0, 0x9cb7,0x9bdb, +0x9cb8,0x9be8, 0x9cb9,0x25a1, 0x9cba,0x8671, 0x9cbb,0x9bd4, 0x9cbc,0x8cc1, +0x9cbd,0x9c08, 0x9cbe,0x25a1, 0x9cbf,0x9c68, 0x9cc0,0x9bf7, 0x9cc1,0x25a1, +0x9cc2,0x25a1, 0x9cc3,0x9c13, 0x9cc4,0x9c77, 0x9cc5,0x9c0d, 0x9cc6,0x9c12, +0x9cc7,0x9c09, 0x9cc8,0x25a1, 0x9cc9,0x25a1, 0x9cca,0x6241, 0x9ccb,0x86a4, +0x9ccc,0x9c32, 0x9ccd,0x9c2d, 0x9cce,0x9c28, 0x9ccf,0x9c25, 0x9cd0,0x9c29, +0x9cd1,0x25a1, 0x9cd2,0x9c1c, 0x9cd3,0x9c33, 0x9cd4,0x9c3e, 0x9cd5,0x9c48, +0x9cd6,0x9c49, 0x9cd7,0x9c3b, 0x9cd8,0x9c49, 0x9cd9,0x5eb8, 0x9cda,0x25a1, +0x9cdb,0x9c3c, 0x9cdc,0x9c56, 0x9cdd,0x9c54, 0x9cde,0x9c57, 0x9cdf,0x9c52, +0x9ce0,0x25a1, 0x9ce1,0x9c32, 0x9ce2,0x9c67, 0x9ce3,0x9c63, 0x9ce4,0x25a1, +0x9ce8,0x25a1, 0x9ceb,0x25a1, 0x9cec,0x25a1, 0x9cee,0x25a1, 0x9cef,0x25a1, +0x9cf0,0x25a1, 0x9cf8,0x25a1, 0x9cfe,0x25a1, 0x9d01,0x25a1, 0x9d02,0x25a1, +0x9d0a,0x25a1, 0x9d0b,0x25a1, 0x9d0c,0x25a1, 0x9d0d,0x25a1, 0x9d0e,0x25a1, +0x9d0f,0x25a1, 0x9d11,0x25a1, 0x9d13,0x25a1, 0x9d16,0x25a1, 0x9d1a,0x25a1, +0x9d1c,0x25a1, 0x9d21,0x25a1, 0x9d24,0x25a1, 0x9d27,0x25a1, 0x9d2a,0x25a1, +0x9d2b,0x25a1, 0x9d2c,0x25a1, 0x9d32,0x25a1, 0x9d34,0x25a1, 0x9d35,0x25a1, +0x9d39,0x25a1, 0x9d3a,0x25a1, 0x9d3c,0x25a1, 0x9d44,0x25a1, 0x9d46,0x25a1, +0x9d47,0x25a1, 0x9d48,0x25a1, 0x9d49,0x25a1, 0x9d4d,0x25a1, 0x9d4e,0x25a1, +0x9d50,0x25a1, 0x9d55,0x25a1, 0x9d5e,0x25a1, 0x9d62,0x25a1, 0x9d63,0x25a1, +0x9d64,0x25a1, 0x9d65,0x25a1, 0x9d66,0x25a1, 0x9d6d,0x25a1, 0x9d6e,0x25a1, +0x9d76,0x25a1, 0x9d7a,0x25a1, 0x9d7c,0x25a1, 0x9d7e,0x25a1, 0x9d83,0x25a1, +0x9d8d,0x25a1, 0x9d8e,0x25a1, 0x9d8f,0x25a1, 0x9d91,0x25a1, 0x9d93,0x25a1, +0x9d95,0x25a1, 0x9da5,0x25a1, 0x9dab,0x25a1, 0x9dae,0x25a1, 0x9db0,0x25a1, +0x9dbd,0x25a1, 0x9dc0,0x25a1, 0x9dc4,0x25a1, 0x9dc6,0x25a1, 0x9dc9,0x25a1, +0x9dd4,0x25a1, 0x9de0,0x25a1, 0x9de7,0x25a1, 0x9dea,0x25a1, 0x9df1,0x25a1, +0x9dfc,0x25a1, 0x9e08,0x25a1, 0x9e0a,0x25a1, 0x9e0c,0x25a1, 0x9e0e,0x25a1, +0x9e16,0x25a1, 0x9e18,0x25a1, 0x9e1c,0x25a1, 0x9e1f,0x9ce5, 0x9e20,0x9ce9, +0x9e21,0x96de, 0x9e22,0x9cf6, 0x9e23,0x9cf4, 0x9e24,0x9cf2, 0x9e25,0x9dd7, +0x9e26,0x9d09, 0x9e27,0x9dac, 0x9e28,0x9d07, 0x9e29,0x9d06, 0x9e2a,0x9d23, +0x9e2b,0x9d87, 0x9e2c,0x9e15, 0x9e2d,0x9d28, 0x9e2e,0x9d1e, 0x9e2f,0x9d26, +0x9e30,0x9d12, 0x9e31,0x9d1f, 0x9e32,0x9d1d, 0x9e33,0x9d1b, 0x9e34,0x25a1, +0x9e35,0x9d15, 0x9e36,0x9de5, 0x9e37,0x9dd9, 0x9e38,0x9d2f, 0x9e39,0x9d30, +0x9e3a,0x9d42, 0x9e3b,0x25a1, 0x9e3c,0x9d43, 0x9e3d,0x9d3f, 0x9e3e,0x9e1e, +0x9e3f,0x9d3b, 0x9e40,0x25a1, 0x9e41,0x9d53, 0x9e42,0x9e1d, 0x9e43,0x9d51, +0x9e44,0x9d60, 0x9e45,0x9d5d, 0x9e46,0x9d52, 0x9e47,0x9df3, 0x9e48,0x9d5c, +0x9e49,0x9d61, 0x9e4a,0x9d72, 0x9e4b,0x82d7, 0x9e4c,0x9d6a, 0x9e4d,0x25a1, +0x9e4e,0x9d6f, 0x9e4f,0x9d6c, 0x9e50,0x25a1, 0x9e51,0x9d89, 0x9e52,0x9d8a, +0x9e53,0x9d77, 0x9e54,0x9deb, 0x9e55,0x9d98, 0x9e56,0x9da1, 0x9e57,0x9d9a, +0x9e58,0x9dbb, 0x9e59,0x9d96, 0x9e5a,0x9dbf, 0x9e5b,0x7709, 0x9e5c,0x9da9, +0x9e5d,0x9dca, 0x9e5e,0x9dc2, 0x9e5f,0x9db2, 0x9e60,0x9db9, 0x9e61,0x9dba, +0x9e62,0x9dc1, 0x9e63,0x9dbc, 0x9e64,0x9db4, 0x9e65,0x9dd6, 0x9e66,0x9e1a, +0x9e67,0x9dd3, 0x9e68,0x9dda, 0x9e69,0x9def, 0x9e6a,0x9de6, 0x9e6b,0x9df2, +0x9e6c,0x9df8, 0x9e6d,0x9dfa, 0x9e6e,0x25a1, 0x9e6f,0x9e07, 0x9e70,0x9df9, +0x9e71,0x7372, 0x9e72,0x9e0f, 0x9e73,0x9e1b, 0x9e74,0x25a1, 0x9e76,0x25a1, +0x9e77,0x25a1, 0x9e78,0x25a1, 0x9e7b,0x25a1, 0x9e7e,0x9e7a, 0x9e81,0x25a1, +0x9e84,0x25a1, 0x9e85,0x25a1, 0x9e8f,0x25a1, 0x9e90,0x25a1, 0x9e95,0x25a1, +0x9e96,0x25a1, 0x9e98,0x25a1, 0x9e9e,0x25a1, 0x9ea2,0x25a1, 0x9ea3,0x25a1, +0x9ea6,0x9ea5, 0x9ea8,0x25a1, 0x9eaa,0x25a1, 0x9eab,0x25a1, 0x9eac,0x25a1, +0x9eaf,0x25a1, 0x9eb1,0x25a1, 0x9eb2,0x25a1, 0x9eb3,0x25a1, 0x9eb8,0x9ea9, +0x9eb9,0x9eb4, 0x9eba,0x9eb5, 0x9ebd,0x9ebc, 0x9ebf,0x25a1, 0x9ec1,0x25a1, +0x9ec4,0x9ec3, 0x9ec5,0x25a1, 0x9ec6,0x25a1, 0x9ec7,0x25a1, 0x9ec9,0x9ecc, +0x9eca,0x25a1, 0x9ecb,0x25a1, 0x9ed2,0x9ed1, 0x9ed7,0x25a1, 0x9ed9,0x9ed8, +0x9ee1,0x9ef6, 0x9ee2,0x68ad, 0x9ee3,0x25a1, 0x9ee9,0x9ef7, 0x9eea,0x9ef2, +0x9eec,0x25a1, 0x9ef1,0x25a1, 0x9ef8,0x25a1, 0x9efe,0x9efd, 0x9f02,0x25a1, +0x9f03,0x25a1, 0x9f04,0x25a1, 0x9f05,0x25a1, 0x9f08,0x25a1, 0x9f0b,0x9eff, +0x9f0c,0x25a1, 0x9f0d,0x9f09, 0x9f11,0x25a1, 0x9f14,0x25a1, 0x9f17,0x9780, +0x9f1d,0x25a1, 0x9f1f,0x25a1, 0x9f21,0x25a1, 0x9f26,0x25a1, 0x9f27,0x25a1, +0x9f39,0x9f34, 0x9f3a,0x25a1, 0x9f3c,0x25a1, 0x9f3f,0x25a1, 0x9f44,0x76bb, +0x9f45,0x25a1, 0x9f50,0x9f4a, 0x9f51,0x9f4f, 0x9f53,0x25a1, 0x9f5a,0x25a1, +0x9f62,0x25a1, 0x9f68,0x25a1, 0x9f69,0x25a1, 0x9f6d,0x25a1, 0x9f73,0x25a1, +0x9f7c,0x25a1, 0x9f7d,0x25a1, 0x9f7f,0x9f52, 0x9f80,0x9f54, 0x9f81,0x9f55, +0x9f82,0x9f57, 0x9f83,0x9f5f, 0x9f84,0x9f61, 0x9f85,0x9f59, 0x9f86,0x9f60, +0x9f87,0x9f5c, 0x9f88,0x9f66, 0x9f89,0x9f6c, 0x9f8a,0x9f6a, 0x9f8b,0x9f72, +0x9f8c,0x9f77, 0x9f8e,0x25a1, 0x9f8f,0x25a1, 0x9f93,0x25a1, 0x9f96,0x25a1, +0x9f97,0x25a1, 0x9f99,0x9f8d, 0x9f9a,0x9f94, 0x9f9b,0x9f95, 0x9f9d,0x25a1, +0x9f9e,0x25a1, 0x9f9f,0x9f9c, 0x9fa1,0x25a1, 0x9fa3,0x25a1, 0x9fa5,0x25a1, +0xf92c,0x25a1, 0xf979,0x25a1, 0xf995,0x25a1, 0xf9e7,0x25a1, 0xf9f1,0x25a1, +0xfa0e,0x25a1, 0xfa0f,0x25a1, 0xfa11,0x25a1, 0xfa13,0x25a1, 0xfa14,0x25a1, +0xfa18,0x25a1, 0xfa1f,0x25a1, 0xfa20,0x25a1, 0xfa21,0x25a1, 0xfa23,0x25a1, +0xfa24,0x25a1, 0xfa27,0x25a1, 0xfa28,0x25a1, 0xfa29,0x25a1, 0xff02,0x301e, +0xff07,0x2032, 0xff3b,0xfe5d, 0xff3d,0xfe5e, 0xff3e,0xfe3f, 0xff3f,0x2574, +0xff40,0x2035, 0xffe2,0x25a1, 0xffe3,0x00af, 0xffe4,0x25a1 +}; diff --git a/Packages/VXHanConvert/Sources/VXHanConvert/VXHCTC2SCTable.c b/Packages/VXHanConvert/Sources/VXHanConvert/VXHCTC2SCTable.c new file mode 100644 index 0000000000000000000000000000000000000000..8c5304ae4115c00bd20768b504b9483e36fa4031 --- /dev/null +++ b/Packages/VXHanConvert/Sources/VXHanConvert/VXHCTC2SCTable.c @@ -0,0 +1,651 @@ +/* VXHCTC2SCTable.c: Traditional Chinese -> Simplified Chinese conv. table + * (VX is abbr. for Vanilla OS X, a legacy from OpenVanilla 0.6.x) + * + * Copyright (c) 2004-2007 The OpenVanilla Project (http://openvanilla.org) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OpenVanilla nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The data is derived from Perl's Encode::HanConvert (0.31), + * Copyright (c) 2002-2004 by Autrijus Tang + * + */ + +unsigned short vxTC2SCTable[3059 * 2]={ + 0x2215,0xff0f, 0x2223,0xff5c, 0x2225,0x2016, 0x2266,0x2264, 0x2267,0x2265, + 0x2550,0x3013, 0x255e,0x251d, 0x2561,0x2525, 0x256a,0x253f, 0x2574,0xff3f, + 0x2594,0xffe3, 0x2f02,0x4e36, 0x2f03,0x4e3f, 0x2f07,0x4ea0, 0x2f0c,0x5182, + 0x2f0d,0x5196, 0x2f0e,0x51ab, 0x2f13,0x52f9, 0x2f19,0x5369, 0x2f1b,0x53b6, + 0x2f22,0x5902, 0x2f27,0x5b80, 0x2f2e,0x5ddb, 0x2f33,0x5e7a, 0x2f34,0x5e7f, + 0x2f35,0x5ef4, 0x2f39,0x5f50, 0x2f3a,0x5f61, 0x2f41,0x6534, 0x2f46,0x65e0, + 0x2f67,0x7592, 0x2faa,0x96b6, 0x301e,0xff02, 0x3029,0x6587, 0x3038,0x5341, + 0x3039,0x5344, 0x303a,0x5345, 0x4e1f,0x4e22, 0x4e26,0x5e76, 0x4e82,0x4e71, + 0x4e99,0x4e98, 0x4e9e,0x4e9a, 0x4eb9,0x5a13, 0x4f00,0x5fea, 0x4f15,0x592b, + 0x4f1d,0x4f20, 0x4f47,0x4f2b, 0x4f48,0x5e03, 0x4f54,0x5360, 0x4f6a,0x5f8a, + 0x4f75,0x5e76, 0x4f86,0x6765, 0x4f96,0x4ed1, 0x4fb6,0x4fa3, 0x4fb7,0x5c40, + 0x4fc1,0x4fe3, 0x4fc2,0x7cfb, 0x4fdb,0x4fef, 0x4fe0,0x4fa0, 0x4ff6,0x501c, + 0x5000,0x4f25, 0x5006,0x4fe9, 0x5009,0x4ed3, 0x500b,0x4e2a, 0x5011,0x4eec, + 0x5016,0x5e78, 0x5023,0x4eff, 0x502b,0x4f26, 0x5049,0x4f1f, 0x5061,0x903c, + 0x5062,0x8e3d, 0x506a,0x903c, 0x5074,0x4fa7, 0x5075,0x4fa6, 0x507d,0x4f2a, + 0x5091,0x6770, 0x5092,0x5faf, 0x5096,0x4f27, 0x5098,0x4f1e, 0x5099,0x5907, + 0x509a,0x6548, 0x50a2,0x5bb6, 0x50ad,0x4f63, 0x50af,0x506c, 0x50b3,0x4f20, + 0x50b4,0x4f1b, 0x50b5,0x503a, 0x50b7,0x4f24, 0x50be,0x503e, 0x50c2,0x507b, + 0x50c5,0x4ec5, 0x50c9,0x4f65, 0x50ca,0x4ed9, 0x50d1,0x4fa8, 0x50d5,0x4ec6, + 0x50e3,0x50ed, 0x50e5,0x4fa5, 0x50e8,0x507e, 0x50f1,0x96c7, 0x50f9,0x4ef7, + 0x5100,0x4eea, 0x5102,0x4fac, 0x5104,0x4ebf, 0x5105,0x5f53, 0x5108,0x4fa9, + 0x5109,0x4fed, 0x510c,0x4fa5, 0x5110,0x50a7, 0x5114,0x4fe6, 0x5115,0x4faa, + 0x5118,0x5c3d, 0x511f,0x507f, 0x512a,0x4f18, 0x5132,0x50a8, 0x5133,0x998b, + 0x5137,0x4fea, 0x5138,0x7f57, 0x5139,0x6512, 0x513a,0x50a9, 0x513b,0x50a5, + 0x513c,0x4fe8, 0x5147,0x51f6, 0x514c,0x5151, 0x5152,0x513f, 0x5157,0x5156, + 0x5167,0x5185, 0x5169,0x4e24, 0x5188,0x7f51, 0x518a,0x518c, 0x5191,0x80c4, + 0x51aa,0x5e42, 0x51c8,0x51c0, 0x51cd,0x51bb, 0x51dc,0x51db, 0x51f1,0x51ef, + 0x5225,0x522b, 0x522a,0x5220, 0x5231,0x521b, 0x5244,0x522d, 0x5247,0x5219, + 0x5249,0x9509, 0x524b,0x514b, 0x524e,0x5239, 0x525b,0x521a, 0x525d,0x5265, + 0x526e,0x5250, 0x5274,0x5240, 0x5275,0x521b, 0x5277,0x94f2, 0x5283,0x5212, + 0x5284,0x672d, 0x5287,0x5267, 0x5289,0x5218, 0x528a,0x523d, 0x528b,0x527f, + 0x528c,0x523f, 0x528d,0x5251, 0x5291,0x5242, 0x52c1,0x52b2, 0x52d5,0x52a8, + 0x52d7,0x52d6, 0x52d9,0x52a1, 0x52db,0x52cb, 0x52dd,0x80dc, 0x52de,0x52b3, + 0x52e2,0x52bf, 0x52e3,0x7ee9, 0x52e6,0x527f, 0x52f1,0x52a2, 0x52f3,0x52cb, + 0x52f5,0x52b1, 0x52f8,0x529d, 0x52fb,0x5300, 0x5309,0x7830, 0x530a,0x63ac, + 0x531f,0x7095, 0x532d,0x5326, 0x532f,0x6c47, 0x5331,0x532e, 0x5340,0x533a, + 0x5354,0x534f, 0x5379,0x6064, 0x537b,0x5374, 0x538e,0x7825, 0x5399,0x538d, + 0x53a7,0x5386, 0x53ad,0x538c, 0x53b2,0x5389, 0x53b4,0x53a3, 0x53c3,0x53c2, + 0x53e1,0x777f, 0x53e2,0x4e1b, 0x540b,0x5bf8, 0x542a,0x8bb9, 0x5433,0x5434, + 0x5436,0x5450, 0x5442,0x5415, 0x544e,0x5c3a, 0x5467,0x8bcb, 0x54b7,0x5555, + 0x54bc,0x5459, 0x54e1,0x5458, 0x5504,0x5457, 0x5505,0x542b, 0x551a,0x5423, + 0x5538,0x5ff5, 0x554f,0x95ee, 0x555e,0x54d1, 0x555f,0x542f, 0x5562,0x5521, + 0x5563,0x8854, 0x557f,0x5556, 0x559a,0x5524, 0x55a5,0x54a4, 0x55aa,0x4e27, + 0x55ab,0x5403, 0x55ac,0x4e54, 0x55ae,0x5355, 0x55b2,0x54df, 0x55c6,0x545b, + 0x55c7,0x556c, 0x55ce,0x5417, 0x55da,0x545c, 0x55e9,0x5522, 0x55f6,0x54d4, + 0x5606,0x53f9, 0x560d,0x55bd, 0x5614,0x5455, 0x5616,0x5567, 0x5617,0x5c1d, + 0x561c,0x551b, 0x5629,0x54d7, 0x562e,0x5520, 0x562f,0x5578, 0x5630,0x53fd, + 0x5635,0x54d3, 0x5638,0x5452, 0x5641,0x6076, 0x5649,0x5556, 0x5653,0x5618, + 0x5660,0x54d2, 0x5665,0x54dd, 0x5666,0x54d5, 0x566f,0x55f3, 0x5672,0x54d9, + 0x5674,0x55b7, 0x5678,0x5428, 0x5679,0x5f53, 0x5680,0x549b, 0x5687,0x5413, + 0x568c,0x54dc, 0x5690,0x5c1d, 0x5695,0x565c, 0x5699,0x556e, 0x56a5,0x54bd, + 0x56a6,0x5456, 0x56a8,0x5499, 0x56aa,0x5556, 0x56ac,0x9891, 0x56ae,0x5411, + 0x56b3,0x55be, 0x56b4,0x4e25, 0x56b6,0x5624, 0x56be,0x6b22, 0x56c0,0x556d, + 0x56c1,0x55eb, 0x56c2,0x56a3, 0x56c5,0x5181, 0x56c8,0x5453, 0x56c9,0x7f57, + 0x56cc,0x82cf, 0x56d1,0x5631, 0x56d3,0x556e, 0x56ea,0x56f1, 0x5707,0x56f5, + 0x570b,0x56fd, 0x570c,0x5459, 0x570d,0x56f4, 0x5712,0x56ed, 0x5713,0x5706, + 0x5716,0x56fe, 0x5718,0x56e2, 0x571e,0x683e, 0x5775,0x4e18, 0x5794,0x5819, + 0x57b5,0x57ef, 0x57e1,0x57ad, 0x57f7,0x6267, 0x5801,0x575d, 0x5805,0x575a, + 0x580a,0x57a9, 0x581d,0x57da, 0x582f,0x5c27, 0x5831,0x62a5, 0x5834,0x573a, + 0x583d,0x5188, 0x583f,0x78b1, 0x584a,0x5757, 0x584b,0x8314, 0x584f,0x57b2, + 0x5852,0x57d8, 0x5857,0x6d82, 0x5859,0x786e, 0x585a,0x51a2, 0x5862,0x575e, + 0x5864,0x57d9, 0x586d,0x761f, 0x5874,0x580b, 0x5875,0x5c18, 0x5879,0x5811, + 0x588a,0x57ab, 0x5891,0x5892, 0x589c,0x5760, 0x58ae,0x5815, 0x58b3,0x575f, + 0x58bb,0x5899, 0x58be,0x57a6, 0x58c7,0x575b, 0x58ce,0x57d9, 0x58d3,0x538b, + 0x58d8,0x5792, 0x58d9,0x5739, 0x58da,0x5786, 0x58de,0x574f, 0x58df,0x5784, + 0x58e2,0x575c, 0x58e9,0x575d, 0x58ef,0x58ee, 0x58fa,0x58f6, 0x58fd,0x5bff, + 0x5920,0x591f, 0x5922,0x68a6, 0x593e,0x5939, 0x5950,0x5942, 0x5967,0x5965, + 0x5969,0x5941, 0x596a,0x593a, 0x596e,0x594b, 0x597c,0x59f9, 0x599d,0x5986, + 0x59b3,0x4f60, 0x59cd,0x59d7, 0x59e6,0x5978, 0x59ea,0x4f84, 0x59ee,0x5ae6, + 0x59f7,0x4f91, 0x5a1b,0x5a31, 0x5a37,0x5077, 0x5a41,0x5a04, 0x5a53,0x6deb, + 0x5a5f,0x5a40, 0x5a66,0x5987, 0x5a6d,0x5a05, 0x5aa7,0x5a32, 0x5aaf,0x59ab, + 0x5abc,0x5aaa, 0x5abd,0x5988, 0x5abf,0x6127, 0x5acb,0x8885, 0x5ad7,0x59aa, + 0x5af5,0x59a9, 0x5afa,0x5a34, 0x5afb,0x5a34, 0x5b08,0x5a06, 0x5b0b,0x5a75, + 0x5b0c,0x5a07, 0x5b19,0x5af1, 0x5b1d,0x8885, 0x5b21,0x5ad2, 0x5b24,0x5b37, + 0x5b2a,0x5ad4, 0x5b2d,0x5976, 0x5b30,0x5a74, 0x5b38,0x5a76, 0x5b3d,0x61d2, + 0x5b43,0x5a18, 0x5b4c,0x5a08, 0x5b6b,0x5b59, 0x5b77,0x6635, 0x5b78,0x5b66, + 0x5b7f,0x5b6a, 0x5bae,0x5bab, 0x5bca,0x5bdd, 0x5bd1,0x5b9e, 0x5bd6,0x6d78, + 0x5bd8,0x7f6e, 0x5be2,0x5bdd, 0x5be6,0x5b9e, 0x5be7,0x5b81, 0x5be9,0x5ba1, + 0x5beb,0x5199, 0x5bec,0x5bbd, 0x5bf1,0x5453, 0x5bf5,0x5ba0, 0x5bf6,0x5b9d, + 0x5c07,0x5c06, 0x5c08,0x4e13, 0x5c0b,0x5bfb, 0x5c0d,0x5bf9, 0x5c0e,0x5bfc, + 0x5c12,0x5c14, 0x5c1f,0x9c9c, 0x5c37,0x5c34, 0x5c46,0x5c4a, 0x5c4d,0x5c38, + 0x5c5c,0x5c49, 0x5c62,0x5c61, 0x5c64,0x5c42, 0x5c68,0x5c66, 0x5c6c,0x5c5e, + 0x5c8a,0x5c9c, 0x5ca1,0x5188, 0x5ca5,0x5761, 0x5cf4,0x5c98, 0x5cf6,0x5c9b, + 0x5cfd,0x5ce1, 0x5d0d,0x5d03, 0x5d11,0x6606, 0x5d17,0x5c97, 0x5d19,0x4ed1, + 0x5d1a,0x5ce5, 0x5d20,0x5cbd, 0x5d22,0x5ce5, 0x5d30,0x5cb7, 0x5d33,0x5d5b, + 0x5d50,0x5c9a, 0x5d51,0x7800, 0x5d55,0x9685, 0x5d68,0x575e, 0x5d7e,0x53c2, + 0x5d81,0x5d5d, 0x5d84,0x5d2d, 0x5d87,0x5c96, 0x5d94,0x5d5a, 0x5d97,0x5d02, + 0x5da0,0x5ce4, 0x5da7,0x5cc4, 0x5da8,0x5c99, 0x5dae,0x9669, 0x5db4,0x5c99, + 0x5db8,0x5d58, 0x5dba,0x5cad, 0x5dbc,0x5c7f, 0x5dbd,0x5cb3, 0x5dcb,0x5cbf, + 0x5dd2,0x5ce6, 0x5dd4,0x5dc5, 0x5dd6,0x5ca9, 0x5df0,0x5def, 0x5df9,0x537a, + 0x5e25,0x5e05, 0x5e2b,0x5e08, 0x5e33,0x5e10, 0x5e36,0x5e26, 0x5e40,0x5e27, + 0x5e43,0x5e0f, 0x5e4e,0x5e42, 0x5e57,0x5e3c, 0x5e58,0x5e3b, 0x5e59,0x5e55, + 0x5e5f,0x5e1c, 0x5e63,0x5e01, 0x5e6b,0x5e2e, 0x5e6c,0x5e31, 0x5e79,0x5e72, + 0x5e7e,0x51e0, 0x5eab,0x5e93, 0x5ec1,0x5395, 0x5ec2,0x53a2, 0x5ec4,0x53a9, + 0x5ec8,0x53a6, 0x5ed5,0x836b, 0x5eda,0x53a8, 0x5edd,0x53ae, 0x5edf,0x5e99, + 0x5ee0,0x5382, 0x5ee1,0x5e91, 0x5ee2,0x5e9f, 0x5ee3,0x5e7f, 0x5ee9,0x5eea, + 0x5eec,0x5e90, 0x5ef3,0x5385, 0x5f12,0x5f11, 0x5f14,0x540a, 0x5f33,0x5f2a, + 0x5f35,0x5f20, 0x5f37,0x5f3a, 0x5f46,0x522b, 0x5f48,0x5f39, 0x5f4a,0x5f3a, + 0x5f4c,0x5f25, 0x5f4e,0x5f2f, 0x5f54,0x5f55, 0x5f59,0x6c47, 0x5f5e,0x5f5d, + 0x5f65,0x5f66, 0x5f6b,0x96d5, 0x5f7e,0x4f36, 0x5f7f,0x4f5b, 0x5f8c,0x540e, + 0x5f91,0x5f84, 0x5f9e,0x4ece, 0x5fa0,0x5f95, 0x5fa9,0x590d, 0x5fac,0x65c1, + 0x5fb9,0x5f7b, 0x5fe3,0x6025, 0x600c,0x6000, 0x6033,0x604d, 0x6046,0x6052, + 0x6049,0x65e8, 0x6065,0x803b, 0x6085,0x60a6, 0x6090,0x54f2, 0x60b5,0x6005, + 0x60b6,0x95f7, 0x60bd,0x51c4, 0x60bf,0x60ca, 0x60c7,0x6566, 0x60c8,0x60dd, + 0x60e1,0x6076, 0x60e4,0x5a6a, 0x60f1,0x607c, 0x60f2,0x607d, 0x60f7,0x8822, + 0x60fb,0x607b, 0x60fc,0x51ff, 0x6105,0x5ff1, 0x611b,0x7231, 0x611c,0x60ec, + 0x6128,0x60ab, 0x612c,0x8bc9, 0x6134,0x6006, 0x6137,0x607a, 0x613e,0x5ffe, + 0x6144,0x6817, 0x6147,0x6bb7, 0x614b,0x6001, 0x614d,0x6120, 0x6158,0x60e8, + 0x615a,0x60ed, 0x615f,0x6078, 0x6163,0x60ef, 0x616a,0x6004, 0x616b,0x6002, + 0x616e,0x8651, 0x6173,0x60ad, 0x6174,0x6151, 0x6176,0x5e86, 0x6179,0x7857, + 0x617c,0x621a, 0x617e,0x6b32, 0x6182,0x5fe7, 0x6183,0x6a3d, 0x618a,0x60eb, + 0x6190,0x601c, 0x6191,0x51ed, 0x6192,0x6126, 0x6193,0x60e0, 0x619a,0x60ee, + 0x61a4,0x6124, 0x61ab,0x60af, 0x61ad,0x6a3d, 0x61ae,0x6003, 0x61b2,0x5baa, + 0x61b6,0x5fc6, 0x61c3,0x52e4, 0x61c7,0x6073, 0x61c9,0x5e94, 0x61cc,0x603f, + 0x61cd,0x61d4, 0x61de,0x8499, 0x61df,0x603c, 0x61e3,0x61d1, 0x61e8,0x6079, + 0x61e9,0x75d2, 0x61f2,0x60e9, 0x61f6,0x61d2, 0x61f7,0x6000, 0x61f8,0x60ac, + 0x61fa,0x5fcf, 0x61fc,0x60e7, 0x61fd,0x6b22, 0x61fe,0x6151, 0x6200,0x604b, + 0x6207,0x6206, 0x6209,0x94ba, 0x6214,0x620b, 0x6227,0x6217, 0x6229,0x622c, + 0x6230,0x6218, 0x6232,0x620f, 0x6236,0x6237, 0x625e,0x634d, 0x6260,0x53c9, + 0x6261,0x62d6, 0x6283,0x62da, 0x62ad,0x8200, 0x62b4,0x62fd, 0x62cb,0x629b, + 0x62d1,0x94b3, 0x632c,0x62d4, 0x633c,0x632a, 0x633e,0x631f, 0x6344,0x6551, + 0x6368,0x820d, 0x636b,0x626a, 0x6372,0x5377, 0x6383,0x626b, 0x6384,0x62a1, + 0x6399,0x6323, 0x639b,0x6302, 0x639c,0x62bb, 0x639e,0x78b0, 0x63a1,0x91c7, + 0x63a4,0x632a, 0x63af,0x636e, 0x63c0,0x62e3, 0x63da,0x626c, 0x63db,0x6362, + 0x63eb,0x63ea, 0x63ee,0x6325, 0x63f0,0x8f70, 0x63f9,0x80cc, 0x6406,0x6784, + 0x640a,0x638f, 0x640d,0x635f, 0x6412,0x699c, 0x6416,0x6447, 0x6417,0x6363, + 0x6424,0x627c, 0x6425,0x6376, 0x6427,0x6247, 0x6428,0x62d3, 0x642b,0x642c, + 0x6436,0x62a2, 0x6439,0x627c, 0x643e,0x69a8, 0x6440,0x6342, 0x6443,0x625b, + 0x6451,0x63b4, 0x645c,0x63bc, 0x645f,0x6402, 0x646f,0x631a, 0x6473,0x62a0, + 0x6476,0x629f, 0x647b,0x63ba, 0x6488,0x635e, 0x6490,0x6491, 0x6493,0x6320, + 0x6498,0x642d, 0x649a,0x637b, 0x649f,0x6322, 0x64a2,0x63b8, 0x64a3,0x63b8, + 0x64a5,0x62e8, 0x64a6,0x626f, 0x64ab,0x629a, 0x64b2,0x6251, 0x64b3,0x63ff, + 0x64bb,0x631e, 0x64be,0x631d, 0x64bf,0x6361, 0x64c1,0x62e5, 0x64c4,0x63b3, + 0x64c7,0x62e9, 0x64ca,0x51fb, 0x64cb,0x6321, 0x64cf,0x64ce, 0x64d4,0x62c5, + 0x64da,0x636e, 0x64e0,0x6324, 0x64e9,0x6363, 0x64ec,0x62df, 0x64ef,0x6448, + 0x64f0,0x62e7, 0x64f1,0x6401, 0x64f2,0x63b7, 0x64f4,0x6269, 0x64f7,0x64b7, + 0x64fa,0x6446, 0x64fb,0x64de, 0x64fc,0x64b8, 0x64fe,0x6270, 0x64ff,0x63b7, + 0x6504,0x6445, 0x6506,0x64b5, 0x650f,0x62e2, 0x6513,0x6434, 0x6514,0x62e6, + 0x6516,0x6484, 0x6517,0x6343, 0x6519,0x6400, 0x651b,0x64ba, 0x651c,0x643a, + 0x651d,0x6444, 0x6522,0x6512, 0x6523,0x631b, 0x6524,0x644a, 0x6529,0x6321, + 0x652a,0x6405, 0x652c,0x63fd, 0x6537,0x8003, 0x6557,0x8d25, 0x6558,0x53d9, + 0x6575,0x654c, 0x6576,0x9635, 0x6578,0x6570, 0x657a,0x9a71, 0x6582,0x655b, + 0x6583,0x6bd9, 0x6592,0x6591, 0x6595,0x6593, 0x65ac,0x65a9, 0x65b2,0x65ab, + 0x65b7,0x65ad, 0x65bc,0x4e8e, 0x65c2,0x65d7, 0x65e1,0x65e0, 0x6607,0x5347, + 0x662b,0x7166, 0x663a,0x70b3, 0x6642,0x65f6, 0x6649,0x664b, 0x665d,0x663c, + 0x6665,0x7696, 0x6688,0x6655, 0x6689,0x6656, 0x6698,0x65f8, 0x66a2,0x7545, + 0x66ab,0x6682, 0x66b1,0x6635, 0x66c4,0x6654, 0x66c6,0x5386, 0x66c7,0x6619, + 0x66c9,0x6653, 0x66cf,0x5411, 0x66d6,0x66a7, 0x66e0,0x65f7, 0x66ec,0x6652, + 0x66f8,0x4e66, 0x6703,0x4f1a, 0x6722,0x671b, 0x6727,0x80e7, 0x672e,0x672f, + 0x6747,0x572c, 0x6771,0x4e1c, 0x6774,0x9528, 0x6792,0x4e2b, 0x679f,0x6a80, + 0x67b4,0x62d0, 0x67df,0x6960, 0x67f5,0x6805, 0x6814,0x5951, 0x687f,0x6746, + 0x6887,0x6994, 0x6894,0x6800, 0x689d,0x6761, 0x689f,0x67ad, 0x68b1,0x6346, + 0x68c4,0x5f03, 0x68d6,0x67a8, 0x68d7,0x67a3, 0x68df,0x680b, 0x68e7,0x6808, + 0x68f2,0x6816, 0x690f,0x6860, 0x6917,0x7887, 0x6937,0x7f04, 0x694a,0x6768, + 0x6953,0x67ab, 0x6965,0x6966, 0x6968,0x6862, 0x696d,0x4e1a, 0x6975,0x6781, + 0x69a6,0x5e72, 0x69aa,0x6769, 0x69ae,0x8363, 0x69bf,0x6864, 0x69c3,0x76d8, + 0x69cb,0x6784, 0x69cd,0x67aa, 0x69d3,0x6760, 0x69e7,0x6920, 0x69e8,0x6901, + 0x69f3,0x6868, 0x69fc,0x89c4, 0x69fe,0x5881, 0x6a01,0x6869, 0x6a02,0x4e50, + 0x6a05,0x679e, 0x6a11,0x6881, 0x6a13,0x697c, 0x6a19,0x6807, 0x6a1e,0x67a2, + 0x6a23,0x6837, 0x6a38,0x6734, 0x6a39,0x6811, 0x6a3a,0x6866, 0x6a46,0x65e0, + 0x6a48,0x6861, 0x6a4b,0x6865, 0x6a55,0x6491, 0x6a5f,0x673a, 0x6a62,0x692d, + 0x6a64,0x854a, 0x6a6b,0x6a2a, 0x6a7e,0x78b0, 0x6a81,0x6aa9, 0x6a89,0x67fd, + 0x6a94,0x6863, 0x6a9c,0x6867, 0x6aa2,0x68c0, 0x6aa3,0x6a2f, 0x6aa5,0x8223, + 0x6aae,0x68bc, 0x6aaf,0x53f0, 0x6ab3,0x69df, 0x6ab8,0x67e0, 0x6abb,0x69db, + 0x6ac2,0x68f9, 0x6ac3,0x67dc, 0x6ad3,0x6a79, 0x6ada,0x6988, 0x6adb,0x6809, + 0x6add,0x691f, 0x6ade,0x6a7c, 0x6adf,0x680e, 0x6ae5,0x6a71, 0x6ae7,0x69e0, + 0x6ae8,0x680c, 0x6aea,0x67a5, 0x6aeb,0x6a65, 0x6aec,0x6987, 0x6af0,0x69d0, + 0x6af3,0x680a, 0x6af8,0x6989, 0x6afa,0x68c2, 0x6afb,0x6a31, 0x6b04,0x680f, + 0x6b0a,0x6743, 0x6b0b,0x68f9, 0x6b0f,0x6924, 0x6b11,0x6512, 0x6b12,0x683e, + 0x6b16,0x6984, 0x6b1e,0x68c2, 0x6b2c,0x54b3, 0x6b3d,0x94a6, 0x6b4e,0x53f9, + 0x6b50,0x6b27, 0x6b5b,0x655b, 0x6b5f,0x6b24, 0x6b61,0x6b22, 0x6b72,0x5c81, + 0x6b77,0x5386, 0x6b78,0x5f52, 0x6b7e,0x6b81, 0x6b7f,0x6b81, 0x6b80,0x592d, + 0x6b98,0x6b8b, 0x6b9e,0x6b92, 0x6ba4,0x6b87, 0x6bab,0x6b9a, 0x6bad,0x50f5, + 0x6bae,0x6b93, 0x6baf,0x6ba1, 0x6bb2,0x6b7c, 0x6bba,0x6740, 0x6bbc,0x58f3, + 0x6bbd,0x6dc6, 0x6bc0,0x6bc1, 0x6bc6,0x6bb4, 0x6bc9,0x533b, 0x6bd8,0x6bd7, + 0x6bde,0x7eb0, 0x6be0,0x8888, 0x6be7,0x7ed2, 0x6bec,0x7403, 0x6bff,0x6bf5, + 0x6c08,0x6be1, 0x6c0c,0x6c07, 0x6c23,0x6c14, 0x6c2b,0x6c22, 0x6c2c,0x6c29, + 0x6c33,0x6c32, 0x6c3e,0x6cdb, 0x6c4e,0x6cdb, 0x6c59,0x6c61, 0x6c7a,0x51b3, + 0x6c7b,0x6d52, 0x6c8d,0x51b1, 0x6c92,0x6ca1, 0x6c96,0x51b2, 0x6cb4,0x6eaf, + 0x6cc1,0x51b5, 0x6d29,0x6cc4, 0x6d36,0x6c79, 0x6d6c,0x91cc, 0x6d79,0x6d43, + 0x6d87,0x6cfe, 0x6db7,0x6d2b, 0x6dbc,0x51c9, 0x6dbd,0x6df9, 0x6dcf,0x6491, + 0x6dd2,0x51c4, 0x6dda,0x6cea, 0x6de5,0x6e0c, 0x6de8,0x51c0, 0x6dea,0x6ca6, + 0x6df5,0x6e0a, 0x6df6,0x6d9e, 0x6dfa,0x6d45, 0x6e19,0x6da3, 0x6e1b,0x51cf, + 0x6e26,0x6da1, 0x6e2c,0x6d4b, 0x6e2e,0x83cf, 0x6e3e,0x6d51, 0x6e4a,0x51d1, + 0x6e5e,0x6d48, 0x6e63,0x6cef, 0x6e67,0x6d8c, 0x6e6f,0x6c64, 0x6e88,0x6ca9, + 0x6e96,0x51c6, 0x6e9d,0x6c9f, 0x6eab,0x6e29, 0x6eb0,0x7691, 0x6eb9,0x6eaf, + 0x6ebc,0x6e7f, 0x6ec4,0x6ca7, 0x6ec5,0x706d, 0x6ecc,0x6da4, 0x6ece,0x8365, + 0x6eec,0x6caa, 0x6eef,0x6ede, 0x6ef2,0x6e17, 0x6ef7,0x5364, 0x6ef8,0x6d52, + 0x6efe,0x6eda, 0x6eff,0x6ee1, 0x6f01,0x6e14, 0x6f1a,0x6ca4, 0x6f22,0x6c49, + 0x6f23,0x6d9f, 0x6f27,0x5e72, 0x6f2c,0x6e0d, 0x6f32,0x6da8, 0x6f35,0x6e86, + 0x6f38,0x6e10, 0x6f3f,0x6d46, 0x6f41,0x988d, 0x6f51,0x6cfc, 0x6f54,0x6d01, + 0x6f5a,0x6f47, 0x6f5b,0x6f5c, 0x6f5f,0x8204, 0x6f64,0x6da6, 0x6f6c,0x6ee9, + 0x6f6f,0x6d54, 0x6f70,0x6e83, 0x6f77,0x6ed7, 0x6f7f,0x6da0, 0x6f80,0x6da9, + 0x6f82,0x6f84, 0x6f86,0x6d47, 0x6f87,0x6d9d, 0x6f94,0x6d69, 0x6f97,0x6da7, + 0x6fa0,0x6e11, 0x6fa3,0x6d63, 0x6fa4,0x6cfd, 0x6fa6,0x6eea, 0x6fa9,0x6cf6, + 0x6fab,0x85d5, 0x6fae,0x6d4d, 0x6fb1,0x6dc0, 0x6fc1,0x6d4a, 0x6fc3,0x6d53, + 0x6fc7,0x6da9, 0x6fca,0x8c41, 0x6fd4,0x5f25, 0x6fd5,0x6e7f, 0x6fd8,0x6cde, + 0x6fdb,0x8499, 0x6fdf,0x6d4e, 0x6fe4,0x6d9b, 0x6feb,0x6ee5, 0x6fec,0x6d5a, + 0x6ff0,0x6f4d, 0x6ff1,0x6ee8, 0x6ffa,0x6e85, 0x6ffc,0x6cfa, 0x6ffe,0x6ee4, + 0x7005,0x6ee2, 0x7006,0x6e0e, 0x7009,0x6cfb, 0x700b,0x6e16, 0x700f,0x6d4f, + 0x7015,0x6fd2, 0x7018,0x6cf8, 0x701d,0x6ca5, 0x701f,0x6f47, 0x7020,0x6f46, + 0x7026,0x6f74, 0x7027,0x6cf7, 0x7028,0x6fd1, 0x7030,0x5f25, 0x7032,0x6f4b, + 0x703e,0x6f9c, 0x7043,0x6ca3, 0x7044,0x6ee0, 0x7051,0x6d12, 0x7055,0x6f13, + 0x7058,0x6ee9, 0x705d,0x704f, 0x7060,0x6f24, 0x7063,0x6e7e, 0x7064,0x6ee6, + 0x7068,0x8d63, 0x7069,0x6edf, 0x707d,0x707e, 0x70a4,0x7167, 0x70ba,0x4e3a, + 0x70cf,0x4e4c, 0x70f4,0x70c3, 0x7121,0x65e0, 0x7123,0x7092, 0x7146,0x867e, + 0x7147,0x8f89, 0x7149,0x70bc, 0x7152,0x709c, 0x7156,0x6696, 0x7159,0x70df, + 0x7162,0x8315, 0x7165,0x7115, 0x7169,0x70e6, 0x716c,0x7080, 0x7192,0x8367, + 0x7197,0x709d, 0x71b1,0x70ed, 0x71be,0x70bd, 0x71bf,0x714c, 0x71c1,0x70e8, + 0x71c4,0x7130, 0x71c8,0x706f, 0x71c9,0x7096, 0x71d0,0x78f7, 0x71d2,0x70e7, + 0x71d9,0x70eb, 0x71dc,0x7116, 0x71df,0x8425, 0x71e6,0x707f, 0x71ec,0x6bc1, + 0x71ed,0x70db, 0x71f4,0x70e9, 0x71fb,0x718f, 0x71fc,0x70ec, 0x71fe,0x7118, + 0x71ff,0x8000, 0x720d,0x70c1, 0x7210,0x7089, 0x7213,0x7130, 0x721b,0x70c2, + 0x721f,0x6b22, 0x722d,0x4e89, 0x723a,0x7237, 0x723e,0x5c14, 0x7246,0x5899, + 0x724b,0x7b3a, 0x7253,0x699c, 0x7258,0x724d, 0x7260,0x5b83, 0x7274,0x62b5, + 0x727d,0x7275, 0x7296,0x8366, 0x729b,0x7266, 0x72a2,0x728a, 0x72a5,0x71ac, + 0x72a7,0x727a, 0x72c0,0x72b6, 0x72cc,0x7329, 0x72f9,0x72ed, 0x72fd,0x72c8, + 0x730b,0x98d9, 0x7319,0x72f0, 0x7336,0x72b9, 0x733b,0x72f2, 0x7343,0x5446, + 0x7344,0x72f1, 0x7345,0x72ee, 0x7349,0x699b, 0x734e,0x5956, 0x7358,0x6bd9, + 0x7367,0x72f7, 0x7368,0x72ec, 0x736a,0x72ef, 0x736b,0x7303, 0x7370,0x72de, + 0x7372,0x83b7, 0x7375,0x730e, 0x7377,0x72b7, 0x7378,0x517d, 0x737a,0x736d, + 0x737b,0x732e, 0x737c,0x7315, 0x7380,0x7321, 0x7381,0x7303, 0x7383,0x883c, + 0x7385,0x5999, 0x7386,0x5179, 0x7394,0x948f, 0x73a1,0x740a, 0x73a8,0x73cf, + 0x73ea,0x572d, 0x73ee,0x4f69, 0x73fd,0x7487, 0x73fe,0x73b0, 0x740d,0x7483, + 0x7416,0x76cf, 0x7431,0x96d5, 0x743a,0x73d0, 0x743f,0x73f2, 0x744b,0x73ae, + 0x7463,0x7410, 0x7464,0x7476, 0x7469,0x83b9, 0x746a,0x739b, 0x746f,0x7405, + 0x7485,0x7410, 0x7486,0x7403, 0x7489,0x740f, 0x749a,0x743c, 0x74a3,0x7391, + 0x74a6,0x7477, 0x74b0,0x73af, 0x74bd,0x73ba, 0x74bf,0x7487, 0x74ca,0x743c, + 0x74cf,0x73d1, 0x74d4,0x748e, 0x74d5,0x5f25, 0x74da,0x74d2, 0x750c,0x74ef, + 0x7515,0x74ee, 0x7516,0x7f42, 0x7522,0x4ea7, 0x7526,0x82cf, 0x753f,0x6c13, + 0x755d,0x4ea9, 0x7562,0x6bd5, 0x756b,0x753b, 0x756c,0x7572, 0x7570,0x5f02, + 0x7576,0x5f53, 0x757d,0x7583, 0x7587,0x7574, 0x758a,0x53e0, 0x7598,0x809b, + 0x75bf,0x75f1, 0x75ce,0x7b54, 0x75cf,0x75d2, 0x75d1,0x606b, 0x75d9,0x75c9, + 0x75e0,0x9178, 0x75f2,0x9ebb, 0x75f3,0x9ebb, 0x75fa,0x75f9, 0x75fe,0x75b4, + 0x7609,0x6108, 0x760b,0x75af, 0x760d,0x75a1, 0x7613,0x75ea, 0x7616,0x5591, + 0x761e,0x7617, 0x7621,0x75ae, 0x7627,0x759f, 0x7628,0x766b, 0x763a,0x7618, + 0x7642,0x7597, 0x7646,0x75e8, 0x7647,0x75eb, 0x7648,0x5e9f, 0x7649,0x7605, + 0x7652,0x6108, 0x7658,0x75a0, 0x765f,0x762a, 0x7661,0x75f4, 0x7662,0x75d2, + 0x7664,0x7596, 0x7665,0x75c7, 0x7669,0x765e, 0x766c,0x7663, 0x766d,0x763f, + 0x766e,0x763e, 0x7670,0x75c8, 0x7671,0x762b, 0x7672,0x766b, 0x767c,0x53d1, + 0x7681,0x7682, 0x768f,0x86d4, 0x769a,0x7691, 0x769b,0x777d, 0x769c,0x98a2, + 0x76b0,0x75b1, 0x76b8,0x76b2, 0x76ba,0x76b1, 0x76bb,0x9f44, 0x76c3,0x676f, + 0x76dc,0x76d7, 0x76de,0x76cf, 0x76e1,0x5c3d, 0x76e3,0x76d1, 0x76e4,0x76d8, + 0x76e7,0x5362, 0x76ea,0x8361, 0x7725,0x7726, 0x773b,0x4ec5, 0x773e,0x4f17, + 0x7744,0x77a7, 0x774f,0x56f0, 0x775c,0x7741, 0x775e,0x7750, 0x7760,0x7737, + 0x776a,0x777e, 0x7787,0x772f, 0x779e,0x7792, 0x77ad,0x4e86, 0x77bc,0x7751, + 0x77c7,0x8499, 0x77c9,0x9891, 0x77d3,0x80e7, 0x77d9,0x77b0, 0x77da,0x77a9, + 0x77ef,0x77eb, 0x7832,0x70ae, 0x7843,0x6731, 0x7864,0x7856, 0x7868,0x7817, + 0x786f,0x781a, 0x78a2,0x7823, 0x78a9,0x7855, 0x78aa,0x7827, 0x78ad,0x7800, + 0x78ba,0x786e, 0x78bb,0x786e, 0x78bc,0x7801, 0x78da,0x7816, 0x78df,0x788c, + 0x78e3,0x789c, 0x78e5,0x78ca, 0x78e7,0x789b, 0x78ef,0x77f6, 0x78fd,0x7857, + 0x790c,0x78ca, 0x790e,0x7840, 0x7914,0x9739, 0x7919,0x788d, 0x7921,0x7934, + 0x7926,0x77ff, 0x7927,0x78ca, 0x792a,0x783a, 0x792b,0x783e, 0x792c,0x77fe, + 0x7931,0x783b, 0x7945,0x8884, 0x7950,0x4f51, 0x7955,0x79d8, 0x7961,0x5939, + 0x797f,0x7984, 0x798d,0x7978, 0x798e,0x796f, 0x79a6,0x5fa1, 0x79aa,0x7985, + 0x79ae,0x793c, 0x79b0,0x7962, 0x79b1,0x7977, 0x79bf,0x79c3, 0x79c8,0x7c7c, + 0x79d6,0x53ea, 0x79fa,0x79bb, 0x7a05,0x7a0e, 0x7a08,0x79c6, 0x7a1c,0x68f1, + 0x7a1f,0x7980, 0x7a2e,0x79cd, 0x7a31,0x79f0, 0x7a40,0x8c37, 0x7a4c,0x7a23, + 0x7a4d,0x79ef, 0x7a4e,0x9896, 0x7a60,0x79fe, 0x7a61,0x7a51, 0x7a62,0x79fd, + 0x7a68,0x9893, 0x7a69,0x7a33, 0x7a6b,0x83b7, 0x7a6d,0x7a06, 0x7a75,0x6316, + 0x7a9e,0x51fc, 0x7aa9,0x7a9d, 0x7aaa,0x6d3c, 0x7aae,0x7a77, 0x7aaf,0x7a91, + 0x7ab4,0x586b, 0x7ab6,0x7aad, 0x7aba,0x7aa5, 0x7ac4,0x7a9c, 0x7ac5,0x7a8d, + 0x7ac7,0x7aa6, 0x7aca,0x7a83, 0x7af6,0x7ade, 0x7b46,0x7b14, 0x7b4d,0x7b0b, + 0x7b66,0x7ba1, 0x7b67,0x7b15, 0x7b69,0x7b52, 0x7b6d,0x7b97, 0x7b74,0x5395, + 0x7b87,0x4e2a, 0x7b8b,0x7b3a, 0x7b8e,0x7bea, 0x7b8f,0x7b5d, 0x7ba0,0x68f0, + 0x7bc0,0x8282, 0x7bc4,0x8303, 0x7bc9,0x7b51, 0x7bcb,0x7ba7, 0x7bdb,0x7bac, + 0x7be0,0x7b71, 0x7be4,0x7b03, 0x7be9,0x7b5b, 0x7bf3,0x7b5a, 0x7c00,0x7ba6, + 0x7c0d,0x7bd3, 0x7c11,0x84d1, 0x7c1e,0x7baa, 0x7c21,0x7b80, 0x7c23,0x7bd1, + 0x7c2b,0x7bab, 0x7c30,0x7b85, 0x7c37,0x6a90, 0x7c3d,0x7b7e, 0x7c3e,0x5e18, + 0x7c43,0x7bee, 0x7c49,0x7b1e, 0x7c4c,0x7b79, 0x7c50,0x85e4, 0x7c5c,0x7ba8, + 0x7c5f,0x7c41, 0x7c60,0x7b3c, 0x7c64,0x7b7e, 0x7c65,0x9fa0, 0x7c69,0x7b3e, + 0x7c6a,0x7c16, 0x7c6c,0x7bf1, 0x7c6e,0x7ba9, 0x7c72,0x5401, 0x7c79,0x5986, + 0x7ca7,0x5986, 0x7cb5,0x7ca4, 0x7cba,0x7a17, 0x7cdd,0x7cc1, 0x7cde,0x7caa, + 0x7ce2,0x6a21, 0x7ce7,0x7cae, 0x7cf0,0x56e2, 0x7cf2,0x7c9d, 0x7cf4,0x7c74, + 0x7cf6,0x7c9c, 0x7cfe,0x7ea0, 0x7d00,0x7eaa, 0x7d02,0x7ea3, 0x7d04,0x7ea6, + 0x7d05,0x7ea2, 0x7d06,0x7ea1, 0x7d07,0x7ea5, 0x7d08,0x7ea8, 0x7d09,0x7eab, + 0x7d0b,0x7eb9, 0x7d0d,0x7eb3, 0x7d10,0x7ebd, 0x7d13,0x7ebe, 0x7d14,0x7eaf, + 0x7d15,0x7eb0, 0x7d17,0x7eb1, 0x7d19,0x7eb8, 0x7d1a,0x7ea7, 0x7d1b,0x7eb7, + 0x7d1c,0x7ead, 0x7d21,0x7eba, 0x7d29,0x7ef8, 0x7d2e,0x624e, 0x7d30,0x7ec6, + 0x7d31,0x7ec2, 0x7d32,0x7ec1, 0x7d33,0x7ec5, 0x7d39,0x7ecd, 0x7d3a,0x7ec0, + 0x7d3c,0x7ecb, 0x7d3f,0x7ed0, 0x7d40,0x7ecc, 0x7d42,0x7ec8, 0x7d43,0x5f26, + 0x7d44,0x7ec4, 0x7d46,0x7eca, 0x7d4e,0x7ed7, 0x7d4f,0x7ec1, 0x7d50,0x7ed3, + 0x7d55,0x7edd, 0x7d56,0x7ea9, 0x7d5b,0x7ee6, 0x7d5c,0x6d01, 0x7d5e,0x7ede, + 0x7d61,0x7edc, 0x7d62,0x7eda, 0x7d66,0x7ed9, 0x7d68,0x7ed2, 0x7d70,0x7ed6, + 0x7d71,0x7edf, 0x7d72,0x4e1d, 0x7d73,0x7edb, 0x7d79,0x7ee2, 0x7d81,0x7ed1, + 0x7d83,0x7ee1, 0x7d86,0x7ee0, 0x7d88,0x7ee8, 0x7d8d,0x7ecb, 0x7d8f,0x7ee5, + 0x7d91,0x56f0, 0x7d93,0x7ecf, 0x7d9c,0x7efc, 0x7d9e,0x7f0d, 0x7da0,0x7eff, + 0x7da2,0x7ef8, 0x7da3,0x7efb, 0x7dac,0x7ef6, 0x7dad,0x7ef4, 0x7db0,0x7efe, + 0x7db1,0x7eb2, 0x7db2,0x7f51, 0x7db4,0x7f00, 0x7db5,0x5f69, 0x7db8,0x7eb6, + 0x7db9,0x7efa, 0x7dba,0x7eee, 0x7dbb,0x7efd, 0x7dbd,0x7ef0, 0x7dbe,0x7eeb, + 0x7dbf,0x7ef5, 0x7dc4,0x7ef2, 0x7dc7,0x7f01, 0x7dca,0x7d27, 0x7dcb,0x7eef, + 0x7dd2,0x7eea, 0x7dd7,0x7f03, 0x7dd8,0x7f04, 0x7dd9,0x7f02, 0x7dda,0x7ebf, + 0x7ddd,0x7f09, 0x7dde,0x7f0e, 0x7de0,0x7f14, 0x7de1,0x7f17, 0x7de3,0x7f18, + 0x7de6,0x7f0c, 0x7de8,0x7f16, 0x7de9,0x7f13, 0x7dec,0x7f05, 0x7def,0x7eac, + 0x7df1,0x7f11, 0x7df2,0x7f08, 0x7df4,0x7ec3, 0x7df6,0x7f0f, 0x7df9,0x7f07, + 0x7dfb,0x81f4, 0x7e08,0x8426, 0x7e09,0x7f19, 0x7e0a,0x7f22, 0x7e0b,0x7f12, + 0x7e10,0x7ec9, 0x7e11,0x7f23, 0x7e1a,0x7ee6, 0x7e1b,0x7f1a, 0x7e1d,0x7f1c, + 0x7e1e,0x7f1f, 0x7e1f,0x7f1b, 0x7e23,0x53bf, 0x7e2b,0x7f1d, 0x7e2d,0x7f21, + 0x7e2e,0x7f29, 0x7e2f,0x6f14, 0x7e31,0x7eb5, 0x7e32,0x7f27, 0x7e34,0x7ea4, + 0x7e35,0x7f26, 0x7e36,0x7d77, 0x7e37,0x7f15, 0x7e39,0x7f25, 0x7e3d,0x603b, + 0x7e3e,0x7ee9, 0x7e43,0x7ef7, 0x7e45,0x7f2b, 0x7e46,0x7f2a, 0x7e48,0x8941, + 0x7e52,0x7f2f, 0x7e54,0x7ec7, 0x7e55,0x7f2e, 0x7e56,0x4f1e, 0x7e59,0x7ffb, + 0x7e5a,0x7f2d, 0x7e5e,0x7ed5, 0x7e61,0x7ee3, 0x7e62,0x7f0b, 0x7e69,0x7ef3, + 0x7e6a,0x7ed8, 0x7e6b,0x7cfb, 0x7e6d,0x8327, 0x7e6f,0x7f33, 0x7e70,0x7f32, + 0x7e73,0x7f34, 0x7e79,0x7ece, 0x7e7c,0x7ee7, 0x7e7d,0x7f24, 0x7e7e,0x7f31, + 0x7e88,0x7f2c, 0x7e8a,0x7ea9, 0x7e8c,0x7eed, 0x7e8d,0x7d2f, 0x7e8f,0x7f20, + 0x7e93,0x7f28, 0x7e94,0x624d, 0x7e96,0x7ea4, 0x7e98,0x7f35, 0x7e9c,0x7f06, + 0x7f3d,0x94b5, 0x7f3e,0x74f6, 0x7f48,0x575b, 0x7f4b,0x74ee, 0x7f4c,0x7f42, + 0x7f4f,0x5786, 0x7f70,0x7f5a, 0x7f75,0x9a82, 0x7f77,0x7f62, 0x7f7c,0x6bd5, + 0x7f83,0x5e42, 0x7f85,0x7f57, 0x7f86,0x7f74, 0x7f88,0x7f81, 0x7f8b,0x8288, + 0x7f91,0x8bf1, 0x7f95,0x6302, 0x7fa2,0x7ed2, 0x7fa5,0x7f9f, 0x7fa8,0x7fa1, + 0x7fa9,0x4e49, 0x7fb6,0x81bb, 0x7fd2,0x4e60, 0x7fe8,0x7fc5, 0x7feb,0x73a9, + 0x7ff9,0x7fd8, 0x8011,0x4e13, 0x8021,0x9504, 0x802c,0x8027, 0x8056,0x5723, + 0x805d,0x9998, 0x805e,0x95fb, 0x806f,0x8054, 0x8070,0x806a, 0x8072,0x58f0, + 0x8073,0x8038, 0x8075,0x8069, 0x8076,0x8042, 0x8077,0x804c, 0x8079,0x804d, + 0x807d,0x542c, 0x807e,0x804b, 0x8085,0x8083, 0x808a,0x81c6, 0x8090,0x80f3, + 0x80ca,0x6710, 0x80d1,0x80a2, 0x8105,0x80c1, 0x8108,0x8109, 0x8115,0x8118, + 0x811b,0x80eb, 0x8123,0x5507, 0x8125,0x8118, 0x8129,0x4fee, 0x812b,0x8131, + 0x8139,0x80c0, 0x813a,0x8106, 0x814e,0x80be, 0x8161,0x8136, 0x8166,0x8111, + 0x816b,0x80bf, 0x8173,0x811a, 0x8178,0x80a0, 0x8183,0x817d, 0x819a,0x80a4, + 0x81a0,0x80f6, 0x81a9,0x817b, 0x81ac,0x8106, 0x81bd,0x80c6, 0x81be,0x810d, + 0x81bf,0x8113, 0x81c9,0x8138, 0x81cd,0x8110, 0x81cf,0x8191, 0x81d5,0x8198, + 0x81d8,0x814a, 0x81d9,0x80ed, 0x81da,0x80ea, 0x81dd,0x88f8, 0x81df,0x810f, + 0x81e0,0x8114, 0x81e2,0x81dc, 0x81e5,0x5367, 0x81e8,0x4e34, 0x81fa,0x53f0, + 0x8207,0x4e0e, 0x8208,0x5174, 0x8209,0x4e3e, 0x820a,0x65e7, 0x8216,0x94fa, + 0x8259,0x8231, 0x8264,0x8223, 0x8266,0x8230, 0x826b,0x823b, 0x8271,0x8270, + 0x8277,0x8273, 0x8278,0x8349, 0x8290,0x82c4, 0x8294,0x5349, 0x82bb,0x520d, + 0x82c3,0x8307, 0x82e7,0x82ce, 0x8316,0x835e, 0x8332,0x5179, 0x8337,0x8585, + 0x834a,0x8346, 0x834c,0x62e3, 0x8373,0x8c46, 0x838a,0x5e84, 0x8396,0x830e, + 0x8399,0x8347, 0x83a2,0x835a, 0x83a4,0x8c46, 0x83a7,0x82cb, 0x83c9,0x7eff, + 0x83d1,0x707e, 0x83e2,0x62b1, 0x83ef,0x534e, 0x8407,0x82cc, 0x840a,0x83b1, + 0x842c,0x4e07, 0x8435,0x83b4, 0x8437,0x5ced, 0x8449,0x53f6, 0x8452,0x836d, + 0x8460,0x53c2, 0x8466,0x82c7, 0x846e,0x846d, 0x846f,0x836f, 0x8477,0x8364, + 0x847e,0x852b, 0x8494,0x83b3, 0x849e,0x8385, 0x84a8,0x831c, 0x84a9,0x83f9, + 0x84bc,0x82cd, 0x84c0,0x836a, 0x84c6,0x5e2d, 0x84cb,0x76d6, 0x84e8,0x839c, + 0x84ee,0x83b2, 0x84ef,0x82c1, 0x84f1,0x8d2b, 0x84f4,0x83bc, 0x84fb,0x827a, + 0x84fd,0x835c, 0x8506,0x83f1, 0x8514,0x535c, 0x8515,0x8482, 0x851e,0x848c, + 0x8523,0x848b, 0x8525,0x8471, 0x8526,0x8311, 0x852d,0x836b, 0x8541,0x8368, + 0x8546,0x8487, 0x854e,0x835e, 0x8553,0x82b8, 0x8555,0x83b8, 0x8558,0x835b, + 0x8562,0x8489, 0x8569,0x8361, 0x856a,0x829c, 0x856d,0x8427, 0x8577,0x84e3, + 0x8580,0x8574, 0x8588,0x835f, 0x8589,0x79fd, 0x858a,0x84df, 0x858c,0x8297, + 0x8591,0x59dc, 0x8594,0x8537, 0x8599,0x5243, 0x859f,0x83b6, 0x85a6,0x8350, + 0x85a9,0x8428, 0x85b6,0x57cb, 0x85ba,0x8360, 0x85c2,0x4e1b, 0x85c7,0x84e3, + 0x85cd,0x84dd, 0x85ce,0x8369, 0x85dd,0x827a, 0x85e5,0x836f, 0x85ea,0x85ae, + 0x85f6,0x82c8, 0x85f9,0x853c, 0x85fa,0x853a, 0x8604,0x8572, 0x8606,0x82a6, + 0x8607,0x82cf, 0x8609,0x7816, 0x860a,0x8574, 0x860b,0x82f9, 0x8617,0x8616, + 0x861a,0x85d3, 0x861c,0x83ca, 0x861e,0x8539, 0x8620,0x8537, 0x8622,0x830f, + 0x862a,0x863c, 0x862d,0x5170, 0x863a,0x84e0, 0x863f,0x841d, 0x8653,0x8327, + 0x8655,0x5904, 0x8656,0x5b93, 0x865b,0x865a, 0x865c,0x864f, 0x865f,0x53f7, + 0x8667,0x4e8f, 0x866f,0x866c, 0x8685,0x8695, 0x8696,0x8788, 0x869a,0x86a7, + 0x86a1,0x869d, 0x86a5,0x86d4, 0x86bf,0x547c, 0x86e3,0x9c92, 0x86fa,0x86f1, + 0x86fb,0x8715, 0x8706,0x86ac, 0x870b,0x8793, 0x8711,0x86cb, 0x8728,0x8776, + 0x873a,0x9713, 0x8755,0x8680, 0x875e,0x7338, 0x875f,0x732c, 0x8761,0x8815, + 0x8766,0x867e, 0x8768,0x8671, 0x876f,0x733f, 0x8773,0x73b3, 0x8778,0x8717, + 0x8784,0x86f3, 0x8798,0x8681, 0x879e,0x8682, 0x87a2,0x8424, 0x87bb,0x877c, + 0x87be,0x8693, 0x87c4,0x86f0, 0x87c8,0x8748, 0x87e3,0x866e, 0x87ec,0x8749, + 0x87ef,0x86f2, 0x87f2,0x866b, 0x87f6,0x86cf, 0x87f7,0x87b3, 0x87fa,0x87ee, + 0x87fb,0x8681, 0x87ff,0x881b, 0x8805,0x8747, 0x8806,0x867f, 0x880d,0x874e, + 0x8810,0x86f4, 0x8811,0x877e, 0x8814,0x869d, 0x881f,0x8721, 0x8823,0x86ce, + 0x8831,0x86ca, 0x8836,0x8695, 0x883b,0x86ee, 0x884a,0x8511, 0x8853,0x672f, + 0x8855,0x540c, 0x8856,0x5f04, 0x885b,0x536b, 0x885d,0x51b2, 0x8879,0x53ea, + 0x8889,0x70ab, 0x8893,0x888d, 0x8898,0x7617, 0x889e,0x886e, 0x889f,0x7c97, + 0x88ba,0x5939, 0x88ca,0x8885, 0x88cc,0x5939, 0x88cf,0x91cc, 0x88dc,0x8865, + 0x88dd,0x88c5, 0x88e1,0x91cc, 0x88fd,0x5236, 0x8907,0x590d, 0x890e,0x8896, + 0x892d,0x8885, 0x8932,0x88e4, 0x8933,0x88e2, 0x8935,0x7f21, 0x8938,0x891b, + 0x893b,0x4eb5, 0x8946,0x5e5e, 0x8949,0x88e5, 0x8956,0x8884, 0x895d,0x88e3, + 0x8960,0x88c6, 0x8962,0x8892, 0x8964,0x8934, 0x896a,0x889c, 0x896d,0x7f2c, + 0x896f,0x886c, 0x8972,0x88ad, 0x8988,0x6838, 0x898b,0x89c1, 0x898f,0x89c4, + 0x8993,0x89c5, 0x8995,0x2171, 0x8996,0x89c6, 0x8998,0x89c7, 0x899c,0x773a, + 0x89a1,0x89cb, 0x89a6,0x89ce, 0x89aa,0x4eb2, 0x89ac,0x89ca, 0x89af,0x89cf, + 0x89b2,0x89d0, 0x89b7,0x89d1, 0x89ba,0x89c9, 0x89bd,0x89c8, 0x89bf,0x89cc, + 0x89c0,0x89c2, 0x89d4,0x7b4b, 0x89dd,0x62b5, 0x89f4,0x89de, 0x89f6,0x89ef, + 0x89f8,0x89e6, 0x8a02,0x8ba2, 0x8a03,0x8ba3, 0x8a08,0x8ba1, 0x8a0a,0x8baf, + 0x8a0c,0x8ba7, 0x8a0e,0x8ba8, 0x8a0f,0x5401, 0x8a10,0x8ba6, 0x8a13,0x8bad, + 0x8a15,0x8baa, 0x8a16,0x8bab, 0x8a17,0x6258, 0x8a18,0x8bb0, 0x8a1b,0x8bb9, + 0x8a1d,0x8bb6, 0x8a1f,0x8bbc, 0x8a22,0x6b23, 0x8a23,0x8bc0, 0x8a25,0x8bb7, + 0x8a2a,0x8bbf, 0x8a2d,0x8bbe, 0x8a31,0x8bb8, 0x8a34,0x8bc9, 0x8a36,0x8bc3, + 0x8a3a,0x8bca, 0x8a3b,0x6ce8, 0x8a3c,0x8bc1, 0x8a3f,0x8a3e, 0x8a41,0x8bc2, + 0x8a46,0x8bcb, 0x8a4e,0x8bb5, 0x8a50,0x8bc8, 0x8a52,0x8bd2, 0x8a54,0x8bcf, + 0x8a55,0x8bc4, 0x8a56,0x8bd0, 0x8a58,0x8bce, 0x8a5b,0x8bc5, 0x8a5e,0x8bcd, + 0x8a60,0x548f, 0x8a61,0x8be9, 0x8a62,0x8be2, 0x8a63,0x8be3, 0x8a66,0x8bd5, + 0x8a69,0x8bd7, 0x8a6b,0x8be7, 0x8a6c,0x8bdf, 0x8a6d,0x8be1, 0x8a6e,0x8be0, + 0x8a70,0x8bd8, 0x8a71,0x8bdd, 0x8a72,0x8be5, 0x8a73,0x8be6, 0x8a75,0x8bdc, + 0x8a7c,0x8bd9, 0x8a7f,0x8bd6, 0x8a84,0x8bd4, 0x8a85,0x8bdb, 0x8a86,0x8bd3, + 0x8a87,0x5938, 0x8a8c,0x5fd7, 0x8a8d,0x8ba4, 0x8a91,0x8bf3, 0x8a92,0x8bf6, + 0x8a95,0x8bde, 0x8a96,0x6096, 0x8a98,0x8bf1, 0x8a9a,0x8bee, 0x8a9e,0x8bed, + 0x8aa0,0x8bda, 0x8aa1,0x8beb, 0x8aa3,0x8bec, 0x8aa4,0x8bef, 0x8aa5,0x8bf0, + 0x8aa6,0x8bf5, 0x8aa8,0x8bf2, 0x8aaa,0x8bf4, 0x8ab0,0x8c01, 0x8ab2,0x8bfe, + 0x8ab6,0x8c07, 0x8ab9,0x8bfd, 0x8abc,0x8c0a, 0x8abf,0x8c03, 0x8ac2,0x8c04, + 0x8ac4,0x8c06, 0x8ac7,0x8c08, 0x8ac9,0x8bff, 0x8acb,0x8bf7, 0x8acd,0x8be4, + 0x8acf,0x8bf9, 0x8ad1,0x8bfc, 0x8ad2,0x8c05, 0x8ad6,0x8bba, 0x8ad7,0x8c02, + 0x8adb,0x8c00, 0x8adc,0x8c0d, 0x8ade,0x8c1d, 0x8ae0,0x55a7, 0x8ae2,0x8be8, + 0x8ae4,0x8c14, 0x8ae6,0x8c1b, 0x8ae7,0x8c10, 0x8aeb,0x8c0f, 0x8aed,0x8c15, + 0x8aee,0x8c18, 0x8af1,0x8bb3, 0x8af3,0x8c19, 0x8af6,0x8c0c, 0x8af7,0x8bbd, + 0x8af8,0x8bf8, 0x8afa,0x8c1a, 0x8afc,0x8c16, 0x8afe,0x8bfa, 0x8b00,0x8c0b, + 0x8b01,0x8c12, 0x8b02,0x8c13, 0x8b04,0x8a8a, 0x8b05,0x8bcc, 0x8b0a,0x8c0e, + 0x8b0e,0x8c1c, 0x8b10,0x8c27, 0x8b14,0x8c11, 0x8b16,0x8c21, 0x8b17,0x8c24, + 0x8b19,0x8c26, 0x8b1a,0x8c25, 0x8b1b,0x8bb2, 0x8b1d,0x8c22, 0x8b20,0x8c23, + 0x8b28,0x8c1f, 0x8b2b,0x8c2a, 0x8b2c,0x8c2c, 0x8b2e,0x5567, 0x8b2f,0x8bc5, + 0x8b33,0x8bb4, 0x8b39,0x8c28, 0x8b3c,0x547c, 0x8b3e,0x8c29, 0x8b41,0x54d7, + 0x8b46,0x563b, 0x8b48,0x619d, 0x8b49,0x8bc1, 0x8b4b,0x8c30, 0x8b4e,0x8c32, + 0x8b4f,0x8ba5, 0x8b54,0x64b0, 0x8b56,0x8c2e, 0x8b58,0x8bc6, 0x8b59,0x8c2f, + 0x8b5a,0x8c2d, 0x8b5c,0x8c31, 0x8b5f,0x566a, 0x8b63,0x9a8c, 0x8b6b,0x8c35, + 0x8b6d,0x6bc1, 0x8b6f,0x8bd1, 0x8b70,0x8bae, 0x8b74,0x8c34, 0x8b77,0x62a4, + 0x8b7d,0x8a89, 0x8b7e,0x8c2b, 0x8b80,0x8bfb, 0x8b85,0x5ba1, 0x8b8a,0x53d8, + 0x8b8c,0x5bb4, 0x8b8e,0x96e0, 0x8b92,0x8c17, 0x8b93,0x8ba9, 0x8b95,0x8c30, + 0x8b96,0x8c36, 0x8b99,0x6b22, 0x8b9a,0x8d5e, 0x8b9c,0x8c20, 0x8b9e,0x8c33, + 0x8c3f,0x6eaa, 0x8c48,0x5c82, 0x8c4e,0x7ad6, 0x8c50,0x4e30, 0x8c54,0x8273, + 0x8c6c,0x732a, 0x8c8d,0x72f8, 0x8c93,0x732b, 0x8c9d,0x8d1d, 0x8c9e,0x8d1e, + 0x8ca0,0x8d1f, 0x8ca1,0x8d22, 0x8ca2,0x8d21, 0x8ca4,0x72b4, 0x8ca7,0x8d2b, + 0x8ca8,0x8d27, 0x8ca9,0x8d29, 0x8caa,0x8d2a, 0x8cab,0x8d2f, 0x8cac,0x8d23, + 0x8caf,0x8d2e, 0x8cb0,0x8d33, 0x8cb2,0x8d40, 0x8cb3,0x8d30, 0x8cb4,0x8d35, + 0x8cb6,0x8d2c, 0x8cb7,0x4e70, 0x8cb8,0x8d37, 0x8cba,0x8d36, 0x8cbb,0x8d39, + 0x8cbc,0x8d34, 0x8cbd,0x8d3b, 0x8cbf,0x8d38, 0x8cc0,0x8d3a, 0x8cc1,0x8d32, + 0x8cc2,0x8d42, 0x8cc3,0x8d41, 0x8cc4,0x8d3f, 0x8cc5,0x8d45, 0x8cc7,0x8d44, + 0x8cc8,0x8d3e, 0x8cca,0x8d3c, 0x8cd1,0x8d48, 0x8cd2,0x8d4a, 0x8cd3,0x5bbe, + 0x8cd5,0x8d47, 0x8cda,0x8d49, 0x8cdc,0x8d50, 0x8cdd,0x741b, 0x8cde,0x8d4f, + 0x8ce0,0x8d54, 0x8ce1,0x8d53, 0x8ce2,0x8d24, 0x8ce3,0x5356, 0x8ce4,0x8d31, + 0x8ce6,0x8d4b, 0x8ce7,0x8d55, 0x8cea,0x8d28, 0x8cec,0x8d26, 0x8ced,0x8d4c, + 0x8cf4,0x8d56, 0x8cf8,0x5269, 0x8cfa,0x8d5a, 0x8cfb,0x8d59, 0x8cfc,0x8d2d, + 0x8cfd,0x8d5b, 0x8cfe,0x8d5c, 0x8d04,0x8d3d, 0x8d05,0x8d58, 0x8d08,0x8d60, + 0x8d0a,0x8d5e, 0x8d0d,0x8d61, 0x8d0f,0x8d62, 0x8d10,0x8d46, 0x8d13,0x8d43, + 0x8d16,0x8d4e, 0x8d17,0x8d5d, 0x8d1b,0x8d63, 0x8d78,0x8d76, 0x8d95,0x8d76, + 0x8d99,0x8d75, 0x8da8,0x8d8b, 0x8dae,0x8e81, 0x8db2,0x8db1, 0x8de1,0x8ff9, + 0x8df0,0x80fc, 0x8df4,0x8e29, 0x8dfc,0x5c40, 0x8e10,0x8df5, 0x8e21,0x8737, + 0x8e30,0x903e, 0x8e34,0x8e0a, 0x8e4c,0x8dc4, 0x8e53,0x905b, 0x8e55,0x8df8, + 0x8e5a,0x8d9f, 0x8e5d,0x5c63, 0x8e5e,0x8e2f, 0x8e5f,0x8ff9, 0x8e60,0x8dd6, + 0x8e62,0x8e2f, 0x8e63,0x8e52, 0x8e64,0x8e2a, 0x8e67,0x7cdf, 0x8e78,0x8e8f, + 0x8e7a,0x8df7, 0x8e82,0x8e0f, 0x8e89,0x8db8, 0x8e8a,0x8e0c, 0x8e8b,0x8dfb, + 0x8e8d,0x8dc3, 0x8e91,0x8e2f, 0x8e92,0x8dde, 0x8e93,0x8e2c, 0x8e95,0x8e70, + 0x8e9a,0x8df9, 0x8ea1,0x8e51, 0x8ea5,0x8e7f, 0x8ea6,0x8e9c, 0x8eaa,0x8e8f, + 0x8ec0,0x8eaf, 0x8eca,0x8f66, 0x8ecb,0x8f67, 0x8ecc,0x8f68, 0x8ecd,0x519b, + 0x8ed2,0x8f69, 0x8ed4,0x8f6b, 0x8edb,0x8f6d, 0x8edf,0x8f6f, 0x8eeb,0x8f78, + 0x8ef6,0x8f6d, 0x8ef8,0x8f74, 0x8ef9,0x8f75, 0x8efa,0x8f7a, 0x8efb,0x8f72, + 0x8efc,0x8f76, 0x8efe,0x8f7c, 0x8f03,0x8f83, 0x8f05,0x8f82, 0x8f07,0x8f81, + 0x8f09,0x8f7d, 0x8f0a,0x8f7e, 0x8f12,0x8f84, 0x8f13,0x633d, 0x8f14,0x8f85, + 0x8f15,0x8f7b, 0x8f1b,0x8f86, 0x8f1c,0x8f8e, 0x8f1d,0x8f89, 0x8f1e,0x8f8b, + 0x8f1f,0x8f8d, 0x8f20,0x9505, 0x8f25,0x8f8a, 0x8f26,0x8f87, 0x8f29,0x8f88, + 0x8f2a,0x8f6e, 0x8f2f,0x8f91, 0x8f33,0x8f8f, 0x8f37,0x8f70, 0x8f38,0x8f93, + 0x8f3b,0x8f90, 0x8f3e,0x8f97, 0x8f3f,0x8206, 0x8f42,0x6bc2, 0x8f44,0x8f96, + 0x8f45,0x8f95, 0x8f46,0x8f98, 0x8f49,0x8f6c, 0x8f4d,0x8f99, 0x8f4e,0x8f7f, + 0x8f54,0x8f9a, 0x8f5d,0x8206, 0x8f5e,0x69db, 0x8f5f,0x8f70, 0x8f61,0x8f94, + 0x8f62,0x8f79, 0x8f64,0x8f73, 0x8fa6,0x529e, 0x8fad,0x8f9e, 0x8fae,0x8fab, + 0x8faf,0x8fa9, 0x8fb2,0x519c, 0x8fc6,0x8fe4, 0x8ff4,0x56de, 0x8ffa,0x4e43, + 0x8fff,0x9002, 0x9015,0x8ff3, 0x9019,0x8fd9, 0x9023,0x8fde, 0x9031,0x5468, + 0x9032,0x8fdb, 0x9049,0x4fa6, 0x904a,0x6e38, 0x904b,0x8fd0, 0x904e,0x8fc7, + 0x9054,0x8fbe, 0x9055,0x8fdd, 0x9059,0x9065, 0x905c,0x900a, 0x905d,0x6c93, + 0x905e,0x9012, 0x9060,0x8fdc, 0x9069,0x9002, 0x906f,0x9041, 0x9070,0x9012, + 0x9072,0x8fdf, 0x9076,0x7ed5, 0x9077,0x8fc1, 0x9078,0x9009, 0x907a,0x9057, + 0x907c,0x8fbd, 0x9081,0x8fc8, 0x9084,0x8fd8, 0x9087,0x8fe9, 0x908a,0x8fb9, + 0x908f,0x903b, 0x9090,0x9026, 0x90c3,0x5408, 0x90df,0x90cf, 0x90f5,0x90ae, + 0x9101,0x90b6, 0x9106,0x90d3, 0x9109,0x4e61, 0x9112,0x90b9, 0x9114,0x90ac, + 0x9116,0x90e7, 0x9118,0x5889, 0x9126,0x8bb8, 0x9127,0x9093, 0x912d,0x90d1, + 0x9130,0x90bb, 0x9132,0x90f8, 0x9134,0x90ba, 0x9136,0x90d0, 0x913a,0x909d, + 0x9148,0x90e6, 0x9183,0x814c, 0x9186,0x76cf, 0x919c,0x4e11, 0x919e,0x915d, + 0x91ab,0x533b, 0x91ac,0x9171, 0x91b1,0x7c95, 0x91c0,0x917f, 0x91c1,0x8845, + 0x91c3,0x917e, 0x91c5,0x917d, 0x91c6,0x91c7, 0x91cb,0x91ca, 0x91d0,0x5398, + 0x91d3,0x9486, 0x91d4,0x9487, 0x91d5,0x948c, 0x91d7,0x948a, 0x91d8,0x9489, + 0x91d9,0x948b, 0x91dd,0x9488, 0x91e3,0x9493, 0x91e4,0x9490, 0x91e6,0x6263, + 0x91e7,0x948f, 0x91e9,0x9492, 0x91f4,0x710a, 0x91f5,0x9497, 0x91f7,0x948d, + 0x91f9,0x9495, 0x9200,0x94af, 0x9201,0x94ab, 0x9204,0x94ad, 0x9205,0x94a5, + 0x9206,0x94c5, 0x9209,0x94a0, 0x920d,0x949d, 0x9210,0x94a4, 0x9211,0x94a3, + 0x9214,0x949e, 0x9215,0x94ae, 0x921e,0x94a7, 0x9223,0x9499, 0x9225,0x94ac, + 0x9226,0x949b, 0x9227,0x94aa, 0x922e,0x94cc, 0x9230,0x94c8, 0x9233,0x94b6, + 0x9234,0x94c3, 0x9237,0x94b4, 0x9238,0x94b9, 0x9239,0x94cd, 0x923a,0x94b0, + 0x923d,0x94b8, 0x923e,0x94c0, 0x923f,0x94bf, 0x9240,0x94be, 0x9245,0x949c, + 0x9246,0x94bb, 0x9248,0x94ca, 0x9249,0x94c9, 0x924b,0x5228, 0x924d,0x94cb, + 0x924f,0x9504, 0x9251,0x94c2, 0x9257,0x94b3, 0x925a,0x94c6, 0x925b,0x94c5, + 0x925e,0x94ba, 0x9264,0x94a9, 0x9266,0x94b2, 0x926c,0x94bc, 0x926d,0x94bd, + 0x9272,0x950e, 0x9278,0x94f0, 0x927a,0x94d2, 0x927b,0x94ec, 0x927f,0x94ea, + 0x9280,0x94f6, 0x9283,0x94f3, 0x9285,0x94dc, 0x9291,0x94e3, 0x9293,0x94e8, + 0x9295,0x94c1, 0x9296,0x94e2, 0x9298,0x94ed, 0x929a,0x94eb, 0x929c,0x8854, + 0x92a0,0x94d1, 0x92a3,0x94f7, 0x92a5,0x94f1, 0x92a6,0x94df, 0x92a8,0x94f5, + 0x92a9,0x94e5, 0x92aa,0x94d5, 0x92ab,0x94ef, 0x92ac,0x94d0, 0x92b2,0x710a, + 0x92b3,0x9510, 0x92b5,0x94ff, 0x92b7,0x9500, 0x92b9,0x9508, 0x92bb,0x9511, + 0x92bc,0x9509, 0x92c1,0x94dd, 0x92c2,0x9545, 0x92c3,0x9512, 0x92c5,0x950c, + 0x92c7,0x94a1, 0x92cc,0x94e4, 0x92cd,0x9b3b, 0x92cf,0x94d7, 0x92d2,0x950b, + 0x92dd,0x950a, 0x92df,0x9513, 0x92e4,0x9504, 0x92e6,0x9514, 0x92e8,0x9507, + 0x92ea,0x94fa, 0x92ee,0x94d6, 0x92ef,0x9506, 0x92f0,0x9502, 0x92f1,0x94fd, + 0x92f8,0x952f, 0x92fc,0x94a2, 0x9301,0x951e, 0x9304,0x5f55, 0x9306,0x9516, + 0x9308,0x9529, 0x9310,0x9525, 0x9312,0x9515, 0x9315,0x951f, 0x9318,0x9524, + 0x9319,0x9531, 0x931a,0x94ee, 0x931b,0x951b, 0x931e,0x9566, 0x931f,0x952c, + 0x9320,0x952d, 0x9321,0x951c, 0x9322,0x94b1, 0x9326,0x9526, 0x9328,0x951a, + 0x932b,0x9521, 0x932e,0x9522, 0x932f,0x9519, 0x9333,0x9530, 0x9336,0x8868, + 0x9338,0x94fc, 0x9346,0x9494, 0x9347,0x9534, 0x934b,0x9505, 0x934d,0x9540, + 0x9354,0x9537, 0x9358,0x94e1, 0x935a,0x9496, 0x935b,0x953b, 0x9364,0x9538, + 0x9365,0x9532, 0x936c,0x9539, 0x9370,0x953e, 0x9375,0x952e, 0x9376,0x9536, + 0x937a,0x9517, 0x937c,0x9488, 0x937e,0x953a, 0x9382,0x9541, 0x938a,0x9551, + 0x938c,0x9570, 0x9392,0x8028, 0x9394,0x7194, 0x9396,0x9501, 0x9397,0x67aa, + 0x9398,0x9549, 0x939a,0x9524, 0x939d,0x951d, 0x93a2,0x94a8, 0x93a6,0x954f, + 0x93a7,0x94e0, 0x93a9,0x94e9, 0x93aa,0x953c, 0x93ac,0x9550, 0x93ae,0x9547, + 0x93b0,0x9552, 0x93b3,0x954d, 0x93b5,0x9553, 0x93c3,0x955e, 0x93c7,0x955f, + 0x93c8,0x94fe, 0x93cc,0x9546, 0x93cd,0x9559, 0x93d1,0x955d, 0x93d7,0x94ff, + 0x93d8,0x9535, 0x93dc,0x9557, 0x93dd,0x9558, 0x93de,0x955b, 0x93df,0x94f2, + 0x93e1,0x955c, 0x93e2,0x9556, 0x93e4,0x9542, 0x93e8,0x933e, 0x93ec,0x7f45, + 0x93f5,0x94e7, 0x93f7,0x9564, 0x93f9,0x956a, 0x93fd,0x9508, 0x9400,0x67dc, + 0x9403,0x94d9, 0x940b,0x94f4, 0x9410,0x9563, 0x9411,0x9532, 0x9412,0x94f9, + 0x9413,0x9566, 0x9414,0x9561, 0x9418,0x949f, 0x9419,0x956b, 0x9420,0x9568, + 0x9428,0x9544, 0x942b,0x954c, 0x942e,0x9570, 0x9431,0x5251, 0x9432,0x956f, + 0x9433,0x956d, 0x9435,0x94c1, 0x9436,0x949a, 0x9438,0x94ce, 0x943a,0x94db, + 0x943f,0x9571, 0x9440,0x953f, 0x9444,0x94f8, 0x944a,0x956c, 0x944c,0x9554, + 0x9451,0x9274, 0x9452,0x9274, 0x9460,0x94c4, 0x9463,0x9573, 0x9464,0x5228, + 0x946a,0x7089, 0x946d,0x9567, 0x9470,0x94a5, 0x9472,0x9576, 0x9473,0x952e, + 0x9475,0x7f50, 0x9477,0x954a, 0x947c,0x9523, 0x947d,0x94bb, 0x947e,0x92ae, + 0x947f,0x51ff, 0x9481,0x9562, 0x9482,0x954b, 0x9577,0x957f, 0x9580,0x95e8, + 0x9582,0x95e9, 0x9583,0x95ea, 0x9586,0x95eb, 0x9589,0x95ed, 0x958b,0x5f00, + 0x958c,0x95f6, 0x958e,0x95f3, 0x958f,0x95f0, 0x9591,0x95f2, 0x9592,0x95f2, + 0x9593,0x95f4, 0x9594,0x95f5, 0x9598,0x95f8, 0x95a1,0x9602, 0x95a3,0x9601, + 0x95a4,0x9601, 0x95a5,0x9600, 0x95a8,0x95fa, 0x95a9,0x95fd, 0x95ab,0x9603, + 0x95ac,0x9606, 0x95ad,0x95fe, 0x95b1,0x9605, 0x95b6,0x960a, 0x95b9,0x9609, + 0x95bb,0x960e, 0x95bc,0x960f, 0x95bd,0x960d, 0x95be,0x9608, 0x95bf,0x960c, + 0x95c0,0x54c4, 0x95c3,0x9612, 0x95c6,0x677f, 0x95c7,0x6697, 0x95c8,0x95f1, + 0x95ca,0x9614, 0x95cb,0x9615, 0x95cc,0x9611, 0x95d0,0x9617, 0x95d4,0x9616, + 0x95d5,0x9619, 0x95d6,0x95ef, 0x95dc,0x5173, 0x95de,0x961a, 0x95e1,0x9610, + 0x95e2,0x8f9f, 0x95e5,0x95fc, 0x9623,0x5c79, 0x9624,0x9640, 0x9628,0x5384, + 0x962c,0x5751, 0x962f,0x5740, 0x9658,0x9649, 0x965d,0x9655, 0x965e,0x5347, + 0x9663,0x9635, 0x9670,0x9634, 0x9673,0x9648, 0x9678,0x9646, 0x967d,0x9633, + 0x9684,0x5824, 0x9689,0x9667, 0x968a,0x961f, 0x968e,0x9636, 0x9695,0x9668, + 0x969b,0x9645, 0x96a4,0x9893, 0x96a8,0x968f, 0x96aa,0x9669, 0x96ae,0x8dfb, + 0x96b1,0x9690, 0x96b4,0x9647, 0x96b8,0x96b6, 0x96bb,0x53ea, 0x96cb,0x96bd, + 0x96d6,0x867d, 0x96d9,0x53cc, 0x96db,0x96cf, 0x96dc,0x6742, 0x96de,0x9e21, + 0x96e2,0x79bb, 0x96e3,0x96be, 0x96f0,0x6c1b, 0x96f2,0x4e91, 0x96fb,0x7535, + 0x9711,0x6cbe, 0x9712,0x9634, 0x9724,0x6e9c, 0x9727,0x96fe, 0x973d,0x9701, + 0x9742,0x96f3, 0x9743,0x970d, 0x9744,0x972d, 0x9748,0x7075, 0x975a,0x9753, + 0x975c,0x9759, 0x9766,0x8146, 0x9768,0x9765, 0x977d,0x7eca, 0x9780,0x9f17, + 0x9781,0x97b4, 0x978f,0x5de9, 0x979c,0x7ef1, 0x97a1,0x9f19, 0x97a6,0x79cb, + 0x97c1,0x7f30, 0x97c3,0x9791, 0x97c6,0x5343, 0x97c9,0x97af, 0x97cb,0x97e6, + 0x97cc,0x97e7, 0x97d3,0x97e9, 0x97d9,0x97ea, 0x97dc,0x97ec, 0x97dd,0x97b2, + 0x97de,0x97eb, 0x97fb,0x97f5, 0x97ff,0x54cd, 0x9801,0x9875, 0x9802,0x9876, + 0x9803,0x9877, 0x9805,0x9879, 0x9806,0x987a, 0x9807,0x9878, 0x9808,0x987b, + 0x980a,0x987c, 0x980c,0x9882, 0x980e,0x9880, 0x980f,0x9883, 0x9810,0x9884, + 0x9811,0x987d, 0x9812,0x9881, 0x9813,0x987f, 0x9816,0x6cee, 0x9817,0x9887, + 0x9818,0x9886, 0x981c,0x988c, 0x9821,0x9889, 0x9824,0x9890, 0x9826,0x988f, + 0x982b,0x4fef, 0x982d,0x5934, 0x9830,0x988a, 0x9837,0x9894, 0x9838,0x9888, + 0x9839,0x9893, 0x983b,0x9891, 0x9846,0x9897, 0x984c,0x9898, 0x984d,0x989d, + 0x984e,0x989a, 0x984f,0x989c, 0x9850,0x8be8, 0x9853,0x989b, 0x9858,0x613f, + 0x9859,0x98a1, 0x985b,0x98a0, 0x985e,0x7c7b, 0x9862,0x989f, 0x9865,0x98a2, + 0x9867,0x987e, 0x986b,0x98a4, 0x986f,0x663e, 0x9870,0x98a6, 0x9871,0x9885, + 0x9873,0x989e, 0x9874,0x98a7, 0x98a8,0x98ce, 0x98ae,0x98d1, 0x98af,0x98d2, + 0x98b1,0x53f0, 0x98b3,0x522e, 0x98b6,0x98d3, 0x98ba,0x626c, 0x98bc,0x98d5, + 0x98bf,0x5e06, 0x98c4,0x98d8, 0x98c6,0x98d9, 0x98db,0x98de, 0x98e2,0x9965, + 0x98e9,0x9968, 0x98ea,0x996a, 0x98eb,0x996b, 0x98ed,0x996c, 0x98ef,0x996d, + 0x98f2,0x996e, 0x98f4,0x9974, 0x98fc,0x9972, 0x98fd,0x9971, 0x98fe,0x9970, + 0x9903,0x997a, 0x9905,0x997c, 0x9908,0x7ccd, 0x9909,0x9977, 0x990a,0x517b, + 0x990c,0x9975, 0x9911,0x997d, 0x9912,0x9981, 0x9913,0x997f, 0x9918,0x9980, + 0x991a,0x80b4, 0x991b,0x9984, 0x991e,0x996f, 0x9921,0x9985, 0x9927,0x5582, + 0x9928,0x9986, 0x992c,0x7cca, 0x9931,0x7cc7, 0x9933,0x9967, 0x9935,0x5582, + 0x993c,0x9969, 0x993d,0x9988, 0x993e,0x998f, 0x993f,0x998a, 0x9943,0x998d, + 0x9945,0x9992, 0x9947,0x996b, 0x9948,0x9990, 0x9949,0x9991, 0x994b,0x9988, + 0x994c,0x9994, 0x9951,0x9965, 0x9952,0x9976, 0x9957,0x98e8, 0x995c,0x990d, + 0x995e,0x998b, 0x995f,0x9977, 0x99ac,0x9a6c, 0x99ad,0x9a6d, 0x99ae,0x51af, + 0x99b1,0x9a6e, 0x99b3,0x9a70, 0x99b4,0x9a6f, 0x99bd,0x7d77, 0x99c1,0x9a73, + 0x99d0,0x9a7b, 0x99d1,0x9a7d, 0x99d2,0x9a79, 0x99d4,0x9a75, 0x99d5,0x9a7e, + 0x99d8,0x9a80, 0x99d9,0x9a78, 0x99db,0x9a76, 0x99dd,0x9a7c, 0x99df,0x9a77, + 0x99e2,0x9a88, 0x99ed,0x9a87, 0x99ee,0x9a73, 0x99f1,0x9a86, 0x99ff,0x9a8f, + 0x9a01,0x9a8b, 0x9a03,0x5446, 0x9a05,0x9a93, 0x9a0d,0x9a92, 0x9a0e,0x9a91, + 0x9a0f,0x9a90, 0x9a16,0x9a9b, 0x9a19,0x9a97, 0x9a23,0x9b03, 0x9a2b,0x9a9e, + 0x9a2d,0x9a98, 0x9a2e,0x9a9d, 0x9a30,0x817e, 0x9a32,0x8349, 0x9a36,0x9a7a, + 0x9a37,0x9a9a, 0x9a38,0x9a9f, 0x9a3e,0x9aa1, 0x9a40,0x84e6, 0x9a41,0x9a9c, + 0x9a42,0x9a96, 0x9a43,0x9aa0, 0x9a44,0x9aa2, 0x9a45,0x9a71, 0x9a4a,0x9a85, + 0x9a4d,0x9a81, 0x9a4f,0x9aa3, 0x9a55,0x9a84, 0x9a57,0x9a8c, 0x9a5a,0x60ca, + 0x9a5b,0x9a7f, 0x9a5f,0x9aa4, 0x9a62,0x9a74, 0x9a64,0x9aa7, 0x9a65,0x9aa5, + 0x9a66,0x9aa6, 0x9a6a,0x9a8a, 0x9a6b,0x9a89, 0x9aaf,0x80ae, 0x9abb,0x80ef, + 0x9abe,0x9ca0, 0x9abf,0x80fc, 0x9ac6,0x818a, 0x9acf,0x9ac5, 0x9ad2,0x810f, + 0x9ad4,0x4f53, 0x9ad5,0x9acc, 0x9ad6,0x9acb, 0x9ae3,0x4eff, 0x9aee,0x53d1, + 0x9af1,0x2171, 0x9af3,0x9ae6, 0x9b06,0x677e, 0x9b0d,0x80e1, 0x9b12,0x7f1c, + 0x9b1a,0x987b, 0x9b22,0x9b13, 0x9b25,0x6597, 0x9b27,0x95f9, 0x9b28,0x54c4, + 0x9b29,0x960b, 0x9b2e,0x9604, 0x9b31,0x90c1, 0x9b4a,0x872e, 0x9b4e,0x9b49, + 0x9b58,0x9b47, 0x9b5a,0x9c7c, 0x9b6f,0x9c81, 0x9b74,0x9c82, 0x9b77,0x9c7f, + 0x9b7c,0x9c88, 0x9b86,0x9c9a, 0x9b90,0x9c90, 0x9b91,0x9c8d, 0x9b92,0x9c8b, + 0x9b9a,0x9c92, 0x9b9e,0x9c95, 0x9baa,0x9c94, 0x9bab,0x9c9b, 0x9bad,0x9c91, + 0x9bae,0x9c9c, 0x9bc0,0x9ca7, 0x9bc1,0x9ca0, 0x9bc7,0x9ca9, 0x9bc9,0x9ca4, + 0x9bca,0x9ca8, 0x9bd4,0x9cbb, 0x9bd6,0x9cad, 0x9bd7,0x9c9e, 0x9bdb,0x9cb7, + 0x9be1,0x9cb1, 0x9be2,0x9cb5, 0x9be4,0x9cb2, 0x9be7,0x9cb3, 0x9be8,0x9cb8, + 0x9bea,0x9cae, 0x9beb,0x9cb0, 0x9bf0,0x9cb6, 0x9bfd,0x9cab, 0x9c08,0x9cbd, + 0x9c09,0x9cc7, 0x9c0d,0x9cc5, 0x9c12,0x9cc6, 0x9c13,0x9cc3, 0x9c23,0x9ca5, + 0x9c25,0x9ccf, 0x9c28,0x9cce, 0x9c29,0x9cd0, 0x9c2d,0x9ccd, 0x9c31,0x9ca2, + 0x9c32,0x9ccc, 0x9c33,0x9cd3, 0x9c37,0x9ca6, 0x9c39,0x9ca3, 0x9c3b,0x9cd7, + 0x9c3c,0x9cdb, 0x9c3e,0x9cd4, 0x9c48,0x9cd5, 0x9c49,0x9cd6, 0x9c4d,0x9c85, + 0x9c52,0x9cdf, 0x9c54,0x9cdd, 0x9c56,0x9cdc, 0x9c57,0x9cde, 0x9c58,0x9c9f, + 0x9c5f,0x9c8e, 0x9c60,0x810d, 0x9c63,0x9cdd, 0x9c67,0x9ce2, 0x9c6d,0x9c9a, + 0x9c77,0x9cc4, 0x9c78,0x9c88, 0x9c7a,0x9ca1, 0x9ce5,0x9e1f, 0x9ce7,0x51eb, + 0x9ce9,0x9e20, 0x9cf3,0x51e4, 0x9cf4,0x9e23, 0x9cf5,0x9e28, 0x9cf6,0x9e22, + 0x9d03,0x89d6, 0x9d06,0x9e29, 0x9d07,0x9e28, 0x9d08,0x96c1, 0x9d09,0x9e26, + 0x9d12,0x4ee4, 0x9d15,0x9e35, 0x9d1b,0x9e33, 0x9d1d,0x9e32, 0x9d1f,0x9e31, + 0x9d23,0x9e2a, 0x9d26,0x9e2f, 0x9d28,0x9e2d, 0x9d2f,0x9e38, 0x9d30,0x9e39, + 0x9d3b,0x9e3f, 0x9d3f,0x9e3d, 0x9d42,0x9e3a, 0x9d43,0x9e3c, 0x9d51,0x9e43, + 0x9d52,0x9e46, 0x9d53,0x9e41, 0x9d5c,0x9e48, 0x9d5d,0x9e45, 0x9d60,0x9e44, + 0x9d61,0x9e49, 0x9d6a,0x9e4c, 0x9d6c,0x9e4f, 0x9d6f,0x9e4e, 0x9d70,0x96d5, + 0x9d72,0x9e4a, 0x9d87,0x9e2b, 0x9d89,0x9e51, 0x9d98,0x9e55, 0x9d9a,0x9e57, + 0x9da9,0x9e5c, 0x9daf,0x83ba, 0x9db4,0x9e64, 0x9db8,0x5f31, 0x9dbb,0x9e58, + 0x9dbc,0x9e63, 0x9dbf,0x9e5a, 0x9dc2,0x9e5e, 0x9dd3,0x9e67, 0x9dd7,0x9e25, + 0x9dd9,0x9e37, 0x9dda,0x9e68, 0x9de5,0x9e36, 0x9de6,0x9e6a, 0x9def,0x9e69, + 0x9df0,0x71d5, 0x9df2,0x9e6b, 0x9df3,0x9e47, 0x9df8,0x9e6c, 0x9df9,0x9e70, + 0x9dfa,0x9e6d, 0x9e15,0x9e2c, 0x9e1a,0x9e66, 0x9e1b,0x9e73, 0x9e1d,0x9e42, + 0x9e1e,0x9e3e, 0x9e75,0x5364, 0x9e79,0x54b8, 0x9e7a,0x9e7e, 0x9e7c,0x7877, + 0x9e7d,0x76d0, 0x9e83,0x6d0b, 0x9e91,0x8c8c, 0x9e97,0x4e3d, 0x9ea4,0x7c97, + 0x9ea5,0x9ea6, 0x9ea9,0x9eb8, 0x9ead,0x5305, 0x9eb5,0x9762, 0x9ebc,0x4e48, + 0x9ec3,0x9ec4, 0x9ecc,0x9ec9, 0x9ede,0x70b9, 0x9ee8,0x515a, 0x9ef0,0x7f1c, + 0x9ef2,0x9eea, 0x9ef4,0x9709, 0x9ef7,0x9ee9, 0x9efd,0x9efe, 0x9eff,0x9f0b, + 0x9f07,0x9ccc, 0x9f09,0x9f0d, 0x9f1e,0x51ac, 0x9f34,0x9f39, 0x9f4a,0x9f50, + 0x9f4b,0x658b, 0x9f4e,0x8d4d, 0x9f4f,0x9f51, 0x9f52,0x9f7f, 0x9f54,0x9f80, + 0x9f59,0x9f85, 0x9f5c,0x9f87, 0x9f5f,0x9f83, 0x9f60,0x9f86, 0x9f61,0x9f84, + 0x9f63,0x51fa, 0x9f66,0x9f88, 0x9f67,0x556e, 0x9f6a,0x9f8a, 0x9f6c,0x9f89, + 0x9f70,0x548b, 0x9f72,0x9f8b, 0x9f76,0x816d, 0x9f77,0x9f8c, 0x9f8d,0x9f99, + 0x9f90,0x5e9e, 0x9f94,0x9f9a, 0x9f95,0x9f9b, 0x9f9c,0x9f9f, 0x9fa2,0x548c, + 0x9fa4,0x8c10, 0xfa0c,0x5140, 0xfe30,0xff1a, 0xfe31,0xff5c, 0xfe35,0xff08, + 0xfe3f,0x2227, 0xfe40,0x2228, 0xfe50,0xff0c, 0xfe51,0x3001, 0xfe52,0xff0e, + 0xfe54,0xff1b, 0xfe55,0xff1a, 0xfe56,0xff1f, 0xfe57,0xff01, 0xfe59,0xff08, + 0xfe5a,0xff09, 0xfe5b,0xff5b, 0xfe5c,0xff5d, 0xfe5d,0x3014, 0xfe5e,0x3015, + 0xfe5f,0xff03, 0xfe60,0xff06, 0xfe61,0xff0a, 0xfe68,0xff3c, 0xff02,0x201d, + 0xff07,0x2019, 0xffe2,0x300c, 0xffe4,0x2506 +}; + diff --git a/Packages/VXHanConvert/Sources/VXHanConvert/VXHanConvert.m b/Packages/VXHanConvert/Sources/VXHanConvert/VXHanConvert.m new file mode 100644 index 0000000000000000000000000000000000000000..b5dcba02b45a166b7c8b127cc61b077034572653 --- /dev/null +++ b/Packages/VXHanConvert/Sources/VXHanConvert/VXHanConvert.m @@ -0,0 +1,70 @@ + +#import "VXHanConvert.h" + +const size_t vxSC2TCTableSize = 8189; +extern unsigned short vxSC2TCTable[]; + +const size_t vxTC2SCTableSize = 3059; +extern unsigned short vxTC2SCTable[]; + +struct VXHCData +{ + unsigned short key, value; +}; + +int VXHCCompare(const void *a, const void *b) +{ + unsigned short x=((const struct VXHCData*)a)->key, y=((const struct VXHCData*)b)->key; + if (x==y) return 0; + if (xvalue; +} + +unsigned short VXUCS2TradToSimpChinese(unsigned short c) +{ + return VXHCFind(c, vxTC2SCTable, vxTC2SCTableSize); +} + +unsigned short VXUCS2SimpToTradChinese(unsigned short c) +{ + return VXHCFind(c, vxSC2TCTable, vxSC2TCTableSize); +} + +@implementation VXHanConvert + ++ (NSString *)convertToKangXiFrom:(NSString *)string NS_SWIFT_NAME(convertToKangXi(from:)) +{ + NSData *utf16Data = [string dataUsingEncoding:NSUTF16StringEncoding]; + unsigned short * bytes = (unsigned short *)utf16Data.bytes; + for(NSInteger i = 0; i < utf16Data.length; i++) { + unsigned short c = bytes[i]; + unsigned short value = VXUCS2TradToSimpChinese(c); + bytes[i] = value ? value : c; + } + + return [[NSString alloc] initWithData:utf16Data encoding:NSUTF16StringEncoding]; +} + ++ (NSString *)convertToTraditionalFrom:(NSString *)string NS_SWIFT_NAME(convertToTraditional(from:)) +{ + NSData *utf16Data = [string dataUsingEncoding:NSUTF16StringEncoding]; + unsigned short * bytes = (unsigned short *)utf16Data.bytes; + for(NSInteger i = 0; i < utf16Data.length; i++) { + unsigned short c = bytes[i]; + unsigned short value = VXUCS2SimpToTradChinese(c); + bytes[i] = value ? value : c; + } + + return [[NSString alloc] initWithData:utf16Data encoding:NSUTF16StringEncoding]; +} + +@end diff --git a/Packages/VXHanConvert/Sources/VXHanConvert/include/VXHanConvert.h b/Packages/VXHanConvert/Sources/VXHanConvert/include/VXHanConvert.h new file mode 100644 index 0000000000000000000000000000000000000000..b3fcb8d83b54f7d6518db373ce829b36662cc068 --- /dev/null +++ b/Packages/VXHanConvert/Sources/VXHanConvert/include/VXHanConvert.h @@ -0,0 +1,19 @@ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// The legacy chinese conversion library from OpenVanilla. +@interface VXHanConvert : NSObject + +/// Converts to Simplified Chinese from Traditional Chinese. +/// @param string The traditional Chinese text. ++ (NSString *)convertToKangXiFrom:(NSString *)string NS_SWIFT_NAME(convertToKangXi(from:)); + +/// Convert to Traditional Chinese from Simplified CHinese. +/// @param string The Simplified Chinese text. ++ (NSString *)convertToTraditionalFrom:(NSString *)string NS_SWIFT_NAME(convertToTraditional(from:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Packages/VXHanConvert/Tests/VXHanConvertTests/VXHanConvertTests.swift b/Packages/VXHanConvert/Tests/VXHanConvertTests/VXHanConvertTests.swift new file mode 100644 index 0000000000000000000000000000000000000000..0b816c7a86c58e62d2a24b90568e0bdc96b911c3 --- /dev/null +++ b/Packages/VXHanConvert/Tests/VXHanConvertTests/VXHanConvertTests.swift @@ -0,0 +1,17 @@ + +import XCTest +@testable import VXHanConvert + +final class VXHanConvertTests: XCTestCase { + func testSC2TC() { + let text = "简体中文转繁体中文" + let converted = VXHanConvert.convertToTraditional(from: text) + XCTAssert(converted == "簡體中文轉繁體中文") + } + + func testTC2SC() { + let text = "繁體中文轉簡體中文" + let converted = VXHanConvert.convertToKangXi(from: text) + XCTAssert(converted == "繁体中文转简体中文") + } +} diff --git a/README.markdown b/README.markdown deleted file mode 100644 index 359a83857f071dfcb74f540a39a8e18efe5a7187..0000000000000000000000000000000000000000 --- a/README.markdown +++ /dev/null @@ -1,14 +0,0 @@ -# OpenVanilla McBopomofo 小麥注音輸入法 - -## 開發流程 - -用 Xcode 開啟 `McBopomofo.xcodeproj`,選 "McBopomofo Installer" target,build 完之後直接執行該安裝程式,就可以安裝小麥注音。 - -第一次安裝完,日後程式碼或詞庫有任何修改,只要重複上述流程,再次安裝小麥注音即可。 - -要注意的是 macOS 可能會限制同一次 login session 能 kill 同一個輸入法 process 的次數(安裝程式透過 kill input method process 來讓新版的輸入法生效)。如果安裝若干次後,發現程式修改的結果並沒有出現,或甚至輸入法已無法再選用,只要登出目前帳號再重新登入即可。 - -## 軟體授權 - -本專案採用 MIT License 釋出,使用者可自由使用、散播本軟體,惟散播時必須完整保留版權聲明及軟體授權([詳全文](https://github.com/openvanilla/McBopomofo/blob/master/LICENSE.txt))。 - diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9265f9069098ed755a2542244cf65da3fc2396cb --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# vChewing 威注音输入法 + +威注音输入法由小麦注音分支而来(且词库内已经移除任何可以妨碍该输入法在世界上任何地方传播的内容),是原生简体中文注音输入法:相比中州韵(鼠须管)而言,威注音能够做到真正的大千声韵并击。 + +威注音分支专案及威注音词库由孙志贵(Shiki Suen)维护。小麦注音官方原始仓库內的词库的内容均与孙志贵无关。 + +## 系统需求 + +建置用系统需求:至少 macOS 10.15 Catalina & Xcode 12。// 原因:Swift 封包管理支持所需。 + +编译出的成品对应系统需求: + +- 至少 macOS El Capitan 10.11.5,否则无法处理 Unicode 8.0 的汉字。即便如此,仍需手动升级苹方至至少 macOS 10.12 开始随赠的版本、以支持 Unicode 8.0 的通用规范汉字表用字(全字库没有「𫫇」字)。 + + - 保留该系统支援的原因:非 Unibody 体型的 MacBook Pro 支援的最后一版 macOS 就是 El Capitan。 + +- **推荐最低系统版本**:macOS 10.12 Sierra,对 Unicode 8.0 开始的《通用规范汉字表》汉字有原生的苹方支持。 + + - 注:能装 macOS 10.13 High Sierra 就不要去碰 macOS 10.12 Sierra 这个半成品。 + +- 关于全字库支持,因下述事实而在理论上很难做到最完美: + + - 很可惜 GB18030-2005 并没有官方提供的逐字读音对照表,所以目前才用了全字库。然而全字库并不等于完美。 + + - 有条件者可以安装全字库字型与花园明朝,否则全字库等高万国码码位汉字恐无法在输入法的选字窗内完整显示。 + + - 全字库汉字显示支持会受到具体系统版本对万国码版本的支持的限制。 + + - 有些全字库汉字一开始会依赖万国码的私人造字区,且在之后被新版本万国码所支持。 + +## 建置流程 + +安装 Xcode 之后,请先配置 Xcode 允许其直接构建在专案所在的资料夹下的 build 资料夹内。步骤: +``` +「Xcode」->「Preferences...」->「Locations」; +「File」->「Project/WorkspaceSettings...」->「Advanced」; +选「Custom」->「Relative to Workspace」即可。不选的话,make 的过程会出错。 +``` +在终端机内定位到威注音的克隆本地专案的本地仓库的目录之后,执行 `make update` 以获取最新词库,在成功之后执行 `make` 即可组建。再执行 `make install` 可以触发威注音的安装程式。 + +第一次安装完,日后程式码或词库有任何修改,只要重复上述流程,再次安装威注音即可。 + +要注意的是 macOS 可能会限制同一次 login session 能终结同一个输入法的执行进程的次数(安装程式透过 kill input method process 来让新版的输入法生效)。如果安装若干次后,发现程式修改的结果并没有出现、或甚至输入法已无法再选用,只需要登出目前的 macOS 系统帐号、再重新登入即可。 + +补记: 该输入法是在 2021 年 11 月初「28ae7deb4092f067539cff600397292e66a5dd56」这一版小麦注音建置的基础上完成的。因为在清洗词库的时候清洗了全部的 git commit 历史,所以无法自动从小麦注音官方仓库上游继承任何改动,只能手动同步任何在此之后的程式修正。最近一次同步參照是小麦注音 2.0.1 版。 + +## 应用授权 + +小麦注音引擎程式版权(MIT 授权):© 2011-2021 OpenVanilla 专案团队。 + +威注音输入法 macOS 版以 3-Clause BSD License 授权释出 (与 MIT 相容):© 2021-2022 vChewing 专案。 + +威注音输入法 macOS 版程式维护:Shiki Suen。特别感谢 Hiraku Wong 等人的技术协力。 + +威注音词库由孙志贵维护,以 3-Clause BSD License 授权释出。 + +本专案采用 3-Clause BSD License 释出:使用者可自由使用、散播本软件,惟散播时必须完整保留版权声明及软件授权、且一旦经过修改便不可以再继续使用威注音的产品名称。 diff --git a/Source/3rdParty/AWFileHash/AWFileHash.h b/Source/3rdParty/AWFileHash/AWFileHash.h new file mode 100644 index 0000000000000000000000000000000000000000..029c8e359420527285a639a9a13dd5e2602bc410 --- /dev/null +++ b/Source/3rdParty/AWFileHash/AWFileHash.h @@ -0,0 +1,23 @@ +// +// AWFileHash.h +// Pods +// +// Created by Alexander Widerberg on 2015-02-17. +// +// + +#import + +@interface AWFileHash : NSObject + ++ (NSString *)md5HashOfData:(NSData *)data; ++ (NSString *)sha1HashOfData:(NSData *)data; ++ (NSString *)sha512HashOfData:(NSData *)data; ++ (NSString *)crc32HashOfData:(NSData *)data; + ++ (NSString *)md5HashOfFileAtPath:(NSString *)filePath; ++ (NSString *)sha1HashOfFileAtPath:(NSString *)filePath; ++ (NSString *)sha512HashOfFileAtPath:(NSString *)filePath; ++ (NSString *)crc32HashOfFileAtPath:(NSString *)filePath; + +@end diff --git a/Source/3rdParty/AWFileHash/AWFileHash.m b/Source/3rdParty/AWFileHash/AWFileHash.m new file mode 100644 index 0000000000000000000000000000000000000000..219cb1e663456d918697169024c3fad983210ad6 --- /dev/null +++ b/Source/3rdParty/AWFileHash/AWFileHash.m @@ -0,0 +1,348 @@ +// +// AWFileHash.m +// Pods +// +// Created by Alexander Widerberg on 2015-02-17. +// +// + +// Header file +#import "AWFileHash.h" + +// System framework and libraries +#include +#include +#include +#include + + +// Constants +size_t FileHashDefaultChunkSizeForReadingData = 4096; // in bytes + +// Function pointer types for functions used in the computation +// of a cryptographic hash. +typedef int (*FileHashInitFunction) (uint8_t *hashObjectPointer[]); +typedef int (*FileHashUpdateFunction) (uint8_t *hashObjectPointer[], const void *data, CC_LONG len); +typedef int (*FileHashFinalFunction) (unsigned char *md, uint8_t *hashObjectPointer[]); + +// Structure used to describe a hash computation context. +typedef struct _FileHashComputationContext { + FileHashInitFunction initFunction; + FileHashUpdateFunction updateFunction; + FileHashFinalFunction finalFunction; + size_t digestLength; + uint8_t **hashObjectPointer; +} FileHashComputationContext; + +#define MAX_READ_STREAM_STATUS_POLLING_ATTEMPTS 10 + +#define FileHashComputationContextInitialize(context, hashAlgorithmName) \ +CC_##hashAlgorithmName##_CTX hashObjectFor##hashAlgorithmName; \ +context.initFunction = (FileHashInitFunction)&CC_##hashAlgorithmName##_Init; \ +context.updateFunction = (FileHashUpdateFunction)&CC_##hashAlgorithmName##_Update; \ +context.finalFunction = (FileHashFinalFunction)&CC_##hashAlgorithmName##_Final; \ +context.digestLength = CC_##hashAlgorithmName##_DIGEST_LENGTH; \ +context.hashObjectPointer = (uint8_t **)&hashObjectFor##hashAlgorithmName + +#pragma mark - CRC32b implementation + +typedef struct { + CC_LONG crc; +} CC_CRC32_CTX; + +static int CC_CRC32_Init(CC_CRC32_CTX *c); +static int CC_CRC32_Update(CC_CRC32_CTX *c, const uint8_t *data, CC_LONG len); +static int CC_CRC32_Final(unsigned char *md, CC_CRC32_CTX *c); + +#define CC_CRC32_DIGEST_LENGTH 4 + +static CC_LONG crc32_tbl[256] = +{ + 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L, + 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, 0x0EDB8832L, 0x79DCB8A4L, + 0xE0D5E91EL, 0x97D2D988L, 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, + 0x90BF1D91L, 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, + 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, 0x136C9856L, + 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L, + 0xFA0F3D63L, 0x8D080DF5L, 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, + 0xA2677172L, 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, + 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L, + 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, 0x26D930ACL, 0x51DE003AL, + 0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, + 0xB8BDA50FL, 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, + 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, 0x76DC4190L, + 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL, + 0x9FBFE4A5L, 0xE8B8D433L, 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, + 0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, + 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 0x6C0695EDL, + 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, 0x65B0D9C6L, 0x12B7E950L, + 0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, + 0xFBD44C65L, 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, + 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, 0x4369E96AL, + 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 0x44042D73L, 0x33031DE5L, + 0xAA0A4C5FL, 0xDD0D7CC9L, 0x5005713CL, 0x270241AAL, 0xBE0B1010L, + 0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, + 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L, + 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, 0xEDB88320L, 0x9ABFB3B6L, + 0x03B6E20CL, 0x74B1D29AL, 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, + 0x73DC1683L, 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, + 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, 0xF00F9344L, + 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL, + 0x196C3671L, 0x6E6B06E7L, 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, + 0x67DD4ACCL, 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, + 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L, + 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, 0xD80D2BDAL, 0xAF0A1B4CL, + 0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, + 0x4669BE79L, 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, + 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, 0xC5BA3BBEL, + 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L, + 0x2CD99E8BL, 0x5BDEAE1DL, 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, + 0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, + 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 0x92D28E9BL, + 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, 0x86D3D2D4L, 0xF1D4E242L, + 0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, + 0x18B74777L, 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, + 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, 0xA00AE278L, + 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 0xA7672661L, 0xD06016F7L, + 0x4969474DL, 0x3E6E77DBL, 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, + 0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, + 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L, + 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, 0xB3667A2EL, 0xC4614AB8L, + 0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, + 0x2D02EF8DL +}; + +int CC_CRC32_Init(CC_CRC32_CTX *c) { + c->crc = 0xFFFFFFFFL; + return 0; +} + +int CC_CRC32_Update(CC_CRC32_CTX *c, const uint8_t *data, CC_LONG len) { + CC_LONG crc = c->crc; + + for(CC_LONG i=0; i>8) ^ crc32_tbl[(crc&0xFF) ^ *data++]; + } + + c->crc = crc; + + return 0; +} + +int CC_CRC32_Final(unsigned char *md, CC_CRC32_CTX *c) { + CC_LONG crc = c->crc; + + crc = crc ^ 0xFFFFFFFFL; + + md[0] = (crc & 0xff000000UL) >> 24; + md[1] = (crc & 0x00ff0000UL) >> 16; + md[2] = (crc & 0x0000ff00UL) >> 8; + md[3] = (crc & 0x000000ffUL) ; + + return 0; +} + +#pragma mark - Begin implementation + +@implementation AWFileHash + +#pragma mark - +#pragma mark private class helpers ++ (NSString *)hashOfFileAtPath:(NSString *)filePath withComputationContext:(FileHashComputationContext *)context { + NSString *result = nil; + CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)filePath, kCFURLPOSIXPathStyle, (Boolean)false); + CFReadStreamRef readStream = fileURL ? CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL) : NULL; + + BOOL didSucceed = readStream ? (BOOL)CFReadStreamOpen(readStream) : NO; + + // Race condition while running om multiple threads patched with big thanks to Aaron Morse + if (!didSucceed) { + if (readStream) CFRelease(readStream); + if (fileURL) CFRelease(fileURL); + return nil; + } + CFStreamStatus myStreamStatus; + NSUInteger attempts = 0; + do { + sleep(1); + myStreamStatus = CFReadStreamGetStatus(readStream); + if (attempts++ > MAX_READ_STREAM_STATUS_POLLING_ATTEMPTS) { + if (readStream) CFRelease(readStream); + if (fileURL) CFRelease(fileURL); + return nil; + } + } while ((myStreamStatus != kCFStreamStatusOpen) && (myStreamStatus != kCFStreamStatusError)); + + if (myStreamStatus == kCFStreamStatusError) { + if (readStream) CFRelease(readStream); + if (fileURL) CFRelease(fileURL); + return nil; + } + // End race condition check + + // Use default value for the chunk size for reading data. + const size_t chunkSizeForReadingData = FileHashDefaultChunkSizeForReadingData; + + // Initialize the hash object + (*context->initFunction)(context->hashObjectPointer); + + // Feed the data to the hash object. + BOOL hasMoreData = YES; + while (hasMoreData) { + uint8_t buffer[chunkSizeForReadingData]; + CFIndex readBytesCount = CFReadStreamRead(readStream, (UInt8 *)buffer, (CFIndex)sizeof(buffer)); + + if (readBytesCount == -1) { + break; + } else if (readBytesCount == 0) { + hasMoreData = NO; + } else { + (*context->updateFunction)(context->hashObjectPointer, (const void *)buffer, (CC_LONG)readBytesCount); + } + } + + // Compute the hash digest + unsigned char digest[context->digestLength]; + (*context->finalFunction)(digest, context->hashObjectPointer); + + // Close the read stream. + CFReadStreamClose(readStream); + + // Proceed if the read operation succeeded. + didSucceed = !hasMoreData; + if (didSucceed) { + char hash[2 * sizeof(digest) + 1]; + for (size_t i = 0; i < sizeof(digest); ++i) { + snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i])); + } + result = [NSString stringWithUTF8String:hash]; + } + + if (readStream) CFRelease(readStream); + if (fileURL) CFRelease(fileURL); + return result; +} + ++ (NSString *)hashOfNSData:(NSData *)data withComputationContext:(FileHashComputationContext *)context { + + NSString *result = nil; + BOOL didSucceed = NO; + + // Use default value for the chunk size for reading data. + size_t chunkSizeForReadingData = 0; + if(FileHashDefaultChunkSizeForReadingData > data.length) { + chunkSizeForReadingData = data.length; + } else { + chunkSizeForReadingData = FileHashDefaultChunkSizeForReadingData; + } + + // Initialize the hash object + (*context->initFunction)(context->hashObjectPointer); + + // Feed the data to the hash object. + BOOL hasMoreData = YES; + CFIndex readBytesCount = 0; + CFIndex totalOffset = 0; + NSRange range; + while (hasMoreData) { + uint8_t buffer[chunkSizeForReadingData]; + + readBytesCount = sizeof(buffer); + // Make sure that we read the correct amount of data + if(totalOffset+readBytesCount > data.length && !(totalOffset == data.length)) { + readBytesCount = (data.length-totalOffset); + } else if(totalOffset == data.length) { + readBytesCount = 0; + } else if(totalOffset > data.length) { + // This should not happen at any time (added for precaution) + break; + } + + range = NSMakeRange(totalOffset, readBytesCount); + + @try { + [data getBytes:buffer range:range]; + } + @catch (NSException *exception) { + NSLog(@"%@", exception.debugDescription); + break; + } + + totalOffset = totalOffset + readBytesCount; + + if (readBytesCount == -1) { + } else if (readBytesCount == 0) { + hasMoreData = NO; + } else { + (*context->updateFunction)(context->hashObjectPointer, (const void *)buffer, (CC_LONG)readBytesCount); + } + } + + // Compute the hash digest + unsigned char digest[context->digestLength]; + (*context->finalFunction)(digest, context->hashObjectPointer); + + // Proceed if the read operation succeeded. + didSucceed = !hasMoreData; + if (didSucceed) { + char hash[2 * sizeof(digest) + 1]; + for (size_t i = 0; i < sizeof(digest); ++i) { + snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i])); + } + result = [NSString stringWithUTF8String:hash]; + } + + return result; +} + +#pragma mark - +#pragma mark public class accessors ++ (NSString *)md5HashOfData:(NSData *)data { + FileHashComputationContext context; + FileHashComputationContextInitialize(context, MD5); + return [self hashOfNSData:data withComputationContext:&context]; +} + ++ (NSString *)sha1HashOfData:(NSData *)data { + FileHashComputationContext context; + FileHashComputationContextInitialize(context, SHA1); + return [self hashOfNSData:data withComputationContext:&context]; +} + ++ (NSString *)sha512HashOfData:(NSData *)data { + FileHashComputationContext context; + FileHashComputationContextInitialize(context, SHA512); + return [self hashOfNSData:data withComputationContext:&context]; +} + ++ (NSString *)crc32HashOfData:(NSData *)data { + FileHashComputationContext context; + FileHashComputationContextInitialize(context, CRC32); + return [self hashOfNSData:data withComputationContext:&context]; +} + ++ (NSString *)md5HashOfFileAtPath:(NSString *)filePath { + FileHashComputationContext context; + FileHashComputationContextInitialize(context, MD5); + return [self hashOfFileAtPath:filePath withComputationContext:&context]; +} + ++ (NSString *)sha1HashOfFileAtPath:(NSString *)filePath { + FileHashComputationContext context; + FileHashComputationContextInitialize(context, SHA1); + return [self hashOfFileAtPath:filePath withComputationContext:&context]; +} + ++ (NSString *)sha512HashOfFileAtPath:(NSString *)filePath { + FileHashComputationContext context; + FileHashComputationContextInitialize(context, SHA512); + return [self hashOfFileAtPath:filePath withComputationContext:&context]; +} + ++ (NSString *)crc32HashOfFileAtPath:(NSString *)filePath { + FileHashComputationContext context; + FileHashComputationContextInitialize(context, CRC32); + return [self hashOfFileAtPath:filePath withComputationContext:&context]; +} + +@end diff --git a/Source/3rdParty/OVMandarin/Mandarin.cpp b/Source/3rdParty/OVMandarin/Mandarin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2ca30a3dae7e2efdd171ec8c94f34f5849063976 --- /dev/null +++ b/Source/3rdParty/OVMandarin/Mandarin.cpp @@ -0,0 +1,1233 @@ + +#include "Mandarin.h" + +#include +#include + +namespace Taiyan { +namespace Mandarin { + +class PinyinParseHelper { + public: + static const bool ConsumePrefix(std::string& target, + const std::string& prefix) { + if (target.length() < prefix.length()) { + return false; + } + + if (target.substr(0, prefix.length()) == prefix) { + target = + target.substr(prefix.length(), target.length() - prefix.length()); + return true; + } + + return false; + } +}; + +class BopomofoCharacterMap { + public: + static const BopomofoCharacterMap& SharedInstance(); + + std::map componentToCharacter; + std::map characterToComponent; + + protected: + BopomofoCharacterMap(); +}; + +const BPMF BPMF::FromHanyuPinyin(const std::string& str) { + if (!str.length()) { + return BPMF(); + } + + std::string pinyin = str; + transform(pinyin.begin(), pinyin.end(), pinyin.begin(), ::tolower); + + BPMF::Component firstComponent = 0; + BPMF::Component secondComponent = 0; + BPMF::Component thirdComponent = 0; + BPMF::Component toneComponent = 0; + + // lookup consonants and consume them + bool independentConsonant = false; + + // the y exceptions fist + if (0) { + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "yuan")) { + secondComponent = BPMF::UE; + thirdComponent = BPMF::AN; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ying")) { + secondComponent = BPMF::I; + thirdComponent = BPMF::ENG; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "yung")) { + secondComponent = BPMF::UE; + thirdComponent = BPMF::ENG; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "yong")) { + secondComponent = BPMF::UE; + thirdComponent = BPMF::ENG; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "yue")) { + secondComponent = BPMF::UE; + thirdComponent = BPMF::E; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "yun")) { + secondComponent = BPMF::UE; + thirdComponent = BPMF::EN; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "you")) { + secondComponent = BPMF::I; + thirdComponent = BPMF::OU; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "yu")) { + secondComponent = BPMF::UE; + } + + // try the first character + char c = pinyin.length() ? pinyin[0] : 0; + switch (c) { + case 'b': + firstComponent = BPMF::B; + pinyin = pinyin.substr(1); + break; + case 'p': + firstComponent = BPMF::P; + pinyin = pinyin.substr(1); + break; + case 'm': + firstComponent = BPMF::M; + pinyin = pinyin.substr(1); + break; + case 'f': + firstComponent = BPMF::F; + pinyin = pinyin.substr(1); + break; + case 'd': + firstComponent = BPMF::D; + pinyin = pinyin.substr(1); + break; + case 't': + firstComponent = BPMF::T; + pinyin = pinyin.substr(1); + break; + case 'n': + firstComponent = BPMF::N; + pinyin = pinyin.substr(1); + break; + case 'l': + firstComponent = BPMF::L; + pinyin = pinyin.substr(1); + break; + case 'g': + firstComponent = BPMF::G; + pinyin = pinyin.substr(1); + break; + case 'k': + firstComponent = BPMF::K; + pinyin = pinyin.substr(1); + break; + case 'h': + firstComponent = BPMF::H; + pinyin = pinyin.substr(1); + break; + case 'j': + firstComponent = BPMF::J; + pinyin = pinyin.substr(1); + break; + case 'q': + firstComponent = BPMF::Q; + pinyin = pinyin.substr(1); + break; + case 'x': + firstComponent = BPMF::X; + pinyin = pinyin.substr(1); + break; + + // special hanlding for w and y + case 'w': + secondComponent = BPMF::U; + pinyin = pinyin.substr(1); + break; + case 'y': + if (!secondComponent && !thirdComponent) { + secondComponent = BPMF::I; + } + pinyin = pinyin.substr(1); + break; + } + + // then we try ZH, CH, SH, R, Z, C, S (in that order) + if (0) { + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "zh")) { + firstComponent = BPMF::ZH; + independentConsonant = true; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ch")) { + firstComponent = BPMF::CH; + independentConsonant = true; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "sh")) { + firstComponent = BPMF::SH; + independentConsonant = true; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "r")) { + firstComponent = BPMF::R; + independentConsonant = true; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "z")) { + firstComponent = BPMF::Z; + independentConsonant = true; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "c")) { + firstComponent = BPMF::C; + independentConsonant = true; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "s")) { + firstComponent = BPMF::S; + independentConsonant = true; + } + + // consume exceptions first: (ien, in), (iou, iu), (uen, un), (veng, iong), + // (ven, vn), (uei, ui), ung but longer sequence takes precedence + if (0) { + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "veng")) { + secondComponent = BPMF::UE; + thirdComponent = BPMF::ENG; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "iong")) { + secondComponent = BPMF::UE; + thirdComponent = BPMF::ENG; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ing")) { + secondComponent = BPMF::I; + thirdComponent = BPMF::ENG; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ien")) { + secondComponent = BPMF::I; + thirdComponent = BPMF::EN; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "iou")) { + secondComponent = BPMF::I; + thirdComponent = BPMF::OU; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "uen")) { + secondComponent = BPMF::U; + thirdComponent = BPMF::EN; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ven")) { + secondComponent = BPMF::UE; + thirdComponent = BPMF::EN; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "uei")) { + secondComponent = BPMF::U; + thirdComponent = BPMF::EI; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ung")) { + // f exception + if (firstComponent == BPMF::F) { + thirdComponent = BPMF::ENG; + } else { + secondComponent = BPMF::U; + thirdComponent = BPMF::ENG; + } + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ong")) { + // f exception + if (firstComponent == BPMF::F) { + thirdComponent = BPMF::ENG; + } else { + secondComponent = BPMF::U; + thirdComponent = BPMF::ENG; + } + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "un")) { + if (firstComponent == BPMF::J || firstComponent == BPMF::Q || + firstComponent == BPMF::X) { + secondComponent = BPMF::UE; + } else { + secondComponent = BPMF::U; + } + thirdComponent = BPMF::EN; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "iu")) { + secondComponent = BPMF::I; + thirdComponent = BPMF::OU; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "in")) { + secondComponent = BPMF::I; + thirdComponent = BPMF::EN; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "vn")) { + secondComponent = BPMF::UE; + thirdComponent = BPMF::EN; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ui")) { + secondComponent = BPMF::U; + thirdComponent = BPMF::EI; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ue")) { + secondComponent = BPMF::UE; + thirdComponent = BPMF::E; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, u8"ü")) { + secondComponent = BPMF::UE; + } + + // then consume the middle component... + if (0) { + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "i")) { + secondComponent = independentConsonant ? 0 : BPMF::I; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "u")) { + if (firstComponent == BPMF::J || firstComponent == BPMF::Q || + firstComponent == BPMF::X) { + secondComponent = BPMF::UE; + } else { + secondComponent = BPMF::U; + } + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "v")) { + secondComponent = BPMF::UE; + } + + // the vowels, longer sequence takes precedence + if (0) { + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ang")) { + thirdComponent = BPMF::ANG; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "eng")) { + thirdComponent = BPMF::ENG; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "err")) { + thirdComponent = BPMF::ERR; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ai")) { + thirdComponent = BPMF::AI; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ei")) { + thirdComponent = BPMF::EI; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ao")) { + thirdComponent = BPMF::AO; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "ou")) { + thirdComponent = BPMF::OU; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "an")) { + thirdComponent = BPMF::AN; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "en")) { + thirdComponent = BPMF::EN; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "er")) { + thirdComponent = BPMF::ERR; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "a")) { + thirdComponent = BPMF::A; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "o")) { + thirdComponent = BPMF::O; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "e")) { + if (secondComponent) { + thirdComponent = BPMF::E; + } else { + thirdComponent = BPMF::ER; + } + } + + // at last! + if (0) { + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "1")) { + toneComponent = BPMF::Tone1; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "2")) { + toneComponent = BPMF::Tone2; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "3")) { + toneComponent = BPMF::Tone3; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "4")) { + toneComponent = BPMF::Tone4; + } else if (PinyinParseHelper::ConsumePrefix(pinyin, "5")) { + toneComponent = BPMF::Tone5; + } + + return BPMF(firstComponent | secondComponent | thirdComponent | + toneComponent); +} + +const std::string BPMF::HanyuPinyinString(bool includesTone, + bool useVForUUmlaut) const { + std::string consonant, middle, vowel, tone; + + Component cc = consonantComponent(), mvc = middleVowelComponent(), + vc = vowelComponent(); + bool hasNoMVCOrVC = !(mvc || vc); + + switch (cc) { + case B: + consonant = "b"; + break; + case P: + consonant = "p"; + break; + case M: + consonant = "m"; + break; + case F: + consonant = "f"; + break; + case D: + consonant = "d"; + break; + case T: + consonant = "t"; + break; + case N: + consonant = "n"; + break; + case L: + consonant = "l"; + break; + case G: + consonant = "g"; + break; + case K: + consonant = "k"; + break; + case H: + consonant = "h"; + break; + case J: + consonant = "j"; + if (hasNoMVCOrVC) middle = "i"; + break; + case Q: + consonant = "q"; + if (hasNoMVCOrVC) middle = "i"; + break; + case X: + consonant = "x"; + if (hasNoMVCOrVC) middle = "i"; + break; + case ZH: + consonant = "zh"; + if (hasNoMVCOrVC) middle = "i"; + break; + case CH: + consonant = "ch"; + if (hasNoMVCOrVC) middle = "i"; + break; + case SH: + consonant = "sh"; + if (hasNoMVCOrVC) middle = "i"; + break; + case R: + consonant = "r"; + if (hasNoMVCOrVC) middle = "i"; + break; + case Z: + consonant = "z"; + if (hasNoMVCOrVC) middle = "i"; + break; + case C: + consonant = "c"; + if (hasNoMVCOrVC) middle = "i"; + break; + case S: + consonant = "s"; + if (hasNoMVCOrVC) middle = "i"; + break; + } + + switch (mvc) { + case I: + if (!cc) { + consonant = "y"; + } + + middle = (!vc || cc) ? "i" : ""; + break; + case U: + if (!cc) { + consonant = "w"; + } + middle = (!vc || cc) ? "u" : ""; + break; + case UE: + if (!cc) { + consonant = "y"; + } + + if ((cc == N || cc == L) && vc != E) { + middle = useVForUUmlaut ? "v" : "ü"; + } else { + middle = "u"; + } + + break; + } + + switch (vc) { + case A: + vowel = "a"; + break; + case O: + vowel = "o"; + break; + case ER: + vowel = "e"; + break; + case E: + vowel = "e"; + break; + case AI: + vowel = "ai"; + break; + case EI: + vowel = "ei"; + break; + case AO: + vowel = "ao"; + break; + case OU: + vowel = "ou"; + break; + case AN: + vowel = "an"; + break; + case EN: + vowel = "en"; + break; + case ANG: + vowel = "ang"; + break; + case ENG: + vowel = "eng"; + break; + case ERR: + vowel = "er"; + break; + } + + // combination rules + + // ueng -> ong, but note "weng" + if ((mvc == U || mvc == UE) && vc == ENG) { + middle = ""; + vowel = (cc == J || cc == Q || cc == X) + ? "iong" + : ((!cc && mvc == U) ? "eng" : "ong"); + } + + // ien, uen, üen -> in, un, ün ; but note "wen", "yin" and "yun" + if (mvc && vc == EN) { + if (cc) { + vowel = "n"; + } else { + if (mvc == UE) { + vowel = "n"; // yun + } else if (mvc == U) { + vowel = "en"; // wen + } else { + vowel = "in"; // yin + } + } + } + + // iou -> iu + if (cc && mvc == I && vc == OU) { + middle = ""; + vowel = "iu"; + } + + // ieng -> ing + if (mvc == I && vc == ENG) { + middle = ""; + vowel = "ing"; + } + + // uei -> ui + if (cc && mvc == U && vc == EI) { + middle = ""; + vowel = "ui"; + } + + if (includesTone) { + switch (toneMarkerComponent()) { + case Tone2: + tone = "2"; + break; + case Tone3: + tone = "3"; + break; + case Tone4: + tone = "4"; + break; + case Tone5: + tone = "5"; + break; + } + } + + return consonant + middle + vowel + tone; +} + +const std::string BPMF::PHTString(bool includesTone) const { + std::string consonant, middle, vowel, tone; + + Component cc = consonantComponent(), mvc = middleVowelComponent(), + vc = vowelComponent(); + bool hasNoMVCOrVC = !(mvc || vc); + + switch (cc) { + case B: + consonant = "p"; + break; + case P: + consonant = "ph"; + break; + case M: + consonant = "m"; + break; + case F: + consonant = "f"; + break; + case D: + consonant = "t"; + break; + case T: + consonant = "th"; + break; + case N: + consonant = "n"; + break; + case L: + consonant = "l"; + break; + case G: + consonant = "k"; + break; + case K: + consonant = "kh"; + break; + case H: + consonant = "h"; + break; + case J: + consonant = "ch"; + if (mvc != I) middle = "i"; + break; + case Q: + consonant = "chh"; + if (mvc != I) middle = "i"; + break; + case X: + consonant = "hs"; + if (mvc != I) middle = "i"; + break; + case ZH: + consonant = "ch"; + if (hasNoMVCOrVC) middle = "i"; + break; + case CH: + consonant = "chh"; + if (hasNoMVCOrVC) middle = "i"; + break; + case SH: + consonant = "sh"; + if (hasNoMVCOrVC) middle = "i"; + break; + case R: + consonant = "r"; + if (hasNoMVCOrVC) middle = "i"; + break; + case Z: + consonant = "ts"; + if (hasNoMVCOrVC) middle = "i"; + break; + case C: + consonant = "tsh"; + if (hasNoMVCOrVC) middle = "i"; + break; + case S: + consonant = "s"; + if (hasNoMVCOrVC) middle = "i"; + break; + } + + switch (mvc) { + case I: + middle = "i"; + break; + case U: + middle = "u"; + break; + case UE: + middle = "uu"; + break; + } + + switch (vc) { + case A: + vowel = "a"; + break; + case O: + vowel = "o"; + break; + case ER: + vowel = "e"; + break; + case E: + vowel = (!(cc || mvc)) ? "eh" : "e"; + break; + case AI: + vowel = "ai"; + break; + case EI: + vowel = "ei"; + break; + case AO: + vowel = "ao"; + break; + case OU: + vowel = "ou"; + break; + case AN: + vowel = "an"; + break; + case EN: + vowel = "en"; + break; + case ANG: + vowel = "ang"; + break; + case ENG: + vowel = "eng"; + break; + case ERR: + vowel = "err"; + break; + } + + // ieng -> ing + if (mvc == I && vc == ENG) { + middle = ""; + vowel = "ing"; + } + + // zh/ch + i without third component -> append h + if (cc == BPMF::ZH || cc == BPMF::CH) { + if (!mvc && !vc) { + vowel = "h"; + } + } + + if (includesTone) { + switch (toneMarkerComponent()) { + case Tone2: + tone = "2"; + break; + case Tone3: + tone = "3"; + break; + case Tone4: + tone = "4"; + break; + case Tone5: + tone = "5"; + break; + } + } + + return consonant + middle + vowel + tone; +} + +const BPMF BPMF::FromPHT(const std::string& str) { + if (!str.length()) { + return BPMF(); + } + + std::string pht = str; + transform(pht.begin(), pht.end(), pht.begin(), ::tolower); + + BPMF::Component firstComponent = 0; + BPMF::Component secondComponent = 0; + BPMF::Component thirdComponent = 0; + BPMF::Component toneComponent = 0; + +#define IF_CONSUME1(k, v) \ + else if (PinyinParseHelper::ConsumePrefix(pht, k)) { \ + firstComponent = v; \ + } + + // consume the first part + if (0) { + } + IF_CONSUME1("ph", BPMF::P) + IF_CONSUME1("p", BPMF::B) + IF_CONSUME1("m", BPMF::M) + IF_CONSUME1("f", BPMF::F) + IF_CONSUME1("th", BPMF::T) + IF_CONSUME1("n", BPMF::N) + IF_CONSUME1("l", BPMF::L) + IF_CONSUME1("kh", BPMF::K) + IF_CONSUME1("k", BPMF::G) + IF_CONSUME1("chh", BPMF::Q) + IF_CONSUME1("ch", BPMF::J) + IF_CONSUME1("hs", BPMF::X) + IF_CONSUME1("sh", BPMF::SH) + IF_CONSUME1("r", BPMF::R) + IF_CONSUME1("tsh", BPMF::C) + IF_CONSUME1("ts", BPMF::Z) + IF_CONSUME1("s", BPMF::S) + IF_CONSUME1("t", BPMF::D) + IF_CONSUME1("h", BPMF::H) + +#define IF_CONSUME2(k, v) \ + else if (PinyinParseHelper::ConsumePrefix(pht, k)) { \ + secondComponent = v; \ + } + // consume the second part + if (0) { + } else if (PinyinParseHelper::ConsumePrefix(pht, "ing")) { + secondComponent = BPMF::I; + thirdComponent = BPMF::ENG; + } else if (PinyinParseHelper::ConsumePrefix(pht, "ih")) { + if (firstComponent == BPMF::J) { + firstComponent = BPMF::ZH; + } else if (firstComponent == BPMF::Q) { + firstComponent = BPMF::CH; + } + } + IF_CONSUME2("i", BPMF::I) + IF_CONSUME2("uu", BPMF::UE) + IF_CONSUME2("u", BPMF::U) + +#undef IF_CONSUME1 +#undef IF_CONSUME2 + + // the vowels, longer sequence takes precedence + if (0) { + } else if (PinyinParseHelper::ConsumePrefix(pht, "ang")) { + thirdComponent = BPMF::ANG; + } else if (PinyinParseHelper::ConsumePrefix(pht, "eng")) { + thirdComponent = BPMF::ENG; + } else if (PinyinParseHelper::ConsumePrefix(pht, "err")) { + thirdComponent = BPMF::ERR; + } else if (PinyinParseHelper::ConsumePrefix(pht, "ai")) { + thirdComponent = BPMF::AI; + } else if (PinyinParseHelper::ConsumePrefix(pht, "ei")) { + thirdComponent = BPMF::EI; + } else if (PinyinParseHelper::ConsumePrefix(pht, "ao")) { + thirdComponent = BPMF::AO; + } else if (PinyinParseHelper::ConsumePrefix(pht, "ou")) { + thirdComponent = BPMF::OU; + } else if (PinyinParseHelper::ConsumePrefix(pht, "an")) { + thirdComponent = BPMF::AN; + } else if (PinyinParseHelper::ConsumePrefix(pht, "en")) { + thirdComponent = BPMF::EN; + } else if (PinyinParseHelper::ConsumePrefix(pht, "er")) { + thirdComponent = BPMF::ERR; + } else if (PinyinParseHelper::ConsumePrefix(pht, "a")) { + thirdComponent = BPMF::A; + } else if (PinyinParseHelper::ConsumePrefix(pht, "o")) { + thirdComponent = BPMF::O; + } else if (PinyinParseHelper::ConsumePrefix(pht, "eh")) { + thirdComponent = BPMF::E; + } else if (PinyinParseHelper::ConsumePrefix(pht, "e")) { + if (secondComponent) { + thirdComponent = BPMF::E; + } else { + thirdComponent = BPMF::ER; + } + } + + // fix ch/chh mappings + Component corresponding = 0; + if (firstComponent == BPMF::J) { + corresponding = BPMF::ZH; + } else if (firstComponent == BPMF::Q) { + corresponding = BPMF::CH; + } + + if (corresponding) { + if (secondComponent == BPMF::I && !thirdComponent) { + // if the second component is I and there's no third component, we use the + // corresponding part firstComponent = corresponding; + } else if (secondComponent == BPMF::U) { + // if second component is U, we use the corresponding part + firstComponent = corresponding; + } else if (!secondComponent) { + // if there's no second component, it must be a corresponding part + firstComponent = corresponding; + } + } + + if (secondComponent == BPMF::I) { + // fixes a few impossible occurances + switch (firstComponent) { + case BPMF::ZH: + case BPMF::CH: + case BPMF::SH: + case BPMF::R: + case BPMF::Z: + case BPMF::C: + case BPMF::S: + secondComponent = 0; + } + } + + // at last! + if (0) { + } else if (PinyinParseHelper::ConsumePrefix(pht, "1")) { + toneComponent = BPMF::Tone1; + } else if (PinyinParseHelper::ConsumePrefix(pht, "2")) { + toneComponent = BPMF::Tone2; + } else if (PinyinParseHelper::ConsumePrefix(pht, "3")) { + toneComponent = BPMF::Tone3; + } else if (PinyinParseHelper::ConsumePrefix(pht, "4")) { + toneComponent = BPMF::Tone4; + } else if (PinyinParseHelper::ConsumePrefix(pht, "5")) { + toneComponent = BPMF::Tone5; + } + + return BPMF(firstComponent | secondComponent | thirdComponent | + toneComponent); +} + +const BPMF BPMF::FromComposedString(const std::string& str) { + BPMF syllable; + auto iter = str.begin(); + while (iter != str.end()) { + // This is a naive implementation and we bail early at anything we don't + // recognize. A sound implementation would require to either use a trie for + // the Bopomofo character map or to split the input by codepoints. This + // suffices for now. + + // Illegal. + if (!(*iter & 0x80)) { + break; + } + + size_t utf8_length = -1; + + // These are the code points for the tone markers. + if ((*iter & (0x80 | 0x40)) && !(*iter & 0x20)) { + utf8_length = 2; + } else if ((*iter & (0x80 | 0x40 | 0x20)) && !(*iter & 0x10)) { + utf8_length = 3; + } else { + // Illegal. + break; + } + + if (iter + (utf8_length - 1) == str.end()) { + break; + } + + std::string component = std::string(iter, iter + utf8_length); + const std::map& charToComp = + BopomofoCharacterMap::SharedInstance().characterToComponent; + std::map::const_iterator result = + charToComp.find(component); + if (result == charToComp.end()) { + break; + } else { + syllable += BPMF((*result).second); + } + iter += utf8_length; + } + return syllable; +} + +const std::string BPMF::composedString() const { + std::string result; +#define APPEND(c) \ + if (syllable_ & c) \ + result += \ + (*BopomofoCharacterMap::SharedInstance().componentToCharacter.find( \ + syllable_ & c)) \ + .second + APPEND(ConsonantMask); + APPEND(MiddleVowelMask); + APPEND(VowelMask); + APPEND(ToneMarkerMask); +#undef APPEND + return result; +} + + + +const BopomofoCharacterMap& BopomofoCharacterMap::SharedInstance() { + static BopomofoCharacterMap* map = new BopomofoCharacterMap(); + return *map; +} + +BopomofoCharacterMap::BopomofoCharacterMap() { + characterToComponent[u8"ㄅ"] = BPMF::B; + characterToComponent[u8"ㄆ"] = BPMF::P; + characterToComponent[u8"ㄇ"] = BPMF::M; + characterToComponent[u8"ㄈ"] = BPMF::F; + characterToComponent[u8"ㄉ"] = BPMF::D; + characterToComponent[u8"ㄊ"] = BPMF::T; + characterToComponent[u8"ㄋ"] = BPMF::N; + characterToComponent[u8"ㄌ"] = BPMF::L; + characterToComponent[u8"ㄎ"] = BPMF::K; + characterToComponent[u8"ㄍ"] = BPMF::G; + characterToComponent[u8"ㄏ"] = BPMF::H; + characterToComponent[u8"ㄐ"] = BPMF::J; + characterToComponent[u8"ㄑ"] = BPMF::Q; + characterToComponent[u8"ㄒ"] = BPMF::X; + characterToComponent[u8"ㄓ"] = BPMF::ZH; + characterToComponent[u8"ㄔ"] = BPMF::CH; + characterToComponent[u8"ㄕ"] = BPMF::SH; + characterToComponent[u8"ㄖ"] = BPMF::R; + characterToComponent[u8"ㄗ"] = BPMF::Z; + characterToComponent[u8"ㄘ"] = BPMF::C; + characterToComponent[u8"ㄙ"] = BPMF::S; + characterToComponent[u8"ㄧ"] = BPMF::I; + characterToComponent[u8"ㄨ"] = BPMF::U; + characterToComponent[u8"ㄩ"] = BPMF::UE; + characterToComponent[u8"ㄚ"] = BPMF::A; + characterToComponent[u8"ㄛ"] = BPMF::O; + characterToComponent[u8"ㄜ"] = BPMF::ER; + characterToComponent[u8"ㄝ"] = BPMF::E; + characterToComponent[u8"ㄞ"] = BPMF::AI; + characterToComponent[u8"ㄟ"] = BPMF::EI; + characterToComponent[u8"ㄠ"] = BPMF::AO; + characterToComponent[u8"ㄡ"] = BPMF::OU; + characterToComponent[u8"ㄢ"] = BPMF::AN; + characterToComponent[u8"ㄣ"] = BPMF::EN; + characterToComponent[u8"ㄤ"] = BPMF::ANG; + characterToComponent[u8"ㄥ"] = BPMF::ENG; + characterToComponent[u8"ㄦ"] = BPMF::ERR; + characterToComponent[u8"ˊ"] = BPMF::Tone2; + characterToComponent[u8"ˇ"] = BPMF::Tone3; + characterToComponent[u8"ˋ"] = BPMF::Tone4; + characterToComponent[u8"˙"] = BPMF::Tone5; + + for (std::map::iterator iter = + characterToComponent.begin(); + iter != characterToComponent.end(); ++iter) + componentToCharacter[(*iter).second] = (*iter).first; +} + +#define ASSIGNKEY1(m, vec, k, val) \ + m[k] = (vec.clear(), vec.push_back((BPMF::Component)val), vec) +#define ASSIGNKEY2(m, vec, k, val1, val2) \ + m[k] = (vec.clear(), vec.push_back((BPMF::Component)val1), \ + vec.push_back((BPMF::Component)val2), vec) +#define ASSIGNKEY3(m, vec, k, val1, val2, val3) \ + m[k] = (vec.clear(), vec.push_back((BPMF::Component)val1), \ + vec.push_back((BPMF::Component)val2), \ + vec.push_back((BPMF::Component)val3), vec) + +static BopomofoKeyboardLayout* CreateStandardLayout() { + std::vector vec; + BopomofoKeyToComponentMap ktcm; + + ASSIGNKEY1(ktcm, vec, '1', BPMF::B); + ASSIGNKEY1(ktcm, vec, 'q', BPMF::P); + ASSIGNKEY1(ktcm, vec, 'a', BPMF::M); + ASSIGNKEY1(ktcm, vec, 'z', BPMF::F); + ASSIGNKEY1(ktcm, vec, '2', BPMF::D); + ASSIGNKEY1(ktcm, vec, 'w', BPMF::T); + ASSIGNKEY1(ktcm, vec, 's', BPMF::N); + ASSIGNKEY1(ktcm, vec, 'x', BPMF::L); + ASSIGNKEY1(ktcm, vec, 'e', BPMF::G); + ASSIGNKEY1(ktcm, vec, 'd', BPMF::K); + ASSIGNKEY1(ktcm, vec, 'c', BPMF::H); + ASSIGNKEY1(ktcm, vec, 'r', BPMF::J); + ASSIGNKEY1(ktcm, vec, 'f', BPMF::Q); + ASSIGNKEY1(ktcm, vec, 'v', BPMF::X); + ASSIGNKEY1(ktcm, vec, '5', BPMF::ZH); + ASSIGNKEY1(ktcm, vec, 't', BPMF::CH); + ASSIGNKEY1(ktcm, vec, 'g', BPMF::SH); + ASSIGNKEY1(ktcm, vec, 'b', BPMF::R); + ASSIGNKEY1(ktcm, vec, 'y', BPMF::Z); + ASSIGNKEY1(ktcm, vec, 'h', BPMF::C); + ASSIGNKEY1(ktcm, vec, 'n', BPMF::S); + ASSIGNKEY1(ktcm, vec, 'u', BPMF::I); + ASSIGNKEY1(ktcm, vec, 'j', BPMF::U); + ASSIGNKEY1(ktcm, vec, 'm', BPMF::UE); + ASSIGNKEY1(ktcm, vec, '8', BPMF::A); + ASSIGNKEY1(ktcm, vec, 'i', BPMF::O); + ASSIGNKEY1(ktcm, vec, 'k', BPMF::ER); + ASSIGNKEY1(ktcm, vec, ',', BPMF::E); + ASSIGNKEY1(ktcm, vec, '9', BPMF::AI); + ASSIGNKEY1(ktcm, vec, 'o', BPMF::EI); + ASSIGNKEY1(ktcm, vec, 'l', BPMF::AO); + ASSIGNKEY1(ktcm, vec, '.', BPMF::OU); + ASSIGNKEY1(ktcm, vec, '0', BPMF::AN); + ASSIGNKEY1(ktcm, vec, 'p', BPMF::EN); + ASSIGNKEY1(ktcm, vec, ';', BPMF::ANG); + ASSIGNKEY1(ktcm, vec, '/', BPMF::ENG); + ASSIGNKEY1(ktcm, vec, '-', BPMF::ERR); + ASSIGNKEY1(ktcm, vec, '3', BPMF::Tone3); + ASSIGNKEY1(ktcm, vec, '4', BPMF::Tone4); + ASSIGNKEY1(ktcm, vec, '6', BPMF::Tone2); + ASSIGNKEY1(ktcm, vec, '7', BPMF::Tone5); + + return new BopomofoKeyboardLayout(ktcm, "Standard"); +} + +static BopomofoKeyboardLayout* CreateIBMLayout() { + std::vector vec; + BopomofoKeyToComponentMap ktcm; + + ASSIGNKEY1(ktcm, vec, '1', BPMF::B); + ASSIGNKEY1(ktcm, vec, '2', BPMF::P); + ASSIGNKEY1(ktcm, vec, '3', BPMF::M); + ASSIGNKEY1(ktcm, vec, '4', BPMF::F); + ASSIGNKEY1(ktcm, vec, '5', BPMF::D); + ASSIGNKEY1(ktcm, vec, '6', BPMF::T); + ASSIGNKEY1(ktcm, vec, '7', BPMF::N); + ASSIGNKEY1(ktcm, vec, '8', BPMF::L); + ASSIGNKEY1(ktcm, vec, '9', BPMF::G); + ASSIGNKEY1(ktcm, vec, '0', BPMF::K); + ASSIGNKEY1(ktcm, vec, '-', BPMF::H); + ASSIGNKEY1(ktcm, vec, 'q', BPMF::J); + ASSIGNKEY1(ktcm, vec, 'w', BPMF::Q); + ASSIGNKEY1(ktcm, vec, 'e', BPMF::X); + ASSIGNKEY1(ktcm, vec, 'r', BPMF::ZH); + ASSIGNKEY1(ktcm, vec, 't', BPMF::CH); + ASSIGNKEY1(ktcm, vec, 'y', BPMF::SH); + ASSIGNKEY1(ktcm, vec, 'u', BPMF::R); + ASSIGNKEY1(ktcm, vec, 'i', BPMF::Z); + ASSIGNKEY1(ktcm, vec, 'o', BPMF::C); + ASSIGNKEY1(ktcm, vec, 'p', BPMF::S); + ASSIGNKEY1(ktcm, vec, 'a', BPMF::I); + ASSIGNKEY1(ktcm, vec, 's', BPMF::U); + ASSIGNKEY1(ktcm, vec, 'd', BPMF::UE); + ASSIGNKEY1(ktcm, vec, 'f', BPMF::A); + ASSIGNKEY1(ktcm, vec, 'g', BPMF::O); + ASSIGNKEY1(ktcm, vec, 'h', BPMF::ER); + ASSIGNKEY1(ktcm, vec, 'j', BPMF::E); + ASSIGNKEY1(ktcm, vec, 'k', BPMF::AI); + ASSIGNKEY1(ktcm, vec, 'l', BPMF::EI); + ASSIGNKEY1(ktcm, vec, ';', BPMF::AO); + ASSIGNKEY1(ktcm, vec, 'z', BPMF::OU); + ASSIGNKEY1(ktcm, vec, 'x', BPMF::AN); + ASSIGNKEY1(ktcm, vec, 'c', BPMF::EN); + ASSIGNKEY1(ktcm, vec, 'v', BPMF::ANG); + ASSIGNKEY1(ktcm, vec, 'b', BPMF::ENG); + ASSIGNKEY1(ktcm, vec, 'n', BPMF::ERR); + ASSIGNKEY1(ktcm, vec, 'm', BPMF::Tone2); + ASSIGNKEY1(ktcm, vec, ',', BPMF::Tone3); + ASSIGNKEY1(ktcm, vec, '.', BPMF::Tone4); + ASSIGNKEY1(ktcm, vec, '/', BPMF::Tone5); + + return new BopomofoKeyboardLayout(ktcm, "IBM"); +} + +static BopomofoKeyboardLayout* CreateETenLayout() { + std::vector vec; + BopomofoKeyToComponentMap ktcm; + + ASSIGNKEY1(ktcm, vec, 'b', BPMF::B); + ASSIGNKEY1(ktcm, vec, 'p', BPMF::P); + ASSIGNKEY1(ktcm, vec, 'm', BPMF::M); + ASSIGNKEY1(ktcm, vec, 'f', BPMF::F); + ASSIGNKEY1(ktcm, vec, 'd', BPMF::D); + ASSIGNKEY1(ktcm, vec, 't', BPMF::T); + ASSIGNKEY1(ktcm, vec, 'n', BPMF::N); + ASSIGNKEY1(ktcm, vec, 'l', BPMF::L); + ASSIGNKEY1(ktcm, vec, 'v', BPMF::G); + ASSIGNKEY1(ktcm, vec, 'k', BPMF::K); + ASSIGNKEY1(ktcm, vec, 'h', BPMF::H); + ASSIGNKEY1(ktcm, vec, 'g', BPMF::J); + ASSIGNKEY1(ktcm, vec, '7', BPMF::Q); + ASSIGNKEY1(ktcm, vec, 'c', BPMF::X); + ASSIGNKEY1(ktcm, vec, ',', BPMF::ZH); + ASSIGNKEY1(ktcm, vec, '.', BPMF::CH); + ASSIGNKEY1(ktcm, vec, '/', BPMF::SH); + ASSIGNKEY1(ktcm, vec, 'j', BPMF::R); + ASSIGNKEY1(ktcm, vec, ';', BPMF::Z); + ASSIGNKEY1(ktcm, vec, '\'', BPMF::C); + ASSIGNKEY1(ktcm, vec, 's', BPMF::S); + ASSIGNKEY1(ktcm, vec, 'e', BPMF::I); + ASSIGNKEY1(ktcm, vec, 'x', BPMF::U); + ASSIGNKEY1(ktcm, vec, 'u', BPMF::UE); + ASSIGNKEY1(ktcm, vec, 'a', BPMF::A); + ASSIGNKEY1(ktcm, vec, 'o', BPMF::O); + ASSIGNKEY1(ktcm, vec, 'r', BPMF::ER); + ASSIGNKEY1(ktcm, vec, 'w', BPMF::E); + ASSIGNKEY1(ktcm, vec, 'i', BPMF::AI); + ASSIGNKEY1(ktcm, vec, 'q', BPMF::EI); + ASSIGNKEY1(ktcm, vec, 'z', BPMF::AO); + ASSIGNKEY1(ktcm, vec, 'y', BPMF::OU); + ASSIGNKEY1(ktcm, vec, '8', BPMF::AN); + ASSIGNKEY1(ktcm, vec, '9', BPMF::EN); + ASSIGNKEY1(ktcm, vec, '0', BPMF::ANG); + ASSIGNKEY1(ktcm, vec, '-', BPMF::ENG); + ASSIGNKEY1(ktcm, vec, '=', BPMF::ERR); + ASSIGNKEY1(ktcm, vec, '2', BPMF::Tone2); + ASSIGNKEY1(ktcm, vec, '3', BPMF::Tone3); + ASSIGNKEY1(ktcm, vec, '4', BPMF::Tone4); + ASSIGNKEY1(ktcm, vec, '1', BPMF::Tone5); + + return new BopomofoKeyboardLayout(ktcm, "ETen"); +} + +static BopomofoKeyboardLayout* CreateHsuLayout() { + std::vector vec; + BopomofoKeyToComponentMap ktcm; + + ASSIGNKEY1(ktcm, vec, 'b', BPMF::B); + ASSIGNKEY1(ktcm, vec, 'p', BPMF::P); + ASSIGNKEY2(ktcm, vec, 'm', BPMF::M, BPMF::AN); + ASSIGNKEY2(ktcm, vec, 'f', BPMF::F, BPMF::Tone3); + ASSIGNKEY2(ktcm, vec, 'd', BPMF::D, BPMF::Tone2); + ASSIGNKEY1(ktcm, vec, 't', BPMF::T); + ASSIGNKEY2(ktcm, vec, 'n', BPMF::N, BPMF::EN); + ASSIGNKEY3(ktcm, vec, 'l', BPMF::L, BPMF::ENG, BPMF::ERR); + ASSIGNKEY2(ktcm, vec, 'g', BPMF::G, BPMF::ER); + ASSIGNKEY2(ktcm, vec, 'k', BPMF::K, BPMF::ANG); + ASSIGNKEY2(ktcm, vec, 'h', BPMF::H, BPMF::O); + ASSIGNKEY3(ktcm, vec, 'j', BPMF::J, BPMF::ZH, BPMF::Tone4); + ASSIGNKEY2(ktcm, vec, 'v', BPMF::Q, BPMF::CH); + ASSIGNKEY2(ktcm, vec, 'c', BPMF::X, BPMF::SH); + ASSIGNKEY1(ktcm, vec, 'r', BPMF::R); + ASSIGNKEY1(ktcm, vec, 'z', BPMF::Z); + ASSIGNKEY2(ktcm, vec, 'a', BPMF::C, BPMF::EI); + ASSIGNKEY2(ktcm, vec, 's', BPMF::S, BPMF::Tone5); + ASSIGNKEY2(ktcm, vec, 'e', BPMF::I, BPMF::E); + ASSIGNKEY1(ktcm, vec, 'x', BPMF::U); + ASSIGNKEY1(ktcm, vec, 'u', BPMF::UE); + ASSIGNKEY1(ktcm, vec, 'y', BPMF::A); + ASSIGNKEY1(ktcm, vec, 'i', BPMF::AI); + ASSIGNKEY1(ktcm, vec, 'w', BPMF::AO); + ASSIGNKEY1(ktcm, vec, 'o', BPMF::OU); + + return new BopomofoKeyboardLayout(ktcm, "Hsu"); +} + +static BopomofoKeyboardLayout* CreateETen26Layout() { + std::vector vec; + BopomofoKeyToComponentMap ktcm; + + ASSIGNKEY1(ktcm, vec, 'b', BPMF::B); + ASSIGNKEY2(ktcm, vec, 'p', BPMF::P, BPMF::OU); + ASSIGNKEY2(ktcm, vec, 'm', BPMF::M, BPMF::AN); + ASSIGNKEY2(ktcm, vec, 'f', BPMF::F, BPMF::Tone2); + ASSIGNKEY2(ktcm, vec, 'd', BPMF::D, BPMF::Tone5); + ASSIGNKEY2(ktcm, vec, 't', BPMF::T, BPMF::ANG); + ASSIGNKEY2(ktcm, vec, 'n', BPMF::N, BPMF::EN); + ASSIGNKEY2(ktcm, vec, 'l', BPMF::L, BPMF::ENG); + ASSIGNKEY2(ktcm, vec, 'v', BPMF::G, BPMF::Q); + ASSIGNKEY2(ktcm, vec, 'k', BPMF::K, BPMF::Tone4); + ASSIGNKEY2(ktcm, vec, 'h', BPMF::H, BPMF::ERR); + ASSIGNKEY2(ktcm, vec, 'g', BPMF::ZH, BPMF::J); + ASSIGNKEY2(ktcm, vec, 'c', BPMF::SH, BPMF::X); + ASSIGNKEY1(ktcm, vec, 'y', BPMF::CH); + ASSIGNKEY2(ktcm, vec, 'j', BPMF::R, BPMF::Tone3); + ASSIGNKEY2(ktcm, vec, 'q', BPMF::Z, BPMF::EI); + ASSIGNKEY2(ktcm, vec, 'w', BPMF::C, BPMF::E); + ASSIGNKEY1(ktcm, vec, 's', BPMF::S); + ASSIGNKEY1(ktcm, vec, 'e', BPMF::I); + ASSIGNKEY1(ktcm, vec, 'x', BPMF::U); + ASSIGNKEY1(ktcm, vec, 'u', BPMF::UE); + ASSIGNKEY1(ktcm, vec, 'a', BPMF::A); + ASSIGNKEY1(ktcm, vec, 'o', BPMF::O); + ASSIGNKEY1(ktcm, vec, 'r', BPMF::ER); + ASSIGNKEY1(ktcm, vec, 'i', BPMF::AI); + ASSIGNKEY1(ktcm, vec, 'z', BPMF::AO); + return new BopomofoKeyboardLayout(ktcm, "ETen26"); +} + +static BopomofoKeyboardLayout* CreateHanyuPinyinLayout() { + BopomofoKeyToComponentMap ktcm; + return new BopomofoKeyboardLayout(ktcm, "HanyuPinyin"); +} + +const BopomofoKeyboardLayout* BopomofoKeyboardLayout::StandardLayout() { + static BopomofoKeyboardLayout* layout = CreateStandardLayout(); + return layout; +} + +const BopomofoKeyboardLayout* BopomofoKeyboardLayout::ETenLayout() { + static BopomofoKeyboardLayout* layout = CreateETenLayout(); + return layout; +} + +const BopomofoKeyboardLayout* BopomofoKeyboardLayout::HsuLayout() { + static BopomofoKeyboardLayout* layout = CreateHsuLayout(); + return layout; +} + +const BopomofoKeyboardLayout* BopomofoKeyboardLayout::ETen26Layout() { + static BopomofoKeyboardLayout* layout = CreateETen26Layout(); + return layout; +} + +const BopomofoKeyboardLayout* BopomofoKeyboardLayout::IBMLayout() { + static BopomofoKeyboardLayout* layout = CreateIBMLayout(); + return layout; +} + +const BopomofoKeyboardLayout* BopomofoKeyboardLayout::HanyuPinyinLayout() { + static BopomofoKeyboardLayout* layout = CreateHanyuPinyinLayout(); + return layout; +} + +} // namespace Mandarin +} // namespace Taiyan diff --git a/Source/3rdParty/OVMandarin/Mandarin.h b/Source/3rdParty/OVMandarin/Mandarin.h new file mode 100644 index 0000000000000000000000000000000000000000..0de4563ef3d3b50399b6418fd538b1c0c8ec83cd --- /dev/null +++ b/Source/3rdParty/OVMandarin/Mandarin.h @@ -0,0 +1,499 @@ + +#ifndef MANDARIN_H_ +#define MANDARIN_H_ + +#include +#include +#include +#include + +namespace Taiyan { +namespace Mandarin { + +class BopomofoSyllable { + public: + typedef uint16_t Component; + + explicit BopomofoSyllable(Component syllable = 0) : syllable_(syllable) {} + + BopomofoSyllable(const BopomofoSyllable&) = default; + BopomofoSyllable(BopomofoSyllable&& another) = default; + BopomofoSyllable& operator=(const BopomofoSyllable&) = default; + BopomofoSyllable& operator=(BopomofoSyllable&&) = default; + + // takes the ASCII-form, "v"-tolerant, TW-style Hanyu Pinyin (fong, pong, bong + // acceptable) + static const BopomofoSyllable FromHanyuPinyin(const std::string& str); + + // TO DO: Support accented vowels + const std::string HanyuPinyinString(bool includesTone, + bool useVForUUmlaut) const; + // const std::string HanyuPinyinString(bool includesTone, bool useVForUUmlaut, + // bool composeAccentedVowel) const; + + // PHT = Pai-hua-tsi + static const BopomofoSyllable FromPHT(const std::string& str); + const std::string PHTString(bool includesTone) const; + + static const BopomofoSyllable FromComposedString(const std::string& str); + const std::string composedString() const; + + void clear() { syllable_ = 0; } + + bool isEmpty() const { return !syllable_; } + + bool hasConsonant() const { return !!(syllable_ & ConsonantMask); } + + bool hasMiddleVowel() const { return !!(syllable_ & MiddleVowelMask); } + bool hasVowel() const { return !!(syllable_ & VowelMask); } + + bool hasToneMarker() const { return !!(syllable_ & ToneMarkerMask); } + + Component consonantComponent() const { return syllable_ & ConsonantMask; } + + Component middleVowelComponent() const { + return syllable_ & MiddleVowelMask; + } + + Component vowelComponent() const { return syllable_ & VowelMask; } + + Component toneMarkerComponent() const { return syllable_ & ToneMarkerMask; } + + bool operator==(const BopomofoSyllable& another) const { + return syllable_ == another.syllable_; + } + + bool operator!=(const BopomofoSyllable& another) const { + return syllable_ != another.syllable_; + } + + bool isOverlappingWith(const BopomofoSyllable& another) const { +#define IOW_SAND(mask) ((syllable_ & mask) && (another.syllable_ & mask)) + return IOW_SAND(ConsonantMask) || IOW_SAND(MiddleVowelMask) || + IOW_SAND(VowelMask) || IOW_SAND(ToneMarkerMask); +#undef IOW_SAND + } + + // consonants J, Q, X all require the existence of vowel I or UE + bool belongsToJQXClass() const { + Component consonant = syllable_ & ConsonantMask; + return (consonant == J || consonant == Q || consonant == X); + } + + // zi, ci, si, chi, chi, shi, ri + bool belongsToZCSRClass() const { + Component consonant = syllable_ & ConsonantMask; + return (consonant >= ZH && consonant <= S); + } + + Component maskType() const { + Component mask = 0; + mask |= (syllable_ & ConsonantMask) ? ConsonantMask : 0; + mask |= (syllable_ & MiddleVowelMask) ? MiddleVowelMask : 0; + mask |= (syllable_ & VowelMask) ? VowelMask : 0; + mask |= (syllable_ & ToneMarkerMask) ? ToneMarkerMask : 0; + return mask; + } + + const BopomofoSyllable operator+(const BopomofoSyllable& another) const { + Component newSyllable = syllable_; +#define OP_SOVER(mask) \ + if (another.syllable_ & mask) { \ + newSyllable = (newSyllable & ~mask) | (another.syllable_ & mask); \ + } + OP_SOVER(ConsonantMask); + OP_SOVER(MiddleVowelMask); + OP_SOVER(VowelMask); + OP_SOVER(ToneMarkerMask); +#undef OP_SOVER + return BopomofoSyllable(newSyllable); + } + + BopomofoSyllable& operator+=(const BopomofoSyllable& another) { +#define OPE_SOVER(mask) \ + if (another.syllable_ & mask) { \ + syllable_ = (syllable_ & ~mask) | (another.syllable_ & mask); \ + } + OPE_SOVER(ConsonantMask); + OPE_SOVER(MiddleVowelMask); + OPE_SOVER(VowelMask); + OPE_SOVER(ToneMarkerMask); +#undef OPE_SOVER + return *this; + } + + uint16_t absoluteOrder() const { + // turn BPMF syllable into a 4*14*4*22 number + return (uint16_t)(syllable_ & ConsonantMask) + + (uint16_t)((syllable_ & MiddleVowelMask) >> 5) * 22 + + (uint16_t)((syllable_ & VowelMask) >> 7) * 22 * 4 + + (uint16_t)((syllable_ & ToneMarkerMask) >> 11) * 22 * 4 * 14; + } + + const std::string absoluteOrderString() const { + // 5*14*4*22 = 6160, we use a 79*79 encoding to represent that + uint16_t order = absoluteOrder(); + char low = 48 + static_cast(order % 79); + char high = 48 + static_cast(order / 79); + std::string result(2, ' '); + result[0] = low; + result[1] = high; + return result; + } + + static BopomofoSyllable FromAbsoluteOrder(uint16_t order) { + return BopomofoSyllable((order % 22) | ((order / 22) % 4) << 5 | + ((order / (22 * 4)) % 14) << 7 | + ((order / (22 * 4 * 14)) % 5) << 11); + } + + static BopomofoSyllable FromAbsoluteOrderString(const std::string& str) { + if (str.length() != 2) return BopomofoSyllable(); + + return FromAbsoluteOrder((uint16_t)(str[1] - 48) * 79 + + (uint16_t)(str[0] - 48)); + } + + friend std::ostream& operator<<(std::ostream& stream, + const BopomofoSyllable& syllable); + + static constexpr Component + ConsonantMask = 0x001f, // 0000 0000 0001 1111, 21 consonants + MiddleVowelMask = 0x0060, // 0000 0000 0110 0000, 3 middle vowels + VowelMask = 0x0780, // 0000 0111 1000 0000, 13 vowels + ToneMarkerMask = 0x3800, // 0011 1000 0000 0000, 5 tones (tone1 = 0x00) + B = 0x0001, P = 0x0002, M = 0x0003, F = 0x0004, D = 0x0005, T = 0x0006, + N = 0x0007, L = 0x0008, G = 0x0009, K = 0x000a, H = 0x000b, J = 0x000c, + Q = 0x000d, X = 0x000e, ZH = 0x000f, CH = 0x0010, SH = 0x0011, R = 0x0012, + Z = 0x0013, C = 0x0014, S = 0x0015, I = 0x0020, U = 0x0040, + UE = 0x0060, // ue = u umlaut (we use the German convention here as an + // ersatz to the /ju:/ sound) + A = 0x0080, O = 0x0100, ER = 0x0180, E = 0x0200, AI = 0x0280, EI = 0x0300, + AO = 0x0380, OU = 0x0400, AN = 0x0480, EN = 0x0500, ANG = 0x0580, + ENG = 0x0600, ERR = 0x0680, Tone1 = 0x0000, Tone2 = 0x0800, + Tone3 = 0x1000, Tone4 = 0x1800, Tone5 = 0x2000; + + protected: + Component syllable_; +}; + +inline std::ostream& operator<<(std::ostream& stream, + const BopomofoSyllable& syllable) { + stream << syllable.composedString(); + return stream; +} + +typedef BopomofoSyllable BPMF; + +typedef std::map > BopomofoKeyToComponentMap; +typedef std::map BopomofoComponentToKeyMap; + +class BopomofoKeyboardLayout { + public: + static const BopomofoKeyboardLayout* StandardLayout(); + static const BopomofoKeyboardLayout* ETenLayout(); + static const BopomofoKeyboardLayout* HsuLayout(); + static const BopomofoKeyboardLayout* ETen26Layout(); + static const BopomofoKeyboardLayout* IBMLayout(); + static const BopomofoKeyboardLayout* HanyuPinyinLayout(); + + BopomofoKeyboardLayout(const BopomofoKeyToComponentMap& ktcm, + const std::string& name) + : m_keyToComponent(ktcm), m_name(name) { + for (BopomofoKeyToComponentMap::const_iterator miter = + m_keyToComponent.begin(); + miter != m_keyToComponent.end(); ++miter) + for (std::vector::const_iterator viter = + (*miter).second.begin(); + viter != (*miter).second.end(); ++viter) + m_componentToKey[*viter] = (*miter).first; + } + + const std::string name() const { return m_name; } + + char componentToKey(BPMF::Component component) const { + BopomofoComponentToKeyMap::const_iterator iter = + m_componentToKey.find(component); + return (iter == m_componentToKey.end()) ? 0 : (*iter).second; + } + + const std::vector keyToComponents(char key) const { + BopomofoKeyToComponentMap::const_iterator iter = m_keyToComponent.find(key); + return (iter == m_keyToComponent.end()) ? std::vector() + : (*iter).second; + } + + const std::string keySequenceFromSyllable(BPMF syllable) const { + std::string sequence; + + BPMF::Component c; + char k; +#define STKS_COMBINE(component) \ + if ((c = component)) { \ + if ((k = componentToKey(c))) sequence += std::string(1, k); \ + } + STKS_COMBINE(syllable.consonantComponent()); + STKS_COMBINE(syllable.middleVowelComponent()); + STKS_COMBINE(syllable.vowelComponent()); + STKS_COMBINE(syllable.toneMarkerComponent()); +#undef STKS_COMBINE + return sequence; + } + + const BPMF syllableFromKeySequence(const std::string& sequence) const { + BPMF syllable; + + for (std::string::const_iterator iter = sequence.begin(); + iter != sequence.end(); ++iter) { + bool beforeSeqHasIorUE = sequenceContainsIorUE(sequence.begin(), iter); + bool aheadSeqHasIorUE = sequenceContainsIorUE(iter + 1, sequence.end()); + + std::vector components = keyToComponents(*iter); + + if (!components.size()) continue; + + if (components.size() == 1) { + syllable += BPMF(components[0]); + continue; + } + + BPMF head = BPMF(components[0]); + BPMF follow = BPMF(components[1]); + BPMF ending = components.size() > 2 ? BPMF(components[2]) : follow; + + // apply the I/UE + E rule + if (head.vowelComponent() == BPMF::E && + follow.vowelComponent() != BPMF::E) { + syllable += beforeSeqHasIorUE ? head : follow; + continue; + } + + if (head.vowelComponent() != BPMF::E && + follow.vowelComponent() == BPMF::E) { + syllable += beforeSeqHasIorUE ? follow : head; + continue; + } + + // apply the J/Q/X + I/UE rule, only two components are allowed in the + // components vector here + if (head.belongsToJQXClass() && !follow.belongsToJQXClass()) { + if (!syllable.isEmpty()) { + if (ending != follow) syllable += ending; + } else { + syllable += aheadSeqHasIorUE ? head : follow; + } + + continue; + } + + if (!head.belongsToJQXClass() && follow.belongsToJQXClass()) { + if (!syllable.isEmpty()) { + if (ending != follow) syllable += ending; + } else { + syllable += aheadSeqHasIorUE ? follow : head; + } + + continue; + } + + // the nasty issue of only one char in the buffer + if (iter == sequence.begin() && iter + 1 == sequence.end()) { + if (head.hasVowel() || follow.hasToneMarker() || + head.belongsToZCSRClass()) { + syllable += head; + } else { + if (follow.hasVowel() || ending.hasToneMarker()) { + syllable += follow; + } else { + syllable += ending; + } + } + + continue; + } + + if (!(syllable.maskType() & head.maskType()) && + !endAheadOrAheadHasToneMarkKey(iter + 1, sequence.end())) { + syllable += head; + } else { + if (endAheadOrAheadHasToneMarkKey(iter + 1, sequence.end()) && + head.belongsToZCSRClass() && syllable.isEmpty()) { + syllable += head; + } else if (syllable.maskType() < follow.maskType()) { + syllable += follow; + } else { + syllable += ending; + } + } + } + + // heuristics for Hsu keyboard layout + if (this == HsuLayout()) { + // fix the left out L to ERR when it has sound, and GI, GUE -> JI, JUE + if (syllable.vowelComponent() == BPMF::ENG && !syllable.hasConsonant() && + !syllable.hasMiddleVowel()) { + syllable += BPMF(BPMF::ERR); + } else if (syllable.consonantComponent() == BPMF::G && + (syllable.middleVowelComponent() == BPMF::I || + syllable.middleVowelComponent() == BPMF::UE)) { + syllable += BPMF(BPMF::J); + } + } + + return syllable; + } + + protected: + bool endAheadOrAheadHasToneMarkKey(std::string::const_iterator ahead, + std::string::const_iterator end) const { + if (ahead == end) return true; + + char tone1 = componentToKey(BPMF::Tone1); + char tone2 = componentToKey(BPMF::Tone2); + char tone3 = componentToKey(BPMF::Tone3); + char tone4 = componentToKey(BPMF::Tone4); + char tone5 = componentToKey(BPMF::Tone5); + + if (tone1) + if (*ahead == tone1) return true; + + if (*ahead == tone2 || *ahead == tone3 || *ahead == tone4 || + *ahead == tone5) + return true; + + return false; + } + + bool sequenceContainsIorUE(std::string::const_iterator start, + std::string::const_iterator end) const { + char iChar = componentToKey(BPMF::I); + char ueChar = componentToKey(BPMF::UE); + + for (; start != end; ++start) + if (*start == iChar || *start == ueChar) return true; + return false; + } + + std::string m_name; + BopomofoKeyToComponentMap m_keyToComponent; + BopomofoComponentToKeyMap m_componentToKey; +}; + +class BopomofoReadingBuffer { + public: + explicit BopomofoReadingBuffer(const BopomofoKeyboardLayout* layout) + : layout_(layout), pinyin_mode_(false) { + if (layout == BopomofoKeyboardLayout::HanyuPinyinLayout()) { + pinyin_mode_ = true; + pinyin_sequence_ = ""; + } + } + + void setKeyboardLayout(const BopomofoKeyboardLayout* layout) { + layout_ = layout; + + if (layout == BopomofoKeyboardLayout::HanyuPinyinLayout()) { + pinyin_mode_ = true; + pinyin_sequence_ = ""; + } + } + + bool isValidKey(char k) const { + if (!pinyin_mode_) { + return layout_ ? (layout_->keyToComponents(k)).size() > 0 : false; + } + + char lk = tolower(k); + if (lk >= 'a' && lk <= 'z') { + // if a tone marker is already in place + if (pinyin_sequence_.length()) { + char lastc = pinyin_sequence_[pinyin_sequence_.length() - 1]; + if (lastc >= '2' && lastc <= '5') { + return false; + } + return true; + } + return true; + } + + if (pinyin_sequence_.length() && (lk >= '2' && lk <= '5')) { + return true; + } + + return false; + } + + bool combineKey(char k) { + if (!isValidKey(k)) return false; + + if (pinyin_mode_) { + pinyin_sequence_ += std::string(1, tolower(k)); + syllable_ = BPMF::FromHanyuPinyin(pinyin_sequence_); + return true; + } + + std::string sequence = + layout_->keySequenceFromSyllable(syllable_) + std::string(1, k); + syllable_ = layout_->syllableFromKeySequence(sequence); + return true; + } + + void clear() { + pinyin_sequence_.clear(); + syllable_.clear(); + } + + void backspace() { + if (!layout_) return; + + if (pinyin_mode_) { + if (pinyin_sequence_.length()) { + pinyin_sequence_ = + pinyin_sequence_.substr(0, pinyin_sequence_.length() - 1); + } + + syllable_ = BPMF::FromHanyuPinyin(pinyin_sequence_); + return; + } + + std::string sequence = layout_->keySequenceFromSyllable(syllable_); + if (sequence.length()) { + sequence = sequence.substr(0, sequence.length() - 1); + syllable_ = layout_->syllableFromKeySequence(sequence); + } + } + + bool isEmpty() const { return syllable_.isEmpty(); } + + const std::string composedString() const { + if (pinyin_mode_) { + return pinyin_sequence_; + } + + return syllable_.composedString(); + } + + const BPMF syllable() const { return syllable_; } + + const std::string standardLayoutQueryString() const { + return BopomofoKeyboardLayout::StandardLayout()->keySequenceFromSyllable( + syllable_); + } + + const std::string absoluteOrderQueryString() const { + return syllable_.absoluteOrderString(); + } + + bool hasToneMarker() const { return syllable_.hasToneMarker(); } + + protected: + const BopomofoKeyboardLayout* layout_; + BPMF syllable_; + + bool pinyin_mode_; + std::string pinyin_sequence_; +}; +} // namespace Mandarin +} // namespace Taiyan + +#endif // MANDARIN_H_ diff --git a/Source/3rdParty/SSZipArchive/SSZipArchive.h b/Source/3rdParty/SSZipArchive/SSZipArchive.h new file mode 100755 index 0000000000000000000000000000000000000000..fb8d055aad6dfb6ad79269d86a75ead37e1b154f --- /dev/null +++ b/Source/3rdParty/SSZipArchive/SSZipArchive.h @@ -0,0 +1,45 @@ +// +// SSZipArchive.h +// SSZipArchive +// +// Created by Sam Soffes on 7/21/10. +// Copyright (c) Sam Soffes 2010-2011. All rights reserved. +// + +#import +#include "minizip/unzip.h" + +@protocol SSZipArchiveDelegate; + +@interface SSZipArchive : NSObject + +// Unzip ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination; ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error; + ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(id)delegate; ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error delegate:(id)delegate; + +// Zip ++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)filenames; + +- (id)initWithPath:(NSString *)path; +- (BOOL)open; +- (BOOL)writeFile:(NSString *)path; +- (BOOL)writeData:(NSData *)data filename:(NSString *)filename; +- (BOOL)close; + +@end + + +@protocol SSZipArchiveDelegate + +@optional + +- (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo; +- (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath; + +- (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo; +- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo; + +@end diff --git a/Source/3rdParty/SSZipArchive/SSZipArchive.m b/Source/3rdParty/SSZipArchive/SSZipArchive.m new file mode 100755 index 0000000000000000000000000000000000000000..c53c192010f20795917b28e1a3f96f4469dc5bcf --- /dev/null +++ b/Source/3rdParty/SSZipArchive/SSZipArchive.m @@ -0,0 +1,421 @@ +// +// SSZipArchive.m +// SSZipArchive +// +// Created by Sam Soffes on 7/21/10. +// Copyright (c) Sam Soffes 2010-2011. All rights reserved. +// + +#import "SSZipArchive.h" +#include "minizip/zip.h" +#import "zlib.h" +#import "zconf.h" + +#include + +#define CHUNK 16384 + +@interface SSZipArchive () ++ (NSDate *)_dateWithMSDOSFormat:(UInt32)msdosDateTime; +@end + + +@implementation SSZipArchive { + NSString *_path; + NSString *_filename; + zipFile _zip; +} + + +#pragma mark - Unzipping + ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination { + return [self unzipFileAtPath:path toDestination:destination delegate:nil]; +} + + ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error { + return [self unzipFileAtPath:path toDestination:destination overwrite:overwrite password:password error:error delegate:nil]; +} + + ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(id)delegate { + return [self unzipFileAtPath:path toDestination:destination overwrite:YES password:nil error:nil delegate:delegate]; +} + + ++ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error delegate:(id)delegate { + // Begin opening + zipFile zip = unzOpen((const char*)[path UTF8String]); + if (zip == NULL) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:@"failed to open zip file" forKey:NSLocalizedDescriptionKey]; + if (error) { + *error = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:-1 userInfo:userInfo]; + } + return NO; + } + + unz_global_info globalInfo = {0ul, 0ul}; + unzGetGlobalInfo(zip, &globalInfo); + + // Begin unzipping + if (unzGoToFirstFile(zip) != UNZ_OK) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:@"failed to open first file in zip file" forKey:NSLocalizedDescriptionKey]; + if (error) { + *error = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:-2 userInfo:userInfo]; + } + return NO; + } + + BOOL success = YES; + int ret = 0; + unsigned char buffer[4096] = {0}; + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSMutableSet *directoriesModificationDates = [[NSMutableSet alloc] init]; + + // Message delegate + if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipArchiveAtPath:zipInfo:)]) { + [delegate zipArchiveWillUnzipArchiveAtPath:path zipInfo:globalInfo]; + } + + NSInteger currentFileNumber = 0; + do { + if ([password length] == 0) { + ret = unzOpenCurrentFile(zip); + } else { + ret = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSASCIIStringEncoding]); + } + + if (ret != UNZ_OK) { + success = NO; + break; + } + + // Reading data and write to file + unz_file_info fileInfo; + memset(&fileInfo, 0, sizeof(unz_file_info)); + + ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0); + if (ret != UNZ_OK) { + success = NO; + unzCloseCurrentFile(zip); + break; + } + + // Message delegate + if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) { + [delegate zipArchiveWillUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry + archivePath:path fileInfo:fileInfo]; + } + + char *filename = (char *)malloc(fileInfo.size_filename + 1); + unzGetCurrentFileInfo(zip, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0); + filename[fileInfo.size_filename] = '\0'; + + // + // NOTE + // I used the ZIP spec from here: + // http://www.pkware.com/documents/casestudies/APPNOTE.TXT + // + // ...to deduce this method of detecting whether the file in the ZIP is a symbolic link. + // If it is, it is listed as a directory but has a data size greater than zero (real + // directories have it equal to 0) and the included, uncompressed data is the symbolic link path. + // + // ZIP files did not originally include support for symbolic links so the specification + // doesn't include anything in them that isn't part of a unix extension that isn't being used + // by the archivers we're testing. Most of this is figured out through trial and error and + // reading ZIP headers in hex editors. This seems to do the trick though. + // + + const uLong ZipCompressionMethodStore = 0; + + BOOL fileIsSymbolicLink = NO; + + if((fileInfo.compression_method == ZipCompressionMethodStore) && // Is it compressed? + (S_ISDIR(fileInfo.external_fa)) && // Is it marked as a directory + (fileInfo.compressed_size > 0)) // Is there any data? + { + fileIsSymbolicLink = YES; + } + + // Check if it contains directory + NSString *strPath = [NSString stringWithCString:filename encoding:NSUTF8StringEncoding]; + BOOL isDirectory = NO; + if (filename[fileInfo.size_filename-1] == '/' || filename[fileInfo.size_filename-1] == '\\') { + isDirectory = YES; + } + free(filename); + + // Contains a path + if ([strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location != NSNotFound) { + strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]; + } + + NSString *fullPath = [destination stringByAppendingPathComponent:strPath]; + NSError *err = nil; + NSDate *modDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dosDate]; + NSDictionary *directoryAttr = [NSDictionary dictionaryWithObjectsAndKeys:modDate, NSFileCreationDate, modDate, NSFileModificationDate, nil]; + + if (isDirectory) { + [fileManager createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:directoryAttr error:&err]; + } else { + [fileManager createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:directoryAttr error:&err]; + } + if (nil != err) { + NSLog(@"[SSZipArchive] Error: %@", err.localizedDescription); + } + + if(!fileIsSymbolicLink) + [directoriesModificationDates addObject: [NSDictionary dictionaryWithObjectsAndKeys:fullPath, @"path", modDate, @"modDate", nil]]; + + if ([fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite) { + unzCloseCurrentFile(zip); + ret = unzGoToNextFile(zip); + continue; + } + + if(!fileIsSymbolicLink) + { + FILE *fp = fopen((const char*)[fullPath UTF8String], "wb"); + while (fp) { + int readBytes = unzReadCurrentFile(zip, buffer, 4096); + + if (readBytes > 0) { + fwrite(buffer, readBytes, 1, fp ); + } else { + break; + } + } + + if (fp) { + fclose(fp); + + // Set the original datetime property + if (fileInfo.dosDate != 0) { + NSDate *orgDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dosDate]; + NSDictionary *attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate]; + + if (attr) { + if ([fileManager setAttributes:attr ofItemAtPath:fullPath error:nil] == NO) { + // Can't set attributes + NSLog(@"[SSZipArchive] Failed to set attributes"); + } + } + } + } + } + else + { + // Get the path for the symbolic link + + NSURL* symlinkURL = [NSURL fileURLWithPath:fullPath]; + NSMutableString* destinationPath = [NSMutableString string]; + + int bytesRead = 0; + while((bytesRead = unzReadCurrentFile(zip, buffer, 4096)) > 0) + { + buffer[bytesRead] = 0; + [destinationPath appendString:[NSString stringWithUTF8String:(const char*)buffer]]; + } + + //NSLog(@"Symlinking to: %@", destinationPath); + + NSURL* destinationURL = [NSURL fileURLWithPath:destinationPath]; + + // Create the symbolic link + NSError* symlinkError = nil; + [fileManager createSymbolicLinkAtURL:symlinkURL withDestinationURL:destinationURL error:&symlinkError]; + + if(symlinkError != nil) + { + NSLog(@"Failed to create symbolic link at \"%@\" to \"%@\". Error: %@", symlinkURL.absoluteString, destinationURL.absoluteString, symlinkError.localizedDescription); + } + } + + unzCloseCurrentFile( zip ); + ret = unzGoToNextFile( zip ); + + // Message delegate + if ([delegate respondsToSelector:@selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) { + [delegate zipArchiveDidUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry + archivePath:path fileInfo:fileInfo]; + } + + currentFileNumber++; + } while(ret == UNZ_OK && UNZ_OK != UNZ_END_OF_LIST_OF_FILE); + + // Close + unzClose(zip); + + // The process of decompressing the .zip archive causes the modification times on the folders + // to be set to the present time. So, when we are done, they need to be explicitly set. + // set the modification date on all of the directories. + NSError * err = nil; + for (NSDictionary * d in directoriesModificationDates) { + if (![[NSFileManager defaultManager] setAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[d objectForKey:@"modDate"], NSFileModificationDate, nil] ofItemAtPath:[d objectForKey:@"path"] error:&err]) { + NSLog(@"[SSZipArchive] Set attributes failed for directory: %@.", [d objectForKey:@"path"]); + } + if (err) { + NSLog(@"[SSZipArchive] Error setting directory file modification date attribute: %@",err.localizedDescription); + } + } + +#if !__has_feature(objc_arc) + [directoriesModificationDates release]; +#endif + + // Message delegate + if (success && [delegate respondsToSelector:@selector(zipArchiveDidUnzipArchiveAtPath:zipInfo:unzippedPath:)]) { + [delegate zipArchiveDidUnzipArchiveAtPath:path zipInfo:globalInfo unzippedPath:destination]; + } + + return success; +} + + +#pragma mark - Zipping + ++ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths { + BOOL success = NO; + SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path]; + if ([zipArchive open]) { + for (path in paths) { + [zipArchive writeFile:path]; + } + success = [zipArchive close]; + } + +#if !__has_feature(objc_arc) + [zipArchive release]; +#endif + + return success; +} + + +- (id)initWithPath:(NSString *)path { + if ((self = [super init])) { + _path = [path copy]; + } + return self; +} + + +#if !__has_feature(objc_arc) +- (void)dealloc { + [_path release]; + [super dealloc]; +} +#endif + + +- (BOOL)open { + NSAssert((_zip == NULL), @"Attempting open an archive which is already open"); + _zip = zipOpen([_path UTF8String], APPEND_STATUS_CREATE); + return (NULL != _zip); +} + + +- (void)zipInfo:(zip_fileinfo*)zipInfo setDate:(NSDate*)date { + NSCalendar *currentCalendar = [NSCalendar currentCalendar]; + uint flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; + NSDateComponents *components = [currentCalendar components:flags fromDate:date]; + zipInfo->tmz_date.tm_sec = (unsigned int)components.second; + zipInfo->tmz_date.tm_min = (unsigned int)components.minute; + zipInfo->tmz_date.tm_hour = (unsigned int)components.hour; + zipInfo->tmz_date.tm_mday = (unsigned int)components.day; + zipInfo->tmz_date.tm_mon = (unsigned int)components.month - 1; + zipInfo->tmz_date.tm_year = (unsigned int)components.year; +} + + +- (BOOL)writeFile:(NSString *)path { + NSAssert((_zip != NULL), @"Attempting to write to an archive which was never opened"); + + FILE *input = fopen([path UTF8String], "r"); + if (NULL == input) { + return NO; + } + + zipOpenNewFileInZip(_zip, [[path lastPathComponent] UTF8String], NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, + Z_DEFAULT_COMPRESSION); + + void *buffer = malloc(CHUNK); + unsigned int len = 0; + while (!feof(input)) { + len = (unsigned int) fread(buffer, 1, CHUNK, input); + zipWriteInFileInZip(_zip, buffer, len); + } + + zipCloseFileInZip(_zip); + free(buffer); + return YES; +} + + +- (BOOL)writeData:(NSData *)data filename:(NSString *)filename { + if (!_zip) { + return NO; + } + if (!data) { + return NO; + } + zip_fileinfo zipInfo = {{0,0,0,0,0,0},0,0,0}; + [self zipInfo:&zipInfo setDate:[NSDate date]]; + + zipOpenNewFileInZip(_zip, [filename UTF8String], &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION); + + zipWriteInFileInZip(_zip, data.bytes, (unsigned int)data.length); + + zipCloseFileInZip(_zip); + return YES; +} + + +- (BOOL)close { + NSAssert((_zip != NULL), @"[SSZipArchive] Attempting to close an archive which was never opened"); + zipClose(_zip, NULL); + return YES; +} + + +#pragma mark - Private + +// Format from http://newsgroups.derkeiler.com/Archive/Comp/comp.os.msdos.programmer/2009-04/msg00060.html +// Two consecutive words, or a longword, YYYYYYYMMMMDDDDD hhhhhmmmmmmsssss +// YYYYYYY is years from 1980 = 0 +// sssss is (seconds/2). +// +// 3658 = 0011 0110 0101 1000 = 0011011 0010 11000 = 27 2 24 = 2007-02-24 +// 7423 = 0111 0100 0010 0011 - 01110 100001 00011 = 14 33 2 = 14:33:06 ++ (NSDate *)_dateWithMSDOSFormat:(UInt32)msdosDateTime { + static const UInt32 kYearMask = 0xFE000000; + static const UInt32 kMonthMask = 0x1E00000; + static const UInt32 kDayMask = 0x1F0000; + static const UInt32 kHourMask = 0xF800; + static const UInt32 kMinuteMask = 0x7E0; + static const UInt32 kSecondMask = 0x1F; + + NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; + NSDateComponents *components = [[NSDateComponents alloc] init]; + + NSAssert(0xFFFFFFFF == (kYearMask | kMonthMask | kDayMask | kHourMask | kMinuteMask | kSecondMask), @"[SSZipArchive] MSDOS date masks don't add up"); + + [components setYear:1980 + ((msdosDateTime & kYearMask) >> 25)]; + [components setMonth:(msdosDateTime & kMonthMask) >> 21]; + [components setDay:(msdosDateTime & kDayMask) >> 16]; + [components setHour:(msdosDateTime & kHourMask) >> 11]; + [components setMinute:(msdosDateTime & kMinuteMask) >> 5]; + [components setSecond:(msdosDateTime & kSecondMask) * 2]; + + NSDate *date = [NSDate dateWithTimeInterval:0 sinceDate:[gregorian dateFromComponents:components]]; + +#if !__has_feature(objc_arc) + [gregorian release]; + [components release]; +#endif + + return date; +} + +@end diff --git a/Source/3rdParty/SSZipArchive/minizip/crypt.h b/Source/3rdParty/SSZipArchive/minizip/crypt.h new file mode 100755 index 0000000000000000000000000000000000000000..a01d08d932852ed4612183cda59d19df97d2ad54 --- /dev/null +++ b/Source/3rdParty/SSZipArchive/minizip/crypt.h @@ -0,0 +1,131 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const unsigned long* pcrc_32_tab, + unsigned long crcForCrypting) +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/Source/3rdParty/SSZipArchive/minizip/ioapi.h b/Source/3rdParty/SSZipArchive/minizip/ioapi.h new file mode 100755 index 0000000000000000000000000000000000000000..7e20e95130d81c7af31176514daf924c0bbcaddb --- /dev/null +++ b/Source/3rdParty/SSZipArchive/minizip/ioapi.h @@ -0,0 +1,201 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#include +#include +#include "zlib.h" + +#define USE_FILE32API +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Source/3rdParty/SSZipArchive/minizip/ioapi.m b/Source/3rdParty/SSZipArchive/minizip/ioapi.m new file mode 100755 index 0000000000000000000000000000000000000000..e0f738297e5b2e93b9fd086679ef5a663d7e8d53 --- /dev/null +++ b/Source/3rdParty/SSZipArchive/minizip/ioapi.m @@ -0,0 +1,239 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#if (defined(_WIN32)) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == ((uLong)-1)) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + +#ifndef __clang_analyzer__ + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; +#endif + + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen64((const char*)filename, mode_fopen); + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = ftello64((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + + if(fseeko64((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/Source/3rdParty/SSZipArchive/minizip/mztools.h b/Source/3rdParty/SSZipArchive/minizip/mztools.h new file mode 100755 index 0000000000000000000000000000000000000000..88b34592bf5ce021640c242c727264e6287edcd7 --- /dev/null +++ b/Source/3rdParty/SSZipArchive/minizip/mztools.h @@ -0,0 +1,31 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + +/* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery +*/ +extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + +#endif diff --git a/Source/3rdParty/SSZipArchive/minizip/mztools.m b/Source/3rdParty/SSZipArchive/minizip/mztools.m new file mode 100755 index 0000000000000000000000000000000000000000..80d50e00820e716a63bc7de3cfa88aabb96e359c --- /dev/null +++ b/Source/3rdParty/SSZipArchive/minizip/mztools.m @@ -0,0 +1,284 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +/* Code */ +#include +#include +#include +#include "zlib.h" +#include "unzip.h" +#include "mztools.h" + +#define READ_8(adr) ((unsigned char)*(adr)) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) + +#define WRITE_8(buff, n) do { \ + *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ +} while(0) +#define WRITE_16(buff, n) do { \ + WRITE_8((unsigned char*)(buff), n); \ + WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ +} while(0) +#define WRITE_32(buff, n) do { \ + WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ + WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ +} while(0) + +extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) +const char* file; +const char* fileOut; +const char* fileOutTmp; +uLong* nRecovered; +uLong* bytesRecovered; +{ + int err = Z_OK; + FILE* fpZip = fopen(file, "rb"); + FILE* fpOut = fopen(fileOut, "wb"); + FILE* fpOutCD = fopen(fileOutTmp, "wb"); + if (fpZip != NULL && fpOut != NULL) { + int entries = 0; + uLong totalBytes = 0; + char header[30]; + char filename[256]; + char extra[1024]; + int offset = 0; + int offsetCD = 0; + while ( fread(header, 1, 30, fpZip) == 30 ) { + int currentOffset = offset; + + /* File entry */ + if (READ_32(header) == 0x04034b50) { + unsigned int version = READ_16(header + 4); + unsigned int gpflag = READ_16(header + 6); + unsigned int method = READ_16(header + 8); + unsigned int filetime = READ_16(header + 10); + unsigned int filedate = READ_16(header + 12); + unsigned int crc = READ_32(header + 14); /* crc */ + unsigned int cpsize = READ_32(header + 18); /* compressed size */ + unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ + unsigned int fnsize = READ_16(header + 26); /* file name length */ + unsigned int extsize = READ_16(header + 28); /* extra field length */ + filename[0] = extra[0] = '\0'; + + /* Header */ + if (fwrite(header, 1, 30, fpOut) == 30) { + offset += 30; + } else { + err = Z_ERRNO; + break; + } + + /* Filename */ + if (fnsize > 0) { + if (fread(filename, 1, fnsize, fpZip) == fnsize) { + if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { + offset += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fread(extra, 1, extsize, fpZip) == extsize) { + if (fwrite(extra, 1, extsize, fpOut) == extsize) { + offset += extsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } + + /* Data */ + { + int dataSize = cpsize; + if (dataSize == 0) { + dataSize = uncpsize; + } + if (dataSize > 0) { + char* data = malloc(dataSize); + if (data != NULL) { + if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { + if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { + offset += dataSize; + totalBytes += dataSize; + } else { + err = Z_ERRNO; + } + } else { + err = Z_ERRNO; + } + free(data); + if (err != Z_OK) { + break; + } + } else { + err = Z_MEM_ERROR; + break; + } + } + } + + /* Central directory entry */ + { + char centralDirectoryEntryHeader[46]; + //char* comment = ""; + //int comsize = (int) strlen(comment); + WRITE_32(centralDirectoryEntryHeader, 0x02014b50); + WRITE_16(centralDirectoryEntryHeader + 4, version); + WRITE_16(centralDirectoryEntryHeader + 6, version); + WRITE_16(centralDirectoryEntryHeader + 8, gpflag); + WRITE_16(centralDirectoryEntryHeader + 10, method); + WRITE_16(centralDirectoryEntryHeader + 12, filetime); + WRITE_16(centralDirectoryEntryHeader + 14, filedate); + WRITE_32(centralDirectoryEntryHeader + 16, crc); + WRITE_32(centralDirectoryEntryHeader + 20, cpsize); + WRITE_32(centralDirectoryEntryHeader + 24, uncpsize); + WRITE_16(centralDirectoryEntryHeader + 28, fnsize); + WRITE_16(centralDirectoryEntryHeader + 30, extsize); + WRITE_16(centralDirectoryEntryHeader + 32, 0 /*comsize*/); + WRITE_16(centralDirectoryEntryHeader + 34, 0); /* disk # */ + WRITE_16(centralDirectoryEntryHeader + 36, 0); /* int attrb */ + WRITE_32(centralDirectoryEntryHeader + 38, 0); /* ext attrb */ + WRITE_32(centralDirectoryEntryHeader + 42, currentOffset); + /* Header */ + if (fwrite(centralDirectoryEntryHeader, 1, 46, fpOutCD) == 46) { + offsetCD += 46; + + /* Filename */ + if (fnsize > 0) { + if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { + offsetCD += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { + offsetCD += extsize; + } else { + err = Z_ERRNO; + break; + } + } + + /* Comment field */ + /* + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { + offsetCD += comsize; + } else { + err = Z_ERRNO; + break; + } + } + */ + + } else { + err = Z_ERRNO; + break; + } + } + + /* Success */ + entries++; + + } else { + break; + } + } + + /* Final central directory */ + { + int entriesZip = entries; + char finalCentralDirectoryHeader[22]; + //char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; + //int comsize = (int) strlen(comment); + if (entriesZip > 0xffff) { + entriesZip = 0xffff; + } + WRITE_32(finalCentralDirectoryHeader, 0x06054b50); + WRITE_16(finalCentralDirectoryHeader + 4, 0); /* disk # */ + WRITE_16(finalCentralDirectoryHeader + 6, 0); /* disk # */ + WRITE_16(finalCentralDirectoryHeader + 8, entriesZip); /* hack */ + WRITE_16(finalCentralDirectoryHeader + 10, entriesZip); /* hack */ + WRITE_32(finalCentralDirectoryHeader + 12, offsetCD); /* size of CD */ + WRITE_32(finalCentralDirectoryHeader + 16, offset); /* offset to CD */ + WRITE_16(finalCentralDirectoryHeader + 20, 0 /*comsize*/); /* comment */ + + /* Header */ + if (fwrite(finalCentralDirectoryHeader, 1, 22, fpOutCD) == 22) { + + /* Comment field */ + /* + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { + err = Z_ERRNO; + } + } + */ + } else { + err = Z_ERRNO; + } + } + + /* Final merge (file + central directory) */ + fclose(fpOutCD); + if (err == Z_OK) { + fpOutCD = fopen(fileOutTmp, "rb"); + if (fpOutCD != NULL) { + int nRead; + char buffer[8192]; + while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { + if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { + err = Z_ERRNO; + break; + } + } + fclose(fpOutCD); + } + } + + /* Close */ + fclose(fpZip); + fclose(fpOut); + + /* Wipe temporary file */ + (void)remove(fileOutTmp); + + /* Number of recovered entries */ + if (err == Z_OK) { + if (nRecovered != NULL) { + *nRecovered = entries; + } + if (bytesRecovered != NULL) { + *bytesRecovered = totalBytes; + } + } + } else { + err = Z_STREAM_ERROR; + } + return err; +} diff --git a/Source/3rdParty/SSZipArchive/minizip/unzip.h b/Source/3rdParty/SSZipArchive/minizip/unzip.h new file mode 100755 index 0000000000000000000000000000000000000000..3183968b771e3c261fdcc7a0f50bd743faf531e3 --- /dev/null +++ b/Source/3rdParty/SSZipArchive/minizip/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/Source/3rdParty/SSZipArchive/minizip/unzip.m b/Source/3rdParty/SSZipArchive/minizip/unzip.m new file mode 100755 index 0000000000000000000000000000000000000000..667189c2e44e7fa9503a0c1e560cbcd88bb5b934 --- /dev/null +++ b/Source/3rdParty/SSZipArchive/minizip/unzip.m @@ -0,0 +1,2150 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include +#include +#include + +//#ifndef NOUNCRYPT +// #define NOUNCRYPT +//#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + +extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz64_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unz64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int *pie)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pie) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pie = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL2; + + if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == (unsigned long)-1) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL2) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + { +#ifndef __clang_analyzer__ + lSeek=0; +#endif + } + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; +#ifndef __clang_analyzer__ + lSeek+=file_info.size_file_comment - uSizeRead; +#endif + } +#ifndef __clang_analyzer__ + else + lSeek+=file_info.size_file_comment; +#endif + + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if (err==UNZ_OK) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date; + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + { +#ifndef __clang_analyzer__ + err=UNZ_BADZIPFILE; +#endif + } + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; +#ifndef __clang_analyzer__ + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; +#endif + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = (const unsigned long*)get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->read_buffer == NULL) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + // NOTE: + // This bit of code seems to try to set the amount of space in the output buffer based on the + // value stored in the headers stored in the .zip file. However, if those values are incorrect + // it may result in a loss of data when uncompresssing that file. The compressed data is still + // legit and will deflate without knowing the uncompressed code so this tidbit is unnecessary and + // may cause issues for some .zip files. + // + // It's removed in here to fix those issues. + // + // See: https://github.com/samsoffes/ssziparchive/issues/16 + // + + /* + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + */ + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} diff --git a/Source/3rdParty/SSZipArchive/minizip/zip.h b/Source/3rdParty/SSZipArchive/minizip/zip.h new file mode 100755 index 0000000000000000000000000000000000000000..eec1082b323474c1b2b5a483b9ba32aced7ea81e --- /dev/null +++ b/Source/3rdParty/SSZipArchive/minizip/zip.h @@ -0,0 +1,362 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ diff --git a/Source/3rdParty/SSZipArchive/minizip/zip.m b/Source/3rdParty/SSZipArchive/minizip/zip.m new file mode 100755 index 0000000000000000000000000000000000000000..b3b39169f81f4f1d6d85dca3093b805bb858cbd6 --- /dev/null +++ b/Source/3rdParty/SSZipArchive/minizip/zip.m @@ -0,0 +1,2023 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + Oct-2009 - Mathias Svensson - Remove old C style function prototypes + Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives + Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. + Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data + It is used when recreting zip archive with RAW when deleting items from a zip. + ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed. + Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + +extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (64*1024) //(16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + + +// NOT sure that this work on ALL platform +#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x6064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralExtra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; + int zip64; /* Add ZIP64 extened information in the extra field */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T totalCompressedData; + ZPOS64_T totalUncompressedData; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile64_info ci; /* info on the file curretly writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writting_offset; + ZPOS64_T number_entry; + +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif + +} zip64_internal; + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(linkedlist_datablock_internal* ldi) +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) +*/ + +local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); +local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) +{ + unsigned char buf[8]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + + +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + uLong year = (uLong)ptm->tm_year; + if (year>=1980) + year-=1980; + else if (year>=80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pye)); + +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pye) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pye = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); + + +local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<24; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<32; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<40; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<48; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<56; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* +Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + { + // Signature "0x07064b50" Zip64 end of central directory locater + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + } + + if (uPosFound!=0) + break; + } + + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) + return 0; + + /* total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto Zip64 end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' + return 0; + + return relativeOffset; +} + +int LoadCentralDirectoryRecord(zip64_internal* pziinit); +int LoadCentralDirectoryRecord(zip64_internal* pziinit) +{ + int err=ZIP_OK; + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry; + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong VersionMadeBy; + uLong VersionNeeded; + uLong size_comment; + + int hasZIP64Record = 0; + + // check first if we find a ZIP64 record + central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); + if(central_pos > 0) + { + hasZIP64Record = 1; + } + else if(central_pos == 0) + { + central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); + } + +/* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; +*/ + + if(hasZIP64Record) + { + ZPOS64_T sizeEndOfCentralDirectory; + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* size of zip64 end of central directory record */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version made by */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version needed to extract */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + // TODO.. + // read the comment from the standard central header. + size_comment = 0; + } + else + { + // Read End of central Directory info + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry = uL; + + /* total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry_CD = uL; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + size_central_dir = uL; + + /* offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + offset_central_dir = uL; + + + /* zipfile global comment length */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + } + + if ((central_posz_filefunc, pziinit->filestream); + return ZIP_ERRNO; + } + + if (size_comment>0) + { + pziinit->globalcomment = (char*)ALLOC(size_comment+1); + if (pziinit->globalcomment) + { + size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); + pziinit->globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); + pziinit->add_position_when_writting_offset = byte_before_the_zipfile; + + { + ZPOS64_T size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); + + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + pziinit->begin_pos = byte_before_the_zipfile; + pziinit->number_entry = number_entry_CD; + + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + return err; +} + + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + + +/************************************************************/ +extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def); +extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; + int err=ZIP_OK; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + + if (append == APPEND_STATUS_CREATEAFTER) + ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + + ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + + zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi==NULL) + { + ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + // Read and Cache Central Directory Records + err = LoadCentralDirectoryRecord(&ziinit); + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + + + +extern zipFile ZEXPORT zipOpen (const char* pathname, int append) +{ + return zipOpen3((const void*)pathname,append,NULL,NULL); +} + +extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) +{ + return zipOpen3(pathname,append,NULL,NULL); +} + +int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local); +int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) +{ + /* write the local header */ + int err; + uInt size_filename = (uInt)strlen(filename); + uInt size_extrafield = size_extrafield_local; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); + + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + } + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if(zi->ci.zip64) + { + size_extrafield += 20; + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); + + if ((err==ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + } + + if ((err==ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + + if ((err==ZIP_OK) && (zi->ci.zip64)) + { + // write the Zip64 extended info + short HeaderID = 1; + short DataSize = 16; + ZPOS64_T CompressedSize = 0; + ZPOS64_T UncompressedSize = 0; + + // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); + +#ifndef __clang_analyzer__ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); +#endif + } + + return err; +} + +/* + NOTE. + When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped + before calling this function it can be done with zipRemoveExtraInfoBlock + + It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize + unnecessary allocations. + */ +extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase, int zip64) +{ + zip64_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + +#ifdef HAVE_BZIP2 + if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) + return ZIP_PARAMERROR; +#else + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; +#endif + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else + zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + zi->ci.flag = flagBase; + if (level==8 || level==9) + zi->ci.flag |= 2; + if (level==2) + zi->ci.flag |= 4; + if (level==1) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); + + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; + zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data + + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); + + zi->ci.size_centralExtra = size_extrafield_global; + zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + if(zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + zi->ci.zip64 = zip64; + zi->ci.totalCompressedData = 0; + zi->ci.totalUncompressedData = 0; + zi->ci.pos_zip64extrainfo = 0; + + err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (uInt)0; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + +#ifdef HAVE_BZIP2 + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) +#else + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) +#endif + { + if(zi->ci.method == Z_DEFLATED) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = Z_DEFLATED; + } + else if(zi->ci.method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + // Init BZip stuff here + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); + if(err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + + } + +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = (const unsigned long*)get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +local int zip64FlushWriteBuffer(zip64_internal* zi) +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); +#endif + } + + if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + + zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED) + { + zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.totalUncompressedData += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) +{ + zip64_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + + + if(err != BZ_RUN_OK) + break; + + if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; +// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; + } + } + + if(err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + if(uTotalOutBefore > zi->ci.stream.total_out) + { + int bBreak = 0; + bBreak++; + } + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + + for (i = 0; i < copy_this; i++) + *(((char*)zi->ci.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + }// while(...) + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + short datasize = 0; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + { +#ifndef __clang_analyzer__ + err = ZIP_ERRNO; +#endif + } + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; +#ifndef __clang_analyzer__ + zi->ci.stream.next_out = zi->ci.buffered_data; +#endif + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + } + else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err==BZ_FINISH_OK) + { + uLong uTotalOutBefore; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.bstream.total_out_lo32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if(err == BZ_STREAM_END) + err = Z_STREAM_END; + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); + } + + if(err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + { + if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + } + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + int tmp_err = deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } +#ifdef HAVE_BZIP2 + else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err==ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.totalUncompressedData; + } + compressed_size = zi->ci.totalCompressedData; + +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + // update Current Item crc and sizes, + if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + /*version Made by*/ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); + /*version needed*/ + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); + + } + + zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + + + if(compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ + + /// set internal file attributes field + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + + if(uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ + + // Add ZIP64 extra info field for uncompressed size + if(uncompressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for compressed size + if(compressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for relative offset to local file header of current file + if(zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + if(datasize > 0) + { + char* p = NULL; + + if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) + { + // we can not write more data to the buffer that we have room for. + return ZIP_BADZIPFILE; + } + + p = zi->ci.central_header + zi->ci.size_centralheader; + + // Add Extra Information Header for 'ZIP64 information' + zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); // DataSize + p += 2; + + if(uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + + if(compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + + if(zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); +#ifndef __clang_analyzer__ + p += 8; +#endif + } + + // Update how much extra free space we got in the memory buffer + // and increase the centralheader size so the new ZIP64 fields are included + // ( 4 below is the size of HeaderID and DataSize field ) + zi->ci.size_centralExtraFree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + + // Update the extra info size field + zi->ci.size_centralExtra += datasize + 4; + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); + } + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); + + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + // Update the LocalFileHeader with the new values. + + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if(uncompressed_size >= 0xffffffff) + { + if(zi->ci.pos_zip64extrainfo > 0) + { + // Update the size in the ZIP64 extended field. + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + } + else + { + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + } + + if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (zipFile file) +{ + return zipCloseFileInZipRaw (file,0,0); +} + +int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip); +int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) +{ + int err = ZIP_OK; + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); + + /*num disks*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + /*relative offset*/ + if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); + + /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); + + return err; +} + +int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip); +int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + uLong Zip64DataSize = 44; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? + + if (err==ZIP_OK) /* version made by */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* version needed */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); + } + return err; +} + +int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip); +int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + /*signature*/ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + { + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + } + + if (err==ZIP_OK) /* total number of entries in the central dir */ + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); + } + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + } + + return err; +} + +int Write_GlobalComment(zip64_internal* zi, const char* global_comment); +int Write_GlobalComment(zip64_internal* zi, const char* global_comment) +{ + int err = ZIP_OK; + uInt size_global_comment = 0; + + if(global_comment != NULL) + size_global_comment = (uInt)strlen(global_comment); + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + return err; +} + +extern int ZEXPORT zipClose (zipFile file, const char* global_comment) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + + centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) + err = ZIP_ERRNO; + } + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_linkedlist(&(zi->central_dir)); + + pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); + Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); + } + + if (err==ZIP_OK) + err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + if(err == ZIP_OK) + err = Write_GlobalComment(zi, global_comment); + + if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} + +extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) +{ + char* p = pData; + int size = 0; + char* pNewHeader; + char* pTmp; + short header; + short dataSize; + + int retVal = ZIP_OK; + + if(pData == NULL || *dataLen < 4) + return ZIP_PARAMERROR; + + pNewHeader = (char*)ALLOC(*dataLen); + pTmp = pNewHeader; + + while(p < (pData + *dataLen)) + { + header = *(short*)p; + dataSize = *(((short*)p)+1); + + if( header == sHeader ) // Header found. + { + p += dataSize + 4; // skip it. do not copy to temp buffer + } + else + { + // Extra Info block should not be removed, So copy it to the temp buffer. + memcpy(pTmp, p, dataSize + 4); + p += dataSize + 4; + size += dataSize + 4; + } + + } + + if(size < *dataLen) + { + // clean old extra info block. + memset(pData,0, *dataLen); + + // copy the new extra info block over the old + if(size > 0) + memcpy(pData, pNewHeader, size); + + // set the new extra info size + *dataLen = size; + + retVal = ZIP_OK; + } + else + retVal = ZIP_ERRNO; + + TRYFREE(pNewHeader); + + return retVal; +} diff --git a/Source/AppDelegate.h b/Source/AppDelegate.h deleted file mode 100644 index 96ee6e0c0df9e194a3e8e496d8823306058fd46f..0000000000000000000000000000000000000000 --- a/Source/AppDelegate.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// AppDelegate.h -// -// Copyright (c) 2011 The McBopomofo Project. -// -// Contributors: -// Mengjuei Hsieh (@mjhsieh) -// Weizhong Yang (@zonble) -// -// Based on the Syrup Project and the Formosana Library -// by Lukhnos Liu (@lukhnos). -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import - -@class PreferencesWindowController; - -@interface AppDelegate : NSObject -{ -@private - NSURLConnection *_updateCheckConnection; - BOOL _currentUpdateCheckIsForced; - NSMutableData *_receivingData; - NSURL *_updateNextStepURL; - PreferencesWindowController *_preferencesWindowController; -} - -- (void)checkForUpdate; -- (void)checkForUpdateForced:(BOOL)forced; -- (void)showPreferences; - -@property (weak, nonatomic) IBOutlet NSWindow *window; -@end diff --git a/Source/AppDelegate.m b/Source/AppDelegate.m deleted file mode 100644 index cc6b896ce730bcca8f1ea58c37b9a88ae099df15..0000000000000000000000000000000000000000 --- a/Source/AppDelegate.m +++ /dev/null @@ -1,271 +0,0 @@ -// -// AppDelegate.m -// -// Copyright (c) 2011 The McBopomofo Project. -// -// Contributors: -// Mengjuei Hsieh (@mjhsieh) -// Weizhong Yang (@zonble) -// -// Based on the Syrup Project and the Formosana Library -// by Lukhnos Liu (@lukhnos). -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "AppDelegate.h" -#import "OVNonModalAlertWindowController.h" -#import "PreferencesWindowController.h" - -extern void LTLoadLanguageModel(void); - -static NSString *kCheckUpdateAutomatically = @"CheckUpdateAutomatically"; -static NSString *kNextUpdateCheckDateKey = @"NextUpdateCheckDate"; -static NSString *kUpdateInfoEndpointKey = @"UpdateInfoEndpoint"; -static NSString *kUpdateInfoSiteKey = @"UpdateInfoSite"; -static const NSTimeInterval kNextCheckInterval = 86400.0; -static const NSTimeInterval kTimeoutInterval = 60.0; - -@interface AppDelegate () -@end - -@implementation AppDelegate -@synthesize window = _window; - -- (void)dealloc -{ - _preferencesWindowController = nil; - _updateCheckConnection = nil; -} - -- (void)applicationDidFinishLaunching:(NSNotification *)inNotification -{ - LTLoadLanguageModel(); - - if (![[NSUserDefaults standardUserDefaults] objectForKey:kCheckUpdateAutomatically]) { - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kCheckUpdateAutomatically]; - [[NSUserDefaults standardUserDefaults] synchronize]; - } - - [self checkForUpdate]; -} - -- (void)checkForUpdate -{ - [self checkForUpdateForced:NO]; -} - -- (void)checkForUpdateForced:(BOOL)forced -{ - if (_updateCheckConnection) { - // busy - return; - } - - _currentUpdateCheckIsForced = forced; - - // time for update? - if (!forced) { - if (![[NSUserDefaults standardUserDefaults] boolForKey:kCheckUpdateAutomatically]) { - return; - } - - NSDate *now = [NSDate date]; - NSDate *date = [[NSUserDefaults standardUserDefaults] objectForKey:kNextUpdateCheckDateKey]; - if (![date isKindOfClass:[NSDate class]]) { - date = now; - } - - if ([now compare:date] == NSOrderedAscending) { - return; - } - } - - NSDate *nextUpdateDate = [NSDate dateWithTimeInterval:kNextCheckInterval sinceDate:[NSDate date]]; - [[NSUserDefaults standardUserDefaults] setObject:nextUpdateDate forKey:kNextUpdateCheckDateKey]; - - NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary]; - NSString *updateInfoURLString = [infoDict objectForKey:kUpdateInfoEndpointKey]; - if (![updateInfoURLString length]) { - return; - } - - NSURL *updateInfoURL = [NSURL URLWithString:updateInfoURLString]; - if (!updateInfoURL) { - return; - } - - NSURLRequest *request = [NSURLRequest requestWithURL:updateInfoURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:kTimeoutInterval]; - if (!request) { - return; - } -#if DEBUG - NSLog(@"about to request update url %@ ",updateInfoURL); -#endif - - if (_receivingData) { - _receivingData = nil; - } - - // create a new data buffer and connection - _receivingData = [[NSMutableData alloc] init]; - _updateCheckConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; - [_updateCheckConnection start]; -} - -- (void)showPreferences -{ - if (!_preferencesWindowController) { - _preferencesWindowController = [[PreferencesWindowController alloc] initWithWindowNibName:@"preferences"]; - } - [[_preferencesWindowController window] center]; - [[_preferencesWindowController window] orderFront:self]; -} - -- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error -{ - BOOL isForcedCheck = _currentUpdateCheckIsForced; - - _receivingData = nil; - _updateCheckConnection = nil; - _currentUpdateCheckIsForced = NO; - - if (isForcedCheck) { - [[OVNonModalAlertWindowController sharedInstance] showWithTitle:NSLocalizedString(@"Update Check Failed", nil) content:[NSString stringWithFormat:NSLocalizedString(@"There may be no internet connection or the server failed to respond.\n\nError message: %@", nil), [error localizedDescription]] confirmButtonTitle:NSLocalizedString(@"Dismiss", nil) cancelButtonTitle:nil cancelAsDefault:NO delegate:nil]; - } -} - -- (void)showNoUpdateAvailableAlert -{ - [[OVNonModalAlertWindowController sharedInstance] showWithTitle:NSLocalizedString(@"Check for Update Completed", nil) content:NSLocalizedString(@"You are already using the latest version of McBopomofo.", nil) confirmButtonTitle:NSLocalizedString(@"OK", nil) cancelButtonTitle:nil cancelAsDefault:NO delegate:nil]; -} - -- (void)connectionDidFinishLoading:(NSURLConnection *)connection -{ - id plist = [NSPropertyListSerialization propertyListWithData:_receivingData options:NSPropertyListImmutable format:NULL error:NULL]; -#if DEBUG - NSLog(@"plist %@",plist); -#endif - - BOOL isForcedCheck = _currentUpdateCheckIsForced; - - _receivingData = nil; - _updateCheckConnection = nil; - _currentUpdateCheckIsForced = NO; - - if (!plist) { - if (isForcedCheck) { - [self showNoUpdateAvailableAlert]; - } - return; - } - - NSString *remoteVersion = [plist objectForKey:(id)kCFBundleVersionKey]; -#if DEBUG - NSLog(@"the remoteversion is %@",remoteVersion); -#endif - if (!remoteVersion) { - if (isForcedCheck) { - [self showNoUpdateAvailableAlert]; - } - return; - } - - // TODO: Validate info (e.g. bundle identifier) - // TODO: Use HTML to display change log, need a new key like UpdateInfoChangeLogURL for this - - NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary]; - NSString *currentVersion = [infoDict objectForKey:(id)kCFBundleVersionKey]; - NSComparisonResult result = [currentVersion compare:remoteVersion options:NSNumericSearch]; - - if (result != NSOrderedAscending) { - if (isForcedCheck) { - [self showNoUpdateAvailableAlert]; - } - return; - } - - - NSString *siteInfoURLString = [plist objectForKey:kUpdateInfoSiteKey]; - if (!siteInfoURLString) { - if (isForcedCheck) { - [self showNoUpdateAvailableAlert]; - } - return; - } - - NSURL *siteInfoURL = [NSURL URLWithString:siteInfoURLString]; - if (!siteInfoURL) { - if (isForcedCheck) { - [self showNoUpdateAvailableAlert]; - } - return; - } - _updateNextStepURL = siteInfoURL; - - NSDictionary *versionDescriptions = [plist objectForKey:@"Description"]; - NSString *versionDescription = @""; - if ([versionDescriptions isKindOfClass:[NSDictionary class]]) { - NSString *locale = @"en"; - NSArray *supportedLocales = [NSArray arrayWithObjects:@"en", @"zh-Hant", @"zh-Hans", nil]; - NSArray *preferredTags = [NSBundle preferredLocalizationsFromArray:supportedLocales]; - if ([preferredTags count]) { - locale = [preferredTags objectAtIndex:0]; - } - versionDescription = [versionDescriptions objectForKey:locale]; - if (!versionDescription) { - versionDescription = [versionDescriptions objectForKey:@"en"]; - } - - if (!versionDescription) { - versionDescription = @""; - } - else { - versionDescription = [@"\n\n" stringByAppendingString:versionDescription]; - } - } - - NSString *content = [NSString stringWithFormat:NSLocalizedString(@"You're currently using McBopomofo %@ (%@), a new version %@ (%@) is now available. Do you want to visit McBopomofo's website to download the version?%@", nil), [infoDict objectForKey:@"CFBundleShortVersionString"], currentVersion, [plist objectForKey:@"CFBundleShortVersionString"], remoteVersion, versionDescription]; - - [[OVNonModalAlertWindowController sharedInstance] showWithTitle:NSLocalizedString(@"New Version Available", nil) content:content confirmButtonTitle:NSLocalizedString(@"Visit Website", nil) cancelButtonTitle:NSLocalizedString(@"Not Now", nil) cancelAsDefault:NO delegate:self]; -} - -- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data -{ - [_receivingData appendData:data]; -} - -- (void)nonModalAlertWindowControllerDidConfirm:(OVNonModalAlertWindowController *)controller -{ - if (_updateNextStepURL) { - [[NSWorkspace sharedWorkspace] openURL:_updateNextStepURL]; - } - - _updateNextStepURL = nil; -} - -- (void)nonModalAlertWindowControllerDidCancel:(OVNonModalAlertWindowController *)controller -{ - _updateNextStepURL = nil; -} - -@end diff --git a/Source/Base.lproj/MainMenu.xib b/Source/Base.lproj/MainMenu.xib deleted file mode 100644 index 5f7bcf12fb539b5f24a1bd5f0e2a0ed8a42d3224..0000000000000000000000000000000000000000 --- a/Source/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,295 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Source/Base.lproj/preferences.xib b/Source/Base.lproj/preferences.xib deleted file mode 100644 index 4534c6b6ec1a26d5b74a0a5de9e725c968b4bb9b..0000000000000000000000000000000000000000 --- a/Source/Base.lproj/preferences.xib +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Item 1 - Item 2 - Item 3 - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Source/CandidateUI/VTCandidateController.h b/Source/CandidateUI/VTCandidateController.h deleted file mode 100644 index 41e36a5cb425bba25506f2f077a6b25ecb867c1c..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTCandidateController.h +++ /dev/null @@ -1,68 +0,0 @@ -// -// VTCandidateController.h -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import - -@class VTCandidateController; - -@protocol VTCandidateControllerDelegate -- (NSUInteger)candidateCountForController:(VTCandidateController *)controller; -- (NSString *)candidateController:(VTCandidateController *)controller candidateAtIndex:(NSUInteger)index; -- (void)candidateController:(VTCandidateController *)controller didSelectCandidateAtIndex:(NSUInteger)index; -@end - -@interface VTCandidateController : NSWindowController -{ -@protected - __weak id _delegate; - NSArray *_keyLabels; - NSFont *_keyLabelFont; - NSFont *_candidateFont; - BOOL _visible; -} - -- (void)reloadData; - -- (BOOL)showNextPage; -- (BOOL)showPreviousPage; -- (BOOL)highlightNextCandidate; -- (BOOL)highlightPreviousCandidate; - -- (void)setWindowTopLeftPoint:(NSPoint)topLeftPoint bottomOutOfScreenAdjustmentHeight:(CGFloat)height; - -- (NSUInteger)candidateIndexAtKeyLabelIndex:(NSUInteger)index; - -@property (weak, nonatomic) id delegate; -@property (assign, nonatomic) NSUInteger selectedCandidateIndex; - -@property (assign, nonatomic) BOOL visible; -@property (assign, nonatomic) NSPoint windowTopLeftPoint; - -@property (copy, nonatomic) NSArray *keyLabels; -@property (copy, nonatomic) NSFont *keyLabelFont; -@property (copy, nonatomic) NSFont *candidateFont; -@end diff --git a/Source/CandidateUI/VTCandidateController.m b/Source/CandidateUI/VTCandidateController.m deleted file mode 100644 index 933d101802e0f1606ce921dd2f4a119962c0efd6..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTCandidateController.m +++ /dev/null @@ -1,178 +0,0 @@ -// -// VTCandidateController.m -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "VTCandidateController.h" - - -@implementation VTCandidateController -@synthesize delegate = _delegate; -@synthesize keyLabels = _keyLabels; -@synthesize keyLabelFont = _keyLabelFont; -@synthesize candidateFont = _candidateFont; - -- (void)dealloc -{ - _keyLabels = nil; - _keyLabelFont = nil; - _candidateFont = nil; -} - -- (id)initWithWindow:(NSWindow *)window -{ - self = [super initWithWindow:window]; - if (self) { - // populate the default values - _keyLabels = @[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9"]; - _keyLabelFont = [NSFont systemFontOfSize:14.0]; - _candidateFont = [NSFont systemFontOfSize:18.0]; - } - return self; -} - -- (void)reloadData -{ -} - -- (BOOL)showNextPage -{ - return NO; -} - -- (BOOL)showPreviousPage -{ - return NO; -} - -- (BOOL)highlightNextCandidate -{ - return NO; -} - -- (BOOL)highlightPreviousCandidate -{ - return NO; -} - -- (void)setWindowTopLeftPoint:(NSPoint)topLeftPoint bottomOutOfScreenAdjustmentHeight:(CGFloat)height -{ - // Since layout is now deferred, the origin setting should also be deferred so that - // the correct visible frame dimensions are used. - NSArray *params = [NSArray arrayWithObjects:[NSValue valueWithPoint:topLeftPoint], [NSNumber numberWithDouble:height], nil]; - [self performSelector:@selector(deferredSetWindowTopLeftPoint:) withObject:params afterDelay:0.0]; -} - -- (void)deferredSetWindowTopLeftPoint:(NSArray *)params -{ - NSPoint topLeftPoint = [[params objectAtIndex:0] pointValue]; - CGFloat height = [[params objectAtIndex:1] doubleValue]; - - NSPoint adjustedPoint = topLeftPoint; - CGFloat adjustedHeight = height; - - // first, locate the screen the point is in - NSRect screenFrame = [[NSScreen mainScreen] visibleFrame]; - - for (NSScreen *screen in [NSScreen screens]) { - NSRect frame = [screen visibleFrame]; - if (topLeftPoint.x >= NSMinX(frame) && topLeftPoint.x <= NSMaxX(frame) && topLeftPoint.y >= NSMinY(frame) && topLeftPoint.y <= NSMaxY(frame)) { - screenFrame = frame; - break; - } - } - - // make sure we don't have any erratic value - if (adjustedHeight > screenFrame.size.height / 2.0) { - adjustedHeight = 0.0; - } - - NSSize windowSize = [[self window] frame].size; - - // bottom beneath the screen? - if (adjustedPoint.y - windowSize.height < NSMinY(screenFrame)) { - adjustedPoint.y = topLeftPoint.y + adjustedHeight + windowSize.height; - } - - // top over the screen? - if (adjustedPoint.y >= NSMaxY(screenFrame)) { - adjustedPoint.y = NSMaxY(screenFrame) - 1.0; - } - - // right - if (adjustedPoint.x + windowSize.width >= NSMaxX(screenFrame)) { - adjustedPoint.x = NSMaxX(screenFrame) - windowSize.width; - } - - // left - if (adjustedPoint.x < NSMinX(screenFrame)) { - adjustedPoint.x = NSMinX(screenFrame); - } - - [[self window] setFrameTopLeftPoint:adjustedPoint]; -} - -- (NSUInteger)candidateIndexAtKeyLabelIndex:(NSUInteger)index -{ - return NSUIntegerMax; -} - -- (BOOL)visible -{ - // Because setVisible: defers its action, we need to use our own visible. Do not use [[self window] isVisible]. - return _visible; -} - -- (void)setVisible:(BOOL)visible -{ - _visible = visible; - if (visible) { - [[self window] performSelector:@selector(orderFront:) withObject:self afterDelay:0.0]; - } - else { - [[self window] performSelector:@selector(orderOut:) withObject:self afterDelay:0.0]; - } -} - -- (NSPoint)windowTopLeftPoint -{ - NSRect frameRect = [[self window] frame]; - return NSMakePoint(frameRect.origin.x, frameRect.origin.y + frameRect.size.height); -} - -- (void)setWindowTopLeftPoint:(NSPoint)topLeftPoint -{ - [self setWindowTopLeftPoint:topLeftPoint bottomOutOfScreenAdjustmentHeight:0.0]; -} - -- (NSUInteger)selectedCandidateIndex -{ - return NSUIntegerMax; -} - -- (void)setSelectedCandidateIndex:(NSUInteger)newIndex -{ -} -@end diff --git a/Source/CandidateUI/VTHorizontalCandidateController.h b/Source/CandidateUI/VTHorizontalCandidateController.h deleted file mode 100644 index 23c9da4e157ce42ba683b163216834486c11b232..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTHorizontalCandidateController.h +++ /dev/null @@ -1,40 +0,0 @@ -// -// VTHorizontalCandidateController.h -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "VTCandidateController.h" - -@class VTHorizontalCandidateView; - -@interface VTHorizontalCandidateController : VTCandidateController -{ -@protected - VTHorizontalCandidateView *_candidateView; - NSButton *_prevPageButton; - NSButton *_nextPageButton; - NSUInteger _currentPage; -} -@end diff --git a/Source/CandidateUI/VTHorizontalCandidateController.m b/Source/CandidateUI/VTHorizontalCandidateController.m deleted file mode 100644 index 4cc8795bc6f75a4d9ab3825ccef8068c04128a88..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTHorizontalCandidateController.m +++ /dev/null @@ -1,250 +0,0 @@ -// -// VTHorizontalCandidateController.m -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "VTHorizontalCandidateController.h" -#import "VTHorizontalCandidateView.h" - -@interface VTHorizontalCandidateController (Private) -- (NSUInteger)pageCount; -- (void)layoutCandidateView; -- (void)pageButtonAction:(id)sender; -- (void)candidateViewMouseDidClick:(id)sender; -@end - - -@implementation VTHorizontalCandidateController - -- (void)dealloc -{ - _candidateView = nil; - _prevPageButton = nil; - _nextPageButton = nil; -} - -- (id)init -{ - NSRect contentRect = NSMakeRect(128.0, 128.0, 0.0, 0.0); - NSUInteger styleMask = NSBorderlessWindowMask | NSNonactivatingPanelMask; - - NSPanel *panel = [[NSPanel alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; - [panel setLevel:kCGPopUpMenuWindowLevel]; - [panel setHasShadow:YES]; - - self = [self initWithWindow:panel]; - if (self) { - contentRect.origin = NSMakePoint(0.0, 0.0); - _candidateView = [[VTHorizontalCandidateView alloc] initWithFrame:contentRect]; - _candidateView.target = self; - _candidateView.action = @selector(candidateViewMouseDidClick:); - [[panel contentView] addSubview:_candidateView]; - - contentRect.size = NSMakeSize(36.0, 20.0); - _nextPageButton = [[NSButton alloc] initWithFrame:contentRect]; - _prevPageButton = [[NSButton alloc] initWithFrame:contentRect]; - [_nextPageButton setButtonType:NSMomentaryLightButton]; - [_nextPageButton setBezelStyle:NSSmallSquareBezelStyle]; - [_nextPageButton setTitle:@"»"]; - [_nextPageButton setTarget:self]; - [_nextPageButton setAction:@selector(pageButtonAction:)]; - - [_prevPageButton setButtonType:NSMomentaryLightButton]; - [_prevPageButton setBezelStyle:NSSmallSquareBezelStyle]; - [_prevPageButton setTitle:@"«"]; - [_prevPageButton setTarget:self]; - [_prevPageButton setAction:@selector(pageButtonAction:)]; - - [[panel contentView] addSubview:_nextPageButton]; - [[panel contentView] addSubview:_prevPageButton]; - } - - return self; -} - -- (void)reloadData -{ - _candidateView.highlightedIndex = 0; - _currentPage = 0; - [self layoutCandidateView]; -} - -- (BOOL)showNextPage -{ - if (_currentPage + 1 >= [self pageCount]) { - return NO; - } - - _currentPage++; - _candidateView.highlightedIndex = 0; - [self layoutCandidateView]; - return YES; -} - -- (BOOL)showPreviousPage -{ - if (_currentPage == 0) { - return NO; - } - - _currentPage--; - _candidateView.highlightedIndex = 0; - [self layoutCandidateView]; - return YES; -} - -- (BOOL)highlightNextCandidate -{ - NSUInteger currentIndex = self.selectedCandidateIndex; - if (currentIndex + 1 >= [_delegate candidateCountForController:self]) { - return NO; - } - - self.selectedCandidateIndex = currentIndex + 1; - return YES; -} - -- (BOOL)highlightPreviousCandidate -{ - NSUInteger currentIndex = self.selectedCandidateIndex; - if (currentIndex == 0) { - return NO; - } - - self.selectedCandidateIndex = currentIndex - 1; - return YES; -} - -- (NSUInteger)candidateIndexAtKeyLabelIndex:(NSUInteger)index -{ - NSUInteger result = _currentPage * [_keyLabels count] + index; - return result < [_delegate candidateCountForController:self] ? result : NSUIntegerMax; -} - - -- (NSUInteger)selectedCandidateIndex -{ - return _currentPage * [_keyLabels count] + _candidateView.highlightedIndex; -} - -- (void)setSelectedCandidateIndex:(NSUInteger)newIndex -{ - NSUInteger keyLabelCount = [_keyLabels count]; - if (newIndex < [_delegate candidateCountForController:self]) { - _currentPage = newIndex / keyLabelCount; - _candidateView.highlightedIndex = newIndex % keyLabelCount; - [self layoutCandidateView]; - } -} -@end - - -@implementation VTHorizontalCandidateController (Private) -- (NSUInteger)pageCount -{ - NSUInteger totalCount = [_delegate candidateCountForController:self]; - NSUInteger keyLabelCount = [_keyLabels count]; - return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0); -} - -- (void)layoutCandidateView -{ - [_candidateView setKeyLabelFont:_keyLabelFont candidateFont:_candidateFont]; - - NSMutableArray *candidates = [NSMutableArray array]; - NSUInteger count = [_delegate candidateCountForController:self]; - NSUInteger keyLabelCount = [_keyLabels count]; - for (NSUInteger index = _currentPage * keyLabelCount, j = 0; index < count && j < keyLabelCount; index++, j++) { - [candidates addObject:[_delegate candidateController:self candidateAtIndex:index]]; - } - - [_candidateView setKeyLabels:_keyLabels displayedCandidates:candidates]; - NSSize newSize = _candidateView.sizeForView; - - NSRect frameRect = [_candidateView frame]; - frameRect.size = newSize; - [_candidateView setFrame:frameRect]; - - if ([self pageCount] > 1) { - NSRect buttonRect = [_nextPageButton frame]; - CGFloat spacing = 0.0; - - if (newSize.height < 40.0) { - buttonRect.size.height = floor(newSize.height / 2); - } - else { - buttonRect.size.height = 20.0; - } - - if (newSize.height >= 60.0) { - spacing = ceil(newSize.height * 0.1); - } - - CGFloat buttonOriginY = (newSize.height - (buttonRect.size.height * 2.0 + spacing)) / 2.0; - buttonRect.origin = NSMakePoint(newSize.width + 8.0, buttonOriginY); - [_nextPageButton setFrame:buttonRect]; - - buttonRect.origin = NSMakePoint(newSize.width + 8.0, buttonOriginY + buttonRect.size.height + spacing); - [_prevPageButton setFrame:buttonRect]; - - [_nextPageButton setEnabled:(_currentPage + 1 < [self pageCount])]; - [_prevPageButton setEnabled:(_currentPage != 0)]; - - newSize.width += 52.0; - - [_nextPageButton setHidden:NO]; - [_prevPageButton setHidden:NO]; - } - else { - [_nextPageButton setHidden:YES]; - [_prevPageButton setHidden:YES]; - } - - frameRect = [[self window] frame]; - NSPoint topLeftPoint = NSMakePoint(frameRect.origin.x, frameRect.origin.y + frameRect.size.height); - - frameRect.size = newSize; - frameRect.origin = NSMakePoint(topLeftPoint.x, topLeftPoint.y - frameRect.size.height); - - [[self window] setFrame:frameRect display:NO]; - [_candidateView setNeedsDisplay:YES]; - -} - -- (void)pageButtonAction:(id)sender -{ - if (sender == _nextPageButton) { - [self showNextPage]; - } - else if (sender == _prevPageButton) { - [self showPreviousPage]; - } -} - -- (void)candidateViewMouseDidClick:(id)sender -{ - [_delegate candidateController:self didSelectCandidateAtIndex:self.selectedCandidateIndex]; -} -@end diff --git a/Source/CandidateUI/VTHorizontalCandidateView.h b/Source/CandidateUI/VTHorizontalCandidateView.h deleted file mode 100644 index 492b7c5c177339131ff0700f9290dd01558a80fb..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTHorizontalCandidateView.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// VTHorizontalCandidateView.h -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import - -@interface VTHorizontalCandidateView : NSView -{ -@protected - NSArray *_keyLabels; - NSArray *_displayedCandidates; - CGFloat _keyLabelHeight; - CGFloat _candidateTextHeight; - CGFloat _cellPadding; - NSDictionary *_keyLabelAttrDict; - NSDictionary *_candidateAttrDict; - NSArray *_elementWidths; - NSUInteger _highlightedIndex; - NSUInteger _trackingHighlightedIndex; - SEL _action; - __weak id _target; -} - -- (void)setKeyLabels:(NSArray *)labels displayedCandidates:(NSArray *)candidates; -- (void)setKeyLabelFont:(NSFont *)labelFont candidateFont:(NSFont *)candidateFont; - -@property (readonly, nonatomic) NSSize sizeForView; -@property (assign, nonatomic) NSUInteger highlightedIndex; -@property (assign, nonatomic) SEL action; -@property (weak, nonatomic) id target; -@end diff --git a/Source/CandidateUI/VTHorizontalCandidateView.m b/Source/CandidateUI/VTHorizontalCandidateView.m deleted file mode 100644 index d24122f50b65f85aa772c9c044eca207e63fe845..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTHorizontalCandidateView.m +++ /dev/null @@ -1,225 +0,0 @@ -// -// VTHorizontalCandidateView.m -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "VTHorizontalCandidateView.h" - -// use these instead of MIN/MAX macro to keep compilers happy with pedantic warnings on -NS_INLINE CGFloat min(CGFloat a, CGFloat b) { return a < b ? a : b; } -NS_INLINE CGFloat max(CGFloat a, CGFloat b) { return a > b ? a : b; } - -@implementation VTHorizontalCandidateView - -@synthesize highlightedIndex = _highlightedIndex; -@synthesize action = _action; -@synthesize target = _target; - -- (void)dealloc -{ - _keyLabels = nil; - _displayedCandidates = nil; - _keyLabelAttrDict = nil; - _candidateAttrDict = nil; - _elementWidths = nil; -} - -- (void)setKeyLabels:(NSArray *)labels displayedCandidates:(NSArray *)candidates -{ - NSUInteger count = min([labels count], [candidates count]); - _keyLabels = [labels subarrayWithRange:NSMakeRange(0, count)]; - _displayedCandidates = [candidates subarrayWithRange:NSMakeRange(0, count)]; - - NSMutableArray *newWidths = [NSMutableArray array]; - - NSSize baseSize = NSMakeSize(10240.0, 10240.0); - for (NSUInteger index = 0; index < count; index++) { - NSRect labelRect = [[_keyLabels objectAtIndex:index] boundingRectWithSize:baseSize options:NSStringDrawingUsesLineFragmentOrigin attributes:_keyLabelAttrDict]; - - NSRect candidateRect = [[_displayedCandidates objectAtIndex:index] boundingRectWithSize:baseSize options:NSStringDrawingUsesLineFragmentOrigin attributes:_candidateAttrDict]; - - CGFloat width = max(labelRect.size.width, candidateRect.size.width) + _cellPadding; - [newWidths addObject:[NSNumber numberWithDouble:width]]; - } - - _elementWidths = newWidths; -} - -- (void)setKeyLabelFont:(NSFont *)labelFont candidateFont:(NSFont *)candidateFont -{ - NSMutableParagraphStyle *paraStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; - [paraStyle setAlignment:NSCenterTextAlignment]; - - _keyLabelAttrDict = [NSDictionary dictionaryWithObjectsAndKeys: - labelFont, NSFontAttributeName, - paraStyle, NSParagraphStyleAttributeName, - [NSColor blackColor], NSForegroundColorAttributeName, - nil]; - _candidateAttrDict = [NSDictionary dictionaryWithObjectsAndKeys: - candidateFont, NSFontAttributeName, - paraStyle, NSParagraphStyleAttributeName, - [NSColor textColor], NSForegroundColorAttributeName, - nil]; - - CGFloat labelFontSize = [labelFont pointSize]; - CGFloat candidateFontSize = [candidateFont pointSize]; - CGFloat biggestSize = max(labelFontSize, candidateFontSize); - - _keyLabelHeight = ceil(labelFontSize * 1.20); - _candidateTextHeight = ceil(candidateFontSize * 1.20); - _cellPadding = ceil(biggestSize / 2.0); -} - - -- (NSSize)sizeForView -{ - NSSize result = NSMakeSize(0.0, 0.0); - if ([_elementWidths count]) { - for (NSNumber *w in _elementWidths) { - result.width += [w doubleValue]; - } - - result.width += [_elementWidths count]; - result.height = _keyLabelHeight + _candidateTextHeight + 1.0; - } - - return result; -} - -- (BOOL)isFlipped -{ - return YES; -} - -- (void)drawRect:(NSRect)dirtyRect -{ - NSColor *backgroundColor = [NSColor controlBackgroundColor]; - NSColor *darkGray = [NSColor colorWithDeviceWhite:0.7 alpha:1.0]; - NSColor *lightGray = [NSColor colorWithDeviceWhite:0.8 alpha:1.0]; - - NSRect bounds = [self bounds]; - - [backgroundColor setFill]; - [NSBezierPath fillRect:bounds]; - - [[NSColor darkGrayColor] setStroke]; - [NSBezierPath strokeLineFromPoint:NSMakePoint(bounds.size.width, 0.0) toPoint:NSMakePoint(bounds.size.width, bounds.size.height)]; - - NSUInteger count = [_elementWidths count]; - CGFloat accuWidth = 0.0; - - for (NSUInteger index = 0; index < count; index++) { - NSDictionary *activeCandidateAttr = _candidateAttrDict; - CGFloat currentWidth = [[_elementWidths objectAtIndex:index] doubleValue]; - NSRect labelRect = NSMakeRect(accuWidth, 0.0, currentWidth, _keyLabelHeight); - NSRect candidateRect = NSMakeRect(accuWidth, _keyLabelHeight + 1.0, currentWidth, _candidateTextHeight); - - if (index == _highlightedIndex) { - [darkGray setFill]; - } - else { - [lightGray setFill]; - } - - [NSBezierPath fillRect:labelRect]; - [[_keyLabels objectAtIndex:index] drawInRect:labelRect withAttributes:_keyLabelAttrDict]; - - if (index == _highlightedIndex) { - [[NSColor selectedTextBackgroundColor] setFill]; - - activeCandidateAttr = [_candidateAttrDict mutableCopy]; - [(NSMutableDictionary *)activeCandidateAttr setObject:[NSColor selectedTextColor] forKey:NSForegroundColorAttributeName]; - } - else { - [backgroundColor setFill]; - } - - [NSBezierPath fillRect:candidateRect]; - [[_displayedCandidates objectAtIndex:index] drawInRect:candidateRect withAttributes:activeCandidateAttr]; - - accuWidth += currentWidth + 1.0; - } -} - -- (NSUInteger)findHitIndex:(NSEvent *)theEvent -{ - NSUInteger result = NSUIntegerMax; - - NSPoint location = [self convertPoint:[theEvent locationInWindow] toView:nil]; - if (!NSPointInRect(location, [self bounds])) { - return result; - } - - NSUInteger count = [_elementWidths count]; - CGFloat accuWidth = 0.0; - for (NSUInteger index = 0; index < count; index++) { - CGFloat currentWidth = [[_elementWidths objectAtIndex:index] doubleValue]; - - if (location.x >= accuWidth && location.x <= accuWidth + currentWidth) { - result = index; - break; - } - - accuWidth += currentWidth + 1.0; - } - - return result; -} - -- (void)mouseDown:(NSEvent *)theEvent -{ - NSUInteger newIndex = [self findHitIndex:theEvent]; - _trackingHighlightedIndex = _highlightedIndex; - - if (newIndex != NSUIntegerMax) { - _highlightedIndex = newIndex; - [self setNeedsDisplay:YES]; - } -} - -- (void)mouseUp:(NSEvent *)theEvent -{ - NSUInteger newIndex = [self findHitIndex:theEvent]; - BOOL triggerAction = NO; - - if (newIndex == _highlightedIndex) { - triggerAction = YES; - } - else { - _highlightedIndex = _trackingHighlightedIndex; - } - - _trackingHighlightedIndex = 0; - [self setNeedsDisplay:YES]; - -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Warc-performSelector-leaks" - if (triggerAction && _target && _action) { - [_target performSelector:_action withObject:self]; - } -# pragma clang diagnostic pop -} - -@end diff --git a/Source/CandidateUI/VTVerticalCandidateController.h b/Source/CandidateUI/VTVerticalCandidateController.h deleted file mode 100644 index 04bdb596eb3900074b6063bb80ce5c00af68b5a4..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTVerticalCandidateController.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// VTVerticalCandidateController.h -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "VTCandidateController.h" - -@class VTVerticalKeyLabelStripView; - -@interface VTVerticalCandidateController : VTCandidateController -{ -@protected - VTVerticalKeyLabelStripView *_keyLabelStripView; - NSScrollView *_scrollView; - NSTableView *_tableView; - NSMutableParagraphStyle *_candidateTextParagraphStyle; - CGFloat _maxCandidateAttrStringWidth; -} -@end diff --git a/Source/CandidateUI/VTVerticalCandidateController.m b/Source/CandidateUI/VTVerticalCandidateController.m deleted file mode 100644 index 7150d45b3ce9143bf34872bad5bb54dbb9a85f12..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTVerticalCandidateController.m +++ /dev/null @@ -1,434 +0,0 @@ -// -// VTVerticalCandidateController.m -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "VTVerticalCandidateController.h" -#import "VTVerticalKeyLabelStripView.h" -#import "VTVerticalCandidateTableView.h" - -// use these instead of MIN/MAX macro to keep compilers happy with pedantic warnings on -NS_INLINE CGFloat min(CGFloat a, CGFloat b) { return a < b ? a : b; } -NS_INLINE CGFloat max(CGFloat a, CGFloat b) { return a > b ? a : b; } - -static const CGFloat kCandidateTextPadding = 24.0; -static const CGFloat kCandidateTextLeftMargin = 8.0; - -#if defined(__MAC_10_16) -static const CGFloat kCandidateTextPaddingWithMandatedTableViewPadding = 18.0; -static const CGFloat kCandidateTextLeftMarginWithMandatedTableViewPadding = 0.0; -#endif - -@interface VTVerticalCandidateController (Private) -- (void)rowDoubleClicked:(id)sender; -- (BOOL)scrollPageByOne:(BOOL)forward; -- (BOOL)moveSelectionByOne:(BOOL)forward; -- (void)layoutCandidateView; -@end - -@implementation VTVerticalCandidateController -{ - // Total padding added to the left and the right of the table view cell text. - CGFloat _candidateTextPadding; - - // The indent of the table view cell text from the left. - CGFloat _candidateTextLeftMargin; -} - - -- (id)init -{ - NSRect contentRect = NSMakeRect(128.0, 128.0, 0.0, 0.0); - NSUInteger styleMask = NSBorderlessWindowMask | NSNonactivatingPanelMask; - - NSPanel *panel = [[NSPanel alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; - [panel setLevel:kCGPopUpMenuWindowLevel]; - [panel setHasShadow:YES]; - - self = [self initWithWindow:panel]; - if (self) { - contentRect.origin = NSMakePoint(0.0, 0.0); - - NSRect stripRect = contentRect; - stripRect.size.width = 10.0; - _keyLabelStripView = [[VTVerticalKeyLabelStripView alloc] initWithFrame:stripRect]; - - [[panel contentView] addSubview:_keyLabelStripView]; - - NSRect scrollViewRect = contentRect; - scrollViewRect.origin.x = stripRect.size.width; - scrollViewRect.size.width -= stripRect.size.width; - - _scrollView = [[NSScrollView alloc] initWithFrame:scrollViewRect]; - - // >=10.7 only, elastic scroll causes some drawing issues with visible scroller, so we disable it - if ([_scrollView respondsToSelector:@selector(setVerticalScrollElasticity:)]) { - [_scrollView setVerticalScrollElasticity:NSScrollElasticityNone]; - } - - _tableView = [[VTVerticalCandidateTableView alloc] initWithFrame:contentRect]; - [_tableView setDataSource:self]; - [_tableView setDelegate:self]; - - NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:@"candidate"]; - [column setDataCell:[[NSTextFieldCell alloc] init]]; - [column setEditable:NO]; - - _candidateTextPadding = kCandidateTextPadding; - _candidateTextLeftMargin = kCandidateTextLeftMargin; - - [_tableView addTableColumn:column]; - [_tableView setIntercellSpacing:NSMakeSize(0.0, 1.0)]; - [_tableView setHeaderView:nil]; - [_tableView setAllowsMultipleSelection:NO]; - [_tableView setAllowsEmptySelection:YES]; - [_tableView setDoubleAction:@selector(rowDoubleClicked:)]; - [_tableView setTarget:self]; - - #if defined(__MAC_10_16) - if (@available(macOS 10.16, *)) { - [_tableView setStyle:NSTableViewStyleFullWidth]; - _candidateTextPadding = kCandidateTextPaddingWithMandatedTableViewPadding; - _candidateTextLeftMargin = kCandidateTextLeftMarginWithMandatedTableViewPadding; - } - #endif - - [_scrollView setDocumentView:_tableView]; - [[panel contentView] addSubview:_scrollView]; - - _candidateTextParagraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; - [_candidateTextParagraphStyle setFirstLineHeadIndent:_candidateTextLeftMargin]; - [_candidateTextParagraphStyle setLineBreakMode:NSLineBreakByClipping]; - } - - return self; -} - -- (void)reloadData -{ - _maxCandidateAttrStringWidth = ceil([_candidateFont pointSize] * 2.0 + _candidateTextPadding); - - [_tableView reloadData]; - [self layoutCandidateView]; - - if ([_delegate candidateCountForController:self]) { - self.selectedCandidateIndex = 0; - } -} - -- (BOOL)showNextPage -{ - return [self scrollPageByOne:YES]; -} - -- (BOOL)showPreviousPage -{ - return [self scrollPageByOne:NO]; -} - -- (BOOL)highlightNextCandidate -{ - return [self moveSelectionByOne:YES]; -} - -- (BOOL)highlightPreviousCandidate -{ - return [self moveSelectionByOne:NO]; -} - -- (NSUInteger)candidateIndexAtKeyLabelIndex:(NSUInteger)index -{ - NSInteger firstVisibleRow = [_tableView rowAtPoint:[_scrollView documentVisibleRect].origin]; - if (firstVisibleRow != -1) { - NSUInteger result = firstVisibleRow + index; - if (result < [_delegate candidateCountForController:self]) { - return result; - } - } - - return NSUIntegerMax; -} - -- (NSUInteger)selectedCandidateIndex -{ - NSInteger selectedRow = [_tableView selectedRow]; - return (selectedRow == -1) ? NSUIntegerMax : selectedRow; -} - -- (void)setSelectedCandidateIndex:(NSUInteger)aNewIndex -{ - NSUInteger newIndex = aNewIndex; - - NSInteger selectedRow = [_tableView selectedRow]; - - NSUInteger labelCount = [_keyLabels count]; - NSUInteger itemCount = [_delegate candidateCountForController:self]; - - if (newIndex == NSUIntegerMax) { - if (itemCount == 0) { - [_tableView deselectAll:self]; - return; - } - newIndex = 0; - } - - NSUInteger lastVisibleRow = newIndex; - if (selectedRow != -1 && itemCount > 0 && itemCount > labelCount) { - if (newIndex > selectedRow && (newIndex - selectedRow) > 1) { - lastVisibleRow = min(newIndex + labelCount - 1, itemCount - 1); - } - - // no need to handle the backward case: (newIndex < selectedRow && selectedRow - newIndex > 1) - } - - if (itemCount > labelCount) { - [_tableView scrollRowToVisible:lastVisibleRow]; - } - - [_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:newIndex] byExtendingSelection:NO]; -} - - -@end - - -@implementation VTVerticalCandidateController (Private) -- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView -{ - return [_delegate candidateCountForController:self]; -} - -- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row -{ - NSString *candidate = @""; - - // rendering can occur when the delegate is already gone or data goes stale; in that case we ignore it - - if (row < [_delegate candidateCountForController:self]) { - candidate = [_delegate candidateController:self candidateAtIndex:row]; - } - - NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:candidate attributes:[NSDictionary dictionaryWithObjectsAndKeys:_candidateFont, NSFontAttributeName, _candidateTextParagraphStyle, NSParagraphStyleAttributeName, nil]]; - - // we do more work than what this method is expected to; normally not a good practice, but for the amount of data (9 to 10 rows max), we can afford the overhead - - // expand the window width if text overflows - NSRect boundingRect = [attrString boundingRectWithSize:NSMakeSize(10240.0, 10240.0) options:NSStringDrawingUsesLineFragmentOrigin]; - CGFloat textWidth = boundingRect.size.width + _candidateTextPadding; - if (textWidth > _maxCandidateAttrStringWidth) { - _maxCandidateAttrStringWidth = textWidth; - [self layoutCandidateView]; - } - - // keep track of the highlighted index in the key label strip - NSUInteger count = [_keyLabels count]; - NSInteger selectedRow = [_tableView selectedRow]; - if (selectedRow != -1) { - // cast this into signed integer to make our life easier - NSInteger newHilightIndex; - - if (_keyLabelStripView.highlightedIndex != -1 && (row >= selectedRow + count || (selectedRow > count && row <= selectedRow - count))) { - newHilightIndex = -1; - } - else { - NSInteger firstVisibleRow = [_tableView rowAtPoint:[_scrollView documentVisibleRect].origin]; - - newHilightIndex = selectedRow - firstVisibleRow; - if (newHilightIndex < -1) { - newHilightIndex = -1; - } - } - - if (newHilightIndex != _keyLabelStripView.highlightedIndex && newHilightIndex >= 0) { - _keyLabelStripView.highlightedIndex = newHilightIndex; - [_keyLabelStripView setNeedsDisplay:YES]; - } - } - - return attrString; -} - -- (void)tableViewSelectionDidChange:(NSNotification *)aNotification -{ - NSInteger selectedRow = [_tableView selectedRow]; - if (selectedRow != -1) { - // keep track of the highlighted index in the key label strip - NSInteger firstVisibleRow = [_tableView rowAtPoint:[_scrollView documentVisibleRect].origin]; - _keyLabelStripView.highlightedIndex = selectedRow - firstVisibleRow; - [_keyLabelStripView setNeedsDisplay:YES]; - - // fix a subtle OS X "bug" that, since we force the scroller to appear, - // scrolling sometimes shows a temporarily "broken" scroll bar - // (but quickly disappears) - if ([_scrollView hasVerticalScroller]) { - [[_scrollView verticalScroller] setNeedsDisplay]; - } - } -} - -- (void)rowDoubleClicked:(id)sender -{ - NSInteger clickedRow = [_tableView clickedRow]; - if (clickedRow != -1) { - [_delegate candidateController:self didSelectCandidateAtIndex:clickedRow]; - } -} - -- (BOOL)scrollPageByOne:(BOOL)forward -{ - NSUInteger labelCount = [_keyLabels count]; - NSUInteger itemCount = [_delegate candidateCountForController:self]; - - if (0 == itemCount) { - return NO; - } - - if (itemCount <= labelCount) { - return NO; - } - - NSUInteger newIndex = self.selectedCandidateIndex; - - if (forward) { - if (newIndex == itemCount - 1) { - return NO; - } - - newIndex = min(newIndex + labelCount, itemCount - 1); - } - else { - if (newIndex == 0) { - return NO; - } - - if (newIndex < labelCount) { - newIndex = 0; - } - else { - newIndex -= labelCount; - } - } - - self.selectedCandidateIndex = newIndex; - return YES; -} - -- (BOOL)moveSelectionByOne:(BOOL)forward -{ - NSUInteger itemCount = [_delegate candidateCountForController:self]; - - if (0 == itemCount) { - return NO; - } - - NSUInteger newIndex = self.selectedCandidateIndex; - - if (forward) { - if (newIndex == itemCount - 1) { - return NO; - } - - newIndex++; - } - else { - if (0 == newIndex) { - return NO; - } - - newIndex--; - } - - self.selectedCandidateIndex = newIndex; - return YES; -} - -- (void)layoutCandidateView -{ - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(doLayoutCanaditeView) object:nil]; - [self performSelector:@selector(doLayoutCanaditeView) withObject:nil afterDelay:0.0]; -} - -- (void)doLayoutCanaditeView -{ - NSUInteger count = [_delegate candidateCountForController:self]; - if (!count) { - return; - } - - CGFloat candidateFontSize = ceil([_candidateFont pointSize]); - CGFloat keyLabelFontSize = ceil([_keyLabelFont pointSize]); - CGFloat fontSize = max(candidateFontSize, keyLabelFontSize); - - NSControlSize controlSize = (fontSize > 36.0) ? NSRegularControlSize : NSSmallControlSize; - - NSUInteger keyLabelCount = [_keyLabels count]; - CGFloat scrollerWidth = 0.0; - if (count <= keyLabelCount) { - keyLabelCount = count; - [_scrollView setHasVerticalScroller:NO]; - } - else { - [_scrollView setHasVerticalScroller:YES]; - - NSScroller *verticalScroller = [_scrollView verticalScroller]; - [verticalScroller setControlSize:controlSize]; - [verticalScroller setScrollerStyle:NSScrollerStyleLegacy]; - scrollerWidth = [NSScroller scrollerWidthForControlSize:controlSize scrollerStyle:NSScrollerStyleLegacy]; - } - - _keyLabelStripView.keyLabelFont = _keyLabelFont; - _keyLabelStripView.keyLabels = [_keyLabels subarrayWithRange:NSMakeRange(0, keyLabelCount)]; - _keyLabelStripView.labelOffsetY = (keyLabelFontSize >= candidateFontSize) ? 0.0 : floor((candidateFontSize - keyLabelFontSize) / 2.0); - - CGFloat rowHeight = ceil(fontSize * 1.25); - [_tableView setRowHeight:rowHeight]; - - CGFloat maxKeyLabelWidth = keyLabelFontSize; - NSDictionary *textAttr = [NSDictionary dictionaryWithObjectsAndKeys: - _keyLabelFont, NSFontAttributeName, - nil]; - NSSize boundingBox = NSMakeSize(1600.0, 1600.0); - for (NSString *label in _keyLabels) { - NSRect rect = [label boundingRectWithSize:boundingBox options:NSStringDrawingUsesLineFragmentOrigin attributes:textAttr]; - maxKeyLabelWidth = max(rect.size.width, maxKeyLabelWidth); - } - - CGFloat rowSpacing = [_tableView intercellSpacing].height; - CGFloat stripWidth = ceil(maxKeyLabelWidth * 1.20); - CGFloat tableViewStartWidth = ceil(_maxCandidateAttrStringWidth + scrollerWidth);; - CGFloat windowWidth = stripWidth + 1.0 + tableViewStartWidth; - CGFloat windowHeight = keyLabelCount * (rowHeight + rowSpacing); - - NSRect frameRect = [[self window] frame]; - NSPoint topLeftPoint = NSMakePoint(frameRect.origin.x, frameRect.origin.y + frameRect.size.height); - - frameRect.size = NSMakeSize(windowWidth, windowHeight); - frameRect.origin = NSMakePoint(topLeftPoint.x, topLeftPoint.y - frameRect.size.height); - - [_keyLabelStripView setFrame:NSMakeRect(0.0, 0.0, stripWidth, windowHeight)]; - [_scrollView setFrame:NSMakeRect(stripWidth + 1.0, 0.0, tableViewStartWidth, windowHeight)]; - [[self window] setFrame:frameRect display:NO]; -} -@end diff --git a/Source/CandidateUI/VTVerticalCandidateTableView.h b/Source/CandidateUI/VTVerticalCandidateTableView.h deleted file mode 100644 index 47bb37acc67a205fbf49f26ac958d07fefea0f27..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTVerticalCandidateTableView.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// VTVerticalCandidateTableView.h -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import - -@interface VTVerticalCandidateTableView : NSTableView -@end diff --git a/Source/CandidateUI/VTVerticalCandidateTableView.m b/Source/CandidateUI/VTVerticalCandidateTableView.m deleted file mode 100644 index bf326ac597bcdde24aee9cd6395a7b8b0997f680..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTVerticalCandidateTableView.m +++ /dev/null @@ -1,38 +0,0 @@ -// -// VTVerticalCandidateTableView.m -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "VTVerticalCandidateTableView.h" - -@implementation VTVerticalCandidateTableView -- (NSRect)adjustScroll:(NSRect)newVisible -{ - NSRect scrollRect = newVisible; - CGFloat rowHeightPlusSpacing = [self rowHeight] + [self intercellSpacing].height; - scrollRect.origin.y = (NSInteger)(scrollRect.origin.y / rowHeightPlusSpacing) * rowHeightPlusSpacing; - return scrollRect; -} -@end diff --git a/Source/CandidateUI/VTVerticalKeyLabelStripView.h b/Source/CandidateUI/VTVerticalKeyLabelStripView.h deleted file mode 100644 index 8439ba1a3ee35e5dfc82d6ad114515ddf1daef01..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTVerticalKeyLabelStripView.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// VTVerticalKeyLabelStripView.m -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import - -@interface VTVerticalKeyLabelStripView : NSView -{ -@protected - NSFont *_keyLabelFont; - CGFloat _labelOffsetY; - NSArray *_keyLabels; - NSInteger _highlightedIndex; -} - -@property (retain, nonatomic) NSFont *keyLabelFont; -@property (assign, nonatomic) CGFloat labelOffsetY; -@property (retain, nonatomic) NSArray *keyLabels; -@property (assign, nonatomic) NSInteger highlightedIndex; -@end diff --git a/Source/CandidateUI/VTVerticalKeyLabelStripView.m b/Source/CandidateUI/VTVerticalKeyLabelStripView.m deleted file mode 100644 index 1a7d2a19b09f0f4da12e5aafbfbb883348bd230b..0000000000000000000000000000000000000000 --- a/Source/CandidateUI/VTVerticalKeyLabelStripView.m +++ /dev/null @@ -1,104 +0,0 @@ -// -// VTVerticalKeyLabelStripView.h -// -// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "VTVerticalKeyLabelStripView.h" - -@implementation VTVerticalKeyLabelStripView -@synthesize keyLabelFont = _keyLabelFont; -@synthesize labelOffsetY = _labelOffsetY; -@synthesize keyLabels = _keyLabels; -@synthesize highlightedIndex = _highlightedIndex; - -- (void)dealloc -{ - _keyLabelFont = nil; - _keyLabels = nil; -} - -- (id)initWithFrame:(NSRect)frameRect -{ - self = [super initWithFrame:frameRect]; - if (self) { - _keyLabelFont = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; - } - - return self; -} - -- (BOOL)isFlipped -{ - return YES; -} - -- (void)drawRect:(NSRect)dirtyRect -{ - NSRect bounds = [self bounds]; - [[NSColor whiteColor] setFill]; - [NSBezierPath fillRect:bounds]; - - NSUInteger count = [_keyLabels count]; - if (!count) { - return; - } - - CGFloat cellHeight = bounds.size.height / count; - NSColor *black = [NSColor blackColor]; - NSColor *darkGray = [NSColor colorWithDeviceWhite:0.7 alpha:1.0]; - NSColor *lightGray = [NSColor colorWithDeviceWhite:0.8 alpha:1.0]; - - NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; - [style setAlignment:NSCenterTextAlignment]; - - NSDictionary *textAttr = [NSDictionary dictionaryWithObjectsAndKeys: - _keyLabelFont, NSFontAttributeName, - black, NSForegroundColorAttributeName, - style, NSParagraphStyleAttributeName, - nil]; - - for (NSUInteger index = 0; index < count; index++) { - NSRect textRect = NSMakeRect(0.0, index * cellHeight + _labelOffsetY, bounds.size.width, cellHeight - _labelOffsetY); - NSRect cellRect = NSMakeRect(0.0, index * cellHeight, bounds.size.width, cellHeight - 1); - - // fill in the last cell - if (index + 1 >= count) { - cellRect.size.height += 1.0; - } - - if (index == _highlightedIndex) { - [darkGray setFill]; - } - else { - [lightGray setFill]; - } - - [NSBezierPath fillRect:cellRect]; - - NSString *text = [_keyLabels objectAtIndex:index]; - [text drawInRect:textRect withAttributes:textAttr]; - } -} -@end diff --git a/Source/Data b/Source/Data new file mode 160000 index 0000000000000000000000000000000000000000..30a5bc773a21d67c3f117eef5346d3b35433bbaa --- /dev/null +++ b/Source/Data @@ -0,0 +1 @@ +Subproject commit 30a5bc773a21d67c3f117eef5346d3b35433bbaa diff --git a/Source/Engine/FastLM.h b/Source/Engine/FastLM.h deleted file mode 100644 index 77aac397002fcfd196c1cfc2de9e6a17294dfb75..0000000000000000000000000000000000000000 --- a/Source/Engine/FastLM.h +++ /dev/null @@ -1,80 +0,0 @@ -// -// FastLM.h: A fast unigram language model for Gramambular -// -// Copyright (c) 2012 Lukhnos Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef FASTLM_H -#define FASTLM_H - -#include -#include -#include -#include "LanguageModel.h" - -// this class relies on the fact that we have a space-separated data -// format, and we use mmap and zero-out the separators and line feeds -// to avoid creating new string objects; the parser is a simple DFA - -namespace Formosa { - namespace Gramambular { - class FastLM : public LanguageModel - { - public: - FastLM(); - ~FastLM(); - - bool open(const char *path); - void close(); - void dump(); - - virtual const vector bigramsForKeys(const string& preceedingKey, const string& key); - virtual const vector unigramsForKeys(const string& key); - virtual bool hasUnigramsForKey(const string& key); - - protected: - struct CStringCmp - { - bool operator()(const char* s1, const char* s2) const - { - return strcmp(s1, s2) < 0; - } - }; - - struct Row { - const char *key; - const char *value; - const char *logProbability; - }; - - map, CStringCmp> keyRowMap; - int fd; - void *data; - size_t length; - }; - - } -} - -#endif diff --git a/Source/Engine/Gramambular/Gramambular.h b/Source/Engine/Gramambular/Gramambular.h deleted file mode 100644 index 1036ff70e522e874f89bdcdab9cd2b5cea427bf9..0000000000000000000000000000000000000000 --- a/Source/Engine/Gramambular/Gramambular.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// Gramambular.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef Gramambular_h -#define Gramambular_h - -#include "Bigram.h" -#include "BlockReadingBuilder.h" -#include "Grid.h" -#include "KeyValuePair.h" -#include "LanguageModel.h" -#include "Node.h" -#include "NodeAnchor.h" -#include "Span.h" -#include "Unigram.h" -#include "Walker.h" - -#endif diff --git a/Source/Engine/Mandarin/Mandarin.cpp b/Source/Engine/Mandarin/Mandarin.cpp deleted file mode 100644 index 2fa0452b734e550d37d2b74c7969a5c419cd880e..0000000000000000000000000000000000000000 --- a/Source/Engine/Mandarin/Mandarin.cpp +++ /dev/null @@ -1,1013 +0,0 @@ -// -// Mandarin.cpp -// -// Copyright (c) 2006-2010 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#include -#include -#include "Mandarin.h" - -#include "OVUTF8Helper.h" -#include "OVWildcard.h" - -namespace Formosa { -namespace Mandarin { - -using namespace OpenVanilla; - -class PinyinParseHelper { -public: - static const bool ConsumePrefix(string &target, const string &prefix) - { - if (target.length() < prefix.length()) { - return false; - } - - if (target.substr(0, prefix.length()) == prefix) { - target = target.substr(prefix.length(), target.length() - prefix.length()); - return true; - } - - return false; - } -}; - -class BopomofoCharacterMap { -public: - static const BopomofoCharacterMap& SharedInstance(); - - map componentToCharacter; - map characterToComponent; - -protected: - BopomofoCharacterMap(); - static BopomofoCharacterMap* c_map; -}; - -const BPMF BPMF::FromHanyuPinyin(const string& str) -{ - if (!str.length()) { - return BPMF(); - } - - string pinyin = str; - transform(pinyin.begin(), pinyin.end(), pinyin.begin(), ::tolower); - - BPMF::Component firstComponent = 0; - BPMF::Component secondComponent = 0; - BPMF::Component thirdComponent = 0; - BPMF::Component toneComponent = 0; - - // lookup consonants and consume them - bool independentConsonant = false; - - // the y exceptions fist - if (0) {} - else if (PinyinParseHelper::ConsumePrefix(pinyin, "yuan")) { secondComponent = BPMF::UE; thirdComponent = BPMF::AN; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ying")) { secondComponent = BPMF::I; thirdComponent = BPMF::ENG; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "yung")) { secondComponent = BPMF::UE; thirdComponent = BPMF::ENG; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "yong")) { secondComponent = BPMF::UE; thirdComponent = BPMF::ENG; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "yue")) { secondComponent = BPMF::UE; thirdComponent = BPMF::E; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "yun")) { secondComponent = BPMF::UE; thirdComponent = BPMF::EN; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "you")) { secondComponent = BPMF::I; thirdComponent = BPMF::OU; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "yu")) { secondComponent = BPMF::UE; } - - - // try the first character - char c = pinyin.length() ? pinyin[0] : 0; - switch (c) { - case 'b': firstComponent = BPMF::B; pinyin = pinyin.substr(1); break; - case 'p': firstComponent = BPMF::P; pinyin = pinyin.substr(1); break; - case 'm': firstComponent = BPMF::M; pinyin = pinyin.substr(1); break; - case 'f': firstComponent = BPMF::F; pinyin = pinyin.substr(1); break; - case 'd': firstComponent = BPMF::D; pinyin = pinyin.substr(1); break; - case 't': firstComponent = BPMF::T; pinyin = pinyin.substr(1); break; - case 'n': firstComponent = BPMF::N; pinyin = pinyin.substr(1); break; - case 'l': firstComponent = BPMF::L; pinyin = pinyin.substr(1); break; - case 'g': firstComponent = BPMF::G; pinyin = pinyin.substr(1); break; - case 'k': firstComponent = BPMF::K; pinyin = pinyin.substr(1); break; - case 'h': firstComponent = BPMF::H; pinyin = pinyin.substr(1); break; - case 'j': firstComponent = BPMF::J; pinyin = pinyin.substr(1); break; - case 'q': firstComponent = BPMF::Q; pinyin = pinyin.substr(1); break; - case 'x': firstComponent = BPMF::X; pinyin = pinyin.substr(1); break; - - // special hanlding for w and y - case 'w': secondComponent = BPMF::U; pinyin = pinyin.substr(1); break; - case 'y': - if (!secondComponent && !thirdComponent) { - secondComponent = BPMF::I; - } - pinyin = pinyin.substr(1); - break; - } - - // then we try ZH, CH, SH, R, Z, C, S (in that order) - if (0) {} - else if (PinyinParseHelper::ConsumePrefix(pinyin, "zh")) { firstComponent = BPMF::ZH; independentConsonant = true; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ch")) { firstComponent = BPMF::CH; independentConsonant = true; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "sh")) { firstComponent = BPMF::SH; independentConsonant = true; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "r")) { firstComponent = BPMF::R; independentConsonant = true; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "z")) { firstComponent = BPMF::Z; independentConsonant = true; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "c")) { firstComponent = BPMF::C; independentConsonant = true; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "s")) { firstComponent = BPMF::S; independentConsonant = true; } - - // consume exceptions first: (ien, in), (iou, iu), (uen, un), (veng, iong), (ven, vn), (uei, ui), ung - // but longer sequence takes precedence - if (0) {} - else if (PinyinParseHelper::ConsumePrefix(pinyin, "veng")) { secondComponent = BPMF::UE; thirdComponent = BPMF::ENG; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "iong")) { secondComponent = BPMF::UE; thirdComponent = BPMF::ENG; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ing")) { secondComponent = BPMF::I; thirdComponent = BPMF::ENG; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ien")) { secondComponent = BPMF::I; thirdComponent = BPMF::EN; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "iou")) { secondComponent = BPMF::I; thirdComponent = BPMF::OU; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "uen")) { secondComponent = BPMF::U; thirdComponent = BPMF::EN; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ven")) { secondComponent = BPMF::UE; thirdComponent = BPMF::EN; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "uei")) { secondComponent = BPMF::U; thirdComponent = BPMF::EI; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ung")) { - // f exception - if (firstComponent == BPMF::F) { - thirdComponent = BPMF::ENG; - } - else { - secondComponent = BPMF::U; thirdComponent = BPMF::ENG; - } - } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ong")) { - // f exception - if (firstComponent == BPMF::F) { - thirdComponent = BPMF::ENG; - } - else { - secondComponent = BPMF::U; - thirdComponent = BPMF::ENG; - } - } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "un")) { - if (firstComponent == BPMF::J || firstComponent == BPMF::Q || firstComponent == BPMF::X) { - secondComponent = BPMF::UE; - } - else { - secondComponent = BPMF::U; - } - thirdComponent = BPMF::EN; - } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "iu")) { secondComponent = BPMF::I; thirdComponent = BPMF::OU; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "in")) { secondComponent = BPMF::I; thirdComponent = BPMF::EN; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "vn")) { secondComponent = BPMF::UE; thirdComponent = BPMF::EN; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ui")) { secondComponent = BPMF::U; thirdComponent = BPMF::EI; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ue")) - { - secondComponent = BPMF::UE; thirdComponent = BPMF::E; - } - - #ifndef _MSC_VER - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ü")) { secondComponent = BPMF::UE; } - #else - else if (PinyinParseHelper::ConsumePrefix(pinyin, "\xc3\xbc")) { secondComponent = BPMF::UE; } - #endif - - // then consume the middle component... - if (0) {} - else if (PinyinParseHelper::ConsumePrefix(pinyin, "i")) { secondComponent = independentConsonant ? 0 : BPMF::I; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "u")) { - if (firstComponent == BPMF::J || firstComponent == BPMF::Q || firstComponent == BPMF::X) { - secondComponent = BPMF::UE; - } - else { - secondComponent = BPMF::U; - } - } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "v")) { secondComponent = BPMF::UE; } - - // the vowels, longer sequence takes precedence - if (0) {} - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ang")) { thirdComponent = BPMF::ANG; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "eng")) { thirdComponent = BPMF::ENG; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "err")) { thirdComponent = BPMF::ERR; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ai")) { thirdComponent = BPMF::AI; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ei")) { thirdComponent = BPMF::EI; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ao")) { thirdComponent = BPMF::AO; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "ou")) { thirdComponent = BPMF::OU; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "an")) { thirdComponent = BPMF::AN; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "en")) { thirdComponent = BPMF::EN; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "er")) { thirdComponent = BPMF::ERR; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "a")) { thirdComponent = BPMF::A; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "o")) { thirdComponent = BPMF::O; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "e")) { - if (secondComponent) { - thirdComponent = BPMF::E; - } - else { - thirdComponent = BPMF::ER; - } - } - - // at last! - if (0) {} - else if (PinyinParseHelper::ConsumePrefix(pinyin, "1")) { toneComponent = BPMF::Tone1; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "2")) { toneComponent = BPMF::Tone2; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "3")) { toneComponent = BPMF::Tone3; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "4")) { toneComponent = BPMF::Tone4; } - else if (PinyinParseHelper::ConsumePrefix(pinyin, "5")) { toneComponent = BPMF::Tone5; } - - return BPMF(firstComponent | secondComponent | thirdComponent | toneComponent); -} - -const string BPMF::HanyuPinyinString(bool includesTone, bool useVForUUmlaut) const -{ - string consonant, middle, vowel, tone; - - Component cc = consonantComponent(), mvc = middleVowelComponent(), vc = vowelComponent(); - bool hasNoMVCOrVC = !(mvc || vc); - - - switch (cc) { - case B: consonant = "b"; break; - case P: consonant = "p"; break; - case M: consonant = "m"; break; - case F: consonant = "f"; break; - case D: consonant = "d"; break; - case T: consonant = "t"; break; - case N: consonant = "n"; break; - case L: consonant = "l"; break; - case G: consonant = "g"; break; - case K: consonant = "k"; break; - case H: consonant = "h"; break; - case J: consonant = "j"; if (hasNoMVCOrVC) middle = "i"; break; - case Q: consonant = "q"; if (hasNoMVCOrVC) middle = "i"; break; - case X: consonant = "x"; if (hasNoMVCOrVC) middle = "i"; break; - case ZH: consonant = "zh"; if (hasNoMVCOrVC) middle = "i"; break; - case CH: consonant = "ch"; if (hasNoMVCOrVC) middle = "i"; break; - case SH: consonant = "sh"; if (hasNoMVCOrVC) middle = "i"; break; - case R: consonant = "r"; if (hasNoMVCOrVC) middle = "i"; break; - case Z: consonant = "z"; if (hasNoMVCOrVC) middle = "i"; break; - case C: consonant = "c"; if (hasNoMVCOrVC) middle = "i"; break; - case S: consonant = "s"; if (hasNoMVCOrVC) middle = "i"; break; - } - - switch (mvc) { - case I: - if (!cc) { - consonant = "y"; - - } - - middle = (!vc || cc) ? "i" : ""; - break; - case U: - if (!cc) { - consonant = "w"; - } - middle = (!vc || cc) ? "u" : ""; - break; - case UE: - if (!cc) { - consonant = "y"; - } - - if ((cc == N || cc == L) && vc != E) { - middle = useVForUUmlaut ? "v" : "ü"; - } - else { - middle = "u"; - } - - break; - } - - switch (vc) { - case A: vowel = "a"; break; - case O: vowel = "o"; break; - case ER: vowel = "e"; break; - case E: vowel = "e"; break; - case AI: vowel = "ai"; break; - case EI: vowel = "ei"; break; - case AO: vowel = "ao"; break; - case OU: vowel = "ou"; break; - case AN: vowel = "an"; break; - case EN: vowel = "en"; break; - case ANG: vowel = "ang"; break; - case ENG: vowel = "eng"; break; - case ERR: vowel = "er"; break; - } - - // combination rules - - // ueng -> ong, but note "weng" - if ((mvc == U || mvc == UE) && vc == ENG) { - middle = ""; - vowel = (cc == J || cc == Q || cc == X) ? "iong" : ((!cc && mvc == U) ? "eng" : "ong"); - } - - // ien, uen, üen -> in, un, ün ; but note "wen", "yin" and "yun" - if (mvc && vc == EN) { - if (cc) { - vowel = "n"; - } - else { - if (mvc == UE) { - vowel = "n"; // yun - } - else if (mvc == U) { - vowel = "en"; // wen - } - else { - vowel = "in"; // yin - } - } - } - - // iou -> iu - if (cc && mvc == I && vc == OU) { - middle = ""; - vowel = "iu"; - } - - // ieng -> ing - if (mvc == I && vc == ENG) { - middle = ""; - vowel = "ing"; - } - - // uei -> ui - if (cc && mvc == U && vc == EI) { - middle = ""; - vowel = "ui"; - } - - - if (includesTone) { - switch (toneMarkerComponent()) { - case Tone2: tone = "2"; break; - case Tone3: tone = "3"; break; - case Tone4: tone = "4"; break; - case Tone5: tone = "5"; break; - } - } - - return consonant + middle + vowel + tone; -} - - - -const string BPMF::PHTString(bool includesTone) const -{ - string consonant, middle, vowel, tone; - - Component cc = consonantComponent(), mvc = middleVowelComponent(), vc = vowelComponent(); - bool hasNoMVCOrVC = !(mvc || vc); - - switch (cc) { - case B: consonant = "p"; break; - case P: consonant = "ph"; break; - case M: consonant = "m"; break; - case F: consonant = "f"; break; - case D: consonant = "t"; break; - case T: consonant = "th"; break; - case N: consonant = "n"; break; - case L: consonant = "l"; break; - case G: consonant = "k"; break; - case K: consonant = "kh"; break; - case H: consonant = "h"; break; - case J: consonant = "ch"; if (mvc != I) middle = "i"; break; - case Q: consonant = "chh"; if (mvc != I) middle = "i"; break; - case X: consonant = "hs"; if (mvc != I) middle = "i"; break; - case ZH: consonant = "ch"; if (hasNoMVCOrVC) middle = "i"; break; - case CH: consonant = "chh"; if (hasNoMVCOrVC) middle = "i"; break; - case SH: consonant = "sh"; if (hasNoMVCOrVC) middle = "i"; break; - case R: consonant = "r"; if (hasNoMVCOrVC) middle = "i"; break; - case Z: consonant = "ts"; if (hasNoMVCOrVC) middle = "i"; break; - case C: consonant = "tsh"; if (hasNoMVCOrVC) middle = "i"; break; - case S: consonant = "s"; if (hasNoMVCOrVC) middle = "i"; break; - } - - switch (mvc) { - case I: - middle = "i"; - break; - case U: - middle = "u"; - break; - case UE: - middle = "uu"; - break; - } - - switch (vc) { - case A: vowel = "a"; break; - case O: vowel = "o"; break; - case ER: vowel = "e"; break; - case E: vowel = (!(cc || mvc)) ? "eh" : "e"; break; - case AI: vowel = "ai"; break; - case EI: vowel = "ei"; break; - case AO: vowel = "ao"; break; - case OU: vowel = "ou"; break; - case AN: vowel = "an"; break; - case EN: vowel = "en"; break; - case ANG: vowel = "ang"; break; - case ENG: vowel = "eng"; break; - case ERR: vowel = "err"; break; - } - - // ieng -> ing - if (mvc == I && vc == ENG) { - middle = ""; - vowel = "ing"; - } - - // zh/ch + i without third component -> append h - if (cc == BPMF::ZH || cc == BPMF::CH) { - if (!mvc && !vc) { - vowel = "h"; - } - } - - - if (includesTone) { - switch (toneMarkerComponent()) { - case Tone2: tone = "2"; break; - case Tone3: tone = "3"; break; - case Tone4: tone = "4"; break; - case Tone5: tone = "5"; break; - } - } - - return consonant + middle + vowel + tone; - -} - -const BPMF BPMF::FromPHT(const string& str) -{ - if (!str.length()) { - return BPMF(); - } - - string pht = str; - transform(pht.begin(), pht.end(), pht.begin(), ::tolower); - - BPMF::Component firstComponent = 0; - BPMF::Component secondComponent = 0; - BPMF::Component thirdComponent = 0; - BPMF::Component toneComponent = 0; - - #define IF_CONSUME1(k, v) else if (PinyinParseHelper::ConsumePrefix(pht, k)) { firstComponent = v; } - - // consume the first part - if (0) {} - IF_CONSUME1("ph", BPMF::P) - IF_CONSUME1("p", BPMF::B) - IF_CONSUME1("m", BPMF::M) - IF_CONSUME1("f", BPMF::F) - IF_CONSUME1("th", BPMF::T) - IF_CONSUME1("n", BPMF::N) - IF_CONSUME1("l", BPMF::L) - IF_CONSUME1("kh", BPMF::K) - IF_CONSUME1("k", BPMF::G) - IF_CONSUME1("chh", BPMF::Q) - IF_CONSUME1("ch", BPMF::J) - IF_CONSUME1("hs", BPMF::X) - IF_CONSUME1("sh", BPMF::SH) - IF_CONSUME1("r", BPMF::R) - IF_CONSUME1("tsh", BPMF::C) - IF_CONSUME1("ts", BPMF::Z) - IF_CONSUME1("s", BPMF::S) - IF_CONSUME1("t", BPMF::D) - IF_CONSUME1("h", BPMF::H) - - #define IF_CONSUME2(k, v) else if (PinyinParseHelper::ConsumePrefix(pht, k)) { secondComponent = v; } - // consume the second part - if (0) {} - else if (PinyinParseHelper::ConsumePrefix(pht, "ing")) { secondComponent = BPMF::I; thirdComponent = BPMF::ENG; } - else if (PinyinParseHelper::ConsumePrefix(pht, "ih")) { - if (firstComponent == BPMF::J) { - firstComponent = BPMF::ZH; - } - else if (firstComponent == BPMF::Q) { - firstComponent = BPMF::CH; - } - } - IF_CONSUME2("i", BPMF::I) - IF_CONSUME2("uu", BPMF::UE) - IF_CONSUME2("u", BPMF::U) - - #undef IF_CONSUME1 - #undef IF_CONSUME2 - - // the vowels, longer sequence takes precedence - if (0) {} - else if (PinyinParseHelper::ConsumePrefix(pht, "ang")) { thirdComponent = BPMF::ANG; } - else if (PinyinParseHelper::ConsumePrefix(pht, "eng")) { thirdComponent = BPMF::ENG; } - else if (PinyinParseHelper::ConsumePrefix(pht, "err")) { thirdComponent = BPMF::ERR; } - else if (PinyinParseHelper::ConsumePrefix(pht, "ai")) { thirdComponent = BPMF::AI; } - else if (PinyinParseHelper::ConsumePrefix(pht, "ei")) { thirdComponent = BPMF::EI; } - else if (PinyinParseHelper::ConsumePrefix(pht, "ao")) { thirdComponent = BPMF::AO; } - else if (PinyinParseHelper::ConsumePrefix(pht, "ou")) { thirdComponent = BPMF::OU; } - else if (PinyinParseHelper::ConsumePrefix(pht, "an")) { thirdComponent = BPMF::AN; } - else if (PinyinParseHelper::ConsumePrefix(pht, "en")) { thirdComponent = BPMF::EN; } - else if (PinyinParseHelper::ConsumePrefix(pht, "er")) { thirdComponent = BPMF::ERR; } - else if (PinyinParseHelper::ConsumePrefix(pht, "a")) { thirdComponent = BPMF::A; } - else if (PinyinParseHelper::ConsumePrefix(pht, "o")) { thirdComponent = BPMF::O; } - else if (PinyinParseHelper::ConsumePrefix(pht, "eh")) { thirdComponent = BPMF::E; } - else if (PinyinParseHelper::ConsumePrefix(pht, "e")) { - if (secondComponent) { - thirdComponent = BPMF::E; - } - else { - thirdComponent = BPMF::ER; - } - } - - // fix ch/chh mappings - Component corresponding = 0; - if (firstComponent == BPMF::J) { - corresponding = BPMF::ZH; - } - else if (firstComponent == BPMF::Q) { - corresponding = BPMF::CH; - } - - if (corresponding) { - if (secondComponent == BPMF::I && !thirdComponent) { - // if the second component is I and there's no third component, we use the corresponding part - // firstComponent = corresponding; - } - else if (secondComponent == BPMF::U) { - // if second component is U, we use the corresponding part - firstComponent = corresponding; - } - else if (!secondComponent) { - // if there's no second component, it must be a corresponding part - firstComponent = corresponding; - } - } - - if (secondComponent == BPMF::I) { - // fixes a few impossible occurances - switch(firstComponent) { - case BPMF::ZH: - case BPMF::CH: - case BPMF::SH: - case BPMF::R: - case BPMF::Z: - case BPMF::C: - case BPMF::S: - secondComponent = 0; - } - } - - - // at last! - if (0) {} - else if (PinyinParseHelper::ConsumePrefix(pht, "1")) { toneComponent = BPMF::Tone1; } - else if (PinyinParseHelper::ConsumePrefix(pht, "2")) { toneComponent = BPMF::Tone2; } - else if (PinyinParseHelper::ConsumePrefix(pht, "3")) { toneComponent = BPMF::Tone3; } - else if (PinyinParseHelper::ConsumePrefix(pht, "4")) { toneComponent = BPMF::Tone4; } - else if (PinyinParseHelper::ConsumePrefix(pht, "5")) { toneComponent = BPMF::Tone5; } - - return BPMF(firstComponent | secondComponent | thirdComponent | toneComponent); -} - -const BPMF BPMF::FromComposedString(const string& str) -{ - BPMF syllable; - vector components = OVUTF8Helper::SplitStringByCodePoint(str); - for (vector::iterator iter = components.begin() ; iter != components.end() ; ++iter) { - - const map& charToComp = BopomofoCharacterMap::SharedInstance().characterToComponent; - map::const_iterator result = charToComp.find(*iter); - if (result != charToComp.end()) - syllable += BPMF((*result).second); - } - - return syllable; -} - -const string BPMF::composedString() const -{ - string result; - #define APPEND(c) if (m_syllable & c) result += (*BopomofoCharacterMap::SharedInstance().componentToCharacter.find(m_syllable & c)).second - APPEND(ConsonantMask); - APPEND(MiddleVowelMask); - APPEND(VowelMask); - APPEND(ToneMarkerMask); - #undef APPEND - return result; -} - -BopomofoCharacterMap* BopomofoCharacterMap::c_map = 0; - -const BopomofoCharacterMap& BopomofoCharacterMap::SharedInstance() -{ - if (!c_map) - c_map = new BopomofoCharacterMap(); - - return *c_map; -} - -BopomofoCharacterMap::BopomofoCharacterMap() -{ -#ifndef _MSC_VER - characterToComponent["ㄅ"] = BPMF::B; - characterToComponent["ㄆ"] = BPMF::P; - characterToComponent["ㄇ"] = BPMF::M; - characterToComponent["ㄈ"] = BPMF::F; - characterToComponent["ㄉ"] = BPMF::D; - characterToComponent["ㄊ"] = BPMF::T; - characterToComponent["ㄋ"] = BPMF::N; - characterToComponent["ㄌ"] = BPMF::L; - characterToComponent["ㄎ"] = BPMF::K; - characterToComponent["ㄍ"] = BPMF::G; - characterToComponent["ㄏ"] = BPMF::H; - characterToComponent["ㄐ"] = BPMF::J; - characterToComponent["ㄑ"] = BPMF::Q; - characterToComponent["ㄒ"] = BPMF::X; - characterToComponent["ㄓ"] = BPMF::ZH; - characterToComponent["ㄔ"] = BPMF::CH; - characterToComponent["ㄕ"] = BPMF::SH; - characterToComponent["ㄖ"] = BPMF::R; - characterToComponent["ㄗ"] = BPMF::Z; - characterToComponent["ㄘ"] = BPMF::C; - characterToComponent["ㄙ"] = BPMF::S; - characterToComponent["ㄧ"] = BPMF::I; - characterToComponent["ㄨ"] = BPMF::U; - characterToComponent["ㄩ"] = BPMF::UE; - characterToComponent["ㄚ"] = BPMF::A; - characterToComponent["ㄛ"] = BPMF::O; - characterToComponent["ㄜ"] = BPMF::ER; - characterToComponent["ㄝ"] = BPMF::E; - characterToComponent["ㄞ"] = BPMF::AI; - characterToComponent["ㄟ"] = BPMF::EI; - characterToComponent["ㄠ"] = BPMF::AO; - characterToComponent["ㄡ"] = BPMF::OU; - characterToComponent["ㄢ"] = BPMF::AN; - characterToComponent["ㄣ"] = BPMF::EN; - characterToComponent["ㄤ"] = BPMF::ANG; - characterToComponent["ㄥ"] = BPMF::ENG; - characterToComponent["ㄦ"] = BPMF::ERR; - characterToComponent["ˊ"] = BPMF::Tone2; - characterToComponent["ˇ"] = BPMF::Tone3; - characterToComponent["ˋ"] = BPMF::Tone4; - characterToComponent["˙"] = BPMF::Tone5; -#else - characterToComponent["\xe3\x84\x85"] = BPMF::B; - characterToComponent["\xe3\x84\x86"] = BPMF::P; - characterToComponent["\xe3\x84\x87"] = BPMF::M; - characterToComponent["\xe3\x84\x88"] = BPMF::F; - characterToComponent["\xe3\x84\x89"] = BPMF::D; - characterToComponent["\xe3\x84\x8a"] = BPMF::T; - characterToComponent["\xe3\x84\x8b"] = BPMF::N; - characterToComponent["\xe3\x84\x8c"] = BPMF::L; - characterToComponent["\xe3\x84\x8e"] = BPMF::K; - characterToComponent["\xe3\x84\x8d"] = BPMF::G; - characterToComponent["\xe3\x84\x8f"] = BPMF::H; - characterToComponent["\xe3\x84\x90"] = BPMF::J; - characterToComponent["\xe3\x84\x91"] = BPMF::Q; - characterToComponent["\xe3\x84\x92"] = BPMF::X; - characterToComponent["\xe3\x84\x93"] = BPMF::ZH; - characterToComponent["\xe3\x84\x94"] = BPMF::CH; - characterToComponent["\xe3\x84\x95"] = BPMF::SH; - characterToComponent["\xe3\x84\x96"] = BPMF::R; - characterToComponent["\xe3\x84\x97"] = BPMF::Z; - characterToComponent["\xe3\x84\x98"] = BPMF::C; - characterToComponent["\xe3\x84\x99"] = BPMF::S; - characterToComponent["\xe3\x84\xa7"] = BPMF::I; - characterToComponent["\xe3\x84\xa8"] = BPMF::U; - characterToComponent["\xe3\x84\xa9"] = BPMF::UE; - characterToComponent["\xe3\x84\x9a"] = BPMF::A; - characterToComponent["\xe3\x84\x9b"] = BPMF::O; - characterToComponent["\xe3\x84\x9c"] = BPMF::ER; - characterToComponent["\xe3\x84\x9d"] = BPMF::E; - characterToComponent["\xe3\x84\x9e"] = BPMF::AI; - characterToComponent["\xe3\x84\x9f"] = BPMF::EI; - characterToComponent["\xe3\x84\xa0"] = BPMF::AO; - characterToComponent["\xe3\x84\xa1"] = BPMF::OU; - characterToComponent["\xe3\x84\xa2"] = BPMF::AN; - characterToComponent["\xe3\x84\xa3"] = BPMF::EN; - characterToComponent["\xe3\x84\xa4"] = BPMF::ANG; - characterToComponent["\xe3\x84\xa5"] = BPMF::ENG; - characterToComponent["\xe3\x84\xa6"] = BPMF::ERR; - characterToComponent["\xcb\x8a"] = BPMF::Tone2; - characterToComponent["\xcb\x87"] = BPMF::Tone3; - characterToComponent["\xcb\x8b"] = BPMF::Tone4; - characterToComponent["\xcb\x99"] = BPMF::Tone5; -#endif - - for (map::iterator iter = characterToComponent.begin() ; iter != characterToComponent.end() ; ++iter) - componentToCharacter[(*iter).second] = (*iter).first; -} - -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::c_StandardLayout = 0; -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::c_ETenLayout = 0; -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::c_HsuLayout = 0; -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::c_ETen26Layout = 0; -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::c_IBMLayout = 0; -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::c_HanyuPinyinLayout = 0; - -void BopomofoKeyboardLayout::FinalizeLayouts() -{ - #define FL(x) if (x) { delete x; } x = 0 - FL(c_StandardLayout); - FL(c_ETenLayout); - FL(c_HsuLayout); - FL(c_ETen26Layout); - FL(c_IBMLayout); - FL(c_HanyuPinyinLayout); - #undef FL -} - -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::LayoutForName(const string& name) -{ - if (OVWildcard::Match(name, "standard")) - return StandardLayout(); - - if (OVWildcard::Match(name, "eten")) - return ETenLayout(); - - if (OVWildcard::Match(name, "hsu")) - return HsuLayout(); - - if (OVWildcard::Match(name, "eten26")) - return ETen26Layout(); - - if (OVWildcard::Match(name, "IBM")) - return IBMLayout(); - - if (OVWildcard::Match(name, "hanyupinyin") || OVWildcard::Match(name, "hanyu pinyin") || OVWildcard::Match(name, "hanyu-pinyin") || OVWildcard::Match(name, "pinyin")) - return HanyuPinyinLayout(); - - return 0; -} - -#define ASSIGNKEY1(m, vec, k, val) m[k] = (vec.clear(), vec.push_back((BPMF::Component)val), vec) -#define ASSIGNKEY2(m, vec, k, val1, val2) m[k] = (vec.clear(), vec.push_back((BPMF::Component)val1), vec.push_back((BPMF::Component)val2), vec) -#define ASSIGNKEY3(m, vec, k, val1, val2, val3) m[k] = (vec.clear(), vec.push_back((BPMF::Component)val1), vec.push_back((BPMF::Component)val2), vec.push_back((BPMF::Component)val3), vec) - -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::StandardLayout() -{ - if (!c_StandardLayout) { - vector vec; - BopomofoKeyToComponentMap ktcm; - - ASSIGNKEY1(ktcm, vec, '1', BPMF::B); - ASSIGNKEY1(ktcm, vec, 'q', BPMF::P); - ASSIGNKEY1(ktcm, vec, 'a', BPMF::M); - ASSIGNKEY1(ktcm, vec, 'z', BPMF::F); - ASSIGNKEY1(ktcm, vec, '2', BPMF::D); - ASSIGNKEY1(ktcm, vec, 'w', BPMF::T); - ASSIGNKEY1(ktcm, vec, 's', BPMF::N); - ASSIGNKEY1(ktcm, vec, 'x', BPMF::L); - ASSIGNKEY1(ktcm, vec, 'e', BPMF::G); - ASSIGNKEY1(ktcm, vec, 'd', BPMF::K); - ASSIGNKEY1(ktcm, vec, 'c', BPMF::H); - ASSIGNKEY1(ktcm, vec, 'r', BPMF::J); - ASSIGNKEY1(ktcm, vec, 'f', BPMF::Q); - ASSIGNKEY1(ktcm, vec, 'v', BPMF::X); - ASSIGNKEY1(ktcm, vec, '5', BPMF::ZH); - ASSIGNKEY1(ktcm, vec, 't', BPMF::CH); - ASSIGNKEY1(ktcm, vec, 'g', BPMF::SH); - ASSIGNKEY1(ktcm, vec, 'b', BPMF::R); - ASSIGNKEY1(ktcm, vec, 'y', BPMF::Z); - ASSIGNKEY1(ktcm, vec, 'h', BPMF::C); - ASSIGNKEY1(ktcm, vec, 'n', BPMF::S); - ASSIGNKEY1(ktcm, vec, 'u', BPMF::I); - ASSIGNKEY1(ktcm, vec, 'j', BPMF::U); - ASSIGNKEY1(ktcm, vec, 'm', BPMF::UE); - ASSIGNKEY1(ktcm, vec, '8', BPMF::A); - ASSIGNKEY1(ktcm, vec, 'i', BPMF::O); - ASSIGNKEY1(ktcm, vec, 'k', BPMF::ER); - ASSIGNKEY1(ktcm, vec, ',', BPMF::E); - ASSIGNKEY1(ktcm, vec, '9', BPMF::AI); - ASSIGNKEY1(ktcm, vec, 'o', BPMF::EI); - ASSIGNKEY1(ktcm, vec, 'l', BPMF::AO); - ASSIGNKEY1(ktcm, vec, '.', BPMF::OU); - ASSIGNKEY1(ktcm, vec, '0', BPMF::AN); - ASSIGNKEY1(ktcm, vec, 'p', BPMF::EN); - ASSIGNKEY1(ktcm, vec, ';', BPMF::ANG); - ASSIGNKEY1(ktcm, vec, '/', BPMF::ENG); - ASSIGNKEY1(ktcm, vec, '-', BPMF::ERR); - ASSIGNKEY1(ktcm, vec, '3', BPMF::Tone3); - ASSIGNKEY1(ktcm, vec, '4', BPMF::Tone4); - ASSIGNKEY1(ktcm, vec, '6', BPMF::Tone2); - ASSIGNKEY1(ktcm, vec, '7', BPMF::Tone5); - - c_StandardLayout = new BopomofoKeyboardLayout(ktcm, "Standard"); - } - - return c_StandardLayout; -} -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::IBMLayout() -{ - if (!c_IBMLayout) { - vector vec; - BopomofoKeyToComponentMap ktcm; - - ASSIGNKEY1(ktcm, vec, '1', BPMF::B); - ASSIGNKEY1(ktcm, vec, '2', BPMF::P); - ASSIGNKEY1(ktcm, vec, '3', BPMF::M); - ASSIGNKEY1(ktcm, vec, '4', BPMF::F); - ASSIGNKEY1(ktcm, vec, '5', BPMF::D); - ASSIGNKEY1(ktcm, vec, '6', BPMF::T); - ASSIGNKEY1(ktcm, vec, '7', BPMF::N); - ASSIGNKEY1(ktcm, vec, '8', BPMF::L); - ASSIGNKEY1(ktcm, vec, '9', BPMF::G); - ASSIGNKEY1(ktcm, vec, '0', BPMF::K); - ASSIGNKEY1(ktcm, vec, '-', BPMF::H); - ASSIGNKEY1(ktcm, vec, 'q', BPMF::J); - ASSIGNKEY1(ktcm, vec, 'w', BPMF::Q); - ASSIGNKEY1(ktcm, vec, 'e', BPMF::X); - ASSIGNKEY1(ktcm, vec, 'r', BPMF::ZH); - ASSIGNKEY1(ktcm, vec, 't', BPMF::CH); - ASSIGNKEY1(ktcm, vec, 'y', BPMF::SH); - ASSIGNKEY1(ktcm, vec, 'u', BPMF::R); - ASSIGNKEY1(ktcm, vec, 'i', BPMF::Z); - ASSIGNKEY1(ktcm, vec, 'o', BPMF::C); - ASSIGNKEY1(ktcm, vec, 'p', BPMF::S); - ASSIGNKEY1(ktcm, vec, 'a', BPMF::I); - ASSIGNKEY1(ktcm, vec, 's', BPMF::U); - ASSIGNKEY1(ktcm, vec, 'd', BPMF::UE); - ASSIGNKEY1(ktcm, vec, 'f', BPMF::A); - ASSIGNKEY1(ktcm, vec, 'g', BPMF::O); - ASSIGNKEY1(ktcm, vec, 'h', BPMF::ER); - ASSIGNKEY1(ktcm, vec, 'j', BPMF::E); - ASSIGNKEY1(ktcm, vec, 'k', BPMF::AI); - ASSIGNKEY1(ktcm, vec, 'l', BPMF::EI); - ASSIGNKEY1(ktcm, vec, ';', BPMF::AO); - ASSIGNKEY1(ktcm, vec, 'z', BPMF::OU); - ASSIGNKEY1(ktcm, vec, 'x', BPMF::AN); - ASSIGNKEY1(ktcm, vec, 'c', BPMF::EN); - ASSIGNKEY1(ktcm, vec, 'v', BPMF::ANG); - ASSIGNKEY1(ktcm, vec, 'b', BPMF::ENG); - ASSIGNKEY1(ktcm, vec, 'n', BPMF::ERR); - ASSIGNKEY1(ktcm, vec, 'm', BPMF::Tone2); - ASSIGNKEY1(ktcm, vec, ',', BPMF::Tone3); - ASSIGNKEY1(ktcm, vec, '.', BPMF::Tone4); - ASSIGNKEY1(ktcm, vec, '/', BPMF::Tone5); - - c_IBMLayout = new BopomofoKeyboardLayout(ktcm, "IBM"); - } - - return c_IBMLayout; -} - -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::ETenLayout() -{ - if (!c_ETenLayout) { - vector vec; - BopomofoKeyToComponentMap ktcm; - - ASSIGNKEY1(ktcm, vec, 'b', BPMF::B); - ASSIGNKEY1(ktcm, vec, 'p', BPMF::P); - ASSIGNKEY1(ktcm, vec, 'm', BPMF::M); - ASSIGNKEY1(ktcm, vec, 'f', BPMF::F); - ASSIGNKEY1(ktcm, vec, 'd', BPMF::D); - ASSIGNKEY1(ktcm, vec, 't', BPMF::T); - ASSIGNKEY1(ktcm, vec, 'n', BPMF::N); - ASSIGNKEY1(ktcm, vec, 'l', BPMF::L); - ASSIGNKEY1(ktcm, vec, 'v', BPMF::G); - ASSIGNKEY1(ktcm, vec, 'k', BPMF::K); - ASSIGNKEY1(ktcm, vec, 'h', BPMF::H); - ASSIGNKEY1(ktcm, vec, 'g', BPMF::J); - ASSIGNKEY1(ktcm, vec, '7', BPMF::Q); - ASSIGNKEY1(ktcm, vec, 'c', BPMF::X); - ASSIGNKEY1(ktcm, vec, ',', BPMF::ZH); - ASSIGNKEY1(ktcm, vec, '.', BPMF::CH); - ASSIGNKEY1(ktcm, vec, '/', BPMF::SH); - ASSIGNKEY1(ktcm, vec, 'j', BPMF::R); - ASSIGNKEY1(ktcm, vec, ';', BPMF::Z); - ASSIGNKEY1(ktcm, vec, '\'', BPMF::C); - ASSIGNKEY1(ktcm, vec, 's', BPMF::S); - ASSIGNKEY1(ktcm, vec, 'e', BPMF::I); - ASSIGNKEY1(ktcm, vec, 'x', BPMF::U); - ASSIGNKEY1(ktcm, vec, 'u', BPMF::UE); - ASSIGNKEY1(ktcm, vec, 'a', BPMF::A); - ASSIGNKEY1(ktcm, vec, 'o', BPMF::O); - ASSIGNKEY1(ktcm, vec, 'r', BPMF::ER); - ASSIGNKEY1(ktcm, vec, 'w', BPMF::E); - ASSIGNKEY1(ktcm, vec, 'i', BPMF::AI); - ASSIGNKEY1(ktcm, vec, 'q', BPMF::EI); - ASSIGNKEY1(ktcm, vec, 'z', BPMF::AO); - ASSIGNKEY1(ktcm, vec, 'y', BPMF::OU); - ASSIGNKEY1(ktcm, vec, '8', BPMF::AN); - ASSIGNKEY1(ktcm, vec, '9', BPMF::EN); - ASSIGNKEY1(ktcm, vec, '0', BPMF::ANG); - ASSIGNKEY1(ktcm, vec, '-', BPMF::ENG); - ASSIGNKEY1(ktcm, vec, '=', BPMF::ERR); - ASSIGNKEY1(ktcm, vec, '2', BPMF::Tone2); - ASSIGNKEY1(ktcm, vec, '3', BPMF::Tone3); - ASSIGNKEY1(ktcm, vec, '4', BPMF::Tone4); - ASSIGNKEY1(ktcm, vec, '1', BPMF::Tone5); - - c_ETenLayout = new BopomofoKeyboardLayout(ktcm, "ETen"); - } - - return c_ETenLayout; -} - -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::HsuLayout() -{ - if (!c_HsuLayout) { - vector vec; - BopomofoKeyToComponentMap ktcm; - - ASSIGNKEY1(ktcm, vec, 'b', BPMF::B); - ASSIGNKEY1(ktcm, vec, 'p', BPMF::P); - ASSIGNKEY2(ktcm, vec, 'm', BPMF::M, BPMF::AN); - ASSIGNKEY2(ktcm, vec, 'f', BPMF::F, BPMF::Tone3); - ASSIGNKEY2(ktcm, vec, 'd', BPMF::D, BPMF::Tone2); - ASSIGNKEY1(ktcm, vec, 't', BPMF::T); - ASSIGNKEY2(ktcm, vec, 'n', BPMF::N, BPMF::EN); - ASSIGNKEY3(ktcm, vec, 'l', BPMF::L, BPMF::ENG, BPMF::ERR); - ASSIGNKEY2(ktcm, vec, 'g', BPMF::G, BPMF::ER); - ASSIGNKEY2(ktcm, vec, 'k', BPMF::K, BPMF::ANG); - ASSIGNKEY2(ktcm, vec, 'h', BPMF::H, BPMF::O); - ASSIGNKEY3(ktcm, vec, 'j', BPMF::J, BPMF::ZH, BPMF::Tone4); - ASSIGNKEY2(ktcm, vec, 'v', BPMF::Q, BPMF::CH); - ASSIGNKEY2(ktcm, vec, 'c', BPMF::X, BPMF::SH); - ASSIGNKEY1(ktcm, vec, 'r', BPMF::R); - ASSIGNKEY1(ktcm, vec, 'z', BPMF::Z); - ASSIGNKEY2(ktcm, vec, 'a', BPMF::C, BPMF::EI); - ASSIGNKEY2(ktcm, vec, 's', BPMF::S, BPMF::Tone5); - ASSIGNKEY2(ktcm, vec, 'e', BPMF::I, BPMF::E); - ASSIGNKEY1(ktcm, vec, 'x', BPMF::U); - ASSIGNKEY1(ktcm, vec, 'u', BPMF::UE); - ASSIGNKEY1(ktcm, vec, 'y', BPMF::A); - ASSIGNKEY1(ktcm, vec, 'i', BPMF::AI); - ASSIGNKEY1(ktcm, vec, 'w', BPMF::AO); - ASSIGNKEY1(ktcm, vec, 'o', BPMF::OU); - - c_HsuLayout = new BopomofoKeyboardLayout(ktcm, "Hsu"); - } - - return c_HsuLayout; -} -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::ETen26Layout() -{ - if (!c_ETen26Layout) { - vector vec; - BopomofoKeyToComponentMap ktcm; - - ASSIGNKEY1(ktcm, vec, 'b', BPMF::B); - ASSIGNKEY2(ktcm, vec, 'p', BPMF::P, BPMF::OU); - ASSIGNKEY2(ktcm, vec, 'm', BPMF::M, BPMF::AN); - ASSIGNKEY2(ktcm, vec, 'f', BPMF::F, BPMF::Tone2); - ASSIGNKEY2(ktcm, vec, 'd', BPMF::D, BPMF::Tone5); - ASSIGNKEY2(ktcm, vec, 't', BPMF::T, BPMF::ANG); - ASSIGNKEY2(ktcm, vec, 'n', BPMF::N, BPMF::EN); - ASSIGNKEY2(ktcm, vec, 'l', BPMF::L, BPMF::ENG); - ASSIGNKEY2(ktcm, vec, 'v', BPMF::G, BPMF::Q); - ASSIGNKEY2(ktcm, vec, 'k', BPMF::K, BPMF::Tone4); - ASSIGNKEY2(ktcm, vec, 'h', BPMF::H, BPMF::ERR); - ASSIGNKEY2(ktcm, vec, 'g', BPMF::ZH, BPMF::J); - ASSIGNKEY2(ktcm, vec, 'c', BPMF::SH, BPMF::X); - ASSIGNKEY1(ktcm, vec, 'y', BPMF::CH); - ASSIGNKEY2(ktcm, vec, 'j', BPMF::R, BPMF::Tone3); - ASSIGNKEY2(ktcm, vec, 'q', BPMF::Z, BPMF::EI); - ASSIGNKEY2(ktcm, vec, 'w', BPMF::C, BPMF::E); - ASSIGNKEY1(ktcm, vec, 's', BPMF::S); - ASSIGNKEY1(ktcm, vec, 'e', BPMF::I); - ASSIGNKEY1(ktcm, vec, 'x', BPMF::U); - ASSIGNKEY1(ktcm, vec, 'u', BPMF::UE); - ASSIGNKEY1(ktcm, vec, 'a', BPMF::A); - ASSIGNKEY1(ktcm, vec, 'o', BPMF::O); - ASSIGNKEY1(ktcm, vec, 'r', BPMF::ER); - ASSIGNKEY1(ktcm, vec, 'i', BPMF::AI); - ASSIGNKEY1(ktcm, vec, 'z', BPMF::AO); - - c_ETen26Layout = new BopomofoKeyboardLayout(ktcm, "ETen26"); - } - - return c_ETen26Layout; -} -const BopomofoKeyboardLayout* BopomofoKeyboardLayout::HanyuPinyinLayout() -{ - if (!c_HanyuPinyinLayout) { - BopomofoKeyToComponentMap ktcm; - c_HanyuPinyinLayout = new BopomofoKeyboardLayout(ktcm, "HanyuPinyin"); - } - return c_HanyuPinyinLayout; -} - - -} // namespace Mandarin -} // namespace Formosa diff --git a/Source/Engine/Mandarin/Mandarin.h b/Source/Engine/Mandarin/Mandarin.h deleted file mode 100644 index 01ede5898d6d85beb1f0459196e59ff672cd9897..0000000000000000000000000000000000000000 --- a/Source/Engine/Mandarin/Mandarin.h +++ /dev/null @@ -1,607 +0,0 @@ -// -// Mandarin.h -// -// Copyright (c) 2006-2010 Lukhnos D. Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef Mandarin_h -#define Mandarin_h - -#include -#include -#include -#include - -namespace Formosa { - namespace Mandarin { - using namespace std; - - class BopomofoSyllable { - public: - typedef unsigned int Component; - BopomofoSyllable(Component syllable = 0) - : m_syllable(syllable) - { - } - - BopomofoSyllable(const BopomofoSyllable& another) - : m_syllable(another.m_syllable) - { - } - - ~BopomofoSyllable() - { - } - - BopomofoSyllable& operator=(const BopomofoSyllable& another) - { - m_syllable = another.m_syllable; - return *this; - } - - // takes the ASCII-form, "v"-tolerant, TW-style Hanyu Pinyin (fong, pong, bong acceptable) - static const BopomofoSyllable FromHanyuPinyin(const string& str); - - // TO DO: Support accented vowels - const string HanyuPinyinString(bool includesTone, bool useVForUUmlaut) const; - // const string HanyuPinyinString(bool includesTone, bool useVForUUmlaut, bool composeAccentedVowel) const; - - // PHT = Pai-hua-tsi - static const BopomofoSyllable FromPHT(const string& str); - const string PHTString(bool includesTone) const; - - static const BopomofoSyllable FromComposedString(const string& str); - const string composedString() const; - - void clear() - { - m_syllable = 0; - } - - bool isEmpty() const - { - return !m_syllable; - } - - bool hasConsonant() const - { - return !!(m_syllable & ConsonantMask); - } - - bool hasMiddleVowel() const - { - return !!(m_syllable & MiddleVowelMask); - } - bool hasVowel() const - { - return !!(m_syllable & VowelMask); - } - - bool hasToneMarker() const - { - return !!(m_syllable & ToneMarkerMask); - } - - Component consonantComponent() const - { - return m_syllable & ConsonantMask; - } - - Component middleVowelComponent() const - { - return m_syllable & MiddleVowelMask; - } - - Component vowelComponent() const - { - return m_syllable & VowelMask; - } - - Component toneMarkerComponent() const - { - return m_syllable & ToneMarkerMask; - } - - bool operator==(const BopomofoSyllable& another) const - { - return m_syllable == another.m_syllable; - } - - bool operator!=(const BopomofoSyllable& another) const - { - return m_syllable != another.m_syllable; - } - - bool isOverlappingWith(const BopomofoSyllable& another) const - { - #define IOW_SAND(mask) ((m_syllable & mask) && (another.m_syllable & mask)) - return IOW_SAND(ConsonantMask) || IOW_SAND(MiddleVowelMask) || IOW_SAND(VowelMask) || IOW_SAND(ToneMarkerMask); - #undef IOW_SAND - } - - // consonants J, Q, X all require the existence of vowel I or UE - bool belongsToJQXClass() const - { - Component consonant = m_syllable & ConsonantMask; - return (consonant == J || consonant == Q || consonant == X); - } - - // zi, ci, si, chi, chi, shi, ri - bool belongsToZCSRClass() const - { - Component consonant = m_syllable & ConsonantMask; - return (consonant >= ZH && consonant <= S); - } - - Component maskType() const - { - Component mask = 0; - mask |= (m_syllable & ConsonantMask) ? ConsonantMask : 0; - mask |= (m_syllable & MiddleVowelMask) ? MiddleVowelMask : 0; - mask |= (m_syllable & VowelMask) ? VowelMask : 0; - mask |= (m_syllable & ToneMarkerMask) ? ToneMarkerMask : 0; - return mask; - } - - const BopomofoSyllable operator+(const BopomofoSyllable& another) const - { - Component newSyllable = m_syllable; - #define OP_SOVER(mask) if (another.m_syllable & mask) newSyllable = (newSyllable & ~mask) | (another.m_syllable & mask) - OP_SOVER(ConsonantMask); - OP_SOVER(MiddleVowelMask); - OP_SOVER(VowelMask); - OP_SOVER(ToneMarkerMask); - #undef OP_SOVER - return BopomofoSyllable(newSyllable); - } - - BopomofoSyllable& operator+=(const BopomofoSyllable& another) - { - #define OPE_SOVER(mask) if (another.m_syllable & mask) m_syllable = (m_syllable & ~mask) | (another.m_syllable & mask) - OPE_SOVER(ConsonantMask); - OPE_SOVER(MiddleVowelMask); - OPE_SOVER(VowelMask); - OPE_SOVER(ToneMarkerMask); - #undef OPE_SOVER - return *this; - } - - short absoluteOrder() const - { - // turn BPMF syllable into a 4*14*4*22 number - return (short)(m_syllable & ConsonantMask) + - (short)((m_syllable & MiddleVowelMask) >> 5) * 22 + - (short)((m_syllable & VowelMask) >> 7) * 22 * 4 + - (short)((m_syllable & ToneMarkerMask) >> 11) * 22 * 4 * 14; - } - - const string absoluteOrderString() const - { - // 5*14*4*22 = 6160, we use a 79*79 encoding to represent that - short order = absoluteOrder(); - char low = 48 + (char)(order % 79); - char high = 48 + (char)(order / 79); - string result(2, ' '); - result[0] = low; - result[1] = high; - return result; - } - - static BopomofoSyllable FromAbsoluteOrder(short order) - { - return BopomofoSyllable( - (order % 22) | - ((order / 22) % 4) << 5 | - ((order / (22 * 4)) % 14) << 7 | - ((order / (22 * 4 * 14)) % 5) << 11 - ); - } - - static BopomofoSyllable FromAbsoluteOrderString(const string& str) - { - if (str.length() != 2) - return BopomofoSyllable(); - - return FromAbsoluteOrder((short)(str[1] - 48) * 79 + (short)(str[0] - 48)); - } - - friend ostream& operator<<(ostream& stream, const BopomofoSyllable& syllable); - - static const Component - ConsonantMask = 0x001f, // 0000 0000 0001 1111, 21 consonants - MiddleVowelMask = 0x0060, // 0000 0000 0110 0000, 3 middle vowels - VowelMask = 0x0780, // 0000 0111 1000 0000, 13 vowels - ToneMarkerMask = 0x3800, // 0011 1000 0000 0000, 5 tones (tone1 = 0x00) - B = 0x0001, P = 0x0002, M = 0x0003, F = 0x0004, - D = 0x0005, T = 0x0006, N = 0x0007, L = 0x0008, - G = 0x0009, K = 0x000a, H = 0x000b, - J = 0x000c, Q = 0x000d, X = 0x000e, - ZH = 0x000f, CH = 0x0010, SH = 0x0011, R = 0x0012, - Z = 0x0013, C = 0x0014, S = 0x0015, - I = 0x0020, U = 0x0040, UE = 0x0060, // ue = u umlaut (we use the German convention here as an ersatz to the /ju:/ sound) - A = 0x0080, O = 0x0100, ER = 0x0180, E = 0x0200, - AI = 0x0280, EI = 0x0300, AO = 0x0380, OU = 0x0400, - AN = 0x0480, EN = 0x0500, ANG = 0x0580, ENG = 0x0600, - ERR = 0x0680, - Tone1 = 0x0000, Tone2 = 0x0800, Tone3 = 0x1000, Tone4 = 0x1800, Tone5 = 0x2000; - - protected: - Component m_syllable; - }; - - inline ostream& operator<<(ostream& stream, const BopomofoSyllable& syllable) - { - stream << syllable.composedString(); - return stream; - } - - typedef BopomofoSyllable BPMF; - - typedef map > BopomofoKeyToComponentMap; - typedef map BopomofoComponentToKeyMap; - - class BopomofoKeyboardLayout { - public: - static void FinalizeLayouts(); - static const BopomofoKeyboardLayout* StandardLayout(); - static const BopomofoKeyboardLayout* ETenLayout(); - static const BopomofoKeyboardLayout* HsuLayout(); - static const BopomofoKeyboardLayout* ETen26Layout(); - static const BopomofoKeyboardLayout* IBMLayout(); - static const BopomofoKeyboardLayout* HanyuPinyinLayout(); - - // recognizes (case-insensitive): standard, eten, hsu, eten26, ibm - static const BopomofoKeyboardLayout* LayoutForName(const string& name); - - BopomofoKeyboardLayout(const BopomofoKeyToComponentMap& ktcm, const string& name) - : m_keyToComponent(ktcm) - , m_name(name) - { - for (BopomofoKeyToComponentMap::const_iterator miter = m_keyToComponent.begin() ; miter != m_keyToComponent.end() ; ++miter) - for (vector::const_iterator viter = (*miter).second.begin() ; viter != (*miter).second.end() ; ++viter) - m_componentToKey[*viter] = (*miter).first; - } - - const string name() const - { - return m_name; - } - - char componentToKey(BPMF::Component component) const - { - BopomofoComponentToKeyMap::const_iterator iter = m_componentToKey.find(component); - return (iter == m_componentToKey.end()) ? 0 : (*iter).second; - } - - const vector keyToComponents(char key) const - { - BopomofoKeyToComponentMap::const_iterator iter = m_keyToComponent.find(key); - return (iter == m_keyToComponent.end()) ? vector() : (*iter).second; - } - - const string keySequenceFromSyllable(BPMF syllable) const - { - string sequence; - - BPMF::Component c; - char k; - #define STKS_COMBINE(component) if ((c = component)) { if ((k = componentToKey(c))) sequence += string(1, k); } - STKS_COMBINE(syllable.consonantComponent()); - STKS_COMBINE(syllable.middleVowelComponent()); - STKS_COMBINE(syllable.vowelComponent()); - STKS_COMBINE(syllable.toneMarkerComponent()); - #undef STKS_COMBINE - return sequence; - } - - const BPMF syllableFromKeySequence(const string& sequence) const - { - BPMF syllable; - - for (string::const_iterator iter = sequence.begin() ; iter != sequence.end() ; ++iter) - { - bool beforeSeqHasIorUE = sequenceContainsIorUE(sequence.begin(), iter); - bool aheadSeqHasIorUE = sequenceContainsIorUE(iter + 1, sequence.end()); - - vector components = keyToComponents(*iter); - - if (!components.size()) - continue; - - if (components.size() == 1) { - syllable += BPMF(components[0]); - continue; - } - - BPMF head = BPMF(components[0]); - BPMF follow = BPMF(components[1]); - BPMF ending = components.size() > 2 ? BPMF(components[2]) : follow; - - // apply the I/UE + E rule - if (head.vowelComponent() == BPMF::E && follow.vowelComponent() != BPMF::E) - { - syllable += beforeSeqHasIorUE ? head : follow; - continue; - } - - if (head.vowelComponent() != BPMF::E && follow.vowelComponent() == BPMF::E) - { - syllable += beforeSeqHasIorUE ? follow : head; - continue; - } - - // apply the J/Q/X + I/UE rule, only two components are allowed in the components vector here - if (head.belongsToJQXClass() && !follow.belongsToJQXClass()) { - if (!syllable.isEmpty()) { - if (ending != follow) - syllable += ending; - } - else { - syllable += aheadSeqHasIorUE ? head : follow; - } - - continue; - } - - if (!head.belongsToJQXClass() && follow.belongsToJQXClass()) { - if (!syllable.isEmpty()) { - if (ending != follow) - syllable += ending; - } - else { - syllable += aheadSeqHasIorUE ? follow : head; - } - - continue; - } - - // the nasty issue of only one char in the buffer - if (iter == sequence.begin() && iter + 1 == sequence.end()) { - if (head.hasVowel() || follow.hasToneMarker() || head.belongsToZCSRClass()) - syllable += head; - else { - if (follow.hasVowel() || ending.hasToneMarker()) - syllable += follow; - else - syllable += ending; - } - - - continue; - } - - if (!(syllable.maskType() & head.maskType()) && !endAheadOrAheadHasToneMarkKey(iter + 1, sequence.end())) { - syllable += head; - } - else { - if (endAheadOrAheadHasToneMarkKey(iter + 1, sequence.end()) && head.belongsToZCSRClass() && syllable.isEmpty()) { - syllable += head; - } - else if (syllable.maskType() < follow.maskType()) { - syllable += follow; - } - else { - syllable += ending; - } - } - } - - // heuristics for Hsu keyboard layout - if (this == HsuLayout()) { - // fix the left out L to ERR when it has sound, and GI, GUE -> JI, JUE - if (syllable.vowelComponent() == BPMF::ENG && !syllable.hasConsonant() && !syllable.hasMiddleVowel()) { - syllable += BPMF(BPMF::ERR); - } - else if (syllable.consonantComponent() == BPMF::G && (syllable.middleVowelComponent() == BPMF::I || syllable.middleVowelComponent() == BPMF::UE)) { - syllable += BPMF(BPMF::J); - } - } - - - return syllable; - } - - - protected: - bool endAheadOrAheadHasToneMarkKey(string::const_iterator ahead, string::const_iterator end) const - { - if (ahead == end) - return true; - - char tone1 = componentToKey(BPMF::Tone1); - char tone2 = componentToKey(BPMF::Tone2); - char tone3 = componentToKey(BPMF::Tone3); - char tone4 = componentToKey(BPMF::Tone4); - char tone5 = componentToKey(BPMF::Tone5); - - if (tone1) - if (*ahead == tone1) return true; - - if (*ahead == tone2 || *ahead == tone3 || *ahead == tone4 || *ahead == tone5) - return true; - - return false; - } - - bool sequenceContainsIorUE(string::const_iterator start, string::const_iterator end) const - { - char iChar = componentToKey(BPMF::I); - char ueChar = componentToKey(BPMF::UE); - - for (; start != end; ++start) - if (*start == iChar || *start == ueChar) - return true; - return false; - } - - string m_name; - BopomofoKeyToComponentMap m_keyToComponent; - BopomofoComponentToKeyMap m_componentToKey; - - static const BopomofoKeyboardLayout* c_StandardLayout; - static const BopomofoKeyboardLayout* c_ETenLayout; - static const BopomofoKeyboardLayout* c_HsuLayout; - static const BopomofoKeyboardLayout* c_ETen26Layout; - static const BopomofoKeyboardLayout* c_IBMLayout; - - // this is essentially an empty layout, but we use pointer semantic to tell the differences--and pass on the responsibility to BopomofoReadingBuffer - static const BopomofoKeyboardLayout* c_HanyuPinyinLayout; - }; - - class BopomofoReadingBuffer { - public: - BopomofoReadingBuffer(const BopomofoKeyboardLayout* layout) - : m_layout(layout) - , m_pinyinMode(false) - { - if (layout == BopomofoKeyboardLayout::HanyuPinyinLayout()) { - m_pinyinMode = true; - m_pinyinSequence = ""; - } - } - - void setKeyboardLayout(const BopomofoKeyboardLayout* layout) - { - m_layout = layout; - - if (layout == BopomofoKeyboardLayout::HanyuPinyinLayout()) { - m_pinyinMode = true; - m_pinyinSequence = ""; - } - } - - bool isValidKey(char k) const - { - if (!m_pinyinMode) { - return m_layout ? (m_layout->keyToComponents(k)).size() > 0 : false; - } - - char lk = tolower(k); - if (lk >= 'a' && lk <= 'z') { - // if a tone marker is already in place - if (m_pinyinSequence.length()) { - char lastc = m_pinyinSequence[m_pinyinSequence.length() - 1]; - if (lastc >= '2' && lastc <= '5') { - return false; - } - return true; - } - return true; - } - - if (m_pinyinSequence.length() && (lk >= '2' && lk <= '5')) { - return true; - } - - return false; - } - - bool combineKey(char k) - { - if (!isValidKey(k)) - return false; - - if (m_pinyinMode) { - m_pinyinSequence += string(1, tolower(k)); - m_syllable = BPMF::FromHanyuPinyin(m_pinyinSequence); - return true; - } - - string sequence = m_layout->keySequenceFromSyllable(m_syllable) + string(1, k); - m_syllable = m_layout->syllableFromKeySequence(sequence); - return true; - } - - void clear() - { - m_pinyinSequence.clear(); - m_syllable.clear(); - } - - void backspace() - { - if (!m_layout) - return; - - if (m_pinyinMode) { - if (m_pinyinSequence.length()) { - m_pinyinSequence = m_pinyinSequence.substr(0, m_pinyinSequence.length() - 1); - } - - m_syllable = BPMF::FromHanyuPinyin(m_pinyinSequence); - return; - } - - string sequence = m_layout->keySequenceFromSyllable(m_syllable); - if (sequence.length()) { - sequence = sequence.substr(0, sequence.length() - 1); - m_syllable = m_layout->syllableFromKeySequence(sequence); - } - } - - bool isEmpty() const - { - return m_syllable.isEmpty(); - } - - const string composedString() const - { - if (m_pinyinMode) { - return m_pinyinSequence; - } - - return m_syllable.composedString(); - } - - const BPMF syllable() const - { - return m_syllable; - } - - const string standardLayoutQueryString() const - { - return BopomofoKeyboardLayout::StandardLayout()->keySequenceFromSyllable(m_syllable); - } - - const string absoluteOrderQueryString() const - { - return m_syllable.absoluteOrderString(); - } - - bool hasToneMarker() const - { - return m_syllable.hasToneMarker(); - } - - protected: - const BopomofoKeyboardLayout* m_layout; - BPMF m_syllable; - - bool m_pinyinMode; - string m_pinyinSequence; - }; - } -} - -#endif diff --git a/Source/Engine/OpenVanilla/OVAroundFilter.h b/Source/Engine/OpenVanilla/OVAroundFilter.h deleted file mode 100644 index dc024f30e47b4392061a486886b00c20e2385233..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVAroundFilter.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// OVAroundFilter.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVAroundFilter_h -#define OVAroundFilter_h - -#if defined(__APPLE__) - #include -#else - #include "OVModule.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVAroundFilter : public OVModule { - public: - virtual bool isAroundFilter() const - { - return true; - } - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVBase.h b/Source/Engine/OpenVanilla/OVBase.h deleted file mode 100644 index aa4c9a398caa952fdbbf5823996b343e8f21ecd6..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVBase.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// OVBase.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVBase_h -#define OVBase_h - -#include -#include -#include - -namespace OpenVanilla { - using namespace std; - - class OVBase { - public: - virtual ~OVBase() - { - } - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVBenchmark.h b/Source/Engine/OpenVanilla/OVBenchmark.h deleted file mode 100644 index f37f625aca1fab733cf7026fdf02ae7e89d52e30..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVBenchmark.h +++ /dev/null @@ -1,102 +0,0 @@ -// -// OVBenchmark.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVBenchmark_h -#define OVBenchmark_h - -#include - -namespace OpenVanilla { - using namespace std; - - class OVBenchmark - { - public: - OVBenchmark() - : m_used(false) - , m_running(false) - , m_start(0) - , m_elapsedTicks(0) - , m_elapsedSeconds(0.0) - { - } - - void start() - { - m_used = true; - m_running = true; - m_elapsedSeconds = 0.0; - m_elapsedTicks = 0; - m_start = clock(); - } - - void stop() - { - if (m_running) { - update(); - m_running = false; - } - } - - clock_t elapsedTicks() - { - if (!m_used) - return 0; - - if (m_running) - update(); - - return m_elapsedTicks; - } - - double elapsedSeconds() - { - if (!m_used) - return 0; - - if (m_running) - update(); - - return m_elapsedSeconds; - } - - protected: - void update() - { - m_elapsedTicks = clock() - m_start; - m_elapsedSeconds = static_cast(m_elapsedTicks) / CLOCKS_PER_SEC; - } - - bool m_used; - bool m_running; - clock_t m_start; - clock_t m_elapsedTicks; - double m_elapsedSeconds; - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVCINDataTable.h b/Source/Engine/OpenVanilla/OVCINDataTable.h deleted file mode 100644 index 3638b76878cf555ba0746f5fcdb7c30b9ecf0558..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVCINDataTable.h +++ /dev/null @@ -1,806 +0,0 @@ -// -// OVCINDataTable.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVCINDataTable_h -#define OVCINDataTable_h - -#include -#include -#include -#include -#include - -#include "OVFileHelper.h" -#include "OVUTF8Helper.h" -#include "OVWildcard.h" - -#include - -namespace OpenVanilla { - using namespace std; - - // CIN := (COMMENT | PROPERTY | KEYNAME | CHARDEF)* - // EOL := \n|\r - // COMMENT := ^#.*(EOL) - // KEY := \w+ - // VALUE := \w([\w\s]*\w)* - // PROPERTY: ^%(KEY)\s+(VALUE)(EOL) - // KEYNAME := - // ^%keyname\s+begin(EOL) - // ^(KEY)\s+(VALUE)(EOL) - // ^%keyname\s+end(EOL) - // CHARDEF: - // ^%chardef\s+begin(EOL) - // ^(KEY)\s+(VALUE)(EOL) - // ^%chardef\s+end(EOL) - - class OVCINDataTableParser; - - class OVFastKeyValuePairMap { - public: - ~OVFastKeyValuePairMap() - { - free(m_data); - } - - size_t size() - { - return m_index; - } - - pair keyValuePairAtIndex(size_t index) - { - if (index >= m_index) - return pair(); - - KVPair* entry = m_data + index; - return pair(entry->key, entry->value); - } - - vector > findPairsWithKey(const char* key) - { - return fetchValuesFromIndex(findFirstOccuranceOfKey(key), key); - } - - vector > findPairsWithWildcard(const OVWildcard& pWildcard) - { - const OVWildcard* ptrWildcard = &pWildcard; - - if (pWildcard.isCaseSensitive() != m_caseSensitive) { - OVWildcard newWildcard(pWildcard.expression(), pWildcard.matchOneChar(), pWildcard.matchZeroOrMoreChar(), m_caseSensitive); - ptrWildcard = &newWildcard; - } - - const OVWildcard& wildcard = *ptrWildcard; - - string headString = wildcard.longestHeadMatchString(); - insensitivizeString(headString); - size_t hSLength = headString.length(); - - size_t start = findFirstOccuranceOfKey(headString.c_str(), true); - vector > result; - - for (size_t index = start; index < m_index; index++) { - KVPair* entry = m_data + index; - string keyString = entry->key; - - // if no more head matchZeroOrMoreChar - string keySubstr = keyString.substr(0, hSLength); - insensitivizeString(keySubstr); - if (keySubstr > headString) - break; - - if (wildcard.match(keyString)) - result.push_back(pair(keyString, entry->value)); - } - - return result; - } - protected: - friend class OVCINDataTableParser; - - OVFastKeyValuePairMap(size_t initSize, size_t growSize, bool caseSensitive = false) - : m_index(0) - , m_size(initSize ? initSize : 1) - , m_growSize(growSize) - , m_caseSensitive(caseSensitive) - { - m_data = (KVPair*)calloc(1, sizeof(KVPair) * m_size); - } - - - void add(char* key, char* value) - { - KVPair* entry = m_data + m_index; - entry->key = key; - entry->value = value; - - m_index++; - if (m_index == m_size) - grow(); - } - - void sortAndFreeze() - { - m_size = m_index; - - if (m_caseSensitive) - qsort(m_data, m_index, sizeof(KVPair), OVFastKeyValuePairMap::qsortCompareCaseSensitive); - else - qsort(m_data, m_index, sizeof(KVPair), OVFastKeyValuePairMap::qsortCompare); - } - - void insensitivizeString(string& str) - { - if (m_caseSensitive) - return; - - for (string::iterator iter = str.begin() ; iter != str.end() ; ++iter) - *iter = tolower(*iter); - } - - protected: - vector > fetchValuesFromIndex(size_t start, const char* key) - { - vector > result; - for (size_t index = start ; index < m_index; index++) { - KVPair* entry = m_data + index; - - if (compareString(entry->key, key) <= 0) { - result.push_back(pair(entry->key, entry->value)); - } - else { - break; - } - } - - return result; - } - - size_t findFirstOccuranceOfKey(const char* key, bool closest = false) - { - if (!m_index) - return m_index; - - size_t mid, low = 0, high = m_index - 1; - - while (low <= high) { - mid = (low + high) / 2; - - char* entryKey = (m_data + mid)->key; - int cmp = compareString(key, entryKey); - - if (!cmp) { - if (!mid) - return mid; - - size_t oneUp = mid - 1; - if (!compareString(key, (m_data + oneUp)->key)) - high = oneUp; - else - return mid; - } - else { - if (closest) { - if (mid > 0) { - if (compareString(key, (m_data + mid - 1)->key) > 0 && compareString(key, entryKey) <= 0) - return mid; - } - } - - if (cmp < 0) { - if (!mid) { - if (closest) - return 0; - - return m_index; - } - - high = mid - 1; - } - else { - if (low + 1 >= m_index) - return m_index; - - low = mid + 1; - } - } - } - - return m_index; - } - - int compareString(const char* a, const char* b) - { - #ifndef WIN32 - return m_caseSensitive ? strcmp(a, b) : strcasecmp(a, b); - #else - return m_caseSensitive ? strcmp(a, b) : _stricmp(a, b); - #endif - } - - static int qsortCompare(const void* a, const void* b) - { - int cmp; - char* aa = ((const KVPair*)a)->key; - char* bb = ((const KVPair*)b)->key; - - #ifndef WIN32 - if (!(cmp = strcasecmp(aa, bb))) - #else - if (!(cmp = _stricmp(aa, bb))) - #endif - return aa == bb ? 0 : (aa > bb ? 1 : -1); - else - return cmp; - } - - static int qsortCompareCaseSensitive(const void* a, const void* b) - { - int cmp; - char* aa = ((const KVPair*)a)->key; - char* bb = ((const KVPair*)b)->key; - - if (!(cmp = strcmp(aa, bb))) - return aa == bb ? 0 : (aa > bb ? 1 : -1); - else - return cmp; - } - - - void grow() - { - size_t growSize = m_growSize ? m_growSize : m_size; - KVPair* newData = (KVPair*)malloc(sizeof(KVPair) * (m_size + growSize)); - memcpy(newData, m_data, sizeof(KVPair) * m_size); - memset(newData + m_size, 0, sizeof(KVPair) * growSize); - - KVPair* tmp = m_data; - m_data = newData; - free(tmp); - - m_size += growSize; - } - - protected: - struct KVPair { - char* key; - char* value; - }; - - bool m_caseSensitive; - size_t m_growSize; - size_t m_size; - size_t m_index; - KVPair* m_data; - }; - - class OVCINDataTable { - public: - ~OVCINDataTable() - { - if (m_propertyMap) - delete m_propertyMap; - if (m_keynameMap) - delete m_keynameMap; - if (m_chardefMap) - delete m_chardefMap; - if (m_data) - free (m_data); - } - - string findProperty(const string& key) - { - vector > result = m_propertyMap->findPairsWithKey(key.c_str()); - if (result.size()) return result[0].second; - return string(); - } - - string findKeyname(const string& key) - { - vector > result = m_keynameMap->findPairsWithKey(key.c_str()); - if (result.size()) return result[0].second; - return string(); - } - - vector findChardef(const string& key) - { - vector > ret = m_chardefMap->findPairsWithKey(key.c_str()); - vector result; - vector >::iterator iter= ret.begin(); - - for ( ; iter != ret.end(); iter++) - result.push_back((*iter).second); - - return result; - } - - vector > findChardefWithWildcard(const OVWildcard& wildcard) - { - return m_chardefMap->findPairsWithWildcard(wildcard); - } - - OVFastKeyValuePairMap* propertyMap() - { - return m_propertyMap; - } - - OVFastKeyValuePairMap* keynameMap() - { - return m_keynameMap; - } - - OVFastKeyValuePairMap* chardefMap() - { - return m_chardefMap; - } - - protected: - friend class OVCINDataTableParser; - OVCINDataTable(char* data, OVFastKeyValuePairMap* propertyMap, OVFastKeyValuePairMap* keynameMap, OVFastKeyValuePairMap* chardefMap) - : m_data(data) - , m_propertyMap(propertyMap) - , m_keynameMap(keynameMap) - , m_chardefMap(chardefMap) - { - } - - char* m_data; - OVFastKeyValuePairMap* m_propertyMap; - OVFastKeyValuePairMap* m_keynameMap; - OVFastKeyValuePairMap* m_chardefMap; - }; - - - - class OVCINDataTableParser { - public: - enum { - NoFileError, - SeekError, - EmptyFileError, - MemoryAllocationError, - ReadError, - NoDataError = EmptyFileError - }; - - OVCINDataTableParser() - : m_data(0) - , m_lastError(0) - { - } - - ~OVCINDataTableParser() - { - if (m_data) - free(m_data); - } - - int lastError() - { - return m_lastError; - } - - OVCINDataTable* CINDataTableFromFileName(const string& filename, bool caseSensitive = false) - { - if (m_data) { - free(m_data); - m_data = 0; - } - - FILE* f = OVFileHelper::OpenStream(filename); - if (!f) { - m_lastError = NoFileError; - return 0; - } - - OVCINDataTable* table; - OVCINDataTableParser parser; - table = parser.CINDataTableFromFileStream(f, caseSensitive); - fclose(f); - return table; - } - - OVCINDataTable* CINDataTableFromString(const char* string, bool caseSensitive = false) - { - if (m_data) { - free(m_data); - m_data = 0; - } - - size_t len = strlen(string); - if (!len) { - m_lastError = NoDataError; - return 0; - } - - m_data = (char*)calloc(1, len + 1); - if (!m_data) { - m_lastError = MemoryAllocationError; - return 0; - } - - memcpy(m_data, string, len); - - return CINDataTableFromRetainedData(caseSensitive); - } - - - OVCINDataTable* CINDataTableFromFileStream(FILE* stream, bool caseSensitive = false) - { - if (m_data) { - free(m_data); - m_data = 0; - } - - if (!stream) { - m_lastError = NoFileError; - return 0; - } - - if (fseek(stream, 0, SEEK_END) == -1) { - m_lastError = SeekError; - return 0; - } - - size_t size; - if (!(size = ftell(stream))) { - m_lastError = EmptyFileError; - return 0; - } - - if (fseek(stream, 0, SEEK_SET) == -1) { - m_lastError = SeekError; - return 0; - } - - m_data = (char*)calloc(1, size + 1); - if (!m_data) { - m_lastError = MemoryAllocationError; - return 0; - } - - if (fread(m_data, 1, size, stream) != size) { - m_lastError = ReadError; - return 0; - } - - return CINDataTableFromRetainedData(caseSensitive); - } - - protected: - OVCINDataTable* CINDataTableFromRetainedData(bool caseSensitive) - { - OVFastKeyValuePairMap* propertyMap = new OVFastKeyValuePairMap(16, 0, caseSensitive); - if (!propertyMap) { - free(m_data); - m_lastError = MemoryAllocationError; - return 0; - } - - OVFastKeyValuePairMap* keynameMap = new OVFastKeyValuePairMap(64, 0, caseSensitive); - if (!keynameMap) { - free(m_data); - delete propertyMap; - m_lastError = MemoryAllocationError; - return 0; - } - - OVFastKeyValuePairMap* chardefMap = new OVFastKeyValuePairMap(1024, 0, caseSensitive); - if (!chardefMap) { - free(m_data); - delete propertyMap; - delete keynameMap; - m_lastError = MemoryAllocationError; - return 0; - } - - m_scanner = m_data; - - char first; - int blockMode = 0; - - while (first = *m_scanner) { - if (blockMode) { - if (first == '\r' || first == '\n') { - m_scanner++; - continue; - } - - char* key = m_scanner; - char* value = const_cast(""); - char endingChar = skipToSpaceCharOrLineEndAndMarkAndForward(); - - if (endingChar == '\r' || endingChar == '\n') { - ; - } - else { - endingChar = skipUntilNonSpaceChar(); - if (endingChar == '\r' || endingChar == '\n') { - ; - } - else { - value = m_scanner; - skipToLineEndAndMarkAndForwardWithoutTrailingSpace(); - } - } - - if (blockMode == 1) { - if (!strcmp(key, "%keyname") && !strcmp(value, "end")) { - blockMode = 0; - } - else { - if (!caseSensitive) - makeLowerCase(key); - - keynameMap->add(key, value); - } - } - else if (blockMode == 2) { - if (!strcmp(key, "%chardef") && !strcmp(value, "end")) { - blockMode = 0; - } - - else { - if (!caseSensitive) - makeLowerCase(key); - - chardefMap->add(key, value); - } - } - - continue; - } - - - if (first == '#') { - skipUntilNextLine(); - continue; - } - - if (first == '%') { - m_scanner++; - - char* key; - char* value = const_cast(""); - - if (*(key = m_scanner)) { - char endingChar = skipToSpaceCharOrLineEndAndMarkAndForward(); - - if (endingChar == '\r' || endingChar == '\n') { - ; - } - else { - endingChar = skipUntilNonSpaceChar(); - if (endingChar == '\r' || endingChar == '\n') { - ; - } - else { - value = m_scanner; - skipToLineEndAndMarkAndForwardWithoutTrailingSpace(); - } - } - - if (!strcmp(key, "keyname") && !strcmp(value, "begin")) { - blockMode = 1; - } - else if (!strcmp(key, "chardef") && !strcmp(value, "begin")) { - blockMode = 2; - } - else { - propertyMap->add(key, value); - } - } - - continue; - } - - m_scanner++; - } - - propertyMap->sortAndFreeze(); - keynameMap->sortAndFreeze(); - chardefMap->sortAndFreeze(); - - OVCINDataTable* table = new OVCINDataTable(m_data, propertyMap, keynameMap, chardefMap); - - if (!table) { - free(m_data); - delete propertyMap; - delete keynameMap; - delete chardefMap; - m_lastError = MemoryAllocationError; - return 0; - } - else { - m_data = 0; - } - - return table; - } - - void skipUntilNextLine() - { - skipUntilEitherCRLF(); - skipUntilNeitherCRLF(); - } - - void skipUntilEitherCRLF() - { - char nextChar; - while (nextChar = *m_scanner) { - if (nextChar == '\r' || nextChar == '\n') break; - m_scanner++; - } - } - - void skipUntilNeitherCRLF() - { - char nextChar; - while (nextChar = *m_scanner) { - if (!(nextChar == '\r' || nextChar == '\n')) break; - m_scanner++; - } - } - - void skipToLineEndAndMarkAndForwardWithoutTrailingSpace() - { - char nextChar; - while (nextChar = *m_scanner) { - if (nextChar == ' ' || nextChar == '\t') { - char* begin = m_scanner; - - m_scanner++; - while (nextChar = *m_scanner) { - if (!(nextChar == ' ' || nextChar == '\t')) break; - m_scanner++; - } - - if (nextChar == '\n' || nextChar == '\r') { - *begin = 0; - m_scanner++; - return; - } - else { - m_scanner++; - continue; - } - } - - if (nextChar == '\n' || nextChar == '\r') { - *m_scanner = 0; - m_scanner++; - return; - } - - m_scanner++; - } - } - - char skipToSpaceCharOrLineEndAndMarkAndForward() - { - char nextChar; - while (nextChar = *m_scanner) { - if (nextChar == ' ' || nextChar == '\t' || nextChar == '\n' || nextChar == '\r') { - *m_scanner = 0; - m_scanner++; - return nextChar; - } - - m_scanner++; - } - - return 0; - } - - char skipUntilNonSpaceChar() - { - char nextChar; - while (nextChar = *m_scanner) { - if (!(nextChar == ' ' || nextChar == '\t')) - return nextChar; - - m_scanner++; - } - - return 0; - } - - void makeLowerCase(char* ptr) - { - while (*ptr) { - *ptr = tolower(*ptr); - ptr++; - } - } - - protected: - char* m_data; - char* m_scanner; - int m_lastError; - - public: - static const map QuickParseProperty(const string& filename) - { - map properties; - FILE* stream = OVFileHelper::OpenStream(filename); - - if (!stream) - return properties; - - while (!feof(stream)) { - char buffer[256]; - fgets(buffer, sizeof(buffer) - 1, stream); - - if (!*buffer) - continue; - - if (*buffer == '#') - continue; - - pair pv = SplitPropertyString(buffer + 1); - if (pv.first == "keyname") - break; - - properties[pv.first] = pv.second; - } - - fclose(stream); - return properties; - } - - static pair SplitPropertyString(const char* str) - { - const char* scanner = str; - while (*scanner) { - if (*scanner == ' ' || *scanner == '\t' || *scanner == '\r' || *scanner == '\n') - break; - scanner++; - } - - string property = string(str, (size_t)(scanner - str)); - - while (*scanner) { - if (*scanner != ' ' && *scanner != '\t') - break; - scanner++; - } - - const char* begin = scanner; - while (*scanner) { - if (*scanner == '\r' || *scanner == '\n') - break; - scanner++; - } - - string value = string(begin, (size_t)(scanner - begin)); - return pair(property, value); - } - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVCINDatabaseService.h b/Source/Engine/OpenVanilla/OVCINDatabaseService.h deleted file mode 100644 index 8ff666cb68b5e0977c8caf19aa609fb7c007d873..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVCINDatabaseService.h +++ /dev/null @@ -1,189 +0,0 @@ -// -// OVCINDatabaseService.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVCINDatabaseService_h -#define OVCINDatabaseService_h - -#if defined(__APPLE__) - #include - #include -#else - #include "OVCINDataTable.h" - #include "OVDatabaseService.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVCINDatabaseService; - - class OVCINKeyValueDataTable : public OVKeyValueDataTableInterface - { - public: - ~OVCINKeyValueDataTable() - { - delete m_table; - } - - virtual const vector valuesForKey(const string& key) - { - return m_table->findChardef(key); - } - - virtual const vector > valuesForKey(const OVWildcard& expression) - { - return m_table->findChardefWithWildcard(expression); - } - - virtual const string valueForProperty(const string& property) - { - if (OVKeynamePropertyHelper::IsPropertyKeyname(property)) - return m_table->findKeyname(OVKeynamePropertyHelper::KeynameFromProperty(property)); - else - return m_table->findProperty(property); - } - - protected: - OVCINDataTable* m_table; - - friend class OVCINDatabaseService; - - OVCINKeyValueDataTable(OVCINDataTable* table) - : m_table(table) - { - } - }; - - - class OVCINDatabaseService : public OVDatabaseService { - public: - OVCINDatabaseService() - { - } - - OVCINDatabaseService(const string& pathToScan, const string& includePattern = "*.cin", const string& excludePattern = "", size_t depth = 1) - { - addDirectory(pathToScan, includePattern, excludePattern, depth); - } - - // note addDirectory overwrites the table data, so scan user directory after scan the systems if you want to give precedence to user' tables - void addDirectory(const string& pathToScan, const string& includePattern = "*.cin", const string& excludePattern = "", size_t depth = 1) - { - string pathPrefix = OVPathHelper::NormalizeByExpandingTilde(pathToScan) + OVPathHelper::Separator(); - size_t prefixLength = pathPrefix.length(); - - vector tables = OVDirectoryHelper::Glob(pathPrefix, includePattern, excludePattern, depth); - - vector::iterator iter = tables.begin(); - for ( ; iter != tables.end(); ++iter) { - const string& path = *iter; - string shortPath = *iter; - shortPath.erase(0, prefixLength); - - string tableName = OVCINDatabaseService::TableNameFromPath(shortPath); - m_tables[tableName] = path; - } - } - - virtual const vector tables(const OVWildcard& filter = string("*")) - { - vector result; - - for (map::iterator iter = m_tables.begin() ; iter != m_tables.end(); ++iter) { - if (filter.match((*iter).first)) - result.push_back((*iter).first); - } - - return result; - } - - virtual bool tableSupportsValueToKeyLookup(const string &tableName) - { - return false; - } - - virtual OVKeyValueDataTableInterface* createKeyValueDataTableInterface(const string& name, bool suggestedCaseSensitivity = false) - { - map::iterator iter = m_tables.find(name); - if (iter == m_tables.end()) - return 0; - - OVCINDataTableParser parser; - OVCINDataTable* table = parser.CINDataTableFromFileName((*iter).second, suggestedCaseSensitivity); - - if (!table) - return 0; - - return new OVCINKeyValueDataTable(table); - } - - - virtual const string valueForPropertyInTable(const string& property, const string& name) - { - map::iterator iter; - - if (name != m_cachedTableName) - { - iter = m_tables.find(name); - if (iter == m_tables.end()) - return string(); - - m_cachedProperties = OVCINDataTableParser::QuickParseProperty((*iter).second); - m_cachedTableName = name; - } - - iter = m_cachedProperties.find(property); - if (iter != m_cachedProperties.end()) - return (*iter).second; - - return string(); - } - - protected: - map m_tables; - map m_cachedProperties; - string m_cachedTableName; - - public: - static const string TableNameFromPath(const string& path) - { - string result; - char separator = OVPathHelper::Separator(); - - string::const_iterator iter = path.begin(); - for ( ; iter != path.end(); ++iter) - if (*iter == separator || *iter == '.') - result += '-'; - else - result += *iter; - - return result; - } - }; -}; - -#endif \ No newline at end of file diff --git a/Source/Engine/OpenVanilla/OVCINToSQLiteConvertor.h b/Source/Engine/OpenVanilla/OVCINToSQLiteConvertor.h deleted file mode 100644 index 4a73d6b3ded7abbf9794070fc68be29674f35965..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVCINToSQLiteConvertor.h +++ /dev/null @@ -1,125 +0,0 @@ -// -// OVCINToSQLiteConvertor.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVCINToSQLiteConvertor_h -#define OVCINToSQLiteConvertor_h - -#if defined(__APPLE__) - #include - #include -#else - #include "OVCINDataTable.h" - #include "OVSQLiteWrapper.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVCINToSQLiteConvertor { - protected: - static bool InsertKeyValue(OVFastKeyValuePairMap* map, OVSQLiteStatement* statement, const char* prefix = 0) - { - string prefixString = prefix ? prefix : ""; - - size_t size = map->size(); - - for (size_t index = 0; index < size; index++) { - pair kvpair = map->keyValuePairAtIndex(index); - - const string& key = prefix ? prefixString + kvpair.first : kvpair.first; - - statement->bindTextToColumn(key, 1); - statement->bindTextToColumn(kvpair.second, 2); - - if (statement->step() != SQLITE_DONE) - return false; - - statement->reset(); - } - - return true; - } - - public: - static bool Convert(OVCINDataTable* table, OVSQLiteConnection* connection, const string& tableName, bool overwriteTable = true) - { - const char* nameStr = tableName.c_str(); - // query if the table exists - OVSQLiteStatement* statement; - - statement = connection->prepare("SELECT name FROM sqlite_master WHERE name = %Q", nameStr); - - if (!statement) - return false; - - if (statement->step() == SQLITE_ROW && overwriteTable) - { - delete statement; - - if (connection->execute("DROP TABLE %Q", nameStr) != SQLITE_OK) { - delete statement; - return false; - } - } - else - delete statement; - - if (connection->execute("CREATE TABLE %Q (key, value)", nameStr) != SQLITE_OK) - return false; - - string indexName = tableName + "_index"; - if (connection->execute("CREATE INDEX %Q on %Q (key)", indexName.c_str(), nameStr) != SQLITE_OK) - return false; - - statement = connection->prepare("INSERT INTO %Q VALUES (?, ?)", nameStr); - if (!statement) { - return false; - } - - if (connection->execute("BEGIN") != SQLITE_OK) { - return false; - } - - string keynameProperty = string(OVPropertyStringInternalPrefix) + string(OVCINKeynameString); - - if (InsertKeyValue(table->propertyMap(), statement, OVPropertyStringInternalPrefix)) - if (InsertKeyValue(table->keynameMap(), statement, keynameProperty.c_str())) - InsertKeyValue(table->chardefMap(), statement); - - delete statement; - - if (connection->execute("COMMIT") != SQLITE_OK) { - return false; - } - - return true; - } - - }; -}; - -#endif \ No newline at end of file diff --git a/Source/Engine/OpenVanilla/OVCandidateService.h b/Source/Engine/OpenVanilla/OVCandidateService.h deleted file mode 100644 index ecaff8c95c357c3ea84d06a995f0fec2b0a9eabd..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVCandidateService.h +++ /dev/null @@ -1,208 +0,0 @@ -// -// OVCandidateService.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVCandidateService_h -#define OVCandidateService_h - -#if defined(__APPLE__) - #include - #include - #include -#else - #include "OVBase.h" - #include "OVKey.h" - #include "OVLoaderService.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVCandidateList : public OVBase { - public: - virtual void clear() = 0; - virtual size_t size() const = 0; - virtual string candidateAtIndex(size_t index) const = 0; - virtual void setCandidate(size_t index, const string& candidate) = 0; - virtual void setCandidates(const vector& candidates) = 0; - virtual void addCandidate(const string& candidate) = 0; - virtual void addCandidates(const vector& candidates) = 0; - }; - - class OVCandidatePanel; - class OVOneDimensionalCandidatePanel; - // class OVTwoDimensionalCandidatePanel; - class OVFreeContentPanel; - class OVPlainTextCandidatePanel; - class OVHTMLCandidatePanel; - - class OVCandidatePanel : public OVBase { - public: - virtual bool isOneDimensionalPanel() const - { - return false; - } - - virtual bool isTwoDimensionalPanel() const - { - return false; - } - - virtual bool isPlainTextPanelPanel() const - { - return false; - } - - virtual bool isHTMLPanel() const - { - return false; - } - - virtual void hide() = 0; - virtual void show() = 0; - virtual void updateDisplay() = 0; - virtual bool isVisible() = 0; - - virtual void setPrompt(const string& prompt) = 0; - virtual string prompt() = 0; - - virtual bool yieldToCandidateEventHandler() = 0; - virtual void cancelEventHandler() = 0; - - virtual void reset() = 0; - }; - - class OVOneDimensionalCandidatePanel : public OVCandidatePanel { - public: - virtual bool isOneDimensionalPanel() const - { - return true; - } - - virtual bool isHorizontal() const = 0; - virtual bool isVertical() const = 0; - - virtual OVCandidateList* candidateList() = 0; - - virtual size_t candidatesPerPage() const = 0; - virtual void setCandidatesPerPage(size_t number) = 0; - virtual size_t pageCount() const = 0; - virtual size_t currentPage() const = 0; - virtual size_t currentPageCandidateCount() const = 0; - virtual bool allowsPageWrapping() const = 0; - virtual void setAllowsPageWrapping(bool allowsPageWrapping) = 0; - - virtual size_t currentHightlightIndex() const = 0; - virtual void setHighlightIndex(size_t index) = 0; - virtual size_t currentHightlightIndexInCandidateList() const = 0; - - virtual size_t goToNextPage() = 0; - virtual size_t goToPreviousPage() = 0; - virtual size_t goToPage(size_t page) = 0; - - virtual const OVKey candidateKeyAtIndex(size_t index) = 0; - virtual void setCandidateKeys(const string& asciiKeys, OVLoaderService* loaderService) - { - OVKeyVector keys; - for (size_t index = 0; index < asciiKeys.length(); index++) { - keys.push_back(loaderService->makeOVKey(asciiKeys[index])); - } - - setCandidateKeys(keys); - setCandidatesPerPage(asciiKeys.length()); - } - - virtual void setCandidateKeys(const OVKeyVector& keys) = 0; - virtual void setNextPageKeys(const OVKeyVector& keys) = 0; - virtual void setPreviousPageKeys(const OVKeyVector& keys) = 0; - virtual void setNextCandidateKeys(const OVKeyVector& keys) = 0; - virtual void setPreviousCandidateKeys(const OVKeyVector& keys) = 0; - virtual void setCancelKeys(const OVKeyVector& keys) = 0; - virtual void setChooseHighlightedCandidateKeys(const OVKeyVector& keys) = 0; - - virtual const OVKeyVector defaultCandidateKeys() const = 0; - virtual const OVKeyVector defaultNextPageKeys() const = 0; - virtual const OVKeyVector defaultNextCandidateKeys() const = 0; - virtual const OVKeyVector defaultPreviousPageKeys() const = 0; - virtual const OVKeyVector defaultPreviousCandidateKeys() const = 0; - virtual const OVKeyVector defaultCancelKeys() const = 0; - virtual const OVKeyVector defaultChooseHighlightedCandidateKeys() const = 0; - }; - - class OVFreeContentStorage : public OVBase { - public: - virtual void clear() = 0; - virtual void setContent(const string& content) = 0; - virtual void appendContent(const string& content) = 0; - }; - - class OVPlainTextCandidatePanel : public OVCandidatePanel { - public: - virtual bool isPlainTextPanelPanel() - { - return true; - } - - virtual OVFreeContentStorage* textStorage() = 0; - }; - - class OVHTMLCandidatePanel : public OVCandidatePanel { - public: - virtual OVFreeContentStorage* HTMLSourceStorage() = 0; - }; - - class OVCandidateService : public OVBase { - public: - virtual OVOneDimensionalCandidatePanel* useHorizontalCandidatePanel() - { - return 0; - } - - virtual OVOneDimensionalCandidatePanel* useVerticalCandidatePanel() - { - return 0; - } - - virtual OVOneDimensionalCandidatePanel* useOneDimensionalCandidatePanel() - { - return useVerticalCandidatePanel(); - } - - // virtual OVTwoDimensionalCandidatePanel* twoDimensionalCandidatePanel(); - - virtual OVPlainTextCandidatePanel* usePlainTextCandidatePanel() - { - return 0; - } - - virtual OVHTMLCandidatePanel* useHTMLCandidatePanel() - { - return 0; - } - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVDatabaseService.h b/Source/Engine/OpenVanilla/OVDatabaseService.h deleted file mode 100644 index 6baf5e0505d40cf42d78932de512ff581f3d23d4..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVDatabaseService.h +++ /dev/null @@ -1,101 +0,0 @@ -// -// OVDatabaseService.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVDatabaseService_h -#define OVDatabaseService_h - -#if defined(__APPLE__) - #include - #include - #include - #include -#else - #include "OVBase.h" - #include "OVCINDataTable.h" - #include "OVFileHelper.h" - #include "OVWildcard.h" -#endif - -#include - -namespace OpenVanilla { - using namespace std; - - // database-backed table uses this prefix to store properties ina key-value data table - #define OVPropertyStringInternalPrefix "__property_" - - #define OVCINKeynameString "keyname-" - #define OVCINKeynameStringLength 8 - - // keyname is defined in the .cin format, not to be confused with the key in key-value pairs - class OVKeynamePropertyHelper : public OVBase { - public: - static bool IsPropertyKeyname(const string& property) - { - return (property.substr(0, OVCINKeynameStringLength) == OVCINKeynameString); - } - - // passes property and gets back the keyname - static const string KeynameFromProperty(const string& property) - { - return IsPropertyKeyname(property) ? property.substr(OVCINKeynameStringLength, property.length() - OVCINKeynameStringLength) : string(); - } - - // passes keyname and gets the combined property - static const string KeynameToProperty(const string& keyname) - { - return string(OVCINKeynameString) + keyname; - } - }; - - class OVKeyValueDataTableInterface : public OVBase { - public: - virtual const vector valuesForKey(const string& key) = 0; - virtual const vector > valuesForKey(const OVWildcard& expression) = 0; - virtual const string valueForProperty(const string& property) = 0; - - // only supported by database services that support value-to-key lookup, the default implementation is an empty vector - virtual const vector keysForValue(const string& value) - { - return vector(); - } - }; - - class OVDatabaseService : public OVBase { - public: - virtual const vector tables(const OVWildcard& filter = string("*")) = 0; - virtual bool tableSupportsValueToKeyLookup(const string &tableName) = 0; - - virtual OVKeyValueDataTableInterface* createKeyValueDataTableInterface(const string& name, bool suggestedCaseSensitivity = false) = 0; - - // this is needed so that modules like OVIMGeneric can know table localized names in advance, without really loading them - virtual const string valueForPropertyInTable(const string& property, const string& name) = 0; - }; - -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVDateTimeHelper.h b/Source/Engine/OpenVanilla/OVDateTimeHelper.h deleted file mode 100644 index 117800ea6875c8cdca03feb568738f6c1bb0161a..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVDateTimeHelper.h +++ /dev/null @@ -1,149 +0,0 @@ -// -// OVDateTimeHelper.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVDateTimeHelper_h -#define OVDateTimeHelper_h - -#include -#include -#include - -namespace OpenVanilla { - using namespace std; - - class OVDateTimeHelper - { - public: - static time_t GetTimeIntervalSince1970() - { - return time(NULL); - } - - static time_t GetTimeIntervalSince1970FromString(const string& s) - { - stringstream sst; - sst << s; - time_t t; - sst >> t; - return t; - } - - static const string GetTimeIntervalSince1970AsString() - { - stringstream sst; - sst << time(NULL); - return sst.str(); - } - - static time_t GetTimeIntervalSince1970AtBeginningOfTodayLocalTime() - { - time_t t = time(NULL); - - #ifdef WIN32 - struct tm tdata; - struct tm* td = &tdata; - if (localtime_s(td, &t)) - return 0; - #else - struct tm* td; - td = localtime(&t); - #endif - - td->tm_hour = 0; - td->tm_min = 0; - td->tm_sec = 0; - - return mktime(td); - } - - static const string LocalTimeString() - { - time_t t = time(NULL); - - #ifdef WIN32 - struct tm tdata; - struct tm* td = &tdata; - if (localtime_s(td, &t)) - return string(); - #else - struct tm* td; - td = localtime(&t); - #endif - - ostringstream sstr; - sstr.width(2); - sstr.fill('0'); - sstr << td->tm_hour << ":"; - sstr.width(2); - sstr.fill('0'); - sstr << td->tm_min << ":"; - sstr.width(2); - sstr.fill('0'); - sstr << td->tm_sec; - return sstr.str(); - } - - static const string LocalDateTimeString() - { - time_t t = time(NULL); - - #ifdef WIN32 - struct tm tdata; - struct tm* td = &tdata; - if (localtime_s(td, &t)) - return string(); - #else - struct tm* td; - td = localtime(&t); - #endif - - ostringstream sstr; - sstr.width(4); - sstr << td->tm_year + 1900 << "-"; - sstr.width(2); - sstr.fill('0'); - sstr << td->tm_mon + 1 << "-"; - sstr.width(2); - sstr.fill('0'); - sstr << td->tm_mday << " "; - - sstr.width(2); - sstr.fill('0'); - sstr << td->tm_hour << ":"; - sstr.width(2); - sstr.fill('0'); - sstr << td->tm_min << ":"; - sstr.width(2); - sstr.fill('0'); - sstr << td->tm_sec; - return sstr.str(); - } - }; - -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVEncodingService.h b/Source/Engine/OpenVanilla/OVEncodingService.h deleted file mode 100644 index 4afd0e4bdb9a50f60c1cd950c9272a6163497548..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVEncodingService.h +++ /dev/null @@ -1,72 +0,0 @@ -// -// OVEncodingService.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVEncodingService_h -#define OVEncodingService_h - -#if defined(__APPLE__) - #include -#else - #include "OVUTF8Helper.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVEncodingService : public OVBase { - public: - virtual bool stringSupportedByEncoding(const string& text, const string& encoding) - { - vector svec = OVUTF8Helper::SplitStringByCodePoint(text); - for (vector::iterator iter = svec.begin() ; iter != svec.end() ; ++iter) - if (!codepointSupportedByEncoding(*iter, encoding)) - return false; - - return true; - } - - virtual bool stringSupportedBySystem(const string& text) - { - vector svec = OVUTF8Helper::SplitStringByCodePoint(text); - for (vector::iterator iter = svec.begin() ; iter != svec.end() ; ++iter) - if (!codepointSupportedBySystem(*iter)) - return false; - - return true; - } - - virtual bool codepointSupportedByEncoding(const string& codepoint, const string& encoding) = 0; - virtual bool codepointSupportedBySystem(const string& codepoint) = 0; - virtual const vector supportedEncodings() = 0; - virtual bool isEncodingSupported(const string& encoding) = 0; - - virtual bool isEncodingConversionSupported(const string& fromEncoding, const string& toEncoding) = 0; - virtual const pair convertEncoding(const string& fromEncoding, const string& toEncoding, const string& text) = 0; - }; -}; - -#endif \ No newline at end of file diff --git a/Source/Engine/OpenVanilla/OVEventHandlingContext.h b/Source/Engine/OpenVanilla/OVEventHandlingContext.h deleted file mode 100644 index 51c12c8b9cc8b9cd1ad72092b6e06a01b752c2a2..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVEventHandlingContext.h +++ /dev/null @@ -1,102 +0,0 @@ -// -// OVEventHandlingContext.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVEventHandlingContext_h -#define OVEventHandlingContext_h - -#if defined(__APPLE__) - #include - #include - #include - #include - #include - #include -#else - #include "OVBase.h" - #include "OVCandidateService.h" - #include "OVStringHelper.h" - #include "OVTextBuffer.h" - #include "OVKey.h" - #include "OVLoaderService.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVEventHandlingContext : public OVBase { - public: - virtual void startSession(OVLoaderService* loaderService) - { - } - - virtual void stopSession(OVLoaderService* loaderService) - { - } - - virtual void clear(OVLoaderService* loaderService) - { - stopSession(loaderService); - startSession(loaderService); - } - - virtual bool handleKey(OVKey* key, OVTextBuffer* readingText, OVTextBuffer* composingText, OVCandidateService* candidateService, OVLoaderService* loaderService) - { - return false; - } - - virtual bool handleDirectText(const vector& segments, OVTextBuffer* readingText, OVTextBuffer* composingText, OVCandidateService* candidateService, OVLoaderService* loaderService) - { - return handleDirectText(OVStringHelper::Join(segments), readingText, composingText, candidateService, loaderService); - } - - virtual bool handleDirectText(const string&, OVTextBuffer* readingText, OVTextBuffer* composingText, OVCandidateService* candidateService, OVLoaderService* loaderService) - { - return false; - } - - virtual void candidateCanceled(OVCandidateService* candidateService, OVTextBuffer* readingText, OVTextBuffer* composingText, OVLoaderService* loaderService) - { - } - - virtual bool candidateSelected(OVCandidateService* candidateService, const string& text, size_t index, OVTextBuffer* readingText, OVTextBuffer* composingText, OVLoaderService* loaderService) - { - return true; - } - - virtual bool candidateNonPanelKeyReceived(OVCandidateService* candidateService, const OVKey* key, OVTextBuffer* readingText, OVTextBuffer* composingText, OVLoaderService* loaderService) - { - return false; - } - - virtual const string filterText(const string& inputText, OVLoaderService* loaderService) - { - return inputText; - } - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVException.h b/Source/Engine/OpenVanilla/OVException.h deleted file mode 100644 index 27b9fb73b83b718750cc22ba60a4c96c05a51f27..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVException.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// OVException.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVException_h -#define OVException_h - -#if defined(__APPLE__) - #include -#else - #include "OVBase.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVException { - public: - class OverflowException {}; - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVFileHelper.h b/Source/Engine/OpenVanilla/OVFileHelper.h deleted file mode 100644 index 3899674a402bcda74566093c0527c0a5292a852e..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVFileHelper.h +++ /dev/null @@ -1,627 +0,0 @@ -// -// OVFileHelper.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVFileHelper_h -#define OVFileHelper_h - -#if defined(__APPLE__) - #include - #include -#else - #include - #include - #include -#endif - -#include - -#include -#include -#include -#include "OVWildcard.h" -#include "OVUTF8Helper.h" - -namespace OpenVanilla { - using namespace std; - - class OVFileHelper { - public: - static FILE* OpenStream(const string& filename, const string& mode = "rb") - { - #ifndef WIN32 - return fopen(filename.c_str(), mode.c_str()); - #else - FILE* stream = NULL; - errno_t err = _wfopen_s(&stream, OVUTF16::FromUTF8(filename).c_str(), OVUTF16::FromUTF8(mode).c_str()); - return err ? 0 : stream; - #endif - } - - static void OpenOFStream(ofstream& stream, const string& filename, ios_base::openmode openMode) - { - #ifndef WIN32 - stream.open(filename.c_str(), openMode); - #else - stream.open(OVUTF16::FromUTF8(filename).c_str(), openMode); - #endif - } - - static void OpenIFStream(ifstream& stream, const string& filename, ios_base::openmode openMode) - { - #ifndef WIN32 - stream.open(filename.c_str(), openMode); - #else - stream.open(OVUTF16::FromUTF8(filename).c_str(), openMode); - #endif - } - - // use free(), not delete[], to free the block allocated - static pair SlurpFile(const string& filename, bool addOneByteOfStringTerminationPadding = false) - { - FILE* stream = OpenStream(filename); - char* buf = 0; - size_t size = 0; - if (stream) { - if (!fseek(stream, 0, SEEK_END)) { - long lsize = ftell(stream); - if (lsize) { - size = (size_t)lsize; - if (!fseek(stream, 0, SEEK_SET)) { - buf = (char*)calloc(1, (size_t)size + (addOneByteOfStringTerminationPadding ? 1 : 0)); - if (buf) { - if (fread(buf, size, 1, stream) != 1) { - free(buf); - buf = 0; - size = 0; - } - } - else { - size = 0; - } - } - else { - size = 0; - } - } - } - - fclose(stream); - } - - return pair(buf, size); - } - }; - - class OVFileTimestamp { - public: - #if defined(__APPLE__) - OVFileTimestamp(__darwin_time_t timestamp = 0, long subtimestamp = 0) - #elif defined(WIN32) - OVFileTimestamp(time_t timestamp = 0, time_t subtimestamp = 0) - #else - #error We don't know about Linux yet, sorry. - #endif - : m_timestamp(timestamp) - , m_subtimestamp(subtimestamp) - { - } - - OVFileTimestamp(const OVFileTimestamp& timestamp) - : m_timestamp(timestamp.m_timestamp) - , m_subtimestamp(timestamp.m_subtimestamp) - { - } - - OVFileTimestamp& operator=(const OVFileTimestamp& timestamp) - { - m_timestamp = timestamp.m_timestamp; - m_subtimestamp = timestamp.m_subtimestamp; - return *this; - } - - - bool operator==(OVFileTimestamp& another) - { - return (m_timestamp == another.m_timestamp) && (m_subtimestamp == another.m_subtimestamp); - } - - bool operator!=(OVFileTimestamp& another) - { - return (m_timestamp != another.m_timestamp) || (m_subtimestamp != another.m_subtimestamp); - } - - bool operator<(OVFileTimestamp& another) - { - return (m_timestamp < another.m_timestamp) || ((m_timestamp == another.m_timestamp) && m_subtimestamp < another.m_subtimestamp); - } - - bool operator>(OVFileTimestamp& another) - { - return (m_timestamp > another.m_timestamp) || ((m_timestamp == another.m_timestamp) && m_subtimestamp > another.m_subtimestamp); - } - - - protected: - #if defined(__APPLE__) - __darwin_time_t m_timestamp; - long m_subtimestamp; - #elif defined(WIN32) - time_t m_timestamp; - time_t m_subtimestamp; - #else - #error We don't know about Linux yet, sorry. - #endif - }; - - - class OVPathHelper { - public: - static char Separator() - { - #ifndef WIN32 - return '/'; - #else - return '\\'; - #endif - } - - - static const string DirectoryFromPath(const string& path) - { - string realPath = OVPathHelper::NormalizeByExpandingTilde(path); - if (OVPathHelper::PathExists(realPath) && OVPathHelper::IsDirectory(realPath)) - return realPath; - - char separator = OVPathHelper::Separator(); - - if (!realPath.length()) - return string("."); - - for (size_t index = realPath.length() - 1; index >= 0 ; index--) { - if (realPath[index] == separator) { - if (index) { - // reserve the \\ on Windows - if (realPath[index-1] == '\\') - return realPath.substr(0, index + 1); - else - return realPath.substr(0, index); - } - else - return realPath.substr(0, 1); - } - - // if we run into : (like C:) on Windows - if (realPath[index] == ':') - return realPath.substr(0, index + 1) + Separator(); - - if (!index) break; - } - - return string("."); - } - - static const string FilenameWithoutPath(const string &path) - { - char separator = OVPathHelper::Separator(); - - if (!path.length()) - return string(); - - for (size_t index = path.length() - 1; index >= 0 ; index--) { - if (path[index] == separator) - return path.substr(index + 1, path.length() - (index + 1)); - - if (!index) break; - } - - return path; - } - - static const string FilenameWithoutExtension(const string &path) - { - char separator = OVPathHelper::Separator(); - if (!path.length()) - return string(); - - for (size_t index = path.length() - 1; index >= 0 ; index--) { - if (path[index] == separator) - break; - - if (path[index] == '.') - return path.substr(0, index); - - if (!index) break; - } - - return path; - } - - static const string ChopTrailingSeparator(const string& path) - { - if (path.length() == 1 && path[0] == Separator()) - return path; - - string result; - - if (path.length()) { - if (path[path.length() - 1] == Separator()) - result = path.substr(0, path.length() - 1); - else - result = path; - } - - return result; - } - - static const string ChopLeadingSeparator(const string& path) - { - if (path.length() == 1 && path[0] == Separator()) - return path; - - string result; - if (path.length()) { - if (path[0] == Separator()) { - result = path.substr(1, path.length() - 1); - } - else { - result = path; - } - } - return result; - } - - static const string PathCat(const string& s1, const string& s2) - { - if (s2.length()) - return ChopTrailingSeparator(s1) + Separator() + ChopLeadingSeparator(s2); - else - return s1; - } - - static const string Normalize(const string& path) - { - string newPath; - size_t length = path.length(); - for (size_t index = 0; index < length; index++) { - if (path[index] == '/' || path[index] == '\\') { - if (index < length - 1) { - if (path[index+1] == '/' || path[index+1] == '\\') - index++; - } - - newPath += Separator(); - } - else - newPath += path[index]; - } - - return ChopTrailingSeparator(newPath); - } - - static const bool PathExists(const string& path) - { - #ifndef WIN32 - struct stat buf; - return !stat(path.c_str(), &buf); - #else - struct _stat buf; - wstring wpath = OVUTF16::FromUTF8(path); - return !_wstat(wpath.c_str(), &buf); - #endif - } - - static const bool IsDirectory(const string& path) - { - #ifndef WIN32 - struct stat buf; - if (!stat(path.c_str(), &buf)) - { - if (buf.st_mode & S_IFDIR) - return true; - } - #else - struct _stat buf; - wstring wpath = OVUTF16::FromUTF8(path); - if (!_wstat(wpath.c_str(), &buf)) - { - if (buf.st_mode & S_IFDIR) - return true; - } - #endif - return false; - } - - static const OVFileTimestamp TimestampForPath(const string& path) - { - OVFileTimestamp timestamp; - #if defined(__APPLE__) - struct stat buf; - if (!stat(path.c_str(), &buf)) - { - timestamp = OVFileTimestamp(buf.st_mtimespec.tv_sec, buf.st_mtimespec.tv_nsec); - } - #elif defined(WIN32) - struct _stat buf; - wstring wpath = OVUTF16::FromUTF8(path); - if (!_wstat(wpath.c_str(), &buf)) - { - timestamp = OVFileTimestamp(buf.st_mtime); - } - #else - #error Sorry, no idea for Linux yet. - #endif - return timestamp; - } - - static bool RemoveEverythingAtPath(const string& path); - static const string NormalizeByExpandingTilde(const string& path); - }; - - class OVDirectoryHelper { - public: - static bool MakeDirectory(const string& path) - { - #ifndef WIN32 - return !mkdir(path.c_str(), S_IRWXU); - #else - wstring wpath = OVUTF16::FromUTF8(path); - return CreateDirectoryW(wpath.c_str(), NULL) == TRUE; - #endif - } - - static bool MakeDirectoryWithImmediates(const string& path) - { - string realPath = OVPathHelper::NormalizeByExpandingTilde(path); - - if (OVPathHelper::PathExists(realPath) && OVPathHelper::IsDirectory(realPath)) { - return true; - } - - string lastPart = OVPathHelper::DirectoryFromPath(realPath); - - if (lastPart != realPath && !OVPathHelper::PathExists(lastPart)) { - if (!MakeDirectoryWithImmediates(lastPart)) - return false; - } - - return MakeDirectory(realPath); - } - - static bool CheckDirectory(const string& path) - { - string realPath = OVPathHelper::NormalizeByExpandingTilde(path); - if (OVPathHelper::PathExists(realPath)) - return OVPathHelper::IsDirectory(realPath); - - return MakeDirectoryWithImmediates(realPath); - } - - static const vector Glob(const string& directory, const string& pattern = "*", const string& excludePattern = "", size_t depth = 1) - { - string sanitizedDirectory = OVPathHelper::NormalizeByExpandingTilde(directory); - - OVWildcard expression(pattern); - OVWildcard negativeExpression(excludePattern); - vector dirResult; - vector fileResult; - struct dirent** namelist = NULL; - - #ifndef WIN32 - int count = scandir(sanitizedDirectory.c_str(), &namelist, NULL, NULL); - for (int index = 0; index < count; index++) { - struct dirent* entry = namelist[index]; - bool isDir = entry->d_type == DT_DIR; - string name = entry->d_name; - #else - vector > foundFiles; - WIN32_FIND_DATAW findData; - HANDLE findHandle = FindFirstFileW(OVUTF16::FromUTF8(OVPathHelper::PathCat(sanitizedDirectory, "*.*")).c_str(), &findData); - if (findHandle != INVALID_HANDLE_VALUE) { - foundFiles.push_back(pair(OVUTF8::FromUTF16(findData.cFileName), (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)); - - while (FindNextFileW(findHandle, &findData)) - { - foundFiles.push_back(pair(OVUTF8::FromUTF16(findData.cFileName), (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)); - } - FindClose(findHandle); - } - - size_t count = foundFiles.size(); - for (size_t index = 0; index < count; index++) { - string name = foundFiles[index].first; - bool isDir = foundFiles[index].second; - #endif - - if ((!depth || depth > 1) && isDir && name != "." && name != "..") { - vector subResult = Glob(OVPathHelper::PathCat(sanitizedDirectory, name), pattern, excludePattern, depth ? depth - 1 : 0); - vector::iterator iter = subResult.begin(); - for ( ; iter != subResult.end() ; iter++) - dirResult.push_back(*iter); - } - - if (name != "." && name != ".." && expression.match(name) && !negativeExpression.match(name)) { - fileResult.push_back(OVPathHelper::PathCat(sanitizedDirectory, name)); - } - - #ifndef WIN32 - free(entry); - #endif - } - - #ifndef WIN32 - if (count != -1) - free(namelist); - #endif - - sort(dirResult.begin(), dirResult.end()); - sort(fileResult.begin(), fileResult.end()); - for (vector::iterator iter = dirResult.begin() ; iter != dirResult.end(); iter++) - fileResult.push_back(*iter); - - return fileResult; - } - - static const string TempDirectory() - { - #ifndef WIN32 - return string("/tmp"); - #else - WCHAR path[MAX_PATH + 1]; - GetTempPathW(MAX_PATH, path); - return OVUTF8::FromUTF16(path); - #endif - } - - static const string GenerateTempFilename(const string& prefix = "temp") - { - string pattern = OVPathHelper::PathCat(TempDirectory(), prefix + "-" + "XXXXXXXX"); - #ifndef WIN32 - char *p = (char*)calloc(1, pattern.length() + 1); - strcpy(p, pattern.c_str()); - char *r = mktemp(p); - if (!r) { - free(p); - return string(); - } - string result = r; - free(p); - return result; - #else - wstring wp = OVUTF16::FromUTF8(pattern); - size_t length = wp.length() + 1; - wchar_t* p = (wchar_t*)calloc(1, length * sizeof(wchar_t)); - wcscpy_s(p, length, wp.c_str()); - errno_t err = _wmktemp_s(p, length); - if (err != 0) { - free(p); - return string(); - } - - string result = OVUTF8::FromUTF16(p); - free(p); - return result; - - #endif - } - - static const string UserHomeDirectory() - { - #ifndef WIN32 - const char* homePath = getenv("HOME"); - if (homePath) - return string(homePath); - return TempDirectory(); - #else - WCHAR path[MAX_PATH + 1]; - HRESULT error = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, path); - if (!error) { - return OVUTF8::FromUTF16(path); - } - return TempDirectory(); - #endif - } - - static const string UserApplicationDataDirectory(const string& applicationName) - { - #if defined(__APPLE__) - return OVPathHelper::PathCat(UserHomeDirectory(), OVPathHelper::PathCat("/Library/", applicationName)); - #elif defined(WIN32) - WCHAR path[MAX_PATH + 1]; - HRESULT error = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, path); - if (!error) { - return OVPathHelper::PathCat(OVUTF8::FromUTF16(path), applicationName); - } - return OVPathHelper::PathCat(TempDirectory(), applicationName); - #else - return OVPathHelper::PathCat(UserHomeDirectory(), string(".") + applicationName); - #endif - } - - static const string UserApplicationSupportDataDirectory(const string& applicationName) - { - #ifdef __APPLE__ - return OVPathHelper::PathCat(UserHomeDirectory(), OVPathHelper::PathCat("/Library/Application Support", applicationName)); - #else - return UserApplicationDataDirectory(applicationName); - #endif - } - - static const string UserPreferencesDirectory(const string& applicationName) - { - #ifdef __APPLE__ - return OVPathHelper::NormalizeByExpandingTilde("~/Library/Preferences"); - #else - return UserApplicationDataDirectory(applicationName); - #endif - } - - }; - - inline const string OVPathHelper::NormalizeByExpandingTilde(const string& path) - { - string newPath = Normalize(path); - - if (newPath.length()) { - if (newPath[0] == '~') { - newPath = OVPathHelper::PathCat(OVDirectoryHelper::UserHomeDirectory(), newPath.substr(1, newPath.length())); - } - } - - return newPath; - } - - inline bool OVPathHelper::RemoveEverythingAtPath(const string& path) - { - if (!PathExists(path)) return false; - - if (IsDirectory(path)) { - vector files = OVDirectoryHelper::Glob(path, "*", "", 0); - vector::iterator iter = files.begin(); - for ( ; iter != files.end(); iter++) { - if (!RemoveEverythingAtPath(*iter)) - return false; - } - - #ifndef WIN32 - return !rmdir(path.c_str()); - #else - wstring wpath = OVUTF16::FromUTF8(path); - return RemoveDirectoryW(wpath.c_str()) == TRUE; - #endif - } - else { - #ifndef WIN32 - return !unlink(path.c_str()); - #else - wstring wpath = OVUTF16::FromUTF8(path); - return DeleteFileW(wpath.c_str()) == TRUE; - #endif - } - } -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVFrameworkInfo.h b/Source/Engine/OpenVanilla/OVFrameworkInfo.h deleted file mode 100644 index 7007063568f6fc3d5d2740962689f632b18b5aec..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVFrameworkInfo.h +++ /dev/null @@ -1,92 +0,0 @@ -// -// OVFrameworkInfo.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVFrameworkVersion_h -#define OVFrameworkVersion_h - -#if defined(__APPLE__) - #include -#else - #include "OVBase.h" -#endif - -#include - -namespace OpenVanilla { - using namespace std; - - class OVFrameworkInfo { - public: - static unsigned int MajorVersion() - { - return c_MajorVersion; - } - - static unsigned int MinorVersion() - { - return c_MinorVersion; - } - - static unsigned int TinyVersion() - { - return c_TinyVersion; - } - - static unsigned int Version() - { - return ((c_MajorVersion & 0xff) << 24) | ((c_MinorVersion & 0xff)<< 16) | (c_TinyVersion & 0xffff); - } - - static unsigned int BuildNumber() - { - return c_FrameworkBuildNumber; - } - - static const string VersionString(bool withBuildNumber = false) - { - stringstream s; - s << c_MajorVersion << "." << c_MinorVersion << "." << c_TinyVersion; - if (withBuildNumber) - s << "." << c_FrameworkBuildNumber; - - return s.str(); - } - - static const string VersionStringWithBuildNumber() - { - return VersionString(true); - } - - protected: - static const unsigned int c_MajorVersion; - static const unsigned int c_MinorVersion; - static const unsigned int c_TinyVersion; - static const unsigned int c_FrameworkBuildNumber; - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVInputMethod.h b/Source/Engine/OpenVanilla/OVInputMethod.h deleted file mode 100644 index 0f4c68e65b844e83a95f55cfa42d80a7d6ff4373..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVInputMethod.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// OVInputMethod.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVInputMethod_h -#define OVInputMethod_h - -#if defined(__APPLE__) - #include -#else - #include "OVModule.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVInputMethod : public OVModule { - public: - virtual bool isInputMethod() const - { - return true; - } - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVKey.h b/Source/Engine/OpenVanilla/OVKey.h deleted file mode 100644 index 222344700167a1d24b8042c460efd58d74b23e3f..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVKey.h +++ /dev/null @@ -1,303 +0,0 @@ -// -// OVKey.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu and Weizhong Yang -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVKey_h -#define OVKey_h - -namespace OpenVanilla { - using namespace std; - - // keyCode() is 0 if receivedString() is a non-ASCII glyph/string - class OVKeyInterface : public OVBase { - public: - virtual const string receivedString() const = 0; - virtual unsigned int keyCode() const = 0; - virtual bool isAltPressed() const = 0; - virtual bool isOptPressed() const = 0; - virtual bool isCtrlPressed() const = 0; - virtual bool isShiftPressed() const = 0; - virtual bool isCommandPressed() const = 0; - virtual bool isNumLockOn() const = 0; - virtual bool isCapsLockOn() const = 0; - - // a direct text key carries a composed glyph (or a string) that semantically differs from the intended keystroke - // (i.e. a half-width char stroke but with a composed, full-width char output) - virtual bool isDirectTextKey() const = 0; - }; - - class OVKeyImpl : public OVKeyInterface { - public: - virtual bool shouldDelete() const = 0; - virtual OVKeyImpl* copy() = 0; - }; - - class OVKey : public OVKeyInterface { - public: - OVKey(OVKeyImpl* keyImpl = 0) - : m_keyImpl(keyImpl) - { - } - - OVKey(const OVKey& aKey) - { - m_keyImpl = aKey.m_keyImpl ? aKey.m_keyImpl->copy() : 0; - } - - ~OVKey() - { - if (m_keyImpl) { - if (m_keyImpl->shouldDelete()) { - delete m_keyImpl; - } - } - } - - OVKey& operator=(const OVKey& aKey) - { - if (m_keyImpl) { - if (m_keyImpl->shouldDelete()) { - delete m_keyImpl; - } - - m_keyImpl = 0; - } - - m_keyImpl = aKey.m_keyImpl ? aKey.m_keyImpl->copy() : 0; - return *this; - } - - virtual bool operator==(const OVKey& key) const - { - if (isAltPressed() == key.isAltPressed() && isOptPressed() == key.isOptPressed() && isCtrlPressed() == key.isCtrlPressed() && isShiftPressed() == key.isShiftPressed() && isCommandPressed() == key.isCommandPressed()) - if (!keyCode() && !key.keyCode()) - return receivedString() == key.receivedString(); - else - return keyCode() == key.keyCode(); - - return false; - } - - virtual bool operator<(const OVKey& key) const - { - if (keyCode() < key.keyCode()) return true; - if (keyCode() > key.keyCode()) return false; - - if (!keyCode() && !key.keyCode()) { - if (receivedString() < key.receivedString()) return true; - if (receivedString() > key.receivedString()) return false; - } - - if (isAltPressed() != key.isAltPressed()) { - if (key.isAltPressed()) return true; - if (isAltPressed()) return false; - } - - if (isOptPressed() != key.isOptPressed()) { - if (key.isOptPressed()) return true; - if (isOptPressed()) return false; - } - - if (isCtrlPressed() != key.isCtrlPressed()) { - if (key.isCtrlPressed()) return true; - if (isCtrlPressed()) return false; - } - - if (isShiftPressed() != key.isShiftPressed()) { - if (key.isShiftPressed()) return true; - if (isShiftPressed()) return false; - } - - if (isCommandPressed() != key.isCommandPressed()) { - if (key.isCommandPressed()) return true; - if (isCommandPressed()) return false; - } - - if (isNumLockOn() != key.isNumLockOn()) { - if (key.isNumLockOn()) return true; - if (isNumLockOn()) return false; - } - - if (isCapsLockOn() != key.isCapsLockOn()) { - if (key.isCapsLockOn()) return true; - if (isCapsLockOn()) return false; - } - - return false; - } - - public: - virtual const string receivedString() const - { - return m_keyImpl ? m_keyImpl->receivedString() : string(); - } - - virtual unsigned int keyCode() const - { - return m_keyImpl ? m_keyImpl->keyCode() : 0; - } - - virtual bool isAltPressed() const - { - return m_keyImpl ? m_keyImpl->isAltPressed() : false; - } - - virtual bool isOptPressed() const - { - return m_keyImpl ? m_keyImpl->isOptPressed() : false; - } - - virtual bool isCtrlPressed() const - { - return m_keyImpl ? m_keyImpl->isCtrlPressed() : false; - } - - virtual bool isShiftPressed() const - { - return m_keyImpl ? m_keyImpl->isShiftPressed() : false; - } - - virtual bool isCommandPressed() const - { - return m_keyImpl ? m_keyImpl->isCommandPressed() : false; - } - - virtual bool isNumLockOn() const - { - return m_keyImpl ? m_keyImpl->isNumLockOn() : false; - } - - virtual bool isCapsLockOn() const - { - return m_keyImpl ? m_keyImpl->isCapsLockOn() : false; - } - - virtual bool isDirectTextKey() const - { - return m_keyImpl ? m_keyImpl->isDirectTextKey() : false; - } - - virtual bool isKeyCodePrintable() const - { - if (keyCode() >= 32 && keyCode() <= 126) - return true; - - return false; - } - - virtual bool isKeyCodeNumeric() const - { - if (keyCode() >= '0' && keyCode() <= '9') - return true; - - return false; - } - - virtual bool isKeyCodeAlpha() const - { - if (keyCode() >= 'A' && keyCode() <= 'Z' || keyCode() >= 'a' && keyCode() <= 'z') - return true; - - return false; - } - - virtual bool isCombinedFunctionKey() const - { - return isCtrlPressed() || isAltPressed() || isOptPressed() || isCommandPressed(); - } - - virtual bool isPrintable() const - { - size_t rssize = receivedString().size(); - unsigned int code = keyCode(); - - if (!rssize) - return false; - - if (rssize > 1) - return true; - - return ((code < 128 && isprint((char)code)) || code > 128); - } - - protected: - OVKeyImpl* m_keyImpl; - }; - - typedef vector OVKeyVector; - - class OVKeyCode { - public: - enum { - Delete = 127, - Backspace = 8, - Up = 30, - Down = 31, - Left = 28, - Right = 29, - Home = 1, - End = 4, - PageUp = 11, - PageDown = 12, - Tab = 9, - Esc = 27, - Space = 32, - Return = 13, - Enter = Return, - LeftShift = 0x10001, - RightShift = 0x10002, - CapsLock = 0x10010, - MacEnter = 0x10020, - F1 = 0x11001, - F2 = 0x11002, - F3 = 0x11003, - F4 = 0x11004, - F5 = 0x11005, - F6 = 0x11006, - F7 = 0x11007, - F8 = 0x11008, - F9 = 0x11009, - F10 = 0x11010, - }; - }; - - class OVKeyMask { - public: - enum { - Alt = 0x0001, - Opt = 0x0002, - AltOpt = 0x0003, - Ctrl = 0x0004, - Shift = 0x008, - Command = 0x0010, - NumLock = 0x0020, - CapsLock = 0x0040, - DirectText = 0x0080 - }; - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVKeyPreprocessor.h b/Source/Engine/OpenVanilla/OVKeyPreprocessor.h deleted file mode 100644 index e82e3d2cddf79c8669662673c8bf5dae5d054949..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVKeyPreprocessor.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// OVKeyPreprocessor.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVKeyPreprocessor_h -#define OVKeyPreprocessor_h - -#if defined(__APPLE__) - #include -#else - #include "OVModule.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVKeyPreprocessor : public OVModule { - public: - virtual bool isPreprocessor() const - { - return true; - } - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVKeyValueMap.h b/Source/Engine/OpenVanilla/OVKeyValueMap.h deleted file mode 100644 index 2d18f2208b66f44f0bc3b2e73045dbff53412c21..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVKeyValueMap.h +++ /dev/null @@ -1,175 +0,0 @@ -// -// OVKeyValueMap.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVKeyValueMap_h -#define OVKeyValueMap_h - -#if defined(__APPLE__) - #include -#else - #include "OVBase.h" -#endif - -#include - -namespace OpenVanilla { - using namespace std; - - class OVKeyValueMapInterface : public OVBase { - public: - virtual bool isReadOnly() = 0; - virtual bool setKeyStringValue(const string& key, const string& value) = 0; - virtual bool hasKey(const string& key) = 0; - virtual const string stringValueForKey(const string& key) = 0; - - virtual bool setKeyIntValue(const string& key, int value) - { - stringstream sstr; - sstr << value; - return setKeyStringValue(key, sstr.str()); - } - - virtual bool setKeyBoolValue(const string& key, bool value) - { - if (value) - return setKeyStringValue(key, "true"); - - return setKeyStringValue(key, "false"); - } - - virtual int intValueForKey(const string& key) - { - string value = stringValueForKey(key); - return atoi(value.c_str()); - } - - virtual const string stringValueForKeyWithDefault(const string& key, const string& defaultValue = "", bool setIfNotFound = true) - { - if (hasKey(key)) - return stringValueForKey(key); - - if (setIfNotFound) - setKeyStringValue(key, defaultValue); - - return defaultValue; - } - - virtual const string operator[](const string& key) - { - return stringValueForKey(key); - } - - virtual bool isKeyTrue(const string& key) - { - if (!hasKey(key)) - return false; - - string value = stringValueForKey(key); - - if (atoi(value.c_str()) > 0) - return true; - - if (value == "true") - return true; - - return false; - } - }; - - class OVKeyValueMapImpl : public OVKeyValueMapInterface { - public: - virtual bool shouldDelete() = 0; - virtual OVKeyValueMapImpl* copy() = 0; - }; - - class OVKeyValueMap : public OVKeyValueMapInterface { - public: - OVKeyValueMap(OVKeyValueMapImpl* keyValueMapImpl = 0) - : m_keyValueMapImpl(keyValueMapImpl) - { - } - - OVKeyValueMap(const OVKeyValueMap& aKeyValueMap) - { - m_keyValueMapImpl = aKeyValueMap.m_keyValueMapImpl ? aKeyValueMap.m_keyValueMapImpl->copy() : 0; - } - - ~OVKeyValueMap() - { - if (m_keyValueMapImpl) { - if (m_keyValueMapImpl->shouldDelete()) { - delete m_keyValueMapImpl; - } - } - } - - OVKeyValueMap& operator=(const OVKeyValueMap& aKeyValueMap) - { - if (m_keyValueMapImpl) { - if (m_keyValueMapImpl->shouldDelete()) { - delete m_keyValueMapImpl; - } - - m_keyValueMapImpl = 0; - } - - m_keyValueMapImpl = aKeyValueMap.m_keyValueMapImpl ? aKeyValueMap.m_keyValueMapImpl->copy() : 0; - return *this; - } - - public: - virtual bool isReadOnly() - { - return m_keyValueMapImpl ? m_keyValueMapImpl->isReadOnly() : true; - } - - virtual bool setKeyStringValue(const string& key, const string& value) - { - return m_keyValueMapImpl ? m_keyValueMapImpl->setKeyStringValue(key, value) : false; - } - - virtual bool hasKey(const string& key) - { - return m_keyValueMapImpl ? m_keyValueMapImpl->hasKey(key) : false; - } - - virtual const string stringValueForKey(const string& key) - { - return m_keyValueMapImpl ? m_keyValueMapImpl->stringValueForKey(key) : string(); - } - - virtual const string stringValueForKeyWithDefault(const string& key, const string& defaultValue = "", bool setIfNotFound = true) - { - return m_keyValueMapImpl ? m_keyValueMapImpl->stringValueForKeyWithDefault(key, defaultValue, setIfNotFound) : string(); - } - - protected: - OVKeyValueMapImpl* m_keyValueMapImpl; - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVLoaderBase.h b/Source/Engine/OpenVanilla/OVLoaderBase.h deleted file mode 100644 index fdaef0a05dd976000eb893b052b77047e54e030e..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVLoaderBase.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// OVLoaderBase.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVLoaderBase_h -#define OVLoaderBase_h - -#if defined(__APPLE__) - #include -#else - #include "OVModule.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVLoader : public OVBase { - public: - virtual OVLoaderService* loaderService() = 0; - virtual OVModule* moduleForIdentifier(const string& identifier) = 0; - virtual vector moduleIdentifiers() = 0; - virtual vector moduleIdentifiersForConditions(bool preprocessor, bool inputMethod, bool outputFilter) = 0; - }; - -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVLoaderService.h b/Source/Engine/OpenVanilla/OVLoaderService.h deleted file mode 100644 index c0994e0a544359cda2ca8a541069d667755ee4c8..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVLoaderService.h +++ /dev/null @@ -1,120 +0,0 @@ -// -// OVLoaderService.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVLoaderService_h -#define OVLoaderService_h - -#if defined(__APPLE__) - #include - #include - #include - #include -#else - #include "OVBase.h" - #include "OVDatabaseService.h" - #include "OVEncodingService.h" - #include "OVKey.h" -#endif - -#include -#include - -namespace OpenVanilla { - using namespace std; - - class OVLogEmitter : public OVBase { - public: - virtual const string sectionName() const = 0; - virtual void setSectionName(const string& sectionName) = 0; - virtual void emitLog(const string& logEntry) = 0; - }; - - class OVLogStringBuffer : public stringbuf { - public: - OVLogStringBuffer(OVLogEmitter* logEmitter = 0) - : m_logEmitter(logEmitter) - { - } - - virtual int sync() { - if (str().length()) { - if (m_logEmitter) - m_logEmitter->emitLog(str()); - else - cerr << "Log: " << str(); - - str(string()); - } - - // clear the buffer - return 0; - } - - virtual OVLogEmitter* logEmitter() const - { - return m_logEmitter; - } - - virtual void setLogEmitter(OVLogEmitter* logEmitter) - { - m_logEmitter = logEmitter; - } - - protected: - OVLogEmitter* m_logEmitter; - }; - - class OVLoaderService : public OVBase { - public: - virtual void beep() = 0; - virtual void notify(const string& message) = 0; - virtual void HTMLNotify(const string& content) = 0; - - virtual const string locale() const = 0; - virtual const OVKey makeOVKey(int characterCode, bool alt = false, bool opt = false, bool ctrl = false, bool shift = false, bool command = false, bool capsLock = false, bool numLock = false) = 0; - virtual const OVKey makeOVKey(const string& receivedString, bool alt = false, bool opt = false, bool ctrl = false, bool shift = false, bool command = false, bool capsLock = false, bool numLock = false) = 0; - - virtual ostream& logger(const string& sectionName = "") = 0; - - virtual OVDatabaseService* defaultDatabaseService() = 0; - virtual OVDatabaseService* CINDatabaseService() = 0; - virtual OVDatabaseService* SQLiteDatabaseService() = 0; - - virtual OVEncodingService* encodingService() = 0; - - virtual void __reserved1(const string&) = 0; - virtual void __reserved2(const string&) = 0; - virtual void __reserved3(const string&) = 0; - virtual void __reserved4(const string&) = 0; - virtual const string __reserved5() const = 0; - virtual void __reserved6(const string&) = 0; - virtual void __reserved7(const string&, const string &) = 0; - virtual void* __reserved8(const string&) = 0; - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVLocalization.h b/Source/Engine/OpenVanilla/OVLocalization.h deleted file mode 100644 index e02bb08d336d16f5c19b379c65ecbd6079e2700b..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVLocalization.h +++ /dev/null @@ -1,136 +0,0 @@ -// -// OVLocalization.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVLocalization_h -#define OVLocalization_h - -#include -#include -#include "OVStringHelper.h" -#include "OVWildcard.h" - -namespace OpenVanilla { - using namespace std; - - class OVLocale { - public: - static const string POSIXLocaleID(const string& locale) - { - string n = OVStringHelper::StringByReplacingOccurrencesOfStringWithString(locale, "-", "_"); - - if (OVWildcard::Match(n, "zh_Hant")) { - return "zh_TW"; - } - - if (OVWildcard::Match(n, "zh_Hans")) { - return "zh_CN"; - } - - if (OVWildcard::Match(n, "zh_HK")) { - return "zh_TW"; - } - - if (OVWildcard::Match(n, "zh_SG")) { - return "zh_CN"; - } - - if (OVWildcard::Match(n, "en_*")) { - return "en"; - } - - return locale; - } - }; - - - template class OVLocalization { - public: - static const void SetDefaultLocale(const string& locale) - { - SharedInstance()->m_defaultLocale = locale.length() ? OVLocale::POSIXLocaleID(locale) : string("en"); - } - - static const string S(const string& locale, const string& text) - { - return SharedInstance()->m_table(locale, text); - } - - static const string S(const string& text) - { - return SharedInstance()->m_table(SharedInstance()->m_defaultLocale, text); - } - - protected: - static OVLocalization* SharedInstance() - { - static OVLocalization* instance = 0; - if (!instance) { - instance = new OVLocalization; - } - - return instance; - } - - OVLocalization() - : m_defaultLocale("en") - { - } - - T m_table; - string m_defaultLocale; - }; - - class OVLocalizationStringTable { - public: - const string operator()(const string& locale, const string& text) const - { - // maybe we'll have fallback logic later here - map >::const_iterator i = m_table.find(locale); - if (i == m_table.end()) { - return text; - } - - map::const_iterator j = (*i).second.find(text); - if (j == (*i).second.end()) { - return text; - } - - return (*j).second; - } - - - protected: - void add(const string& locale, const string& original, const string& localized) - { - m_table[locale][original] = localized; - } - - map > m_table; - }; -}; - -#endif \ No newline at end of file diff --git a/Source/Engine/OpenVanilla/OVModule.h b/Source/Engine/OpenVanilla/OVModule.h deleted file mode 100644 index 4694aee95a35d69630f8b9f4c6725212a59a4909..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVModule.h +++ /dev/null @@ -1,146 +0,0 @@ -// -// OVModule.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVModule_h -#define OVModule_h - -#if defined(__APPLE__) - #include - #include - #include -#else - #include "OVEventHandlingContext.h" - #include "OVKeyValueMap.h" - #include "OVPathInfo.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVModule : public OVBase { - public: - OVModule() - : m_initialized(false) - , m_usable(false) - { - } - - virtual bool isInitialized() const - { - return m_initialized; - } - - virtual bool isUsable() const - { - return m_usable; - } - - virtual bool isPreprocessor() const - { - return false; - } - - virtual bool isInputMethod() const - { - return false; - } - - virtual bool isOutputFilter() const - { - return false; - } - - virtual bool isAroundFilter() const - { - return false; - } - - // the smaller it gets, the closer the the filter gets to the commit event - virtual int suggestedOrder() const - { - return 0; - } - - virtual OVEventHandlingContext* createContext() - { - return 0; - } - - virtual const string identifier() const = 0; - - virtual const string localizedName(const string& locale) - { - return identifier(); - - } - - virtual bool moduleInitialize(OVPathInfo* pathInfo, OVLoaderService* loaderService) - { - if (m_initialized) - return false; - - m_usable = initialize(pathInfo, loaderService); - m_initialized = true; - return m_usable; - } - - virtual bool initialize(OVPathInfo* pathInfo, OVLoaderService* loaderService) - { - return true; - } - - virtual void finalize() - { - } - - virtual void loadConfig(OVKeyValueMap* moduleConfig, OVLoaderService* loaderService) - { - } - - virtual void saveConfig(OVKeyValueMap* moduleConfig, OVLoaderService* loaderService) - { - } - - enum AroundFilterDisplayOption { - ShownAsPreprocessor, - ShownAsOutputFilter, - ShownAsBoth - }; - - // around filter modules need to tell loader how it wishes to be placed in the menu - virtual AroundFilterDisplayOption aroundFilterPreferredDisplayOption() - { - return ShownAsBoth; - } - - protected: - bool m_initialized; - bool m_usable; - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVModulePackage.h b/Source/Engine/OpenVanilla/OVModulePackage.h deleted file mode 100644 index 21c9808073f10b6f605f2507198a493a4cbf92d6..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVModulePackage.h +++ /dev/null @@ -1,100 +0,0 @@ -// -// OVModulePackage.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVModulePackage_h -#define OVModulePackage_h - -#if defined(__APPLE__) - #include - #include -#else - #include "OVFrameworkInfo.h" - #include "OVModule.h" -#endif - -#ifdef WIN32 - #define OVEXPORT __declspec(dllexport) -#else - #define OVEXPORT -#endif - -namespace OpenVanilla { - using namespace std; - - class OVModuleClassWrapperBase : public OVBase { - public: - virtual OVModule* newModule() - { - // this member function can't be abstract, or vector wouldn't instantiate under VC++ 2005 - return 0; - } - }; - - template class OVModuleClassWrapper : public OVModuleClassWrapperBase { - public: - virtual OVModule* newModule() - { - return new T; - } - }; - - // we encourage people to do the real initialization in initialize - class OVModulePackage : OVBase { - public: - ~OVModulePackage() - { - vector::iterator iter = m_moduleVector.begin(); - for ( ; iter != m_moduleVector.end(); ++iter) - delete *iter; - } - virtual bool initialize(OVPathInfo* , OVLoaderService* loaderService) - { - // in your derived class, add class wrappers to m_moduleVector - return true; - } - - virtual void finalize() - { - } - - virtual size_t numberOfModules(OVLoaderService*) - { - return m_moduleVector.size(); - } - - virtual OVModule* moduleAtIndex(size_t index, OVLoaderService*) - { - if (index > m_moduleVector.size()) return 0; - return m_moduleVector[index]->newModule(); - } - - protected: - vector m_moduleVector; - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVOutputFilter.h b/Source/Engine/OpenVanilla/OVOutputFilter.h deleted file mode 100644 index 5477b9dc6966b3f3665fded0c145e9835d05c348..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVOutputFilter.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// OVOutputFilter.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVOutputFilter_h -#define OVOutputFilter_h - -#if defined(__APPLE__) - #include -#else - #include "OVModule.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVOutputFilter : public OVModule { - public: - virtual bool isOutputFilter() const - { - return true; - } - }; -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVPathInfo.h b/Source/Engine/OpenVanilla/OVPathInfo.h deleted file mode 100644 index 70eab573623824e1b94e2522d133f3924d251159..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVPathInfo.h +++ /dev/null @@ -1,63 +0,0 @@ -// -// OVPathInfo.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVPathInfo_h -#define OVPathInfo_h - -#if defined(__APPLE__) - #include -#else - #include "OVFileHelper.h" -#endif - -namespace OpenVanilla { - using namespace std; - - struct OVPathInfo { - string loadedPath; - string resourcePath; - string writablePath; - - static const OVPathInfo DefaultPathInfo() { - string tmpdir = OVDirectoryHelper::TempDirectory(); - OVPathInfo pathInfo; - - pathInfo.loadedPath = tmpdir; - pathInfo.resourcePath = tmpdir; - pathInfo.writablePath = tmpdir; - return pathInfo; - } - }; - - inline ostream& operator<<(ostream& stream, const OVPathInfo& info) - { - stream << "OVPathInfo = (loaded path = " << info.loadedPath << ", resource path = " << info.resourcePath << ", writable path = " << info.writablePath << ")"; - return stream; - } -}; - -#endif diff --git a/Source/Engine/OpenVanilla/OVSQLiteDatabaseService.h b/Source/Engine/OpenVanilla/OVSQLiteDatabaseService.h deleted file mode 100644 index a5b2333c1dbcb895f9a16511d3f445a3765e1bc2..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVSQLiteDatabaseService.h +++ /dev/null @@ -1,249 +0,0 @@ -// -// OVSQLiteDatabaseService.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVSQLiteDatabaseService_h -#define OVSQLiteDatabaseService_h - -#if defined(__APPLE__) - #include - #include - #include -#else - #include "OVDatabaseService.h" - #include "OVSQLiteWrapper.h" - #include "OVWildcard.h" -#endif - -namespace OpenVanilla { - using namespace std; - - class OVSQLiteHelper { - public: - static const pair SQLiteStringFromWildcard(const OVWildcard& wildcard) - { - const string& expression = wildcard.expression(); - string sqlstr; - - char mOC = wildcard.matchOneChar(); - char mZOMC = wildcard.matchZeroOrMoreChar(); - char escChar = mZOMC ? mZOMC : mOC; - - for (string::const_iterator iter = expression.begin() ; iter != expression.end() ; ++iter) { - if (*iter == mOC) { - sqlstr += '_'; - } - else if (*iter == mZOMC) { - sqlstr += '%'; - } - else if (*iter == '_') { - sqlstr += escChar; - sqlstr += '_'; - } - else if (*iter == '%') { - sqlstr += escChar; - sqlstr += '%'; - } - else { - sqlstr += *iter; - } - } - - return pair(sqlstr, string(1, escChar)); - } - }; - - class OVSQLiteDatabaseService; - - class OVSQLiteKeyValueDataTable : public OVKeyValueDataTableInterface { - public: - virtual const vector valuesForKey(const string& key); - virtual const vector > valuesForKey(const OVWildcard& expression); - virtual const string valueForProperty(const string& property); - virtual const vector keysForValue(const string& value); - - protected: - OVSQLiteDatabaseService* m_source; - string m_tableName; - - friend class OVSQLiteDatabaseService; - OVSQLiteKeyValueDataTable(OVSQLiteDatabaseService* source, const string& tableName) - : m_source(source) - , m_tableName(tableName) - { - } - }; - - class OVSQLiteDatabaseService : public OVDatabaseService { - public: - ~OVSQLiteDatabaseService() - { - if (m_ownsConnection) - delete m_connection; - } - - virtual const vector tables(const OVWildcard& filter = string("*")) - { - pair exp = OVSQLiteHelper::SQLiteStringFromWildcard(filter); - - vector result; - OVSQLiteStatement* statement = m_connection->prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name LIKE %Q ESCAPE %Q ORDER BY name", exp.first.c_str(), exp.second.c_str()); - if (statement) { - while (statement->step() == SQLITE_ROW) { - result.push_back(statement->textOfColumn(0)); - } - - delete statement; - } - - return result; - } - - virtual bool tableSupportsValueToKeyLookup(const string &tableName) - { - return true; - } - - virtual OVKeyValueDataTableInterface* createKeyValueDataTableInterface(const string& name, bool suggestedCaseSensitivity = false) - { - return new OVSQLiteKeyValueDataTable(this, name); - } - - virtual const string valueForPropertyInTable(const string& property, const string& name) - { - OVSQLiteStatement* statement = m_connection->prepare("SELECT VALUE FROM %Q WHERE KEY = ?", name.c_str()); - string result; - - if (statement) { - statement->bindTextToColumn(string(OVPropertyStringInternalPrefix) + property, 1); - - if (statement->step() == SQLITE_ROW) { - result = statement->textOfColumn(0); - while (statement->step() == SQLITE_ROW) ; - } - - delete statement; - } - - return result; - } - - virtual const string filename() - { - return m_connection->filename(); - } - - static OVSQLiteDatabaseService* Create(const string& filename = ":memory:") - { - OVSQLiteConnection* connection = OVSQLiteConnection::Open(filename); - if (!connection) - return 0; - - return new OVSQLiteDatabaseService(connection, true); - } - - static OVSQLiteDatabaseService* ServiceWithExistingConnection(OVSQLiteConnection* connection, bool ownsConnection = false) - { - return new OVSQLiteDatabaseService(connection, ownsConnection); - } - - OVSQLiteConnection* connection() - { - return m_connection; - } - - protected: - friend class OVSQLiteKeyValueDataTable; - - OVSQLiteDatabaseService(OVSQLiteConnection* connection, bool ownsConnection = false) - : m_connection(connection) - , m_ownsConnection(ownsConnection) - { - } - - OVSQLiteConnection* m_connection; - bool m_ownsConnection; - }; - - inline const vector OVSQLiteKeyValueDataTable::valuesForKey(const string& key) - { - vector result; - OVSQLiteStatement* statement = m_source->connection()->prepare("SELECT value FROM %Q WHERE key = %Q", m_tableName.c_str(), key.c_str()); - if (statement) { - while (statement->step() == SQLITE_ROW) { - result.push_back(statement->textOfColumn(0)); - } - - delete statement; - } - - return result; - } - - inline const vector OVSQLiteKeyValueDataTable::keysForValue(const string& value) - { - vector result; - OVSQLiteStatement* statement = m_source->connection()->prepare("SELECT key FROM %Q WHERE value = %Q", m_tableName.c_str(), value.c_str()); - if (statement) { - while (statement->step() == SQLITE_ROW) { - string key = statement->textOfColumn(0); - - // we don't want property get into it - if (!OVWildcard::Match(key, OVPropertyStringInternalPrefix "*")) { - result.push_back(key); - } - } - - delete statement; - } - - return result; - } - - inline const vector > OVSQLiteKeyValueDataTable::valuesForKey(const OVWildcard& expression) - { - pair exp = OVSQLiteHelper::SQLiteStringFromWildcard(expression); - - vector > result; - OVSQLiteStatement* statement = m_source->connection()->prepare("SELECT key, value FROM %Q WHERE key like %Q escape %Q", m_tableName.c_str(), exp.first.c_str(), exp.second.c_str()); - if (statement) { - while (statement->step() == SQLITE_ROW) { - result.push_back(pair(statement->textOfColumn(0), statement->textOfColumn(1))); - } - - delete statement; - } - - return result; - } - - inline const string OVSQLiteKeyValueDataTable::valueForProperty(const string& property) - { - return m_source->valueForPropertyInTable(property, m_tableName); - } -}; - -#endif \ No newline at end of file diff --git a/Source/Engine/OpenVanilla/OVSQLiteWrapper.h b/Source/Engine/OpenVanilla/OVSQLiteWrapper.h deleted file mode 100644 index 1e056f92cbfa06eee8da6a42ba5ecdf0dfb286fc..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVSQLiteWrapper.h +++ /dev/null @@ -1,278 +0,0 @@ -// -// OVSQLiteWrapper.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVSQLite3Wrapper -#define OVSQLite3Wrapper - -#include - -#if defined(__APPLE__) - #include -#else - #include "OpenVanilla.h" -#endif - -// For status codes (SQLITE_OK, SQLITE_ERROR, etc.), please refer to sqlite3.h - -namespace OpenVanilla { - using namespace std; - - class OVSQLiteStatement; - - class OVSQLiteConnection { - public: - // remember to manage the object returned by this class member function - static OVSQLiteConnection* Open(const string& filename = ":memory:"); - ~OVSQLiteConnection(); - - int lastError(); - const char* lastErrorMessage(); - - int execute(const char* sqlcmd, ...); - OVSQLiteStatement* prepare(const char* sqlcmd, ...); - - // helper for table creation and detection - bool hasTable(const string& tableName); - bool dropTable(const string& tableName); - bool createTable(const string& tableName, const string& columnString = "key, value", bool dropIfExists = false); - bool createIndexOnTable(const string& indexName, const string& tableName, const string& indexColumns = "key"); - - sqlite3* connection(); - const string filename(); - - protected: - sqlite3* m_connection; - string m_filename; - OVSQLiteConnection(sqlite3* connection, const string& filename); - }; - - class OVSQLiteStatement { - public: - ~OVSQLiteStatement(); - - int reset(); - - // *nota bene* column starts from 1 ! - int bindTextToColumn(const char*str, int column); - int bindTextToColumn(const string& str, int column); - int bindIntToColumn(int value, int column); - int bindDoubleToColumn(double value, int column); - - int step(); - int columnCount(); - const char* textOfColumn(int column); - int intOfColumn(int column); - double doubleOfColumn(int column); - - protected: - sqlite3_stmt* m_statement; - - friend class OVSQLiteConnection; - OVSQLiteStatement(sqlite3_stmt* statement); - }; - - inline sqlite3* OVSQLiteConnection::connection() - { - return m_connection; - } - - inline OVSQLiteConnection* OVSQLiteConnection::Open(const string& filename) - { - sqlite3* connection; - - if (sqlite3_open(filename.c_str(), &connection) != SQLITE_OK) - return 0; - - if (!connection) - return 0; - - return new OVSQLiteConnection(connection, filename); - } - - inline OVSQLiteConnection::OVSQLiteConnection(sqlite3* connection, const string& filename) - : m_connection(connection) - , m_filename(filename) - { - } - - inline OVSQLiteConnection::~OVSQLiteConnection() - { - - int result = sqlite3_close(m_connection); - if (result) { - ; - } - } - - inline const string OVSQLiteConnection::filename() - { - return m_filename; - } - - inline int OVSQLiteConnection::lastError() - { - return sqlite3_errcode(m_connection); - } - - inline const char* OVSQLiteConnection::lastErrorMessage() - { - return sqlite3_errmsg(m_connection); - } - - inline int OVSQLiteConnection::execute(const char* sqlcmd, ...) - { - va_list l; - va_start(l, sqlcmd); - char* cmd = sqlite3_vmprintf(sqlcmd, l); - va_end(l); - int result = sqlite3_exec(m_connection, cmd, NULL, NULL, NULL); - sqlite3_free(cmd); - return result; - } - - inline OVSQLiteStatement* OVSQLiteConnection::prepare(const char* sqlcmd, ...) - { - va_list l; - va_start(l, sqlcmd); - char* cmd = sqlite3_vmprintf(sqlcmd, l); - va_end(l); - - sqlite3_stmt* stmt; - OVSQLiteStatement* result = 0; - - const char* remainingSt = 0; - if (sqlite3_prepare_v2(m_connection, cmd, -1, &stmt, &remainingSt) == SQLITE_OK) - result = new OVSQLiteStatement(stmt); - sqlite3_free(cmd); - - return result; - } - - inline bool OVSQLiteConnection::hasTable(const string& tableName) - { - bool result = false; - OVSQLiteStatement* statement = prepare("SELECT name FROM sqlite_master WHERE name = %Q", tableName.c_str()); - if (statement) { - if (statement->step() == SQLITE_ROW) { - result = true; - while (statement->step() == SQLITE_ROW) ; - } - - delete statement; - } - - return result; - } - - inline bool OVSQLiteConnection::dropTable(const string& tableName) - { - return SQLITE_OK == execute("DROP TABLE %Q", tableName.c_str()); - } - - inline bool OVSQLiteConnection::createTable(const string& tableName, const string& columnString, bool dropIfExists) - { - if (hasTable(tableName)) { - if (dropIfExists) { - if (!dropTable(tableName)) - return false; - } - else { - return false; - } - } - - - return SQLITE_OK == execute("CREATE TABLE %Q (%s)", tableName.c_str(), columnString.c_str()); - } - - inline bool OVSQLiteConnection::createIndexOnTable(const string& indexName, const string& tableName, const string& indexColumns) - { - return SQLITE_OK == execute("CREATE INDEX %Q on %Q (%s)", indexName.c_str(), tableName.c_str(), indexColumns.c_str()); - } - - inline OVSQLiteStatement::OVSQLiteStatement(sqlite3_stmt* statement) - : m_statement(statement) - { - } - - inline OVSQLiteStatement::~OVSQLiteStatement() - { - sqlite3_finalize(m_statement); - } - - inline int OVSQLiteStatement::reset() - { - return sqlite3_reset(m_statement); - } - - inline int OVSQLiteStatement::bindTextToColumn(const char* str, int column) - { - return sqlite3_bind_text(m_statement, column, str, -1, SQLITE_TRANSIENT); - } - - inline int OVSQLiteStatement::bindTextToColumn(const string& str, int column) - { - return bindTextToColumn(str.c_str(), column); - } - - inline int OVSQLiteStatement::bindIntToColumn(int value, int column) - { - return sqlite3_bind_int(m_statement, column, value); - } - - inline int OVSQLiteStatement::bindDoubleToColumn(double value, int column) - { - return sqlite3_bind_double(m_statement, column, value); - } - - inline int OVSQLiteStatement::step() - { - return sqlite3_step(m_statement); - } - - inline int OVSQLiteStatement::columnCount() - { - return sqlite3_column_count(m_statement); - } - - inline const char* OVSQLiteStatement::textOfColumn(int column) - { - return (const char*)sqlite3_column_text(m_statement, column); - } - - inline int OVSQLiteStatement::intOfColumn(int column) - { - return sqlite3_column_int(m_statement, column); - } - - inline double OVSQLiteStatement::doubleOfColumn(int column) - { - return sqlite3_column_double(m_statement, column); - } -}; - -#endif \ No newline at end of file diff --git a/Source/Engine/OpenVanilla/OVStringHelper.h b/Source/Engine/OpenVanilla/OVStringHelper.h deleted file mode 100644 index 7e2b8e2b0a3c35defc5da0418ef650173af89a1c..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVStringHelper.h +++ /dev/null @@ -1,218 +0,0 @@ -// -// OVStringHelper.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVStringHelper_h -#define OVStringHelper_h - -#include -#include -#include - -namespace OpenVanilla { - using namespace std; - - class OVStringHelper { - public: - static const vector SplitBySpacesOrTabsWithDoubleQuoteSupport(const string& text) - { - vector result; - size_t index = 0, last = 0, length = text.length(); - while (index < length) { - if (text[index] == '\"') { - index++; - string tmp; - while (index < length) { - if (text[index] == '\"') { - index++; - break; - } - - if (text[index] == '\\' && index + 1 < length) { - index++; - char c = text[index]; - switch (c) { - case 'r': - tmp += '\r'; - break; - case 'n': - tmp += '\n'; - break; - case '\"': - tmp += '\"'; - break; - case '\\': - tmp += '\\'; - break; - } - } - else { - tmp += text[index]; - } - - index++; - } - result.push_back(tmp); - } - - if (text[index] != ' ' && text[index] != '\t') { - last = index; - while (index < length) { - if (text[index] == ' ' || text[index] == '\t') { - if (index - last) - result.push_back(text.substr(last, index - last)); - break; - } - index++; - } - - if (index == length && index - last) - result.push_back(text.substr(last, index - last)); - } - - index++; - } - - return result; - } - - static const vector SplitBySpacesOrTabs(const string& text) - { - vector result; - size_t index = 0, last = 0, length = text.length(); - while (index < length) { - if (text[index] != ' ' && text[index] != '\t') { - last = index; - while (index < length) { - if (text[index] == ' ' || text[index] == '\t') { - if (index - last) - result.push_back(text.substr(last, index - last)); - break; - } - index++; - } - - if (index == length && index - last) - result.push_back(text.substr(last, index - last)); - } - - index++; - } - - return result; - } - - static const vector Split(const string& text, char c) - { - vector result; - size_t index = 0, last = 0, length = text.length(); - while (index < length) { - while (index < length) { - if (text[index] == c) { - result.push_back(text.substr(last, index - last)); - last = index + 1; - break; - } - index++; - } - - index++; - } - - if (last <= index) { - result.push_back(text.substr(last, index - last)); - } - - return result; - } - - // named after Cocoa's NSString -stringByReplacingOccurrencesOfString:WithString:, horrible - static const string StringByReplacingOccurrencesOfStringWithString(const string& source, const string& substr, const string& replacement) - { - if (!substr.length()) - return source; - - size_t pos; - if ((pos = source.find(substr)) >= source.length()) - return source; - - return source.substr(0, pos) + replacement + StringByReplacingOccurrencesOfStringWithString(source.substr(pos + substr.length()), substr, replacement); - } - - static const string Join(const vector& vec) - { - string result; - for (vector::const_iterator iter = vec.begin(); iter != vec.end() ; ++iter) - result += *iter; - - return result; - } - - static const string Join(const vector& vec, const string& separator) - { - return Join(vec.begin(), vec.end(), separator); - } - - static const string Join(const vector& vec, size_t from, size_t size, const string& separator) - { - return Join(vec.begin() + from, vec.begin() + from + size, separator); - } - - static const string Join(vector::const_iterator begin, vector::const_iterator end, const string& separator) - { - string result; - for (vector::const_iterator iter = begin ; iter != end ; ) { - result += *iter; - if (++iter != end) - result += separator; - } - return result; - } - - static const string PercentEncode(const string& text) - { - stringstream sst; - sst << hex; - - for (string::const_iterator i = text.begin() ; i != text.end() ; ++i) { - if ((*i >= '0' && *i <= '9') || (*i >= 'A' && *i <= 'Z') || (*i >= 'a' && *i <= 'z') || *i == '-' || *i == '_' || *i == '.' || *i == '~') { - sst << (char)*i; - } - else { - sst << '%'; - sst.width(2); - sst.fill('0'); - unsigned char c = *i; - sst << (unsigned int)c; - } - } - - return sst.str(); - } - }; -} - -#endif diff --git a/Source/Engine/OpenVanilla/OVTextBuffer.h b/Source/Engine/OpenVanilla/OVTextBuffer.h deleted file mode 100644 index 21300c854b3b3a3185c34a799af9e01324059133..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVTextBuffer.h +++ /dev/null @@ -1,102 +0,0 @@ -// -// OVTextBuffer.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVTextBuffer_h -#define OVTextBuffer_h - -#if defined(__APPLE__) - #include -#else - #include "OVBase.h" -#endif - -namespace OpenVanilla { - using namespace std; - - // Terminologies: - // * Text buffer = a generic term - // * Composing text = composing buffer = composition buffer - // In Windows speak, "composition buffer" doesn't contain reading - // (Reading is a separate concept in Windows) - // In Mac speak, "composing buffer" == composing text + reading text - // * Reading text = currently in-wait-state radicals - // * Pre-edit, pre-edit area or pre-edit buffer (X11 speak) = composing text + reading - // Mac's composing buffer is actually pre-edit in this sense - - - class OVTextBuffer : public OVBase { - public: - - virtual void clear() = 0; - virtual void setText(const string& text) = 0; - virtual void appendText(const string& text, bool moveCursor = true) = 0; - - // when the text buffer is committed, the buffer itself, along with settings like cursor, and tooltip (for both composing text and reading text), highlight, word segments, and suggested display style (for reading text) are cleared; the combined committed string will be available at composedCommittedText() - virtual void commit() = 0; - virtual void commitAsTextSegment() = 0; - virtual void commit(const string& text) = 0; - virtual void commitAsTextSegment(const string& text) = 0; - - virtual void updateDisplay() = 0; - virtual bool isEmpty() const = 0; - virtual size_t codePointCount() const = 0; - virtual const string codePointAt(size_t index) const = 0; - virtual const string composedText() const = 0; - virtual const string composedCommittedText() const = 0; - virtual const vector composedCommittedTextSegments() const = 0; - - // Composing text (composing buffer, composition buffer)-only members - public: - typedef pair RangePair; - - // composing buffer should support these four, but reading buffer doesn't need to (anyway it's meaningless) - virtual void setCursorPosition(size_t position) = 0; - virtual size_t cursorPosition() const = 0; - virtual void showToolTip(const string& text) = 0; - virtual void clearToolTip() = 0; - - // implementation details: composing buffer might support this, but reading buffer doesn't - virtual void setHighlightMark(const RangePair& range) = 0; - - // word segments: on Windows, this is an independent (though application-dependent) feature, on Mac OS X, word segments cannot overlap with the highlight mark, and also, when the highlight mark is on, the cursor is off - virtual void setWordSegments(const vector& segments) = 0; - - // Reading text only members - public: - enum ReadingTextStyle { - Horizontal = 0, - Vertical = 1 - }; - - // this is only for the reading buffer, and is not a required implementation - virtual void setSuggestedReadingTextStyle(ReadingTextStyle style) = 0; - virtual ReadingTextStyle defaultReadingTextStyle() const = 0; - }; -}; - -#endif - diff --git a/Source/Engine/OpenVanilla/OVUTF8Helper.h b/Source/Engine/OpenVanilla/OVUTF8Helper.h deleted file mode 100644 index cd1e004949dc17a8d0f99a64eb28da184a83dced..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVUTF8Helper.h +++ /dev/null @@ -1,194 +0,0 @@ -// -// OVUTF8Helper.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVUTF8Helper_h -#define OVUTF8Helper_h - -#include -#include -#include - -#include - -namespace OpenVanilla { - using namespace std; - - class OVUTF8Helper { - public: - static const vector SplitStringByCodePoint(const string& utf8String) - { - size_t index, length = utf8String.length(); - vector result; - - for (index = 0; index < length; index++) { - unsigned char c = utf8String[index]; - - if (!(c & 0x80)) { - result.push_back(utf8String.substr(index, 1)); - } - else if ((c & (0x80 | 0x40)) && !(c & 0x20)) { - result.push_back(utf8String.substr(index, 2)); - index += 1; - } - else if ((c & (0x80 | 0x40 | 0x20)) && !(c & 0x10)) { - result.push_back(utf8String.substr(index, 3)); - index += 2; - } - else if ((c & (0x80 | 0x40 | 0x20 | 0x10)) && !(c & 0x8)) { - result.push_back(utf8String.substr(index, 4)); - index += 3; - } - } - - return result; - } - - static const string CombineCodePoints(const vector& codePoints) - { - string result; - for (vector::const_iterator iter = codePoints.begin(); iter != codePoints.end() ; ++iter) - result += *iter; - - return result; - } - - static const wstring ConvertStringToUTF16WideString(const string& utf8String) - { - wstring wideString; - vector charVector = OVUTF8Helper::SplitStringByCodePoint(utf8String); - - size_t length = charVector.size(); - for (size_t index = 0; index < length; index++) - { - unsigned int codePoint = OVUTF8Helper::CodePointFromSingleUTF8String(charVector[index]); - - if (codePoint < 0x10000) { - wideString += (wchar_t)codePoint; - } - else { - const unsigned int leadOffset = 0xD800 - (0x10000 >> 10); - unsigned int lead = leadOffset + (codePoint >> 10); - unsigned int trail = 0xdc00 + (codePoint & 0x3ff); - wideString += (wchar_t)lead; - wideString += (wchar_t)trail; - } - } - - return wideString; - } - - static const string StringFromUTF16WideString(const wstring& utf16WideString) - { - string utf8String; - size_t length = utf16WideString.length(); - - unsigned int u16; - for (size_t index = 0; index < length; index++) { - u16 = utf16WideString[index]; - - if (u16 >= 0xd800 && u16 <= 0xdbff) { - if (index + 1 < length) { - unsigned int trailing = utf16WideString[index + 1]; - if (trailing >= 0xdc00 && trailing <= 0xdfff) { - index++; - - const unsigned int surrogateOffset = 0x10000 - (0xD800 << 10) - 0xDC00; - unsigned int codePoint = (u16 << 10) + trailing + surrogateOffset; - utf8String += OVUTF8Helper::SingleUTF8StringFromCodePoint(codePoint); - } - } - } - else if (!(u16 >= 0xdc00 && u16 <= 0xdfff)) - { - utf8String += OVUTF8Helper::SingleUTF8StringFromCodePoint(u16); - } - } - - return utf8String; - } - - static const string SingleUTF8StringFromCodePoint(unsigned int codePoint) - { - string utf8String; - - if (codePoint < 0x80) { - utf8String += (unsigned char)codePoint; - } - else if (codePoint < 0x800) { - utf8String += (unsigned char)((codePoint >> 6) | 0xc0); - utf8String += (unsigned char)((codePoint & 0x3f) | 0x80); - } - else if (codePoint < 0x10000) { - utf8String += (unsigned char)((codePoint >> 12) | 0xe0); - utf8String += (unsigned char)(((codePoint >> 6) & 0x3f) | 0x80); - utf8String += (unsigned char)((codePoint & 0x3f) | 0x80); - } - else { - utf8String += (unsigned char)((codePoint >> 18) | 0xf0); - utf8String += (unsigned char)((codePoint >> 12) | 0x80); - utf8String += (unsigned char)(((codePoint >> 6) & 0x3f) | 0x80); - utf8String += (unsigned char)((codePoint & 0x3f) | 0x80); - } - - return utf8String; - } - - static unsigned int CodePointFromSingleUTF8String(const string& utf8String) - { - switch(utf8String.length()) { - case 1: - return (unsigned int)utf8String[0]; - case 2: - return (((unsigned char)utf8String[0] << 6) & 0x7ff) + ((unsigned char)utf8String[1] & 0x3f); - case 3: - return (((unsigned char)utf8String[0] << 12) & 0xffff) + (((unsigned char)utf8String[1] << 6) & 0xfff) + ((unsigned char)utf8String[2] & 0x3f); - case 4: - return (((unsigned char)utf8String[0] << 18) & 0x1fffff) + (((unsigned char)utf8String[1] << 12) & 0x3ffff) + (((unsigned char)utf8String[2] << 6) & 0xfff) + ((unsigned char)utf8String[3] & 0x3f); - } - - return 0; - } - }; - - class OVUTF8 { - public: - static const string FromUTF16(const wstring& utf16String) - { - return OVUTF8Helper::StringFromUTF16WideString(utf16String); - } - }; - - class OVUTF16 { - public: - static const wstring FromUTF8(const string& utf8String) - { - return OVUTF8Helper::ConvertStringToUTF16WideString(utf8String); - } - }; -} - -#endif diff --git a/Source/Engine/OpenVanilla/OVWildcard.h b/Source/Engine/OpenVanilla/OVWildcard.h deleted file mode 100644 index 6a7906ce13d9e4a5d913d7f7d2ed90fa6c805530..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OVWildcard.h +++ /dev/null @@ -1,248 +0,0 @@ -// -// OVWildcard.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OVWildcard_h -#define OVWildcard_h - -#include -#include -#include -#include - -namespace OpenVanilla { - using namespace std; - - class OVWildcard { - public: - OVWildcard(const string& expression, char matchOneChar = '?', char matchZeroOrMoreChar = '*', bool matchEndOfLine = true, bool caseSensitive = false) - : m_caseSensitive(caseSensitive) - , m_expression(expression) - , m_matchEndOfLine(matchEndOfLine) - , m_matchOneChar(matchOneChar) - , m_matchZeroOrMoreChar(matchZeroOrMoreChar) - { - size_t index; - for (index = 0; index < expression.length(); index++) { - if (expression[index] == matchOneChar || expression[index] == matchZeroOrMoreChar) break; - } - - m_longestHeadMatchString = expression.substr(0, index); - - for (string::size_type i = 0; i < expression.length(); i++) { - char c = expression[i]; - if (c == matchOneChar) { - m_states.push_back(State(AnyOne, 0)); - } - else if (c == matchZeroOrMoreChar) { - char nextChar = 0; - string::size_type j; - for (j = i + 1; j < expression.length(); j++) { - char k = expression[j]; - if (k != matchZeroOrMoreChar) { - if (k == matchOneChar) k = -1; - - nextChar = k; - break; - } - } - - i = j; - m_states.push_back(State(AnyUntil, nextChar)); - } - else { - m_states.push_back(State(Exact, c)); - } - } - } - - bool match(const string& target, size_t fromState = 0) const - { - string::size_type i = 0, slength = target.length(); - vector::size_type j, vlength = m_states.size(); - - for (j = fromState; j < vlength; j++) { - State state = m_states[j]; - Directive d = state.first; - int k = state.second; - - if (i >= slength) { - if (d == AnyUntil && !k) return true; - return false; - } - - switch (d) { - case Exact: - if (!equalChars(target[i], k)) return false; - i++; - break; - - case AnyOne: - i++; - break; - - case AnyUntil: - if (k == -1) { - // means *?, equals ?, so just advance one character - i++; - } - else if (k == 0) { - // until end, always true - return true; - } - else { - bool found = false; - string::size_type backIndex; - - for (backIndex = slength - 1; backIndex >= i; backIndex--) { - if (equalChars(target[backIndex], k)) { - string substring = target.substr(backIndex + 1, slength - (backIndex + 1)); - - if (match(substring, j + 1)) { - found = true; - i = backIndex + 1; - break; - } - } - - if (!backIndex) - break; - } - - if (!found) - return false; - } - - break; - } - } - - if (m_matchEndOfLine && i != slength) - return false; - - return true; - } - - const string longestHeadMatchString() const - { - return m_longestHeadMatchString; - } - - const string expression() const - { - return m_expression; - } - - bool isCaseSensitive() const - { - return m_caseSensitive; - } - - char matchOneChar() const - { - return m_matchOneChar; - } - - char matchZeroOrMoreChar() const - { - return m_matchZeroOrMoreChar; - } - - friend ostream& operator<<(ostream& stream, const OVWildcard& wildcard); - - protected: - enum Directive { - Exact, - AnyOne, - AnyUntil - }; - - typedef pair State; - - bool equalChars(char a, char b) const - { - if (m_caseSensitive) - return a == b; - else - return tolower(a) == tolower(b); - } - - bool m_caseSensitive; - bool m_matchEndOfLine; - char m_matchOneChar; - char m_matchZeroOrMoreChar; - vector m_states; - - string m_expression; - string m_longestHeadMatchString; - - public: - static const bool Match(const string& text, const string& expression, char matchOneChar = '?', char matchZeroOrMoreChar = '*', bool matchEndOfLine = true, bool caseSensitive = false) - { - OVWildcard exp(expression, matchOneChar, matchZeroOrMoreChar, matchEndOfLine, caseSensitive); - return exp.match(text); - } - - static const vector WildcardsFromStrings(const vector& expressions, char matchOneChar = '?', char matchZeroOrMoreChar = '*', bool matchEndOfLine = true, bool caseSensitive = false) - { - vector result; - vector::const_iterator iter = expressions.begin(); - for ( ; iter != expressions.end(); iter++) - result.push_back(OVWildcard(*iter, matchOneChar, matchZeroOrMoreChar, matchEndOfLine, caseSensitive)); - - return result; - } - - static bool MultiWildcardMatchAny(const string& target, const vector& expressions, char matchOneChar = '?', char matchZeroOrMoreChar = '*', bool matchEndOfLine = true, bool caseSensitive = false) - { - return MultiWildcardMatchAny(target, WildcardsFromStrings(expressions, matchOneChar, matchZeroOrMoreChar, matchEndOfLine, caseSensitive)); - } - - static bool MultiWildcardMatchAny(const string& target, const vector& expressions) - { - vector::const_iterator iter = expressions.begin(); - for ( ; iter != expressions.end(); iter++) { - if ((*iter).match(target)) - return true; - } - - return false; - } - }; - - inline ostream& operator<<(ostream& stream, const OVWildcard& wildcard) - { - vector::size_type i, size = wildcard.m_states.size(); - for (i = 0; i < size; i++) { - const OVWildcard::State& state = wildcard.m_states[i]; - stream << "State " << i << ": " << state.first << ", " << state.second << endl; - } - - return stream; - } -} - -#endif diff --git a/Source/Engine/OpenVanilla/OpenVanilla.h b/Source/Engine/OpenVanilla/OpenVanilla.h deleted file mode 100644 index c78271fd5afe7534fb72d150d8113ed2fa93ac40..0000000000000000000000000000000000000000 --- a/Source/Engine/OpenVanilla/OpenVanilla.h +++ /dev/null @@ -1,97 +0,0 @@ -// -// OpenVanilla.h -// -// Copyright (c) 2007-2010 Lukhnos D. Liu -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#ifndef OpenVanilla_h -#define OpenVanilla_h - -#if defined(__APPLE__) - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - - #ifdef OV_USE_SQLITE - #include - #include - #endif -#else - #ifdef WIN32 - #include - #endif - - #include "OVAroundFilter.h" - #include "OVBase.h" - #include "OVBenchmark.h" - #include "OVCandidateService.h" - #include "OVCINDataTable.h" - #include "OVCINDatabaseService.h" - #include "OVDatabaseService.h" - #include "OVDateTimeHelper.h" - #include "OVEventHandlingContext.h" - #include "OVFileHelper.h" - #include "OVFrameworkInfo.h" - #include "OVInputMethod.h" - #include "OVLocalization.h" - #include "OVKey.h" - #include "OVKeyValueMap.h" - #include "OVLoaderService.h" - #include "OVModule.h" - #include "OVModulePackage.h" - #include "OVOutputFilter.h" - #include "OVPathInfo.h" - #include "OVStringHelper.h" - #include "OVTextBuffer.h" - #include "OVUTF8Helper.h" - #include "OVWildcard.h" - - #ifdef OV_USE_SQLITE - #include "OVSQLiteDatabaseService.h" - #include "OVSQLiteWrapper.h" - #endif -#endif - -#endif diff --git a/Source/McBopomofo-Bridging-Header.h b/Source/Headers/vChewing-Bridging-Header.h similarity index 60% rename from Source/McBopomofo-Bridging-Header.h rename to Source/Headers/vChewing-Bridging-Header.h index 1b2cb5d6d09fe5019d2f930632eaa15b4e51aedc..368a0cb2d76ae760f18b63dbe82947839049755b 100644 --- a/Source/McBopomofo-Bridging-Header.h +++ b/Source/Headers/vChewing-Bridging-Header.h @@ -2,3 +2,7 @@ // Use this file to import your target's public headers that you would like to expose to Swift. // +@import Foundation; + +#import "KeyHandler.h" +#import "mgrLangModel.h" diff --git a/Source/McBopomofo-Prefix.pch b/Source/Headers/vChewing-Prefix.pch similarity index 38% rename from Source/McBopomofo-Prefix.pch rename to Source/Headers/vChewing-Prefix.pch index ca6fec9581231d46c165d1bbc8cedaf412b06c53..fe236fd9618146f6c61bdca2274fc9bb43535e62 100644 --- a/Source/McBopomofo-Prefix.pch +++ b/Source/Headers/vChewing-Prefix.pch @@ -1,5 +1,5 @@ // -// Prefix header for all source files of the 'McBopomofo' target in the 'McBopomofo' project +// Prefix header for all source files of the 'vChewing' target in the 'vChewing' project // #ifdef __OBJC__ diff --git a/Source/Images/Bopomofo.tiff b/Source/Images/Bopomofo.tiff deleted file mode 100644 index a1c29ed1e1980c6ecab09eed3f39456c9eba20e0..0000000000000000000000000000000000000000 Binary files a/Source/Images/Bopomofo.tiff and /dev/null differ diff --git a/Source/Images/Bopomofo@2x.tiff b/Source/Images/Bopomofo@2x.tiff deleted file mode 100644 index 61adceebc6394eed7d637f150c81fa2a7de72f49..0000000000000000000000000000000000000000 Binary files a/Source/Images/Bopomofo@2x.tiff and /dev/null differ diff --git a/Source/Images/Images.xcassets/AlertIcon.imageset/128X128.png b/Source/Images/Images.xcassets/AlertIcon.imageset/128X128.png deleted file mode 100644 index 1a599df979101d94f100c41c0ad1362746ec28a1..0000000000000000000000000000000000000000 Binary files a/Source/Images/Images.xcassets/AlertIcon.imageset/128X128.png and /dev/null differ diff --git a/Source/Images/Images.xcassets/AlertIcon.imageset/192x192.png b/Source/Images/Images.xcassets/AlertIcon.imageset/192x192.png deleted file mode 100644 index 33fa764a86ba61ad3a4398ed0d8a67edddcdca1c..0000000000000000000000000000000000000000 Binary files a/Source/Images/Images.xcassets/AlertIcon.imageset/192x192.png and /dev/null differ diff --git a/Source/Images/Images.xcassets/AlertIcon.imageset/64X64.png b/Source/Images/Images.xcassets/AlertIcon.imageset/64X64.png deleted file mode 100644 index 2b3d950bfee38959be3b8aa7a30729fa66d575a9..0000000000000000000000000000000000000000 Binary files a/Source/Images/Images.xcassets/AlertIcon.imageset/64X64.png and /dev/null differ diff --git a/Source/Images/Images.xcassets/AppIcon.appiconset/1024X1024.png b/Source/Images/Images.xcassets/AppIcon.appiconset/1024X1024.png deleted file mode 100644 index cffcacb296d4b557db27400204768bd0c99dd380..0000000000000000000000000000000000000000 Binary files a/Source/Images/Images.xcassets/AppIcon.appiconset/1024X1024.png and /dev/null differ diff --git a/Source/Images/Images.xcassets/AppIcon.appiconset/128X128.png b/Source/Images/Images.xcassets/AppIcon.appiconset/128X128.png deleted file mode 100644 index 1a599df979101d94f100c41c0ad1362746ec28a1..0000000000000000000000000000000000000000 Binary files a/Source/Images/Images.xcassets/AppIcon.appiconset/128X128.png and /dev/null differ diff --git a/Source/Images/Images.xcassets/AppIcon.appiconset/16X16.png b/Source/Images/Images.xcassets/AppIcon.appiconset/16X16.png deleted file mode 100644 index 58e99c3bea56acde722af5774ad421a464756125..0000000000000000000000000000000000000000 Binary files a/Source/Images/Images.xcassets/AppIcon.appiconset/16X16.png and /dev/null differ diff --git a/Source/Images/Images.xcassets/AppIcon.appiconset/256X256.png b/Source/Images/Images.xcassets/AppIcon.appiconset/256X256.png deleted file mode 100644 index 77503fcd2e8b4f5ad22f3d36ac844b3a41f52d90..0000000000000000000000000000000000000000 Binary files a/Source/Images/Images.xcassets/AppIcon.appiconset/256X256.png and /dev/null differ diff --git a/Source/Images/Images.xcassets/AppIcon.appiconset/32X32.png b/Source/Images/Images.xcassets/AppIcon.appiconset/32X32.png deleted file mode 100644 index 157177af26dc7fd6965e0af032d9b6b0c9073022..0000000000000000000000000000000000000000 Binary files a/Source/Images/Images.xcassets/AppIcon.appiconset/32X32.png and /dev/null differ diff --git a/Source/Images/Images.xcassets/AppIcon.appiconset/512X512.png b/Source/Images/Images.xcassets/AppIcon.appiconset/512X512.png deleted file mode 100644 index 350731f867784febe1f9f7b8bbc4ac57ed75ec6b..0000000000000000000000000000000000000000 Binary files a/Source/Images/Images.xcassets/AppIcon.appiconset/512X512.png and /dev/null differ diff --git a/Source/Images/Images.xcassets/AppIcon.appiconset/64X64.png b/Source/Images/Images.xcassets/AppIcon.appiconset/64X64.png deleted file mode 100644 index 2b3d950bfee38959be3b8aa7a30729fa66d575a9..0000000000000000000000000000000000000000 Binary files a/Source/Images/Images.xcassets/AppIcon.appiconset/64X64.png and /dev/null differ diff --git a/Source/Images/PlainBopomofo.tiff b/Source/Images/PlainBopomofo.tiff deleted file mode 100644 index 2aee9334b9ca69115810f7dd4dcb99b9e5efe879..0000000000000000000000000000000000000000 Binary files a/Source/Images/PlainBopomofo.tiff and /dev/null differ diff --git a/Source/Images/PlainBopomofo@2x.tiff b/Source/Images/PlainBopomofo@2x.tiff deleted file mode 100644 index af559d636b88242db3064aa4ed26ebbeea70bbbf..0000000000000000000000000000000000000000 Binary files a/Source/Images/PlainBopomofo@2x.tiff and /dev/null differ diff --git a/Source/InputMethodController.h b/Source/InputMethodController.h deleted file mode 100644 index 8741cbedbf9bf82ee1713eef790291ac04ad504c..0000000000000000000000000000000000000000 --- a/Source/InputMethodController.h +++ /dev/null @@ -1,78 +0,0 @@ -// -// InputMethodController.h -// -// Copyright (c) 2011 The McBopomofo Project. -// -// Contributors: -// Mengjuei Hsieh (@mjhsieh) -// Weizhong Yang (@zonble) -// -// Based on the Syrup Project and the Formosana Library -// by Lukhnos Liu (@lukhnos). -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import -#import -#import "Mandarin.h" -#import "Gramambular.h" -#import "FastLM.h" - -@interface McBopomofoInputMethodController : IMKInputController -{ -@private - // the reading buffer that takes user input - Formosa::Mandarin::BopomofoReadingBuffer* _bpmfReadingBuffer; - - // language model - Formosa::Gramambular::FastLM *_languageModel; - - // the grid (lattice) builder for the unigrams (and bigrams) - Formosa::Gramambular::BlockReadingBuilder* _builder; - - // latest walked path (trellis) using the Viterbi algorithm - std::vector _walkedNodes; - - // the latest composing buffer that is updated to the foreground app - NSMutableString *_composingBuffer; - NSInteger _latestReadingCursor; - - // the current text input client; we need to keep this when candidate panel is on - id _currentCandidateClient; - - // a special deferred client for Terminal.app fix - id _currentDeferredClient; - - // currently available candidates - NSMutableArray *_candidates; - - // current input mode - NSString *_inputMode; - - // if Chinese conversion is enabled - BOOL _chineseConversionEnabled; -} -@end - -// the shared language model object -extern "C" void LTLoadLanguageModel(); diff --git a/Source/InputMethodController.mm b/Source/InputMethodController.mm deleted file mode 100644 index 9dec8a06b8d19d5cb825d59173e48a1102995f1c..0000000000000000000000000000000000000000 --- a/Source/InputMethodController.mm +++ /dev/null @@ -1,1589 +0,0 @@ -// -// InputMethodController.m -// -// Copyright (c) 2011 The McBopomofo Project. -// -// Contributors: -// Mengjuei Hsieh (@mjhsieh) -// Weizhong Yang (@zonble) -// -// Based on the Syrup Project and the Formosana Library -// by Lukhnos Liu (@lukhnos). -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "InputMethodController.h" -#import -#import -#import -#import "OVStringHelper.h" -#import "OVUTF8Helper.h" -#import "AppDelegate.h" -#import "VTHorizontalCandidateController.h" -#import "VTVerticalCandidateController.h" -#import "McBopomofo-Swift.h" - -//@import SwiftUI; - -// C++ namespace usages -using namespace std; -using namespace Formosa::Mandarin; -using namespace Formosa::Gramambular; -using namespace OpenVanilla; - -// default, min and max candidate list text size -static const NSInteger kDefaultCandidateListTextSize = 16; -static const NSInteger kMinKeyLabelSize = 10; -static const NSInteger kMinCandidateListTextSize = 12; -static const NSInteger kMaxCandidateListTextSize = 196; - -// default, min and max composing buffer size (in codepoints) -// modern Macs can usually work up to 16 codepoints when the builder still -// walks the grid with good performance; slower Macs (like old PowerBooks) -// will start to sputter beyond 12; such is the algorithmatic complexity -// of the Viterbi algorithm used in the builder library (at O(N^2)) -static const NSInteger kDefaultComposingBufferSize = 10; -static const NSInteger kMinComposingBufferSize = 4; -static const NSInteger kMaxComposingBufferSize = 20; - -// user defaults (app perferences) key names; in this project we use -// NSUserDefaults throughout and do not wrap them in another config object -static NSString *const kKeyboardLayoutPreferenceKey = @"KeyboardLayout"; -static NSString *const kBasisKeyboardLayoutPreferenceKey = @"BasisKeyboardLayout"; // alphanumeric ("ASCII") input basis -static NSString *const kFunctionKeyKeyboardLayoutPreferenceKey = @"FunctionKeyKeyboardLayout"; // alphanumeric ("ASCII") input basis -static NSString *const kFunctionKeyKeyboardLayoutOverrideIncludeShiftKey = @"FunctionKeyKeyboardLayoutOverrideIncludeShift"; // whether include shift -static NSString *const kCandidateListTextSizeKey = @"CandidateListTextSize"; -static NSString *const kSelectPhraseAfterCursorAsCandidatePreferenceKey = @"SelectPhraseAfterCursorAsCandidate"; -static NSString *const kUseHorizontalCandidateListPreferenceKey = @"UseHorizontalCandidateList"; -static NSString *const kComposingBufferSizePreferenceKey = @"ComposingBufferSize"; -static NSString *const kDisableUserCandidateSelectionLearning = @"DisableUserCandidateSelectionLearning"; -static NSString *const kChooseCandidateUsingSpaceKey = @"ChooseCandidateUsingSpaceKey"; -static NSString *const kChineseConversionEnabledKey = @"ChineseConversionEnabledKey"; - -// advanced (usually optional) settings -static NSString *const kCandidateTextFontName = @"CandidateTextFontName"; -static NSString *const kCandidateKeyLabelFontName = @"CandidateKeyLabelFontName"; -static NSString *const kCandidateKeys = @"CandidateKeys"; - -// input modes -static NSString *const kBopomofoModeIdentifier = @"org.openvanilla.inputmethod.McBopomofo.Bopomofo"; -static NSString *const kPlainBopomofoModeIdentifier = @"org.openvanilla.inputmethod.McBopomofo.PlainBopomofo"; - -// key code enums -enum { - kEnterKeyCode = 76, - kUpKeyCode = 126, - kDownKeyCode = 125, - kLeftKeyCode = 123, - kRightKeyCode = 124, - kPageUpKeyCode = 116, - kPageDownKeyCode = 121, - kHomeKeyCode = 115, - kEndKeyCode = 119, - kDeleteKeyCode = 117 -}; - -// a global object for saving the "learned" user candidate selections -NSMutableDictionary *gCandidateLearningDictionary = nil; -NSString *gUserCandidatesDictionaryPath = nil; -VTCandidateController *gCurrentCandidateController = nil; - -// if DEBUG is defined, a DOT file (GraphViz format) will be written to the -// specified path everytime the grid is walked -#if DEBUG -static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot"; -#endif - -// shared language model object that stores our phrase-term probability database -FastLM gLanguageModel; -FastLM gLanguageModelPlainBopomofo; - -// https://clang-analyzer.llvm.org/faq.html -__attribute__((annotate("returns_localized_nsstring"))) -static inline NSString *LocalizationNotNeeded(NSString *s) { - return s; -} - -// private methods -@interface McBopomofoInputMethodController () -+ (VTHorizontalCandidateController *)horizontalCandidateController; -+ (VTVerticalCandidateController *)verticalCandidateController; - -- (void)collectCandidates; - -- (size_t)actualCandidateCursorIndex; -- (NSString *)neighborTrigramString; - -- (void)_performDeferredSaveUserCandidatesDictionary; -- (void)saveUserCandidatesDictionary; -- (void)_showCandidateWindowUsingVerticalMode:(BOOL)useVerticalMode client:(id)client; - -- (void)beep; -- (BOOL)handleInputText:(NSString*)inputText key:(NSInteger)keyCode modifiers:(NSUInteger)flags client:(id)client; -- (BOOL)handleCandidateEventWithInputText:(NSString *)inputText charCode:(UniChar)charCode keyCode:(NSUInteger)keyCode; -@end - -// sort helper -class NodeAnchorDescendingSorter -{ -public: - bool operator()(const NodeAnchor& a, const NodeAnchor &b) const { - return a.node->key().length() > b.node->key().length(); - } -}; - -@implementation McBopomofoInputMethodController -- (void)dealloc -{ - // clean up everything - if (_bpmfReadingBuffer) { - delete _bpmfReadingBuffer; - } - - if (_builder) { - delete _builder; - } - // the two client pointers are weak pointers (i.e. we don't retain them) - // therefore we don't do anything about it -} - -- (id)initWithServer:(IMKServer *)server delegate:(id)delegate client:(id)client -{ - // an instance is initialized whenever a text input client (a Mac app) requires - // text input from an IME - - self = [super initWithServer:server delegate:delegate client:client]; - if (self) { - _candidates = [[NSMutableArray alloc] init]; - - // create the reading buffer - _bpmfReadingBuffer = new BopomofoReadingBuffer(BopomofoKeyboardLayout::StandardLayout()); - - // create the lattice builder - _languageModel = &gLanguageModel; - _builder = new BlockReadingBuilder(_languageModel); - - // each Mandarin syllable is separated by a hyphen - _builder->setJoinSeparator("-"); - - // create the composing buffer - _composingBuffer = [[NSMutableString alloc] init]; - - // populate the settings, by default, DISABLE user candidate learning - if (![[NSUserDefaults standardUserDefaults] objectForKey:kDisableUserCandidateSelectionLearning]) { - [[NSUserDefaults standardUserDefaults] setObject:(id)kCFBooleanTrue forKey:kDisableUserCandidateSelectionLearning]; - } - - _inputMode = kBopomofoModeIdentifier; - _chineseConversionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:kChineseConversionEnabledKey]; - } - - return self; -} - -- (NSMenu *)menu -{ - // a menu instance (autoreleased) is requested every time the user click on the input menu - NSMenu *menu = [[NSMenu alloc] initWithTitle:LocalizationNotNeeded(@"Input Method Menu")]; - NSMenuItem *preferenceMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"McBopomofo Preferences", @"") action:@selector(showPreferences:) keyEquivalent:@""]; - [menu addItem:preferenceMenuItem]; - - // If Option key is pressed, show the learning-related menu - - #if DEBUG - //I think the following line is 10.6+ specific - if ([[NSEvent class] respondsToSelector:@selector(modifierFlags)] && ([NSEvent modifierFlags] & NSAlternateKeyMask)) { - - BOOL learningEnabled = ![[NSUserDefaults standardUserDefaults] boolForKey:kDisableUserCandidateSelectionLearning]; - - NSMenuItem *learnMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Enable Selection Learning", @"") action:@selector(toggleLearning:) keyEquivalent:@""]; - learnMenuItem.state = learningEnabled ? NSControlStateValueOn : NSControlStateValueOff; - [menu addItem:learnMenuItem]; - - if (learningEnabled) { - NSString *clearMenuItemTitle = [NSString stringWithFormat:NSLocalizedString(@"Clear Learning Dictionary (%ju Items)", @""), (uintmax_t)[gCandidateLearningDictionary count]]; - NSMenuItem *clearMenuItem = [[NSMenuItem alloc] initWithTitle:clearMenuItemTitle action:@selector(clearLearningDictionary:) keyEquivalent:@""]; - [menu addItem:clearMenuItem]; - - - NSMenuItem *dumpMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Dump Learning Data to Console", @"") action:@selector(dumpLearningDictionary:) keyEquivalent:@""]; - [menu addItem:dumpMenuItem]; - } - } - #endif //DEBUG - - NSMenuItem *chineseConversionMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Chinese Conversion", @"") action:@selector(toggleChineseConverter:) keyEquivalent:@"G"]; - chineseConversionMenuItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | NSEventModifierFlagControl; - chineseConversionMenuItem.state = _chineseConversionEnabled ? NSControlStateValueOn : NSControlStateValueOff; - [menu addItem:chineseConversionMenuItem]; - - NSMenuItem *updateCheckItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Check for Updates…", @"") action:@selector(checkForUpdate:) keyEquivalent:@""]; - [menu addItem:updateCheckItem]; - - NSMenuItem *aboutMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"About McBopomofo…", @"") action:@selector(showAbout:) keyEquivalent:@""]; - [menu addItem:aboutMenuItem]; - - return menu; -} - -#pragma mark - IMKStateSetting protocol methods - -- (void)activateServer:(id)client -{ - [[NSUserDefaults standardUserDefaults] synchronize]; - - // Override the keyboard layout. Use US if not set. - NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; - if (!basisKeyboardLayoutID) { - basisKeyboardLayoutID = @"com.apple.keylayout.US"; - } - [client overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID]; - - // reset the state - _currentDeferredClient = nil; - _currentCandidateClient = nil; - _builder->clear(); - _walkedNodes.clear(); - [_composingBuffer setString:@""]; - - // checks and populates the default settings - NSInteger keyboardLayout = [[NSUserDefaults standardUserDefaults] integerForKey:kKeyboardLayoutPreferenceKey]; - switch (keyboardLayout) { - case 0: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::StandardLayout()); - break; - case 1: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::ETenLayout()); - break; - case 2: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::HsuLayout()); - break; - case 3: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::ETen26Layout()); - break; - case 4: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::HanyuPinyinLayout()); - break; - case 5: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::IBMLayout()); - break; - default: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::StandardLayout()); - [[NSUserDefaults standardUserDefaults] setInteger:0 forKey:kKeyboardLayoutPreferenceKey]; - } - - // set the size - NSInteger textSize = [[NSUserDefaults standardUserDefaults] integerForKey:kCandidateListTextSizeKey]; - NSInteger previousTextSize = textSize; - if (textSize == 0) { - textSize = kDefaultCandidateListTextSize; - } - else if (textSize < kMinCandidateListTextSize) { - textSize = kMinCandidateListTextSize; - } - else if (textSize > kMaxCandidateListTextSize) { - textSize = kMaxCandidateListTextSize; - } - - if (textSize != previousTextSize) { - [[NSUserDefaults standardUserDefaults] setInteger:textSize forKey:kCandidateListTextSizeKey]; - } - if (![[NSUserDefaults standardUserDefaults] objectForKey:kChooseCandidateUsingSpaceKey]) { - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kChooseCandidateUsingSpaceKey]; - } - - [(AppDelegate *)[NSApp delegate] checkForUpdate]; -} - -- (void)deactivateServer:(id)client -{ - // clean up reading buffer residues - if (!_bpmfReadingBuffer->isEmpty()) { - _bpmfReadingBuffer->clear(); - [client setMarkedText:@"" selectionRange:NSMakeRange(0, 0) replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; - } - - // commit any residue in the composing buffer - [self commitComposition:client]; - - _currentDeferredClient = nil; - _currentCandidateClient = nil; - - gCurrentCandidateController.delegate = nil; - gCurrentCandidateController.visible = NO; - [_candidates removeAllObjects]; -} - -- (void)setValue:(id)value forTag:(long)tag client:(id)sender -{ - NSString *newInputMode; - Formosa::Gramambular::FastLM *newLanguageModel; - - if ([value isKindOfClass:[NSString class]] && [value isEqual:kPlainBopomofoModeIdentifier]) { - newInputMode = kPlainBopomofoModeIdentifier; - newLanguageModel = &gLanguageModelPlainBopomofo; - } - else { - newInputMode = kBopomofoModeIdentifier; - newLanguageModel = &gLanguageModel; - } - - // Only apply the changes if the value is changed - if (![_inputMode isEqualToString:newInputMode]) { - [[NSUserDefaults standardUserDefaults] synchronize]; - - // Remember to override the keyboard layout again -- treat this as an activate eventy - NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; - if (!basisKeyboardLayoutID) { - basisKeyboardLayoutID = @"com.apple.keylayout.US"; - } - [sender overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID]; - - _inputMode = newInputMode; - _languageModel = newLanguageModel; - - if (!_bpmfReadingBuffer->isEmpty()) { - _bpmfReadingBuffer->clear(); - [self updateClientComposingBuffer:sender]; - } - - if ([_composingBuffer length] > 0) { - [self commitComposition:sender]; - } - - if (_builder) { - delete _builder; - _builder = new BlockReadingBuilder(_languageModel); - _builder->setJoinSeparator("-"); - } - } -} - -#pragma mark - IMKServerInput protocol methods - -- (void)commitComposition:(id)client -{ - // if it's Terminal, we don't commit at the first call (the client of which will not be IPMDServerClientWrapper) - // then we defer the update in the next runloop round -- so that the composing buffer is not - // meaninglessly flushed, an annoying bug in Terminal.app since Mac OS X 10.5 - if ([[client bundleIdentifier] isEqualToString:@"com.apple.Terminal"] && ![NSStringFromClass([client class]) isEqualToString:@"IPMDServerClientWrapper"]) - { - if (_currentDeferredClient) { - [self performSelector:@selector(updateClientComposingBuffer:) withObject:_currentDeferredClient afterDelay:0.0]; - } - return; - } - - // Chinese conversion. - NSString *buffer = _composingBuffer; - if (_chineseConversionEnabled) { - buffer = [OpenCCBridge convert:_composingBuffer]; - } - - // commit the text, clear the state - [client insertText:buffer replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; - _builder->clear(); - _walkedNodes.clear(); - [_composingBuffer setString:@""]; - gCurrentCandidateController.visible = NO; - [_candidates removeAllObjects]; -} - -// TODO: bug #28 is more likely to live in this method. -- (void)updateClientComposingBuffer:(id)client -{ - // "updating the composing buffer" means to request the client to "refresh" the text input buffer - // with our "composing text" - - [_composingBuffer setString:@""]; - NSInteger composedStringCursorIndex = 0; - - size_t readingCursorIndex = 0; - size_t builderCursorIndex = _builder->cursorIndex(); - - // we must do some Unicode codepoint counting to find the actual cursor location for the client - // i.e. we need to take UTF-16 into consideration, for which a surrogate pair takes 2 UniChars - // locations - for (vector::iterator wi = _walkedNodes.begin(), we = _walkedNodes.end() ; wi != we ; ++wi) { - if ((*wi).node) { - string nodeStr = (*wi).node->currentKeyValue().value; - vector codepoints = OVUTF8Helper::SplitStringByCodePoint(nodeStr); - size_t codepointCount = codepoints.size(); - - NSString *valueString = [NSString stringWithUTF8String:nodeStr.c_str()]; - [_composingBuffer appendString:valueString]; - - // this re-aligns the cursor index in the composed string - // (the actual cursor on the screen) with the builder's logical - // cursor (reading) cursor; each built node has a "spanning length" - // (e.g. two reading blocks has a spanning length of 2), and we - // accumulate those lengthes to calculate the displayed cursor - // index - size_t spanningLength = (*wi).spanningLength; - if (readingCursorIndex + spanningLength <= builderCursorIndex) { - composedStringCursorIndex += [valueString length]; - readingCursorIndex += spanningLength; - } - else { - for (size_t i = 0; i < codepointCount && readingCursorIndex < builderCursorIndex; i++) { - composedStringCursorIndex += [[NSString stringWithUTF8String:codepoints[i].c_str()] length]; - readingCursorIndex++; - } - } - } - } - - // now we gather all the info, we separate the composing buffer to two parts, head and tail, - // and insert the reading text (the Mandarin syllable) in between them; - // the reading text is what the user is typing - NSString *head = [_composingBuffer substringToIndex:composedStringCursorIndex]; - NSString *reading = [NSString stringWithUTF8String:_bpmfReadingBuffer->composedString().c_str()]; - NSString *tail = [_composingBuffer substringFromIndex:composedStringCursorIndex]; - NSString *composedText = [head stringByAppendingString:[reading stringByAppendingString:tail]]; - NSInteger cursorIndex = composedStringCursorIndex + [reading length]; - - // we must use NSAttributedString so that the cursor is visible -- - // can't just use NSString - NSDictionary *attrDict = @{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle), - NSMarkedClauseSegmentAttributeName: @0}; - NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:composedText attributes:attrDict]; - - // the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound, - // i.e. the client app needs to take care of where to put ths composing buffer - [client setMarkedText:attrString selectionRange:NSMakeRange(cursorIndex, 0) replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; - - _latestReadingCursor = cursorIndex; -} - -- (void)walk -{ - // retrieve the most likely trellis, i.e. a Maximum Likelihood Estimation - // of the best possible Mandarain characters given the input syllables, - // using the Viterbi algorithm implemented in the Gramambular library - Walker walker(&_builder->grid()); - - // the reverse walk traces the trellis from the end - _walkedNodes = walker.reverseWalk(_builder->grid().width()); - - // then we reverse the nodes so that we get the forward-walked nodes - reverse(_walkedNodes.begin(), _walkedNodes.end()); - - // if DEBUG is defined, a GraphViz file is written to kGraphVizOutputfile - #if DEBUG - string dotDump = _builder->grid().dumpDOT(); - NSString *dotStr = [NSString stringWithUTF8String:dotDump.c_str()]; - NSError *error = nil; - - BOOL __unused success = [dotStr writeToFile:kGraphVizOutputfile atomically:YES encoding:NSUTF8StringEncoding error:&error]; - #endif -} - -- (void)popOverflowComposingTextAndWalk:(id)client -{ - // in an ideal world, we can as well let the user type forever, - // but because the Viterbi algorithm has a complexity of O(N^2), - // the walk will become slower as the number of nodes increase, - // therefore we need to "pop out" overflown text -- they usually - // lose their influence over the whole MLE anyway -- so tht when - // the user type along, the already composed text at front will - // be popped out - - NSInteger _composingBufferSize = [[NSUserDefaults standardUserDefaults] integerForKey:kComposingBufferSizePreferenceKey]; - NSInteger previousComposingBufferSize = _composingBufferSize; - - if (_composingBufferSize == 0) { - _composingBufferSize = kDefaultComposingBufferSize; - } - else if (_composingBufferSize < kMinComposingBufferSize) { - _composingBufferSize = kMinComposingBufferSize; - } - else if (_composingBufferSize > kMaxComposingBufferSize) { - _composingBufferSize = kMaxComposingBufferSize; - } - - if (_composingBufferSize != previousComposingBufferSize) { - [[NSUserDefaults standardUserDefaults] setInteger:_composingBufferSize forKey:kComposingBufferSizePreferenceKey]; - } - - if (_builder->grid().width() > (size_t)_composingBufferSize) { - if (_walkedNodes.size() > 0) { - NodeAnchor &anchor = _walkedNodes[0]; - NSString *popedText = [NSString stringWithUTF8String:anchor.node->currentKeyValue().value.c_str()]; - // Chinese conversion. - if (_chineseConversionEnabled) { - popedText = [OpenCCBridge convert:popedText]; - } - [client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; - _builder->removeHeadReadings(anchor.spanningLength); - } - } - - [self walk]; -} - -- (void)beep -{ - // use the system's default sound (configurable in System Preferences) to give a warning - NSBeep(); -} - -- (string)currentLayout -{ - string layout = string("Standard_");; - NSInteger keyboardLayout = [[NSUserDefaults standardUserDefaults] integerForKey:kKeyboardLayoutPreferenceKey]; - switch (keyboardLayout) { - case 0: - layout = string("Standard_"); - break; - case 1: - layout = string("ETen_"); - break; - case 2: - layout = string("ETen26_"); - break; - case 3: - layout = string("Hsu_"); - break; - case 4: - layout = string("HanyuPinyin_"); - break; - case 5: - layout = string("IBM_"); - break; - default: - break; - } - return layout; -} - -- (BOOL)handleInputText:(NSString*)inputText key:(NSInteger)keyCode modifiers:(NSUInteger)flags client:(id)client -{ - NSRect textFrame = NSZeroRect; - NSDictionary *attributes = nil; - - bool composeReading = false; - BOOL useVerticalMode = NO; - - @try { - attributes = [client attributesForCharacterIndex:0 lineHeightRectangle:&textFrame]; - useVerticalMode = [attributes objectForKey:@"IMKTextOrientation"] && [[attributes objectForKey:@"IMKTextOrientation"] integerValue] == 0; - } - @catch (NSException *e) { - // exception may raise while using Twitter.app's search filed. - } - - NSInteger cursorForwardKey = useVerticalMode ? kDownKeyCode : kRightKeyCode; - NSInteger cursorBackwardKey = useVerticalMode ? kUpKeyCode : kLeftKeyCode; - NSInteger extraChooseCandidateKey = useVerticalMode ? kLeftKeyCode : kDownKeyCode; - NSInteger absorbedArrowKey = useVerticalMode ? kRightKeyCode : kUpKeyCode; - NSInteger verticalModeOnlyChooseCandidateKey = useVerticalMode ? absorbedArrowKey : 0; - - // get the unicode character code - UniChar charCode = [inputText length] ? [inputText characterAtIndex:0] : 0; - - if ([[client bundleIdentifier] isEqualToString:@"com.apple.Terminal"] && [NSStringFromClass([client class]) isEqualToString:@"IPMDServerClientWrapper"]) { - // special handling for com.apple.Terminal - _currentDeferredClient = client; - } - - // if the inputText is empty, it's a function key combination, we ignore it - if (![inputText length]) { - return NO; - } - - // if the composing buffer is empty and there's no reading, and there is some function key combination, we ignore it - if (![_composingBuffer length] && _bpmfReadingBuffer->isEmpty() && ((flags & NSCommandKeyMask) || (flags & NSControlKeyMask) || (flags & NSAlternateKeyMask) || (flags & NSNumericPadKeyMask))) { - return NO; - } - - - // Caps Lock processing : if Caps Lock is on, temporarily disable bopomofo. - if (charCode == 8 || charCode == 13 || keyCode == absorbedArrowKey || keyCode == extraChooseCandidateKey || keyCode == cursorForwardKey || keyCode == cursorBackwardKey) { - // do nothing if backspace is pressed -- we ignore the key - } - else if (flags & NSAlphaShiftKeyMask) { - // process all possible combination, we hope. - if ([_composingBuffer length]) { - [self commitComposition:client]; - } - - // first commit everything in the buffer. - if (flags & NSShiftKeyMask) { - return NO; - } - - // if ASCII but not printable, don't use insertText:replacementRange: as many apps don't handle non-ASCII char insertions. - if (charCode < 0x80 && !isprint(charCode)) { - return NO; - } - - // when shift is pressed, don't do further processing, since it outputs capital letter anyway. - NSString *popedText = [inputText lowercaseString]; - [client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; - return YES; - } - - if (flags & NSNumericPadKeyMask) { - if (keyCode != kLeftKeyCode && keyCode != kRightKeyCode && keyCode != kDownKeyCode && keyCode != kUpKeyCode && charCode != 32 && isprint(charCode)) { - if ([_composingBuffer length]) { - [self commitComposition:client]; - } - - NSString *popedText = [inputText lowercaseString]; - [client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; - return YES; - } - } - - // if we have candidate, it means we need to pass the event to the candidate handler - if ([_candidates count]) { - return [self handleCandidateEventWithInputText:inputText charCode:charCode keyCode:keyCode]; - } - - // see if it's valid BPMF reading - if (_bpmfReadingBuffer->isValidKey((char)charCode)) { - _bpmfReadingBuffer->combineKey((char)charCode); - - // if we have a tone marker, we have to insert the reading to the builder - // in other words, if we don't have a tone marker, we just update the composing buffer - composeReading = _bpmfReadingBuffer->hasToneMarker(); - if (!composeReading) { - [self updateClientComposingBuffer:client]; - return YES; - } - } - - // see if we have composition if Enter/Space is hit and buffer is not empty - // this is bit-OR'ed so that the tone marker key is also taken into account - composeReading |= (!_bpmfReadingBuffer->isEmpty() && (charCode == 32 || charCode == 13)); - if (composeReading) { - // combine the reading - string reading = _bpmfReadingBuffer->syllable().composedString(); - - // see if we have a unigram for this - if (!_languageModel->hasUnigramsForKey(reading)) { - [self beep]; - [self updateClientComposingBuffer:client]; - return YES; - } - - // and insert it into the lattice - _builder->insertReadingAtCursor(reading); - - // then walk the lattice - [self popOverflowComposingTextAndWalk:client]; - - // see if we need to override the selection if a learned one exists - if (![[NSUserDefaults standardUserDefaults] boolForKey:kDisableUserCandidateSelectionLearning]) { - NSString *trigram = [self neighborTrigramString]; - - // Lookup from the user dict to see if the trigram fit or not - NSString *overrideCandidateString = [gCandidateLearningDictionary objectForKey:trigram]; - if (overrideCandidateString) { - [self candidateSelected:(NSAttributedString *)overrideCandidateString]; - } - } - - // then update the text - _bpmfReadingBuffer->clear(); - [self updateClientComposingBuffer:client]; - - if (_inputMode == kPlainBopomofoModeIdentifier) { - [self _showCandidateWindowUsingVerticalMode:useVerticalMode client:client]; - } - - // and tells the client that the key is consumed - return YES; - } - - // keyCode 125 = Down, charCode 32 = Space - if (_bpmfReadingBuffer->isEmpty() && [_composingBuffer length] > 0 && (keyCode == extraChooseCandidateKey || charCode == 32 || (useVerticalMode && (keyCode == verticalModeOnlyChooseCandidateKey)))) { - if (charCode == 32) { - // if the spacebar is NOT set to be a selection key - if (![[NSUserDefaults standardUserDefaults] boolForKey:kChooseCandidateUsingSpaceKey]) { - if (_builder->cursorIndex() >= _builder->length()) { - [_composingBuffer appendString:@" "]; - [self commitComposition:client]; - _bpmfReadingBuffer->clear(); - } - else if (_languageModel->hasUnigramsForKey(" ")) { - _builder->insertReadingAtCursor(" "); - [self popOverflowComposingTextAndWalk:client]; - [self updateClientComposingBuffer:client]; - } - return YES; - - } - } - [self _showCandidateWindowUsingVerticalMode:useVerticalMode client:client]; - return YES; - } - - // Esc - if (charCode == 27) { - // if reading is not empty, we cancel the reading; Apple's built-in Zhuyin (and the erstwhile Hanin) has a default option that Esc "cancels" the current composed character and revert it to Bopomofo reading, in odds with the expectation of users from other platforms - - if (_bpmfReadingBuffer->isEmpty()) { - // no nee to beep since the event is deliberately triggered by user - - if (![_composingBuffer length]) { - return NO; - } - } - else { - _bpmfReadingBuffer->clear(); - } - - [self updateClientComposingBuffer:client]; - return YES; - } - - // handle cursor backward - if (keyCode == cursorBackwardKey) { - if (!_bpmfReadingBuffer->isEmpty()) { - [self beep]; - } - else { - if (![_composingBuffer length]) { - return NO; - } - - if (_builder->cursorIndex() > 0) { - _builder->setCursorIndex(_builder->cursorIndex() - 1); - } - else { - [self beep]; - } - } - - [self updateClientComposingBuffer:client]; - return YES; - } - - // handle cursor forward - if (keyCode == cursorForwardKey) { - if (!_bpmfReadingBuffer->isEmpty()) { - [self beep]; - } - else { - if (![_composingBuffer length]) { - return NO; - } - - if (_builder->cursorIndex() < _builder->length()) { - _builder->setCursorIndex(_builder->cursorIndex() + 1); - } - else { - [self beep]; - } - } - - [self updateClientComposingBuffer:client]; - return YES; - } - - if (keyCode == kHomeKeyCode) { - if (!_bpmfReadingBuffer->isEmpty()) { - [self beep]; - } - else { - if (![_composingBuffer length]) { - return NO; - } - - if (_builder->cursorIndex()) { - _builder->setCursorIndex(0); - } - else { - [self beep]; - } - } - - [self updateClientComposingBuffer:client]; - return YES; - } - - if (keyCode == kEndKeyCode) { - if (!_bpmfReadingBuffer->isEmpty()) { - [self beep]; - } - else { - if (![_composingBuffer length]) { - return NO; - } - - if (_builder->cursorIndex() != _builder->length()) { - _builder->setCursorIndex(_builder->length()); - } - else { - [self beep]; - } - } - - [self updateClientComposingBuffer:client]; - return YES; - } - - if (keyCode == absorbedArrowKey || keyCode == extraChooseCandidateKey) { - if (!_bpmfReadingBuffer->isEmpty()) { - [self beep]; - } - [self updateClientComposingBuffer:client]; - return YES; - } - - // Backspace - if (charCode == 8) { - if (_bpmfReadingBuffer->isEmpty()) { - if (![_composingBuffer length]) { - return NO; - } - - if (_builder->cursorIndex()) { - _builder->deleteReadingBeforeCursor(); - [self walk]; - } - else { - [self beep]; - } - } - else { - _bpmfReadingBuffer->backspace(); - } - - [self updateClientComposingBuffer:client]; - return YES; - } - - // Delete - if (keyCode == kDeleteKeyCode) { - if (_bpmfReadingBuffer->isEmpty()) { - if (![_composingBuffer length]) { - return NO; - } - - if (_builder->cursorIndex() != _builder->length()) { - _builder->deleteReadingAfterCursor(); - [self walk]; - } - else { - [self beep]; - } - } - else { - [self beep]; - } - - [self updateClientComposingBuffer:client]; - return YES; - } - - - // Enter - if (charCode == 13) { - if (![_composingBuffer length]) { - return NO; - } - - [self commitComposition:client]; - return YES; - } - - // punctuation list - if ((char)charCode == '`') { - if (_languageModel->hasUnigramsForKey(string("_punctuation_list"))) { - if (_bpmfReadingBuffer->isEmpty()) { - _builder->insertReadingAtCursor(string("_punctuation_list")); - [self popOverflowComposingTextAndWalk:client]; - [self _showCandidateWindowUsingVerticalMode:useVerticalMode client:client]; - } - else { // If there is still unfinished bpmf reading, ignore the punctuation - [self beep]; - } - [self updateClientComposingBuffer:client]; - return YES; - } - } - - string layout = [self currentLayout]; - string customPunctuation = string("_punctuation_") + layout + string(1, (char)charCode); - if (_languageModel->hasUnigramsForKey(customPunctuation)) { - if (_bpmfReadingBuffer->isEmpty()) { - _builder->insertReadingAtCursor(customPunctuation); - [self popOverflowComposingTextAndWalk:client]; - } - else { // If there is still unfinished bpmf reading, ignore the punctuation - [self beep]; - } - [self updateClientComposingBuffer:client]; - - if (_inputMode == kPlainBopomofoModeIdentifier && _bpmfReadingBuffer->isEmpty()) { - [self collectCandidates]; - if ([_candidates count] == 1) { - [self commitComposition:client]; - } - else { - [self _showCandidateWindowUsingVerticalMode:useVerticalMode client:client]; - } - } - - return YES; - } - - // if nothing is matched, see if it's a punctuation key - string punctuation = string("_punctuation_") + string(1, (char)charCode); - if (_languageModel->hasUnigramsForKey(punctuation)) { - if (_bpmfReadingBuffer->isEmpty()) { - _builder->insertReadingAtCursor(punctuation); - [self popOverflowComposingTextAndWalk:client]; - } - else { // If there is still unfinished bpmf reading, ignore the punctuation - [self beep]; - } - [self updateClientComposingBuffer:client]; - - if (_inputMode == kPlainBopomofoModeIdentifier && _bpmfReadingBuffer->isEmpty()) { - [self collectCandidates]; - if ([_candidates count] == 1) { - [self commitComposition:client]; - } - else { - [self _showCandidateWindowUsingVerticalMode:useVerticalMode client:client]; - } - } - - return YES; - } - - // still nothing, then we update the composing buffer (some app has - // strange behavior if we don't do this, "thinking" the key is not - // actually consumed) - if ([_composingBuffer length] || !_bpmfReadingBuffer->isEmpty()) { - [self beep]; - [self updateClientComposingBuffer:client]; - return YES; - } - - return NO; -} - -- (BOOL)handleCandidateEventWithInputText:(NSString *)inputText charCode:(UniChar)charCode keyCode:(NSUInteger)keyCode -{ -// if (_inputMode == kPlainBopomofoModeIdentifier) { -// if (charCode == '<') { -// keyCode = kPageUpKeyCode; -// } -// else if (charCode == '>') { -// keyCode = kPageDownKeyCode; -// } -// } - - BOOL cancelCandidateKey = - (charCode == 27) || - ((_inputMode == kPlainBopomofoModeIdentifier) && - (charCode == 8 || keyCode == kDeleteKeyCode)); - - if (cancelCandidateKey) { - gCurrentCandidateController.visible = NO; - [_candidates removeAllObjects]; - - if (_inputMode == kPlainBopomofoModeIdentifier) { - _builder->clear(); - _walkedNodes.clear(); - [_composingBuffer setString:@""]; - } - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - else if (charCode == 13 || keyCode == kEnterKeyCode) { - [self candidateController:gCurrentCandidateController didSelectCandidateAtIndex:gCurrentCandidateController.selectedCandidateIndex]; - return YES; - } - else if (charCode == 32 || keyCode == kPageDownKeyCode) { - BOOL updated = [gCurrentCandidateController showNextPage]; - if (!updated) { - [self beep]; - } - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - else if (keyCode == kPageUpKeyCode) { - BOOL updated = [gCurrentCandidateController showPreviousPage]; - if (!updated) { - [self beep]; - } - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - else if (keyCode == kLeftKeyCode) { - if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) { - BOOL updated = [gCurrentCandidateController highlightPreviousCandidate]; - if (!updated) { - [self beep]; - } - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - else { - BOOL updated = [gCurrentCandidateController showPreviousPage]; - if (!updated) { - [self beep]; - } - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - } - else if (keyCode == kRightKeyCode) { - if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) { - BOOL updated = [gCurrentCandidateController highlightNextCandidate]; - if (!updated) { - [self beep]; - } - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - else { - BOOL updated = [gCurrentCandidateController showNextPage]; - if (!updated) { - [self beep]; - } - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - } - else if (keyCode == kUpKeyCode) { - if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) { - BOOL updated = [gCurrentCandidateController showPreviousPage]; - if (!updated) { - [self beep]; - } - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - else { - BOOL updated = [gCurrentCandidateController highlightPreviousCandidate]; - if (!updated) { - [self beep]; - } - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - } - else if (keyCode == kDownKeyCode) { - if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) { - BOOL updated = [gCurrentCandidateController showNextPage]; - if (!updated) { - [self beep]; - } - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - else { - BOOL updated = [gCurrentCandidateController highlightNextCandidate]; - if (!updated) { - [self beep]; - } - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - } - else if (keyCode == kHomeKeyCode) { - if (gCurrentCandidateController.selectedCandidateIndex == 0) { - [self beep]; - - } - else { - gCurrentCandidateController.selectedCandidateIndex = 0; - } - - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - else if (keyCode == kEndKeyCode && [_candidates count] > 0) { - if (gCurrentCandidateController.selectedCandidateIndex == [_candidates count] - 1) { - [self beep]; - } - else { - gCurrentCandidateController.selectedCandidateIndex = [_candidates count] - 1; - } - - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } - else { - NSInteger index = NSNotFound; - for (NSUInteger j = 0, c = [gCurrentCandidateController.keyLabels count]; j < c; j++) { - if ([inputText compare:[gCurrentCandidateController.keyLabels objectAtIndex:j] options:NSCaseInsensitiveSearch] == NSOrderedSame) { - index = j; - break; - } - } - - [gCurrentCandidateController.keyLabels indexOfObject:inputText]; - if (index != NSNotFound) { - NSUInteger candidateIndex = [gCurrentCandidateController candidateIndexAtKeyLabelIndex:index]; - if (candidateIndex != NSUIntegerMax) { - [self candidateController:gCurrentCandidateController didSelectCandidateAtIndex:candidateIndex]; - return YES; - } - } - - if (_inputMode == kPlainBopomofoModeIdentifier) { - string layout = [self currentLayout]; - string customPunctuation = string("_punctuation_") + layout + string(1, (char)charCode); - string punctuation = string("_punctuation_") + string(1, (char)charCode); - - BOOL shouldAutoSelectCandidate = _bpmfReadingBuffer->isValidKey((char)charCode) || _languageModel->hasUnigramsForKey(customPunctuation) || - _languageModel->hasUnigramsForKey(punctuation); - - if (shouldAutoSelectCandidate) { - NSUInteger candidateIndex = [gCurrentCandidateController candidateIndexAtKeyLabelIndex:0]; - if (candidateIndex != NSUIntegerMax) { - [self candidateController:gCurrentCandidateController didSelectCandidateAtIndex:candidateIndex]; - return [self handleInputText:inputText key:keyCode modifiers:0 client:_currentCandidateClient]; - } - } - } - - [self beep]; - [self updateClientComposingBuffer:_currentCandidateClient]; - return YES; - } -} - -- (NSUInteger)recognizedEvents:(id)sender -{ - return NSKeyDownMask | NSFlagsChangedMask; -} - -- (BOOL)handleEvent:(NSEvent *)event client:(id)client -{ - if ([event type] == NSFlagsChanged) { - NSString *functionKeyKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kFunctionKeyKeyboardLayoutPreferenceKey]; - if (!functionKeyKeyboardLayoutID) { - functionKeyKeyboardLayoutID = @"com.apple.keylayout.US"; - } - - NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; - if (!basisKeyboardLayoutID) { - basisKeyboardLayoutID = @"com.apple.keylayout.US"; - } - - // If no override is needed, just return NO. - if ([functionKeyKeyboardLayoutID isEqualToString:basisKeyboardLayoutID]) { - return NO; - } - - // Function key pressed. - BOOL includeShift = [[NSUserDefaults standardUserDefaults] boolForKey:kFunctionKeyKeyboardLayoutOverrideIncludeShiftKey]; - if (([event modifierFlags] & ~NSShiftKeyMask) || (([event modifierFlags] & NSShiftKeyMask) && includeShift)) { - // Override the keyboard layout and let the OS do its thing - [client overrideKeyboardWithKeyboardNamed:functionKeyKeyboardLayoutID]; - return NO; - } - - // Revert back to the basis layout when the function key is released - [client overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID]; - return NO; - } - - NSString *inputText = [event characters]; - NSInteger keyCode = [event keyCode]; - NSUInteger flags = [event modifierFlags]; - return [self handleInputText:inputText key:keyCode modifiers:flags client:client]; -} - -#pragma mark - Private methods - -+ (VTHorizontalCandidateController *)horizontalCandidateController -{ - static VTHorizontalCandidateController *instance = nil; - @synchronized(self) { - if (!instance) { - instance = [[VTHorizontalCandidateController alloc] init]; - } - } - - return instance; -} - -+ (VTVerticalCandidateController *)verticalCandidateController -{ - static VTVerticalCandidateController *instance = nil; - @synchronized(self) { - if (!instance) { - instance = [[VTVerticalCandidateController alloc] init]; - } - } - - return instance; -} - -- (void)collectCandidates -{ - // returns the candidate - [_candidates removeAllObjects]; - - size_t cursorIndex = [self actualCandidateCursorIndex]; - vector nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); - - // sort the nodes, so that longer nodes (representing longer phrases) are placed at the top of the candidate list - stable_sort(nodes.begin(), nodes.end(), NodeAnchorDescendingSorter()); - - // then use the C++ trick to retrieve the candidates for each node at/crossing the cursor - for (vector::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) { - const vector& candidates = (*ni).node->candidates(); - for (vector::const_iterator ci = candidates.begin(), ce = candidates.end(); ci != ce; ++ci) { - [_candidates addObject:[NSString stringWithUTF8String:(*ci).value.c_str()]]; - } - } -} - -- (size_t)actualCandidateCursorIndex -{ - size_t cursorIndex = _builder->cursorIndex(); - - BOOL candidatePhraseLocatedAfterCursor = [[NSUserDefaults standardUserDefaults] boolForKey:kSelectPhraseAfterCursorAsCandidatePreferenceKey]; - - if (candidatePhraseLocatedAfterCursor) { - // MS Phonetics IME style, phrase is *after* the cursor, i.e. cursor is always *before* the phrase - if (cursorIndex < _builder->length()) { - ++cursorIndex; - } - } - else { - if (!cursorIndex) { - ++cursorIndex; - } - } - - return cursorIndex; -} - -- (NSString *)neighborTrigramString -{ - // gather the "trigram" for user candidate selection learning - - NSMutableArray *termArray = [NSMutableArray array]; - - size_t cursorIndex = [self actualCandidateCursorIndex]; - vector nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); - - const Node* prev = 0; - const Node* current = 0; - const Node* next = 0; - - size_t wni = 0; - size_t wnc = _walkedNodes.size(); - size_t accuSpanningLength = 0; - for (wni = 0; wni < wnc; wni++) { - NodeAnchor& anchor = _walkedNodes[wni]; - if (!anchor.node) { - continue; - } - - accuSpanningLength += anchor.spanningLength; - if (accuSpanningLength >= cursorIndex) { - prev = current; - current = anchor.node; - break; - } - - current = anchor.node; - } - - if (wni + 1 < wnc) { - next = _walkedNodes[wni + 1].node; - } - - string term; - if (prev) { - term = prev->currentKeyValue().key; - [termArray addObject:[NSString stringWithUTF8String:term.c_str()]]; - } - - if (current) { - term = current->currentKeyValue().key; - [termArray addObject:[NSString stringWithUTF8String:term.c_str()]]; - } - - if (next) { - term = next->currentKeyValue().key; - [termArray addObject:[NSString stringWithUTF8String:term.c_str()]]; - } - - return [termArray componentsJoinedByString:@"-"]; -} - -- (void)_performDeferredSaveUserCandidatesDictionary -{ - BOOL __unused success = [gCandidateLearningDictionary writeToFile:gUserCandidatesDictionaryPath atomically:YES]; -} - -- (void)saveUserCandidatesDictionary -{ - if (!gUserCandidatesDictionaryPath) { - return; - } - - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_performDeferredSaveUserCandidatesDictionary) object:nil]; - - // TODO: Const-ize the delay - [self performSelector:@selector(_performDeferredSaveUserCandidatesDictionary) withObject:nil afterDelay:5.0]; -} - -- (void)_showCandidateWindowUsingVerticalMode:(BOOL)useVerticalMode client:(id)client -{ - // set the candidate panel style - BOOL useHorizontalCandidateList = [[NSUserDefaults standardUserDefaults] boolForKey:kUseHorizontalCandidateListPreferenceKey]; - - if (useVerticalMode) { - gCurrentCandidateController = [McBopomofoInputMethodController verticalCandidateController]; - } - else if (useHorizontalCandidateList) { - gCurrentCandidateController = [McBopomofoInputMethodController horizontalCandidateController]; - } - else { - gCurrentCandidateController = [McBopomofoInputMethodController verticalCandidateController]; - } - - // set the attributes for the candidate panel (which uses NSAttributedString) - NSInteger textSize = [[NSUserDefaults standardUserDefaults] integerForKey:kCandidateListTextSizeKey]; - - NSInteger keyLabelSize = textSize / 2; - if (keyLabelSize < kMinKeyLabelSize) { - keyLabelSize = kMinKeyLabelSize; - } - - NSString *ctFontName = [[NSUserDefaults standardUserDefaults] stringForKey:kCandidateTextFontName]; - NSString *klFontName = [[NSUserDefaults standardUserDefaults] stringForKey:kCandidateKeyLabelFontName]; - NSString *ckeys = [[NSUserDefaults standardUserDefaults] stringForKey:kCandidateKeys]; - - gCurrentCandidateController.keyLabelFont = klFontName ? [NSFont fontWithName:klFontName size:keyLabelSize] : [NSFont systemFontOfSize:keyLabelSize]; - gCurrentCandidateController.candidateFont = ctFontName ? [NSFont fontWithName:ctFontName size:textSize] : [NSFont systemFontOfSize:textSize]; - - NSMutableArray *keyLabels = [NSMutableArray arrayWithObjects:@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", nil]; - - if ([ckeys length] > 1) { - [keyLabels removeAllObjects]; - for (NSUInteger i = 0, c = [ckeys length]; i < c; i++) { - [keyLabels addObject:[ckeys substringWithRange:NSMakeRange(i, 1)]]; - } - } - - gCurrentCandidateController.keyLabels = keyLabels; - [self collectCandidates]; - - if (_inputMode == kPlainBopomofoModeIdentifier && [_candidates count] == 1) { - [self commitComposition:client]; - return; - } - - gCurrentCandidateController.delegate = self; - [gCurrentCandidateController reloadData]; - - // update the composing text, set the client - [self updateClientComposingBuffer:client]; - _currentCandidateClient = client; - - NSRect lineHeightRect = NSMakeRect(0.0, 0.0, 16.0, 16.0); - - NSInteger cursor = _latestReadingCursor; - if (cursor == [_composingBuffer length] && cursor != 0) { - cursor--; - } - - // some apps (e.g. Twitter for Mac's search bar) handle this call incorrectly, hence the try-catch - @try { - [client attributesForCharacterIndex:cursor lineHeightRectangle:&lineHeightRect]; - } - @catch (NSException *exception) { - NSLog(@"%@", exception); - } - - if (useVerticalMode) { - [gCurrentCandidateController setWindowTopLeftPoint:NSMakePoint(lineHeightRect.origin.x + lineHeightRect.size.width + 4.0, lineHeightRect.origin.y - 4.0) bottomOutOfScreenAdjustmentHeight:lineHeightRect.size.height + 4.0]; - } - else { - [gCurrentCandidateController setWindowTopLeftPoint:NSMakePoint(lineHeightRect.origin.x, lineHeightRect.origin.y - 4.0) bottomOutOfScreenAdjustmentHeight:lineHeightRect.size.height + 4.0]; - } - - gCurrentCandidateController.visible = YES; -} - -#pragma mark - Misc menu items - -- (void)showPreferences:(id)sender -{ - // show the preferences panel, and also make the IME app itself the focus - if ([IMKInputController instancesRespondToSelector:@selector(showPreferences:)]) { - [super showPreferences:sender]; - } else { - [(AppDelegate *)[NSApp delegate] showPreferences]; - } - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; -} - -- (void)checkForUpdate:(id)sender -{ - [(AppDelegate *)[[NSApplication sharedApplication] delegate] checkForUpdateForced:YES]; -} - -- (void)showAbout:(id)sender -{ - [[NSApplication sharedApplication] orderFrontStandardAboutPanel:sender]; - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; -} - -- (void)toggleLearning:(id)sender -{ - BOOL toggle = ![[NSUserDefaults standardUserDefaults] boolForKey:kDisableUserCandidateSelectionLearning]; - - [[NSUserDefaults standardUserDefaults] setBool:toggle forKey:kDisableUserCandidateSelectionLearning]; -} - -- (void)toggleChineseConverter:(id)sender -{ - _chineseConversionEnabled = !_chineseConversionEnabled; - [[NSUserDefaults standardUserDefaults] setBool:_chineseConversionEnabled forKey:kChineseConversionEnabledKey]; -} - -- (void)clearLearningDictionary:(id)sender -{ - [gCandidateLearningDictionary removeAllObjects]; - [self _performDeferredSaveUserCandidatesDictionary]; -} - -- (void)dumpLearningDictionary:(id)sender -{ - NSLog(@"%@", gCandidateLearningDictionary); -} - -- (NSUInteger)candidateCountForController:(VTCandidateController *)controller -{ - return [_candidates count]; -} - -- (NSString *)candidateController:(VTCandidateController *)controller candidateAtIndex:(NSUInteger)index -{ - return [_candidates objectAtIndex:index]; -} - -- (void)candidateController:(VTCandidateController *)controller didSelectCandidateAtIndex:(NSUInteger)index -{ - gCurrentCandidateController.visible = NO; - - // candidate selected, override the node with selection - string selectedValue = [[_candidates objectAtIndex:index] UTF8String]; - - if (![[NSUserDefaults standardUserDefaults] boolForKey:kDisableUserCandidateSelectionLearning]) { - NSString *trigram = [self neighborTrigramString]; - NSString *selectedNSString = [NSString stringWithUTF8String:selectedValue.c_str()]; - [gCandidateLearningDictionary setObject:selectedNSString forKey:trigram]; - [self saveUserCandidatesDictionary]; - } - - size_t cursorIndex = [self actualCandidateCursorIndex]; - _builder->grid().fixNodeSelectedCandidate(cursorIndex, selectedValue); - - [_candidates removeAllObjects]; - - [self walk]; - [self updateClientComposingBuffer:_currentCandidateClient]; - - if (_inputMode == kPlainBopomofoModeIdentifier) { - [self commitComposition:_currentCandidateClient]; - return; - } -} - -@end - -static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, FastLM &lm) -{ - NSString *dataPath = [[NSBundle bundleForClass:[McBopomofoInputMethodController class]] pathForResource:filenameWithoutExtension ofType:@"txt"]; - bool result = lm.open([dataPath UTF8String]); - if (!result) { - NSLog(@"Failed opening language model: %@", dataPath); - } -} - - -void LTLoadLanguageModel() -{ - LTLoadLanguageModelFile(@"data", gLanguageModel); - LTLoadLanguageModelFile(@"data-plain-bpmf", gLanguageModelPlainBopomofo); - - - // initialize the singleton learning dictionary - // putting singleton in @synchronized is the standard way in Objective-C - // to avoid race condition - gCandidateLearningDictionary = [[NSMutableDictionary alloc] init]; - - // the first instance is also responsible for loading the dictionary - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDirectory, YES); - if (![paths count]) { - NSLog(@"Fatal error: cannot find Applicaiton Support directory."); - return; - } - - NSString *appSupportPath = [paths objectAtIndex:0]; - NSString *userDictPath = [appSupportPath stringByAppendingPathComponent:@"McBopomofo"]; - - BOOL isDir = NO; - BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:userDictPath isDirectory:&isDir]; - - if (exists) { - if (!isDir) { - NSLog(@"Fatal error: Path '%@' is not a directory", userDictPath); - return; - } - } - else { - NSError *error = nil; - BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:userDictPath withIntermediateDirectories:YES attributes:nil error:&error]; - if (!success) { - NSLog(@"Failed to create directory '%@', error: %@", userDictPath, error); - return; - } - } - - // TODO: Change this - NSString *userDictFile = [userDictPath stringByAppendingPathComponent:@"UserCandidatesCache.plist"]; - gUserCandidatesDictionaryPath = userDictFile; - - exists = [[NSFileManager defaultManager] fileExistsAtPath:userDictFile isDirectory:&isDir]; - if (exists && !isDir) { - NSData *data = [NSData dataWithContentsOfFile:userDictFile]; - if (!data) { - return; - } - - id plist = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:NULL]; - if (plist && [plist isKindOfClass:[NSDictionary class]]) { - [gCandidateLearningDictionary setDictionary:(NSDictionary *)plist]; - NSLog(@"User dictionary read, item count: %ju", (uintmax_t)[gCandidateLearningDictionary count]); - } - } - -} diff --git a/Source/Installer/AppDelegate.h b/Source/Installer/AppDelegate.h deleted file mode 100644 index 32b4936f889519004132cd3f6ba7b65b2bb3e868..0000000000000000000000000000000000000000 --- a/Source/Installer/AppDelegate.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// AppDelegate.h -// -// Copyright (c) 2011-2012 The McBopomofo Project. -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import -#import "ArchiveUtil.h" - -@interface AppDelegate : NSWindowController -{ -@protected - ArchiveUtil *_archiveUtil; - NSString *_installingVersion; - BOOL _upgrading; - NSButton *__weak _installButton; - NSButton *__weak _cancelButton; - NSTextView *__unsafe_unretained _textView; - NSWindow *__weak _progressSheet; - NSProgressIndicator *__weak _progressIndicator; - NSDate *_translocationRemovalStartTime; - NSInteger _currentVersionNumber; -} -- (IBAction)agreeAndInstallAction:(id)sender; -- (IBAction)cancelAction:(id)sender; - -@property (weak) IBOutlet NSButton *installButton; -@property (weak) IBOutlet NSButton *cancelButton; -@property (unsafe_unretained) IBOutlet NSTextView *textView; -@property (weak) IBOutlet NSWindow *progressSheet; -@property (weak) IBOutlet NSProgressIndicator *progressIndicator; -@end diff --git a/Source/Installer/AppDelegate.m b/Source/Installer/AppDelegate.m deleted file mode 100644 index 17485951f640eaacb8ba5f3a8b6a7d94b9dc7de6..0000000000000000000000000000000000000000 --- a/Source/Installer/AppDelegate.m +++ /dev/null @@ -1,292 +0,0 @@ -// -// AppDelegate.m -// -// Copyright (c) 2011-2012 The McBopomofo Project. -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "AppDelegate.h" -#import -#import "OVInputSourceHelper.h" - -static NSString *const kTargetBin = @"McBopomofo"; -static NSString *const kTargetType = @"app"; -static NSString *const kTargetBundle = @"McBopomofo.app"; -static NSString *const kDestinationPartial = @"~/Library/Input Methods/"; -static NSString *const kTargetPartialPath = @"~/Library/Input Methods/McBopomofo.app"; -static NSString *const kTargetFullBinPartialPath = @"~/Library/Input Methods/McBopomofo.app/Contents/MacOS/McBopomofo"; - -static const NSTimeInterval kTranslocationRemovalTickInterval = 0.5; -static const NSTimeInterval kTranslocationRemovalDeadline = 60.0; - -/// A simple replacement for the deprecated NSRunAlertPanel. -void RunAlertPanel(NSString *title, NSString *message, NSString *buttonTitle) { - NSAlert *alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSAlertStyleInformational]; - [alert setMessageText:title]; - [alert setInformativeText:message]; - [alert addButtonWithTitle:buttonTitle]; - [alert runModal]; -} - -@implementation AppDelegate -@synthesize installButton = _installButton; -@synthesize cancelButton = _cancelButton; -@synthesize textView = _textView; -@synthesize progressSheet = _progressSheet; -@synthesize progressIndicator = _progressIndicator; - -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification -{ - _installingVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:(id)kCFBundleVersionKey]; - NSString *versionString = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; - - _archiveUtil = [[ArchiveUtil alloc] initWithAppName:kTargetBin targetAppBundleName:kTargetBundle]; - [_archiveUtil validateIfNotarizedArchiveExists]; - - [self.cancelButton setNextKeyView:self.installButton]; - [self.installButton setNextKeyView:self.cancelButton]; - [[self window] setDefaultButtonCell:[self.installButton cell]]; - - NSAttributedString *attrStr = [[NSAttributedString alloc] initWithRTF:[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"License" ofType:@"rtf"]] documentAttributes:NULL]; - - NSMutableAttributedString *mutableAttrStr = [attrStr mutableCopy]; - [mutableAttrStr addAttribute:NSForegroundColorAttributeName value:[NSColor controlTextColor] range:NSMakeRange(0, [mutableAttrStr length])]; - [[self.textView textStorage] setAttributedString:mutableAttrStr]; - [self.textView setSelectedRange:NSMakeRange(0, 0)]; - - [[self window] setTitle:[NSString stringWithFormat:NSLocalizedString(@"%@ (for version %@, r%@)", nil), [[self window] title], versionString, _installingVersion]]; - - if ([[NSFileManager defaultManager] fileExistsAtPath:[kTargetPartialPath stringByExpandingTildeInPath]]) { - NSBundle *currentBundle = [NSBundle bundleWithPath:[kTargetPartialPath stringByExpandingTildeInPath]]; - - NSString *shortVersion = [[currentBundle infoDictionary] objectForKey:@"CFBundleShortVersionString"]; - NSString *currentVersion = [[currentBundle infoDictionary] objectForKey:(id)kCFBundleVersionKey]; - - _currentVersionNumber = [currentVersion integerValue]; - if (shortVersion && currentVersion && [currentVersion compare:_installingVersion options:NSNumericSearch] == NSOrderedAscending) { - _upgrading = YES; - } - } - - if (_upgrading) { - [_installButton setTitle:NSLocalizedString(@"Agree and Upgrade", nil)]; - } - - [[self window] center]; - [[self window] orderFront:self]; - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; -} - -- (IBAction)agreeAndInstallAction:(id)sender -{ - [_cancelButton setEnabled:NO]; - [_installButton setEnabled:NO]; - [self removeThenInstallInputMethod]; -} - -- (void)removeThenInstallInputMethod -{ - if ([[NSFileManager defaultManager] fileExistsAtPath:[kTargetPartialPath stringByExpandingTildeInPath]]) { - - BOOL shouldWaitForTranslocationRemoval = - [self appBundleTranslocatedToARandomizedPath:kTargetPartialPath] && - [self.window respondsToSelector:@selector(beginSheet:completionHandler:)]; - - // http://www.cocoadev.com/index.pl?MoveToTrash - NSString *sourceDir = [kDestinationPartial stringByExpandingTildeInPath]; - NSString *trashDir = [NSHomeDirectory() stringByAppendingPathComponent:@".Trash"]; - NSInteger tag; - - [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:sourceDir destination:trashDir files:[NSArray arrayWithObject:kTargetBundle] tag:&tag]; - (void)tag; - - NSTask *killTask = [NSTask launchedTaskWithLaunchPath:@"/usr/bin/killall" arguments:[NSArray arrayWithObjects: @"-9", kTargetBin, nil]]; - [killTask waitUntilExit]; - - if (shouldWaitForTranslocationRemoval) { - [self.progressIndicator startAnimation:self]; - [self.window beginSheet:self.progressSheet completionHandler:^(NSModalResponse returnCode) { - // Schedule the install action in runloop so that the sheet gets a change to dismiss itself. - dispatch_async(dispatch_get_main_queue(), ^{ - if (returnCode == NSModalResponseContinue) { - [self installInputMethodWithPreviousExists:YES previousVersionNotFullyDeactivatedWarning:NO]; - } else { - [self installInputMethodWithPreviousExists:YES previousVersionNotFullyDeactivatedWarning:YES]; - } - }); - }]; - - _translocationRemovalStartTime = [NSDate date]; - [NSTimer scheduledTimerWithTimeInterval:kTranslocationRemovalTickInterval target:self selector:@selector(timerTick:) userInfo:nil repeats:YES]; - return; - } - } - - [self installInputMethodWithPreviousExists:NO previousVersionNotFullyDeactivatedWarning:NO]; -} - -- (void)timerTick:(NSTimer *)timer -{ - NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:_translocationRemovalStartTime]; - [self.progressIndicator setDoubleValue:MIN(elapsed / kTranslocationRemovalDeadline, 1.0)]; - - if (elapsed >= kTranslocationRemovalDeadline) { - [timer invalidate]; - [self.window endSheet:self.progressSheet returnCode:NSModalResponseCancel]; - } else if (![self appBundleTranslocatedToARandomizedPath:kTargetPartialPath]) { - [self.progressIndicator setDoubleValue:1.0]; - [timer invalidate]; - [self.window endSheet:self.progressSheet returnCode:NSModalResponseContinue]; - } -} - - -- (void)installInputMethodWithPreviousExists:(BOOL)previousVersionExists previousVersionNotFullyDeactivatedWarning:(BOOL)warning -{ - // If the unzipped archive does not exist, this must be a dev-mode installer. - NSString *targetBundle = [_archiveUtil unzipNotarizedArchive]; - if (!targetBundle) { - targetBundle = [[NSBundle mainBundle] pathForResource:kTargetBin ofType:kTargetType]; - } - - NSTask *cpTask = [NSTask launchedTaskWithLaunchPath:@"/bin/cp" arguments:[NSArray arrayWithObjects:@"-R", targetBundle, [kDestinationPartial stringByExpandingTildeInPath], nil]]; - [cpTask waitUntilExit]; - if ([cpTask terminationStatus] != 0) { - RunAlertPanel(NSLocalizedString(@"Install Failed", nil), NSLocalizedString(@"Cannot copy the file to the destination.", nil), NSLocalizedString(@"Cancel", nil)); - [NSApp terminate:self]; - } - - NSBundle *imeBundle = [NSBundle bundleWithPath:[kTargetPartialPath stringByExpandingTildeInPath]]; - NSCAssert(imeBundle != nil, @"Target bundle must exists"); - NSURL *imeBundleURL = imeBundle.bundleURL; - NSString *imeIdentifier = imeBundle.bundleIdentifier; - - TISInputSourceRef inputSource = [OVInputSourceHelper inputSourceForInputSourceID:imeIdentifier]; - - // if this IME name is not found in the list of available IMEs - if (!inputSource) { - NSLog(@"Registering input source %@ at %@.", imeIdentifier, imeBundleURL.absoluteString); - // then register - BOOL status = [OVInputSourceHelper registerInputSource:imeBundleURL]; - - if (!status) { - NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Cannot register input source %@ at %@.", nil), imeIdentifier, imeBundleURL.absoluteString]; - RunAlertPanel(NSLocalizedString(@"Fatal Error", nil), message, NSLocalizedString(@"Abort", nil)); - [self endAppWithDelay]; - return; - } - - inputSource = [OVInputSourceHelper inputSourceForInputSourceID:imeIdentifier]; - // if it still doesn't register successfully, bail. - if (!inputSource) { - NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Cannot find input source %@ after registration.", nil), imeIdentifier]; - RunAlertPanel(NSLocalizedString(@"Fatal Error", nil), message, NSLocalizedString(@"Abort", nil)); - [self endAppWithDelay]; - return; - } - } - - BOOL isMacOS12OrAbove = NO; - if (@available(macOS 12.0, *)) { - NSLog(@"macOS 12 or later detected."); - isMacOS12OrAbove = YES; - } else { - NSLog(@"Installer runs with the pre-macOS 12 flow."); - } - - // If the IME is not enabled, enable it. Also, unconditionally enable it on macOS 12.0+, - // as the kTISPropertyInputSourceIsEnabled can still be true even if the IME is *not* - // enabled in the user's current set of IMEs (which means the IME does not show up in - // the user's input menu). - BOOL mainInputSourceEnabled = [OVInputSourceHelper inputSourceEnabled:inputSource]; - if (!mainInputSourceEnabled || isMacOS12OrAbove) { - - mainInputSourceEnabled = [OVInputSourceHelper enableInputSource:inputSource]; - if (mainInputSourceEnabled) { - NSLog(@"Input method enabled: %@", imeIdentifier); - } else { - NSLog(@"Failed to enable input method: %@", imeIdentifier); - } - } - - if (warning) { - RunAlertPanel(NSLocalizedString(@"Attention", nil), NSLocalizedString(@"McBopomofo is upgraded, but please log out or reboot for the new version to be fully functional.", nil), NSLocalizedString(@"OK", nil)); - } else { - // Only prompt a warning if pre-macOS 12. The flag is not indicative of anything meaningful due to the need of user intervention in Prefernces.app on macOS 12. - if (!mainInputSourceEnabled && !isMacOS12OrAbove) { - RunAlertPanel(NSLocalizedString(@"Warning", nil), NSLocalizedString(@"Input method may not be fully enabled. Please enable it through System Preferences > Keyboard > Input Sources.", nil), NSLocalizedString(@"Continue", nil)); - } else { - RunAlertPanel(NSLocalizedString(@"Installation Successful", nil), NSLocalizedString(@"McBopomofo is ready to use.", nil), NSLocalizedString(@"OK", nil)); - } - } - - [self endAppWithDelay]; -} - -- (void)endAppWithDelay -{ - [[NSApplication sharedApplication] performSelector:@selector(terminate:) withObject:self afterDelay:0.1]; -} - -- (IBAction)cancelAction:(id)sender -{ - [NSApp terminate:self]; -} - -- (void)windowWillClose:(NSNotification *)notification -{ - [NSApp terminate:self]; -} - -// Determines if an app is translocated by Gatekeeper to a randomized path -// See https://weblog.rogueamoeba.com/2016/06/29/sierra-and-gatekeeper-path-randomization/ -- (BOOL)appBundleTranslocatedToARandomizedPath:(NSString *)bundle -{ - const char *bundleAbsPath = [[bundle stringByExpandingTildeInPath] UTF8String]; - int entryCount = getfsstat(NULL, 0, 0); - int entrySize = sizeof(struct statfs); - struct statfs *bufs = (struct statfs *)calloc(entryCount, entrySize); - entryCount = getfsstat(bufs, entryCount * entrySize, MNT_NOWAIT); - for (int i = 0; i < entryCount; i++) { - if (!strcmp(bundleAbsPath, bufs[i].f_mntfromname)) { - free(bufs); - - // getfsstat() may return us a cached result, and so we need to get the stat of the mounted fs. - // If statfs() returns an error, the mounted fs is already gone. - struct statfs stat; - int checkResult = statfs(bundleAbsPath, &stat); - if (checkResult != 0) { - // Meaning the app's bundle is not mounted, that is it's not translocated. - // It also means that the app is not loaded. - return NO; - } - - return YES; - } - } - free(bufs); - return NO; - -} -@end diff --git a/Source/Installer/ArchiveUtil.h b/Source/Installer/ArchiveUtil.h deleted file mode 100644 index aab19c611041fd7797bca23c52e438a437079458..0000000000000000000000000000000000000000 --- a/Source/Installer/ArchiveUtil.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2011-2019 The McBopomofo Project. -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. - -#import - -@interface ArchiveUtil : NSObject { - NSString *_appName; - NSString *_targetAppBundleName; -} -- (instancetype _Nonnull)initWithAppName:(NSString *_Nonnull)name - targetAppBundleName:(NSString *_Nonnull)invalidAppBundleName; - -// Returns YES if (1) a zip file under -// Resources/NotarizedArchives/$_appName-$bundleVersion.zip exists, and (2) if -// Resources/$_invalidAppBundleName does not exist. -- (BOOL)validateIfNotarizedArchiveExists; - -- (NSString *_Nullable)unzipNotarizedArchive; -@end diff --git a/Source/Installer/ArchiveUtil.m b/Source/Installer/ArchiveUtil.m deleted file mode 100644 index 90d47e35c6dcbe8ff9f485be6ce52b4a164207c0..0000000000000000000000000000000000000000 --- a/Source/Installer/ArchiveUtil.m +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2011-2019 The McBopomofo Project. -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. - -#import "ArchiveUtil.h" - -@implementation ArchiveUtil -- (instancetype)initWithAppName:(NSString *)name - targetAppBundleName:(NSString *)targetAppBundleName { - self = [super init]; - if (self) { - _appName = name; - _targetAppBundleName = targetAppBundleName; - } - return self; -} - -- (void)delloc { - _appName = nil; - _targetAppBundleName = nil; -} - -- (BOOL)validateIfNotarizedArchiveExists { - NSString *resourePath = [[NSBundle mainBundle] resourcePath]; - NSString *devModeAppBundlePath = - [resourePath stringByAppendingPathComponent:_targetAppBundleName]; - - NSArray *notarizedArchivesContent = - [[NSFileManager defaultManager] subpathsAtPath:[self notarizedArchivesPath]]; - NSInteger count = [notarizedArchivesContent count]; - BOOL notarizedArchiveExists = - [[NSFileManager defaultManager] fileExistsAtPath:[self notarizedArchive]]; - BOOL devModeAppBundleExists = - [[NSFileManager defaultManager] fileExistsAtPath:devModeAppBundlePath]; - - if (count > 0) { - // Not a valid distribution package. - if (count != 1 || !notarizedArchiveExists || devModeAppBundleExists) { - NSAlert *alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSAlertStyleInformational]; - [alert setMessageText:@"Internal Error"]; - [alert - setInformativeText: - [NSString stringWithFormat:@"devMode installer, expected archive name: %@, " - @"archive exists: %d, devMode app bundle exists: %d", - [self notarizedArchive], notarizedArchiveExists, - devModeAppBundleExists]]; - [alert addButtonWithTitle:@"Terminate"]; - [alert runModal]; - - [[NSApplication sharedApplication] terminate:nil]; - } else { - return YES; - } - } - - if (!devModeAppBundleExists) { - NSAlert *alert = [[NSAlert alloc] init]; - [alert setAlertStyle:NSAlertStyleInformational]; - [alert setMessageText:@"Internal Error"]; - [alert - setInformativeText:[NSString stringWithFormat:@"Dev target bundle does not exist: %@", - devModeAppBundlePath]]; - [alert addButtonWithTitle:@"Terminate"]; - [alert runModal]; - [[NSApplication sharedApplication] terminate:nil]; - } - - // Notarized archive does not exist, but it's ok. - return NO; -} - -- (NSString *)unzipNotarizedArchive { - if (![self validateIfNotarizedArchiveExists]) { - return nil; - } - - NSString *tempFilePath = - [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; - NSArray *arguments = @[ [self notarizedArchive], @"-d", tempFilePath ]; - - NSTask *unzipTask = [[NSTask alloc] init]; - [unzipTask setLaunchPath:@"/usr/bin/unzip"]; - [unzipTask setCurrentDirectoryPath:[[NSBundle mainBundle] resourcePath]]; - [unzipTask setArguments:arguments]; - [unzipTask launch]; - [unzipTask waitUntilExit]; - - NSAssert(unzipTask.terminationStatus == 0, @"Must successfully unzipped"); - - NSString *result = [tempFilePath stringByAppendingPathComponent:_targetAppBundleName]; - NSAssert([[NSFileManager defaultManager] fileExistsAtPath:result], - @"App bundle must be unzipped at %@", result); - return result; -} - -- (NSString *)notarizedArchivesPath { - NSString *resourePath = [[NSBundle mainBundle] resourcePath]; - NSString *notarizedArchivesPath = - [resourePath stringByAppendingPathComponent:@"NotarizedArchives"]; - return notarizedArchivesPath; -} - -- (NSString *)notarizedArchive { - NSString *bundleVersion = - [[[NSBundle mainBundle] infoDictionary] objectForKey:(id)kCFBundleVersionKey]; - NSString *notarizedArchiveBasename = - [NSString stringWithFormat:@"%@-r%@.zip", _appName, bundleVersion]; - NSString *notarizedArchive = - [[self notarizedArchivesPath] stringByAppendingPathComponent:notarizedArchiveBasename]; - return notarizedArchive; -} -@end diff --git a/Source/Installer/en.lproj/InfoPlist.strings b/Source/Installer/en.lproj/InfoPlist.strings deleted file mode 100644 index 6472f62de17a9930748da0ebcfcea44ab85c15f5..0000000000000000000000000000000000000000 --- a/Source/Installer/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,4 +0,0 @@ -/* Localized versions of Info.plist keys */ - -CFBundleName = "Install McBopomofo"; -NSHumanReadableCopyright = "Copyright © 2011-2021 Mengjuei Hsieh et al.\nAll Rights Reserved."; diff --git a/Source/Installer/en.lproj/License.rtf b/Source/Installer/en.lproj/License.rtf deleted file mode 100644 index 72e324611211d79fb0152987dc21367a1d4a5753..0000000000000000000000000000000000000000 --- a/Source/Installer/en.lproj/License.rtf +++ /dev/null @@ -1,17 +0,0 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820 -{\fonttbl\f0\fnil\fcharset0 LucidaGrande-Bold;\f1\fnil\fcharset0 LucidaGrande;} -{\colortbl;\red255\green255\blue255;} -{\*\expandedcolortbl;;} -\margl1440\margr1440\vieww16860\viewh12620\viewkind0 -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 - -\f0\b\fs36 \cf0 McBopomofo License Agreement -\f1\b0\fs24 \ -\ -Copyright \'a9 2011-2021 Mengjuei Hsieh et al.\ -\ -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \'93Software\'94), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\ -\ -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\ -\ -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.} diff --git a/Source/Installer/main.m b/Source/Installer/main.m deleted file mode 100644 index 103bf28f8ea85bae81cbec7f065046ad644b2bf5..0000000000000000000000000000000000000000 --- a/Source/Installer/main.m +++ /dev/null @@ -1,33 +0,0 @@ -// -// main.m -// -// Copyright (c) 2011-2012 The McBopomofo Project. -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import - -int main(int argc, char *argv[]) -{ - return NSApplicationMain(argc, (const char **)argv); -} diff --git a/Source/Installer/zh-Hant.lproj/InfoPlist.strings b/Source/Installer/zh-Hant.lproj/InfoPlist.strings deleted file mode 100644 index 929742bd6d05096f2443bc46d325b8c318866aca..0000000000000000000000000000000000000000 --- a/Source/Installer/zh-Hant.lproj/InfoPlist.strings +++ /dev/null @@ -1,5 +0,0 @@ -/* Localized versions of Info.plist keys */ - -CFBundleName = "安裝小麥注音"; -NSHumanReadableCopyright = "Copyright © 2011-2021 Mengjuei Hsieh et al.\nAll Rights Reserved."; - diff --git a/Source/Installer/zh-Hant.lproj/License.rtf b/Source/Installer/zh-Hant.lproj/License.rtf deleted file mode 100644 index 24d7d652b17c481c09a0f275785b6d268f3ac246..0000000000000000000000000000000000000000 --- a/Source/Installer/zh-Hant.lproj/License.rtf +++ /dev/null @@ -1,52 +0,0 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820 -{\fonttbl\f0\fnil\fcharset0 LucidaGrande-Bold;\f1\fnil\fcharset0 LucidaGrande;\f2\fnil\fcharset136 PingFangTC-Regular; -} -{\colortbl;\red255\green255\blue255;} -{\*\expandedcolortbl;;} -\margl1440\margr1440\vieww16860\viewh12620\viewkind0 -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 - -\f0\b\fs36 \cf0 McBopomofo License Agreement -\f1\b0\fs24 \ -\ -Copyright \'a9 2011-2021 Mengjuei Hsieh et al.\ - -\f2 \cf0 \'b5\'db\'a7\'40\'c5\'76\'a7\'51\'a9\'d2\'a6\'b3 -\f1 \'a9 2011-2021 Mengjuei Hsieh -\f2 \'b5\'a5\'a4\'48 -\f1 \ -\ - -\f2 \'b3\'6e\'c5\'e9\'aa\'ba\'b5\'db\'a7\'40\'c5\'76\'a7\'51\'a4\'48\'a8\'cc\'a6\'b9 -\f1 MIT -\f2 \'b1\'c2\'c5\'76\'b1\'f8\'b4\'da\'a1\'41\'b1\'4e\'a8\'e4\'b9\'ef\'a9\'f3\'b3\'6e\'c5\'e9\'aa\'ba\'b5\'db\'a7\'40\'c5\'76\'a7\'51\'b1\'c2\'c5\'76\'c4\'c0\'a5\'58\'a1\'41\'a5\'75\'ad\'6e\'a8\'cf\'a5\'ce\'aa\'cc\'bd\'ee\'bc\'69\'a5\'48\'a4\'55\'a4\'47\'b6\'b5\'b1\'c2\'c5\'76\'b1\'f8\'b4\'da\'b1\'d4\'a9\'fa\'aa\'ba\'b8\'71\'b0\'c8\'a9\'ca\'b3\'57\'a9\'77\'a1\'41\'a8\'e4\'a7\'59\'a8\'c9\'a6\'b3\'b9\'ef\'a6\'b9\'b3\'6e\'c5\'e9\'b5\'7b\'a6\'a1\'a4\'ce\'a8\'e4\'ac\'db\'c3\'f6\'bb\'a1\'a9\'fa\'a4\'e5\'c0\'c9\'a6\'db\'a5\'d1\'a4\'a3\'a8\'fc\'ad\'ad\'a8\'ee\'a6\'61\'b6\'69\'a6\'e6\'a7\'51\'a5\'ce\'aa\'ba\'c5\'76\'a7\'51\'a1\'41\'bd\'64\'b3\'f2\'a5\'5d\'ac\'41\'a1\'75\'a8\'cf\'a5\'ce\'a1\'42\'ad\'ab\'bb\'73\'a1\'42\'ad\'d7\'a7\'ef\'a1\'42\'a6\'58\'a8\'d6\'a1\'42\'a5\'58\'aa\'a9\'a1\'42\'b4\'b2\'a5\'ac\'a1\'42\'a6\'41\'b1\'c2\'c5\'76\'a1\'42\'a4\'ce\'b3\'63\'b0\'e2\'b5\'7b\'a6\'a1\'ad\'ab\'bb\'73\'a7\'40\'ab\'7e\'a1\'76\'b5\'a5\'bd\'d1\'a6\'68\'a4\'e8\'ad\'b1\'aa\'ba\'c0\'b3\'a5\'ce\'a1\'41\'a6\'d3\'b4\'b2\'a5\'ac\'b5\'7b\'a6\'a1\'a4\'a7\'a4\'48\'a1\'42\'a7\'f3\'a5\'69\'b1\'4e\'a4\'57\'ad\'7a\'c5\'76\'a7\'51\'b6\'c7\'bb\'bc\'a4\'a9\'a8\'e4\'ab\'e1\'a6\'ac\'a8\'fc\'b5\'7b\'a6\'a1\'aa\'ba\'ab\'e1\'a4\'e2\'a1\'41\'ad\'d5\'ad\'59\'a8\'e4\'ab\'e1\'a6\'ac\'a8\'fc\'b5\'7b\'a6\'a1\'a4\'a7\'a4\'48\'a5\'e7\'aa\'41\'c1\'74\'a5\'48\'a4\'55\'a4\'47\'b6\'b5\'b1\'c2\'c5\'76\'b1\'f8\'b4\'da\'aa\'ba\'b8\'71\'b0\'c8\'a9\'ca\'b3\'57\'a9\'77\'a1\'41\'ab\'68\'a8\'e4\'b9\'ef\'b5\'7b\'a6\'a1\'a5\'e7\'a8\'c9\'a6\'b3\'bb\'50\'ab\'65\'a4\'e2\'b9\'42\'a5\'ce\'bd\'64\'b3\'f2\'ac\'db\'a6\'50\'aa\'ba\'a6\'50\'a4\'40\'c5\'76\'a7\'51\'a1\'43 -\f1 \ -\ - -\f2 \'b4\'b2\'a5\'ac\'a6\'b9\'a4\'40\'b3\'6e\'c5\'e9\'b5\'7b\'a6\'a1\'aa\'cc\'a1\'41\'b6\'b7\'b1\'4e\'a5\'bb\'b1\'f8\'b4\'da\'a8\'e4\'a4\'57\'aa\'ba\'a1\'75\'b5\'db\'a7\'40\'c5\'76\'c1\'6e\'a9\'fa\'a1\'76\'a4\'ce\'a5\'48\'a4\'55\'aa\'ba\'a1\'75\'a7\'4b\'b3\'64\'c1\'6e\'a9\'fa\'a1\'76\'a1\'41\'a4\'ba\'b4\'4f\'a9\'f3\'b3\'6e\'c5\'e9\'b5\'7b\'a6\'a1\'a4\'ce\'a8\'e4\'ad\'ab\'bb\'73\'a7\'40\'ab\'7e\'aa\'ba\'b9\'ea\'c5\'e9\'a4\'a7\'a4\'a4\'a1\'43 -\f1 \ -\ - -\f2 \'a6\'5d -\f1 MIT -\f2 \'b3\'6e\'c5\'e9\'b5\'7b\'a6\'a1\'aa\'ba\'b1\'c2\'c5\'76\'bc\'d2\'a6\'a1\'a4\'44\'ac\'4f\'b5\'4c\'c0\'76\'b4\'a3\'a8\'d1\'a1\'41\'ac\'4f\'a5\'48\'a6\'62\'b2\'7b\'a6\'e6\'aa\'6b\'ab\'df\'aa\'ba\'ac\'5b\'ba\'63\'a4\'55\'a5\'69\'a5\'48\'a5\'44\'b1\'69\'a6\'58\'b2\'7a\'aa\'ba\'a7\'4b\'b0\'a3\'be\'e1\'ab\'4f\'b3\'64\'a5\'f4\'a1\'43 -\f1 MIT -\f2 \'b3\'6e\'c5\'e9\'aa\'ba\'b5\'db\'a7\'40\'c5\'76\'a4\'48\'a9\'ce\'a5\'f4\'a6\'f3\'aa\'ba\'ab\'e1\'c4\'f2\'b4\'b2\'a5\'ac\'aa\'cc\'a1\'41\'b9\'ef\'a9\'f3\'a8\'e4\'a9\'d2\'b4\'b2\'a5\'ac\'aa\'ba -\f1 MIT -\f2 \'b3\'6e\'c5\'e9\'b5\'7b\'a6\'a1\'ac\'d2\'a4\'a3\'ad\'74\'a5\'f4\'a6\'f3\'a7\'ce\'a6\'a1\'a4\'57\'b9\'ea\'bd\'e8\'a4\'57\'aa\'ba\'be\'e1\'ab\'4f\'b3\'64\'a5\'f4\'a1\'41\'a9\'fa\'a5\'dc\'a5\'e7\'a9\'ce\'c1\'f4\'b3\'eb\'a1\'42\'b0\'d3\'b7\'7e\'a7\'51\'a5\'ce\'a9\'ca\'a5\'e7\'a9\'ce\'af\'53\'a9\'77\'a5\'d8\'aa\'ba\'a8\'cf\'a5\'ce\'a9\'ca\'a1\'41\'b3\'6f\'a8\'c7\'a7\'a1\'a4\'a3\'a6\'62\'ab\'4f\'bb\'d9\'a4\'a7\'a6\'43\'a1\'43\'a7\'51\'a5\'ce -\f1 MIT -\f2 \'b3\'6e\'c5\'e9\'b5\'7b\'a6\'a1\'aa\'ba\'a9\'d2\'a6\'b3\'ad\'b7\'c0\'49\'a7\'a1\'a5\'d1\'a8\'cf\'a5\'ce\'aa\'cc\'a6\'db\'a6\'e6\'be\'e1\'ad\'74\'a1\'43\'b0\'b2\'a6\'70\'a9\'d2\'a8\'cf\'a5\'ce\'aa\'ba -\f1 MIT -\f2 \'b5\'7b\'a6\'a1\'b5\'6f\'a5\'cd\'af\'ca\'b3\'b4\'a9\'ca\'b0\'dd\'c3\'44\'a1\'41\'a8\'cf\'a5\'ce\'aa\'cc\'bb\'dd\'a6\'db\'a6\'e6\'be\'e1\'ad\'74\'ad\'d7\'a5\'bf\'a1\'42\'a7\'ef\'a5\'bf\'a4\'ce\'a5\'b2\'ad\'6e\'aa\'ba\'aa\'41\'b0\'c8\'a4\'e4\'a5\'58\'a1\'43 -\f1 MIT -\f2 \'b3\'6e\'c5\'e9\'b5\'7b\'a6\'a1\'aa\'ba\'b5\'db\'a7\'40\'c5\'76\'a4\'48\'a4\'a3\'ad\'74\'a5\'f4\'a6\'f3\'a7\'ce\'a6\'a1\'a4\'57\'b9\'ea\'bd\'e8\'a4\'57\'aa\'ba\'be\'e1\'ab\'4f\'b3\'64\'a5\'f4\'a1\'41\'b5\'4c\'bd\'d7\'a5\'f4\'a6\'f3\'a4\'40\'af\'eb\'aa\'ba\'a1\'42\'af\'53\'ae\'ed\'aa\'ba\'a1\'42\'b0\'b8\'b5\'6f\'aa\'ba\'a1\'42\'a6\'5d\'aa\'47\'c3\'f6\'ab\'59\'a6\'a1\'aa\'ba\'b7\'6c\'ae\'60\'a1\'41\'a9\'ce\'ac\'4f -\f1 MIT -\f2 \'b3\'6e\'c5\'e9\'b5\'7b\'a6\'a1\'aa\'ba\'a4\'a3\'be\'41\'a5\'ce\'a9\'ca\'a1\'41\'a7\'a1\'b6\'b7\'a5\'d1\'a8\'cf\'a5\'ce\'aa\'cc\'a6\'db\'a6\'e6\'ad\'74\'be\'e1\'a1\'43 -\f1 \ -\ -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \'93Software\'94), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\ -\ -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\ -\ -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\ -} diff --git a/Source/Installer/zh-Hant.lproj/Localizable.strings b/Source/Installer/zh-Hant.lproj/Localizable.strings deleted file mode 100644 index 5a492caa1380308d0bd64e83f39664808273120a..0000000000000000000000000000000000000000 --- a/Source/Installer/zh-Hant.lproj/Localizable.strings +++ /dev/null @@ -1,39 +0,0 @@ -/* No comment provided by engineer. */ -"%@ (for version %@)" = "%1$@ (%2$@ 版)"; - -/* No comment provided by engineer. */ -"Agree and Upgrade" = "同意並升級"; - -/* No comment provided by engineer. */ -"Cancel" = "取消"; - -/* No comment provided by engineer. */ -"Cannot activate the input method." = "無法啟用輸入法。"; - -/* No comment provided by engineer. */ -"Cannot copy the file to the destination." = "無法將輸入法拷貝至目的地。"; - -/* No comment provided by engineer. */ -"Install Failed" = "安裝失敗"; - -/* No comment provided by engineer. */ -"Installation Successful" = "安裝成功"; - -/* No comment provided by engineer. */ -"OK" = "好"; - -/* No comment provided by engineer. */ -"McBopomofo is ready to use." = "小麥注音輸入法安裝成功"; - -"Finish" = "結束"; -"Attention" = "請注意"; -"McBopomofo is upgraded, but please log out or reboot for the new version to be fully functional." = "McBopomofo 安裝完成,但建議您登出或重新開機,以便順利使用新版。"; - -"Fatal Error" = "安裝錯誤"; -"Abort" = "放棄安裝"; -"Cannot register input source %@ at %@." = "無法從檔案位置 %2$@ 安裝輸入法 \"%1$@\"。"; -"Cannot find input source %@ after registration." = "在註冊完輸入法 \"%@\" 仍然無法找到輸入法。"; - -"Warning" = "安裝不完整"; -"Input method may not be fully enabled. Please enable it through System Preferences > Keyboard > Input Sources." = "輸入法已經安裝好,但可能沒有完全啟用。請從「系統偏好設定」 > 「鍵盤」 > 「輸入方式」分頁加入輸入法。"; -"Continue" = "繼續"; diff --git a/Source/Installer/zh-Hant.lproj/MainMenu.xib b/Source/Installer/zh-Hant.lproj/MainMenu.xib deleted file mode 100644 index c9bcd182cef030926a6bfd0a58d36ef08c9e917e..0000000000000000000000000000000000000000 --- a/Source/Installer/zh-Hant.lproj/MainMenu.xib +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Source/Modules/.gitignore b/Source/Modules/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..2dff2f0c9a277436692376e0ca80793ba437cd72 --- /dev/null +++ b/Source/Modules/.gitignore @@ -0,0 +1 @@ +cmake-build-debug diff --git a/Source/Modules/AppDelegate.swift b/Source/Modules/AppDelegate.swift new file mode 100644 index 0000000000000000000000000000000000000000..d0647f188a9d0605cc680b504b1fc983a7ba02b8 --- /dev/null +++ b/Source/Modules/AppDelegate.swift @@ -0,0 +1,235 @@ + +import Cocoa +import InputMethodKit + +private let kCheckUpdateAutomatically = "CheckUpdateAutomatically" +private let kNextUpdateCheckDateKey = "NextUpdateCheckDate" +private let kUpdateInfoEndpointKey = "UpdateInfoEndpoint" +private let kUpdateInfoSiteKey = "UpdateInfoSite" +private let kNextCheckInterval: TimeInterval = 86400.0 +private let kTimeoutInterval: TimeInterval = 60.0 + +struct VersionUpdateReport { + var siteUrl: URL? + var currentShortVersion: String = "" + var currentVersion: String = "" + var remoteShortVersion: String = "" + var remoteVersion: String = "" + var versionDescription: String = "" +} + +enum VersionUpdateApiResult { + case shouldUpdate(report: VersionUpdateReport) + case noNeedToUpdate + case ignored +} + +enum VersionUpdateApiError: Error, LocalizedError { + case connectionError(message: String) + + var errorDescription: String? { + switch self { + case .connectionError(let message): + return String(format: NSLocalizedString("There may be no internet connection or the server failed to respond.\n\nError message: %@", comment: ""), message) + } + } +} + +struct VersionUpdateApi { + static func check(forced: Bool, callback: @escaping (Result) -> ()) -> URLSessionTask? { + guard let infoDict = Bundle.main.infoDictionary, + let updateInfoURLString = infoDict[kUpdateInfoEndpointKey] as? String, + let updateInfoURL = URL(string: updateInfoURLString) else { + return nil + } + + let request = URLRequest(url: updateInfoURL, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: kTimeoutInterval) + let task = URLSession.shared.dataTask(with: request) { data, response, error in + if let error = error { + DispatchQueue.main.async { + forced ? + callback(.failure(VersionUpdateApiError.connectionError(message: error.localizedDescription))) : + callback(.success(.ignored)) + } + return + } + + do { + guard let plist = try PropertyListSerialization.propertyList(from: data ?? Data(), options: [], format: nil) as? [AnyHashable: Any], + let remoteVersion = plist[kCFBundleVersionKey] as? String, + let infoDict = Bundle.main.infoDictionary + else { + DispatchQueue.main.async { + forced ? callback(.success(.noNeedToUpdate)) : callback(.success(.ignored)) + } + return + } + + // TODO: Validate info (e.g. bundle identifier) + // TODO: Use HTML to display change log, need a new key like UpdateInfoChangeLogURL for this + + let currentVersion = infoDict[kCFBundleVersionKey as String] as? String ?? "" + let result = currentVersion.compare(remoteVersion, options: .numeric, range: nil, locale: nil) + + if result != .orderedAscending { + DispatchQueue.main.async { + forced ? callback(.success(.noNeedToUpdate)) : callback(.success(.ignored)) + } + return + } + + guard let siteInfoURLString = plist[kUpdateInfoSiteKey] as? String, + let siteInfoURL = URL(string: siteInfoURLString) + else { + DispatchQueue.main.async { + forced ? callback(.success(.noNeedToUpdate)) : callback(.success(.ignored)) + } + return + } + + var report = VersionUpdateReport(siteUrl: siteInfoURL) + var versionDescription = "" + let versionDescriptions = plist["Description"] as? [AnyHashable: Any] + if let versionDescriptions = versionDescriptions { + var locale = "en" + let supportedLocales = ["en", "zh-Hant", "zh-Hans"] + let preferredTags = Bundle.preferredLocalizations(from: supportedLocales) + if let first = preferredTags.first { + locale = first + } + versionDescription = versionDescriptions[locale] as? String ?? versionDescriptions["en"] as? String ?? "" + if !versionDescription.isEmpty { + versionDescription = "\n\n" + versionDescription + } + } + report.currentShortVersion = infoDict["CFBundleShortVersionString"] as? String ?? "" + report.currentVersion = currentVersion + report.remoteShortVersion = plist["CFBundleShortVersionString"] as? String ?? "" + report.remoteVersion = remoteVersion + report.versionDescription = versionDescription + DispatchQueue.main.async { + callback(.success(.shouldUpdate(report: report))) + } + } catch { + DispatchQueue.main.async { + forced ? callback(.success(.noNeedToUpdate)) : callback(.success(.ignored)) + } + } + } + task.resume() + return task + } +} + +@objc(AppDelegate) +class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControllerDelegate { + + @IBOutlet weak var window: NSWindow? + private var ctlPrefWindowInstance: ctlPrefWindow? + private var checkTask: URLSessionTask? + private var updateNextStepURL: URL? + private var fsStreamHelper = FSEventStreamHelper(path: mgrLangModel.dataFolderPath, queue: DispatchQueue(label: "User Phrases")) + + func applicationDidFinishLaunching(_ notification: Notification) { + mgrLangModel.setupDataModelValueConverter() + mgrLangModel.loadUserPhrases() + mgrLangModel.loadUserPhraseReplacement() + fsStreamHelper.delegate = self + _ = fsStreamHelper.start() + + if UserDefaults.standard.object(forKey: kCheckUpdateAutomatically) == nil { + UserDefaults.standard.set(true, forKey: kCheckUpdateAutomatically) + UserDefaults.standard.synchronize() + } + checkForUpdate() + } + + @objc func showPreferences() { + if ctlPrefWindowInstance == nil { + ctlPrefWindowInstance = ctlPrefWindow(windowNibName: "frmPrefWIndow") + } + ctlPrefWindowInstance?.window?.center() + ctlPrefWindowInstance?.window?.orderFront(self) + } + + @objc(checkForUpdate) + func checkForUpdate() { + checkForUpdate(forced: false) + } + + @objc(checkForUpdateForced:) + func checkForUpdate(forced: Bool) { + + if checkTask != nil { + // busy + return + } + + // time for update? + if !forced { + if UserDefaults.standard.bool(forKey: kCheckUpdateAutomatically) == false { + return + } + let now = Date() + let date = UserDefaults.standard.object(forKey: kNextUpdateCheckDateKey) as? Date ?? now + if now.compare(date) == .orderedAscending { + return + } + } + + let nextUpdateDate = Date(timeInterval: kNextCheckInterval, since: Date()) + UserDefaults.standard.set(nextUpdateDate, forKey: kNextUpdateCheckDateKey) + + checkTask = VersionUpdateApi.check(forced: forced) { result in + defer { + self.checkTask = nil + } + switch result { + case .success(let apiResult): + switch apiResult { + case .shouldUpdate(let report): + self.updateNextStepURL = report.siteUrl + let content = String(format: NSLocalizedString("You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?%@", comment: ""), + report.currentShortVersion, + report.currentVersion, + report.remoteShortVersion, + report.remoteVersion, + report.versionDescription) + NonModalAlertWindowController.shared.show(title: NSLocalizedString("New Version Available", comment: ""), content: content, confirmButtonTitle: NSLocalizedString("Visit Website", comment: ""), cancelButtonTitle: NSLocalizedString("Not Now", comment: ""), cancelAsDefault: false, delegate: self) + case .noNeedToUpdate, .ignored: + break + } + case .failure(let error): + switch error { + case VersionUpdateApiError.connectionError(let message): + let title = NSLocalizedString("Update Check Failed", comment: "") + let content = String(format: NSLocalizedString("There may be no internet connection or the server failed to respond.\n\nError message: %@", comment: ""), message) + let buttonTitle = NSLocalizedString("Dismiss", comment: "") + NonModalAlertWindowController.shared.show(title: title, content: content, confirmButtonTitle: buttonTitle, cancelButtonTitle: nil, cancelAsDefault: false, delegate: nil) + default: + break + } + } + } + } + + func nonModalAlertWindowControllerDidConfirm(_ controller: NonModalAlertWindowController) { + if let updateNextStepURL = updateNextStepURL { + NSWorkspace.shared.open(updateNextStepURL) + } + updateNextStepURL = nil + } + + func nonModalAlertWindowControllerDidCancel(_ controller: NonModalAlertWindowController) { + updateNextStepURL = nil + } +} + +extension AppDelegate: FSEventStreamHelperDelegate { + func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event]) { + DispatchQueue.main.async { + mgrLangModel.loadUserPhrases() + mgrLangModel.loadUserPhraseReplacement() + } + } +} diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift new file mode 100644 index 0000000000000000000000000000000000000000..cec70e4f9f7ff3a18460ea0a02ce4967ddc006d8 --- /dev/null +++ b/Source/Modules/ControllerModules/InputState.swift @@ -0,0 +1,343 @@ + +import Cocoa + +/// Represents the states for the input method controller. +/// +/// An input method is actually a finite state machine. It receives the inputs +/// from hardware like keyboard and mouse, changes its state, updates user +/// interface by the state, and finally produces the text output and then them +/// to the client apps. It should be a one-way data flow, and the user interface +/// and text output should follow unconditionally one single data source. +/// +/// The InputState class is for representing what the input controller is doing, +/// and the place to store the variables that could be used. For example, the +/// array for the candidate list is useful only when the user is choosing a +/// candidate, and the array should not exist when the input controller is in +/// another state. +/// +/// They are immutable objects. When the state changes, the controller should +/// create a new state object to replace the current state instead of modifying +/// the existing one. +/// +/// vChewing's input controller has following possible states: +/// +/// - Deactivated: The user is not using vChewing yet. +/// - Empty: The user has switched to vChewing but did not input anything yet, +/// or, he or she has committed text into the client apps and starts a new +/// input phase. +/// - Committing: The input controller is sending text to the client apps. +/// - Inputting: The user has inputted something and the input buffer is +/// visible. +/// - Marking: The user is creating a area in the input buffer and about to +/// create a new user phrase. +/// - Choosing Candidate: The candidate window is open to let the user to choose +/// one among the candidates. +class InputState: NSObject { + + /// Represents that the input controller is deactivated. + @objc (InputStateDeactivated) + class Deactivated: InputState { + override var description: String { + "" + } + } + + // MARK: - + + /// Represents that the composing buffer is empty. + @objc (InputStateEmpty) + class Empty: InputState { + @objc var composingBuffer: String { + "" + } + + override var description: String { + "" + } + } + + // MARK: - + + /// Represents that the composing buffer is empty. + @objc (InputStateEmptyIgnoringPreviousState) + class EmptyIgnoringPreviousState: InputState { + @objc var composingBuffer: String { + "" + } + override var description: String { + "" + } + } + + // MARK: - + + /// Represents that the input controller is committing text into client app. + @objc (InputStateCommitting) + class Committing: InputState { + @objc private(set) var poppedText: String = "" + + @objc convenience init(poppedText: String) { + self.init() + self.poppedText = poppedText + } + + override var description: String { + "" + } + } + + // MARK: - + + /// Represents that the composing buffer is not empty. + @objc (InputStateNotEmpty) + class NotEmpty: InputState { + @objc private(set) var composingBuffer: String + @objc private(set) var cursorIndex: UInt + + @objc init(composingBuffer: String, cursorIndex: UInt) { + self.composingBuffer = composingBuffer + self.cursorIndex = cursorIndex + } + + override var description: String { + "" + } + } + + // MARK: - + + /// Represents that the user is inputting text. + @objc (InputStateInputting) + class Inputting: NotEmpty { + @objc var poppedText: String = "" + @objc var tooltip: String = "" + + @objc override init(composingBuffer: String, cursorIndex: UInt) { + super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex) + } + + @objc var attributedString: NSAttributedString { + let attributedSting = NSAttributedString(string: composingBuffer, attributes: [ + .underlineStyle: NSUnderlineStyle.single.rawValue, + .markedClauseSegment: 0 + ]) + return attributedSting + } + + override var description: String { + ", poppedText:\(poppedText)>" + } + } + + // MARK: - + + private let kMinMarkRangeLength = 2 + private let kMaxMarkRangeLength = 6 + + /// Represents that the user is marking a range in the composing buffer. + @objc (InputStateMarking) + class Marking: NotEmpty { + + @objc private(set) var markerIndex: UInt + @objc private(set) var markedRange: NSRange + @objc var tooltip: String { + + if composingBuffer.count != readings.count { + return NSLocalizedString("There are special phrases in your text. We don't support adding new phrases in this case.", comment: "") + } + + if Preferences.phraseReplacementEnabled { + return NSLocalizedString("Phrase replacement mode is on. Not suggested to add phrase in the mode.", comment: "") + } + if markedRange.length == 0 { + return "" + } + + let text = (composingBuffer as NSString).substring(with: markedRange) + if markedRange.length < kMinMarkRangeLength { + return String(format: NSLocalizedString("You are now selecting \"%@\". You can add a phrase with two or more characters.", comment: ""), text) + } else if (markedRange.length > kMaxMarkRangeLength) { + return String(format: NSLocalizedString("You are now selecting \"%@\". A phrase cannot be longer than %d characters.", comment: ""), text, kMaxMarkRangeLength) + } + + let (exactBegin, _) = (composingBuffer as NSString).characterIndex(from: markedRange.location) + let (exactEnd, _) = (composingBuffer as NSString).characterIndex(from: markedRange.location + markedRange.length) + let selectedReadings = readings[exactBegin.." + } + + @objc func convertToInputting() -> Inputting { + let state = Inputting(composingBuffer: composingBuffer, cursorIndex: cursorIndex) + state.tooltip = tooltipForInputting + return state + } + + @objc var validToWrite: Bool { + /// vChewing allows users to input a string whose length differs + /// from the amount of Bopomofo readings. In this case, the range + /// in the composing buffer and the readings could not match, so + /// we disable the function to write user phrases in this case. + if composingBuffer.count != readings.count { + return false + } + if markedRange.length < kMinMarkRangeLength { + return false + } + if markedRange.length > kMaxMarkRangeLength { + return false + } + let text = (composingBuffer as NSString).substring(with: markedRange) + let (exactBegin, _) = (composingBuffer as NSString).characterIndex(from: markedRange.location) + let (exactEnd, _) = (composingBuffer as NSString).characterIndex(from: markedRange.location + markedRange.length) + let selectedReadings = readings[exactBegin.." + } + } + + // MARK: - + + /// Represents that the user is choosing in a candidates list + /// in the associated phrases mode. + @objc (InputStateAssociatedPhrases) + class AssociatedPhrases: InputState { + @objc private(set) var candidates: [String] = [] + @objc private(set) var useVerticalMode: Bool = false + @objc init(candidates: [String], useVerticalMode: Bool) { + self.candidates = candidates + self.useVerticalMode = useVerticalMode + super.init() + } + + override var description: String { + "" + } + } + + @objc (InputStateSymbolTable) + class SymbolTable: ChoosingCandidate { + @objc var node: SymbolNode + + @objc init(node: SymbolNode, useVerticalMode: Bool) { + self.node = node + let candidates = node.children?.map { $0.title } ?? [String]() + super.init(composingBuffer: "", cursorIndex: 0, candidates: candidates, useVerticalMode: useVerticalMode) + } + + override var description: String { + "" + } + } + +} + +@objc class SymbolNode: NSObject { + @objc var title: String + @objc var children: [SymbolNode]? + + @objc init(_ title: String, _ children: [SymbolNode]? = nil) { + self.title = title + self.children = children + super.init() + } + + @objc init(_ title: String, symbols: String) { + self.title = title + self.children = Array(symbols).map { SymbolNode(String($0), nil) } + super.init() + } + + @objc static let root: SymbolNode = SymbolNode("/", [ + SymbolNode("…"), + SymbolNode("※"), + SymbolNode("常用符號", symbols:",、。.?!;:‧‥﹐﹒˙·‘’“”〝〞‵′〃~$%@&#*"), + SymbolNode("左右括號", symbols:"()「」〔〕{}〈〉『』《》【】﹙﹚﹝﹞﹛﹜"), + SymbolNode("上下括號", symbols:"︵︶﹁﹂︹︺︷︸︿﹀﹃﹄︽︾︻︼"), + SymbolNode("希臘字母", symbols:"αβγδεζηθικλμνξοπρστυφχψωΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ"), + SymbolNode("數學符號", symbols:"+-×÷=≠≒∞±√<>﹤﹥≦≧∩∪ˇ⊥∠∟⊿㏒㏑∫∮∵∴╳﹢"), + SymbolNode("特殊圖形", symbols:"↑↓←→↖↗↙↘㊣◎○●⊕⊙○●△▲☆★◇◆□■▽▼§¥〒¢£※♀♂"), + SymbolNode("Unicode", symbols:"♨☀☁☂☃♠♥♣♦♩♪♫♬☺☻"), + SymbolNode("單線框", symbols:"├─┼┴┬┤┌┐╞═╪╡│▕└┘╭╮╰╯"), + SymbolNode("雙線框", symbols:"╔╦╗╠═╬╣╓╥╖╒╤╕║╚╩╝╟╫╢╙╨╜╞╪╡╘╧╛"), + SymbolNode("填色方塊", symbols:"_ˍ▁▂▃▄▅▆▇█▏▎▍▌▋▊▉◢◣◥◤"), + SymbolNode("線段", symbols:"﹣﹦≡|∣∥–︱—︳╴¯ ̄﹉﹊﹍﹎﹋﹌﹏︴∕﹨╱╲/\"), + ]) +} diff --git a/Source/Modules/ControllerModules/KeyHandler.h b/Source/Modules/ControllerModules/KeyHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..0b585376ac8cc3cb1cd4155c347081d07061572c --- /dev/null +++ b/Source/Modules/ControllerModules/KeyHandler.h @@ -0,0 +1,39 @@ + +#import + +@class KeyHandlerInput; +@class InputState; + +NS_ASSUME_NONNULL_BEGIN + +typedef NSString *const InputMode NS_TYPED_ENUM; +extern InputMode InputModeBopomofo; +extern InputMode InputModePlainBopomofo; + +@class KeyHandler; + +@protocol KeyHandlerDelegate +- (id)candidateControllerForKeyHandler:(KeyHandler *)keyHandler; +- (void)keyHandler:(KeyHandler *)keyHandler didSelectCandidateAtIndex:(NSInteger)index candidateController:(id)controller; +- (BOOL)keyHandler:(KeyHandler *)keyHandler didRequestWriteUserPhraseWithState:(InputState *)state; +@end + +@interface KeyHandler : NSObject + +- (BOOL)handleInput:(KeyHandlerInput *)input + state:(InputState *)state + stateCallback:(void (^)(InputState *))stateCallback + errorCallback:(void (^)(void))errorCallback NS_SWIFT_NAME(handle(input:state:stateCallback:errorCallback:)); + +- (void)syncWithPreferences; +- (void)fixNodeWithValue:(NSString *)value NS_SWIFT_NAME(fixNode(value:)); +- (void)clear; + +- (InputState *)buildInputtingState; +- (nullable InputState *)buildAssociatePhraseStateWithKey:(NSString *)key useVerticalMode:(BOOL)useVerticalMode; + +@property (strong, nonatomic) InputMode inputMode; +@property (weak, nonatomic) id delegate; +@end + +NS_ASSUME_NONNULL_END diff --git a/Source/Modules/ControllerModules/KeyHandler.mm b/Source/Modules/ControllerModules/KeyHandler.mm new file mode 100644 index 0000000000000000000000000000000000000000..18eef860cc9c01a79372ae36b4a09ffe7f20651c --- /dev/null +++ b/Source/Modules/ControllerModules/KeyHandler.mm @@ -0,0 +1,1319 @@ + +#import "Mandarin.h" +#import "Gramambular.h" +#import "vChewingLM.h" +#import "UserOverrideModel.h" +#import "mgrLangModel_Privates.h" +#import "KeyHandler.h" +#import "vChewing-Swift.h" +#import + +// C++ namespace usages +using namespace std; +using namespace Taiyan::Mandarin; +using namespace Taiyan::Gramambular; +using namespace vChewing; + +InputMode InputModeBopomofo = @"org.atelierInmu.inputmethod.vChewing.IMECHT"; +InputMode InputModePlainBopomofo = @"org.atelierInmu.inputmethod.vChewing.IMECHS"; + +static const double kEpsilon = 0.000001; + +static double FindHighestScore(const vector &nodes, double epsilon) { + double highestScore = 0.0; + for (auto ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) { + double score = ni->node->highestUnigramScore(); + if (score > highestScore) { + highestScore = score; + } + } + return highestScore + epsilon; +} + +// sort helper +class NodeAnchorDescendingSorter +{ +public: + bool operator()(const NodeAnchor &a, const NodeAnchor &b) const { + return a.node->key().length() > b.node->key().length(); + } +}; + +// if DEBUG is defined, a DOT file (GraphViz format) will be written to the +// specified path every time the grid is walked +#if DEBUG +static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; +#endif + + +@implementation KeyHandler +{ + // the reading buffer that takes user input + Taiyan::Mandarin::BopomofoReadingBuffer *_bpmfReadingBuffer; + + // language model + vChewing::vChewingLM *_languageModel; + + // user override model + vChewing::UserOverrideModel *_userOverrideModel; + + // the grid (lattice) builder for the unigrams (and bigrams) + Taiyan::Gramambular::BlockReadingBuilder *_builder; + + // latest walked path (trellis) using the Viterbi algorithm + std::vector _walkedNodes; + + NSString *_inputMode; +} + +//@synthesize inputMode = _inputMode; +@synthesize delegate = _delegate; + +- (NSString *)inputMode +{ + return _inputMode; +} + +- (void)setInputMode:(NSString *)value +{ + NSString *newInputMode; + vChewingLM *newLanguageModel; + + if ([value isKindOfClass:[NSString class]] && [value isEqual:InputModePlainBopomofo]) { + newInputMode = InputModePlainBopomofo; + newLanguageModel = [mgrLangModel languageModelPlainBopomofo]; + newLanguageModel->setPhraseReplacementEnabled(false); + } else { + newInputMode = InputModeBopomofo; + newLanguageModel = [mgrLangModel languageModelvChewing]; + newLanguageModel->setPhraseReplacementEnabled(Preferences.phraseReplacementEnabled); + } + + // Only apply the changes if the value is changed + if (![_inputMode isEqualToString:newInputMode]) { + _inputMode = newInputMode; + _languageModel = newLanguageModel; + + if (_builder) { + delete _builder; + _builder = new BlockReadingBuilder(_languageModel); + _builder->setJoinSeparator("-"); + } + + if (!_bpmfReadingBuffer->isEmpty()) { + _bpmfReadingBuffer->clear(); + } + } +} + +- (void)dealloc +{ + // clean up everything + if (_bpmfReadingBuffer) { + delete _bpmfReadingBuffer; + } + + if (_builder) { + delete _builder; + } +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _bpmfReadingBuffer = new BopomofoReadingBuffer(BopomofoKeyboardLayout::StandardLayout()); + + // create the lattice builder + _languageModel = [mgrLangModel languageModelvChewing]; + _languageModel->setPhraseReplacementEnabled(Preferences.phraseReplacementEnabled); + _userOverrideModel = [mgrLangModel userOverrideModel]; + + _builder = new BlockReadingBuilder(_languageModel); + + // each Mandarin syllable is separated by a hyphen + _builder->setJoinSeparator("-"); + _inputMode = InputModeBopomofo; + } + return self; +} + +- (void)syncWithPreferences +{ + NSInteger layout = Preferences.keyboardLayout; + switch (layout) { + case KeyboardLayoutStandard: + _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::StandardLayout()); + break; + case KeyboardLayoutEten: + _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::ETenLayout()); + break; + case KeyboardLayoutHsu: + _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::HsuLayout()); + break; + case KeyboardLayoutEten26: + _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::ETen26Layout()); + break; + case KeyboardLayoutHanyuPinyin: + _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::HanyuPinyinLayout()); + break; + case KeyboardLayoutIBM: + _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::IBMLayout()); + break; + default: + _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::StandardLayout()); + Preferences.keyboardLayout = KeyboardLayoutStandard; + } +} + +- (void)fixNodeWithValue:(NSString *)value +{ + size_t cursorIndex = [self _actualCandidateCursorIndex]; + string stringValue = [value UTF8String]; + _builder->grid().fixNodeSelectedCandidate(cursorIndex, stringValue); + if (_inputMode != InputModePlainBopomofo) { + _userOverrideModel->observe(_walkedNodes, cursorIndex, stringValue, [[NSDate date] timeIntervalSince1970]); + } + [self _walk]; + + if (Preferences.selectPhraseAfterCursorAsCandidate && + Preferences.moveCursorAfterSelectingCandidate) { + size_t nextPosition = 0; + for (auto node: _walkedNodes) { + if (nextPosition >= cursorIndex) { + break; + } + nextPosition += node.spanningLength; + } + if (nextPosition <= _builder->length()) { + _builder->setCursorIndex(nextPosition); + } + } +} + +- (void)clear +{ + _bpmfReadingBuffer->clear(); + _builder->clear(); + _walkedNodes.clear(); +} + +- (string)_currentLayout +{ + NSString *keyboardLayoutName = Preferences.keyboardLayoutName; + string layout = string(keyboardLayoutName.UTF8String) + string("_"); + return layout; +} + +- (BOOL)handleInput:(KeyHandlerInput *)input state:(InputState *)inState stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +{ + InputState *state = inState; + UniChar charCode = input.charCode; + vChewingEmacsKey emacsKey = input.emacsKey; + + // if the inputText is empty, it's a function key combination, we ignore it + if (!input.inputText.length) { + return NO; + } + + // if the composing buffer is empty and there's no reading, and there is some function key combination, we ignore it + BOOL isFunctionKey = ([input isCommandHold] || [input isOptionHold] || [input isNumericPad]) || [input isControlHotKey]; + if (![state isKindOfClass:[InputStateNotEmpty class]] && + ![state isKindOfClass:[InputStateAssociatedPhrases class]] && + isFunctionKey) { + return NO; + } + + // Caps Lock processing : if Caps Lock is on, temporarily disable bopomofo. + if (charCode == 8 || charCode == 13 || [input isAbsorbedArrowKey] || [input isExtraChooseCandidateKey] || [input isCursorForward] || [input isCursorBackward]) { + // do nothing if backspace is pressed -- we ignore the key + } else if ([input isCapsLockOn]) { + // process all possible combination, we hope. + [self clear]; + InputStateEmpty *emptyState = [[InputStateEmpty alloc] init]; + stateCallback(emptyState); + + // first commit everything in the buffer. + if ([input isShiftHold]) { + return NO; + } + + // if ASCII but not printable, don't use insertText:replacementRange: as many apps don't handle non-ASCII char insertions. + if (charCode < 0x80 && !isprint(charCode)) { + return NO; + } + + // when shift is pressed, don't do further processing, since it outputs capital letter anyway. + InputStateCommitting *committingState = [[InputStateCommitting alloc] initWithPoppedText:[input.inputText lowercaseString]]; + stateCallback(committingState); + stateCallback(emptyState); + return YES; + } + + if ([input isNumericPad]) { + if (![input isLeft] && ![input isRight] && ![input isDown] && ![input isUp] && charCode != 32 && isprint(charCode)) { + [self clear]; + InputStateEmpty *emptyState = [[InputStateEmpty alloc] init]; + stateCallback(emptyState); + InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:[input.inputText lowercaseString]]; + stateCallback(committing); + stateCallback(emptyState); + return YES; + } + } + + // MARK: Handle Candidates + if ([state isKindOfClass:[InputStateChoosingCandidate class]]) { + return [self _handleCandidateState:state input:input stateCallback:stateCallback errorCallback:errorCallback]; + } + + // MARK: Handle Associated Phrases + if ([state isKindOfClass:[InputStateAssociatedPhrases class]]) { + BOOL result = [self _handleCandidateState:state input:input stateCallback:stateCallback errorCallback:errorCallback]; + if (result) { + return YES; + } + state = [[InputStateEmpty alloc] init]; + stateCallback(state); + } + + // MARK: Handle Marking + if ([state isKindOfClass:[InputStateMarking class]]) { + InputStateMarking *marking = (InputStateMarking *) state; + if ([self _handleMarkingState:(InputStateMarking *) state input:input stateCallback:stateCallback errorCallback:errorCallback]) { + return YES; + } + state = [marking convertToInputting]; + stateCallback(state); + } + + bool composeReading = false; + BOOL skipBpmfHandling = [input isReservedKey] || [input isControlHold]; + + // MARK: Handle BPMF Keys + + // see if it's valid BPMF reading + if (!skipBpmfHandling && _bpmfReadingBuffer->isValidKey((char) charCode)) { + _bpmfReadingBuffer->combineKey((char) charCode); + + // if we have a tone marker, we have to insert the reading to the + // builder in other words, if we don't have a tone marker, we just + // update the composing buffer + composeReading = _bpmfReadingBuffer->hasToneMarker(); + if (!composeReading) { + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + stateCallback(inputting); + return YES; + } + } + + // see if we have composition if Enter/Space is hit and buffer is not empty + // this is bit-OR'ed so that the tone marker key is also taken into account + composeReading |= (!_bpmfReadingBuffer->isEmpty() && (charCode == 32 || charCode == 13)); + if (composeReading) { + // combine the reading + string reading = _bpmfReadingBuffer->syllable().composedString(); + + // see if we have a unigram for this + if (!_languageModel->hasUnigramsForKey(reading)) { + errorCallback(); + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + stateCallback(inputting); + return YES; + } + + // and insert it into the lattice + _builder->insertReadingAtCursor(reading); + + // then walk the lattice + NSString *poppedText = [self _popOverflowComposingTextAndWalk]; + + // get user override model suggestion + string overrideValue = (_inputMode == InputModePlainBopomofo) ? "" : + _userOverrideModel->suggest(_walkedNodes, _builder->cursorIndex(), [[NSDate date] timeIntervalSince1970]); + + if (!overrideValue.empty()) { + size_t cursorIndex = [self _actualCandidateCursorIndex]; + vector nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); + double highestScore = FindHighestScore(nodes, kEpsilon); + _builder->grid().overrideNodeScoreForSelectedCandidate(cursorIndex, overrideValue, static_cast(highestScore)); + } + + // then update the text + _bpmfReadingBuffer->clear(); + + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + inputting.poppedText = poppedText; + stateCallback(inputting); + + if (_inputMode == InputModePlainBopomofo) { + InputStateChoosingCandidate *choosingCandidates = [self _buildCandidateState:inputting useVerticalMode:input.useVerticalMode]; + if (choosingCandidates.candidates.count == 1) { + [self clear]; + NSString *text = choosingCandidates.candidates.firstObject; + InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:text]; + stateCallback(committing); + + if (!Preferences.associatedPhrasesEnabled) { + InputStateEmpty *empty = [[InputStateEmpty alloc] init]; + stateCallback(empty); + } else { + InputStateAssociatedPhrases *associatedPhrases = (InputStateAssociatedPhrases *)[self buildAssociatePhraseStateWithKey:text useVerticalMode:input.useVerticalMode]; + if (associatedPhrases) { + stateCallback(associatedPhrases); + } else { + InputStateEmpty *empty = [[InputStateEmpty alloc] init]; + stateCallback(empty); + } + } + } else { + stateCallback(choosingCandidates); + } + } + + // and tells the client that the key is consumed + return YES; + } + + // MARK: Space and Down + // keyCode 125 = Down, charCode 32 = Space + if (_bpmfReadingBuffer->isEmpty() && + [state isKindOfClass:[InputStateNotEmpty class]] && + ([input isExtraChooseCandidateKey] || charCode == 32 || (input.useVerticalMode && ([input isVerticalModeOnlyChooseCandidateKey])))) { + if (charCode == 32) { + // if the spacebar is NOT set to be a selection key + if ([input isShiftHold] || !Preferences.chooseCandidateUsingSpace) { + if (_builder->cursorIndex() >= _builder->length()) { + NSString *composingBuffer = [(InputStateNotEmpty*) state composingBuffer]; + if (composingBuffer.length) { + InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:composingBuffer]; + stateCallback (committing); + } + [self clear]; + InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:@" "]; + stateCallback(committing); + InputStateEmpty *empty = [[InputStateEmpty alloc] init]; + stateCallback(empty); + } else if (_languageModel->hasUnigramsForKey(" ")) { + _builder->insertReadingAtCursor(" "); + NSString *poppedText = [self _popOverflowComposingTextAndWalk]; + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + inputting.poppedText = poppedText; + stateCallback(inputting); + } + return YES; + + } + } + InputStateChoosingCandidate *choosingCandidates = [self _buildCandidateState:(InputStateNotEmpty *) state useVerticalMode:input.useVerticalMode]; + stateCallback(choosingCandidates); + return YES; + } + + // MARK: Esc + if (charCode == 27) { + return [self _handleEscWithState:state stateCallback:stateCallback errorCallback:errorCallback]; + } + + // MARK: Cursor backward + if ([input isCursorBackward] || emacsKey == vChewingEmacsKeyBackward) { + return [self _handleBackwardWithState:state input:input stateCallback:stateCallback errorCallback:errorCallback]; + } + + // MARK: Cursor forward + if ([input isCursorForward] || emacsKey == vChewingEmacsKeyForward) { + return [self _handleForwardWithState:state input:input stateCallback:stateCallback errorCallback:errorCallback]; + } + + // MARK: Home + if ([input isHome] || emacsKey == vChewingEmacsKeyHome) { + return [self _handleHomeWithState:state stateCallback:stateCallback errorCallback:errorCallback]; + } + + // MARK: End + if ([input isEnd] || emacsKey == vChewingEmacsKeyEnd) { + return [self _handleEndWithState:state stateCallback:stateCallback errorCallback:errorCallback]; + } + + // MARK: AbsorbedArrowKey + if ([input isAbsorbedArrowKey] || [input isExtraChooseCandidateKey]) { + return [self _handleAbsorbedArrowKeyWithState:state stateCallback:stateCallback errorCallback:errorCallback]; + } + + // MARK: Backspace + if (charCode == 8) { + return [self _handleBackspaceWithState:state stateCallback:stateCallback errorCallback:errorCallback]; + } + + // MARK: Delete + if ([input isDelete] || emacsKey == vChewingEmacsKeyDelete) { + return [self _handleDeleteWithState:state stateCallback:stateCallback errorCallback:errorCallback]; + } + + // MARK: Enter + if (charCode == 13) { + return [self _handleEnterWithState:state stateCallback:stateCallback errorCallback:errorCallback]; + } + + // MARK: Punctuation list + if ((char) charCode == '`') { + InputStateEmpty *empty = [[InputStateEmpty alloc] init]; + stateCallback(empty); + + SymbolNode *root = [SymbolNode root]; + InputStateSymbolTable *symbolState = [[InputStateSymbolTable alloc] initWithNode:root useVerticalMode:input.useVerticalMode]; + stateCallback(symbolState); + return YES; +// if (_languageModel->hasUnigramsForKey(string("_punctuation_list"))) { +// if (_bpmfReadingBuffer->isEmpty()) { +// _builder->insertReadingAtCursor(string("_punctuation_list")); +// NSString *poppedText = [self _popOverflowComposingTextAndWalk]; +// InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; +// inputting.poppedText = poppedText; +// stateCallback(inputting); +// InputStateChoosingCandidate *choosingCandidate = [self _buildCandidateState:inputting useVerticalMode:input.useVerticalMode]; +// stateCallback(choosingCandidate); +// } else { // If there is still unfinished bpmf reading, ignore the punctuation +// errorCallback(); +// } +// return YES; +// } + } + + // MARK: Punctuation + // if nothing is matched, see if it's a punctuation key for current layout. + + string punctuationNamePrefix; + if ([input isControlHold]) { + punctuationNamePrefix = string("_ctrl_punctuation_"); + } else if (Preferences.halfWidthPunctuationEnabled) { + punctuationNamePrefix = string("_half_punctuation_"); + } else { + punctuationNamePrefix = string("_punctuation_"); + } + string layout = [self _currentLayout]; + string customPunctuation = punctuationNamePrefix + layout + string(1, (char) charCode); + if ([self _handlePunctuation:customPunctuation state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) { + return YES; + } + + // if nothing is matched, see if it's a punctuation key. + string punctuation = punctuationNamePrefix + string(1, (char) charCode); + if ([self _handlePunctuation:punctuation state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) { + return YES; + } + + if ((char) charCode >= 'A' && (char) charCode <= 'Z') { + string letter = string("_letter_") + string(1, (char) charCode); + if ([self _handlePunctuation:letter state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) { + return YES; + } + } + + // still nothing, then we update the composing buffer (some app has + // strange behavior if we don't do this, "thinking" the key is not + // actually consumed) + if ([state isKindOfClass:[InputStateNotEmpty class]] || !_bpmfReadingBuffer->isEmpty()) { + errorCallback(); + stateCallback(state); + return YES; + } + + return NO; +} + +- (BOOL)_handleEscWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +{ + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + + BOOL escToClearInputBufferEnabled = Preferences.escToCleanInputBuffer; + + if (escToClearInputBufferEnabled) { + // if the option is enabled, we clear everything including the composing + // buffer, walked nodes and the reading. + [self clear]; + InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init]; + stateCallback(empty); + } else { + // if reading is not empty, we cancel the reading; Apple's built-in + // Zhuyin (and the erstwhile Hanin) has a default option that Esc + // "cancels" the current composed character and revert it to + // Bopomofo reading, in odds with the expectation of users from + // other platforms + + if (!_bpmfReadingBuffer->isEmpty()) { + _bpmfReadingBuffer->clear(); + if (!_builder->length()) { + InputStateEmpty *empty = [[InputStateEmpty alloc] init]; + stateCallback(empty); + } else { + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + stateCallback(inputting); + } + } + } + return YES; +} + +- (BOOL)_handleBackwardWithState:(InputState *)state input:(KeyHandlerInput *)input stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +{ + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + + if (!_bpmfReadingBuffer->isEmpty()) { + errorCallback(); + stateCallback(state); + return YES; + } + + InputStateInputting *currentState = (InputStateInputting *) state; + + if ([input isShiftHold]) { + // Shift + left + if (currentState.cursorIndex > 0) { + NSInteger previousPosition = [currentState.composingBuffer previousUtf16PositionFor:currentState.cursorIndex]; + InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:previousPosition readings:[self _currentReadings]]; + marking.tooltipForInputting = currentState.tooltip; + stateCallback(marking); + } else { + errorCallback(); + stateCallback(state); + } + } else { + if (_builder->cursorIndex() > 0) { + _builder->setCursorIndex(_builder->cursorIndex() - 1); + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + stateCallback(inputting); + } else { + errorCallback(); + stateCallback(state); + } + } + return YES; +} + +- (BOOL)_handleForwardWithState:(InputState *)state input:(KeyHandlerInput *)input stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +{ + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + + if (!_bpmfReadingBuffer->isEmpty()) { + errorCallback(); + stateCallback(state); + return YES; + } + + InputStateInputting *currentState = (InputStateInputting *) state; + + if ([input isShiftHold]) { + // Shift + Right + if (currentState.cursorIndex < currentState.composingBuffer.length) { + NSInteger nextPosition = [currentState.composingBuffer nextUtf16PositionFor:currentState.cursorIndex]; + InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:nextPosition readings:[self _currentReadings]]; + marking.tooltipForInputting = currentState.tooltip; + stateCallback(marking); + } else { + errorCallback(); + stateCallback(state); + } + } else { + if (_builder->cursorIndex() < _builder->length()) { + _builder->setCursorIndex(_builder->cursorIndex() + 1); + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + stateCallback(inputting); + } else { + errorCallback(); + stateCallback(state); + } + } + + return YES; +} + +- (BOOL)_handleHomeWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +{ + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + + if (!_bpmfReadingBuffer->isEmpty()) { + errorCallback(); + stateCallback(state); + return YES; + } + + if (_builder->cursorIndex()) { + _builder->setCursorIndex(0); + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + stateCallback(inputting); + } else { + errorCallback(); + stateCallback(state); + } + + return YES; +} + +- (BOOL)_handleEndWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +{ + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + + if (!_bpmfReadingBuffer->isEmpty()) { + errorCallback(); + stateCallback(state); + return YES; + } + + if (_builder->cursorIndex() != _builder->length()) { + _builder->setCursorIndex(_builder->length()); + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + stateCallback(inputting); + } else { + errorCallback(); + stateCallback(state); + } + + return YES; +} + +- (BOOL)_handleAbsorbedArrowKeyWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +{ + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + + if (!_bpmfReadingBuffer->isEmpty()) { + errorCallback(); + } + stateCallback(state); + return YES; +} + +- (BOOL)_handleBackspaceWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +{ + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + + if (_bpmfReadingBuffer->isEmpty()) { + if (_builder->cursorIndex()) { + _builder->deleteReadingBeforeCursor(); + [self _walk]; + } else { + errorCallback(); + stateCallback(state); + return YES; + } + } else { + _bpmfReadingBuffer->backspace(); + } + + if (_bpmfReadingBuffer->isEmpty() && !_builder->length()) { + InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init]; + stateCallback(empty); + } else { + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + stateCallback(inputting); + } + return YES; +} + +- (BOOL)_handleDeleteWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +{ + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + + if (_bpmfReadingBuffer->isEmpty()) { + if (_builder->cursorIndex() != _builder->length()) { + _builder->deleteReadingAfterCursor(); + [self _walk]; + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + if (!inputting.composingBuffer.length) { + InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init]; + stateCallback(empty); + } else { + stateCallback(inputting); + } + } else { + errorCallback(); + stateCallback(state); + } + } else { + errorCallback(); + stateCallback(state); + } + + return YES; +} + +- (BOOL)_handleEnterWithState:(InputState *)state stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +{ + if (![state isKindOfClass:[InputStateInputting class]]) { + return NO; + } + +// Actually the lines would not be reached. When there is BMPF reading and +// a user input enter, we just send the readings to the client app. + +// if (_inputMode == InputModePlainBopomofo) { +// if (!_bpmfReadingBuffer->isEmpty()) { +// errorCallback(); +// } +// return YES; +// } + + [self clear]; + + InputStateInputting *current = (InputStateInputting *) state; + NSString *composingBuffer = current.composingBuffer; + InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:composingBuffer]; + stateCallback(committing); + InputStateEmpty *empty = [[InputStateEmpty alloc] init]; + stateCallback(empty); + return YES; +} + +- (BOOL)_handlePunctuation:(string)customPunctuation state:(InputState *)state usingVerticalMode:(BOOL)useVerticalMode stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +{ + if (!_languageModel->hasUnigramsForKey(customPunctuation)) { + return NO; + } + + NSString *poppedText; + if (_bpmfReadingBuffer->isEmpty()) { + _builder->insertReadingAtCursor(customPunctuation); + poppedText = [self _popOverflowComposingTextAndWalk]; + } else { // If there is still unfinished bpmf reading, ignore the punctuation + errorCallback(); + stateCallback(state); + return YES; + } + + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + inputting.poppedText = poppedText; + stateCallback(inputting); + + if (_inputMode == InputModePlainBopomofo && _bpmfReadingBuffer->isEmpty()) { + InputStateChoosingCandidate *candidateState = [self _buildCandidateState:inputting useVerticalMode:useVerticalMode]; + + if ([candidateState.candidates count] == 1) { + [self clear]; + InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:candidateState.candidates.firstObject]; + stateCallback(committing); + InputStateEmpty *empty = [[InputStateEmpty alloc] init]; + stateCallback(empty); + } else { + stateCallback(candidateState); + } + } + return YES; +} + + +- (BOOL)_handleMarkingState:(InputStateMarking *)state + input:(KeyHandlerInput *)input + stateCallback:(void (^)(InputState *))stateCallback + errorCallback:(void (^)(void))errorCallback +{ + UniChar charCode = input.charCode; + + if (charCode == 27) { + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + stateCallback(inputting); + return YES; + } + + // Enter + if (charCode == 13) { + if (![self.delegate keyHandler:self didRequestWriteUserPhraseWithState:state]) { + errorCallback(); + return YES; + } + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + stateCallback(inputting); + return YES; + } + + // Shift + left + if (([input isCursorBackward] || input.emacsKey == vChewingEmacsKeyBackward) + && ([input isShiftHold])) { + NSUInteger index = state.markerIndex; + if (index > 0) { + index = [state.composingBuffer previousUtf16PositionFor:index]; + InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index readings:state.readings]; + marking.tooltipForInputting = state.tooltipForInputting; + + if (marking.markedRange.length == 0) { + InputState *inputting = [marking convertToInputting]; + stateCallback(inputting); + } else { + stateCallback(marking); + } + } else { + errorCallback(); + stateCallback(state); + } + return YES; + } + + // Shift + Right + if (([input isCursorForward] || input.emacsKey == vChewingEmacsKeyForward) + && ([input isShiftHold])) { + NSUInteger index = state.markerIndex; + if (index < state.composingBuffer.length) { + index = [state.composingBuffer nextUtf16PositionFor:index]; + InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index readings:state.readings]; + marking.tooltipForInputting = state.tooltipForInputting; + if (marking.markedRange.length == 0) { + InputState *inputting = [marking convertToInputting]; + stateCallback(inputting); + } else { + stateCallback(marking); + } + } else { + errorCallback(); + stateCallback(state); + } + return YES; + } + return NO; +} + + +- (BOOL)_handleCandidateState:(InputState *)state + input:(KeyHandlerInput *)input + stateCallback:(void (^)(InputState *))stateCallback + errorCallback:(void (^)(void))errorCallback; +{ + NSString *inputText = input.inputText; + UniChar charCode = input.charCode; + VTCandidateController *gCurrentCandidateController = [self.delegate candidateControllerForKeyHandler:self]; + + BOOL cancelCandidateKey = (charCode == 27) || (charCode == 8) || [input isDelete]; + + if (cancelCandidateKey) { + if ([state isKindOfClass: [InputStateAssociatedPhrases class]]) { + [self clear]; + InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init]; + stateCallback(empty); + } + else if (_inputMode == InputModePlainBopomofo) { + [self clear]; + InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init]; + stateCallback(empty); + } else { + InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState]; + stateCallback(inputting); + } + return YES; + } + + if (charCode == 13 || [input isEnter]) { + if ([state isKindOfClass: [InputStateAssociatedPhrases class]]) { + [self clear]; + InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init]; + stateCallback(empty); + return YES; + } + [self.delegate keyHandler:self didSelectCandidateAtIndex:gCurrentCandidateController.selectedCandidateIndex candidateController:gCurrentCandidateController]; + return YES; + } + + if (charCode == 32 || [input isPageDown] || input.emacsKey == vChewingEmacsKeyNextPage) { + BOOL updated = [gCurrentCandidateController showNextPage]; + if (!updated) { + errorCallback(); + } + return YES; + } + + if ([input isPageUp]) { + BOOL updated = [gCurrentCandidateController showPreviousPage]; + if (!updated) { + errorCallback(); + } + return YES; + } + + if ([input isLeft]) { + if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) { + BOOL updated = [gCurrentCandidateController highlightPreviousCandidate]; + if (!updated) { + errorCallback(); + } + } else { + BOOL updated = [gCurrentCandidateController showPreviousPage]; + if (!updated) { + errorCallback(); + } + } + return YES; + } + + if (input.emacsKey == vChewingEmacsKeyBackward) { + BOOL updated = [gCurrentCandidateController highlightPreviousCandidate]; + if (!updated) { + errorCallback(); + } + return YES; + } + + if ([input isRight]) { + if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) { + BOOL updated = [gCurrentCandidateController highlightNextCandidate]; + if (!updated) { + errorCallback(); + } + } else { + BOOL updated = [gCurrentCandidateController showNextPage]; + if (!updated) { + errorCallback(); + } + } + return YES; + } + + if (input.emacsKey == vChewingEmacsKeyForward) { + BOOL updated = [gCurrentCandidateController highlightNextCandidate]; + if (!updated) { + errorCallback(); + } + return YES; + } + + if ([input isUp]) { + if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) { + BOOL updated = [gCurrentCandidateController showPreviousPage]; + if (!updated) { + errorCallback(); + } + } else { + BOOL updated = [gCurrentCandidateController highlightPreviousCandidate]; + if (!updated) { + errorCallback(); + } + } + return YES; + } + + if ([input isDown]) { + if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) { + BOOL updated = [gCurrentCandidateController showNextPage]; + if (!updated) { + errorCallback(); + } + } else { + BOOL updated = [gCurrentCandidateController highlightNextCandidate]; + if (!updated) { + errorCallback(); + } + } + return YES; + } + + if ([input isHome] || input.emacsKey == vChewingEmacsKeyHome) { + if (gCurrentCandidateController.selectedCandidateIndex == 0) { + errorCallback(); + } else { + gCurrentCandidateController.selectedCandidateIndex = 0; + } + + return YES; + } + + NSArray *candidates; + + if ([state isKindOfClass: [InputStateChoosingCandidate class]]) { + candidates = [(InputStateChoosingCandidate *)state candidates]; + } else if ([state isKindOfClass: [InputStateAssociatedPhrases class]]) { + candidates = [(InputStateAssociatedPhrases *)state candidates]; + } + + if (!candidates) { + return NO; + } + + if (([input isEnd] || input.emacsKey == vChewingEmacsKeyEnd) && candidates.count > 0) { + if (gCurrentCandidateController.selectedCandidateIndex == candidates.count - 1) { + errorCallback(); + } else { + gCurrentCandidateController.selectedCandidateIndex = candidates.count - 1; + } + return YES; + } + + if ([state isKindOfClass:[InputStateAssociatedPhrases class]]) { + if (![input isShiftHold]) { + return NO; + } + } + + NSInteger index = NSNotFound; + NSString *match; + if ([state isKindOfClass:[InputStateAssociatedPhrases class]]) { + match = input.inputTextIgnoringModifiers; + } else { + match = inputText; + } + + for (NSUInteger j = 0, c = [gCurrentCandidateController.keyLabels count]; j < c; j++) { + VTCandidateKeyLabel *label = gCurrentCandidateController.keyLabels[j]; + if ([match compare:label.key options:NSCaseInsensitiveSearch] == NSOrderedSame) { + index = j; + break; + } + } + + if (index != NSNotFound) { + NSUInteger candidateIndex = [gCurrentCandidateController candidateIndexAtKeyLabelIndex:index]; + if (candidateIndex != NSUIntegerMax) { + [self.delegate keyHandler:self didSelectCandidateAtIndex:candidateIndex candidateController:gCurrentCandidateController]; + return YES; + } + } + + if ([state isKindOfClass:[InputStateAssociatedPhrases class]]) { + return NO; + } + + if (_inputMode == InputModePlainBopomofo) { + string layout = [self _currentLayout]; + string punctuationNamePrefix; + if ([input isControlHold]) { + punctuationNamePrefix = string("_ctrl_punctuation_"); + } else if (Preferences.halfWidthPunctuationEnabled) { + punctuationNamePrefix = string("_half_punctuation_"); + } else { + punctuationNamePrefix = string("_punctuation_"); + } + string customPunctuation = punctuationNamePrefix + layout + string(1, (char) charCode); + string punctuation = punctuationNamePrefix + string(1, (char) charCode); + + BOOL shouldAutoSelectCandidate = _bpmfReadingBuffer->isValidKey((char) charCode) || _languageModel->hasUnigramsForKey(customPunctuation) || + _languageModel->hasUnigramsForKey(punctuation); + + if (!shouldAutoSelectCandidate && (char) charCode >= 'A' && (char) charCode <= 'Z') { + string letter = string("_letter_") + string(1, (char) charCode); + if (_languageModel->hasUnigramsForKey(letter)) { + shouldAutoSelectCandidate = YES; + } + } + + if (shouldAutoSelectCandidate) { + NSUInteger candidateIndex = [gCurrentCandidateController candidateIndexAtKeyLabelIndex:0]; + if (candidateIndex != NSUIntegerMax) { + [self.delegate keyHandler:self didSelectCandidateAtIndex:candidateIndex candidateController:gCurrentCandidateController]; + [self clear]; + InputStateEmptyIgnoringPreviousState *empty = [[InputStateEmptyIgnoringPreviousState alloc] init]; + stateCallback(empty); + [self handleInput:input state:empty stateCallback:stateCallback errorCallback:errorCallback]; + } + return YES; + } + } + + errorCallback(); + return YES; +} + +#pragma mark - States Building + +- (InputStateInputting *)buildInputtingState +{ + // "updating the composing buffer" means to request the client to "refresh" the text input buffer + // with our "composing text" + NSMutableString *composingBuffer = [[NSMutableString alloc] init]; + NSInteger composedStringCursorIndex = 0; + + size_t readingCursorIndex = 0; + size_t builderCursorIndex = _builder->cursorIndex(); + + NSString *tooltip = @""; + + // we must do some Unicode codepoint counting to find the actual cursor location for the client + // i.e. we need to take UTF-16 into consideration, for which a surrogate pair takes 2 UniChars + // locations + for (vector::iterator wi = _walkedNodes.begin(), we = _walkedNodes.end(); wi != we; ++wi) { + if ((*wi).node) { + string nodeStr = (*wi).node->currentKeyValue().value; + NSString *valueString = [NSString stringWithUTF8String:nodeStr.c_str()]; + [composingBuffer appendString:valueString]; + + NSArray *splited = [valueString split]; + NSInteger codepointCount = splited.count; + + // this re-aligns the cursor index in the composed string + // (the actual cursor on the screen) with the builder's logical + // cursor (reading) cursor; each built node has a "spanning length" + // (e.g. two reading blocks has a spanning length of 2), and we + // accumulate those lengths to calculate the displayed cursor + // index + size_t spanningLength = (*wi).spanningLength; + if (readingCursorIndex + spanningLength <= builderCursorIndex) { + composedStringCursorIndex += [valueString length]; + readingCursorIndex += spanningLength; + } else { + if (codepointCount == spanningLength) { + for (size_t i = 0; i < codepointCount && readingCursorIndex < builderCursorIndex; i++) { + composedStringCursorIndex += [splited[i] length]; + readingCursorIndex++; + } + } else { + if (readingCursorIndex < builderCursorIndex) { + composedStringCursorIndex += [valueString length]; + readingCursorIndex += spanningLength; + if (readingCursorIndex > builderCursorIndex) { + readingCursorIndex = builderCursorIndex; + } + if (builderCursorIndex == 0) { + tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is before \"%@\".", @""), + [NSString stringWithUTF8String:_builder->readings()[builderCursorIndex].c_str()]]; + } else if (builderCursorIndex >= _builder->readings().size()) { + tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is after \"%@\".", @""), + [NSString stringWithUTF8String:_builder->readings()[_builder->readings().size() - 1].c_str()]]; + } else { + tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is between \"%@\" and \"%@\".", @""), + [NSString stringWithUTF8String:_builder->readings()[builderCursorIndex - 1].c_str()], + [NSString stringWithUTF8String:_builder->readings()[builderCursorIndex].c_str()]]; + } + } + } + } + } + } + + // now we gather all the info, we separate the composing buffer to two parts, head and tail, + // and insert the reading text (the Mandarin syllable) in between them; + // the reading text is what the user is typing + NSString *head = [composingBuffer substringToIndex:composedStringCursorIndex]; + NSString *reading = [NSString stringWithUTF8String:_bpmfReadingBuffer->composedString().c_str()]; + NSString *tail = [composingBuffer substringFromIndex:composedStringCursorIndex]; + NSString *composedText = [head stringByAppendingString:[reading stringByAppendingString:tail]]; + NSInteger cursorIndex = composedStringCursorIndex + [reading length]; + + InputStateInputting *newState = [[InputStateInputting alloc] initWithComposingBuffer:composedText cursorIndex:cursorIndex]; + newState.tooltip = tooltip; + return newState; +} + +- (void)_walk +{ + // retrieve the most likely trellis, i.e. a Maximum Likelihood Estimation + // of the best possible Mandarain characters given the input syllables, + // using the Viterbi algorithm implemented in the Gramambular library + Walker walker(&_builder->grid()); + + // the reverse walk traces the trellis from the end + _walkedNodes = walker.reverseWalk(_builder->grid().width()); + + // then we reverse the nodes so that we get the forward-walked nodes + reverse(_walkedNodes.begin(), _walkedNodes.end()); + + // if DEBUG is defined, a GraphViz file is written to kGraphVizOutputfile +#if DEBUG + string dotDump = _builder->grid().dumpDOT(); + NSString *dotStr = [NSString stringWithUTF8String:dotDump.c_str()]; + NSError *error = nil; + + BOOL __unused success = [dotStr writeToFile:kGraphVizOutputfile atomically:YES encoding:NSUTF8StringEncoding error:&error]; +#endif +} + +- (NSString *)_popOverflowComposingTextAndWalk +{ + // in an ideal world, we can as well let the user type forever, + // but because the Viterbi algorithm has a complexity of O(N^2), + // the walk will become slower as the number of nodes increase, + // therefore we need to "pop out" overflown text -- they usually + // lose their influence over the whole MLE anyway -- so that when + // the user type along, the already composed text at front will + // be popped out + + NSString *poppedText = @""; + NSInteger composingBufferSize = Preferences.composingBufferSize; + + if (_builder->grid().width() > (size_t) composingBufferSize) { + if (_walkedNodes.size() > 0) { + NodeAnchor &anchor = _walkedNodes[0]; + poppedText = [NSString stringWithUTF8String:anchor.node->currentKeyValue().value.c_str()]; + _builder->removeHeadReadings(anchor.spanningLength); + } + } + + [self _walk]; + return poppedText; +} + +- (InputStateChoosingCandidate *)_buildCandidateState:(InputStateNotEmpty *)currentState useVerticalMode:(BOOL)useVerticalMode +{ + NSMutableArray *candidatesArray = [[NSMutableArray alloc] init]; + + size_t cursorIndex = [self _actualCandidateCursorIndex]; + vector nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); + + // sort the nodes, so that longer nodes (representing longer phrases) are placed at the top of the candidate list + stable_sort(nodes.begin(), nodes.end(), NodeAnchorDescendingSorter()); + + // then use the C++ trick to retrieve the candidates for each node at/crossing the cursor + for (vector::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) { + const vector &candidates = (*ni).node->candidates(); + for (vector::const_iterator ci = candidates.begin(), ce = candidates.end(); ci != ce; ++ci) { + [candidatesArray addObject:[NSString stringWithUTF8String:(*ci).value.c_str()]]; + } + } + + InputStateChoosingCandidate *state = [[InputStateChoosingCandidate alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex candidates:candidatesArray useVerticalMode:useVerticalMode]; + return state; +} + +- (size_t)_actualCandidateCursorIndex +{ + size_t cursorIndex = _builder->cursorIndex(); + if (Preferences.selectPhraseAfterCursorAsCandidate) { + // MS Phonetics IME style, phrase is *after* the cursor, i.e. cursor is always *before* the phrase + if (cursorIndex < _builder->length()) { + ++cursorIndex; + } + } else { + if (!cursorIndex) { + ++cursorIndex; + } + } + + return cursorIndex; +} + +- (NSArray *)_currentReadings +{ + NSMutableArray *readingsArray = [[NSMutableArray alloc] init]; + vector v = _builder->readings(); + for (vector::iterator it_i = v.begin(); it_i != v.end(); ++it_i) { + [readingsArray addObject:[NSString stringWithUTF8String:it_i->c_str()]]; + } + return readingsArray; +} + +- (nullable InputState *)buildAssociatePhraseStateWithKey:(NSString *)key useVerticalMode:(BOOL)useVerticalMode +{ + string cppKey = string(key.UTF8String); + if (_languageModel->hasAssociatedPhrasesForKey(cppKey)) { + vector phrases = _languageModel->associatedPhrasesForKey(cppKey); + NSMutableArray *array = [NSMutableArray array]; + for (auto phrase: phrases) { + NSString *item = [[NSString alloc] initWithUTF8String:phrase.c_str()]; + [array addObject:item]; + } + InputStateAssociatedPhrases *associatedPhrases = [[InputStateAssociatedPhrases alloc] initWithCandidates:array useVerticalMode:useVerticalMode]; + return associatedPhrases; + } + return nil; +} + +@end diff --git a/Source/Modules/ControllerModules/KeyHandlerInput.swift b/Source/Modules/ControllerModules/KeyHandlerInput.swift new file mode 100644 index 0000000000000000000000000000000000000000..b7d0a319b44f71b68457b8882d157467e17ae20d --- /dev/null +++ b/Source/Modules/ControllerModules/KeyHandlerInput.swift @@ -0,0 +1,189 @@ + +import Cocoa + +enum KeyCode: UInt16 { + case none = 0 + case enter = 76 + case up = 126 + case down = 125 + case left = 123 + case right = 124 + case pageUp = 116 + case pageDown = 121 + case home = 115 + case end = 119 + case delete = 117 +} + +class KeyHandlerInput: NSObject { + @objc private (set) var useVerticalMode: Bool + @objc private (set) var inputText: String? + @objc private (set) var inputTextIgnoringModifiers: String? + @objc private (set) var charCode: UInt16 + @objc private (set) var keyCode: UInt16 + private var flags: NSEvent.ModifierFlags + private var cursorForwardKey: KeyCode + private var cursorBackwardKey: KeyCode + private var extraChooseCandidateKey: KeyCode + private var absorbedArrowKey: KeyCode + private var verticalModeOnlyChooseCandidateKey: KeyCode + @objc private (set) var emacsKey: vChewingEmacsKey + + @objc init(inputText: String?, keyCode: UInt16, charCode: UInt16, flags: NSEvent.ModifierFlags, isVerticalMode: Bool, inputTextIgnoringModifiers: String? = nil) { + self.inputText = inputText + self.inputTextIgnoringModifiers = inputTextIgnoringModifiers ?? inputText + self.keyCode = keyCode + self.charCode = charCode + self.flags = flags + useVerticalMode = isVerticalMode + emacsKey = EmacsKeyHelper.detect(charCode: charCode, flags: flags) + cursorForwardKey = useVerticalMode ? .down : .right + cursorBackwardKey = useVerticalMode ? .up : .left + extraChooseCandidateKey = useVerticalMode ? .left : .down + absorbedArrowKey = useVerticalMode ? .right : .up + verticalModeOnlyChooseCandidateKey = useVerticalMode ? absorbedArrowKey : .none + super.init() + } + + @objc init(event: NSEvent, isVerticalMode: Bool) { + inputText = event.characters + inputTextIgnoringModifiers = event.charactersIgnoringModifiers + keyCode = event.keyCode + flags = event.modifierFlags + useVerticalMode = isVerticalMode + let charCode: UInt16 = { + guard let inputText = event.characters, inputText.count > 0 else { + return 0 + } + let first = inputText[inputText.startIndex].utf16.first! + return first + }() + self.charCode = charCode + emacsKey = EmacsKeyHelper.detect(charCode: charCode, flags: event.modifierFlags) + cursorForwardKey = useVerticalMode ? .down : .right + cursorBackwardKey = useVerticalMode ? .up : .left + extraChooseCandidateKey = useVerticalMode ? .left : .down + absorbedArrowKey = useVerticalMode ? .right : .up + verticalModeOnlyChooseCandidateKey = useVerticalMode ? absorbedArrowKey : .none + super.init() + } + + override var description: String { + return "<\(super.description) inputText:\(String(describing: inputText)), inputTextIgnoringModifiers:\(String(describing: inputTextIgnoringModifiers)) charCode:\(charCode), keyCode:\(keyCode), flags:\(flags), cursorForwardKey:\(cursorForwardKey), cursorBackwardKey:\(cursorBackwardKey), extraChooseCandidateKey:\(extraChooseCandidateKey), absorbedArrowKey:\(absorbedArrowKey), verticalModeOnlyChooseCandidateKey:\(verticalModeOnlyChooseCandidateKey), emacsKey:\(emacsKey), useVerticalMode:\(useVerticalMode)>" + } + + @objc var isShiftHold: Bool { + flags.contains([.shift]) + } + + @objc var isCommandHold: Bool { + flags.contains([.command]) + } + + @objc var isControlHold: Bool { + flags.contains([.control]) + } + + @objc var isControlHotKey: Bool { + flags.contains([.control]) && inputText?.first?.isLetter ?? false + } + + @objc var isOptionHold: Bool { + flags.contains([.option]) + } + + @objc var isCapsLockOn: Bool { + flags.contains([.capsLock]) + } + + @objc var isNumericPad: Bool { + flags.contains([.numericPad]) + } + + @objc var isReservedKey: Bool { + guard let code = KeyCode(rawValue: keyCode) else { + return false + } + return code.rawValue != KeyCode.none.rawValue + } + + @objc var isEnter: Bool { + KeyCode(rawValue: keyCode) == KeyCode.enter + } + + @objc var isUp: Bool { + KeyCode(rawValue: keyCode) == KeyCode.up + } + + @objc var isDown: Bool { + KeyCode(rawValue: keyCode) == KeyCode.down + } + + @objc var isLeft: Bool { + KeyCode(rawValue: keyCode) == KeyCode.left + } + + @objc var isRight: Bool { + KeyCode(rawValue: keyCode) == KeyCode.right + } + + @objc var isPageUp: Bool { + KeyCode(rawValue: keyCode) == KeyCode.pageUp + } + + @objc var isPageDown: Bool { + KeyCode(rawValue: keyCode) == KeyCode.pageDown + } + + @objc var isHome: Bool { + KeyCode(rawValue: keyCode) == KeyCode.home + } + + @objc var isEnd: Bool { + KeyCode(rawValue: keyCode) == KeyCode.end + } + + @objc var isDelete: Bool { + KeyCode(rawValue: keyCode) == KeyCode.delete + } + + @objc var isCursorBackward: Bool { + KeyCode(rawValue: keyCode) == cursorBackwardKey + } + + @objc var isCursorForward: Bool { + KeyCode(rawValue: keyCode) == cursorForwardKey + } + + @objc var isAbsorbedArrowKey: Bool { + KeyCode(rawValue: keyCode) == absorbedArrowKey + } + + @objc var isExtraChooseCandidateKey: Bool { + KeyCode(rawValue: keyCode) == extraChooseCandidateKey + } + + @objc var isVerticalModeOnlyChooseCandidateKey: Bool { + KeyCode(rawValue: keyCode) == verticalModeOnlyChooseCandidateKey + } + +} + +@objc enum vChewingEmacsKey: UInt16 { + case none = 0 + case forward = 6 // F + case backward = 2 // B + case home = 1 // A + case end = 5 // E + case delete = 4 // D + case nextPage = 22 // V +} + +class EmacsKeyHelper: NSObject { + @objc static func detect(charCode: UniChar, flags: NSEvent.ModifierFlags) -> vChewingEmacsKey { + if flags.contains(.control) { + return vChewingEmacsKey(rawValue: charCode) ?? .none + } + return .none; + } +} diff --git a/Source/Modules/ControllerModules/KeyValueBlobReader.cpp b/Source/Modules/ControllerModules/KeyValueBlobReader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..930e318912f1103c0b761492302e4191749950f4 --- /dev/null +++ b/Source/Modules/ControllerModules/KeyValueBlobReader.cpp @@ -0,0 +1,120 @@ + +#include "KeyValueBlobReader.h" + +namespace vChewing { + +KeyValueBlobReader::State KeyValueBlobReader::Next(KeyValue* out) +{ + static auto new_line = [](char c) { return c == '\n' || c == '\r'; }; + static auto blank = [](char c) { return c == ' ' || c == '\t'; }; + static auto blank_or_newline + = [](char c) { return blank(c) || new_line(c); }; + static auto content_char = [](char c) { return !blank(c) && !new_line(c); }; + + if (state_ == State::ERROR) { + return state_; + } + + const char* key_begin = nullptr; + size_t key_length = 0; + const char* value_begin = nullptr; + size_t value_length = 0; + + while (true) { + state_ = SkipUntilNot(blank_or_newline); + if (state_ != State::CAN_CONTINUE) { + return state_; + } + + // Check if it's a comment line; if so, read until end of line. + if (*current_ != '#') { + break; + } + state_ = SkipUntil(new_line); + if (state_ != State::CAN_CONTINUE) { + return state_; + } + } + + // No need to check whether* current_ is a content_char, since content_char + // is defined as not blank and not new_line. + + key_begin = current_; + state_ = SkipUntilNot(content_char); + if (state_ != State::CAN_CONTINUE) { + goto error; + } + key_length = current_ - key_begin; + + // There should be at least one blank character after the key string. + if (!blank(*current_)) { + goto error; + } + + state_ = SkipUntilNot(blank); + if (state_ != State::CAN_CONTINUE) { + goto error; + } + + if (!content_char(*current_)) { + goto error; + } + + value_begin = current_; + // value must only contain content characters, blanks not are allowed. + // also, there's no need to check the state after this, since we will always + // emit the value. This also avoids the situation where trailing spaces in a + // line would become part of the value. + SkipUntilNot(content_char); + value_length = current_ - value_begin; + + // Unconditionally skip until the end of the line. This prevents the case + // like "foo bar baz\n" where baz should not be treated as the Next key. + SkipUntil(new_line); + + if (out != nullptr) { + *out = KeyValue { std::string_view { key_begin, key_length }, + std::string_view { value_begin, value_length } }; + } + state_ = State::HAS_PAIR; + return state_; + +error: + state_ = State::ERROR; + return state_; +} + +KeyValueBlobReader::State KeyValueBlobReader::SkipUntilNot( + const std::function& f) +{ + while (current_ != end_ && *current_) { + if (!f(*current_)) { + return State::CAN_CONTINUE; + } + ++current_; + } + + return State::END; +} + +KeyValueBlobReader::State KeyValueBlobReader::SkipUntil( + const std::function& f) +{ + while (current_ != end_ && *current_) { + if (f(*current_)) { + return State::CAN_CONTINUE; + } + ++current_; + } + + return State::END; +} + +std::ostream& operator<<( + std::ostream& os, const KeyValueBlobReader::KeyValue& kv) +{ + os << "(key: " << kv.key << ", value: " << kv.value << ")"; + return os; +} + +} // namespace vChewing diff --git a/Source/Modules/ControllerModules/KeyValueBlobReader.h b/Source/Modules/ControllerModules/KeyValueBlobReader.h new file mode 100644 index 0000000000000000000000000000000000000000..a6141eb3c1358a73c85e1dfaf12a57115a7c7fe6 --- /dev/null +++ b/Source/Modules/ControllerModules/KeyValueBlobReader.h @@ -0,0 +1,84 @@ + +#ifndef SOURCE_ENGINE_KEYVALUEBLOBREADER_H_ +#define SOURCE_ENGINE_KEYVALUEBLOBREADER_H_ + +#include +#include +#include +#include + +// A reader for text-based, blank-separated key-value pairs in a binary blob. +// +// This reader is suitable for reading language model files that entirely +// consist of key-value pairs. Leading or trailing spaces are ignored. +// Lines that start with "#" are treated as comments. Values cannot contain +// spaces. Any space after the value string is parsed is ignored. This implies +// that after a blank, anything that comes after the value can be used as +// comment. Both ' ' and '\t' are treated as blank characters, and the parser +// is agnostic to how lines are ended, and so LF, CR LF, and CR are all valid +// line endings. +// +// std::string_view is used to allow returning results efficiently. As a result, +// the blob is a const char* and will never be mutated. This implies, for +// example, read-only mmap can be used to parse large files. +namespace vChewing { + +class KeyValueBlobReader { +public: + enum class State : int { + // There are no more key-value pairs in this blob. + END = 0, + // The reader has produced a new key-value pair. + HAS_PAIR = 1, + // An error is encountered and the parsing stopped. + ERROR = -1, + // Internal-only state: the parser can continue parsing. + CAN_CONTINUE = 2 + }; + + struct KeyValue { + constexpr KeyValue() + : key("") + , value("") + { + } + constexpr KeyValue(std::string_view k, std::string_view v) + : key(k) + , value(v) + { + } + + bool operator==(const KeyValue& another) const + { + return key == another.key && value == another.value; + } + + std::string_view key; + std::string_view value; + }; + + KeyValueBlobReader(const char* blob, size_t size) + : current_(blob) + , end_(blob + size) + { + } + + // Parse the next key-value pair and return the state of the reader. If + // `out` is passed, out will be set to the produced key-value pair if there + // is one. + State Next(KeyValue* out = nullptr); + +private: + State SkipUntil(const std::function& f); + State SkipUntilNot(const std::function& f); + + const char* current_; + const char* end_; + State state_ = State::CAN_CONTINUE; +}; + +std::ostream& operator<<(std::ostream&, const KeyValueBlobReader::KeyValue&); + +} // namespace vChewing + +#endif // SOURCE_ENGINE_KEYVALUEBLOBREADER_H_ diff --git a/Source/Modules/ControllerModules/NSStringUtils.swift b/Source/Modules/ControllerModules/NSStringUtils.swift new file mode 100644 index 0000000000000000000000000000000000000000..e6e371e5d9c5080d6c9b764aff95d4833d2e0bea --- /dev/null +++ b/Source/Modules/ControllerModules/NSStringUtils.swift @@ -0,0 +1,51 @@ + +import Cocoa + +public extension NSString { + + /// Converts the index in an NSString to the index in a Swift string. + /// + /// An Emoji might be compose by more than one UTF-16 code points, however + /// the length of an NSString is only the sum of the UTF-16 code points. It + /// causes that the NSString and Swift string representation of the same + /// string have different lengths once the string contains such Emoji. The + /// method helps to find the index in a Swift string by passing the index + /// in an NSString. + func characterIndex(from utf16Index:Int) -> (Int, String) { + let string = (self as String) + var length = 0 + for (i, character) in string.enumerated() { + length += character.utf16.count + if length > utf16Index { + return (i, string) + } + } + return (string.count, string) + } + + @objc func nextUtf16Position(for index: Int) -> Int { + var (fixedIndex, string) = characterIndex(from: index) + if fixedIndex < string.count { + fixedIndex += 1 + } + return string[.. Int { + var (fixedIndex, string) = characterIndex(from: index) + if fixedIndex > 0 { + fixedIndex -= 1 + } + return string[.. [NSString] { + Array(self as String).map { + NSString(string: String($0)) + } + } +} diff --git a/Source/Modules/FileHandlers/FSEventStreamHelper.swift b/Source/Modules/FileHandlers/FSEventStreamHelper.swift new file mode 100644 index 0000000000000000000000000000000000000000..3cec28f90622f722a296be3b07986ec41e0f4ab9 --- /dev/null +++ b/Source/Modules/FileHandlers/FSEventStreamHelper.swift @@ -0,0 +1,74 @@ + +import Cocoa + +public protocol FSEventStreamHelperDelegate: AnyObject { + func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event]) +} + +public class FSEventStreamHelper : NSObject { + + public struct Event { + var path: String + var flags: FSEventStreamEventFlags + var id: FSEventStreamEventId + } + + public let path: String + public let dispatchQueue: DispatchQueue + public weak var delegate: FSEventStreamHelperDelegate? + + @objc public init(path: String, queue: DispatchQueue) { + self.path = path + self.dispatchQueue = queue + } + + private var stream: FSEventStreamRef? = nil + + public func start() -> Bool { + if stream != nil { + return false + } + var context = FSEventStreamContext() + context.info = Unmanaged.passUnretained(self).toOpaque() + guard let stream = FSEventStreamCreate(nil, { + (stream, clientCallBackInfo, eventCount, eventPaths, eventFlags, eventIds) in + let helper = Unmanaged.fromOpaque(clientCallBackInfo!).takeUnretainedValue() + let pathsBase = eventPaths.assumingMemoryBound(to: UnsafePointer.self) + let pathsPtr = UnsafeBufferPointer(start: pathsBase, count: eventCount) + let flagsPtr = UnsafeBufferPointer(start: eventFlags, count: eventCount) + let eventIDsPtr = UnsafeBufferPointer(start: eventIds, count: eventCount) + let events = (0.. +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +namespace vChewing { + +class LMConsolidator +{ +public: + static bool FixEOF(const char *path); + static bool ConsolidateContent(const char *path, bool shouldsort); +}; + +} // namespace vChewing +#endif /* LMConsolidator_hpp */ diff --git a/Source/Modules/FileHandlers/LMConsolidator.mm b/Source/Modules/FileHandlers/LMConsolidator.mm new file mode 100644 index 0000000000000000000000000000000000000000..81fcd1bcaeb1831e9a70fdb1eb4dd4cb8a82724e --- /dev/null +++ b/Source/Modules/FileHandlers/LMConsolidator.mm @@ -0,0 +1,89 @@ +/* + * LMConsolidator.mm + * vChewing-Specific module for Consolidating Language Model Data files. + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +#include "LMConsolidator.h" + +namespace vChewing { + +// EOF FIXER. CREDIT: Shiki Suen. +bool LMConsolidator::FixEOF(const char *path) +{ + std::fstream zfdEOFFixerIncomingStream(path); + zfdEOFFixerIncomingStream.seekg(-1,std::ios_base::end); + char z; + zfdEOFFixerIncomingStream.get(z); + if(z!='\n'){ + syslog(LOG_CONS, "// REPORT: Data File not ended with a new line.\n"); + syslog(LOG_CONS, "// DATA FILE: %s", path); + syslog(LOG_CONS, "// PROCEDURE: Trying to insert a new line as EOF before per-line check process.\n"); + std::ofstream zfdEOFFixerOutput(path, std::ios_base::app); + zfdEOFFixerOutput << std::endl; + zfdEOFFixerOutput.close(); + if (zfdEOFFixerOutput.fail()) { + syslog(LOG_CONS, "// REPORT: Failed to append a newline to the data file. Insufficient Privileges?\n"); + syslog(LOG_CONS, "// DATA FILE: %s", path); + return false; + } + } + zfdEOFFixerIncomingStream.close(); + if (zfdEOFFixerIncomingStream.fail()) { + syslog(LOG_CONS, "// REPORT: Failed to read lines through the data file for EOF check. Insufficient Privileges?\n"); + syslog(LOG_CONS, "// DATA FILE: %s", path); + return false; + } + return true; +} // END: EOF FIXER. + +// CONTENT CONSOLIDATOR. CREDIT: Shiki Suen. +bool LMConsolidator::ConsolidateContent(const char *path, bool shouldsort) { + ifstream zfdContentConsolidatorIncomingStream(path); + vectorvecEntry; + while(!zfdContentConsolidatorIncomingStream.eof()) + { // Xcode 13 能用的 ObjCpp 與 Cpp 並無原生支援「\h」這個 Regex 參數的能力,只能逐行處理。 + string zfdBuffer; + getline(zfdContentConsolidatorIncomingStream,zfdBuffer); + vecEntry.push_back(zfdBuffer); + } + // 第一遍 for 用來統整每行內的內容。 + // regex sedCJKWhiteSpace("\\x{3000}"), sedNonBreakWhiteSpace("\\x{A0}"), sedWhiteSpace("\\s+"), sedLeadingSpace("^\\s"), sedTrailingSpace("\\s$"); // 這樣寫會導致輸入法敲不了任何字,推測 Xcode 13 支援的 cpp / objCpp 可能對某些 Regex 寫法有相容性問題。 + regex sedCJKWhiteSpace(" "), sedNonBreakWhiteSpace(" "), sedWhiteSpace("\\s+"), sedLeadingSpace("^\\s"), sedTrailingSpace("\\s$"); // RegEx 先定義好。 + for(int i=0;i [TISInputSource] { + TISCreateInputSourceList(nil, true).takeRetainedValue() as! [TISInputSource] + } + + @objc(inputSourceForProperty:stringValue:) + public static func inputSource(for propertyKey: CFString, stringValue: String) -> TISInputSource? { + let stringID = CFStringGetTypeID() + for source in allInstalledInputSources() { + if let propertyPtr = TISGetInputSourceProperty(source, propertyKey) { + let property = Unmanaged.fromOpaque(propertyPtr).takeUnretainedValue() + let typeID = CFGetTypeID(property) + if typeID != stringID { + continue + } + if stringValue == property as? String { + return source + } + } + } + return nil + } + + @objc(inputSourceForInputSourceID:) + public static func inputSource(for sourceID: String) -> TISInputSource? { + inputSource(for: kTISPropertyInputSourceID, stringValue: sourceID) + } + + @objc(inputSourceEnabled:) + public static func inputSourceEnabled(for source: TISInputSource) -> Bool { + if let valuePts = TISGetInputSourceProperty(source, kTISPropertyInputSourceIsEnabled) { + let value = Unmanaged.fromOpaque(valuePts).takeUnretainedValue() + return value == kCFBooleanTrue + } + return false + } + + @objc(enableInputSource:) + public static func enable(inputSource: TISInputSource) -> Bool { + let status = TISEnableInputSource(inputSource) + return status == noErr + } + + @objc(enableAllInputModesForInputSourceBundleID:) + public static func enableAllInputMode(for inputSourceBundleD: String) -> Bool { + var enabled = false + for source in allInstalledInputSources() { + guard let bundleIDPtr = TISGetInputSourceProperty(source, kTISPropertyBundleID), + let _ = TISGetInputSourceProperty(source, kTISPropertyInputModeID) else { + continue + } + let bundleID = Unmanaged.fromOpaque(bundleIDPtr).takeUnretainedValue() + if String(bundleID) == inputSourceBundleD { + let modeEnabled = self.enable(inputSource: source) + if !modeEnabled { + return false + } + enabled = true + } + } + + return enabled + } + + @objc(enableInputMode:forInputSourceBundleID:) + public static func enable(inputMode modeID: String, for bundleID: String) -> Bool { + for source in allInstalledInputSources() { + guard let bundleIDPtr = TISGetInputSourceProperty(source, kTISPropertyBundleID), + let modePtr = TISGetInputSourceProperty(source, kTISPropertyInputModeID) else { + continue + } + let inputsSourceBundleID = Unmanaged.fromOpaque(bundleIDPtr).takeUnretainedValue() + let inputsSourceModeID = Unmanaged.fromOpaque(modePtr).takeUnretainedValue() + if modeID == String(inputsSourceModeID) && bundleID == String(inputsSourceBundleID) { + let enabled = enable(inputSource: source) + print("Attempt to enable input source of mode: \(modeID), bundle ID: \(bundleID), result: \(enabled)") + return enabled + } + + } + print("Failed to find any matching input source of mode: \(modeID), bundle ID: \(bundleID)") + return false + + } + + @objc(disableInputSource:) + public static func disable(inputSource: TISInputSource) -> Bool { + let status = TISDisableInputSource(inputSource) + return status == noErr + } + + @objc(registerInputSource:) + public static func registerTnputSource(at url: URL) -> Bool { + let status = TISRegisterInputSource(url as CFURL) + return status == noErr + } + +} + diff --git a/Source/Modules/IMEModules/OpenCCBridge.swift b/Source/Modules/IMEModules/OpenCCBridge.swift new file mode 100644 index 0000000000000000000000000000000000000000..b77cc295933ba9fe93f58b479e678b08fe646a2f --- /dev/null +++ b/Source/Modules/IMEModules/OpenCCBridge.swift @@ -0,0 +1,25 @@ + +import Foundation +import OpenCC + +/// A bridge to let Objctive-C code to access SwiftyOpenCC. +/// +/// Since SwiftyOpenCC only provide Swift classes, we create an NSObject subclass +/// in Swift in order to bridge the Swift classes into our Objective-C++ project. +public class OpenCCBridge: NSObject { + private static let shared = OpenCCBridge() + private var converter: ChineseConverter? + + private override init() { + try? converter = ChineseConverter(options: .simplify) + super.init() + } + + /// Converts to Simplified Chinese. + /// + /// - Parameter string: Text in Traditional Chinese. + /// - Returns: Text in Simplified Chinese. + @objc public static func convertToKangXi(_ string: String) -> String? { + shared.converter?.convert(string) + } +} diff --git a/Source/Modules/IMEModules/PreferencesModule.swift b/Source/Modules/IMEModules/PreferencesModule.swift new file mode 100644 index 0000000000000000000000000000000000000000..a6f8b5350f7104d53fb6ce82e75f52d0007dcf67 --- /dev/null +++ b/Source/Modules/IMEModules/PreferencesModule.swift @@ -0,0 +1,484 @@ +/* + * PreferencesModule.swift + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +import Cocoa + +private let kCheckUpdateAutomatically = "CheckUpdateAutomatically" +private let kKeyboardLayoutPreference = "KeyboardLayout" +private let kBasisKeyboardLayoutPreference = "BasisKeyboardLayout" +private let kFunctionKeyKeyboardLayoutPreference = "FunctionKeyKeyboardLayout" +private let kFunctionKeyKeyboardLayoutOverrideIncludeShift = "FunctionKeyKeyboardLayoutOverrideIncludeShift" +private let kCandidateListTextSize = "CandidateListTextSize" +private let kAppleLanguagesPreferences = "AppleLanguages" +private let kShouldAutoReloadUserDataFiles = "ShouldAutoReloadUserDataFiles" +private let kShouldAutoSortUserPhrasesAndExclListOnLoad = "ShouldAutoSortUserPhrasesAndExclListOnLoad" +private let kShouldAutoSortPhraseReplacementMapOnLoad = "ShouldAutoSortPhraseReplacementMapOnLoad" +private let kSelectPhraseAfterCursorAsCandidatePreference = "SelectPhraseAfterCursorAsCandidate" +private let kUseHorizontalCandidateListPreference = "UseHorizontalCandidateList" +private let kComposingBufferSizePreference = "ComposingBufferSize" +private let kChooseCandidateUsingSpace = "ChooseCandidateUsingSpaceKey" +private let kCNS11643Enabled = "CNS11643Enabled" +private let kChineseConversionEnabled = "ChineseConversionEnabled" +private let kHalfWidthPunctuationEnabled = "HalfWidthPunctuationEnable" +private let kMoveCursorAfterSelectingCandidate = "MoveCursorAfterSelectingCandidate" +private let kEscToCleanInputBuffer = "EscToCleanInputBuffer" +private let kUseSCPCTypingMode = "UseSCPCTypingMode" +private let kMaxCandidateLength = "MaxCandidateLength" +private let kShouldNotFartInLieuOfBeep = "ShouldNotFartInLieuOfBeep" + +private let kCandidateTextFontName = "CandidateTextFontName" +private let kCandidateKeyLabelFontName = "CandidateKeyLabelFontName" +private let kCandidateKeys = "CandidateKeys" + +private let kChineseConversionEngineKey = "ChineseConversionEngine" +private let kChineseConversionStyleKey = "ChineseConversionStyle" +private let kAssociatedPhrasesEnabled = "AssociatedPhrasesEnabled" +private let kPhraseReplacementEnabled = "PhraseReplacementEnabled" + +private let kDefaultCandidateListTextSize: CGFloat = 18 +private let kMinKeyLabelSize: CGFloat = 10 +private let kMinCandidateListTextSize: CGFloat = 12 +private let kMaxCandidateListTextSize: CGFloat = 196 + +// default, min and max composing buffer size (in codepoints) +// modern Macs can usually work up to 16 codepoints when the builder still +// walks the grid with good performance slower Macs (like old PowerBooks) +// will start to sputter beyond 12 such is the algorithmatic complexity +// of the Viterbi algorithm used in the builder library (at O(N^2)) +private let kDefaultComposingBufferSize = 20 +private let kMinComposingBufferSize = 4 +private let kMaxComposingBufferSize = 30 + +private let kDefaultKeys = "123456789" +private let kDefaultAssociatedPhrasesKeys = "!@#$%^&*(" + +// MARK: Property wrappers + +@propertyWrapper +struct UserDefault { + let key: String + let defaultValue: Value + var container: UserDefaults = .standard + + var wrappedValue: Value { + get { + container.object(forKey: key) as? Value ?? defaultValue + } + set { + container.set(newValue, forKey: key) + } + } +} + +@propertyWrapper +struct CandidateListTextSize { + let key: String + let defaultValue: CGFloat = kDefaultCandidateListTextSize + lazy var container: UserDefault = { + UserDefault(key: key, defaultValue: defaultValue) + }() + + var wrappedValue: CGFloat { + mutating get { + var value = container.wrappedValue + if value < kMinCandidateListTextSize { + value = kMinCandidateListTextSize + } else if value > kMaxCandidateListTextSize { + value = kMaxCandidateListTextSize + } + return value + } + set { + var value = newValue + if value < kMinCandidateListTextSize { + value = kMinCandidateListTextSize + } else if value > kMaxCandidateListTextSize { + value = kMaxCandidateListTextSize + } + container.wrappedValue = value + } + } +} + +@propertyWrapper +struct ComposingBufferSize { + let key: String + let defaultValue: Int = kDefaultComposingBufferSize + lazy var container: UserDefault = { + UserDefault(key: key, defaultValue: defaultValue) + }() + + var wrappedValue: Int { + mutating get { + let currentValue = container.wrappedValue + if currentValue < kMinComposingBufferSize { + return kMinComposingBufferSize + } else if currentValue > kMaxComposingBufferSize { + return kMaxComposingBufferSize + } + return currentValue + } + set { + var value = newValue + if value < kMinComposingBufferSize { + value = kMinComposingBufferSize + } else if value > kMaxComposingBufferSize { + value = kMaxComposingBufferSize + } + container.wrappedValue = value + } + } +} + +// MARK: - + +@objc enum KeyboardLayout: Int { + case standard = 0 + case eten = 1 + case hsu = 2 + case eten26 = 3 + case hanyuPinyin = 4 + case IBM = 5 + + var name: String { + switch (self) { + case .standard: + return "Standard" + case .eten: + return "ETen" + case .hsu: + return "Hsu" + case .eten26: + return "ETen26" + case .hanyuPinyin: + return "HanyuPinyin" + case .IBM: + return "IBM" + } + } +} + +@objc enum ChineseConversionEngine: Int { + case openCC + case vxHanConvert + + var name: String { + switch (self) { + case .openCC: + return "OpenCC" + case .vxHanConvert: + return "VXHanConvert" + } + } +} + +@objc enum ChineseConversionStyle: Int { + case output + case model + + var name: String { + switch (self) { + case .output: + return "output" + case .model: + return "model" + } + } +} + +// MARK: - +@objc public class Preferences: NSObject { + static var allKeys:[String] { + [kKeyboardLayoutPreference, + kBasisKeyboardLayoutPreference, + kFunctionKeyKeyboardLayoutPreference, + kFunctionKeyKeyboardLayoutOverrideIncludeShift, + kCandidateListTextSize, + kAppleLanguagesPreferences, + kShouldAutoReloadUserDataFiles, + kShouldAutoSortUserPhrasesAndExclListOnLoad, + kShouldAutoSortPhraseReplacementMapOnLoad, + kSelectPhraseAfterCursorAsCandidatePreference, + kUseHorizontalCandidateListPreference, + kComposingBufferSizePreference, + kChooseCandidateUsingSpace, + kCNS11643Enabled, + kChineseConversionEnabled, + kHalfWidthPunctuationEnabled, + kEscToCleanInputBuffer, + kCandidateTextFontName, + kCandidateKeyLabelFontName, + kCandidateKeys, + kMoveCursorAfterSelectingCandidate, + kPhraseReplacementEnabled, + kUseSCPCTypingMode, + kMaxCandidateLength, + kShouldNotFartInLieuOfBeep, + kChineseConversionEngineKey, + kChineseConversionStyleKey, + kAssociatedPhrasesEnabled] + } + + @objc public static func setMissingDefaults () { + // 既然 Preferences Module 的預設屬性不自動寫入 plist、而且還是 private,那這邊就先寫入了。 + + // 首次啟用輸入法時設定不要自動更新,免得在某些要隔絕外部網路連線的保密機構內觸犯資安規則。 + if UserDefaults.standard.object(forKey: kCheckUpdateAutomatically) == nil { + UserDefaults.standard.set(false, forKey: kCheckUpdateAutomatically) + } + + // 預設選字窗字詞文字尺寸,設成 18 剛剛好 + if UserDefaults.standard.object(forKey: kCandidateListTextSize) == nil { + UserDefaults.standard.set(Preferences.candidateListTextSize, forKey: kCandidateListTextSize) + } + + // 預設摁空格鍵來選字,所以設成 true + if UserDefaults.standard.object(forKey: kChooseCandidateUsingSpace) == nil { + UserDefaults.standard.set(Preferences.chooseCandidateUsingSpace, forKey: kChooseCandidateUsingSpace) + } + + // 在檔案載入時,預設不啟用使用者自訂語彙表與語彙排除表的內容排序。 + if UserDefaults.standard.object(forKey: kShouldAutoReloadUserDataFiles) == nil { + UserDefaults.standard.set(Preferences.shouldAutoReloadUserDataFiles, forKey: kShouldAutoReloadUserDataFiles) + } + + // 在檔案載入時,預設不啟用語彙置換表的內容排序。 + if UserDefaults.standard.object(forKey: kShouldAutoSortUserPhrasesAndExclListOnLoad) == nil { + UserDefaults.standard.set(Preferences.ShouldAutoSortUserPhrasesAndExclListOnLoad, forKey: kShouldAutoSortUserPhrasesAndExclListOnLoad) + } + + // 自動檢測使用者自訂語彙數據的變動並載入。 + if UserDefaults.standard.object(forKey: kShouldAutoSortPhraseReplacementMapOnLoad) == nil { + UserDefaults.standard.set(Preferences.shouldAutoSortPhraseReplacementMapOnLoad, forKey: kShouldAutoSortPhraseReplacementMapOnLoad) + } + + // 預設禁用逐字選字模式(就是每個字都要選的那種),所以設成 false + if UserDefaults.standard.object(forKey: kUseSCPCTypingMode) == nil { + UserDefaults.standard.set(Preferences.useSCPCTypingMode, forKey: kUseSCPCTypingMode) + } + + // 預設漢音風格選字,所以要設成 0 + if UserDefaults.standard.object(forKey: kSelectPhraseAfterCursorAsCandidatePreference) == nil { + UserDefaults.standard.set(Preferences.selectPhraseAfterCursorAsCandidate, forKey: kSelectPhraseAfterCursorAsCandidatePreference) + } + + // 預設在選字後自動移動游標 + if UserDefaults.standard.object(forKey: kMoveCursorAfterSelectingCandidate) == nil { + UserDefaults.standard.set(Preferences.moveCursorAfterSelectingCandidate, forKey: kMoveCursorAfterSelectingCandidate) + } + + // 預設橫向選字窗,不爽請自行改成縱向選字窗 + if UserDefaults.standard.object(forKey: kUseHorizontalCandidateListPreference) == nil { + UserDefaults.standard.set(Preferences.useHorizontalCandidateList, forKey: kUseHorizontalCandidateListPreference) + } + + // 預設停用全字庫支援 + if UserDefaults.standard.object(forKey: kCNS11643Enabled) == nil { + UserDefaults.standard.set(Preferences.cns11643Enabled, forKey: kCNS11643Enabled) + } + + // 預設停用繁體轉康熙模組 + if UserDefaults.standard.object(forKey: kChineseConversionEnabled) == nil { + UserDefaults.standard.set(Preferences.chineseConversionEnabled, forKey: kChineseConversionEnabled) + } + + // 預設停用自訂語彙置換 + if UserDefaults.standard.object(forKey: kPhraseReplacementEnabled) == nil { + UserDefaults.standard.set(Preferences.phraseReplacementEnabled, forKey: kPhraseReplacementEnabled) + } + + // 預設沒事不要在那裡放屁 + if UserDefaults.standard.object(forKey: kShouldNotFartInLieuOfBeep) == nil { + UserDefaults.standard.set(Preferences.shouldNotFartInLieuOfBeep, forKey: kShouldNotFartInLieuOfBeep) + } + + UserDefaults.standard.synchronize() + } + + @UserDefault(key: kAppleLanguagesPreferences, defaultValue: []) + @objc static var appleLanguages: Array + + @UserDefault(key: kKeyboardLayoutPreference, defaultValue: 0) + @objc static var keyboardLayout: Int + + @objc static var keyboardLayoutName: String { + (KeyboardLayout(rawValue: self.keyboardLayout) ?? KeyboardLayout.standard).name + } + + @UserDefault(key: kBasisKeyboardLayoutPreference, defaultValue: "com.apple.keylayout.US") + @objc static var basisKeyboardLayout: String + + @UserDefault(key: kFunctionKeyKeyboardLayoutPreference, defaultValue: "com.apple.keylayout.US") + @objc static var functionKeyboardLayout: String + + @UserDefault(key: kFunctionKeyKeyboardLayoutOverrideIncludeShift, defaultValue: false) + @objc static var functionKeyKeyboardLayoutOverrideIncludeShiftKey: Bool + + @CandidateListTextSize(key: kCandidateListTextSize) + @objc static var candidateListTextSize: CGFloat + + @UserDefault(key: kShouldAutoReloadUserDataFiles, defaultValue: true) + @objc static var shouldAutoReloadUserDataFiles: Bool + + @UserDefault(key: kShouldAutoSortUserPhrasesAndExclListOnLoad, defaultValue: false) + @objc static var ShouldAutoSortUserPhrasesAndExclListOnLoad: Bool + + @UserDefault(key: kShouldAutoSortPhraseReplacementMapOnLoad, defaultValue: false) + @objc static var shouldAutoSortPhraseReplacementMapOnLoad: Bool + + @UserDefault(key: kSelectPhraseAfterCursorAsCandidatePreference, defaultValue: false) + @objc static var selectPhraseAfterCursorAsCandidate: Bool + + @UserDefault(key: kMoveCursorAfterSelectingCandidate, defaultValue: false) + @objc static var moveCursorAfterSelectingCandidate: Bool + + @UserDefault(key: kUseHorizontalCandidateListPreference, defaultValue: true) + @objc static var useHorizontalCandidateList: Bool + + @ComposingBufferSize(key: kComposingBufferSizePreference) + @objc static var composingBufferSize: Int + + @UserDefault(key: kChooseCandidateUsingSpace, defaultValue: true) + @objc static var chooseCandidateUsingSpace: Bool + + @UserDefault(key: kUseSCPCTypingMode, defaultValue: false) + @objc static var useSCPCTypingMode: Bool + + @objc static func toggleSCPCTypingModeEnabled() -> Bool { + useSCPCTypingMode = !useSCPCTypingMode + UserDefaults.standard.set(useSCPCTypingMode, forKey: kUseSCPCTypingMode) + return useSCPCTypingMode + } + + @UserDefault(key: kMaxCandidateLength, defaultValue: 10) + @objc static var maxCandidateLength: Int + + @UserDefault(key: kShouldNotFartInLieuOfBeep, defaultValue: true) + @objc static var shouldNotFartInLieuOfBeep: Bool + + @objc static func toggleShouldNotFartInLieuOfBeep() -> Bool { + shouldNotFartInLieuOfBeep = !shouldNotFartInLieuOfBeep + UserDefaults.standard.set(shouldNotFartInLieuOfBeep, forKey: kShouldNotFartInLieuOfBeep) + return shouldNotFartInLieuOfBeep + } + + @UserDefault(key: kCNS11643Enabled, defaultValue: false) + @objc static var cns11643Enabled: Bool + + @objc static func toggleCNS11643Enabled() -> Bool { + cns11643Enabled = !cns11643Enabled + UserDefaults.standard.set(cns11643Enabled, forKey: kCNS11643Enabled) + return cns11643Enabled + } + + @UserDefault(key: kChineseConversionEnabled, defaultValue: false) + @objc static var chineseConversionEnabled: Bool + + @objc static func toggleChineseConversionEnabled() -> Bool { + chineseConversionEnabled = !chineseConversionEnabled + UserDefaults.standard.set(chineseConversionEnabled, forKey: kChineseConversionEnabled) + return chineseConversionEnabled + } + + @UserDefault(key: kHalfWidthPunctuationEnabled, defaultValue: false) + @objc static var halfWidthPunctuationEnabled: Bool + + @objc static func toggleHalfWidthPunctuationEnabled() -> Bool { + halfWidthPunctuationEnabled = !halfWidthPunctuationEnabled + return halfWidthPunctuationEnabled + } + + @UserDefault(key: kEscToCleanInputBuffer, defaultValue: true) + @objc static var escToCleanInputBuffer: Bool + + // MARK: Optional settings + @UserDefault(key: kCandidateTextFontName, defaultValue: nil) + @objc static var candidateTextFontName: String? + + @UserDefault(key: kCandidateKeyLabelFontName, defaultValue: nil) + @objc static var candidateKeyLabelFontName: String? + + @UserDefault(key: kCandidateKeys, defaultValue: kDefaultKeys) + @objc static var candidateKeys: String + + @objc static var defaultCandidateKeys: String { + kDefaultKeys + } + @objc static var suggestedCandidateKeys: [String] { + [kDefaultKeys, "234567890", "QWERTYUIO", "QWERTASDF", "ASDFGHJKL", "ASDFZXCVB"] + } + + @objc static func validate(candidateKeys: String) throws { + let trimmed = candidateKeys.trimmingCharacters(in: .whitespacesAndNewlines) + if trimmed.isEmpty { + throw CandidateKeyError.empty + } + if !trimmed.canBeConverted(to: .ascii) { + throw CandidateKeyError.invalidCharacters + } + if trimmed.contains(" ") { + throw CandidateKeyError.containSpace + } + if trimmed.count < 4 { + throw CandidateKeyError.tooShort + } + if trimmed.count > 15 { + throw CandidateKeyError.tooLong + } + let set = Set(Array(trimmed)) + if set.count != trimmed.count { + throw CandidateKeyError.duplicatedCharacters + } + } + + enum CandidateKeyError: Error, LocalizedError { + case empty + case invalidCharacters + case containSpace + case duplicatedCharacters + case tooShort + case tooLong + + var errorDescription: String? { + switch self { + case .empty: + return NSLocalizedString("Candidates keys cannot be empty.", comment: "") + case .invalidCharacters: + return NSLocalizedString("Candidate keys can only contain ASCII characters like alphanumerals.", comment: "") + case .containSpace: + return NSLocalizedString("Candidate keys cannot contain space.", comment: "") + case .duplicatedCharacters: + return NSLocalizedString("There should not be duplicated keys.", comment: "") + case .tooShort: + return NSLocalizedString("Please specify at least 4 candidate keys.", comment: "") + case .tooLong: + return NSLocalizedString("Maximum 15 candidate keys allowed.", comment: "") + } + } + + } + + @UserDefault(key: kPhraseReplacementEnabled, defaultValue: false) + @objc static var phraseReplacementEnabled: Bool + + @objc static func togglePhraseReplacementEnabled() -> Bool { + phraseReplacementEnabled = !phraseReplacementEnabled + UserDefaults.standard.set(phraseReplacementEnabled, forKey: kPhraseReplacementEnabled) + return phraseReplacementEnabled + } + + @UserDefault(key: kAssociatedPhrasesEnabled, defaultValue: false) + @objc static var associatedPhrasesEnabled: Bool + + @objc static func toggleAssociatedPhrasesEnabled() -> Bool { + associatedPhrasesEnabled = !associatedPhrasesEnabled + UserDefaults.standard.set(associatedPhrasesEnabled, forKey: kAssociatedPhrasesEnabled) + return associatedPhrasesEnabled + } + +} diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift new file mode 100644 index 0000000000000000000000000000000000000000..574d17c87863a1a058fa9451c1d3979c8ef07d88 --- /dev/null +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -0,0 +1,593 @@ + +import Cocoa +import InputMethodKit +import VXHanConvert + +extension Bool { + var state: NSControl.StateValue { + self ? .on : .off + } +} + +private let kMinKeyLabelSize: CGFloat = 10 + +private var gCurrentCandidateController: CandidateController? + +@objc(ctlInputMethod) +class ctlInputMethod: IMKInputController { + + private static let horizontalCandidateController = HorizontalCandidateController() + private static let verticalCandidateController = VerticalCandidateController() + private static let tooltipController = TooltipController() + + // MARK: - + + private var currentCandidateClient: Any? + private var currentDeferredClient: Any? + + private var keyHandler: KeyHandler = KeyHandler() + private var state: InputState = InputState.Empty() + + // MARK: - IMKInputController methods + + override init!(server: IMKServer!, delegate: Any!, client inputClient: Any!) { + super.init(server: server, delegate: delegate, client: inputClient) + keyHandler.delegate = self + } + + override func menu() -> NSMenu! { + let menu = NSMenu(title: "Input Method Menu") + menu.addItem(withTitle: NSLocalizedString("vChewing Preferences", comment: ""), action: #selector(showPreferences(_:)), keyEquivalent: "") + + let chineseConversionItem = menu.addItem(withTitle: NSLocalizedString("Chinese Conversion", comment: ""), action: #selector(toggleChineseConverter(_:)), keyEquivalent: "g") + chineseConversionItem.keyEquivalentModifierMask = [.command, .control] + chineseConversionItem.state = Preferences.chineseConversionEnabled.state + + let halfWidthPunctuationItem = menu.addItem(withTitle: NSLocalizedString("Use Half-Width Punctuations", comment: ""), action: #selector(toggleHalfWidthPunctuation(_:)), keyEquivalent: "h") + halfWidthPunctuationItem.keyEquivalentModifierMask = [.command, .control] + halfWidthPunctuationItem.state = Preferences.halfWidthPunctuationEnabled.state + + let inputMode = keyHandler.inputMode + let optionKeyPressed = NSEvent.modifierFlags.contains(.option) + + if inputMode == .plainBopomofo { + let associatedPhrasesItem = menu.addItem(withTitle: NSLocalizedString("Associated Phrases", comment: ""), action: #selector(toggleAssociatedPhrasesEnabled(_:)), keyEquivalent: "") + associatedPhrasesItem.state = Preferences.associatedPhrasesEnabled.state + } + + if inputMode == .bopomofo && optionKeyPressed { + let phaseReplacementItem = menu.addItem(withTitle: NSLocalizedString("Use Phrase Replacement", comment: ""), action: #selector(togglePhraseReplacement(_:)), keyEquivalent: "") + phaseReplacementItem.state = Preferences.phraseReplacementEnabled.state + } + + menu.addItem(NSMenuItem.separator()) + menu.addItem(withTitle: NSLocalizedString("User Phrases", comment: ""), action: nil, keyEquivalent: "") + + if inputMode == .plainBopomofo { + menu.addItem(withTitle: NSLocalizedString("Edit Excluded Phrases", comment: ""), action: #selector(openExcludedPhrasesPlainBopomofo(_:)), keyEquivalent: "") + } else { + menu.addItem(withTitle: NSLocalizedString("Edit User Phrases", comment: ""), action: #selector(openUserPhrases(_:)), keyEquivalent: "") + menu.addItem(withTitle: NSLocalizedString("Edit Excluded Phrases", comment: ""), action: #selector(openExcludedPhrasesvChewing(_:)), keyEquivalent: "") + if optionKeyPressed { + menu.addItem(withTitle: NSLocalizedString("Edit Phrase Replacement Table", comment: ""), action: #selector(openPhraseReplacementvChewing(_:)), keyEquivalent: "") + } + } + + menu.addItem(withTitle: NSLocalizedString("Reload User Phrases", comment: ""), action: #selector(reloadUserPhrases(_:)), keyEquivalent: "") + menu.addItem(NSMenuItem.separator()) + + menu.addItem(withTitle: NSLocalizedString("Check for Updates…", comment: ""), action: #selector(checkForUpdate(_:)), keyEquivalent: "") + menu.addItem(withTitle: NSLocalizedString("About vChewing…", comment: ""), action: #selector(showAbout(_:)), keyEquivalent: "") + return menu + } + + // MARK: - IMKStateSetting protocol methods + + override func activateServer(_ client: Any!) { + UserDefaults.standard.synchronize() + + // Override the keyboard layout. Use US if not set. + (client as? IMKTextInput)?.overrideKeyboard(withKeyboardNamed: Preferences.basisKeyboardLayout) + // reset the state + currentDeferredClient = nil + currentCandidateClient = nil + + keyHandler.clear() + keyHandler.syncWithPreferences() + self.handle(state: .Empty(), client: client) + (NSApp.delegate as? AppDelegate)?.checkForUpdate() + } + + override func deactivateServer(_ client: Any!) { + keyHandler.clear() + self.handle(state: .Empty(), client: client) + self.handle(state: .Deactivated(), client: client) + } + + override func setValue(_ value: Any!, forTag tag: Int, client: Any!) { + let newInputMode = InputMode(rawValue: value as? String ?? InputMode.bopomofo.rawValue) + mgrLangModel.loadDataModel(newInputMode) + if keyHandler.inputMode != newInputMode { + UserDefaults.standard.synchronize() + // Remember to override the keyboard layout again -- treat this as an activate event. + (client as? IMKTextInput)?.overrideKeyboard(withKeyboardNamed: Preferences.basisKeyboardLayout) + keyHandler.clear() + keyHandler.inputMode = newInputMode + self.handle(state: .Empty(), client: client) + } + } + + // MARK: - IMKServerInput protocol methods + + override func recognizedEvents(_ sender: Any!) -> Int { + let events: NSEvent.EventTypeMask = [.keyDown, .flagsChanged] + return Int(events.rawValue) + } + + override func handle(_ event: NSEvent!, client: Any!) -> Bool { + if event.type == .flagsChanged { + let functionKeyKeyboardLayoutID = Preferences.functionKeyboardLayout + let basisKeyboardLayoutID = Preferences.basisKeyboardLayout + + if functionKeyKeyboardLayoutID == basisKeyboardLayoutID { + return false + } + + let includeShift = Preferences.functionKeyKeyboardLayoutOverrideIncludeShiftKey + let notShift = NSEvent.ModifierFlags(rawValue: ~(NSEvent.ModifierFlags.shift.rawValue)) + if event.modifierFlags.contains(notShift) || + (event.modifierFlags.contains(.shift) && includeShift) { + (client as? IMKTextInput)?.overrideKeyboard(withKeyboardNamed: functionKeyKeyboardLayoutID) + return false + } + (client as? IMKTextInput)?.overrideKeyboard(withKeyboardNamed: basisKeyboardLayoutID) + return false + } + + var textFrame = NSRect.zero + let attributes: [AnyHashable: Any]? = (client as? IMKTextInput)?.attributes(forCharacterIndex: 0, lineHeightRectangle: &textFrame) + let useVerticalMode = (attributes?["IMKTextOrientation"] as? NSNumber)?.intValue == 0 || false + + if (client as? IMKTextInput)?.bundleIdentifier() == "com.apple.Terminal" && + NSStringFromClass(client.self as! AnyClass) == "IPMDServerClientWrapper" { + currentDeferredClient = client + } + + let input = KeyHandlerInput(event: event, isVerticalMode: useVerticalMode) + + let result = keyHandler.handle(input: input, state: state) { newState in + self.handle(state: newState, client: client) + } errorCallback: { + NSSound.beep() + } + return result + } + + // MARK: - Menu Items + + @objc override func showPreferences(_ sender: Any?) { + super.showPreferences(sender) + } + + @objc func toggleChineseConverter(_ sender: Any?) { + let enabled = Preferences.toggleChineseConversionEnabled() + NotifierController.notify(message: enabled ? NSLocalizedString("Chinese conversion on", comment: "") : NSLocalizedString("Chinese conversion off", comment: "")) + } + + @objc func toggleHalfWidthPunctuation(_ sender: Any?) { + let enabled = Preferences.togglePhraseReplacementEnabled() + NotifierController.notify(message: enabled ? NSLocalizedString("Half-width punctuation on", comment: "") : NSLocalizedString("Half-width punctuation off", comment: "")) + } + + @objc func toggleAssociatedPhrasesEnabled(_ sender: Any?) { + _ = Preferences.toggleAssociatedPhrasesEnabled() + } + + @objc func togglePhraseReplacement(_ sender: Any?) { + let enabled = Preferences.togglePhraseReplacementEnabled() + mgrLangModel.phraseReplacementEnabled = enabled + } + + @objc func checkForUpdate(_ sender: Any?) { + (NSApp.delegate as? AppDelegate)?.checkForUpdate(forced: true) + } + + private func open(userFileAt path: String) { + func checkIfUserFilesExist() -> Bool { + if !mgrLangModel.checkIfUserLanguageModelFilesExist() { + let content = String(format: NSLocalizedString("Please check the permission of at \"%@\".", comment: ""), mgrLangModel.dataFolderPath) + NonModalAlertWindowController.shared.show(title: NSLocalizedString("Unable to create the user phrase file.", comment: ""), content: content, confirmButtonTitle: NSLocalizedString("OK", comment: ""), cancelButtonTitle: nil, cancelAsDefault: false, delegate: nil) + return false + } + return true + } + + if !checkIfUserFilesExist() { + return + } + let url = URL(fileURLWithPath: path) + NSWorkspace.shared.open(url) + } + + @objc func openUserPhrases(_ sender: Any?) { + open(userFileAt: mgrLangModel.userPhrasesDataPathvChewing) + } + + @objc func openExcludedPhrasesPlainBopomofo(_ sender: Any?) { + open(userFileAt: mgrLangModel.excludedPhrasesDataPathPlainBopomofo) + } + + @objc func openExcludedPhrasesvChewing(_ sender: Any?) { + open(userFileAt: mgrLangModel.excludedPhrasesDataPathvChewing) + } + + @objc func openPhraseReplacementvChewing(_ sender: Any?) { + open(userFileAt: mgrLangModel.phraseReplacementDataPathvChewing) + } + + @objc func reloadUserPhrases(_ sender: Any?) { + mgrLangModel.loadUserPhrases() + mgrLangModel.loadUserPhraseReplacement() + } + + @objc func showAbout(_ sender: Any?) { + NSApp.orderFrontStandardAboutPanel(sender) + NSApp.activate(ignoringOtherApps: true) + } + +} + +// MARK: - State Handling + +extension ctlInputMethod { + + private func handle(state newState: InputState, client: Any?) { + let previous = state + state = newState + + if let newState = newState as? InputState.Deactivated { + handle(state: newState, previous: previous, client: client) + } else if let newState = newState as? InputState.Empty { + handle(state: newState, previous: previous, client: client) + } else if let newState = newState as? InputState.EmptyIgnoringPreviousState { + handle(state: newState, previous: previous, client: client) + } else if let newState = newState as? InputState.Committing { + handle(state: newState, previous: previous, client: client) + } else if let newState = newState as? InputState.Inputting { + handle(state: newState, previous: previous, client: client) + } else if let newState = newState as? InputState.Marking { + handle(state: newState, previous: previous, client: client) + } else if let newState = newState as? InputState.ChoosingCandidate { + handle(state: newState, previous: previous, client: client) + } else if let newState = newState as? InputState.AssociatedPhrases { + handle(state: newState, previous: previous, client: client) + } + } + + private func commit(text: String, client: Any!) { + + func convertToKangXiChineseIfRequired(_ text: String) -> String { + if !Preferences.chineseConversionEnabled { + return text + } + return OpenCCBridge.convertToKangXi(text) ?? "" + } + + let buffer = convertToKangXiChineseIfRequired(text) + if buffer.isEmpty { + return + } + // if it's Terminal, we don't commit at the first call (the client of which will not be IPMDServerClientWrapper) + // then we defer the update in the next runloop round -- so that the composing buffer is not + // meaninglessly flushed, an annoying bug in Terminal.app since Mac OS X 10.5 + if (client as? IMKTextInput)?.bundleIdentifier() == "com.apple.Terminal" && NSStringFromClass(client.self as! AnyClass) != "IPMDServerClientWrapper" { + let innerCurrentDeferredClient = currentDeferredClient + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) { + (innerCurrentDeferredClient as? IMKTextInput)?.insertText(buffer, replacementRange: NSRange(location: NSNotFound, length: NSNotFound)) + } + } + (client as? IMKTextInput)?.insertText(buffer, replacementRange: NSRange(location: NSNotFound, length: NSNotFound)) + } + + private func handle(state: InputState.Deactivated, previous: InputState, client: Any?) { + currentDeferredClient = nil + currentCandidateClient = nil + + gCurrentCandidateController?.delegate = nil + gCurrentCandidateController?.visible = false + hideTooltip() + + if let previous = previous as? InputState.NotEmpty { + commit(text: previous.composingBuffer, client: client) + } + (client as? IMKTextInput)?.setMarkedText("", selectionRange: NSMakeRange(0, 0), replacementRange: NSMakeRange(NSNotFound, NSNotFound)) + } + + private func handle(state: InputState.Empty, previous: InputState, client: Any?) { + gCurrentCandidateController?.visible = false + hideTooltip() + + guard let client = client as? IMKTextInput else { + return + } + + if let previous = previous as? InputState.NotEmpty { + commit(text: previous.composingBuffer, client: client) + } + client.setMarkedText("", selectionRange: NSMakeRange(0, 0), replacementRange: NSMakeRange(NSNotFound, NSNotFound)) + } + + private func handle(state: InputState.EmptyIgnoringPreviousState, previous: InputState, client: Any!) { + gCurrentCandidateController?.visible = false + hideTooltip() + + guard let client = client as? IMKTextInput else { + return + } + + client.setMarkedText("", selectionRange: NSMakeRange(0, 0), replacementRange: NSMakeRange(NSNotFound, NSNotFound)) + } + + private func handle(state: InputState.Committing, previous: InputState, client: Any?) { + gCurrentCandidateController?.visible = false + hideTooltip() + + guard let client = client as? IMKTextInput else { + return + } + + let poppedText = state.poppedText + if !poppedText.isEmpty { + commit(text: poppedText, client: client) + } + client.setMarkedText("", selectionRange: NSMakeRange(0, 0), replacementRange: NSMakeRange(NSNotFound, NSNotFound)) + } + + private func handle(state: InputState.Inputting, previous: InputState, client: Any?) { + gCurrentCandidateController?.visible = false + hideTooltip() + + guard let client = client as? IMKTextInput else { + return + } + + let poppedText = state.poppedText + if !poppedText.isEmpty { + commit(text: poppedText, client: client) + } + + // the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound, + // i.e. the client app needs to take care of where to put this composing buffer + client.setMarkedText(state.attributedString, selectionRange: NSMakeRange(Int(state.cursorIndex), 0), replacementRange: NSMakeRange(NSNotFound, NSNotFound)) + if !state.tooltip.isEmpty { + show(tooltip: state.tooltip, composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex, client: client) + } + } + + private func handle(state: InputState.Marking, previous: InputState, client: Any?) { + gCurrentCandidateController?.visible = false + guard let client = client as? IMKTextInput else { + hideTooltip() + return + } + + // the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound, + // i.e. the client app needs to take care of where to put this composing buffer + client.setMarkedText(state.attributedString, selectionRange: NSMakeRange(Int(state.cursorIndex), 0), replacementRange: NSMakeRange(NSNotFound, NSNotFound)) + + if state.tooltip.isEmpty { + hideTooltip() + } else { + show(tooltip: state.tooltip, composingBuffer: state.composingBuffer, cursorIndex: state.markerIndex, client: client) + } + } + + private func handle(state: InputState.ChoosingCandidate, previous: InputState, client: Any?) { + hideTooltip() + guard let client = client as? IMKTextInput else { + gCurrentCandidateController?.visible = false + return + } + + // the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound, + // i.e. the client app needs to take care of where to put this composing buffer + client.setMarkedText(state.attributedString, selectionRange: NSMakeRange(Int(state.cursorIndex), 0), replacementRange: NSMakeRange(NSNotFound, NSNotFound)) + show(candidateWindowWith: state, client: client) + } + + private func handle(state: InputState.AssociatedPhrases, previous: InputState, client: Any?) { + hideTooltip() + guard let client = client as? IMKTextInput else { + gCurrentCandidateController?.visible = false + return + } + client.setMarkedText("", selectionRange: NSMakeRange(0, 0), replacementRange: NSMakeRange(NSNotFound, NSNotFound)) + show(candidateWindowWith: state, client: client) + } +} + +// MARK: - + +extension ctlInputMethod { + + private func show(candidateWindowWith state: InputState, client: Any!) { + let useVerticalMode: Bool = { + if let state = state as? InputState.ChoosingCandidate { + return state.useVerticalMode + } else if let state = state as? InputState.AssociatedPhrases { + return state.useVerticalMode + } + return false + }() + + if useVerticalMode { + gCurrentCandidateController = ctlInputMethod.verticalCandidateController + } else if Preferences.useHorizontalCandidateList { + gCurrentCandidateController = ctlInputMethod.horizontalCandidateController + } else { + gCurrentCandidateController = ctlInputMethod.verticalCandidateController + } + + // set the attributes for the candidate panel (which uses NSAttributedString) + let textSize = Preferences.candidateListTextSize + let keyLabelSize = max(textSize / 2, kMinKeyLabelSize) + + func font(name: String?, size: CGFloat) -> NSFont { + if let name = name { + return NSFont(name: name, size: size) ?? NSFont.systemFont(ofSize: size) + } + return NSFont.systemFont(ofSize: size) + } + + gCurrentCandidateController?.keyLabelFont = font(name: Preferences.candidateKeyLabelFontName, size: keyLabelSize) + gCurrentCandidateController?.candidateFont = font(name: Preferences.candidateTextFontName, size: textSize) + + let candidateKeys = Preferences.candidateKeys + let keyLabels = candidateKeys.count > 4 ? Array(candidateKeys) : Array(Preferences.defaultCandidateKeys) + let keyLabelPrefix = state is InputState.AssociatedPhrases ? "⇧ " : "" + gCurrentCandidateController?.keyLabels = keyLabels.map { + CandidateKeyLabel(key: String($0), displayedText: keyLabelPrefix + String($0)) + } + + gCurrentCandidateController?.delegate = self + gCurrentCandidateController?.reloadData() + currentCandidateClient = client + + gCurrentCandidateController?.visible = true + + var lineHeightRect = NSMakeRect(0.0, 0.0, 16.0, 16.0) + var cursor: Int = 0 + + if let state = state as? InputState.ChoosingCandidate { + cursor = Int(state.cursorIndex) + if cursor == state.composingBuffer.count && cursor != 0 { + cursor -= 1 + } + } + + while lineHeightRect.origin.x == 0 && lineHeightRect.origin.y == 0 && cursor >= 0 { + (client as? IMKTextInput)?.attributes(forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect) + cursor -= 1 + } + + if useVerticalMode { + gCurrentCandidateController?.set(windowTopLeftPoint: NSMakePoint(lineHeightRect.origin.x + lineHeightRect.size.width + 4.0, lineHeightRect.origin.y - 4.0), bottomOutOfScreenAdjustmentHeight: lineHeightRect.size.height + 4.0) + } else { + gCurrentCandidateController?.set(windowTopLeftPoint: NSMakePoint(lineHeightRect.origin.x, lineHeightRect.origin.y - 4.0), bottomOutOfScreenAdjustmentHeight: lineHeightRect.size.height + 4.0) + } + } + + private func show(tooltip: String, composingBuffer: String, cursorIndex: UInt, client: Any!) { + var lineHeightRect = NSMakeRect(0.0, 0.0, 16.0, 16.0) + var cursor: Int = Int(cursorIndex) + if cursor == composingBuffer.count && cursor != 0 { + cursor -= 1 + } + while lineHeightRect.origin.x == 0 && lineHeightRect.origin.y == 0 && cursor >= 0 { + (client as? IMKTextInput)?.attributes(forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect) + cursor -= 1 + } + ctlInputMethod.tooltipController.show(tooltip: tooltip, at: lineHeightRect.origin) + } + + private func hideTooltip() { + ctlInputMethod.tooltipController.hide() + } +} + +// MARK: - + +extension ctlInputMethod: KeyHandlerDelegate { + func candidateController(for keyHandler: KeyHandler) -> Any { + gCurrentCandidateController ?? ctlInputMethod.verticalCandidateController + } + + func keyHandler(_ keyHandler: KeyHandler, didSelectCandidateAt index: Int, candidateController controller: Any) { + if let controller = controller as? CandidateController { + self.candidateController(controller, didSelectCandidateAtIndex: UInt(index)) + } + } + + func keyHandler(_ keyHandler: KeyHandler, didRequestWriteUserPhraseWith state: InputState) -> Bool { + guard let state = state as? InputState.Marking else { + return false + } + if !state.validToWrite { + return false + } + mgrLangModel.writeUserPhrase(state.userPhrase) + return true + } +} + +// MARK: - + +extension ctlInputMethod: CandidateControllerDelegate { + func candidateCountForController(_ controller: CandidateController) -> UInt { + if let state = state as? InputState.ChoosingCandidate { + return UInt(state.candidates.count) + } else if let state = state as? InputState.AssociatedPhrases { + return UInt(state.candidates.count) + } + return 0 + } + + func candidateController(_ controller: CandidateController, candidateAtIndex index: UInt) -> String { + if let state = state as? InputState.ChoosingCandidate { + return state.candidates[Int(index)] + } else if let state = state as? InputState.AssociatedPhrases { + return state.candidates[Int(index)] + } + return "" + } + + func candidateController(_ controller: CandidateController, didSelectCandidateAtIndex index: UInt) { + let client = currentCandidateClient + + if let state = state as? InputState.SymbolTable, + let node = state.node.children?[Int(index)] { + if let children = node.children, !children.isEmpty { + self.handle(state: .SymbolTable(node: node, useVerticalMode: state.useVerticalMode), client: currentCandidateClient) + } else { + self.handle(state: .Committing(poppedText: node.title), client: client) + self.handle(state: .Empty(), client: client) + } + return + } + + if let state = state as? InputState.ChoosingCandidate { + let selectedValue = state.candidates[Int(index)] + keyHandler.fixNode(value: selectedValue) + + guard let inputting = keyHandler.buildInputtingState() as? InputState.Inputting else { + return + } + + if keyHandler.inputMode == .plainBopomofo { + keyHandler.clear() + let composingBuffer = inputting.composingBuffer + handle(state: .Committing(poppedText: composingBuffer), client: client) + if Preferences.associatedPhrasesEnabled, + let associatePhrases = keyHandler.buildAssociatePhraseState(withKey: composingBuffer, useVerticalMode: state.useVerticalMode) as? InputState.AssociatedPhrases { + self.handle(state: associatePhrases, client: client) + } else { + handle(state: .Empty(), client: client) + } + } else { + handle(state: inputting, client: client) + } + return + } + + if let state = state as? InputState.AssociatedPhrases { + let selectedValue = state.candidates[Int(index)] + handle(state: .Committing(poppedText: selectedValue), client: currentCandidateClient) + if Preferences.associatedPhrasesEnabled, + let associatePhrases = keyHandler.buildAssociatePhraseState(withKey: selectedValue, useVerticalMode: state.useVerticalMode) as? InputState.AssociatedPhrases { + self.handle(state: associatePhrases, client: client) + } else { + handle(state: .Empty(), client: client) + } + } + } +} diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/AssociatedPhrases.cpp b/Source/Modules/LangModelRelated/SubLanguageModels/AssociatedPhrases.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d919afea54a4768d62cea186180684c622e1791 --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/AssociatedPhrases.cpp @@ -0,0 +1,101 @@ + +#include "AssociatedPhrases.h" + +#include +#include +#include +#include +#include + +#include "KeyValueBlobReader.h" + +namespace vChewing { + +AssociatedPhrases::AssociatedPhrases() +: fd(-1) +, data(0) +, length(0) +{ +} + +AssociatedPhrases::~AssociatedPhrases() +{ + if (data) { + close(); + } +} + +const bool AssociatedPhrases::isLoaded() +{ + if (data) { + return true; + } + return false; +} + +bool AssociatedPhrases::open(const char *path) +{ + if (data) { + return false; + } + + fd = ::open(path, O_RDONLY); + if (fd == -1) { + printf("open:: file not exist"); + return false; + } + + struct stat sb; + if (fstat(fd, &sb) == -1) { + printf("open:: cannot open file"); + return false; + } + + length = (size_t)sb.st_size; + + data = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0); + if (!data) { + ::close(fd); + return false; + } + + KeyValueBlobReader reader(static_cast(data), length); + KeyValueBlobReader::KeyValue keyValue; + KeyValueBlobReader::State state; + while ((state = reader.Next(&keyValue)) == KeyValueBlobReader::State::HAS_PAIR) { + keyRowMap[keyValue.key].emplace_back(keyValue.key, keyValue.value); + } + return true; +} + +void AssociatedPhrases::close() +{ + if (data) { + munmap(data, length); + ::close(fd); + data = 0; + } + + keyRowMap.clear(); +} + +const std::vector AssociatedPhrases::valuesForKey(const std::string& key) +{ + std::vector v; + auto iter = keyRowMap.find(key); + if (iter != keyRowMap.end()) { + const std::vector& rows = iter->second; + for (const auto& row : rows) { + std::string_view value = row.value; + v.push_back({value.data(), value.size()}); + } + } + return v; +} + +const bool AssociatedPhrases::hasValuesForKey(const std::string& key) +{ + return keyRowMap.find(key) != keyRowMap.end(); +} + +}; // namespace vChewing diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/AssociatedPhrases.h b/Source/Modules/LangModelRelated/SubLanguageModels/AssociatedPhrases.h new file mode 100644 index 0000000000000000000000000000000000000000..6740ff0bbcda5c80463698b5cf82ddb9927ad115 --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/AssociatedPhrases.h @@ -0,0 +1,40 @@ + +#ifndef ASSOCIATEDPHRASES_H +#define ASSOCIATEDPHRASES_H + +#include +#include +#include +#include + +namespace vChewing { + +class AssociatedPhrases +{ +public: + AssociatedPhrases(); + ~AssociatedPhrases(); + + const bool isLoaded(); + bool open(const char *path); + void close(); + const std::vector valuesForKey(const std::string& key); + const bool hasValuesForKey(const std::string& key); + +protected: + struct Row { + Row(std::string_view& k, std::string_view& v) : key(k), value(v) {} + std::string_view key; + std::string_view value; + }; + + std::map> keyRowMap; + + int fd; + void *data; + size_t length; +}; + +} + +#endif /* AssociatedPhrases_hpp */ diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/CNSLM.h b/Source/Modules/LangModelRelated/SubLanguageModels/CNSLM.h new file mode 100644 index 0000000000000000000000000000000000000000..fd2d199ba285f6eace25060cea55adaae72c0ea3 --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/CNSLM.h @@ -0,0 +1,48 @@ +/* + * CNSLM.h + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +#ifndef CNSLM_H +#define CNSLM_H + +#include +#include +#include +#include "LanguageModel.h" + +namespace vChewing { + +class CNSLM : public Taiyan::Gramambular::LanguageModel +{ +public: + CNSLM(); + ~CNSLM(); + + bool open(const char *path); + void close(); + void dump(); + + virtual const std::vector bigramsForKeys(const std::string& preceedingKey, const std::string& key); + virtual const std::vector unigramsForKey(const std::string& key); + virtual bool hasUnigramsForKey(const std::string& key); + +protected: + struct Row { + Row(std::string_view& k, std::string_view& v) : key(k), value(v) {} + std::string_view key; + std::string_view value; + }; + + std::map> keyRowMap; + int fd; + void *data; + size_t length; +}; + +} + +#endif diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/CNSLM.mm b/Source/Modules/LangModelRelated/SubLanguageModels/CNSLM.mm new file mode 100644 index 0000000000000000000000000000000000000000..970cff4817d1a0d804e64ec84e160d0824b9faa9 --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/CNSLM.mm @@ -0,0 +1,131 @@ +/* + * CNSLM.mm + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +#include "CNSLM.h" + +#include +#include +#include +#include +#include +#include + +#include "KeyValueBlobReader.h" + +namespace vChewing { + +CNSLM::CNSLM() + : fd(-1) + , data(0) + , length(0) +{ +} + +CNSLM::~CNSLM() +{ + if (data) { + close(); + } +} + +bool CNSLM::open(const char *path) +{ + if (data) { + syslog(LOG_CONS, "CNSLM: Failed at Open Step 1.\n"); + return false; + } + + fd = ::open(path, O_RDONLY); + if (fd == -1) { + syslog(LOG_CONS, "CNSLM: Failed at Open Step 2.\n"); + printf("open:: file not exist"); + return false; + } + + struct stat sb; + if (fstat(fd, &sb) == -1) { + syslog(LOG_CONS, "CNSLM: Failed at Open Step 3.\n"); + printf("open:: cannot open file"); + return false; + } + + length = (size_t)sb.st_size; + + data = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0); + if (!data) { + ::close(fd); + syslog(LOG_CONS, "CNSLM: Failed at Open Step 4.\n"); + return false; + } + + KeyValueBlobReader reader(static_cast(data), length); + KeyValueBlobReader::KeyValue keyValue; + KeyValueBlobReader::State state; + while ((state = reader.Next(&keyValue)) == KeyValueBlobReader::State::HAS_PAIR) { + // We invert the key and value, since in user phrases, "key" is the phrase value, and "value" is the BPMF reading. + keyRowMap[keyValue.value].emplace_back(keyValue.value, keyValue.key); + } + // 下面這一段或許可以做成開關、來詢問是否對使用者語彙採取寬鬆策略(哪怕有行內容寫錯也會放行) + if (state == KeyValueBlobReader::State::ERROR) { + // close(); + syslog(LOG_CONS, "CNSLM: Failed at Open Step 5. On Error Resume Next.\n"); + // return false; + } + return true; +} + +void CNSLM::close() +{ + if (data) { + munmap(data, length); + ::close(fd); + data = 0; + } + + keyRowMap.clear(); +} + +void CNSLM::dump() +{ + for (const auto& entry : keyRowMap) { + const std::vector& rows = entry.second; + for (const auto& row : rows) { + std::cerr << row.key << " " << row.value << "\n"; + } + } +} + +const std::vector CNSLM::bigramsForKeys(const std::string& preceedingKey, const std::string& key) +{ + return std::vector(); +} + +const std::vector CNSLM::unigramsForKey(const std::string& key) +{ + std::vector v; + auto iter = keyRowMap.find(key); + if (iter != keyRowMap.end()) { + const std::vector& rows = iter->second; + for (const auto& row : rows) { + Taiyan::Gramambular::Unigram g; + g.keyValue.key = row.key; + g.keyValue.value = row.value; + g.score = -17.0; + v.push_back(g); + } + } + + return v; +} + +bool CNSLM::hasUnigramsForKey(const std::string& key) +{ + return keyRowMap.find(key) != keyRowMap.end(); +} + +}; // namespace vChewing diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.h b/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.h new file mode 100644 index 0000000000000000000000000000000000000000..b26bf941f065fa2f9ada1127571c16cbd0fbdf55 --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.h @@ -0,0 +1,64 @@ +/* + * CoreLM.h + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +#ifndef CoreLM_H +#define CoreLM_H + +#include "LanguageModel.h" +#include +#include +#include +#include + +// this class relies on the fact that we have a space-separated data +// format, and we use mmap and zero-out the separators and line feeds +// to avoid creating new string objects; the parser is a simple DFA + +using namespace std; +using namespace Taiyan::Gramambular; + +namespace vChewing { + +class CoreLM : public Taiyan::Gramambular::LanguageModel { +public: + CoreLM(); + ~CoreLM(); + + bool isLoaded(); + bool open(const char *path); + void close(); + void dump(); + + virtual const vector bigramsForKeys(const string& preceedingKey, const string& key); + virtual const vector unigramsForKey(const string& key); + virtual bool hasUnigramsForKey(const string& key); + +protected: + struct CStringCmp + { + bool operator()(const char* s1, const char* s2) const + { + return strcmp(s1, s2) < 0; + } + }; + + struct Row { + const char *key; + const char *value; + const char *logProbability; + }; + + map, CStringCmp> keyRowMap; + int fd; + void *data; + size_t length; +}; + +}; // namespace vChewing + +#endif diff --git a/Source/Engine/FastLM.cpp b/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.mm similarity index 76% rename from Source/Engine/FastLM.cpp rename to Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.mm index 48569c65d0c67077df3642b6baa05de551cd7ed4..d5900fdeaa581f3fbf871970165c88f80b8ef28c 100644 --- a/Source/Engine/FastLM.cpp +++ b/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.mm @@ -1,59 +1,49 @@ -// -// FastLM.h: A fast unigram language model for Gramambular -// -// Copyright (c) 2012 Lukhnos Liu (http://lukhnos.org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#include "FastLM.h" +/* + * CoreLM.mm + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +#include "CoreLM.h" #include #include #include #include #include +#include -using namespace Formosa::Gramambular; +using namespace Taiyan::Gramambular; -FastLM::FastLM() +vChewing::CoreLM::CoreLM() : fd(-1) , data(0) , length(0) { } -FastLM::~FastLM() +vChewing::CoreLM::~CoreLM() { if (data) { close(); } } -bool FastLM::open(const char *path) +bool vChewing::CoreLM::isLoaded() { if (data) { - return false; + return true; } + return false; +} +bool vChewing::CoreLM::open(const char *path) +{ + if (data) { + return false; + } + fd = ::open(path, O_RDONLY); if (fd == -1) { return false; @@ -256,7 +246,7 @@ end: return true; } -void FastLM::close() +void vChewing::CoreLM::close() { if (data) { munmap(data, length); @@ -267,7 +257,7 @@ void FastLM::close() keyRowMap.clear(); } -void FastLM::dump() +void vChewing::CoreLM::dump() { size_t rows = 0; for (map >::const_iterator i = keyRowMap.begin(), e = keyRowMap.end(); i != e; ++i) { @@ -280,12 +270,12 @@ void FastLM::dump() } } -const vector FastLM::bigramsForKeys(const string& preceedingKey, const string& key) +const vector vChewing::CoreLM::bigramsForKeys(const string& preceedingKey, const string& key) { return vector(); } -const vector FastLM::unigramsForKeys(const string& key) +const vector vChewing::CoreLM::unigramsForKey(const string& key) { vector v; map >::const_iterator i = keyRowMap.find(key.c_str()); @@ -304,7 +294,7 @@ const vector FastLM::unigramsForKeys(const string& key) return v; } -bool FastLM::hasUnigramsForKey(const string& key) +bool vChewing::CoreLM::hasUnigramsForKey(const string& key) { return keyRowMap.find(key.c_str()) != keyRowMap.end(); } diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/ParselessLM.cpp b/Source/Modules/LangModelRelated/SubLanguageModels/ParselessLM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..500c37b07a65364e9a25d1cadae47ab6cd849ef6 --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/ParselessLM.cpp @@ -0,0 +1,135 @@ +/* + * ParselessLM.cpp + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +#include "ParselessLM.h" + +#include +#include +#include +#include + +#include + +vChewing::ParselessLM::~ParselessLM() { close(); } + +bool vChewing::ParselessLM::isLoaded() +{ + if (data_) { + return true; + } + return false; +} + +bool vChewing::ParselessLM::open(const std::string_view& path) +{ + if (data_) { + return false; + } + + fd_ = ::open(path.data(), O_RDONLY); + if (fd_ == -1) { + return false; + } + + struct stat sb; + if (fstat(fd_, &sb) == -1) { + ::close(fd_); + fd_ = -1; + return false; + } + + length_ = static_cast(sb.st_size); + + data_ = mmap(NULL, length_, PROT_READ, MAP_SHARED, fd_, 0); + if (data_ == nullptr) { + ::close(fd_); + fd_ = -1; + length_ = 0; + return false; + } + + db_ = std::unique_ptr(new ParselessPhraseDB( + static_cast(data_), length_)); + return true; +} + +void vChewing::ParselessLM::close() +{ + if (data_ != nullptr) { + munmap(data_, length_); + ::close(fd_); + fd_ = -1; + length_ = 0; + data_ = nullptr; + } +} + +const std::vector +vChewing::ParselessLM::bigramsForKeys( + const std::string& preceedingKey, const std::string& key) +{ + return std::vector(); +} + +const std::vector +vChewing::ParselessLM::unigramsForKey(const std::string& key) +{ + if (db_ == nullptr) { + return std::vector(); + } + + std::vector results; + for (const auto& row : db_->findRows(key + " ")) { + Taiyan::Gramambular::Unigram unigram; + + // Move ahead until we encounter the first space. This is the key. + auto it = row.begin(); + while (it != row.end() && *it != ' ') { + ++it; + } + + unigram.keyValue.key = std::string(row.begin(), it); + + // Read past the space. + if (it != row.end()) { + ++it; + } + + if (it != row.end()) { + // Now it is the start of the value portion. + auto value_begin = it; + + // Move ahead until we encounter the second space. This is the + // value. + while (it != row.end() && *it != ' ') { + ++it; + } + unigram.keyValue.value = std::string(value_begin, it); + } + + // Read past the space. The remainder, if it exists, is the score. + if (it != row.end()) { + ++it; + } + + if (it != row.end()) { + unigram.score = std::stod(std::string(it, row.end())); + } + results.push_back(unigram); + } + return results; +} + +bool vChewing::ParselessLM::hasUnigramsForKey(const std::string& key) +{ + if (db_ == nullptr) { + return false; + } + + return db_->findFirstMatchingLine(key + " ") != nullptr; +} diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/ParselessLM.h b/Source/Modules/LangModelRelated/SubLanguageModels/ParselessLM.h new file mode 100644 index 0000000000000000000000000000000000000000..3b065699479d53b98dd58f0b4ad12031b6525ffc --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/ParselessLM.h @@ -0,0 +1,44 @@ +/* + * ParselessLM.h + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +#ifndef SOURCE_ENGINE_PARSELESSLM_H_ +#define SOURCE_ENGINE_PARSELESSLM_H_ + +#include +#include +#include + +#include "LanguageModel.h" +#include "ParselessPhraseDB.h" + +namespace vChewing { + +class ParselessLM : public Taiyan::Gramambular::LanguageModel { +public: + ~ParselessLM() override; + + bool isLoaded(); + bool open(const std::string_view& path); + void close(); + + const std::vector bigramsForKeys( + const std::string& preceedingKey, const std::string& key) override; + const std::vector unigramsForKey( + const std::string& key) override; + bool hasUnigramsForKey(const std::string& key) override; + +private: + int fd_ = -1; + void* data_ = nullptr; + size_t length_ = 0; + std::unique_ptr db_; +}; + +}; // namespace vChewing + +#endif // SOURCE_ENGINE_PARSELESSLM_H_ diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/ParselessPhraseDB.cpp b/Source/Modules/LangModelRelated/SubLanguageModels/ParselessPhraseDB.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ecd77e898126bf18f1c1abbb9f3fb660528ef7f --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/ParselessPhraseDB.cpp @@ -0,0 +1,126 @@ + +#include "ParselessPhraseDB.h" + +#include +#include + +namespace vChewing { + +ParselessPhraseDB::ParselessPhraseDB( + const char* buf, size_t length) + : begin_(buf) + , end_(buf + length) +{ +} + +std::vector ParselessPhraseDB::findRows( + const std::string_view& key) +{ + std::vector rows; + + const char* ptr = findFirstMatchingLine(key); + if (ptr == nullptr) { + return rows; + } + + while (ptr + key.length() <= end_ + && memcmp(ptr, key.data(), key.length()) == 0) { + const char* eol = ptr; + + while (eol != end_ && *eol != '\n') { + ++eol; + } + + rows.emplace_back(ptr, eol - ptr); + if (eol == end_) { + break; + } + + ptr = ++eol; + } + + return rows; +} + +// Implements a binary search that returns the pointer to the first matching +// row. In its core it's just a standard binary search, but we use backtracking +// to locate the line start. We also check the previous line to see if the +// current line is actually the first matching line: if the previous line is +// less to the key and the current line starts exactly with the key, then +// the current line is the first matching line. +const char* ParselessPhraseDB::findFirstMatchingLine( + const std::string_view& key) +{ + if (key.empty()) { + return begin_; + } + + const char* top = begin_; + const char* bottom = end_; + + while (top < bottom) { + const char* mid = top + (bottom - top) / 2; + const char* ptr = mid; + + if (ptr != begin_) { + --ptr; + } + + while (ptr != begin_ && *ptr != '\n') { + --ptr; + } + + const char* prev = nullptr; + if (*ptr == '\n') { + prev = ptr; + ++ptr; + } + + // ptr is now in the "current" line we're interested in. + if (ptr + key.length() > end_) { + // not enough data to compare at this point, bail. + break; + } + + int current_cmp = memcmp(ptr, key.data(), key.length()); + + if (current_cmp > 0) { + bottom = mid - 1; + continue; + } + + if (current_cmp < 0) { + top = mid + 1; + continue; + } + + if (!prev) { + return ptr; + } + + // Move the prev so that it reaches the previous line. + if (prev != begin_) { + --prev; + } + while (prev != begin_ && *prev != '\n') { + --prev; + } + if (*prev == '\n') { + ++prev; + } + + int prev_cmp = memcmp(prev, key.data(), key.length()); + + // This is the first occurrence. + if (prev_cmp < 0 && current_cmp == 0) { + return ptr; + } + + // This is not, which means ptr is "larger" than the keyData. + bottom = mid - 1; + } + + return nullptr; +} + +}; // namespace vChewing diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/ParselessPhraseDB.h b/Source/Modules/LangModelRelated/SubLanguageModels/ParselessPhraseDB.h new file mode 100644 index 0000000000000000000000000000000000000000..4c278cf4cd7d1be18c3a3cb40effd05b32580a82 --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/ParselessPhraseDB.h @@ -0,0 +1,35 @@ + +#ifndef SOURCE_ENGINE_PARSELESSPHRASEDB_H_ +#define SOURCE_ENGINE_PARSELESSPHRASEDB_H_ + +#include +#include +#include + +namespace vChewing { + +// Defines phrase database that consists of (key, value, score) rows that are +// pre-sorted by the byte value of the keys. It is way faster than FastLM +// because it does not need to parse anything. Instead, it relies on the fact +// that the database is already sorted, and binary search is used to find the +// rows. +class ParselessPhraseDB { +public: + ParselessPhraseDB( + const char* buf, size_t length); + + // Find the rows that match the key. Note that prefix match is used. If you + // need exact match, the key will need to have a delimiter (usually a space) + // at the end. + std::vector findRows(const std::string_view& key); + + const char* findFirstMatchingLine(const std::string_view& key); + +private: + const char* begin_; + const char* end_; +}; + +}; // namespace vChewing + +#endif // SOURCE_ENGINE_PARSELESSPHRASEDB_H_ diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/PhraseReplacementMap.cpp b/Source/Modules/LangModelRelated/SubLanguageModels/PhraseReplacementMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3366eb51134108430198e7d6ea8150f919c8ac3 --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/PhraseReplacementMap.cpp @@ -0,0 +1,86 @@ +#include "PhraseReplacementMap.h" + +#include +#include +#include +#include +#include + +#include "KeyValueBlobReader.h" + +namespace vChewing { + +using std::string; + +PhraseReplacementMap::PhraseReplacementMap() +: fd(-1) +, data(0) +, length(0) +{ +} + +PhraseReplacementMap::~PhraseReplacementMap() +{ + if (data) { + close(); + } +} + +bool PhraseReplacementMap::open(const char *path) +{ + if (data) { + return false; + } + + fd = ::open(path, O_RDONLY); + if (fd == -1) { + printf("open:: file not exist"); + return false; + } + + struct stat sb; + if (fstat(fd, &sb) == -1) { + printf("open:: cannot open file"); + return false; + } + + length = (size_t)sb.st_size; + + data = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0); + if (!data) { + ::close(fd); + return false; + } + + KeyValueBlobReader reader(static_cast(data), length); + KeyValueBlobReader::KeyValue keyValue; + KeyValueBlobReader::State state; + while ((state = reader.Next(&keyValue)) == KeyValueBlobReader::State::HAS_PAIR) { + keyValueMap[keyValue.key] = keyValue.value; + } + return true; +} + +void PhraseReplacementMap::close() +{ + if (data) { + munmap(data, length); + ::close(fd); + data = 0; + } + + keyValueMap.clear(); +} + +const std::string PhraseReplacementMap::valueForKey(const std::string& key) +{ + auto iter = keyValueMap.find(key); + if (iter != keyValueMap.end()) { + const std::string_view v = iter->second; + return {v.data(), v.size()}; + } + return string(""); +} + + +} diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/PhraseReplacementMap.h b/Source/Modules/LangModelRelated/SubLanguageModels/PhraseReplacementMap.h new file mode 100644 index 0000000000000000000000000000000000000000..af1959cf0e56b417b4dceb4e11cc4d1d21c12689 --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/PhraseReplacementMap.h @@ -0,0 +1,30 @@ + +#ifndef PHRASEREPLACEMENTMAP_H +#define PHRASEREPLACEMENTMAP_H + +#include +#include +#include + +namespace vChewing { + +class PhraseReplacementMap +{ +public: + PhraseReplacementMap(); + ~PhraseReplacementMap(); + + bool open(const char *path); + void close(); + const std::string valueForKey(const std::string& key); + +protected: + std::map keyValueMap; + int fd; + void *data; + size_t length; +}; + +} + +#endif diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.cpp b/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ee7d2dde058d0bdb60fd49a5c820e120d48434f --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.cpp @@ -0,0 +1,193 @@ + +#include "UserOverrideModel.h" + +#include +#include +#include + +using namespace vChewing; + +// About 20 generations. +static const double DecayThreshould = 1.0 / 1048576.0; + +static double Score(size_t eventCount, + size_t totalCount, + double eventTimestamp, + double timestamp, + double lambda); +static bool IsEndingPunctuation(const string& value); +static string WalkedNodesToKey(const std::vector& walkedNodes, + size_t cursorIndex); + +UserOverrideModel::UserOverrideModel(size_t capacity, double decayConstant) + : m_capacity(capacity) { + assert(m_capacity > 0); + m_decayExponent = log(0.5) / decayConstant; +} + +void UserOverrideModel::observe(const std::vector& walkedNodes, + size_t cursorIndex, + const string& candidate, + double timestamp) { + string key = WalkedNodesToKey(walkedNodes, cursorIndex); + auto mapIter = m_lruMap.find(key); + if (mapIter == m_lruMap.end()) { + auto keyValuePair = KeyObservationPair(key, Observation()); + Observation& observation = keyValuePair.second; + observation.update(candidate, timestamp); + + m_lruList.push_front(keyValuePair); + auto listIter = m_lruList.begin(); + auto lruKeyValue = std::pair::iterator>(key, listIter); + m_lruMap.insert(lruKeyValue); + + if (m_lruList.size() > m_capacity) { + auto lastKeyValuePair = m_lruList.end(); + --lastKeyValuePair; + m_lruMap.erase(lastKeyValuePair->first); + m_lruList.pop_back(); + } + } else { + auto listIter = mapIter->second; + m_lruList.splice(m_lruList.begin(), m_lruList, listIter); + + auto& keyValuePair = *listIter; + Observation& observation = keyValuePair.second; + observation.update(candidate, timestamp); + } +} + +string UserOverrideModel::suggest(const std::vector& walkedNodes, + size_t cursorIndex, + double timestamp) { + string key = WalkedNodesToKey(walkedNodes, cursorIndex); + auto mapIter = m_lruMap.find(key); + if (mapIter == m_lruMap.end()) { + return string(); + } + + auto listIter = mapIter->second; + auto& keyValuePair = *listIter; + const Observation& observation = keyValuePair.second; + + string candidate; + double score = 0.0; + for (auto i = observation.overrides.begin(); + i != observation.overrides.end(); + ++i) { + const Override& o = i->second; + double overrideScore = Score(o.count, + observation.count, + o.timestamp, + timestamp, + m_decayExponent); + if (overrideScore == 0.0) { + continue; + } + + if (overrideScore > score) { + candidate = i->first; + score = overrideScore; + } + } + return candidate; +} + +void UserOverrideModel::Observation::update(const string& candidate, + double timestamp) { + count++; + auto& o = overrides[candidate]; + o.timestamp = timestamp; + o.count++; +} + +static double Score(size_t eventCount, + size_t totalCount, + double eventTimestamp, + double timestamp, + double lambda) { + double decay = exp((timestamp - eventTimestamp) * lambda); + if (decay < DecayThreshould) { + return 0.0; + } + + double prob = (double)eventCount / (double)totalCount; + return prob * decay; +} + +static bool IsEndingPunctuation(const string& value) { + return value == "," || value == "。" || value== "!" || value == "?" || + value == "」" || value == "』" || value== "”" || value == "”"; +} +static string WalkedNodesToKey(const std::vector& walkedNodes, + size_t cursorIndex) { + std::stringstream s; + std::vector n; + size_t ll = 0; + for (std::vector::const_iterator i = walkedNodes.begin(); + i != walkedNodes.end(); + ++i) { + const auto& nn = *i; + n.push_back(nn); + ll += nn.spanningLength; + if (ll >= cursorIndex) { + break; + } + } + + std::vector::const_reverse_iterator r = n.rbegin(); + + if (r == n.rend()) { + return ""; + } + + string current = (*r).node->currentKeyValue().key; + ++r; + + s.clear(); + s.str(std::string()); + if (r != n.rend()) { + string value = (*r).node->currentKeyValue().value; + if (IsEndingPunctuation(value)) { + s << "()"; + r = n.rend(); + } else { + s << "(" + << (*r).node->currentKeyValue().key + << "," + << value + << ")"; + ++r; + } + } else { + s << "()"; + } + string prev = s.str(); + + s.clear(); + s.str(std::string()); + if (r != n.rend()) { + string value = (*r).node->currentKeyValue().value; + if (IsEndingPunctuation(value)) { + s << "()"; + r = n.rend(); + } else { + s << "(" + << (*r).node->currentKeyValue().key + << "," + << value + << ")"; + ++r; + } + } else { + s << "()"; + } + string anterior = s.str(); + + s.clear(); + s.str(std::string()); + s << "(" << anterior << "," << prev << "," << current << ")"; + + return s.str(); +} diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.h b/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.h new file mode 100644 index 0000000000000000000000000000000000000000..6753da508ff1c084c734b8e47845bc6edb4e015e --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.h @@ -0,0 +1,55 @@ + +#ifndef USEROVERRIDEMODEL_H +#define USEROVERRIDEMODEL_H + +#include +#include +#include + +#include "Gramambular.h" + +namespace vChewing { + +using namespace Taiyan::Gramambular; + +class UserOverrideModel { +public: + UserOverrideModel(size_t capacity, double decayConstant); + + void observe(const std::vector& walkedNodes, + size_t cursorIndex, + const string& candidate, + double timestamp); + + string suggest(const std::vector& walkedNodes, + size_t cursorIndex, + double timestamp); + +private: + struct Override { + size_t count; + double timestamp; + + Override() : count(0), timestamp(0.0) {} + }; + + struct Observation { + size_t count; + std::map overrides; + + Observation() : count(0) {} + void update(const string& candidate, double timestamp); + }; + + typedef std::pair KeyObservationPair; + + size_t m_capacity; + double m_decayExponent; + std::list m_lruList; + std::map::iterator> m_lruMap; +}; + +}; // namespace vChewing + +#endif + diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/UserPhrasesLM.cpp b/Source/Modules/LangModelRelated/SubLanguageModels/UserPhrasesLM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..872fa9f01fb66f02e1b743f782accb868192b33f --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/UserPhrasesLM.cpp @@ -0,0 +1,121 @@ + +#include "UserPhrasesLM.h" + +#include +#include +#include +#include +#include + +#include "KeyValueBlobReader.h" + +namespace vChewing { + +UserPhrasesLM::UserPhrasesLM() + : fd(-1) + , data(0) + , length(0) +{ +} + +UserPhrasesLM::~UserPhrasesLM() +{ + if (data) { + close(); + } +} + +bool UserPhrasesLM::isLoaded() +{ + if (data) { + return true; + } + return false; +} + +bool UserPhrasesLM::open(const char *path) +{ + if (data) { + return false; + } + + fd = ::open(path, O_RDONLY); + if (fd == -1) { + printf("open:: file not exist"); + return false; + } + + struct stat sb; + if (fstat(fd, &sb) == -1) { + printf("open:: cannot open file"); + return false; + } + + length = (size_t)sb.st_size; + + data = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0); + if (!data) { + ::close(fd); + return false; + } + + KeyValueBlobReader reader(static_cast(data), length); + KeyValueBlobReader::KeyValue keyValue; + KeyValueBlobReader::State state; + while ((state = reader.Next(&keyValue)) == KeyValueBlobReader::State::HAS_PAIR) { + // We invert the key and value, since in user phrases, "key" is the phrase value, and "value" is the BPMF reading. + keyRowMap[keyValue.value].emplace_back(keyValue.value, keyValue.key); + } + return true; +} + +void UserPhrasesLM::close() +{ + if (data) { + munmap(data, length); + ::close(fd); + data = 0; + } + + keyRowMap.clear(); +} + +void UserPhrasesLM::dump() +{ + for (const auto& entry : keyRowMap) { + const std::vector& rows = entry.second; + for (const auto& row : rows) { + std::cerr << row.key << " " << row.value << "\n"; + } + } +} + +const std::vector UserPhrasesLM::bigramsForKeys(const std::string& preceedingKey, const std::string& key) +{ + return std::vector(); +} + +const std::vector UserPhrasesLM::unigramsForKey(const std::string& key) +{ + std::vector v; + auto iter = keyRowMap.find(key); + if (iter != keyRowMap.end()) { + const std::vector& rows = iter->second; + for (const auto& row : rows) { + Taiyan::Gramambular::Unigram g; + g.keyValue.key = row.key; + g.keyValue.value = row.value; + g.score = 0.0; + v.push_back(g); + } + } + + return v; +} + +bool UserPhrasesLM::hasUnigramsForKey(const std::string& key) +{ + return keyRowMap.find(key) != keyRowMap.end(); +} + +}; // namespace vChewing diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/UserPhrasesLM.h b/Source/Modules/LangModelRelated/SubLanguageModels/UserPhrasesLM.h new file mode 100644 index 0000000000000000000000000000000000000000..3fe4865f6004a76f63940f6c05789b5c5ff6dd14 --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLanguageModels/UserPhrasesLM.h @@ -0,0 +1,42 @@ + +#ifndef USERPHRASESLM_H +#define USERPHRASESLM_H + +#include +#include +#include +#include "LanguageModel.h" + +namespace vChewing { + +class UserPhrasesLM : public Taiyan::Gramambular::LanguageModel +{ +public: + UserPhrasesLM(); + ~UserPhrasesLM(); + + bool isLoaded(); + bool open(const char *path); + void close(); + void dump(); + + virtual const std::vector bigramsForKeys(const std::string& preceedingKey, const std::string& key); + virtual const std::vector unigramsForKey(const std::string& key); + virtual bool hasUnigramsForKey(const std::string& key); + +protected: + struct Row { + Row(std::string_view& k, std::string_view& v) : key(k), value(v) {} + std::string_view key; + std::string_view value; + }; + + std::map> keyRowMap; + int fd; + void *data; + size_t length; +}; + +} + +#endif diff --git a/Source/Modules/LangModelRelated/mgrLangModel.h b/Source/Modules/LangModelRelated/mgrLangModel.h new file mode 100644 index 0000000000000000000000000000000000000000..1e0f3b221bbf2efb98f6600d3e662580d29d41a9 --- /dev/null +++ b/Source/Modules/LangModelRelated/mgrLangModel.h @@ -0,0 +1,32 @@ + +#import +#import "KeyHandler.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface mgrLangModel : NSObject + ++ (void)loadDataModel:(InputMode)mode; ++ (void)loadUserPhrases; ++ (void)loadUserPhraseReplacement; ++ (void)setupDataModelValueConverter; ++ (BOOL)checkIfUserLanguageModelFilesExist; + ++ (BOOL)checkIfUserPhraseExist:(NSString *)userPhrase key:(NSString *)key NS_SWIFT_NAME(checkIfExist(userPhrase:key:)); ++ (BOOL)writeUserPhrase:(NSString *)userPhrase; + +@property (class, readonly, nonatomic) NSString *dataFolderPath; +@property (class, readonly, nonatomic) NSString *userPhrasesDataPathvChewing; +@property (class, readonly, nonatomic) NSString *excludedPhrasesDataPathvChewing; +@property (class, readonly, nonatomic) NSString *excludedPhrasesDataPathPlainBopomofo; +@property (class, readonly, nonatomic) NSString *phraseReplacementDataPathvChewing; +@property (class, assign, nonatomic) BOOL phraseReplacementEnabled; + +@end + +/// The following methods are merely for testing. +@interface mgrLangModel () ++ (void)loadDataModels; +@end + +NS_ASSUME_NONNULL_END diff --git a/Source/Modules/LangModelRelated/mgrLangModel.mm b/Source/Modules/LangModelRelated/mgrLangModel.mm new file mode 100644 index 0000000000000000000000000000000000000000..cff9d82b536c9f013fff7d1e49205010f41de863 --- /dev/null +++ b/Source/Modules/LangModelRelated/mgrLangModel.mm @@ -0,0 +1,289 @@ + +#import "mgrLangModel.h" +#import "mgrLangModel_Privates.h" +#import "vChewing-Swift.h" + +@import VXHanConvert; + +using namespace std; +using namespace vChewing; + +static const int kUserOverrideModelCapacity = 500; +static const double kObservedOverrideHalflife = 5400.0; // 1.5 hr. + +static vChewingLM gLangModelCHT; +static vChewingLM gLangModelCHS; +static UserOverrideModel gUserOverrideModel(kUserOverrideModelCapacity, kObservedOverrideHalflife); + +static NSString *const kUserDataTemplateName = @"template-data"; +static NSString *const kExcludedPhrasesvChewingTemplateName = @"template-exclude-phrases"; +static NSString *const kExcludedPhrasesPlainBopomofoTemplateName = @"template-exclude-phrases-plain-bpmf"; +static NSString *const kPhraseReplacementTemplateName = @"template-phrases-replacement"; +static NSString *const kTemplateExtension = @".txt"; + +@implementation mgrLangModel + +static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewingLM &lm) +{ + Class cls = NSClassFromString(@"ctlInputMethod"); + NSString *dataPath = [[NSBundle bundleForClass:cls] pathForResource:filenameWithoutExtension ofType:@"txt"]; + lm.loadLanguageModel([dataPath UTF8String]); +} + +static void LTLoadAssociatedPhrases(vChewingLM &lm) +{ + Class cls = NSClassFromString(@"ctlInputMethod"); + NSString *dataPath = [[NSBundle bundleForClass:cls] pathForResource:@"assPhrases" ofType:@"txt"]; + lm.loadAssociatedPhrases([dataPath UTF8String]); +} + ++ (void)loadDataModels +{ + if (!gLangModelCHT.isDataModelLoaded()) { + LTLoadLanguageModelFile(@"data-cht", gLangModelCHT); + } + if (!gLangModelCHS.isDataModelLoaded()) { + LTLoadLanguageModelFile(@"data-chs", gLangModelCHS); + } + if (!gLangModelCHS.isAssociatedPhrasesLoaded()) { + LTLoadAssociatedPhrases(gLangModelCHS); + } +} + ++ (void)loadDataModel:(InputMode)mode +{ + if ([mode isEqualToString:InputModeBopomofo]) { + if (!gLangModelCHT.isDataModelLoaded()) { + LTLoadLanguageModelFile(@"data-cht", gLangModelCHT); + } + } + + if ([mode isEqualToString:InputModePlainBopomofo]) { + if (!gLangModelCHS.isDataModelLoaded()) { + LTLoadLanguageModelFile(@"data-chs", gLangModelCHS); + } + if (!gLangModelCHS.isAssociatedPhrasesLoaded()) { + LTLoadAssociatedPhrases(gLangModelCHS); + } + } +} + ++ (void)loadUserPhrases +{ + gLangModelCHT.loadUserPhrases([[self userPhrasesDataPathvChewing] UTF8String], [[self excludedPhrasesDataPathvChewing] UTF8String]); + gLangModelCHS.loadUserPhrases(NULL, [[self excludedPhrasesDataPathPlainBopomofo] UTF8String]); +} + ++ (void)loadUserPhraseReplacement +{ + gLangModelCHT.loadPhraseReplacementMap([[self phraseReplacementDataPathvChewing] UTF8String]); +} + ++ (void)setupDataModelValueConverter +{ + auto converter = [] (string input) { +// if (!Preferences.chineseConversionEnabled) { +// return input; +// } +// +// if (Preferences.chineseConversionStyle == 0) { +// return input; +// } +// +// NSString *text = [NSString stringWithUTF8String:input.c_str()]; +// if (Preferences.chineseConversionEngine == 1) { +// text = [VXHanConvert convertToKangXiFrom:text]; +// } +// else { +// text = [OpenCCBridge convertToKangXi:text]; +// } +// return string(text.UTF8String); + return input; + }; + + gLangModelCHT.setExternalConverter(converter); + gLangModelCHS.setExternalConverter(converter); +} + ++ (BOOL)checkIfUserDataFolderExists +{ + NSString *folderPath = [self dataFolderPath]; + BOOL isFolder = NO; + BOOL folderExist = [[NSFileManager defaultManager] fileExistsAtPath:folderPath isDirectory:&isFolder]; + if (folderExist && !isFolder) { + NSError *error = nil; + [[NSFileManager defaultManager] removeItemAtPath:folderPath error:&error]; + if (error) { + NSLog(@"Failed to remove folder %@", error); + return NO; + } + folderExist = NO; + } + if (!folderExist) { + NSError *error = nil; + [[NSFileManager defaultManager] createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:&error]; + if (error) { + NSLog(@"Failed to create folder %@", error); + return NO; + } + } + return YES; +} + ++ (BOOL)ensureFileExists:(NSString *)filePath populateWithTemplate:(NSString *)templateBasename extension:(NSString *)ext +{ + if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) { + + NSURL *templateURL = [[NSBundle mainBundle] URLForResource:templateBasename withExtension:ext]; + NSData *templateData; + if (templateURL) { + templateData = [NSData dataWithContentsOfURL:templateURL]; + } else { + templateData = [@"" dataUsingEncoding:NSUTF8StringEncoding]; + } + + BOOL result = [templateData writeToFile:filePath atomically:YES]; + if (!result) { + NSLog(@"Failed to write file"); + return NO; + } + } + return YES; +} + ++ (BOOL)checkIfUserLanguageModelFilesExist +{ + if (![self checkIfUserDataFolderExists]) { + return NO; + } + if (![self ensureFileExists:[self userPhrasesDataPathvChewing] populateWithTemplate:kUserDataTemplateName extension:kTemplateExtension]) { + return NO; + } + if (![self ensureFileExists:[self excludedPhrasesDataPathvChewing] populateWithTemplate:kExcludedPhrasesvChewingTemplateName extension:kTemplateExtension]) { + return NO; + } + if (![self ensureFileExists:[self excludedPhrasesDataPathPlainBopomofo] populateWithTemplate:kExcludedPhrasesPlainBopomofoTemplateName extension:kTemplateExtension]) { + return NO; + } + if (![self ensureFileExists:[self phraseReplacementDataPathvChewing] populateWithTemplate:kPhraseReplacementTemplateName extension:kTemplateExtension]) { + return NO; + } + return YES; +} + ++ (BOOL)checkIfUserPhraseExist:(NSString *)userPhrase key:(NSString *)key NS_SWIFT_NAME(checkIfExist(userPhrase:key:)) +{ + string unigramKey = string(key.UTF8String); + vector unigrams = gLangModelCHT.unigramsForKey(unigramKey); + string userPhraseString = string(userPhrase.UTF8String); + for (auto unigram: unigrams) { + if (unigram.keyValue.value == userPhraseString) { + return YES; + } + } + return NO; +} + ++ (BOOL)writeUserPhrase:(NSString *)userPhrase +{ + if (![self checkIfUserLanguageModelFilesExist]) { + return NO; + } + + BOOL addLineBreakAtFront = NO; + NSString *path = [self userPhrasesDataPathvChewing]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { + NSError *error = nil; + NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error]; + unsigned long long fileSize = [attr fileSize]; + if (!error && fileSize) { + NSFileHandle *readFile = [NSFileHandle fileHandleForReadingAtPath:path]; + if (readFile) { + [readFile seekToFileOffset:fileSize - 1]; + NSData *data = [readFile readDataToEndOfFile]; + const void *bytes = [data bytes]; + if (*(char *)bytes != '\n') { + addLineBreakAtFront = YES; + } + [readFile closeFile]; + } + } + } + + NSMutableString *currentMarkedPhrase = [NSMutableString string]; + if (addLineBreakAtFront) { + [currentMarkedPhrase appendString:@"\n"]; + } + [currentMarkedPhrase appendString:userPhrase]; + [currentMarkedPhrase appendString:@"\n"]; + + NSFileHandle *writeFile = [NSFileHandle fileHandleForUpdatingAtPath:path]; + if (!writeFile) { + return NO; + } + [writeFile seekToEndOfFile]; + NSData *data = [currentMarkedPhrase dataUsingEncoding:NSUTF8StringEncoding]; + [writeFile writeData:data]; + [writeFile closeFile]; + +// We use FSEventStream to monitor the change of the user phrase folder, +// so we don't have to load data here. +// [self loadUserPhrases]; + return YES; +} + ++ (NSString *)dataFolderPath +{ + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDirectory, YES); + NSString *appSupportPath = paths[0]; + NSString *userDictPath = [appSupportPath stringByAppendingPathComponent:@"vChewing"]; + return userDictPath; +} + ++ (NSString *)userPhrasesDataPathvChewing +{ + return [[self dataFolderPath] stringByAppendingPathComponent:@"userdata-cht.txt"]; +} + ++ (NSString *)excludedPhrasesDataPathvChewing +{ + return [[self dataFolderPath] stringByAppendingPathComponent:@"exclude-phrases-cht.txt"]; +} + ++ (NSString *)excludedPhrasesDataPathPlainBopomofo +{ + return [[self dataFolderPath] stringByAppendingPathComponent:@"exclude-phrases-chs.txt"]; +} + ++ (NSString *)phraseReplacementDataPathvChewing +{ + return [[self dataFolderPath] stringByAppendingPathComponent:@"phrases-replacement-cht.txt"]; +} + + + (vChewingLM *)languageModelvChewing +{ + return &gLangModelCHT; +} + ++ (vChewingLM *)languageModelPlainBopomofo +{ + return &gLangModelCHS; +} + ++ (vChewing::UserOverrideModel *)userOverrideModel +{ + return &gUserOverrideModel; +} + ++ (BOOL)phraseReplacementEnabled +{ + return gLangModelCHT.phraseReplacementEnabled(); +} + ++ (void)setPhraseReplacementEnabled:(BOOL)phraseReplacementEnabled +{ + gLangModelCHT.setPhraseReplacementEnabled(phraseReplacementEnabled); +} + +@end diff --git a/Source/Modules/LangModelRelated/mgrLangModel_Privates.h b/Source/Modules/LangModelRelated/mgrLangModel_Privates.h new file mode 100644 index 0000000000000000000000000000000000000000..ba4d2b6bd0f98ad91b89856701f2fd4e4ba1940f --- /dev/null +++ b/Source/Modules/LangModelRelated/mgrLangModel_Privates.h @@ -0,0 +1,14 @@ + +#import "mgrLangModel.h" +#import "UserOverrideModel.h" +#import "vChewingLM.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface mgrLangModel () +@property (class, readonly, nonatomic) vChewing::vChewingLM *languageModelvChewing; +@property (class, readonly, nonatomic) vChewing::vChewingLM *languageModelPlainBopomofo; +@property (class, readonly, nonatomic) vChewing::UserOverrideModel *userOverrideModel; +@end + +NS_ASSUME_NONNULL_END diff --git a/Source/Modules/LangModelRelated/vChewingLM.cpp b/Source/Modules/LangModelRelated/vChewingLM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c46ec52a0b92909e16682590a766ec104d365d48 --- /dev/null +++ b/Source/Modules/LangModelRelated/vChewingLM.cpp @@ -0,0 +1,193 @@ + +#include "vChewingLM.h" +#include +#include + +using namespace vChewing; + +vChewingLM::vChewingLM() +{ +} + +vChewingLM::~vChewingLM() +{ + m_languageModel.close(); + m_userPhrases.close(); + m_excludedPhrases.close(); + m_phraseReplacement.close(); + m_associatedPhrases.close(); +} + +void vChewingLM::loadLanguageModel(const char* languageModelDataPath) +{ + if (languageModelDataPath) { + m_languageModel.close(); + m_languageModel.open(languageModelDataPath); + } +} + +bool vChewingLM::isDataModelLoaded() +{ + return m_languageModel.isLoaded(); +} + +void vChewingLM::loadAssociatedPhrases(const char* associatedPhrasesPath) +{ + if (associatedPhrasesPath) { + m_associatedPhrases.close(); + m_associatedPhrases.open(associatedPhrasesPath); + } +} + +bool vChewingLM::isAssociatedPhrasesLoaded() +{ + return m_associatedPhrases.isLoaded(); +} + +void vChewingLM::loadUserPhrases(const char* userPhrasesDataPath, + const char* excludedPhrasesDataPath) +{ + if (userPhrasesDataPath) { + m_userPhrases.close(); + m_userPhrases.open(userPhrasesDataPath); + } + if (excludedPhrasesDataPath) { + m_excludedPhrases.close(); + m_excludedPhrases.open(excludedPhrasesDataPath); + } +} + +void vChewingLM::loadPhraseReplacementMap(const char* phraseReplacementPath) +{ + if (phraseReplacementPath) { + m_phraseReplacement.close(); + m_phraseReplacement.open(phraseReplacementPath); + } +} + +const vector vChewingLM::bigramsForKeys(const string& preceedingKey, const string& key) +{ + return vector(); +} + +const vector vChewingLM::unigramsForKey(const string& key) +{ + if (key == " ") { + vector spaceUnigrams; + Unigram g; + g.keyValue.key = " "; + g.keyValue.value= " "; + g.score = 0; + spaceUnigrams.push_back(g); + return spaceUnigrams; + } + + vector allUnigrams; + vector userUnigrams; + + unordered_set excludedValues; + unordered_set insertedValues; + + if (m_excludedPhrases.hasUnigramsForKey(key)) { + vector excludedUnigrams = m_excludedPhrases.unigramsForKey(key); + transform(excludedUnigrams.begin(), excludedUnigrams.end(), + inserter(excludedValues, excludedValues.end()), + [](const Unigram& u) { return u.keyValue.value; }); + } + + if (m_userPhrases.hasUnigramsForKey(key)) { + vector rawUserUnigrams = m_userPhrases.unigramsForKey(key); + userUnigrams = filterAndTransformUnigrams(rawUserUnigrams, excludedValues, insertedValues); + } + + if (m_languageModel.hasUnigramsForKey(key)) { + vector rawGlobalUnigrams = m_languageModel.unigramsForKey(key); + allUnigrams = filterAndTransformUnigrams(rawGlobalUnigrams, excludedValues, insertedValues); + } + + allUnigrams.insert(allUnigrams.begin(), userUnigrams.begin(), userUnigrams.end()); + return allUnigrams; +} + +bool vChewingLM::hasUnigramsForKey(const string& key) +{ + if (key == " ") { + return true; + } + + if (!m_excludedPhrases.hasUnigramsForKey(key)) { + return m_userPhrases.hasUnigramsForKey(key) || m_languageModel.hasUnigramsForKey(key); + } + + return unigramsForKey(key).size() > 0; +} + +void vChewingLM::setPhraseReplacementEnabled(bool enabled) +{ + m_phraseReplacementEnabled = enabled; +} + +bool vChewingLM::phraseReplacementEnabled() +{ + return m_phraseReplacementEnabled; +} + +void vChewingLM::setExternalConverterEnabled(bool enabled) +{ + m_externalConverterEnabled = enabled; +} + +bool vChewingLM::externalConverterEnabled() +{ + return m_externalConverterEnabled; +} + +void vChewingLM::setExternalConverter(std::function externalConverter) +{ + m_externalConverter = externalConverter; +} + +const vector vChewingLM::filterAndTransformUnigrams(const vector unigrams, const unordered_set& excludedValues, unordered_set& insertedValues) +{ + vector results; + + for (auto&& unigram : unigrams) { + // excludedValues filters out the unigrams with the original value. + // insertedValues filters out the ones with the converted value + string originalValue = unigram.keyValue.value; + if (excludedValues.find(originalValue) != excludedValues.end()) { + continue; + } + + string value = originalValue; + if (m_phraseReplacementEnabled) { + string replacement = m_phraseReplacement.valueForKey(value); + if (replacement != "") { + value = replacement; + } + } + if (m_externalConverterEnabled && m_externalConverter) { + string replacement = m_externalConverter(value); + value = replacement; + } + if (insertedValues.find(value) == insertedValues.end()) { + Unigram g; + g.keyValue.value = value; + g.keyValue.key = unigram.keyValue.key; + g.score = unigram.score; + results.push_back(g); + insertedValues.insert(value); + } + } + return results; +} + +const vector vChewingLM::associatedPhrasesForKey(const string& key) +{ + return m_associatedPhrases.valuesForKey(key); +} + +bool vChewingLM::hasAssociatedPhrasesForKey(const string& key) +{ + return m_associatedPhrases.hasValuesForKey(key); +} diff --git a/Source/Modules/LangModelRelated/vChewingLM.h b/Source/Modules/LangModelRelated/vChewingLM.h new file mode 100644 index 0000000000000000000000000000000000000000..7dca1ae003db88f95fd253550a1765e990e2dad0 --- /dev/null +++ b/Source/Modules/LangModelRelated/vChewingLM.h @@ -0,0 +1,112 @@ + +#ifndef VCHEWINGLM_H +#define VCHEWINGLM_H + +#include +#include "UserPhrasesLM.h" +#include "ParselessLM.h" +#include "PhraseReplacementMap.h" +#include "AssociatedPhrases.h" +#include + +namespace vChewing { + +using namespace Taiyan::Gramambular; + +/// vChewingLM is a facade for managing a set of models including +/// the input method language model, user phrases and excluded phrases. +/// +/// It is the primary model class that the input controller and grammar builder +/// of vChewing talks to. When the grammar builder starts to build a sentence +/// from a series of BPMF readings, it passes the readings to the model to see +/// if there are valid unigrams, and use returned unigrams to produce the final +/// results. +/// +/// vChewingLM combine and transform the unigrams from the primary language +/// model and user phrases. The process is +/// +/// 1) Get the original unigrams. +/// 2) Drop the unigrams whose value is contained in the exclusion map. +/// 3) Replace the values of the unigrams using the phrase replacement map. +/// 4) Replace the values of the unigrams using an external converter lambda. +/// 5) Drop the duplicated phrases. +/// +/// The controller can ask the model to load the primary input method language +/// model while launching and to load the user phrases anytime if the custom +/// files are modified. It does not keep the reference of the data pathes but +/// you have to pass the paths when you ask it to do loading. +class vChewingLM : public LanguageModel { +public: + vChewingLM(); + ~vChewingLM(); + + /// Asks to load the primary language model at the given path. + /// @param languageModelPath The path of the language model. + void loadLanguageModel(const char* languageModelPath); + /// If the data model is already loaded. + bool isDataModelLoaded(); + + /// Asks to load the associated phrases at the given path. + /// @param associatedPhrasesPath The path of the associated phrases. + void loadAssociatedPhrases(const char* associatedPhrasesPath); + /// If the associated phrases already loaded. + bool isAssociatedPhrasesLoaded(); + + /// Asks to load the user phrases and excluded phrases at the given path. + /// @param userPhrasesPath The path of user phrases. + /// @param excludedPhrasesPath The path of excluded phrases. + void loadUserPhrases(const char* userPhrasesPath, const char* excludedPhrasesPath); + /// Asks to load the phrase replacement table at the given path. + /// @param phraseReplacementPath The path of the phrase replacement table. + void loadPhraseReplacementMap(const char* phraseReplacementPath); + + /// Not implemented since we do not have data to provide bigram function. + const vector bigramsForKeys(const string& preceedingKey, const string& key); + /// Returns a list of available unigram for the given key. + /// @param key A string represents the BPMF reading or a symbol key. For + /// example, it you pass "ㄇㄚ", it returns "嗎", "媽", and so on. + const vector unigramsForKey(const string& key); + /// If the model has unigrams for the given key. + /// @param key The key. + bool hasUnigramsForKey(const string& key); + + /// Enables or disables phrase replacement. + void setPhraseReplacementEnabled(bool enabled); + /// If phrase replacement is enabled or not. + bool phraseReplacementEnabled(); + + /// Enables or disables the external converter. + void setExternalConverterEnabled(bool enabled); + /// If the external converted is enabled or not. + bool externalConverterEnabled(); + /// Sets a lambda to let the values of unigrams could be converted by it. + void setExternalConverter(std::function externalConverter); + + const vector associatedPhrasesForKey(const string& key); + bool hasAssociatedPhrasesForKey(const string& key); + + +protected: + /// Filters and converts the input unigrams and return a new list of unigrams. + /// + /// @param unigrams The unigrams to be processed. + /// @param excludedValues The values to excluded unigrams. + /// @param insertedValues The values for unigrams already in the results. + /// It helps to prevent duplicated unigrams. Please note that the method + /// has a side effect that it inserts values to `insertedValues`. + const vector filterAndTransformUnigrams(const vector unigrams, + const std::unordered_set& excludedValues, + std::unordered_set& insertedValues); + + ParselessLM m_languageModel; + UserPhrasesLM m_userPhrases; + UserPhrasesLM m_excludedPhrases; + PhraseReplacementMap m_phraseReplacement; + AssociatedPhrases m_associatedPhrases; + bool m_phraseReplacementEnabled; + bool m_externalConverterEnabled; + std::function m_externalConverter; +}; +}; + +#endif diff --git a/Source/Engine/Gramambular/Bigram.h b/Source/Modules/LanguageParsers/Gramambular/Bigram.h similarity index 68% rename from Source/Engine/Gramambular/Bigram.h rename to Source/Modules/LanguageParsers/Gramambular/Bigram.h index 194ea755c7e716b394589cba6a563977e6f07b58..55d55e16f1e36e0a9e198bb0e97c24a390e3a9db 100644 --- a/Source/Engine/Gramambular/Bigram.h +++ b/Source/Modules/LanguageParsers/Gramambular/Bigram.h @@ -3,34 +3,16 @@ // // Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) // -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. // #ifndef Bigram_h #define Bigram_h +#include + #include "KeyValuePair.h" -namespace Formosa { +namespace Taiyan { namespace Gramambular { class Bigram { public: diff --git a/Source/Engine/Gramambular/BlockReadingBuilder.h b/Source/Modules/LanguageParsers/Gramambular/BlockReadingBuilder.h similarity index 77% rename from Source/Engine/Gramambular/BlockReadingBuilder.h rename to Source/Modules/LanguageParsers/Gramambular/BlockReadingBuilder.h index f6909b063d342c67b8cff19bafdd4df31abb9d08..95ed44e66bf1dc75a4f0deba35c38cec681e3579 100644 --- a/Source/Engine/Gramambular/BlockReadingBuilder.h +++ b/Source/Modules/LanguageParsers/Gramambular/BlockReadingBuilder.h @@ -3,26 +3,6 @@ // // Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) // -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. // #ifndef BlockReadingBuilder_h @@ -32,7 +12,7 @@ #include "Grid.h" #include "LanguageModel.h" -namespace Formosa { +namespace Taiyan { namespace Gramambular { using namespace std; @@ -52,7 +32,9 @@ namespace Formosa { void setJoinSeparator(const string& separator); const string joinSeparator() const; - + + vector readings() const; + Grid& grid(); protected: @@ -98,7 +80,6 @@ namespace Formosa { { m_cursorIndex = inNewIndex > m_readings.size() ? m_readings.size() : inNewIndex; } - inline void BlockReadingBuilder::insertReadingAtCursor(const string& inReading) { @@ -108,6 +89,11 @@ namespace Formosa { build(); m_cursorIndex++; } + + inline vector BlockReadingBuilder::readings() const + { + return m_readings; + } inline bool BlockReadingBuilder::deleteReadingBeforeCursor() { @@ -166,7 +152,7 @@ namespace Formosa { { return m_grid; } - + inline void BlockReadingBuilder::build() { if (!m_LM) { @@ -190,16 +176,19 @@ namespace Formosa { for (size_t p = begin ; p < end ; p++) { for (size_t q = 1 ; q <= MaximumBuildSpanLength && p+q <= end ; q++) { string combinedReading = Join(m_readings.begin() + p, m_readings.begin() + p + q, m_joinSeparator); - - if (m_LM->hasUnigramsForKey(combinedReading) && !m_grid.hasNodeAtLocationSpanningLengthMatchingKey(p, q, combinedReading)) { - Node n(combinedReading, m_LM->unigramsForKeys(combinedReading), vector()); - m_grid.insertNode(n, p, q); + if (!m_grid.hasNodeAtLocationSpanningLengthMatchingKey(p, q, combinedReading)) { + vector unigrams = m_LM->unigramsForKey(combinedReading); + + if (unigrams.size() > 0) { + Node n(combinedReading, unigrams, vector()); + m_grid.insertNode(n, p, q); + } } } } } - const string BlockReadingBuilder::Join(vector::const_iterator begin, vector::const_iterator end, const string& separator) + inline const string BlockReadingBuilder::Join(vector::const_iterator begin, vector::const_iterator end, const string& separator) { string result; for (vector::const_iterator iter = begin ; iter != end ; ) { diff --git a/Source/Modules/LanguageParsers/Gramambular/Gramambular.h b/Source/Modules/LanguageParsers/Gramambular/Gramambular.h new file mode 100644 index 0000000000000000000000000000000000000000..2df37008faf4462f31b7bb147ae65e53ae7cbf61 --- /dev/null +++ b/Source/Modules/LanguageParsers/Gramambular/Gramambular.h @@ -0,0 +1,22 @@ +// +// Gramambular.h +// +// Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) +// +// + +#ifndef Gramambular_h +#define Gramambular_h + +#include "Bigram.h" +#include "BlockReadingBuilder.h" +#include "Grid.h" +#include "KeyValuePair.h" +#include "LanguageModel.h" +#include "Node.h" +#include "NodeAnchor.h" +#include "Span.h" +#include "Unigram.h" +#include "Walker.h" + +#endif diff --git a/Source/Engine/Gramambular/Grid.h b/Source/Modules/LanguageParsers/Gramambular/Grid.h similarity index 82% rename from Source/Engine/Gramambular/Grid.h rename to Source/Modules/LanguageParsers/Gramambular/Grid.h index e13c8eab89972cdbe1de2cf855fa9e7ad2044227..b604de9858a9693657da6170edbcdd8a13825971 100644 --- a/Source/Engine/Gramambular/Grid.h +++ b/Source/Modules/LanguageParsers/Gramambular/Grid.h @@ -3,26 +3,6 @@ // // Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) // -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. // #ifndef Grid_h @@ -32,7 +12,7 @@ #include "NodeAnchor.h" #include "Span.h" -namespace Formosa { +namespace Taiyan { namespace Gramambular { class Grid { @@ -47,7 +27,18 @@ namespace Formosa { size_t width() const; vector nodesEndingAt(size_t inLocation); vector nodesCrossingOrEndingAt(size_t inLocation); + + // "Freeze" the node with the unigram that represents the selected canditate value. + // After this, the node that contains the unigram will always be evaluated to that + // unigram, while all other overlapping nodes will be reset to their initial state + // (that is, if any of those nodes were "frozen" or fixed, they will be unfrozen.) void fixNodeSelectedCandidate(size_t location, const string& value); + + // Similar to fixNodeSelectedCandidate, but instead of "freezing" the node, only + // boost the unigram that represents the value with an overriding score. This + // has the same side effect as fixNodeSelectedCandidate, which is that all other + // overlapping nodes will be reset to their initial state. + void overrideNodeScoreForSelectedCandidate(size_t location, const string& value, float overridingScore); const string dumpDOT(); @@ -194,6 +185,24 @@ namespace Formosa { } } } + + inline void Grid::overrideNodeScoreForSelectedCandidate(size_t location, const string& value, float overridingScore) + { + vector nodes = nodesCrossingOrEndingAt(location); + for (auto nodeAnchor : nodes) { + auto candidates = nodeAnchor.node->candidates(); + + // Reset the candidate-fixed state of every node at the location. + const_cast(nodeAnchor.node)->resetCandidate(); + + for (size_t i = 0, c = candidates.size(); i < c; ++i) { + if (candidates[i].value == value) { + const_cast(nodeAnchor.node)->selectFloatingCandidateAtIndex(i, overridingScore); + break; + } + } + } + } inline const string Grid::dumpDOT() { diff --git a/Source/Engine/Gramambular/KeyValuePair.h b/Source/Modules/LanguageParsers/Gramambular/KeyValuePair.h similarity index 50% rename from Source/Engine/Gramambular/KeyValuePair.h rename to Source/Modules/LanguageParsers/Gramambular/KeyValuePair.h index ea6fd33d46edafcfe2c6a5302d5388898b6e7fa0..8e7ddbee39a75fd335b77b9386b7bc252e0672bc 100644 --- a/Source/Engine/Gramambular/KeyValuePair.h +++ b/Source/Modules/LanguageParsers/Gramambular/KeyValuePair.h @@ -3,34 +3,15 @@ // // Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) // -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. // #ifndef KeyValuePair_h #define KeyValuePair_h +#include #include -namespace Formosa { +namespace Taiyan { namespace Gramambular { using namespace std; diff --git a/Source/Engine/Gramambular/LanguageModel.h b/Source/Modules/LanguageParsers/Gramambular/LanguageModel.h similarity index 32% rename from Source/Engine/Gramambular/LanguageModel.h rename to Source/Modules/LanguageParsers/Gramambular/LanguageModel.h index 46c2e1d4642f0ca8fbdb2e7742a6e1315515a24d..9d776b1189d422e2ddf1d0f00378db9119103ab7 100644 --- a/Source/Engine/Gramambular/LanguageModel.h +++ b/Source/Modules/LanguageParsers/Gramambular/LanguageModel.h @@ -3,26 +3,6 @@ // // Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) // -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. // #ifndef LanguageModel_h @@ -32,7 +12,7 @@ #include "Bigram.h" #include "Unigram.h" -namespace Formosa { +namespace Taiyan { namespace Gramambular { using namespace std; @@ -42,7 +22,7 @@ namespace Formosa { virtual ~LanguageModel() {} virtual const vector bigramsForKeys(const string &preceedingKey, const string& key) = 0; - virtual const vector unigramsForKeys(const string &key) = 0; + virtual const vector unigramsForKey(const string &key) = 0; virtual bool hasUnigramsForKey(const string& key) = 0; }; } diff --git a/Source/Engine/Gramambular/Node.h b/Source/Modules/LanguageParsers/Gramambular/Node.h similarity index 84% rename from Source/Engine/Gramambular/Node.h rename to Source/Modules/LanguageParsers/Gramambular/Node.h index 89a748134c4dff336c25d2eeda1f3db362d14e8a..f80a9fea30b91332680c71aca1fe362605fe8e35 100644 --- a/Source/Engine/Gramambular/Node.h +++ b/Source/Modules/LanguageParsers/Gramambular/Node.h @@ -3,26 +3,6 @@ // // Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) // -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. // #ifndef Node_h @@ -32,7 +12,7 @@ #include #include "LanguageModel.h" -namespace Formosa { +namespace Taiyan { namespace Gramambular { using namespace std; @@ -47,10 +27,12 @@ namespace Formosa { const vector& candidates() const; void selectCandidateAtIndex(size_t inIndex = 0, bool inFix = true); void resetCandidate(); + void selectFloatingCandidateAtIndex(size_t index, double score); const string& key() const; double score() const; const KeyValuePair currentKeyValue() const; + double highestUnigramScore() const; protected: const LanguageModel* m_LM; @@ -175,6 +157,16 @@ namespace Formosa { m_score = m_unigrams[0].score; } } + + inline void Node::selectFloatingCandidateAtIndex(size_t index, double score) { + if (index >= m_unigrams.size()) { + m_selectedUnigramIndex = 0; + } else { + m_selectedUnigramIndex = index; + } + m_candidateFixed = false; + m_score = score; + } inline const string& Node::key() const { @@ -185,6 +177,13 @@ namespace Formosa { { return m_score; } + + inline double Node::highestUnigramScore() const { + if (m_unigrams.empty()) { + return 0.0; + } + return m_unigrams[0].score; + } inline const KeyValuePair Node::currentKeyValue() const { diff --git a/Source/Engine/Gramambular/NodeAnchor.h b/Source/Modules/LanguageParsers/Gramambular/NodeAnchor.h similarity index 56% rename from Source/Engine/Gramambular/NodeAnchor.h rename to Source/Modules/LanguageParsers/Gramambular/NodeAnchor.h index 62e5e12ef875733dbcc1858158d7ff8467f5902b..73b624e4e6507fa3ea9a1094cb694dac7a1766a2 100644 --- a/Source/Engine/Gramambular/NodeAnchor.h +++ b/Source/Modules/LanguageParsers/Gramambular/NodeAnchor.h @@ -3,26 +3,6 @@ // // Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) // -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. // #ifndef NodeAnchor_h @@ -30,7 +10,7 @@ #include "Node.h" -namespace Formosa { +namespace Taiyan { namespace Gramambular { class NodeAnchor { public: diff --git a/Source/Engine/Gramambular/Span.h b/Source/Modules/LanguageParsers/Gramambular/Span.h similarity index 68% rename from Source/Engine/Gramambular/Span.h rename to Source/Modules/LanguageParsers/Gramambular/Span.h index 87cb6563830b215bd82d54faeb73322c1e57e8a2..a010780f45d2e8b6d92442dbfa3b70e0c214aaa8 100644 --- a/Source/Engine/Gramambular/Span.h +++ b/Source/Modules/LanguageParsers/Gramambular/Span.h @@ -3,26 +3,6 @@ // // Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) // -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. // #ifndef Span_h @@ -33,7 +13,7 @@ #include #include "Node.h" -namespace Formosa { +namespace Taiyan { namespace Gramambular { class Span { public: diff --git a/Source/Engine/Gramambular/Unigram.h b/Source/Modules/LanguageParsers/Gramambular/Unigram.h similarity index 67% rename from Source/Engine/Gramambular/Unigram.h rename to Source/Modules/LanguageParsers/Gramambular/Unigram.h index 5af28502153026e03c28cfabdd23582038f33562..ae66ef8a37298a102bc217ebde1d10b0d5298578 100644 --- a/Source/Engine/Gramambular/Unigram.h +++ b/Source/Modules/LanguageParsers/Gramambular/Unigram.h @@ -3,26 +3,6 @@ // // Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) // -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. // #ifndef Unigram_h @@ -31,7 +11,7 @@ #include #include "KeyValuePair.h" -namespace Formosa { +namespace Taiyan { namespace Gramambular { class Unigram { public: diff --git a/Source/Engine/Gramambular/Walker.h b/Source/Modules/LanguageParsers/Gramambular/Walker.h similarity index 64% rename from Source/Engine/Gramambular/Walker.h rename to Source/Modules/LanguageParsers/Gramambular/Walker.h index c40ffbf19007c34e895c87d9f01754d33b0faf55..1a6601310a0087d0f7b8531e804bc0821e031a04 100644 --- a/Source/Engine/Gramambular/Walker.h +++ b/Source/Modules/LanguageParsers/Gramambular/Walker.h @@ -3,26 +3,6 @@ // // Copyright (c) 2007-2010 Lukhnos D. Liu (http://lukhnos.org) // -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. // #ifndef Walker_h @@ -31,7 +11,7 @@ #include #include "Grid.h" -namespace Formosa { +namespace Taiyan { namespace Gramambular { using namespace std; diff --git a/Source/Modules/Mandarin/CMakeLists.txt b/Source/Modules/Mandarin/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..fbfedea2ad2ee2944fb6f8d863080780ac51b8c9 --- /dev/null +++ b/Source/Modules/Mandarin/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.17) +project(Mandarin) + +set(CMAKE_CXX_STANDARD 17) + +add_library(MandarinLib Mandarin.h Mandarin.cpp) + +# Let CMake fetch Google Test for us. +# https://github.com/google/googletest/tree/main/googletest#incorporating-into-an-existing-cmake-project +include(FetchContent) + +FetchContent_Declare( + googletest + # Specify the commit you depend on and update it regularly. + URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip +) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +# Test target declarations. +add_executable(MandarinTest MandarinTest.cpp) +target_link_libraries(MandarinTest gtest_main MandarinLib) +include(GoogleTest) +gtest_discover_tests(MandarinTest) + +add_custom_target( + runTest + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/MandarinTest +) +add_dependencies(runTest MandarinTest) diff --git a/Source/Modules/Mandarin/MandarinTest.cpp b/Source/Modules/Mandarin/MandarinTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ee48580cb1a62bd95cc35b21f2d2066158a3873 --- /dev/null +++ b/Source/Modules/Mandarin/MandarinTest.cpp @@ -0,0 +1,120 @@ +// Copyright (c) 2022 and onwards Lukhnos Liu +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include "Mandarin.h" +#include "gtest/gtest.h" + +namespace Formosa { +namespace Mandarin { + +static std::string RoundTrip(const std::string& composedString) { + return BopomofoSyllable::FromComposedString(composedString).composedString(); +} + +TEST(MandarinTest, FromComposedString) { + ASSERT_EQ(RoundTrip("ㄅ"), "ㄅ"); + ASSERT_EQ(RoundTrip("ㄅㄧ"), "ㄅㄧ"); + ASSERT_EQ(RoundTrip("ㄅㄧˇ"), "ㄅㄧˇ"); + ASSERT_EQ(RoundTrip("ㄅㄧˇㄆ"), "ㄆㄧˇ"); + ASSERT_EQ(RoundTrip("ㄅㄧˇㄆ"), "ㄆㄧˇ"); + ASSERT_EQ(RoundTrip("e"), ""); + ASSERT_EQ(RoundTrip("é"), ""); + ASSERT_EQ(RoundTrip("ㄅéㄆ"), "ㄅ"); + ASSERT_EQ(RoundTrip("ㄅeㄆ"), "ㄅ"); +} + +TEST(MandarinTest, SimpleCompositions) { + BopomofoSyllable syllable; + syllable += BopomofoSyllable(BopomofoSyllable::X); + syllable += BopomofoSyllable(BopomofoSyllable::I); + ASSERT_EQ(syllable.composedString(), "ㄒㄧ"); + + syllable.clear(); + syllable += BopomofoSyllable(BopomofoSyllable::Z); + syllable += BopomofoSyllable(BopomofoSyllable::ANG); + syllable += BopomofoSyllable(BopomofoSyllable::Tone4); + ASSERT_EQ(syllable.composedString(), "ㄗㄤˋ"); +} + +TEST(MandarinTest, StandardLayout) { + BopomofoReadingBuffer buf(BopomofoKeyboardLayout::StandardLayout()); + buf.combineKey('w'); + buf.combineKey('9'); + buf.combineKey('6'); + ASSERT_EQ(buf.composedString(), "ㄊㄞˊ"); +} + +TEST(MandarinTest, StandardLayoutCombination) { + BopomofoReadingBuffer buf(BopomofoKeyboardLayout::StandardLayout()); + buf.combineKey('w'); + buf.combineKey('9'); + buf.combineKey('6'); + ASSERT_EQ(buf.composedString(), "ㄊㄞˊ"); + + buf.backspace(); + ASSERT_EQ(buf.composedString(), "ㄊㄞ"); + + buf.combineKey('y'); + ASSERT_EQ(buf.composedString(), "ㄗㄞ"); + + buf.combineKey('4'); + ASSERT_EQ(buf.composedString(), "ㄗㄞˋ"); + + buf.combineKey('3'); + ASSERT_EQ(buf.composedString(), "ㄗㄞˇ"); +} + +TEST(MandarinTest, ETenLayout) { + BopomofoReadingBuffer buf(BopomofoKeyboardLayout::ETenLayout()); + buf.combineKey('x'); + buf.combineKey('8'); + ASSERT_EQ(buf.composedString(), "ㄨㄢ"); +} + +TEST(MandarinTest, ETen26Layout) { + BopomofoReadingBuffer buf(BopomofoKeyboardLayout::ETen26Layout()); + buf.combineKey('q'); + buf.combineKey('m'); // AN in the vowel state + buf.combineKey('k'); // Tone 4 in the tone state + ASSERT_EQ(buf.composedString(), "ㄗㄢˋ"); +} + +TEST(MandarinTest, HsuLayout) { + BopomofoReadingBuffer buf(BopomofoKeyboardLayout::HsuLayout()); + buf.combineKey('f'); + buf.combineKey('a'); // EI when in the vowel state + buf.combineKey('f'); // Tone 3 when in the tone state + ASSERT_EQ(buf.composedString(), "ㄈㄟˇ"); +} + +TEST(MandarinTest, IBMLayout) { + BopomofoReadingBuffer buf(BopomofoKeyboardLayout::IBMLayout()); + buf.combineKey('9'); + buf.combineKey('s'); + buf.combineKey('g'); + buf.combineKey('m'); + ASSERT_EQ(buf.composedString(), "ㄍㄨㄛˊ"); +} + +} // namespace Mandarin +} // namespace Formosa diff --git a/Source/Modules/SFX/clsSFX.swift b/Source/Modules/SFX/clsSFX.swift new file mode 100644 index 0000000000000000000000000000000000000000..a7b20df1c4faa0ad72396f382a78cc36d9b86fbe --- /dev/null +++ b/Source/Modules/SFX/clsSFX.swift @@ -0,0 +1,48 @@ +/* + * clsSFX.swift + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +import Cocoa + +@objc public class clsSFX: NSObject, NSSoundDelegate { + private static let shared = clsSFX() + private override init(){ + super.init() + } + private var currentBeep: NSSound? + private func beep() { + // Stop existing beep + if let beep = currentBeep { + if beep.isPlaying { + beep.stop() + } + } + // Create a new beep sound if possible + var sndBeep:String + if Preferences.shouldNotFartInLieuOfBeep == false { + sndBeep = "Fart" + } else { + sndBeep = "Beep" + } + guard + let beep = NSSound(named:sndBeep) + else { + NSSound.beep() + return + } + beep.delegate = self + beep.volume = 0.4 + beep.play() + currentBeep = beep + } + @objc public func sound(_ sound: NSSound, didFinishPlaying flag: Bool) { + currentBeep = nil + } + @objc static func beep() { + shared.beep() + } +} diff --git a/Source/Modules/main.swift b/Source/Modules/main.swift new file mode 100644 index 0000000000000000000000000000000000000000..b7099011aacc7719a7e3b3c0b47ebb9e3cfcc478 --- /dev/null +++ b/Source/Modules/main.swift @@ -0,0 +1,75 @@ + +import Cocoa +import InputMethodKit + +private func install() -> Int32 { + guard let bundleID = Bundle.main.bundleIdentifier else { + return -1 + } + let bundleUrl = Bundle.main.bundleURL + var maybeInputSource = InputSourceHelper.inputSource(for: bundleID) + + if maybeInputSource == nil { + NSLog("Registering input source \(bundleID) at \(bundleUrl.absoluteString)"); + // then register + let status = InputSourceHelper.registerTnputSource(at: bundleUrl) + + if !status { + NSLog("Fatal error: Cannot register input source \(bundleID) at \(bundleUrl.absoluteString).") + return -1 + } + + maybeInputSource = InputSourceHelper.inputSource(for: bundleID) + } + + guard let inputSource = maybeInputSource else { + NSLog("Fatal error: Cannot find input source \(bundleID) after registration.") + return -1 + } + + if !InputSourceHelper.inputSourceEnabled(for: inputSource) { + NSLog("Enabling input source \(bundleID) at \(bundleUrl.absoluteString).") + let status = InputSourceHelper.enable(inputSource: inputSource) + if !status { + NSLog("Fatal error: Cannot enable input source \(bundleID).") + return -1 + } + if !InputSourceHelper.inputSourceEnabled(for: inputSource) { + NSLog("Fatal error: Cannot enable input source \(bundleID).") + return -1 + } + } + + if CommandLine.arguments.count > 2 && CommandLine.arguments[2] == "--all" { + let enabled = InputSourceHelper.enableAllInputMode(for: bundleID) + NSLog(enabled ? "All input sources enabled for \(bundleID)" : "Cannot enable all input sources for \(bundleID), but this is ignored") + } + return 0 +} + +let kConnectionName = "vChewing_1_Connection" + +if CommandLine.arguments.count > 1 { + if CommandLine.arguments[1] == "install" { + let exitCode = install() + exit(exitCode) + } +} + +guard let mainNibName = Bundle.main.infoDictionary?["NSMainNibFile"] as? String else { + NSLog("Fatal error: NSMainNibFile key not defined in Info.plist."); + exit(-1) +} + +let loaded = Bundle.main.loadNibNamed(mainNibName, owner: NSApp, topLevelObjects: nil) +if !loaded { + NSLog("Fatal error: Cannot load \(mainNibName).") + exit(-1) +} + +guard let bundleID = Bundle.main.bundleIdentifier, let server = IMKServer(name: kConnectionName, bundleIdentifier: bundleID) else { + NSLog("Fatal error: Cannot initialize input method server with connection \(kConnectionName).") + exit(-1) +} + +NSApp.run() diff --git a/Source/OVInputSourceHelper.h b/Source/OVInputSourceHelper.h deleted file mode 100644 index cc4c89191f9e2bf382603d65993b22f00a7e18e2..0000000000000000000000000000000000000000 --- a/Source/OVInputSourceHelper.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// OVInputSourceHelper.h -// -// Copyright (c) 2010-2011 Lukhnos D. Liu (lukhnos at lukhnos dot org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import - -@interface OVInputSourceHelper : NSObject -// list all installed input sources -+ (NSArray *)allInstalledInputSources; - -// search for a certain input source -+ (TISInputSourceRef)inputSourceForProperty:(CFStringRef)inPropertyKey stringValue:(NSString *)inValue; - -// shorthand for -inputSourceForProerty:kTISPropertyInputSourceID stringValue: -+ (TISInputSourceRef)inputSourceForInputSourceID:(NSString *)inID; - -// enable/disable an input source (along with all its input modes) -+ (BOOL)inputSourceEnabled:(TISInputSourceRef)inInputSource; -+ (BOOL)enableInputSource:(TISInputSourceRef)inInputSource; -+ (BOOL)enableAllInputModesForInputSourceBundleID:(NSString *)inID; -+ (BOOL)enableInputMode:(NSString *)modeID forInputSourceBundleID:(NSString *)bundleID; -+ (BOOL)disableInputSource:(TISInputSourceRef)inInputSource; - -// register (i.e. make available to Input Source tab in Language & Text Preferences) -// an input source installed in (~)/Library/Input Methods or (~)/Library/Keyboard Layouts/ -+ (BOOL)registerInputSource:(NSURL *)inBundleURL; -@end diff --git a/Source/OVInputSourceHelper.m b/Source/OVInputSourceHelper.m deleted file mode 100644 index b7638a34f1b375463302d44a81626294ea813eef..0000000000000000000000000000000000000000 --- a/Source/OVInputSourceHelper.m +++ /dev/null @@ -1,122 +0,0 @@ -// -// OVInputSourceHelper.m -// -// Copyright (c) 2010-2011 Lukhnos D. Liu (lukhnos at lukhnos dot org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "OVInputSourceHelper.h" - -@implementation OVInputSourceHelper -+ (NSArray *)allInstalledInputSources -{ - CFArrayRef list = TISCreateInputSourceList(NULL, true); - return (__bridge NSArray *)list; -// return [NSMakeCollectable(list) autorelease]; -} - -+ (TISInputSourceRef)inputSourceForProperty:(CFStringRef)inPropertyKey stringValue:(NSString *)inValue -{ - CFTypeID stringID = CFStringGetTypeID(); - - for (id source in [self allInstalledInputSources]) { - CFTypeRef property = TISGetInputSourceProperty((__bridge TISInputSourceRef)source, inPropertyKey); - if (!property || CFGetTypeID(property) != stringID) { - continue; - } - - if (inValue && [inValue compare:(__bridge NSString *)property] == NSOrderedSame) { - return (__bridge TISInputSourceRef)source; - } - } - return NULL; -} - -+ (TISInputSourceRef)inputSourceForInputSourceID:(NSString *)inID -{ - return [self inputSourceForProperty:kTISPropertyInputSourceID stringValue:inID]; -} - -+ (BOOL)inputSourceEnabled:(TISInputSourceRef)inInputSource -{ - CFBooleanRef value = TISGetInputSourceProperty(inInputSource, kTISPropertyInputSourceIsEnabled); - return value ? (BOOL)CFBooleanGetValue(value) : NO; -} - -+ (BOOL)enableInputSource:(TISInputSourceRef)inInputSource -{ - OSStatus status = TISEnableInputSource(inInputSource); - return status == noErr; -} - -+ (BOOL)enableAllInputModesForInputSourceBundleID:(NSString *)inID -{ - BOOL enabled = NO; - - for (id source in [self allInstalledInputSources]) { - TISInputSourceRef inputSource = (__bridge TISInputSourceRef)source; - NSString *bundleID = (__bridge NSString *)TISGetInputSourceProperty(inputSource, kTISPropertyBundleID); - NSString *mode = (NSString *)CFBridgingRelease(TISGetInputSourceProperty(inputSource, kTISPropertyInputModeID)); - if (mode && [bundleID isEqualToString:inID]) { - BOOL modeEnabled = [self enableInputSource:inputSource]; - if (!modeEnabled) { - return NO; - } - - enabled = YES; - } - } - - return enabled; -} - -+ (BOOL)enableInputMode:(NSString *)modeID forInputSourceBundleID:(NSString *)bundleID -{ - for (id source in [self allInstalledInputSources]) { - TISInputSourceRef inputSource = (__bridge TISInputSourceRef)source; - NSString *inputSoureBundleID = (__bridge NSString *)TISGetInputSourceProperty(inputSource, kTISPropertyBundleID); - NSString *inputSourceModeID = (NSString *)CFBridgingRelease(TISGetInputSourceProperty(inputSource, kTISPropertyInputModeID)); - - if ([modeID isEqual:inputSourceModeID] && [bundleID isEqual:inputSoureBundleID]) { - BOOL enabled = [self enableInputSource:inputSource]; - NSLog(@"Attempt to enable input source of mode: %@, bundle ID: %@, result: %d", modeID, bundleID, enabled); - return enabled; - } - } - - NSLog(@"Failed to find any matching input source of mode: %@, bundle ID: %@", modeID, bundleID); - return NO; -} - -+ (BOOL)disableInputSource:(TISInputSourceRef)inInputSource -{ - OSStatus status = TISDisableInputSource(inInputSource); - return status == noErr; -} - -+ (BOOL)registerInputSource:(NSURL *)inBundleURL -{ - OSStatus status = TISRegisterInputSource((__bridge CFURLRef)inBundleURL); - return status == noErr; -} -@end diff --git a/Source/OVNonModalAlertWindowController.h b/Source/OVNonModalAlertWindowController.h deleted file mode 100644 index e0eea1e2512e30623a600117032676f820296f1b..0000000000000000000000000000000000000000 --- a/Source/OVNonModalAlertWindowController.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// OVNonModalAlertWindowController.h -// OpenVanilla -// -// Created by Lukhnos Liu on 10/17/12. -// Copyright (c) 2012 The OpenVanilla Project. All rights reserved. -// - -#import - -@class OVNonModalAlertWindowController; - -@protocol OVNonModalAlertWindowControllerDelegate -- (void)nonModalAlertWindowControllerDidConfirm:(OVNonModalAlertWindowController *)controller; - -@optional -- (void)nonModalAlertWindowControllerDidCancel:(OVNonModalAlertWindowController *)controller; -@end - -@interface OVNonModalAlertWindowController : NSWindowController - -+ (OVNonModalAlertWindowController *)sharedInstance; -- (void)showWithTitle:(NSString *)title content:(NSString *)content confirmButtonTitle:(NSString *)confirmTitle cancelButtonTitle:(NSString *)cancelButtonTitle cancelAsDefault:(BOOL)cancelAsDefault delegate:(id)delegate; -- (IBAction)confirmButtonAction:(id)sender; -- (IBAction)cancelButtonAction:(id)sender; -@property (assign, nonatomic) IBOutlet NSTextField *titleTextField; -@property (assign, nonatomic) IBOutlet NSTextField *contentTextField; -@property (assign, nonatomic) IBOutlet NSButton *confirmButton; -@property (assign, nonatomic) IBOutlet NSButton *cancelButton; -@property (assign, nonatomic) id delegate; -@end diff --git a/Source/OVNonModalAlertWindowController.m b/Source/OVNonModalAlertWindowController.m deleted file mode 100644 index 48302d684e7ed253fa5da7f8462e79ba3386f6db..0000000000000000000000000000000000000000 --- a/Source/OVNonModalAlertWindowController.m +++ /dev/null @@ -1,131 +0,0 @@ -// -// OVNonModalAlertWindowController.m -// OpenVanilla -// -// Created by Lukhnos Liu on 10/17/12. -// Copyright (c) 2012 The OpenVanilla Project. All rights reserved. -// - -#import "OVNonModalAlertWindowController.h" - -@implementation OVNonModalAlertWindowController -@synthesize titleTextField = _titleTextField; -@synthesize contentTextField = _contentTextField; -@synthesize confirmButton = _confirmButton; -@synthesize cancelButton = _cancelButton; -@synthesize delegate = _delegate; - -+ (OVNonModalAlertWindowController *)sharedInstance -{ - static OVNonModalAlertWindowController *instance; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [[OVNonModalAlertWindowController alloc] initWithWindowNibName:@"OVNonModalAlertWindowController"]; - [instance window]; - }); - return instance; -} - -// Suppress the use of the MIN/MAX macros -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wgnu-statement-expression" - -- (void)showWithTitle:(NSString *)title content:(NSString *)content confirmButtonTitle:(NSString *)confirmTitle cancelButtonTitle:(NSString *)cancelButtonTitle cancelAsDefault:(BOOL)cancelAsDefault delegate:(id )delegate; -{ - // cancel previous alert - if (self.window.visible) { - if ([_delegate respondsToSelector:@selector(nonModalAlertWindowControllerDidCancel:)]) { - [_delegate nonModalAlertWindowControllerDidCancel:self]; - } - } - - _delegate = delegate; - - NSRect oldFrame = self.confirmButton.frame; - [self.confirmButton setTitle:confirmTitle]; - [self.confirmButton sizeToFit]; - - NSRect newFrame = self.confirmButton.frame; - - newFrame.size.width = MAX(90.0, (newFrame.size.width + 10.0)); - newFrame.origin.x += (oldFrame.size.width - newFrame.size.width); - [self.confirmButton setFrame:newFrame]; - - if (cancelButtonTitle) { - [self.cancelButton setTitle:cancelButtonTitle]; - [self.cancelButton sizeToFit]; - NSRect adjustedFrame = self.cancelButton.frame; - adjustedFrame.size.width = MAX(90.0, (adjustedFrame.size.width + 10.0)); - adjustedFrame.origin.x = newFrame.origin.x - adjustedFrame.size.width; - self.cancelButton.frame = adjustedFrame; - self.cancelButton.hidden = NO; - } - else { - self.cancelButton.hidden = YES; - } - - self.cancelButton.nextKeyView = self.confirmButton; - self.confirmButton.nextKeyView = self.cancelButton; - - if (cancelButtonTitle) { - if (cancelAsDefault) { - [self.window setDefaultButtonCell:self.cancelButton.cell]; - } - else { - self.cancelButton.keyEquivalent = @" "; - [self.window setDefaultButtonCell:self.confirmButton.cell]; - } - } - else { - [[self window] setDefaultButtonCell:self.confirmButton.cell]; - } - - self.titleTextField.stringValue = title; - - oldFrame = [self.contentTextField frame]; - self.contentTextField.stringValue = content; - - NSRect infiniteHeightFrame = oldFrame; - infiniteHeightFrame.size.width -= 4.0; - infiniteHeightFrame.size.height = 10240; - newFrame = [content boundingRectWithSize:infiniteHeightFrame.size options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: self.contentTextField.font}]; - newFrame.size.width = MAX(newFrame.size.width, oldFrame.size.width); - newFrame.size.height += 4.0; - newFrame.origin = oldFrame.origin; - newFrame.origin.y -= (newFrame.size.height - oldFrame.size.height); - [self.contentTextField setFrame:newFrame]; - - NSRect windowFrame = [[self window] frame]; - windowFrame.size.height += (newFrame.size.height - oldFrame.size.height); - - self.window.level = CGShieldingWindowLevel() + 1; - [self.window setFrame:windowFrame display:YES]; - [self.window center]; - [self.window makeKeyAndOrderFront:self]; - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; -} - -#pragma GCC diagnostic pop - -- (IBAction)confirmButtonAction:(id)sender -{ - [_delegate nonModalAlertWindowControllerDidConfirm:self]; - [self.window orderOut:self]; -} - -- (IBAction)cancelButtonAction:(id)sender -{ - [self cancel:sender]; -} - -- (void)cancel:(id)sender -{ - if ([_delegate respondsToSelector:@selector(nonModalAlertWindowControllerDidCancel:)]) { - [_delegate nonModalAlertWindowControllerDidCancel:self]; - } - - _delegate = nil; - [self.window orderOut:self]; -} - -@end diff --git a/Source/OpenCCBridge.swift b/Source/OpenCCBridge.swift deleted file mode 100644 index a9c639890ce39b2a269acfcbfd2594701f259244..0000000000000000000000000000000000000000 --- a/Source/OpenCCBridge.swift +++ /dev/null @@ -1,22 +0,0 @@ -import Foundation -import OpenCC - -// Since SwiftyOpenCC only provide Swift classes, we create an NSObject subclass -// in Swift in order to bridge the Swift classes into our Objective-C++ project. -class OpenCCBridge : NSObject { - private static let shared = OpenCCBridge() - private var conveter: ChineseConverter? - - override init() { - try? conveter = ChineseConverter(options: .simplify) - super.init() - } - - @objc static func convert(_ string:String) -> String? { - return shared.conveter?.convert(string) - } - - private func convert(_ string:String) -> String? { - return conveter?.convert(string) - } -} diff --git a/Source/PreferencesWindowController.h b/Source/PreferencesWindowController.h deleted file mode 100644 index 538ddd5b49cfcef2df13a70d441b78a7237f1649..0000000000000000000000000000000000000000 --- a/Source/PreferencesWindowController.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// PreferencesWindowController.h -// -// Copyright (c) 2011 The McBopomofo Project. -// -// Contributors: -// Mengjuei Hsieh (@mjhsieh) -// Weizhong Yang (@zonble) -// -// Based on the Syrup Project and the Formosana Library -// by Lukhnos Liu (@lukhnos). -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -#import - -@interface PreferencesWindowController : NSWindowController -{ -@private - NSPopUpButton *__weak _fontSizePopUpButton; - NSPopUpButton *__weak _basisKeyboardLayoutButton; - NSComboBox *__weak _selectionKeyComboBox; -} - -- (IBAction)updateBasisKeyboardLayoutAction:(id)sender; -- (IBAction)changeSelectionKeyAction:(id)sender; - -@property (weak, nonatomic) IBOutlet NSPopUpButton *fontSizePopUpButton; -@property (weak, nonatomic) IBOutlet NSPopUpButton *basisKeyboardLayoutButton; -@property (weak, nonatomic) IBOutlet NSComboBox *selectionKeyComboBox; -@end diff --git a/Source/PreferencesWindowController.m b/Source/PreferencesWindowController.m deleted file mode 100644 index 29253196120d60201a27f5affc1a5817ba5c29e5..0000000000000000000000000000000000000000 --- a/Source/PreferencesWindowController.m +++ /dev/null @@ -1,139 +0,0 @@ -// -// PreferencesWindowController.m -// -// Copyright (c) 2011 The McBopomofo Project. -// -// Contributors: -// Mengjuei Hsieh (@mjhsieh) -// Weizhong Yang (@zonble) -// -// Based on the Syrup Project and the Formosana Library -// by Lukhnos Liu (@lukhnos). -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -#import "PreferencesWindowController.h" -#import - -static NSString *const kBasisKeyboardLayoutPreferenceKey = @"BasisKeyboardLayout"; // alphanumeric ("ASCII") input basis -static NSString *const kCandidateKeys = @"CandidateKeys"; -static NSString *const kDefaultKeys = @"123456789"; - -@implementation PreferencesWindowController -@synthesize fontSizePopUpButton = _fontSizePopUpButton; -@synthesize basisKeyboardLayoutButton = _basisKeyboardLayoutButton; -@synthesize selectionKeyComboBox = _selectionKeyComboBox; - -- (void)awakeFromNib -{ - CFArrayRef list = TISCreateInputSourceList(NULL, true); - NSMenuItem *usKeyboardLayoutItem = nil; - NSMenuItem *chosenItem = nil; - - [self.basisKeyboardLayoutButton.menu removeAllItems]; - - NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; - - for (int i = 0; i < CFArrayGetCount(list); i++) { - TISInputSourceRef source = (TISInputSourceRef)CFArrayGetValueAtIndex(list, i); - - CFStringRef category = TISGetInputSourceProperty(source, kTISPropertyInputSourceCategory); - if (CFStringCompare(category, kTISCategoryKeyboardInputSource, 0) != kCFCompareEqualTo) { - continue; - } - - CFBooleanRef asciiCapable = TISGetInputSourceProperty(source, kTISPropertyInputSourceIsASCIICapable); - if (!CFBooleanGetValue(asciiCapable)) { - continue; - } - - CFStringRef sourceType = TISGetInputSourceProperty(source, kTISPropertyInputSourceType); - if (CFStringCompare(sourceType, kTISTypeKeyboardLayout, 0) != kCFCompareEqualTo) { - continue; - } - - NSString *sourceID = (__bridge NSString *)TISGetInputSourceProperty(source, kTISPropertyInputSourceID); - NSString *localizedName = (__bridge NSString *)TISGetInputSourceProperty(source, kTISPropertyLocalizedName); - - NSMenuItem *item = [[NSMenuItem alloc] init]; - item.title = localizedName; - item.representedObject = sourceID; - - if ([sourceID isEqualToString:@"com.apple.keylayout.US"]) { - usKeyboardLayoutItem = item; - } - - // false if nil - if ([basisKeyboardLayoutID isEqualToString:sourceID]) { - chosenItem = item; - } - - [self.basisKeyboardLayoutButton.menu addItem:item]; - } - - [self.basisKeyboardLayoutButton selectItem:(chosenItem ? chosenItem : usKeyboardLayoutItem)]; - CFRelease(list); - - self.selectionKeyComboBox.usesDataSource = NO; - [self.selectionKeyComboBox removeAllItems]; - [self.selectionKeyComboBox addItemsWithObjectValues:@[ - kDefaultKeys, - @"asdfghjkl", - @"asdfzxcvb" - ]]; - - NSString *ckeys = [[NSUserDefaults standardUserDefaults] stringForKey:kCandidateKeys]; - if (!ckeys || [ckeys stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length == 0) { - ckeys = kDefaultKeys; - } - - [self.selectionKeyComboBox setStringValue:ckeys]; -} - -- (IBAction)updateBasisKeyboardLayoutAction:(id)sender -{ - NSString *sourceID = [[self.basisKeyboardLayoutButton selectedItem] representedObject]; - if (sourceID) { - [[NSUserDefaults standardUserDefaults] setObject:sourceID forKey:kBasisKeyboardLayoutPreferenceKey]; - } -} - -- (IBAction)changeSelectionKeyAction:(id)sender -{ - NSString *keys = [[sender stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - if (keys.length != 9 || - ![keys canBeConvertedToEncoding:NSASCIIStringEncoding]) { - [self.selectionKeyComboBox setStringValue:kDefaultKeys]; - [[NSUserDefaults standardUserDefaults] removeObjectForKey:kCandidateKeys]; - NSBeep(); - return; - } - - [self.selectionKeyComboBox setStringValue:keys]; - if ([keys isEqualToString:kDefaultKeys]) { - [[NSUserDefaults standardUserDefaults] removeObjectForKey:kCandidateKeys]; - } else { - [[NSUserDefaults standardUserDefaults] setObject:keys forKey:kCandidateKeys]; - } -} - -@end diff --git a/Source/README b/Source/README index 823841342e8fd90f22f652ac9d38be1fa43733ed..1092f5c718486f7727470f080579316218bc0050 100644 --- a/Source/README +++ b/Source/README @@ -1,19 +1,15 @@ . -├── AppDelegate.h -├── AppDelegate.m -├── CandidateUI -│   ├── VTCandidateController.h -│   ├── VTCandidateController.m -│   ├── VTHorizontalCandidateController.h -│   ├── VTHorizontalCandidateController.m -│   ├── VTHorizontalCandidateView.h -│   ├── VTHorizontalCandidateView.m -│   ├── VTVerticalCandidateController.h -│   ├── VTVerticalCandidateController.m -│   ├── VTVerticalCandidateTableView.h -│   ├── VTVerticalCandidateTableView.m -│   ├── VTVerticalKeyLabelStripView.h -│   └── VTVerticalKeyLabelStripView.m +├── AppDelegate.swift +├── Base.lproj +│   ├── Credits.rtf +│   ├── InfoPlist.strings +│   ├── Localizable.strings +│   ├── MainMenu.xib +│   ├── preferences.xib +│   ├── template-data.txt +│   ├── template-exclude-phrases-plain-bpmf.txt +│   ├── template-exclude-phrases.txt +│   └── template-phrases-replacement.txt ├── Data │   ├── BPMFBase.txt │   ├── BPMFMappings.txt @@ -22,21 +18,21 @@ │   ├── PhraseFreq.txt │   ├── README │   ├── Symbols.txt +│   ├── associated-phrases.cin │   ├── bin │   │   ├── C_Version -│   │   │   ├── C_count.occ.exe │   │   │   ├── Makefile │   │   │   ├── count.bash │   │   │   └── count.occurrence.c │   │   ├── README │   │   ├── Sample_Prep │   │   │   ├── build.bash -│   │   │   ├── filter.bash -│   │   │   └── filter.py +│   │   │   └── filter.bash │   │   ├── bpmfmap.py │   │   ├── buildFreq.py │   │   ├── cook-plain-bpmf.py │   │   ├── cook.py +│   │   ├── cook_util.py │   │   ├── count.bash │   │   ├── count.occurrence.py │   │   ├── disabled @@ -47,7 +43,6 @@ │   │   │   ├── cook.rb │   │   │   ├── count.occurrence.pl │   │   │   ├── countphrase.bash -│   │   │   ├── filter.bash │   │   │   ├── randomShuffle.bash │   │   │   ├── typocorrection.bash │   │   │   └── utf8length.pl @@ -55,6 +50,7 @@ │   │   ├── self-score-test.py │   │   └── textpool.rc │   ├── data-plain-bpmf.txt +│   ├── data.txt │   ├── exclusion.txt │   ├── heterophony1.list │   ├── heterophony2.list @@ -64,11 +60,11 @@ │   │   ├── covered_by_others.txt │   │   ├── covered_by_singles.txt │   │   └── falsecount.txt -│   ├── phrase.occ -│   └── problem.txt +│   └── phrase.occ ├── Engine -│   ├── FastLM.cpp -│   ├── FastLM.h +│   ├── AssociatedPhrases.cpp +│   ├── AssociatedPhrases.h +│   ├── CMakeLists.txt │   ├── Gramambular │   │   ├── Bigram.h │   │   ├── BlockReadingBuilder.h @@ -81,121 +77,106 @@ │   │   ├── Span.h │   │   ├── Unigram.h │   │   └── Walker.h +│   ├── KeyValueBlobReader.cpp +│   ├── KeyValueBlobReader.h +│   ├── KeyValueBlobReaderTest.cpp │   ├── Mandarin +│   │   ├── CMakeLists.txt │   │   ├── Mandarin.cpp -│   │   └── Mandarin.h -│   └── OpenVanilla -│   ├── OVAroundFilter.h -│   ├── OVBase.h -│   ├── OVBenchmark.h -│   ├── OVCINDataTable.h -│   ├── OVCINDatabaseService.h -│   ├── OVCINToSQLiteConvertor.h -│   ├── OVCandidateService.h -│   ├── OVDatabaseService.h -│   ├── OVDateTimeHelper.h -│   ├── OVEncodingService.h -│   ├── OVEventHandlingContext.h -│   ├── OVException.h -│   ├── OVFileHelper.h -│   ├── OVFrameworkInfo.h -│   ├── OVInputMethod.h -│   ├── OVKey.h -│   ├── OVKeyPreprocessor.h -│   ├── OVKeyValueMap.h -│   ├── OVLoaderBase.h -│   ├── OVLoaderService.h -│   ├── OVLocalization.h -│   ├── OVModule.h -│   ├── OVModulePackage.h -│   ├── OVOutputFilter.h -│   ├── OVPathInfo.h -│   ├── OVSQLiteDatabaseService.h -│   ├── OVSQLiteWrapper.h -│   ├── OVStringHelper.h -│   ├── OVTextBuffer.h -│   ├── OVUTF8Helper.h -│   ├── OVWildcard.h -│   └── OpenVanilla.h -├── IconMaker -│   ├── AppIconRendererView.h -│   ├── AppIconRendererView.m -│   ├── BopomofoIconRenderView.h -│   ├── BopomofoIconRenderView.m -│   ├── IconMaker-Info.plist -│   ├── IconMaker-Prefix.pch -│   ├── IconMaker.xcodeproj -│   │   └── project.pbxproj -│   ├── IconMakerAppDelegate.h -│   ├── IconMakerAppDelegate.m -│   ├── ImageZoomInView.h -│   ├── ImageZoomInView.m -│   ├── TISIconRendererView.h -│   ├── TISIconRendererView.m -│   ├── en.lproj -│   │   └── MainMenu.xib -│   └── main.m +│   │   ├── Mandarin.h +│   │   └── MandarinTest.cpp +│   ├── McBopomofoLM.cpp +│   ├── McBopomofoLM.h +│   ├── ParselessLM.cpp +│   ├── ParselessLM.h +│   ├── ParselessLMBenchmark.cpp +│   ├── ParselessLMTest.cpp +│   ├── ParselessPhraseDB.cpp +│   ├── ParselessPhraseDB.h +│   ├── ParselessPhraseDBTest.cpp +│   ├── PhraseReplacementMap.cpp +│   ├── PhraseReplacementMap.h +│   ├── PhraseReplacementMapTest.cpp +│   ├── UserOverrideModel.cpp +│   ├── UserOverrideModel.h +│   ├── UserPhrasesLM.cpp +│   ├── UserPhrasesLM.h +│   └── UserPhrasesLMTest.cpp ├── Images │   ├── Bopomofo.tiff │   ├── Bopomofo@2x.tiff -│   ├── BopomofoTextMenu.tiff -│   ├── BopomofoTextMenu@2x.tiff -│   ├── McBopomofo.iconset -│   │   ├── icon_128x128.png -│   │   ├── icon_128x128@2x.png -│   │   ├── icon_16x16.png -│   │   ├── icon_16x16@2x.png -│   │   ├── icon_256x256.png -│   │   ├── icon_256x256@2x.png -│   │   ├── icon_32x32.png -│   │   ├── icon_32x32@2x.png -│   │   ├── icon_512x512.png -│   │   └── icon_512x512@2x.png +│   ├── Images.xcassets +│   │   ├── AlertIcon.imageset +│   │   │   ├── 128X128.png +│   │   │   ├── 192x192.png +│   │   │   ├── 64X64.png +│   │   │   └── Contents.json +│   │   ├── AppIcon.appiconset +│   │   │   ├── 1024X1024.png +│   │   │   ├── 128X128.png +│   │   │   ├── 16X16.png +│   │   │   ├── 256X256.png +│   │   │   ├── 32X32.png +│   │   │   ├── 512X512.png +│   │   │   ├── 64X64.png +│   │   │   └── Contents.json +│   │   └── Contents.json │   ├── PlainBopomofo.tiff -│   ├── PlainBopomofo@2x.tiff -│   ├── favicon.ico -│   ├── favicon.png -│   └── favicon.tiff -├── InputMethodController.h -├── InputMethodController.mm +│   └── PlainBopomofo@2x.tiff +├── InputMethodController.swift +├── InputState.swift ├── Installer -│   ├── AppDelegate.h -│   ├── AppDelegate.m +│   ├── AppDelegate.swift +│   ├── ArchiveUtil.swift +│   ├── Base.lproj +│   │   └── MainMenu.xib +│   ├── BundleTranslocate.h +│   ├── BundleTranslocate.m │   ├── Installer-Info.plist │   ├── Installer-Prefix.pch +│   ├── McBopomofoInstaller-Bridging-Header.h +│   ├── NotarizedArchives +│   │   └── README.md │   ├── en.lproj │   │   ├── InfoPlist.strings │   │   ├── License.rtf -│   │   ├── Localizable.strings -│   │   └── MainMenu.xib -│   ├── main.m +│   │   └── Localizable.strings │   └── zh-Hant.lproj │   ├── InfoPlist.strings │   ├── License.rtf │   ├── Localizable.strings │   └── MainMenu.xib +├── KeyHandler.h +├── KeyHandler.mm +├── KeyHandlerInput.swift +├── LanguageModelManager+Privates.h +├── LanguageModelManager.h +├── LanguageModelManager.mm +├── McBopomofo-Bridging-Header.h ├── McBopomofo-Info.plist ├── McBopomofo-Prefix.pch -├── OVInputSourceHelper.h -├── OVInputSourceHelper.m -├── PreferencesWindowController.h -├── PreferencesWindowController.m +├── NonModalAlertWindowController.swift +├── NonModalAlertWindowController.xib +├── Preferences.swift +├── PreferencesWindowController.swift ├── README ├── Tools │   ├── genRTF.py │   └── tistool.m -├── UpdateNotificationController.h -├── UpdateNotificationController.m ├── en.lproj +│   ├── Credits.rtf │   ├── InfoPlist.strings -│   ├── Localizable.strings -│   ├── MainMenu.xib -│   ├── UpdateNotificationController.xib -│   └── preferences.xib -├── main.m +│   └── Localizable.strings +├── main.swift └── zh-Hant.lproj + ├── Credits.rtf ├── InfoPlist.strings ├── Localizable.strings ├── MainMenu.xib - ├── UpdateNotificationController.xib - └── preferences.xib + ├── preferences.xib + ├── template-data.txt + ├── template-exclude-phrases-plain-bpmf.txt + ├── template-exclude-phrases.txt + └── template-phrases-replacement.txt + +22 directories, 157 files diff --git a/Source/Resources/Base.lproj/InfoPlist.strings b/Source/Resources/Base.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..bd58d7495f8317cd85abfb71eab35e9d7e74d6ad --- /dev/null +++ b/Source/Resources/Base.lproj/InfoPlist.strings @@ -0,0 +1,5 @@ +CFBundleName = "vChewing"; +CFBundleDisplayName = "vChewing"; +NSHumanReadableCopyright = "Copyright © 2011-2022 Mengjuei Hsieh et al.\nAll Rights Reserved."; +"org.atelierInmu.inputmethod.vChewing.IMECHT" = "vChewing-CHT"; +"org.atelierInmu.inputmethod.vChewing.IMECHS" = "vChewing-CHS"; diff --git a/Source/Resources/Base.lproj/Localizable.strings b/Source/Resources/Base.lproj/Localizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..9a2bfde29ae5b4a81f909ab8c74e17491e5618c3 --- /dev/null +++ b/Source/Resources/Base.lproj/Localizable.strings @@ -0,0 +1,94 @@ +/* No comment provided by engineer. */ +"About vChewing…" = "About vChewing…"; + +/* No comment provided by engineer. */ +"vChewing Preferences" = "vChewing Preferences"; + +/* No comment provided by engineer. */ +"Check for Updates…" = "Check for Updates…"; + +/* No comment provided by engineer. */ +"Update Check Failed" = "Update Check Failed"; + +/* No comment provided by engineer. */ +"There may be no internet connection or the server failed to respond.\n\nError message: %@" = "There may be no internet connection or the server failed to respond.\n\nError message: %@"; + +/* No comment provided by engineer. */ +"OK" = "OK"; + +/* No comment provided by engineer. */ +"Dismiss" = "Dismiss"; + +/* No comment provided by engineer. */ +"New Version Available" = "New Version Available"; + +/* No comment provided by engineer. */ +"Not Now" = "Not Now"; + +/* No comment provided by engineer. */ +"Visit Website" = "Visit Website"; + +/* No comment provided by engineer. */ +"You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?%@" = "You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?%@"; + +"Chinese Conversion" = "Convert to Simplified Chinese"; + +"User Phrases" = "User Phrases"; + +"Edit User Phrases" = "Edit User Phrases"; + +"Reload User Phrases" = "Reload User Phrases"; + +"Unable to create the user phrase file." = "Unable to create the user phrase file."; + +"Please check the permission of at \"%@\"." = "Please check the permission of at \"%@\"."; + +"Edit Excluded Phrases" = "Edit Excluded Phrases"; + +"Use Half-Width Punctuations" = "Use Half-Width Punctuations"; + +"You are now selecting \"%@\". You can add a phrase with two or more characters." = "You are now selecting \"%@\". You can add a phrase with two or more characters."; + +"You are now selecting \"%@\". Press enter to add a new phrase." = "You are now selecting \"%@\". Press enter to add a new phrase."; + +"You are now selecting \"%@\". A phrase cannot be longer than %d characters." = "You are now selecting \"%@\". A phrase cannot be longer than %d characters."; + +"Chinese conversion on" = "Chinese conversion on"; + +"Chinese conversion off" = "Chinese conversion off"; + +"Edit Phrase Replacement Table" = "Edit Phrase Replacement Table"; + +"Use Phrase Replacement" = "Use Phrase Replacement"; + +"Candidates keys cannot be empty." = "Candidates keys cannot be empty."; + +"Candidate keys can only contain latin characters and numbers." = "Candidate keys can only contain latin characters and numbers."; + +"Candidate keys cannot contain space." = "Candidate keys cannot contain space."; + +"There should not be duplicated keys." = "There should not be duplicated keys."; + +"The length of your candidate keys can not be less than 4 characters." = "The length of your candidate keys can not be less than 4 characters."; + +"The length of your candidate keys can not be larger than 15 characters." = "The length of your candidate keys can not be larger than 15 characters."; + +"Phrase replacement mode is on. Not suggested to add phrase in the mode." = "Phrase replacement mode is on. Not suggested to add phrase in the mode."; + +"Model based Chinese conversion is on. Not suggested to add phrase in the mode." = "Model based Chinese conversion is on. Not suggested to add phrase in the mode."; + +"Half-width punctuation on" = "Half-width punctuation on"; + +"Half-width punctuation off" = "Half-width punctuation off"; + +"Associated Phrases" = "Associated Phrases"; + +"There are special phrases in your text. We don't support adding new phrases in this case." = "There are special phrases in your text. We don't support adding new phrases in this case."; + +"Cursor is before \"%@\"." = "Cursor is before \"%@\"."; + +"Cursor is after \"%@\"." = "Cursor is after \"%@\"."; + +"Cursor is between \"%@\" and \"%@\"." = "Cursor is between \"%@\" and \"%@\"."; + +"You are now selecting \"%@\". The phrase already exists." = "You are now selecting \"%@\". The phrase already exists."; diff --git a/Source/McBopomofo-Info.plist b/Source/Resources/IME-Info.plist similarity index 63% rename from Source/McBopomofo-Info.plist rename to Source/Resources/IME-Info.plist index 199cc007708cfb11c5649bec56455e003ad22ee8..b2aea63597cd3c6f60ce328dbb4a99d6ff748b75 100644 --- a/Source/McBopomofo-Info.plist +++ b/Source/Resources/IME-Info.plist @@ -15,24 +15,28 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.1 + $(MARKETING_VERSION) CFBundleSignature BPMF CFBundleVersion - 879 + $(CURRENT_PROJECT_VERSION) + CFEULAContent + License texts used in the customized about window. ComponentInputModeDict tsInputModeListKey - org.openvanilla.inputmethod.McBopomofo.Bopomofo + org.atelierInmu.inputmethod.vChewing.IMECHS TISDoubleSpaceSubstitution + TISIntendedLanguage + zh-Hans tsInputModeAlternateMenuIconFileKey - Bopomofo.tiff + MenuIcon-SCVIM.png tsInputModeCharacterRepertoireKey - Hant + Hans Han tsInputModeDefaultStateKey @@ -42,29 +46,22 @@ tsInputModeKeyEquivalentModifiersKey 4608 tsInputModeMenuIconFileKey - Bopomofo.tiff + MenuIcon-SCVIM.png tsInputModePaletteIconFileKey - Bopomofo.tiff + MenuIcon-SCVIM.png tsInputModePrimaryInScriptKey tsInputModeScriptKey smTradChinese - TISIntendedLanguage - zh-Hant - tsInputModeCharacterRepertoireKey - - Hant - Han - - tsInputModeKeyEquivalentModifiersKey - 4608 - org.openvanilla.inputmethod.McBopomofo.PlainBopomofo + org.atelierInmu.inputmethod.vChewing.IMECHT TISDoubleSpaceSubstitution + TISIntendedLanguage + zh-Hant tsInputModeAlternateMenuIconFileKey - PlainBopomofo.tiff + MenuIcon-TCVIM.png tsInputModeCharacterRepertoireKey Hant @@ -77,38 +74,29 @@ tsInputModeKeyEquivalentModifiersKey 4608 tsInputModeMenuIconFileKey - PlainBopomofo.tiff + MenuIcon-TCVIM.png tsInputModePaletteIconFileKey - PlainBopomofo.tiff + MenuIcon-TCVIM.png tsInputModePrimaryInScriptKey tsInputModeScriptKey smTradChinese - TISIntendedLanguage - zh-Hant - tsInputModeCharacterRepertoireKey - - Hant - Han - - tsInputModeKeyEquivalentModifiersKey - 4608 tsVisibleInputModeOrderedArrayKey - org.openvanilla.inputmethod.McBopomofo.Bopomofo - org.openvanilla.inputmethod.McBopomofo.PlainBopomofo + org.atelierInmu.inputmethod.vChewing.IMECHT + org.atelierInmu.inputmethod.vChewing.IMECHS InputMethodConnectionName - McBopomofo_1_Connection + vChewing_1_Connection InputMethodServerControllerClass - McBopomofoInputMethodController + ctlInputMethod InputMethodServerDelegateClass - McBopomofoInputMethodController + ctlInputMethod InputMethodServerPreferencesWindowControllerClass - PreferencesWindowController + ctlPrefWindow LSApplicationCategoryType public.app-category.utilities LSHasLocalizedDisplayName @@ -118,27 +106,32 @@ LSUIElement NSHumanReadableCopyright - Copyright © 2011-2021 Mengjuei Hsieh et al. + © 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project. NSMainNibFile MainMenu NSPrincipalClass NSApplication + NSRequiresAquaSystemAppearance + No + NSWindowDarkChocolate + Yes TICapsLockLanguageSwitchCapable TISInputSourceID - org.openvanilla.inputmethod.McBopomofo + org.atelierInmu.inputmethod.vChewing TISIntendedLanguage - zh-Hant + zh-Hans TISParticipatesInTouchBar UpdateInfoEndpoint - https://mcbopomofo.openvanilla.org/updates/Info.plist + https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist UpdateInfoSite - https://mcbopomofo.openvanilla.org/ + https://gitee.com/vchewing/vChewing-macOS tsInputMethodCharacterRepertoireKey - Hant Hans + Hant + Han tsInputMethodIconFileKey Bopomofo.tiff diff --git a/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner.png b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner.png new file mode 100644 index 0000000000000000000000000000000000000000..20a77a7d34ff6a449fb96ebeb005ecb74da8f06a Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner.png differ diff --git a/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@2x.png b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..87412a5d6a9cac61d77845b09b395611a1e70019 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@2x.png differ diff --git a/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@3x.png b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..b2d74cb862732517a89e33c5474b5477a7bf0888 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/AboutBanner@3x.png differ diff --git a/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/Contents.json b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..46812c397d6d4b5fb851d41615225f6fe3241de5 --- /dev/null +++ b/Source/Resources/Images/Images.xcassets/AboutBanner.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "AboutBanner.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "AboutBanner@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "AboutBanner@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/128X128.png b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/128X128.png new file mode 100644 index 0000000000000000000000000000000000000000..9087448a8688c431d98d6b75ec1821f5faa2dfc3 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/128X128.png differ diff --git a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/192x192.png b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..2494c7241b77d7054f8d646b38f38b24f2321ac0 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/192x192.png differ diff --git a/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/64X64.png b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/64X64.png new file mode 100644 index 0000000000000000000000000000000000000000..13ee05fdc940fd006922df59a091cd8adaf59470 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/64X64.png differ diff --git a/Source/Images/Images.xcassets/AlertIcon.imageset/Contents.json b/Source/Resources/Images/Images.xcassets/AlertIcon.imageset/Contents.json similarity index 100% rename from Source/Images/Images.xcassets/AlertIcon.imageset/Contents.json rename to Source/Resources/Images/Images.xcassets/AlertIcon.imageset/Contents.json diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/1024X1024.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/1024X1024.png new file mode 100644 index 0000000000000000000000000000000000000000..83dc07ed35cd4a55f10ef90615f93df0ce0da15a Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/1024X1024.png differ diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/128X128.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/128X128.png new file mode 100644 index 0000000000000000000000000000000000000000..9087448a8688c431d98d6b75ec1821f5faa2dfc3 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/128X128.png differ diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/16X16.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/16X16.png new file mode 100644 index 0000000000000000000000000000000000000000..7c9922316e6c3f4a9e28a4d546460afe2fe551f0 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/16X16.png differ diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/256X256.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/256X256.png new file mode 100644 index 0000000000000000000000000000000000000000..021c6f1998af721246a7d7eba4f9f10dccf699b5 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/256X256.png differ diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/32X32.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/32X32.png new file mode 100644 index 0000000000000000000000000000000000000000..923e104c0ce0909702fd08d4d074442e490622e9 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/32X32.png differ diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/512X512.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/512X512.png new file mode 100644 index 0000000000000000000000000000000000000000..b8a42ce4f0df844f6c3777647fc96f4fbbd2ae73 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/512X512.png differ diff --git a/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/64X64.png b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/64X64.png new file mode 100644 index 0000000000000000000000000000000000000000..13ee05fdc940fd006922df59a091cd8adaf59470 Binary files /dev/null and b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/64X64.png differ diff --git a/Source/Images/Images.xcassets/AppIcon.appiconset/Contents.json b/Source/Resources/Images/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Source/Images/Images.xcassets/AppIcon.appiconset/Contents.json rename to Source/Resources/Images/Images.xcassets/AppIcon.appiconset/Contents.json diff --git a/Source/Images/Images.xcassets/Contents.json b/Source/Resources/Images/Images.xcassets/Contents.json similarity index 100% rename from Source/Images/Images.xcassets/Contents.json rename to Source/Resources/Images/Images.xcassets/Contents.json diff --git a/Source/Resources/Images/RAW/March.jpg b/Source/Resources/Images/RAW/March.jpg new file mode 100644 index 0000000000000000000000000000000000000000..72e80e8a527d143806e777bdf7b64c085d50c67f Binary files /dev/null and b/Source/Resources/Images/RAW/March.jpg differ diff --git a/Source/Resources/Images/RAW/vChewing.svg b/Source/Resources/Images/RAW/vChewing.svg new file mode 100644 index 0000000000000000000000000000000000000000..2fb29e0b94f819f86b7517e9672892469b659890 --- /dev/null +++ b/Source/Resources/Images/RAW/vChewing.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Resources/MenuIcons/MenuIcon-SCVIM.png b/Source/Resources/MenuIcons/MenuIcon-SCVIM.png new file mode 100644 index 0000000000000000000000000000000000000000..86c8e604a4d9910c12a6296e2e50daed36cd9b9f Binary files /dev/null and b/Source/Resources/MenuIcons/MenuIcon-SCVIM.png differ diff --git a/Source/Resources/MenuIcons/MenuIcon-SCVIM@2x.png b/Source/Resources/MenuIcons/MenuIcon-SCVIM@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2511631aa817242a1d02f75520304bc404245a05 Binary files /dev/null and b/Source/Resources/MenuIcons/MenuIcon-SCVIM@2x.png differ diff --git a/Source/Resources/MenuIcons/MenuIcon-TCVIM.png b/Source/Resources/MenuIcons/MenuIcon-TCVIM.png new file mode 100644 index 0000000000000000000000000000000000000000..e88ae4d5d47809e390e9f073f964cb9b7c50fd02 Binary files /dev/null and b/Source/Resources/MenuIcons/MenuIcon-TCVIM.png differ diff --git a/Source/Resources/MenuIcons/MenuIcon-TCVIM@2x.png b/Source/Resources/MenuIcons/MenuIcon-TCVIM@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ca92d0eca45b953486389cc5c01ba284fba40b12 Binary files /dev/null and b/Source/Resources/MenuIcons/MenuIcon-TCVIM@2x.png differ diff --git a/Source/Resources/SoundFiles/Beep.m4a b/Source/Resources/SoundFiles/Beep.m4a new file mode 100644 index 0000000000000000000000000000000000000000..6e4e31508a274bb6de069f7aee7ce673153f9d8a Binary files /dev/null and b/Source/Resources/SoundFiles/Beep.m4a differ diff --git a/Source/Resources/SoundFiles/Fart.m4a b/Source/Resources/SoundFiles/Fart.m4a new file mode 100644 index 0000000000000000000000000000000000000000..82a7711ad7990045445aaad0ff43f4a58a379a9e Binary files /dev/null and b/Source/Resources/SoundFiles/Fart.m4a differ diff --git a/Source/Tools/genRTF.py b/Source/Tools/genRTF.py deleted file mode 100755 index f60f69e48df44dbec6570ba95221bde906db7902..0000000000000000000000000000000000000000 --- a/Source/Tools/genRTF.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -import sys, os -import platform -myversion, _, _ = platform.mac_ver() -myversion = float('.'.join(myversion.split('.')[:2])) - -if myversion == 10.8: - os.environ["MACOSX_DEPLOYMENT_TARGET"] = "10.8" - print myversion -else: - os.environ["MACOSX_DEPLOYMENT_TARGET"] = "10.7" - -os.environ["PYTHONPATH"] = "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/" - -import subprocess, getopt -from Foundation import * -from AppKit import * - -def generateRTF(inString="", inFile=""): - if len(inString) == 0: return - if len(inFile) == 0: return - paragraphStyle = NSMutableParagraphStyle.alloc().init() - paragraphStyle.setAlignment_(NSCenterTextAlignment) - attributedString = NSAttributedString.alloc().initWithString_attributes_(inString, { - NSParagraphStyleAttributeName: paragraphStyle, - NSFontAttributeName: NSFont.systemFontOfSize_(11) - }) - data = attributedString.RTFFromRange_documentAttributes_(NSMakeRange(0, len(inString)), None) - try: os.remove(inFile) - except: pass - data.writeToFile_atomically_(inFile, True) - os.utime(inFile, None) # Touch the file - -def main(argv=None): - if argv is None: - argv = sys.argv - try: - path = argv[1] - except: - return - - path = os.path.abspath(path) - cmd = "/usr/bin/git log --format='%h' -1" - try: - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - lines = "" - while True: - line = p.stdout.readline() - if not line: break - line = line.strip() - if len(line): lines += line + "\n" - lines = lines.strip() - generateRTF("Build: " + lines, os.path.join(path, "Credits.rtf")) - except Exception, e: - pass - -if __name__ == "__main__": - sys.exit(main()) diff --git a/Source/Tools/tistool.m b/Source/Tools/tistool.m deleted file mode 100644 index b8cf190184860e653ab149373c6c3404b37cac46..0000000000000000000000000000000000000000 --- a/Source/Tools/tistool.m +++ /dev/null @@ -1,134 +0,0 @@ -// -// tistool.m -// -// Copyright (c) 2010-2011 Lukhnos D. Liu (lukhnos at lukhnos dot org) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "OVInputSourceHelper.h" - -static void PrintUsage(); - -int main(int argc, char **argv) -{ - // we'll let the OS clean up this pool for us - [NSAutoreleasePool new]; - - if (argc < 2) { - PrintUsage(); - return 1; - } - - int opt; - while ((opt = getopt(argc, argv, "lr:e:d:s:")) != -1) { - switch (opt) { - case 'l': - { - for (id source in [OVInputSourceHelper allInstalledInputSources]) { - if (TISGetInputSourceProperty((TISInputSourceRef)source, kTISPropertyInputSourceType) != kTISTypeKeyboardInputMode) { - printf("%s\n", [(id)TISGetInputSourceProperty((TISInputSourceRef)source, kTISPropertyInputSourceID) UTF8String]); - } - } - break; - } - - case 'r': - { - NSURL *bundle = [NSURL fileURLWithPath:[NSString stringWithUTF8String:optarg]]; - if (bundle) { - BOOL status = [OVInputSourceHelper registerInputSource:bundle]; - NSLog(@"register input source at: %@, result: %d", [bundle absoluteString], status); - } - break; - } - - - case 'e': - { - TISInputSourceRef inputSource = [OVInputSourceHelper inputSourceForInputSourceID:[NSString stringWithUTF8String:optarg]]; - if (!inputSource) { - NSLog(@"Cannot find input source: %s", optarg); - return 1; - } - - BOOL status = [OVInputSourceHelper enableInputSource:inputSource]; - NSLog(@"Enable input source: %s, result: %d", optarg, status); - return status; - } - - case 'd': - { - TISInputSourceRef inputSource = [OVInputSourceHelper inputSourceForInputSourceID:[NSString stringWithUTF8String:optarg]]; - if (!inputSource) { - NSLog(@"Cannot find input source: %s", optarg); - return 1; - } - - BOOL status = [OVInputSourceHelper disableInputSource:inputSource]; - NSLog(@"Disable input source: %s, result: %d", optarg, status); - return status; - } - - case 's': - { - TISInputSourceRef inputSource = [OVInputSourceHelper inputSourceForInputSourceID:[NSString stringWithUTF8String:optarg]]; - if (!inputSource) { - NSLog(@"Cannot find input source: %s", optarg); - return 1; - } - - BOOL status = [OVInputSourceHelper inputSourceEnabled:inputSource]; - NSLog(@"Input source: %s, enabled: %@", optarg, (status ? @"yes" : @"no")); - return 0; - } - default: - PrintUsage(); - return 1; - } - } - - return 0; -} - -static void PrintUsage() -{ - fprintf(stderr, "usage: tistool [options]\n" - "options:\n" - " -l list all input sources\n" - " -r register an input source\n" - " -e enable an input source\n" - " -d disable an input source\n" - " -s check if an input source is enabled\n\n" - " is an input source id, a few examples:\n" - " com.apple.inputmethod.Kotoeri (Apple's Japanese input method)\n" - " com.apple.CharacterPaletteIM (Keyboard/Character Viewer palettes)\n" - " com.apple.keylayout.German (German keyboard layout)\n" - "\n" - " must be a bundle in one of the directories:\n" - " ~/Library/Input Methods/\n" - " /Library/Input Methods/\n" - " ~/Library/Keyboard Layouts/\n" - " /Library/Keyboard Layouts/\n" - "\n" - ); -} diff --git a/Source/UI/CandidateUI/CandidateController.swift b/Source/UI/CandidateUI/CandidateController.swift new file mode 100644 index 0000000000000000000000000000000000000000..bc099e8d8dd9dbd62df4628b777cab6629586dd2 --- /dev/null +++ b/Source/UI/CandidateUI/CandidateController.swift @@ -0,0 +1,147 @@ + +import Cocoa + +@objc(VTCandidateKeyLabel) +public class CandidateKeyLabel: NSObject { + @objc public private(set) var key: String + @objc public private(set) var displayedText: String + + public init(key: String, displayedText: String) { + self.key = key + self.displayedText = displayedText + super.init() + } +} + +@objc(VTCandidateControllerDelegate) +public protocol CandidateControllerDelegate: AnyObject { + func candidateCountForController(_ controller: CandidateController) -> UInt + func candidateController(_ controller: CandidateController, candidateAtIndex index: UInt) -> String + func candidateController(_ controller: CandidateController, didSelectCandidateAtIndex index: UInt) +} + +@objc(VTCandidateController) +public class CandidateController: NSWindowController { + @objc public weak var delegate: CandidateControllerDelegate? { + didSet { + reloadData() + } + } + @objc public var selectedCandidateIndex: UInt = UInt.max + @objc public var visible: Bool = false { + didSet { + NSObject.cancelPreviousPerformRequests(withTarget: self) + if visible { + window?.perform(#selector(NSWindow.orderFront(_:)), with: self, afterDelay: 0.0) + } else { + window?.perform(#selector(NSWindow.orderOut(_:)), with: self, afterDelay: 0.0) + } + } + } + @objc public var windowTopLeftPoint: NSPoint { + get { + guard let frameRect = window?.frame else { + return NSPoint.zero + } + return NSPoint(x: frameRect.minX, y: frameRect.maxY) + } + set { + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) { + self.set(windowTopLeftPoint: newValue, bottomOutOfScreenAdjustmentHeight: 0) + } + } + } + + @objc public var keyLabels: [CandidateKeyLabel] = ["1", "2", "3", "4", "5", "6", "7", "8", "9"].map { + CandidateKeyLabel(key: $0, displayedText: $0) + } + @objc public var keyLabelFont: NSFont = NSFont.systemFont(ofSize: 14) + @objc public var candidateFont: NSFont = NSFont.systemFont(ofSize: 18) + @objc public var tooltip: String = "" + + @objc public func reloadData() { + } + + @objc public func showNextPage() -> Bool { + false + } + + @objc public func showPreviousPage() -> Bool { + false + } + + @objc public func highlightNextCandidate() -> Bool { + false + } + + @objc public func highlightPreviousCandidate() -> Bool { + false + } + + @objc public func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt { + UInt.max + } + + /// Sets the location of the candidate window. + /// + /// Please note that the method has side effects that modifies + /// `windowTopLeftPoint` to make the candidate window to stay in at least + /// in a screen. + /// + /// - Parameters: + /// - windowTopLeftPoint: The given location. + /// - height: The height that helps the window not to be out of the bottom + /// of a screen. + @objc(setWindowTopLeftPoint:bottomOutOfScreenAdjustmentHeight:) + public func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight height: CGFloat) { + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) { + self.doSet(windowTopLeftPoint: windowTopLeftPoint, bottomOutOfScreenAdjustmentHeight: height) + } + } + + func doSet(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight height: CGFloat) { + var adjustedPoint = windowTopLeftPoint + var adjustedHeight = height + + var screenFrame = NSScreen.main?.visibleFrame ?? NSRect.zero + for screen in NSScreen.screens { + let frame = screen.visibleFrame + if windowTopLeftPoint.x >= frame.minX && + windowTopLeftPoint.x <= frame.maxX && + windowTopLeftPoint.y >= frame.minY && + windowTopLeftPoint.y <= frame.maxY { + screenFrame = frame + break + } + } + + if adjustedHeight > screenFrame.size.height / 2.0 { + adjustedHeight = 0.0 + } + + let windowSize = window?.frame.size ?? NSSize.zero + + // bottom beneath the screen? + if adjustedPoint.y - windowSize.height < screenFrame.minY { + adjustedPoint.y = windowTopLeftPoint.y + adjustedHeight + windowSize.height + } + + // top over the screen? + if adjustedPoint.y >= screenFrame.maxY { + adjustedPoint.y = screenFrame.maxY - 1.0 + } + + // right + if adjustedPoint.x + windowSize.width >= screenFrame.maxX { + adjustedPoint.x = screenFrame.maxX - windowSize.width + } + + // left + if adjustedPoint.x < screenFrame.minX { + adjustedPoint.x = screenFrame.minX + } + + window?.setFrameTopLeftPoint(adjustedPoint) + } + +} diff --git a/Source/UI/CandidateUI/HorizontalCandidateController.swift b/Source/UI/CandidateUI/HorizontalCandidateController.swift new file mode 100644 index 0000000000000000000000000000000000000000..5aa6729a8bdea4aac859f31fc5df5a4a0c388a69 --- /dev/null +++ b/Source/UI/CandidateUI/HorizontalCandidateController.swift @@ -0,0 +1,413 @@ + +import Cocoa + +fileprivate class HorizontalCandidateView: NSView { + var highlightedIndex: UInt = 0 + var action: Selector? + weak var target: AnyObject? + + private var keyLabels: [String] = [] + private var displayedCandidates: [String] = [] + private var keyLabelHeight: CGFloat = 0 + private var candidateTextHeight: CGFloat = 0 + private var cellPadding: CGFloat = 0 + private var keyLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:] + private var candidateAttrDict: [NSAttributedString.Key: AnyObject] = [:] + private var elementWidths: [CGFloat] = [] + private var trackingHighlightedIndex: UInt = UInt.max + + private let tooltipPadding: CGFloat = 2.0 + private var tooltipSize: NSSize = NSSize.zero + + override var toolTip: String? { + didSet { + if let toolTip = toolTip, !toolTip.isEmpty { + let baseSize = NSSize(width: 10240.0, height: 10240.0) + var tooltipRect = (toolTip as NSString).boundingRect(with: baseSize, options: .usesLineFragmentOrigin, attributes: keyLabelAttrDict) + tooltipRect.size.height += tooltipPadding * 2 + tooltipRect.size.width += tooltipPadding * 2 + self.tooltipSize = tooltipRect.size + } else { + self.tooltipSize = NSSize.zero + } + } + } + + override var isFlipped: Bool { + true + } + + var sizeForView: NSSize { + var result = NSSize.zero + + if !elementWidths.isEmpty { + result.width = elementWidths.reduce(0, +) + result.width += CGFloat(elementWidths.count) + result.height = keyLabelHeight + candidateTextHeight + 1.0 + } + + result.height += tooltipSize.height + result.width = max(tooltipSize.width, result.width) + return result + } + + func set(keyLabels labels: [String], displayedCandidates candidates: [String]) { + let count = min(labels.count, candidates.count) + keyLabels = Array(labels[0.. UInt? { + let location = convert(event.locationInWindow, to: nil) + if !NSPointInRect(location, self.bounds) { + return nil + } + var accuWidth: CGFloat = 0.0 + for index in 0..= accuWidth && location.x <= accuWidth + currentWidth { + return UInt(index) + } + accuWidth += currentWidth + 1.0 + } + return nil + + } + + override func mouseUp(with event: NSEvent) { + trackingHighlightedIndex = highlightedIndex + guard let newIndex = findHitIndex(event: event) else { + return + } + highlightedIndex = newIndex + self.setNeedsDisplay(self.bounds) + } + + override func mouseDown(with event: NSEvent) { + guard let newIndex = findHitIndex(event: event) else { + return + } + var triggerAction = false + if newIndex == highlightedIndex { + triggerAction = true + } else { + highlightedIndex = trackingHighlightedIndex + } + + trackingHighlightedIndex = 0 + self.setNeedsDisplay(self.bounds) + if triggerAction { + if let target = target as? NSObject, let action = action { + target.perform(action, with: self) + } + } + } +} + +@objc(VTHorizontalCandidateController) +public class HorizontalCandidateController: CandidateController { + private var candidateView: HorizontalCandidateView + private var prevPageButton: NSButton + private var nextPageButton: NSButton + private var currentPage: UInt = 0 + + public init() { + var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0) + let styleMask: NSWindow.StyleMask = [.borderless, .nonactivatingPanel] + let panel = NSPanel(contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false) + panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1) + panel.hasShadow = true + + contentRect.origin = NSPoint.zero + candidateView = HorizontalCandidateView(frame: contentRect) + panel.contentView?.addSubview(candidateView) + + contentRect.size = NSSize(width: 36.0, height: 20.0) + nextPageButton = NSButton(frame: contentRect) + nextPageButton.setButtonType(.momentaryLight) + nextPageButton.bezelStyle = .smallSquare + nextPageButton.title = "»" + + prevPageButton = NSButton(frame: contentRect) + prevPageButton.setButtonType(.momentaryLight) + prevPageButton.bezelStyle = .smallSquare + prevPageButton.title = "«" + + panel.contentView?.addSubview(nextPageButton) + panel.contentView?.addSubview(prevPageButton) + + super.init(window: panel) + + candidateView.target = self + candidateView.action = #selector(candidateViewMouseDidClick(_:)) + + nextPageButton.target = self + nextPageButton.action = #selector(pageButtonAction(_:)) + + prevPageButton.target = self + prevPageButton.action = #selector(pageButtonAction(_:)) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public override func reloadData() { + candidateView.highlightedIndex = 0 + currentPage = 0 + layoutCandidateView() + } + + public override func showNextPage() -> Bool { + guard delegate != nil else { + return false + } + + if currentPage + 1 >= pageCount { + return false + } + + currentPage += 1 + candidateView.highlightedIndex = 0 + layoutCandidateView() + return true + } + + public override func showPreviousPage() -> Bool { + guard delegate != nil else { + return false + } + + if currentPage == 0 { + return false + } + + currentPage -= 1 + candidateView.highlightedIndex = 0 + layoutCandidateView() + return true + } + + public override func highlightNextCandidate() -> Bool { + guard let delegate = delegate else { + return false + } + + let currentIndex = selectedCandidateIndex + if currentIndex + 1 >= delegate.candidateCountForController(self) { + return false + } + selectedCandidateIndex = currentIndex + 1 + return true + } + + public override func highlightPreviousCandidate() -> Bool { + guard delegate != nil else { + return false + } + + let currentIndex = selectedCandidateIndex + if currentIndex == 0 { + return false + } + + selectedCandidateIndex = currentIndex - 1 + return true + } + + public override func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt { + guard let delegate = delegate else { + return UInt.max + } + + let result = currentPage * UInt(keyLabels.count) + index + return result < delegate.candidateCountForController(self) ? result : UInt.max + } + + public override var selectedCandidateIndex: UInt { + get { + currentPage * UInt(keyLabels.count) + candidateView.highlightedIndex + } + set { + guard let delegate = delegate else { + return + } + let keyLabelCount = UInt(keyLabels.count) + if newValue < delegate.candidateCountForController(self) { + currentPage = newValue / keyLabelCount + candidateView.highlightedIndex = newValue % keyLabelCount + layoutCandidateView() + } + } + } +} + +extension HorizontalCandidateController { + + private var pageCount: UInt { + guard let delegate = delegate else { + return 0 + } + let totalCount = delegate.candidateCountForController(self) + let keyLabelCount = UInt(keyLabels.count) + return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0) + } + + private func layoutCandidateView() { + guard let delegate = delegate else { + return + } + + candidateView.set(keyLabelFont: keyLabelFont, candidateFont: candidateFont) + var candidates = [String]() + let count = delegate.candidateCountForController(self) + let keyLabelCount = UInt(keyLabels.count) + + let begin = currentPage * keyLabelCount + for index in begin.. 1 { + var buttonRect = nextPageButton.frame + var spacing: CGFloat = 0.0 + + if newSize.height < 40.0 { + buttonRect.size.height = floor(newSize.height / 2) + } else { + buttonRect.size.height = 20.0 + } + + if newSize.height >= 60.0 { + spacing = ceil(newSize.height * 0.1) + } + + let buttonOriginY = (newSize.height - (buttonRect.size.height * 2.0 + spacing)) / 2.0 + buttonRect.origin = NSPoint(x: newSize.width + 8.0, y: buttonOriginY) + nextPageButton.frame = buttonRect + + buttonRect.origin = NSPoint(x: newSize.width + 8.0, y: buttonOriginY + buttonRect.size.height + spacing) + prevPageButton.frame = buttonRect + + newSize.width += 52.0 + nextPageButton.isHidden = false + prevPageButton.isHidden = false + } else { + nextPageButton.isHidden = true + prevPageButton.isHidden = true + } + + frameRect = window?.frame ?? NSRect.zero + + let topLeftPoint = NSMakePoint(frameRect.origin.x, frameRect.origin.y + frameRect.size.height) + frameRect.size = newSize + frameRect.origin = NSMakePoint(topLeftPoint.x, topLeftPoint.y - frameRect.size.height) + self.window?.setFrame(frameRect, display: false) + candidateView.setNeedsDisplay(candidateView.bounds) + } + + @objc fileprivate func pageButtonAction(_ sender: Any) { + guard let sender = sender as? NSButton else { + return + } + if sender == nextPageButton { + _ = showNextPage() + } else if sender == prevPageButton { + _ = showPreviousPage() + } + } + + @objc fileprivate func candidateViewMouseDidClick(_ sender: Any) { + delegate?.candidateController(self, didSelectCandidateAtIndex: selectedCandidateIndex) + } + +} diff --git a/Source/UI/CandidateUI/VerticalCandidateController.swift b/Source/UI/CandidateUI/VerticalCandidateController.swift new file mode 100644 index 0000000000000000000000000000000000000000..28c224a9862927ad24de360a5e2e6ad6bb6cb9be --- /dev/null +++ b/Source/UI/CandidateUI/VerticalCandidateController.swift @@ -0,0 +1,464 @@ + +import Cocoa + +fileprivate class VerticalKeyLabelStripView: NSView { + var keyLabelFont: NSFont = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize) + var labelOffsetY: CGFloat = 0 + var keyLabels: [String] = [] + var highlightedIndex: UInt = UInt.max + + override var isFlipped: Bool { + true + } + + override func draw(_ dirtyRect: NSRect) { + let bounds = self.bounds + NSColor.white.setFill() + NSBezierPath.fill(bounds) + + let count = UInt(keyLabels.count) + if count == 0 { + return + } + let cellHeight: CGFloat = bounds.size.height / CGFloat(count) + let black = NSColor.black + let darkGray = NSColor(deviceWhite: 0.7, alpha: 1.0) + let lightGray = NSColor(deviceWhite: 0.8, alpha: 1.0) + + let paraStyle = NSMutableParagraphStyle() + paraStyle.setParagraphStyle(NSParagraphStyle.default) + paraStyle.alignment = .center + + let textAttr: [NSAttributedString.Key: AnyObject] = [ + .font: keyLabelFont, + .foregroundColor: black, + .paragraphStyle: paraStyle] + for index in 0..= count { + cellRect.size.height += 1.0 + } + + (index == highlightedIndex ? darkGray : lightGray).setFill() + NSBezierPath.fill(cellRect) + let text = keyLabels[Int(index)] + (text as NSString).draw(in: textRect, withAttributes: textAttr) + } + } +} + +fileprivate class VerticalCandidateTableView: NSTableView { + override func adjustScroll(_ newVisible: NSRect) -> NSRect { + var scrollRect = newVisible + let rowHeightPlusSpacing = rowHeight + intercellSpacing.height + scrollRect.origin.y = (scrollRect.origin.y / rowHeightPlusSpacing) * rowHeightPlusSpacing + return scrollRect + } +} + +private let kCandidateTextPadding: CGFloat = 24.0 +private let kCandidateTextLeftMargin: CGFloat = 8.0 +private let kCandidateTextPaddingWithMandatedTableViewPadding: CGFloat = 18.0 +private let kCandidateTextLeftMarginWithMandatedTableViewPadding: CGFloat = 0.0 + +private class BackgroundView: NSView { + override func draw(_ dirtyRect: NSRect) { + NSColor.windowBackgroundColor.setFill() + NSBezierPath.fill(self.bounds) + } +} + +@objc(VTVerticalCandidateController) +public class VerticalCandidateController: CandidateController { + private var keyLabelStripView: VerticalKeyLabelStripView + private var scrollView: NSScrollView + private var tableView: NSTableView + private var candidateTextParagraphStyle: NSMutableParagraphStyle + private var candidateTextPadding: CGFloat = kCandidateTextPadding + private var candidateTextLeftMargin: CGFloat = kCandidateTextLeftMargin + private var maxCandidateAttrStringWidth: CGFloat = 0 + private let tooltipPadding: CGFloat = 2.0 + private var tooltipView: NSTextField + + public init() { + var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0) + let styleMask: NSWindow.StyleMask = [.borderless, .nonactivatingPanel] + let panel = NSPanel(contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false) + panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1) + panel.hasShadow = true + panel.contentView = BackgroundView() + + tooltipView = NSTextField(frame: NSRect.zero) + tooltipView.isEditable = false + tooltipView.isSelectable = false + tooltipView.isBezeled = false + tooltipView.drawsBackground = true + tooltipView.lineBreakMode = .byTruncatingTail + + contentRect.origin = NSPoint.zero + var stripRect = contentRect + stripRect.size.width = 10.0 + keyLabelStripView = VerticalKeyLabelStripView(frame: stripRect) + panel.contentView?.addSubview(keyLabelStripView) + + var scrollViewRect = contentRect + scrollViewRect.origin.x = stripRect.size.width + scrollViewRect.size.width -= stripRect.size.width + scrollView = NSScrollView(frame: scrollViewRect) + scrollView.verticalScrollElasticity = .none + + tableView = NSTableView(frame: contentRect) + let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "candidate")) + column.dataCell = NSTextFieldCell() + column.isEditable = false + + candidateTextPadding = kCandidateTextPadding + candidateTextLeftMargin = kCandidateTextLeftMargin + + tableView.addTableColumn(column) + tableView.intercellSpacing = NSSize(width: 0.0, height: 1.0) + tableView.headerView = nil + tableView.allowsMultipleSelection = false + tableView.allowsEmptySelection = false + + if #available(macOS 10.16, *) { + tableView.style = .fullWidth + candidateTextPadding = kCandidateTextPaddingWithMandatedTableViewPadding + candidateTextLeftMargin = kCandidateTextLeftMarginWithMandatedTableViewPadding + } + + scrollView.documentView = tableView + panel.contentView?.addSubview(scrollView) + + let paraStyle = NSMutableParagraphStyle() + paraStyle.setParagraphStyle(NSParagraphStyle.default) + paraStyle.firstLineHeadIndent = candidateTextLeftMargin + paraStyle.lineBreakMode = .byClipping + + candidateTextParagraphStyle = paraStyle + + super.init(window: panel) + tableView.dataSource = self + tableView.delegate = self + tableView.doubleAction = #selector(rowDoubleClicked(_:)) + tableView.target = self + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public override func reloadData() { + maxCandidateAttrStringWidth = ceil(candidateFont.pointSize * 2.0 + candidateTextPadding) + tableView.reloadData() + layoutCandidateView() + if delegate?.candidateCountForController(self) ?? 0 > 0 { + selectedCandidateIndex = 0 + } + } + + public override func showNextPage() -> Bool { + scrollPageByOne(true) + } + + public override func showPreviousPage() -> Bool { + scrollPageByOne(false) + } + + public override func highlightNextCandidate() -> Bool { + moveSelectionByOne(true) + } + + public override func highlightPreviousCandidate() -> Bool { + moveSelectionByOne(false) + } + + public override func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt { + guard let delegate = delegate else { + return UInt.max + } + + let firstVisibleRow = tableView.row(at: scrollView.documentVisibleRect.origin) + if firstVisibleRow != -1 { + let result = UInt(firstVisibleRow) + index + if result < delegate.candidateCountForController(self) { + return result + } + } + + return UInt.max + } + + public override var selectedCandidateIndex: UInt { + get { + let selectedRow = tableView.selectedRow + return selectedRow == -1 ? UInt.max : UInt(selectedRow) + + } + set { + guard let delegate = delegate else { + return + } + var newIndex = newValue + let selectedRow = tableView.selectedRow + let labelCount = keyLabels.count + let itemCount = delegate.candidateCountForController(self) + + if newIndex == UInt.max { + if itemCount == 0 { + tableView.deselectAll(self) + return + } + newIndex = 0 + } + + var lastVisibleRow = newValue + + if selectedRow != -1 && itemCount > 0 && itemCount > labelCount { + if newIndex > selectedRow && (Int(newIndex) - selectedRow) > 1 { + lastVisibleRow = min(newIndex + UInt(labelCount) - 1, itemCount - 1) + } + // no need to handle the backward case: (newIndex < selectedRow && selectedRow - newIndex > 1) + } + + if itemCount > labelCount { + tableView.scrollRowToVisible(Int(lastVisibleRow)) + } + tableView.selectRowIndexes(IndexSet(integer: Int(newIndex)), byExtendingSelection: false) + } + } +} + +extension VerticalCandidateController: NSTableViewDataSource, NSTableViewDelegate { + + public func numberOfRows(in tableView: NSTableView) -> Int { + Int(delegate?.candidateCountForController(self) ?? 0) + } + + public func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { + guard let delegate = delegate else { + return nil + } + var candidate = "" + if row < delegate.candidateCountForController(self) { + candidate = delegate.candidateController(self, candidateAtIndex: UInt(row)) + } + let attrString = NSAttributedString(string: candidate, attributes: [ + .font: candidateFont, + .paragraphStyle: candidateTextParagraphStyle + ]) + + // we do more work than what this method is expected to; normally not a good practice, but for the amount of data (9 to 10 rows max), we can afford the overhead + + // expand the window width if text overflows + let boundingRect = attrString.boundingRect(with: NSSize(width: 10240.0, height: 10240.0), options: .usesLineFragmentOrigin) + let textWidth = boundingRect.size.width + candidateTextPadding + if textWidth > maxCandidateAttrStringWidth { + maxCandidateAttrStringWidth = textWidth + layoutCandidateView() + } + + // keep track of the highlighted index in the key label strip + let count = UInt(keyLabels.count) + let selectedRow = tableView.selectedRow + + if selectedRow != -1 { + var newHilightIndex = 0 + + if keyLabelStripView.highlightedIndex != -1 && + (row >= selectedRow + Int(count) || (selectedRow > count && row <= selectedRow - Int(count))) { + newHilightIndex = -1 + } else { + let firstVisibleRow = tableView.row(at: scrollView.documentVisibleRect.origin) + newHilightIndex = selectedRow - firstVisibleRow + if newHilightIndex < -1 { + newHilightIndex = -1 + } + } + + if newHilightIndex != keyLabelStripView.highlightedIndex && newHilightIndex >= 0 { + keyLabelStripView.highlightedIndex = UInt(newHilightIndex) + keyLabelStripView.setNeedsDisplay(keyLabelStripView.frame) + } + + } + return attrString + } + + public func tableViewSelectionDidChange(_ notification: Notification) { + let selectedRow = tableView.selectedRow + if selectedRow != -1 { + // keep track of the highlighted index in the key label strip + let firstVisibleRow = tableView.row(at: scrollView.documentVisibleRect.origin) + // firstVisibleRow cannot be larger than selectedRow. + if selectedRow >= firstVisibleRow { + keyLabelStripView.highlightedIndex = UInt(selectedRow - firstVisibleRow) + } else { + keyLabelStripView.highlightedIndex = UInt.max + } + + keyLabelStripView.setNeedsDisplay(keyLabelStripView.frame) + + // fix a subtle OS X "bug" that, since we force the scroller to appear, + // scrolling sometimes shows a temporarily "broken" scroll bar + // (but quickly disappears) + if scrollView.hasVerticalScroller { + scrollView.verticalScroller?.setNeedsDisplay() + } + } + } + + @objc func rowDoubleClicked(_ sender: Any) { + let clickedRow = tableView.clickedRow + if clickedRow != -1 { + delegate?.candidateController(self, didSelectCandidateAtIndex: UInt(clickedRow)) + } + } + + func scrollPageByOne(_ forward: Bool) -> Bool { + guard let delegate = delegate else { + return false + } + let labelCount = UInt(keyLabels.count) + let itemCount = delegate.candidateCountForController(self) + if 0 == itemCount { + return false + } + if itemCount <= labelCount { + return false + } + + var newIndex = selectedCandidateIndex + if forward { + if newIndex >= itemCount - 1 { + return false + } + newIndex = min(newIndex + labelCount, itemCount - 1) + } else { + if newIndex == 0 { + return false + } + + if newIndex < labelCount { + newIndex = 0 + } else { + newIndex -= labelCount + } + } + selectedCandidateIndex = newIndex + return true + } + + private func moveSelectionByOne(_ forward: Bool) -> Bool { + guard let delegate = delegate else { + return false + } + let itemCount = delegate.candidateCountForController(self) + if 0 == itemCount { + return false + } + var newIndex = selectedCandidateIndex + if newIndex == UInt.max { + return false + } + + if forward { + if newIndex >= itemCount - 1 { + return false + } + newIndex += 1 + } else { + if 0 == newIndex { + return false + } + newIndex -= 1 + } + selectedCandidateIndex = newIndex + return true + } + + private func layoutCandidateView() { + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) { [self] in + doLayoutCandidateView() + } + } + + private func doLayoutCandidateView() { + guard let delegate = delegate else { + return + } + let count = delegate.candidateCountForController(self) + if 0 == count { + return + } + + + var tooltipHeight: CGFloat = 0 + var tooltipWidth: CGFloat = 0 + + if !tooltip.isEmpty { + tooltipView.stringValue = tooltip + let size = tooltipView.intrinsicContentSize + tooltipWidth = size.width + tooltipPadding * 2 + tooltipHeight = size.height + tooltipPadding * 2 + self.window?.contentView?.addSubview(tooltipView) + } else { + tooltipView.removeFromSuperview() + } + + let candidateFontSize = ceil(candidateFont.pointSize) + let keyLabelFontSize = ceil(keyLabelFont.pointSize) + let fontSize = max(candidateFontSize, keyLabelFontSize) + + let controlSize: NSControl.ControlSize = fontSize > 36.0 ? .regular : .small + + var keyLabelCount = UInt(keyLabels.count) + var scrollerWidth: CGFloat = 0.0 + if count <= keyLabelCount { + keyLabelCount = count + scrollView.hasVerticalScroller = false + } else { + scrollView.hasVerticalScroller = true + let verticalScroller = scrollView.verticalScroller + verticalScroller?.controlSize = controlSize + verticalScroller?.scrollerStyle = .legacy + scrollerWidth = NSScroller.scrollerWidth(for: controlSize, scrollerStyle: .legacy) + } + + keyLabelStripView.keyLabelFont = keyLabelFont + let actualKeyLabels = keyLabels[0..= candidateFontSize) ? 0.0 : floor((candidateFontSize - keyLabelFontSize) / 2.0) + + let rowHeight = ceil(fontSize * 1.25) + tableView.rowHeight = rowHeight + + var maxKeyLabelWidth = keyLabelFontSize + let textAttr: [NSAttributedString.Key: AnyObject] = [.font: keyLabelFont] + let boundingBox = NSSize(width: 1600.0, height: 1600.0) + + for label in actualKeyLabels { + let rect = (label as NSString).boundingRect(with: boundingBox, options: .usesLineFragmentOrigin, attributes: textAttr) + maxKeyLabelWidth = max(rect.size.width, maxKeyLabelWidth) + } + + let rowSpacing = tableView.intercellSpacing.height + let stripWidth = ceil(maxKeyLabelWidth * 1.20) + let tableViewStartWidth = ceil(maxCandidateAttrStringWidth + scrollerWidth) + let windowWidth = max(stripWidth + 1.0 + tableViewStartWidth, tooltipWidth) + let windowHeight = CGFloat(keyLabelCount) * (rowHeight + rowSpacing) + tooltipHeight + + var frameRect = self.window?.frame ?? NSRect.zero + let topLeftPoint = NSMakePoint(frameRect.origin.x, frameRect.origin.y + frameRect.size.height) + + frameRect.size = NSMakeSize(windowWidth, windowHeight) + frameRect.origin = NSMakePoint(topLeftPoint.x, topLeftPoint.y - frameRect.size.height) + + keyLabelStripView.frame = NSRect(x: 0.0, y: 0, width: stripWidth, height: windowHeight - tooltipHeight) + scrollView.frame = NSRect(x: stripWidth + 1.0, y: 0, width: (windowWidth - stripWidth - 1), height: windowHeight - tooltipHeight) + tooltipView.frame = NSRect(x: tooltipPadding, y: windowHeight - tooltipHeight + tooltipPadding, width: windowWidth, height: tooltipHeight) + self.window?.setFrame(frameRect, display: false) + } +} diff --git a/Source/UI/NotifierUI/NotifierController.swift b/Source/UI/NotifierUI/NotifierController.swift new file mode 100644 index 0000000000000000000000000000000000000000..00823979dcac296cefa113a4d6716131f9d52894 --- /dev/null +++ b/Source/UI/NotifierUI/NotifierController.swift @@ -0,0 +1,172 @@ + +import Cocoa + +private protocol NotifierWindowDelegate: AnyObject { + func windowDidBecomeClicked(_ window: NotifierWindow) +} + +private class NotifierWindow: NSWindow { + weak var clickDelegate: NotifierWindowDelegate? + + override func mouseDown(with event: NSEvent) { + clickDelegate?.windowDidBecomeClicked(self) + } +} + +private let kWindowWidth: CGFloat = 160.0 +private let kWindowHeight: CGFloat = 80.0 + +public class NotifierController: NSWindowController, NotifierWindowDelegate { + private var messageTextField: NSTextField + + private var message: String = "" { + didSet { + let paraStyle = NSMutableParagraphStyle() + paraStyle.setParagraphStyle(NSParagraphStyle.default) + paraStyle.alignment = .center + let attr: [NSAttributedString.Key: AnyObject] = [ + .foregroundColor: foregroundColor, + .font: NSFont.systemFont(ofSize: NSFont.systemFontSize(for: .regular)), + .paragraphStyle: paraStyle + ] + let attrString = NSAttributedString(string: message, attributes: attr) + messageTextField.attributedStringValue = attrString + let width = window?.frame.width ?? kWindowWidth + let rect = attrString.boundingRect(with: NSSize(width: width, height: 1600), options: .usesLineFragmentOrigin) + let height = rect.height + let x = messageTextField.frame.origin.x + let y = ((window?.frame.height ?? kWindowHeight) - height) / 2 + let newFrame = NSRect(x: x, y: y, width: width, height: height) + messageTextField.frame = newFrame + } + } + private var shouldStay: Bool = false + private var backgroundColor: NSColor = .black { + didSet { + self.window?.backgroundColor = backgroundColor + self.messageTextField.backgroundColor = backgroundColor + } + } + private var foregroundColor: NSColor = .white { + didSet { + self.messageTextField.textColor = foregroundColor + } + } + private var waitTimer: Timer? + private var fadeTimer: Timer? + + private static var instanceCount = 0 + private static var lastLocation = NSPoint.zero + + @objc public static func notify(message: String, stay: Bool = false) { + let controller = NotifierController() + controller.message = message + controller.shouldStay = stay + controller.show() + } + + private static func increaseInstanceCount() { + instanceCount += 1 + } + + private static func decreaseInstanceCount() { + instanceCount -= 1 + if instanceCount < 0 { + instanceCount = 0 + } + } + + private init() { + let screenRect = NSScreen.main?.visibleFrame ?? NSRect.zero + let contentRect = NSRect(x: 0, y: 0, width: kWindowWidth, height: kWindowHeight) + var windowRect = contentRect + windowRect.origin.x = screenRect.maxX - windowRect.width - 10 + windowRect.origin.y = screenRect.maxY - windowRect.height - 10 + let styleMask: NSWindow.StyleMask = [.borderless] + let panel = NotifierWindow(contentRect: windowRect, styleMask: styleMask, backing: .buffered, defer: false) + panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel)) + panel.hasShadow = true + panel.backgroundColor = backgroundColor + + messageTextField = NSTextField() + messageTextField.frame = contentRect + messageTextField.isEditable = false + messageTextField.isSelectable = false + messageTextField.isBezeled = false + messageTextField.textColor = foregroundColor + messageTextField.drawsBackground = true + messageTextField.backgroundColor = backgroundColor + messageTextField.font = .systemFont(ofSize: NSFont.systemFontSize(for: .small)) + panel.contentView?.addSubview(messageTextField) + + super.init(window: panel) + + panel.clickDelegate = self + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func show() { + func setStartLocation() { + if NotifierController.instanceCount == 0 { + return + } + let lastLocation = NotifierController.lastLocation + let screenRect = NSScreen.main?.visibleFrame ?? NSRect.zero + var windowRect = self.window?.frame ?? NSRect.zero + windowRect.origin.x = lastLocation.x + windowRect.origin.y = lastLocation.y - 10 - windowRect.height + + if windowRect.origin.y < screenRect.minY { + return + } + + self.window?.setFrame(windowRect, display: true) + } + + func moveIn() { + let afterRect = self.window?.frame ?? NSRect.zero + NotifierController.lastLocation = afterRect.origin + var beforeRect = afterRect + beforeRect.origin.y += 10 + window?.setFrame(beforeRect, display: true) + window?.orderFront(self) + window?.setFrame(afterRect, display: true, animate: true) + } + + setStartLocation() + moveIn() + NotifierController.increaseInstanceCount() + waitTimer = Timer.scheduledTimer(timeInterval: shouldStay ? 5 : 1, target: self, selector: #selector(fadeOut), userInfo: nil, repeats: false) + } + + @objc private func doFadeOut(_ timer: Timer) { + let opacity = self.window?.alphaValue ?? 0 + if opacity <= 0 { + self.close() + } else { + self.window?.alphaValue = opacity - 0.2 + } + } + + @objc private func fadeOut() { + waitTimer?.invalidate() + waitTimer = nil + NotifierController.decreaseInstanceCount() + fadeTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(doFadeOut(_:)), userInfo: nil, repeats: true) + } + + public override func close() { + waitTimer?.invalidate() + waitTimer = nil + fadeTimer?.invalidate() + fadeTimer = nil + super.close() + } + + fileprivate func windowDidBecomeClicked(_ window: NotifierWindow) { + self.fadeOut() + } +} diff --git a/Source/UI/TooltipUI/TooltipController.swift b/Source/UI/TooltipUI/TooltipController.swift new file mode 100644 index 0000000000000000000000000000000000000000..19715b52860e3613de501d4beb4dbfdee358431f --- /dev/null +++ b/Source/UI/TooltipUI/TooltipController.swift @@ -0,0 +1,101 @@ + +import Cocoa + +public class TooltipController: NSWindowController { + private let backgroundColor = NSColor(calibratedHue: 0.16, saturation: 0.22, brightness: 0.97, alpha: 1.0) + private var messageTextField: NSTextField + private var tooltip: String = "" { + didSet { + messageTextField.stringValue = tooltip + adjustSize() + } + } + + public init() { + let contentRect = NSRect(x: 128.0, y: 128.0, width: 300.0, height: 20.0) + let styleMask: NSWindow.StyleMask = [.borderless, .nonactivatingPanel] + let panel = NSPanel(contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false) + panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1) + panel.hasShadow = true + + messageTextField = NSTextField() + messageTextField.isEditable = false + messageTextField.isSelectable = false + messageTextField.isBezeled = false + messageTextField.textColor = .black + messageTextField.drawsBackground = true + messageTextField.backgroundColor = backgroundColor + messageTextField.font = .systemFont(ofSize: NSFont.systemFontSize(for: .small)) + panel.contentView?.addSubview(messageTextField) + + super.init(window: panel) + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc(showTooltip:atPoint:) + public func show(tooltip: String, at point: NSPoint) { + self.tooltip = tooltip + window?.orderFront(nil) + set(windowLocation: point) + } + + @objc + public func hide() { + window?.orderOut(nil) + } + + private func set(windowLocation windowTopLeftPoint: NSPoint) { + + var adjustedPoint = windowTopLeftPoint + adjustedPoint.y -= 5 + + var screenFrame = NSScreen.main?.visibleFrame ?? NSRect.zero + for screen in NSScreen.screens { + let frame = screen.visibleFrame + if windowTopLeftPoint.x >= frame.minX && + windowTopLeftPoint.x <= frame.maxX && + windowTopLeftPoint.y >= frame.minY && + windowTopLeftPoint.y <= frame.maxY { + screenFrame = frame + break + } + } + + let windowSize = window?.frame.size ?? NSSize.zero + + // bottom beneath the screen? + if adjustedPoint.y - windowSize.height < screenFrame.minY { + adjustedPoint.y = screenFrame.minY + windowSize.height + } + + // top over the screen? + if adjustedPoint.y >= screenFrame.maxY { + adjustedPoint.y = screenFrame.maxY - 1.0 + } + + // right + if adjustedPoint.x + windowSize.width >= screenFrame.maxX { + adjustedPoint.x = screenFrame.maxX - windowSize.width + } + + // left + if adjustedPoint.x < screenFrame.minX { + adjustedPoint.x = screenFrame.minX + } + + window?.setFrameTopLeftPoint(adjustedPoint) + + } + + private func adjustSize() { + let attrString = messageTextField.attributedStringValue; + var rect = attrString.boundingRect(with: NSSize(width: 1600.0, height: 1600.0), options: .usesLineFragmentOrigin) + rect.size.width += 10 + messageTextField.frame = rect + window?.setFrame(rect, display: true) + } + +} diff --git a/Source/UpdateNotificationController.h b/Source/UpdateNotificationController.h deleted file mode 100644 index 4392bee88a0b49fb8baeb89dd55747bb85dfc2db..0000000000000000000000000000000000000000 --- a/Source/UpdateNotificationController.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// UpdateNotificationController.h -// -// Copyright (c) 2011 The McBopomofo Project. -// -// Contributors: -// Mengjuei Hsieh (@mjhsieh) -// Weizhong Yang (@zonble) -// -// Based on the Syrup Project and the Formosana Library -// by Lukhnos Liu (@lukhnos). -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import - -@interface UpdateNotificationController : NSWindowController -{ - NSButton *_visitButton; - NSButton *_laterButton; - NSTextField *_infoTextField; - - NSURL *_siteURL; - NSString *_infoText; -} -- (IBAction)laterAction:(id)sender; -- (IBAction)visitAction:(id)sender; - -@property (assign, nonatomic) IBOutlet NSButton *visitButton; -@property (assign, nonatomic) IBOutlet NSButton *laterButton; -@property (assign, nonatomic) IBOutlet NSTextField *infoTextField; -@property (retain, nonatomic) NSURL *siteURL; -@property (retain, nonatomic) NSString *infoText; -@end diff --git a/Source/UpdateNotificationController.m b/Source/UpdateNotificationController.m deleted file mode 100644 index 766365928c59ee6866d18dc17b7491d506388654..0000000000000000000000000000000000000000 --- a/Source/UpdateNotificationController.m +++ /dev/null @@ -1,90 +0,0 @@ -// -// UpdateNotificationController.m -// -// Copyright (c) 2011 The McBopomofo Project. -// -// Contributors: -// Mengjuei Hsieh (@mjhsieh) -// Weizhong Yang (@zonble) -// -// Based on the Syrup Project and the Formosana Library -// by Lukhnos Liu (@lukhnos). -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import "UpdateNotificationController.h" - -@implementation UpdateNotificationController -@synthesize visitButton = _visitButton; -@synthesize laterButton = _laterButton; -@synthesize infoTextField = _infoTextField; -@synthesize siteURL = _siteURL; -@synthesize infoText = _infoText; - -- (id)initWithWindow:(NSWindow *)window -{ - self = [super initWithWindow:window]; - if (self) { - _infoText = @"Version info here"; - } - - return self; -} - -- (void)dealloc -{ - [_siteURL release]; - [_infoText release]; - [super dealloc]; -} - -- (void)awakeFromNib -{ - [[self window] setTitle:NSLocalizedString(@"New Version Available", @"")]; - [_visitButton setTitle:NSLocalizedString(@"Visit Website", @"")]; - [_laterButton setTitle:NSLocalizedString(@"Check Later", @"")]; - [_infoTextField setStringValue:_infoText]; - - [[self window] makeFirstResponder:_visitButton]; -} - -- (void)windowDidLoad -{ - [super windowDidLoad]; - - // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. -} - -- (IBAction)laterAction:(id)sender -{ - [[self window] performClose:self]; -} - -- (IBAction)visitAction:(id)sender -{ - if (_siteURL) { - [[NSWorkspace sharedWorkspace] openURL:_siteURL]; - } - [[self window] performClose:self]; -} -@end diff --git a/Source/WindowControllers/ctlAboutWindow.swift b/Source/WindowControllers/ctlAboutWindow.swift new file mode 100644 index 0000000000000000000000000000000000000000..267657a3439bd99206fcb8bca3d40647dc69aeb0 --- /dev/null +++ b/Source/WindowControllers/ctlAboutWindow.swift @@ -0,0 +1,35 @@ +/* + * AboutWindow.swift + * + * Copyright 2021-2022 vChewing Project (3-Clause BSD License). + * Derived from 2011-2022 OpenVanilla Project (MIT License). + * Some rights reserved. See "LICENSE.TXT" for details. + */ + +import Cocoa + +@objc(AboutWindow) class ctlAboutWindow: NSWindowController { + @IBOutlet weak var appVersionLabel: NSTextField! + @IBOutlet weak var appCopyrightLabel: NSTextField! + @IBOutlet var appEULAContent: NSTextView! + + override func windowDidLoad() { + super.windowDidLoad() + + window?.standardWindowButton(.closeButton)?.isHidden = true + window?.standardWindowButton(.miniaturizeButton)?.isHidden = true + window?.standardWindowButton(.zoomButton)?.isHidden = true + guard let installingVersion = Bundle.main.infoDictionary?[kCFBundleVersionKey as String] as? String, + let versionString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else { + return + } + if let copyrightLabel = Bundle.main.localizedInfoDictionary?["NSHumanReadableCopyright"] as? String { + appCopyrightLabel.stringValue = copyrightLabel + } + if let eulaContent = Bundle.main.localizedInfoDictionary?["CFEULAContent"] as? String { + appEULAContent.string = eulaContent + } + appVersionLabel.stringValue = String(format: "%@ Build %@", versionString, installingVersion) + } + +} diff --git a/Source/WindowControllers/ctlNonModalAlertWindow.swift b/Source/WindowControllers/ctlNonModalAlertWindow.swift new file mode 100644 index 0000000000000000000000000000000000000000..e3930d58e2942aa3b31bfe7c83cf525482fefd9c --- /dev/null +++ b/Source/WindowControllers/ctlNonModalAlertWindow.swift @@ -0,0 +1,100 @@ + +import Cocoa + +@objc protocol NonModalAlertWindowControllerDelegate: AnyObject { + func nonModalAlertWindowControllerDidConfirm(_ controller: NonModalAlertWindowController) + func nonModalAlertWindowControllerDidCancel(_ controller: NonModalAlertWindowController) +} + +class NonModalAlertWindowController: NSWindowController { + @objc(sharedInstance) + static let shared = NonModalAlertWindowController(windowNibName: "NonModalAlertWindowController") + + @IBOutlet weak var titleTextField: NSTextField! + @IBOutlet weak var contentTextField: NSTextField! + @IBOutlet weak var confirmButton: NSButton! + @IBOutlet weak var cancelButton: NSButton! + weak var delegate: NonModalAlertWindowControllerDelegate? + + @objc func show(title: String, content: String, confirmButtonTitle: String, cancelButtonTitle: String?, cancelAsDefault: Bool, delegate: NonModalAlertWindowControllerDelegate?) { + if window?.isVisible == true { + self.delegate?.nonModalAlertWindowControllerDidCancel(self) + } + + self.delegate = delegate + + var oldFrame = confirmButton.frame + confirmButton.title = confirmButtonTitle + confirmButton.sizeToFit() + + var newFrame = confirmButton.frame + newFrame.size.width = max(90, newFrame.size.width + 10) + newFrame.origin.x += oldFrame.size.width - newFrame.size.width + confirmButton.frame = newFrame + + if let cancelButtonTitle = cancelButtonTitle { + cancelButton.title = cancelButtonTitle + cancelButton.sizeToFit() + var adjustFrame = cancelButton.frame + adjustFrame.size.width = max(90, adjustFrame.size.width + 10) + adjustFrame.origin.x = newFrame.origin.x - adjustFrame.size.width + confirmButton.frame = adjustFrame + cancelButton.isHidden = false + } else { + cancelButton.isHidden = true + } + + cancelButton.nextKeyView = confirmButton + confirmButton.nextKeyView = cancelButton + + if cancelButtonTitle != nil { + if cancelAsDefault { + window?.defaultButtonCell = cancelButton.cell as? NSButtonCell + } else { + cancelButton.keyEquivalent = " " + window?.defaultButtonCell = confirmButton.cell as? NSButtonCell + } + } else { + window?.defaultButtonCell = confirmButton.cell as? NSButtonCell + } + + titleTextField.stringValue = title + + oldFrame = contentTextField.frame + contentTextField.stringValue = content + + var infiniteHeightFrame = oldFrame + infiniteHeightFrame.size.width -= 4.0 + infiniteHeightFrame.size.height = 10240 + newFrame = (content as NSString).boundingRect(with: infiniteHeightFrame.size, options: [.usesLineFragmentOrigin], attributes: [.font: contentTextField.font!]) + newFrame.size.width = max(newFrame.size.width, oldFrame.size.width) + newFrame.size.height += 4.0 + newFrame.origin = oldFrame.origin + newFrame.origin.y -= (newFrame.size.height - oldFrame.size.height) + contentTextField.frame = newFrame + + var windowFrame = window?.frame ?? NSRect.zero + windowFrame.size.height += (newFrame.size.height - oldFrame.size.height) + window?.level = NSWindow.Level(Int(CGShieldingWindowLevel()) + 1) + window?.setFrame(windowFrame, display: true) + window?.center() + window?.makeKeyAndOrderFront(self) + NSApp.activate(ignoringOtherApps: true) + } + + @IBAction func confirmButtonAction(_ sender: Any) { + delegate?.nonModalAlertWindowControllerDidConfirm(self) + window?.orderOut(self) + } + + @IBAction func cancelButtonAction(_ sender: Any) { + cancel(sender) + } + + func cancel(_ sender: Any) { + delegate?.nonModalAlertWindowControllerDidCancel(self) + delegate = nil + window?.orderOut(self) + } + +} diff --git a/Source/WindowControllers/ctlPrefWindow.swift b/Source/WindowControllers/ctlPrefWindow.swift new file mode 100644 index 0000000000000000000000000000000000000000..271c9ceea7214bcd164c7ca919e633464918d92e --- /dev/null +++ b/Source/WindowControllers/ctlPrefWindow.swift @@ -0,0 +1,135 @@ + +import Cocoa +import Carbon + +// Please note that the class should be exposed as "ctlPrefWindow" +// in Objective-C in order to let IMK to see the same class name as +// the "InputMethodServerctlPrefWindowClass" in Info.plist. +@objc(ctlPrefWindow) class ctlPrefWindow: NSWindowController { + @IBOutlet weak var fontSizePopUpButton: NSPopUpButton! + @IBOutlet weak var basisKeyboardLayoutButton: NSPopUpButton! + @IBOutlet weak var selectionKeyComboBox: NSComboBox! + + override func awakeFromNib() { + let list = TISCreateInputSourceList(nil, true).takeRetainedValue() as! [TISInputSource] + var usKeyboardLayoutItem: NSMenuItem? = nil + var chosenItem: NSMenuItem? = nil + + basisKeyboardLayoutButton.menu?.removeAllItems() + + let basisKeyboardLayoutID = Preferences.basisKeyboardLayout + for source in list { + + func getString(_ key: CFString) -> String? { + if let ptr = TISGetInputSourceProperty(source, key) { + return String(Unmanaged.fromOpaque(ptr).takeUnretainedValue()) + } + return nil + } + + func getBool(_ key: CFString) -> Bool? { + if let ptr = TISGetInputSourceProperty(source, key) { + return Unmanaged.fromOpaque(ptr).takeUnretainedValue() == kCFBooleanTrue + } + return nil + } + + if let category = getString(kTISPropertyInputSourceCategory) { + if category != String(kTISCategoryKeyboardInputSource) { + continue + } + } else { + continue + } + + if let asciiCapable = getBool(kTISPropertyInputSourceIsASCIICapable) { + if !asciiCapable { + continue + } + } else { + continue + } + + if let sourceType = getString(kTISPropertyInputSourceType) { + if sourceType != String(kTISTypeKeyboardLayout) { + continue + } + } else { + continue + } + + guard let sourceID = getString(kTISPropertyInputSourceID), + let localizedName = getString(kTISPropertyLocalizedName) else { + continue + } + + let menuItem = NSMenuItem() + menuItem.title = localizedName + menuItem.representedObject = sourceID + + if let iconPtr = TISGetInputSourceProperty(source, kTISPropertyIconRef) { + let icon = IconRef(iconPtr) + let image = NSImage(iconRef: icon) + + func resize(_ image: NSImage) -> NSImage { + let newImage = NSImage(size: NSSize(width: 16, height: 16)) + newImage.lockFocus() + image.draw(in: NSRect(x: 0, y: 0, width: 16, height: 16)) + newImage.unlockFocus() + return newImage + } + + menuItem.image = resize(image) + } + + if sourceID == "com.apple.keylayout.US" { + usKeyboardLayoutItem = menuItem + } + if basisKeyboardLayoutID == sourceID { + chosenItem = menuItem + } + basisKeyboardLayoutButton.menu?.addItem(menuItem) + } + + basisKeyboardLayoutButton.select(chosenItem ?? usKeyboardLayoutItem) + selectionKeyComboBox.usesDataSource = false + selectionKeyComboBox.removeAllItems() + selectionKeyComboBox.addItems(withObjectValues: Preferences.suggestedCandidateKeys) + + var candidateSelectionKeys = Preferences.candidateKeys + if candidateSelectionKeys.isEmpty { + candidateSelectionKeys = Preferences.defaultCandidateKeys + } + + selectionKeyComboBox.stringValue = candidateSelectionKeys + } + + @IBAction func updateBasisKeyboardLayoutAction(_ sender: Any) { + if let sourceID = basisKeyboardLayoutButton.selectedItem?.representedObject as? String { + Preferences.basisKeyboardLayout = sourceID + } + } + + @IBAction func changeSelectionKeyAction(_ sender: Any) { + guard let keys = (sender as AnyObject).stringValue? + .trimmingCharacters(in: .whitespacesAndNewlines) + .lowercased() else { + return + } + do { + try Preferences.validate(candidateKeys: keys) + Preferences.candidateKeys = keys + } catch Preferences.CandidateKeyError.empty { + selectionKeyComboBox.stringValue = Preferences.candidateKeys + } catch { + if let window = window { + let alert = NSAlert(error: error) + alert.beginSheetModal(for: window) { response in + self.selectionKeyComboBox.stringValue = Preferences.candidateKeys + } + } + } + } + +} + diff --git a/Source/WindowNIBs/Base.lproj/MainMenu.xib b/Source/WindowNIBs/Base.lproj/MainMenu.xib new file mode 100644 index 0000000000000000000000000000000000000000..ccea8b9c16c3c79d990a412fb9a0a3eca45947f4 --- /dev/null +++ b/Source/WindowNIBs/Base.lproj/MainMenu.xib @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/WindowNIBs/Base.lproj/frmAboutWindow.xib b/Source/WindowNIBs/Base.lproj/frmAboutWindow.xib new file mode 100644 index 0000000000000000000000000000000000000000..c6030e049770de8e6b2b139f55922b3fe86e696b --- /dev/null +++ b/Source/WindowNIBs/Base.lproj/frmAboutWindow.xib @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + McBopomofo Engine by Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, et al. +vChewing macOS Development Reinforced by Hiraku Wang. +vChewing Phrase Database Maintained by Shiki Suen. + + + + + + + + + + + + + + + + + + + + + + + DISCLAIMER: The vChewing project, having no relationship of cooperation or affiliation with the OpenVanilla project, is not responsible for the phrase database shipped in the original McBopomofo project. Certain geopolitical and ideological contents, which are potentially harmful to the global spread of this software, have been removed from vChewing official phrase database. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/OVNonModalAlertWindowController.xib b/Source/WindowNIBs/Base.lproj/frmNonModalAlertWindow.xib similarity index 54% rename from Source/OVNonModalAlertWindowController.xib rename to Source/WindowNIBs/Base.lproj/frmNonModalAlertWindow.xib index 430b3b36a1001197b16642b4b32c8d176718f63b..9a161183e562f72b034c3150e14453192baf0065 100644 --- a/Source/OVNonModalAlertWindowController.xib +++ b/Source/WindowNIBs/Base.lproj/frmNonModalAlertWindow.xib @@ -1,12 +1,12 @@ - + - + - + @@ -17,18 +17,20 @@ - - + + - + - - - + - + + + - - - + + + + + - - - + + @@ -72,6 +79,22 @@ + + + + + + + + + + + + + + + + diff --git a/Source/WindowNIBs/Base.lproj/frmPreferences.xib b/Source/WindowNIBs/Base.lproj/frmPreferences.xib new file mode 100644 index 0000000000000000000000000000000000000000..5d62f70a7f5076d872c1e39498cb12e4c3639e08 --- /dev/null +++ b/Source/WindowNIBs/Base.lproj/frmPreferences.xib @@ -0,0 +1,656 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Item 1 + Item 2 + Item 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/WindowNIBs/en.lproj/NonModalAlertWindowController.strings b/Source/WindowNIBs/en.lproj/NonModalAlertWindowController.strings new file mode 100644 index 0000000000000000000000000000000000000000..731a867322e37d8e91cdb5074fe3750e3ef6340f --- /dev/null +++ b/Source/WindowNIBs/en.lproj/NonModalAlertWindowController.strings @@ -0,0 +1,12 @@ + +/* Class = "NSButtonCell"; title = "Button"; ObjectID = "6"; */ +"6.title" = "Button"; + +/* Class = "NSTextFieldCell"; title = "Lorem ipsum"; ObjectID = "40"; */ +"40.title" = "Lorem ipsum"; + +/* Class = "NSTextFieldCell"; title = "Lorem ipsum"; ObjectID = "60"; */ +"60.title" = "Lorem ipsum"; + +/* Class = "NSButtonCell"; title = "Button"; ObjectID = "73"; */ +"73.title" = "Button"; diff --git a/Source/WindowNIBs/en.lproj/frmAboutWindow.strings b/Source/WindowNIBs/en.lproj/frmAboutWindow.strings new file mode 100644 index 0000000000000000000000000000000000000000..abfa15688a985b8056a21fdf16c7daee0dc799e0 --- /dev/null +++ b/Source/WindowNIBs/en.lproj/frmAboutWindow.strings @@ -0,0 +1,27 @@ + +/* Class = "NSTextFieldCell"; title = "3-Clause BSD License:"; ObjectID = "lblLicense"; */ +"lblLicense.title" = "3-Clause BSD License:"; + +/* Class = "NSTextFieldCell"; title = "version"; ObjectID = "lblVersionString"; */ +// "lblVersionString.title" = "version"; + +/* Class = "NSWindow"; title = "About vChewing for macOS"; ObjectID = "ttlAboutWindow"; */ +"ttlAboutWindow.title" = "About vChewing for macOS"; + +/* Class = "NSTextFieldCell"; title = "Derived from OpenVanilla McBopopmofo Project."; ObjectID = "lblProjectDescription"; */ +"lblProjectDescription.title" = "Derived from OpenVanilla McBopopmofo Project."; + +/* Class = "NSButtonCell"; title = "OK"; ObjectID = "btnConfirm"; */ +"btnConfirm.title" = "OK"; + +/* Class = "NSTextFieldCell"; title = "vChewing for macOS"; ObjectID = "lblAppTitle"; */ +"lblAppTitle.title" = "vChewing for macOS"; + +/* Class = "NSTextFieldCell"; title = "DISCLAIMER: The vChewing project, having no relationship of cooperation or affiliation with the OpenVanilla project, is not responsible for the phrase database shipped in the original McBopomofo project. Certain geopolitical and ideological contents, which are potentially harmful to the global spread of this software, have been removed from vChewing official phrase database."; ObjectID = "lblDisclaimer"; */ +"lblDisclaimer.title" = "DISCLAIMER: The vChewing project, having no relationship of cooperation or affiliation with the OpenVanilla project, is not responsible for the phrase database shipped in the original McBopomofo project. Certain geopolitical and ideological contents, which are potentially harmful to the global spread of this software, have been removed from vChewing official phrase database."; + +/* Class = "NSTextFieldCell"; title = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project."; ObjectID = "lblCopyright"; */ +// "lblCopyright.title" = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project."; + +/* Class = "NSTextFieldCell"; title = "McBopomofo Engine by Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, et al.\nvChewing macOS Development Reinforced by Hiraku Wang.\nvChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "lblCredits"; */ +"lblCredits.title" = "McBopomofo Engine by Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, et al.\nvChewing macOS Development Reinforced by Hiraku Wang.\nvChewing Phrase Database Maintained by Shiki Suen."; diff --git a/Source/WindowNIBs/en.lproj/frmPreferences.strings b/Source/WindowNIBs/en.lproj/frmPreferences.strings new file mode 100644 index 0000000000000000000000000000000000000000..d6fbba8f24786347c981445e13b478c5eca03dc0 --- /dev/null +++ b/Source/WindowNIBs/en.lproj/frmPreferences.strings @@ -0,0 +1,189 @@ + +/* Class = "NSWindow"; title = "vChewing Preferences"; ObjectID = "1"; */ +"1.title" = "vChewing Preferences"; + +/* Class = "NSMenu"; title = "OtherViews"; ObjectID = "5"; */ +"5.title" = "OtherViews"; + +/* Class = "NSMenuItem"; title = "Standard"; ObjectID = "6"; */ +"6.title" = "Standard"; + +/* Class = "NSMenuItem"; title = "ETen"; ObjectID = "7"; */ +"7.title" = "ETen"; + +/* Class = "NSMenuItem"; title = "Hsu"; ObjectID = "8"; */ +"8.title" = "Hsu"; + +/* Class = "NSMenuItem"; title = "ETen26"; ObjectID = "9"; */ +"9.title" = "ETen26"; + +/* Class = "NSMenuItem"; title = "Hanyu Pinyin"; ObjectID = "10"; */ +"10.title" = "Hanyu Pinyin"; + +/* Class = "NSTextFieldCell"; title = "Bopomofo:"; ObjectID = "12"; */ +"12.title" = "Bopomofo:"; + +/* Class = "NSTextFieldCell"; title = "Choose the cursor position where you want to list possible candidates."; ObjectID = "14"; */ +"14.title" = "Choose the cursor position where you want to list possible candidates."; + +/* Class = "NSButtonCell"; title = "Cursor to the front of the phrase (like Matsushita Hanin IME)"; ObjectID = "16"; */ +"16.title" = "Cursor to the front of the phrase (like Matsushita Hanin IME)"; + +/* Class = "NSButtonCell"; title = "Cursor to the rear of the phrase (like MS New-Phonetic IME)"; ObjectID = "17"; */ +"17.title" = "Cursor to the rear of the phrase (like MS New-Phonetic IME)"; + +/* Class = "NSButtonCell"; title = "Radio"; ObjectID = "18"; */ +"18.title" = "Radio"; + +/* Class = "NSButtonCell"; title = "Radio"; ObjectID = "20"; */ +"20.title" = "Radio"; + +/* Class = "NSButtonCell"; title = "Horizontal"; ObjectID = "21"; */ +"21.title" = "Horizontal"; + +/* Class = "NSButtonCell"; title = "Vertical"; ObjectID = "22"; */ +"22.title" = "Vertical"; + +/* Class = "NSTextFieldCell"; title = "Candidate List Layout:"; ObjectID = "24"; */ +"24.title" = "Candidate List Layout:"; + +/* Class = "NSTextFieldCell"; title = "Candidate UI font size:"; ObjectID = "29"; */ +"29.title" = "Candidate UI font size:"; + +/* Class = "NSMenu"; title = "OtherViews"; ObjectID = "92"; */ +"92.title" = "OtherViews"; + +/* Class = "NSMenuItem"; title = "12"; ObjectID = "93"; */ +"93.title" = "12"; + +/* Class = "NSMenuItem"; title = "14"; ObjectID = "94"; */ +"94.title" = "14"; + +/* Class = "NSMenuItem"; title = "16"; ObjectID = "95"; */ +"95.title" = "16"; + +/* Class = "NSMenuItem"; title = "18"; ObjectID = "96"; */ +"96.title" = "18"; + +/* Class = "NSMenuItem"; title = "24"; ObjectID = "98"; */ +"98.title" = "24"; + +/* Class = "NSMenuItem"; title = "32"; ObjectID = "99"; */ +"99.title" = "32"; + +/* Class = "NSMenuItem"; title = "64"; ObjectID = "100"; */ +"100.title" = "64"; + +/* Class = "NSMenuItem"; title = "96"; ObjectID = "101"; */ +"101.title" = "96"; + +/* Class = "NSButtonCell"; title = "Enable SPACE key for calling candidate window"; ObjectID = "110"; */ +"110.title" = "Enable SPACE key for calling candidate window"; + +/* Class = "NSTextFieldCell"; title = "Alphanumeric:"; ObjectID = "126"; */ +"126.title" = "Alphanumeric:"; + +/* Class = "NSMenu"; title = "OtherViews"; ObjectID = "128"; */ +"128.title" = "OtherViews"; + +/* Class = "NSMenuItem"; title = "IBM"; ObjectID = "137"; */ +"137.title" = "IBM"; + +/* Class = "NSTabViewItem"; label = "Keyboard"; ObjectID = "1AW-xf-c2f"; */ +"1AW-xf-c2f.label" = "Keyboard"; + +/* Class = "NSBox"; title = "General Settings"; ObjectID = "2Y6-Am-WM1"; */ +"2Y6-Am-WM1.title" = "General Settings"; + +/* Class = "NSTextFieldCell"; title = "Choose which keys you prefer for selecting candidates."; ObjectID = "2pS-nv-te4"; */ +"2pS-nv-te4.title" = "Choose which keys you prefer for selecting candidates."; + +/* Class = "NSButtonCell"; title = "Stop farting (when typed phonetic combination is invalid, etc.)"; ObjectID = "62u-jY-BRh"; */ +"62u-jY-BRh.title" = "Stop farting (when typed phonetic combination is invalid, etc.)"; + +/* Class = "NSTextFieldCell"; title = "UI language setting:"; ObjectID = "9DS-Rc-TXq"; */ +"9DS-Rc-TXq.title" = "UI language setting:"; + +/* Class = "NSButtonCell"; title = "Emulating select-candidate-per-character mode"; ObjectID = "ArK-Vk-OoT"; */ +"ArK-Vk-OoT.title" = "Emulating select-candidate-per-character mode"; + +/* Class = "NSButtonCell"; title = "Auto-convert traditional Chinese glyphs to KangXi characters"; ObjectID = "BSK-bH-Gct"; */ +"BSK-bH-Gct.title" = "Auto-convert traditional Chinese glyphs to KangXi characters"; + +/* Class = "NSBox"; title = "Advanced Settings"; ObjectID = "E1l-m8-xgb"; */ +"E1l-m8-xgb.title" = "Advanced Settings"; + +/* Class = "NSMenuItem"; title = "English"; ObjectID = "FSG-lN-CJO"; */ +"FSG-lN-CJO.title" = "English"; + +/* Class = "NSTextFieldCell"; title = "Selection Keys:"; ObjectID = "FnD-oH-El5"; */ +"FnD-oH-El5.title" = "Selection Keys:"; + +/* Class = "NSMenuItem"; title = "Auto-Select"; ObjectID = "GlJ-Ns-9eE"; */ +"GlJ-Ns-9eE.title" = "Auto-Select"; + +/* Class = "NSButtonCell"; title = "Sort entries when reloading user phrases and excluded phrases list"; ObjectID = "Li3-Yg-SOC"; */ +"Li3-Yg-SOC.title" = "Sort entries when reloading user phrases and excluded phrases list"; + +/* Class = "NSTabViewItem"; label = "General"; ObjectID = "QUQ-oY-4Hc"; */ +"QUQ-oY-4Hc.label" = "General"; + +/* Class = "NSTextFieldCell"; title = "Choose your preferred keyboard layout."; ObjectID = "RQ6-MS-m4C"; */ +"RQ6-MS-m4C.title" = "Choose your preferred keyboard layout."; + +/* Class = "NSMenuItem"; title = "Traditional Chinese"; ObjectID = "TXr-FF-ehw"; */ +"TXr-FF-ehw.title" = "Traditional Chinese"; + +/* Class = "NSBox"; title = "Output Settings"; ObjectID = "Uyz-xL-TVN"; */ +"Uyz-xL-TVN.title" = "Output Settings"; + +/* Class = "NSButtonCell"; title = "Enable CNS11643 Support (2022-01-07)"; ObjectID = "W24-T4-cg0"; */ +"W24-T4-cg0.title" = "Enable CNS11643 Support (2022-01-07)"; + +/* Class = "NSBox"; title = "Keyboard Layout"; ObjectID = "Wvt-HE-LOv"; */ +"Wvt-HE-LOv.title" = "Keyboard Layout"; + +/* Class = "NSButtonCell"; title = "Check for updates automatically"; ObjectID = "Z9t-P0-BLF"; */ +"Z9t-P0-BLF.title" = "Check for updates automatically"; + +/* Class = "NSTextFieldCell"; title = "Change user interface language (will reboot the IME)."; ObjectID = "ZEv-Q2-mYL"; */ +"ZEv-Q2-mYL.title" = "Change user interface language (will reboot the IME)."; + +/* Class = "NSMenuItem"; title = "Simplified Chinese"; ObjectID = "akC-2g-ybz"; */ +"akC-2g-ybz.title" = "Simplified Chinese"; + +/* Class = "NSButtonCell"; title = "Use ESC key to clear entire input buffer"; ObjectID = "f2j-xD-4xK"; */ +"f2j-xD-4xK.title" = "Use ESC key to clear entire input buffer"; + +/* Class = "NSButtonCell"; title = "Automatically reload user data files if changes detected"; ObjectID = "f8i-69-zxm"; */ +"f8i-69-zxm.title" = "Automatically reload user data files if changes detected"; + +/* Class = "NSTextFieldCell"; title = "Change UI font size of candidate window for a better visual clarity."; ObjectID = "iRg-wx-Nx2"; */ +"iRg-wx-Nx2.title" = "Change UI font size of candidate window for a better visual clarity."; + +/* Class = "NSTextFieldCell"; title = "Define your preferred action when user data files reload."; ObjectID = "j48-5a-cEs"; */ +"j48-5a-cEs.title" = "Define your preferred action when user data files reload."; + +/* Class = "NSComboBoxCell"; jQC-12-UuK.ibShadowedObjectValues[0] = "Item 1"; ObjectID = "jQC-12-UuK"; */ +"jQC-12-UuK.ibShadowedObjectValues[0]" = "Item 1"; + +/* Class = "NSComboBoxCell"; jQC-12-UuK.ibShadowedObjectValues[1] = "Item 2"; ObjectID = "jQC-12-UuK"; */ +"jQC-12-UuK.ibShadowedObjectValues[1]" = "Item 2"; + +/* Class = "NSComboBoxCell"; jQC-12-UuK.ibShadowedObjectValues[2] = "Item 3"; ObjectID = "jQC-12-UuK"; */ +"jQC-12-UuK.ibShadowedObjectValues[2]" = "Item 3"; + +/* Class = "NSButtonCell"; title = "Sort entries when reloading the phrase replacement map"; ObjectID = "o60-vW-i1B"; */ +"o60-vW-i1B.title" = "Sort entries when reloading the phrase replacement map"; + +/* Class = "NSMenuItem"; title = "Japanese"; ObjectID = "rVQ-Hx-cGi"; */ +"rVQ-Hx-cGi.title" = "Japanese"; + +/* Class = "NSBox"; title = "Dictionary Settings"; ObjectID = "s4r-ji-vbr"; */ +"s4r-ji-vbr.title" = "Dictionary Settings"; + +/* Class = "NSTextFieldCell"; title = "Choose your preferred layout of the candidate window."; ObjectID = "xC5-yV-1W1"; */ +"xC5-yV-1W1.title" = "Choose your preferred layout of the candidate window."; + +/* Class = "NSTabViewItem"; label = "Advanced"; ObjectID = "xrE-8T-WKO"; */ +"xrE-8T-WKO.label" = "Advanced"; diff --git a/Source/en.lproj/InfoPlist.strings b/Source/en.lproj/InfoPlist.strings deleted file mode 100644 index 889f77494ab0c12e6f7986a2cbc5bfb2c36ee9e7..0000000000000000000000000000000000000000 --- a/Source/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,6 +0,0 @@ -CFBundleName = "McBopomofo"; -CFBundleDisplayName = "McBopomofo"; -NSHumanReadableCopyright = "Copyright © 2011-2021 Mengjuei Hsieh et al.\nAll Rights Reserved."; -"org.openvanilla.inputmethod.McBopomofo.Bopomofo" = "Bopomofo"; -"org.openvanilla.inputmethod.McBopomofo.PlainBopomofo" = "Plain Bopomofo"; - diff --git a/Source/en.lproj/Localizable.strings b/Source/en.lproj/Localizable.strings deleted file mode 100644 index 4fdc110c53ffb5447b5b5a2554322eff8941fa66..0000000000000000000000000000000000000000 --- a/Source/en.lproj/Localizable.strings +++ /dev/null @@ -1,52 +0,0 @@ -/* No comment provided by engineer. */ -"About McBopomofo…" = "About McBopomofo…"; - -/* No comment provided by engineer. */ -"Clear Learning Dictionary (%ju Items)" = "Clear Learning Dictionary (%ju Items)"; - -/* No comment provided by engineer. */ -"Dump Learning Data to Console" = "Dump Learning Data to Console"; - -/* No comment provided by engineer. */ -"Enable Selection Learning" = "Enable Selection Learning"; - -/* No comment provided by engineer. */ -"McBopomofo Preferences" = "McBopomofo Preferences"; - -/* No comment provided by engineer. */ -"Check Later" = "Check Later"; - -/* No comment provided by engineer. */ -"Check for Updates…" = "Check for Updates…"; - -/* No comment provided by engineer. */ -"Check for Update Completed" = "Check for Update Completed"; - -/* No comment provided by engineer. */ -"You are already using the latest version of McBopomofo." = "You are already using the latest version of McBopomofo."; - -/* No comment provided by engineer. */ -"Update Check Failed" = "Update Check Failed"; - -/* No comment provided by engineer. */ -"There may be no internet connection or the server failed to respond.\n\nError message: %@" = "There may be no internet connection or the server failed to respond.\n\nError message: %@"; - -/* No comment provided by engineer. */ -"OK" = "OK"; - -/* No comment provided by engineer. */ -"Dismiss" = "Dismiss"; - -/* No comment provided by engineer. */ -"New Version Available" = "New Version Available"; - -/* No comment provided by engineer. */ -"Not Now" = "Not Now"; - -/* No comment provided by engineer. */ -"Visit Website" = "Visit Website"; - -/* No comment provided by engineer. */ -"You're currently using McBopomofo %@ (%@), a new version %@ (%@) is now available. Do you want to visit McBopomofo's website to download the version?%@" = "You're currently using McBopomofo %@ (%@), a new version %@ (%@) is now available. Do you want to visit McBopomofo's website to download the version?%@"; - -"Chinese Conversion" = "Convert to Simplified Chinese"; diff --git a/Source/main.m b/Source/main.m deleted file mode 100644 index bca49bd0f0c7ab59be91b3a11f22614ed0d50a0a..0000000000000000000000000000000000000000 --- a/Source/main.m +++ /dev/null @@ -1,127 +0,0 @@ -// -// main.m -// -// Copyright (c) 2011 The McBopomofo Project. -// -// Contributors: -// Mengjuei Hsieh (@mjhsieh) -// Weizhong Yang (@zonble) -// -// Based on the Syrup Project and the Formosana Library -// by Lukhnos Liu (@lukhnos). -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// - -#import -#import "OVInputSourceHelper.h" - -static NSString *const kConnectionName = @"McBopomofo_1_Connection"; - -int main(int argc, char *argv[]) -{ - @autoreleasepool { - - // register and enable the input source (along with all its input modes) - if (argc > 1 && !strcmp(argv[1], "install")) { - NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; - NSURL *bundleURL = nil; - if ([[NSBundle mainBundle] respondsToSelector:@selector(bundleURL)]) { - // For Mac OS X 10.6+ - bundleURL = [[NSBundle mainBundle] bundleURL]; - } - else { - // For Mac OS X 10.5 - bundleURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; - } - - TISInputSourceRef inputSource = [OVInputSourceHelper inputSourceForInputSourceID:bundleID]; - - // if this IME name is not found in the list of available IMEs - if (!inputSource) { - NSLog(@"Registering input source %@ at %@.", bundleID, [bundleURL absoluteString]); - // then register - BOOL status = [OVInputSourceHelper registerInputSource:bundleURL]; - - if (!status) { - NSLog(@"Fatal error: Cannot register input source %@ at %@.", bundleID, [bundleURL absoluteString]); - return -1; - } - - inputSource = [OVInputSourceHelper inputSourceForInputSourceID:bundleID]; - // if it still doesn't register successfully, bail. - if (!inputSource) { - NSLog(@"Fatal error: Cannot find input source %@ after registration.", bundleID); - return -1; - } - } - - // if it's not enabled, just enabled it - if (inputSource && ![OVInputSourceHelper inputSourceEnabled:inputSource]) { - NSLog(@"Enabling input source %@ at %@.", bundleID, [bundleURL absoluteString]); - BOOL status = [OVInputSourceHelper enableInputSource:inputSource]; - - if (!status) { - NSLog(@"Fatal error: Cannot enable input source %@.", bundleID); - return -1; - } - if (![OVInputSourceHelper inputSourceEnabled:inputSource]){ - NSLog(@"Fatal error: Cannot enable input source %@.", bundleID); - return -1; - } - } - - if (argc > 2 && !strcmp(argv[2], "--all")) { - BOOL enabled = [OVInputSourceHelper enableAllInputModesForInputSourceBundleID:bundleID]; - if (enabled) { - NSLog(@"All input sources enabled for %@", bundleID); - } - else { - NSLog(@"Cannot enable all input sources for %@, but this is ignored", bundleID); - } - } - - return 0; - } - - NSString *mainNibName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"NSMainNibFile"]; - if (!mainNibName) { - NSLog(@"Fatal error: NSMainNibFile key not defined in Info.plist."); - return -1; - } - - BOOL loadResult = [[NSBundle mainBundle] loadNibNamed:mainNibName owner:[NSApplication sharedApplication] topLevelObjects:NULL]; - if (!loadResult) { - NSLog(@"Fatal error: Cannot load %@.", mainNibName); - return -1; - } - - IMKServer *server = [[IMKServer alloc] initWithName:kConnectionName bundleIdentifier:[[NSBundle mainBundle] bundleIdentifier]]; - if (!server) { - NSLog(@"Fatal error: Cannot initialize input method server with connection %@.", kConnectionName); - return -1; - } - - [[NSApplication sharedApplication] run]; - } - return 0; -} diff --git a/Source/zh-Hant.lproj/InfoPlist.strings b/Source/zh-Hant.lproj/InfoPlist.strings deleted file mode 100644 index a3286784628999d0911e7ce4e086732fc1372bb4..0000000000000000000000000000000000000000 --- a/Source/zh-Hant.lproj/InfoPlist.strings +++ /dev/null @@ -1,5 +0,0 @@ -CFBundleName = "小麥注音"; -CFBundleDisplayName = "小麥注音"; -NSHumanReadableCopyright = "Copyright © 2011-2021 Mengjuei Hsieh et al.\nAll Rights Reserved."; -"org.openvanilla.inputmethod.McBopomofo.Bopomofo" = "小麥注音"; -"org.openvanilla.inputmethod.McBopomofo.PlainBopomofo" = "傳統注音"; diff --git a/Source/zh-Hant.lproj/Localizable.strings b/Source/zh-Hant.lproj/Localizable.strings deleted file mode 100644 index e49af52709fef46f98b1e29b23d40a4f9bf5ba13..0000000000000000000000000000000000000000 --- a/Source/zh-Hant.lproj/Localizable.strings +++ /dev/null @@ -1,52 +0,0 @@ -/* No comment provided by engineer. */ -"About McBopomofo…" = "關於小麥注音…"; - -/* No comment provided by engineer. */ -"Clear Learning Dictionary (%ju Items)" = "清除學習辭典 (%ju 個項目)"; - -/* No comment provided by engineer. */ -"Dump Learning Data to Console" = "將學習辭典內容輸出到 Console 上"; - -/* No comment provided by engineer. */ -"Enable Selection Learning" = "使用自動學習功能"; - -/* No comment provided by engineer. */ -"McBopomofo Preferences" = "小麥注音偏好設定"; - -/* No comment provided by engineer. */ -"Check Later" = "晚點再通知我"; - -/* No comment provided by engineer. */ -"Check for Updates…" = "檢查是否有新版…"; - -/* No comment provided by engineer. */ -"Check for Update Completed" = "新版檢查完畢"; - -/* No comment provided by engineer. */ -"You are already using the latest version of McBopomofo." = "目前使用的已經是最新版本。"; - -/* No comment provided by engineer. */ -"Update Check Failed" = "無法檢查新版"; - -/* No comment provided by engineer. */ -"There may be no internet connection or the server failed to respond.\n\nError message: %@" = "網路連線失敗,或是伺服器沒有回應。\n\n錯誤說明:%@"; - -/* No comment provided by engineer. */ -"OK" = "好"; - -/* No comment provided by engineer. */ -"Dismiss" = "關閉本視窗"; - -/* No comment provided by engineer. */ -"New Version Available" = "有新版可下載"; - -/* No comment provided by engineer. */ -"Not Now" = "以後再說"; - -/* No comment provided by engineer. */ -"Visit Website" = "前往網站"; - -/* No comment provided by engineer. */ -"You're currently using McBopomofo %@ (%@), a new version %@ (%@) is now available. Do you want to visit McBopomofo's website to download the version?%@" = "目前使用的小麥注音版本是 %1$@ (%2$@),網路上有更新版本 %3$@ (%4$@) 可供下載。是否要前往小麥注音網站下載新版來安裝?%5$@"; - -"Chinese Conversion" = "輸出簡體中文"; diff --git a/Source/zh-Hant.lproj/MainMenu.xib b/Source/zh-Hant.lproj/MainMenu.xib deleted file mode 100644 index 5f7bcf12fb539b5f24a1bd5f0e2a0ed8a42d3224..0000000000000000000000000000000000000000 --- a/Source/zh-Hant.lproj/MainMenu.xib +++ /dev/null @@ -1,295 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Source/zh-Hant.lproj/preferences.xib b/Source/zh-Hant.lproj/preferences.xib deleted file mode 100644 index 17e6e2c9a3dc74c041306e97f3393db43489e34f..0000000000000000000000000000000000000000 --- a/Source/zh-Hant.lproj/preferences.xib +++ /dev/null @@ -1,237 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Item 1 - Item 2 - Item 3 - - - - - - - - - - - - - - - - - - - - - - diff --git a/Update-Info.plist b/Update-Info.plist new file mode 100644 index 0000000000000000000000000000000000000000..15d51d0dee122da4a8f760377e7257470e4af0af --- /dev/null +++ b/Update-Info.plist @@ -0,0 +1,14 @@ + + + + + UpdateInfoEndpoint + https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist + UpdateInfoSite + https://gitee.com/vchewing/vChewing-macOS + CFBundleVersion + 893 + CFBundleShortVersionString + 1.2.0 + + diff --git a/McBopomofo.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj similarity index 41% rename from McBopomofo.xcodeproj/project.pbxproj rename to vChewing.xcodeproj/project.pbxproj index 64f7b808cba533f2ff5d0cbc9a6304dbe86c4584..7d54eb33d074e8f155186c6b5d682822c6cddb0c 100644 --- a/McBopomofo.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -7,48 +7,71 @@ objects = { /* Begin PBXBuildFile section */ - 6A0421A815FEF3F50061ED63 /* FastLM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A0421A615FEF3F50061ED63 /* FastLM.cpp */; }; - 6A0D4EA715FC0D2D00ABF4B3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A0D4EA615FC0D2D00ABF4B3 /* Cocoa.framework */; }; - 6A0D4ED015FC0D6400ABF4B3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EC415FC0D6400ABF4B3 /* AppDelegate.m */; }; - 6A0D4ED215FC0D6400ABF4B3 /* InputMethodController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EC715FC0D6400ABF4B3 /* InputMethodController.mm */; }; - 6A0D4ED315FC0D6400ABF4B3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EC815FC0D6400ABF4B3 /* main.m */; }; - 6A0D4ED415FC0D6400ABF4B3 /* OVInputSourceHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4ECA15FC0D6400ABF4B3 /* OVInputSourceHelper.m */; }; - 6A0D4ED515FC0D6400ABF4B3 /* PreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4ECC15FC0D6400ABF4B3 /* PreferencesWindowController.m */; }; - 6A0D4EFE15FC0DA600ABF4B3 /* VTCandidateController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EDA15FC0DA600ABF4B3 /* VTCandidateController.m */; }; - 6A0D4EFF15FC0DA600ABF4B3 /* VTHorizontalCandidateController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EDC15FC0DA600ABF4B3 /* VTHorizontalCandidateController.m */; }; - 6A0D4F0015FC0DA600ABF4B3 /* VTHorizontalCandidateView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EDE15FC0DA600ABF4B3 /* VTHorizontalCandidateView.m */; }; - 6A0D4F0115FC0DA600ABF4B3 /* VTVerticalCandidateController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EE015FC0DA600ABF4B3 /* VTVerticalCandidateController.m */; }; - 6A0D4F0215FC0DA600ABF4B3 /* VTVerticalCandidateTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EE215FC0DA600ABF4B3 /* VTVerticalCandidateTableView.m */; }; - 6A0D4F0315FC0DA600ABF4B3 /* VTVerticalKeyLabelStripView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EE415FC0DA600ABF4B3 /* VTVerticalKeyLabelStripView.m */; }; - 6A0D4F0815FC0DA600ABF4B3 /* Bopomofo.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4EEF15FC0DA600ABF4B3 /* Bopomofo.tiff */; }; - 6A0D4F0915FC0DA600ABF4B3 /* Bopomofo@2x.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4EF015FC0DA600ABF4B3 /* Bopomofo@2x.tiff */; }; + 5B2DB16F27AF6891006D874E /* data-chs.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5B2DB16D27AF6891006D874E /* data-chs.txt */; }; + 5B2DB17027AF6891006D874E /* data-cht.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5B2DB16E27AF6891006D874E /* data-cht.txt */; }; + 5B62A31727AE73A700A19448 /* unzip.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A30927AE73A700A19448 /* unzip.m */; }; + 5B62A31827AE73A700A19448 /* zip.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A30A27AE73A700A19448 /* zip.m */; }; + 5B62A31927AE73A700A19448 /* ioapi.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A30B27AE73A700A19448 /* ioapi.m */; }; + 5B62A31A27AE73A700A19448 /* mztools.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A30C27AE73A700A19448 /* mztools.m */; }; + 5B62A31B27AE73A700A19448 /* SSZipArchive.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A31327AE73A700A19448 /* SSZipArchive.m */; }; + 5B62A31C27AE73A700A19448 /* AWFileHash.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A31627AE73A700A19448 /* AWFileHash.m */; }; + 5B62A32927AE77D100A19448 /* FSEventStreamHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */; }; + 5B62A32E27AE78B000A19448 /* CNSLM.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A32A27AE78B000A19448 /* CNSLM.mm */; }; + 5B62A32F27AE78B000A19448 /* CoreLM.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A32D27AE78B000A19448 /* CoreLM.mm */; }; + 5B62A33227AE792F00A19448 /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */; }; + 5B62A33427AE793F00A19448 /* OpenCCBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33327AE793F00A19448 /* OpenCCBridge.swift */; }; + 5B62A33627AE795800A19448 /* PreferencesModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33527AE795800A19448 /* PreferencesModule.swift */; }; + 5B62A33827AE79CD00A19448 /* NSStringUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33727AE79CD00A19448 /* NSStringUtils.swift */; }; + 5B62A33D27AE7CC100A19448 /* ctlAboutWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */; }; + 5B62A34627AE7CD900A19448 /* HorizontalCandidateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33F27AE7CD900A19448 /* HorizontalCandidateController.swift */; }; + 5B62A34727AE7CD900A19448 /* CandidateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34027AE7CD900A19448 /* CandidateController.swift */; }; + 5B62A34827AE7CD900A19448 /* VerticalCandidateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34127AE7CD900A19448 /* VerticalCandidateController.swift */; }; + 5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34327AE7CD900A19448 /* TooltipController.swift */; }; + 5B62A34A27AE7CD900A19448 /* NotifierController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34527AE7CD900A19448 /* NotifierController.swift */; }; + 5B62A35227AE822400A19448 /* OpenCC in Frameworks */ = {isa = PBXBuildFile; productRef = 5B62A35127AE822400A19448 /* OpenCC */; }; + 5B62A35327AE89C400A19448 /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */; }; + 5BBBB75F27AED54C0023B93A /* Beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB75D27AED54C0023B93A /* Beep.m4a */; }; + 5BBBB76027AED54C0023B93A /* Fart.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB75E27AED54C0023B93A /* Fart.m4a */; }; + 5BBBB76B27AED5DB0023B93A /* frmNonModalAlertWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB76527AED5DB0023B93A /* frmNonModalAlertWindow.xib */; }; + 5BBBB76C27AED5DB0023B93A /* frmPreferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB76727AED5DB0023B93A /* frmPreferences.xib */; }; + 5BBBB76D27AED5DB0023B93A /* frmAboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB76927AED5DB0023B93A /* frmAboutWindow.xib */; }; + 5BBBB77327AED70B0023B93A /* MenuIcon-TCVIM@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB76F27AED70B0023B93A /* MenuIcon-TCVIM@2x.png */; }; + 5BBBB77427AED70B0023B93A /* MenuIcon-SCVIM@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB77027AED70B0023B93A /* MenuIcon-SCVIM@2x.png */; }; + 5BBBB77527AED70B0023B93A /* MenuIcon-SCVIM.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB77127AED70B0023B93A /* MenuIcon-SCVIM.png */; }; + 5BBBB77627AED70B0023B93A /* MenuIcon-TCVIM.png in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB77227AED70B0023B93A /* MenuIcon-TCVIM.png */; }; + 5BBBB77A27AEDC690023B93A /* clsSFX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BBBB77927AEDC690023B93A /* clsSFX.swift */; }; 6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F2015FC0EB100ABF4B3 /* Mandarin.cpp */; }; - 6A0D4F5315FC0EE100ABF4B3 /* preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4F4E15FC0EE100ABF4B3 /* preferences.xib */; }; - 6A0D4F5715FC0EF900ABF4B3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4F4815FC0EE100ABF4B3 /* InfoPlist.strings */; }; - 6A0D4F5815FC0EF900ABF4B3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4F4A15FC0EE100ABF4B3 /* Localizable.strings */; }; 6A187E2616004C5900466B2E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6A187E2816004C5900466B2E /* MainMenu.xib */; }; 6A225A1F23679F2600F685C6 /* NotarizedArchives in Resources */ = {isa = PBXBuildFile; fileRef = 6A225A1E23679F2600F685C6 /* NotarizedArchives */; }; - 6A225A232367A1D700F685C6 /* ArchiveUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A225A222367A1D700F685C6 /* ArchiveUtil.m */; }; 6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A2E40F5253A69DA00D1AE1D /* Images.xcassets */; }; 6A2E40F9253A6AA000D1AE1D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A2E40F5253A69DA00D1AE1D /* Images.xcassets */; }; - 6A38BC1515FC117A00A8A51F /* data.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6A38BBF615FC117A00A8A51F /* data.txt */; }; - 6A38BC2815FC158A00A8A51F /* InputMethodKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A38BC2715FC158A00A8A51F /* InputMethodKit.framework */; }; - 6AB3620D274CA50700AC7547 /* OVInputSourceHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4ECA15FC0D6400ABF4B3 /* OVInputSourceHelper.m */; }; - 6ACA41CD15FC1D7500935EF6 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A0D4EA615FC0D2D00ABF4B3 /* Cocoa.framework */; }; - 6ACA41F915FC1D9000935EF6 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6ACA41E915FC1D9000935EF6 /* AppDelegate.m */; }; 6ACA41FA15FC1D9000935EF6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6ACA41EA15FC1D9000935EF6 /* InfoPlist.strings */; }; - 6ACA41FB15FC1D9000935EF6 /* License.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 6ACA41EC15FC1D9000935EF6 /* License.rtf */; }; 6ACA41FC15FC1D9000935EF6 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6ACA41EE15FC1D9000935EF6 /* Localizable.strings */; }; 6ACA41FD15FC1D9000935EF6 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6ACA41F015FC1D9000935EF6 /* MainMenu.xib */; }; - 6ACA41FF15FC1D9000935EF6 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6ACA41F415FC1D9000935EF6 /* main.m */; }; - 6ACA420215FC1E5200935EF6 /* McBopomofo.app in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4EA215FC0D2D00ABF4B3 /* McBopomofo.app */; }; - 6AD7CBC815FE555000691B5B /* data-plain-bpmf.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6AD7CBC715FE555000691B5B /* data-plain-bpmf.txt */; }; - 6AE210B215FC63CC003659FE /* PlainBopomofo.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 6AE210B015FC63CC003659FE /* PlainBopomofo.tiff */; }; - 6AE210B315FC63CC003659FE /* PlainBopomofo@2x.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 6AE210B115FC63CC003659FE /* PlainBopomofo@2x.tiff */; }; - 6AFF97F2253B299E007F1C49 /* OVNonModalAlertWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6AFF97F0253B299E007F1C49 /* OVNonModalAlertWindowController.xib */; }; - 6AFF97F3253B299E007F1C49 /* OVNonModalAlertWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AFF97F1253B299E007F1C49 /* OVNonModalAlertWindowController.m */; }; - D427A9C125ED28CC005D43E0 /* OpenCCBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */; }; - D48550A325EBE689006A204C /* OpenCC in Frameworks */ = {isa = PBXBuildFile; productRef = D48550A225EBE689006A204C /* OpenCC */; }; + 6ACA420215FC1E5200935EF6 /* vChewing.app in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */; }; + 6ACC3D3F27914F2400F1B140 /* KeyValueBlobReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6ACC3D3E27914F2400F1B140 /* KeyValueBlobReader.cpp */; }; + 6ACC3D442793701600F1B140 /* ParselessPhraseDB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6ACC3D402793701600F1B140 /* ParselessPhraseDB.cpp */; }; + 6ACC3D452793701600F1B140 /* ParselessLM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6ACC3D422793701600F1B140 /* ParselessLM.cpp */; }; + D41355D8278D74B5005E5CBD /* mgrLangModel.mm in Sources */ = {isa = PBXBuildFile; fileRef = D41355D7278D7409005E5CBD /* mgrLangModel.mm */; }; + D41355DB278E6D17005E5CBD /* vChewingLM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D41355D9278E6D17005E5CBD /* vChewingLM.cpp */; }; + D41355DE278EA3ED005E5CBD /* UserPhrasesLM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D41355DC278EA3ED005E5CBD /* UserPhrasesLM.cpp */; }; + D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427F76B278CA1BA004A2160 /* AppDelegate.swift */; }; + D44FB74A2791B829003C80A6 /* VXHanConvert in Frameworks */ = {isa = PBXBuildFile; productRef = D44FB7492791B829003C80A6 /* VXHanConvert */; }; + D44FB74D2792189A003C80A6 /* PhraseReplacementMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D44FB74B2792189A003C80A6 /* PhraseReplacementMap.cpp */; }; + D456576E279E4F7B00DF6BC9 /* KeyHandlerInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = D456576D279E4F7B00DF6BC9 /* KeyHandlerInput.swift */; }; + D461B792279DAC010070E734 /* InputState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D461B791279DAC010070E734 /* InputState.swift */; }; + D47B92C027972AD100458394 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47B92BF27972AC800458394 /* main.swift */; }; + D47D73AC27A6CAE600255A50 /* AssociatedPhrases.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D47D73AA27A6CAE600255A50 /* AssociatedPhrases.cpp */; }; + D47F7DCE278BFB57002F9DD7 /* ctlPrefWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCD278BFB57002F9DD7 /* ctlPrefWindow.swift */; }; + D47F7DD0278C0897002F9DD7 /* ctlNonModalAlertWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCF278C0897002F9DD7 /* ctlNonModalAlertWindow.swift */; }; + D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */; }; + D4A13D5A27A59F0B003BE359 /* ctlInputMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A13D5927A59D5C003BE359 /* ctlInputMethod.swift */; }; + D4E33D8A27A838CF006DB1CF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D4E33D8827A838CF006DB1CF /* Localizable.strings */; }; + D4E33D8F27A838F0006DB1CF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D4E33D8D27A838F0006DB1CF /* InfoPlist.strings */; }; + D4E569DC27A34D0E00AC2CEF /* KeyHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = D4E569DB27A34CC100AC2CEF /* KeyHandler.mm */; }; + D4F0BBDF279AF1AF0071253C /* ArchiveUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F0BBDE279AF1AF0071253C /* ArchiveUtil.swift */; }; + D4F0BBE1279AF8B30071253C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F0BBE0279AF8B30071253C /* AppDelegate.swift */; }; + D4F0BBE4279B08900071253C /* Chronosphere.m in Sources */ = {isa = PBXBuildFile; fileRef = D4F0BBE3279B08900071253C /* Chronosphere.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -64,42 +87,59 @@ containerPortal = 6A0D4E9415FC0CFA00ABF4B3 /* Project object */; proxyType = 1; remoteGlobalIDString = 6A0D4EA115FC0D2D00ABF4B3; - remoteInfo = McBopomofo; + remoteInfo = vChewing; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 6A0421A615FEF3F50061ED63 /* FastLM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FastLM.cpp; sourceTree = ""; }; - 6A0421A715FEF3F50061ED63 /* FastLM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FastLM.h; sourceTree = ""; }; - 6A0D4EA215FC0D2D00ABF4B3 /* McBopomofo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = McBopomofo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 6A0D4EA615FC0D2D00ABF4B3 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; - 6A0D4EA915FC0D2D00ABF4B3 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; - 6A0D4EAB15FC0D2D00ABF4B3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 6A0D4EC315FC0D6400ABF4B3 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 6A0D4EC415FC0D6400ABF4B3 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 6A0D4EC615FC0D6400ABF4B3 /* InputMethodController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputMethodController.h; sourceTree = ""; }; - 6A0D4EC715FC0D6400ABF4B3 /* InputMethodController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InputMethodController.mm; sourceTree = ""; }; - 6A0D4EC815FC0D6400ABF4B3 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 6A0D4EC915FC0D6400ABF4B3 /* OVInputSourceHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVInputSourceHelper.h; sourceTree = ""; }; - 6A0D4ECA15FC0D6400ABF4B3 /* OVInputSourceHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OVInputSourceHelper.m; sourceTree = ""; }; - 6A0D4ECB15FC0D6400ABF4B3 /* PreferencesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesWindowController.h; sourceTree = ""; }; - 6A0D4ECC15FC0D6400ABF4B3 /* PreferencesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesWindowController.m; sourceTree = ""; }; - 6A0D4ED915FC0DA600ABF4B3 /* VTCandidateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTCandidateController.h; sourceTree = ""; }; - 6A0D4EDA15FC0DA600ABF4B3 /* VTCandidateController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VTCandidateController.m; sourceTree = ""; }; - 6A0D4EDB15FC0DA600ABF4B3 /* VTHorizontalCandidateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTHorizontalCandidateController.h; sourceTree = ""; }; - 6A0D4EDC15FC0DA600ABF4B3 /* VTHorizontalCandidateController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VTHorizontalCandidateController.m; sourceTree = ""; }; - 6A0D4EDD15FC0DA600ABF4B3 /* VTHorizontalCandidateView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTHorizontalCandidateView.h; sourceTree = ""; }; - 6A0D4EDE15FC0DA600ABF4B3 /* VTHorizontalCandidateView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VTHorizontalCandidateView.m; sourceTree = ""; }; - 6A0D4EDF15FC0DA600ABF4B3 /* VTVerticalCandidateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTVerticalCandidateController.h; sourceTree = ""; }; - 6A0D4EE015FC0DA600ABF4B3 /* VTVerticalCandidateController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VTVerticalCandidateController.m; sourceTree = ""; }; - 6A0D4EE115FC0DA600ABF4B3 /* VTVerticalCandidateTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTVerticalCandidateTableView.h; sourceTree = ""; }; - 6A0D4EE215FC0DA600ABF4B3 /* VTVerticalCandidateTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VTVerticalCandidateTableView.m; sourceTree = ""; }; - 6A0D4EE315FC0DA600ABF4B3 /* VTVerticalKeyLabelStripView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTVerticalKeyLabelStripView.h; sourceTree = ""; }; - 6A0D4EE415FC0DA600ABF4B3 /* VTVerticalKeyLabelStripView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VTVerticalKeyLabelStripView.m; sourceTree = ""; }; - 6A0D4EEF15FC0DA600ABF4B3 /* Bopomofo.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Bopomofo.tiff; sourceTree = ""; }; - 6A0D4EF015FC0DA600ABF4B3 /* Bopomofo@2x.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "Bopomofo@2x.tiff"; sourceTree = ""; }; - 6A0D4EF515FC0DA600ABF4B3 /* McBopomofo-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "McBopomofo-Info.plist"; sourceTree = ""; }; - 6A0D4EF615FC0DA600ABF4B3 /* McBopomofo-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "McBopomofo-Prefix.pch"; sourceTree = ""; }; + 5B0CF37F27AD476E00784B08 /* SwiftyOpenCC */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = SwiftyOpenCC; path = Packages/SwiftyOpenCC; sourceTree = ""; }; + 5B2DB16D27AF6891006D874E /* data-chs.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "data-chs.txt"; path = "Data/data-chs.txt"; sourceTree = ""; }; + 5B2DB16E27AF6891006D874E /* data-cht.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "data-cht.txt"; path = "Data/data-cht.txt"; sourceTree = ""; }; + 5B2DB17127AF8771006D874E /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = Data/Makefile; sourceTree = ""; }; + 5B62A30927AE73A700A19448 /* unzip.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = unzip.m; sourceTree = ""; }; + 5B62A30A27AE73A700A19448 /* zip.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = zip.m; sourceTree = ""; }; + 5B62A30B27AE73A700A19448 /* ioapi.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ioapi.m; sourceTree = ""; }; + 5B62A30C27AE73A700A19448 /* mztools.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = mztools.m; sourceTree = ""; }; + 5B62A30D27AE73A700A19448 /* crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypt.h; sourceTree = ""; }; + 5B62A30E27AE73A700A19448 /* zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zip.h; sourceTree = ""; }; + 5B62A30F27AE73A700A19448 /* unzip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unzip.h; sourceTree = ""; }; + 5B62A31027AE73A700A19448 /* mztools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mztools.h; sourceTree = ""; }; + 5B62A31127AE73A700A19448 /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = ""; }; + 5B62A31227AE73A700A19448 /* SSZipArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSZipArchive.h; sourceTree = ""; }; + 5B62A31327AE73A700A19448 /* SSZipArchive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSZipArchive.m; sourceTree = ""; }; + 5B62A31527AE73A700A19448 /* AWFileHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AWFileHash.h; sourceTree = ""; }; + 5B62A31627AE73A700A19448 /* AWFileHash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AWFileHash.m; sourceTree = ""; }; + 5B62A32627AE77BB00A19448 /* LMConsolidator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LMConsolidator.h; sourceTree = ""; }; + 5B62A32727AE77BB00A19448 /* LMConsolidator.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LMConsolidator.mm; sourceTree = ""; }; + 5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FSEventStreamHelper.swift; sourceTree = ""; }; + 5B62A32A27AE78B000A19448 /* CNSLM.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CNSLM.mm; sourceTree = ""; }; + 5B62A32B27AE78B000A19448 /* CNSLM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNSLM.h; sourceTree = ""; }; + 5B62A32C27AE78B000A19448 /* CoreLM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CoreLM.h; sourceTree = ""; }; + 5B62A32D27AE78B000A19448 /* CoreLM.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreLM.mm; sourceTree = ""; }; + 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputSourceHelper.swift; sourceTree = ""; }; + 5B62A33327AE793F00A19448 /* OpenCCBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenCCBridge.swift; sourceTree = ""; }; + 5B62A33527AE795800A19448 /* PreferencesModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesModule.swift; sourceTree = ""; }; + 5B62A33727AE79CD00A19448 /* NSStringUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSStringUtils.swift; sourceTree = ""; }; + 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlAboutWindow.swift; sourceTree = ""; }; + 5B62A33F27AE7CD900A19448 /* HorizontalCandidateController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalCandidateController.swift; sourceTree = ""; }; + 5B62A34027AE7CD900A19448 /* CandidateController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CandidateController.swift; sourceTree = ""; }; + 5B62A34127AE7CD900A19448 /* VerticalCandidateController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerticalCandidateController.swift; sourceTree = ""; }; + 5B62A34327AE7CD900A19448 /* TooltipController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TooltipController.swift; sourceTree = ""; }; + 5B62A34527AE7CD900A19448 /* NotifierController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotifierController.swift; sourceTree = ""; }; + 5BBBB75D27AED54C0023B93A /* Beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Beep.m4a; sourceTree = ""; }; + 5BBBB75E27AED54C0023B93A /* Fart.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Fart.m4a; sourceTree = ""; }; + 5BBBB76627AED5DB0023B93A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmNonModalAlertWindow.xib; sourceTree = ""; }; + 5BBBB76827AED5DB0023B93A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmPreferences.xib; sourceTree = ""; }; + 5BBBB76A27AED5DB0023B93A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmAboutWindow.xib; sourceTree = ""; }; + 5BBBB76F27AED70B0023B93A /* MenuIcon-TCVIM@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MenuIcon-TCVIM@2x.png"; sourceTree = ""; }; + 5BBBB77027AED70B0023B93A /* MenuIcon-SCVIM@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MenuIcon-SCVIM@2x.png"; sourceTree = ""; }; + 5BBBB77127AED70B0023B93A /* MenuIcon-SCVIM.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MenuIcon-SCVIM.png"; sourceTree = ""; }; + 5BBBB77227AED70B0023B93A /* MenuIcon-TCVIM.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MenuIcon-TCVIM.png"; sourceTree = ""; }; + 5BBBB77727AEDB290023B93A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = ""; }; + 5BBBB77927AEDC690023B93A /* clsSFX.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = clsSFX.swift; sourceTree = ""; }; + 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = vChewing.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 6A0D4EF515FC0DA600ABF4B3 /* IME-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "IME-Info.plist"; sourceTree = ""; }; + 6A0D4EF615FC0DA600ABF4B3 /* vChewing-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "vChewing-Prefix.pch"; sourceTree = ""; }; 6A0D4F1415FC0EB100ABF4B3 /* Bigram.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bigram.h; sourceTree = ""; }; 6A0D4F1515FC0EB100ABF4B3 /* BlockReadingBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockReadingBuilder.h; sourceTree = ""; }; 6A0D4F1615FC0EB100ABF4B3 /* Gramambular.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Gramambular.h; sourceTree = ""; }; @@ -113,104 +153,52 @@ 6A0D4F1E15FC0EB100ABF4B3 /* Walker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Walker.h; sourceTree = ""; }; 6A0D4F2015FC0EB100ABF4B3 /* Mandarin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mandarin.cpp; sourceTree = ""; }; 6A0D4F2115FC0EB100ABF4B3 /* Mandarin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mandarin.h; sourceTree = ""; }; - 6A0D4F2315FC0EB100ABF4B3 /* OpenVanilla.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVanilla.h; sourceTree = ""; }; - 6A0D4F2415FC0EB100ABF4B3 /* OVAroundFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVAroundFilter.h; sourceTree = ""; }; - 6A0D4F2515FC0EB100ABF4B3 /* OVBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVBase.h; sourceTree = ""; }; - 6A0D4F2615FC0EB100ABF4B3 /* OVBenchmark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVBenchmark.h; sourceTree = ""; }; - 6A0D4F2715FC0EB100ABF4B3 /* OVCandidateService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVCandidateService.h; sourceTree = ""; }; - 6A0D4F2815FC0EB100ABF4B3 /* OVCINDatabaseService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVCINDatabaseService.h; sourceTree = ""; }; - 6A0D4F2915FC0EB100ABF4B3 /* OVCINDataTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVCINDataTable.h; sourceTree = ""; }; - 6A0D4F2A15FC0EB100ABF4B3 /* OVCINToSQLiteConvertor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVCINToSQLiteConvertor.h; sourceTree = ""; }; - 6A0D4F2B15FC0EB100ABF4B3 /* OVDatabaseService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVDatabaseService.h; sourceTree = ""; }; - 6A0D4F2C15FC0EB100ABF4B3 /* OVDateTimeHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVDateTimeHelper.h; sourceTree = ""; }; - 6A0D4F2D15FC0EB100ABF4B3 /* OVEncodingService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVEncodingService.h; sourceTree = ""; }; - 6A0D4F2E15FC0EB100ABF4B3 /* OVEventHandlingContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVEventHandlingContext.h; sourceTree = ""; }; - 6A0D4F2F15FC0EB100ABF4B3 /* OVException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVException.h; sourceTree = ""; }; - 6A0D4F3015FC0EB100ABF4B3 /* OVFileHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVFileHelper.h; sourceTree = ""; }; - 6A0D4F3115FC0EB100ABF4B3 /* OVFrameworkInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVFrameworkInfo.h; sourceTree = ""; }; - 6A0D4F3215FC0EB100ABF4B3 /* OVInputMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVInputMethod.h; sourceTree = ""; }; - 6A0D4F3315FC0EB100ABF4B3 /* OVKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVKey.h; sourceTree = ""; }; - 6A0D4F3415FC0EB100ABF4B3 /* OVKeyPreprocessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVKeyPreprocessor.h; sourceTree = ""; }; - 6A0D4F3515FC0EB100ABF4B3 /* OVKeyValueMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVKeyValueMap.h; sourceTree = ""; }; - 6A0D4F3615FC0EB100ABF4B3 /* OVLoaderBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVLoaderBase.h; sourceTree = ""; }; - 6A0D4F3715FC0EB100ABF4B3 /* OVLoaderService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVLoaderService.h; sourceTree = ""; }; - 6A0D4F3815FC0EB100ABF4B3 /* OVLocalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVLocalization.h; sourceTree = ""; }; - 6A0D4F3915FC0EB100ABF4B3 /* OVModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVModule.h; sourceTree = ""; }; - 6A0D4F3A15FC0EB100ABF4B3 /* OVModulePackage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVModulePackage.h; sourceTree = ""; }; - 6A0D4F3B15FC0EB100ABF4B3 /* OVOutputFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVOutputFilter.h; sourceTree = ""; }; - 6A0D4F3C15FC0EB100ABF4B3 /* OVPathInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVPathInfo.h; sourceTree = ""; }; - 6A0D4F3D15FC0EB100ABF4B3 /* OVSQLiteDatabaseService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVSQLiteDatabaseService.h; sourceTree = ""; }; - 6A0D4F3E15FC0EB100ABF4B3 /* OVSQLiteWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVSQLiteWrapper.h; sourceTree = ""; }; - 6A0D4F3F15FC0EB100ABF4B3 /* OVStringHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVStringHelper.h; sourceTree = ""; }; - 6A0D4F4015FC0EB100ABF4B3 /* OVTextBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVTextBuffer.h; sourceTree = ""; }; - 6A0D4F4115FC0EB100ABF4B3 /* OVUTF8Helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVUTF8Helper.h; sourceTree = ""; }; - 6A0D4F4215FC0EB100ABF4B3 /* OVWildcard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVWildcard.h; sourceTree = ""; }; - 6A0D4F4915FC0EE100ABF4B3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Source/en.lproj/InfoPlist.strings; sourceTree = ""; }; - 6A0D4F4B15FC0EE100ABF4B3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Source/en.lproj/Localizable.strings; sourceTree = ""; }; - 6A0D4F5415FC0EF900ABF4B3 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "Source/zh-Hant.lproj/InfoPlist.strings"; sourceTree = ""; }; - 6A0D4F5515FC0EF900ABF4B3 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "Source/zh-Hant.lproj/Localizable.strings"; sourceTree = ""; }; - 6A0D4F5615FC0EF900ABF4B3 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "zh-Hant"; path = "Source/zh-Hant.lproj/preferences.xib"; sourceTree = ""; }; 6A15B32421A51F2300B92CD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 6A15B32521A51F2300B92CD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 6A15B32721A51F2300B92CD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Source/Base.lproj/preferences.xib; sourceTree = ""; }; - 6A187E2916004C7300466B2E /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "zh-Hant"; path = "zh-Hant.lproj/MainMenu.xib"; sourceTree = ""; }; 6A225A1E23679F2600F685C6 /* NotarizedArchives */ = {isa = PBXFileReference; lastKnownFileType = folder; path = NotarizedArchives; sourceTree = ""; }; - 6A225A212367A1D700F685C6 /* ArchiveUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchiveUtil.h; sourceTree = ""; }; - 6A225A222367A1D700F685C6 /* ArchiveUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArchiveUtil.m; sourceTree = ""; }; 6A2E40F5253A69DA00D1AE1D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - 6A38BBDE15FC117A00A8A51F /* 4_in_5.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = 4_in_5.txt; sourceTree = ""; }; - 6A38BBDF15FC117A00A8A51F /* 4_in_6.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = 4_in_6.txt; sourceTree = ""; }; - 6A38BBE015FC117A00A8A51F /* 5_in_6.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = 5_in_6.txt; sourceTree = ""; }; - 6A38BBE215FC117A00A8A51F /* BIG5toUTF8.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = BIG5toUTF8.pl; sourceTree = ""; }; - 6A38BBE315FC117A00A8A51F /* build4wlist.bash */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = build4wlist.bash; sourceTree = ""; }; - 6A38BBE415FC117A00A8A51F /* buildFreq.bash */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = buildFreq.bash; sourceTree = ""; }; - 6A38BBE515FC117A00A8A51F /* cook.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = cook.py; sourceTree = ""; }; - 6A38BBE615FC117A00A8A51F /* cook.rb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.ruby; path = cook.rb; sourceTree = ""; }; - 6A38BBE715FC117A00A8A51F /* count.bash */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = count.bash; sourceTree = ""; }; - 6A38BBE815FC117A00A8A51F /* count.occurrence.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = count.occurrence.c; sourceTree = ""; }; - 6A38BBE915FC117A00A8A51F /* count.occurrence.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = count.occurrence.pl; sourceTree = ""; }; - 6A38BBEA15FC117A00A8A51F /* count.occurrence.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = count.occurrence.py; sourceTree = ""; }; - 6A38BBEB15FC117A00A8A51F /* countphrase.bash */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = countphrase.bash; sourceTree = ""; }; - 6A38BBEC15FC117A00A8A51F /* filter.bash */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = filter.bash; sourceTree = ""; }; - 6A38BBED15FC117A00A8A51F /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; - 6A38BBEE15FC117A00A8A51F /* randomShuffle.bash */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = randomShuffle.bash; sourceTree = ""; }; - 6A38BBEF15FC117A00A8A51F /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; - 6A38BBF015FC117A00A8A51F /* typocorrection.bash */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = typocorrection.bash; sourceTree = ""; }; - 6A38BBF115FC117A00A8A51F /* utf8length.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = utf8length.pl; sourceTree = ""; }; - 6A38BBF215FC117A00A8A51F /* blacklist.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = blacklist.txt; sourceTree = ""; }; - 6A38BBF315FC117A00A8A51F /* BPMFBase.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BPMFBase.txt; sourceTree = ""; }; - 6A38BBF415FC117A00A8A51F /* BPMFMappings.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BPMFMappings.txt; sourceTree = ""; }; - 6A38BBF515FC117A00A8A51F /* BPMFPunctuations.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BPMFPunctuations.txt; sourceTree = ""; }; - 6A38BBF615FC117A00A8A51F /* data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = data.txt; sourceTree = ""; }; - 6A38BBF715FC117A00A8A51F /* heterophony1.list */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = heterophony1.list; sourceTree = ""; }; - 6A38BBF815FC117A00A8A51F /* heterophony2.list */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = heterophony2.list; sourceTree = ""; }; - 6A38BBF915FC117A00A8A51F /* heterophony3.list */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = heterophony3.list; sourceTree = ""; }; - 6A38BBFA15FC117A00A8A51F /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; - 6A38BBFB15FC117A00A8A51F /* phrase.occ */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = phrase.occ; sourceTree = ""; }; - 6A38BBFC15FC117A00A8A51F /* PhraseFreq.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PhraseFreq.txt; sourceTree = ""; }; - 6A38BBFD15FC117A00A8A51F /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; - 6A38BC2715FC158A00A8A51F /* InputMethodKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = InputMethodKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/InputMethodKit.framework; sourceTree = DEVELOPER_DIR; }; - 6ACA41CB15FC1D7500935EF6 /* McBopomofoInstaller.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = McBopomofoInstaller.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 6ACA41E815FC1D9000935EF6 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Source/Installer/AppDelegate.h; sourceTree = SOURCE_ROOT; }; - 6ACA41E915FC1D9000935EF6 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Source/Installer/AppDelegate.m; sourceTree = SOURCE_ROOT; }; + 6A93050C279877FF00D370DA /* vChewingInstaller-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "vChewingInstaller-Bridging-Header.h"; sourceTree = ""; }; + 6ACA41CB15FC1D7500935EF6 /* vChewingInstaller.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = vChewingInstaller.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6ACA41EB15FC1D9000935EF6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 6ACA41ED15FC1D9000935EF6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/License.rtf; sourceTree = ""; }; 6ACA41EF15FC1D9000935EF6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - 6ACA41F215FC1D9000935EF6 /* Installer-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Installer-Info.plist"; path = "Source/Installer/Installer-Info.plist"; sourceTree = SOURCE_ROOT; }; - 6ACA41F315FC1D9000935EF6 /* Installer-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Installer-Prefix.pch"; path = "Source/Installer/Installer-Prefix.pch"; sourceTree = SOURCE_ROOT; }; - 6ACA41F415FC1D9000935EF6 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Source/Installer/main.m; sourceTree = SOURCE_ROOT; }; - 6ACA41F515FC1D9000935EF6 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = ""; }; - 6ACA41F615FC1D9000935EF6 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = "zh-Hant"; path = "zh-Hant.lproj/License.rtf"; sourceTree = ""; }; - 6ACA41F715FC1D9000935EF6 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = ""; }; - 6ACA41F815FC1D9000935EF6 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "zh-Hant"; path = "zh-Hant.lproj/MainMenu.xib"; sourceTree = ""; }; - 6AD7CBC715FE555000691B5B /* data-plain-bpmf.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "data-plain-bpmf.txt"; sourceTree = ""; }; - 6AE210B015FC63CC003659FE /* PlainBopomofo.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = PlainBopomofo.tiff; sourceTree = ""; }; - 6AE210B115FC63CC003659FE /* PlainBopomofo@2x.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "PlainBopomofo@2x.tiff"; sourceTree = ""; }; - 6AFF97EF253B299E007F1C49 /* OVNonModalAlertWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVNonModalAlertWindowController.h; sourceTree = ""; }; - 6AFF97F0253B299E007F1C49 /* OVNonModalAlertWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OVNonModalAlertWindowController.xib; sourceTree = ""; }; - 6AFF97F1253B299E007F1C49 /* OVNonModalAlertWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OVNonModalAlertWindowController.m; sourceTree = ""; }; - D427A9BF25ED28CC005D43E0 /* McBopomofo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "McBopomofo-Bridging-Header.h"; sourceTree = ""; }; - D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenCCBridge.swift; sourceTree = ""; }; + 6ACA41F215FC1D9000935EF6 /* Installer-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Installer-Info.plist"; path = "Installer/Installer-Info.plist"; sourceTree = SOURCE_ROOT; }; + 6ACA41F315FC1D9000935EF6 /* Installer-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Installer-Prefix.pch"; path = "Installer/Installer-Prefix.pch"; sourceTree = SOURCE_ROOT; }; + 6ACC3D3C27914AAB00F1B140 /* KeyValueBlobReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyValueBlobReader.h; sourceTree = ""; }; + 6ACC3D3E27914F2400F1B140 /* KeyValueBlobReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyValueBlobReader.cpp; sourceTree = ""; }; + 6ACC3D402793701600F1B140 /* ParselessPhraseDB.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParselessPhraseDB.cpp; sourceTree = ""; }; + 6ACC3D412793701600F1B140 /* ParselessPhraseDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParselessPhraseDB.h; sourceTree = ""; }; + 6ACC3D422793701600F1B140 /* ParselessLM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParselessLM.cpp; sourceTree = ""; }; + 6ACC3D432793701600F1B140 /* ParselessLM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParselessLM.h; sourceTree = ""; }; + D41355D6278D7409005E5CBD /* mgrLangModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mgrLangModel.h; sourceTree = ""; }; + D41355D7278D7409005E5CBD /* mgrLangModel.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = mgrLangModel.mm; sourceTree = ""; }; + D41355D9278E6D17005E5CBD /* vChewingLM.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = vChewingLM.cpp; sourceTree = ""; }; + D41355DA278E6D17005E5CBD /* vChewingLM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vChewingLM.h; sourceTree = ""; }; + D41355DC278EA3ED005E5CBD /* UserPhrasesLM.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UserPhrasesLM.cpp; sourceTree = ""; }; + D41355DD278EA3ED005E5CBD /* UserPhrasesLM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UserPhrasesLM.h; sourceTree = ""; }; + D427A9BF25ED28CC005D43E0 /* vChewing-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "vChewing-Bridging-Header.h"; sourceTree = ""; }; + D427F76B278CA1BA004A2160 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + D44FB7482791B346003C80A6 /* VXHanConvert */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = VXHanConvert; path = Packages/VXHanConvert; sourceTree = ""; }; + D44FB74B2792189A003C80A6 /* PhraseReplacementMap.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PhraseReplacementMap.cpp; sourceTree = ""; }; + D44FB74C2792189A003C80A6 /* PhraseReplacementMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PhraseReplacementMap.h; sourceTree = ""; }; + D456576D279E4F7B00DF6BC9 /* KeyHandlerInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyHandlerInput.swift; sourceTree = ""; }; + D461B791279DAC010070E734 /* InputState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputState.swift; sourceTree = ""; }; + D47B92BF27972AC800458394 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + D47D73AA27A6CAE600255A50 /* AssociatedPhrases.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AssociatedPhrases.cpp; sourceTree = ""; }; + D47D73AB27A6CAE600255A50 /* AssociatedPhrases.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AssociatedPhrases.h; sourceTree = ""; }; + D47F7DCD278BFB57002F9DD7 /* ctlPrefWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlPrefWindow.swift; sourceTree = ""; }; + D47F7DCF278C0897002F9DD7 /* ctlNonModalAlertWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlNonModalAlertWindow.swift; sourceTree = ""; }; + D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserOverrideModel.h; sourceTree = ""; }; + D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserOverrideModel.cpp; sourceTree = ""; }; + D495583A27A5C6C4006ADE1C /* mgrLangModel_Privates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mgrLangModel_Privates.h; sourceTree = ""; }; + D4A13D5927A59D5C003BE359 /* ctlInputMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod.swift; sourceTree = ""; }; + D4E33D8927A838CF006DB1CF /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; + D4E33D8E27A838F0006DB1CF /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = ""; }; + D4E569DA27A34CC100AC2CEF /* KeyHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyHandler.h; sourceTree = ""; }; + D4E569DB27A34CC100AC2CEF /* KeyHandler.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyHandler.mm; sourceTree = ""; }; + D4F0BBDE279AF1AF0071253C /* ArchiveUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveUtil.swift; sourceTree = ""; }; + D4F0BBE0279AF8B30071253C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + D4F0BBE2279B08900071253C /* Chronosphere.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Chronosphere.h; sourceTree = ""; }; + D4F0BBE3279B08900071253C /* Chronosphere.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Chronosphere.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -218,9 +206,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 6A38BC2815FC158A00A8A51F /* InputMethodKit.framework in Frameworks */, - D48550A325EBE689006A204C /* OpenCC in Frameworks */, - 6A0D4EA715FC0D2D00ABF4B3 /* Cocoa.framework in Frameworks */, + 5B62A35227AE822400A19448 /* OpenCC in Frameworks */, + D44FB74A2791B829003C80A6 /* VXHanConvert in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -228,263 +215,387 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 6ACA41CD15FC1D7500935EF6 /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 6A0D4E9215FC0CFA00ABF4B3 = { + 5B62A30127AE732800A19448 /* 3rdParty */ = { isa = PBXGroup; children = ( - 6A0D4EC215FC0D3C00ABF4B3 /* Source */, - 6A0D4EA515FC0D2D00ABF4B3 /* Frameworks */, - 6A0D4EA315FC0D2D00ABF4B3 /* Products */, + 5B62A31427AE73A700A19448 /* AWFileHash */, + 5B62A30727AE73A700A19448 /* SSZipArchive */, + 5B62A30227AE733500A19448 /* OVMandarin */, ); + path = 3rdParty; sourceTree = ""; }; - 6A0D4EA315FC0D2D00ABF4B3 /* Products */ = { + 5B62A30227AE733500A19448 /* OVMandarin */ = { isa = PBXGroup; children = ( - 6A0D4EA215FC0D2D00ABF4B3 /* McBopomofo.app */, - 6ACA41CB15FC1D7500935EF6 /* McBopomofoInstaller.app */, + 6A0D4F2015FC0EB100ABF4B3 /* Mandarin.cpp */, + 6A0D4F2115FC0EB100ABF4B3 /* Mandarin.h */, ); - name = Products; + path = OVMandarin; sourceTree = ""; }; - 6A0D4EA515FC0D2D00ABF4B3 /* Frameworks */ = { + 5B62A30727AE73A700A19448 /* SSZipArchive */ = { isa = PBXGroup; children = ( - 6A0D4EA915FC0D2D00ABF4B3 /* AppKit.framework */, - 6A0D4EA615FC0D2D00ABF4B3 /* Cocoa.framework */, - 6A0D4EAB15FC0D2D00ABF4B3 /* Foundation.framework */, - 6A38BC2715FC158A00A8A51F /* InputMethodKit.framework */, + 5B62A30827AE73A700A19448 /* minizip */, + 5B62A31227AE73A700A19448 /* SSZipArchive.h */, + 5B62A31327AE73A700A19448 /* SSZipArchive.m */, ); - name = Frameworks; + path = SSZipArchive; sourceTree = ""; }; - 6A0D4EC215FC0D3C00ABF4B3 /* Source */ = { + 5B62A30827AE73A700A19448 /* minizip */ = { isa = PBXGroup; children = ( - 6A0D4ED815FC0DA600ABF4B3 /* CandidateUI */, - 6A38BBDD15FC115800A8A51F /* Data */, - 6A0D4F1215FC0EB100ABF4B3 /* Engine */, - 6ACA41E715FC1D9000935EF6 /* Installer */, - 6A0D4F4715FC0EB900ABF4B3 /* Resources */, - 6A0D4EC315FC0D6400ABF4B3 /* AppDelegate.h */, - 6A0D4EC415FC0D6400ABF4B3 /* AppDelegate.m */, - 6A0D4EC615FC0D6400ABF4B3 /* InputMethodController.h */, - 6A0D4EC715FC0D6400ABF4B3 /* InputMethodController.mm */, - 6A0D4EC815FC0D6400ABF4B3 /* main.m */, - 6A0D4EF615FC0DA600ABF4B3 /* McBopomofo-Prefix.pch */, - 6AFF97EF253B299E007F1C49 /* OVNonModalAlertWindowController.h */, - 6AFF97F1253B299E007F1C49 /* OVNonModalAlertWindowController.m */, - 6A0D4EC915FC0D6400ABF4B3 /* OVInputSourceHelper.h */, - 6A0D4ECA15FC0D6400ABF4B3 /* OVInputSourceHelper.m */, - 6A0D4ECB15FC0D6400ABF4B3 /* PreferencesWindowController.h */, - 6A0D4ECC15FC0D6400ABF4B3 /* PreferencesWindowController.m */, - D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */, - D427A9BF25ED28CC005D43E0 /* McBopomofo-Bridging-Header.h */, + 5B62A30927AE73A700A19448 /* unzip.m */, + 5B62A30A27AE73A700A19448 /* zip.m */, + 5B62A30B27AE73A700A19448 /* ioapi.m */, + 5B62A30C27AE73A700A19448 /* mztools.m */, + 5B62A30D27AE73A700A19448 /* crypt.h */, + 5B62A30E27AE73A700A19448 /* zip.h */, + 5B62A30F27AE73A700A19448 /* unzip.h */, + 5B62A31027AE73A700A19448 /* mztools.h */, + 5B62A31127AE73A700A19448 /* ioapi.h */, ); - path = Source; + path = minizip; sourceTree = ""; }; - 6A0D4ED815FC0DA600ABF4B3 /* CandidateUI */ = { + 5B62A31427AE73A700A19448 /* AWFileHash */ = { isa = PBXGroup; children = ( - 6A0D4ED915FC0DA600ABF4B3 /* VTCandidateController.h */, - 6A0D4EDA15FC0DA600ABF4B3 /* VTCandidateController.m */, - 6A0D4EDB15FC0DA600ABF4B3 /* VTHorizontalCandidateController.h */, - 6A0D4EDC15FC0DA600ABF4B3 /* VTHorizontalCandidateController.m */, - 6A0D4EDD15FC0DA600ABF4B3 /* VTHorizontalCandidateView.h */, - 6A0D4EDE15FC0DA600ABF4B3 /* VTHorizontalCandidateView.m */, - 6A0D4EDF15FC0DA600ABF4B3 /* VTVerticalCandidateController.h */, - 6A0D4EE015FC0DA600ABF4B3 /* VTVerticalCandidateController.m */, - 6A0D4EE115FC0DA600ABF4B3 /* VTVerticalCandidateTableView.h */, - 6A0D4EE215FC0DA600ABF4B3 /* VTVerticalCandidateTableView.m */, - 6A0D4EE315FC0DA600ABF4B3 /* VTVerticalKeyLabelStripView.h */, - 6A0D4EE415FC0DA600ABF4B3 /* VTVerticalKeyLabelStripView.m */, + 5B62A31527AE73A700A19448 /* AWFileHash.h */, + 5B62A31627AE73A700A19448 /* AWFileHash.m */, ); - path = CandidateUI; + path = AWFileHash; sourceTree = ""; }; - 6A0D4EEE15FC0DA600ABF4B3 /* Images */ = { + 5B62A31E27AE74E400A19448 /* SFX */ = { isa = PBXGroup; children = ( - 6A2E40F5253A69DA00D1AE1D /* Images.xcassets */, - 6A0D4EEF15FC0DA600ABF4B3 /* Bopomofo.tiff */, - 6A0D4EF015FC0DA600ABF4B3 /* Bopomofo@2x.tiff */, - 6AE210B015FC63CC003659FE /* PlainBopomofo.tiff */, - 6AE210B115FC63CC003659FE /* PlainBopomofo@2x.tiff */, + 5BBBB77927AEDC690023B93A /* clsSFX.swift */, ); - path = Images; + path = SFX; sourceTree = ""; }; - 6A0D4F1215FC0EB100ABF4B3 /* Engine */ = { + 5B62A31F27AE74E900A19448 /* ControllerModules */ = { isa = PBXGroup; children = ( - 6A0D4F1315FC0EB100ABF4B3 /* Gramambular */, - 6A0D4F1F15FC0EB100ABF4B3 /* Mandarin */, - 6A0D4F2215FC0EB100ABF4B3 /* OpenVanilla */, - 6A0421A615FEF3F50061ED63 /* FastLM.cpp */, - 6A0421A715FEF3F50061ED63 /* FastLM.h */, + D4E569DA27A34CC100AC2CEF /* KeyHandler.h */, + D4E569DB27A34CC100AC2CEF /* KeyHandler.mm */, + D456576D279E4F7B00DF6BC9 /* KeyHandlerInput.swift */, + 6ACC3D3E27914F2400F1B140 /* KeyValueBlobReader.cpp */, + 6ACC3D3C27914AAB00F1B140 /* KeyValueBlobReader.h */, + D461B791279DAC010070E734 /* InputState.swift */, + 5B62A33727AE79CD00A19448 /* NSStringUtils.swift */, ); - path = Engine; + path = ControllerModules; sourceTree = ""; }; - 6A0D4F1315FC0EB100ABF4B3 /* Gramambular */ = { + 5B62A32027AE752000A19448 /* Headers */ = { isa = PBXGroup; children = ( - 6A0D4F1415FC0EB100ABF4B3 /* Bigram.h */, - 6A0D4F1515FC0EB100ABF4B3 /* BlockReadingBuilder.h */, - 6A0D4F1615FC0EB100ABF4B3 /* Gramambular.h */, - 6A0D4F1715FC0EB100ABF4B3 /* Grid.h */, - 6A0D4F1815FC0EB100ABF4B3 /* KeyValuePair.h */, - 6A0D4F1915FC0EB100ABF4B3 /* LanguageModel.h */, - 6A0D4F1A15FC0EB100ABF4B3 /* Node.h */, - 6A0D4F1B15FC0EB100ABF4B3 /* NodeAnchor.h */, - 6A0D4F1C15FC0EB100ABF4B3 /* Span.h */, - 6A0D4F1D15FC0EB100ABF4B3 /* Unigram.h */, - 6A0D4F1E15FC0EB100ABF4B3 /* Walker.h */, + 6A0D4EF615FC0DA600ABF4B3 /* vChewing-Prefix.pch */, + D427A9BF25ED28CC005D43E0 /* vChewing-Bridging-Header.h */, ); - path = Gramambular; + path = Headers; sourceTree = ""; }; - 6A0D4F1F15FC0EB100ABF4B3 /* Mandarin */ = { + 5B62A32127AE755D00A19448 /* FileHandlers */ = { isa = PBXGroup; children = ( - 6A0D4F2015FC0EB100ABF4B3 /* Mandarin.cpp */, - 6A0D4F2115FC0EB100ABF4B3 /* Mandarin.h */, + 5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */, + 5B62A32627AE77BB00A19448 /* LMConsolidator.h */, + 5B62A32727AE77BB00A19448 /* LMConsolidator.mm */, + ); + path = FileHandlers; + sourceTree = ""; + }; + 5B62A32227AE756300A19448 /* IMEModules */ = { + isa = PBXGroup; + children = ( + D4A13D5927A59D5C003BE359 /* ctlInputMethod.swift */, + 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */, + 5B62A33327AE793F00A19448 /* OpenCCBridge.swift */, + 5B62A33527AE795800A19448 /* PreferencesModule.swift */, ); - path = Mandarin; + path = IMEModules; sourceTree = ""; }; - 6A0D4F2215FC0EB100ABF4B3 /* OpenVanilla */ = { + 5B62A32327AE756800A19448 /* LanguageParsers */ = { isa = PBXGroup; children = ( - 6A0D4F2315FC0EB100ABF4B3 /* OpenVanilla.h */, - 6A0D4F2415FC0EB100ABF4B3 /* OVAroundFilter.h */, - 6A0D4F2515FC0EB100ABF4B3 /* OVBase.h */, - 6A0D4F2615FC0EB100ABF4B3 /* OVBenchmark.h */, - 6A0D4F2715FC0EB100ABF4B3 /* OVCandidateService.h */, - 6A0D4F2815FC0EB100ABF4B3 /* OVCINDatabaseService.h */, - 6A0D4F2915FC0EB100ABF4B3 /* OVCINDataTable.h */, - 6A0D4F2A15FC0EB100ABF4B3 /* OVCINToSQLiteConvertor.h */, - 6A0D4F2B15FC0EB100ABF4B3 /* OVDatabaseService.h */, - 6A0D4F2C15FC0EB100ABF4B3 /* OVDateTimeHelper.h */, - 6A0D4F2D15FC0EB100ABF4B3 /* OVEncodingService.h */, - 6A0D4F2E15FC0EB100ABF4B3 /* OVEventHandlingContext.h */, - 6A0D4F2F15FC0EB100ABF4B3 /* OVException.h */, - 6A0D4F3015FC0EB100ABF4B3 /* OVFileHelper.h */, - 6A0D4F3115FC0EB100ABF4B3 /* OVFrameworkInfo.h */, - 6A0D4F3215FC0EB100ABF4B3 /* OVInputMethod.h */, - 6A0D4F3315FC0EB100ABF4B3 /* OVKey.h */, - 6A0D4F3415FC0EB100ABF4B3 /* OVKeyPreprocessor.h */, - 6A0D4F3515FC0EB100ABF4B3 /* OVKeyValueMap.h */, - 6A0D4F3615FC0EB100ABF4B3 /* OVLoaderBase.h */, - 6A0D4F3715FC0EB100ABF4B3 /* OVLoaderService.h */, - 6A0D4F3815FC0EB100ABF4B3 /* OVLocalization.h */, - 6A0D4F3915FC0EB100ABF4B3 /* OVModule.h */, - 6A0D4F3A15FC0EB100ABF4B3 /* OVModulePackage.h */, - 6A0D4F3B15FC0EB100ABF4B3 /* OVOutputFilter.h */, - 6A0D4F3C15FC0EB100ABF4B3 /* OVPathInfo.h */, - 6A0D4F3D15FC0EB100ABF4B3 /* OVSQLiteDatabaseService.h */, - 6A0D4F3E15FC0EB100ABF4B3 /* OVSQLiteWrapper.h */, - 6A0D4F3F15FC0EB100ABF4B3 /* OVStringHelper.h */, - 6A0D4F4015FC0EB100ABF4B3 /* OVTextBuffer.h */, - 6A0D4F4115FC0EB100ABF4B3 /* OVUTF8Helper.h */, - 6A0D4F4215FC0EB100ABF4B3 /* OVWildcard.h */, - ); - path = OpenVanilla; + 6A0D4F1315FC0EB100ABF4B3 /* Gramambular */, + ); + path = LanguageParsers; sourceTree = ""; }; - 6A0D4F4715FC0EB900ABF4B3 /* Resources */ = { + 5B62A32427AE757300A19448 /* LangModelRelated */ = { + isa = PBXGroup; + children = ( + D41355D6278D7409005E5CBD /* mgrLangModel.h */, + D495583A27A5C6C4006ADE1C /* mgrLangModel_Privates.h */, + D41355D7278D7409005E5CBD /* mgrLangModel.mm */, + 5B62A32527AE758000A19448 /* SubLanguageModels */, + D41355D9278E6D17005E5CBD /* vChewingLM.cpp */, + D41355DA278E6D17005E5CBD /* vChewingLM.h */, + ); + path = LangModelRelated; + sourceTree = ""; + }; + 5B62A32527AE758000A19448 /* SubLanguageModels */ = { + isa = PBXGroup; + children = ( + 5B62A32B27AE78B000A19448 /* CNSLM.h */, + 5B62A32A27AE78B000A19448 /* CNSLM.mm */, + 5B62A32C27AE78B000A19448 /* CoreLM.h */, + 5B62A32D27AE78B000A19448 /* CoreLM.mm */, + D41355DC278EA3ED005E5CBD /* UserPhrasesLM.cpp */, + D41355DD278EA3ED005E5CBD /* UserPhrasesLM.h */, + 6ACC3D422793701600F1B140 /* ParselessLM.cpp */, + 6ACC3D432793701600F1B140 /* ParselessLM.h */, + 6ACC3D402793701600F1B140 /* ParselessPhraseDB.cpp */, + 6ACC3D412793701600F1B140 /* ParselessPhraseDB.h */, + D44FB74B2792189A003C80A6 /* PhraseReplacementMap.cpp */, + D44FB74C2792189A003C80A6 /* PhraseReplacementMap.h */, + D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */, + D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */, + D47D73AA27A6CAE600255A50 /* AssociatedPhrases.cpp */, + D47D73AB27A6CAE600255A50 /* AssociatedPhrases.h */, + ); + path = SubLanguageModels; + sourceTree = ""; + }; + 5B62A33027AE78E500A19448 /* Resources */ = { isa = PBXGroup; children = ( - 6AFF97F0253B299E007F1C49 /* OVNonModalAlertWindowController.xib */, 6A0D4EEE15FC0DA600ABF4B3 /* Images */, - 6A0D4EF515FC0DA600ABF4B3 /* McBopomofo-Info.plist */, - 6A0D4F4815FC0EE100ABF4B3 /* InfoPlist.strings */, - 6A0D4F4A15FC0EE100ABF4B3 /* Localizable.strings */, + 5BBBB76E27AED70B0023B93A /* MenuIcons */, + 5BBBB75C27AED54C0023B93A /* SoundFiles */, + 6A0D4EF515FC0DA600ABF4B3 /* IME-Info.plist */, + D4E33D8D27A838F0006DB1CF /* InfoPlist.strings */, + D4E33D8827A838CF006DB1CF /* Localizable.strings */, + ); + path = Resources; + sourceTree = ""; + }; + 5B62A33927AE7C6700A19448 /* UI */ = { + isa = PBXGroup; + children = ( + 5B62A33E27AE7CD900A19448 /* CandidateUI */, + 5B62A34227AE7CD900A19448 /* TooltipUI */, + 5B62A34427AE7CD900A19448 /* NotifierUI */, + ); + path = UI; + sourceTree = ""; + }; + 5B62A33A27AE7C7500A19448 /* WindowControllers */ = { + isa = PBXGroup; + children = ( + 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */, + D47F7DCF278C0897002F9DD7 /* ctlNonModalAlertWindow.swift */, + D47F7DCD278BFB57002F9DD7 /* ctlPrefWindow.swift */, + ); + path = WindowControllers; + sourceTree = ""; + }; + 5B62A33B27AE7C7F00A19448 /* WindowNIBs */ = { + isa = PBXGroup; + children = ( + 5BBBB76927AED5DB0023B93A /* frmAboutWindow.xib */, + 5BBBB76527AED5DB0023B93A /* frmNonModalAlertWindow.xib */, + 5BBBB76727AED5DB0023B93A /* frmPreferences.xib */, 6A187E2816004C5900466B2E /* MainMenu.xib */, - 6A0D4F4E15FC0EE100ABF4B3 /* preferences.xib */, ); - name = Resources; + path = WindowNIBs; sourceTree = ""; }; - 6A38BBDD15FC115800A8A51F /* Data */ = { + 5B62A33E27AE7CD900A19448 /* CandidateUI */ = { isa = PBXGroup; children = ( - 6A38BBE115FC117A00A8A51F /* bin */, - 6A38BBDE15FC117A00A8A51F /* 4_in_5.txt */, - 6A38BBDF15FC117A00A8A51F /* 4_in_6.txt */, - 6A38BBE015FC117A00A8A51F /* 5_in_6.txt */, - 6A38BBF215FC117A00A8A51F /* blacklist.txt */, - 6A38BBF315FC117A00A8A51F /* BPMFBase.txt */, - 6A38BBF415FC117A00A8A51F /* BPMFMappings.txt */, - 6A38BBF515FC117A00A8A51F /* BPMFPunctuations.txt */, - 6A38BBF615FC117A00A8A51F /* data.txt */, - 6AD7CBC715FE555000691B5B /* data-plain-bpmf.txt */, - 6A38BBF715FC117A00A8A51F /* heterophony1.list */, - 6A38BBF815FC117A00A8A51F /* heterophony2.list */, - 6A38BBF915FC117A00A8A51F /* heterophony3.list */, - 6A38BBFA15FC117A00A8A51F /* Makefile */, - 6A38BBFB15FC117A00A8A51F /* phrase.occ */, - 6A38BBFC15FC117A00A8A51F /* PhraseFreq.txt */, - 6A38BBFD15FC117A00A8A51F /* README */, - ); - path = Data; + 5B62A33F27AE7CD900A19448 /* HorizontalCandidateController.swift */, + 5B62A34027AE7CD900A19448 /* CandidateController.swift */, + 5B62A34127AE7CD900A19448 /* VerticalCandidateController.swift */, + ); + path = CandidateUI; sourceTree = ""; }; - 6A38BBE115FC117A00A8A51F /* bin */ = { + 5B62A34227AE7CD900A19448 /* TooltipUI */ = { isa = PBXGroup; children = ( - 6A38BBE215FC117A00A8A51F /* BIG5toUTF8.pl */, - 6A38BBE315FC117A00A8A51F /* build4wlist.bash */, - 6A38BBE415FC117A00A8A51F /* buildFreq.bash */, - 6A38BBE515FC117A00A8A51F /* cook.py */, - 6A38BBE615FC117A00A8A51F /* cook.rb */, - 6A38BBE715FC117A00A8A51F /* count.bash */, - 6A38BBE815FC117A00A8A51F /* count.occurrence.c */, - 6A38BBE915FC117A00A8A51F /* count.occurrence.pl */, - 6A38BBEA15FC117A00A8A51F /* count.occurrence.py */, - 6A38BBEB15FC117A00A8A51F /* countphrase.bash */, - 6A38BBEC15FC117A00A8A51F /* filter.bash */, - 6A38BBED15FC117A00A8A51F /* Makefile */, - 6A38BBEE15FC117A00A8A51F /* randomShuffle.bash */, - 6A38BBEF15FC117A00A8A51F /* README */, - 6A38BBF015FC117A00A8A51F /* typocorrection.bash */, - 6A38BBF115FC117A00A8A51F /* utf8length.pl */, - ); - path = bin; + 5B62A34327AE7CD900A19448 /* TooltipController.swift */, + ); + path = TooltipUI; sourceTree = ""; }; - 6ACA41E715FC1D9000935EF6 /* Installer */ = { + 5B62A34427AE7CD900A19448 /* NotifierUI */ = { + isa = PBXGroup; + children = ( + 5B62A34527AE7CD900A19448 /* NotifierController.swift */, + ); + path = NotifierUI; + sourceTree = ""; + }; + 5B62A35027AE7F6600A19448 /* Data */ = { + isa = PBXGroup; + children = ( + 5B2DB17127AF8771006D874E /* Makefile */, + 5B2DB16D27AF6891006D874E /* data-chs.txt */, + 5B2DB16E27AF6891006D874E /* data-cht.txt */, + ); + name = Data; + sourceTree = ""; + }; + 5BBBB75C27AED54C0023B93A /* SoundFiles */ = { + isa = PBXGroup; + children = ( + 5BBBB75D27AED54C0023B93A /* Beep.m4a */, + 5BBBB75E27AED54C0023B93A /* Fart.m4a */, + ); + path = SoundFiles; + sourceTree = ""; + }; + 5BBBB76E27AED70B0023B93A /* MenuIcons */ = { + isa = PBXGroup; + children = ( + 5BBBB76F27AED70B0023B93A /* MenuIcon-TCVIM@2x.png */, + 5BBBB77027AED70B0023B93A /* MenuIcon-SCVIM@2x.png */, + 5BBBB77127AED70B0023B93A /* MenuIcon-SCVIM.png */, + 5BBBB77227AED70B0023B93A /* MenuIcon-TCVIM.png */, + ); + name = MenuIcons; + path = Source/Resources/MenuIcons; + sourceTree = SOURCE_ROOT; + }; + 5BBBB77827AEDB330023B93A /* Resources */ = { isa = PBXGroup; children = ( - 6A225A212367A1D700F685C6 /* ArchiveUtil.h */, - 6A225A222367A1D700F685C6 /* ArchiveUtil.m */, - 6A225A1E23679F2600F685C6 /* NotarizedArchives */, - 6ACA41E815FC1D9000935EF6 /* AppDelegate.h */, - 6ACA41E915FC1D9000935EF6 /* AppDelegate.m */, 6ACA41EA15FC1D9000935EF6 /* InfoPlist.strings */, - 6ACA41EC15FC1D9000935EF6 /* License.rtf */, 6ACA41EE15FC1D9000935EF6 /* Localizable.strings */, 6ACA41F015FC1D9000935EF6 /* MainMenu.xib */, + ); + path = Resources; + sourceTree = ""; + }; + 6A0D4E9215FC0CFA00ABF4B3 = { + isa = PBXGroup; + children = ( + 6ACA41E715FC1D9000935EF6 /* Installer */, + 6A0D4EC215FC0D3C00ABF4B3 /* Source */, + D427F766278C9CBD004A2160 /* Packages */, + 6A0D4EA315FC0D2D00ABF4B3 /* Products */, + D47D73C127A7200500255A50 /* Frameworks */, + ); + sourceTree = ""; + }; + 6A0D4EA315FC0D2D00ABF4B3 /* Products */ = { + isa = PBXGroup; + children = ( + 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */, + 6ACA41CB15FC1D7500935EF6 /* vChewingInstaller.app */, + ); + name = Products; + sourceTree = ""; + }; + 6A0D4EC215FC0D3C00ABF4B3 /* Source */ = { + isa = PBXGroup; + children = ( + 5B62A35027AE7F6600A19448 /* Data */, + 5B62A30127AE732800A19448 /* 3rdParty */, + 5B62A32027AE752000A19448 /* Headers */, + 6A0D4F1215FC0EB100ABF4B3 /* Modules */, + 5B62A33027AE78E500A19448 /* Resources */, + 5B62A33927AE7C6700A19448 /* UI */, + 5B62A33A27AE7C7500A19448 /* WindowControllers */, + 5B62A33B27AE7C7F00A19448 /* WindowNIBs */, + ); + path = Source; + sourceTree = ""; + }; + 6A0D4EEE15FC0DA600ABF4B3 /* Images */ = { + isa = PBXGroup; + children = ( + 6A2E40F5253A69DA00D1AE1D /* Images.xcassets */, + ); + path = Images; + sourceTree = ""; + }; + 6A0D4F1215FC0EB100ABF4B3 /* Modules */ = { + isa = PBXGroup; + children = ( + D427F76B278CA1BA004A2160 /* AppDelegate.swift */, + D47B92BF27972AC800458394 /* main.swift */, + 5B62A31F27AE74E900A19448 /* ControllerModules */, + 5B62A32127AE755D00A19448 /* FileHandlers */, + 5B62A32227AE756300A19448 /* IMEModules */, + 5B62A32427AE757300A19448 /* LangModelRelated */, + 5B62A32327AE756800A19448 /* LanguageParsers */, + 5B62A31E27AE74E400A19448 /* SFX */, + ); + path = Modules; + sourceTree = ""; + }; + 6A0D4F1315FC0EB100ABF4B3 /* Gramambular */ = { + isa = PBXGroup; + children = ( + 6A0D4F1415FC0EB100ABF4B3 /* Bigram.h */, + 6A0D4F1515FC0EB100ABF4B3 /* BlockReadingBuilder.h */, + 6A0D4F1615FC0EB100ABF4B3 /* Gramambular.h */, + 6A0D4F1715FC0EB100ABF4B3 /* Grid.h */, + 6A0D4F1815FC0EB100ABF4B3 /* KeyValuePair.h */, + 6A0D4F1915FC0EB100ABF4B3 /* LanguageModel.h */, + 6A0D4F1A15FC0EB100ABF4B3 /* Node.h */, + 6A0D4F1B15FC0EB100ABF4B3 /* NodeAnchor.h */, + 6A0D4F1C15FC0EB100ABF4B3 /* Span.h */, + 6A0D4F1D15FC0EB100ABF4B3 /* Unigram.h */, + 6A0D4F1E15FC0EB100ABF4B3 /* Walker.h */, + ); + path = Gramambular; + sourceTree = ""; + }; + 6ACA41E715FC1D9000935EF6 /* Installer */ = { + isa = PBXGroup; + children = ( + 6A225A1E23679F2600F685C6 /* NotarizedArchives */, + 5BBBB77827AEDB330023B93A /* Resources */, + D4F0BBE0279AF8B30071253C /* AppDelegate.swift */, + D4F0BBDE279AF1AF0071253C /* ArchiveUtil.swift */, 6ACA41F215FC1D9000935EF6 /* Installer-Info.plist */, 6ACA41F315FC1D9000935EF6 /* Installer-Prefix.pch */, - 6ACA41F415FC1D9000935EF6 /* main.m */, + 6A93050C279877FF00D370DA /* vChewingInstaller-Bridging-Header.h */, + D4F0BBE2279B08900071253C /* Chronosphere.h */, + D4F0BBE3279B08900071253C /* Chronosphere.m */, ); path = Installer; sourceTree = ""; }; + D427F766278C9CBD004A2160 /* Packages */ = { + isa = PBXGroup; + children = ( + 5B0CF37F27AD476E00784B08 /* SwiftyOpenCC */, + D44FB7482791B346003C80A6 /* VXHanConvert */, + ); + name = Packages; + sourceTree = ""; + }; + D47D73C127A7200500255A50 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXLegacyTarget section */ 6A38BC2115FC12FD00A8A51F /* Data */ = { isa = PBXLegacyTarget; - buildArgumentsString = "$(ACTION)"; + buildArgumentsString = "$(ACTION) macv"; buildConfigurationList = 6A38BC2215FC12FD00A8A51F /* Build configuration list for PBXLegacyTarget "Data" */; buildPhases = ( ); @@ -499,9 +610,9 @@ /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ - 6A0D4EA115FC0D2D00ABF4B3 /* McBopomofo */ = { + 6A0D4EA115FC0D2D00ABF4B3 /* vChewing */ = { isa = PBXNativeTarget; - buildConfigurationList = 6A0D4EC015FC0D2E00ABF4B3 /* Build configuration list for PBXNativeTarget "McBopomofo" */; + buildConfigurationList = 6A0D4EC015FC0D2E00ABF4B3 /* Build configuration list for PBXNativeTarget "vChewing" */; buildPhases = ( 6A0D4E9E15FC0D2D00ABF4B3 /* Sources */, 6A0D4E9F15FC0D2D00ABF4B3 /* Frameworks */, @@ -512,17 +623,18 @@ dependencies = ( 6A38BC2615FC131100A8A51F /* PBXTargetDependency */, ); - name = McBopomofo; + name = vChewing; packageProductDependencies = ( - D48550A225EBE689006A204C /* OpenCC */, + D44FB7492791B829003C80A6 /* VXHanConvert */, + 5B62A35127AE822400A19448 /* OpenCC */, ); - productName = McBopomofo; - productReference = 6A0D4EA215FC0D2D00ABF4B3 /* McBopomofo.app */; + productName = vChewing; + productReference = 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */; productType = "com.apple.product-type.application"; }; - 6ACA41CA15FC1D7500935EF6 /* McBopomofoInstaller */ = { + 6ACA41CA15FC1D7500935EF6 /* vChewingInstaller */ = { isa = PBXNativeTarget; - buildConfigurationList = 6ACA41E415FC1D7600935EF6 /* Build configuration list for PBXNativeTarget "McBopomofoInstaller" */; + buildConfigurationList = 6ACA41E415FC1D7600935EF6 /* Build configuration list for PBXNativeTarget "vChewingInstaller" */; buildPhases = ( 6ACA41C715FC1D7500935EF6 /* Sources */, 6ACA41C815FC1D7500935EF6 /* Frameworks */, @@ -534,9 +646,11 @@ dependencies = ( 6ACA420115FC1DCC00935EF6 /* PBXTargetDependency */, ); - name = McBopomofoInstaller; - productName = McBopomofoInstaller; - productReference = 6ACA41CB15FC1D7500935EF6 /* McBopomofoInstaller.app */; + name = vChewingInstaller; + packageProductDependencies = ( + ); + productName = vChewingInstaller; + productReference = 6ACA41CB15FC1D7500935EF6 /* vChewingInstaller.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -545,32 +659,34 @@ 6A0D4E9415FC0CFA00ABF4B3 /* Project object */ = { isa = PBXProject; attributes = { + LastSwiftUpdateCheck = 1320; LastUpgradeCheck = 1310; TargetAttributes = { 6A0D4EA115FC0D2D00ABF4B3 = { LastSwiftMigration = 1240; }; + 6ACA41CA15FC1D7500935EF6 = { + LastSwiftMigration = 1320; + }; }; }; - buildConfigurationList = 6A0D4E9715FC0CFA00ABF4B3 /* Build configuration list for PBXProject "McBopomofo" */; + buildConfigurationList = 6A0D4E9715FC0CFA00ABF4B3 /* Build configuration list for PBXProject "vChewing" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, - "zh-Hant", Base, ); mainGroup = 6A0D4E9215FC0CFA00ABF4B3; packageReferences = ( - D48550A125EBE689006A204C /* XCRemoteSwiftPackageReference "SwiftyOpenCC" */, ); productRefGroup = 6A0D4EA315FC0D2D00ABF4B3 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - 6A0D4EA115FC0D2D00ABF4B3 /* McBopomofo */, - 6ACA41CA15FC1D7500935EF6 /* McBopomofoInstaller */, + 6A0D4EA115FC0D2D00ABF4B3 /* vChewing */, + 6ACA41CA15FC1D7500935EF6 /* vChewingInstaller */, 6A38BC2115FC12FD00A8A51F /* Data */, ); }; @@ -581,18 +697,21 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6A0D4F0815FC0DA600ABF4B3 /* Bopomofo.tiff in Resources */, - 6A0D4F0915FC0DA600ABF4B3 /* Bopomofo@2x.tiff in Resources */, - 6A0D4F5315FC0EE100ABF4B3 /* preferences.xib in Resources */, - 6A0D4F5715FC0EF900ABF4B3 /* InfoPlist.strings in Resources */, - 6A0D4F5815FC0EF900ABF4B3 /* Localizable.strings in Resources */, + 5BBBB77427AED70B0023B93A /* MenuIcon-SCVIM@2x.png in Resources */, + D4E33D8A27A838CF006DB1CF /* Localizable.strings in Resources */, + 5BBBB76C27AED5DB0023B93A /* frmPreferences.xib in Resources */, + 5BBBB76027AED54C0023B93A /* Fart.m4a in Resources */, 6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */, - 6A38BC1515FC117A00A8A51F /* data.txt in Resources */, - 6AFF97F2253B299E007F1C49 /* OVNonModalAlertWindowController.xib in Resources */, - 6AE210B215FC63CC003659FE /* PlainBopomofo.tiff in Resources */, - 6AE210B315FC63CC003659FE /* PlainBopomofo@2x.tiff in Resources */, - 6AD7CBC815FE555000691B5B /* data-plain-bpmf.txt in Resources */, + D4E33D8F27A838F0006DB1CF /* InfoPlist.strings in Resources */, + 5BBBB76B27AED5DB0023B93A /* frmNonModalAlertWindow.xib in Resources */, + 5BBBB76D27AED5DB0023B93A /* frmAboutWindow.xib in Resources */, + 5BBBB77527AED70B0023B93A /* MenuIcon-SCVIM.png in Resources */, + 5B2DB17027AF6891006D874E /* data-cht.txt in Resources */, + 5BBBB77327AED70B0023B93A /* MenuIcon-TCVIM@2x.png in Resources */, + 5BBBB77627AED70B0023B93A /* MenuIcon-TCVIM.png in Resources */, 6A187E2616004C5900466B2E /* MainMenu.xib in Resources */, + 5BBBB75F27AED54C0023B93A /* Beep.m4a in Resources */, + 5B2DB16F27AF6891006D874E /* data-chs.txt in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -600,11 +719,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6ACA420215FC1E5200935EF6 /* McBopomofo.app in Resources */, + 6ACA420215FC1E5200935EF6 /* vChewing.app in Resources */, 6A2E40F9253A6AA000D1AE1D /* Images.xcassets in Resources */, 6ACA41FA15FC1D9000935EF6 /* InfoPlist.strings in Resources */, 6A225A1F23679F2600F685C6 /* NotarizedArchives in Resources */, - 6ACA41FB15FC1D9000935EF6 /* License.rtf in Resources */, 6ACA41FC15FC1D9000935EF6 /* Localizable.strings in Resources */, 6ACA41FD15FC1D9000935EF6 /* MainMenu.xib in Resources */, ); @@ -637,21 +755,44 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6A0D4ED015FC0D6400ABF4B3 /* AppDelegate.m in Sources */, - 6A0D4ED215FC0D6400ABF4B3 /* InputMethodController.mm in Sources */, - 6A0D4ED315FC0D6400ABF4B3 /* main.m in Sources */, - 6A0D4ED415FC0D6400ABF4B3 /* OVInputSourceHelper.m in Sources */, - 6A0D4ED515FC0D6400ABF4B3 /* PreferencesWindowController.m in Sources */, - 6A0D4EFE15FC0DA600ABF4B3 /* VTCandidateController.m in Sources */, - 6A0D4EFF15FC0DA600ABF4B3 /* VTHorizontalCandidateController.m in Sources */, - 6A0D4F0015FC0DA600ABF4B3 /* VTHorizontalCandidateView.m in Sources */, - 6AFF97F3253B299E007F1C49 /* OVNonModalAlertWindowController.m in Sources */, - 6A0D4F0115FC0DA600ABF4B3 /* VTVerticalCandidateController.m in Sources */, - 6A0D4F0215FC0DA600ABF4B3 /* VTVerticalCandidateTableView.m in Sources */, - 6A0D4F0315FC0DA600ABF4B3 /* VTVerticalKeyLabelStripView.m in Sources */, - D427A9C125ED28CC005D43E0 /* OpenCCBridge.swift in Sources */, + 5B62A31927AE73A700A19448 /* ioapi.m in Sources */, + 5B62A31C27AE73A700A19448 /* AWFileHash.m in Sources */, + D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */, + 6ACC3D442793701600F1B140 /* ParselessPhraseDB.cpp in Sources */, + D461B792279DAC010070E734 /* InputState.swift in Sources */, + 5B62A33D27AE7CC100A19448 /* ctlAboutWindow.swift in Sources */, + D47B92C027972AD100458394 /* main.swift in Sources */, + D44FB74D2792189A003C80A6 /* PhraseReplacementMap.cpp in Sources */, + D4A13D5A27A59F0B003BE359 /* ctlInputMethod.swift in Sources */, + D4E569DC27A34D0E00AC2CEF /* KeyHandler.mm in Sources */, + D47F7DD0278C0897002F9DD7 /* ctlNonModalAlertWindow.swift in Sources */, + 5B62A32F27AE78B000A19448 /* CoreLM.mm in Sources */, + 5B62A33427AE793F00A19448 /* OpenCCBridge.swift in Sources */, + D456576E279E4F7B00DF6BC9 /* KeyHandlerInput.swift in Sources */, + D47F7DCE278BFB57002F9DD7 /* ctlPrefWindow.swift in Sources */, + D47D73AC27A6CAE600255A50 /* AssociatedPhrases.cpp in Sources */, + 5B62A34A27AE7CD900A19448 /* NotifierController.swift in Sources */, + 5B62A31827AE73A700A19448 /* zip.m in Sources */, + 5B62A32E27AE78B000A19448 /* CNSLM.mm in Sources */, + D41355DB278E6D17005E5CBD /* vChewingLM.cpp in Sources */, + 5B62A31A27AE73A700A19448 /* mztools.m in Sources */, + 5B62A32927AE77D100A19448 /* FSEventStreamHelper.swift in Sources */, + D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */, + 5B62A33627AE795800A19448 /* PreferencesModule.swift in Sources */, + 5B62A33827AE79CD00A19448 /* NSStringUtils.swift in Sources */, + 5B62A33227AE792F00A19448 /* InputSourceHelper.swift in Sources */, + 5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */, 6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */, - 6A0421A815FEF3F50061ED63 /* FastLM.cpp in Sources */, + 5B62A34827AE7CD900A19448 /* VerticalCandidateController.swift in Sources */, + 6ACC3D452793701600F1B140 /* ParselessLM.cpp in Sources */, + 5BBBB77A27AEDC690023B93A /* clsSFX.swift in Sources */, + 5B62A31727AE73A700A19448 /* unzip.m in Sources */, + 5B62A34627AE7CD900A19448 /* HorizontalCandidateController.swift in Sources */, + 5B62A34727AE7CD900A19448 /* CandidateController.swift in Sources */, + 5B62A31B27AE73A700A19448 /* SSZipArchive.m in Sources */, + D41355DE278EA3ED005E5CBD /* UserPhrasesLM.cpp in Sources */, + 6ACC3D3F27914F2400F1B140 /* KeyValueBlobReader.cpp in Sources */, + D41355D8278D74B5005E5CBD /* mgrLangModel.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -659,10 +800,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6ACA41F915FC1D9000935EF6 /* AppDelegate.m in Sources */, - 6A225A232367A1D700F685C6 /* ArchiveUtil.m in Sources */, - 6AB3620D274CA50700AC7547 /* OVInputSourceHelper.m in Sources */, - 6ACA41FF15FC1D9000935EF6 /* main.m in Sources */, + D4F0BBE1279AF8B30071253C /* AppDelegate.swift in Sources */, + D4F0BBE4279B08900071253C /* Chronosphere.m in Sources */, + D4F0BBDF279AF1AF0071253C /* ArchiveUtil.swift in Sources */, + 5B62A35327AE89C400A19448 /* InputSourceHelper.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -676,46 +817,39 @@ }; 6ACA420115FC1DCC00935EF6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 6A0D4EA115FC0D2D00ABF4B3 /* McBopomofo */; + target = 6A0D4EA115FC0D2D00ABF4B3 /* vChewing */; targetProxy = 6ACA420015FC1DCC00935EF6 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ - 6A0D4F4815FC0EE100ABF4B3 /* InfoPlist.strings */ = { + 5BBBB76527AED5DB0023B93A /* frmNonModalAlertWindow.xib */ = { isa = PBXVariantGroup; children = ( - 6A0D4F4915FC0EE100ABF4B3 /* en */, - 6A0D4F5415FC0EF900ABF4B3 /* zh-Hant */, + 5BBBB76627AED5DB0023B93A /* Base */, ); - name = InfoPlist.strings; - path = ..; + name = frmNonModalAlertWindow.xib; sourceTree = ""; }; - 6A0D4F4A15FC0EE100ABF4B3 /* Localizable.strings */ = { + 5BBBB76727AED5DB0023B93A /* frmPreferences.xib */ = { isa = PBXVariantGroup; children = ( - 6A0D4F4B15FC0EE100ABF4B3 /* en */, - 6A0D4F5515FC0EF900ABF4B3 /* zh-Hant */, + 5BBBB76827AED5DB0023B93A /* Base */, ); - name = Localizable.strings; - path = ..; + name = frmPreferences.xib; sourceTree = ""; }; - 6A0D4F4E15FC0EE100ABF4B3 /* preferences.xib */ = { + 5BBBB76927AED5DB0023B93A /* frmAboutWindow.xib */ = { isa = PBXVariantGroup; children = ( - 6A0D4F5615FC0EF900ABF4B3 /* zh-Hant */, - 6A15B32721A51F2300B92CD3 /* Base */, + 5BBBB76A27AED5DB0023B93A /* Base */, ); - name = preferences.xib; - path = ..; + name = frmAboutWindow.xib; sourceTree = ""; }; 6A187E2816004C5900466B2E /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( - 6A187E2916004C7300466B2E /* zh-Hant */, 6A15B32521A51F2300B92CD3 /* Base */, ); name = MainMenu.xib; @@ -725,41 +859,42 @@ isa = PBXVariantGroup; children = ( 6ACA41EB15FC1D9000935EF6 /* en */, - 6ACA41F515FC1D9000935EF6 /* zh-Hant */, ); name = InfoPlist.strings; - path = Source/Installer; - sourceTree = SOURCE_ROOT; - }; - 6ACA41EC15FC1D9000935EF6 /* License.rtf */ = { - isa = PBXVariantGroup; - children = ( - 6ACA41ED15FC1D9000935EF6 /* en */, - 6ACA41F615FC1D9000935EF6 /* zh-Hant */, - ); - name = License.rtf; - path = Source/Installer; - sourceTree = SOURCE_ROOT; + sourceTree = ""; }; 6ACA41EE15FC1D9000935EF6 /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( 6ACA41EF15FC1D9000935EF6 /* en */, - 6ACA41F715FC1D9000935EF6 /* zh-Hant */, ); name = Localizable.strings; - path = Source/Installer; - sourceTree = SOURCE_ROOT; + sourceTree = ""; }; 6ACA41F015FC1D9000935EF6 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( - 6ACA41F815FC1D9000935EF6 /* zh-Hant */, 6A15B32421A51F2300B92CD3 /* Base */, + 5BBBB77727AEDB290023B93A /* en */, ); name = MainMenu.xib; - path = Source/Installer; - sourceTree = SOURCE_ROOT; + sourceTree = ""; + }; + D4E33D8827A838CF006DB1CF /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + D4E33D8927A838CF006DB1CF /* Base */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + D4E33D8D27A838F0006DB1CF /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + D4E33D8E27A838F0006DB1CF /* Base */, + ); + name = InfoPlist.strings; + sourceTree = ""; }; /* End PBXVariantGroup section */ @@ -796,6 +931,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11.5; ONLY_ACTIVE_ARCH = YES; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", @@ -835,6 +971,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11.5; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-fcxx-modules", @@ -848,7 +985,8 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; @@ -860,12 +998,13 @@ CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1919; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Source/McBopomofo-Prefix.pch"; + GCC_PREFIX_HEADER = "Source/Headers/vChewing-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", @@ -886,17 +1025,18 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_VARIABLE = YES; - INFOPLIST_FILE = "Source/McBopomofo-Info.plist"; + INFOPLIST_FILE = "Source/Resources/IME-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.11.5; + MARKETING_VERSION = 1.3.0; ONLY_ACTIVE_ARCH = YES; - PRODUCT_BUNDLE_IDENTIFIER = org.openvanilla.inputmethod.McBopomofo; + PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; - SWIFT_OBJC_BRIDGING_HEADER = "Source/McBopomofo-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "Source/Headers/vChewing-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; WRAPPER_EXTENSION = app; @@ -908,7 +1048,8 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; @@ -920,11 +1061,12 @@ CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; + CURRENT_PROJECT_VERSION = 1919; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Source/McBopomofo-Prefix.pch"; + GCC_PREFIX_HEADER = "Source/Headers/vChewing-Prefix.pch"; GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; @@ -940,16 +1082,17 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_VARIABLE = YES; - INFOPLIST_FILE = "Source/McBopomofo-Info.plist"; + INFOPLIST_FILE = "Source/Resources/IME-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.10; - PRODUCT_BUNDLE_IDENTIFIER = org.openvanilla.inputmethod.McBopomofo; + MACOSX_DEPLOYMENT_TARGET = 10.11.5; + MARKETING_VERSION = 1.3.0; + PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; - SWIFT_OBJC_BRIDGING_HEADER = "Source/McBopomofo-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "Source/Headers/vChewing-Bridging-Header.h"; SWIFT_VERSION = 5.0; WRAPPER_EXTENSION = app; }; @@ -1017,19 +1160,22 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1919; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Source/Installer/Installer-Prefix.pch"; + GCC_PREFIX_HEADER = "Installer/Installer-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", @@ -1041,12 +1187,20 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ../; - INFOPLIST_FILE = "Source/Installer/Installer-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.10; + INFOPLIST_FILE = "Installer/Installer-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.11.5; + MARKETING_VERSION = 1.3.0; ONLY_ACTIVE_ARCH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "org.openvanilla.McBopomofo.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; + SWIFT_OBJC_BRIDGING_HEADER = "Installer/vChewingInstaller-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; WRAPPER_EXTENSION = app; }; name = Debug; @@ -1056,29 +1210,39 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1919; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Source/Installer/Installer-Prefix.pch"; + GCC_PREFIX_HEADER = "Installer/Installer-Prefix.pch"; GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ../; - INFOPLIST_FILE = "Source/Installer/Installer-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - PRODUCT_BUNDLE_IDENTIFIER = "org.openvanilla.McBopomofo.${PRODUCT_NAME:rfc1034identifier}"; + INFOPLIST_FILE = "Installer/Installer-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.11.5; + MARKETING_VERSION = 1.3.0; + PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; + SWIFT_OBJC_BRIDGING_HEADER = "Installer/vChewingInstaller-Bridging-Header.h"; + SWIFT_VERSION = 5.0; WRAPPER_EXTENSION = app; }; name = Release; @@ -1086,7 +1250,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 6A0D4E9715FC0CFA00ABF4B3 /* Build configuration list for PBXProject "McBopomofo" */ = { + 6A0D4E9715FC0CFA00ABF4B3 /* Build configuration list for PBXProject "vChewing" */ = { isa = XCConfigurationList; buildConfigurations = ( 6A0D4E9915FC0CFA00ABF4B3 /* Debug */, @@ -1095,7 +1259,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 6A0D4EC015FC0D2E00ABF4B3 /* Build configuration list for PBXNativeTarget "McBopomofo" */ = { + 6A0D4EC015FC0D2E00ABF4B3 /* Build configuration list for PBXNativeTarget "vChewing" */ = { isa = XCConfigurationList; buildConfigurations = ( 6A0D4EBE15FC0D2E00ABF4B3 /* Debug */, @@ -1113,7 +1277,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 6ACA41E415FC1D7600935EF6 /* Build configuration list for PBXNativeTarget "McBopomofoInstaller" */ = { + 6ACA41E415FC1D7600935EF6 /* Build configuration list for PBXNativeTarget "vChewingInstaller" */ = { isa = XCConfigurationList; buildConfigurations = ( 6ACA41E515FC1D7600935EF6 /* Debug */, @@ -1124,23 +1288,15 @@ }; /* End XCConfigurationList section */ -/* Begin XCRemoteSwiftPackageReference section */ - D48550A125EBE689006A204C /* XCRemoteSwiftPackageReference "SwiftyOpenCC" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ddddxxx/SwiftyOpenCC.git"; - requirement = { - kind = revision; - revision = 1d8105a0f7199c90af722bff62728050c858e777; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - /* Begin XCSwiftPackageProductDependency section */ - D48550A225EBE689006A204C /* OpenCC */ = { + 5B62A35127AE822400A19448 /* OpenCC */ = { isa = XCSwiftPackageProductDependency; - package = D48550A125EBE689006A204C /* XCRemoteSwiftPackageReference "SwiftyOpenCC" */; productName = OpenCC; }; + D44FB7492791B829003C80A6 /* VXHanConvert */ = { + isa = XCSwiftPackageProductDependency; + productName = VXHanConvert; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 6A0D4E9415FC0CFA00ABF4B3 /* Project object */; diff --git a/vChewing.xcodeproj/xcshareddata/xcschemes/Data.xcscheme b/vChewing.xcodeproj/xcshareddata/xcschemes/Data.xcscheme new file mode 100644 index 0000000000000000000000000000000000000000..ca7f98940b553cb011ef3f99d57ce66a09b7e9a9 --- /dev/null +++ b/vChewing.xcodeproj/xcshareddata/xcschemes/Data.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/McBopomofo.xcodeproj/xcshareddata/xcschemes/McBopomofo.xcscheme b/vChewing.xcodeproj/xcshareddata/xcschemes/vChewing.xcscheme similarity index 81% rename from McBopomofo.xcodeproj/xcshareddata/xcschemes/McBopomofo.xcscheme rename to vChewing.xcodeproj/xcshareddata/xcschemes/vChewing.xcscheme index 3b2c3c69a406b8d14c5a08d5f0239cbee1c24fe9..972b0d97e383199f28ec6696fac5e0d2919fd370 100644 --- a/McBopomofo.xcodeproj/xcshareddata/xcschemes/McBopomofo.xcscheme +++ b/vChewing.xcodeproj/xcshareddata/xcschemes/vChewing.xcscheme @@ -1,6 +1,6 @@ + BuildableName = "vChewing.app" + BlueprintName = "vChewing" + ReferencedContainer = "container:vChewing.xcodeproj"> @@ -31,7 +31,7 @@ + BuildableName = "vChewing.app" + BlueprintName = "vChewing" + ReferencedContainer = "container:vChewing.xcodeproj"> @@ -62,9 +62,9 @@ + BuildableName = "vChewing.app" + BlueprintName = "vChewing" + ReferencedContainer = "container:vChewing.xcodeproj"> diff --git a/McBopomofo.xcodeproj/xcshareddata/xcschemes/McBopomofoInstaller.xcscheme b/vChewing.xcodeproj/xcshareddata/xcschemes/vChewingInstaller.xcscheme similarity index 79% rename from McBopomofo.xcodeproj/xcshareddata/xcschemes/McBopomofoInstaller.xcscheme rename to vChewing.xcodeproj/xcshareddata/xcschemes/vChewingInstaller.xcscheme index b3daf3755f922d5d1b9dc982a51b47b883997d0f..e47eb40cc8961e22ada4b3928ead8a8db722a94b 100644 --- a/McBopomofo.xcodeproj/xcshareddata/xcschemes/McBopomofoInstaller.xcscheme +++ b/vChewing.xcodeproj/xcshareddata/xcschemes/vChewingInstaller.xcscheme @@ -1,6 +1,6 @@ + BuildableName = "vChewingInstaller.app" + BlueprintName = "vChewingInstaller" + ReferencedContainer = "container:vChewing.xcodeproj"> @@ -31,7 +31,7 @@ + BuildableName = "vChewingInstaller.app" + BlueprintName = "vChewingInstaller" + ReferencedContainer = "container:vChewing.xcodeproj"> @@ -62,9 +62,9 @@ + BuildableName = "vChewingInstaller.app" + BlueprintName = "vChewingInstaller" + ReferencedContainer = "container:vChewing.xcodeproj">